Ejemplo n.º 1
0
    def handle_fn_get_azs(self, intrinsic_value, ignore_errors):
        """
        { "Fn::GetAZs" : "" }
        { "Fn::GetAZs" : { "Ref" : "AWS::Region" } }
        { "Fn::GetAZs" : "us-east-1" }
        This intrinsic function will get the availability zones specified for the specified region. This is usually used
        with {"Ref": "AWS::Region"}. If it is an empty string, it will get the default region.

        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::GetAZs intrinsic function property

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

        if not intrinsic_value:
            intrinsic_value = self._symbol_resolver.handle_pseudo_region()

        if intrinsic_value not in self._symbol_resolver.REGIONS:
            raise InvalidIntrinsicException(
                "Invalid region string passed in to {}".format(
                    IntrinsicResolver.FN_GET_AZS))

        return self._symbol_resolver.REGIONS.get(intrinsic_value)
    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
Ejemplo n.º 3
0
    def resolve_attribute(self, cloud_formation_property, ignore_errors=False):
        """
        This will parse through every entry in a CloudFormation root key and resolve them based on the symbol_resolver.
        Customers can optionally ignore resource errors and default to whatever the resource provides.

        Parameters
        -----------
        cloud_formation_property: dict
            A high Level dictionary containg either the Mappings, Resources, Outputs, or Parameters Dictionary
        ignore_errors: bool
            An option to ignore errors that are InvalidIntrinsicException and InvalidSymbolException
        Return
        -------
        A resolved template with all references possible simplified
        """
        processed_dict = OrderedDict()
        for key, val in cloud_formation_property.items():
            processed_key = self._symbol_resolver.get_translation(key) or key
            try:
                processed_resource = self.intrinsic_property_resolver(
                    val, ignore_errors, parent_function=processed_key)
                processed_dict[processed_key] = processed_resource
            except (InvalidIntrinsicException, InvalidSymbolException) as e:
                resource_type = val.get("Type", "")
                if ignore_errors:
                    LOG.error("Unable to process properties of %s.%s", key,
                              resource_type)
                    processed_dict[key] = val
                else:
                    raise InvalidIntrinsicException(
                        "Exception with property of {}.{}".format(
                            key, resource_type) + ": " + str(e.args)) from e
        return processed_dict
def verify_non_null(argument,
                    property_type="",
                    message="",
                    position_in_list=""):
    if argument is None:
        raise InvalidIntrinsicException(
            message
            or "The {} argument to {} is missing from the intrinsic function".
            format(position_in_list, property_type))
    def intrinsic_property_resolver(self, intrinsic, parent_function="template"):
        """
        This resolves the intrinsic of the format
        {
            intrinsic: dict
        } by calling the function with the relevant intrinsic function resolver.

        This also supports returning a string, list, boolean, int since they may be intermediate steps in the recursion
        process. No transformations are done on these.

        By default this will just return the item if non of the types match. This is because of the function
        resolve_all_attributes which will recreate the resources by processing every aspect of resource.

        This code resolves in a top down depth first fashion in order to create a functional style recursion that
        doesn't mutate any of the properties.

        Parameters
        ----------
        intrinsic: dict, str, list, bool, int
            This is an intrinsic property or an intermediate step
        parent_function: str
            In case there is a missing property, this is used to figure out where the property resolved is missing.
        Return
        ---------
        The simplified version of the intrinsic function. This could be a list,str,dict depending on the format required
        """
        if intrinsic is None:
            raise InvalidIntrinsicException("Missing Intrinsic property in {}".format(parent_function))
        if isinstance(intrinsic, list):
            return [self.intrinsic_property_resolver(item) for item in intrinsic]
        if not isinstance(intrinsic, dict) or intrinsic == {}:
            return intrinsic

        # `intrinsic` is a dict at this point.

        keys = list(intrinsic.keys())
        key = keys[0]

        if key in self.intrinsic_key_function_map:
            intrinsic_value = intrinsic.get(key)
            return self.intrinsic_key_function_map.get(key)(intrinsic_value)
        elif key in self.conditional_key_function_map:
            intrinsic_value = intrinsic.get(key)
            return self.conditional_key_function_map.get(key)(intrinsic_value)

        # In this case, it is a dictionary that doesn't directly contain an intrinsic resolver, we must recursively
        # resolve each of it's sub properties.
        sanitized_dict = {}
        for key, val in intrinsic.items():
            sanitized_key = self.intrinsic_property_resolver(key, parent_function=parent_function)
            sanitized_val = self.intrinsic_property_resolver(val, parent_function=parent_function)
            verify_intrinsic_type_str(sanitized_key,
                                      message="The keys of the dictionary {} in {} must all resolve to a string".format(
                                          sanitized_key, parent_function
                                      ))
            sanitized_dict[sanitized_key] = sanitized_val
        return sanitized_dict
def verify_intrinsic_type(argument,
                          property_type="",
                          message="",
                          position_in_list="",
                          primitive_type=string_types):
    verify_non_null(argument, property_type, message, position_in_list)
    if not isinstance(argument, primitive_type):
        raise InvalidIntrinsicException(
            message
            or "The {} argument to {} must resolve to a {} type".format(
                position_in_list, property_type, primitive_type))
    def handle_fn_import_value(self, intrinsic_value, ignore_errors):
        """
        { "Fn::ImportValue" : sharedValueToImport }
        This intrinsic function requires handling multiple stacks, which is not currently supported by SAM-CLI.
        Thus, it will thrown an exception.

        Return
        -------
        An InvalidIntrinsicException
        """
        raise InvalidIntrinsicException("Fn::ImportValue is currently not supported by IntrinsicResolver")
def verify_intrinsic_type_int(argument,
                              property_type="",
                              message="",
                              position_in_list=""):
    # Special case since bool is a subclass of int in python
    if isinstance(argument, bool):
        raise InvalidIntrinsicException(
            message
            or "The {} argument to {} must resolve to a {} type".format(
                position_in_list, property_type, int))
    verify_intrinsic_type(argument,
                          property_type,
                          message,
                          position_in_list,
                          primitive_type=int)
def verify_in_bounds(objects, index, property_type=""):
    if index < 0 or index >= len(objects):
        raise InvalidIntrinsicException(
            "The index of {} resolved properties must be within the range".
            format(property_type))
def verify_number_arguments(arguments, property_type="", num=0):
    if not len(arguments) == num:
        raise InvalidIntrinsicException(
            "The arguments to {} must have {} arguments instead of {} arguments"
            .format(property_type, num, len(arguments)))