def test_create_stack_calls_cloudformation_api_properly_with_service_role(self, _, cloudformation_mock): stack = Mock(spec=CloudFormationStack) stack.name = "stack-name" stack.get_parameters_list.return_value = [('a', 'b')] stack.get_tags_list.return_value = [('any-tag', 'any-tag-value')] stack.parameters = {} stack.template = Mock(spec=CloudFormationTemplate) stack.template.name = "template-name" stack.template.get_template_json.return_value = {'key': 'value'} stack.service_role = "arn:aws:iam::1234567890:role/my-role" stack.stack_policy = None stack.failure_action = None stack.disable_rollback = False stack.timeout = 42 cfn = CloudFormation() cfn.create_stack(stack) cloudformation_mock.return_value.create_stack.assert_called_once_with( Capabilities=['CAPABILITY_IAM', 'CAPABILITY_NAMED_IAM'], Parameters=[('a', 'b')], StackName='stack-name', Tags=[('any-tag', 'any-tag-value')], TemplateBody={'key': 'value'}, RoleARN="arn:aws:iam::1234567890:role/my-role" )
def test_create_stack_calls_cloudformation_api_properly_with_stack_policy(self, _, cloudformation_mock): stack = Mock(spec=CloudFormationStack) stack.name = "stack-name" stack.get_parameters_list.return_value = [('a', 'b')] stack.get_tags_list.return_value = [('any-tag', 'any-tag-value')] stack.parameters = {} stack.template = Mock(spec=CloudFormationTemplate) stack.template.name = "template-name" stack.template.get_template_json.return_value = {'key': 'value'} stack.service_role = None stack.stack_policy = "{foo:baa}" stack.timeout = 42 cfn = CloudFormation() cfn.create_stack(stack) cloudformation_mock.return_value.create_stack.assert_called_once_with( Capabilities=['CAPABILITY_IAM', 'CAPABILITY_NAMED_IAM'], OnFailure='ROLLBACK', Parameters=[('a', 'b')], StackName='stack-name', Tags=[('any-tag', 'any-tag-value')], TemplateBody={'key': 'value'}, StackPolicyBody='"{foo:baa}"' )
def test_create_stack_calls_cloudformation_api_properly_with_disable_rollback_true(self, _, cloudformation_mock): stack = Mock(spec=CloudFormationStack) stack.name = "stack-name" stack.get_parameters_list.return_value = [('a', 'b')] stack.get_tags_list.return_value = [('any-tag', 'any-tag-value')] stack.parameters = {} stack.template = Mock(spec=CloudFormationTemplate) stack.template.name = "template-name" stack.template.get_template_json.return_value = {'key': 'value'} stack.service_role = None stack.stack_policy = "{foo:baa}" stack.failure_action = "DO_NOTHING" stack.disable_rollback = "True" stack.timeout = 42 cfn = CloudFormation() cfn.create_stack(stack) cloudformation_mock.return_value.create_stack.assert_called_once_with( Capabilities=['CAPABILITY_IAM', 'CAPABILITY_NAMED_IAM'], OnFailure='DO_NOTHING', DisableRollback=True, Parameters=[('a', 'b')], StackName='stack-name', Tags=[('any-tag', 'any-tag-value')], TemplateBody={'key': 'value'}, StackPolicyBody='"{foo:baa}"' )
class StackActionHandler(object): def __init__(self, config): self.logger = get_logger(root=True) self.config = config self.cfn = CloudFormation(region=self.config.region) self.parameter_resolver = ParameterResolver(region=self.config.region) self.cli_parameters = config.cli_params def create_or_update_stacks(self): existing_stacks = self.cfn.get_stack_names() desired_stacks = self.config.stacks stack_processing_order = DependencyResolver().get_stack_order(desired_stacks) if len(stack_processing_order) > 1: self.logger.info( "Will process stacks in the following order: {0}".format(", ".join(stack_processing_order))) for stack_name in stack_processing_order: stack_config = self.config.stacks.get(stack_name) raw_template = FileLoader.get_file_from_url(stack_config.template_url, stack_config.working_dir) template = CloudFormationTemplateTransformer.transform_template(raw_template) parameters = self.parameter_resolver.resolve_parameter_values(stack_config.parameters, stack_name) merged_parameters = self.parameter_resolver.update_parameters_with_cli_parameters( parameters=parameters, cli_parameters=self.cli_parameters, stack_name=stack_name) stack = CloudFormationStack(template=template, parameters=merged_parameters, tags=self.config.tags, name=stack_name, region=self.config.region, timeout=stack_config.timeout) if stack_name in existing_stacks: self.cfn.validate_stack_is_ready_for_action(stack) self.cfn.update_stack(stack) else: self.cfn.create_stack(stack) CustomResourceHandler.process_post_resources(stack) def delete_stacks(self): existing_stacks = self.cfn.get_stack_names() stacks = self.config.stacks stack_processing_order = DependencyResolver().get_stack_order(stacks) stack_processing_order.reverse() self.logger.info("Will delete stacks in the following order: {0}".format(", ".join(stack_processing_order))) for stack_name in stack_processing_order: if stack_name in existing_stacks: stack = CloudFormationStack(None, None, stack_name, None, None) self.cfn.validate_stack_is_ready_for_action(stack) self.cfn.delete_stack(stack) else: self.logger.info("Stack {0} is already deleted".format(stack_name))
def test_create_stack_calls_wait_properly(self, wait_mock, _a, _b): stack = Mock(spec=CloudFormationStack) stack.name = "stack-name" stack.get_parameters_list.return_value = [] stack.parameters = {} stack.template = Mock(spec=CloudFormationTemplate) stack.template.name = "template-name" stack.timeout = 42 cfn = CloudFormation() cfn.create_stack(stack) wait_mock.assert_called_once_with(stack.name, 'create', stack.timeout)
def test_create_stack_calls_cloudformation_api_properly(self, _, cloudformation_mock): stack = Mock(spec=CloudFormationStack) stack.name = "stack-name" stack.get_parameters_list.return_value = [('a', 'b')] stack.tags = [('any-tag', 'any-tag-value')] stack.parameters = {} stack.template = Mock(spec=CloudFormationTemplate) stack.template.name = "template-name" stack.template.get_template_json.return_value = {'key': 'value'} stack.timeout = 42 cfn = CloudFormation() cfn.create_stack(stack) cloudformation_mock.return_value.create_stack.assert_called_once_with('stack-name', capabilities=['CAPABILITY_IAM'], parameters=[('a', 'b')], tags=[('any-tag', 'any-tag-value')], template_body={'key': 'value'})
def test_create_stack_calls_cloudformation_api_properly( self, _, cloudformation_mock): stack = Mock(spec=CloudFormationStack) stack.name = "stack-name" stack.get_parameters_list.return_value = [('a', 'b')] stack.tags = [('any-tag', 'any-tag-value')] stack.parameters = {} stack.template = Mock(spec=CloudFormationTemplate) stack.template.name = "template-name" stack.template.get_template_json.return_value = {'key': 'value'} stack.timeout = 42 cfn = CloudFormation() cfn.create_stack(stack) cloudformation_mock.return_value.create_stack.assert_called_once_with( 'stack-name', capabilities=['CAPABILITY_IAM'], parameters=[('a', 'b')], tags=[('any-tag', 'any-tag-value')], template_body={'key': 'value'})
class StackActionHandler(object): def __init__(self, config): self.logger = get_logger(root=True) self.config = config self.cfn = CloudFormation(region=self.config.region) self.parameter_resolver = ParameterResolver(region=self.config.region) self.cli_parameters = config.cli_params def create_or_update_stacks(self): existing_stacks = self.cfn.get_stack_names() desired_stacks = self.config.stacks stack_processing_order = DependencyResolver().get_stack_order( desired_stacks) if len(stack_processing_order) > 1: self.logger.info( "Will process stacks in the following order: {0}".format( ", ".join(stack_processing_order))) for stack_name in stack_processing_order: stack_config = self.config.stacks.get(stack_name) if stack_config.stack_policy_url: self.logger.info("Using stack policy from {0}".format( stack_config.stack_policy_url)) stack_policy = FileLoader.get_yaml_or_json_file( stack_config.stack_policy_url, stack_config.working_dir) else: stack_policy = None template = TemplateHandler.get_template(stack_config.template_url, stack_config.working_dir) parameters = self.parameter_resolver.resolve_parameter_values( stack_name, stack_config, self.cli_parameters) stack = CloudFormationStack( template=template, parameters=parameters, tags=stack_config.tags, name=stack_name, region=self.config.region, timeout=stack_config.timeout, service_role=stack_config.service_role, stack_policy=stack_policy, failure_action=stack_config.failure_action) if stack_name in existing_stacks: self.cfn.validate_stack_is_ready_for_action(stack) self.cfn.update_stack(stack) else: self.cfn.create_stack(stack) def delete_stacks(self): existing_stacks = self.cfn.get_stack_names() stacks = self.config.stacks stack_processing_order = DependencyResolver().get_stack_order(stacks) stack_processing_order.reverse() self.logger.info( "Will delete stacks in the following order: {0}".format( ", ".join(stack_processing_order))) for stack_name in stack_processing_order: stack_config = self.config.stacks.get(stack_name) if stack_name in existing_stacks: stack = CloudFormationStack( None, None, stack_name, None, None, service_role=stack_config.service_role) self.cfn.validate_stack_is_ready_for_action(stack) self.cfn.delete_stack(stack) else: self.logger.info( "Stack {0} is already deleted".format(stack_name))
class StackActionHandler(object): def __init__(self, config): self.logger = get_logger(root=True) self.config = config self.cfn = CloudFormation(region=self.config.region) self.parameter_resolver = ParameterResolver(region=self.config.region) self.cli_parameters = config.cli_params def create_or_update_stacks(self): existing_stacks = self.cfn.get_stack_names() desired_stacks = self.config.stacks stack_processing_order = DependencyResolver().get_stack_order(desired_stacks) if len(stack_processing_order) > 1: self.logger.info( "Will process stacks in the following order: {0}".format(", ".join(stack_processing_order)) ) for stack_name in stack_processing_order: stack_config = self.config.stacks.get(stack_name) if stack_config.stack_policy_url: self.logger.info("Using stack policy from {0}".format(stack_config.stack_policy_url)) stack_policy = FileLoader.get_yaml_or_json_file(stack_config.stack_policy_url, stack_config.working_dir) else: stack_policy = None template = TemplateHandler.get_template(stack_config.template_url, stack_config.working_dir) parameters = self.parameter_resolver.resolve_parameter_values(stack_name, stack_config, self.cli_parameters) stack = CloudFormationStack( template=template, parameters=parameters, tags=stack_config.tags, name=stack_name, region=self.config.region, timeout=stack_config.timeout, service_role=stack_config.service_role, stack_policy=stack_policy, failure_action=stack_config.failure_action, ) if stack_name in existing_stacks: self.cfn.validate_stack_is_ready_for_action(stack) self.cfn.update_stack(stack) else: self.cfn.create_stack(stack) CustomResourceHandler.process_post_resources(stack) def delete_stacks(self): existing_stacks = self.cfn.get_stack_names() stacks = self.config.stacks stack_processing_order = DependencyResolver().get_stack_order(stacks) stack_processing_order.reverse() self.logger.info("Will delete stacks in the following order: {0}".format(", ".join(stack_processing_order))) for stack_name in stack_processing_order: stack_config = self.config.stacks.get(stack_name) if stack_name in existing_stacks: stack = CloudFormationStack(None, None, stack_name, None, None, service_role=stack_config.service_role) self.cfn.validate_stack_is_ready_for_action(stack) self.cfn.delete_stack(stack) else: self.logger.info("Stack {0} is already deleted".format(stack_name))
class StackActionHandler(object): def __init__(self, config, dry_run=False): self.logger = get_logger(root=True) self.config = config self.cfn = CloudFormation(region=self.config.region, dry_run=dry_run) self.parameter_resolver = ParameterResolver(self.cfn, region=self.config.region) self.cli_parameters = config.cli_params def execute_change_set(self): print('executing change set') print(self.config.change_set) change_set = self.cfn.get_change_set(self.config.change_set) if change_set is None: raise CfnStackActionFailedException( "Could not execute change set {0}: Does not exist or is in an invalid state." .format(self.config.change_set)) stack_name = self.cfn.get_stack_name_by_arn(change_set['StackId']) stack = self.cfn.get_stack(stack_name) if not self.cfn.change_set_is_executable(change_set): raise CfnStackActionFailedException( "Could not execute change set {0}: Does not exist or is in an invalid state." .format(self.config.change_set)) else: self.cfn.execute_change_set(stack, self.config.change_set) def create_change_set(self): existing_stacks = self.cfn.get_stack_names() desired_stacks = self.config.stacks stack_processing_order = DependencyResolver().get_stack_order( desired_stacks) if len(stack_processing_order) > 1: self.logger.info( "Will process stacks in the following order: {0}".format( ", ".join(stack_processing_order))) for stack_name in stack_processing_order: stack_config = self.config.stacks.get(stack_name) if stack_config.stack_policy_url: self.logger.info("Using stack policy from {0}".format( stack_config.stack_policy_url)) stack_policy = FileLoader.get_yaml_or_json_file( stack_config.stack_policy_url, stack_config.working_dir) else: stack_policy = None template = TemplateHandler.get_template( stack_config.template_url, stack_config.working_dir, self.config.region, stack_config.package_bucket) parameters = self.parameter_resolver.resolve_parameter_values( stack_name, stack_config, self.cli_parameters) stack = CloudFormationStack( template=template, parameters=parameters, tags=stack_config.tags, name=stack_name, region=self.config.region, timeout=stack_config.timeout, service_role=stack_config.service_role, stack_policy=stack_policy, failure_action=stack_config.failure_action) if stack_name in existing_stacks: self.cfn.create_change_set(stack, 'UPDATE') else: self.cfn.create_change_set(stack, 'CREATE') def create_or_update_stacks(self): existing_stacks = self.cfn.get_stack_names() desired_stacks = self.config.stacks stack_processing_order = DependencyResolver().get_stack_order( desired_stacks) if len(stack_processing_order) > 1: self.logger.info( "Will process stacks in the following order: {0}".format( ", ".join(stack_processing_order))) for stack_name in stack_processing_order: stack_config = self.config.stacks.get(stack_name) if stack_config.stack_policy_url: self.logger.info("Using stack policy from {0}".format( stack_config.stack_policy_url)) stack_policy = FileLoader.get_yaml_or_json_file( stack_config.stack_policy_url, stack_config.working_dir) else: stack_policy = None template = TemplateHandler.get_template( stack_config.template_url, stack_config.working_dir, self.config.region, stack_config.package_bucket) parameters = self.parameter_resolver.resolve_parameter_values( stack_name, stack_config, self.cli_parameters) stack = CloudFormationStack( template=template, parameters=parameters, tags=stack_config.tags, name=stack_name, region=self.config.region, timeout=stack_config.timeout, service_role=stack_config.service_role, stack_policy=stack_policy, failure_action=stack_config.failure_action) if stack_name in existing_stacks: self.cfn.validate_stack_is_ready_for_action(stack) self.cfn.update_stack(stack) else: self.cfn.create_stack(stack) def delete_stacks(self): existing_stacks = self.cfn.get_stack_names() stacks = self.config.stacks stack_processing_order = DependencyResolver().get_stack_order(stacks) stack_processing_order.reverse() self.logger.info( "Will delete stacks in the following order: {0}".format( ", ".join(stack_processing_order))) for stack_name in stack_processing_order: stack_config = self.config.stacks.get(stack_name) if stack_name in existing_stacks: stack = CloudFormationStack( None, None, stack_name, None, None, service_role=stack_config.service_role) self.cfn.validate_stack_is_ready_for_action(stack) self.cfn.delete_stack(stack) else: self.logger.info( "Stack {0} is already deleted".format(stack_name))
class StackActionHandler(object): def __init__(self, config): self.logger = get_logger(root=True) self.config = config self.region = config.region self.cfn = CloudFormation(region=self.region) self.parameter_resolver = ParameterResolver(region=self.region) def create_or_update_stacks(self): existing_stacks = self.cfn.get_stack_names() desired_stacks = self.config.stacks stack_processing_order = DependencyResolver().get_stack_order( desired_stacks) if len(stack_processing_order) > 1: self.logger.info( "Will process stacks in the following order: {0}".format( ", ".join(stack_processing_order))) for stack_name in stack_processing_order: stack_config = self.config.stacks.get(stack_name) raw_template = FileLoader.get_file_from_url( stack_config.template_url, stack_config.working_dir) template = CloudFormationTemplateTransformer.transform_template( raw_template) parameters = self.parameter_resolver.resolve_parameter_values( stack_config.parameters, stack_name) stack = CloudFormationStack(template=template, parameters=parameters, tags=(stack_config.tags), name=stack_name, region=self.region, timeout=stack_config.timeout) if stack_name in existing_stacks: self.cfn.validate_stack_is_ready_for_action(stack) self.cfn.update_stack(stack) else: self.cfn.create_stack(stack) CustomResourceHandler.process_post_resources(stack) def delete_stacks(self): existing_stacks = self.cfn.get_stack_names() stacks = self.config.stacks stack_processing_order = DependencyResolver().get_stack_order(stacks) stack_processing_order.reverse() self.logger.info( "Will delete stacks in the following order: {0}".format( ", ".join(stack_processing_order))) for stack_name in stack_processing_order: if stack_name in existing_stacks: stack = CloudFormationStack(None, None, stack_name, None, None) self.cfn.validate_stack_is_ready_for_action(stack) self.cfn.delete_stack(stack) else: self.logger.info( "Stack {0} is already deleted".format(stack_name))