Skip to content

Commit

Permalink
Add rollback feature
Browse files Browse the repository at this point in the history
  • Loading branch information
caiovfernandes committed Jun 25, 2023
1 parent 25b53a4 commit 9ae856e
Show file tree
Hide file tree
Showing 6 changed files with 402 additions and 254 deletions.
191 changes: 111 additions & 80 deletions src/clone_blue_environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,88 +2,119 @@
import logging
import time

# noqa: E502


def main(BLUE_ENV_NAME, GREEN_ENV_NAME, BEANSTALK_APP_NAME, S3_ARTIFACTS_BUCKET, boto_authenticated_client):
beanstalkclient = boto_authenticated_client.client('elasticbeanstalk',region_name='ap-southeast-2')
s3client = boto_authenticated_client.client('s3',region_name='ap-southeast-2')

blue_env_info=get_blue_env_info(beanstalkclient, BLUE_ENV_NAME)
blue_env_id=(blue_env_info['Environments'][0]['EnvironmentId'])
blue_version_label=(blue_env_info['Environments'][0]['VersionLabel'])

#Calling CreateConfigTemplate API
config_template=create_config_template(beanstalkclient, AppName=(BEANSTALK_APP_NAME),blue_env_id=blue_env_id,TempName="BlueEnvConfig")
ReturnedTempName=config_template
if not ReturnedTempName:
#raise Exception if the Config file does not exist
raise Exception("There were some issue while creating a Configuration Template from the Blue Environment")
else:
green_env_id, did_new_env_was_created = create_green_environment(beanstalkclient, GREEN_ENV_NAME, ReturnedTempName, blue_version_label, BEANSTALK_APP_NAME)

# wait_green_be_ready(beanstalkclient, GREEN_ENV_NAME)

print("Green environment ID: " + green_env_id)
if green_env_id and did_new_env_was_created:
#Create a CNAME Config file
BlueEnvCname=(blue_env_info['Environments'][0]['CNAME'])
BlueEnvCnameFile = {'BlueEnvUrl': BlueEnvCname}
file_name = "blue_green_assets/blue_cname.json"
response = s3client.put_object(Bucket=S3_ARTIFACTS_BUCKET, Key=file_name, Body=json.dumps(BlueEnvCnameFile))

print("Created a new CNAME file at S3")

beanstalkclient = boto_authenticated_client.client(
'elasticbeanstalk', region_name='us-east-1')
s3client = boto_authenticated_client.client(
's3', region_name='us-east-1')


blue_env_info = get_env_info(beanstalkclient, BLUE_ENV_NAME)
blue_env_id = blue_env_info['Environments'][0]['EnvironmentId']
blue_version_label = blue_env_info['Environments'][0]['VersionLabel']

# Calling CreateConfigTemplate API
config_template = create_config_template(beanstalkclient, AppName=(
BEANSTALK_APP_NAME), blue_env_id=blue_env_id, TempName="BlueEnvConfig")
ReturnedTempName = config_template
if not ReturnedTempName:
# raise Exception if the Config file does not exist
raise Exception(
"There were some issue while creating a Configuration Template from the Blue Environment")
else:
green_env_id, did_new_env_was_created = create_green_environment(
beanstalkclient, GREEN_ENV_NAME,
ReturnedTempName, blue_version_label,
BEANSTALK_APP_NAME
)

# wait_green_be_ready(beanstalkclient, GREEN_ENV_NAME)

print("Green environment ID: " + green_env_id)
if green_env_id and did_new_env_was_created:
# Create a CNAME Config file
blue_env_cname = blue_env_info['Environments'][0]['CNAME']
blue_env_cname_file = {'BlueEnvUrl': blue_env_cname}
file_name = "blue_green_assets/blue_cname.json"
response = s3client.put_object(
Bucket=S3_ARTIFACTS_BUCKET, Key=file_name, Body=json.dumps(blue_env_cname_file))

print("Created a new CNAME file at S3")


def create_config_template(beanstalkclient, AppName, blue_env_id, TempName):
ListTemplates = beanstalkclient.describe_applications(ApplicationNames=[AppName])['Applications'][0]['ConfigurationTemplates']
count = 0
while count < len(ListTemplates):
if ListTemplates[count] == TempName:
print ("Configuration template already exists")
return TempName
count += 1
response = beanstalkclient.create_configuration_template(
ApplicationName=AppName,
TemplateName=TempName,
EnvironmentId=blue_env_id)
return response['TemplateName']

def get_blue_env_info(beanstalkclient, env_name):
response = beanstalkclient.describe_environments(
EnvironmentNames=[
env_name
])
return response

def create_green_environment(beanstalkclient, env_name,config_template,AppVersion,AppName):
did_new_env_was_created = True
response = (beanstalkclient.describe_environments(EnvironmentNames=[env_name]))
InvalidStatus = ["Terminating","Terminated"]
GetEnvData = [item for item in response['Environments'] if item['Status'] not in InvalidStatus]
if not(GetEnvData==[]):
did_new_env_was_created = False
if not(GetEnvData[0]['Status']) in InvalidStatus:
print("Environment already exists")
print(f"Existing Environment - {env_name} - it is in a Valid Status: {GetEnvData[0]['Status']}")
return (GetEnvData[0]['EnvironmentId']), did_new_env_was_created
print ("Creating a new Environment")
response = beanstalkclient.create_environment(
ApplicationName=AppName,
EnvironmentName=env_name,
TemplateName=config_template,
VersionLabel=AppVersion)
return response['EnvironmentId'], did_new_env_was_created
'''Creates a ElasticBeanstalk deployment template and return the Template Name'''
ListTemplates = beanstalkclient.describe_applications(
ApplicationNames=[AppName])['Applications'][0]['ConfigurationTemplates']
count = 0
while count < len(ListTemplates):
if ListTemplates[count] == TempName:
print("Configuration template already exists")
return TempName
count += 1
response = beanstalkclient.create_configuration_template(
ApplicationName=AppName,
TemplateName=TempName,
EnvironmentId=blue_env_id)
return response['TemplateName']


def get_env_info(beanstalkclient, env_name):
''' Get an beanstalk environment description by its name '''
response = beanstalkclient.describe_environments(
EnvironmentNames=[
env_name
])
return response


def create_green_environment(beanstalkclient, env_name, config_template, app_version, app_name):
''' Create a new elastic beansatalk environment based on a Environment Template'''
did_new_env_was_created = True
response = (beanstalkclient.describe_environments(
EnvironmentNames=[env_name]))
InvalidStatus = ["Terminating", "Terminated"]
GetEnvData = [item for item in response['Environments']
if item['Status'] not in InvalidStatus]
if not (GetEnvData == []):
did_new_env_was_created = False
if not (GetEnvData[0]['Status']) in InvalidStatus:
print("Environment already exists")
print(
f"Existing Environment - {env_name} - it is in a Valid Status: {GetEnvData[0]['Status']}")
return (GetEnvData[0]['EnvironmentId']), did_new_env_was_created
print("Creating a new Environment")
response = beanstalkclient.create_environment(
ApplicationName=app_name,
EnvironmentName=env_name,
TemplateName=config_template,
VersionLabel=app_version)
return response['EnvironmentId'], did_new_env_was_created


def wait_green_be_ready(beanstalkclient, GREEN_ENV_NAME):
green_env_info = get_green_env_info(beanstalkclient, GREEN_ENV_NAME)
while green_env_info["Environments"][0]["Status"] != "Ready":
print("Waiting the blue environment be Ready!")
time.sleep(10)
green_env_info = get_green_env_info(beanstalkclient, GREEN_ENV_NAME)

def get_green_env_info(beanstalkclient, env_name):
response = beanstalkclient.describe_environments(
EnvironmentNames=[
env_name
])
return response

def timeout(event):
logging.error('Execution is about to time out, sending failure response to CodePipeline')
''' Stop code execution until an Beanstalk Environment gets in the Ready status'''
green_env_info = get_env_info(beanstalkclient, GREEN_ENV_NAME)
while green_env_info["Environments"][0]["Status"] != "Ready":
print("Waiting the blue environment be Ready!")
time.sleep(10)
green_env_info = get_env_info(beanstalkclient, GREEN_ENV_NAME)


def rollback_created_env(boto_authenticated_client, environment_name):
''' Terminate a beanstalk environment'''
beanstalkclient = boto_authenticated_client.client(
'elasticbeanstalk', region_name='us-east-1')

green_env_info = get_env_info(beanstalkclient, environment_name)
if len(green_env_info["Environments"]) == 0:
return "Environment terminated successfully!"
beanstalkclient.terminate_environment(
EnvironmentName=environment_name,
EnvironmentId=green_env_info["Environments"][0]["EnvironmentId"]
)
return "Environment terminaated successfully!!"
35 changes: 16 additions & 19 deletions src/deploy_release.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import os
from time import strftime, sleep
from botocore.exceptions import ClientError



def main(BUCKET_KEY, S3_ARTIFACTS_BUCKET, BLUE_ENV_NAME, BEANSTALK_APP_NAME, boto_authenticated_client):
VERSION_LABEL = strftime("%Y%m%d%H%M%S")
try:
Expand All @@ -13,15 +11,14 @@ def main(BUCKET_KEY, S3_ARTIFACTS_BUCKET, BLUE_ENV_NAME, BEANSTALK_APP_NAME, bot
return False

if not create_new_version(beanstalkclient, VERSION_LABEL, BUCKET_KEY, S3_ARTIFACTS_BUCKET, BEANSTALK_APP_NAME):
raise Exception("Create new version.")
raise Exception("Failed to create beanstalk release.")

wait_until_env_be_ready(beanstalkclient, BLUE_ENV_NAME)
# Wait for the new version to be consistent before deploying
if not deploy_new_version(beanstalkclient, BEANSTALK_APP_NAME, BLUE_ENV_NAME, VERSION_LABEL):
raise Exception("Failed to deploy new version.")



def create_new_version(beanstalkclient, VERSION_LABEL, BUCKET_KEY, S3_ARTIFACTS_BUCKET, BEANSTALK_APP_NAME):
"""
Creates a new application version in AWS Elastic Beanstalk
Expand Down Expand Up @@ -52,6 +49,7 @@ def create_new_version(beanstalkclient, VERSION_LABEL, BUCKET_KEY, S3_ARTIFACTS_
print(str(err))
return False


def deploy_new_version(beanstalkclient, BEANSTALK_APP_NAME, BLUE_ENV_NAME, VERSION_LABEL):
"""
Deploy a new version to AWS Elastic Beanstalk
Expand All @@ -66,24 +64,23 @@ def deploy_new_version(beanstalkclient, BEANSTALK_APP_NAME, BLUE_ENV_NAME, VERSI
print("Failed to update environment.\n" + str(err))
return False

print(response)
print("The new version was deployed successfully!")
print(f"New version environment URL: http://{response['EnvironmentName']}.elasticbeanstalk.com")
return True


def wait_until_env_be_ready(beanstalkclient, ENV_NAME):
env_info = get_env_info(beanstalkclient, ENV_NAME)
while env_info["Environments"][0]["Status"] != "Ready":
print("Waiting the blue environment be Ready!")
sleep(5)
env_info = get_env_info(beanstalkclient, ENV_NAME)
return "Env is ready"
while env_info["Environments"][0]["Status"] != "Ready":
print("Waiting the blue environment be Ready!")
sleep(5)
env_info = get_env_info(beanstalkclient, ENV_NAME)
return "Env is ready"


def get_env_info(beanstalkclient, env_name):
response = beanstalkclient.describe_environments(
EnvironmentNames=[
env_name
])
return response

if __name__ == "__main__":
main()
response = beanstalkclient.describe_environments(
EnvironmentNames=[
env_name
])
return response
Loading

0 comments on commit 9ae856e

Please sign in to comment.