mirror of
https://github.com/grafana/grafana.git
synced 2025-09-22 01:46:39 +08:00
Cloudwatch: Refactor datasource instance factory method (#57452)
* wip * fix broken test
This commit is contained in:
@ -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())
|
||||
|
36
pkg/tsdb/cloudwatch/models/settings.go
Normal file
36
pkg/tsdb/cloudwatch/models/settings.go
Normal file
@ -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
|
||||
}
|
74
pkg/tsdb/cloudwatch/models/settings_test.go
Normal file
74
pkg/tsdb/cloudwatch/models/settings_test.go
Normal file
@ -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())
|
||||
|
||||
|
Reference in New Issue
Block a user