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