serverless-plugin-canary-deployments
Version:
A Serverless plugin to implement canary deployment of Lambda functions
575 lines • 16.7 kB
JSON
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "The AWS CloudFormation template for this Serverless application",
"Resources": {
"ServerlessDeploymentBucket": {
"Type": "AWS::S3::Bucket"
},
"HelloLogGroup": {
"Type": "AWS::Logs::LogGroup",
"Properties": {
"LogGroupName": "/aws/lambda/canary-deployments-test-appsync-datasources-dev-Hello"
}
},
"PreHookLogGroup": {
"Type": "AWS::Logs::LogGroup",
"Properties": {
"LogGroupName": "/aws/lambda/canary-deployments-test-appsync-datasources-devpreHook"
}
},
"PostHookLogGroup": {
"Type": "AWS::Logs::LogGroup",
"Properties": {
"LogGroupName": "/aws/lambda/canary-deployments-test-appsync-datasources-devpostHook"
}
},
"HelloLambdaAppSynDataSource": {
"Type": "AWS::AppSync::DataSource",
"Properties": {
"ApiId": {
"Ref": "TestApi"
},
"Name": "test-lambda-datasource",
"Description": "Hello Lambda DataSource",
"Type": "AWS_LAMBDA",
"ServiceRoleArn": {
"Fn::GetAtt": [
"IamRoleLambdaExecution",
"Arn"
]
},
"LambdaConfig": {
"LambdaFunctionArn": {
"Ref": "HelloLambdaFunctionAliasLive"
}
}
}
},
"IamRoleLambdaExecution": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"lambda.amazonaws.com"
]
},
"Action": [
"sts:AssumeRole"
]
}
]
},
"Policies": [
{
"PolicyName": {
"Fn::Join": [
"-",
[
"dev",
"canary-deployments-test-appsync-datasource",
"lambda"
]
]
},
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogStream"
],
"Resource": [
{
"Fn::Sub": "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/canary-deployments-test-appsync-datasources-dev-Hello:*"
},
{
"Fn::Sub": "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/canary-deployments-test-appsync-datasources-devpreHook:*"
},
{
"Fn::Sub": "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/canary-deployments-test-appsync-datasources-devpostHook:*"
}
]
},
{
"Effect": "Allow",
"Action": [
"logs:PutLogEvents"
],
"Resource": [
{
"Fn::Sub": "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/canary-deployments-test-appsync-datasources-dev-Hello:*:*"
},
{
"Fn::Sub": "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/canary-deployments-test-appsync-datasources-devpreHook:*:*"
},
{
"Fn::Sub": "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/canary-deployments-test-appsync-datasources-devpostHook:*:*"
}
]
},
{
"Effect": "Allow",
"Action": [
"codedeploy:*"
],
"Resource": [
"*"
]
},
{
"Action": [
"codedeploy:PutLifecycleEventHookExecutionStatus"
],
"Effect": "Allow",
"Resource": [
{
"Fn::Sub": "arn:${AWS::Partition}:codedeploy:${AWS::Region}:${AWS::AccountId}:deploymentgroup:${CanarydeploymentstestappsyncdatasourcesdevDeploymentApplication}/canary-deployments-test-appsync-datasources-dev-HelloLambdaFunctionDeploymentGroup"
}
]
}
]
}
}
],
"Path": "/",
"RoleName": {
"Fn::Join": [
"-",
[
"canary-deployments-test-appsync-datasource",
"dev",
"us-east-1",
"lambdaRole"
]
]
}
}
},
"HelloLambdaFunction": {
"Type": "AWS::Lambda::Function",
"Properties": {
"Code": {
"S3Bucket": {
"Ref": "ServerlessDeploymentBucket"
},
"S3Key": "serverless/canary-deployments-test-appsync-datasource/dev/1520191533287-2018-03-04T19:25:33.287Z/canary-deployments-test-appsync-datasource.zip"
},
"FunctionName": "canary-deployments-test-appsync-datasources-dev-Hello",
"Handler": "handler.hello",
"MemorySize": 1024,
"Role": {
"Fn::GetAtt": [
"IamRoleLambdaExecution",
"Arn"
]
},
"Runtime": "nodejs6.10",
"Timeout": 6
},
"DependsOn": [
"HelloLogGroup",
"IamRoleLambdaExecution"
]
},
"HelloLambdaVersionFYAirphUvjV7H12yGxU1eQrqAiSBMjAi9hdLPgV62L8": {
"Type": "AWS::Lambda::Version",
"DeletionPolicy": "Retain",
"Properties": {
"FunctionName": {
"Ref": "HelloLambdaFunction"
},
"CodeSha256": "sZvdDgxnAbKe1yaQga0XJPD82+o5jFWz+J3lR+q9UHU="
}
},
"PreHookLambdaFunction": {
"Type": "AWS::Lambda::Function",
"Properties": {
"Code": {
"S3Bucket": {
"Ref": "ServerlessDeploymentBucket"
},
"S3Key": "serverless/canary-deployments-test-appsync-datasource/dev/1520191533287-2018-03-04T19:25:33.287Z/canary-deployments-test-appsync-datasource.zip"
},
"FunctionName": "canary-deployments-test-appsync-datasources-devpreHook",
"Handler": "hooks.pre",
"MemorySize": 1024,
"Role": {
"Fn::GetAtt": [
"IamRoleLambdaExecution",
"Arn"
]
},
"Runtime": "nodejs6.10",
"Timeout": 6
},
"DependsOn": [
"PreHookLogGroup",
"IamRoleLambdaExecution"
]
},
"PreHookLambdaVersionIYyrXlfQM5jjU68REvnAzRxhgq9eoLqSsDjy0": {
"Type": "AWS::Lambda::Version",
"DeletionPolicy": "Retain",
"Properties": {
"FunctionName": {
"Ref": "PreHookLambdaFunction"
},
"CodeSha256": "sZvdDgxnAbKe1yaQga0XJPD82+o5jFWz+J3lR+q9UHU="
}
},
"PostHookLambdaFunction": {
"Type": "AWS::Lambda::Function",
"Properties": {
"Code": {
"S3Bucket": {
"Ref": "ServerlessDeploymentBucket"
},
"S3Key": "serverless/canary-deployments-test-appsync-datasource/dev/1520191533287-2018-03-04T19:25:33.287Z/canary-deployments-test-appsync-datasource.zip"
},
"FunctionName": "canary-deployments-test-appsync-datasources-devpostHook",
"Handler": "hooks.post",
"MemorySize": 1024,
"Role": {
"Fn::GetAtt": [
"IamRoleLambdaExecution",
"Arn"
]
},
"Runtime": "nodejs6.10",
"Timeout": 6
},
"DependsOn": [
"PostHookLogGroup",
"IamRoleLambdaExecution"
]
},
"PostHookLambdaVersiondh0VUUAh9BrmvORqx3vDEIcHxolKWKCO1YL45mVTbg": {
"Type": "AWS::Lambda::Version",
"DeletionPolicy": "Retain",
"Properties": {
"FunctionName": {
"Ref": "PostHookLambdaFunction"
},
"CodeSha256": "sZvdDgxnAbKe1yaQga0XJPD82+o5jFWz+J3lR+q9UHU="
}
},
"ApiGatewayRestApi": {
"Type": "AWS::ApiGateway::RestApi",
"Properties": {
"Name": "dev-canary-deployments-test-appsync-datasource",
"EndpointConfiguration": {
"Types": [
"EDGE"
]
}
}
},
"ApiGatewayResourceHello": {
"Type": "AWS::ApiGateway::Resource",
"Properties": {
"ParentId": {
"Fn::GetAtt": [
"ApiGatewayRestApi",
"RootResourceId"
]
},
"PathPart": "hello",
"RestApiId": {
"Ref": "ApiGatewayRestApi"
}
}
},
"ApiGatewayMethodHelloGet": {
"Type": "AWS::ApiGateway::Method",
"Properties": {
"HttpMethod": "GET",
"RequestParameters": {},
"ResourceId": {
"Ref": "ApiGatewayResourceHello"
},
"RestApiId": {
"Ref": "ApiGatewayRestApi"
},
"ApiKeyRequired": false,
"AuthorizationType": "NONE",
"Integration": {
"IntegrationHttpMethod": "POST",
"Type": "AWS_PROXY",
"Uri": {
"Fn::Join": [
"",
[
"arn:aws:apigateway:",
{
"Ref": "AWS::Region"
},
":lambda:path/2015-03-31/functions/",
{
"Ref": "HelloLambdaFunctionAliasLive"
},
"/invocations"
]
]
}
},
"MethodResponses": []
}
},
"ApiGatewayDeployment12345": {
"Type": "AWS::ApiGateway::Deployment",
"Properties": {
"RestApiId": {
"Ref": "ApiGatewayRestApi"
},
"StageName": "dev"
},
"DependsOn": [
"ApiGatewayMethodHelloGet"
]
},
"HelloLambdaPermissionApiGateway": {
"Type": "AWS::Lambda::Permission",
"Properties": {
"FunctionName": {
"Ref": "HelloLambdaFunctionAliasLive"
},
"Action": "lambda:InvokeFunction",
"Principal": "apigateway.amazonaws.com",
"SourceArn": {
"Fn::Join": [
"",
[
"arn:aws:execute-api:",
{
"Ref": "AWS::Region"
},
":",
{
"Ref": "AWS::AccountId"
},
":",
{
"Ref": "ApiGatewayRestApi"
},
"/*/*"
]
]
}
}
},
"S3BucketS3SampleBucket": {
"Type": "AWS::S3::Bucket",
"Properties": {
"BucketName": "s3SampleBucket",
"NotificationConfiguration": {
"LambdaConfigurations": [
{
"Event": "s3:ObjectCreated:*",
"Function": {
"Ref": "HelloLambdaFunctionAliasLive"
}
}
]
}
},
"DependsOn": [
"HelloLambdaPermissionS3SampleBucketS3"
]
},
"HelloLambdaPermissionS3SampleBucketS3": {
"Type": "AWS::Lambda::Permission",
"Properties": {
"FunctionName": {
"Ref": "HelloLambdaFunctionAliasLive"
},
"Action": "lambda:InvokeFunction",
"Principal": "s3.amazonaws.com",
"SourceArn": {
"Fn::Join": [
"",
[
"arn:aws:s3:::s3SampleBucket"
]
]
}
}
},
"HelloFooAlarm": {
"Type": "AWS::CloudWatch::Alarm",
"Properties": {
"Namespace": "AWS/Lambda",
"MetricName": "Errors",
"Threshold": 1,
"Period": 60,
"EvaluationPeriods": 1,
"ComparisonOperator": "GreaterThanOrEqualToThreshold",
"OKActions": [],
"AlarmActions": [],
"InsufficientDataActions": [],
"Dimensions": [
{
"Name": "FunctionName",
"Value": {
"Ref": "HelloLambdaFunction"
}
}
],
"TreatMissingData": "missing",
"Statistic": "Minimum"
}
},
"CanarydeploymentstestappsyncdatasourcesdevDeploymentApplication": {
"Type": "AWS::CodeDeploy::Application",
"Properties": {
"ComputePlatform": "Lambda"
}
},
"CodeDeployServiceRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"ManagedPolicyArns": [
"arn:aws:iam::aws:policy/service-role/AWSCodeDeployRoleForLambdaLimited",
"arn:aws:iam::aws:policy/AWSLambda_FullAccess"
],
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"sts:AssumeRole"
],
"Effect": "Allow",
"Principal": {
"Service": [
"codedeploy.amazonaws.com"
]
}
}
]
}
}
},
"HelloLambdaFunctionDeploymentGroup": {
"Type": "AWS::CodeDeploy::DeploymentGroup",
"Properties": {
"ApplicationName": {
"Ref": "CanarydeploymentstestappsyncdatasourcesdevDeploymentApplication"
},
"AutoRollbackConfiguration": {
"Enabled": true,
"Events": [
"DEPLOYMENT_FAILURE",
"DEPLOYMENT_STOP_ON_ALARM",
"DEPLOYMENT_STOP_ON_REQUEST"
]
},
"ServiceRoleArn": {
"Fn::GetAtt": [
"CodeDeployServiceRole",
"Arn"
]
},
"DeploymentConfigName": {
"Fn::Sub": [
"CodeDeployDefault.Lambda${ConfigName}",
{
"ConfigName": "Linear10PercentEvery1Minute"
}
]
},
"DeploymentGroupName": "canary-deployments-test-appsync-datasources-dev-HelloLambdaFunctionDeploymentGroup",
"DeploymentStyle": {
"DeploymentType": "BLUE_GREEN",
"DeploymentOption": "WITH_TRAFFIC_CONTROL"
},
"AlarmConfiguration": {
"Alarms": [
{
"Name": {
"Ref": "HelloFooAlarm"
}
}
],
"Enabled": true
}
}
},
"HelloLambdaFunctionAliasLive": {
"Type": "AWS::Lambda::Alias",
"Properties": {
"FunctionVersion": {
"Fn::GetAtt": [
"HelloLambdaVersionFYAirphUvjV7H12yGxU1eQrqAiSBMjAi9hdLPgV62L8",
"Version"
]
},
"FunctionName": {
"Ref": "HelloLambdaFunction"
},
"Name": "Live"
},
"UpdatePolicy": {
"CodeDeployLambdaAliasUpdate": {
"ApplicationName": {
"Ref": "CanarydeploymentstestappsyncdatasourcesdevDeploymentApplication"
},
"AfterAllowTrafficHook": {
"Ref": "PostHookLambdaFunction"
},
"BeforeAllowTrafficHook": {
"Ref": "PreHookLambdaFunction"
},
"DeploymentGroupName": {
"Ref": "HelloLambdaFunctionDeploymentGroup"
}
}
}
}
},
"Outputs": {
"ServerlessDeploymentBucketName": {
"Value": {
"Ref": "ServerlessDeploymentBucket"
}
},
"HelloLambdaFunctionQualifiedArn": {
"Description": "Current Lambda function version",
"Value": {
"Ref": "HelloLambdaVersionFYAirphUvjV7H12yGxU1eQrqAiSBMjAi9hdLPgV62L8"
}
},
"PreHookLambdaFunctionQualifiedArn": {
"Description": "Current Lambda function version",
"Value": {
"Ref": "PreHookLambdaVersionIYyrXlfQM5jjU68REvnAzRxhgq9eoLqSsDjy0"
}
},
"PostHookLambdaFunctionQualifiedArn": {
"Description": "Current Lambda function version",
"Value": {
"Ref": "PostHookLambdaVersiondh0VUUAh9BrmvORqx3vDEIcHxolKWKCO1YL45mVTbg"
}
},
"ServiceEndpoint": {
"Description": "URL of the service endpoint",
"Value": {
"Fn::Join": [
"",
[
"https://",
{
"Ref": "ApiGatewayRestApi"
},
".execute-api.us-east-1.amazonaws.com/dev"
]
]
}
}
}
}