From bff769e8dc7aef4b64d455c22fb223a68bc13add Mon Sep 17 00:00:00 2001 From: Ahmed Basha <127721368+abasha1234@users.noreply.github.com> Date: Thu, 6 Jun 2024 13:28:20 +0530 Subject: [PATCH] feat: add support for tags to the `newrelic_entity` data source (#2682) Co-authored-by: pranav-new-relic --- go.mod | 12 +++--- go.sum | 27 ++++++------ newrelic/data_source_newrelic_entity.go | 26 +++++++++++- ...source_newrelic_entity_integration_test.go | 5 +++ website/docs/d/entity.html.markdown | 42 ++++++++++++++++++- 5 files changed, 90 insertions(+), 22 deletions(-) diff --git a/go.mod b/go.mod index 3ad922888..6d05ec050 100644 --- a/go.mod +++ b/go.mod @@ -7,8 +7,8 @@ require ( github.com/mitchellh/go-homedir v1.1.0 github.com/newrelic/go-agent/v3 v3.30.0 github.com/newrelic/go-insights v1.0.3 - github.com/newrelic/newrelic-client-go/v2 v2.36.0 - github.com/stretchr/testify v1.8.4 + github.com/newrelic/newrelic-client-go/v2 v2.37.0 + github.com/stretchr/testify v1.9.0 golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 ) @@ -40,7 +40,7 @@ require ( github.com/hashicorp/terraform-registry-address v0.1.0 // indirect github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734 // indirect github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d // indirect - github.com/imdario/mergo v0.3.13 // indirect + github.com/imdario/mergo v0.3.16 // indirect github.com/mattn/go-colorable v0.1.12 // indirect github.com/mattn/go-isatty v0.0.14 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect @@ -50,9 +50,9 @@ require ( github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/oklog/run v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/sirupsen/logrus v1.8.1 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 // indirect - github.com/valyala/fastjson v1.6.3 // indirect + github.com/valyala/fastjson v1.6.4 // indirect github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect github.com/vmihailenco/msgpack/v4 v4.3.12 // indirect github.com/vmihailenco/tagparser v0.1.1 // indirect @@ -60,7 +60,7 @@ require ( golang.org/x/crypto v0.21.0 // indirect golang.org/x/mod v0.16.0 // indirect golang.org/x/net v0.23.0 // indirect - golang.org/x/sys v0.18.0 // indirect + golang.org/x/sys v0.20.0 // indirect golang.org/x/text v0.14.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect diff --git a/go.sum b/go.sum index b571fdd71..e9355bfca 100644 --- a/go.sum +++ b/go.sum @@ -193,8 +193,8 @@ github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= -github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= -github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= +github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= +github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= @@ -267,8 +267,8 @@ github.com/newrelic/go-agent/v3 v3.30.0 h1:ZXHCT/Cot4iIPwcegCZURuRQOsfmGA6wilW+S github.com/newrelic/go-agent/v3 v3.30.0/go.mod h1:9utrgxlSryNqRrTvII2XBL+0lpofXbqXApvVWPpbzUg= github.com/newrelic/go-insights v1.0.3 h1:zSNp1CEZnXktzSIEsbHJk8v6ZihdPFP2WsO/fzau3OQ= github.com/newrelic/go-insights v1.0.3/go.mod h1:A20BoT8TNkqPGX2nS/Z2fYmKl3Cqa3iKZd4whzedCY4= -github.com/newrelic/newrelic-client-go/v2 v2.36.0 h1:A9NZ0xAcgIVyhdSIpg9+dqTKWqtNKsqZQZmmXn+LMZc= -github.com/newrelic/newrelic-client-go/v2 v2.36.0/go.mod h1:JCIsx0H/5MPuP9DzOWMFBrfBZ0apc2NZvsk+Q8CFb7k= +github.com/newrelic/newrelic-client-go/v2 v2.37.0 h1:Uq/FjtDhT+y2iSm/GctBaiHQeN6Wi6ClK6V4OQ44GLg= +github.com/newrelic/newrelic-client-go/v2 v2.37.0/go.mod h1:pDFY24/6iIMEbPIdowTRrRn9YYwkXc3j+B+XpTb4oF4= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= @@ -312,8 +312,8 @@ github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOms github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= -github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= @@ -338,8 +338,8 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/timakin/bodyclose v0.0.0-20190930140734-f7f2e9bca95e/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= @@ -353,8 +353,8 @@ github.com/ultraware/whitespace v0.0.4/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89 github.com/uudashr/gocognit v1.0.1/go.mod h1:j44Ayx2KW4+oB6SWMv8KsmHzZrOInQav7D3cQMJ5JUM= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v1.2.0/go.mod h1:4vX61m6KN+xDduDNwXrhIAVZaZaZiQ1luJk8LWSxF3s= -github.com/valyala/fastjson v1.6.3 h1:tAKFnnwmeMGPbwJ7IwxcTPCNr3uIzoIj3/Fh90ra4xc= -github.com/valyala/fastjson v1.6.3/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= +github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ= +github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= github.com/valyala/quicktemplate v1.2.0/go.mod h1:EH+4AkTd43SvgIbQHYu59/cJyxDoOVRUAfrukLPuGJ4= github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= @@ -446,7 +446,6 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -459,10 +458,11 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= @@ -540,7 +540,6 @@ gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/newrelic/data_source_newrelic_entity.go b/newrelic/data_source_newrelic_entity.go index 77aa86c18..2b81147ec 100644 --- a/newrelic/data_source_newrelic_entity.go +++ b/newrelic/data_source_newrelic_entity.go @@ -2,6 +2,7 @@ package newrelic import ( "context" + "encoding/json" "fmt" "log" "strings" @@ -70,6 +71,11 @@ func dataSourceNewRelicEntity() *schema.Resource { }, }, }, + "entity_tags": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, "account_id": { Type: schema.TypeInt, Optional: true, @@ -133,7 +139,6 @@ func dataSourceNewRelicEntityRead(ctx context.Context, d *schema.ResourceData, m var entity *entities.EntityOutlineInterface for _, e := range entityResults.Results.Entities { // Conditional on case-sensitive match - str := e.GetName() str = strings.TrimSpace(str) @@ -195,6 +200,25 @@ func flattenEntityData(entity *entities.EntityOutlineInterface, d *schema.Resour return err } + entityTags := (*entity).GetTags() + if len(entityTags) != 0 { + entityTagsJSONMarshalled, jsonMarshalError := json.Marshal(entityTags) + if jsonMarshalError != nil { + log.Printf("[WARNING] Error marshalling entity tags: %v", jsonMarshalError) + log.Printf("[WARNING] The above error is disallowing setting `entity_tags` in the data source") + // do not throw an error, to prevent blocking results being returned by the data source if there is an issue with tag marshalling + return nil + } + if entityTagsJSONMarshalled != nil { + if entityTagsSetError := d.Set("entity_tags", string(entityTagsJSONMarshalled)); err != nil { + log.Printf("[WARNING] Error setting marshalled entity tags to the state: %v", entityTagsSetError) + log.Printf("[WARNING] The above error is disallowing setting `entity_tags` in the data source") + // do not throw an error, to prevent blocking results being returned by the data source if there is an issue with string conversion + return nil + } + } + } + // store extra values per Entity Type, have to repeat code here due to // go handling of type switching switch e := (*entity).(type) { diff --git a/newrelic/data_source_newrelic_entity_integration_test.go b/newrelic/data_source_newrelic_entity_integration_test.go index 800f047d8..0cf990a08 100644 --- a/newrelic/data_source_newrelic_entity_integration_test.go +++ b/newrelic/data_source_newrelic_entity_integration_test.go @@ -169,6 +169,11 @@ func testAccCheckNewRelicEntityDataExists(t *testing.T, n string, appName string return fmt.Errorf("expected the entity name to be: %s, but got: %s", appName, a["name"]) } + entityTags := a["entity_tags"] + if entityTags == "" || entityTags == "null" { + return fmt.Errorf("expected entity tags to be present and not null") + } + return nil } } diff --git a/website/docs/d/entity.html.markdown b/website/docs/d/entity.html.markdown index 64b9a44f0..84b92c8b8 100644 --- a/website/docs/d/entity.html.markdown +++ b/website/docs/d/entity.html.markdown @@ -165,7 +165,8 @@ In addition to all arguments above, the following attributes are exported: * `guid` - The unique GUID of the entity. * `application_id` - The domain-specific application ID of the entity. Only returned for APM and Browser applications. * `serving_apm_application_id` - The browser-specific ID of the backing APM entity. Only returned for Browser applications. - +* `entity_tags` - A JSON-encoded string, comprising tags associated with the entity fetched. + * See the [**Additional Examples**](#using-the-entity_tags-attribute-to-fetch-tags-associated-with-the-entity) section below, for an illustration depicting the usage of `jsondecode` with the attribute `entity_tags`, to get the tags associated with the entity fetched. ## Additional Examples @@ -194,3 +195,42 @@ data "newrelic_entity" "app" { type = "AWSLAMBDAFUNCTION" } ``` + +### Using the `entity_tags` Attribute to Fetch Tags Associated with the Entity + +As stated above in the [**Attributes Reference**](#attributes-reference) section, while the attribute `entity_tags` helps retrieve tags associated with the entity fetched by the data source, the tags are returned as a JSON-encoded string and not a conventional list or a map, owing to a couple of design considerations; which is why one would need to use the Terraform function `jsondecode()`, along with the attribute `entity_tags` in order to convert the JSON-encoded string into a map with key-value pairs. + +The following is an illustration of the aforementioned scenario. It may be observed that a key-value pair version of the JSON-encoded string exported by `entity_tags` is written to the variable `key_value_maps` , using the `jsondecode()` function. + +```hcl +data "newrelic_entity" "foo" { + name = "Sample Searchable Entity" + domain = "EXT" + type = "SERVICE_LEVEL" +} + +locals { + key_value_map = { for pair in jsondecode(data.newrelic_entity.foo.entity_tags) : pair.key => pair.values } +} + +output "key_value_map" { + value = local.key_value_map +} + +``` +The value of `local.key_value_map` would look like the following. +```hcl +{ + env = ["production"] + team = ["ops"] +} +``` + +In order to prevent an error being thrown by the variable added if no tags are associated with the entity (consequently, the value of `entity_tags` is an empty string), the value of the variable may be conditionally defined in order to not throw an error, as shown below. + +```hcl +locals { + key_value_map = data.newrelic_entity.foo.entity_tags != null ? { for pair in jsondecode(data.newrelic_entity.foo.entity_tags) : pair.key => pair.values } : null +} +``` +