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  }