aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/hashicorp/terraform/terraform/resource_address.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/hashicorp/terraform/terraform/resource_address.go')
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/resource_address.go176
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.
98func (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.
104func (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.
118func (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.
264func 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.
279func (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.
202func (addr *ResourceAddress) Equals(raw interface{}) bool { 320func (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.
361func (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
236func ParseResourceIndex(s string) (int, error) { 406func 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)