Cloudwatch: Refactor datasource instance factory method (#57452)

* wip

* fix broken test
pull/57615/head
Erik Sundell 3 years ago committed by GitHub
parent d9a6c3f398
commit 8adbacb18e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      pkg/tsdb/cloudwatch/annotation_query_test.go
  2. 108
      pkg/tsdb/cloudwatch/cloudwatch.go
  3. 71
      pkg/tsdb/cloudwatch/cloudwatch_test.go
  4. 4
      pkg/tsdb/cloudwatch/log_actions.go
  5. 17
      pkg/tsdb/cloudwatch/log_actions_test.go
  6. 40
      pkg/tsdb/cloudwatch/metric_find_query.go
  7. 13
      pkg/tsdb/cloudwatch/metric_find_query_test.go
  8. 36
      pkg/tsdb/cloudwatch/models/settings.go
  9. 74
      pkg/tsdb/cloudwatch/models/settings_test.go
  10. 8
      pkg/tsdb/cloudwatch/time_series_query_test.go

@ -13,6 +13,7 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend/datasource"
"github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@ -31,7 +32,7 @@ func TestQuery_AnnotationQuery(t *testing.T) {
t.Run("DescribeAlarmsForMetric is called with minimum parameters", func(t *testing.T) {
client = fakeCWAnnotationsClient{describeAlarmsForMetricOutput: &cloudwatch.DescribeAlarmsForMetricOutput{}}
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return datasourceInfo{}, nil
return DataSource{Settings: &models.CloudWatchSettings{}}, nil
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}, featuremgmt.WithFeatures())
@ -65,7 +66,7 @@ func TestQuery_AnnotationQuery(t *testing.T) {
t.Run("DescribeAlarms is called when prefixMatching is true", func(t *testing.T) {
client = fakeCWAnnotationsClient{describeAlarmsOutput: &cloudwatch.DescribeAlarmsOutput{}}
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return datasourceInfo{}, nil
return DataSource{Settings: &models.CloudWatchSettings{}}, nil
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}, featuremgmt.WithFeatures())

@ -34,23 +34,6 @@ import (
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models"
)
type datasourceInfo struct {
profile string
region string
authType awsds.AuthType
assumeRoleARN string
externalID string
namespace string
endpoint string
accessKey string
secretKey string
datasourceID int64
HTTPClient *http.Client
}
type DataQueryJson struct {
QueryType string `json:"type,omitempty"`
QueryMode string
@ -65,6 +48,11 @@ type DataQueryJson struct {
AlarmNamePrefix string
}
type DataSource struct {
Settings *models.CloudWatchSettings
HTTPClient *http.Client
}
const (
cloudWatchTSFormat = "2006-01-02 15:04:05.000"
defaultRegion = "default"
@ -120,11 +108,11 @@ func newExecutor(im instancemgmt.InstanceManager, cfg *setting.Cfg, sessions Ses
func (e *cloudWatchExecutor) getClients(pluginCtx backend.PluginContext, region string) (models.Clients, error) {
r := region
if region == defaultRegion {
dsInfo, err := e.getDSInfo(pluginCtx)
instance, err := e.getInstance(pluginCtx)
if err != nil {
return models.Clients{}, err
}
r = dsInfo.region
r = instance.Settings.Region
}
sess, err := e.newSession(pluginCtx, r)
@ -138,17 +126,7 @@ func (e *cloudWatchExecutor) getClients(pluginCtx backend.PluginContext, region
func NewInstanceSettings(httpClientProvider httpclient.Provider) datasource.InstanceFactoryFunc {
return func(settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
jsonData := struct {
Profile string `json:"profile"`
Region string `json:"defaultRegion"`
AssumeRoleARN string `json:"assumeRoleArn"`
ExternalID string `json:"externalId"`
Endpoint string `json:"endpoint"`
Namespace string `json:"customMetricsNamespaces"`
AuthType string `json:"authType"`
}{}
err := json.Unmarshal(settings.JSONData, &jsonData)
instanceSettings, err := models.LoadCloudWatchSettings(settings)
if err != nil {
return nil, fmt.Errorf("error reading settings: %w", err)
}
@ -158,44 +136,10 @@ func NewInstanceSettings(httpClientProvider httpclient.Provider) datasource.Inst
return nil, fmt.Errorf("error creating http client: %w", err)
}
model := datasourceInfo{
profile: jsonData.Profile,
region: jsonData.Region,
assumeRoleARN: jsonData.AssumeRoleARN,
externalID: jsonData.ExternalID,
endpoint: jsonData.Endpoint,
namespace: jsonData.Namespace,
datasourceID: settings.ID,
HTTPClient: httpClient,
}
at := awsds.AuthTypeDefault
switch jsonData.AuthType {
case "credentials":
at = awsds.AuthTypeSharedCreds
case "keys":
at = awsds.AuthTypeKeys
case "default":
at = awsds.AuthTypeDefault
case "ec2_iam_role":
at = awsds.AuthTypeEC2IAMRole
case "arn":
at = awsds.AuthTypeDefault
cwlog.Warn("Authentication type \"arn\" is deprecated, falling back to default")
default:
cwlog.Warn("Unrecognized AWS authentication type", "type", jsonData.AuthType)
}
model.authType = at
if model.profile == "" {
model.profile = settings.Database // legacy support
}
model.accessKey = settings.DecryptedSecureJSONData["accessKey"]
model.secretKey = settings.DecryptedSecureJSONData["secretKey"]
return model, nil
return DataSource{
Settings: instanceSettings,
HTTPClient: httpClient,
}, nil
}
}
@ -257,28 +201,28 @@ func (e *cloudWatchExecutor) CheckHealth(ctx context.Context, req *backend.Check
}
func (e *cloudWatchExecutor) newSession(pluginCtx backend.PluginContext, region string) (*session.Session, error) {
dsInfo, err := e.getDSInfo(pluginCtx)
instance, err := e.getInstance(pluginCtx)
if err != nil {
return nil, err
}
if region == defaultRegion {
region = dsInfo.region
region = instance.Settings.Region
}
return e.sessions.GetSession(awsds.SessionConfig{
// https://github.com/grafana/grafana/issues/46365
// HTTPClient: dsInfo.HTTPClient,
Settings: awsds.AWSDatasourceSettings{
Profile: dsInfo.profile,
Profile: instance.Settings.Profile,
Region: region,
AuthType: dsInfo.authType,
AssumeRoleARN: dsInfo.assumeRoleARN,
ExternalID: dsInfo.externalID,
Endpoint: dsInfo.endpoint,
DefaultRegion: dsInfo.region,
AccessKey: dsInfo.accessKey,
SecretKey: dsInfo.secretKey,
AuthType: instance.Settings.AuthType,
AssumeRoleARN: instance.Settings.AssumeRoleARN,
ExternalID: instance.Settings.ExternalID,
Endpoint: instance.Settings.Endpoint,
DefaultRegion: instance.Settings.Region,
AccessKey: instance.Settings.AccessKey,
SecretKey: instance.Settings.SecretKey,
},
UserAgentName: aws.String("Cloudwatch"),
})
@ -407,11 +351,11 @@ func (e *cloudWatchExecutor) executeLogAlertQuery(ctx context.Context, req *back
region := model.Region
if model.Region == "" || region == defaultRegion {
dsInfo, err := e.getDSInfo(req.PluginContext)
instance, err := e.getInstance(req.PluginContext)
if err != nil {
return nil, err
}
model.Region = dsInfo.region
model.Region = instance.Settings.Region
}
logsClient, err := e.getCWLogsClient(req.PluginContext, region)
@ -447,13 +391,13 @@ func (e *cloudWatchExecutor) executeLogAlertQuery(ctx context.Context, req *back
return resp, nil
}
func (e *cloudWatchExecutor) getDSInfo(pluginCtx backend.PluginContext) (*datasourceInfo, error) {
func (e *cloudWatchExecutor) getInstance(pluginCtx backend.PluginContext) (*DataSource, error) {
i, err := e.im.Get(pluginCtx)
if err != nil {
return nil, err
}
instance := i.(datasourceInfo)
instance := i.(DataSource)
return &instance, nil
}

@ -32,7 +32,7 @@ func TestNewInstanceSettings(t *testing.T) {
tests := []struct {
name string
settings backend.DataSourceInstanceSettings
expectedDS datasourceInfo
expectedDS DataSource
Err require.ErrorAssertionFunc
}{
{
@ -52,16 +52,20 @@ func TestNewInstanceSettings(t *testing.T) {
"secretKey": "secret",
},
},
expectedDS: datasourceInfo{
profile: "foo",
region: "us-east2",
assumeRoleARN: "role",
externalID: "id",
endpoint: "bar",
namespace: "ns",
authType: awsds.AuthTypeKeys,
accessKey: "A123",
secretKey: "secret",
expectedDS: DataSource{
Settings: &models.CloudWatchSettings{
AWSDatasourceSettings: awsds.AWSDatasourceSettings{
Profile: "foo",
Region: "us-east2",
AssumeRoleARN: "role",
ExternalID: "id",
Endpoint: "bar",
AuthType: awsds.AuthTypeKeys,
AccessKey: "A123",
SecretKey: "secret",
},
Namespace: "ns",
},
},
Err: require.NoError,
},
@ -72,19 +76,18 @@ func TestNewInstanceSettings(t *testing.T) {
f := NewInstanceSettings(httpclient.NewProvider())
model, err := f(tt.settings)
tt.Err(t, err)
datasourceComparer := cmp.Comparer(func(d1 datasourceInfo, d2 datasourceInfo) bool {
return d1.profile == d2.profile &&
d1.region == d2.region &&
d1.authType == d2.authType &&
d1.assumeRoleARN == d2.assumeRoleARN &&
d1.externalID == d2.externalID &&
d1.namespace == d2.namespace &&
d1.endpoint == d2.endpoint &&
d1.accessKey == d2.accessKey &&
d1.secretKey == d2.secretKey &&
d1.datasourceID == d2.datasourceID
datasourceComparer := cmp.Comparer(func(d1 DataSource, d2 DataSource) bool {
return d1.Settings.Profile == d2.Settings.Profile &&
d1.Settings.Region == d2.Settings.Region &&
d1.Settings.AuthType == d2.Settings.AuthType &&
d1.Settings.AssumeRoleARN == d2.Settings.AssumeRoleARN &&
d1.Settings.ExternalID == d2.Settings.ExternalID &&
d1.Settings.Namespace == d2.Settings.Namespace &&
d1.Settings.Endpoint == d2.Settings.Endpoint &&
d1.Settings.AccessKey == d2.Settings.AccessKey &&
d1.Settings.SecretKey == d2.Settings.SecretKey
})
if !cmp.Equal(model.(datasourceInfo), tt.expectedDS, datasourceComparer) {
if !cmp.Equal(model.(DataSource), tt.expectedDS, datasourceComparer) {
t.Errorf("Unexpected result. Expecting\n%v \nGot:\n%v", model, tt.expectedDS)
}
})
@ -110,7 +113,7 @@ func Test_CheckHealth(t *testing.T) {
t.Run("successfully query metrics and logs", func(t *testing.T) {
client = fakeCheckHealthClient{}
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return datasourceInfo{}, nil
return DataSource{Settings: &models.CloudWatchSettings{}}, nil
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}, featuremgmt.WithFeatures())
@ -131,7 +134,7 @@ func Test_CheckHealth(t *testing.T) {
return nil, fmt.Errorf("some logs query error")
}}
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return datasourceInfo{}, nil
return DataSource{Settings: &models.CloudWatchSettings{}}, nil
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}, featuremgmt.WithFeatures())
@ -152,7 +155,7 @@ func Test_CheckHealth(t *testing.T) {
return fmt.Errorf("some list metrics error")
}}
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return datasourceInfo{}, nil
return DataSource{Settings: &models.CloudWatchSettings{}}, nil
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}, featuremgmt.WithFeatures())
@ -170,7 +173,7 @@ func Test_CheckHealth(t *testing.T) {
t.Run("fail to get clients", func(t *testing.T) {
client = fakeCheckHealthClient{}
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return datasourceInfo{}, nil
return DataSource{Settings: &models.CloudWatchSettings{}}, nil
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{getSession: func(c awsds.SessionConfig) (*session.Session, error) {
return nil, fmt.Errorf("some sessions error")
@ -201,7 +204,7 @@ func Test_executeLogAlertQuery(t *testing.T) {
t.Run("getCWLogsClient is called with region from input JSON", func(t *testing.T) {
cli = fakeCWLogsClient{queryResults: cloudwatchlogs.GetQueryResultsOutput{Status: aws.String("Complete")}}
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return datasourceInfo{}, nil
return DataSource{Settings: &models.CloudWatchSettings{}}, nil
})
sess := fakeSessionCache{}
executor := newExecutor(im, newTestConfig(), &sess, featuremgmt.WithFeatures())
@ -227,7 +230,7 @@ func Test_executeLogAlertQuery(t *testing.T) {
t.Run("getCWLogsClient is called with region from instance manager when region is default", func(t *testing.T) {
cli = fakeCWLogsClient{queryResults: cloudwatchlogs.GetQueryResultsOutput{Status: aws.String("Complete")}}
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return datasourceInfo{region: "instance manager's region"}, nil
return DataSource{Settings: &models.CloudWatchSettings{AWSDatasourceSettings: awsds.AWSDatasourceSettings{Region: "instance manager's region"}}}, nil
})
sess := fakeSessionCache{}
@ -264,7 +267,7 @@ func TestQuery_ResourceRequest_DescribeAllLogGroups(t *testing.T) {
}
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return datasourceInfo{}, nil
return DataSource{Settings: &models.CloudWatchSettings{}}, nil
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}, featuremgmt.WithFeatures())
@ -343,7 +346,7 @@ func TestQuery_ResourceRequest_DescribeLogGroups(t *testing.T) {
}
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return datasourceInfo{}, nil
return DataSource{Settings: &models.CloudWatchSettings{}}, nil
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}, featuremgmt.WithFeatures())
@ -398,7 +401,7 @@ func TestQuery_ResourceRequest_DescribeLogGroups(t *testing.T) {
}
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return datasourceInfo{}, nil
return DataSource{Settings: &models.CloudWatchSettings{}}, nil
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}, featuremgmt.WithFeatures())
@ -436,7 +439,7 @@ func TestQuery_ResourceRequest_DescribeLogGroups(t *testing.T) {
}
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return datasourceInfo{}, nil
return DataSource{Settings: &models.CloudWatchSettings{}}, nil
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}, featuremgmt.WithFeatures())
@ -477,7 +480,7 @@ func Test_CloudWatch_CallResource_Integration_Test(t *testing.T) {
return &api
}
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return datasourceInfo{}, nil
return DataSource{Settings: &models.CloudWatchSettings{}}, nil
})
t.Run("Should handle dimension value request and return values from the api", func(t *testing.T) {

@ -110,12 +110,12 @@ func (e *cloudWatchExecutor) executeLogActions(ctx context.Context, req *backend
}
func (e *cloudWatchExecutor) executeLogAction(ctx context.Context, model LogQueryJson, query backend.DataQuery, pluginCtx backend.PluginContext) (*data.Frame, error) {
dsInfo, err := e.getDSInfo(pluginCtx)
instance, err := e.getInstance(pluginCtx)
if err != nil {
return nil, err
}
region := dsInfo.region
region := instance.Settings.Region
if model.Region != "" {
region = model.Region
}

@ -15,6 +15,7 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt"
"github.com/grafana/grafana-plugin-sdk-go/data"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@ -82,7 +83,7 @@ func TestQuery_GetLogEvents(t *testing.T) {
cli = fakeCWLogsClient{}
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return datasourceInfo{}, nil
return DataSource{Settings: &models.CloudWatchSettings{}}, nil
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}, featuremgmt.WithFeatures())
@ -140,7 +141,7 @@ func TestQuery_GetLogGroupFields(t *testing.T) {
const refID = "A"
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return datasourceInfo{}, nil
return DataSource{Settings: &models.CloudWatchSettings{}}, nil
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}, featuremgmt.WithFeatures())
@ -221,7 +222,7 @@ func TestQuery_StartQuery(t *testing.T) {
}
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return datasourceInfo{}, nil
return DataSource{Settings: &models.CloudWatchSettings{}}, nil
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}, featuremgmt.WithFeatures())
@ -274,7 +275,7 @@ func TestQuery_StartQuery(t *testing.T) {
}
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return datasourceInfo{}, nil
return DataSource{Settings: &models.CloudWatchSettings{}}, nil
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}, featuremgmt.WithFeatures())
@ -332,7 +333,7 @@ func Test_executeStartQuery(t *testing.T) {
t.Run("successfully parses information from JSON to StartQueryWithContext", func(t *testing.T) {
cli = fakeCWLogsClient{}
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return datasourceInfo{}, nil
return DataSource{Settings: &models.CloudWatchSettings{}}, nil
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}, featuremgmt.WithFeatures())
@ -368,7 +369,7 @@ func Test_executeStartQuery(t *testing.T) {
t.Run("does not populate StartQueryInput.limit when no limit provided", func(t *testing.T) {
cli = fakeCWLogsClient{}
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return datasourceInfo{}, nil
return DataSource{Settings: &models.CloudWatchSettings{}}, nil
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}, featuremgmt.WithFeatures())
@ -424,7 +425,7 @@ func TestQuery_StopQuery(t *testing.T) {
}
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return datasourceInfo{}, nil
return DataSource{Settings: &models.CloudWatchSettings{}}, nil
})
timeRange := backend.TimeRange{
@ -519,7 +520,7 @@ func TestQuery_GetQueryResults(t *testing.T) {
}
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return datasourceInfo{}, nil
return DataSource{Settings: &models.CloudWatchSettings{}}, nil
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}, featuremgmt.WithFeatures())

@ -55,12 +55,12 @@ func parseMultiSelectValue(input string) []string {
// Whenever this list is updated, the frontend list should also be updated.
// Please update the region list in public/app/plugins/datasource/cloudwatch/partials/config.html
func (e *cloudWatchExecutor) handleGetRegions(pluginCtx backend.PluginContext, parameters url.Values) ([]suggestData, error) {
dsInfo, err := e.getDSInfo(pluginCtx)
instance, err := e.getInstance(pluginCtx)
if err != nil {
return nil, err
}
profile := dsInfo.profile
profile := instance.Settings.Profile
if cache, ok := regionCache.Load(profile); ok {
if cache2, ok2 := cache.([]suggestData); ok2 {
return cache2, nil
@ -109,12 +109,12 @@ func (e *cloudWatchExecutor) handleGetNamespaces(pluginCtx backend.PluginContext
keys = append(keys, key)
}
dsInfo, err := e.getDSInfo(pluginCtx)
instance, err := e.getInstance(pluginCtx)
if err != nil {
return nil, err
}
customNamespaces := dsInfo.namespace
customNamespaces := instance.Settings.Namespace
if customNamespaces != "" {
keys = append(keys, strings.Split(customNamespaces, ",")...)
}
@ -395,24 +395,24 @@ func (e *cloudWatchExecutor) getMetricsForCustomMetrics(region, namespace string
metricsCacheLock.Lock()
defer metricsCacheLock.Unlock()
dsInfo, err := e.getDSInfo(pluginCtx)
instance, err := e.getInstance(pluginCtx)
if err != nil {
return nil, err
}
if _, ok := customMetricsMetricsMap[dsInfo.profile]; !ok {
customMetricsMetricsMap[dsInfo.profile] = make(map[string]map[string]*customMetricsCache)
if _, ok := customMetricsMetricsMap[instance.Settings.Profile]; !ok {
customMetricsMetricsMap[instance.Settings.Profile] = make(map[string]map[string]*customMetricsCache)
}
if _, ok := customMetricsMetricsMap[dsInfo.profile][dsInfo.region]; !ok {
customMetricsMetricsMap[dsInfo.profile][dsInfo.region] = make(map[string]*customMetricsCache)
if _, ok := customMetricsMetricsMap[instance.Settings.Profile][instance.Settings.Region]; !ok {
customMetricsMetricsMap[instance.Settings.Profile][instance.Settings.Region] = make(map[string]*customMetricsCache)
}
if _, ok := customMetricsMetricsMap[dsInfo.profile][dsInfo.region][namespace]; !ok {
customMetricsMetricsMap[dsInfo.profile][dsInfo.region][namespace] = &customMetricsCache{}
customMetricsMetricsMap[dsInfo.profile][dsInfo.region][namespace].Cache = make([]string, 0)
if _, ok := customMetricsMetricsMap[instance.Settings.Profile][instance.Settings.Region][namespace]; !ok {
customMetricsMetricsMap[instance.Settings.Profile][instance.Settings.Region][namespace] = &customMetricsCache{}
customMetricsMetricsMap[instance.Settings.Profile][instance.Settings.Region][namespace].Cache = make([]string, 0)
}
if customMetricsMetricsMap[dsInfo.profile][dsInfo.region][namespace].Expire.After(time.Now()) {
return customMetricsMetricsMap[dsInfo.profile][dsInfo.region][namespace].Cache, nil
if customMetricsMetricsMap[instance.Settings.Profile][instance.Settings.Region][namespace].Expire.After(time.Now()) {
return customMetricsMetricsMap[instance.Settings.Profile][instance.Settings.Region][namespace].Cache, nil
}
metrics, err := e.listMetrics(pluginCtx, region, &cloudwatch.ListMetricsInput{
Namespace: aws.String(namespace),
@ -421,18 +421,18 @@ func (e *cloudWatchExecutor) getMetricsForCustomMetrics(region, namespace string
return []string{}, err
}
customMetricsMetricsMap[dsInfo.profile][dsInfo.region][namespace].Cache = make([]string, 0)
customMetricsMetricsMap[dsInfo.profile][dsInfo.region][namespace].Expire = time.Now().Add(5 * time.Minute)
customMetricsMetricsMap[instance.Settings.Profile][instance.Settings.Region][namespace].Cache = make([]string, 0)
customMetricsMetricsMap[instance.Settings.Profile][instance.Settings.Region][namespace].Expire = time.Now().Add(5 * time.Minute)
for _, metric := range metrics {
if isDuplicate(customMetricsMetricsMap[dsInfo.profile][dsInfo.region][namespace].Cache, *metric.MetricName) {
if isDuplicate(customMetricsMetricsMap[instance.Settings.Profile][instance.Settings.Region][namespace].Cache, *metric.MetricName) {
continue
}
customMetricsMetricsMap[dsInfo.profile][dsInfo.region][namespace].Cache = append(
customMetricsMetricsMap[dsInfo.profile][dsInfo.region][namespace].Cache, *metric.MetricName)
customMetricsMetricsMap[instance.Settings.Profile][instance.Settings.Region][namespace].Cache = append(
customMetricsMetricsMap[instance.Settings.Profile][instance.Settings.Region][namespace].Cache, *metric.MetricName)
}
return customMetricsMetricsMap[dsInfo.profile][dsInfo.region][namespace].Cache, nil
return customMetricsMetricsMap[instance.Settings.Profile][instance.Settings.Region][namespace].Cache, nil
}
func (e *cloudWatchExecutor) handleGetLogGroups(pluginCtx backend.PluginContext, parameters url.Values) ([]suggestData, error) {

@ -21,6 +21,7 @@ import (
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/constants"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/mocks"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@ -52,7 +53,7 @@ func TestQuery_Metrics(t *testing.T) {
}
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return datasourceInfo{}, nil
return DataSource{Settings: &models.CloudWatchSettings{}}, nil
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}, featuremgmt.WithFeatures())
@ -92,7 +93,7 @@ func TestQuery_Regions(t *testing.T) {
}
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return datasourceInfo{}, nil
return DataSource{Settings: &models.CloudWatchSettings{}}, nil
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}, featuremgmt.WithFeatures())
@ -159,7 +160,7 @@ func TestQuery_InstanceAttributes(t *testing.T) {
}
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return datasourceInfo{}, nil
return DataSource{Settings: &models.CloudWatchSettings{}}, nil
})
filterMap := map[string][]string{
@ -242,7 +243,7 @@ func TestQuery_EBSVolumeIDs(t *testing.T) {
}
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return datasourceInfo{}, nil
return DataSource{Settings: &models.CloudWatchSettings{}}, nil
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}, featuremgmt.WithFeatures())
@ -302,7 +303,7 @@ func TestQuery_ResourceARNs(t *testing.T) {
}
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return datasourceInfo{}, nil
return DataSource{Settings: &models.CloudWatchSettings{}}, nil
})
tagMap := map[string][]string{
@ -338,7 +339,7 @@ func TestQuery_ResourceARNs(t *testing.T) {
func TestQuery_GetAllMetrics(t *testing.T) {
t.Run("all metrics in all namespaces are being returned", func(t *testing.T) {
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return datasourceInfo{}, nil
return DataSource{Settings: &models.CloudWatchSettings{}}, nil
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}, featuremgmt.WithFeatures())

@ -0,0 +1,36 @@
package models
import (
"encoding/json"
"fmt"
"github.com/grafana/grafana-aws-sdk/pkg/awsds"
"github.com/grafana/grafana-plugin-sdk-go/backend"
)
type CloudWatchSettings struct {
awsds.AWSDatasourceSettings
Namespace string `json:"customMetricsNamespaces"`
}
func LoadCloudWatchSettings(config backend.DataSourceInstanceSettings) (*CloudWatchSettings, error) {
instance := &CloudWatchSettings{}
if config.JSONData != nil && len(config.JSONData) > 1 {
if err := json.Unmarshal(config.JSONData, instance); err != nil {
return nil, fmt.Errorf("could not unmarshal DatasourceSettings json: %w", err)
}
}
if instance.Region == "default" || instance.Region == "" {
instance.Region = instance.DefaultRegion
}
if instance.Profile == "" {
instance.Profile = config.Database
}
instance.AccessKey = config.DecryptedSecureJSONData["accessKey"]
instance.SecretKey = config.DecryptedSecureJSONData["secretKey"]
return instance, nil
}

@ -0,0 +1,74 @@
package models
import (
"testing"
"github.com/grafana/grafana-aws-sdk/pkg/awsds"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func Test_Settings_LoadCloudWatchSettings(t *testing.T) {
t.Run("Should parse keys query type", func(t *testing.T) {
settings := backend.DataSourceInstanceSettings{
ID: 33,
JSONData: []byte(`{
"authType": "keys",
"assumeRoleArn": "arn:aws:iam::123456789012:role/grafana",
"customMetricsNamespaces": "AWS/EC2,AWS/ELB",
"defaultRegion": "us-east-1",
"externalId": "123456789012",
"profile": "default",
"endpoint": "https://monitoring.us-east-1.amazonaws.com"
}`),
DecryptedSecureJSONData: map[string]string{
"accessKey": "AKIAIOSFODNN7EXAMPLE",
"secretKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
},
}
s, err := LoadCloudWatchSettings(settings)
require.NoError(t, err)
assert.Equal(t, awsds.AuthTypeKeys, s.AuthType)
assert.Equal(t, "arn:aws:iam::123456789012:role/grafana", s.AssumeRoleARN)
assert.Equal(t, "AWS/EC2,AWS/ELB", s.Namespace)
assert.Equal(t, "us-east-1", s.Region)
assert.Equal(t, "123456789012", s.ExternalID)
assert.Equal(t, "default", s.Profile)
assert.Equal(t, "https://monitoring.us-east-1.amazonaws.com", s.Endpoint)
assert.Equal(t, "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", s.SecretKey)
assert.Equal(t, "AKIAIOSFODNN7EXAMPLE", s.AccessKey)
})
t.Run("Should handle legacy auth type arn as default", func(t *testing.T) {
settings := backend.DataSourceInstanceSettings{
ID: 33,
JSONData: []byte(`{
"authType": "arn",
"assumeRoleArn": "arn:aws:iam::123456789012:role/grafana",
"customMetricsNamespaces": "AWS/EC2,AWS/ELB",
"defaultRegion": "us-east-1",
"externalId": "123456789012",
"profile": "default",
"endpoint": "https://monitoring.us-east-1.amazonaws.com"
}`),
DecryptedSecureJSONData: map[string]string{
"accessKey": "AKIAIOSFODNN7EXAMPLE",
"secretKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
},
}
s, err := LoadCloudWatchSettings(settings)
require.NoError(t, err)
assert.Equal(t, awsds.AuthTypeDefault, s.AuthType)
assert.Equal(t, "arn:aws:iam::123456789012:role/grafana", s.AssumeRoleARN)
assert.Equal(t, "AWS/EC2,AWS/ELB", s.Namespace)
assert.Equal(t, "us-east-1", s.Region)
assert.Equal(t, "123456789012", s.ExternalID)
assert.Equal(t, "default", s.Profile)
assert.Equal(t, "https://monitoring.us-east-1.amazonaws.com", s.Endpoint)
assert.Equal(t, "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", s.SecretKey)
assert.Equal(t, "AKIAIOSFODNN7EXAMPLE", s.AccessKey)
})
}

@ -56,7 +56,7 @@ func TestTimeSeriesQuery(t *testing.T) {
}
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return datasourceInfo{}, nil
return DataSource{Settings: &models.CloudWatchSettings{}}, nil
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}, featuremgmt.WithFeatures())
@ -156,7 +156,7 @@ func Test_executeTimeSeriesQuery_getCWClient_is_called_once_per_region_and_GetMe
}
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return datasourceInfo{}, nil
return DataSource{Settings: &models.CloudWatchSettings{}}, nil
})
t.Run("Queries with the same region should call GetSession with that region 1 time and call GetMetricDataWithContext 1 time", func(t *testing.T) {
@ -348,7 +348,7 @@ func Test_QueryData_timeSeriesQuery_GetMetricDataWithContext(t *testing.T) {
}
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return datasourceInfo{}, nil
return DataSource{Settings: &models.CloudWatchSettings{}}, nil
})
t.Run("passes query label as GetMetricData label when dynamic labels feature toggle is enabled", func(t *testing.T) {
@ -446,7 +446,7 @@ func Test_QueryData_response_data_frame_names(t *testing.T) {
},
}
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return datasourceInfo{}, nil
return DataSource{Settings: &models.CloudWatchSettings{}}, nil
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}, featuremgmt.WithFeatures())

Loading…
Cancel
Save