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