Bitbucket & CodeDeploy P2

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