From 73adb9625ca086965373b8b5010dd61f66467e81 Mon Sep 17 00:00:00 2001 From: Chris Josephs Date: Mon, 25 Nov 2024 16:19:30 -0800 Subject: [PATCH 01/13] add target_appd_url with url input validation --- signalfx/resource_signalfx_data_link.go | 66 ++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/signalfx/resource_signalfx_data_link.go b/signalfx/resource_signalfx_data_link.go index 6f2d3898..67b38181 100644 --- a/signalfx/resource_signalfx_data_link.go +++ b/signalfx/resource_signalfx_data_link.go @@ -8,6 +8,8 @@ import ( "encoding/json" "fmt" "log" + "net/url" + "strconv" "strings" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -128,6 +130,25 @@ func dataLinkResource() *schema.Resource { }, }, }, + "target_appd_url": { + Type: schema.TypeSet, + Optional: true, + Description: "Link to AppDynamics URL", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "User-assigned target name. Use this value to differentiate between the link targets for a data link object.", + }, + "url": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "URL string for an AppDyanmics data link target.", + }, + }, + }, + }, }, Create: dataLinkCreate, @@ -206,6 +227,49 @@ func getPayloadDataLink(d *schema.ResourceData) (*datalink.CreateUpdateDataLinkR } } + // New AppD datalink check + // REQ: url validation + // REQ: url follows appd pattern + // REQ: appd applicatin id and content id are of type integer + if val, ok := d.GetOk("target_appd_url"); ok { + appdURLs := val.(*schema.Set).List() + + for _, tfLink := range appdURLs { + tfLink := tfLink.(map[string]interface{}) + + // AppD URL validation + appdUrl, err := url.ParseRequestURI(tfLink["url"].(string)) + if err != nil { + return dataLink, fmt.Errorf("Invalid URL") + } + if !strings.HasSuffix(appdUrl.Host, ".saas.appdynamics.com") || !strings.HasPrefix(appdUrl.Path, "/controller") { + return dataLink, fmt.Errorf("Invalid AppDynamics URL") + } + + queryParams := appdUrl.Query() + componentId, applicationId := queryParams["component"], queryParams["application"] + if len(componentId) != 1 || len(applicationId) != 1 { + return dataLink, fmt.Errorf("URL must include a valid component and application ID") + } + + _, componentIdErr := strconv.Atoi(componentId[0]) + _, applicationIdErr := strconv.Atoi(applicationId[0]) + if componentIdErr != nil || applicationIdErr != nil { + return dataLink, fmt.Errorf("URL must include a valid component and application ID") + } + + dl := &datalink.Target{ + Name: tfLink["name"].(string), + URL: tfLink["url"].(string), + // Need to add APPD_LINK type to signalfx-go library + // Type: datalink.APPD_LINK, + Type: datalink.EXTERNAL_LINK, + } + + dataLink.Targets = append(dataLink.Targets, dl) + } + } + if val, ok := d.GetOk("target_external_url"); ok { exURLs := val.(*schema.Set).List() @@ -249,7 +313,7 @@ func getPayloadDataLink(d *schema.ResourceData) (*datalink.CreateUpdateDataLinkR } if len(dataLink.Targets) < 1 { - return dataLink, fmt.Errorf("You must provide one or more of `target_signalfx_dashboard`, `target_external_url`, or `target_splunk`") + return dataLink, fmt.Errorf("You must provide one or more of `target_signalfx_dashboard`, `target_external_url`, `target_appd_url` or `target_splunk`") } return dataLink, nil From 8e53ed701f43aec1a0912e1a44508479ab0eec54 Mon Sep 17 00:00:00 2001 From: Chris Josephs Date: Tue, 26 Nov 2024 10:38:26 -0800 Subject: [PATCH 02/13] add acceptance tests for new appd data link --- signalfx/resource_signalfx_data_link_test.go | 56 ++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/signalfx/resource_signalfx_data_link_test.go b/signalfx/resource_signalfx_data_link_test.go index d89547b9..d9a273a7 100644 --- a/signalfx/resource_signalfx_data_link_test.go +++ b/signalfx/resource_signalfx_data_link_test.go @@ -72,6 +72,30 @@ resource "signalfx_data_link" "big_test_data_link" { } ` +const newDataLinkAppdConfig = ` + resource "signalfx_data_link" "big_test_data_link" { + property_name = "pname" + property_value = "pvalue" + + target_appd_url { + name = "appd_url" + url = "https://example.saas.appdynamics.com/controller/#/application=3039831&component=3677819" + } + } +` + +const newDataLinkAppdConfigBadUrlErr = ` + resource "signalfx_data_link" "big_test_data_link" { + property_name = "pname" + property_value = "pvalue" + + target_appd_url { + name = "appd_url" + url = "https://example.saas.appdynamics.com/controller/#/application=3039831" + } + } +` + func TestAccCreateDashboardDataLinkFails(t *testing.T) { resource.Test(t, resource.TestCase{ Providers: testAccProviders, @@ -140,6 +164,38 @@ func TestAccCreateUpdateDataLinkWithoutPropertyValue(t *testing.T) { }) } +// AppD DataLink acceptance tests +func testAccCreateAppdDataLinkFails(t *testing.T) { + resource.Test(t, resource.TestCase{ + Providers: testAccProviders, + CheckDestroy: testAccDataLinkDestroy, + Steps: []resource.TestStep{ + { + Config: newDataLinkAppdConfigBadUrlErr, + ExpectError: regexp.MustCompile("URL must include a valid component and application ID"), + }, + }, + }) +} +func testAccCreateAppdDataLink(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccDataLinkDestroy, + Steps: []resource.TestStep{ + // Create + { + Config: newDataLinkAppdConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckDataLinkResourceExists, + resource.TestCheckResourceAttr("signalfx_data_link.big_test_data_link", "property_name", "pname"), + resource.TestCheckResourceAttr("signalfx_data_link.big_test_data_link", "property_value", "pvalue"), + ), + }, + }, + }) +} + func testDataLinkUpdated(s *terraform.State) error { for _, rs := range s.RootModule().Resources { switch rs.Type { From 7fa2958d47d6377ec1938a4da5a332905741470a Mon Sep 17 00:00:00 2001 From: Chris Josephs Date: Wed, 27 Nov 2024 14:34:18 -0800 Subject: [PATCH 03/13] bump signalfx-go version --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 2ec5c618..8ffb27cb 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/hashicorp/terraform-plugin-log v0.9.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.35.0 github.com/mitchellh/go-homedir v1.1.0 - github.com/signalfx/signalfx-go v1.43.0 + github.com/signalfx/signalfx-go v1.44.0 github.com/stretchr/testify v1.10.0 go.uber.org/multierr v1.11.0 ) diff --git a/go.sum b/go.sum index 8aabd097..85dfd1aa 100644 --- a/go.sum +++ b/go.sum @@ -138,6 +138,8 @@ github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/signalfx/signalfx-go v1.43.0 h1:Wp/XkyETzRyFvtuCGTN039hYwVgwIPfkBciqs19hqv4= github.com/signalfx/signalfx-go v1.43.0/go.mod h1:I30umyhRTu8mPpEtMzEbG0z9wOYjkUKTp9U0gFxFsmk= +github.com/signalfx/signalfx-go v1.44.0 h1:BkLtohTJkq3mr1Yl1OzCWK+e2DZRqZ0M0zD9Gs+c41Q= +github.com/signalfx/signalfx-go v1.44.0/go.mod h1:I30umyhRTu8mPpEtMzEbG0z9wOYjkUKTp9U0gFxFsmk= github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A= github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= From 32f4281a69509243f09df530b01ee1874560e24b Mon Sep 17 00:00:00 2001 From: Chris Josephs Date: Wed, 27 Nov 2024 14:34:37 -0800 Subject: [PATCH 04/13] set datalink type as APPD_LINK --- signalfx/resource_signalfx_data_link.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/signalfx/resource_signalfx_data_link.go b/signalfx/resource_signalfx_data_link.go index 67b38181..bf214d05 100644 --- a/signalfx/resource_signalfx_data_link.go +++ b/signalfx/resource_signalfx_data_link.go @@ -263,7 +263,7 @@ func getPayloadDataLink(d *schema.ResourceData) (*datalink.CreateUpdateDataLinkR URL: tfLink["url"].(string), // Need to add APPD_LINK type to signalfx-go library // Type: datalink.APPD_LINK, - Type: datalink.EXTERNAL_LINK, + Type: datalink.APPD_LINK, } dataLink.Targets = append(dataLink.Targets, dl) From bc657ad6f3a40ad4fc2c01af82e905e3423a619e Mon Sep 17 00:00:00 2001 From: Chris Josephs Date: Wed, 27 Nov 2024 16:41:07 -0800 Subject: [PATCH 05/13] chore: cleanup comments --- signalfx/resource_signalfx_data_link.go | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/signalfx/resource_signalfx_data_link.go b/signalfx/resource_signalfx_data_link.go index bf214d05..80544980 100644 --- a/signalfx/resource_signalfx_data_link.go +++ b/signalfx/resource_signalfx_data_link.go @@ -227,17 +227,12 @@ func getPayloadDataLink(d *schema.ResourceData) (*datalink.CreateUpdateDataLinkR } } - // New AppD datalink check - // REQ: url validation - // REQ: url follows appd pattern - // REQ: appd applicatin id and content id are of type integer if val, ok := d.GetOk("target_appd_url"); ok { appdURLs := val.(*schema.Set).List() for _, tfLink := range appdURLs { tfLink := tfLink.(map[string]interface{}) - // AppD URL validation appdUrl, err := url.ParseRequestURI(tfLink["url"].(string)) if err != nil { return dataLink, fmt.Errorf("Invalid URL") @@ -255,14 +250,12 @@ func getPayloadDataLink(d *schema.ResourceData) (*datalink.CreateUpdateDataLinkR _, componentIdErr := strconv.Atoi(componentId[0]) _, applicationIdErr := strconv.Atoi(applicationId[0]) if componentIdErr != nil || applicationIdErr != nil { - return dataLink, fmt.Errorf("URL must include a valid component and application ID") + return dataLink, fmt.Errorf("URL must include a valid component and application IDs") } dl := &datalink.Target{ Name: tfLink["name"].(string), URL: tfLink["url"].(string), - // Need to add APPD_LINK type to signalfx-go library - // Type: datalink.APPD_LINK, Type: datalink.APPD_LINK, } From 0921ec1478bdcc3d00d8b8accc8d457ad0a167dd Mon Sep 17 00:00:00 2001 From: Chris Josephs Date: Mon, 2 Dec 2024 14:43:56 -0800 Subject: [PATCH 06/13] adjust appd_link url parsing to match expected appd_link input --- signalfx/resource_signalfx_data_link.go | 35 +++++++++++++++++-------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/signalfx/resource_signalfx_data_link.go b/signalfx/resource_signalfx_data_link.go index 80544980..470f5117 100644 --- a/signalfx/resource_signalfx_data_link.go +++ b/signalfx/resource_signalfx_data_link.go @@ -233,7 +233,13 @@ func getPayloadDataLink(d *schema.ResourceData) (*datalink.CreateUpdateDataLinkR for _, tfLink := range appdURLs { tfLink := tfLink.(map[string]interface{}) - appdUrl, err := url.ParseRequestURI(tfLink["url"].(string)) + dl := &datalink.Target{ + Name: tfLink["name"].(string), + URL: tfLink["url"].(string), + Type: datalink.APPD_LINK, + } + + appdUrl, err := url.ParseRequestURI(dl.URL) if err != nil { return dataLink, fmt.Errorf("Invalid URL") } @@ -241,22 +247,17 @@ func getPayloadDataLink(d *schema.ResourceData) (*datalink.CreateUpdateDataLinkR return dataLink, fmt.Errorf("Invalid AppDynamics URL") } - queryParams := appdUrl.Query() + queryStr := strings.TrimPrefix(appdUrl.Path, "/controller/#/") + queryParams, err := url.ParseQuery(queryStr) componentId, applicationId := queryParams["component"], queryParams["application"] - if len(componentId) != 1 || len(applicationId) != 1 { - return dataLink, fmt.Errorf("URL must include a valid component and application ID") + if len(componentId) != 1 || len(applicationId) != 1 || err != nil { + return dataLink, fmt.Errorf("URL must include component and application IDs") } _, componentIdErr := strconv.Atoi(componentId[0]) _, applicationIdErr := strconv.Atoi(applicationId[0]) if componentIdErr != nil || applicationIdErr != nil { - return dataLink, fmt.Errorf("URL must include a valid component and application IDs") - } - - dl := &datalink.Target{ - Name: tfLink["name"].(string), - URL: tfLink["url"].(string), - Type: datalink.APPD_LINK, + return dataLink, fmt.Errorf("URL must include valid component and application IDs") } dataLink.Targets = append(dataLink.Targets, dl) @@ -347,6 +348,7 @@ func dataLinkAPIToTF(d *schema.ResourceData, dl *datalink.DataLink) error { var internalLinks []map[string]interface{} var externalLinks []map[string]interface{} var splunkLinks []map[string]interface{} + var appdLinks []map[string]interface{} for _, t := range dl.Targets { switch t.Type { @@ -373,6 +375,12 @@ func dataLinkAPIToTF(d *schema.ResourceData, dl *datalink.DataLink) error { "property_key_mapping": t.PropertyKeyMapping, } splunkLinks = append(splunkLinks, tfTarget) + case datalink.APPD_LINK: + tfTarget := map[string]interface{}{ + "name": t.Name, + "url": t.URL, + } + appdLinks = append(appdLinks, tfTarget) default: return fmt.Errorf("Unknown link type: %s", t.Type) } @@ -392,6 +400,11 @@ func dataLinkAPIToTF(d *schema.ResourceData, dl *datalink.DataLink) error { return err } } + if appdLinks != nil && len(appdLinks) > 0 { + if err := d.Set("target_appd_url", appdLinks); err != nil { + return err + } + } return nil } From 0eb937b308f3a80e21a4d81d8f9f11099d046fc7 Mon Sep 17 00:00:00 2001 From: Chris Josephs Date: Mon, 2 Dec 2024 15:03:59 -0800 Subject: [PATCH 07/13] fix typo --- signalfx/resource_signalfx_data_link_test.go | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/signalfx/resource_signalfx_data_link_test.go b/signalfx/resource_signalfx_data_link_test.go index d9a273a7..2131d480 100644 --- a/signalfx/resource_signalfx_data_link_test.go +++ b/signalfx/resource_signalfx_data_link_test.go @@ -164,26 +164,24 @@ func TestAccCreateUpdateDataLinkWithoutPropertyValue(t *testing.T) { }) } -// AppD DataLink acceptance tests -func testAccCreateAppdDataLinkFails(t *testing.T) { +func TestAccCreateAppdDataLinkFails(t *testing.T) { resource.Test(t, resource.TestCase{ Providers: testAccProviders, CheckDestroy: testAccDataLinkDestroy, Steps: []resource.TestStep{ { Config: newDataLinkAppdConfigBadUrlErr, - ExpectError: regexp.MustCompile("URL must include a valid component and application ID"), + ExpectError: regexp.MustCompile("URL must include component and application IDs"), }, }, }) } -func testAccCreateAppdDataLink(t *testing.T) { +func TestAccCreateAppdDataLink(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testAccDataLinkDestroy, Steps: []resource.TestStep{ - // Create { Config: newDataLinkAppdConfig, Check: resource.ComposeTestCheckFunc( From 928e7e9c43ff5b4d04a9127bea13dff4893a3335 Mon Sep 17 00:00:00 2001 From: Chris Josephs Date: Thu, 9 Jan 2025 12:46:08 -0800 Subject: [PATCH 08/13] Refactor url validation to use regex --- signalfx/resource_signalfx_data_link.go | 29 ++++++------------------- 1 file changed, 7 insertions(+), 22 deletions(-) diff --git a/signalfx/resource_signalfx_data_link.go b/signalfx/resource_signalfx_data_link.go index 470f5117..66efc684 100644 --- a/signalfx/resource_signalfx_data_link.go +++ b/signalfx/resource_signalfx_data_link.go @@ -8,8 +8,7 @@ import ( "encoding/json" "fmt" "log" - "net/url" - "strconv" + "regexp" "strings" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -230,6 +229,9 @@ func getPayloadDataLink(d *schema.ResourceData) (*datalink.CreateUpdateDataLinkR if val, ok := d.GetOk("target_appd_url"); ok { appdURLs := val.(*schema.Set).List() + appdUrlPatternRegex := "^https?:\\/\\/[a-zA-Z0-9-]+\\.saas\\.appdynamics\\.com\\/.*application=\\d+.*component=\\d+.*" + re := regexp.MustCompile(appdUrlPatternRegex) + for _, tfLink := range appdURLs { tfLink := tfLink.(map[string]interface{}) @@ -238,26 +240,9 @@ func getPayloadDataLink(d *schema.ResourceData) (*datalink.CreateUpdateDataLinkR URL: tfLink["url"].(string), Type: datalink.APPD_LINK, } - - appdUrl, err := url.ParseRequestURI(dl.URL) - if err != nil { - return dataLink, fmt.Errorf("Invalid URL") - } - if !strings.HasSuffix(appdUrl.Host, ".saas.appdynamics.com") || !strings.HasPrefix(appdUrl.Path, "/controller") { - return dataLink, fmt.Errorf("Invalid AppDynamics URL") - } - - queryStr := strings.TrimPrefix(appdUrl.Path, "/controller/#/") - queryParams, err := url.ParseQuery(queryStr) - componentId, applicationId := queryParams["component"], queryParams["application"] - if len(componentId) != 1 || len(applicationId) != 1 || err != nil { - return dataLink, fmt.Errorf("URL must include component and application IDs") - } - - _, componentIdErr := strconv.Atoi(componentId[0]) - _, applicationIdErr := strconv.Atoi(applicationId[0]) - if componentIdErr != nil || applicationIdErr != nil { - return dataLink, fmt.Errorf("URL must include valid component and application IDs") + match := re.MatchString(dl.URL) + if !match { + return dataLink, fmt.Errorf("Enter a valid AppD Link. The link needs to include the contoller URL, application ID, and Application component.") } dataLink.Targets = append(dataLink.Targets, dl) From c7d900fa8ad3f64deda67b4948ff02e1b2d4a905 Mon Sep 17 00:00:00 2001 From: Chris Josephs Date: Thu, 9 Jan 2025 12:58:34 -0800 Subject: [PATCH 09/13] Update expected message --- signalfx/resource_signalfx_data_link_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/signalfx/resource_signalfx_data_link_test.go b/signalfx/resource_signalfx_data_link_test.go index 2131d480..5858d39b 100644 --- a/signalfx/resource_signalfx_data_link_test.go +++ b/signalfx/resource_signalfx_data_link_test.go @@ -171,7 +171,7 @@ func TestAccCreateAppdDataLinkFails(t *testing.T) { Steps: []resource.TestStep{ { Config: newDataLinkAppdConfigBadUrlErr, - ExpectError: regexp.MustCompile("URL must include component and application IDs"), + ExpectError: regexp.MustCompile("Enter a valid AppD Link. The link needs to include the contoller URL, application ID, and Application component."), }, }, }) From 09452510c6bcb7cc7e447257e854d49898fe399a Mon Sep 17 00:00:00 2001 From: Chris Josephs Date: Sat, 11 Jan 2025 12:36:22 -0800 Subject: [PATCH 10/13] chore: update go.sum --- go.sum | 2 -- 1 file changed, 2 deletions(-) diff --git a/go.sum b/go.sum index 85dfd1aa..9a3b60d7 100644 --- a/go.sum +++ b/go.sum @@ -136,8 +136,6 @@ github.com/rogpeppe/go-internal v1.6.2 h1:aIihoIOHCiLZHxyoNQ+ABL4NKhFTgKLBdMLyEA github.com/rogpeppe/go-internal v1.6.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= -github.com/signalfx/signalfx-go v1.43.0 h1:Wp/XkyETzRyFvtuCGTN039hYwVgwIPfkBciqs19hqv4= -github.com/signalfx/signalfx-go v1.43.0/go.mod h1:I30umyhRTu8mPpEtMzEbG0z9wOYjkUKTp9U0gFxFsmk= github.com/signalfx/signalfx-go v1.44.0 h1:BkLtohTJkq3mr1Yl1OzCWK+e2DZRqZ0M0zD9Gs+c41Q= github.com/signalfx/signalfx-go v1.44.0/go.mod h1:I30umyhRTu8mPpEtMzEbG0z9wOYjkUKTp9U0gFxFsmk= github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A= From d4f8b44b238b509f27403290ab031e2732fe7c14 Mon Sep 17 00:00:00 2001 From: Chris Josephs Date: Sun, 12 Jan 2025 15:23:30 -0800 Subject: [PATCH 11/13] use regex Compile instead of MustCompile --- signalfx/resource_signalfx_data_link.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/signalfx/resource_signalfx_data_link.go b/signalfx/resource_signalfx_data_link.go index 66efc684..cc9e739e 100644 --- a/signalfx/resource_signalfx_data_link.go +++ b/signalfx/resource_signalfx_data_link.go @@ -229,8 +229,12 @@ func getPayloadDataLink(d *schema.ResourceData) (*datalink.CreateUpdateDataLinkR if val, ok := d.GetOk("target_appd_url"); ok { appdURLs := val.(*schema.Set).List() - appdUrlPatternRegex := "^https?:\\/\\/[a-zA-Z0-9-]+\\.saas\\.appdynamics\\.com\\/.*application=\\d+.*component=\\d+.*" - re := regexp.MustCompile(appdUrlPatternRegex) + appdURLPatternRegex := "^https?:\\/\\/[a-zA-Z0-9-]+\\.saas\\.appdynamics\\.com\\/.*application=\\d+.*component=\\d+.*" + re, err := regexp.Compile(appdURLPatternRegex) + + if err != nil { + return dataLink, err + } for _, tfLink := range appdURLs { tfLink := tfLink.(map[string]interface{}) From b9527854a679ad3c0edca4d3c001f932bd7d11a7 Mon Sep 17 00:00:00 2001 From: Chris Josephs Date: Sun, 12 Jan 2025 15:24:52 -0800 Subject: [PATCH 12/13] fix linter errors - capitalizations and unnecessary nil check --- signalfx/resource_signalfx_data_link.go | 4 ++-- signalfx/resource_signalfx_data_link_test.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/signalfx/resource_signalfx_data_link.go b/signalfx/resource_signalfx_data_link.go index cc9e739e..c87f0498 100644 --- a/signalfx/resource_signalfx_data_link.go +++ b/signalfx/resource_signalfx_data_link.go @@ -246,7 +246,7 @@ func getPayloadDataLink(d *schema.ResourceData) (*datalink.CreateUpdateDataLinkR } match := re.MatchString(dl.URL) if !match { - return dataLink, fmt.Errorf("Enter a valid AppD Link. The link needs to include the contoller URL, application ID, and Application component.") + return dataLink, fmt.Errorf("enter a valid AppD Link. The link needs to include the contoller URL, application ID, and Application component") } dataLink.Targets = append(dataLink.Targets, dl) @@ -389,7 +389,7 @@ func dataLinkAPIToTF(d *schema.ResourceData, dl *datalink.DataLink) error { return err } } - if appdLinks != nil && len(appdLinks) > 0 { + if len(appdLinks) > 0 { if err := d.Set("target_appd_url", appdLinks); err != nil { return err } diff --git a/signalfx/resource_signalfx_data_link_test.go b/signalfx/resource_signalfx_data_link_test.go index 5858d39b..0cf78858 100644 --- a/signalfx/resource_signalfx_data_link_test.go +++ b/signalfx/resource_signalfx_data_link_test.go @@ -84,7 +84,7 @@ const newDataLinkAppdConfig = ` } ` -const newDataLinkAppdConfigBadUrlErr = ` +const newDataLinkAppdConfigBadURLErr = ` resource "signalfx_data_link" "big_test_data_link" { property_name = "pname" property_value = "pvalue" From 81c7e5f71d81cd34125e9338b11752ee7d5b207a Mon Sep 17 00:00:00 2001 From: Chris Josephs Date: Tue, 14 Jan 2025 10:22:49 -0800 Subject: [PATCH 13/13] update data link docs --- website/docs/r/data_link.html.markdown | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/website/docs/r/data_link.html.markdown b/website/docs/r/data_link.html.markdown index 2374669a..3941eb00 100644 --- a/website/docs/r/data_link.html.markdown +++ b/website/docs/r/data_link.html.markdown @@ -41,6 +41,17 @@ resource "signalfx_data_link" "my_data_link_dash" { } } } + +# A link to an AppDynamics Service +resource "signalfx_data_link" "my_data_link_appd" { + property_name = "pname3" + property_value = "pvalue" + + target_appd_url { + name = "appd_url" + url = "https://www.example.saas.appdynamics.com/#/application=1234&component=5678" + } +} ``` ## Arguments @@ -64,6 +75,9 @@ The following arguments are supported in the resource block: * `target_splunk` - (Optional) Link to an external URL * `name` (Required) User-assigned target name. Use this value to differentiate between the link targets for a data link object. * `property_key_mapping` - Describes the relationship between Splunk Observability Cloud metadata keys and external system properties when the key names are different. +* `target_appd_url` - (Optional) Link to an AppDynamics URL + * `name` (Required) User-assigned target name. Use this value to differentiate between the link targets for a data link object. + * `url`- (Required) URL string for an AppDynamics instance. ## Attributes