From 3ef06a0c8872945ee867e90cc0b2b9c88a83f1ef Mon Sep 17 00:00:00 2001 From: Dhananjay <45629183+gdhananjay@users.noreply.github.com> Date: Thu, 2 Jul 2020 18:54:36 +0530 Subject: [PATCH] Cloudwatch: Add Support for external ID in assume role (#23685) Co-authored by: Arve Knudsen --- .../features/datasources/cloudwatch.md | 1 + go.mod | 1 + go.sum | 7 + pkg/tsdb/cloudwatch/cloudwatch.go | 1 + pkg/tsdb/cloudwatch/credentials.go | 45 +- pkg/tsdb/cloudwatch/credentials_test.go | 121 ++++- pkg/tsdb/cloudwatch/metric_find_query.go | 2 +- pkg/tsdb/cloudwatch/mock_stsiface/stsapi.go | 436 ++++++++++++++++++ .../components/ConfigEditor.test.tsx | 1 + .../cloudwatch/components/ConfigEditor.tsx | 17 + .../plugins/datasource/cloudwatch/types.ts | 1 + 11 files changed, 602 insertions(+), 31 deletions(-) create mode 100644 pkg/tsdb/cloudwatch/mock_stsiface/stsapi.go diff --git a/docs/sources/features/datasources/cloudwatch.md b/docs/sources/features/datasources/cloudwatch.md index d3a7286ae58..a8623b17027 100755 --- a/docs/sources/features/datasources/cloudwatch.md +++ b/docs/sources/features/datasources/cloudwatch.md @@ -34,6 +34,7 @@ build dashboards or use Explore with CloudWatch metrics and CloudWatch Logs. | _Auth Provider_ | Specify the provider to get credentials. | | _Credentials_ profile name | Specify the name of the profile to use (if you use `~/.aws/credentials` file), leave blank for default. | | _Assume Role Arn_ | Specify the ARN of the role to assume | +| _External ID_ | If you are assuming a role in another account, that has been created with an external ID, specify the exterrnal ID here. | ## Authentication diff --git a/go.mod b/go.mod index fe0585e63da..9898e7e8a75 100644 --- a/go.mod +++ b/go.mod @@ -25,6 +25,7 @@ require ( github.com/go-sql-driver/mysql v1.5.0 github.com/go-stack/stack v1.8.0 github.com/gobwas/glob v0.2.3 + github.com/golang/mock v1.4.3 github.com/golang/protobuf v1.4.0 github.com/google/go-cmp v0.4.0 github.com/gorilla/websocket v1.4.1 diff --git a/go.sum b/go.sum index 7da750ff1a7..69a9229faa8 100644 --- a/go.sum +++ b/go.sum @@ -108,7 +108,10 @@ github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.4.3 h1:GV+pQPG/EUUbkh47niozDcADz6go/dUwhVzdUQHIVRw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -437,6 +440,7 @@ golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= @@ -450,6 +454,7 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190802220118-1d1727260058/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= @@ -526,6 +531,8 @@ honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= xorm.io/builder v0.3.6 h1:ha28mQ2M+TFx96Hxo+iq6tQgnkC9IZkM6D8w9sKHHF8= xorm.io/builder v0.3.6/go.mod h1:LEFAPISnRzG+zxaxj2vPicRwz67BdhFreKg8yv8/TgU= xorm.io/core v0.7.2/go.mod h1:jJfd0UAEzZ4t87nbQYtVjmqpIODugN6PD2D9E+dJvdM= diff --git a/pkg/tsdb/cloudwatch/cloudwatch.go b/pkg/tsdb/cloudwatch/cloudwatch.go index ff858076e30..92df32b3c08 100644 --- a/pkg/tsdb/cloudwatch/cloudwatch.go +++ b/pkg/tsdb/cloudwatch/cloudwatch.go @@ -32,6 +32,7 @@ type DatasourceInfo struct { Region string AuthType string AssumeRoleArn string + ExternalID string Namespace string AccessKey string diff --git a/pkg/tsdb/cloudwatch/credentials.go b/pkg/tsdb/cloudwatch/credentials.go index 3a1a901f40c..d66fa4e9e7f 100644 --- a/pkg/tsdb/cloudwatch/credentials.go +++ b/pkg/tsdb/cloudwatch/credentials.go @@ -7,6 +7,7 @@ import ( "time" "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/client" "github.com/aws/aws-sdk-go/aws/credentials" "github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds" "github.com/aws/aws-sdk-go/aws/credentials/endpointcreds" @@ -18,6 +19,7 @@ import ( "github.com/aws/aws-sdk-go/service/cloudwatch" "github.com/aws/aws-sdk-go/service/cloudwatchlogs" "github.com/aws/aws-sdk-go/service/sts" + "github.com/aws/aws-sdk-go/service/sts/stsiface" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/setting" ) @@ -30,7 +32,25 @@ type cache struct { var awsCredentialCache = make(map[string]cache) var credentialCacheLock sync.RWMutex -func GetCredentials(dsInfo *DatasourceInfo) (*credentials.Credentials, error) { +// Session factory. +// Stubbable by tests. +var newSession = func(cfgs ...*aws.Config) (*session.Session, error) { + return session.NewSession(cfgs...) +} + +// STS service factory. +// Stubbable by tests. +var newSTSService = func(p client.ConfigProvider, cfgs ...*aws.Config) stsiface.STSAPI { + return sts.New(p, cfgs...) +} + +// EC2Metadata service factory. +// Stubbable by tests. +var newEC2Metadata = func(p client.ConfigProvider, cfgs ...*aws.Config) *ec2metadata.EC2Metadata { + return ec2metadata.New(p, cfgs...) +} + +func getCredentials(dsInfo *DatasourceInfo) (*credentials.Credentials, error) { cacheKey := fmt.Sprintf("%s:%s:%s:%s", dsInfo.AuthType, dsInfo.AccessKey, dsInfo.Profile, dsInfo.AssumeRoleArn) credentialCacheLock.RLock() if _, ok := awsCredentialCache[cacheKey]; ok { @@ -53,8 +73,11 @@ func GetCredentials(dsInfo *DatasourceInfo) (*credentials.Credentials, error) { RoleSessionName: aws.String("GrafanaSession"), DurationSeconds: aws.Int64(900), } + if dsInfo.ExternalID != "" { + params.ExternalId = aws.String(dsInfo.ExternalID) + } - stsSess, err := session.NewSession() + stsSess, err := newSession() if err != nil { return nil, err } @@ -70,11 +93,11 @@ func GetCredentials(dsInfo *DatasourceInfo) (*credentials.Credentials, error) { Credentials: stsCreds, } - sess, err := session.NewSession(stsConfig) + sess, err := newSession(stsConfig) if err != nil { return nil, err } - svc := sts.New(sess, stsConfig) + svc := newSTSService(sess, stsConfig) resp, err := svc.AssumeRole(params) if err != nil { return nil, err @@ -91,7 +114,7 @@ func GetCredentials(dsInfo *DatasourceInfo) (*credentials.Credentials, error) { expiration = &e } - sess, err := session.NewSession() + sess, err := newSession() if err != nil { return nil, err } @@ -123,7 +146,7 @@ func GetCredentials(dsInfo *DatasourceInfo) (*credentials.Credentials, error) { } func webIdentityProvider(sess *session.Session) credentials.Provider { - svc := sts.New(sess) + svc := newSTSService(sess) roleARN := os.Getenv("AWS_ROLE_ARN") tokenFilepath := os.Getenv("AWS_WEB_IDENTITY_TOKEN_FILE") @@ -152,7 +175,7 @@ func ecsCredProvider(sess *session.Session, uri string) credentials.Provider { } func ec2RoleProvider(sess *session.Session) credentials.Provider { - return &ec2rolecreds.EC2RoleProvider{Client: ec2metadata.New(sess), ExpiryWindow: 5 * time.Minute} + return &ec2rolecreds.EC2RoleProvider{Client: newEC2Metadata(sess), ExpiryWindow: 5 * time.Minute} } func (e *CloudWatchExecutor) getDsInfo(region string) *DatasourceInfo { @@ -167,6 +190,7 @@ func retrieveDsInfo(datasource *models.DataSource, region string) *DatasourceInf authType := datasource.JsonData.Get("authType").MustString() assumeRoleArn := datasource.JsonData.Get("assumeRoleArn").MustString() + externalID := datasource.JsonData.Get("externalId").MustString() decrypted := datasource.DecryptedValues() accessKey := decrypted["accessKey"] secretKey := decrypted["secretKey"] @@ -176,6 +200,7 @@ func retrieveDsInfo(datasource *models.DataSource, region string) *DatasourceInf Profile: datasource.Database, AuthType: authType, AssumeRoleArn: assumeRoleArn, + ExternalID: externalID, AccessKey: accessKey, SecretKey: secretKey, } @@ -184,7 +209,7 @@ func retrieveDsInfo(datasource *models.DataSource, region string) *DatasourceInf } func getAwsConfig(dsInfo *DatasourceInfo) (*aws.Config, error) { - creds, err := GetCredentials(dsInfo) + creds, err := getCredentials(dsInfo) if err != nil { return nil, err } @@ -204,7 +229,7 @@ func (e *CloudWatchExecutor) getClient(region string) (*cloudwatch.CloudWatch, e return nil, err } - sess, err := session.NewSession(cfg) + sess, err := newSession(cfg) if err != nil { return nil, err } @@ -224,7 +249,7 @@ func retrieveLogsClient(datasourceInfo *DatasourceInfo) (*cloudwatchlogs.CloudWa return nil, err } - sess, err := session.NewSession(cfg) + sess, err := newSession(cfg) if err != nil { return nil, err } diff --git a/pkg/tsdb/cloudwatch/credentials_test.go b/pkg/tsdb/cloudwatch/credentials_test.go index a0b51ec4669..e3d5f200ba7 100644 --- a/pkg/tsdb/cloudwatch/credentials_test.go +++ b/pkg/tsdb/cloudwatch/credentials_test.go @@ -4,39 +4,120 @@ import ( "os" "testing" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/client" "github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds" "github.com/aws/aws-sdk-go/aws/credentials/endpointcreds" + "github.com/aws/aws-sdk-go/aws/ec2metadata" "github.com/aws/aws-sdk-go/aws/session" - . "github.com/smartystreets/goconvey/convey" + "github.com/aws/aws-sdk-go/service/sts" + "github.com/aws/aws-sdk-go/service/sts/stsiface" + "github.com/golang/mock/gomock" + "github.com/grafana/grafana/pkg/tsdb/cloudwatch/mock_stsiface" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestECSCredProvider(t *testing.T) { - Convey("Running in an ECS container task", t, func() { - defer os.Clearenv() - os.Setenv("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI", "/abc/123") - - sess, _ := session.NewSession() - provider := remoteCredProvider(sess) + os.Setenv("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI", "/abc/123") + t.Cleanup(func() { + os.Unsetenv("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI") + }) - So(provider, ShouldNotBeNil) + sess, err := session.NewSession() + require.NoError(t, err) + provider := remoteCredProvider(sess) + require.NotNil(t, provider) - ecsProvider, ok := provider.(*endpointcreds.Provider) - So(ecsProvider, ShouldNotBeNil) - So(ok, ShouldBeTrue) + ecsProvider, ok := provider.(*endpointcreds.Provider) + require.NotNil(t, ecsProvider) + require.True(t, ok) - So(ecsProvider.Client.Endpoint, ShouldEqual, "http://169.254.170.2/abc/123") - }) + assert.Equal(t, "http://169.254.170.2/abc/123", ecsProvider.Client.Endpoint) } func TestDefaultEC2RoleProvider(t *testing.T) { - Convey("Running outside an ECS container task", t, func() { - sess, _ := session.NewSession() - provider := remoteCredProvider(sess) + sess, err := session.NewSession() + require.NoError(t, err) + provider := remoteCredProvider(sess) + require.NotNil(t, provider) + + ec2Provider, ok := provider.(*ec2rolecreds.EC2RoleProvider) + require.NotNil(t, ec2Provider) + require.True(t, ok) +} + +func TestGetCredentials_ARNAuthType(t *testing.T) { + ctrl := gomock.NewController(t) + var stsMock *mock_stsiface.MockSTSAPI + + origNewSession := newSession + origNewSTSService := newSTSService + origNewEC2Metadata := newEC2Metadata + t.Cleanup(func() { + newSession = origNewSession + newSTSService = origNewSTSService + newEC2Metadata = origNewEC2Metadata + }) + newSession = func(cfgs ...*aws.Config) (*session.Session, error) { + return &session.Session{}, nil + } + newSTSService = func(p client.ConfigProvider, cfgs ...*aws.Config) stsiface.STSAPI { + return stsMock + } + newEC2Metadata = func(p client.ConfigProvider, cfgs ...*aws.Config) *ec2metadata.EC2Metadata { + return nil + } + + t.Run("Without external ID", func(t *testing.T) { + stsMock = mock_stsiface.NewMockSTSAPI(ctrl) + stsMock. + EXPECT(). + AssumeRole(gomock.Eq(&sts.AssumeRoleInput{ + RoleArn: aws.String(""), + DurationSeconds: aws.Int64(900), + RoleSessionName: aws.String("GrafanaSession"), + })). + Return(&sts.AssumeRoleOutput{ + Credentials: &sts.Credentials{ + AccessKeyId: aws.String("id"), + SecretAccessKey: aws.String("secret"), + SessionToken: aws.String("token"), + }, + }, nil). + Times(1) + + creds, err := getCredentials(&DatasourceInfo{ + AuthType: "arn", + }) + require.NoError(t, err) + require.NotNil(t, creds) + }) - So(provider, ShouldNotBeNil) + t.Run("With external ID", func(t *testing.T) { + stsMock = mock_stsiface.NewMockSTSAPI(ctrl) + stsMock. + EXPECT(). + AssumeRole(gomock.Eq(&sts.AssumeRoleInput{ + RoleArn: aws.String(""), + DurationSeconds: aws.Int64(900), + RoleSessionName: aws.String("GrafanaSession"), + ExternalId: aws.String("external-id"), + })). + Return(&sts.AssumeRoleOutput{ + Credentials: &sts.Credentials{ + AccessKeyId: aws.String("id"), + SecretAccessKey: aws.String("secret"), + SessionToken: aws.String("token"), + }, + }, nil). + Times(1) - ec2Provider, ok := provider.(*ec2rolecreds.EC2RoleProvider) - So(ec2Provider, ShouldNotBeNil) - So(ok, ShouldBeTrue) + creds, err := getCredentials(&DatasourceInfo{ + AuthType: "arn", + ExternalID: "external-id", + }) + require.NoError(t, err) + require.NotNil(t, creds) }) } diff --git a/pkg/tsdb/cloudwatch/metric_find_query.go b/pkg/tsdb/cloudwatch/metric_find_query.go index 22e157f26f3..825d2ae12e8 100644 --- a/pkg/tsdb/cloudwatch/metric_find_query.go +++ b/pkg/tsdb/cloudwatch/metric_find_query.go @@ -740,7 +740,7 @@ func (e *CloudWatchExecutor) resourceGroupsGetResources(region string, filters [ } func getAllMetrics(cwData *DatasourceInfo) (cloudwatch.ListMetricsOutput, error) { - creds, err := GetCredentials(cwData) + creds, err := getCredentials(cwData) if err != nil { return cloudwatch.ListMetricsOutput{}, err } diff --git a/pkg/tsdb/cloudwatch/mock_stsiface/stsapi.go b/pkg/tsdb/cloudwatch/mock_stsiface/stsapi.go new file mode 100644 index 00000000000..f7937852a91 --- /dev/null +++ b/pkg/tsdb/cloudwatch/mock_stsiface/stsapi.go @@ -0,0 +1,436 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/aws/aws-sdk-go/service/sts/stsiface (interfaces: STSAPI) + +// Package mock_stsiface is a generated GoMock package. +package mock_stsiface + +import ( + context "context" + request "github.com/aws/aws-sdk-go/aws/request" + sts "github.com/aws/aws-sdk-go/service/sts" + gomock "github.com/golang/mock/gomock" + reflect "reflect" +) + +// MockSTSAPI is a mock of STSAPI interface +type MockSTSAPI struct { + ctrl *gomock.Controller + recorder *MockSTSAPIMockRecorder +} + +// MockSTSAPIMockRecorder is the mock recorder for MockSTSAPI +type MockSTSAPIMockRecorder struct { + mock *MockSTSAPI +} + +// NewMockSTSAPI creates a new mock instance +func NewMockSTSAPI(ctrl *gomock.Controller) *MockSTSAPI { + mock := &MockSTSAPI{ctrl: ctrl} + mock.recorder = &MockSTSAPIMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockSTSAPI) EXPECT() *MockSTSAPIMockRecorder { + return m.recorder +} + +// AssumeRole mocks base method +func (m *MockSTSAPI) AssumeRole(arg0 *sts.AssumeRoleInput) (*sts.AssumeRoleOutput, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AssumeRole", arg0) + ret0, _ := ret[0].(*sts.AssumeRoleOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// AssumeRole indicates an expected call of AssumeRole +func (mr *MockSTSAPIMockRecorder) AssumeRole(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssumeRole", reflect.TypeOf((*MockSTSAPI)(nil).AssumeRole), arg0) +} + +// AssumeRoleRequest mocks base method +func (m *MockSTSAPI) AssumeRoleRequest(arg0 *sts.AssumeRoleInput) (*request.Request, *sts.AssumeRoleOutput) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AssumeRoleRequest", arg0) + ret0, _ := ret[0].(*request.Request) + ret1, _ := ret[1].(*sts.AssumeRoleOutput) + return ret0, ret1 +} + +// AssumeRoleRequest indicates an expected call of AssumeRoleRequest +func (mr *MockSTSAPIMockRecorder) AssumeRoleRequest(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssumeRoleRequest", reflect.TypeOf((*MockSTSAPI)(nil).AssumeRoleRequest), arg0) +} + +// AssumeRoleWithContext mocks base method +func (m *MockSTSAPI) AssumeRoleWithContext(arg0 context.Context, arg1 *sts.AssumeRoleInput, arg2 ...request.Option) (*sts.AssumeRoleOutput, error) { + m.ctrl.T.Helper() + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "AssumeRoleWithContext", varargs...) + ret0, _ := ret[0].(*sts.AssumeRoleOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// AssumeRoleWithContext indicates an expected call of AssumeRoleWithContext +func (mr *MockSTSAPIMockRecorder) AssumeRoleWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssumeRoleWithContext", reflect.TypeOf((*MockSTSAPI)(nil).AssumeRoleWithContext), varargs...) +} + +// AssumeRoleWithSAML mocks base method +func (m *MockSTSAPI) AssumeRoleWithSAML(arg0 *sts.AssumeRoleWithSAMLInput) (*sts.AssumeRoleWithSAMLOutput, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AssumeRoleWithSAML", arg0) + ret0, _ := ret[0].(*sts.AssumeRoleWithSAMLOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// AssumeRoleWithSAML indicates an expected call of AssumeRoleWithSAML +func (mr *MockSTSAPIMockRecorder) AssumeRoleWithSAML(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssumeRoleWithSAML", reflect.TypeOf((*MockSTSAPI)(nil).AssumeRoleWithSAML), arg0) +} + +// AssumeRoleWithSAMLRequest mocks base method +func (m *MockSTSAPI) AssumeRoleWithSAMLRequest(arg0 *sts.AssumeRoleWithSAMLInput) (*request.Request, *sts.AssumeRoleWithSAMLOutput) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AssumeRoleWithSAMLRequest", arg0) + ret0, _ := ret[0].(*request.Request) + ret1, _ := ret[1].(*sts.AssumeRoleWithSAMLOutput) + return ret0, ret1 +} + +// AssumeRoleWithSAMLRequest indicates an expected call of AssumeRoleWithSAMLRequest +func (mr *MockSTSAPIMockRecorder) AssumeRoleWithSAMLRequest(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssumeRoleWithSAMLRequest", reflect.TypeOf((*MockSTSAPI)(nil).AssumeRoleWithSAMLRequest), arg0) +} + +// AssumeRoleWithSAMLWithContext mocks base method +func (m *MockSTSAPI) AssumeRoleWithSAMLWithContext(arg0 context.Context, arg1 *sts.AssumeRoleWithSAMLInput, arg2 ...request.Option) (*sts.AssumeRoleWithSAMLOutput, error) { + m.ctrl.T.Helper() + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "AssumeRoleWithSAMLWithContext", varargs...) + ret0, _ := ret[0].(*sts.AssumeRoleWithSAMLOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// AssumeRoleWithSAMLWithContext indicates an expected call of AssumeRoleWithSAMLWithContext +func (mr *MockSTSAPIMockRecorder) AssumeRoleWithSAMLWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssumeRoleWithSAMLWithContext", reflect.TypeOf((*MockSTSAPI)(nil).AssumeRoleWithSAMLWithContext), varargs...) +} + +// AssumeRoleWithWebIdentity mocks base method +func (m *MockSTSAPI) AssumeRoleWithWebIdentity(arg0 *sts.AssumeRoleWithWebIdentityInput) (*sts.AssumeRoleWithWebIdentityOutput, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AssumeRoleWithWebIdentity", arg0) + ret0, _ := ret[0].(*sts.AssumeRoleWithWebIdentityOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// AssumeRoleWithWebIdentity indicates an expected call of AssumeRoleWithWebIdentity +func (mr *MockSTSAPIMockRecorder) AssumeRoleWithWebIdentity(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssumeRoleWithWebIdentity", reflect.TypeOf((*MockSTSAPI)(nil).AssumeRoleWithWebIdentity), arg0) +} + +// AssumeRoleWithWebIdentityRequest mocks base method +func (m *MockSTSAPI) AssumeRoleWithWebIdentityRequest(arg0 *sts.AssumeRoleWithWebIdentityInput) (*request.Request, *sts.AssumeRoleWithWebIdentityOutput) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AssumeRoleWithWebIdentityRequest", arg0) + ret0, _ := ret[0].(*request.Request) + ret1, _ := ret[1].(*sts.AssumeRoleWithWebIdentityOutput) + return ret0, ret1 +} + +// AssumeRoleWithWebIdentityRequest indicates an expected call of AssumeRoleWithWebIdentityRequest +func (mr *MockSTSAPIMockRecorder) AssumeRoleWithWebIdentityRequest(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssumeRoleWithWebIdentityRequest", reflect.TypeOf((*MockSTSAPI)(nil).AssumeRoleWithWebIdentityRequest), arg0) +} + +// AssumeRoleWithWebIdentityWithContext mocks base method +func (m *MockSTSAPI) AssumeRoleWithWebIdentityWithContext(arg0 context.Context, arg1 *sts.AssumeRoleWithWebIdentityInput, arg2 ...request.Option) (*sts.AssumeRoleWithWebIdentityOutput, error) { + m.ctrl.T.Helper() + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "AssumeRoleWithWebIdentityWithContext", varargs...) + ret0, _ := ret[0].(*sts.AssumeRoleWithWebIdentityOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// AssumeRoleWithWebIdentityWithContext indicates an expected call of AssumeRoleWithWebIdentityWithContext +func (mr *MockSTSAPIMockRecorder) AssumeRoleWithWebIdentityWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssumeRoleWithWebIdentityWithContext", reflect.TypeOf((*MockSTSAPI)(nil).AssumeRoleWithWebIdentityWithContext), varargs...) +} + +// DecodeAuthorizationMessage mocks base method +func (m *MockSTSAPI) DecodeAuthorizationMessage(arg0 *sts.DecodeAuthorizationMessageInput) (*sts.DecodeAuthorizationMessageOutput, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DecodeAuthorizationMessage", arg0) + ret0, _ := ret[0].(*sts.DecodeAuthorizationMessageOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DecodeAuthorizationMessage indicates an expected call of DecodeAuthorizationMessage +func (mr *MockSTSAPIMockRecorder) DecodeAuthorizationMessage(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DecodeAuthorizationMessage", reflect.TypeOf((*MockSTSAPI)(nil).DecodeAuthorizationMessage), arg0) +} + +// DecodeAuthorizationMessageRequest mocks base method +func (m *MockSTSAPI) DecodeAuthorizationMessageRequest(arg0 *sts.DecodeAuthorizationMessageInput) (*request.Request, *sts.DecodeAuthorizationMessageOutput) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DecodeAuthorizationMessageRequest", arg0) + ret0, _ := ret[0].(*request.Request) + ret1, _ := ret[1].(*sts.DecodeAuthorizationMessageOutput) + return ret0, ret1 +} + +// DecodeAuthorizationMessageRequest indicates an expected call of DecodeAuthorizationMessageRequest +func (mr *MockSTSAPIMockRecorder) DecodeAuthorizationMessageRequest(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DecodeAuthorizationMessageRequest", reflect.TypeOf((*MockSTSAPI)(nil).DecodeAuthorizationMessageRequest), arg0) +} + +// DecodeAuthorizationMessageWithContext mocks base method +func (m *MockSTSAPI) DecodeAuthorizationMessageWithContext(arg0 context.Context, arg1 *sts.DecodeAuthorizationMessageInput, arg2 ...request.Option) (*sts.DecodeAuthorizationMessageOutput, error) { + m.ctrl.T.Helper() + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DecodeAuthorizationMessageWithContext", varargs...) + ret0, _ := ret[0].(*sts.DecodeAuthorizationMessageOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DecodeAuthorizationMessageWithContext indicates an expected call of DecodeAuthorizationMessageWithContext +func (mr *MockSTSAPIMockRecorder) DecodeAuthorizationMessageWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DecodeAuthorizationMessageWithContext", reflect.TypeOf((*MockSTSAPI)(nil).DecodeAuthorizationMessageWithContext), varargs...) +} + +// GetAccessKeyInfo mocks base method +func (m *MockSTSAPI) GetAccessKeyInfo(arg0 *sts.GetAccessKeyInfoInput) (*sts.GetAccessKeyInfoOutput, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAccessKeyInfo", arg0) + ret0, _ := ret[0].(*sts.GetAccessKeyInfoOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetAccessKeyInfo indicates an expected call of GetAccessKeyInfo +func (mr *MockSTSAPIMockRecorder) GetAccessKeyInfo(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAccessKeyInfo", reflect.TypeOf((*MockSTSAPI)(nil).GetAccessKeyInfo), arg0) +} + +// GetAccessKeyInfoRequest mocks base method +func (m *MockSTSAPI) GetAccessKeyInfoRequest(arg0 *sts.GetAccessKeyInfoInput) (*request.Request, *sts.GetAccessKeyInfoOutput) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAccessKeyInfoRequest", arg0) + ret0, _ := ret[0].(*request.Request) + ret1, _ := ret[1].(*sts.GetAccessKeyInfoOutput) + return ret0, ret1 +} + +// GetAccessKeyInfoRequest indicates an expected call of GetAccessKeyInfoRequest +func (mr *MockSTSAPIMockRecorder) GetAccessKeyInfoRequest(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAccessKeyInfoRequest", reflect.TypeOf((*MockSTSAPI)(nil).GetAccessKeyInfoRequest), arg0) +} + +// GetAccessKeyInfoWithContext mocks base method +func (m *MockSTSAPI) GetAccessKeyInfoWithContext(arg0 context.Context, arg1 *sts.GetAccessKeyInfoInput, arg2 ...request.Option) (*sts.GetAccessKeyInfoOutput, error) { + m.ctrl.T.Helper() + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetAccessKeyInfoWithContext", varargs...) + ret0, _ := ret[0].(*sts.GetAccessKeyInfoOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetAccessKeyInfoWithContext indicates an expected call of GetAccessKeyInfoWithContext +func (mr *MockSTSAPIMockRecorder) GetAccessKeyInfoWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAccessKeyInfoWithContext", reflect.TypeOf((*MockSTSAPI)(nil).GetAccessKeyInfoWithContext), varargs...) +} + +// GetCallerIdentity mocks base method +func (m *MockSTSAPI) GetCallerIdentity(arg0 *sts.GetCallerIdentityInput) (*sts.GetCallerIdentityOutput, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetCallerIdentity", arg0) + ret0, _ := ret[0].(*sts.GetCallerIdentityOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetCallerIdentity indicates an expected call of GetCallerIdentity +func (mr *MockSTSAPIMockRecorder) GetCallerIdentity(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCallerIdentity", reflect.TypeOf((*MockSTSAPI)(nil).GetCallerIdentity), arg0) +} + +// GetCallerIdentityRequest mocks base method +func (m *MockSTSAPI) GetCallerIdentityRequest(arg0 *sts.GetCallerIdentityInput) (*request.Request, *sts.GetCallerIdentityOutput) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetCallerIdentityRequest", arg0) + ret0, _ := ret[0].(*request.Request) + ret1, _ := ret[1].(*sts.GetCallerIdentityOutput) + return ret0, ret1 +} + +// GetCallerIdentityRequest indicates an expected call of GetCallerIdentityRequest +func (mr *MockSTSAPIMockRecorder) GetCallerIdentityRequest(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCallerIdentityRequest", reflect.TypeOf((*MockSTSAPI)(nil).GetCallerIdentityRequest), arg0) +} + +// GetCallerIdentityWithContext mocks base method +func (m *MockSTSAPI) GetCallerIdentityWithContext(arg0 context.Context, arg1 *sts.GetCallerIdentityInput, arg2 ...request.Option) (*sts.GetCallerIdentityOutput, error) { + m.ctrl.T.Helper() + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetCallerIdentityWithContext", varargs...) + ret0, _ := ret[0].(*sts.GetCallerIdentityOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetCallerIdentityWithContext indicates an expected call of GetCallerIdentityWithContext +func (mr *MockSTSAPIMockRecorder) GetCallerIdentityWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCallerIdentityWithContext", reflect.TypeOf((*MockSTSAPI)(nil).GetCallerIdentityWithContext), varargs...) +} + +// GetFederationToken mocks base method +func (m *MockSTSAPI) GetFederationToken(arg0 *sts.GetFederationTokenInput) (*sts.GetFederationTokenOutput, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetFederationToken", arg0) + ret0, _ := ret[0].(*sts.GetFederationTokenOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetFederationToken indicates an expected call of GetFederationToken +func (mr *MockSTSAPIMockRecorder) GetFederationToken(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFederationToken", reflect.TypeOf((*MockSTSAPI)(nil).GetFederationToken), arg0) +} + +// GetFederationTokenRequest mocks base method +func (m *MockSTSAPI) GetFederationTokenRequest(arg0 *sts.GetFederationTokenInput) (*request.Request, *sts.GetFederationTokenOutput) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetFederationTokenRequest", arg0) + ret0, _ := ret[0].(*request.Request) + ret1, _ := ret[1].(*sts.GetFederationTokenOutput) + return ret0, ret1 +} + +// GetFederationTokenRequest indicates an expected call of GetFederationTokenRequest +func (mr *MockSTSAPIMockRecorder) GetFederationTokenRequest(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFederationTokenRequest", reflect.TypeOf((*MockSTSAPI)(nil).GetFederationTokenRequest), arg0) +} + +// GetFederationTokenWithContext mocks base method +func (m *MockSTSAPI) GetFederationTokenWithContext(arg0 context.Context, arg1 *sts.GetFederationTokenInput, arg2 ...request.Option) (*sts.GetFederationTokenOutput, error) { + m.ctrl.T.Helper() + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetFederationTokenWithContext", varargs...) + ret0, _ := ret[0].(*sts.GetFederationTokenOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetFederationTokenWithContext indicates an expected call of GetFederationTokenWithContext +func (mr *MockSTSAPIMockRecorder) GetFederationTokenWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFederationTokenWithContext", reflect.TypeOf((*MockSTSAPI)(nil).GetFederationTokenWithContext), varargs...) +} + +// GetSessionToken mocks base method +func (m *MockSTSAPI) GetSessionToken(arg0 *sts.GetSessionTokenInput) (*sts.GetSessionTokenOutput, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetSessionToken", arg0) + ret0, _ := ret[0].(*sts.GetSessionTokenOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetSessionToken indicates an expected call of GetSessionToken +func (mr *MockSTSAPIMockRecorder) GetSessionToken(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSessionToken", reflect.TypeOf((*MockSTSAPI)(nil).GetSessionToken), arg0) +} + +// GetSessionTokenRequest mocks base method +func (m *MockSTSAPI) GetSessionTokenRequest(arg0 *sts.GetSessionTokenInput) (*request.Request, *sts.GetSessionTokenOutput) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetSessionTokenRequest", arg0) + ret0, _ := ret[0].(*request.Request) + ret1, _ := ret[1].(*sts.GetSessionTokenOutput) + return ret0, ret1 +} + +// GetSessionTokenRequest indicates an expected call of GetSessionTokenRequest +func (mr *MockSTSAPIMockRecorder) GetSessionTokenRequest(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSessionTokenRequest", reflect.TypeOf((*MockSTSAPI)(nil).GetSessionTokenRequest), arg0) +} + +// GetSessionTokenWithContext mocks base method +func (m *MockSTSAPI) GetSessionTokenWithContext(arg0 context.Context, arg1 *sts.GetSessionTokenInput, arg2 ...request.Option) (*sts.GetSessionTokenOutput, error) { + m.ctrl.T.Helper() + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetSessionTokenWithContext", varargs...) + ret0, _ := ret[0].(*sts.GetSessionTokenOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetSessionTokenWithContext indicates an expected call of GetSessionTokenWithContext +func (mr *MockSTSAPIMockRecorder) GetSessionTokenWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSessionTokenWithContext", reflect.TypeOf((*MockSTSAPI)(nil).GetSessionTokenWithContext), varargs...) +} diff --git a/public/app/plugins/datasource/cloudwatch/components/ConfigEditor.test.tsx b/public/app/plugins/datasource/cloudwatch/components/ConfigEditor.test.tsx index 560035a1a91..5f510208a8b 100644 --- a/public/app/plugins/datasource/cloudwatch/components/ConfigEditor.test.tsx +++ b/public/app/plugins/datasource/cloudwatch/components/ConfigEditor.test.tsx @@ -42,6 +42,7 @@ const setup = (propOverrides?: object) => { }, jsonData: { assumeRoleArn: '', + externalId: '', database: '', customMetricsNamespaces: '', authType: 'keys', diff --git a/public/app/plugins/datasource/cloudwatch/components/ConfigEditor.tsx b/public/app/plugins/datasource/cloudwatch/components/ConfigEditor.tsx index cd36315f3f3..89cb8bc6d19 100644 --- a/public/app/plugins/datasource/cloudwatch/components/ConfigEditor.tsx +++ b/public/app/plugins/datasource/cloudwatch/components/ConfigEditor.tsx @@ -130,6 +130,7 @@ export class ConfigEditor extends PureComponent { onChange={option => { if (options.jsonData.authType === 'arn' && option.value !== 'arn') { delete this.props.options.jsonData.assumeRoleArn; + delete this.props.options.jsonData.externalId; } onUpdateDatasourceJsonDataOptionSelect(this.props, 'authType')(option); }} @@ -239,6 +240,22 @@ export class ConfigEditor extends PureComponent { /> +
+ + External ID + +
+ +
+
)}
diff --git a/public/app/plugins/datasource/cloudwatch/types.ts b/public/app/plugins/datasource/cloudwatch/types.ts index 8bbb9bf911d..5bab1b6957d 100644 --- a/public/app/plugins/datasource/cloudwatch/types.ts +++ b/public/app/plugins/datasource/cloudwatch/types.ts @@ -59,6 +59,7 @@ export type SelectableStrings = Array>; export interface CloudWatchJsonData extends DataSourceJsonData { timeField?: string; assumeRoleArn?: string; + externalId?: string; database?: string; customMetricsNamespaces?: string; }