]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blame - 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
CommitLineData
bae9f6d2
JC
1package terraform
2
3import (
107c1cdb 4 "fmt"
bae9f6d2 5
107c1cdb
ND
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"
bae9f6d2
JC
12)
13
14// ModuleVariableTransformer is a GraphTransformer that adds all the variables
15// in the configuration to the graph.
16//
107c1cdb
ND
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.
bae9f6d2 24type ModuleVariableTransformer struct {
107c1cdb 25 Config *configs.Config
bae9f6d2
JC
26}
27
28func (t *ModuleVariableTransformer) Transform(g *Graph) error {
107c1cdb 29 return t.transform(g, nil, t.Config)
bae9f6d2
JC
30}
31
107c1cdb
ND
32func (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 {
bae9f6d2
JC
35 return nil
36 }
37
107c1cdb
ND
38 // Transform all the children first.
39 for _, cc := range c.Children {
40 if err := t.transform(g, c, cc); err != nil {
bae9f6d2
JC
41 return err
42 }
43 }
44
107c1cdb
ND
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).
bae9f6d2
JC
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 {
107c1cdb 51 if err := t.transformSingle(g, parent, c); err != nil {
bae9f6d2
JC
52 return err
53 }
54 }
55
56 return nil
57}
58
107c1cdb
ND
59func (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))
bae9f6d2
JC
77 }
78
107c1cdb
ND
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 })
bae9f6d2 88 }
107c1cdb
ND
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()
bae9f6d2
JC
98 }
99
107c1cdb
ND
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
bae9f6d2
JC
110 }
111 }
112
107c1cdb
ND
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.
bae9f6d2 117 node := &NodeApplyableModuleVariable{
107c1cdb
ND
118 Addr: path.InputVariable(v.Name),
119 Config: v,
120 Expr: expr,
bae9f6d2 121 }
bae9f6d2
JC
122 g.Add(node)
123 }
124
125 return nil
126}