From 4f3d64e8b7174bfb98da6c1d5004d203c3aea8ae Mon Sep 17 00:00:00 2001 From: Isabella Siu Date: Mon, 6 Mar 2023 16:00:59 -0500 Subject: [PATCH] CloudWatch: Make deeplinks work for us-gov and china regions (#64080) --- .../cloudwatch/models/cloudwatch_query.go | 22 +++++++++++++++++-- .../models/cloudwatch_query_test.go | 17 ++++++++++++++ .../datasource/cloudwatch/aws_url.test.ts | 18 +++++++++++++++ .../plugins/datasource/cloudwatch/aws_url.ts | 21 +++++++++++++++--- 4 files changed, 73 insertions(+), 5 deletions(-) create mode 100644 public/app/plugins/datasource/cloudwatch/aws_url.test.ts diff --git a/pkg/tsdb/cloudwatch/models/cloudwatch_query.go b/pkg/tsdb/cloudwatch/models/cloudwatch_query.go index 5ee725ec866..b100bd18772 100644 --- a/pkg/tsdb/cloudwatch/models/cloudwatch_query.go +++ b/pkg/tsdb/cloudwatch/models/cloudwatch_query.go @@ -12,6 +12,7 @@ import ( "strings" "time" + "github.com/aws/aws-sdk-go/aws/endpoints" "github.com/google/uuid" "github.com/grafana/grafana-plugin-sdk-go/backend" @@ -41,7 +42,12 @@ const ( GMDApiModeSQLExpression ) -const defaultRegion = "default" +const ( + defaultRegion = "default" + defaultConsoleURL = "console.aws.amazon.com" + usGovConsoleURL = "console.amazonaws-us-gov.com" + chinaConsoleURL = "console.amazonaws.cn" +) type CloudWatchQuery struct { logger log.Logger @@ -187,7 +193,7 @@ func (q *CloudWatchQuery) BuildDeepLink(startTime time.Time, endTime time.Time, return "", fmt.Errorf("could not marshal link: %w", err) } - url, err := url.Parse(fmt.Sprintf(`https://%s.console.aws.amazon.com/cloudwatch/deeplink.js`, q.Region)) + url, err := url.Parse(fmt.Sprintf(`https://%s/cloudwatch/deeplink.js`, getEndpoint(q.Region))) if err != nil { return "", fmt.Errorf("unable to parse CloudWatch console deep link") } @@ -485,3 +491,15 @@ func sortDimensions(dimensions map[string][]string) map[string][]string { } return sortedDimensions } + +func getEndpoint(region string) string { + partition, _ := endpoints.PartitionForRegion(endpoints.DefaultPartitions(), region) + url := defaultConsoleURL + if partition.ID() == endpoints.AwsUsGovPartitionID { + url = usGovConsoleURL + } + if partition.ID() == endpoints.AwsCnPartitionID { + url = chinaConsoleURL + } + return fmt.Sprintf("%s.%s", region, url) +} diff --git a/pkg/tsdb/cloudwatch/models/cloudwatch_query_test.go b/pkg/tsdb/cloudwatch/models/cloudwatch_query_test.go index f82db0b50ea..da1ee6f8081 100644 --- a/pkg/tsdb/cloudwatch/models/cloudwatch_query_test.go +++ b/pkg/tsdb/cloudwatch/models/cloudwatch_query_test.go @@ -1300,3 +1300,20 @@ func Test_ParseMetricDataQueries_ApplyMacros(t *testing.T) { assert.Equal(t, "SEARCH('{AWS/EC2,InstanceId}', 'Average', $__period_auto)", actual[0].Expression) }) } + +func TestGetEndpoint(t *testing.T) { + testcases := []struct { + region string + expectedEndpoint string + }{ + {"us-east-1", "us-east-1.console.aws.amazon.com"}, + {"us-gov-east-1", "us-gov-east-1.console.amazonaws-us-gov.com"}, + {"cn-northwest-1", "cn-northwest-1.console.amazonaws.cn"}, + } + for _, ts := range testcases { + t.Run(fmt.Sprintf("should create correct endpoint for %s", ts), func(t *testing.T) { + actual := getEndpoint(ts.region) + assert.Equal(t, ts.expectedEndpoint, actual) + }) + } +} diff --git a/public/app/plugins/datasource/cloudwatch/aws_url.test.ts b/public/app/plugins/datasource/cloudwatch/aws_url.test.ts new file mode 100644 index 00000000000..c1d13a5458c --- /dev/null +++ b/public/app/plugins/datasource/cloudwatch/aws_url.test.ts @@ -0,0 +1,18 @@ +import { getLogsEndpoint } from './aws_url'; + +describe('getEndpoint', () => { + it('should return the default url for normal regions', () => { + const result = getLogsEndpoint('us-east-1'); + expect(result).toBe('us-east-1.console.aws.amazon.com'); + }); + + it('should return the us-gov url for us-gov regions', () => { + const result = getLogsEndpoint('us-gov-east-1'); + expect(result).toBe('us-gov-east-1.console.amazonaws-us-gov.com'); + }); + + it('should return the china url for cn regions', () => { + const result = getLogsEndpoint('cn-northwest-1'); + expect(result).toBe('cn-northwest-1.console.amazonaws.cn'); + }); +}); diff --git a/public/app/plugins/datasource/cloudwatch/aws_url.ts b/public/app/plugins/datasource/cloudwatch/aws_url.ts index 3982b3af421..53e55314ebd 100644 --- a/public/app/plugins/datasource/cloudwatch/aws_url.ts +++ b/public/app/plugins/datasource/cloudwatch/aws_url.ts @@ -11,8 +11,23 @@ export interface AwsUrl { source: string[]; } +const defaultURL = 'console.aws.amazon.com'; +const usGovURL = 'console.amazonaws-us-gov.com'; +const chinaURL = 'console.amazonaws.cn'; + +export function getLogsEndpoint(region: string): string { + let url = defaultURL; + if (region.startsWith('us-gov-')) { + url = usGovURL; + } + if (region.startsWith('cn-')) { + url = chinaURL; + } + return `${region}.${url}`; +} + export function encodeUrl(obj: AwsUrl, region: string): string { - return `https://${region}.console.aws.amazon.com/cloudwatch/home?region=${region}#logs-insights:queryDetail=${JSURL.stringify( - obj - )}`; + return `https://${getLogsEndpoint( + region + )}/cloudwatch/home?region=${region}#logs-insights:queryDetail=${JSURL.stringify(obj)}`; }