mirror of
https://github.com/serverless/serverless.git
synced 2026-01-18 14:58:43 +00:00
Merge pull request #5851 from exoego/tagging-apigw
Add tags to AWS APIGateway Stage
This commit is contained in:
commit
381aa728cf
@ -280,7 +280,7 @@ functions:
|
||||
maxAge: 86400
|
||||
```
|
||||
|
||||
If you are using CloudFront or another CDN for your API Gateway, you may want to setup a `Cache-Control` header to allow for OPTIONS request to be cached to avoid the additional hop.
|
||||
If you are using CloudFront or another CDN for your API Gateway, you may want to setup a `Cache-Control` header to allow for OPTIONS request to be cached to avoid the additional hop.
|
||||
|
||||
To enable the `Cache-Control` header on preflight response, set the `cacheControl` property in the `cors` object:
|
||||
|
||||
@ -1282,7 +1282,7 @@ functions:
|
||||
events:
|
||||
- http:
|
||||
path: /users
|
||||
...
|
||||
...
|
||||
authorizer:
|
||||
# Provide both type and authorizerId
|
||||
type: COGNITO_USER_POOLS # TOKEN or REQUEST or COGNITO_USER_POOLS, same as AWS Cloudformation documentation
|
||||
@ -1294,7 +1294,7 @@ functions:
|
||||
events:
|
||||
- http:
|
||||
path: /users/{userId}
|
||||
...
|
||||
...
|
||||
# Provide both type and authorizerId
|
||||
type: COGNITO_USER_POOLS # TOKEN or REQUEST or COGNITO_USER_POOLS, same as AWS Cloudformation documentation
|
||||
authorizerId:
|
||||
@ -1349,11 +1349,13 @@ provider:
|
||||
minimumCompressionSize: 1024
|
||||
```
|
||||
|
||||
## AWS X-Ray Tracing
|
||||
## Stage specific setups
|
||||
|
||||
**IMPORTANT:** Due to CloudFormation limitations it's not possible to enable AWS X-Ray Tracing on existing deployments. Please remove your old API Gateway and re-deploy it with enabled tracing if you want to use AWS X-Ray Tracing for API Gateway. Once tracing is enabled you can re-deploy your service anytime without issues.
|
||||
**IMPORTANT:** Due to CloudFormation limitations it's not possible to enable API Gateway stage settings on existing deployments. Please remove your old API Gateway and re-deploy with your new stage configuration. Once done, subsequent deployments should work without any issues.
|
||||
|
||||
Disabling tracing might result in unexpected behavior. We recommend to remove and re-deploy your service if you want to disable tracing.
|
||||
Disabling settings might result in unexpected behavior. We recommend to remove and re-deploy your service without such stage settings.
|
||||
|
||||
### AWS X-Ray Tracing
|
||||
|
||||
API Gateway supports a form of out of the box distributed tracing via [AWS X-Ray](https://aws.amazon.com/xray/) though enabling [active tracing](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-xray.html). To enable this feature for your serverless
|
||||
application's API Gateway add the following to your `serverless.yml`
|
||||
@ -1366,3 +1368,18 @@ provider:
|
||||
tracing:
|
||||
apiGateway: true
|
||||
```
|
||||
|
||||
### Tags / Stack Tags
|
||||
|
||||
API Gateway stages will be tagged with the `tags` and `stackTags` values defined at the `provider` level:
|
||||
|
||||
```yml
|
||||
# serverless.yml
|
||||
|
||||
provider:
|
||||
name: aws
|
||||
stackTags:
|
||||
stackTagKey: stackTagValue
|
||||
tags:
|
||||
tagKey: tagValue
|
||||
```
|
||||
|
||||
@ -2,10 +2,6 @@
|
||||
|
||||
const BbPromise = require('bluebird');
|
||||
|
||||
// NOTE: the checks here are X-Ray specific. However the error messages can be updated
|
||||
// to reflect the general problem which occurrs when upgrading / downgrading the
|
||||
// Stage resource / Deplyment resource
|
||||
|
||||
module.exports = {
|
||||
checkForBreakingChanges() {
|
||||
const StackName = this.provider.naming.getStackName();
|
||||
@ -27,7 +23,7 @@ module.exports = {
|
||||
// the old state still uses the stage defined on the AWS::ApiGateway::Deployment resource
|
||||
if (oldResources[oldDeploymentLogicalId] && oldResources[oldDeploymentLogicalId].Properties.StageName && newResources[stageLogicalId]) { // eslint-disable-line max-len
|
||||
const msg = [
|
||||
'NOTE: Enabling API Gateway X-Ray Tracing for existing ',
|
||||
'NOTE: Enabling API Gateway stage settings for existing ',
|
||||
'deployments requires a remove and re-deploy of your API Gateway. ',
|
||||
'\n\n ',
|
||||
'Please refer to our documentation for more information.',
|
||||
@ -40,7 +36,7 @@ module.exports = {
|
||||
if (oldResources[stageLogicalId] && newResources[newDeploymentLogicalId] && newResources[newDeploymentLogicalId].Properties.StageName) { // eslint-disable-line
|
||||
if (!this.options.force) {
|
||||
const msg = [
|
||||
'NOTE: Disabling API Gateway X-Ray Tracing for existing ',
|
||||
'NOTE: Disabling API Gateway stage settings for existing ',
|
||||
'deployments might result in unexpected behavior.',
|
||||
'\n ',
|
||||
'We recommend to remove and re-deploy your API Gateway. ',
|
||||
|
||||
@ -5,17 +5,35 @@ const BbPromise = require('bluebird');
|
||||
|
||||
module.exports = {
|
||||
compileStage() {
|
||||
// NOTE: right now we're only using a dedicated Stage resource if AWS X-Ray
|
||||
// tracing is enabled. We'll change this in the future so that users can
|
||||
const provider = this.serverless.service.provider;
|
||||
|
||||
// TracingEnabled
|
||||
const tracing = provider.tracing;
|
||||
const TracingEnabled = !_.isEmpty(tracing) && tracing.apiGateway;
|
||||
|
||||
// Tags
|
||||
const tagsMerged = [provider.stackTags, provider.tags].reduce((lastTags, newTags) => {
|
||||
if (_.isPlainObject(newTags)) {
|
||||
return _.extend(lastTags, newTags);
|
||||
}
|
||||
return lastTags;
|
||||
}, {});
|
||||
const Tags = _.entriesIn(tagsMerged).map(pair => ({
|
||||
Key: pair[0],
|
||||
Value: pair[1],
|
||||
}));
|
||||
|
||||
// NOTE: the DeploymentId is random, therefore we rely on prior usage here
|
||||
const deploymentId = this.apiGatewayDeploymentLogicalId;
|
||||
this.apiGatewayStageLogicalId = this.provider.naming
|
||||
.getStageLogicalId();
|
||||
|
||||
// NOTE: right now we're only using a dedicated Stage resource
|
||||
// - if AWS X-Ray tracing is enabled
|
||||
// - if Tags are provided
|
||||
// We'll change this in the future so that users can
|
||||
// opt-in for other features as well
|
||||
const tracing = this.serverless.service.provider.tracing;
|
||||
|
||||
if (!_.isEmpty(tracing) && tracing.apiGateway) {
|
||||
// NOTE: the DeploymentId is random, therefore we rely on prior usage here
|
||||
const deploymentId = this.apiGatewayDeploymentLogicalId;
|
||||
this.apiGatewayStageLogicalId = this.provider.naming
|
||||
.getStageLogicalId();
|
||||
|
||||
if (TracingEnabled || Tags.length > 0) {
|
||||
_.merge(this.serverless.service.provider.compiledCloudFormationTemplate.Resources, {
|
||||
[this.apiGatewayStageLogicalId]: {
|
||||
Type: 'AWS::ApiGateway::Stage',
|
||||
@ -25,7 +43,8 @@ module.exports = {
|
||||
},
|
||||
RestApiId: this.provider.getApiGatewayRestApiId(),
|
||||
StageName: this.provider.getStage(),
|
||||
TracingEnabled: true,
|
||||
TracingEnabled,
|
||||
Tags,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@ -31,10 +31,6 @@ describe('#compileStage()', () => {
|
||||
stage = awsCompileApigEvents.provider.getStage();
|
||||
stageLogicalId = awsCompileApigEvents.provider.naming
|
||||
.getStageLogicalId();
|
||||
// setting up AWS X-Ray tracing
|
||||
awsCompileApigEvents.serverless.service.provider.tracing = {
|
||||
apiGateway: true,
|
||||
};
|
||||
// mocking the result of a Deployment resource since we remove the stage name
|
||||
// when using the Stage resource
|
||||
awsCompileApigEvents.serverless.service.provider.compiledCloudFormationTemplate
|
||||
@ -45,45 +41,154 @@ describe('#compileStage()', () => {
|
||||
};
|
||||
});
|
||||
|
||||
it('should create a dedicated stage resource if tracing is configured', () => awsCompileApigEvents
|
||||
.compileStage().then(() => {
|
||||
const resources = awsCompileApigEvents.serverless.service.provider
|
||||
.compiledCloudFormationTemplate.Resources;
|
||||
describe('tracing', () => {
|
||||
beforeEach(() => {
|
||||
// setting up AWS X-Ray tracing
|
||||
awsCompileApigEvents.serverless.service.provider.tracing = {
|
||||
apiGateway: true,
|
||||
};
|
||||
});
|
||||
|
||||
expect(resources[stageLogicalId]).to.deep.equal({
|
||||
Type: 'AWS::ApiGateway::Stage',
|
||||
Properties: {
|
||||
RestApiId: {
|
||||
Ref: awsCompileApigEvents.apiGatewayRestApiLogicalId,
|
||||
it('should create a dedicated stage resource if tracing is configured', () =>
|
||||
awsCompileApigEvents.compileStage().then(() => {
|
||||
const resources = awsCompileApigEvents.serverless.service.provider
|
||||
.compiledCloudFormationTemplate.Resources;
|
||||
|
||||
expect(resources[stageLogicalId]).to.deep.equal({
|
||||
Type: 'AWS::ApiGateway::Stage',
|
||||
Properties: {
|
||||
RestApiId: {
|
||||
Ref: awsCompileApigEvents.apiGatewayRestApiLogicalId,
|
||||
},
|
||||
DeploymentId: {
|
||||
Ref: awsCompileApigEvents.apiGatewayDeploymentLogicalId,
|
||||
},
|
||||
StageName: 'dev',
|
||||
Tags: [],
|
||||
TracingEnabled: true,
|
||||
},
|
||||
DeploymentId: {
|
||||
Ref: awsCompileApigEvents.apiGatewayDeploymentLogicalId,
|
||||
});
|
||||
|
||||
expect(resources[awsCompileApigEvents.apiGatewayDeploymentLogicalId]).to.deep.equal({
|
||||
Properties: {},
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
it('should NOT create a dedicated stage resource if tracing is not enabled', () => {
|
||||
awsCompileApigEvents.serverless.service.provider.tracing = {};
|
||||
|
||||
return awsCompileApigEvents.compileStage().then(() => {
|
||||
const resources = awsCompileApigEvents.serverless.service.provider
|
||||
.compiledCloudFormationTemplate.Resources;
|
||||
|
||||
// eslint-disable-next-line
|
||||
expect(resources[stageLogicalId]).not.to.exist;
|
||||
|
||||
expect(resources[awsCompileApigEvents.apiGatewayDeploymentLogicalId]).to.deep.equal({
|
||||
Properties: {
|
||||
StageName: stage,
|
||||
},
|
||||
StageName: 'dev',
|
||||
TracingEnabled: true,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
expect(resources[awsCompileApigEvents.apiGatewayDeploymentLogicalId]).to.deep.equal({
|
||||
Properties: {},
|
||||
describe('tags', () => {
|
||||
it('should create a dedicated stage resource if provider.stackTags is configured', () => {
|
||||
awsCompileApigEvents.serverless.service.provider.stackTags = {
|
||||
foo: '1',
|
||||
};
|
||||
|
||||
awsCompileApigEvents.compileStage().then(() => {
|
||||
const resources = awsCompileApigEvents.serverless.service.provider
|
||||
.compiledCloudFormationTemplate.Resources;
|
||||
expect(resources[awsCompileApigEvents.apiGatewayDeploymentLogicalId]).to.deep.equal({
|
||||
Properties: {},
|
||||
});
|
||||
|
||||
expect(resources[stageLogicalId]).to.deep.equal({
|
||||
Type: 'AWS::ApiGateway::Stage',
|
||||
Properties: {
|
||||
RestApiId: {
|
||||
Ref: awsCompileApigEvents.apiGatewayRestApiLogicalId,
|
||||
},
|
||||
DeploymentId: {
|
||||
Ref: awsCompileApigEvents.apiGatewayDeploymentLogicalId,
|
||||
},
|
||||
StageName: stage,
|
||||
TracingEnabled: false,
|
||||
Tags: [
|
||||
{ Key: 'foo', Value: '1' },
|
||||
],
|
||||
},
|
||||
});
|
||||
});
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('should NOT create a dedicated stage resource if tracing is not enabled', () => {
|
||||
awsCompileApigEvents.serverless.service.provider.tracing = {};
|
||||
it('should create a dedicated stage resource if provider.tags is configured', () => {
|
||||
awsCompileApigEvents.serverless.service.provider.tags = {
|
||||
foo: '1',
|
||||
};
|
||||
|
||||
return awsCompileApigEvents.compileStage().then(() => {
|
||||
const resources = awsCompileApigEvents.serverless.service.provider
|
||||
.compiledCloudFormationTemplate.Resources;
|
||||
awsCompileApigEvents.compileStage().then(() => {
|
||||
const resources = awsCompileApigEvents.serverless.service.provider
|
||||
.compiledCloudFormationTemplate.Resources;
|
||||
expect(resources[awsCompileApigEvents.apiGatewayDeploymentLogicalId]).to.deep.equal({
|
||||
Properties: {},
|
||||
});
|
||||
|
||||
// eslint-disable-next-line
|
||||
expect(resources[stageLogicalId]).not.to.exist;
|
||||
expect(resources[stageLogicalId]).to.deep.equal({
|
||||
Type: 'AWS::ApiGateway::Stage',
|
||||
Properties: {
|
||||
RestApiId: {
|
||||
Ref: awsCompileApigEvents.apiGatewayRestApiLogicalId,
|
||||
},
|
||||
DeploymentId: {
|
||||
Ref: awsCompileApigEvents.apiGatewayDeploymentLogicalId,
|
||||
},
|
||||
StageName: stage,
|
||||
TracingEnabled: false,
|
||||
Tags: [
|
||||
{ Key: 'foo', Value: '1' },
|
||||
],
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
expect(resources[awsCompileApigEvents.apiGatewayDeploymentLogicalId]).to.deep.equal({
|
||||
Properties: {
|
||||
StageName: stage,
|
||||
},
|
||||
it('should override provider.stackTags by provider.tags', () => {
|
||||
awsCompileApigEvents.serverless.service.provider.stackTags = {
|
||||
foo: 'from-stackTags',
|
||||
bar: 'from-stackTags',
|
||||
};
|
||||
awsCompileApigEvents.serverless.service.provider.tags = {
|
||||
foo: 'from-tags',
|
||||
buz: 'from-tags',
|
||||
};
|
||||
|
||||
awsCompileApigEvents.compileStage().then(() => {
|
||||
const resources = awsCompileApigEvents.serverless.service.provider
|
||||
.compiledCloudFormationTemplate.Resources;
|
||||
|
||||
expect(resources[stageLogicalId]).to.deep.equal({
|
||||
Type: 'AWS::ApiGateway::Stage',
|
||||
Properties: {
|
||||
RestApiId: {
|
||||
Ref: awsCompileApigEvents.apiGatewayRestApiLogicalId,
|
||||
},
|
||||
DeploymentId: {
|
||||
Ref: awsCompileApigEvents.apiGatewayDeploymentLogicalId,
|
||||
},
|
||||
StageName: stage,
|
||||
TracingEnabled: false,
|
||||
Tags: [
|
||||
{ Key: 'foo', Value: 'from-tags' },
|
||||
{ Key: 'bar', Value: 'from-stackTags' },
|
||||
{ Key: 'buz', Value: 'from-tags' },
|
||||
],
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user