def test_transform_template_raises_exception_on_embedded_reference(self): template_dict = { "Resources": {"key1": {"foo": ["|foo|foo", "b"]}} } with self.assertRaises(TemplateErrorException): CloudFormationTemplateTransformer.transform_template(CloudFormationTemplate(template_dict, "foo"))
def test_transform_template_raises_exception_on_unknown_at_reference_key( self): template_dict = {'Resources': {'@foo@': "foo"}} with self.assertRaises(TemplateErrorException): CloudFormationTemplateTransformer.transform_template( CloudFormationTemplate(template_dict, 'foo'))
def test_transform_template_raises_exception_on_unknown_reference_key(self): template_dict = { "Resources": {"|key|": "foo"} } with self.assertRaises(TemplateErrorException): CloudFormationTemplateTransformer.transform_template(CloudFormationTemplate(template_dict, "foo"))
def test_transform_template_raises_exception_on_unknown_at_reference_key(self): template_dict = { 'Resources': {'@foo@': "foo"} } with self.assertRaises(TemplateErrorException): CloudFormationTemplateTransformer.transform_template(CloudFormationTemplate(template_dict, 'foo'))
def test_transform_template_raises_exception_on_embedded_reference(self): template_dict = { 'Resources': {'key1': {"foo": ["|foo|foo", "b"]}} } with self.assertRaises(TemplateErrorException): CloudFormationTemplateTransformer.transform_template(CloudFormationTemplate(template_dict, 'foo'))
def test_transform_template_properly_handles_reference_in_list_of_lists(self): template_dict = { 'Resources': { 'myResource': { "Properties": { "PolicyDocument": { "Statement": [{ "Resource": { "Fn::Join": [ "", [ "a", "|Ref|b", "c" ] ] } }] } } } } } result = CloudFormationTemplateTransformer.transform_template(CloudFormationTemplate(template_dict, 'foo')) expected = {'myResource': {'Properties': { 'PolicyDocument': {'Statement': [{'Resource': {'Fn::Join': ['', ['a', {'Ref': 'b'}, 'c']]}}]}}}} self.assertEqual(expected, result.resources)
def render_template(filename): check_update_available() loader = FileLoader() template = loader.get_file_from_url(filename, None) template = CloudFormationTemplateTransformer.transform_template(template) click.echo(template.get_template_json())
def test_transform_template_properly_handles_reference_in_list_of_lists(self): template_dict = { "Resources": { "myResource": { "Properties": { "PolicyDocument": { "Statement": [{ "Resource": { "Fn::Join": [ "", [ "a", "|Ref|b", "c" ] ] } }] } } } } } result = CloudFormationTemplateTransformer.transform_template(CloudFormationTemplate(template_dict, "foo")) expected = {"myResource": {"Properties": { "PolicyDocument": {"Statement": [{"Resource": {"Fn::Join": ["", ["a", {"Ref": "b"}, "c"]]}}]}}}} self.assertEqual(expected, result.resources)
def test_transform_template_transforms_dict_list_items(self): template_dict = { 'Resources': { 'key1': { 'key2': [{ 'key3': 'value3', 'foo': { '|Join|': ['a', 'b'] } }] } } } result = CloudFormationTemplateTransformer.transform_template( CloudFormationTemplate(template_dict, 'foo')) expected = { 'key1': { 'key2': [{ 'foo': { 'Fn::Join': ['', ['a', 'b']] }, 'key3': 'value3' }] } } self.assertEqual(expected, result.resources)
def upload_cfn_to_s3(project, logger): """ This task is separate since they only work with Python2 >2.6 by the time being. Python3 support is underway. This means, when using Python<2.7, this task is not visible (see __init__.py). """ from cfn_sphere.file_loader import FileLoader from cfn_sphere.template.transformer import CloudFormationTemplateTransformer for path, filename in project.get_property('template_files'): template = FileLoader.get_file_from_url(filename, path) transformed = CloudFormationTemplateTransformer.transform_template( template) output = transformed.get_template_json() bucket_name = project.get_property('bucket_name') key_prefix = project.get_property('template_key_prefix') filename = filename.replace('.yml', '.json') filename = filename.replace('.yaml', '.json') version_path = '{0}v{1}/{2}'.format( key_prefix, project.version, filename) # latest_path = '{0}latest/{1}'.format(key_prefix, filename) acl = project.get_property('template_file_access_control') check_acl_parameter_validity('template_file_access_control', acl) upload_helper(logger, bucket_name, version_path, output, acl)
def upload_cfn_to_s3(project, logger): """ This task is separate since they only work with Python2 >2.6 by the time being. Python3 support is underway. This means, when using Python<2.7, this task is not visible (see __init__.py). """ from cfn_sphere.file_loader import FileLoader from cfn_sphere.template.transformer import CloudFormationTemplateTransformer for path, filename in project.get_property('template_files'): template = FileLoader.get_cloudformation_template(filename, path) transformed = CloudFormationTemplateTransformer.transform_template( template) output = transformed.get_template_json() bucket_name = project.get_property('bucket_name') key_prefix = project.get_property('template_key_prefix') filename = filename.replace('.yml', '.json') filename = filename.replace('.yaml', '.json') version_path = '{0}v{1}/{2}'.format(key_prefix, project.version, filename) # latest_path = '{0}latest/{1}'.format(key_prefix, filename) acl = project.get_property('template_file_access_control') check_acl_parameter_validity('template_file_access_control', acl) upload_helper(logger, bucket_name, version_path, output, acl)
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) combined_tags = dict(self.config.tags) combined_tags.update(stack_config.tags) parameters = self.parameter_resolver.resolve_parameter_values(stack_config.parameters, stack_name) stack = CloudFormationStack(template=template, parameters=parameters, tags=combined_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 test_transform_template_transforms_dict_list_items(self): template_dict = { "Resources": { "key1": { "key2": [{ "key3": "value3", "foo": { "|Join|": ["a", "b"] } }] } } } result = CloudFormationTemplateTransformer.transform_template( CloudFormationTemplate(template_dict, "foo")) expected = { "key1": { "key2": [{ "foo": { "Fn::Join": ["", ["a", "b"]] }, "key3": "value3" }] } } self.assertEqual(expected, result.resources)
def test_transform_template_transforms_join_with_embedded_ref(self): template_dict = {'Resources': {'key1': {"|join|.": ["|ref|foo", "b"]}}} result = CloudFormationTemplateTransformer.transform_template( CloudFormationTemplate(template_dict, 'foo')) expected = {'key1': {'Fn::Join': ['.', [{'Ref': 'foo'}, 'b']]}} self.assertEqual(expected, result.resources)
def test_transform_template_transforms_list_values(self): template_dict = {'Resources': {'key1': ["|ref|foo", "a", "b"]}} result = CloudFormationTemplateTransformer.transform_template( CloudFormationTemplate(template_dict, 'foo')) expected = {'key1': [{'Ref': 'foo'}, 'a', 'b']} self.assertEqual(expected, result.resources)
def test_transform_template_transforms_join_with_embedded_ref(self): template_dict = {"Resources": {"key1": {"|join|.": ["|ref|foo", "b"]}}} result = CloudFormationTemplateTransformer.transform_template( CloudFormationTemplate(template_dict, "foo")) expected = {"key1": {"Fn::Join": [".", [{"Ref": "foo"}, "b"]]}} self.assertEqual(expected, result.resources)
def test_transform_template_transforms_list_values(self): template_dict = {"Resources": {"key1": ["|ref|foo", "a", "b"]}} result = CloudFormationTemplateTransformer.transform_template( CloudFormationTemplate(template_dict, "foo")) expected = {"key1": [{"Ref": "foo"}, "a", "b"]} self.assertEqual(expected, result.resources)
def render_template(template_file, confirm): if not confirm: check_update_available() loader = FileLoader() template = loader.get_file_from_url(template_file, None) template = CloudFormationTemplateTransformer.transform_template(template) click.echo(template.get_pretty_template_json())
def test_transform_template_transforms_dict_list_items(self): template_dict = { 'Resources': {'key1': {'key2': [{'key3': 'value3', 'foo': {'|Join|': ['a', 'b']}}]}} } result = CloudFormationTemplateTransformer.transform_template(CloudFormationTemplate(template_dict, 'foo')) expected = {'key1': {'key2': [{'foo': {'Fn::Join': ['', ['a', 'b']]}, 'key3': 'value3'}]}} self.assertEqual(expected, result.resources)
def test_transform_template_transforms_references_in_conditions_section(self): template_dict = { 'Conditions': {'key1': ["|ref|foo", "a", "b"], "key2": "|Ref|baa"} } result = CloudFormationTemplateTransformer.transform_template(CloudFormationTemplate(template_dict, 'foo')) expected = {'key1': [{'Ref': 'foo'}, 'a', 'b'], 'key2': {'Ref': 'baa'}} self.assertEqual(expected, result.conditions)
def test_transform_template_transforms_list_values(self): template_dict = { 'Resources': {'key1': ["|ref|foo", "a", "b"]} } result = CloudFormationTemplateTransformer.transform_template(CloudFormationTemplate(template_dict, 'foo')) expected = {'key1': [{'Ref': 'foo'}, 'a', 'b']} self.assertEqual(expected, result.resources)
def test_transform_template_transforms_references_in_conditions_section(self): template_dict = { "Conditions": {"key1": ["|ref|foo", "a", "b"], "key2": "|Ref|baa"} } result = CloudFormationTemplateTransformer.transform_template(CloudFormationTemplate(template_dict, "foo")) expected = {"key1": [{"Ref": "foo"}, "a", "b"], "key2": {"Ref": "baa"}} self.assertEqual(expected, result.conditions)
def test_transform_template_transforms_join_with_embedded_ref(self): template_dict = { 'Resources': {'key1': {"|join|.": ["|ref|foo", "b"]}} } result = CloudFormationTemplateTransformer.transform_template(CloudFormationTemplate(template_dict, 'foo')) expected = {'key1': {'Fn::Join': ['.', [{'Ref': 'foo'}, 'b']]}} self.assertEqual(expected, result.resources)
def render_template(template_file, confirm, yes): confirm = confirm or yes if not confirm: check_update_available() loader = FileLoader() template = loader.get_cloudformation_template(template_file, None) template = CloudFormationTemplateTransformer.transform_template(template) click.echo(template.get_pretty_template_json())
def render_template(template_file, confirm, yes): confirm = confirm or yes if not confirm: check_update_available() loader = FileLoader() template = loader.get_cloudformation_template(template_file, None) template = CloudFormationTemplateTransformer.transform_template(template) click.echo(template.get_pretty_template_json())
def test_transform_template_properly_renders_dict(self): template_dict = { 'Resources': { 'key1': '|ref|value', 'key2': '|getatt|resource|attribute', '@TaupageUserData@': { 'key1': 'value', 'key2': { 'ref': 'value' }, 'key3': { '|join|.': ['a', 'b', 'c'] } } } } result = CloudFormationTemplateTransformer.transform_template( CloudFormationTemplate(template_dict, 'foo')) expected = { "key1": { "Ref": "value" }, "key2": { "Fn::GetAtt": ["resource", "attribute"] }, "UserData": { "Fn::Base64": { "Fn::Join": [ "\n", [ "#taupage-ami-config", { "Fn::Join": [": ", ["key1", "value"]] }, { "Fn::Join": [": ", ["key2", { "ref": "value" }]] }, { "Fn::Join": [ ": ", [ "key3", { "Fn::Join": [".", ["a", "b", "c"]] } ] ] } ] ] } } } six.assertCountEqual(self, expected, result.resources)
def get_template(template_url, working_dir, region, package_bucket): template = FileLoader.get_cloudformation_template( template_url, working_dir) additional_stack_description = "Config repo url: {0}".format( get_git_repository_remote_url(working_dir)) template = CloudFormationTemplateTransformer.transform_template( template, additional_stack_description) template = CloudFormationSamPackager.package(template_url, working_dir, template, region, package_bucket) return template
def test_transform_template_transforms_references_in_conditions_section( self): template_dict = { 'Conditions': { 'key1': ["|ref|foo", "a", "b"], "key2": "|Ref|baa" } } result = CloudFormationTemplateTransformer.transform_template( CloudFormationTemplate(template_dict, 'foo')) expected = {'key1': [{'Ref': 'foo'}, 'a', 'b'], 'key2': {'Ref': 'baa'}} self.assertEqual(expected, result.conditions)
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) template = FileLoader.get_cloudformation_template(stack_config.template_url,stack_config.working_dir) transformed_template = CloudFormationTemplateTransformer.transform_template(template) 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 parameters = self.parameter_resolver.resolve_parameter_values(stack_name, stack_config) merged_parameters = self.parameter_resolver.update_parameters_with_cli_parameters( parameters=parameters, cli_parameters=self.cli_parameters, stack_name=stack_name) self.logger.debug("Parameters after merging with cli options: {0}".format(merged_parameters)) stack = CloudFormationStack(template=transformed_template, parameters=merged_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) 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 validate_template(template_file, confirm): if not confirm: check_update_available() try: loader = FileLoader() template = loader.get_file_from_url(template_file, None) template = CloudFormationTemplateTransformer.transform_template(template) CloudFormation().validate_template(template) click.echo("Template is valid") except CfnSphereException as e: LOGGER.error(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)
def validate_template(template_file, confirm, yes): confirm = confirm or yes if not confirm: check_update_available() try: loader = FileLoader() template = loader.get_cloudformation_template(template_file, None) template = CloudFormationTemplateTransformer.transform_template(template) CloudFormation().validate_template(template) click.echo("Template is valid") except CfnSphereException as e: LOGGER.error(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)
def test_transform_template_properly_handles_reference_in_list_of_lists( self): template_dict = { 'Resources': { 'myResource': { "Properties": { "PolicyDocument": { "Statement": [{ "Resource": { "Fn::Join": ["", ["a", "|Ref|b", "c"]] } }] } } } } } result = CloudFormationTemplateTransformer.transform_template( CloudFormationTemplate(template_dict, 'foo')) expected = { 'myResource': { 'Properties': { 'PolicyDocument': { 'Statement': [{ 'Resource': { 'Fn::Join': ['', ['a', { 'Ref': 'b' }, 'c']] } }] } } } } self.assertEqual(expected, result.resources)
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 get_template(template_url, working_dir): template = FileLoader.get_cloudformation_template(template_url, working_dir) additional_stack_description = "Config repo url: {0}".format(get_git_repository_remote_url(working_dir)) return CloudFormationTemplateTransformer.transform_template(template, additional_stack_description)
def test_transform_template_properly_renders_dict(self): template_dict = { "Resources": { "myResource": { "key1": "|ref|value", "key2": "|getatt|resource|attribute", "@TaupageUserData@": { "key1": "value", "key2": { "ref": "value" }, "key3": { "|join|.": ["|Ref|a", "b", "c"] }, "key4": "|ref|value" } } } } result = CloudFormationTemplateTransformer.transform_template( CloudFormationTemplate(template_dict, "foo")) expected = { "myResource": { "key1": { "Ref": "value" }, "key2": { "Fn::GetAtt": ["resource", "attribute"] }, "UserData": { "Fn::Base64": { "Fn::Join": [ "\n", [ "#taupage-ami-config", { "Fn::Join": [": ", ["key1", "value"]] }, { "Fn::Join": [": ", ["key2", { "ref": "value" }]] }, { "Fn::Join": [ ": ", [ "key3", { "Fn::Join": [".", [{ "Ref": "a" }, "b", "c"]] } ] ] }, { "Fn::Join": [": ", ["key4", { "Ref": "value" }]] }, ] ] } } } } self.assertEqual(expected, result.resources)
def test_transform_template_properly_renders_dict(self): template_dict = { 'Resources': { "myResource": { 'key1': '|ref|value', 'key2': '|getatt|resource|attribute', '@TaupageUserData@': { 'key1': 'value', 'key2': {'ref': 'value'}, 'key3': {'|join|.': ['|Ref|a', 'b', 'c']}, 'key4': '|ref|value' } } } } result = CloudFormationTemplateTransformer.transform_template(CloudFormationTemplate(template_dict, 'foo')) expected = { "myResource": { "key1": { "Ref": "value" }, "key2": { "Fn::GetAtt": [ "resource", "attribute" ] }, "UserData": { "Fn::Base64": { "Fn::Join": [ "\n", [ "#taupage-ami-config", { "Fn::Join": [ ": ", [ "key1", "value" ] ] }, { "Fn::Join": [ ": ", [ "key2", { "ref": "value" } ] ] }, { "Fn::Join": [ ": ", [ "key3", { "Fn::Join": [ ".", [ {"Ref": "a"}, "b", "c" ] ] } ] ] }, { "Fn::Join": [ ": ", [ "key4", { "Ref": "value" } ] ] }, ] ] } } } } self.assertEqual(expected, result.resources)