Beispiel #1
0
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))
Beispiel #2
0
    def test_validate_stack_is_ready_for_action_passes_if_stack_is_in_rollback_complete_state(self, get_stack_mock):
        stack_mock = Mock()
        stack_mock.stack_name = "my-stack"
        stack_mock.stack_status = "ROLLBACK_COMPLETE"
        get_stack_mock.return_value = stack_mock

        stack = CloudFormationStack('', [], 'my-stack', 'my-region')

        cfn = CloudFormation()
        cfn.validate_stack_is_ready_for_action(stack)
Beispiel #3
0
    def test_validate_stack_is_ready_for_action_passes_if_stack_is_in_rollback_complete_state(self, get_stack_mock):
        stack_mock = Mock()
        stack_mock.stack_name = "my-stack"
        stack_mock.stack_status = "ROLLBACK_COMPLETE"
        get_stack_mock.return_value = stack_mock

        stack = CloudFormationStack('', [], 'my-stack', 'my-region')

        cfn = CloudFormation()
        cfn.validate_stack_is_ready_for_action(stack)
    def test_validate_stack_is_ready_for_action_raises_proper_exception_on_boto_error(self, cloudformation_mock):
        cloudformation_mock.return_value.describe_stacks.side_effect = BotoServerError('400', 'Bad Request')

        stack = CloudFormationStack('', [], 'my-stack', 'my-region')

        cfn = CloudFormation()
        with self.assertRaises(CfnSphereBotoError):
            cfn.validate_stack_is_ready_for_action(stack)

        cloudformation_mock.return_value.describe_stacks.assert_called_once_with('my-stack')
Beispiel #5
0
    def test_validate_stack_is_ready_for_action_raises_exception_on_create_in_progress(self, get_stack_mock):
        stack_mock = Mock()
        stack_mock.stack_name = "my-stack"
        stack_mock.stack_status = "CREATE_IN_PROGRESS"
        get_stack_mock.return_value = stack_mock

        stack = CloudFormationStack('', [], 'my-stack', 'my-region')

        cfn = CloudFormation()
        with self.assertRaises(CfnStackActionFailedException):
            cfn.validate_stack_is_ready_for_action(stack)
Beispiel #6
0
    def test_validate_stack_is_ready_for_action_raises_exception_on_create_in_progress(self, get_stack_mock):
        stack_mock = Mock()
        stack_mock.stack_name = "my-stack"
        stack_mock.stack_status = "CREATE_IN_PROGRESS"
        get_stack_mock.return_value = stack_mock

        stack = CloudFormationStack('', [], 'my-stack', 'my-region')

        cfn = CloudFormation()
        with self.assertRaises(CfnStackActionFailedException):
            cfn.validate_stack_is_ready_for_action(stack)
Beispiel #7
0
    def test_validate_stack_is_ready_for_action_raises_exception_on_unknown_stack_state(self, get_stack_mock):
        stack_mock = Mock()
        stack_mock.stack_name = "my-stack"
        stack_mock.stack_status = "FOO"
        get_stack_mock.return_value = stack_mock

        stack = CloudFormationStack('', [], 'my-stack', 'my-region')

        cfn = CloudFormation()
        with self.assertRaises(CfnStackActionFailedException):
            cfn.validate_stack_is_ready_for_action(stack)
Beispiel #8
0
    def test_validate_stack_is_ready_for_action_raises_exception_on_unknown_stack_state(self, get_stack_mock):
        stack_mock = Mock()
        stack_mock.stack_name = "my-stack"
        stack_mock.stack_status = "FOO"
        get_stack_mock.return_value = stack_mock

        stack = CloudFormationStack('', [], 'my-stack', 'my-region')

        cfn = CloudFormation()
        with self.assertRaises(CfnStackActionFailedException):
            cfn.validate_stack_is_ready_for_action(stack)
    def test_validate_stack_is_ready_for_action_raises_proper_exception_on_boto_error(
            self, cloudformation_mock):
        cloudformation_mock.return_value.describe_stacks.side_effect = BotoServerError(
            '400', 'Bad Request')

        stack = CloudFormationStack('', [], 'my-stack', 'my-region')

        cfn = CloudFormation()
        with self.assertRaises(CfnSphereBotoError):
            cfn.validate_stack_is_ready_for_action(stack)

        cloudformation_mock.return_value.describe_stacks.assert_called_once_with(
            'my-stack')
Beispiel #10
0
    def test_validate_stack_is_ready_for_action_raises_proper_exception_on_boto_error(self, get_stack_mock):
        get_stack_mock.side_effect = CfnSphereBotoError(None)

        stack_mock = Mock()
        stack_mock.stack_name = "my-stack"
        stack_mock.stack_status = "UPDATE_COMPLETE"
        get_stack_mock.return_value = stack_mock

        stack = CloudFormationStack('', [], 'my-stack', 'my-region')

        cfn = CloudFormation()
        with self.assertRaises(CfnSphereBotoError):
            cfn.validate_stack_is_ready_for_action(stack)
    def test_validate_stack_is_ready_for_action_passes_if_stack_is_in_good_state(self, cloudformation_mock):
        describe_stack_mock = Mock()
        describe_stack_mock.stack_status = "UPDATE_COMPLETE"
        describe_stack_mock.stack_name = "my-stack"

        cloudformation_mock.return_value.describe_stacks.return_value = [describe_stack_mock]

        stack = CloudFormationStack('', [], 'my-stack', 'my-region')

        cfn = CloudFormation()
        cfn.validate_stack_is_ready_for_action(stack)

        cloudformation_mock.return_value.describe_stacks.assert_called_once_with('my-stack')
Beispiel #12
0
    def test_validate_stack_is_ready_for_action_raises_proper_exception_on_boto_error(self, get_stack_mock):
        get_stack_mock.side_effect = CfnSphereBotoError(None)

        stack_mock = Mock()
        stack_mock.stack_name = "my-stack"
        stack_mock.stack_status = "UPDATE_COMPLETE"
        get_stack_mock.return_value = stack_mock

        stack = CloudFormationStack('', [], 'my-stack', 'my-region')

        cfn = CloudFormation()
        with self.assertRaises(CfnSphereBotoError):
            cfn.validate_stack_is_ready_for_action(stack)
    def test_validate_stack_is_ready_for_action_raises_exception_on_bad_stack_state(self, cloudformation_mock):
        describe_stack_mock = Mock()
        describe_stack_mock.stack_status = "UPDATE_IN_PROGRESS"
        describe_stack_mock.stack_name = "my-stack"

        cloudformation_mock.return_value.describe_stacks.return_value = [describe_stack_mock]

        stack = CloudFormationStack('', [], 'my-stack', 'my-region')

        cfn = CloudFormation()
        with self.assertRaises(CfnStackActionFailedException):
            cfn.validate_stack_is_ready_for_action(stack)

        cloudformation_mock.return_value.describe_stacks.assert_called_once_with('my-stack')
    def test_validate_stack_is_ready_for_action_passes_if_stack_is_in_good_state(
            self, cloudformation_mock):
        describe_stack_mock = Mock()
        describe_stack_mock.stack_status = "UPDATE_COMPLETE"
        describe_stack_mock.stack_name = "my-stack"

        cloudformation_mock.return_value.describe_stacks.return_value = [
            describe_stack_mock
        ]

        stack = CloudFormationStack('', [], 'my-stack', 'my-region')

        cfn = CloudFormation()
        cfn.validate_stack_is_ready_for_action(stack)

        cloudformation_mock.return_value.describe_stacks.assert_called_once_with(
            'my-stack')
    def test_validate_stack_is_ready_for_action_raises_exception_on_bad_stack_state(
            self, cloudformation_mock):
        describe_stack_mock = Mock()
        describe_stack_mock.stack_status = "UPDATE_IN_PROGRESS"
        describe_stack_mock.stack_name = "my-stack"

        cloudformation_mock.return_value.describe_stacks.return_value = [
            describe_stack_mock
        ]

        stack = CloudFormationStack('', [], 'my-stack', 'my-region')

        cfn = CloudFormation()
        with self.assertRaises(CfnStackActionFailedException):
            cfn.validate_stack_is_ready_for_action(stack)

        cloudformation_mock.return_value.describe_stacks.assert_called_once_with(
            'my-stack')
Beispiel #16
0
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))
Beispiel #17
0
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))
Beispiel #18
0
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))
Beispiel #19
0
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))