├── .metadata ├── CODEOWNERS ├── .gitmodules ├── functions ├── packages │ ├── CreateEnvironment │ │ └── creategreenenv.zip │ ├── SwapEnvironments │ │ └── swapenvironments.zip │ ├── TerminateandReSwap │ │ └── terminategreenenv.zip │ └── TestBlueEnvironment │ │ └── testBlueenvironment.zip └── source │ ├── SwapEnvironments │ ├── buildspec.yml │ └── swapenvironments.sh │ ├── TestBlueEnvironment │ ├── buildspec.yml │ └── testwebsitecodebuild.sh │ ├── TerminateandReSwap │ └── index.py │ └── CreateEnvironment │ └── index.py ├── README.md ├── NOTICE.txt ├── ci ├── withoutGittoS3withBeanstalkSample.json ├── config.yml ├── taskcat.yml ├── withGittoS3withBeanstalkSample.json ├── withoutGittoS3withnoBeanstalkSample.json └── withGittoS3withnoBeanstalkSample.json ├── .taskcat.yml ├── LICENSE.txt └── templates ├── elasticbeanstalk-sample.template ├── copyfunction-to-s3bucket.template ├── codepipeline-stack.template └── bluegreen-deployment-master.template /.metadata: -------------------------------------------------------------------------------- 1 | language_type: cloudformation -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @aws-quickstart/aws_quickstart_team 2 | 3 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "submodules/quickstart-git2s3"] 2 | path = submodules/quickstart-git2s3 3 | url = ../../aws-quickstart/quickstart-git2s3.git 4 | branch = main 5 | -------------------------------------------------------------------------------- /functions/packages/CreateEnvironment/creategreenenv.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-quickstart/quickstart-codepipeline-bluegreen-deployment/HEAD/functions/packages/CreateEnvironment/creategreenenv.zip -------------------------------------------------------------------------------- /functions/packages/SwapEnvironments/swapenvironments.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-quickstart/quickstart-codepipeline-bluegreen-deployment/HEAD/functions/packages/SwapEnvironments/swapenvironments.zip -------------------------------------------------------------------------------- /functions/packages/TerminateandReSwap/terminategreenenv.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-quickstart/quickstart-codepipeline-bluegreen-deployment/HEAD/functions/packages/TerminateandReSwap/terminategreenenv.zip -------------------------------------------------------------------------------- /functions/source/SwapEnvironments/buildspec.yml: -------------------------------------------------------------------------------- 1 | version: 0.2 2 | 3 | phases: 4 | install: 5 | commands: 6 | - apt-get update -y 7 | - apt-get install jq -y 8 | - ./swapenvironments.sh 9 | -------------------------------------------------------------------------------- /functions/packages/TestBlueEnvironment/testBlueenvironment.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-quickstart/quickstart-codepipeline-bluegreen-deployment/HEAD/functions/packages/TestBlueEnvironment/testBlueenvironment.zip -------------------------------------------------------------------------------- /functions/source/TestBlueEnvironment/buildspec.yml: -------------------------------------------------------------------------------- 1 | version: 0.2 2 | 3 | phases: 4 | install: 5 | commands: 6 | #- apt-get update -y 7 | #- apt-get install jq -y 8 | - ./testwebsitecodebuild.sh 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # quickstart-codepipeline-bluegreen-deployment 2 | ## Deprecation Notice 3 | 4 | :x: This repository is subject to deprecation in Q4 2024. For more details, [please review this announcement](https://github.com/aws-ia/.announcements/issues/1). 5 | 6 | ## This repository has been deprecated in favor of https://github.com/aws-ia/cfn-ps-codepipeline-bluegreen-deployment. 7 | ***We will archive this repository and keep it publicly available until May 1, 2024.*** 8 | -------------------------------------------------------------------------------- /NOTICE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2016-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance with the License. A copy of the License is located at 4 | 5 | http://aws.amazon.com/apache2.0/ 6 | 7 | or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. 8 | -------------------------------------------------------------------------------- /functions/source/TestBlueEnvironment/testwebsitecodebuild.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -x 2 | 3 | echo $BlueEnvName 4 | cname=$(aws elasticbeanstalk describe-environments --environment-names ${BlueEnvName} --region $AWS_REGION --query Environments[0].CNAME --output text) 5 | echo $cname 6 | if [ $cname ] 7 | then 8 | status=$( curl -LI http://$cname -o /dev/null -w '%{http_code}\n' -s ) 9 | echo $status 10 | echo $BlueEnvName 11 | if [ ${status} = "200" ] || [ ${status} = "301" ] 12 | then exit 0 13 | else 14 | exit 1 15 | fi 16 | else 17 | exit 1 18 | fi 19 | -------------------------------------------------------------------------------- /functions/source/SwapEnvironments/swapenvironments.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | #a=$(aws elasticbeanstalk describe-environments --environment-names Test-env8 --region eu-west-1 | jq -r .Environments[0].Status) 4 | #call S3 to get the CNAME file content 5 | aws s3api get-object --bucket $BlueCNAMEConfigBucket --key $BlueCNAMEConfigFile $BlueCNAMEConfigFile --region us-east-2 6 | file="./$BlueCNAMEConfigFile" 7 | if [ ! -f "$file" ]; 8 | then 9 | echo "Nothing to do" 10 | else 11 | Blueurl=$(cat $BlueCNAMEConfigFile |jq -r .BlueEnvUrl) 12 | echo $Blueurl 13 | GreenCNAME=$(aws elasticbeanstalk describe-environments --environment-names $GreenEnvName --region $AWS_REGION --query Environments[0].CNAME --output text) 14 | echo $GreenCNAME 15 | if [ $Blueurl = $GreenCNAME ]; 16 | then 17 | echo "nothing to Swap" 18 | else 19 | while true 20 | do 21 | greenenvstatus=$(aws elasticbeanstalk describe-environments --environment-names $GreenEnvName --region $AWS_REGION --query Environments[0].Status --output text) 22 | echo $greenenvstatus 23 | sleep 10s 24 | if [ $greenenvstatus = "Ready" ] 25 | then 26 | echo $(aws elasticbeanstalk swap-environment-cnames --source-environment-name $BlueEnvName --destination-environment-name $GreenEnvName --region $AWS_REGION) 27 | echo "Urls are swapped now" 28 | break 29 | fi 30 | done 31 | fi 32 | fi 33 | -------------------------------------------------------------------------------- /ci/withoutGittoS3withBeanstalkSample.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "ParameterKey": "AdministratorEmail", 3 | "ParameterValue": "test@email.com" 4 | }, { 5 | "ParameterKey": "AllowedIps", 6 | "ParameterValue": "131.103.20.160/27,165.254.145.0/26,104.192.143.0/24" 7 | }, { 8 | "ParameterKey": "ApiSecret", 9 | "ParameterValue": "test123" 10 | }, { 11 | "ParameterKey": "BeanstalkSourceStageS3BucketName", 12 | "ParameterValue": "" 13 | }, { 14 | "ParameterKey": "BeanstalkSourceStageS3BucketKey", 15 | "ParameterValue": "php-sample.zip" 16 | },{ 17 | "ParameterKey": "CustomDomainName", 18 | "ParameterValue": "" 19 | },{ 20 | "ParameterKey": "GitToken", 21 | "ParameterValue": "" 22 | },{ 23 | "ParameterKey": "GitToS3integration", 24 | "ParameterValue": "false" 25 | },{ 26 | "ParameterKey": "GreenEnvironmentName", 27 | "ParameterValue": "GreenEnvironment3" 28 | },{ 29 | "ParameterKey": "NameofthePipeline", 30 | "ParameterValue": "BlueGreenCICDPipeline3" 31 | },{ 32 | "ParameterKey": "OauthKey", 33 | "ParameterValue": "" 34 | },{ 35 | "ParameterKey": "OauthSecret", 36 | "ParameterValue": "" 37 | }, 38 | { 39 | "ParameterKey": "QSS3BucketName", 40 | "ParameterValue": "$[taskcat_autobucket]" 41 | }, 42 | { 43 | "ParameterKey": "QSS3BucketRegion", 44 | "ParameterValue": "$[taskcat_current_region]" 45 | }, 46 | { 47 | "ParameterKey": "QSS3KeyPrefix", 48 | "ParameterValue": "quickstart-codepipeline-bluegreen-deployment/" 49 | }] 50 | -------------------------------------------------------------------------------- /ci/config.yml: -------------------------------------------------------------------------------- 1 | --- 2 | global: 3 | marketplace-ami: false 4 | owner: quickstart-eng@amazon.com 5 | qsname: quickstart-codepipeline-bluegreen-deployment 6 | regions: 7 | - us-east-2 8 | - us-east-1 9 | - us-west-1 10 | - us-west-2 11 | - ap-south-1 12 | - eu-west-3 13 | - eu-west-2 14 | - eu-west-1 15 | - ap-northeast-3 16 | - ap-northeast-2 17 | - ap-northeast-1 18 | - sa-east-1 19 | - ca-central-1 20 | - ap-southeast-1 21 | - ap-southeast-2 22 | - eu-central-1 23 | reporting: true 24 | tests: 25 | test-withoutGittoS3withBeanstalkSample: #test without GittoS3 Integration enabled with sample Beanstalk app 26 | parameter_input: withoutGittoS3withBeanstalkSample.json 27 | template_file: bluegreen-deployment-master.template 28 | regions: 29 | - us-west-1 30 | test-withGittoS3withBeanstalkSample: #test with GittoS3 Integration enabled with sample Beanstalk app 31 | parameter_input: withGittoS3withBeanstalkSample.json 32 | template_file: bluegreen-deployment-master.template 33 | regions: 34 | - us-west-2 35 | test-withoutGittoS3withnoBeanstalkSample: #test without GittoS3 Integration enabled with no sample Beanstalk app 36 | parameter_input: withoutGittoS3withnoBeanstalkSample.json 37 | template_file: bluegreen-deployment-master.template 38 | regions: 39 | - us-east-1 40 | test-withGittoS3withnoBeanstalkSample: #test with GittoS3 Integration enabled with no sample Beanstalk app 41 | parameter_input: withGittoS3withnoBeanstalkSample.json 42 | template_file: bluegreen-deployment-master.template 43 | regions: 44 | - us-east-2 45 | -------------------------------------------------------------------------------- /ci/taskcat.yml: -------------------------------------------------------------------------------- 1 | --- 2 | global: 3 | marketplace-ami: false 4 | owner: quickstart-eng@amazon.com 5 | qsname: quickstart-codepipeline-bluegreen-deployment 6 | regions: 7 | - us-east-2 8 | - us-east-1 9 | - us-west-1 10 | - us-west-2 11 | - ap-south-1 12 | - eu-west-3 13 | - eu-west-2 14 | - eu-west-1 15 | - ap-northeast-3 16 | - ap-northeast-2 17 | - ap-northeast-1 18 | - sa-east-1 19 | - ca-central-1 20 | - ap-southeast-1 21 | - ap-southeast-2 22 | - eu-central-1 23 | reporting: true 24 | tests: 25 | test-withoutGittoS3withBeanstalkSample: #test without GittoS3 Integration enabled with sample Beanstalk app 26 | parameter_input: withoutGittoS3withBeanstalkSample.json 27 | template_file: bluegreen-deployment-master.template 28 | regions: 29 | - us-west-1 30 | test-withGittoS3withBeanstalkSample: #test with GittoS3 Integration enabled with sample Beanstalk app 31 | parameter_input: withGittoS3withBeanstalkSample.json 32 | template_file: bluegreen-deployment-master.template 33 | regions: 34 | - us-west-2 35 | test-withoutGittoS3withnoBeanstalkSample: #test without GittoS3 Integration enabled with no sample Beanstalk app 36 | parameter_input: withoutGittoS3withnoBeanstalkSample.json 37 | template_file: bluegreen-deployment-master.template 38 | regions: 39 | - us-east-1 40 | test-withGittoS3withnoBeanstalkSample: #test with GittoS3 Integration enabled with no sample Beanstalk app 41 | parameter_input: withGittoS3withnoBeanstalkSample.json 42 | template_file: bluegreen-deployment-master.template 43 | regions: 44 | - us-east-2 45 | -------------------------------------------------------------------------------- /ci/withGittoS3withBeanstalkSample.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "ParameterKey": "AdministratorEmail", 3 | "ParameterValue": "test@email.com" 4 | }, { 5 | "ParameterKey": "AllowedIps", 6 | "ParameterValue": "131.103.20.160/27,165.254.145.0/26,104.192.143.0/24" 7 | }, { 8 | "ParameterKey": "ApiSecret", 9 | "ParameterValue": "test123" 10 | }, { 11 | "ParameterKey": "BeanstalkSourceStageS3BucketName", 12 | "ParameterValue": "" 13 | }, { 14 | "ParameterKey": "BeanstalkSourceStageS3BucketKey", 15 | "ParameterValue": "ckirankumar1989/BeanstalkPHPSample/master/BeanstalkPHPSample.zip" 16 | },{ 17 | "ParameterKey": "CustomDomainName", 18 | "ParameterValue": "" 19 | },{ 20 | "ParameterKey": "ExistingBeanstalkApplicationName", 21 | "ParameterValue": "" 22 | },{ 23 | "ParameterKey": "ExistingBlueEnvironmentName", 24 | "ParameterValue": "" 25 | },{ 26 | "ParameterKey": "GitToken", 27 | "ParameterValue": "" 28 | },{ 29 | "ParameterKey": "GitToS3integration", 30 | "ParameterValue": "true" 31 | },{ 32 | "ParameterKey": "GreenEnvironmentName", 33 | "ParameterValue": "GreenEnvironment1" 34 | },{ 35 | "ParameterKey": "NameofthePipeline", 36 | "ParameterValue": "BlueGreenCICDPipeline1" 37 | },{ 38 | "ParameterKey": "OauthKey", 39 | "ParameterValue": "" 40 | },{ 41 | "ParameterKey": "OauthSecret", 42 | "ParameterValue": "" 43 | }, 44 | { 45 | "ParameterKey": "QSS3BucketName", 46 | "ParameterValue": "$[taskcat_autobucket]" 47 | }, 48 | { 49 | "ParameterKey": "QSS3BucketRegion", 50 | "ParameterValue": "$[taskcat_current_region]" 51 | }, 52 | { 53 | "ParameterKey": "QSS3KeyPrefix", 54 | "ParameterValue": "quickstart-codepipeline-bluegreen-deployment/" 55 | }] 56 | -------------------------------------------------------------------------------- /ci/withoutGittoS3withnoBeanstalkSample.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "ParameterKey": "AdministratorEmail", 3 | "ParameterValue": "test@email.com" 4 | }, { 5 | "ParameterKey": "AllowedIps", 6 | "ParameterValue": "131.103.20.160/27,165.254.145.0/26,104.192.143.0/24" 7 | }, { 8 | "ParameterKey": "ApiSecret", 9 | "ParameterValue": "test123" 10 | }, { 11 | "ParameterKey": "BeanstalkSourceStageS3BucketName", 12 | "ParameterValue": "" 13 | }, { 14 | "ParameterKey": "BeanstalkSourceStageS3BucketKey", 15 | "ParameterValue": "php-sample.zip" 16 | },{ 17 | "ParameterKey": "CustomDomainName", 18 | "ParameterValue": "" 19 | },{ 20 | "ParameterKey": "ExistingBeanstalkApplicationName", 21 | "ParameterValue": "BlueGreenBeanstalkApplication" 22 | },{ 23 | "ParameterKey": "ExistingBlueEnvironmentName", 24 | "ParameterValue": "BlueEnvironment" 25 | },{ 26 | "ParameterKey": "GitToken", 27 | "ParameterValue": "" 28 | },{ 29 | "ParameterKey": "GitToS3integration", 30 | "ParameterValue": "false" 31 | },{ 32 | "ParameterKey": "GreenEnvironmentName", 33 | "ParameterValue": "GreenEnvironment4" 34 | },{ 35 | "ParameterKey": "NameofthePipeline", 36 | "ParameterValue": "BlueGreenCICDPipeline4" 37 | },{ 38 | "ParameterKey": "OauthKey", 39 | "ParameterValue": "" 40 | },{ 41 | "ParameterKey": "OauthSecret", 42 | "ParameterValue": "" 43 | }, 44 | { 45 | "ParameterKey": "QSS3BucketName", 46 | "ParameterValue": "$[taskcat_autobucket]" 47 | }, 48 | { 49 | "ParameterKey": "QSS3BucketRegion", 50 | "ParameterValue": "$[taskcat_current_region]" 51 | }, 52 | { 53 | "ParameterKey": "QSS3KeyPrefix", 54 | "ParameterValue": "quickstart-codepipeline-bluegreen-deployment/" 55 | }] 56 | -------------------------------------------------------------------------------- /ci/withGittoS3withnoBeanstalkSample.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "ParameterKey": "AdministratorEmail", 3 | "ParameterValue": "test@email.com" 4 | }, { 5 | "ParameterKey": "AllowedIps", 6 | "ParameterValue": "131.103.20.160/27,165.254.145.0/26,104.192.143.0/24" 7 | }, { 8 | "ParameterKey": "ApiSecret", 9 | "ParameterValue": "test123" 10 | }, { 11 | "ParameterKey": "BeanstalkSourceStageS3BucketName", 12 | "ParameterValue": "" 13 | }, { 14 | "ParameterKey": "BeanstalkSourceStageS3BucketKey", 15 | "ParameterValue": "ckirankumar1989/BeanstalkPHPSample/master/BeanstalkPHPSample.zip" 16 | },{ 17 | "ParameterKey": "CustomDomainName", 18 | "ParameterValue": "" 19 | },{ 20 | "ParameterKey": "ExistingBeanstalkApplicationName", 21 | "ParameterValue": "BlueGreenBeanstalkApplication" 22 | },{ 23 | "ParameterKey": "ExistingBlueEnvironmentName", 24 | "ParameterValue": "BlueEnvironment" 25 | },{ 26 | "ParameterKey": "GitToken", 27 | "ParameterValue": "" 28 | },{ 29 | "ParameterKey": "GitToS3integration", 30 | "ParameterValue": "true" 31 | },{ 32 | "ParameterKey": "GreenEnvironmentName", 33 | "ParameterValue": "GreenEnvironment2" 34 | },{ 35 | "ParameterKey": "NameofthePipeline", 36 | "ParameterValue": "BlueGreenCICDPipeline2" 37 | },{ 38 | "ParameterKey": "OauthKey", 39 | "ParameterValue": "" 40 | },{ 41 | "ParameterKey": "OauthSecret", 42 | "ParameterValue": "" 43 | }, 44 | { 45 | "ParameterKey": "QSS3BucketName", 46 | "ParameterValue": "$[taskcat_autobucket]" 47 | }, 48 | { 49 | "ParameterKey": "QSS3BucketRegion", 50 | "ParameterValue": "$[taskcat_current_region]" 51 | }, 52 | { 53 | "ParameterKey": "QSS3KeyPrefix", 54 | "ParameterValue": "quickstart-codepipeline-bluegreen-deployment/" 55 | }] 56 | -------------------------------------------------------------------------------- /.taskcat.yml: -------------------------------------------------------------------------------- 1 | project: 2 | name: quickstart-codepipeline-bluegreen-deployment 3 | owner: quickstart-eng@amazon.com 4 | package_lambda: false 5 | regions: 6 | - us-east-2 7 | - us-east-1 8 | - us-west-2 9 | - ap-south-1 10 | - eu-west-3 11 | - eu-west-2 12 | - eu-west-1 13 | - ap-northeast-3 14 | - ap-northeast-2 15 | - ap-northeast-1 16 | - sa-east-1 17 | - ca-central-1 18 | - ap-southeast-1 19 | - ap-southeast-2 20 | - eu-central-1 21 | s3_bucket: '' 22 | tests: 23 | #test-withGittoS3withBeanstalkSample: 24 | # parameters: 25 | # AdministratorEmail: test@email.com 26 | # AllowedIps: 131.103.20.160/27,165.254.145.0/26,104.192.143.0/24 27 | # ApiSecret: test123 28 | # BeanstalkSourceStageS3BucketKey: ckirankumar1989/BeanstalkPHPSample/master/BeanstalkPHPSample.zip 29 | # BeanstalkSourceStageS3BucketName: '' 30 | # CustomDomainName: '' 31 | # ExistingBeanstalkApplicationName: '' 32 | # ExistingBlueEnvironmentName: '' 33 | # GitToS3integration: 'true' 34 | # GreenEnvironmentName: GreenEnvironment1 35 | # NameofthePipeline: BlueGreenCICDPipeline1 36 | # QSS3BucketName: $[taskcat_autobucket] 37 | # QSS3BucketRegion: $[taskcat_current_region] 38 | # QSS3KeyPrefix: quickstart-codepipeline-bluegreen-deployment/ 39 | # regions: 40 | # - us-west-2 41 | # s3_bucket: '' 42 | # template: templates/bluegreen-deployment-master.template 43 | test-withoutGittoS3withBeanstalkSample: 44 | parameters: 45 | AdministratorEmail: test@email.com 46 | AllowedIps: 131.103.20.160/27,165.254.145.0/26,104.192.143.0/24 47 | ApiSecret: test123 48 | BeanstalkSourceStageS3BucketKey: php-sample.zip 49 | BeanstalkSourceStageS3BucketName: '' 50 | CustomDomainName: '' 51 | GitToS3integration: 'false' 52 | GreenEnvironmentName: GreenEnvironment3 53 | NameofthePipeline: BlueGreenCICDPipeline3 54 | QSS3BucketName: $[taskcat_autobucket] 55 | QSS3BucketRegion: $[taskcat_current_region] 56 | QSS3KeyPrefix: quickstart-codepipeline-bluegreen-deployment/ 57 | regions: 58 | - us-east-1 59 | s3_bucket: '' 60 | template: templates/bluegreen-deployment-master.template 61 | 62 | -------------------------------------------------------------------------------- /functions/source/TerminateandReSwap/index.py: -------------------------------------------------------------------------------- 1 | import boto3 2 | import json 3 | import traceback 4 | import time 5 | import sys 6 | import logging 7 | import threading 8 | 9 | beanstalkclient = boto3.client('elasticbeanstalk') 10 | codepipelineclient = boto3.client('codepipeline') 11 | 12 | def handler(event, context): 13 | # make sure we send a failure to CodePipeline if the function is going to timeout 14 | timer = threading.Timer((context.get_remaining_time_in_millis() / 1000.00) - 0.5, timeout, args=[event, context]) 15 | timer.start() 16 | try: 17 | # Extract the Job ID 18 | job_id = event['CodePipeline.job']['id'] 19 | # Extract the Job Data 20 | job_data = event['CodePipeline.job']['data'] 21 | user_parameters = job_data['actionConfiguration']['configuration']['UserParameters'] 22 | #Calling DeleteConfigTemplate API 23 | DeleteConfigTemplate=DeleteConfigTemplateBlue(AppName=(json.loads(user_parameters)['BeanstalkAppName']),TempName=(json.loads(user_parameters)['CreateConfigTempName'])) 24 | print (DeleteConfigTemplate) 25 | #re-swapping the urls 26 | reswap = SwapGreenandBlue(SourceEnv=(json.loads(user_parameters)['BlueEnvName']),DestEnv=(json.loads(user_parameters)['GreenEnvName'])) 27 | if reswap == "Failure": 28 | raise Exception("Re-Swap did not happen") 29 | print ("Deleting the GreenEnvironment") 30 | DeleteGreenEnvironment(EnvName=(json.loads(user_parameters)['GreenEnvName'])) 31 | #Delete the S3 CNAME Config file 32 | s3 = boto3.resource('s3') 33 | bucket = s3.Bucket(json.loads(user_parameters)['BlueCNAMEConfigBucket']) 34 | key = 'hello.json' 35 | objs = list(bucket.objects.filter(Prefix=key)) 36 | if len(objs) > 0 and objs[0].key == key: 37 | obj = s3.Object(json.loads(user_parameters)['BlueCNAMEConfigBucket'],json.loads(user_parameters)['BlueCNAMEConfigFile']) 38 | obj.delete() 39 | print ("Successfully deleted the CNAME Config file") 40 | else: 41 | print("Seems like the CNAME Config file is already deleted!") 42 | #Send Success Message to CodePipeline 43 | Status="Success" 44 | Message="Successfully reswapped and terminated the Green Environment" 45 | 46 | except Exception as e: 47 | print('Function failed due to exception.') 48 | e = sys.exc_info()[0] 49 | print(e) 50 | traceback.print_exc() 51 | Status="Failure" 52 | Message=("Error occured while executing this. The error is %s" %e) 53 | 54 | finally: 55 | timer.cancel() 56 | if (Status =="Success"): 57 | put_job_success(job_id, Message) 58 | else: 59 | put_job_failure(job_id, Message) 60 | 61 | def DeleteConfigTemplateBlue(AppName,TempName): 62 | #check if the config template exists 63 | ListTemplates = beanstalkclient.describe_applications(ApplicationNames=[AppName])['Applications'][0]['ConfigurationTemplates'] 64 | if TempName not in ListTemplates: 65 | return ("Config Template does not exist") 66 | else: 67 | response = beanstalkclient.delete_configuration_template(ApplicationName=AppName,TemplateName=TempName) 68 | return ("Config Template Deleted") 69 | 70 | def SwapGreenandBlue(SourceEnv, DestEnv): 71 | GetEnvData = (beanstalkclient.describe_environments(EnvironmentNames=[SourceEnv,DestEnv],IncludeDeleted=False)) 72 | print (GetEnvData) 73 | if (((GetEnvData['Environments'][0]['Status']) == "Ready") and ((GetEnvData['Environments'][1]['Status']) == "Ready")): 74 | response = beanstalkclient.swap_environment_cnames(SourceEnvironmentName=SourceEnv,DestinationEnvironmentName=DestEnv) 75 | return ("Successful") 76 | else: 77 | return ("Failure") 78 | 79 | def DeleteGreenEnvironment(EnvName): 80 | GetEnvData = (beanstalkclient.describe_environments(EnvironmentNames=[EnvName])) 81 | print(GetEnvData) 82 | #print (B['Environments'][0]['Status']) 83 | InvalidStatus = ["Terminating","Terminated"] 84 | if not(GetEnvData['Environments']==[]): 85 | #if not(B['Environments'][0]['Status']=="Terminated"): #or not(B['Environments'][0]['Status']=="Terminating")): 86 | if (GetEnvData['Environments'][0]['Status']) in InvalidStatus: 87 | return ("Already Terminated") 88 | while True: 89 | GreenEnvStatus = (beanstalkclient.describe_environments(EnvironmentNames=[EnvName]))['Environments'][0]['Status'] 90 | print (GreenEnvStatus) 91 | time.sleep(10) 92 | if (GreenEnvStatus == 'Ready'): 93 | response = beanstalkclient.terminate_environment(EnvironmentName=EnvName) 94 | print (response) 95 | print ("Successfully Terminated Green Environment") 96 | return 97 | def timeout(event, context): 98 | logging.error('Execution is about to time out, sending failure response to CodePipeline') 99 | put_job_failure(event['CodePipeline.job']['id'], "FunctionTimeOut") 100 | 101 | def put_job_success(job, message): 102 | print('Putting job success') 103 | print(message) 104 | codepipelineclient.put_job_success_result(jobId=job) 105 | 106 | def put_job_failure(job, message): 107 | print('Putting job failure') 108 | print(message) 109 | codepipelineclient.put_job_failure_result(jobId=job, failureDetails={'message': message, 'type': 'JobFailed'}) 110 | -------------------------------------------------------------------------------- /functions/source/CreateEnvironment/index.py: -------------------------------------------------------------------------------- 1 | import boto3 2 | import json 3 | import traceback 4 | import sys 5 | import logging 6 | import threading 7 | import time 8 | 9 | beanstalkclient = boto3.client('elasticbeanstalk') 10 | codepipelineclient = boto3.client('codepipeline') 11 | 12 | def handler(event, context): 13 | timer = threading.Timer((context.get_remaining_time_in_millis() / 1000.00) - 0.5, timeout, args=[event, context]) 14 | timer.start() 15 | try: 16 | # Extract the Job ID 17 | job_id = event['CodePipeline.job']['id'] 18 | # Extract the Job Data 19 | job_data = event['CodePipeline.job']['data'] 20 | user_parameters = job_data['actionConfiguration']['configuration']['UserParameters'] 21 | print(job_data) 22 | print(event) 23 | BlueEnvInfo=GetBlueEnvInfo(EnvName=(json.loads(user_parameters)['BlueEnvName'])) 24 | BlueEnvId=(BlueEnvInfo['Environments'][0]['EnvironmentId']) 25 | BlueVersionLabel=(BlueEnvInfo['Environments'][0]['VersionLabel']) 26 | 27 | #Calling CreateConfigTemplate API 28 | ConfigTemplate=CreateConfigTemplateBlue(AppName=(json.loads(user_parameters)['BeanstalkAppName']),BlueEnvId=BlueEnvId,TempName=json.loads(user_parameters)['CreateConfigTempName']) 29 | ReturnedTempName=ConfigTemplate 30 | print (ReturnedTempName) 31 | if not ReturnedTempName: 32 | #raise Exception if the Config file does not exist 33 | raise Exception("There were some issue while creating a Configuration Template from the Blue Environment") 34 | else: 35 | GreenEnvId=CreateGreenEnvironment(EnvName=(json.loads(user_parameters)['GreenEnvName']),ConfigTemplate=ReturnedTempName,AppVersion=BlueVersionLabel,AppName=(json.loads(user_parameters)['BeanstalkAppName'])) 36 | print (GreenEnvId) 37 | #print (GreenEnvIddetails) 38 | if GreenEnvId: 39 | Status="Success" 40 | Message="Successfully created the Green Environment/Environment with the provided name already exists" 41 | #Create a CNAME Config file 42 | BlueEnvCname=(BlueEnvInfo['Environments'][0]['CNAME']) 43 | s3 = boto3.resource('s3') 44 | bucket = s3.Bucket(json.loads(user_parameters)['BlueCNAMEConfigBucket']) 45 | key = json.loads(user_parameters)['BlueCNAMEConfigFile'] 46 | objs = list(bucket.objects.filter(Prefix=key)) 47 | if len(objs) > 0 and objs[0].key == key: 48 | print("BlueCNAMEConfigFile Already Exists!") 49 | else: 50 | obj = s3.Object(json.loads(user_parameters)['BlueCNAMEConfigBucket'], json.loads(user_parameters)['BlueCNAMEConfigFile']) 51 | BlueEnvCnameFile = {'BlueEnvUrl': BlueEnvCname} 52 | obj.put(Body=json.dumps(BlueEnvCnameFile)) 53 | print ("Created a new CNAME file") 54 | else: 55 | Status="Failure" 56 | Message="Something went wrong on GreenEnv Creation" 57 | except Exception as e: 58 | print('Function failed due to exception.') 59 | e = sys.exc_info()[0] 60 | print(e) 61 | traceback.print_exc() 62 | Status="Failure" 63 | Message=("Error occured while executing this. The error is %s" %e) 64 | finally: 65 | timer.cancel() 66 | if (Status =="Success"): 67 | put_job_success(job_id, Message) 68 | else: 69 | put_job_failure(job_id, Message) 70 | 71 | def CreateConfigTemplateBlue(AppName,BlueEnvId,TempName): 72 | ListTemplates = beanstalkclient.describe_applications(ApplicationNames=[AppName])['Applications'][0]['ConfigurationTemplates'] 73 | count = 0 74 | while count < len(ListTemplates): 75 | print (ListTemplates[count]) 76 | if ListTemplates[count] == TempName: 77 | print ("ConfigTempAlreadyExists") 78 | return TempName 79 | break 80 | count += 1 81 | response = beanstalkclient.create_configuration_template( 82 | ApplicationName=AppName, 83 | TemplateName=TempName, 84 | EnvironmentId=BlueEnvId) 85 | return response['TemplateName'] 86 | 87 | def GetBlueEnvInfo(EnvName): 88 | response = beanstalkclient.describe_environments( 89 | EnvironmentNames=[ 90 | EnvName 91 | ]) 92 | print("Described the environment") 93 | return response 94 | 95 | def CreateGreenEnvironment(EnvName,ConfigTemplate,AppVersion,AppName): 96 | GetEnvData = (beanstalkclient.describe_environments(EnvironmentNames=[EnvName])) 97 | print(GetEnvData) 98 | #print (B['Environments'][0]['Status']) 99 | InvalidStatus = ["Terminating","Terminated"] 100 | if not(GetEnvData['Environments']==[]): 101 | print("Environment Exists") 102 | if not(GetEnvData['Environments'][0]['Status']) in InvalidStatus: 103 | print("Existing Environment with the name %s not in Invalid Status" % EnvName) 104 | return (GetEnvData['Environments'][0]['EnvironmentId']) 105 | print ("Creating a new Environment") 106 | response = beanstalkclient.create_environment( 107 | ApplicationName=AppName, 108 | EnvironmentName=EnvName, 109 | TemplateName=ConfigTemplate, 110 | VersionLabel=AppVersion) 111 | return response['EnvironmentId'] 112 | 113 | def timeout(event, context): 114 | logging.error('Execution is about to time out, sending failure response to CodePipeline') 115 | put_job_failure(event['CodePipeline.job']['id'], "FunctionTimeOut") 116 | 117 | def put_job_success(job, message): 118 | print('Putting job success') 119 | print(message) 120 | codepipelineclient.put_job_success_result(jobId=job) 121 | 122 | def put_job_failure(job, message): 123 | print('Putting job failure') 124 | print(message) 125 | codepipelineclient.put_job_failure_result(jobId=job, failureDetails={'message': message, 'type': 'JobFailed'}) 126 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /templates/elasticbeanstalk-sample.template: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Description: Sample Beanstalk environmment template (qs-1rt5l9ase) 3 | Metadata: 4 | QSLint: 5 | Exclusions: [ W9002, W9003, W9004, W9006 ] 6 | cfn-lint: 7 | config: 8 | ignore_checks: 9 | - E9904 10 | - E9902 11 | - E9010 12 | - W9901 13 | Conditions: 14 | CreateNewBeanstalkApp: !Equals 15 | - !Ref 'ExistingBeanstalkApplicationName' 16 | - '' 17 | CreateNewBeanstalkEnv: !Equals 18 | - !Ref 'ExistingBlueEnvironmentName' 19 | - '' 20 | CreateSampleAppForBeanstalk: !Equals 21 | - !Ref 'AppPackageS3Bucket' 22 | - elasticbeanstalk-samples 23 | Parameters: 24 | AppPackageS3Bucket: 25 | Default: elasticbeanstalk-samples 26 | Description: Provide the S3 bucket where the Application Package exists for creating 27 | a new Beanstalk environment. This parameter can be ignored if using an existing 28 | Environment. 29 | Type: String 30 | AppPackageS3key: 31 | Default: php-sample.zip 32 | Description: Provide the S3 bucket key with the zip file package name for creating 33 | a new Beanstalk environment. This parameter can be ignored if using an existing 34 | Environment 35 | Type: String 36 | ExistingBeanstalkApplicationName: 37 | Default: '' 38 | Description: >- 39 | OPTIONAL: Required if the parameter 'ExistingBlueEnvironmentName' is provided. 40 | Give the Name of the Existing Beantalk Application where the existing Beanstalk 41 | Environment is running. Leave in blank if you want to create a new Application 42 | Type: String 43 | ExistingBlueEnvironmentName: 44 | Default: '' 45 | Description: >- 46 | Name of the Existing Beanstalk Environment as Blue Environment. Leave it blank 47 | if you want to create a new Environment. Provide a value to this parameter for 48 | which you would like to utilize the cost efficient Blue-Green deployments by 49 | creating a temporary cloned environment for routing the live traffic when this 50 | environment is in the Deployment/Test lifecycle 51 | Type: String 52 | GreenEnvironmentName: 53 | Default: GreenEnvironment 54 | Description: >- 55 | Provide a Name for the Green Environment, which will be the clone of the Blue 56 | Environment where the traffic will be routed temporarily for the amount of time 57 | the Blue Environment is completed with the deployment and tested. After the 58 | successful deployment to Blue Environment, the traffic will be routed back to 59 | Blue and the Green Environment will be terminated 60 | Type: String 61 | NewBeanstalkApplicationName: 62 | Default: BlueGreenBeanstalkApplication 63 | Description: >- 64 | OPTIONAL:Provide a name for a new Beantalk Application where the new Blue Environment 65 | and the clone will be created. If not provided, the name will be 'BlueGreenBeanstalkApplication' 66 | by default. Value for this parameter is required only when you leave the 'ExistingBlueEnvironmentName' 67 | and 'ExistingBeanstalkApplicationName' property empty 68 | Type: String 69 | NewBlueEnvironmentName: 70 | Default: BlueEnvironment 71 | Description: >- 72 | Provide a name for creating a new Beanstalk Environment as Blue Environment 73 | that uses a Sample Application. This is the main environment from which a temporary 74 | clone called 'Green Environment' will be created to route the live traffic until 75 | the deployment is completed and tested with this one. Value for this parameter 76 | is required only when you leave the 'ExistingBlueEnvironmentName' property empty 77 | Type: String 78 | SolutionStackForNewBeanstalkEnv: 79 | Default: 64bit Amazon Linux 2 v3.5.0 running PHP 8.0 80 | Description: >- 81 | Provide a name for the Beanstalk Solution stack for launching the new Blue Environment. 82 | If not provided, the default will be a PHP solution stack. Please refer the 83 | following document https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/concepts.platforms.html 84 | for all the solution stack values. Value for this parameter is required only 85 | when you leave the 'ExistingBlueEnvironmentName' property empty 86 | Type: String 87 | Resources: 88 | BeanstalkAppVersion: 89 | Condition: CreateNewBeanstalkEnv 90 | Properties: 91 | ApplicationName: !If 92 | - CreateNewBeanstalkApp 93 | - !Ref 'BeanstalkApplication' 94 | - !Ref 'ExistingBeanstalkApplicationName' 95 | Description: my sample version 96 | SourceBundle: 97 | S3Bucket: !If 98 | - CreateSampleAppForBeanstalk 99 | - !Join 100 | - '' 101 | - - !Ref 'AppPackageS3Bucket' 102 | - '-' 103 | - !Ref 'AWS::Region' 104 | - !Ref 'AppPackageS3Bucket' 105 | S3Key: !Ref 'AppPackageS3key' 106 | Type: AWS::ElasticBeanstalk::ApplicationVersion 107 | BeanstalkApplication: 108 | Condition: CreateNewBeanstalkApp 109 | Properties: 110 | ApplicationName: !Ref 'NewBeanstalkApplicationName' 111 | Description: AWS Elastic Beanstalk PHP Sample Application 112 | Type: AWS::ElasticBeanstalk::Application 113 | BeanstalkEnvironment: 114 | Condition: CreateNewBeanstalkEnv 115 | Properties: 116 | ApplicationName: !If 117 | - CreateNewBeanstalkApp 118 | - !Ref 'BeanstalkApplication' 119 | - !Ref 'ExistingBeanstalkApplicationName' 120 | Description: AWS Elastic Beanstalk Environment running PHP Sample Application 121 | EnvironmentName: !Ref 'NewBlueEnvironmentName' 122 | OptionSettings: 123 | - Namespace: aws:autoscaling:launchconfiguration 124 | OptionName: IamInstanceProfile 125 | Value: !Ref 'BeanstalkInstanceProfile' 126 | - Namespace: aws:elasticbeanstalk:environment 127 | OptionName: ServiceRole 128 | Value: !Ref 'BeanstalkServiceRole' 129 | SolutionStackName: !Ref 'SolutionStackForNewBeanstalkEnv' 130 | VersionLabel: !Ref 'BeanstalkAppVersion' 131 | Type: AWS::ElasticBeanstalk::Environment 132 | BeanstalkInstanceProfile: 133 | Condition: CreateNewBeanstalkEnv 134 | Properties: 135 | Path: / 136 | Roles: 137 | - !Ref 'BeanstalkInstanceProfileRole' 138 | Type: AWS::IAM::InstanceProfile 139 | BeanstalkInstanceProfileRole: 140 | Condition: CreateNewBeanstalkEnv 141 | Properties: 142 | AssumeRolePolicyDocument: 143 | Statement: 144 | - Action: 145 | - sts:AssumeRole 146 | Effect: Allow 147 | Principal: 148 | Service: 149 | - ec2.amazonaws.com 150 | Version: '2012-10-17' 151 | Path: / 152 | Policies: 153 | - PolicyDocument: 154 | Statement: 155 | - Action: 156 | - s3:GetStorageLensDashboard 157 | - s3:GetAccessPoint 158 | - s3:GetObject 159 | - s3:GetAccessPointPolicyStatus 160 | - s3:GetReplicationConfiguration 161 | - s3:GetObjectTagging 162 | - s3:GetBucketLocation 163 | - s3:GetAccessPointForObjectLambda 164 | - s3:GetBucketRequestPayment 165 | - s3:GetObjectVersionTorrent 166 | - s3:GetBucketAcl 167 | - s3:GetBucketPublicAccessBlock 168 | - s3:GetAnalyticsConfiguration 169 | - s3:GetAccessPointPolicy 170 | - s3:GetObjectLegalHold 171 | - s3:GetAccelerateConfiguration 172 | - s3:GetBucketOwnershipControls 173 | - s3:GetBucketPolicyStatus 174 | - s3:GetObjectVersionAcl 175 | - s3:GetBucketLogging 176 | - s3:GetBucketPolicy 177 | - s3:GetAccessPointPolicyForObjectLambda 178 | - s3:GetBucketWebsite 179 | - s3:GetObjectAcl 180 | - s3:GetObjectRetention 181 | - s3:GetJobTagging 182 | - s3:GetMetricsConfiguration 183 | - s3:GetStorageLensConfiguration 184 | - s3:GetBucketNotification 185 | - s3:GetBucketTagging 186 | - s3:GetEncryptionConfiguration 187 | - s3:GetAccessPointPolicyStatusForObjectLambda 188 | - s3:GetObjectTorrent 189 | - s3:GetAccountPublicAccessBlock 190 | - s3:GetBucketObjectLockConfiguration 191 | - s3:GetIntelligentTieringConfiguration 192 | - s3:GetObjectVersionForReplication 193 | - s3:GetBucketVersioning 194 | - s3:GetInventoryConfiguration 195 | - s3:GetObjectVersion 196 | - s3:GetBucketCORS 197 | - s3:GetAccessPointConfigurationForObjectLambda 198 | - s3:GetObjectVersionTagging 199 | - s3:GetLifecycleConfiguratio 200 | - s3:GetStorageLensConfigurationTagging 201 | - s3:listmultipartuploadparts 202 | - s3:listbucketmultipartuploads 203 | - s3:listjobs 204 | - s3:listallmybuckets 205 | - s3:listbucket 206 | - s3:listaccesspoints 207 | - s3:listaccesspointsforobjectlambda 208 | - s3:liststoragelensconfigurations 209 | - s3:listbucketversions 210 | - s3:PutObject 211 | Effect: Allow 212 | Resource: 213 | - !Join 214 | - '' 215 | - - 'arn:' 216 | - !Ref 'AWS::Partition' 217 | - :s3:::elasticbeanstalk-*- 218 | - !Ref 'AWS::AccountId' 219 | - !Join 220 | - '' 221 | - - 'arn:' 222 | - !Ref 'AWS::Partition' 223 | - :s3:::elasticbeanstalk-*- 224 | - !Ref 'AWS::AccountId' 225 | - /* 226 | - !Join 227 | - '' 228 | - - 'arn:' 229 | - !Ref 'AWS::Partition' 230 | - :s3:::elasticbeanstalk-*- 231 | - !Ref 'AWS::AccountId' 232 | - -* 233 | - !Join 234 | - '' 235 | - - 'arn:' 236 | - !Ref 'AWS::Partition' 237 | - :s3:::elasticbeanstalk-*- 238 | - !Ref 'AWS::AccountId' 239 | - -*/* 240 | Sid: BucketAccess 241 | - Action: 242 | - cloudwatch:PutMetricData 243 | Effect: Allow 244 | Resource: '*' 245 | Sid: MetricsAccess 246 | - Action: 247 | - logs:PutLogEvents 248 | - logs:CreateLogStream 249 | - logs:DescribeLogStreams 250 | - logs:DescribeLogGroups 251 | Effect: Allow 252 | Resource: 253 | - !Sub 'arn:${AWS::Partition}:logs:*:*:log-group:/aws/elasticbeanstalk*' 254 | Sid: CloudWatchLogsAccess 255 | Version: '2012-10-17' 256 | PolicyName: root 257 | Type: AWS::IAM::Role 258 | BeanstalkServiceRole: 259 | Metadata: 260 | cfn-lint: 261 | config: 262 | ignore_checks: 263 | - EIAMPolicyWildcardResource 264 | ignore_reasons: 265 | EIAMPolicyWildcardResource: Done by Design 266 | Condition: CreateNewBeanstalkEnv 267 | Properties: 268 | AssumeRolePolicyDocument: 269 | Statement: 270 | - Action: sts:AssumeRole 271 | Condition: 272 | StringEquals: 273 | sts:ExternalId: elasticbeanstalk 274 | Effect: Allow 275 | Principal: 276 | Service: elasticbeanstalk.amazonaws.com 277 | Sid: '' 278 | Version: '2012-10-17' 279 | Path: / 280 | Policies: 281 | - PolicyDocument: 282 | Statement: 283 | - Action: 284 | - elasticloadbalancing:DescribeInstanceHealth 285 | - ec2:DescribeInstances 286 | - ec2:DescribeInstanceStatus 287 | - ec2:GetConsoleOutput 288 | - ec2:AssociateAddress 289 | - ec2:DescribeAddresses 290 | - ec2:DescribeSecurityGroups 291 | - sqs:GetQueueAttributes 292 | - sqs:GetQueueUrl 293 | - autoscaling:DescribeAutoScalingGroups 294 | - autoscaling:DescribeAutoScalingInstances 295 | - autoscaling:DescribeScalingActivities 296 | - autoscaling:DescribeNotificationConfigurations 297 | Effect: Allow 298 | Resource: 299 | - '*' 300 | Version: '2012-10-17' 301 | PolicyName: root 302 | Type: AWS::IAM::Role 303 | Outputs: 304 | BeanstalkEnvironment: 305 | Value: !If 306 | - CreateNewBeanstalkEnv 307 | - !Ref 'BeanstalkEnvironment' 308 | - '' 309 | BeanstalkEnvEndPointUrl: 310 | Description: New Beanstalk Environment Endpoint URL 311 | Value: !If 312 | - CreateNewBeanstalkEnv 313 | - !GetAtt 'BeanstalkEnvironment.EndpointURL' 314 | - '' 315 | -------------------------------------------------------------------------------- /templates/copyfunction-to-s3bucket.template: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Description: Copy Function template that creates the Asset bucket for Lambda and upload the code. (qs-1rt5l9b00) 3 | Parameters: 4 | BeanstalkSourceStageS3BucketName: 5 | Default: '' 6 | Description: >- 7 | Provide the S3 bucket name where the application package can be uploaded/is 8 | uploaded for the CodePipeline Source Stage. If not provided, a bucket will be 9 | created. This can be ignored if Git2S3GitToS3integration parameter is set to 10 | 'true' 11 | Type: String 12 | GitToS3integration: 13 | AllowedValues: 14 | - 'true' 15 | - 'false' 16 | Default: 'false' 17 | Description: 'Select ''true'' if you want to have GittoS3 integration setup. If 18 | not leave it as default ''false'' ' 19 | Type: String 20 | QSS3BucketName: 21 | AllowedPattern: ^[0-9a-zA-Z]+([0-9a-zA-Z-]*[0-9a-zA-Z])*$ 22 | ConstraintDescription: Quick Start bucket name can include numbers, lowercase 23 | letters, uppercase letters, and hyphens (-). It cannot start or end with a hyphen 24 | (-). 25 | Default: aws-quickstart 26 | Description: S3 bucket name for the Quick Start assets. Quick Start bucket name 27 | can include numbers, lowercase letters, uppercase letters, and hyphens (-). 28 | It cannot start or end with a hyphen (-). 29 | Type: String 30 | QSS3KeyPrefix: 31 | AllowedPattern: ^[0-9a-zA-Z-/]*$ 32 | ConstraintDescription: Quick Start key prefix can include numbers, lowercase letters, 33 | uppercase letters, hyphens (-), and forward slash (/). 34 | Default: quickstart-codepipeline-bluegreen-deployment/ 35 | Description: S3 key prefix for the Quick Start assets. Quick Start key prefix 36 | can include numbers, lowercase letters, uppercase letters, hyphens (-), and 37 | forward slash (/). 38 | Type: String 39 | Conditions: 40 | UsingDefaultBucket: !Equals [!Ref QSS3BucketName, 'aws-quickstart'] 41 | CreateBucketForBeanstalkSource: !And 42 | - !Equals 43 | - !Ref 'BeanstalkSourceStageS3BucketName' 44 | - '' 45 | - !Not 46 | - !Equals 47 | - !Ref 'GitToS3integration' 48 | - 'true' 49 | Resources: 50 | BeanstalkSourceBucket: 51 | Condition: CreateBucketForBeanstalkSource 52 | Properties: 53 | Tags: [] 54 | VersioningConfiguration: 55 | Status: Enabled 56 | Type: AWS::S3::Bucket 57 | CodePipelineArtifactStore: 58 | Properties: 59 | Tags: [] 60 | Type: AWS::S3::Bucket 61 | CodePipelineArtifactStoreCleanUp: 62 | Properties: 63 | DestBucket: !Ref 'CodePipelineArtifactStore' 64 | ServiceToken: !GetAtt 'S3CleanUpFunction.Arn' 65 | Type: AWS::CloudFormation::CustomResource 66 | CopyZips: 67 | Type: AWS::CloudFormation::CustomResource 68 | Properties: 69 | ServiceToken: !GetAtt CopyZipsFunction.Arn 70 | DestRegion: !Ref "AWS::Region" 71 | DestBucket: !Ref LambdaZipsBucket 72 | SourceBucket: !If [ UsingDefaultBucket, !Sub '${QSS3BucketName}-${AWS::Region}', !Ref QSS3BucketName ] 73 | Prefix: !Ref QSS3KeyPrefix 74 | Objects: 75 | - functions/packages/CreateEnvironment/creategreenenv.zip 76 | - functions/packages/SwapEnvironments/swapenvironments.zip 77 | - functions/packages/TestBlueEnvironment/testBlueenvironment.zip 78 | - functions/packages/TerminateandReSwap/terminategreenenv.zip 79 | CopyZipsFunction: 80 | Type: AWS::Lambda::Function 81 | Properties: 82 | Description: Copies objects from a source S3 bucket to a destination 83 | Handler: index.handler 84 | Runtime: python3.7 85 | Role: !GetAtt CopyRole.Arn 86 | Timeout: 240 87 | Code: 88 | ZipFile: | 89 | import json 90 | import logging 91 | import threading 92 | import boto3 93 | import cfnresponse 94 | def copy_objects(source_bucket, dest_bucket, prefix, objects): 95 | s3 = boto3.client('s3') 96 | for o in objects: 97 | key = prefix + o 98 | copy_source = { 99 | 'Bucket': source_bucket, 100 | 'Key': key 101 | } 102 | s3.copy_object(CopySource=copy_source, Bucket=dest_bucket, Key=key) 103 | def delete_objects(bucket, prefix, objects): 104 | s3 = boto3.client('s3') 105 | objects = {'Objects': [{'Key': prefix + o} for o in objects]} 106 | s3.delete_objects(Bucket=bucket, Delete=objects) 107 | def timeout(event, context): 108 | logging.error('Execution is about to time out, sending failure response to CloudFormation') 109 | cfnresponse.send(event, context, cfnresponse.FAILED, {}, None) 110 | def handler(event, context): 111 | # make sure we send a failure to CloudFormation if the function is going to timeout 112 | timer = threading.Timer((context.get_remaining_time_in_millis() / 1000.00) - 0.5, timeout, args=[event, context]) 113 | timer.start() 114 | print('Received event: %s' % json.dumps(event)) 115 | status = cfnresponse.SUCCESS 116 | try: 117 | source_bucket = event['ResourceProperties']['SourceBucket'] 118 | dest_bucket = event['ResourceProperties']['DestBucket'] 119 | prefix = event['ResourceProperties']['Prefix'] 120 | objects = event['ResourceProperties']['Objects'] 121 | if event['RequestType'] == 'Delete': 122 | delete_objects(dest_bucket, prefix, objects) 123 | else: 124 | copy_objects(source_bucket, dest_bucket, prefix, objects) 125 | except Exception as e: 126 | logging.error('Exception: %s' % e, exc_info=True) 127 | status = cfnresponse.FAILED 128 | finally: 129 | timer.cancel() 130 | cfnresponse.send(event, context, status, {}, None) 131 | CopyRole: 132 | Type: AWS::IAM::Role 133 | Properties: 134 | Path: / 135 | AssumeRolePolicyDocument: 136 | Version: 2012-10-17 137 | Statement: 138 | - Effect: Allow 139 | Principal: 140 | Service: lambda.amazonaws.com 141 | Action: sts:AssumeRole 142 | Policies: 143 | - PolicyName: ConfigPolicy 144 | PolicyDocument: 145 | Version: 2012-10-17 146 | Statement: 147 | - Sid: Logging 148 | Effect: Allow 149 | Action: 150 | - logs:StartQuery 151 | - logs:DeleteLogGroup 152 | - logs:CreateLogStream 153 | - logs:DisassociateKmsKey 154 | - logs:StopQuery 155 | - logs:UntagLogGroup 156 | - logs:PutResourcePolicy 157 | - logs:GetLogGroupFields 158 | - logs:GetLogDelivery 159 | - logs:TagLogGroup 160 | - logs:DeleteRetentionPolicy 161 | - logs:PutQueryDefinition 162 | - logs:UpdateLogDelivery 163 | - logs:FilterLogEvents 164 | - logs:PutRetentionPolicy 165 | - logs:PutMetricFilter 166 | - logs:DescribeQueryDefinitions 167 | - logs:PutDestination 168 | - logs:GetLogRecord 169 | - logs:PutLogEvents 170 | - logs:ListLogDeliveries 171 | - logs:DescribeExportTasks 172 | - logs:DescribeLogStreams 173 | - logs:CreateLogGroup 174 | - logs:DeleteMetricFilter 175 | - logs:CancelExportTask 176 | - logs:DescribeMetricFilters 177 | - logs:DeleteSubscriptionFilter 178 | - logs:DescribeResourcePolicies 179 | - logs:DescribeSubscriptionFilters 180 | - logs:GetQueryResults 181 | - logs:DeleteQueryDefinition 182 | - logs:DeleteResourcePolicy 183 | - logs:DeleteLogStream 184 | - logs:CreateExportTask 185 | - logs:DeleteLogDelivery 186 | - logs:DescribeLogGroups 187 | - logs:CreateLogDelivery 188 | - logs:PutDestinationPolicy 189 | - logs:GetLogEvents 190 | - logs:DescribeQueries 191 | - logs:DescribeDestinations 192 | - logs:PutSubscriptionFilter 193 | - logs:DeleteDestination 194 | - logs:TestMetricFilter 195 | - logs:ListTagsLogGroup 196 | Resource: !Sub arn:${AWS::Partition}:s3:::* 197 | - Sid: S3Get 198 | Effect: Allow 199 | Action: 200 | - s3:GetObject 201 | Resource: !Sub 202 | - arn:${AWS::Partition}:s3:::${S3Bucket}/${QSS3KeyPrefix}* 203 | - S3Bucket: !If [ UsingDefaultBucket, !Sub '${QSS3BucketName}-${AWS::Region}', !Ref QSS3BucketName ] 204 | - Sid: S3Put 205 | Effect: Allow 206 | Action: 207 | - s3:PutObject 208 | - s3:DeleteObject 209 | Resource: !Sub arn:${AWS::Partition}:s3:::${LambdaZipsBucket}/* 210 | EmptyBeanstalkSourceBucketCleanup: 211 | Condition: CreateBucketForBeanstalkSource 212 | Properties: 213 | DestBucket: !Ref 'BeanstalkSourceBucket' 214 | ServiceToken: !GetAtt 'S3CleanUpFunction.Arn' 215 | Type: AWS::CloudFormation::CustomResource 216 | LambdaZipsBucket: 217 | Properties: 218 | Tags: [] 219 | VersioningConfiguration: 220 | Status: Enabled 221 | Type: AWS::S3::Bucket 222 | S3CleanUpFunction: 223 | Properties: 224 | Code: 225 | ZipFile: | 226 | import json 227 | import logging 228 | import threading 229 | import boto3 230 | import cfnresponse 231 | 232 | client = boto3.client('s3') 233 | 234 | 235 | def delete_NonVersionedobjects(bucket): 236 | print(("Collecting data from" + bucket)) 237 | paginator = client.get_paginator(list_objects_v2) 238 | result = paginator.paginate(Bucket=bucket) 239 | objects = [] 240 | for page in result: 241 | try: 242 | for k in page[Contents]: 243 | objects.append({Key: k[Key]}) 244 | print("deleting objects") 245 | client.delete_objects(Bucket=bucket, Delete={Objects: 246 | objects}) 247 | objects = [] 248 | except: 249 | pass 250 | print("bucket is already empty") 251 | 252 | def delete_versionedobjects(bucket): 253 | print(("Collecting data from" + bucket)) 254 | paginator = client.get_paginator(list_object_versions) 255 | result = paginator.paginate(Bucket=bucket) 256 | objects = [] 257 | for page in result: 258 | try: 259 | for k in page[Versions]: 260 | objects.append({Key:k[Key],VersionId: k[VersionId]}) 261 | try: 262 | for k in page[DeleteMarkers]: 263 | version = k[VersionId] 264 | key = k[Key] 265 | objects.append({Key: key,VersionId: version}) 266 | except: 267 | pass 268 | print("deleting objects") 269 | client.delete_objects(Bucket=bucket, Delete={Objects: 270 | objects}) 271 | # objects = [] 272 | except: 273 | pass 274 | print("bucket already empty") 275 | 276 | 277 | 278 | def timeout(event, context): 279 | logging.error('Execution is about to time out, sending failure response to CloudFormation') 280 | cfnresponse.send(event, context, cfnresponse.FAILED, {}, None) 281 | 282 | def handler(event, context): 283 | # make sure we send a failure to CloudFormation if the function is going to timeout 284 | timer = threading.Timer((context.get_remaining_time_in_millis() 285 | / 1000.00) - 0.5, timeout, args=[event, context]) 286 | timer.start() 287 | 288 | print(('Received event: %s' % json.dumps(event))) 289 | status = cfnresponse.SUCCESS 290 | try: 291 | dest_bucket = event['ResourceProperties']['DestBucket'] 292 | if event['RequestType'] == 'Delete': 293 | CheckifVersioned = client.get_bucket_versioning(Bucket=dest_bucket) 294 | print(CheckifVersioned) 295 | if 'Status' in CheckifVersioned: 296 | print(CheckifVersioned['Status']) 297 | print ("This is a versioned Bucket") 298 | delete_versionedobjects(dest_bucket) 299 | else: 300 | print("This is not a versioned bucket") 301 | delete_NonVersionedobjects(dest_bucket) 302 | else: 303 | print("Nothing to do") 304 | except Exception as e: 305 | logging.error('Exception: %s' % e, exc_info=True) 306 | status = cfnresponse.FAILED 307 | finally: 308 | timer.cancel() 309 | cfnresponse.send(event, context, status, {}, None) 310 | 311 | 312 | Description: Empty the S3 Buckets while deleting the Stack 313 | Handler: index.handler 314 | Role: !GetAtt 'S3CleanUpRole.Arn' 315 | Runtime: python3.8 316 | Timeout: 240 317 | Type: AWS::Lambda::Function 318 | S3CleanUpRole: 319 | Properties: 320 | AssumeRolePolicyDocument: 321 | Statement: 322 | - Action: sts:AssumeRole 323 | Effect: Allow 324 | Principal: 325 | Service: lambda.amazonaws.com 326 | Version: '2012-10-17' 327 | ManagedPolicyArns: 328 | - !Sub arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole 329 | Path: / 330 | Policies: 331 | - PolicyDocument: 332 | Statement: 333 | - Action: 334 | - s3:PutObject 335 | - s3:DeleteObject 336 | - s3:GetObject 337 | - s3:ListBucket 338 | - s3:ListBucketVersions 339 | - s3:DeleteObjectVersion 340 | - s3:GetObjectVersion 341 | - s3:GetBucketVersioning 342 | Effect: Allow 343 | Resource: !If 344 | - CreateBucketForBeanstalkSource 345 | - - !Sub 'arn:aws:s3:::${CodePipelineArtifactStore}/*' 346 | - !Sub 'arn:aws:s3:::${CodePipelineArtifactStore}' 347 | - !Sub 'arn:aws:s3:::${BeanstalkSourceBucket}/*' 348 | - !Sub 'arn:aws:s3:::${BeanstalkSourceBucket}' 349 | - - !Sub 'arn:aws:s3:::${CodePipelineArtifactStore}/*' 350 | - !Sub 'arn:aws:s3:::*' 351 | Version: '2012-10-17' 352 | PolicyName: lambda-copier 353 | Type: AWS::IAM::Role 354 | Outputs: 355 | BeanstalkSourceBucket: 356 | Condition: CreateBucketForBeanstalkSource 357 | Description: S3 Bucket for the CodePipeline Source Stage for Beanstalk 358 | Value: !Ref 'BeanstalkSourceBucket' 359 | CodePipelineArtifactStore: 360 | Description: S3 Bucket for the CodePipeline Artifcat 361 | Value: !Ref 'CodePipelineArtifactStore' 362 | LambdaZipsBucket: 363 | Description: S3 Bucket for the Lambda Function Code 364 | Value: !Ref 'LambdaZipsBucket' 365 | -------------------------------------------------------------------------------- /templates/codepipeline-stack.template: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Description: CICD Pipeline setup for a cost efficient Elastic Beanstalk Blue-Green (qs-1rt5l9b08) 3 | deployment. 4 | Metadata: 5 | QSLint: 6 | Exclusions: [ W9002, W9003, W9004, W9006 ] 7 | Parameters: 8 | AdministratorEmail: 9 | AllowedPattern: ^[a-z0-9]+(\.[_a-z0-9]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,15})$ 10 | ConstraintDescription: Can contain only ASCII characters. This must be in the 11 | format of username@email.com 12 | Description: >- 13 | Provide an administrator email for Pipeline Manual Approval. SNS subscription 14 | Email will be sent to this address for the Manual Approval Stage. This is mandatory 15 | for the Manual approval Stage of the CodePipelinee 16 | Type: String 17 | BeanstalkApplicationName: 18 | Description: Name of the Beanstalk Application where the Blue Environment exists 19 | Type: String 20 | BeanstalkSourceStageBucket: 21 | Description: Name of the S3 bucket for the Pipeline Source Stage for ElasticBeanstalk 22 | Type: String 23 | BeanstalkSourceStageBucketKey: 24 | Description: CodePipeline Source Stage Bucket key required for the ElasticBeanstalk 25 | deployment 26 | Type: String 27 | BlueEnvironmentName: 28 | Description: Provide the Name of the Beanstalk Environment as Blue Environment. 29 | Type: String 30 | CodePipelineArtifactStore: 31 | Description: CodePipeline Artifact S3 bucket 32 | Type: String 33 | GreenEnvironmentName: 34 | Description: Name of the Green Environment that will be created as a Clone of 35 | the Blue Environment to temporarily route the traffic when the deployment is 36 | going on for the Blue Environment 37 | Type: String 38 | LambdaZipsBucket: 39 | Description: 'Name of the S3 Bucket where the lambda assets are copied ' 40 | Type: String 41 | NameofthePipeline: 42 | AllowedPattern: '[A-Za-z0-9.@\-_]+' 43 | ConstraintDescription: Can contain Only letters, numbers and certain special characters 44 | such as . (period), @ (at sign), - (minus sign), and _ (underscore) 45 | Default: BlueGreenCICDPipeline 46 | Description: Name of the CICDPipeline used for Blue-Green Deployment 47 | MaxLength: '100' 48 | MinLength: '1' 49 | Type: String 50 | QSS3KeyPrefix: 51 | AllowedPattern: ^[0-9a-zA-Z-/]*$ 52 | ConstraintDescription: Quick Start key prefix can include numbers, lowercase letters, 53 | uppercase letters, hyphens (-), and forward slash (/). 54 | Default: quickstart-codepipeline-bluegreen-deployment/ 55 | Description: S3 key prefix for the Quick Start assets. Quick Start key prefix 56 | can include numbers, lowercase letters, uppercase letters, hyphens (-), and 57 | forward slash (/). 58 | Type: String 59 | UrlSwapCodeBuildServerName: 60 | Description: Url swap CodeBuild server name 61 | Type: String 62 | Resources: 63 | BlueGreenCICDPipeline: 64 | Properties: 65 | ArtifactStore: 66 | Location: !Ref 'CodePipelineArtifactStore' 67 | Type: S3 68 | Name: !Ref 'NameofthePipeline' 69 | RoleArn: !GetAtt 'PipelineServiceRole.Arn' 70 | Stages: 71 | - Actions: 72 | - ActionTypeId: 73 | Category: Source 74 | Owner: AWS 75 | Provider: S3 76 | Version: '1' 77 | Configuration: 78 | PollForSourceChanges: 'true' 79 | S3Bucket: !Ref 'BeanstalkSourceStageBucket' 80 | S3ObjectKey: !Ref 'BeanstalkSourceStageBucketKey' 81 | Name: SourceForElasticBeanstalk 82 | OutputArtifacts: 83 | - Name: ElasticBeanstalkPackage 84 | RunOrder: 1 85 | - ActionTypeId: 86 | Category: Source 87 | Owner: AWS 88 | Provider: S3 89 | Version: '1' 90 | Configuration: 91 | PollForSourceChanges: 'false' 92 | S3Bucket: !Ref 'LambdaZipsBucket' 93 | S3ObjectKey: !Sub '${QSS3KeyPrefix}functions/packages/SwapEnvironments/swapenvironments.zip' 94 | Name: SourceForCodeBuildStage 95 | OutputArtifacts: 96 | - Name: UrlSwapPackage 97 | RunOrder: 2 98 | - ActionTypeId: 99 | Category: Source 100 | Owner: AWS 101 | Provider: S3 102 | Version: '1' 103 | Configuration: 104 | PollForSourceChanges: 'false' 105 | S3Bucket: !Ref 'LambdaZipsBucket' 106 | S3ObjectKey: !Sub '${QSS3KeyPrefix}functions/packages/TestBlueEnvironment/testBlueenvironment.zip' 107 | Name: SourceForCodeBuildTestStage 108 | OutputArtifacts: 109 | - Name: BlueEnvTestPackage 110 | RunOrder: 2 111 | Name: SourceForElasticBeanstalk 112 | - Actions: 113 | - ActionTypeId: 114 | Category: Invoke 115 | Owner: AWS 116 | Provider: Lambda 117 | Version: '1' 118 | Configuration: 119 | FunctionName: !Ref 'CreateCloneLambdaFunction' 120 | UserParameters: !Join 121 | - '' 122 | - - '{"BlueEnvName":"' 123 | - !Ref 'BlueEnvironmentName' 124 | - '","GreenEnvName":"' 125 | - !Ref 'GreenEnvironmentName' 126 | - '","BlueCNAMEConfigBucket":"' 127 | - !Ref 'LambdaZipsBucket' 128 | - '","BeanstalkAppName":"' 129 | - !Ref 'BeanstalkApplicationName' 130 | - '","CreateConfigTempName":"BlueEnvConfig' 131 | - '","BlueCNAMEConfigFile":"bluecnameconfig.json' 132 | - '"}' 133 | Name: LambdaFunctionForNewEnvCreation 134 | RunOrder: 1 135 | Name: Lambda 136 | - Actions: 137 | - ActionTypeId: 138 | Category: Approval 139 | Owner: AWS 140 | Provider: Manual 141 | Version: '1' 142 | Configuration: 143 | NotificationArn: !Ref 'ManualApprovalSNSTopic' 144 | InputArtifacts: [] 145 | Name: manualapp 146 | OutputArtifacts: [] 147 | RunOrder: 1 148 | Name: ManualApprovalForUrlSwap 149 | - Actions: 150 | - ActionTypeId: 151 | Category: Test 152 | Owner: AWS 153 | Provider: CodeBuild 154 | Version: '1' 155 | Configuration: 156 | ProjectName: !Ref 'CodeBuildSwapServer' 157 | InputArtifacts: 158 | - Name: UrlSwapPackage 159 | Name: SwapUrlBeanstalk 160 | RunOrder: 1 161 | Name: SwapUrlCodeBuild 162 | - Actions: 163 | - ActionTypeId: 164 | Category: Deploy 165 | Owner: AWS 166 | Provider: ElasticBeanstalk 167 | Version: '1' 168 | Configuration: 169 | ApplicationName: !Ref 'BeanstalkApplicationName' 170 | EnvironmentName: !Ref 'BlueEnvironmentName' 171 | InputArtifacts: 172 | - Name: ElasticBeanstalkPackage 173 | Name: BeanstalkBlueDeploy 174 | RunOrder: 1 175 | Name: DeploytoBlueEnvironment 176 | - Actions: 177 | - ActionTypeId: 178 | Category: Test 179 | Owner: AWS 180 | Provider: CodeBuild 181 | Version: '1' 182 | Configuration: 183 | ProjectName: !Ref 'CodeBuildTestServer' 184 | InputArtifacts: 185 | - Name: BlueEnvTestPackage 186 | Name: BlueEnvTestBeanstalk 187 | RunOrder: 1 188 | Name: BlueEnvTestCodeBuild 189 | - Actions: 190 | - ActionTypeId: 191 | Category: Invoke 192 | Owner: AWS 193 | Provider: Lambda 194 | Version: '1' 195 | Configuration: 196 | FunctionName: !Ref 'TerminateGreenEnvLambdaFunction' 197 | UserParameters: !Join 198 | - '' 199 | - - '{"BlueEnvName":"' 200 | - !Ref 'BlueEnvironmentName' 201 | - '","GreenEnvName":"' 202 | - !Ref 'GreenEnvironmentName' 203 | - '","BlueCNAMEConfigBucket":"' 204 | - !Ref 'LambdaZipsBucket' 205 | - '","BeanstalkAppName":"' 206 | - !Ref 'BeanstalkApplicationName' 207 | - '","CreateConfigTempName":"BlueEnvConfig' 208 | - '","BlueCNAMEConfigFile":"bluecnameconfig.json' 209 | - '"}' 210 | Name: ReswapAndCleanUpGreenEnv 211 | RunOrder: 1 212 | Name: ReswapAndCleanUpGreenEnv 213 | Type: AWS::CodePipeline::Pipeline 214 | BuildServiceRole: 215 | Properties: 216 | AssumeRolePolicyDocument: 217 | Statement: 218 | - Action: sts:AssumeRole 219 | Effect: Allow 220 | Principal: 221 | Service: codebuild.amazonaws.com 222 | Version: '2012-10-17' 223 | Path: / 224 | Policies: 225 | - PolicyDocument: 226 | Statement: 227 | - Action: 228 | - logs:CreateLogGroup 229 | - logs:CreateLogStream 230 | - logs:PutLogEvents 231 | Effect: Allow 232 | Resource: 233 | - !Sub 'arn:${AWS::Partition}:logs:*:*:log-group:*:*' 234 | Sid: CloudWatchLogsPolicy 235 | - Action: 236 | - s3:GetObject 237 | - s3:ListObjects 238 | - s3:GetObjectVersion 239 | Effect: Allow 240 | Resource: 241 | - !Sub 'arn:${AWS::Partition}:s3:::*' 242 | Sid: S3GetObjectPolicy 243 | - Action: 244 | - s3:PutObject 245 | Effect: Allow 246 | Resource: 247 | - !Sub 'arn:${AWS::Partition}:s3:::*' 248 | Sid: S3PutObjectPolicy 249 | - Action: 250 | - elasticbeanstalk:SwapEnvironmentCNAMEs 251 | - elasticbeanstalk:DescribeEnvironmentManagedActionHistory 252 | - elasticbeanstalk:DescribeConfigurationSettings 253 | - elasticbeanstalk:DescribeEvents 254 | - elasticbeanstalk:DescribeEnvironments 255 | - elasticbeanstalk:DescribeEnvironmentHealth 256 | - elasticbeanstalk:DescribeAccountAttributes 257 | - elasticbeanstalk:DescribeEnvironmentManagedActions 258 | - elasticbeanstalk:DescribeApplicationVersion 259 | - elasticbeanstalk:DescribePlatformVersion 260 | - elasticbeanstalk:DescribeInstancesHealth 261 | - elasticbeanstalk:DescribeConfigurationOptions 262 | - elasticbeanstalk:DescribeEnvironmentResources 263 | - elasticbeanstalk:DescribeApplications 264 | - cloudformation:GetTemplate 265 | Effect: Allow 266 | Resource: 267 | - !Sub 'arn:${AWS::Partition}:elasticbeanstalk:::*' 268 | Sid: EBAccess 269 | Version: '2012-10-17' 270 | PolicyName: codebuildpolicy 271 | Type: AWS::IAM::Role 272 | CodeBuildSwapServer: 273 | Properties: 274 | Artifacts: 275 | Type: CODEPIPELINE 276 | Description: 'CodeBuild Server to swap the urls between the Blue and Green Environments ' 277 | Environment: 278 | ComputeType: BUILD_GENERAL1_SMALL 279 | EnvironmentVariables: 280 | - Name: BlueEnvName 281 | Value: !Ref 'BlueEnvironmentName' 282 | - Name: GreenEnvName 283 | Value: !Ref 'GreenEnvironmentName' 284 | - Name: BlueCNAMEConfigBucket 285 | Value: !Ref 'LambdaZipsBucket' 286 | - Name: BlueCNAMEConfigFile 287 | Value: bluecnameconfig.json 288 | Image: aws/codebuild/ubuntu-base:14.04 289 | Type: LINUX_CONTAINER 290 | Name: !Ref UrlSwapCodeBuildServerName 291 | ServiceRole: !GetAtt 'BuildServiceRole.Arn' 292 | Source: 293 | Type: CODEPIPELINE 294 | TimeoutInMinutes: 60 295 | Type: AWS::CodeBuild::Project 296 | CodeBuildTestServer: 297 | Properties: 298 | Artifacts: 299 | Type: CODEPIPELINE 300 | Description: CodeBuild Test Server for the Blue Environment after new deployment 301 | Environment: 302 | ComputeType: BUILD_GENERAL1_SMALL 303 | EnvironmentVariables: 304 | - Name: BlueEnvName 305 | Value: !Ref 'BlueEnvironmentName' 306 | - Name: GreenEnvName 307 | Value: !Ref 'GreenEnvironmentName' 308 | - Name: BlueCNAMEConfigFile 309 | Value: bluecnameconfig.json 310 | Image: aws/codebuild/ubuntu-base:14.04 311 | Type: LINUX_CONTAINER 312 | Name: CICDBlueDeploymentTest 313 | ServiceRole: !GetAtt 'BuildServiceRole.Arn' 314 | Source: 315 | Type: CODEPIPELINE 316 | TimeoutInMinutes: 60 317 | Type: AWS::CodeBuild::Project 318 | CreateCloneLambdaFunction: 319 | Properties: 320 | Code: 321 | S3Bucket: !Ref 'LambdaZipsBucket' 322 | S3Key: !Sub ${QSS3KeyPrefix}functions/packages/CreateEnvironment/creategreenenv.zip 323 | Handler: index.handler 324 | Role: !GetAtt 'LambdaExecutionRole.Arn' 325 | Runtime: python3.7 326 | Timeout: 300 327 | Type: AWS::Lambda::Function 328 | LambdaExecutionRole: 329 | Properties: 330 | AssumeRolePolicyDocument: 331 | Statement: 332 | - Action: 333 | - sts:AssumeRole 334 | Effect: Allow 335 | Principal: 336 | Service: 337 | - lambda.amazonaws.com 338 | Version: '2012-10-17' 339 | ManagedPolicyArns: 340 | - !Sub arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole 341 | - !Sub arn:${AWS::Partition}:iam::aws:policy/AdministratorAccess-AWSElasticBeanstalk 342 | Path: / 343 | Policies: 344 | - PolicyDocument: 345 | Statement: 346 | - Action: 347 | - codepipeline:PutJobSuccessResult 348 | - codepipeline:PutJobFailureResult 349 | Effect: Allow 350 | Resource: '*' 351 | Version: '2012-10-17' 352 | PolicyName: CodePipelinePutSuccessFailurePolicy 353 | Type: AWS::IAM::Role 354 | ManualApprovalSNSTopic: 355 | Properties: 356 | Subscription: 357 | - Endpoint: !Ref 'AdministratorEmail' 358 | Protocol: email 359 | Type: AWS::SNS::Topic 360 | PipelineServiceRole: 361 | Metadata: 362 | cfn-lint: 363 | config: 364 | ignore_checks: 365 | - EIAMPolicyActionWildcard 366 | ignore_reason: 367 | EIAMPolicyActionWildcard: Done by design 368 | Properties: 369 | AssumeRolePolicyDocument: 370 | Statement: 371 | - Action: sts:AssumeRole 372 | Effect: Allow 373 | Principal: 374 | Service: codepipeline.amazonaws.com 375 | Sid: '' 376 | Version: '2012-10-17' 377 | Path: / 378 | Policies: 379 | - PolicyDocument: 380 | Statement: 381 | - Action: 382 | - s3:GetObject 383 | - s3:GetObjectVersion 384 | - s3:GetBucketVersioning 385 | Effect: Allow 386 | Resource: 387 | - !Sub arn:${AWS::Partition}:s3:::codepipeline* 388 | - !Sub arn:${AWS::Partition}:s3:::elasticbeanstalk* 389 | - Action: 390 | - s3:PutObject 391 | Effect: Allow 392 | Resource: 393 | - !Sub arn:${AWS::Partition}:s3:::codepipeline* 394 | - !Sub arn:${AWS::Partition}:s3:::elasticbeanstalk* 395 | - Action: 396 | - elasticbeanstalk:* 397 | - ec2:* 398 | - elasticloadbalancing:* 399 | - autoscaling:* 400 | - cloudformation:* 401 | - cloudwatch:* 402 | - sns:* 403 | - rds:* 404 | - sqs:* 405 | - ecs:* 406 | - iam:PassRole 407 | Effect: Allow 408 | Resource: 409 | - !Sub arn:${AWS::Partition}:s3:::codepipeline* 410 | - !Sub arn:${AWS::Partition}:s3:::elasticbeanstalk* 411 | - Action: 412 | - lambda:InvokeFunction 413 | - lambda:ListFunctions 414 | Effect: Allow 415 | Resource: 416 | - !Sub arn:${AWS::Partition}:s3:::codepipeline* 417 | - !Sub arn:${AWS::Partition}:s3:::elasticbeanstalk* 418 | - Action: 419 | - codebuild:BatchGetBuilds 420 | - codebuild:StartBuild 421 | Effect: Allow 422 | Resource: 423 | - !Sub arn:${AWS::Partition}:s3:::codepipeline* 424 | - !Sub arn:${AWS::Partition}:s3:::elasticbeanstalk* 425 | Version: '2012-10-17' 426 | PolicyName: codepipelinepolicy 427 | Type: AWS::IAM::Role 428 | TerminateGreenEnvLambdaFunction: 429 | Properties: 430 | Code: 431 | S3Bucket: !Ref 'LambdaZipsBucket' 432 | S3Key: !Sub '${QSS3KeyPrefix}functions/packages/TerminateandReSwap/terminategreenenv.zip' 433 | Handler: index.handler 434 | Role: !GetAtt 'LambdaExecutionRole.Arn' 435 | Runtime: python3.7 436 | Timeout: 300 437 | Type: AWS::Lambda::Function 438 | -------------------------------------------------------------------------------- /templates/bluegreen-deployment-master.template: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Description: CICD Pipeline setup for a cost efficient Elastic Beanstalk Blue-Green 3 | deployment (qs-1odpn28j4). 4 | Metadata: 5 | QSLint: 6 | Exclusions: [ W9002, W9003, W9004, W9006 ] 7 | cfn-lint: 8 | config: 9 | ignore_checks: 10 | - E0002 11 | AWS::CloudFormation::Interface: 12 | ParameterGroups: 13 | - Label: 14 | default: AWS Elastic Beanstalk configuration 15 | Parameters: 16 | - BeanstalkSourceStageS3BucketName 17 | - BeanstalkSourceStageS3BucketKey 18 | - ExistingBlueEnvironmentName 19 | - ExistingBeanstalkApplicationName 20 | - GreenEnvironmentName 21 | - Label: 22 | default: AWS CodePipeline parameters 23 | Parameters: 24 | - AdministratorEmail 25 | - NameofthePipeline 26 | - UrlSwapCodeBuildServerName 27 | - Label: 28 | default: Git2s3 setup parameters. Valid only when GitToS3integration parameter 29 | is set to true. Ignore otherwise. 30 | Parameters: 31 | - GitToS3integration 32 | - CustomDomainName 33 | - ApiSecret 34 | - AllowedIps 35 | - Label: 36 | default: AWS Quick Start Configuration 37 | Parameters: 38 | - QSS3BucketName 39 | - QSS3BucketRegion 40 | - QSS3KeyPrefix 41 | ParameterLabels: 42 | AdministratorEmail: 43 | default: Admin Email Address 44 | AllowedIps: 45 | default: Allowed IPs 46 | ApiSecret: 47 | default: API Secret 48 | BeanstalkSourceStageS3BucketKey: 49 | default: Beanstalk Source Stage S3 Bucket key 50 | BeanstalkSourceStageS3BucketName: 51 | default: Beanstalk Source Stage S3 Bucket 52 | CustomDomainName: 53 | default: Custom Domain Name 54 | ExistingBeanstalkApplicationName: 55 | default: Existing Beanstalk Application Name 56 | ExistingBlueEnvironmentName: 57 | default: Existing Blue Environment Name 58 | GitToS3integration: 59 | default: Git to S3 integration 60 | GreenEnvironmentName: 61 | default: Green Environment Name 62 | NameofthePipeline: 63 | default: Name of the Pipeline 64 | QSS3BucketName: 65 | default: Quick Start S3 Bucket Name 66 | QSS3BucketRegion: 67 | default: Quick Start S3 bucket region 68 | QSS3KeyPrefix: 69 | default: Quick Start S3 Key Prefix 70 | UrlSwapCodeBuildServerName: 71 | default: Url Swap CodeBuild Server Name 72 | Conditions: 73 | CreateBeanstalkStack: !Or 74 | - !Condition 'CreateNewBeanstalkEnv' 75 | - !Condition 'CreateNewBeanstalkApp' 76 | CreateBucketForBeanstalkSource: !And 77 | - !Equals 78 | - !Ref 'BeanstalkSourceStageS3BucketName' 79 | - '' 80 | - !Not 81 | - !Equals 82 | - !Ref 'GitToS3integration' 83 | - 'true' 84 | CreateGittoS3Integration: !Equals 85 | - !Ref 'GitToS3integration' 86 | - 'true' 87 | CreateNewBeanstalkApp: !Equals 88 | - !Ref 'ExistingBeanstalkApplicationName' 89 | - '' 90 | CreateNewBeanstalkEnv: !Equals 91 | - !Ref 'ExistingBlueEnvironmentName' 92 | - '' 93 | GovCloudCondition: !Equals 94 | - !Ref 'AWS::Region' 95 | - us-gov-west-1 96 | UsingDefaultBucket: !Equals [!Ref QSS3BucketName, 'aws-quickstart'] 97 | Mappings: 98 | SampleBeantalkparameters: 99 | php: 100 | NewBlueEnvironmentName: BlueEnvironment 101 | NewBeanstalkApplicationName: BlueGreenBeanstalkApplication 102 | SolutionStackForNewBeanstalkEnv: 64bit Amazon Linux 2 v3.5.0 running PHP 8.0 103 | AppPackageS3Bucket: elasticbeanstalk-samples 104 | AppPackageS3key: php-sample.zip 105 | Parameters: 106 | AdministratorEmail: 107 | AllowedPattern: ^[a-z0-9]+(\.[_a-z0-9]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,15})$ 108 | ConstraintDescription: Can contain only ASCII characters. This must be in the 109 | format of something@email.com 110 | Description: The administrator email address for the manual approval stage in 111 | the pipeline. The Amazon SNS subscription email will be sent to this address. 112 | Type: String 113 | AllowedIps: 114 | Default: 131.103.20.160/27,165.254.145.0/26,104.192.143.0/24 115 | Description: >- 116 | (Optional) This applies only to the gitpull method. This is a comma-separated 117 | list of IP CIDR blocks for source IP authentication. Bitbucket Cloud IP ranges 118 | are provided as defaults. Provide this value only when the GitToS3integration 119 | parameter is set to true. 120 | Type: String 121 | ApiSecret: 122 | Default: '' 123 | Description: >- 124 | (Optional) This applies only to the git pull method. WebHook Secrets for use 125 | with GitHub Enterprise and GitLab. If a secret is matched IP range authentication 126 | is bypassed. Cannot contain: comma, backward slash, and double quotes.Provide 127 | this value only when the GitToS3integration parameter is set to true. 128 | NoEcho: 'true' 129 | Type: String 130 | BeanstalkSourceStageS3BucketKey: 131 | Default: '' 132 | Description: >- 133 | The path to the Elastic Beanstalk application source package (in .zip format) 134 | that will trigger the source stage in the pipeline. If the GitToS3integration 135 | parameter is set to true, this parameter is the S3 bucket key where the Git 136 | webhook will place the zip file as input to the source stage in the pipeline. 137 | The key should be in the format git-user/git-repository/git-user_git-repository.zip. 138 | This value differs from one Git repo to another. For more information, see the 139 | deployment steps in the Git Webhooks with AWS Services Quick Start deployment 140 | guide. 141 | Type: String 142 | BeanstalkSourceStageS3BucketName: 143 | Default: '' 144 | Description: >- 145 | (Optional) The S3 bucket for the source stage of the pipeline that AWS CodePipeline 146 | uses to pull the application package. If the GitToS3integration parameter value 147 | is set to false and if this value is left blank, a bucket will be created. If 148 | a bucket name is provided, that will be the bucket CodePipeline will look in 149 | to get the application source package. If the GitToS3integration parameter value 150 | is set to true, a new bucket will be created with this name to put the source 151 | package (zip file). If left blank, a bucket name will be automatically generated. 152 | Provide this value only when the GitToS3integration parameter is set to true. 153 | Type: String 154 | CustomDomainName: 155 | Default: '' 156 | Description: >- 157 | (Optional) Use a custom domain name for the webhook endpoint. If left blank, 158 | API Gateway will create a domain name for you. Provide this value only when 159 | the GitToS3integration parameter is set to true. 160 | Type: String 161 | ExistingBeanstalkApplicationName: 162 | Default: '' 163 | Description: >- 164 | (Optional) Required if the parameter ExistingBlueEnvironmentName is provided. 165 | Give the name of the existing Elastic Beanstalk application where the existing 166 | Elastic Beanstalk environment is running. Leaving this value blank creates a 167 | new sample application. You must provide a value for this parameter if you provide 168 | a value for ExistingBlueEnvironmentName. 169 | Type: String 170 | ExistingBlueEnvironmentName: 171 | Default: '' 172 | Description: >- 173 | (Optional) The name of the Elastic Beanstalk environment that’s designated as 174 | the blue environment. Leave this value blank, if you want to create a new sample 175 | environment with the PHP solution stack. Otherwise, provide a value to use for 176 | blue-green deployment. 177 | Type: String 178 | GitToS3integration: 179 | AllowedValues: 180 | - 'true' 181 | - 'false' 182 | Default: 'false' 183 | Description: >- 184 | Select true if you want to set up Git to S3 integration. If not, leave the default 185 | value as false. This will allow you to use an existing Git repository when deploying 186 | an application to Elastic Beanstalk. 187 | Type: String 188 | GreenEnvironmentName: 189 | Default: GreenEnvironment 190 | Description: >- 191 | The name of the green environment, which will be the clone of the blue environment. 192 | Traffic will be routed temporarily to the green environment, until the blue 193 | environment is finished with the deployment and testing. After successful deployment 194 | to the blue environment, traffic will be routed back to the blue environment, 195 | and the green environment will be terminated. 196 | Type: String 197 | NameofthePipeline: 198 | AllowedPattern: '[A-Za-z0-9.@\-_]+' 199 | ConstraintDescription: Can contain Only letters, numbers and certain special characters 200 | such as . (period), @ (at sign), - (hyphen), and _ (underscore) 201 | Default: BlueGreenCICDPipeline 202 | Description: The name of the CI/CD pipeline used in the blue-green deployment. 203 | MaxLength: '100' 204 | MinLength: '1' 205 | Type: String 206 | QSS3BucketName: 207 | AllowedPattern: ^[0-9a-zA-Z]+([0-9a-zA-Z-]*[0-9a-zA-Z])*$ 208 | ConstraintDescription: Quick Start bucket name can include numbers, lowercase 209 | letters, uppercase letters, and hyphens (-). It cannot start or end with a hyphen 210 | (-). 211 | Default: aws-quickstart 212 | Description: S3 bucket name for the Quick Start assets. Quick Start bucket name 213 | can include numbers, lowercase letters, uppercase letters, and hyphens (-). 214 | It cannot start or end with a hyphen (-). 215 | Type: String 216 | QSS3BucketRegion: 217 | Default: 'us-east-1' 218 | Description: 'The AWS Region where the Quick Start S3 bucket (QSS3BucketName) is hosted. When using your own bucket, you must specify this value.' 219 | Type: String 220 | QSS3KeyPrefix: 221 | AllowedPattern: ^[0-9a-zA-Z-/]*$ 222 | ConstraintDescription: Quick Start key prefix can include numbers, lowercase letters, 223 | uppercase letters, hyphens (-), and forward slash (/). 224 | Default: quickstart-codepipeline-bluegreen-deployment/ 225 | Description: S3 key prefix for the Quick Start assets. Quick Start key prefix 226 | can include numbers, lowercase letters, uppercase letters, hyphens (-), and 227 | forward slash (/). 228 | Type: String 229 | UrlSwapCodeBuildServerName: 230 | Default: 'CICDurlSwap' 231 | Description: Url swap CodeBuild server name 232 | Type: String 233 | Rules: 234 | CheckforBeanstalkSourceBucketKey: 235 | RuleCondition: !Equals 236 | - '' 237 | - !Ref 'BeanstalkSourceStageS3BucketKey' 238 | Assertions: 239 | - Assert: !Not 240 | - !Equals 241 | - '' 242 | - !Ref 'BeanstalkSourceStageS3BucketKey' 243 | AssertDescription: Parameter 'BeanstalkSourceStageS3BucketKey' requires a 244 | value 245 | Resources: 246 | GittoS3IntegrationStack: 247 | Condition: CreateGittoS3Integration 248 | Type: AWS::CloudFormation::Stack 249 | Properties: 250 | TemplateURL: 251 | !Sub 252 | - 'https://${S3Bucket}.s3.${S3Region}.${AWS::URLSuffix}/${QSS3KeyPrefix}submodules/quickstart-git2s3/templates/git2s3.template.yaml' 253 | - S3Region: !If [UsingDefaultBucket, !Ref 'AWS::Region', !Ref QSS3BucketRegion] 254 | S3Bucket: !If [UsingDefaultBucket, !Sub '${QSS3BucketName}-${AWS::Region}', !Ref QSS3BucketName] 255 | Parameters: 256 | AllowedIps: !Ref 'AllowedIps' 257 | ApiSecret: !Ref 'ApiSecret' 258 | CustomDomainName: !Ref 'CustomDomainName' 259 | OutputBucketName: !Ref 'BeanstalkSourceStageS3BucketName' 260 | BeanstalkSampleApplicationStack: 261 | Condition: CreateBeanstalkStack 262 | Type: AWS::CloudFormation::Stack 263 | Properties: 264 | TemplateURL: 265 | !Sub 266 | - 'https://${S3Bucket}.s3.${S3Region}.${AWS::URLSuffix}/${QSS3KeyPrefix}templates/elasticbeanstalk-sample.template' 267 | - S3Region: !If [UsingDefaultBucket, !Ref 'AWS::Region', !Ref QSS3BucketRegion] 268 | S3Bucket: !If [UsingDefaultBucket, !Sub '${QSS3BucketName}-${AWS::Region}', !Ref QSS3BucketName] 269 | Parameters: 270 | ExistingBlueEnvironmentName: !Ref 'ExistingBlueEnvironmentName' 271 | ExistingBeanstalkApplicationName: !Ref 'ExistingBeanstalkApplicationName' 272 | NewBlueEnvironmentName: !FindInMap 273 | - SampleBeantalkparameters 274 | - php 275 | - NewBlueEnvironmentName 276 | GreenEnvironmentName: !Ref 'GreenEnvironmentName' 277 | NewBeanstalkApplicationName: !FindInMap 278 | - SampleBeantalkparameters 279 | - php 280 | - NewBeanstalkApplicationName 281 | SolutionStackForNewBeanstalkEnv: !FindInMap 282 | - SampleBeantalkparameters 283 | - php 284 | - SolutionStackForNewBeanstalkEnv 285 | AppPackageS3Bucket: !FindInMap 286 | - SampleBeantalkparameters 287 | - php 288 | - AppPackageS3Bucket 289 | AppPackageS3key: !FindInMap 290 | - SampleBeantalkparameters 291 | - php 292 | - AppPackageS3key 293 | CopyFunctiontoS3BucketStack: 294 | Type: AWS::CloudFormation::Stack 295 | Properties: 296 | TemplateURL: 297 | !Sub 298 | - 'https://${S3Bucket}.s3.${S3Region}.${AWS::URLSuffix}/${QSS3KeyPrefix}templates/copyfunction-to-s3bucket.template' 299 | - S3Region: !If [UsingDefaultBucket, !Ref 'AWS::Region', !Ref QSS3BucketRegion] 300 | S3Bucket: !If [UsingDefaultBucket, !Sub '${QSS3BucketName}-${AWS::Region}', !Ref QSS3BucketName] 301 | Parameters: 302 | QSS3BucketName: !Ref 'QSS3BucketName' 303 | #QSS3BucketRegion: !Ref 'QSS3BucketRegion' 304 | QSS3KeyPrefix: !Ref 'QSS3KeyPrefix' 305 | GitToS3integration: !Ref 'GitToS3integration' 306 | BeanstalkSourceStageS3BucketName: !Ref 'BeanstalkSourceStageS3BucketName' 307 | CodePipelineStack: 308 | Type: AWS::CloudFormation::Stack 309 | Properties: 310 | TemplateURL: 311 | !Sub 312 | - 'https://${S3Bucket}.s3.${S3Region}.${AWS::URLSuffix}/${QSS3KeyPrefix}templates/codepipeline-stack.template' 313 | - S3Region: !If [UsingDefaultBucket, !Ref 'AWS::Region', !Ref QSS3BucketRegion] 314 | S3Bucket: !If [UsingDefaultBucket, !Sub '${QSS3BucketName}-${AWS::Region}', !Ref QSS3BucketName] 315 | Parameters: 316 | AdministratorEmail: !Ref 'AdministratorEmail' 317 | NameofthePipeline: !Ref 'NameofthePipeline' 318 | QSS3KeyPrefix: !Ref 'QSS3KeyPrefix' 319 | LambdaZipsBucket: !GetAtt 'CopyFunctiontoS3BucketStack.Outputs.LambdaZipsBucket' 320 | BlueEnvironmentName: !If 321 | - CreateNewBeanstalkEnv 322 | - !GetAtt 'BeanstalkSampleApplicationStack.Outputs.BeanstalkEnvironment' 323 | - !Ref 'ExistingBlueEnvironmentName' 324 | GreenEnvironmentName: !Ref 'GreenEnvironmentName' 325 | BeanstalkApplicationName: !If 326 | - CreateNewBeanstalkApp 327 | - !FindInMap 328 | - SampleBeantalkparameters 329 | - php 330 | - NewBeanstalkApplicationName 331 | - !Ref 'ExistingBeanstalkApplicationName' 332 | BeanstalkSourceStageBucketKey: !Ref 'BeanstalkSourceStageS3BucketKey' 333 | BeanstalkSourceStageBucket: !If 334 | - CreateGittoS3Integration 335 | - !GetAtt 'GittoS3IntegrationStack.Outputs.OutputBucketName' 336 | - !If 337 | - CreateBucketForBeanstalkSource 338 | - !GetAtt 'CopyFunctiontoS3BucketStack.Outputs.BeanstalkSourceBucket' 339 | - !Ref 'BeanstalkSourceStageS3BucketName' 340 | CodePipelineArtifactStore: !GetAtt 'CopyFunctiontoS3BucketStack.Outputs.CodePipelineArtifactStore' 341 | UrlSwapCodeBuildServerName: !Ref 'UrlSwapCodeBuildServerName' 342 | Outputs: 343 | NewBeanstalkEnvEndPointUrl: 344 | Condition: CreateNewBeanstalkEnv 345 | Description: New Beanstalk Environment Endpoint URL 346 | Value: !Join 347 | - '' 348 | - - http:// 349 | - !GetAtt 'BeanstalkSampleApplicationStack.Outputs.BeanstalkEnvEndPointUrl' 350 | CustomDomainNameCNAME: 351 | Condition: CreateGittoS3Integration 352 | Description: One of the Git2S3Integration Output 353 | Value: !GetAtt 'GittoS3IntegrationStack.Outputs.CustomDomainNameCNAME' 354 | PublicSSHKey: 355 | Condition: CreateGittoS3Integration 356 | Description: One of the Git2S3Integration Output 357 | Value: !GetAtt 'GittoS3IntegrationStack.Outputs.PublicSSHKey' 358 | GitPullWebHookApi: 359 | Condition: CreateGittoS3Integration 360 | Description: One of the Git2S3Integration Output 361 | Value: !GetAtt 'GittoS3IntegrationStack.Outputs.GitPullWebHookApi' 362 | ZipDownloadWebHookApi: 363 | Condition: CreateGittoS3Integration 364 | Description: One of the Git2S3Integration Output 365 | Value: !GetAtt 'GittoS3IntegrationStack.Outputs.ZipDownloadWebHookApi' 366 | GittoS3IntegrationOutputBucketName: 367 | Condition: CreateGittoS3Integration 368 | Description: One of the Git2S3Integration Output 369 | Value: !GetAtt 'GittoS3IntegrationStack.Outputs.OutputBucketName' 370 | CodePipelineName: 371 | Description: Name of the Pipeline 372 | Value: !Ref 'NameofthePipeline' 373 | BlueEnvironmentName: 374 | Description: Name of the Blue Environment 375 | Value: !If 376 | - CreateNewBeanstalkEnv 377 | - !GetAtt 'BeanstalkSampleApplicationStack.Outputs.BeanstalkEnvironment' 378 | - !Ref 'ExistingBlueEnvironmentName' 379 | GreenEnvironmentName: 380 | Description: Name of the Green Environment 381 | Value: !Ref 'GreenEnvironmentName' 382 | BeanstalkSourceBucketName: 383 | Description: Name of the bucket where the application code should be uploaded 384 | for the Elastic Beanstalk application in the CodePipeline Source Stage 385 | Value: !If 386 | - CreateGittoS3Integration 387 | - !GetAtt 'GittoS3IntegrationStack.Outputs.OutputBucketName' 388 | - !If 389 | - CreateBucketForBeanstalkSource 390 | - !GetAtt 'CopyFunctiontoS3BucketStack.Outputs.BeanstalkSourceBucket' 391 | - !Ref 'BeanstalkSourceStageS3BucketName' 392 | --------------------------------------------------------------------------------