ecsDeploy
ecsDeploy.py
Deploy a new task definition to an existing ECS Cluster/Service
NOTE 1: This is NOT blue/green. Look at ecsBlueGreenDeploy.py
NOTE 2: This will check if the clusterArn/serviceArn are NOT aws arns and instead
use them as ssm parameter names to grab the values
tag: String (Optional) - Will use release.get_version()
as default
clusterArn: String (Optional) Will use ECS_CLUSTER_ARN from os.environ as default
serviceArn: String (Optional) Will use ECS_SERVICE_ARN from os.environ as default
1#!/usr/bin/env python3 2""" 3ecsDeploy.py 4 5Deploy a new task definition to an existing ECS Cluster/Service 6 7NOTE 1: This is NOT blue/green. Look at `ecsBlueGreenDeploy.py` 8NOTE 2: This will check if the clusterArn/serviceArn are NOT aws arns and instead 9 use them as ssm parameter names to grab the values 10 11tag: String (Optional) - Will use `release.get_version()` as default 12clusterArn: String (Optional) Will use ECS_CLUSTER_ARN from os.environ as default 13serviceArn: String (Optional) Will use ECS_SERVICE_ARN from os.environ as default 14""" 15from utils import aws, release 16import argparse 17import os 18import sys 19 20if __name__ == "__main__": 21 print("ecsDeploy.__main__(): BEGIN") 22 23 # 24 # ArgParse 25 # 26 parser = argparse.ArgumentParser(description='Deploy a new task definition to an existing ECS Cluster/Service') 27 28 parser.add_argument( 29 '-t', 30 '--tag', 31 action='store', 32 type=str, 33 required=False, 34 default=release.get_version(), 35 help='container tag: Defaults to aws.get_version()') 36 37 parser.add_argument( 38 '-C', 39 '--cluster', 40 action='store', 41 type=str, 42 required=False, 43 default=os.environ.get('ECS_CLUSTER_ARN', None), 44 help='Cluster ARN to deploy container into. Defaults to ENV ECS_CLUSTER_ARN') 45 46 parser.add_argument( 47 '-s', 48 '--service', 49 action='store', 50 type=str, 51 required=False, 52 default=os.environ.get('ECS_SERVICE_ARN', None), 53 help='Service ARN to deploy container into. Defaults to ENV ECS_SERVICE_ARN') 54 55 args = parser.parse_args() 56 57 _TAG = args.tag 58 _CLUSTER_ARN = args.cluster 59 _SERVICE_ARN = args.service 60 61 if _TAG is None or _CLUSTER_ARN is None or _SERVICE_ARN is None: 62 sys.exit("ecsDeploy(): Tage, Cluster or Service is None. Please ensure arguments or environment variables are set.") 63 64 """ 65 If the _CLUSTER_ARN or _SERVICE_ARN are not in ARN format, consider them SSM Param names 66 and use them to grab the ARNS out of SSM Params 67 """ 68 _CLUSTER = _CLUSTER_ARN if ':' in _CLUSTER_ARN else aws.ssm_get_parameter(name=_CLUSTER_ARN) 69 _SERVICE = _SERVICE_ARN if ':' in _SERVICE_ARN else aws.ssm_get_parameter(name=_SERVICE_ARN) 70 71 """ 72 go get the entire task definition for a service by name (might need the cluster too) 73 """ 74 print("ecsDeploy(): Looking up latest task definition for cluster/service") 75 current_task_definition_arn = aws.ecs_get_latest_task_definition_arn(cluster=_CLUSTER, service=_SERVICE) 76 print("ecsDeploy(): Storing the entire current task definition for rollback") 77 current_task_definition = aws.ecs_get_task_definition_from_arn(task_def_arn=current_task_definition_arn) 78 79 """ 80 This iterates through all current_task_definition.containers 81 then for each container -> iterate through container.secrets 82 for each secret -> find one where the key is "VERSION" 83 if found, return the value which will be an ssm param arn 84 """ 85 version_ssm_param_arn = aws.ecs_get_version_param_name_from_task_def(task_def=current_task_definition) 86 87 """ 88 Get the currently deployed version number 89 """ 90 old_version = aws.ssm_get_parameter(name=version_ssm_param_arn) 91 92 """ 93 set the new version provided by the caller 94 """ 95 new_version = _TAG 96 97 """ 98 This iterates over the containers again to set 99 the new image in the container where 100 we simply get the old image and replace the :{tag} 101 before: docker.devops.rekor.io/blue/api:12345 102 after: docker.devops.rekor.io/blue/api:$newVersion 103 """ 104 new_task_definition = aws.ecs_set_new_image_in_task_def(task_def=current_task_definition, version=new_version) 105 106 """ 107 Go register the next task def 108 there should now be a new version of the task def 109 """ 110 new_task_definition_arn = aws.ecs_register_task_definition_revision(task_def=new_task_definition) 111 112 """ 113 update the ssm param with the new tag. 114 This function should fail gracefully as not all appilcations use an SSM param 115 to store its version. Scout uses the git commit hash for version awareness. 116 """ 117 aws.ssm_put_parameter(name=version_ssm_param_arn, value=_TAG) 118 119 """ 120 deploy new task def to the service 121 """ 122 aws.ecs_deploy_new_task_definition(cluster=_CLUSTER, service=_SERVICE, task_def_arn=new_task_definition_arn) 123 124 deploy_status = aws.ecs_wait_services_stable(cluster=_CLUSTER, service=_SERVICE) 125 if not deploy_status: 126 print("ecsDeploy(): Deploy FAILED! Rolling back to original task def!") 127 # Roll back procedures by rolling back the version param and setting the service back to the original task def 128 aws.ssm_put_parameter(name=version_ssm_param_arn, value=old_version) 129 aws.ecs_deploy_new_task_definition(cluster=_CLUSTER, service=_SERVICE, task_def_arn=current_task_definition_arn) 130 deploy_status = aws.ecs_wait_services_stable(cluster=_CLUSTER, service=_SERVICE) 131 if not deploy_status: 132 sys.exit("ecsDeploy(): Rolling back to original task def failed!") 133 134 aws.ecs_deregister_task_def(task_def=new_task_definition_arn) 135 sys.exit("ecsDeploy(): Deploy Failed! Rolled back to original task def.") 136 137 print("ecsDeploy(): Deploy Successful") 138 139 sys.exit(0)