]>
Commit | Line | Data |
---|---|---|
bae9f6d2 JC |
1 | package terraform |
2 | ||
3 | import ( | |
4 | "fmt" | |
107c1cdb | 5 | "log" |
bae9f6d2 | 6 | |
107c1cdb ND |
7 | "github.com/hashicorp/hcl2/hcl" |
8 | ||
9 | "github.com/hashicorp/terraform/addrs" | |
10 | "github.com/hashicorp/terraform/configs" | |
11 | "github.com/hashicorp/terraform/providers" | |
12 | "github.com/hashicorp/terraform/tfdiags" | |
bae9f6d2 JC |
13 | ) |
14 | ||
107c1cdb ND |
15 | func buildProviderConfig(ctx EvalContext, addr addrs.ProviderConfig, config *configs.Provider) hcl.Body { |
16 | var configBody hcl.Body | |
17 | if config != nil { | |
18 | configBody = config.Config | |
19 | } | |
bae9f6d2 | 20 | |
107c1cdb ND |
21 | var inputBody hcl.Body |
22 | inputConfig := ctx.ProviderInput(addr) | |
23 | if len(inputConfig) > 0 { | |
24 | inputBody = configs.SynthBody("<input-prompt>", inputConfig) | |
bae9f6d2 JC |
25 | } |
26 | ||
107c1cdb ND |
27 | switch { |
28 | case configBody != nil && inputBody != nil: | |
29 | log.Printf("[TRACE] buildProviderConfig for %s: merging explicit config and input", addr) | |
30 | // Note that the inputBody is the _base_ here, because configs.MergeBodies | |
31 | // expects the base have all of the required fields, while these are | |
32 | // forced to be optional for the override. The input process should | |
33 | // guarantee that we have a value for each of the required arguments and | |
34 | // that in practice the sets of attributes in each body will be | |
35 | // disjoint. | |
36 | return configs.MergeBodies(inputBody, configBody) | |
37 | case configBody != nil: | |
38 | log.Printf("[TRACE] buildProviderConfig for %s: using explicit config only", addr) | |
39 | return configBody | |
40 | case inputBody != nil: | |
41 | log.Printf("[TRACE] buildProviderConfig for %s: using input only", addr) | |
42 | return inputBody | |
43 | default: | |
44 | log.Printf("[TRACE] buildProviderConfig for %s: no configuration at all", addr) | |
45 | return hcl.EmptyBody() | |
46 | } | |
bae9f6d2 JC |
47 | } |
48 | ||
49 | // EvalConfigProvider is an EvalNode implementation that configures | |
50 | // a provider that is already initialized and retrieved. | |
51 | type EvalConfigProvider struct { | |
107c1cdb ND |
52 | Addr addrs.ProviderConfig |
53 | Provider *providers.Interface | |
54 | Config *configs.Provider | |
bae9f6d2 JC |
55 | } |
56 | ||
57 | func (n *EvalConfigProvider) Eval(ctx EvalContext) (interface{}, error) { | |
107c1cdb ND |
58 | if n.Provider == nil { |
59 | return nil, fmt.Errorf("EvalConfigProvider Provider is nil") | |
60 | } | |
61 | ||
62 | var diags tfdiags.Diagnostics | |
63 | provider := *n.Provider | |
64 | config := n.Config | |
65 | ||
66 | configBody := buildProviderConfig(ctx, n.Addr, config) | |
67 | ||
68 | resp := provider.GetSchema() | |
69 | diags = diags.Append(resp.Diagnostics) | |
70 | if diags.HasErrors() { | |
71 | return nil, diags.NonFatalErr() | |
72 | } | |
73 | ||
74 | configSchema := resp.Provider.Block | |
75 | configVal, configBody, evalDiags := ctx.EvaluateBlock(configBody, configSchema, nil, EvalDataForNoInstanceKey) | |
76 | diags = diags.Append(evalDiags) | |
77 | if evalDiags.HasErrors() { | |
78 | return nil, diags.NonFatalErr() | |
79 | } | |
80 | ||
81 | configDiags := ctx.ConfigureProvider(n.Addr, configVal) | |
82 | configDiags = configDiags.InConfigBody(configBody) | |
83 | ||
84 | return nil, configDiags.ErrWithWarnings() | |
bae9f6d2 JC |
85 | } |
86 | ||
87 | // EvalInitProvider is an EvalNode implementation that initializes a provider | |
88 | // and returns nothing. The provider can be retrieved again with the | |
89 | // EvalGetProvider node. | |
90 | type EvalInitProvider struct { | |
15c0b25d | 91 | TypeName string |
107c1cdb | 92 | Addr addrs.ProviderConfig |
bae9f6d2 JC |
93 | } |
94 | ||
95 | func (n *EvalInitProvider) Eval(ctx EvalContext) (interface{}, error) { | |
107c1cdb | 96 | return ctx.InitProvider(n.TypeName, n.Addr) |
bae9f6d2 JC |
97 | } |
98 | ||
99 | // EvalCloseProvider is an EvalNode implementation that closes provider | |
100 | // connections that aren't needed anymore. | |
101 | type EvalCloseProvider struct { | |
107c1cdb | 102 | Addr addrs.ProviderConfig |
bae9f6d2 JC |
103 | } |
104 | ||
105 | func (n *EvalCloseProvider) Eval(ctx EvalContext) (interface{}, error) { | |
107c1cdb | 106 | ctx.CloseProvider(n.Addr) |
bae9f6d2 JC |
107 | return nil, nil |
108 | } | |
109 | ||
110 | // EvalGetProvider is an EvalNode implementation that retrieves an already | |
111 | // initialized provider instance for the given name. | |
107c1cdb ND |
112 | // |
113 | // Unlike most eval nodes, this takes an _absolute_ provider configuration, | |
114 | // because providers can be passed into and inherited between modules. | |
115 | // Resource nodes must therefore know the absolute path of the provider they | |
116 | // will use, which is usually accomplished by implementing | |
117 | // interface GraphNodeProviderConsumer. | |
bae9f6d2 | 118 | type EvalGetProvider struct { |
107c1cdb ND |
119 | Addr addrs.AbsProviderConfig |
120 | Output *providers.Interface | |
121 | ||
122 | // If non-nil, Schema will be updated after eval to refer to the | |
123 | // schema of the provider. | |
124 | Schema **ProviderSchema | |
bae9f6d2 JC |
125 | } |
126 | ||
127 | func (n *EvalGetProvider) Eval(ctx EvalContext) (interface{}, error) { | |
107c1cdb ND |
128 | if n.Addr.ProviderConfig.Type == "" { |
129 | // Should never happen | |
130 | panic("EvalGetProvider used with uninitialized provider configuration address") | |
131 | } | |
132 | ||
133 | result := ctx.Provider(n.Addr) | |
bae9f6d2 | 134 | if result == nil { |
107c1cdb | 135 | return nil, fmt.Errorf("provider %s not initialized", n.Addr) |
bae9f6d2 JC |
136 | } |
137 | ||
138 | if n.Output != nil { | |
139 | *n.Output = result | |
140 | } | |
141 | ||
107c1cdb ND |
142 | if n.Schema != nil { |
143 | *n.Schema = ctx.ProviderSchema(n.Addr) | |
bae9f6d2 JC |
144 | } |
145 | ||
bae9f6d2 JC |
146 | return nil, nil |
147 | } |