Exemplo n.º 1
0
    def test_handle_file_value_loads_file_for_reference_with_pattern_containing_pipe(
            self, f, jmespath_search_mock):
        f.return_value = {"a": "b"}

        ParameterResolver.handle_file_value(
            "|file|s3://myBucket/myAwsAccounts.json|a|b", None)
        jmespath_search_mock.assert_called_once_with("a|b", {'a': 'b'})
Exemplo n.º 2
0
 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
Exemplo n.º 3
0
 def test_get_latest_value_raises_exception_on_error(self):
     self.cfn_mock.get_stack_parameters_dict = MagicMock(
         side_effect=Exception("foo"))
     resolver = ParameterResolver(self.cfn_mock)
     with self.assertRaises(CfnSphereException):
         resolver.get_latest_value('my-key', '|keepOrUse|default-value',
                                   'my-stack')
Exemplo n.º 4
0
    def test_get_latest_value_returns_default_value_called_once_with_stack(self):
        self.cfn_mock.return_value.get_stack_parameters_dict.return_value = {'not-my-key': 'my-actual-value'}

        pr = ParameterResolver()
        result = pr.get_latest_value('my-key', '|keepOrUse|default-value', 'my-stack')

        self.cfn_mock.return_value.get_stack_parameters_dict.assert_called_once_with('my-stack')
        self.assertEqual('default-value', result)
    def test_get_latest_value_returns_default_value(self):
        self.cfn_mock.return_value.get_stack_parameters_dict.side_effect = CfnSphereBotoError(
            BotoServerError("500", "foo")
        )

        resolver = ParameterResolver()
        with self.assertRaises(CfnSphereException):
            resolver.get_latest_value("my-key", "|keepOrUse|default-value", "my-stack")
    def test_get_latest_value_returns_default_value_called_once_with_stack(self):
        self.cfn_mock.return_value.get_stack_parameters_dict.return_value = {"not-my-key": "my-actual-value"}

        pr = ParameterResolver()
        result = pr.get_latest_value("my-key", "|keepOrUse|default-value", "my-stack")

        self.cfn_mock.return_value.get_stack_parameters_dict.assert_called_once_with("my-stack")
        self.assertEqual("default-value", result)
    def test_get_latest_value_returns_default_value_called_once_with_stack(self):
        self.cfn_mock.return_value.get_stack_parameters_dict.return_value = {'not-my-key': 'my-actual-value'}

        pr = ParameterResolver()
        result = pr.get_latest_value('my-key', '|keepOrUse|default-value', 'my-stack')

        self.cfn_mock.return_value.get_stack_parameters_dict.assert_called_once_with('my-stack')
        self.assertEqual('default-value', result)
    def test_get_latest_value_returns_stacks_actual_value(self, kms,  ec2_api, cfn_mock):
        cfn_mock.return_value.get_stack_parameters_dict.return_value = {'my-key': 'my-actual-value'}

        pr = ParameterResolver()
        result = pr.get_latest_value('my-key', '|keepOrUse|default-value', 'my-stack')

        cfn_mock.return_value.get_stack_parameters_dict.assert_called_once_with('my-stack')
        self.assertEqual('my-actual-value', result)
Exemplo n.º 9
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))
Exemplo n.º 10
0
    def test_get_latest_value_returns_stacks_actual_value(self):
        self.cfn_mock.get_stack_parameters_dict = MagicMock(
            return_value={'my-key': 'my-actual-value'})

        pr = ParameterResolver(self.cfn_mock)
        result = pr.get_latest_value('my-key', '|keepOrUse|default-value',
                                     'my-stack')

        self.cfn_mock.get_stack_parameters_dict.assert_called_once_with(
            'my-stack')
        self.assertEqual('my-actual-value', result)
Exemplo n.º 11
0
    def test_resolve_parameter_values_returns_list_with_string_value(self):
        stack_config = Mock()
        stack_config.parameters = {'foo': "baa"}

        result = ParameterResolver().resolve_parameter_values(
            'foo', stack_config)
        self.assertEqual({'foo': 'baa'}, result)
Exemplo n.º 12
0
    def test_resolve_parameter_values_raises_exception_on_none_value(self):
        stack_config = Mock()
        stack_config.parameters = {'foo': None}

        with self.assertRaises(CfnSphereException):
            ParameterResolver(self.cfn_mock).resolve_parameter_values(
                'foo', stack_config)
Exemplo n.º 13
0
    def test_handle_file_value_loads_file_for_reference_with_pattern(self, get_yaml_or_json_file_mock):
        get_yaml_or_json_file_mock.return_value = {"accounts": [{"id": 1}, {"id": 2}, {"id": 3}]}

        result = ParameterResolver.handle_file_value("|file|s3://myBucket/myAwsAccounts.json|accounts[*].id", None)

        get_yaml_or_json_file_mock.assert_called_once_with("s3://myBucket/myAwsAccounts.json", None)
        self.assertEqual([1, 2, 3], result)
Exemplo n.º 14
0
 def test_resolve_parameter_values_returns_str_representation_of_float(
         self):
     stack_config = Mock()
     stack_config.parameters = {'foo': 5.555}
     result = ParameterResolver().resolve_parameter_values(
         'foo', stack_config)
     self.assertEqual({'foo': '5.555'}, result)
Exemplo n.º 15
0
    def test_resolve_parameter_values_calls_convert_list_to_string_on_list_value(
            self, convert_list_to_string_mock):
        stack_config = Mock()
        stack_config.parameters = {'foo': ['a', 'b']}

        ParameterResolver().resolve_parameter_values('foo', stack_config)
        convert_list_to_string_mock.assert_called_once_with(['a', 'b'])
Exemplo n.º 16
0
    def test_handle_kms_value_ignores_encryption_context_if_not_set(self):
        self.kms_mock.return_value.decrypt.return_value = "decryptedValue"
        result = ParameterResolver().handle_kms_value('|kms|encryptedValue')

        self.kms_mock.return_value.decrypt.assert_called_once_with(
            'encryptedValue')
        self.assertEqual(result, 'decryptedValue')
Exemplo n.º 17
0
    def test_handle_file_value_loads_file_for_simple_file_reference(self, get_file_mock):
        get_file_mock.return_value = "myValue"

        result = ParameterResolver.handle_file_value("|file|s3://myBucket/myParameter.txt", None)

        get_file_mock.assert_called_once_with("s3://myBucket/myParameter.txt", None)
        self.assertEqual("myValue", result)
Exemplo n.º 18
0
    def test_resolve_parameter_values_returns_str_representation_of_false(
            self):
        stack_config = Mock()
        stack_config.parameters = {'foo': False}

        result = ParameterResolver(self.cfn_mock).resolve_parameter_values(
            'foo', stack_config)
        self.assertEqual({'foo': 'false'}, result)
Exemplo n.º 19
0
    def test_resolve_parameter_values_returns_decrypted_value(self):
        self.kms_mock.return_value.decrypt.return_value = "decryptedValue"

        stack_config = Mock()
        stack_config.parameters = {'foo': '|kms|encryptedValue'}

        result = ParameterResolver().resolve_parameter_values('foo', stack_config)
        self.assertEqual(result, {'foo': 'decryptedValue'})
Exemplo n.º 20
0
def test_resolve_value_from_file(self, get_file_mock):
    get_file_mock.return_value = "line1\nline2"

    stack_config = Mock()
    stack_config.parameters = {'foo': "|file|abc.txt"}

    result = ParameterResolver().resolve_parameter_values('foo', stack_config)
    self.assertEqual({'foo': 'line1\nline2'}, result)
Exemplo n.º 21
0
 def test_update_parameters_with_cli_parameters_with_string_param_value(
         self):
     result = ParameterResolver().update_parameters_with_cli_parameters(
         parameters={'foo': "foo"},
         cli_parameters={'stack1': {
             'foo': 'foobar'
         }},
         stack_name='stack1')
     self.assertEqual({'foo': 'foobar'}, result)
Exemplo n.º 22
0
    def test_resolve_parameter_values_returns_ssm_value(self):
        self.ssm_mock.return_value.get_parameter.return_value = "decryptedValue"

        stack_config = Mock()
        stack_config.parameters = {'foo': '|ssm|/path/to/my/key'}

        result = ParameterResolver().resolve_parameter_values(
            'foo', stack_config)
        self.assertEqual(result, {'foo': 'decryptedValue'})
Exemplo n.º 23
0
 def test_update_parameters_with_cli_parameters_adds_new_cli_parameter(
         self):
     result = ParameterResolver().update_parameters_with_cli_parameters(
         parameters={'foo': 'foo'},
         cli_parameters={'stack1': {
             'moppel': 'foo'
         }},
         stack_name='stack1')
     self.assertDictEqual({'foo': 'foo', 'moppel': 'foo'}, result)
Exemplo n.º 24
0
def test_update_parameters_with_cli_parameters_does_not_affect_other_stacks(
        self):
    result = ParameterResolver().update_parameters_with_cli_parameters(
        parameters={'foo': "foo"},
        cli_parameters={'stack1': {
            'foo': 'foobar'
        }},
        stack_name='stack2')
    self.assertEqual({'foo': 'foo'}, result)
Exemplo n.º 25
0
    def test_resolve_parameters_with_cli_parameters_(self):
        cli_parameters = {'stack1': {'foo': 'foobar'}, 'stack2': {'foo': 'foofoo'}}

        stack_config = Mock()
        stack_config.parameters = {'foo': "bar"}

        result = ParameterResolver().resolve_parameter_values("stack1", stack_config, cli_parameters)

        self.assertEqual({'foo': 'foobar'}, result)
Exemplo n.º 26
0
    def test_resolve_parameter_values_returns_ref_list_value(self, cfn_mock, get_output_value_mock):
        cfn_mock.return_value.get_stacks_outputs.return_value = None
        get_output_value_mock.return_value = 'bar'

        stack_config = Mock()
        stack_config.parameters = {'foo': ['|Ref|stack.output', '|Ref|stack.output']}

        result = ParameterResolver().resolve_parameter_values('foo', stack_config)

        get_output_value_mock.assert_called_with(None, "stack", "output")
        self.assertEqual({'foo': 'bar,bar'}, result)
Exemplo n.º 27
0
    def test_resolve_parameter_values_returns_ref_value(
            self, get_output_value_mock):
        self.cfn_mock.get_stacks_outputs = MagicMock(return_value=None)
        get_output_value_mock.return_value = 'bar'

        stack_config = Mock()
        stack_config.parameters = {'foo': '|Ref|stack.output'}

        result = ParameterResolver(self.cfn_mock).resolve_parameter_values(
            'foo', stack_config)

        get_output_value_mock.assert_called_with(None, "stack", "output")
        self.assertEqual({'foo': 'bar'}, result)
Exemplo n.º 28
0
 def test_update_parameters_with_cli_parameters_with_string_param_value_for_several_stacks(
         self):
     result = ParameterResolver(
         self.cfn_mock).update_parameters_with_cli_parameters(
             parameters={'foo': "foo"},
             cli_parameters={
                 'stack1': {
                     'foo': 'foobar'
                 },
                 'stack2': {
                     'foo': 'foofoo'
                 }
             },
             stack_name='stack2')
     self.assertEqual({'foo': 'foofoo'}, result)
    def test_get_latest_value_raises_exception_on_error(self):
        self.cfn_mock.return_value.get_stack_parameters_dict.side_effect = CfnSphereBotoError(Exception("foo"))

        resolver = ParameterResolver()
        with self.assertRaises(CfnSphereException):
            resolver.get_latest_value('my-key', '|keepOrUse|default-value', 'my-stack')
Exemplo n.º 30
0
 def test_is_keep_value_returns_true_for_keep_keyword(self):
     result = ParameterResolver.is_keep_value("|keeporuse|")
     self.assertTrue(result)
Exemplo n.º 31
0
    def test_resolve_parameter_values_raises_exception_on_none_value(self):
        stack_config = Mock()
        stack_config.parameters = {'foo': None}

        with self.assertRaises(NotImplementedError):
            ParameterResolver().resolve_parameter_values('foo', stack_config)
 def test_is_keep_value_returns_false_for_empty_value(self):
     result = ParameterResolver.is_keep_value('')
     self.assertFalse(result)
 def test_get_default_from_keep_value_returns_empty_string(self):
     result = ParameterResolver.get_default_from_keep_value('|keepOrUse|')
     self.assertEqual('', result)
Exemplo n.º 34
0
 def test_handle_file_value_raises_exception_on_invalid_macro_syntax(self):
     with self.assertRaises(CfnSphereException):
         ParameterResolver.handle_file_value("|file", None)
 def test_handle_file_value_raises_exception_on_invalid_jmespath_pattern_syntax(self, _):
     with self.assertRaises(CfnSphereException):
         ParameterResolver.handle_file_value("|file|path|broken_pattern{}}", None)
    def test_handle_file_value_loads_file_for_reference_with_pattern_containing_pipe(self, f, jmespath_search_mock):
        f.return_value = {"a": "b"}

        ParameterResolver.handle_file_value("|file|s3://myBucket/myAwsAccounts.json|a|b", None)
        jmespath_search_mock.assert_called_once_with("a|b", {'a': 'b'})
Exemplo n.º 37
0
 def test_get_default_from_keep_value_returns_proper_string(self):
     result = ParameterResolver.get_default_from_keep_value("|keepOrUse|foo")
     self.assertEqual("foo", result)
 def test_is_keep_value_returns_true_for_uppercase_keep_keyword(self):
     result = ParameterResolver.is_keep_value('|KEEPORUSE|')
     self.assertTrue(result)
 def test_convert_list_to_string_returns_valid_string_if_list_contains_int(self):
     list = ['a', 6, 'c']
     self.assertEqual("a,6,c", ParameterResolver.convert_list_to_string(list))
 def test_is_keep_value_returns_true_for_mixed_case_keep_keyword(self):
     result = ParameterResolver.is_keep_value('|keepOrUse|')
     self.assertTrue(result)
Exemplo n.º 41
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))
 def test_get_default_from_keep_value_returns_proper_string_if_it_contains_separator(self):
     result = ParameterResolver.get_default_from_keep_value('|keepOrUse|foo|foo.de')
     self.assertEqual('foo|foo.de', result)
Exemplo n.º 43
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))
 def test_convert_list_to_string_returns_valid_string(self):
     list = ['a', 'b', 'c']
     self.assertEqual("a,b,c", ParameterResolver.convert_list_to_string(list))
Exemplo n.º 45
0
 def test_convert_list_to_string_returns_valid_string(self):
     list = ['a', 'b', 'c']
     self.assertEqual("a,b,c", ParameterResolver.convert_list_to_string(list))
 def test_convert_list_to_string_returns_empty_list_on_empty_list(self):
     self.assertEqual("", ParameterResolver.convert_list_to_string([]))
Exemplo n.º 47
0
 def test_convert_list_to_string_returns_valid_string_if_list_contains_int(self):
     list = ['a', 6, 'c']
     self.assertEqual("a,6,c", ParameterResolver.convert_list_to_string(list))
Exemplo n.º 48
0
 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)
Exemplo n.º 49
0
 def test_convert_list_to_string_returns_empty_list_on_empty_list(self):
     self.assertEqual("", ParameterResolver.convert_list_to_string([]))