func (t *ConfigTransformer) Transform(g *Graph) error { // A module is required and also must be completely loaded. if t.Module == nil { return errors.New("module must not be nil") } if !t.Module.Loaded() { return errors.New("module must be loaded") } // Get the module we care about module := t.Module.Child(g.Path[1:]) if module == nil { return nil } // Get the configuration for this module config := module.Config() // Create the node list we'll use for the graph nodes := make([]graphNodeConfig, 0, (len(config.Variables)+ len(config.ProviderConfigs)+ len(config.Modules)+ len(config.Resources)+ len(config.Outputs))*2) // Write all the variables out for _, v := range config.Variables { nodes = append(nodes, &GraphNodeConfigVariable{Variable: v}) } // Write all the provider configs out for _, pc := range config.ProviderConfigs { nodes = append(nodes, &GraphNodeConfigProvider{Provider: pc}) } // Write all the resources out for _, r := range config.Resources { nodes = append(nodes, &GraphNodeConfigResource{ Resource: r, Path: g.Path, }) } // Write all the modules out children := module.Children() for _, m := range config.Modules { path := make([]string, len(g.Path), len(g.Path)+1) copy(path, g.Path) path = append(path, m.Name) nodes = append(nodes, &GraphNodeConfigModule{ Path: path, Module: m, Tree: children[m.Name], }) } // Write all the outputs out for _, o := range config.Outputs { nodes = append(nodes, &GraphNodeConfigOutput{Output: o}) } // Err is where the final error value will go if there is one var err error // Build the graph vertices for _, n := range nodes { g.Add(n) } // Build up the dependencies. We have to do this outside of the above // loop since the nodes need to be in place for us to build the deps. for _, n := range nodes { if missing := g.ConnectDependent(n); len(missing) > 0 { for _, m := range missing { err = multierror.Append(err, fmt.Errorf( "%s: missing dependency: %s", n.Name(), m)) } } } return err }
func (t *OrphanTransformer) Transform(g *Graph) error { if t.State == nil { // If the entire state is nil, there can't be any orphans return nil } if t.Targeting { log.Printf("Skipping orphan transformer because we have targets.") // If we are in a run where we are targeting nodes, we won't process // orphans for this run. return nil } // Build up all our state representatives resourceRep := make(map[string]struct{}) for _, v := range g.Vertices() { if sr, ok := v.(GraphNodeStateRepresentative); ok { for _, k := range sr.StateId() { resourceRep[k] = struct{}{} } } } var config *config.Config if t.Module != nil { if module := t.Module.Child(g.Path[1:]); module != nil { config = module.Config() } } var resourceVertexes []dag.Vertex if state := t.State.ModuleByPath(g.Path); state != nil { // If we have state, then we can have orphan resources // If we have a view, get the view if t.View != "" { state = state.View(t.View) } // Go over each resource orphan and add it to the graph. resourceOrphans := state.Orphans(config) resourceVertexes = make([]dag.Vertex, len(resourceOrphans)) for i, k := range resourceOrphans { // If this orphan is represented by some other node somehow, // then ignore it. if _, ok := resourceRep[k]; ok { continue } rs := state.Resources[k] resourceVertexes[i] = g.Add(&graphNodeOrphanResource{ ResourceName: k, ResourceType: rs.Type, Provider: rs.Provider, dependentOn: rs.Dependencies, }) } } // Go over each module orphan and add it to the graph. We store the // vertexes and states outside so that we can connect dependencies later. moduleOrphans := t.State.ModuleOrphans(g.Path, config) moduleVertexes := make([]dag.Vertex, len(moduleOrphans)) for i, path := range moduleOrphans { moduleVertexes[i] = g.Add(&graphNodeOrphanModule{ Path: path, dependentOn: t.State.ModuleByPath(path).Dependencies, }) } // Now do the dependencies. We do this _after_ adding all the orphan // nodes above because there are cases in which the orphans themselves // depend on other orphans. // Resource dependencies for _, v := range resourceVertexes { g.ConnectDependent(v) } // Module dependencies for _, v := range moduleVertexes { g.ConnectDependent(v) } return nil }