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  }