]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blobdiff - vendor/github.com/hashicorp/terraform/terraform/transform_module_variable.go
Merge branch 'fix_read_test' of github.com:alexandreFre/terraform-provider-statuscake
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / terraform / terraform / transform_module_variable.go
index 467950bdc67a769d1baa48caab40099859a4e608..a994bd4faf6308a2f64b7e8a42cd38e5c1958965 100644 (file)
@@ -1,46 +1,54 @@
 package terraform
 
 import (
-       "log"
+       "fmt"
 
-       "github.com/hashicorp/terraform/config"
-       "github.com/hashicorp/terraform/config/module"
-       "github.com/hashicorp/terraform/dag"
+       "github.com/hashicorp/hcl2/hcl/hclsyntax"
+       "github.com/hashicorp/terraform/tfdiags"
+       "github.com/zclconf/go-cty/cty"
+
+       "github.com/hashicorp/hcl2/hcl"
+       "github.com/hashicorp/terraform/configs"
 )
 
 // ModuleVariableTransformer is a GraphTransformer that adds all the variables
 // in the configuration to the graph.
 //
-// This only adds variables that are referenced by other things in the graph.
-// If a module variable is not referenced, it won't be added to the graph.
+// Any "variable" block present in any non-root module is included here, even
+// if a particular variable is not referenced from anywhere.
+//
+// The transform will produce errors if a call to a module does not conform
+// to the expected set of arguments, but this transformer is not in a good
+// position to return errors and so the validate walk should include specific
+// steps for validating module blocks, separate from this transform.
 type ModuleVariableTransformer struct {
-       Module *module.Tree
-
-       DisablePrune bool // True if pruning unreferenced should be disabled
+       Config *configs.Config
 }
 
 func (t *ModuleVariableTransformer) Transform(g *Graph) error {
-       return t.transform(g, nil, t.Module)
+       return t.transform(g, nil, t.Config)
 }
 
-func (t *ModuleVariableTransformer) transform(g *Graph, parent, m *module.Tree) error {
-       // If no config, no variables
-       if m == nil {
+func (t *ModuleVariableTransformer) transform(g *Graph, parent, c *configs.Config) error {
+       // We can have no variables if we have no configuration.
+       if c == nil {
                return nil
        }
 
-       // Transform all the children. This must be done BEFORE the transform
-       // above since child module variables can reference parent module variables.
-       for _, c := range m.Children() {
-               if err := t.transform(g, m, c); err != nil {
+       // Transform all the children first.
+       for _, cc := range c.Children {
+               if err := t.transform(g, c, cc); err != nil {
                        return err
                }
        }
 
+       // If we're processing anything other than the root module then we'll
+       // add graph nodes for variables defined inside. (Variables for the root
+       // module are dealt with in RootVariableTransformer).
        // If we have a parent, we can determine if a module variable is being
        // used, so we transform this.
        if parent != nil {
-               if err := t.transformSingle(g, parent, m); err != nil {
+               if err := t.transformSingle(g, parent, c); err != nil {
                        return err
                }
        }
@@ -48,71 +56,69 @@ func (t *ModuleVariableTransformer) transform(g *Graph, parent, m *module.Tree)
        return nil
 }
 
-func (t *ModuleVariableTransformer) transformSingle(g *Graph, parent, m *module.Tree) error {
-       // If we have no vars, we're done!
-       vars := m.Config().Variables
-       if len(vars) == 0 {
-               log.Printf("[TRACE] Module %#v has no variables, skipping.", m.Path())
-               return nil
+func (t *ModuleVariableTransformer) transformSingle(g *Graph, parent, c *configs.Config) error {
+
+       // Our addressing system distinguishes between modules and module instances,
+       // but we're not yet ready to make that distinction here (since we don't
+       // support "count"/"for_each" on modules) and so we just do a naive
+       // transform of the module path into a module instance path, assuming that
+       // no keys are in use. This should be removed when "count" and "for_each"
+       // are implemented for modules.
+       path := c.Path.UnkeyedInstanceShim()
+       _, call := path.Call()
+
+       // Find the call in the parent module configuration, so we can get the
+       // expressions given for each input variable at the call site.
+       callConfig, exists := parent.Module.ModuleCalls[call.Name]
+       if !exists {
+               // This should never happen, since it indicates an improperly-constructed
+               // configuration tree.
+               panic(fmt.Errorf("no module call block found for %s", path))
        }
 
-       // Look for usage of this module
-       var mod *config.Module
-       for _, modUse := range parent.Config().Modules {
-               if modUse.Name == m.Name() {
-                       mod = modUse
-                       break
-               }
+       // We need to construct a schema for the expected call arguments based on
+       // the configured variables in our config, which we can then use to
+       // decode the content of the call block.
+       schema := &hcl.BodySchema{}
+       for _, v := range c.Module.Variables {
+               schema.Attributes = append(schema.Attributes, hcl.AttributeSchema{
+                       Name:     v.Name,
+                       Required: v.Default == cty.NilVal,
+               })
        }
-       if mod == nil {
-               log.Printf("[INFO] Module %#v not used, not adding variables", m.Path())
-               return nil
+
+       content, contentDiags := callConfig.Config.Content(schema)
+       if contentDiags.HasErrors() {
+               // Validation code elsewhere should deal with any errors before we
+               // get in here, but we'll report them out here just in case, to
+               // avoid crashes.
+               var diags tfdiags.Diagnostics
+               diags = diags.Append(contentDiags)
+               return diags.Err()
        }
 
-       // Build the reference map so we can determine if we're referencing things.
-       refMap := NewReferenceMap(g.Vertices())
-
-       // Add all variables here
-       for _, v := range vars {
-               // Determine the value of the variable. If it isn't in the
-               // configuration then it was never set and that's not a problem.
-               var value *config.RawConfig
-               if raw, ok := mod.RawConfig.Raw[v.Name]; ok {
-                       var err error
-                       value, err = config.NewRawConfig(map[string]interface{}{
-                               v.Name: raw,
-                       })
-                       if err != nil {
-                               // This shouldn't happen because it is already in
-                               // a RawConfig above meaning it worked once before.
-                               panic(err)
+       for _, v := range c.Module.Variables {
+               var expr hcl.Expression
+               if attr := content.Attributes[v.Name]; attr != nil {
+                       expr = attr.Expr
+               } else {
+                       // No expression provided for this variable, so we'll make a
+                       // synthetic one using the variable's default value.
+                       expr = &hclsyntax.LiteralValueExpr{
+                               Val:      v.Default,
+                               SrcRange: v.DeclRange, // This is not exact, but close enough
                        }
                }
 
-               // Build the node.
-               //
-               // NOTE: For now this is just an "applyable" variable. As we build
-               // new graph builders for the other operations I suspect we'll
-               // find a way to parameterize this, require new transforms, etc.
+               // For now we treat all module variables as "applyable", even though
+               // such nodes are valid to use on other walks too. We may specialize
+               // this in future if we find reasons to employ different behaviors
+               // in different scenarios.
                node := &NodeApplyableModuleVariable{
-                       PathValue: normalizeModulePath(m.Path()),
-                       Config:    v,
-                       Value:     value,
-                       Module:    t.Module,
+                       Addr:   path.InputVariable(v.Name),
+                       Config: v,
+                       Expr:   expr,
                }
-
-               if !t.DisablePrune {
-                       // If the node is not referenced by anything, then we don't need
-                       // to include it since it won't be used.
-                       if matches := refMap.ReferencedBy(node); len(matches) == 0 {
-                               log.Printf(
-                                       "[INFO] Not including %q in graph, nothing depends on it",
-                                       dag.VertexName(node))
-                               continue
-                       }
-               }
-
-               // Add it!
                g.Add(node)
        }