github.com/muratcelep/terraform@v1.1.0-beta2-not-internal-4/not-internal/terraform/node_module_expand.go (about) 1 package terraform 2 3 import ( 4 "log" 5 6 "github.com/muratcelep/terraform/not-internal/addrs" 7 "github.com/muratcelep/terraform/not-internal/configs" 8 "github.com/muratcelep/terraform/not-internal/dag" 9 "github.com/muratcelep/terraform/not-internal/lang" 10 "github.com/muratcelep/terraform/not-internal/tfdiags" 11 ) 12 13 type ConcreteModuleNodeFunc func(n *nodeExpandModule) dag.Vertex 14 15 // nodeExpandModule represents a module call in the configuration that 16 // might expand into multiple module instances depending on how it is 17 // configured. 18 type nodeExpandModule struct { 19 Addr addrs.Module 20 Config *configs.Module 21 ModuleCall *configs.ModuleCall 22 } 23 24 var ( 25 _ GraphNodeExecutable = (*nodeExpandModule)(nil) 26 _ GraphNodeReferencer = (*nodeExpandModule)(nil) 27 _ GraphNodeReferenceOutside = (*nodeExpandModule)(nil) 28 _ graphNodeExpandsInstances = (*nodeExpandModule)(nil) 29 ) 30 31 func (n *nodeExpandModule) expandsInstances() {} 32 33 func (n *nodeExpandModule) Name() string { 34 return n.Addr.String() + " (expand)" 35 } 36 37 // GraphNodeModulePath implementation 38 func (n *nodeExpandModule) ModulePath() addrs.Module { 39 return n.Addr 40 } 41 42 // GraphNodeReferencer implementation 43 func (n *nodeExpandModule) References() []*addrs.Reference { 44 var refs []*addrs.Reference 45 46 if n.ModuleCall == nil { 47 return nil 48 } 49 50 refs = append(refs, n.DependsOn()...) 51 52 // Expansion only uses the count and for_each expressions, so this 53 // particular graph node only refers to those. 54 // Individual variable values in the module call definition might also 55 // refer to other objects, but that's handled by 56 // NodeApplyableModuleVariable. 57 // 58 // Because our Path method returns the module instance that contains 59 // our call, these references will be correctly interpreted as being 60 // in the calling module's namespace, not the namespaces of any of the 61 // child module instances we might expand to during our evaluation. 62 63 if n.ModuleCall.Count != nil { 64 countRefs, _ := lang.ReferencesInExpr(n.ModuleCall.Count) 65 refs = append(refs, countRefs...) 66 } 67 if n.ModuleCall.ForEach != nil { 68 forEachRefs, _ := lang.ReferencesInExpr(n.ModuleCall.ForEach) 69 refs = append(refs, forEachRefs...) 70 } 71 return refs 72 } 73 74 func (n *nodeExpandModule) DependsOn() []*addrs.Reference { 75 if n.ModuleCall == nil { 76 return nil 77 } 78 79 var refs []*addrs.Reference 80 for _, traversal := range n.ModuleCall.DependsOn { 81 ref, diags := addrs.ParseRef(traversal) 82 if diags.HasErrors() { 83 // We ignore this here, because this isn't a suitable place to return 84 // errors. This situation should be caught and rejected during 85 // validation. 86 log.Printf("[ERROR] Can't parse %#v from depends_on as reference: %s", traversal, diags.Err()) 87 continue 88 } 89 90 refs = append(refs, ref) 91 } 92 93 return refs 94 } 95 96 // GraphNodeReferenceOutside 97 func (n *nodeExpandModule) ReferenceOutside() (selfPath, referencePath addrs.Module) { 98 return n.Addr, n.Addr.Parent() 99 } 100 101 // GraphNodeExecutable 102 func (n *nodeExpandModule) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) { 103 expander := ctx.InstanceExpander() 104 _, call := n.Addr.Call() 105 106 // nodeExpandModule itself does not have visibility into how its ancestors 107 // were expanded, so we use the expander here to provide all possible paths 108 // to our module, and register module instances with each of them. 109 for _, module := range expander.ExpandModule(n.Addr.Parent()) { 110 ctx = ctx.WithPath(module) 111 switch { 112 case n.ModuleCall.Count != nil: 113 count, ctDiags := evaluateCountExpression(n.ModuleCall.Count, ctx) 114 diags = diags.Append(ctDiags) 115 if diags.HasErrors() { 116 return diags 117 } 118 expander.SetModuleCount(module, call, count) 119 120 case n.ModuleCall.ForEach != nil: 121 forEach, feDiags := evaluateForEachExpression(n.ModuleCall.ForEach, ctx) 122 diags = diags.Append(feDiags) 123 if diags.HasErrors() { 124 return diags 125 } 126 expander.SetModuleForEach(module, call, forEach) 127 128 default: 129 expander.SetModuleSingle(module, call) 130 } 131 } 132 133 return diags 134 135 } 136 137 // nodeCloseModule represents an expanded module during apply, and is visited 138 // after all other module instance nodes. This node will depend on all module 139 // instance resource and outputs, and anything depending on the module should 140 // wait on this node. 141 // Besides providing a root node for dependency ordering, nodeCloseModule also 142 // cleans up state after all the module nodes have been evaluated, removing 143 // empty resources and modules from the state. 144 // The root module instance also closes any remaining provisioner plugins which 145 // do not have a lifecycle controlled by individual graph nodes. 146 type nodeCloseModule struct { 147 Addr addrs.Module 148 } 149 150 var ( 151 _ GraphNodeReferenceable = (*nodeCloseModule)(nil) 152 _ GraphNodeReferenceOutside = (*nodeCloseModule)(nil) 153 _ GraphNodeExecutable = (*nodeCloseModule)(nil) 154 ) 155 156 func (n *nodeCloseModule) ModulePath() addrs.Module { 157 return n.Addr 158 } 159 160 func (n *nodeCloseModule) ReferenceOutside() (selfPath, referencePath addrs.Module) { 161 return n.Addr.Parent(), n.Addr 162 } 163 164 func (n *nodeCloseModule) ReferenceableAddrs() []addrs.Referenceable { 165 _, call := n.Addr.Call() 166 return []addrs.Referenceable{ 167 call, 168 } 169 } 170 171 func (n *nodeCloseModule) Name() string { 172 if len(n.Addr) == 0 { 173 return "root" 174 } 175 return n.Addr.String() + " (close)" 176 } 177 178 func (n *nodeCloseModule) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) { 179 if n.Addr.IsRoot() { 180 // If this is the root module, we are cleaning up the walk, so close 181 // any running provisioners 182 diags = diags.Append(ctx.CloseProvisioners()) 183 } 184 185 switch op { 186 case walkApply, walkDestroy: 187 state := ctx.State().Lock() 188 defer ctx.State().Unlock() 189 190 for modKey, mod := range state.Modules { 191 if !n.Addr.Equal(mod.Addr.Module()) { 192 continue 193 } 194 195 // clean out any empty resources 196 for resKey, res := range mod.Resources { 197 if len(res.Instances) == 0 { 198 delete(mod.Resources, resKey) 199 } 200 } 201 202 // empty child modules are always removed 203 if len(mod.Resources) == 0 && !mod.Addr.IsRoot() { 204 delete(state.Modules, modKey) 205 } 206 } 207 return nil 208 default: 209 return nil 210 } 211 } 212 213 // nodeValidateModule wraps a nodeExpand module for validation, ensuring that 214 // no expansion is attempted during evaluation, when count and for_each 215 // expressions may not be known. 216 type nodeValidateModule struct { 217 nodeExpandModule 218 } 219 220 var _ GraphNodeExecutable = (*nodeValidateModule)(nil) 221 222 // GraphNodeEvalable 223 func (n *nodeValidateModule) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) { 224 _, call := n.Addr.Call() 225 expander := ctx.InstanceExpander() 226 227 // Modules all evaluate to single instances during validation, only to 228 // create a proper context within which to evaluate. All parent modules 229 // will be a single instance, but still get our address in the expected 230 // manner anyway to ensure they've been registered correctly. 231 for _, module := range expander.ExpandModule(n.Addr.Parent()) { 232 ctx = ctx.WithPath(module) 233 234 // Validate our for_each and count expressions at a basic level 235 // We skip validation on known, because there will be unknown values before 236 // a full expansion, presuming these errors will be caught in later steps 237 switch { 238 case n.ModuleCall.Count != nil: 239 _, countDiags := evaluateCountExpressionValue(n.ModuleCall.Count, ctx) 240 diags = diags.Append(countDiags) 241 242 case n.ModuleCall.ForEach != nil: 243 _, forEachDiags := evaluateForEachExpressionValue(n.ModuleCall.ForEach, ctx, true) 244 diags = diags.Append(forEachDiags) 245 } 246 247 diags = diags.Append(validateDependsOn(ctx, n.ModuleCall.DependsOn)) 248 249 // now set our own mode to single 250 expander.SetModuleSingle(module, call) 251 } 252 253 return diags 254 }