diff options
Diffstat (limited to 'vendor/github.com/hashicorp/terraform/terraform/resource_address.go')
-rw-r--r-- | vendor/github.com/hashicorp/terraform/terraform/resource_address.go | 176 |
1 files changed, 173 insertions, 3 deletions
diff --git a/vendor/github.com/hashicorp/terraform/terraform/resource_address.go b/vendor/github.com/hashicorp/terraform/terraform/resource_address.go index a8a0c95..8badca8 100644 --- a/vendor/github.com/hashicorp/terraform/terraform/resource_address.go +++ b/vendor/github.com/hashicorp/terraform/terraform/resource_address.go | |||
@@ -8,6 +8,7 @@ import ( | |||
8 | "strings" | 8 | "strings" |
9 | 9 | ||
10 | "github.com/hashicorp/terraform/config" | 10 | "github.com/hashicorp/terraform/config" |
11 | "github.com/hashicorp/terraform/config/module" | ||
11 | ) | 12 | ) |
12 | 13 | ||
13 | // ResourceAddress is a way of identifying an individual resource (or, | 14 | // ResourceAddress is a way of identifying an individual resource (or, |
@@ -89,6 +90,51 @@ func (r *ResourceAddress) String() string { | |||
89 | return strings.Join(result, ".") | 90 | return strings.Join(result, ".") |
90 | } | 91 | } |
91 | 92 | ||
93 | // HasResourceSpec returns true if the address has a resource spec, as | ||
94 | // defined in the documentation: | ||
95 | // https://www.terraform.io/docs/internals/resource-addressing.html | ||
96 | // In particular, this returns false if the address contains only | ||
97 | // a module path, thus addressing the entire module. | ||
98 | func (r *ResourceAddress) HasResourceSpec() bool { | ||
99 | return r.Type != "" && r.Name != "" | ||
100 | } | ||
101 | |||
102 | // WholeModuleAddress returns the resource address that refers to all | ||
103 | // resources in the same module as the receiver address. | ||
104 | func (r *ResourceAddress) WholeModuleAddress() *ResourceAddress { | ||
105 | return &ResourceAddress{ | ||
106 | Path: r.Path, | ||
107 | Index: -1, | ||
108 | InstanceTypeSet: false, | ||
109 | } | ||
110 | } | ||
111 | |||
112 | // MatchesConfig returns true if the receiver matches the given | ||
113 | // configuration resource within the given configuration module. | ||
114 | // | ||
115 | // Since resource configuration blocks represent all of the instances of | ||
116 | // a multi-instance resource, the index of the address (if any) is not | ||
117 | // considered. | ||
118 | func (r *ResourceAddress) MatchesConfig(mod *module.Tree, rc *config.Resource) bool { | ||
119 | if r.HasResourceSpec() { | ||
120 | if r.Mode != rc.Mode || r.Type != rc.Type || r.Name != rc.Name { | ||
121 | return false | ||
122 | } | ||
123 | } | ||
124 | |||
125 | addrPath := r.Path | ||
126 | cfgPath := mod.Path() | ||
127 | |||
128 | // normalize | ||
129 | if len(addrPath) == 0 { | ||
130 | addrPath = nil | ||
131 | } | ||
132 | if len(cfgPath) == 0 { | ||
133 | cfgPath = nil | ||
134 | } | ||
135 | return reflect.DeepEqual(addrPath, cfgPath) | ||
136 | } | ||
137 | |||
92 | // stateId returns the ID that this resource should be entered with | 138 | // stateId returns the ID that this resource should be entered with |
93 | // in the state. This is also used for diffs. In the future, we'd like to | 139 | // in the state. This is also used for diffs. In the future, we'd like to |
94 | // move away from this string field so I don't export this. | 140 | // move away from this string field so I don't export this. |
@@ -185,7 +231,10 @@ func ParseResourceAddress(s string) (*ResourceAddress, error) { | |||
185 | 231 | ||
186 | // not allowed to say "data." without a type following | 232 | // not allowed to say "data." without a type following |
187 | if mode == config.DataResourceMode && matches["type"] == "" { | 233 | if mode == config.DataResourceMode && matches["type"] == "" { |
188 | return nil, fmt.Errorf("must target specific data instance") | 234 | return nil, fmt.Errorf( |
235 | "invalid resource address %q: must target specific data instance", | ||
236 | s, | ||
237 | ) | ||
189 | } | 238 | } |
190 | 239 | ||
191 | return &ResourceAddress{ | 240 | return &ResourceAddress{ |
@@ -199,6 +248,75 @@ func ParseResourceAddress(s string) (*ResourceAddress, error) { | |||
199 | }, nil | 248 | }, nil |
200 | } | 249 | } |
201 | 250 | ||
251 | // ParseResourceAddressForInstanceDiff creates a ResourceAddress for a | ||
252 | // resource name as described in a module diff. | ||
253 | // | ||
254 | // For historical reasons a different addressing format is used in this | ||
255 | // context. The internal format should not be shown in the UI and instead | ||
256 | // this function should be used to translate to a ResourceAddress and | ||
257 | // then, where appropriate, use the String method to produce a canonical | ||
258 | // resource address string for display in the UI. | ||
259 | // | ||
260 | // The given path slice must be empty (or nil) for the root module, and | ||
261 | // otherwise consist of a sequence of module names traversing down into | ||
262 | // the module tree. If a non-nil path is provided, the caller must not | ||
263 | // modify its underlying array after passing it to this function. | ||
264 | func ParseResourceAddressForInstanceDiff(path []string, key string) (*ResourceAddress, error) { | ||
265 | addr, err := parseResourceAddressInternal(key) | ||
266 | if err != nil { | ||
267 | return nil, err | ||
268 | } | ||
269 | addr.Path = path | ||
270 | return addr, nil | ||
271 | } | ||
272 | |||
273 | // Contains returns true if and only if the given node is contained within | ||
274 | // the receiver. | ||
275 | // | ||
276 | // Containment is defined in terms of the module and resource heirarchy: | ||
277 | // a resource is contained within its module and any ancestor modules, | ||
278 | // an indexed resource instance is contained with the unindexed resource, etc. | ||
279 | func (addr *ResourceAddress) Contains(other *ResourceAddress) bool { | ||
280 | ourPath := addr.Path | ||
281 | givenPath := other.Path | ||
282 | if len(givenPath) < len(ourPath) { | ||
283 | return false | ||
284 | } | ||
285 | for i := range ourPath { | ||
286 | if ourPath[i] != givenPath[i] { | ||
287 | return false | ||
288 | } | ||
289 | } | ||
290 | |||
291 | // If the receiver is a whole-module address then the path prefix | ||
292 | // matching is all we need. | ||
293 | if !addr.HasResourceSpec() { | ||
294 | return true | ||
295 | } | ||
296 | |||
297 | if addr.Type != other.Type || addr.Name != other.Name || addr.Mode != other.Mode { | ||
298 | return false | ||
299 | } | ||
300 | |||
301 | if addr.Index != -1 && addr.Index != other.Index { | ||
302 | return false | ||
303 | } | ||
304 | |||
305 | if addr.InstanceTypeSet && (addr.InstanceTypeSet != other.InstanceTypeSet || addr.InstanceType != other.InstanceType) { | ||
306 | return false | ||
307 | } | ||
308 | |||
309 | return true | ||
310 | } | ||
311 | |||
312 | // Equals returns true if the receiver matches the given address. | ||
313 | // | ||
314 | // The name of this method is a misnomer, since it doesn't test for exact | ||
315 | // equality. Instead, it tests that the _specified_ parts of each | ||
316 | // address match, treating any unspecified parts as wildcards. | ||
317 | // | ||
318 | // See also Contains, which takes a more heirarchical approach to comparing | ||
319 | // addresses. | ||
202 | func (addr *ResourceAddress) Equals(raw interface{}) bool { | 320 | func (addr *ResourceAddress) Equals(raw interface{}) bool { |
203 | other, ok := raw.(*ResourceAddress) | 321 | other, ok := raw.(*ResourceAddress) |
204 | if !ok { | 322 | if !ok { |
@@ -233,6 +351,58 @@ func (addr *ResourceAddress) Equals(raw interface{}) bool { | |||
233 | modeMatch | 351 | modeMatch |
234 | } | 352 | } |
235 | 353 | ||
354 | // Less returns true if and only if the receiver should be sorted before | ||
355 | // the given address when presenting a list of resource addresses to | ||
356 | // an end-user. | ||
357 | // | ||
358 | // This sort uses lexicographic sorting for most components, but uses | ||
359 | // numeric sort for indices, thus causing index 10 to sort after | ||
360 | // index 9, rather than after index 1. | ||
361 | func (addr *ResourceAddress) Less(other *ResourceAddress) bool { | ||
362 | |||
363 | switch { | ||
364 | |||
365 | case len(addr.Path) < len(other.Path): | ||
366 | return true | ||
367 | |||
368 | case !reflect.DeepEqual(addr.Path, other.Path): | ||
369 | // If the two paths are the same length but don't match, we'll just | ||
370 | // cheat and compare the string forms since it's easier than | ||
371 | // comparing all of the path segments in turn. | ||
372 | addrStr := addr.String() | ||
373 | otherStr := other.String() | ||
374 | return addrStr < otherStr | ||
375 | |||
376 | case addr.Mode == config.DataResourceMode && other.Mode != config.DataResourceMode: | ||
377 | return true | ||
378 | |||
379 | case addr.Type < other.Type: | ||
380 | return true | ||
381 | |||
382 | case addr.Name < other.Name: | ||
383 | return true | ||
384 | |||
385 | case addr.Index < other.Index: | ||
386 | // Since "Index" is -1 for an un-indexed address, this also conveniently | ||
387 | // sorts unindexed addresses before indexed ones, should they both | ||
388 | // appear for some reason. | ||
389 | return true | ||
390 | |||
391 | case other.InstanceTypeSet && !addr.InstanceTypeSet: | ||
392 | return true | ||
393 | |||
394 | case addr.InstanceType < other.InstanceType: | ||
395 | // InstanceType is actually an enum, so this is just an arbitrary | ||
396 | // sort based on the enum numeric values, and thus not particularly | ||
397 | // meaningful. | ||
398 | return true | ||
399 | |||
400 | default: | ||
401 | return false | ||
402 | |||
403 | } | ||
404 | } | ||
405 | |||
236 | func ParseResourceIndex(s string) (int, error) { | 406 | func ParseResourceIndex(s string) (int, error) { |
237 | if s == "" { | 407 | if s == "" { |
238 | return -1, nil | 408 | return -1, nil |
@@ -275,7 +445,7 @@ func tokenizeResourceAddress(s string) (map[string]string, error) { | |||
275 | // string "aws_instance.web.tainted[1]" | 445 | // string "aws_instance.web.tainted[1]" |
276 | re := regexp.MustCompile(`\A` + | 446 | re := regexp.MustCompile(`\A` + |
277 | // "module.foo.module.bar" (optional) | 447 | // "module.foo.module.bar" (optional) |
278 | `(?P<path>(?:module\.[^.]+\.?)*)` + | 448 | `(?P<path>(?:module\.(?P<module_name>[^.]+)\.?)*)` + |
279 | // possibly "data.", if targeting is a data resource | 449 | // possibly "data.", if targeting is a data resource |
280 | `(?P<data_prefix>(?:data\.)?)` + | 450 | `(?P<data_prefix>(?:data\.)?)` + |
281 | // "aws_instance.web" (optional when module path specified) | 451 | // "aws_instance.web" (optional when module path specified) |
@@ -289,7 +459,7 @@ func tokenizeResourceAddress(s string) (map[string]string, error) { | |||
289 | groupNames := re.SubexpNames() | 459 | groupNames := re.SubexpNames() |
290 | rawMatches := re.FindAllStringSubmatch(s, -1) | 460 | rawMatches := re.FindAllStringSubmatch(s, -1) |
291 | if len(rawMatches) != 1 { | 461 | if len(rawMatches) != 1 { |
292 | return nil, fmt.Errorf("Problem parsing address: %q", s) | 462 | return nil, fmt.Errorf("invalid resource address %q", s) |
293 | } | 463 | } |
294 | 464 | ||
295 | matches := make(map[string]string) | 465 | matches := make(map[string]string) |