def find_path_from_referenced_vertices( referenced_vertices: List[VertexReference], vertex_attributes: Dict[str, Any] ) -> Tuple[List[str], str]: """ :param referenced_vertices: an array of VertexReference :param vertex_attributes: attributes to search :return attribute_path: [] if referenced_vertices does not contain vertex_attributes, else the path to the searched attribute: ['vpc_id'] :return origin_value """ for vertex_reference in referenced_vertices: block_type = vertex_reference.block_type.value attribute_path = vertex_reference.sub_parts copy_of_attribute_path = deepcopy(attribute_path) if vertex_attributes[CustomAttributes.BLOCK_TYPE] == block_type: for i in range(len(copy_of_attribute_path)): copy_of_attribute_path[i] = remove_index_pattern_from_str(copy_of_attribute_path[i]) name = ".".join(copy_of_attribute_path[: i + 1]) if vertex_attributes[CustomAttributes.BLOCK_NAME] == name: return attribute_path, vertex_reference.origin_value elif block_type == BlockType.MODULE: copy_of_attribute_path.reverse() for i in range(len(copy_of_attribute_path)): copy_of_attribute_path[i] = remove_index_pattern_from_str(copy_of_attribute_path[i]) name = ".".join(copy_of_attribute_path[: i + 1]) if vertex_attributes[CustomAttributes.BLOCK_NAME] == name: return name.split("."), vertex_reference.origin_value return [], ""
def _build_edges(self): logging.info('Creating edges') self.get_module_vertices_mapping() aliases = self._get_aliases() for origin_node_index, vertex in enumerate(self.vertices): for attribute_key in vertex.attributes: if attribute_key in reserved_attribute_names or attribute_has_nested_attributes( attribute_key, vertex.attributes): continue referenced_vertices = get_referenced_vertices_in_value( value=vertex.attributes[attribute_key], aliases=aliases, resources_types=self.get_resources_types_in_graph()) for vertex_reference in referenced_vertices: # for certain blocks such as data and resource, the block name is composed from several parts. # the purpose of the loop is to avoid not finding the node if the name has several parts sub_values = [ remove_index_pattern_from_str(sub_value) for sub_value in vertex_reference.sub_parts ] for i in range(len(sub_values)): reference_name = join_trimmed_strings( char_to_join=".", str_lst=sub_values, num_to_trim=i) if vertex.module_dependency: dest_node_index = self._find_vertex_index_relative_to_path( vertex_reference.block_type, reference_name, vertex.path, vertex.module_dependency) if dest_node_index == -1: dest_node_index = self._find_vertex_index_relative_to_path( vertex_reference.block_type, reference_name, vertex.path, vertex.path) else: dest_node_index = self._find_vertex_index_relative_to_path( vertex_reference.block_type, reference_name, vertex.path, vertex.module_dependency) if dest_node_index > -1 and origin_node_index > -1: if vertex_reference.block_type == BlockType.MODULE: try: self._connect_module( sub_values, attribute_key, self.vertices[dest_node_index], origin_node_index) except Exception as e: logging.warning( f'Module {self.vertices[dest_node_index]} does not have source attribute, skipping' ) logging.warning(e, stack_info=True) else: self._create_edge(origin_node_index, dest_node_index, attribute_key) break if vertex.block_type == BlockType.MODULE: target_path = vertex.path if vertex.module_dependency != '': target_path = unify_dependency_path( [vertex.module_dependency, vertex.path]) target_variables = list( filter( lambda v: self.vertices[v].module_dependency == target_path, self.vertices_by_block_type.get( BlockType.VARIABLE, {}))) for attribute, value in vertex.attributes.items(): if attribute in MODULE_RESERVED_ATTRIBUTES: continue target_variable = None for v in target_variables: if self.vertices[v].name == attribute: target_variable = v break if target_variable is not None: self._create_edge(target_variable, origin_node_index, 'default') elif vertex.block_type == BlockType.TF_VARIABLE: if vertex.module_dependency != '': target_path = unify_dependency_path( [vertex.module_dependency, vertex.path]) # Assuming the tfvars file is in the same directory as the variables file (best practice) target_variables = list( filter( lambda v: os.path.dirname(self.vertices[v].path) == os. path.dirname(vertex.path), self.vertices_block_name_map.get( BlockType.VARIABLE, {}).get(vertex.name, []))) if len(target_variables) == 1: self._create_edge(target_variables[0], origin_node_index, 'default')