def test_read_reads_config_file_with_base_config(self): with self.runner.isolated_filesystem(): project_path = os.path.abspath('./example') config_dir = os.path.join(project_path, "config") stack_group_dir = os.path.join(config_dir, "A") os.makedirs(stack_group_dir) config = {"config": "config"} with open(os.path.join(stack_group_dir, "stack.yaml"), 'w') as\ config_file: yaml.safe_dump( config, stream=config_file, default_flow_style=False ) base_config = { "base_config": "base_config" } self.context.project_path = project_path config = ConfigReader(self.context).read( "A/stack.yaml", base_config ) assert config == { "project_path": project_path, "stack_group_path": "A", "config": "config", "base_config": "base_config" }
def step_impl(context, stack_name): config_reader = ConfigReader(context.sceptre_dir) stack = config_reader.construct_stack(stack_name + ".yaml") try: context.response = stack.template.validate() except ClientError as e: context.error = e
def step_impl(context, stack_name): config_reader = ConfigReader(context.sceptre_dir) stack = config_reader.construct_stack(stack_name + ".yaml") try: context.output = stack.template.body except Exception as e: context.error = e
def step_impl(context, stack_name): config_reader = ConfigReader(context.sceptre_dir) stack = config_reader.construct_stack(stack_name + ".yaml") try: stack.lock() except ClientError as e: context.error = e
def test_read_with_empty_config_file(self): config_reader = ConfigReader(self.context) config = config_reader.read("account/stack-group/region/subnets.yaml") assert config == { "project_path": self.test_project_path, "stack_group_path": "account/stack-group/region" }
def test_construct_stacks_with_valid_config(self, command_path, filepaths, expected_stacks, expected_command_stacks, full_scan): project_path, config_dir = self.create_project() for rel_path in filepaths: config = { "region": "region", "project_code": "project_code", "template_path": rel_path } abs_path = os.path.join(config_dir, rel_path) self.write_config(abs_path, config) self.context.project_path = project_path self.context.command_path = command_path self.context.full_scan = full_scan config_reader = ConfigReader(self.context) all_stacks, command_stacks = config_reader.construct_stacks() assert {str(stack) for stack in all_stacks} == expected_stacks assert {str(stack) for stack in command_stacks} == expected_command_stacks
def test_read_with_templated_config_file(self): self.context.user_variables = {"variable_key": "user_variable_value"} config_reader = ConfigReader(self.context) config_reader.templating_vars["stack_group_config"] = { "region": "region_region", "project_code": "account_project_code", "required_version": "'>1.0'", "template_bucket_name": "stack_group_template_bucket_name" } os.environ["TEST_ENV_VAR"] = "environment_variable_value" config = config_reader.read( "account/stack-group/region/security_groups.yaml" ) assert config == { 'project_path': self.context.project_path, "stack_group_path": "account/stack-group/region", "parameters": { "param1": "user_variable_value", "param2": "environment_variable_value", "param3": "region_region", "param4": "account_project_code", "param5": ">1.0", "param6": "stack_group_template_bucket_name" } }
def test_construct_stacks_constructs_stack(self, mock_Stack, mock_collect_s3_details): mock_Stack.return_value = sentinel.stack sentinel.stack.dependencies = [] mock_collect_s3_details.return_value = sentinel.s3_details self.context.project_path = os.path.abspath("tests/fixtures-vpc") self.context.command_path = "account/stack-group/region/vpc.yaml" stacks = ConfigReader(self.context).construct_stacks() mock_Stack.assert_any_call( name="account/stack-group/region/vpc", project_code="account_project_code", template_path=os.path.join(self.context.project_path, "templates/path/to/template"), region="region_region", profile="account_profile", parameters={"param1": "val1"}, sceptre_user_data={}, hooks={}, s3_details=sentinel.s3_details, dependencies=["child/level", "top/level"], iam_role=None, role_arn=None, protected=False, tags={}, external_name=None, notifications=None, on_failure=None, stack_timeout=0, required_version='>1.0', template_bucket_name='stack_group_template_bucket_name', template_key_prefix=None, stack_group_config={"custom_key": "custom_value"}) assert stacks == ({sentinel.stack}, {sentinel.stack})
def test_construct_stack_with_valid_config(self, mock_Stack, mock_collect_s3_details): mock_Stack.return_value = sentinel.stack mock_collect_s3_details.return_value = sentinel.s3_details config_reader = ConfigReader(self.test_project_pathectory) stack = config_reader.construct_stack( "account/stack-group/region/vpc.yaml") mock_Stack.assert_called_with( name="account/stack-group/region/vpc", project_code="account_project_code", template_path=os.path.join(self.test_project_pathectory, "path/to/template"), region="region_region", profile="account_profile", parameters={"param1": "val1"}, sceptre_user_data={}, hooks={}, s3_details=sentinel.s3_details, dependencies=["child/level", "top/level"], role_arn=None, protected=False, tags={}, external_name=None, notifications=None, on_failure=None, stack_timeout=0) assert stack == sentinel.stack
def test_missing_attr( self, filepaths, del_key ): project_path, config_dir = self.create_project() for rel_path in filepaths: config = { "project_code": "project_code", "region": "region", "template_path": rel_path } # Delete the mandatory key to be tested. del config[del_key] abs_path = os.path.join(config_dir, rel_path) self.write_config(abs_path, config) self.context.project_path = project_path try: config_reader = ConfigReader(self.context) all_stacks, command_stacks = config_reader.construct_stacks() except InvalidConfigFileError as e: # Test that the missing key is reported. assert del_key in str(e) except Exception: raise else: assert False
def test_read_with_empty_config_file(self): config_reader = ConfigReader(self.test_sceptre_directory) config = config_reader.read("account/stack-group/region/subnets.yaml") assert config == { "sceptre_dir": self.test_sceptre_directory, "stack_group_path": "account/stack-group/region" }
def test_existing_dependency( self, filepaths, dependency ): project_path, config_dir = self.create_project() for rel_path in filepaths: # Set up config with reference to an existing stack config = { "project_code": "project_code", "region": "region", "template_path": rel_path, "dependencies": [dependency] } abs_path = os.path.join(config_dir, rel_path) self.write_config(abs_path, config) self.context.project_path = project_path try: config_reader = ConfigReader(self.context) all_stacks, command_stacks = config_reader.construct_stacks() except Exception: raise else: assert True
def test_missing_dependency( self, filepaths, dependency ): project_path, config_dir = self.create_project() for rel_path in filepaths: # Set up config with reference to non-existing stack config = { "project_code": "project_code", "region": "region", "template_path": rel_path, "dependencies": [dependency] } abs_path = os.path.join(config_dir, rel_path) self.write_config(abs_path, config) self.context.project_path = project_path try: config_reader = ConfigReader(self.context) all_stacks, command_stacks = config_reader.construct_stacks() except DependencyDoesNotExistError as e: # Test that the missing dependency is reported. assert dependency in str(e) except Exception: raise else: assert False
def step_impl(context, stack_name): config_reader = ConfigReader(context.sceptre_dir) stack = config_reader.construct_stack(stack_name + ".yaml") try: stack.launch() except Exception as e: context.error = e
def test_read_reads_config_file(self, filepaths, target): with self.runner.isolated_filesystem(): project_path = os.path.abspath('./example') config_dir = os.path.join(project_path, "config") os.makedirs(config_dir) for rel_path in filepaths: abs_path = os.path.join(config_dir, rel_path) if not os.path.exists(os.path.dirname(abs_path)): try: os.makedirs(os.path.dirname(abs_path)) except OSError as exc: if exc.errno != errno.EEXIST: raise config = {"filepath": rel_path} with open(abs_path, 'w') as config_file: yaml.safe_dump( config, stream=config_file, default_flow_style=False ) self.context.project_path = project_path config = ConfigReader(self.context).read(target) assert config == { "project_path": project_path, "stack_group_path": os.path.split(target)[0], "filepath": target }
def test_construct_stacks_with_valid_config( self, filepaths, expected_stacks ): with self.runner.isolated_filesystem(): project_path = os.path.abspath('./example') config_dir = os.path.join(project_path, "config") os.makedirs(config_dir) for rel_path in filepaths: abs_path = os.path.join(config_dir, rel_path) dir_path = abs_path if abs_path.endswith(".yaml"): dir_path = os.path.split(abs_path)[0] if not os.path.exists(dir_path): try: os.makedirs(dir_path) except OSError as exc: if exc.errno != errno.EEXIST: raise config = { "region": "region", "project_code": "project_code", "template_path": rel_path } with open(abs_path, 'w') as config_file: yaml.safe_dump( config, stream=config_file, default_flow_style=False ) self.context.project_path = project_path config_reader = ConfigReader(self.context) all_stacks, command_stacks = config_reader.construct_stacks() assert {str(stack) for stack in all_stacks} == expected_stacks
def test_read_with_nonexistant_filepath(self): with self.runner.isolated_filesystem(): sceptre_dir = os.path.abspath('./example') config_dir = os.path.join(sceptre_dir, "config") os.makedirs(config_dir) with pytest.raises(ConfigFileNotFoundError): ConfigReader(sceptre_dir).read("stack.yaml")
def test_read_with_nonexistant_filepath(self): with self.runner.isolated_filesystem(): project_path = os.path.abspath('./example') config_dir = os.path.join(project_path, "config") os.makedirs(config_dir) self.context.project_path = project_path with pytest.raises(ConfigFileNotFoundError): ConfigReader(self.context).read("stack.yaml")
def step_impl(context, stack_name): config_reader = ConfigReader(context.sceptre_dir) stack = config_reader.construct_stack(stack_name + ".yaml") try: stack.create() except ClientError as e: if e.response['Error']['Code'] == 'AlreadyExistsException' \ and e.response['Error']['Message'].endswith("already exists"): return else: raise e
def step_impl(context, stack_name): config_reader = ConfigReader(context.sceptre_dir) stack = config_reader.construct_stack(stack_name + ".yaml") try: stack.delete() except ClientError as e: if e.response['Error']['Code'] == 'ValidationError' \ and e.response['Error']['Message'].endswith("does not exist"): return else: raise e
def get_stack(ctx, path): """ Parses the path to generate relevant StackGroup and Stack object. :param ctx: Cli context. :type ctx: click.Context :param path: Path to either stack config or stack_group folder. :type path: str """ return ConfigReader(ctx.obj["sceptre_dir"], ctx.obj["options"]).construct_stack(path)
def get_stack(context, path): """ Parses the path to generate relevant StackGroup and Stack object. :param context: Cli context. :type context: click.Context :param path: Path to either stack config or stack_group folder. :type path: str """ return ConfigReader( context.project_path, context.options ).construct_stack(path)
def test_resolve_node_tag(self): mock_loader = MagicMock(yaml.Loader) mock_loader.resolve.return_value = "new_tag" mock_node = MagicMock(yaml.Node) mock_node.tag = "old_tag" mock_node.value = "String" config_reader = ConfigReader(self.context) new_node = config_reader.resolve_node_tag(mock_loader, mock_node) assert new_node.tag == 'new_tag'
def step_impl(context, change_set_name, stack_name): config_reader = ConfigReader(context.sceptre_dir) stack = config_reader.construct_stack(stack_name + ".yaml") allowed_errors = {'ValidationError', 'ChangeSetNotFound'} try: stack.execute_change_set(change_set_name) except ClientError as e: if e.response['Error']['Code'] in allowed_errors: context.error = e return else: raise e
def step_impl(context, stack_name): config_reader = ConfigReader(context.sceptre_dir) stack = config_reader.construct_stack(stack_name + ".yaml") try: stack.update() except ClientError as e: message = e.response['Error']['Message'] if e.response['Error']['Code'] == 'ValidationError' \ and (message.endswith("does not exist") or message.endswith("No updates are to be performed.")): return else: raise e
def test_read_reads_config_file(self, filepaths, target): project_path, config_dir = self.create_project() for rel_path in filepaths: config = {"filepath": rel_path} abs_path = os.path.join(config_dir, rel_path) self.write_config(abs_path, config) self.context.project_path = project_path config = ConfigReader(self.context).read(target) assert config == { "project_path": project_path, "stack_group_path": os.path.split(target)[0], "filepath": target }
def __init__(self, context): """ Intialises a SceptrePlan and generates the Stacks, StackGraph and launch order of required. :param context: A SceptreContext :type sceptre.context.SceptreContext: """ self.context = context self.command = None self.reverse = None self.launch_order = None config_reader = ConfigReader(context) all_stacks, command_stacks = config_reader.construct_stacks() self.graph = StackGraph(all_stacks) self.command_stacks = command_stacks
def test_missing_attr( self, filepaths, target, del_key ): with self.runner.isolated_filesystem(): project_path = os.path.abspath('./example') config_dir = os.path.join(project_path, "config") os.makedirs(config_dir) self.context.project_path = project_path for rel_path in filepaths: abs_path = os.path.join(config_dir, rel_path) dir_path = abs_path if abs_path.endswith(".yaml"): dir_path = os.path.split(abs_path)[0] if not os.path.exists(dir_path): try: os.makedirs(dir_path) except OSError as exc: if exc.errno != errno.EEXIST: raise config = { "project_code": "project_code", "region": "region", "template_path": rel_path } # Delete the mandatory key to be tested. del config[del_key] with open(abs_path, 'w') as config_file: yaml.safe_dump( config, stream=config_file, default_flow_style=False ) try: config_reader = ConfigReader(self.context) all_stacks, command_stacks = config_reader.construct_stacks() except InvalidConfigFileError as e: # Test that the missing key is reported. assert del_key in str(e) except Exception: raise else: assert False
def test_construct_stack_group_with_valid_config(self, filepaths, targets, results): with self.runner.isolated_filesystem(): project_path = os.path.abspath('./example') config_dir = os.path.join(project_path, "config") os.makedirs(config_dir) for rel_path in filepaths: abs_path = os.path.join(config_dir, rel_path) dir_path = abs_path if abs_path.endswith(".yaml"): dir_path = os.path.split(abs_path)[0] if not os.path.exists(dir_path): try: os.makedirs(dir_path) except OSError as exc: if exc.errno != errno.EEXIST: raise config = { "region": "region", "project_code": "project_code", "template_path": rel_path } with open(abs_path, 'w') as config_file: yaml.safe_dump(config, stream=config_file, default_flow_style=False) config_reader = ConfigReader(project_path) def check_stack_group(stack_group, details): assert sorted(details["stacks"]) == sorted( [stack.name for stack in stack_group.stacks]) for sub_group in stack_group.sub_stack_groups: sub_group_details =\ details["stack_groups"][sub_group.path] check_stack_group(sub_group, sub_group_details) for i, target in enumerate(targets): stack_group =\ config_reader.construct_stack_group(target) expected = results[i] check_stack_group(stack_group, expected[stack_group.path])
def get_stack_or_stack_group(ctx, path): """ Parses the path to generate relevant Stack Group and Stack object. :param ctx: Cli context. :type ctx: click.Context :param path: Path to either stack config or stack_group folder. :type path: str """ stack = None stack_group = None config_reader = ConfigReader(ctx.obj["sceptre_dir"], ctx.obj["user_variables"]) if os.path.splitext(path)[1]: stack = config_reader.construct_stack(path) else: stack_group = config_reader.construct_stack_group(path) return (stack, stack_group)