def get_export_value(self, param=None, fully_qualified_param_name=None): if not fully_qualified_param_name: fully_qualified_param_name = f"{self.stack_name}-{param}" if len(self.exports) == 0: self._load_export_values() val = self.exports.get(fully_qualified_param_name, None) if val is None: print_utility.warn(f"Could not locate export value - {fully_qualified_param_name}") return val
def _get_cluster_stack_export_value(cf, deploy_ctx, param): # type: (CloudFormationBuddy,DeployContext) -> str val = None try: cf.stack_name = deploy_ctx.cluster_stack_name val = cf.get_export_value(param) except Exception as e: print_utility.warn( "Exception getting export for helper function - {}".format(e)) finally: return val
def validate(self): self.print_template_description() self.print_known_parameters() self.print_export() config_files = self.get_rendered_config_files() if len(config_files) == 0: print_utility.warn("No Configuration Files") else: print_utility.warn("Configuration Files:") for config_file in config_files: self._print_file(config_file)
def requires_update(self): if not self.new_image: print_utility.warn("Checking for ECS update without registering new image ") return False if not self.ecs_task_family: print_utility.warn("No ECS Task family found - assuming first deploy of stack and skipping ECS update") return False self._describe_task_definition() existing = pydash.get(self.task_definition_description, "containerDefinitions[0].image") print_utility.info(f"ECS task existing image - {existing}") print_utility.info(f"ECS task desired image - {self.new_image}") return self.run_task or existing != self.new_image
def _load_monitor_definition(artifact_directory): artifact_def_path = os.path.join(artifact_directory, _ARTIFACT_FILE) if os.path.exists(artifact_def_path): print_utility.info( "Defining artifact definition with monitor.json - {}".format( artifact_def_path)) with open(artifact_def_path, 'r') as art_def: return json.load(art_def) else: print_utility.warn( "Monitor definition (monitor.json) did not exist in artifact directory." " Continuing infrastructure update without monitor deploy.") return None
def _search_for_legacy_implementation(artifact_directory): image_definition = os.path.join(artifact_directory, "containerurl.txt") ret = {_ARTIFACT_TYPE: _CONTAINER_ARTIFACT_TYPE} if os.path.exists(image_definition): print_utility.warn( "Defining ECS service udpate with deprecated containerurl.txt artifact" ) with open(image_definition, 'r') as image: image_def = image.read().strip() rfind = image_def.rfind(":") ret[_ARTIFACT_LOCATION] = image_def[:rfind] ret[_ARTIFACT_IDENTIFIER] = image_def[rfind + 1:] return ret return None
def _internal_deploy(self, dry_run): self.ecs_buddy.set_container_image(self.artifact_location, self.artifact_id) if dry_run: print_utility.warn( f"[Dry Run] ECS Deploy intends to: {self.ecs_buddy.what_is_your_plan()}" ) return None if self.ecs_buddy.requires_update(): self.ecs_buddy.perform_update() print_utility.progress(self.ecs_buddy.what_is_your_plan()) return True else: print_utility.progress( f"ECS does not require update - {self.artifact_location}:{self.artifact_id}" ) return False
def _print_stack_events(self): events = [] res = self.client.describe_stack_events(StackName=self.stack_name) res_list = res['StackEvents'] while res_list is not None: events.extend(res_list) next_ = res.get('NextToken', None) if next_: res = self.client.describe_stack_events(StackName=self.stack_name, NextToken=next_) res_list = res['StackEvents'] else: res_list = None for ev in events: if "ResourceStatusReason" in ev: template = "{Timestamp}\t{ResourceStatus}\t{ResourceType}\t{LogicalResourceId}\t{ResourceStatusReason}" else: template = "{Timestamp}\t{ResourceStatus}\t{ResourceType}\t{LogicalResourceId}" print_utility.warn(template.format(**ev))
def do_command(deploy_ctx, service_template_directory=None, service_type=None, destination=None): # type: (DeployContext,[str or None],str) -> str if service_template_directory is None: print_utility.warn( "Service template directory was not provided. Assuming service-type '{}' is built-in.".format( service_type)) template = deploy_ctx.template_manager.get_known_template(template_name=service_type) deploy = CloudFormationDeploy(stack_name=deploy_ctx.stack_name, template=template, deploy_ctx=deploy_ctx) else: deploy = CloudFormationDeploy(stack_name=deploy_ctx.stack_name, template=NamedLocalTemplate(service_template_directory), deploy_ctx=deploy_ctx) return ServiceDefinition.save_to_file(application=deploy_ctx.application, role=deploy_ctx.role, deploy_params=deploy.get_default_params(), known_service_modifications=deploy_ctx.template_manager.get_service_modifications_for_service(service_type) , service_type=service_type, destination=destination)
def _initalize_defaults(self, defaults, environment): self['DATADOG_KEY'] = "" self['ENVIRONMENT'] = environment.lower() if environment else "dev" if defaults: self.update(defaults) self.update(os.environ) if 'REGION' not in self: print_utility.warn( "Region not configured using default 'us-west-1'. " "This is probably not what you want - N. California is slow, like real slow." " Set the environment variable 'REGION' or pass a default configuration file to override. " ) self['REGION'] = 'us-west-1' self.template_manager = TemplateManager( self.get_deploy_templates(), self.get_service_modification_templates()) self.stack_name_cache = [] if self.get('DATADOG_KEY', '') != '': self.notifier = DataDogNotifier(key=self['DATADOG_KEY'], deploy_context=self) else: self.notifier = None
def _internal_deploy(self, dry_run): # Initialize our buddies s3 = CloudFormationDeployS3Buddy(self.deploy_ctx) cloud_formation = CloudFormationBuddy(self.deploy_ctx) if dry_run: self.validate() return # Upload our template to s3 to make things a bit easier and keep a record template_file_url = s3.upload(file=(self.template_file)) # Upload all of our config files to S3 rendering any variables config_files = self.get_rendered_config_files() for rendered in config_files: s3.upload(file=rendered) # render our parameter files parameter_file_rendered = self.get_rendered_param_file() # see if we are updating or creating if cloud_formation.should_create_change_set(): cloud_formation.create_change_set( template_file_url=template_file_url, parameter_file=parameter_file_rendered) # make sure it is available and that there are no special conditions if cloud_formation.should_execute_change_set(): print_utility.progress( "Updating existing stack with ChangeSet - {}".format( self.stack_name)) cloud_formation.execute_change_set() else: print_utility.warn("No computed changes for stack - {}".format( self.stack_name)) # if there are no changes then clean up and exit cloud_formation.delete_change_set() return else: print_utility.progress("Creating new stack - {}".format( self.stack_name)) cloud_formation.create_stack( template_file_url=template_file_url, parameter_file=parameter_file_rendered)
def print_self(self): print_utility.warn("Context:") print_utility.warn("Stack: {}".format(self.stack_name)) if len(self.stack_name_cache) > 0: print_utility.warn("Depth: {}".format(self.stack_name_cache)) if self.current_deploy: print_utility.banner_info("Deploy Defaults:", pformat(self.current_deploy.defaults)) print_utility.banner_info("Environment:", pformat(self))
def _print_info(self, errors): for key, errs in errors.items(): print_utility.warn(pformat(key, indent=4)) print_utility.banner(pformat(errs, indent=8))
def _print_file(self, config_file): with open(config_file, 'r') as cf: print_utility.warn(os.path.basename(config_file)) for line in cf.readlines(): print_utility.banner(line)
def notify_event(self, title, type, message=None): if self.notifier: self.notifier.notify_event(title, type, message) else: print_utility.warn("Notify {type}: {title} - {message}".format( type=type, title=title, message=message))