]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/hashicorp/terraform/addrs/provider_config.go
Upgrade to 0.12
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / terraform / addrs / provider_config.go
1 package addrs
2
3 import (
4 "fmt"
5
6 "github.com/hashicorp/terraform/tfdiags"
7
8 "github.com/hashicorp/hcl2/hcl"
9 "github.com/hashicorp/hcl2/hcl/hclsyntax"
10 )
11
12 // ProviderConfig is the address of a provider configuration.
13 type ProviderConfig struct {
14 Type string
15
16 // If not empty, Alias identifies which non-default (aliased) provider
17 // configuration this address refers to.
18 Alias string
19 }
20
21 // NewDefaultProviderConfig returns the address of the default (un-aliased)
22 // configuration for the provider with the given type name.
23 func NewDefaultProviderConfig(typeName string) ProviderConfig {
24 return ProviderConfig{
25 Type: typeName,
26 }
27 }
28
29 // ParseProviderConfigCompact parses the given absolute traversal as a relative
30 // provider address in compact form. The following are examples of traversals
31 // that can be successfully parsed as compact relative provider configuration
32 // addresses:
33 //
34 // aws
35 // aws.foo
36 //
37 // This function will panic if given a relative traversal.
38 //
39 // If the returned diagnostics contains errors then the result value is invalid
40 // and must not be used.
41 func ParseProviderConfigCompact(traversal hcl.Traversal) (ProviderConfig, tfdiags.Diagnostics) {
42 var diags tfdiags.Diagnostics
43 ret := ProviderConfig{
44 Type: traversal.RootName(),
45 }
46
47 if len(traversal) < 2 {
48 // Just a type name, then.
49 return ret, diags
50 }
51
52 aliasStep := traversal[1]
53 switch ts := aliasStep.(type) {
54 case hcl.TraverseAttr:
55 ret.Alias = ts.Name
56 return ret, diags
57 default:
58 diags = diags.Append(&hcl.Diagnostic{
59 Severity: hcl.DiagError,
60 Summary: "Invalid provider configuration address",
61 Detail: "The provider type name must either stand alone or be followed by an alias name separated with a dot.",
62 Subject: aliasStep.SourceRange().Ptr(),
63 })
64 }
65
66 if len(traversal) > 2 {
67 diags = diags.Append(&hcl.Diagnostic{
68 Severity: hcl.DiagError,
69 Summary: "Invalid provider configuration address",
70 Detail: "Extraneous extra operators after provider configuration address.",
71 Subject: traversal[2:].SourceRange().Ptr(),
72 })
73 }
74
75 return ret, diags
76 }
77
78 // ParseProviderConfigCompactStr is a helper wrapper around ParseProviderConfigCompact
79 // that takes a string and parses it with the HCL native syntax traversal parser
80 // before interpreting it.
81 //
82 // This should be used only in specialized situations since it will cause the
83 // created references to not have any meaningful source location information.
84 // If a reference string is coming from a source that should be identified in
85 // error messages then the caller should instead parse it directly using a
86 // suitable function from the HCL API and pass the traversal itself to
87 // ParseProviderConfigCompact.
88 //
89 // Error diagnostics are returned if either the parsing fails or the analysis
90 // of the traversal fails. There is no way for the caller to distinguish the
91 // two kinds of diagnostics programmatically. If error diagnostics are returned
92 // then the returned address is invalid.
93 func ParseProviderConfigCompactStr(str string) (ProviderConfig, tfdiags.Diagnostics) {
94 var diags tfdiags.Diagnostics
95
96 traversal, parseDiags := hclsyntax.ParseTraversalAbs([]byte(str), "", hcl.Pos{Line: 1, Column: 1})
97 diags = diags.Append(parseDiags)
98 if parseDiags.HasErrors() {
99 return ProviderConfig{}, diags
100 }
101
102 addr, addrDiags := ParseProviderConfigCompact(traversal)
103 diags = diags.Append(addrDiags)
104 return addr, diags
105 }
106
107 // Absolute returns an AbsProviderConfig from the receiver and the given module
108 // instance address.
109 func (pc ProviderConfig) Absolute(module ModuleInstance) AbsProviderConfig {
110 return AbsProviderConfig{
111 Module: module,
112 ProviderConfig: pc,
113 }
114 }
115
116 func (pc ProviderConfig) String() string {
117 if pc.Type == "" {
118 // Should never happen; always indicates a bug
119 return "provider.<invalid>"
120 }
121
122 if pc.Alias != "" {
123 return fmt.Sprintf("provider.%s.%s", pc.Type, pc.Alias)
124 }
125
126 return "provider." + pc.Type
127 }
128
129 // StringCompact is an alternative to String that returns the form that can
130 // be parsed by ParseProviderConfigCompact, without the "provider." prefix.
131 func (pc ProviderConfig) StringCompact() string {
132 if pc.Alias != "" {
133 return fmt.Sprintf("%s.%s", pc.Type, pc.Alias)
134 }
135 return pc.Type
136 }
137
138 // AbsProviderConfig is the absolute address of a provider configuration
139 // within a particular module instance.
140 type AbsProviderConfig struct {
141 Module ModuleInstance
142 ProviderConfig ProviderConfig
143 }
144
145 // ParseAbsProviderConfig parses the given traversal as an absolute provider
146 // address. The following are examples of traversals that can be successfully
147 // parsed as absolute provider configuration addresses:
148 //
149 // provider.aws
150 // provider.aws.foo
151 // module.bar.provider.aws
152 // module.bar.module.baz.provider.aws.foo
153 // module.foo[1].provider.aws.foo
154 //
155 // This type of address is used, for example, to record the relationships
156 // between resources and provider configurations in the state structure.
157 // This type of address is not generally used in the UI, except in error
158 // messages that refer to provider configurations.
159 func ParseAbsProviderConfig(traversal hcl.Traversal) (AbsProviderConfig, tfdiags.Diagnostics) {
160 modInst, remain, diags := parseModuleInstancePrefix(traversal)
161 ret := AbsProviderConfig{
162 Module: modInst,
163 }
164 if len(remain) < 2 || remain.RootName() != "provider" {
165 diags = diags.Append(&hcl.Diagnostic{
166 Severity: hcl.DiagError,
167 Summary: "Invalid provider configuration address",
168 Detail: "Provider address must begin with \"provider.\", followed by a provider type name.",
169 Subject: remain.SourceRange().Ptr(),
170 })
171 return ret, diags
172 }
173 if len(remain) > 3 {
174 diags = diags.Append(&hcl.Diagnostic{
175 Severity: hcl.DiagError,
176 Summary: "Invalid provider configuration address",
177 Detail: "Extraneous operators after provider configuration alias.",
178 Subject: hcl.Traversal(remain[3:]).SourceRange().Ptr(),
179 })
180 return ret, diags
181 }
182
183 if tt, ok := remain[1].(hcl.TraverseAttr); ok {
184 ret.ProviderConfig.Type = tt.Name
185 } else {
186 diags = diags.Append(&hcl.Diagnostic{
187 Severity: hcl.DiagError,
188 Summary: "Invalid provider configuration address",
189 Detail: "The prefix \"provider.\" must be followed by a provider type name.",
190 Subject: remain[1].SourceRange().Ptr(),
191 })
192 return ret, diags
193 }
194
195 if len(remain) == 3 {
196 if tt, ok := remain[2].(hcl.TraverseAttr); ok {
197 ret.ProviderConfig.Alias = tt.Name
198 } else {
199 diags = diags.Append(&hcl.Diagnostic{
200 Severity: hcl.DiagError,
201 Summary: "Invalid provider configuration address",
202 Detail: "Provider type name must be followed by a configuration alias name.",
203 Subject: remain[2].SourceRange().Ptr(),
204 })
205 return ret, diags
206 }
207 }
208
209 return ret, diags
210 }
211
212 // ParseAbsProviderConfigStr is a helper wrapper around ParseAbsProviderConfig
213 // that takes a string and parses it with the HCL native syntax traversal parser
214 // before interpreting it.
215 //
216 // This should be used only in specialized situations since it will cause the
217 // created references to not have any meaningful source location information.
218 // If a reference string is coming from a source that should be identified in
219 // error messages then the caller should instead parse it directly using a
220 // suitable function from the HCL API and pass the traversal itself to
221 // ParseAbsProviderConfig.
222 //
223 // Error diagnostics are returned if either the parsing fails or the analysis
224 // of the traversal fails. There is no way for the caller to distinguish the
225 // two kinds of diagnostics programmatically. If error diagnostics are returned
226 // the returned address is invalid.
227 func ParseAbsProviderConfigStr(str string) (AbsProviderConfig, tfdiags.Diagnostics) {
228 var diags tfdiags.Diagnostics
229
230 traversal, parseDiags := hclsyntax.ParseTraversalAbs([]byte(str), "", hcl.Pos{Line: 1, Column: 1})
231 diags = diags.Append(parseDiags)
232 if parseDiags.HasErrors() {
233 return AbsProviderConfig{}, diags
234 }
235
236 addr, addrDiags := ParseAbsProviderConfig(traversal)
237 diags = diags.Append(addrDiags)
238 return addr, diags
239 }
240
241 // ProviderConfigDefault returns the address of the default provider config
242 // of the given type inside the recieving module instance.
243 func (m ModuleInstance) ProviderConfigDefault(name string) AbsProviderConfig {
244 return AbsProviderConfig{
245 Module: m,
246 ProviderConfig: ProviderConfig{
247 Type: name,
248 },
249 }
250 }
251
252 // ProviderConfigAliased returns the address of an aliased provider config
253 // of with given type and alias inside the recieving module instance.
254 func (m ModuleInstance) ProviderConfigAliased(name, alias string) AbsProviderConfig {
255 return AbsProviderConfig{
256 Module: m,
257 ProviderConfig: ProviderConfig{
258 Type: name,
259 Alias: alias,
260 },
261 }
262 }
263
264 // Inherited returns an address that the receiving configuration address might
265 // inherit from in a parent module. The second bool return value indicates if
266 // such inheritance is possible, and thus whether the returned address is valid.
267 //
268 // Inheritance is possible only for default (un-aliased) providers in modules
269 // other than the root module. Even if a valid address is returned, inheritence
270 // may not be performed for other reasons, such as if the calling module
271 // provided explicit provider configurations within the call for this module.
272 // The ProviderTransformer graph transform in the main terraform module has
273 // the authoritative logic for provider inheritance, and this method is here
274 // mainly just for its benefit.
275 func (pc AbsProviderConfig) Inherited() (AbsProviderConfig, bool) {
276 // Can't inherit if we're already in the root.
277 if len(pc.Module) == 0 {
278 return AbsProviderConfig{}, false
279 }
280
281 // Can't inherit if we have an alias.
282 if pc.ProviderConfig.Alias != "" {
283 return AbsProviderConfig{}, false
284 }
285
286 // Otherwise, we might inherit from a configuration with the same
287 // provider name in the parent module instance.
288 parentMod := pc.Module.Parent()
289 return pc.ProviderConfig.Absolute(parentMod), true
290 }
291
292 func (pc AbsProviderConfig) String() string {
293 if len(pc.Module) == 0 {
294 return pc.ProviderConfig.String()
295 }
296 return fmt.Sprintf("%s.%s", pc.Module.String(), pc.ProviderConfig.String())
297 }