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