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