Esempio n. 1
0
    def test_default_service_role_is_used_if_not_overwritten_by_stack_config(
            self):
        config = Config(
            config_dict={
                'region': 'eu-west-1',
                'service-role': 'arn:aws:iam::123456789:role/my-role1',
                'tags': {
                    'global-tag': 'global-tag-value'
                },
                'stacks': {
                    'any-stack': {
                        'timeout': 99,
                        'template-url': 'foo.json',
                        'tags': {
                            'any-tag': 'any-tag-value'
                        },
                        'parameters': {
                            'any-parameter': 'any-value'
                        }
                    }
                }
            })

        self.assertEqual('arn:aws:iam::123456789:role/my-role1',
                         config.stacks["any-stack"].service_role)
Esempio n. 2
0
    def test_config_reads_config_from_file(self, get_file_mock, getcwd_mock):
        getcwd_mock.return_value = "/home/user/something"
        get_file_mock.return_value = {"region": "eu-west-1", "stacks": {
            "some-stack": {"template-url": "some-template.yml"}}}

        Config("my-stacks/stacks.yml")
        get_file_mock.assert_called_once_with("my-stacks/stacks.yml", working_dir="/home/user/something")
Esempio n. 3
0
 def sync_stacks_with_parameters_overwrite(self, cli_params):
     config = Config(config_file=os.path.join(self.test_resources_dir,
                                              "stacks.yml"),
                     cli_params=cli_params)
     stack_handler = StackActionHandler(config)
     self.logger.info("Syncing stacks")
     stack_handler.create_or_update_stacks()
Esempio n. 4
0
    def test_apply_stack_name_suffix_does_not_append_none_suffix(self):
        stacks = {
            "stack-d": StackConfig({"template-url": "some-url"})
        }

        result = Config._apply_stack_name_suffix(stacks, None)
        self.assertEqual(result, stacks)
Esempio n. 5
0
def delete(config, suffix, debug, confirm, yes):
    confirm = confirm or yes
    if debug:
        LOGGER.setLevel(logging.DEBUG)
    else:
        LOGGER.setLevel(logging.INFO)

    if not confirm:
        check_update_available()
        click.confirm(
            'This action will delete all stacks in {0} from account: {1}\nAre you sure?'
            .format(config, get_first_account_alias_or_account_id()),
            abort=True)

    try:

        config = Config(config, stack_name_suffix=suffix)
        StackActionHandler(config).delete_stacks()
    except CfnSphereException as e:
        LOGGER.error(e)
        if debug:
            LOGGER.exception(e)
        sys.exit(1)
    except Exception as e:
        LOGGER.error("Failed with unexpected error")
        LOGGER.exception(e)
        LOGGER.info(
            "Please report at https://github.com/cfn-sphere/cfn-sphere/issues!"
        )
        sys.exit(1)
Esempio n. 6
0
 def test_parse_cli_parameters(self):
     config = Config(cli_params=("stack1.p1=v1", "stack1.p2=v2"),
                     config_dict={'region': 'eu-west-1', 'stacks': {'stack1': {'template-url': 'foo.json'}}})
     self.assertTrue('p1' in config.cli_params['stack1'])
     self.assertTrue('p2' in config.cli_params['stack1'])
     self.assertTrue('v1' in config.cli_params['stack1'].values())
     self.assertTrue('v2' in config.cli_params['stack1'].values())
Esempio n. 7
0
def sync(config, parameter, suffix, debug, confirm, yes):
    confirm = confirm or yes
    if debug:
        LOGGER.setLevel(logging.DEBUG)
        boto3.set_stream_logger(name='boto3', level=logging.DEBUG)
        boto3.set_stream_logger(name='botocore', level=logging.DEBUG)
    else:
        LOGGER.setLevel(logging.INFO)

    if not confirm:
        check_update_available()
        click.confirm(
            'This action will modify AWS infrastructure in account: {0}\nAre you sure?'
            .format(get_first_account_alias_or_account_id()),
            abort=True)

    try:

        config = Config(config_file=config,
                        cli_params=parameter,
                        stack_name_suffix=suffix)
        StackActionHandler(config).create_or_update_stacks()
    except CfnSphereException as e:
        LOGGER.error(e)
        if debug:
            LOGGER.exception(e)
        sys.exit(1)
    except Exception as e:
        LOGGER.error("Failed with unexpected error")
        LOGGER.exception(e)
        LOGGER.info(
            "Please report at https://github.com/cfn-sphere/cfn-sphere/issues!"
        )
        sys.exit(1)
Esempio n. 8
0
 def test_config_properties_parsing(self):
     config = Config(
         config_dict={
             'region': 'eu-west-1',
             'tags': {
                 'global-tag': 'global-tag-value'
             },
             'stacks': {
                 'any-stack': {
                     'timeout': 99,
                     'template-url': 'foo.json',
                     'tags': {
                         'any-tag': 'any-tag-value'
                     },
                     'parameters': {
                         'any-parameter': 'any-value'
                     }
                 }
             }
         })
     self.assertEqual('eu-west-1', config.region)
     self.assertEqual(1, len(config.stacks.keys()))
     self.assertTrue(isinstance(config.stacks['any-stack'], StackConfig))
     self.assertEqual('foo.json', config.stacks['any-stack'].template_url)
     self.assertDictContainsSubset(
         {
             'any-tag': 'any-tag-value',
             'global-tag': 'global-tag-value'
         }, config.stacks['any-stack'].tags)
     self.assertDictContainsSubset({'global-tag': 'global-tag-value'},
                                   config.default_tags)
     self.assertDictContainsSubset({'any-parameter': 'any-value'},
                                   config.stacks['any-stack'].parameters)
     self.assertEqual(99, config.stacks['any-stack'].timeout)
def get_stack_action_handler(domain,
                             verification_token=None,
                             dkim_tokens=None):
    verification_token = verification_token or ""
    dkim_tokens = dkim_tokens or ["", "", ""]

    return StackActionHandler(config=Config(
        config_dict={
            'region': REGION,
            'stacks': {
                get_dns_stack_name(domain): {
                    'template-url': recordset_template.name,
                    'parameters': {
                        'dnsBaseName': domain + ".",
                        'dkimOne': dkim_tokens[0],
                        'dkimTwo': dkim_tokens[1],
                        'dkimThree': dkim_tokens[2],
                        'verifyTxt': verification_token
                    }
                },
                get_bucket_stack_name(domain): {
                    'template-url': ses_template.name,
                }
            }
        }))
Esempio n. 10
0
 def __init__(self):
     self.logger = logging.getLogger(__name__)
     self.logger.setLevel(logging.INFO)
     self.test_resources_dir = self._get_resources_dir()
     self.cfn_conn = boto3.client('cloudformation', region_name='eu-west-1')
     self.kms_conn = boto3.client('kms', region_name='eu-west-1')
     self.config = Config(
         config_file=os.path.join(self.test_resources_dir, "stacks.yml"))
    def setUpClass(cls):
        test_resources_dir = get_resources_dir()
        cls.cfn_conn = cloudformation.connect_to_region("eu-west-1")
        cls.config = Config(config_file=os.path.join(test_resources_dir, "stacks.yml"))
        cls.stack_handler = StackActionHandler(cls.config)

        LOGGER.info("Syncing stacks")
        cls.stack_handler.create_or_update_stacks()
Esempio n. 12
0
    def test_apply_stack_name_suffix_does_not_modify_externally_referenced_stacks(self):
        stacks = {
            "stack-c": StackConfig({"template-url": "some-url", "parameters": {"a": 1, "b": "|ref|external_stack.a"}})
        }

        result = Config._apply_stack_name_suffix(stacks, "-test")

        self.assertEqual(result["stack-c-test"].parameters["a"], 1)
        self.assertEqual(result["stack-c-test"].parameters["b"], "|ref|external_stack.a")
Esempio n. 13
0
 def test_raises_exception_if_no_region_key(self):
     with self.assertRaises(NoConfigException):
         Config(config_dict={
             'foo': '',
             'stacks': {
                 'any-stack': {
                     'template': 'foo.json'
                 }
             }
         })
Esempio n. 14
0
 def test_validate_raises_exception_for_empty_stack_config(self):
     with self.assertRaises(InvalidConfigException):
         Config(
             config_dict={
                 'invalid-key': 'some-value',
                 'region': 'eu-west-1',
                 'stacks': {
                     'stack2': None
                 }
             })
Esempio n. 15
0
    def test_apply_stack_name_suffix_applies_suffix_to_sublist_items(self):
        stacks = {
            "stack-a": StackConfig(
                {"template-url": "some-url", "parameters": {"alist": ["|ref|stack-b.a", "|ref|stack-b.b"]}}),
            "stack-b": StackConfig({"template-url": "some-url"})
        }

        result = Config._apply_stack_name_suffix(stacks, "-test")

        self.assertEqual(result["stack-a-test"].parameters["alist"][0], "|ref|stack-b-test.a")
        self.assertEqual(result["stack-a-test"].parameters["alist"][1], "|ref|stack-b-test.b")
Esempio n. 16
0
    def test_apply_stack_name_suffix_appends_number_suffix_to_all_stacks(self):
        stacks = {
            "stack-a": StackConfig({"template-url": "some-url", "parameters": {"a": 1, "b": "|ref|stack-b.a"}}),
            "stack-b": StackConfig({"template-url": "some-url", "parameters": {"a": 1, "b": "foo"}})
        }

        result = Config._apply_stack_name_suffix(stacks, 3)

        self.assertEqual(result["stack-a3"].parameters["a"], 1)
        self.assertEqual(result["stack-a3"].parameters["b"], "|ref|stack-b3.a")
        self.assertEqual(result["stack-b3"].parameters["a"], 1)
        self.assertEqual(result["stack-b3"].parameters["b"], "foo")
Esempio n. 17
0
 def test_validate_raises_exception_for_invalid_config_key(self):
     with self.assertRaises(InvalidConfigException):
         Config(
             config_dict={
                 'invalid-key': 'some-value',
                 'region': 'eu-west-1',
                 'stacks': {
                     'stack2': {
                         'template-url': 'foo.json'
                     }
                 }
             })
Esempio n. 18
0
 def test_validate_raises_exception_for_cli_param_on_non_configured_stack(
         self):
     with self.assertRaises(InvalidConfigException):
         Config(cli_params=("stack1.p1=v1", ),
                config_dict={
                    'region': 'eu-west-1',
                    'stacks': {
                        'stack2': {
                            'template-url': 'foo.json'
                        }
                    }
                })
Esempio n. 19
0
 def test_validate_passes_on_valid_service_role_value(self):
     with self.assertRaises(InvalidConfigException):
         Config(
             config_dict={
                 'region': 'eu-west-q',
                 'service-role': 'some-role',
                 'stacks': {
                     'any-stack': {
                         'template': 'foo.json'
                     }
                 }
             })
Esempio n. 20
0
 def test_validate_raises_exception_on_invalid_service_role_value(self):
     with self.assertRaises(InvalidConfigException):
         Config(
             config_dict={
                 'region': 'eu-west-q',
                 'service-role': 'arn:aws:iam::123456789:role/my-role',
                 'stacks': {
                     'any-stack': {
                         'template': 'foo.json'
                     }
                 }
             })
Esempio n. 21
0
 def test_parse_cli_parameters_accepts_spaces(self):
     self.assertDictEqual(
         {
             'stack1': {
                 'p1': 'v1',
                 'p2': 'v2'
             },
             'stack2': {
                 'p1': 'v1'
             }
         },
         Config._parse_cli_parameters(
             ("stack1.p1 = v1 ", "stack1.p2=v2", "stack2.p1=v1 ")))
Esempio n. 22
0
    def create_config_object():
        config_dict = {
            'region': 'region a',
            'tags': {'key_a': 'value a'},
            'stacks': {
                'stack_a': {
                    'template-url': 'template_a',
                    'parameters': 'any parameters'
                }
            }
        }

        return Config(config_dict=config_dict, cli_params=['stack_a.cli_parameter_a=cli_value_a'])
Esempio n. 23
0
 def test_a_stacks_timeout_is_set_if_not_configured(self):
     config = Config(
         config_dict={
             'region': 'eu-west-1',
             'tags': {
                 'global-tag': 'global-tag-value'
             },
             'stacks': {
                 'any-stack': {
                     'template-url': 'foo.json',
                     'tags': {
                         'any-tag': 'any-tag-value'
                     },
                     'parameters': {
                         'any-parameter': 'any-value'
                     }
                 }
             }
         })
     self.assertTrue(isinstance(config.stacks["any-stack"].timeout, int))
Esempio n. 24
0
 def test_a_stacks_service_role_is_none_if_not_configured(self):
     config = Config(
         config_dict={
             'region': 'eu-west-1',
             'tags': {
                 'global-tag': 'global-tag-value'
             },
             'stacks': {
                 'any-stack': {
                     'timeout': 99,
                     'template-url': 'foo.json',
                     'tags': {
                         'any-tag': 'any-tag-value'
                     },
                     'parameters': {
                         'any-parameter': 'any-value'
                     }
                 }
             }
         })
     self.assertIsNone(config.stacks["any-stack"].service_role)
Esempio n. 25
0
def execute_change_set(change_set, debug, confirm, yes, region):
    confirm = confirm or yes
    if debug:
        LOGGER.setLevel(logging.DEBUG)
        boto3.set_stream_logger(name='boto3', level=logging.DEBUG)
        boto3.set_stream_logger(name='botocore', level=logging.DEBUG)
    else:
        LOGGER.setLevel(logging.INFO)

    if not confirm:
        check_update_available()
        click.confirm(
            'This action will modify AWS infrastructure in account: {0}\nAre you sure?'
            .format(get_first_account_alias_or_account_id()),
            abort=True)

    try:
        matched = re.match(r'arn:aws:cloudformation:([^:]+):.*', change_set)

        if matched:
            LOGGER.info('ARN detected, setting region to {}'.format(
                matched.group(1)))
            region = matched.group(1)

        config_dict = {'change_set': change_set, 'region': str(region)}
        config = Config(config_dict=config_dict)
        StackActionHandler(config).execute_change_set()
    except CfnSphereException as e:
        LOGGER.error(e)
        if debug:
            LOGGER.exception(e)
        sys.exit(1)
    except Exception as e:
        LOGGER.error("Failed with unexpected error")
        LOGGER.exception(e)
        LOGGER.info(
            "Please report at https://github.com/KCOM-Enterprise/cfn-square/issues!"
        )
        sys.exit(1)
Esempio n. 26
0
 def test_parse_cli_parameters_throws_exception_on_invalid_syntax(self):
     with self.assertRaises(CfnSphereException):
         Config._parse_cli_parameters(("foo", ))
Esempio n. 27
0
 def test_parse_cli_parameters_parses_single_int_parameter(self):
     self.assertDictEqual({'stack1': {
         'p1': '2'
     }}, Config._parse_cli_parameters(("stack1.p1=2", )))
Esempio n. 28
0
 def test_parse_cli_parameters_accepts_list_of_strings(self):
     self.assertDictEqual({'stack1': {
         'p1': 'v1,v2,v3'
     }}, Config._parse_cli_parameters(("stack1.p1=v1,v2,v3", )))
Esempio n. 29
0
 def test_parse_cli_parameters_throws_exception_on_invalid_syntax(self):
     with self.assertRaises(CfnSphereException):
         Config._parse_cli_parameters(("foo",))
Esempio n. 30
0
 def test_parse_cli_parameters_accepts_list_of_int(self):
     self.assertDictEqual({'stack1': {'p1': '1,2,3'}},
                          Config._parse_cli_parameters(("stack1.p1=1,2,3",)))
Esempio n. 31
0
 def test_parse_cli_parameters_accepts_list_of_strings(self):
     self.assertDictEqual({'stack1': {'p1': 'v1,v2,v3'}},
                          Config._parse_cli_parameters(("stack1.p1=v1,v2,v3",)))
Esempio n. 32
0
 def test_parse_cli_parameters_parses_single_int_parameter(self):
     self.assertDictEqual({'stack1': {'p1': '2'}}, Config._parse_cli_parameters(("stack1.p1=2",)))
Esempio n. 33
0
 def test_parse_cli_parameters_accepts_spaces(self):
     self.assertDictEqual({'stack1': {'p1': 'v1', 'p2': 'v2'}, 'stack2': {'p1': 'v1'}},
                          Config._parse_cli_parameters(("stack1.p1 = v1 ", "stack1.p2=v2", "stack2.p1=v1 ")))
Esempio n. 34
0
 def test_raises_exception_if_no_stacks_key(self):
     with self.assertRaises(NoConfigException):
         Config(config_dict={'region': 'eu-west-1'})
Esempio n. 35
0
 def test_parse_cli_parameters_accepts_list_of_int(self):
     self.assertDictEqual({'stack1': {
         'p1': '1,2,3'
     }}, Config._parse_cli_parameters(("stack1.p1=1,2,3", )))