def test_get_no_echo_parameter_keys_returns_parameter_keys_with_no_echo_set( self): template_body = { 'Parameters': { 'myParameter1': { 'Type': 'String', 'NoEcho': True }, 'myParameter2': { 'Type': 'String' }, 'myParameter3': { 'Type': 'Number', 'NoEcho': 'true' }, 'myParameter4': { 'Type': 'Number', 'NoEcho': 'false' }, 'myParameter5': { 'Type': 'Number', 'NoEcho': False } } } template = CloudFormationTemplate(template_body, 'some name') six.assertCountEqual(self, ['myParameter1', 'myParameter3'], template.get_no_echo_parameter_keys())
def get_file_from_url(cls, url, working_dir): if url.lower().startswith("s3://"): return CloudFormationTemplate(body_dict=cls._s3_get_file(url), name=os.path.basename(url)) else: return CloudFormationTemplate(body_dict=cls._fs_get_file( url, working_dir), name=os.path.basename(url))
def test_get_no_echo_parameter_keys_returns_parameter_keys_with_no_echo_set(self): template_body = { "Parameters": { "myParameter1": {"Type": "String", "NoEcho": True}, "myParameter2": {"Type": "String"}, "myParameter3": {"Type": "Number", "NoEcho": "true"}, "myParameter4": {"Type": "Number", "NoEcho": "false"}, "myParameter5": {"Type": "Number", "NoEcho": False}, } } template = CloudFormationTemplate(template_body, "some name") six.assertCountEqual(self, ["myParameter1", "myParameter3"], template.get_no_echo_parameter_keys())
def test_process_post_resources(self, handle_sns_subscriptions_mock): custom_resource_yaml = dedent(""" PostCustomResources: exposeTopicSubscription: Type: "Custom::SNS::Subscription" Properties: TopicArn: Ref: exposeTopicArn QueueResourceName: exposeQueue """) custom_resource_dict = yaml.load(custom_resource_yaml) template = CloudFormationTemplate(custom_resource_dict, 'foo') stack = CloudFormationStack(template, {}, 'foo', 'foo-region') CustomResourceHandler.process_post_resources(stack) handle_sns_subscriptions_mock.assert_called_once_with( { 'Type': 'Custom::SNS::Subscription', 'Properties': { 'TopicArn': { 'Ref': 'exposeTopicArn' }, 'QueueResourceName': 'exposeQueue' } }, 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_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_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_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_reference_key(self): template_dict = { "Resources": {"|key|": "foo"} } with self.assertRaises(TemplateErrorException): CloudFormationTemplateTransformer.transform_template(CloudFormationTemplate(template_dict, "foo"))
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_get_template_body_dict(self): template_body = { 'Description': 'some description', 'Metadata': { 'meta': 'value' }, 'Parameters': { 'parameter': 'value' }, 'Mappings': { 'mapping': 'value' }, 'Conditions': { 'condition': 'value' }, 'Resources': { 'resource': 'value' }, 'Outputs': { 'output': 'value' } } template = CloudFormationTemplate(template_body, 'some name') self.assertEquals(template.template_format_version, '2010-09-09') self.assertEquals(template.description, 'some description') self.assertEquals(template.metadata, {'meta': 'value'}) self.assertEquals(template.parameters, {'parameter': 'value'}) self.assertEquals(template.mappings, {'mapping': 'value'}) self.assertEquals(template.conditions, {'condition': 'value'}) self.assertEquals(template.resources, {'resource': 'value'}) self.assertEquals(template.outputs, {'output': 'value'})
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_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_get_template_body_dict_returns_template_format_value_as_string_if_date_given( self): template_dict = {'AWSTemplateFormatVersion': datetime.date(2010, 9, 9)} result = CloudFormationTemplate(template_dict, "Something").get_template_body_dict() template_version = result["AWSTemplateFormatVersion"] self.assertIsInstance(template_version, string_types) self.assertEqual(result["AWSTemplateFormatVersion"], "2010-09-09")
def test_get_template_body_dict_returns_default_version_if_none_given( self): template_dict = {} result = CloudFormationTemplate(template_dict, "Something").get_template_body_dict() template_version = result["AWSTemplateFormatVersion"] self.assertIsInstance(template_version, string_types) self.assertEqual(result["AWSTemplateFormatVersion"], "2010-09-09")
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_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 package(cls, template_url, working_dir, template, region, package_bucket): logger = get_logger() if not package_bucket: return template if template_url.lower().startswith( "s3://") or template_url.lower().startswith("https://"): raise Exception( "SAM packaging is only supported for local templates (not S3/HTTPS)" ) template_body_dict = template.get_template_body_dict() # Save template to a temporary file in the original template's # directory. Call `aws cloudformation package` to upload artifacts # to S3. aws_credentials = boto3.DEFAULT_SESSION.get_credentials() with tempfile.NamedTemporaryFile( mode="w", dir=os.path.dirname(os.path.join(working_dir, template_url)), suffix=".json") as src_fp: # Save the template. Ensure the buffer's flushed to disk before # calling `aws cloudformation package`. json.dump(template_body_dict, src_fp) src_fp.flush() # Open temporary file for the packaged template. # We'd previously used stdout, but the packaging process also # wrote status to stdout when the source artifact changed, causing # malformed JSON. with tempfile.NamedTemporaryFile(mode="r") as dst_fp: logger.info("Packaging {}".format(template_url)) result = subprocess.check_call( args=[ "aws", "cloudformation", "package", "--template-file", src_fp.name, "--s3-bucket", package_bucket, "--output-template-file", dst_fp.name, "--use-json" ], env=dict(os.environ, AWS_REGION=region, AWS_ACCESS_KEY_ID=aws_credentials.access_key, AWS_SECRET_ACCESS_KEY=aws_credentials.secret_key, AWS_SESSION_TOKEN=aws_credentials.token or ''), stdout=subprocess.DEVNULL, stderr=sys.stderr) result = dst_fp.read() template_body_dict = json.loads(result) template = CloudFormationTemplate(template_body_dict, template.name) return template
def get_cloudformation_template(cls, url, working_dir): """ Load file content from url and return cfn-sphere CloudFormationTemplate :param url: str :param working_dir: str :return: CloudFormationTemplate """ try: template_body_dict = cls.get_yaml_or_json_file(url, working_dir) return CloudFormationTemplate(body_dict=template_body_dict, name=os.path.basename(url)) except Exception as e: raise TemplateErrorException("Could not load file from {0}: {1}".format(url, e))
def test_get_pretty_parameters_string(self): template_body = { 'Parameters': { 'myParameter1': { 'Type': 'String', 'NoEcho': True }, 'myParameter2': { 'Type': 'String' }, 'myParameter3': { 'Type': 'Number', 'NoEcho': 'true' }, 'myParameter4': { 'Type': 'Number', 'NoEcho': 'false' }, 'myParameter5': { 'Type': 'Number', 'NoEcho': False } } } parameters = { 'myParameter1': 'super-secret', 'myParameter2': 'not-that-secret', 'myParameter3': 'also-super-secret', 'myParameter4': 'could-be-public', 'myParameter5': 'also-ok' } template = CloudFormationTemplate(template_body, 'just-another-template') stack = CloudFormationStack(template, parameters, 'just-another-stack', 'eu-west-1') expected_string = """+--------------+-----------------+ | Parameter | Value | +--------------+-----------------+ | myParameter1 | *** | | myParameter2 | not-that-secret | | myParameter3 | *** | | myParameter4 | could-be-public | | myParameter5 | also-ok | +--------------+-----------------+""" self.assertEqual(expected_string, util.get_pretty_parameters_string(stack))
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_get_template_calls_file_handler( self, get_git_repository_remote_url_mock, template_transformer_mock, file_loader_mock): template = CloudFormationTemplate({}, "my-template") file_loader_mock.get_cloudformation_template.return_value = template get_git_repository_remote_url_mock.return_value = "my-repository-url" TemplateHandler.get_template("my-template-url", "my-working-directory") file_loader_mock.get_cloudformation_template.assert_called_once_with( "my-template-url", "my-working-directory") get_git_repository_remote_url_mock.assert_called_once_with( "my-working-directory") template_transformer_mock.transform_template.assert_called_once_with( template, "Config repo url: my-repository-url")
def test_get_no_echo_parameter_keys(self): template_dict = { 'Parameters': { "a": { "Description": "param a", "Type": "String", "NoEcho": True }, "b": { "Description": "param a", "Type": "String" }, "c": { "Description": "param a", "Type": "String" }, "d": { "Description": "param a", "Type": "String", "NoEcho": "true" }, "e": { "Description": "param a", "Type": "String", "NoEcho": "True" }, "f": { "Description": "param a", "Type": "String", "NoEcho": None }, "g": { "Description": "param a", "Type": "String", "noecho": True }, } } result = CloudFormationTemplate( template_dict, "Something").get_no_echo_parameter_keys() self.assertEqual(sorted(result), ['a', 'd', 'e'])
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_get_no_echo_parameter_keys_returns_empty_list_with_none_parameters(self): template_body = {"Parameters": None} template = CloudFormationTemplate(template_body, "some name") six.assertCountEqual(self, [], template.get_no_echo_parameter_keys())
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_get_no_echo_parameter_keys_returns_empty_list_with_none_parameters( self): template_body = {'Parameters': None} template = CloudFormationTemplate(template_body, 'some name') six.assertCountEqual(self, [], template.get_no_echo_parameter_keys())
def test_get_no_echo_parameter_keys_for_empty_parameters(self): template_dict = {} result = CloudFormationTemplate( template_dict, "Something").get_no_echo_parameter_keys() self.assertEqual(result, [])