def handle_fn_transform(self, intrinsic_value, ignore_errors):
        """
        { "Fn::Transform" : { "Name" : macro name, "Parameters" : {key : value, ... } } }
        This intrinsic function will transform the data with the body provided

        This intrinsic function will resolve all the objects within the function's value and check their type.
        Parameter
        ----------
        intrinsic_value: list, dict
           This is the value of the object inside the Fn::Transform intrinsic function property

        Return
        -------
        A string with the resolved attributes
        """
        macro_name = intrinsic_value.get("Name")
        name = self.intrinsic_property_resolver(
            macro_name, ignore_errors, parent_function=IntrinsicResolver.FN_TRANSFORM
        )

        if name not in IntrinsicResolver.SUPPORTED_MACRO_TRANSFORMATIONS:
            raise InvalidIntrinsicException(
                "The type {} is not currently supported in {}".format(name, IntrinsicResolver.FN_TRANSFORM)
            )

        parameters = intrinsic_value.get("Parameters")
        verify_intrinsic_type_dict(
            parameters, IntrinsicResolver.FN_TRANSFORM, message=" Fn::Transform requires parameters section"
        )

        location = self.intrinsic_property_resolver(parameters.get("Location"), ignore_errors)
        location_data = get_template_data(location)

        return location_data
    def handle_fn_if(self, intrinsic_value, ignore_errors):
        """
        {"Fn::If": [condition_name, value_if_true, value_if_false]}
        This intrinsic function will evaluate the condition from the Conditions dictionary and then return value_if_true
        or value_if_false depending on the value.

        The Conditions dictionary will have the following format:
        {
            "Conditions": {
                "condition_name": True/False or "{Intrinsic Function}"
            }
        }

        This intrinsic function will resolve all the objects within the function's value and check their type.
        Parameter
        ----------
        intrinsic_value: list, dict
           This is the value of the object inside the Fn::Join intrinsic function property

        Return
        -------
        This will return value_if_true and value_if_false depending on how the condition is evaluated
        """
        arguments = self.intrinsic_property_resolver(
            intrinsic_value, ignore_errors, parent_function=IntrinsicResolver.FN_IF
        )
        verify_intrinsic_type_list(arguments, IntrinsicResolver.FN_IF)
        verify_number_arguments(arguments, IntrinsicResolver.FN_IF, num=3)

        condition_name = self.intrinsic_property_resolver(
            arguments[0], ignore_errors, parent_function=IntrinsicResolver.FN_IF
        )
        verify_intrinsic_type_str(condition_name, IntrinsicResolver.FN_IF)

        value_if_true = self.intrinsic_property_resolver(
            arguments[1], ignore_errors, parent_function=IntrinsicResolver.FN_IF
        )
        value_if_false = self.intrinsic_property_resolver(
            arguments[2], ignore_errors, parent_function=IntrinsicResolver.FN_IF
        )

        condition = self._conditions.get(condition_name)
        verify_intrinsic_type_dict(
            condition,
            IntrinsicResolver.FN_IF,
            message="The condition is missing in the Conditions dictionary for {}".format(IntrinsicResolver.FN_IF),
        )

        condition_evaluated = self.intrinsic_property_resolver(
            condition, ignore_errors, parent_function=IntrinsicResolver.FN_IF
        )
        verify_intrinsic_type_bool(
            condition_evaluated,
            IntrinsicResolver.FN_IF,
            message="The result of {} must evaluate to bool".format(IntrinsicResolver.FN_IF),
        )

        return value_if_true if condition_evaluated else value_if_false
    def handle_fn_sub(self, intrinsic_value, ignore_errors):
        """
        { "Fn::Sub" : [ String, { Var1Name: Var1Value, Var2Name: Var2Value } ] } or { "Fn::Sub" : String }
        This intrinsic function will substitute the variables specified in the list into the string provided. The string
        will also parse out pseudo properties and anything of the form ${}.

        This intrinsic function will resolve all the objects within the function's value and check their type.
        Parameter
        ----------
        intrinsic_value: list, dict
           This is the value of the object inside the Fn::Join intrinsic function property

        Return
        -------
        A string with the resolved attributes
        """

        def resolve_sub_attribute(intrinsic_item, symbol_resolver):
            if "." in intrinsic_item:
                (logical_id, attribute_type) = intrinsic_item.rsplit(".", 1)
            else:
                (logical_id, attribute_type) = intrinsic_item, IntrinsicResolver.REF
            return symbol_resolver.resolve_symbols(logical_id, attribute_type, ignore_errors=True)

        if isinstance(intrinsic_value, str):
            intrinsic_value = [intrinsic_value, {}]

        verify_intrinsic_type_list(
            intrinsic_value, IntrinsicResolver.FN_SUB, message="The arguments to a Fn::Sub must be a list or a string"
        )

        verify_number_arguments(intrinsic_value, IntrinsicResolver.FN_SUB, num=2)

        sub_str = self.intrinsic_property_resolver(
            intrinsic_value[0], ignore_errors, parent_function=IntrinsicResolver.FN_SUB
        )
        verify_intrinsic_type_str(sub_str, IntrinsicResolver.FN_SUB, position_in_list="first")

        variables = intrinsic_value[1]
        verify_intrinsic_type_dict(variables, IntrinsicResolver.FN_SUB, position_in_list="second")

        sanitized_variables = self.intrinsic_property_resolver(
            variables, ignore_errors, parent_function=IntrinsicResolver.FN_SUB
        )

        subable_props = re.findall(string=sub_str, pattern=IntrinsicResolver._REGEX_SUB_FUNCTION)
        for sub_item in subable_props:
            sanitized_item = sanitized_variables[sub_item] if sub_item in sanitized_variables else sub_item
            result = resolve_sub_attribute(sanitized_item, self._symbol_resolver)
            sub_str = re.sub(pattern=r"\$\{" + sub_item + r"\}", string=sub_str, repl=str(result))
        return sub_str
Exemple #4
0
    def handle_find_in_map(self, intrinsic_value, ignore_errors):
        """
        { "Fn::FindInMap" : [ "MapName", "TopLevelKey", "SecondLevelKey"] } This function will then lookup the
        specified dictionary in the Mappings dictionary as mappings[map_name][top_level_key][second_level_key].

        This intrinsic function will resolve all the objects within the function's value and check their type.

        The format of the Mappings dictionary is:
        "Mappings": {
            "map_name": {
                "top_level_key": {
                    "second_level_key": "value"
                    }
                }
            }
        }
        Parameter
        ----------
        intrinsic_value: list, dict
           This is the value of the object inside the Fn::FindInMap intrinsic function property

        Return
        -------
        A string with the resolved attributes
        """
        arguments = self.intrinsic_property_resolver(
            intrinsic_value,
            ignore_errors,
            parent_function=IntrinsicResolver.FN_FIND_IN_MAP)

        verify_intrinsic_type_list(arguments, IntrinsicResolver.FN_FIND_IN_MAP)

        verify_number_arguments(arguments,
                                num=3,
                                property_type=IntrinsicResolver.FN_FIND_IN_MAP)

        map_name = self.intrinsic_property_resolver(
            arguments[0],
            ignore_errors,
            parent_function=IntrinsicResolver.FN_FIND_IN_MAP)
        top_level_key = self.intrinsic_property_resolver(
            arguments[1],
            ignore_errors,
            parent_function=IntrinsicResolver.FN_FIND_IN_MAP)
        second_level_key = self.intrinsic_property_resolver(
            arguments[2],
            ignore_errors,
            parent_function=IntrinsicResolver.FN_FIND_IN_MAP)

        verify_intrinsic_type_str(map_name,
                                  IntrinsicResolver.FN_FIND_IN_MAP,
                                  position_in_list="first")
        verify_intrinsic_type_str(top_level_key,
                                  IntrinsicResolver.FN_FIND_IN_MAP,
                                  position_in_list="second")
        verify_intrinsic_type_str(second_level_key,
                                  IntrinsicResolver.FN_FIND_IN_MAP,
                                  position_in_list="third")

        map_value = self._mapping.get(map_name)
        verify_intrinsic_type_dict(
            map_value,
            IntrinsicResolver.FN_FIND_IN_MAP,
            position_in_list="first",
            message=
            "The MapName is missing in the Mappings dictionary in Fn::FindInMap  for {}"
            .format(map_name),
        )

        top_level_value = map_value.get(top_level_key)
        verify_intrinsic_type_dict(
            top_level_value,
            IntrinsicResolver.FN_FIND_IN_MAP,
            message=
            "The TopLevelKey is missing in the Mappings dictionary in Fn::FindInMap "
            "for {}".format(top_level_key),
        )

        second_level_value = top_level_value.get(second_level_key)
        verify_intrinsic_type_str(
            second_level_value,
            IntrinsicResolver.FN_FIND_IN_MAP,
            message=
            "The SecondLevelKey is missing in the Mappings dictionary in Fn::FindInMap  "
            "for {}".format(second_level_key),
        )

        return second_level_value