github.com/hashicorp/terraform-plugin-sdk@v1.17.2/internal/command/format/object_id.go (about) 1 package format 2 3 import ( 4 "github.com/zclconf/go-cty/cty" 5 ) 6 7 // ObjectValueID takes a value that is assumed to be an object representation 8 // of some resource instance object and attempts to heuristically find an 9 // attribute of it that is likely to be a unique identifier in the remote 10 // system that it belongs to which will be useful to the user. 11 // 12 // If such an attribute is found, its name and string value intended for 13 // display are returned. Both returned strings are empty if no such attribute 14 // exists, in which case the caller should assume that the resource instance 15 // address within the Terraform configuration is the best available identifier. 16 // 17 // This is only a best-effort sort of thing, relying on naming conventions in 18 // our resource type schemas. The result is not guaranteed to be unique, but 19 // should generally be suitable for display to an end-user anyway. 20 // 21 // This function will panic if the given value is not of an object type. 22 func ObjectValueID(obj cty.Value) (k, v string) { 23 if obj.IsNull() || !obj.IsKnown() { 24 return "", "" 25 } 26 27 atys := obj.Type().AttributeTypes() 28 29 switch { 30 31 case atys["id"] == cty.String: 32 v := obj.GetAttr("id") 33 if v.IsKnown() && !v.IsNull() { 34 return "id", v.AsString() 35 } 36 37 case atys["name"] == cty.String: 38 // "name" isn't always globally unique, but if there isn't also an 39 // "id" then it _often_ is, in practice. 40 v := obj.GetAttr("name") 41 if v.IsKnown() && !v.IsNull() { 42 return "name", v.AsString() 43 } 44 } 45 46 return "", "" 47 } 48 49 // ObjectValueName takes a value that is assumed to be an object representation 50 // of some resource instance object and attempts to heuristically find an 51 // attribute of it that is likely to be a human-friendly name in the remote 52 // system that it belongs to which will be useful to the user. 53 // 54 // If such an attribute is found, its name and string value intended for 55 // display are returned. Both returned strings are empty if no such attribute 56 // exists, in which case the caller should assume that the resource instance 57 // address within the Terraform configuration is the best available identifier. 58 // 59 // This is only a best-effort sort of thing, relying on naming conventions in 60 // our resource type schemas. The result is not guaranteed to be unique, but 61 // should generally be suitable for display to an end-user anyway. 62 // 63 // Callers that use both ObjectValueName and ObjectValueID at the same time 64 // should be prepared to get the same attribute key and value from both in 65 // some cases, since there is overlap betweek the id-extraction and 66 // name-extraction heuristics. 67 // 68 // This function will panic if the given value is not of an object type. 69 func ObjectValueName(obj cty.Value) (k, v string) { 70 if obj.IsNull() || !obj.IsKnown() { 71 return "", "" 72 } 73 74 atys := obj.Type().AttributeTypes() 75 76 switch { 77 78 case atys["name"] == cty.String: 79 v := obj.GetAttr("name") 80 if v.IsKnown() && !v.IsNull() { 81 return "name", v.AsString() 82 } 83 84 case atys["tags"].IsMapType() && atys["tags"].ElementType() == cty.String: 85 tags := obj.GetAttr("tags") 86 if tags.IsNull() || !tags.IsWhollyKnown() { 87 break 88 } 89 90 switch { 91 case tags.HasIndex(cty.StringVal("name")).RawEquals(cty.True): 92 v := tags.Index(cty.StringVal("name")) 93 if v.IsKnown() && !v.IsNull() { 94 return "tags.name", v.AsString() 95 } 96 case tags.HasIndex(cty.StringVal("Name")).RawEquals(cty.True): 97 // AWS-style naming convention 98 v := tags.Index(cty.StringVal("Name")) 99 if v.IsKnown() && !v.IsNull() { 100 return "tags.Name", v.AsString() 101 } 102 } 103 } 104 105 return "", "" 106 } 107 108 // ObjectValueIDOrName is a convenience wrapper around both ObjectValueID 109 // and ObjectValueName (in that preference order) to try to extract some sort 110 // of human-friendly descriptive string value for an object as additional 111 // context about an object when it is being displayed in a compact way (where 112 // not all of the attributes are visible.) 113 // 114 // Just as with the two functions it wraps, it is a best-effort and may return 115 // two empty strings if no suitable attribute can be found for a given object. 116 func ObjectValueIDOrName(obj cty.Value) (k, v string) { 117 k, v = ObjectValueID(obj) 118 if k != "" { 119 return 120 } 121 k, v = ObjectValueName(obj) 122 return 123 }