Esempio n. 1
0
def _parameterize_string(raw):
    """Substitute placeholders in a string using CloudFormation references.

    Args:
        raw (str): String to be processed. Byte strings are not
            supported; decode them before passing them to this function.

    Returns:
        str | :class:`troposphere.GenericHelperFn`: An expression with
            placeholders from the input replaced, suitable to be passed to
            Troposphere to be included in CloudFormation template. This will
            be the input string without modification if no substitutions are
            found, and a composition of CloudFormation calls otherwise.

    """
    parts = []
    s_index = 0

    for match in _PARAMETER_PATTERN.finditer(raw):
        parts.append(raw[s_index:match.start()])
        parts.append({u"Ref": match.group(1)})
        s_index = match.end()

    if not parts:
        return GenericHelperFn(raw)

    parts.append(raw[s_index:])
    return GenericHelperFn({u"Fn::Join": [u"", parts]})
Esempio n. 2
0
def parameterized_codec(raw, b64):
    pattern = re.compile(r'{{(\w+)}}')

    parts = []
    s_index = 0

    for match in pattern.finditer(raw):
        parts.append(raw[s_index:match.start()])
        parts.append({"Ref": match.group(1)})
        s_index = match.end()

    parts.append(raw[s_index:])
    result = {"Fn::Join": ["", parts]}

    # Note, since we want a raw JSON object (not a string) output in the template,
    # we wrap the result in GenericHelperFn (not needed if we're using Base64)
    return Base64(result) if b64 else GenericHelperFn(result)
    def _create_instance(self, cls, args, ref=None):
        """
        Returns an instance of `cls` with `args` passed as arguments.

        Recursively inspects `args` to create nested objects and functions as
        necessary.

        `cls` will only be considered only if it's an object we track
         (i.e.: troposphere objects).

        If `cls` has a `props` attribute, nested properties will be
         instanciated as troposphere Property objects as necessary.

        If `cls` is a list and contains a single troposphere type, the
         returned value will be a list of instances of that type.
        """
        if isinstance(cls, Sequence):
            if len(cls) == 1:
                # a list of 1 type means we must provide a list of such objects
                if (isinstance(args, basestring)
                        or not isinstance(args, Sequence)):
                    args = [args]
                return [self._create_instance(cls[0], v) for v in args]

        if isinstance(cls, Sequence) or cls not in self.inspect_members:
            # this object doesn't map to any known object. could be a string
            # or int, or a Ref... or a list of types such as
            # [basestring, FindInMap, Ref] or maybe a
            # validator such as `integer` or `port_range`
            return self._convert_definition(args)

        elif issubclass(cls, AWSHelperFn):
            # special handling for functions, we want to handle it before
            # entering the other conditions.
            try:
                if (isinstance(args, Sequence)
                        and not isinstance(args, basestring)):
                    return cls(*self._convert_definition(args))

                if issubclass(cls, autoscaling.Metadata):
                    return self._generate_autoscaling_metadata(cls, args)

                args = self._convert_definition(args)
                if isinstance(args, Ref) and issubclass(cls, Ref):
                    # watch out for double-refs...
                    # this can happen if an object's .props has 'Ref'
                    # as the expected type (which is wrong and should be
                    # changed to basestring!)
                    return args

                return cls(args)

            except TypeError as ex:
                if '__init__() takes exactly' not in ex.message:
                    raise
                # special AWSHelperFn typically take lowercased parameters,
                # but templates use uppercase. for this reason we cannot
                # map to most of them, so we fallback with a generic one.
                # this might not work for all types if they do extra
                # processing in their init routine
                return GenericHelperFn(args)

        elif isinstance(args, Mapping):
            # we try to build as many troposphere objects as we can by
            # inspecting its type validation metadata
            kwargs = {}
            kwargs.update(args)
            for prop_name in getattr(cls, 'props', []):
                if prop_name not in kwargs:
                    continue  # the user did not specify this value; skip it
                expected_type = cls.props[prop_name][0]

                if (isinstance(expected_type, Sequence)
                        or expected_type in self.inspect_members):
                    kwargs[prop_name] = self._create_instance(
                        expected_type, kwargs[prop_name], prop_name)
                else:
                    kwargs[prop_name] = self._convert_definition(
                        kwargs[prop_name], prop_name)

            args = self._convert_definition(kwargs)
            if isinstance(args, Ref):
                # use the returned ref instead of creating a new object
                return args
            assert isinstance(args, Mapping)
            return cls(title=ref, **args)

        return cls(self._convert_definition(args))