Exemplo n.º 1
0
    def test_len_single_resource(self):
        resource_refs = SupportedResourceReferences()

        resource_refs.add("logicalId1", "property1", "value1")
        resource_refs.add("logicalId1", "property2", "value2")
        self.assertEqual(
            1, len(resource_refs))  # Each unique logicalId adds one to the len
Exemplo n.º 2
0
    def setUp(self):
        self.supported_resource_refs = SupportedResourceReferences()
        self.supported_resource_refs.add("id1", "prop1", "value1")
        self.supported_resource_refs.add("id1", "prop2", "value2")
        self.supported_resource_refs.add("id2", "prop3", "value3")

        self.input_sub_value = "Hello ${id1.prop1} ${id1.prop2}${id2.prop3} ${id1.prop1.arn} ${id1.prop2.arn.name.foo} ${!id1.prop1} ${unknown} ${some.arn} World"
        self.expected_output_sub_value = "Hello ${value1} ${value2}${value3} ${value1.arn} ${value2.arn.name.foo} ${!id1.prop1} ${unknown} ${some.arn} World"
    def test_add_must_error_on_duplicate_value(self):

        resource_refs = SupportedResourceReferences()

        resource_refs.add("logicalId", "property", "value1")

        with self.assertRaises(ValueError):
            resource_refs.add("logicalId", "property", "value2")
Exemplo n.º 4
0
    def test_get_must_return_correct_value(self):
        resource_refs = SupportedResourceReferences()

        resource_refs.add("logicalId1", "property1", "value1")
        resource_refs.add("logicalId1", "property2", "value2")
        resource_refs.add("newLogicalId", "newProperty", "newValue")

        self.assertEqual("value1", resource_refs.get("logicalId1",
                                                     "property1"))
        self.assertEqual("value2", resource_refs.get("logicalId1",
                                                     "property2"))
        self.assertEqual("newValue",
                         resource_refs.get("newLogicalId", "newProperty"))
Exemplo n.º 5
0
    def test_add_multiple_logical_ids(self):
        resource_refs = SupportedResourceReferences()

        resource_refs.add("logicalId1", "property1", "value1")
        resource_refs.add("logicalId2", "property2", "value2")
        resource_refs.add("logicalId3", "property3", "value3")

        self.assertEqual({"property1": "value1"},
                         resource_refs.get_all("logicalId1"))
        self.assertEqual({"property2": "value2"},
                         resource_refs.get_all("logicalId2"))
        self.assertEqual({"property3": "value3"},
                         resource_refs.get_all("logicalId3"))
    def setUp(self):
        self.supported_resource_refs = SupportedResourceReferences()
        self.supported_resource_refs.add("id1", "prop1", "value1")
        self.supported_resource_refs.add("id1", "prop2", "value2")
        self.supported_resource_refs.add("id2", "prop3", "value3")

        self.input_sub_value = "Hello ${id1.prop1} ${id1.prop2}${id2.prop3} ${id1.prop1.arn} ${id1.prop2.arn.name.foo} ${!id1.prop1} ${unknown} ${some.arn} World"
        self.expected_output_sub_value = "Hello ${value1} ${value2}${value3} ${value1.arn} ${value2.arn.name.foo} ${!id1.prop1} ${unknown} ${some.arn} World"
    def test_get_must_return_correct_value(self):
        resource_refs = SupportedResourceReferences()

        resource_refs.add("logicalId1", "property1", "value1")
        resource_refs.add("logicalId1", "property2", "value2")
        resource_refs.add("newLogicalId", "newProperty", "newValue")

        self.assertEquals("value1", resource_refs.get("logicalId1", "property1"))
        self.assertEquals("value2", resource_refs.get("logicalId1", "property2"))
        self.assertEquals("newValue", resource_refs.get("newLogicalId", "newProperty"))
    def test_add_multiple_logical_ids(self):
        resource_refs = SupportedResourceReferences()

        resource_refs.add("logicalId1", "property1", "value1")
        resource_refs.add("logicalId2", "property2", "value2")
        resource_refs.add("logicalId3", "property3", "value3")

        self.assertEquals({"property1": "value1"}, resource_refs.get_all("logicalId1"))
        self.assertEquals({"property2": "value2"}, resource_refs.get_all("logicalId2"))
        self.assertEquals({"property3": "value3"}, resource_refs.get_all("logicalId3"))
Exemplo n.º 9
0
    def test_add_must_error_on_duplicate_value(self):

        resource_refs = SupportedResourceReferences()

        resource_refs.add("logicalId", "property", "value1")

        with self.assertRaises(ValueError):
            resource_refs.add("logicalId", "property", "value2")
Exemplo n.º 10
0
    def test_get_on_non_existent_property(self):
        resource_refs = SupportedResourceReferences()

        resource_refs.add("logicalId1", "property1", "value1")
        self.assertEquals(None, resource_refs.get("logicalId1",
                                                  "SomeProperty"))
        self.assertEquals(None, resource_refs.get("SomeLogicalId",
                                                  "property1"))
Exemplo n.º 11
0
    def test_add_multiple_properties_to_one_logicalId(self):

        resource_refs = SupportedResourceReferences()

        resource_refs.add("logicalId", "property1", "value1")
        resource_refs.add("logicalId", "property2", "value2")
        resource_refs.add("logicalId", "property3", "value3")

        expected = {
            "property1": "value1",
            "property2": "value2",
            "property3": "value3"
        }

        self.assertEqual(expected, resource_refs.get_all("logicalId"))
    def test_add_multiple_properties_to_one_logicalId(self):

        resource_refs = SupportedResourceReferences()

        resource_refs.add("logicalId", "property1", "value1")
        resource_refs.add("logicalId", "property2", "value2")
        resource_refs.add("logicalId", "property3", "value3")

        expected = {
            "property1": "value1",
            "property2": "value2",
            "property3": "value3"
        }

        self.assertEquals(expected, resource_refs.get_all("logicalId"))
Exemplo n.º 13
0
 def setUp(self):
     self.supported_resource_refs = SupportedResourceReferences()
     self.supported_resource_refs.add("id1", "prop1", "value1")
Exemplo n.º 14
0
class TestGetAttCanResolveResourceRefs(TestCase):
    def setUp(self):
        self.supported_resource_refs = SupportedResourceReferences()
        self.supported_resource_refs.add("id1", "prop1", "value1")

    def test_must_resolve_simple_refs(self):
        input = {"Fn::GetAtt": ["id1.prop1", "Arn"]}

        expected = {"Fn::GetAtt": ["value1", "Arn"]}

        getatt = GetAttAction()
        output = getatt.resolve_resource_refs(input,
                                              self.supported_resource_refs)

        self.assertEqual(expected, output)

    def test_must_resolve_refs_with_many_attributes(self):
        input = {"Fn::GetAtt": ["id1.prop1", "Arn1", "Arn2", "Arn3"]}

        expected = {"Fn::GetAtt": ["value1", "Arn1", "Arn2", "Arn3"]}

        getatt = GetAttAction()
        output = getatt.resolve_resource_refs(input,
                                              self.supported_resource_refs)

        self.assertEqual(expected, output)

    def test_must_resolve_with_splitted_resource_refs(self):
        input = {
            # Reference to resource `id1.prop1` is split into different elements
            "Fn::GetAtt": ["id1", "prop1", "Arn1", "Arn2", "Arn3"]
        }

        expected = {"Fn::GetAtt": ["value1", "Arn1", "Arn2", "Arn3"]}

        getatt = GetAttAction()
        output = getatt.resolve_resource_refs(input,
                                              self.supported_resource_refs)

        self.assertEqual(expected, output)

    def test_must_ignore_refs_without_attributes(self):
        input = {
            # No actual attributes. But since we have two entries in the array, we try to resolve them
            "Fn::GetAtt": ["id1", "prop1"]
        }

        expected = {"Fn::GetAtt": ["value1"]}

        getatt = GetAttAction()
        output = getatt.resolve_resource_refs(input,
                                              self.supported_resource_refs)

        self.assertEqual(expected, output)

    def test_must_ignore_refs_without_attributes_in_concatenated_form(self):
        input = {
            # No actual attributes. with just only one entry in array, the value never gets resolved
            "Fn::GetAtt": ["id1.prop1"]
        }

        expected = {"Fn::GetAtt": ["id1.prop1"]}

        getatt = GetAttAction()
        output = getatt.resolve_resource_refs(input,
                                              self.supported_resource_refs)

        self.assertEqual(expected, output)

    def test_must_ignore_invalid_value_array(self):
        input = {
            # No actual attributes
            "Fn::GetAtt": ["id1"]
        }

        expected = {"Fn::GetAtt": ["id1"]}

        getatt = GetAttAction()
        output = getatt.resolve_resource_refs(input,
                                              self.supported_resource_refs)

        self.assertEqual(expected, output)

    def test_must_ignore_invalid_value_type(self):
        input = {
            # No actual attributes
            "Fn::GetAtt": {
                "a": "b"
            }
        }

        expected = {"Fn::GetAtt": {"a": "b"}}

        getatt = GetAttAction()
        output = getatt.resolve_resource_refs(input,
                                              self.supported_resource_refs)

        self.assertEqual(expected, output)

    def test_must_ignore_missing_properties_with_dot_after(self):
        input = {"Fn::GetAtt": ["id1.", "foo"]}
        expected = {"Fn::GetAtt": ["id1.", "foo"]}

        getatt = GetAttAction()
        output = getatt.resolve_resource_refs(input,
                                              self.supported_resource_refs)

        self.assertEqual(expected, output)

    def test_must_ignore_missing_properties_with_dot_before(self):
        input = {"Fn::GetAtt": [".id1", "foo"]}
        expected = {"Fn::GetAtt": [".id1", "foo"]}

        getatt = GetAttAction()
        output = getatt.resolve_resource_refs(input,
                                              self.supported_resource_refs)

        self.assertEqual(expected, output)

    @patch.object(GetAttAction, "can_handle")
    def test_return_value_if_cannot_handle(self, can_handle_mock):
        input = {"Fn::GetAtt": ["id1", "prop1"]}
        expected = {"Fn::GetAtt": ["id1", "prop1"]}

        getatt = GetAttAction()
        can_handle_mock.return_value = False  # Simulate failure to handle the input. Result should be same as input
        self.assertEqual(
            expected,
            getatt.resolve_resource_refs(input, self.supported_resource_refs))
 def test_add_must_error_if_value_is_not_string(self):
     resource_refs = SupportedResourceReferences()
     with self.assertRaises(ValueError):
         resource_refs.add("logicalId", "property", {"a": "b"})
    def test_len_multiple_resources(self):
        resource_refs = SupportedResourceReferences()

        resource_refs.add("logicalId1", "property1", "value1")
        resource_refs.add("logicalId2", "property2", "value2")
        self.assertEquals(2, len(resource_refs))
class TestGetAttCanResolveResourceRefs(TestCase):

    def setUp(self):
        self.supported_resource_refs = SupportedResourceReferences()
        self.supported_resource_refs.add("id1", "prop1", "value1")

    def test_must_resolve_simple_refs(self):
        input = {
            "Fn::GetAtt": ["id1.prop1", "Arn"]
        }

        expected = {
            "Fn::GetAtt": ["value1", "Arn"]
        }

        getatt = GetAttAction()
        output = getatt.resolve_resource_refs(input, self.supported_resource_refs)

        self.assertEqual(expected, output)

    def test_must_resolve_refs_with_many_attributes(self):
        input = {
            "Fn::GetAtt": ["id1.prop1", "Arn1", "Arn2", "Arn3"]
        }

        expected = {
            "Fn::GetAtt": ["value1", "Arn1", "Arn2", "Arn3"]
        }

        getatt = GetAttAction()
        output = getatt.resolve_resource_refs(input, self.supported_resource_refs)

        self.assertEqual(expected, output)

    def test_must_resolve_with_splitted_resource_refs(self):
        input = {
            # Reference to resource `id1.prop1` is split into different elements
            "Fn::GetAtt": ["id1", "prop1", "Arn1", "Arn2", "Arn3"]
        }

        expected = {
            "Fn::GetAtt": ["value1", "Arn1", "Arn2", "Arn3"]
        }

        getatt = GetAttAction()
        output = getatt.resolve_resource_refs(input, self.supported_resource_refs)

        self.assertEqual(expected, output)

    def test_must_ignore_refs_without_attributes(self):
        input = {
            # No actual attributes. But since we have two entries in the array, we try to resolve them
            "Fn::GetAtt": ["id1", "prop1"]
        }

        expected = {
            "Fn::GetAtt": ["value1"]
        }

        getatt = GetAttAction()
        output = getatt.resolve_resource_refs(input, self.supported_resource_refs)

        self.assertEqual(expected, output)

    def test_must_ignore_refs_without_attributes_in_concatenated_form(self):
        input = {
            # No actual attributes. with just only one entry in array, the value never gets resolved
            "Fn::GetAtt": ["id1.prop1"]
        }

        expected = {
            "Fn::GetAtt": ["id1.prop1"]
        }

        getatt = GetAttAction()
        output = getatt.resolve_resource_refs(input, self.supported_resource_refs)

        self.assertEqual(expected, output)

    def test_must_ignore_invalid_value_array(self):
        input = {
            # No actual attributes
            "Fn::GetAtt": ["id1"]
        }

        expected = {
            "Fn::GetAtt": ["id1"]
        }

        getatt = GetAttAction()
        output = getatt.resolve_resource_refs(input, self.supported_resource_refs)

        self.assertEqual(expected, output)

    def test_must_ignore_invalid_value_type(self):
        input = {
            # No actual attributes
            "Fn::GetAtt": {"a": "b"}
        }

        expected = {
            "Fn::GetAtt": {"a": "b"}
        }

        getatt = GetAttAction()
        output = getatt.resolve_resource_refs(input, self.supported_resource_refs)

        self.assertEqual(expected, output)

    def test_must_ignore_missing_properties_with_dot_after(self):
        input = {
            "Fn::GetAtt": ["id1.", "foo"]
        }
        expected = {
            "Fn::GetAtt": ["id1.", "foo"]
        }

        getatt = GetAttAction()
        output = getatt.resolve_resource_refs(input, self.supported_resource_refs)

        self.assertEqual(expected, output)

    def test_must_ignore_missing_properties_with_dot_before(self):
        input = {
            "Fn::GetAtt": [".id1", "foo"]
        }
        expected = {
            "Fn::GetAtt": [".id1", "foo"]
        }

        getatt = GetAttAction()
        output = getatt.resolve_resource_refs(input, self.supported_resource_refs)

        self.assertEqual(expected, output)

    @patch.object(GetAttAction, "can_handle")
    def test_return_value_if_cannot_handle(self, can_handle_mock):
        input = {
            "Fn::GetAtt": ["id1", "prop1"]
        }
        expected = {
            "Fn::GetAtt": ["id1", "prop1"]
        }

        getatt = GetAttAction()
        can_handle_mock.return_value = False # Simulate failure to handle the input. Result should be same as input
        self.assertEqual(expected, getatt.resolve_resource_refs(input, self.supported_resource_refs))
class TestSubCanResolveResourceRefs(TestCase):

    def setUp(self):
        self.supported_resource_refs = SupportedResourceReferences()
        self.supported_resource_refs.add("id1", "prop1", "value1")
        self.supported_resource_refs.add("id1", "prop2", "value2")
        self.supported_resource_refs.add("id2", "prop3", "value3")

        self.input_sub_value = "Hello ${id1.prop1} ${id1.prop2}${id2.prop3} ${id1.prop1.arn} ${id1.prop2.arn.name.foo} ${!id1.prop1} ${unknown} ${some.arn} World"
        self.expected_output_sub_value = "Hello ${value1} ${value2}${value3} ${value1.arn} ${value2.arn.name.foo} ${!id1.prop1} ${unknown} ${some.arn} World"

    def test_must_resolve_string_value(self):

        input = {
            "Fn::Sub": self.input_sub_value
        }
        expected = {
            "Fn::Sub": self.expected_output_sub_value
        }

        sub = SubAction()
        result = sub.resolve_resource_refs(input, self.supported_resource_refs)

        self.assertEqual(expected, result)

    def test_must_resolve_array_value(self):
        input = {
            "Fn::Sub": [self.input_sub_value, {"unknown":"a"}]
        }

        expected = {
            "Fn::Sub": [self.expected_output_sub_value, {"unknown": "a"}]
        }

        sub = SubAction()
        result = sub.resolve_resource_refs(input, self.supported_resource_refs)

        self.assertEqual(expected, result)

    def test_sub_all_refs_with_list_input(self):
        parameters = {
            "key1": "value1",
            "key2": "value2"
        }
        input = {
            "Fn::Sub": ["key1", "key2"]
        }
        expected = {
            "Fn::Sub": ["key1", "key2"]
        }

        sub = SubAction()
        result = sub.resolve_resource_refs(input, parameters)

        self.assertEqual(expected, result)

    def test_sub_all_refs_with_dict_input(self):
        parameters = {
            "key1": "value1",
            "key2": "value2"
        }
        input = {
            "Fn::Sub": {"a": "key1", "b": "key2"}
        }
        expected = {
            "Fn::Sub": {"a": "key1", "b": "key2"}
        }

        sub = SubAction()
        result = sub.resolve_resource_refs(input, parameters)

        self.assertEqual(expected, result)

    @patch.object(SubAction, "can_handle")
    def test_return_value_if_cannot_handle(self, can_handle_mock):
        parameters = {
            "key": "value"
        }
        input = {
            "Fn::Sub": "${key}"
        }
        expected = {
            "Fn::Sub": "${key}"
        }

        sub = SubAction()
        can_handle_mock.return_value = False # Simulate failure to handle the input. Result should be same as input
        self.assertEqual(expected, sub.resolve_resource_refs(input, parameters))
Exemplo n.º 19
0
 def setUp(self):
     self.supported_resource_refs = SupportedResourceReferences()
Exemplo n.º 20
0
 def test_add_must_error_when_property_is_absent(self):
     resource_refs = SupportedResourceReferences()
     with self.assertRaises(ValueError):
         resource_refs.add("logicalId", "", "value1")
class TestSamResourceReferableProperties(TestCase):

    class ResourceType1(Resource):
        resource_type = "resource_type1"
        property_types = {}

    class ResourceType2(Resource):
        resource_type = "resource_type2"
        property_types = {}

    class ResourceType3(Resource):
        resource_type = "resource_type3"
        property_types = {}

    def setUp(self):
        self.supported_resource_refs = SupportedResourceReferences()

    def test_must_get_property_for_available_resources(self):
        class NewSamResource(SamResourceMacro):
            resource_type = "foo"
            property_types = {}
            referable_properties = {
                "prop1": "resource_type1",
                "prop2": "resource_type2",
                "prop3": "resource_type3"
            }

        sam_resource = NewSamResource("SamLogicalId")

        cfn_resources = [self.ResourceType1("logicalId1"),
                     self.ResourceType2("logicalId2")]

        self.supported_resource_refs = \
            sam_resource.get_resource_references(cfn_resources, self.supported_resource_refs)

        self.assertEqual("logicalId1", self.supported_resource_refs.get("SamLogicalId", "prop1"))
        self.assertEqual("logicalId2", self.supported_resource_refs.get("SamLogicalId", "prop2"))

        # there is no cfn resource of for "prop3" in the cfn_resources list
        self.assertEqual(None, self.supported_resource_refs.get("SamLogicalId", "prop3"))

        # Must add only for the given SAM resource
        self.assertEqual(1, len(self.supported_resource_refs))

    def test_must_work_with_two_resources_of_same_type(self):
        class NewSamResource(SamResourceMacro):
            resource_type = "foo"
            property_types = {}
            referable_properties = {
                "prop1": "resource_type1",
                "prop2": "resource_type2",
                "prop3": "resource_type3"
            }

        sam_resource1 = NewSamResource("SamLogicalId1")
        sam_resource2 = NewSamResource("SamLogicalId2")

        cfn_resources = [self.ResourceType1("logicalId1"),
                         self.ResourceType2("logicalId2")
                         ]

        self.supported_resource_refs = \
            sam_resource1.get_resource_references(cfn_resources, self.supported_resource_refs)

        self.supported_resource_refs = \
            sam_resource2.get_resource_references(cfn_resources, self.supported_resource_refs)

        self.assertEqual("logicalId1", self.supported_resource_refs.get("SamLogicalId1", "prop1"))
        self.assertEqual("logicalId2", self.supported_resource_refs.get("SamLogicalId1", "prop2"))
        self.assertEqual("logicalId1", self.supported_resource_refs.get("SamLogicalId2", "prop1"))
        self.assertEqual("logicalId2", self.supported_resource_refs.get("SamLogicalId2", "prop2"))

        self.assertEqual(2, len(self.supported_resource_refs))

    def test_must_skip_unknown_resource_types(self):
        class NewSamResource(SamResourceMacro):
            resource_type = "foo"
            property_types = {}
            referable_properties = {
                "prop1": "foo",
                "prop2": "bar",
            }

        sam_resource = NewSamResource("SamLogicalId")

        # None of the CFN resource types are in the referable list
        cfn_resources = [self.ResourceType1("logicalId1"),
                     self.ResourceType2("logicalId2")]

        self.supported_resource_refs = \
            sam_resource.get_resource_references(cfn_resources, self.supported_resource_refs)

        self.assertEqual(0, len(self.supported_resource_refs))

    def test_must_skip_if_no_supported_properties(self):
        class NewSamResource(SamResourceMacro):
            resource_type = "foo"
            property_types = {}
            referable_properties = {}

        sam_resource = NewSamResource("SamLogicalId")

        cfn_resources = [self.ResourceType1("logicalId1"),
                     self.ResourceType2("logicalId2")]

        self.supported_resource_refs = \
            sam_resource.get_resource_references(cfn_resources, self.supported_resource_refs)

        self.assertEqual(0, len(self.supported_resource_refs))

    def test_must_skip_if_no_resources(self):
        class NewSamResource(SamResourceMacro):
            resource_type = "foo"
            property_types = {}
            referable_properties = {"prop1": "resource_type1"}

        sam_resource = NewSamResource("SamLogicalId")

        cfn_resources = []

        self.supported_resource_refs = \
            sam_resource.get_resource_references(cfn_resources, self.supported_resource_refs)

        self.assertEqual(0, len(self.supported_resource_refs))

    def test_must_raise_if_input_is_absent(self):
        class NewSamResource(SamResourceMacro):
            resource_type = "foo"
            property_types = {}
            referable_properties = {"prop1": "resource_type1"}

        sam_resource = NewSamResource("SamLogicalId")

        cfn_resources = [self.ResourceType1("logicalId1")]

        with self.assertRaises(ValueError):
            sam_resource.get_resource_references(cfn_resources, None)
Exemplo n.º 22
0
 def test_add_must_error_if_value_is_not_string(self):
     resource_refs = SupportedResourceReferences()
     with self.assertRaises(ValueError):
         resource_refs.add("logicalId", "property", {"a": "b"})
    def test_get_all_on_non_existent_logical_id(self):
        resource_refs = SupportedResourceReferences()

        resource_refs.add("logicalId", "property", "value1")

        self.assertEquals(None, resource_refs.get_all("some logical id"))
    def test_get_on_non_existent_property(self):
        resource_refs = SupportedResourceReferences()

        resource_refs.add("logicalId1", "property1", "value1")
        self.assertEquals(None, resource_refs.get("logicalId1", "SomeProperty"))
        self.assertEquals(None, resource_refs.get("SomeLogicalId", "property1"))
Exemplo n.º 25
0
    def test_len_multiple_resources(self):
        resource_refs = SupportedResourceReferences()

        resource_refs.add("logicalId1", "property1", "value1")
        resource_refs.add("logicalId2", "property2", "value2")
        self.assertEqual(2, len(resource_refs))
Exemplo n.º 26
0
    def translate(self, sam_template, parameter_values):
        """Loads the SAM resources from the given SAM manifest, replaces them with their corresponding
        CloudFormation resources, and returns the resulting CloudFormation template.

        :param dict sam_template: the SAM manifest, as loaded by json.load() or yaml.load(), or as provided by \
                CloudFormation transforms.
        :param dict parameter_values: Map of template parameter names to their values. It is a required parameter that
                should at least be an empty map. By providing an empty map, the caller explicitly opts-into the idea that
                some functionality that relies on resolving parameter references might not work as expected
                (ex: auto-creating new Lambda Version when CodeUri contains reference to template parameter). This is why
                this parameter is required

        :returns: a copy of the template with SAM resources replaced with the corresponding CloudFormation, which may \
                be dumped into a valid CloudFormation JSON or YAML template
        """
        # Create & Install plugins
        sam_plugins = prepare_plugins(self.plugins)
        parameter_values = self._add_default_parameter_values(
            sam_template, parameter_values)

        self.sam_parser.parse(sam_template=sam_template,
                              parameter_values=parameter_values,
                              sam_plugins=sam_plugins)

        template = copy.deepcopy(sam_template)
        macro_resolver = ResourceTypeResolver(sam_resources)
        intrinsics_resolver = IntrinsicsResolver(parameter_values)
        deployment_preference_collection = DeploymentPreferenceCollection()
        supported_resource_refs = SupportedResourceReferences()
        document_errors = []
        changed_logical_ids = {}

        for logical_id, resource_dict in self._get_resources_to_iterate(
                sam_template, macro_resolver):
            try:
                macro = macro_resolver\
                    .resolve_resource_type(resource_dict)\
                    .from_dict(logical_id, resource_dict, sam_plugins=sam_plugins)

                kwargs = macro.resources_to_link(sam_template['Resources'])
                kwargs['managed_policy_map'] = self.managed_policy_map
                kwargs['intrinsics_resolver'] = intrinsics_resolver
                kwargs[
                    'deployment_preference_collection'] = deployment_preference_collection
                translated = macro.to_cloudformation(**kwargs)

                supported_resource_refs = macro.get_resource_references(
                    translated, supported_resource_refs)

                # Some resources mutate their logical ids. Track those to change all references to them:
                if logical_id != macro.logical_id:
                    changed_logical_ids[logical_id] = macro.logical_id

                del template['Resources'][logical_id]
                for resource in translated:
                    if verify_unique_logical_id(resource,
                                                sam_template['Resources']):
                        template['Resources'].update(resource.to_dict())
                    else:
                        document_errors.append(
                            DuplicateLogicalIdException(
                                logical_id, resource.logical_id,
                                resource.resource_type))
            except (InvalidResourceException, InvalidEventException) as e:
                document_errors.append(e)

        if deployment_preference_collection.any_enabled():
            template['Resources'].update(deployment_preference_collection.
                                         codedeploy_application.to_dict())

            if not deployment_preference_collection.can_skip_service_role():
                template['Resources'].update(deployment_preference_collection.
                                             codedeploy_iam_role.to_dict())

            for logical_id in deployment_preference_collection.enabled_logical_ids(
            ):
                template['Resources'].update(
                    deployment_preference_collection.deployment_group(
                        logical_id).to_dict())

        # Run the after-transform plugin target
        try:
            sam_plugins.act(LifeCycleEvents.after_transform_template, template)
        except (InvalidDocumentException, InvalidResourceException) as e:
            document_errors.append(e)

        # Cleanup
        if 'Transform' in template:
            del template['Transform']

        if len(document_errors) is 0:
            template = intrinsics_resolver.resolve_sam_resource_id_refs(
                template, changed_logical_ids)
            template = intrinsics_resolver.resolve_sam_resource_refs(
                template, supported_resource_refs)
            return template
        else:
            raise InvalidDocumentException(document_errors)
Exemplo n.º 27
0
class TestSamResourceReferableProperties(TestCase):
    class ResourceType1(Resource):
        resource_type = "resource_type1"
        property_types = {}

    class ResourceType2(Resource):
        resource_type = "resource_type2"
        property_types = {}

    class ResourceType3(Resource):
        resource_type = "resource_type3"
        property_types = {}

    def setUp(self):
        self.supported_resource_refs = SupportedResourceReferences()

    def test_must_get_property_for_available_resources(self):
        class NewSamResource(SamResourceMacro):
            resource_type = "foo"
            property_types = {}
            referable_properties = {
                "prop1": "resource_type1",
                "prop2": "resource_type2",
                "prop3": "resource_type3"
            }

        sam_resource = NewSamResource("SamLogicalId")

        cfn_resources = [
            self.ResourceType1("logicalId1"),
            self.ResourceType2("logicalId2")
        ]

        self.supported_resource_refs = \
            sam_resource.get_resource_references(cfn_resources, self.supported_resource_refs)

        self.assertEquals(
            "logicalId1",
            self.supported_resource_refs.get("SamLogicalId", "prop1"))
        self.assertEquals(
            "logicalId2",
            self.supported_resource_refs.get("SamLogicalId", "prop2"))

        # there is no cfn resource of for "prop3" in the cfn_resources list
        self.assertEquals(
            None, self.supported_resource_refs.get("SamLogicalId", "prop3"))

        # Must add only for the given SAM resource
        self.assertEquals(1, len(self.supported_resource_refs))

    def test_must_work_with_two_resources_of_same_type(self):
        class NewSamResource(SamResourceMacro):
            resource_type = "foo"
            property_types = {}
            referable_properties = {
                "prop1": "resource_type1",
                "prop2": "resource_type2",
                "prop3": "resource_type3"
            }

        sam_resource1 = NewSamResource("SamLogicalId1")
        sam_resource2 = NewSamResource("SamLogicalId2")

        cfn_resources = [
            self.ResourceType1("logicalId1"),
            self.ResourceType2("logicalId2")
        ]

        self.supported_resource_refs = \
            sam_resource1.get_resource_references(cfn_resources, self.supported_resource_refs)

        self.supported_resource_refs = \
            sam_resource2.get_resource_references(cfn_resources, self.supported_resource_refs)

        self.assertEquals(
            "logicalId1",
            self.supported_resource_refs.get("SamLogicalId1", "prop1"))
        self.assertEquals(
            "logicalId2",
            self.supported_resource_refs.get("SamLogicalId1", "prop2"))
        self.assertEquals(
            "logicalId1",
            self.supported_resource_refs.get("SamLogicalId2", "prop1"))
        self.assertEquals(
            "logicalId2",
            self.supported_resource_refs.get("SamLogicalId2", "prop2"))

        self.assertEquals(2, len(self.supported_resource_refs))

    def test_must_skip_unknown_resource_types(self):
        class NewSamResource(SamResourceMacro):
            resource_type = "foo"
            property_types = {}
            referable_properties = {
                "prop1": "foo",
                "prop2": "bar",
            }

        sam_resource = NewSamResource("SamLogicalId")

        # None of the CFN resource types are in the referable list
        cfn_resources = [
            self.ResourceType1("logicalId1"),
            self.ResourceType2("logicalId2")
        ]

        self.supported_resource_refs = \
            sam_resource.get_resource_references(cfn_resources, self.supported_resource_refs)

        self.assertEquals(0, len(self.supported_resource_refs))

    def test_must_skip_if_no_supported_properties(self):
        class NewSamResource(SamResourceMacro):
            resource_type = "foo"
            property_types = {}
            referable_properties = {}

        sam_resource = NewSamResource("SamLogicalId")

        cfn_resources = [
            self.ResourceType1("logicalId1"),
            self.ResourceType2("logicalId2")
        ]

        self.supported_resource_refs = \
            sam_resource.get_resource_references(cfn_resources, self.supported_resource_refs)

        self.assertEquals(0, len(self.supported_resource_refs))

    def test_must_skip_if_no_resources(self):
        class NewSamResource(SamResourceMacro):
            resource_type = "foo"
            property_types = {}
            referable_properties = {"prop1": "resource_type1"}

        sam_resource = NewSamResource("SamLogicalId")

        cfn_resources = []

        self.supported_resource_refs = \
            sam_resource.get_resource_references(cfn_resources, self.supported_resource_refs)

        self.assertEquals(0, len(self.supported_resource_refs))

    def test_must_raise_if_input_is_absent(self):
        class NewSamResource(SamResourceMacro):
            resource_type = "foo"
            property_types = {}
            referable_properties = {"prop1": "resource_type1"}

        sam_resource = NewSamResource("SamLogicalId")

        cfn_resources = [self.ResourceType1("logicalId1")]

        with self.assertRaises(ValueError):
            sam_resource.get_resource_references(cfn_resources, None)
Exemplo n.º 28
0
    def test_get_all_on_non_existent_logical_id(self):
        resource_refs = SupportedResourceReferences()

        resource_refs.add("logicalId", "property", "value1")

        self.assertEqual(None, resource_refs.get_all("some logical id"))
Exemplo n.º 29
0
    def translate(self, sam_template, parameter_values, feature_toggle=None):
        """Loads the SAM resources from the given SAM manifest, replaces them with their corresponding
        CloudFormation resources, and returns the resulting CloudFormation template.

        :param dict sam_template: the SAM manifest, as loaded by json.load() or yaml.load(), or as provided by \
                CloudFormation transforms.
        :param dict parameter_values: Map of template parameter names to their values. It is a required parameter that
                should at least be an empty map. By providing an empty map, the caller explicitly opts-into the idea
                that some functionality that relies on resolving parameter references might not work as expected
                (ex: auto-creating new Lambda Version when CodeUri contains reference to template parameter). This is
                why this parameter is required

        :returns: a copy of the template with SAM resources replaced with the corresponding CloudFormation, which may \
                be dumped into a valid CloudFormation JSON or YAML template
        """
        self.feature_toggle = (feature_toggle
                               if feature_toggle else FeatureToggle(
                                   FeatureToggleDefaultConfigProvider(),
                                   stage=None,
                                   account_id=None,
                                   region=None))
        self.function_names = dict()
        self.redeploy_restapi_parameters = dict()
        sam_parameter_values = SamParameterValues(parameter_values)
        sam_parameter_values.add_default_parameter_values(sam_template)
        sam_parameter_values.add_pseudo_parameter_values(self.boto_session)
        parameter_values = sam_parameter_values.parameter_values
        # Create & Install plugins
        sam_plugins = prepare_plugins(self.plugins, parameter_values)

        self.sam_parser.parse(sam_template=sam_template,
                              parameter_values=parameter_values,
                              sam_plugins=sam_plugins)

        template = copy.deepcopy(sam_template)
        macro_resolver = ResourceTypeResolver(sam_resources)
        intrinsics_resolver = IntrinsicsResolver(parameter_values)
        mappings_resolver = IntrinsicsResolver(
            template.get("Mappings", {}),
            {FindInMapAction.intrinsic_name: FindInMapAction()})
        deployment_preference_collection = DeploymentPreferenceCollection()
        supported_resource_refs = SupportedResourceReferences()
        shared_api_usage_plan = SharedApiUsagePlan()
        document_errors = []
        changed_logical_ids = {}
        for logical_id, resource_dict in self._get_resources_to_iterate(
                sam_template, macro_resolver):
            try:
                macro = macro_resolver.resolve_resource_type(
                    resource_dict).from_dict(logical_id,
                                             resource_dict,
                                             sam_plugins=sam_plugins)

                kwargs = macro.resources_to_link(sam_template["Resources"])
                kwargs["managed_policy_map"] = self.managed_policy_map
                kwargs["intrinsics_resolver"] = intrinsics_resolver
                kwargs["mappings_resolver"] = mappings_resolver
                kwargs[
                    "deployment_preference_collection"] = deployment_preference_collection
                kwargs["conditions"] = template.get("Conditions")
                # add the value of FunctionName property if the function is referenced with the api resource
                self.redeploy_restapi_parameters[
                    "function_names"] = self._get_function_names(
                        resource_dict, intrinsics_resolver)
                kwargs[
                    "redeploy_restapi_parameters"] = self.redeploy_restapi_parameters
                kwargs["shared_api_usage_plan"] = shared_api_usage_plan
                translated = macro.to_cloudformation(**kwargs)

                supported_resource_refs = macro.get_resource_references(
                    translated, supported_resource_refs)

                # Some resources mutate their logical ids. Track those to change all references to them:
                if logical_id != macro.logical_id:
                    changed_logical_ids[logical_id] = macro.logical_id

                del template["Resources"][logical_id]
                for resource in translated:
                    if verify_unique_logical_id(resource,
                                                sam_template["Resources"]):
                        template["Resources"].update(resource.to_dict())
                    else:
                        document_errors.append(
                            DuplicateLogicalIdException(
                                logical_id, resource.logical_id,
                                resource.resource_type))
            except (InvalidResourceException, InvalidEventException) as e:
                document_errors.append(e)

        if deployment_preference_collection.any_enabled():
            template["Resources"].update(deployment_preference_collection.
                                         codedeploy_application.to_dict())

            if not deployment_preference_collection.can_skip_service_role():
                template["Resources"].update(deployment_preference_collection.
                                             codedeploy_iam_role.to_dict())

            for logical_id in deployment_preference_collection.enabled_logical_ids(
            ):
                try:
                    template["Resources"].update(
                        deployment_preference_collection.deployment_group(
                            logical_id).to_dict())
                except InvalidResourceException as e:
                    document_errors.append(e)

        # Run the after-transform plugin target
        try:
            sam_plugins.act(LifeCycleEvents.after_transform_template, template)
        except (InvalidDocumentException, InvalidResourceException) as e:
            document_errors.append(e)

        # Cleanup
        if "Transform" in template:
            del template["Transform"]

        if len(document_errors) == 0:
            template = intrinsics_resolver.resolve_sam_resource_id_refs(
                template, changed_logical_ids)
            template = intrinsics_resolver.resolve_sam_resource_refs(
                template, supported_resource_refs)
            return template
        else:
            raise InvalidDocumentException(document_errors)
 def test_add_must_error_when_property_is_absent(self):
     resource_refs = SupportedResourceReferences()
     with self.assertRaises(ValueError):
         resource_refs.add("logicalId", "", "value1")
 def setUp(self):
     self.supported_resource_refs = SupportedResourceReferences()
Exemplo n.º 32
0
class TestSubCanResolveResourceRefs(TestCase):
    def setUp(self):
        self.supported_resource_refs = SupportedResourceReferences()
        self.supported_resource_refs.add("id1", "prop1", "value1")
        self.supported_resource_refs.add("id1", "prop2", "value2")
        self.supported_resource_refs.add("id2", "prop3", "value3")

        self.input_sub_value = "Hello ${id1.prop1} ${id1.prop2}${id2.prop3} ${id1.prop1.arn} ${id1.prop2.arn.name.foo} ${!id1.prop1} ${unknown} ${some.arn} World"
        self.expected_output_sub_value = "Hello ${value1} ${value2}${value3} ${value1.arn} ${value2.arn.name.foo} ${!id1.prop1} ${unknown} ${some.arn} World"

    def test_must_resolve_string_value(self):

        input = {"Fn::Sub": self.input_sub_value}
        expected = {"Fn::Sub": self.expected_output_sub_value}

        sub = SubAction()
        result = sub.resolve_resource_refs(input, self.supported_resource_refs)

        self.assertEqual(expected, result)

    def test_must_resolve_array_value(self):
        input = {"Fn::Sub": [self.input_sub_value, {"unknown": "a"}]}

        expected = {
            "Fn::Sub": [self.expected_output_sub_value, {
                "unknown": "a"
            }]
        }

        sub = SubAction()
        result = sub.resolve_resource_refs(input, self.supported_resource_refs)

        self.assertEqual(expected, result)

    def test_sub_all_refs_with_list_input(self):
        parameters = {"key1": "value1", "key2": "value2"}
        input = {"Fn::Sub": ["key1", "key2"]}
        expected = {"Fn::Sub": ["key1", "key2"]}

        sub = SubAction()
        result = sub.resolve_resource_refs(input, parameters)

        self.assertEqual(expected, result)

    def test_sub_all_refs_with_dict_input(self):
        parameters = {"key1": "value1", "key2": "value2"}
        input = {"Fn::Sub": {"a": "key1", "b": "key2"}}
        expected = {"Fn::Sub": {"a": "key1", "b": "key2"}}

        sub = SubAction()
        result = sub.resolve_resource_refs(input, parameters)

        self.assertEqual(expected, result)

    @patch.object(SubAction, "can_handle")
    def test_return_value_if_cannot_handle(self, can_handle_mock):
        parameters = {"key": "value"}
        input = {"Fn::Sub": "${key}"}
        expected = {"Fn::Sub": "${key}"}

        sub = SubAction()
        can_handle_mock.return_value = False  # Simulate failure to handle the input. Result should be same as input
        self.assertEqual(expected,
                         sub.resolve_resource_refs(input, parameters))
 def setUp(self):
     self.supported_resource_refs = SupportedResourceReferences()
     self.supported_resource_refs.add("id1", "prop1", "value1")
    def test_len_single_resource(self):
        resource_refs = SupportedResourceReferences()

        resource_refs.add("logicalId1", "property1", "value1")
        resource_refs.add("logicalId1", "property2", "value2")
        self.assertEquals(1, len(resource_refs))  # Each unique logicalId adds one to the len