github.com/kanishk98/terraform@v1.3.0-dev.0.20220917174235-661ca8088a6a/internal/terraform/transform_output.go (about) 1 package terraform 2 3 import ( 4 "log" 5 6 "github.com/hashicorp/terraform/internal/addrs" 7 "github.com/hashicorp/terraform/internal/configs" 8 "github.com/hashicorp/terraform/internal/dag" 9 "github.com/hashicorp/terraform/internal/plans" 10 ) 11 12 // OutputTransformer is a GraphTransformer that adds all the outputs 13 // in the configuration to the graph. 14 // 15 // This is done for the apply graph builder even if dependent nodes 16 // aren't changing since there is no downside: the state will be available 17 // even if the dependent items aren't changing. 18 type OutputTransformer struct { 19 Config *configs.Config 20 Changes *plans.Changes 21 22 // If this is a planned destroy, root outputs are still in the configuration 23 // so we need to record that we wish to remove them 24 removeRootOutputs bool 25 26 // Refresh-only mode means that any failing output preconditions are 27 // reported as warnings rather than errors 28 RefreshOnly bool 29 } 30 31 func (t *OutputTransformer) Transform(g *Graph) error { 32 return t.transform(g, t.Config) 33 } 34 35 func (t *OutputTransformer) transform(g *Graph, c *configs.Config) error { 36 // If we have no config then there can be no outputs. 37 if c == nil { 38 return nil 39 } 40 41 // Transform all the children. We must do this first because 42 // we can reference module outputs and they must show up in the 43 // reference map. 44 for _, cc := range c.Children { 45 if err := t.transform(g, cc); err != nil { 46 return err 47 } 48 } 49 50 // Add outputs to the graph, which will be dynamically expanded 51 // into NodeApplyableOutputs to reflect possible expansion 52 // through the presence of "count" or "for_each" on the modules. 53 54 var changes []*plans.OutputChangeSrc 55 if t.Changes != nil { 56 changes = t.Changes.Outputs 57 } 58 59 for _, o := range c.Module.Outputs { 60 addr := addrs.OutputValue{Name: o.Name} 61 62 var rootChange *plans.OutputChangeSrc 63 for _, c := range changes { 64 if c.Addr.Module.IsRoot() && c.Addr.OutputValue.Name == o.Name { 65 rootChange = c 66 } 67 } 68 69 destroy := t.removeRootOutputs 70 if rootChange != nil { 71 destroy = rootChange.Action == plans.Delete 72 } 73 74 // If this is a root output and we're destroying, we add the destroy 75 // node directly, as there is no need to expand. 76 77 var node dag.Vertex 78 switch { 79 case c.Path.IsRoot() && destroy: 80 node = &NodeDestroyableOutput{ 81 Addr: addr.Absolute(addrs.RootModuleInstance), 82 Config: o, 83 } 84 85 default: 86 node = &nodeExpandOutput{ 87 Addr: addr, 88 Module: c.Path, 89 Config: o, 90 Destroy: t.removeRootOutputs, 91 RefreshOnly: t.RefreshOnly, 92 } 93 } 94 95 log.Printf("[TRACE] OutputTransformer: adding %s as %T", o.Name, node) 96 g.Add(node) 97 } 98 99 return nil 100 }