def __init__(self, environment): self.environment = environment environment_configuration = EnvironmentConfiguration( self.environment ) environment_configuration.update_config() self.configuration = environment_configuration.get_config()[self.environment] self.cluster_name = get_cluster_name(environment) self.client = get_client_for('cloudformation', self.environment)
def get_region_for_environment(environment): if environment: return EnvironmentConfiguration(environment).get_config()[environment]['region'] else: # Get the region from the AWS credentials used to execute cloudlift aws_session = boto3.session.Session() return aws_session.region_name
def get_environment_level_alb_listener(environment): env_spec = EnvironmentConfiguration(environment).get_config()[environment] if 'loadbalancer_listener_arn' not in env_spec: raise UnrecoverableException('environment level ALB not defined. ' + 'Please run update_environment and set "loadbalancer_listener_arn".') return env_spec['loadbalancer_listener_arn']
def get_ssl_certification_for_environment(environment): try: return EnvironmentConfiguration( environment ).get_config()[environment]['environment']["ssl_certificate_arn"] except KeyError: raise UnrecoverableException("Unable to find ssl certificate for {environment}".format(**locals()))
def test_get_config(self): self.setup_existing_params() store_object = EnvironmentConfiguration('dummy-staging') response = store_object.get_config() assert response == { "dummy-staging": { "cluster": { "instance_type": "m5.xlarge", "key_name": "staging-cluster-v3", "max_instances": 10, "min_instances": 5 }, "environment": { "notifications_arn": "arn:aws:sns:ap-south-1:725827686899:non-prod-mumbai", "ssl_certificate_arn": "arn:aws:acm:ap-south-1:725827686899:certificate/380232d3-d868-4ce3-a43d-211cdfd39d26" }, "region": "ap-south-1", "vpc": { "cidr": "10.30.0.0/16", "nat-gateway": { "elastic-ip-allocation-id": "eipalloc-05f2599c8bd8d3d28" }, "subnets": { "private": { "subnet-1": { "cidr": "10.30.4.0/22" }, "subnet-2": { "cidr": "10.30.12.0/22" } }, "public": { "subnet-1": { "cidr": "10.30.0.0/22" }, "subnet-2": { "cidr": "10.30.8.0/22" } } } } } }
def get_notifications_arn_for_environment(environment): try: return EnvironmentConfiguration(environment).get_config( )[environment]['environment']["notifications_arn"] except KeyError: log_err("Unable to find notifications arn for {environment}".format( **locals())) exit(1)
def get_region_for_environment(environment): global local_cache if 'region' not in local_cache: if environment: local_cache['region'] = EnvironmentConfiguration(environment).get_config()[environment]['region'] else: # Get the region from the AWS credentials used to execute cloudlift aws_session = boto3.session.Session() local_cache['region'] = aws_session.region_name return local_cache['region']
def get_service_templates_bucket_for_environment(environment): global local_cache if 'bucket' not in local_cache: config = EnvironmentConfiguration(environment).get_config() if 'service_templates_bucket' not in config[environment]: return None local_cache['bucket'] = config[environment]['service_templates_bucket'] return local_cache['bucket']
class EnvironmentCreator(object): def __init__(self, environment): self.environment = environment self.environment_configuration = EnvironmentConfiguration( self.environment) self.environment_configuration.update_config() self.configuration = self.environment_configuration.get_config()[ self.environment] self.cluster_name = get_cluster_name(environment) self.client = get_client_for('cloudformation', self.environment) self.key_name = self.configuration['cluster']['key_name'] def run(self): try: log("Check if stack already exists for " + self.cluster_name) environment_stack = self.client.describe_stacks( StackName=self.cluster_name)['Stacks'][0] log(self.cluster_name + " stack exists. ID: " + environment_stack['StackId']) log_err("Cannot create environment with duplicate name: " + self.cluster_name) except Exception: log(self.cluster_name + " stack does not exist. Creating new stack.") # When creating a cluster, desired_instance count is same # as min_instance count environment_stack_template_body = ClusterTemplateGenerator( self.environment, self.configuration).generate_cluster() self.existing_events = get_stack_events(self.client, self.cluster_name) environment_stack = self.client.create_stack( StackName=self.cluster_name, TemplateBody=environment_stack_template_body, Parameters=[{ 'ParameterKey': 'KeyPair', 'ParameterValue': self.key_name, }, { 'ParameterKey': 'Environment', 'ParameterValue': self.environment, }], OnFailure='DO_NOTHING', Capabilities=['CAPABILITY_NAMED_IAM'], ) log_bold("Submitted to cloudformation. Checking progress...") self.__print_progress() log_bold(self.cluster_name + " stack created. ID: " + environment_stack['StackId']) def run_update(self, update_ecs_agents): if update_ecs_agents: self.__run_ecs_container_agent_udpate() try: log("Initiating environment stack update.") # self.environment_configuration.update_cloudlift_version() environment_stack_template_body = ClusterTemplateGenerator( self.environment, self.configuration, self.__get_desired_count()).generate_cluster() log("Template generation complete.") change_set = create_change_set(self.client, environment_stack_template_body, "TemplateBody", self.cluster_name, self.key_name, self.environment) self.existing_events = get_stack_events(self.client, self.cluster_name) log_bold("Executing changeset. Checking progress...") if change_set is None: return self.client.execute_change_set( ChangeSetName=change_set['ChangeSetId']) self.__print_progress() except ClientError as e: log_err("No updates are to be performed") except Exception as e: raise e # log_err("Something went wrong") # TODO: Describe error here. def __get_desired_count(self): try: auto_scaling_client = get_client_for('autoscaling', self.environment) cloudformation_client = get_client_for('cloudformation', self.environment) cfn_resources = cloudformation_client.list_stack_resources( StackName=self.cluster_name) auto_scaling_group_name = list( filter( lambda x: x['ResourceType' ] == "AWS::AutoScaling::AutoScalingGroup", cfn_resources['StackResourceSummaries']) )[0]['PhysicalResourceId'] response = auto_scaling_client.describe_auto_scaling_groups( AutoScalingGroupNames=[auto_scaling_group_name]) return response['AutoScalingGroups'][0]['DesiredCapacity'] except Exception as err: raise err raise UnrecoverableException( "Unable to fetch desired instance count. {}".format(err)) def __print_progress(self): while True: response = self.client.describe_stacks(StackName=self.cluster_name) if "IN_PROGRESS" not in response['Stacks'][0]['StackStatus']: break all_events = get_stack_events(self.client, self.cluster_name) print_new_events(all_events, self.existing_events) self.existing_events = all_events sleep(5) log_bold("Finished and Status: %s" % (response['Stacks'][0]['StackStatus'])) def __run_ecs_container_agent_udpate(self): log("Initiating agent update") ecs_client = get_client_for('ecs', self.environment) response = ecs_client.list_container_instances( cluster=self.cluster_name) container_instance_arns = response['containerInstanceArns'] for container_instance_arn in response['containerInstanceArns']: try: response = ecs_client.update_container_agent( cluster=self.cluster_name, containerInstance=container_instance_arn) except ClientError as exception: if "There is no update available for your container agent." in str( exception): log("There is no update available for your container agent " + container_instance_arn) elif "Agent update is already in progress." in str(exception): log("Agent update is already in progress " + container_instance_arn) else: raise exception while True: sleep(1) response = ecs_client.describe_container_instances( cluster=self.cluster_name, containerInstances=container_instance_arns) update_statuses = map( lambda x: { "arn": x['containerInstanceArn'], "status": x.get('agentUpdateStatus', 'UPDATED') }, response['containerInstances']) finished = True status_string = '\r' for status in update_statuses: status_string += status['arn'] + ":\033[92m" + \ status['status'] + " \033[0m" if status['status'] != 'UPDATED': finished = False sys.stdout.write(status_string) sys.stdout.flush() if finished: print("") break
def test_get_all_environments(self): self.setup_existing_params() store_object = EnvironmentConfiguration('dummy-staging') response = store_object.get_all_environments() assert response == ['dummy-staging', 'random-environment']
def test_initialization(self): self.setup_existing_params() store_object = EnvironmentConfiguration('dummy-staging') assert store_object.environment == 'dummy-staging' assert store_object.table is not None