def get_and_replace_parent_variables(self): """ Checks the particles desired state definition and checks to see if there are values that dependent on one of its parents. The format should look like $flavor:pcf_name$key_in_parent_current_state_definition. If there are values then this function looks for the corresponding parents and adds those values to this particles desired_state_definition. """ var_lookup_list = pcf_util.find_nested_vars( self.desired_state_definition, var_list=[]) for (nested_key, id_var) in var_lookup_list: if id_var[0] == "inherit": pcf_id = id_var[1] parent_var = id_var[2] try: parent = next(p for p in self.parents if p.pcf_id == pcf_id) except StopIteration: raise pcf_exceptions.InvalidValueReplaceException( "{} parent was not found".format(pcf_id)) else: var = pcf_util.find_nested_dict_value( curr_dict=parent.current_state_definition, list_nested_keys=parent_var.split('.')) if not var: raise pcf_exceptions.InvalidValueReplaceException( "{} var was not found in {}".format( parent_var, pcf_id)) pcf_util.replace_value_nested_dict( curr_dict=self.desired_state_definition, list_nested_keys=nested_key.split('.'), new_value=var)
def _fuse_particles(self): """ This functions adds all particles to a pcf object (pcf_field). If a particle contains a multiplier field that number of particles are created with indexes appended to the particle's unique identifier. If the quasiparticle has a parent, that parent is added to all particles in the quasiparticle. Finally link_particles is called on the pcf_field. """ for particle in self.member_particles: if not particle.get("pcf_name"): particle["pcf_name"] = self.name multiplier = particle.get("multiplier", False) base_particle_config = particle.get("base_particle_config", False) if base_particle_config: particle = self.update_particle_definition( particle, self.pcf_field.get_particle_from_pcf_id( particle["flavor"] + ":" + base_particle_config)) # when there is no multiplier add quasiparticle parents to particle and add particle to pcf field if not multiplier: if self.particle_definition.get("parents"): particle = self.add_parents_to_particle(particle) self.pcf_field.load_particle_definition(particle) # when there is a multiplier get the unique identifers, index them, add quasiparticle parents, and then add all particles to the pcf field else: particle_name = particle["pcf_name"] unique_identifier_list = pcf_util.get_particle_unique_identifiers( particle['flavor']) unqiue_value_dict = dict([ (x, pcf_util.find_nested_dict_value(particle, x.split('.'))) for x in unique_identifier_list ]) for i in range(multiplier): particle_multiple = deepcopy(particle) particle_multiple["pcf_name"] = particle_name + "-" + str( i) # appends the correct index to each item in particle definition that is unique particle_multiple = functools.reduce( (lambda d, l: pcf_util.replace_value_nested_dict( d, l.split('.'), unqiue_value_dict.get(l) + '-' + str(i))), unique_identifier_list, particle_multiple) if self.particle_definition.get("parents"): particle_multiple = self.add_parents_to_particle( particle_multiple) self.pcf_field.load_particle_definition(particle_multiple) self.pcf_field.link_particles(self.pcf_field.particles)
def is_state_definition_equivalent(self): """ Determines if the current state definition and the desired state definition are equivalent. Returns: bool """ filtered_curr_def = pcf_util.param_filter( self.current_state_definition, self.UPDATE_PARAM_FILTER) filtered_des_def = pcf_util.param_filter(self.desired_state_definition, self.REMOVE_PARAM_FILTER, True) def_diff = pcf_util.diff_dict(filtered_curr_def, filtered_des_def) curr_tags = self.client.describe_tags(ResourceArns=[self.arn]) curr_tags = curr_tags.get('TagDescriptions')[0].get('Tags', None) des_tags = self.desired_state_definition.get('Tags', None) curr_availabilty_zones = pcf_util.find_nested_dict_value( self.current_state_definition, ['AvailabilityZones']) curr_subnets_list = pcf_util.transform_list_of_dicts_to_desired_list( curr_availabilty_zones, 'SubnetId') des_subnets_list = self.desired_state_definition.get('Subnets') curr_listeners = [ pcf_util.param_filter(x, {'SslPolicy'}, True) for x in self.get_listener_status() ] des_listeners = self.custom_config['Listeners'] for item in des_listeners: item.update({'Protocol': item.get('Protocol').upper()}) for item in curr_listeners: if 'ListenerArn' in item: item.pop('ListenerArn') if def_diff or self._need_update(curr_tags, des_tags) or self._need_update(curr_listeners, des_listeners) \ or not pcf_util.is_list_equal(curr_subnets_list, des_subnets_list): return False return True
def validate_unique_id(self): """ Throws an error if particle flavor or any unique identifiers are missing """ flavor_name = self.particle_definition.get("flavor") if not flavor_name: raise pcf_exceptions.FlavorMissingException try: # get list from UNIQUE_KEYS unique_identifier_list = pcf_util.get_particle_unique_identifiers( flavor_name) for uid in unique_identifier_list: if not pcf_util.find_nested_dict_value( self.particle_definition, uid.split('.')): raise pcf_exceptions.InvalidUniqueKeysException except AttributeError: # UNIQUE_KEYS list does not exist - disregard and move on (Only when UNIQUE_KEYS is not defined in a class) pass
def _update(self): """ updates the alb particle to match the desired state """ filtered_curr_def = pcf_util.param_filter( self.current_state_definition, self.UPDATE_PARAM_FILTER) filtered_des_def = pcf_util.param_filter(self.desired_state_definition, self.REMOVE_PARAM_FILTER, True) diff = pcf_util.diff_dict(filtered_curr_def, filtered_des_def) curr_tags = self.client.describe_tags(ResourceArns=[self.arn]) curr_tags = curr_tags.get('TagDescriptions')[0].get('Tags') des_tags = self.desired_state_definition.get('Tags', [{}]) curr_listeners = [x for x in self.get_listener_status()] # Format current listener to compare. filtered_curr_listeners = [x for x in self.get_listener_status()] for item in filtered_curr_listeners: if 'ListenerArn' in item: item.pop('ListenerArn') des_listeners = self.custom_config['Listeners'] if diff.get('SecurityGroups', None): self.client.set_security_groups( LoadBalancerArn=self.arn, SecurityGroups=filtered_des_def.get('SecurityGroups')) curr_availabilty_zones = pcf_util.find_nested_dict_value( self.current_state_definition, ['AvailabilityZones']) curr_subnets_list = pcf_util.transform_list_of_dicts_to_desired_list( curr_availabilty_zones, 'SubnetId') des_subnets_list = self.desired_state_definition.get('Subnets') if not pcf_util.is_list_equal(curr_subnets_list, des_subnets_list): update = des_subnets_list if update: self.client.set_subnets(LoadBalancerArn=self.arn, Subnets=list(update)) if self._need_update(curr_tags, des_tags): add = list( itertools.filterfalse(lambda x: x in curr_tags, des_tags)) remove = list( itertools.filterfalse(lambda x: x in des_tags, curr_tags)) if remove: self.client.remove_tags(ResourceArns=[self.arn], TagKeys=[x.get('Key') for x in remove]) if add: self.client.add_tags(ResourceArns=[self.arn], Tags=add) if self._need_update(filtered_curr_listeners, des_listeners): #Format current listener and desired listener to compare. for item in des_listeners: item.update({'Protocol': item.get('Protocol').upper()}) for item in curr_listeners: self.client.delete_listener(ListenerArn=item['ListenerArn']) for item in des_listeners: item['LoadBalancerArn'] = self.arn self.create_listener(item)