kubeform.dev/terraform-backend-sdk@v0.0.0-20220310143633-45f07fe731c5/configs/config.go (about) 1 package configs 2 3 import ( 4 "fmt" 5 "sort" 6 7 version "github.com/hashicorp/go-version" 8 "github.com/hashicorp/hcl/v2" 9 "kubeform.dev/terraform-backend-sdk/addrs" 10 "kubeform.dev/terraform-backend-sdk/getproviders" 11 ) 12 13 // A Config is a node in the tree of modules within a configuration. 14 // 15 // The module tree is constructed by following ModuleCall instances recursively 16 // through the root module transitively into descendent modules. 17 // 18 // A module tree described in *this* package represents the static tree 19 // represented by configuration. During evaluation a static ModuleNode may 20 // expand into zero or more module instances depending on the use of count and 21 // for_each configuration attributes within each call. 22 type Config struct { 23 // RootModule points to the Config for the root module within the same 24 // module tree as this module. If this module _is_ the root module then 25 // this is self-referential. 26 Root *Config 27 28 // ParentModule points to the Config for the module that directly calls 29 // this module. If this is the root module then this field is nil. 30 Parent *Config 31 32 // Path is a sequence of module logical names that traverse from the root 33 // module to this config. Path is empty for the root module. 34 // 35 // This should only be used to display paths to the end-user in rare cases 36 // where we are talking about the static module tree, before module calls 37 // have been resolved. In most cases, an addrs.ModuleInstance describing 38 // a node in the dynamic module tree is better, since it will then include 39 // any keys resulting from evaluating "count" and "for_each" arguments. 40 Path addrs.Module 41 42 // ChildModules points to the Config for each of the direct child modules 43 // called from this module. The keys in this map match the keys in 44 // Module.ModuleCalls. 45 Children map[string]*Config 46 47 // Module points to the object describing the configuration for the 48 // various elements (variables, resources, etc) defined by this module. 49 Module *Module 50 51 // CallRange is the source range for the header of the module block that 52 // requested this module. 53 // 54 // This field is meaningless for the root module, where its contents are undefined. 55 CallRange hcl.Range 56 57 // SourceAddr is the source address that the referenced module was requested 58 // from, as specified in configuration. SourceAddrRaw is the same 59 // information, but as the raw string the user originally entered. 60 // 61 // These fields are meaningless for the root module, where their contents are undefined. 62 SourceAddr addrs.ModuleSource 63 SourceAddrRaw string 64 65 // SourceAddrRange is the location in the configuration source where the 66 // SourceAddr value was set, for use in diagnostic messages. 67 // 68 // This field is meaningless for the root module, where its contents are undefined. 69 SourceAddrRange hcl.Range 70 71 // Version is the specific version that was selected for this module, 72 // based on version constraints given in configuration. 73 // 74 // This field is nil if the module was loaded from a non-registry source, 75 // since versions are not supported for other sources. 76 // 77 // This field is meaningless for the root module, where it will always 78 // be nil. 79 Version *version.Version 80 } 81 82 // ModuleRequirements represents the provider requirements for an individual 83 // module, along with references to any child modules. This is used to 84 // determine which modules require which providers. 85 type ModuleRequirements struct { 86 Name string 87 SourceAddr addrs.ModuleSource 88 SourceDir string 89 Requirements getproviders.Requirements 90 Children map[string]*ModuleRequirements 91 } 92 93 // NewEmptyConfig constructs a single-node configuration tree with an empty 94 // root module. This is generally a pretty useless thing to do, so most callers 95 // should instead use BuildConfig. 96 func NewEmptyConfig() *Config { 97 ret := &Config{} 98 ret.Root = ret 99 ret.Children = make(map[string]*Config) 100 ret.Module = &Module{} 101 return ret 102 } 103 104 // Depth returns the number of "hops" the receiver is from the root of its 105 // module tree, with the root module having a depth of zero. 106 func (c *Config) Depth() int { 107 ret := 0 108 this := c 109 for this.Parent != nil { 110 ret++ 111 this = this.Parent 112 } 113 return ret 114 } 115 116 // DeepEach calls the given function once for each module in the tree, starting 117 // with the receiver. 118 // 119 // A parent is always called before its children and children of a particular 120 // node are visited in lexicographic order by their names. 121 func (c *Config) DeepEach(cb func(c *Config)) { 122 cb(c) 123 124 names := make([]string, 0, len(c.Children)) 125 for name := range c.Children { 126 names = append(names, name) 127 } 128 129 for _, name := range names { 130 c.Children[name].DeepEach(cb) 131 } 132 } 133 134 // AllModules returns a slice of all the receiver and all of its descendent 135 // nodes in the module tree, in the same order they would be visited by 136 // DeepEach. 137 func (c *Config) AllModules() []*Config { 138 var ret []*Config 139 c.DeepEach(func(c *Config) { 140 ret = append(ret, c) 141 }) 142 return ret 143 } 144 145 // Descendent returns the descendent config that has the given path beneath 146 // the receiver, or nil if there is no such module. 147 // 148 // The path traverses the static module tree, prior to any expansion to handle 149 // count and for_each arguments. 150 // 151 // An empty path will just return the receiver, and is therefore pointless. 152 func (c *Config) Descendent(path addrs.Module) *Config { 153 current := c 154 for _, name := range path { 155 current = current.Children[name] 156 if current == nil { 157 return nil 158 } 159 } 160 return current 161 } 162 163 // DescendentForInstance is like Descendent except that it accepts a path 164 // to a particular module instance in the dynamic module graph, returning 165 // the node from the static module graph that corresponds to it. 166 // 167 // All instances created by a particular module call share the same 168 // configuration, so the keys within the given path are disregarded. 169 func (c *Config) DescendentForInstance(path addrs.ModuleInstance) *Config { 170 current := c 171 for _, step := range path { 172 current = current.Children[step.Name] 173 if current == nil { 174 return nil 175 } 176 } 177 return current 178 } 179 180 // EntersNewPackage returns true if this call is to an external module, either 181 // directly via a remote source address or indirectly via a registry source 182 // address. 183 // 184 // Other behaviors in Terraform may treat package crossings as a special 185 // situation, because that indicates that the caller and callee can change 186 // independently of one another and thus we should disallow using any features 187 // where the caller assumes anything about the callee other than its input 188 // variables, required provider configurations, and output values. 189 // 190 // It's not meaningful to ask if the Config representing the root module enters 191 // a new package because the root module is always outside of all module 192 // packages, and so this function will arbitrarily return false in that case. 193 func (c *Config) EntersNewPackage() bool { 194 return moduleSourceAddrEntersNewPackage(c.SourceAddr) 195 } 196 197 // ProviderRequirements searches the full tree of modules under the receiver 198 // for both explicit and implicit dependencies on providers. 199 // 200 // The result is a full manifest of all of the providers that must be available 201 // in order to work with the receiving configuration. 202 // 203 // If the returned diagnostics includes errors then the resulting Requirements 204 // may be incomplete. 205 func (c *Config) ProviderRequirements() (getproviders.Requirements, hcl.Diagnostics) { 206 reqs := make(getproviders.Requirements) 207 diags := c.addProviderRequirements(reqs, true) 208 209 return reqs, diags 210 } 211 212 // ProviderRequirementsShallow searches only the direct receiver for explicit 213 // and implicit dependencies on providers. Descendant modules are ignored. 214 // 215 // If the returned diagnostics includes errors then the resulting Requirements 216 // may be incomplete. 217 func (c *Config) ProviderRequirementsShallow() (getproviders.Requirements, hcl.Diagnostics) { 218 reqs := make(getproviders.Requirements) 219 diags := c.addProviderRequirements(reqs, false) 220 221 return reqs, diags 222 } 223 224 // ProviderRequirementsByModule searches the full tree of modules under the 225 // receiver for both explicit and implicit dependencies on providers, 226 // constructing a tree where the requirements are broken out by module. 227 // 228 // If the returned diagnostics includes errors then the resulting Requirements 229 // may be incomplete. 230 func (c *Config) ProviderRequirementsByModule() (*ModuleRequirements, hcl.Diagnostics) { 231 reqs := make(getproviders.Requirements) 232 diags := c.addProviderRequirements(reqs, false) 233 234 children := make(map[string]*ModuleRequirements) 235 for name, child := range c.Children { 236 childReqs, childDiags := child.ProviderRequirementsByModule() 237 childReqs.Name = name 238 children[name] = childReqs 239 diags = append(diags, childDiags...) 240 } 241 242 ret := &ModuleRequirements{ 243 SourceAddr: c.SourceAddr, 244 SourceDir: c.Module.SourceDir, 245 Requirements: reqs, 246 Children: children, 247 } 248 249 return ret, diags 250 } 251 252 // addProviderRequirements is the main part of the ProviderRequirements 253 // implementation, gradually mutating a shared requirements object to 254 // eventually return. If the recurse argument is true, the requirements will 255 // include all descendant modules; otherwise, only the specified module. 256 func (c *Config) addProviderRequirements(reqs getproviders.Requirements, recurse bool) hcl.Diagnostics { 257 var diags hcl.Diagnostics 258 259 // First we'll deal with the requirements directly in _our_ module... 260 if c.Module.ProviderRequirements != nil { 261 for _, providerReqs := range c.Module.ProviderRequirements.RequiredProviders { 262 fqn := providerReqs.Type 263 if _, ok := reqs[fqn]; !ok { 264 // We'll at least have an unconstrained dependency then, but might 265 // add to this in the loop below. 266 reqs[fqn] = nil 267 } 268 // The model of version constraints in this package is still the 269 // old one using a different upstream module to represent versions, 270 // so we'll need to shim that out here for now. The two parsers 271 // don't exactly agree in practice 🙄 so this might produce new errors. 272 // TODO: Use the new parser throughout this package so we can get the 273 // better error messages it produces in more situations. 274 constraints, err := getproviders.ParseVersionConstraints(providerReqs.Requirement.Required.String()) 275 if err != nil { 276 diags = diags.Append(&hcl.Diagnostic{ 277 Severity: hcl.DiagError, 278 Summary: "Invalid version constraint", 279 // The errors returned by ParseVersionConstraint already include 280 // the section of input that was incorrect, so we don't need to 281 // include that here. 282 Detail: fmt.Sprintf("Incorrect version constraint syntax: %s.", err.Error()), 283 Subject: providerReqs.Requirement.DeclRange.Ptr(), 284 }) 285 } 286 reqs[fqn] = append(reqs[fqn], constraints...) 287 } 288 } 289 290 // Each resource in the configuration creates an *implicit* provider 291 // dependency, though we'll only record it if there isn't already 292 // an explicit dependency on the same provider. 293 for _, rc := range c.Module.ManagedResources { 294 fqn := rc.Provider 295 if _, exists := reqs[fqn]; exists { 296 // Explicit dependency already present 297 continue 298 } 299 reqs[fqn] = nil 300 } 301 for _, rc := range c.Module.DataResources { 302 fqn := rc.Provider 303 if _, exists := reqs[fqn]; exists { 304 // Explicit dependency already present 305 continue 306 } 307 reqs[fqn] = nil 308 } 309 310 // "provider" block can also contain version constraints 311 for _, provider := range c.Module.ProviderConfigs { 312 fqn := c.Module.ProviderForLocalConfig(addrs.LocalProviderConfig{LocalName: provider.Name}) 313 if _, ok := reqs[fqn]; !ok { 314 // We'll at least have an unconstrained dependency then, but might 315 // add to this in the loop below. 316 reqs[fqn] = nil 317 } 318 if provider.Version.Required != nil { 319 // The model of version constraints in this package is still the 320 // old one using a different upstream module to represent versions, 321 // so we'll need to shim that out here for now. The two parsers 322 // don't exactly agree in practice 🙄 so this might produce new errors. 323 // TODO: Use the new parser throughout this package so we can get the 324 // better error messages it produces in more situations. 325 constraints, err := getproviders.ParseVersionConstraints(provider.Version.Required.String()) 326 if err != nil { 327 diags = diags.Append(&hcl.Diagnostic{ 328 Severity: hcl.DiagError, 329 Summary: "Invalid version constraint", 330 // The errors returned by ParseVersionConstraint already include 331 // the section of input that was incorrect, so we don't need to 332 // include that here. 333 Detail: fmt.Sprintf("Incorrect version constraint syntax: %s.", err.Error()), 334 Subject: provider.Version.DeclRange.Ptr(), 335 }) 336 } 337 reqs[fqn] = append(reqs[fqn], constraints...) 338 } 339 } 340 341 if recurse { 342 for _, childConfig := range c.Children { 343 moreDiags := childConfig.addProviderRequirements(reqs, true) 344 diags = append(diags, moreDiags...) 345 } 346 } 347 348 return diags 349 } 350 351 // resolveProviderTypes walks through the providers in the module and ensures 352 // the true types are assigned based on the provider requirements for the 353 // module. 354 func (c *Config) resolveProviderTypes() { 355 for _, child := range c.Children { 356 child.resolveProviderTypes() 357 } 358 359 // collect the required_providers, and then add any missing default providers 360 providers := map[string]addrs.Provider{} 361 for name, p := range c.Module.ProviderRequirements.RequiredProviders { 362 providers[name] = p.Type 363 } 364 365 // ensure all provider configs know their correct type 366 for _, p := range c.Module.ProviderConfigs { 367 addr, required := providers[p.Name] 368 if required { 369 p.providerType = addr 370 } else { 371 addr := addrs.NewDefaultProvider(p.Name) 372 p.providerType = addr 373 providers[p.Name] = addr 374 } 375 } 376 377 // connect module call providers to the correct type 378 for _, mod := range c.Module.ModuleCalls { 379 for _, p := range mod.Providers { 380 if addr, known := providers[p.InParent.Name]; known { 381 p.InParent.providerType = addr 382 } 383 } 384 } 385 386 // fill in parent module calls too 387 if c.Parent != nil { 388 for _, mod := range c.Parent.Module.ModuleCalls { 389 for _, p := range mod.Providers { 390 if addr, known := providers[p.InChild.Name]; known { 391 p.InChild.providerType = addr 392 } 393 } 394 } 395 } 396 } 397 398 // ProviderTypes returns the FQNs of each distinct provider type referenced 399 // in the receiving configuration. 400 // 401 // This is a helper for easily determining which provider types are required 402 // to fully interpret the configuration, though it does not include version 403 // information and so callers are expected to have already dealt with 404 // provider version selection in an earlier step and have identified suitable 405 // versions for each provider. 406 func (c *Config) ProviderTypes() []addrs.Provider { 407 // Ignore diagnostics here because they relate to version constraints 408 reqs, _ := c.ProviderRequirements() 409 410 ret := make([]addrs.Provider, 0, len(reqs)) 411 for k := range reqs { 412 ret = append(ret, k) 413 } 414 sort.Slice(ret, func(i, j int) bool { 415 return ret[i].String() < ret[j].String() 416 }) 417 return ret 418 } 419 420 // ResolveAbsProviderAddr returns the AbsProviderConfig represented by the given 421 // ProviderConfig address, which must not be nil or this method will panic. 422 // 423 // If the given address is already an AbsProviderConfig then this method returns 424 // it verbatim, and will always succeed. If it's a LocalProviderConfig then 425 // it will consult the local-to-FQN mapping table for the given module 426 // to find the absolute address corresponding to the given local one. 427 // 428 // The module address to resolve local addresses in must be given in the second 429 // argument, and must refer to a module that exists under the receiver or 430 // else this method will panic. 431 func (c *Config) ResolveAbsProviderAddr(addr addrs.ProviderConfig, inModule addrs.Module) addrs.AbsProviderConfig { 432 switch addr := addr.(type) { 433 434 case addrs.AbsProviderConfig: 435 return addr 436 437 case addrs.LocalProviderConfig: 438 // Find the descendent Config that contains the module that this 439 // local config belongs to. 440 mc := c.Descendent(inModule) 441 if mc == nil { 442 panic(fmt.Sprintf("ResolveAbsProviderAddr with non-existent module %s", inModule.String())) 443 } 444 445 var provider addrs.Provider 446 if providerReq, exists := c.Module.ProviderRequirements.RequiredProviders[addr.LocalName]; exists { 447 provider = providerReq.Type 448 } else { 449 provider = addrs.ImpliedProviderForUnqualifiedType(addr.LocalName) 450 } 451 452 return addrs.AbsProviderConfig{ 453 Module: inModule, 454 Provider: provider, 455 Alias: addr.Alias, 456 } 457 458 default: 459 panic(fmt.Sprintf("cannot ResolveAbsProviderAddr(%v, ...)", addr)) 460 } 461 462 } 463 464 // ProviderForConfigAddr returns the FQN for a given addrs.ProviderConfig, first 465 // by checking for the provider in module.ProviderRequirements and falling 466 // back to addrs.NewDefaultProvider if it is not found. 467 func (c *Config) ProviderForConfigAddr(addr addrs.LocalProviderConfig) addrs.Provider { 468 if provider, exists := c.Module.ProviderRequirements.RequiredProviders[addr.LocalName]; exists { 469 return provider.Type 470 } 471 return c.ResolveAbsProviderAddr(addr, addrs.RootModule).Provider 472 }