github.com/muratcelep/terraform@v1.1.0-beta2-not-internal-4/not-internal/terraform/transform_module_variable.go (about)

     1  package terraform
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/hashicorp/hcl/v2/hclsyntax"
     7  	"github.com/muratcelep/terraform/not-internal/addrs"
     8  	"github.com/muratcelep/terraform/not-internal/tfdiags"
     9  	"github.com/zclconf/go-cty/cty"
    10  
    11  	"github.com/hashicorp/hcl/v2"
    12  	"github.com/muratcelep/terraform/not-internal/configs"
    13  )
    14  
    15  // ModuleVariableTransformer is a GraphTransformer that adds all the variables
    16  // in the configuration to the graph.
    17  //
    18  // Any "variable" block present in any non-root module is included here, even
    19  // if a particular variable is not referenced from anywhere.
    20  //
    21  // The transform will produce errors if a call to a module does not conform
    22  // to the expected set of arguments, but this transformer is not in a good
    23  // position to return errors and so the validate walk should include specific
    24  // steps for validating module blocks, separate from this transform.
    25  type ModuleVariableTransformer struct {
    26  	Config *configs.Config
    27  }
    28  
    29  func (t *ModuleVariableTransformer) Transform(g *Graph) error {
    30  	return t.transform(g, nil, t.Config)
    31  }
    32  
    33  func (t *ModuleVariableTransformer) transform(g *Graph, parent, c *configs.Config) error {
    34  	// We can have no variables if we have no configuration.
    35  	if c == nil {
    36  		return nil
    37  	}
    38  
    39  	// Transform all the children first.
    40  	for _, cc := range c.Children {
    41  		if err := t.transform(g, c, cc); err != nil {
    42  			return err
    43  		}
    44  	}
    45  
    46  	// If we're processing anything other than the root module then we'll
    47  	// add graph nodes for variables defined inside. (Variables for the root
    48  	// module are dealt with in RootVariableTransformer).
    49  	// If we have a parent, we can determine if a module variable is being
    50  	// used, so we transform this.
    51  	if parent != nil {
    52  		if err := t.transformSingle(g, parent, c); err != nil {
    53  			return err
    54  		}
    55  	}
    56  
    57  	return nil
    58  }
    59  
    60  func (t *ModuleVariableTransformer) transformSingle(g *Graph, parent, c *configs.Config) error {
    61  	_, call := c.Path.Call()
    62  
    63  	// Find the call in the parent module configuration, so we can get the
    64  	// expressions given for each input variable at the call site.
    65  	callConfig, exists := parent.Module.ModuleCalls[call.Name]
    66  	if !exists {
    67  		// This should never happen, since it indicates an improperly-constructed
    68  		// configuration tree.
    69  		panic(fmt.Errorf("no module call block found for %s", c.Path))
    70  	}
    71  
    72  	// We need to construct a schema for the expected call arguments based on
    73  	// the configured variables in our config, which we can then use to
    74  	// decode the content of the call block.
    75  	schema := &hcl.BodySchema{}
    76  	for _, v := range c.Module.Variables {
    77  		schema.Attributes = append(schema.Attributes, hcl.AttributeSchema{
    78  			Name:     v.Name,
    79  			Required: v.Default == cty.NilVal,
    80  		})
    81  	}
    82  
    83  	content, contentDiags := callConfig.Config.Content(schema)
    84  	if contentDiags.HasErrors() {
    85  		// Validation code elsewhere should deal with any errors before we
    86  		// get in here, but we'll report them out here just in case, to
    87  		// avoid crashes.
    88  		var diags tfdiags.Diagnostics
    89  		diags = diags.Append(contentDiags)
    90  		return diags.Err()
    91  	}
    92  
    93  	for _, v := range c.Module.Variables {
    94  		var expr hcl.Expression
    95  		if attr := content.Attributes[v.Name]; attr != nil {
    96  			expr = attr.Expr
    97  		} else {
    98  			// No expression provided for this variable, so we'll make a
    99  			// synthetic one using the variable's default value.
   100  			expr = &hclsyntax.LiteralValueExpr{
   101  				Val:      v.Default,
   102  				SrcRange: v.DeclRange, // This is not exact, but close enough
   103  			}
   104  		}
   105  
   106  		// Add a plannable node, as the variable may expand
   107  		// during module expansion
   108  		node := &nodeExpandModuleVariable{
   109  			Addr: addrs.InputVariable{
   110  				Name: v.Name,
   111  			},
   112  			Module: c.Path,
   113  			Config: v,
   114  			Expr:   expr,
   115  		}
   116  		g.Add(node)
   117  	}
   118  
   119  	return nil
   120  }