This post will describe the configuration used to implement CICD using Bitbucket and AWS CodeDeploy
First create your bitbucket repository and code. For this example I will use one of the advent of code tests adventofcode.com
AWS & Bitbucket Code
In the newly created bitbucket repository create these 3 files at the top layer. The first is specific to this exercise the other two are generic and could be used in other repositories.
appspec.yml
version: 0.0 os: linux files: - source: / destination: /tmp owner: ec2-user mode: 777 # - source: index.html # destination: /var/www/html hooks: BeforeInstall: - location: Day4/scripts/before_install.sh timeout: 300 runas: ec2-user AfterInstall: - location: Day4/scripts/after_install.sh timeout: 300 runas: ec2-user ApplicationStart: - location: Day4/scripts/application_start.sh timeout: 300 runas: ec2-user
bitbucket-pipelines.yml
image: python:3.8.1 pipelines: branches: master: - step: script: - apt-get update # required to install zip - apt-get install -y zip # required for packaging up the application - pip install boto3==1.3.0 # required for codedeploy_deploy.py - zip -r /tmp/artifact.zip * # package up the application for deployment - python codedeploy_deploy.py # run the deployment script variables: AWS_DEFAULT_REGION: $AWS_DEFAULT_REGION AWS_ACCESS_KEY_ID: $AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY: $AWS_SECRET_ACCESS_KEY APPLICATION_NAME: $APPLICATION_NAME DEPLOYMENT_CONFIG: $DEPLOYMENT_CONFIG DEPLOYMENT_GROUP_NAME: $DEPLOYMENT_GROUP_NAME S3_BUCKET: $S3_BUCKET IGNORE_APPLICATION_STOP_FAILURES: 'true' FILE_EXISTS_BEHAVIOR: 'OVERWRITE'
codedeploy_deploy.py
# 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 http://aws.amazon.com/apache2.0/ # 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. """ try again and again A BitBucket Builds template for deploying an application revision to AWS CodeDeploy narshiva@amazon.com v1.0.0 """ from __future__ import print_function import os import sys from time import strftime, sleep import boto3 from botocore.exceptions import ClientError VERSION_LABEL = strftime("%Y%m%d%H%M%S") BUCKET_KEY = os.getenv('APPLICATION_NAME') + '/' + VERSION_LABEL + \ '-bitbucket_builds.zip' def upload_to_s3(artifact): """ Uploads an artifact to Amazon S3 """ try: client = boto3.client('s3') except ClientError as err: print("Failed to create boto3 client.\n" + str(err)) return False try: client.put_object( Body=open(artifact, 'rb'), Bucket=os.getenv('S3_BUCKET'), Key=BUCKET_KEY ) except ClientError as err: print("Failed to upload artifact to S3.\n" + str(err)) return False except IOError as err: print("Failed to access artifact.zip in this directory.\n" + str(err)) return False print("Success - upload artifact to S3.") return True def deploy_new_revision(): """ Deploy a new application revision to AWS CodeDeploy Deployment Group """ try: client = boto3.client('codedeploy') except ClientError as err: print("Failed to create boto3 client.\n" + str(err)) return False try: response = client.create_deployment( applicationName=str(os.getenv('APPLICATION_NAME')), deploymentGroupName=str(os.getenv('DEPLOYMENT_GROUP_NAME')), revision={ 'revisionType': 'S3', 's3Location': { 'bucket': os.getenv('S3_BUCKET'), 'key': BUCKET_KEY, 'bundleType': 'zip' } }, deploymentConfigName=str(os.getenv('DEPLOYMENT_CONFIG')), description='New deployment from BitBucket', ignoreApplicationStopFailures=True ) except ClientError as err: print("002 Failed to deploy application revision.\n" + str(err)) print("002 Failed to deploy application revision.\n" + str(deploymentGroupName)) print("002 Failed to deploy application revision.\n" + str(applicationName)) return False """ Wait for deployment to complete """ while 1: try: deploymentResponse = client.get_deployment( deploymentId=str(response['deploymentId']) ) deploymentStatus=deploymentResponse['deploymentInfo']['status'] if deploymentStatus == 'Succeeded': print ("Deployment Succeeded") return True elif (deploymentStatus == 'Failed') or (deploymentStatus == 'Stopped') : print ("Deployment Failed") return False elif (deploymentStatus == 'InProgress') or (deploymentStatus == 'Queued') or (deploymentStatus == 'Created'): continue except ClientError as err: print("001 Failed to deploy application revision.\n" + str(err)) return False return True def main(): if not upload_to_s3('/tmp/artifact.zip'): sys.exit(1) if not deploy_new_revision(): sys.exit(1) if __name__ == "__main__": main()
Application code
Under the bitbucket repository create the directory Day4.
Under the Day4 directory create the following file
first.py
A = 402328 B = 864247 # # Answer from Jonathan Paulson # poss = 0 for pwd in range(A, B+1): digits = [int(C) for C in str(pwd)] dble = any( digits[x] == digits[x+1] for x in range(5)) nouse = any( digits[x] > digits[x+1] for x in range(5)) if dble and not nouse: poss += 1 print('TOTALS ',poss)
Under the Day4 directory create a directory named “scripts”
Under the Day4/scripts directory create the following 3 files
before_install.sh
#!/bin/bash #This will ensure the environment is ready for us sudo yum update sudo yum install nodejs-legacy -y sudo yum install npm -y sudo npm install forever -g #Log the fact this script has run for debugging purposes echo "BEFORE" > ~/one.log
after_install.sh
#log the fact this script has run for debugging purposes echo "AFTER" > ~/two.log
application_start.sh
#!/bin/bash #Stop all servers and start the server #forever stopall #forever start /home/ec2-user/my-app1/app.js python first.py > ~/firstP.log #log the fact this script has run for debugging purposes echo "APPLICATION START" > ~/three.log