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]
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
def __init__(self, __env, __name, layer_type=None, logger=None, loader=None, humilis_profile=None, **user_params): self.__environment_repr = repr(__env) self.environment = __env if not humilis_profile: self.cf = self.environment.cf else: config.boto_config.activate_profile(humilis_profile) self.cf = Cloudformation(config.boto_config) if logger is None: self.logger = logging.getLogger(__name__) # To prevent warnings self.logger.addHandler(logging.NullHandler()) else: self.logger = logger self.name = __name self.env_name = self.environment.name self.env_stage = self.environment.stage self.env_basedir = self.environment.basedir self.depends_on = [] self.section = {} self.type = layer_type self.s3_prefix = "{base}{env}/{stage}/{layer}/".format( base=config.boto_config.profile.get("s3prefix"), env=self.environment.name, stage=self.environment.stage, layer=__name) if layer_type is not None: basedir = config.layers.get(layer_type) if not basedir: msg = ("The plugin providing the layer type '{}' is not " "installed in this system. Please install it and " "try again.").format(layer_type) raise MissingPluginError(msg) else: basedir = None if basedir is None: basedir = os.path.join(self.env_basedir, 'layers', self.name) self.basedir = basedir if loader is None: loader = DirTreeBackedObject(basedir, self.logger) self.loader = loader # These param set will be sent to the template compiler and will be # populated once the layers this layer depend on have been created. self.params = {} # the parameters that will be used to compile meta.yaml self.meta = {} meta_params = { p[0]: p[1] for p in itertools.chain(self.loader_params.items(), user_params.items()) } self.meta = self.loader.load_section('meta', params=meta_params) self.sns_topic_arn = self.environment.sns_topic_arn self.tags = { 'humilis:environment': self.env_name, 'humilis:layer': self.name, 'humilis:stage': self.env_stage, 'humilis:created': str(datetime.datetime.now()) } for tagname, tagvalue in self.environment.tags.items(): self.tags[tagname] = tagvalue for tagname, tagvalue in self.meta.get('tags', {}).items(): self.tags[tagname] = tagvalue self.yaml_params = self.meta.get('parameters', {}) for k, v in self.yaml_params.items(): # Set 1 as default priority for all parameters v['priority'] = v.get('priority', 1) # User params override what is in the layer definition file self.user_params = user_params for pname, pvalue in user_params.items(): if pname in self.yaml_params: self.yaml_params[pname]['value'] = pvalue self.__ec2 = None self.__s3 = None
def __init__(self, yml_path, logger=None, stage=None, vault_layer=None, parameters=None): if logger is None: self.logger = logging.getLogger(__name__) # To prevent warnings self.logger.addHandler(logging.NullHandler()) else: self.logger = logger self.__yml_path = yml_path self.stage = stage and stage.upper() basedir, envfile = os.path.split(yml_path) self.basedir = os.path.abspath(basedir) self._j2_env = j2.Environment(extensions=["jinja2.ext.with_"], loader=j2.FileSystemLoader(self.basedir)) # Add custom functions and filters utils.update_jinja2_env(self._j2_env) if parameters is None: parameters = {} if "_default" in parameters: def_params = parameters.get("_default", {}) del parameters["_default"] parameters.update(def_params) parameters.update(os.environ) with open(yml_path, 'r') as f: if os.path.splitext(yml_path)[1] == ".j2": template = self._j2_env.get_template(envfile) meta = yaml.load(template.render(stage=stage, **parameters)) else: meta = yaml.load(f) self.name = list(meta.keys())[0] self.meta = meta.get(self.name) if len(self.meta) == 0: raise FileFormatError(yml_path, "Error getting environment name ", logger=self.logger) self.cf = Cloudformation(config.boto_config) self.sns_topic_arn = self.meta.get('sns-topic-arn', []) self.tags = self.meta.get('tags', {}) self.tags['humilis:environment'] = self.name self.layers = [] for layer in self.meta.get('layers', []): layer_name = layer.get('layer', None) if layer_name is None: msg = "Wrongly formatted layer: {}".format(layer) raise FileFormatError(yml_path, msg) if layer.get('disable', False): message = ("Layer {} is disabled by configuration. " "Skipping.".format(layer.get('layer'))) self.logger.warning(message) continue # Get the layer params provided in the environment spec layer_params = {k: v for k, v in layer.items() if k != 'layer'} layer_obj = Layer(self, layer_name, **layer_params) self.layers.append(layer_obj) self.vault_layer = self.get_layer(vault_layer or 'secrets-vault') self.__secrets_table_name = "{}-{}-secrets".format( self.name, self.stage) if self.stage: self.__keychain_namespace = "{}:{}".format(self.name, self.stage.lower()) else: self.__keychain_namespace = self.name self.__dynamodb = None
def cf(): """Create a Cloudformation facade object""" yield Cloudformation(config.boto_config)
def __init__(self, yml_path, logger=None, stage=None, vault_layer=None, parameters=None): if logger is None: self.logger = logging.getLogger(__name__) # To prevent warnings self.logger.addHandler(logging.NullHandler()) else: self.logger = logger if stage is None: raise ValueError("stage can't be None") self.__yml_path = yml_path self.stage = stage and stage.upper() basedir, envfile = os.path.split(yml_path) self.basedir = os.path.abspath(basedir) self._j2_env = j2.Environment(loader=j2.FileSystemLoader(self.basedir)) # Add custom functions and filters utils.update_jinja2_env(self._j2_env) parameters = self._preprocess_parameters(parameters) with open(yml_path, 'r') as f: if os.path.splitext(yml_path)[1] == ".j2": template = self._j2_env.get_template(envfile) meta = yaml.load( template.render( stage=stage, # Backwards compatibility __context={ 'stage': stage, 'aws': { 'account_id': boto3.client('sts').get_caller_identity().get( 'Account') } }, __env=os.environ, **parameters), Loader=yaml.FullLoader) else: meta = yaml.load(f, Loader=yaml.FullLoader) self.name = list(meta.keys())[0] self.meta = meta.get(self.name) if len(self.meta) == 0: raise FileFormatError(yml_path, "Error getting environment name ", logger=self.logger) self.cf = Cloudformation(config.boto_config) self.sns_topic_arn = self.meta.get('sns-topic-arn', []) self.tags = self.meta.get('tags', {}) self.tags['humilis:environment'] = self.name self.layers = [] for layer in self.meta.get('layers', []): layer_name = layer.get('layer', None) if layer_name is None: msg = "Wrongly formatted layer: {}".format(layer) raise FileFormatError(yml_path, msg) if layer.get('disable', False): message = ("Layer {} is disabled by configuration. " "Skipping.".format(layer.get('layer'))) self.logger.warning(message) continue # Get the layer params provided in the environment spec layer_params = {k: v for k, v in layer.items() if k != 'layer'} layer_obj = Layer(self, layer_name, **layer_params) self.layers.append(layer_obj) self.vault_layer = self.get_layer(vault_layer or 'secrets-vault') self.__secrets_table_name = "{}-{}-secrets".format( self.name, self.stage) self.__keychain_namespace = "{}:{}".format(self.name, self.stage.lower()) self.__dynamodb = None