Skip to content

Commit 709bbf8

Browse files
Sergii KovalevEnase
authored andcommitted
allow configurable master alias
Update README with configurable master alias usage Remove Merge markers
1 parent 3975159 commit 709bbf8

File tree

9 files changed

+102
-20
lines changed

9 files changed

+102
-20
lines changed

README.md

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,17 @@ functionality for aliases.
3636
## Deploy the default alias
3737

3838
The default alias (for the stage) is deployed just by doing a standard stage
39-
deployment with `serverless deploy`. From now on you can reference the aliased
40-
versions on Lambda invokes with the stage qualifier. The aliased version is
41-
read only in the AWS console, so it is guaranteed that the environment and
42-
function parameters (memory, etc.) cannot be changed for a deployed version
43-
by accident, as it can be done with the `$LATEST` qualifier.
44-
This adds an additional level of stability to your deployment process.
39+
deployment with `serverless deploy`. By default the alias is set to the stage
40+
name. Optionally you can set the name of the default (master) alias using the
41+
option `--masterAlias`, e.g., `serverless deploy --masterAlias`. (If you have
42+
already created a serverless deployment without manually setting the default
43+
alias, this option should not be used.)
44+
From now on you can reference the aliased versions on Lambda invokes with the
45+
stage qualifier. The aliased version is read only in the AWS console, so it is
46+
guaranteed that the environment and function parameters (memory, etc.) cannot
47+
be changed for a deployed version by accident, as it can be done with the
48+
`$LATEST` qualifier.This adds an additional level of stability to your deployment
49+
process.
4550

4651
## Deploy a single function
4752

lib/aliasRestructureStack.js

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,15 +73,30 @@ module.exports = {
7373
return BbPromise.resolve([ currentTemplate, aliasStackTemplates, currentAliasStackTemplate ]);
7474
},
7575

76-
aliasRestructureStack(currentTemplate, aliasStackTemplates, currentAliasStackTemplate) {
76+
addMasterAliasName(currentTemplate, aliasStackTemplates, currentAliasStackTemplate) {
77+
const stageStack = this._serverless.service.provider.compiledCloudFormationTemplate;
78+
if (stageStack && !stageStack.Outputs.MasterAliasName) {
79+
const masterAlias = this._masterAlias || currentTemplate.Outputs.MasterAliasName.Value;
80+
stageStack.Outputs.MasterAliasName = {
81+
Description: 'Master Alias name (serverless-aws-alias plugin)',
82+
Value: masterAlias,
83+
Export: {
84+
Name: `${this._provider.naming.getStackName()}-MasterAliasName`
85+
}
86+
};
87+
}
88+
return BbPromise.resolve([ currentTemplate, aliasStackTemplates, currentAliasStackTemplate ]);
89+
},
7790

91+
aliasRestructureStack(currentTemplate, aliasStackTemplates, currentAliasStackTemplate) {
7892
this._serverless.cli.log('Preparing alias ...');
7993

80-
if (_.isEmpty(aliasStackTemplates) && this._stage !== this._alias) {
81-
throw new this._serverless.classes.Error(new Error('You have to deploy the master alias at least once with "serverless deploy"'));
94+
if (_.isEmpty(aliasStackTemplates) && this._masterAlias !== this._alias) {
95+
throw new this._serverless.classes.Error(new Error('You have to deploy the master alias at least once with "serverless deploy [--masterAlias]"'));
8296
}
8397

8498
return BbPromise.resolve([ currentTemplate, aliasStackTemplates, currentAliasStackTemplate ]).bind(this)
99+
.spread(this.addMasterAliasName)
85100
.spread(this.aliasInit)
86101
.spread(this.aliasHandleUserResources)
87102
.spread(this.aliasHandleLambdaRole)

lib/removeAlias.js

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -221,26 +221,27 @@ module.exports = {
221221
this._serverless.cli.log('noDeploy option active - will do nothing');
222222
return BbPromise.resolve();
223223
}
224-
225-
if (this._stage && this._stage === this._alias) {
224+
225+
this._masterAlias = currentTemplate.Outputs.MasterAliasName.Value;
226+
if (this._stage && this._masterAlias === this._alias) {
226227
// Removal of the master alias is requested -> check if any other aliases are still deployed.
227228
const aliases = _.map(aliasStackTemplates, aliasTemplate => _.get(aliasTemplate, 'Outputs.ServerlessAliasName.Value'));
228229
if (!_.isEmpty(aliases)) {
229-
throw new this._serverless.classes.Error(`Remove the other deployed aliases before removing the service: ${_.without(aliases, this._alias)}`);
230+
throw new this._serverless.classes.Error(`Remove the other deployed aliases before removing the service: ${_.without(aliases, this._masterAlias)}`);
230231
}
231232
if (_.isEmpty(currentAliasStackTemplate)) {
232-
throw new this._serverless.classes.Error(`Internal error: Stack for master alias ${this._alias} is not deployed. Try to solve the problem by manual interaction with the AWS console.`);
233+
throw new this._serverless.classes.Error(`Internal error: Stack for master alias ${this._masterAlias} is not deployed. Try to solve the problem by manual interaction with the AWS console.`);
233234
}
234235

235236
// We're ready for removal
236-
this._serverless.cli.log(`Removing master alias and stage ${this._alias} ...`);
237+
this._serverless.cli.log(`Removing master alias and stage ${this._masterAlias} ...`);
237238

238239
return BbPromise.resolve([ currentTemplate, aliasStackTemplates, currentAliasStackTemplate ]).bind(this)
239240
.spread(this.aliasRemoveAliasStack)
240241
.then(() => this._serverless.pluginManager.spawn('remove'));
241242
}
242243

243-
this._serverless.cli.log(`Removing alias ${this._alias} ...`);
244+
this._serverless.cli.log(`Removing alias ${this._masterAlias} ...`);
244245

245246
return BbPromise.resolve([ currentTemplate, aliasStackTemplates, currentAliasStackTemplate ]).bind(this)
246247
.spread(this.aliasCreateStackChanges)

lib/stackops/apiGateway.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,7 @@ module.exports = function(currentTemplate, aliasStackTemplates, currentAliasStac
278278
// Adjust permission to reference the function aliases
279279
_.forOwn(apiLambdaPermissions, (permission, name) => {
280280
const functionName = _.replace(name, /LambdaPermissionApiGateway$/, '');
281+
281282
const versionName = utils.getFunctionVersionName(versions, functionName);
282283
const aliasName = utils.getAliasVersionName(aliases, functionName);
283284
const isExternalRef = isExternalRefAuthorizerPredicate(permission.Properties.FunctionName);

lib/validate.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ module.exports = {
1717

1818
// Set configuration
1919
this._stage = this._provider.getStage();
20-
this._alias = this._options.alias || this._stage;
20+
this._masterAlias = this._options.masterAlias || this._stage;
21+
this._alias = this._options.alias || this._masterAlias;
2122
this._stackName = this._provider.naming.getStackName();
2223

2324
// Make alias available as ${self:provider.alias}

test/aliasRestructureStack.test.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,45 @@ describe('aliasRestructureStack', () => {
5656
sandbox.restore();
5757
});
5858

59+
describe('#addMasterAliasName', () => {
60+
it('should add the master alias name as output from command line option', () => {
61+
serverless.service.provider.compiledCloudFormationTemplate = _.cloneDeep({
62+
Resources: {},
63+
Outputs: {}
64+
});
65+
awsAlias._masterAlias = 'master'
66+
return expect(awsAlias.addMasterAliasName()).to.be.fulfilled
67+
.then(() =>
68+
expect(serverless.service.provider.compiledCloudFormationTemplate.Outputs.MasterAliasName.Value)
69+
.to.equal('master')
70+
);
71+
});
72+
73+
it('should add the master alias name as output from existing stack', () => {
74+
const masterAliasStackOutput = {
75+
MasterAliasName: {
76+
Description: 'Master Alias name (serverless-aws-alias plugin)',
77+
Value: 'master',
78+
Export: {
79+
Name: 'sls-test-project-dev-master'
80+
}
81+
}
82+
};
83+
const currentTemplate = {
84+
Outputs: masterAliasStackOutput
85+
};
86+
serverless.service.provider.compiledCloudFormationTemplate = _.cloneDeep({
87+
Resources: {},
88+
Outputs: {}
89+
});
90+
return expect(awsAlias.addMasterAliasName(currentTemplate)).to.be.fulfilled
91+
.then(() =>
92+
expect(serverless.service.provider.compiledCloudFormationTemplate.Outputs.MasterAliasName.Value)
93+
.to.equal('master')
94+
);
95+
});
96+
});
97+
5998
describe('#aliasFinalize()', () => {
6099
it('should stringify flags', () => {
61100
serverless.service.provider.compiledCloudFormationAliasTemplate = {
@@ -85,6 +124,7 @@ describe('aliasRestructureStack', () => {
85124
});
86125

87126
it('should propagate templates through all stack operations', () => {
127+
const addMasterAliasNameSpy = sandbox.spy(awsAlias, 'addMasterAliasName');
88128
const aliasInitSpy = sandbox.spy(awsAlias, 'aliasInit');
89129
const aliasHandleUserResourcesSpy = sandbox.spy(awsAlias, 'aliasHandleUserResources');
90130
const aliasHandleLambdaRoleSpy = sandbox.spy(awsAlias, 'aliasHandleLambdaRole');
@@ -102,6 +142,7 @@ describe('aliasRestructureStack', () => {
102142
return expect(awsAlias.aliasRestructureStack(currentTemplate, [ aliasTemplate ], currentAliasStackTemplate))
103143
.to.be.fulfilled
104144
.then(() => BbPromise.all([
145+
expect(addMasterAliasNameSpy).to.have.been.calledWithExactly(currentTemplate, [ aliasTemplate ], currentAliasStackTemplate),
105146
expect(aliasInitSpy).to.have.been.calledWithExactly(currentTemplate, [ aliasTemplate ], currentAliasStackTemplate),
106147
expect(aliasHandleUserResourcesSpy).to.have.been.calledWithExactly(currentTemplate, [ aliasTemplate ], currentAliasStackTemplate),
107148
expect(aliasHandleLambdaRoleSpy).to.have.been.calledWithExactly(currentTemplate, [ aliasTemplate ], currentAliasStackTemplate),

test/data/sls-stack-2.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,13 @@
322322
]
323323
]
324324
}
325+
},
326+
"MasterAliasName": {
327+
"Description": "Master Alias name (serverless-aws-alias plugin)",
328+
"Value": "master",
329+
"Export": {
330+
"Name": "sls-test-project-dev-master"
331+
}
325332
}
326333
}
327334
}

test/removeAlias.test.js

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,10 @@ describe('removeAlias', () => {
9090

9191
it('should error if an alias is deployed on stage removal', () => {
9292
awsAlias._options = { alias: 'myStage' };
93-
awsAlias._alias = 'myStage';
93+
awsAlias._alias = 'master';
94+
slsStack1.Outputs.MasterAliasName = {
95+
Value: 'master'
96+
};
9497

9598
expect(() => awsAlias.removeAlias(slsStack1, [ aliasStack1 ], aliasStack2)).to.throw(/myAlias/);
9699
return BbPromise.all([
@@ -103,7 +106,10 @@ describe('removeAlias', () => {
103106

104107
it('should error if the master alias is not deployed on stage removal', () => {
105108
awsAlias._options = { alias: 'myStage' };
106-
awsAlias._alias = 'myStage';
109+
awsAlias._alias = 'master';
110+
slsStack1.Outputs.MasterAliasName = {
111+
Value: 'master'
112+
};
107113

108114
expect(() => awsAlias.removeAlias(slsStack1, [], {})).to.throw(/Internal error/);
109115
return BbPromise.all([
@@ -116,7 +122,10 @@ describe('removeAlias', () => {
116122

117123
it('should remove alias and service stack on stage removal', () => {
118124
awsAlias._options = { alias: 'myStage' };
119-
awsAlias._alias = 'myStage';
125+
awsAlias._alias = 'master';
126+
slsStack1.Outputs.MasterAliasName = {
127+
Value: 'master'
128+
};
120129

121130
return expect(awsAlias.removeAlias(slsStack1, [], aliasStack2)).to.be.fulfilled
122131
.then(() => BbPromise.all([
@@ -128,6 +137,9 @@ describe('removeAlias', () => {
128137
});
129138

130139
it('should remove alias stack', () => {
140+
slsStack1.Outputs.MasterAliasName = {
141+
Value: 'master'
142+
};
131143
aliasApplyStackChangesStub.returns([ slsStack1, [ aliasStack2 ], aliasStack1 ]);
132144
aliasCreateStackChangesStub.returns([ slsStack1, [ aliasStack2 ], aliasStack1 ]);
133145
aliasRemoveAliasStackStub.returns([ slsStack1, [ aliasStack2 ], aliasStack1 ]);

test/updateAliasStack.test.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,6 @@ describe('updateAliasStack', () => {
262262
it('should resolve in case no updates are performed', () => {
263263
providerRequestStub.returns(BbPromise.resolve("done"));
264264
monitorStackStub.rejects(new Error('No updates are to be performed.'));
265-
266265
return expect(awsAlias.updateAlias()).to.be.fulfilled
267266
.then(() => expect(providerRequestStub).to.have.been.calledOnce);
268267
});

0 commit comments

Comments
 (0)