Exemplo n.º 1
0
def output(layer, config, layer_name=None, output_name=None,
           environment_name=None, stage=None):
    """Gets the value of an output produced by an already deployed layer.

    :param layer: The Layer object for the layer declaring the reference.
    :param config: An object holding humilis configuration options.
    :param layer_name: The logical name of the layer that produced the output.
    :param output_name: The logical name of the output parameter.
    """
    if not environment_name or not stage:
        environment_name = layer.env_name
        stage = layer.env_stage

    stack_name = utils.get_cf_name(environment_name, layer_name, stage=stage)
    cf = Cloudformation(config)
    try:
        output = cf.get_stack_output(stack_name, output_name)
    except AttributeError:
        msg = "No output '{}' in CF stack '{}'".format(output_name, stack_name)
        ref = "output/{}/{}/{}/{}".format(environment_name, layer_name, stage,
                                          output_name)
        raise ReferenceError(ref, msg)
    if len(output) < 1:
        all_stack_outputs = [x['OutputKey'] for x
                             in cf.stack_outputs[stack_name]]
        msg = ("{} output does not exist for stack {} "
               "(with outputs {}).").format(output_name,
                                            stack_name,
                                            all_stack_outputs)
        ref = "output ({}/{})".format(layer_name, output_name)
        raise ReferenceError(ref, msg, logger=layer.logger)
    return output[0]
Exemplo n.º 2
0
def boto3(layer,
          config,
          service=None,
          call=None,
          output_attribute=None,
          output_key=None):
    """Calls a boto3facade method.

    :param layer: The Layer object for the layer declaring the reference.
    :param config: An object holding humilis configuration options.
    :param service: The name of the AWS service.
    :param call: A dict with two keys: method, and parameters.
    :param output_attribute: Object attribute to return.
    :param output_key: Dictionary key to return.

    :returns: The call response, or its corresp. attribute or key.
    """
    facade_name = service.title()
    if not hasattr(boto3facade, service):
        ref = "boto3facade.{}.{}.{}: {}".format(service, facade_name,
                                                call['method'],
                                                call['parameters'])
        msg = "Service {} not supported".format(service)
        raise ReferenceError(ref, msg, logger=layer.logger)

    module = importlib.import_module("boto3facade.{}".format(service))
    facade_cls = getattr(module, facade_name)
    facade = facade_cls(config)
    method = getattr(facade, call['method'])
    args = call.get('args', [])
    kwargs = call.get('kwargs', {})
    result = method(*args, **kwargs)
    if not isinstance(result, str) and not isinstance(result, dict) and \
        hasattr(result, '__iter__'):
        # Convert iterables to lists
        result = list(result)
    if isinstance(result, list):
        if len(result) == 1:
            result = result[0]
        else:
            raise ReferenceError(
                "boto3/{}/{}".format(service, call),
                "Must produce exactly one result but {} were produced".format(
                    len(result)))

    if output_attribute is not None:
        result = getattr(result, output_attribute)
    if output_key is not None:
        return result.get(output_key)
    else:
        return result
Exemplo n.º 3
0
 def _resolve_ref(self, parsername, parameters):
     """Resolves references."""
     parser = config.reference_parsers.get(parsername)
     if not parser:
         msg = "Invalid reference parser '{}' in layer '{}'".format(
             parsername, self.cf_name)
         raise ReferenceError(ref, msg, logger=self.logger)
     result = parser(self, config.boto_config, **parameters)
     return result
Exemplo n.º 4
0
def j2_template(layer, config, path=None, s3_upload=False, params=None):
    """Render a j2 template and return the local or s3 path of the result.

    :param layer: The layer object for the layer declaring the reference.
    :param config: An object holding humilis configuration options.
    :param path: The path of the j2 template to render. Relative to meta.yml.
    :param s3_upload: Upload the rendered template to s3 or not.
    :param params: A dict containing the values to render the template.

    :returns: The local or s3 path of the rendered template.
    """
    if params is None:
        msg = ("Missing params for j2 rendering in layer '{}' "
               "and env '{}'").format(layer.name, layer.env_name)
        ref = "j2_template '{}')".format(path)
        raise ReferenceError(ref, msg, logger=layer.logger)
    basefile, j2_ext = os.path.splitext(path)
    if j2_ext not in {".j2"}:
        msg = ("The file is not a Jinja2 template. layer : '{}', "
               "env : '{}'".format(layer.name, layer.env_name))
        ref = "j2_template '{}')".format(path)
        raise ReferenceError(ref, msg, logger=layer.logger)

    _, ext = os.path.splitext(basefile)
    _, filename = os.path.split(path)
    env = jinja2.Environment(
        extensions=["jinja2.ext.with_"],
        loader=jinja2.FileSystemLoader(layer.basedir))
    result = env.get_template(filename).render(params)
    output_path = os.path.join(layer.env_basedir, "ref-j2_template_" +
                               str(uuid.uuid4()) + ext)
    with open(output_path, "w") as f:
        f.write(result)
    if s3_upload:
        s3bucket, s3key = _get_s3path(layer, config, output_path)
        s3 = S3(config)
        s3.cp(output_path, s3bucket, s3key)
        layer.logger.info("{} -> {}/{}".format(output_path, s3bucket, s3key))
        return os.path.join("s3://", s3bucket, s3key)

    return output_path
Exemplo n.º 5
0
def _get_stack_resource(layer, config, stack_name, resource_name):
    """Gets the physical ID of a resource in a CF Stack.

    :param stack_name: The name of the CF stack.
    :param resource_name: The logical name of the CF resource.

    :returns: The physical ID of the resource.
    """
    cf = Cloudformation(config)
    resource = cf.get_stack_resource(stack_name, resource_name)

    if len(resource) < 1:
        all_stack_resources = [x.logical_resource_id for x
                               in cf.get_stack_resources(stack_name)]
        msg = "{} does not exist in stack {} (with resources {}).".format(
            resource_name, stack_name, all_stack_resources)
        raise ReferenceError(resource_name, msg, logger=layer.logger)

    return resource[0].physical_resource_id