CloudWatch: Remove dependencies on grafana/pkg/setting (#81208)

This commit is contained in:
Isabella Siu
2024-02-05 13:59:32 -05:00
committed by GitHub
parent 2ab7d3c725
commit 81da3ff753
28 changed files with 440 additions and 214 deletions

View File

@@ -10,9 +10,6 @@ import (
"github.com/aws/aws-sdk-go/service/cloudwatch"
"github.com/aws/aws-sdk-go/service/cloudwatch/cloudwatchiface"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/backend/datasource"
"github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -30,11 +27,9 @@ 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(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil
})
im := defaultTestInstanceManager()
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(im, &fakeSessionCache{})
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{},
@@ -64,11 +59,9 @@ 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(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil
})
im := defaultTestInstanceManager()
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(im, &fakeSessionCache{})
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{},

View File

@@ -6,7 +6,6 @@ import (
"github.com/aws/aws-sdk-go/aws/awsutil"
"github.com/aws/aws-sdk-go/service/cloudwatch"
"github.com/grafana/grafana/pkg/infra/metrics"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models/resources"
)
@@ -14,11 +13,11 @@ import (
// this client wraps the CloudWatch API and handles pagination and the composition of the MetricResponse DTO
type metricsClient struct {
models.CloudWatchMetricsAPIProvider
config *setting.Cfg
listMetricsPageLimit int
}
func NewMetricsClient(api models.CloudWatchMetricsAPIProvider, config *setting.Cfg) *metricsClient {
return &metricsClient{CloudWatchMetricsAPIProvider: api, config: config}
func NewMetricsClient(api models.CloudWatchMetricsAPIProvider, pageLimit int) *metricsClient {
return &metricsClient{CloudWatchMetricsAPIProvider: api, listMetricsPageLimit: pageLimit}
}
func (l *metricsClient) ListMetricsWithPageLimit(ctx context.Context, params *cloudwatch.ListMetricsInput) ([]resources.MetricResponse, error) {
@@ -37,7 +36,7 @@ func (l *metricsClient) ListMetricsWithPageLimit(ctx context.Context, params *cl
cloudWatchMetrics = append(cloudWatchMetrics, metric)
}
}
return !lastPage && pageNum < l.config.AWSListMetricsPageLimit
return !lastPage && pageNum < l.listMetricsPageLimit
})
return cloudWatchMetrics, err

View File

@@ -6,7 +6,6 @@ import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/cloudwatch"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/mocks"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models/resources"
"github.com/stretchr/testify/assert"
@@ -31,7 +30,7 @@ func TestMetricsClient(t *testing.T) {
t.Run("List Metrics and page limit is reached", func(t *testing.T) {
pageLimit := 3
fakeApi := &mocks.FakeMetricsAPI{Metrics: metrics, MetricsPerPage: 2}
client := NewMetricsClient(fakeApi, &setting.Cfg{AWSListMetricsPageLimit: pageLimit})
client := NewMetricsClient(fakeApi, pageLimit)
response, err := client.ListMetricsWithPageLimit(ctx, &cloudwatch.ListMetricsInput{})
require.NoError(t, err)
@@ -42,7 +41,7 @@ func TestMetricsClient(t *testing.T) {
t.Run("List Metrics and page limit is not reached", func(t *testing.T) {
pageLimit := 2
fakeApi := &mocks.FakeMetricsAPI{Metrics: metrics}
client := NewMetricsClient(fakeApi, &setting.Cfg{AWSListMetricsPageLimit: pageLimit})
client := NewMetricsClient(fakeApi, pageLimit)
response, err := client.ListMetricsWithPageLimit(ctx, &cloudwatch.ListMetricsInput{})
require.NoError(t, err)
@@ -56,7 +55,7 @@ func TestMetricsClient(t *testing.T) {
{MetricName: aws.String("Test_MetricName2")},
{MetricName: aws.String("Test_MetricName3")},
}, OwningAccounts: []*string{aws.String("1234567890"), aws.String("1234567890"), aws.String("1234567895")}}
client := NewMetricsClient(fakeApi, &setting.Cfg{AWSListMetricsPageLimit: 100})
client := NewMetricsClient(fakeApi, 100)
response, err := client.ListMetricsWithPageLimit(ctx, &cloudwatch.ListMetricsInput{IncludeLinkedAccounts: aws.Bool(true)})
require.NoError(t, err)
@@ -70,7 +69,7 @@ func TestMetricsClient(t *testing.T) {
t.Run("Should not return account id in case IncludeLinkedAccounts is set to false", func(t *testing.T) {
fakeApi := &mocks.FakeMetricsAPI{Metrics: []*cloudwatch.Metric{{MetricName: aws.String("Test_MetricName1")}}, OwningAccounts: []*string{aws.String("1234567890")}}
client := NewMetricsClient(fakeApi, &setting.Cfg{AWSListMetricsPageLimit: 100})
client := NewMetricsClient(fakeApi, 100)
response, err := client.ListMetricsWithPageLimit(ctx, &cloudwatch.ListMetricsInput{IncludeLinkedAccounts: aws.Bool(false)})
require.NoError(t, err)

View File

@@ -24,7 +24,6 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend/proxy"
"github.com/grafana/grafana-plugin-sdk-go/backend/resource/httpadapter"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/clients"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/kinds/dataquery"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models"
@@ -64,19 +63,16 @@ const (
var logger = log.New("tsdb.cloudwatch")
func ProvideService(cfg *setting.Cfg, httpClientProvider *httpclient.Provider) *CloudWatchService {
func ProvideService(httpClientProvider *httpclient.Provider) *CloudWatchService {
logger.Debug("Initializing")
executor := newExecutor(datasource.NewInstanceManager(NewInstanceSettings(httpClientProvider)), cfg, awsds.NewSessionCache())
executor := newExecutor(datasource.NewInstanceManager(NewInstanceSettings(httpClientProvider)), awsds.NewSessionCache())
return &CloudWatchService{
Cfg: cfg,
Executor: executor,
}
}
type CloudWatchService struct {
Cfg *setting.Cfg
Executor *cloudWatchExecutor
}
@@ -84,10 +80,9 @@ type SessionCache interface {
GetSession(c awsds.SessionConfig) (*session.Session, error)
}
func newExecutor(im instancemgmt.InstanceManager, cfg *setting.Cfg, sessions SessionCache) *cloudWatchExecutor {
func newExecutor(im instancemgmt.InstanceManager, sessions SessionCache) *cloudWatchExecutor {
e := &cloudWatchExecutor{
im: im,
cfg: cfg,
sessions: sessions,
}
@@ -97,7 +92,7 @@ func newExecutor(im instancemgmt.InstanceManager, cfg *setting.Cfg, sessions Ses
func NewInstanceSettings(httpClientProvider *httpclient.Provider) datasource.InstanceFactoryFunc {
return func(ctx context.Context, settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
instanceSettings, err := models.LoadCloudWatchSettings(settings)
instanceSettings, err := models.LoadCloudWatchSettings(ctx, settings)
if err != nil {
return nil, fmt.Errorf("error reading settings: %w", err)
}
@@ -125,7 +120,6 @@ func NewInstanceSettings(httpClientProvider *httpclient.Provider) datasource.Ins
// cloudWatchExecutor executes CloudWatch requests.
type cloudWatchExecutor struct {
im instancemgmt.InstanceManager
cfg *setting.Cfg
sessions SessionCache
regionCache sync.Map
@@ -154,7 +148,7 @@ func (e *cloudWatchExecutor) getRequestContext(ctx context.Context, pluginCtx ba
return models.RequestContext{
OAMAPIProvider: NewOAMAPI(sess),
MetricsClientProvider: clients.NewMetricsClient(NewMetricsAPI(sess), e.cfg),
MetricsClientProvider: clients.NewMetricsClient(NewMetricsAPI(sess), instance.Settings.GrafanaSettings.ListMetricsPageLimit),
LogsAPIProvider: NewLogsAPI(sess),
EC2APIProvider: ec2Client,
Settings: instance.Settings,
@@ -236,7 +230,13 @@ func (e *cloudWatchExecutor) checkHealthMetrics(ctx context.Context, pluginCtx b
if err != nil {
return err
}
metricClient := clients.NewMetricsClient(NewMetricsAPI(session), e.cfg)
instance, err := e.getInstance(ctx, pluginCtx)
if err != nil {
return err
}
metricClient := clients.NewMetricsClient(NewMetricsAPI(session), instance.Settings.GrafanaSettings.ListMetricsPageLimit)
_, err = metricClient.ListMetricsWithPageLimit(ctx, params)
return err
}
@@ -279,13 +279,14 @@ func (e *cloudWatchExecutor) newSession(ctx context.Context, pluginCtx backend.P
SecretKey: instance.Settings.SecretKey,
},
UserAgentName: aws.String("Cloudwatch"),
AuthSettings: &instance.Settings.GrafanaSettings,
})
if err != nil {
return nil, err
}
// work around until https://github.com/grafana/grafana/issues/39089 is implemented
if e.cfg.SecureSocksDSProxy.Enabled && instance.Settings.SecureSocksProxyEnabled {
if instance.Settings.GrafanaSettings.SecureSocksDSProxyEnabled && instance.Settings.SecureSocksProxyEnabled {
// only update the transport to try to avoid the issue mentioned here https://github.com/grafana/grafana/issues/46365
// also, 'sess' is cached and reused, so the first time it might have the transport not set, the following uses it will
if sess.Config.HTTPClient.Transport == nil {

View File

@@ -16,7 +16,6 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/backend/datasource"
"github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/mocks"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models/resources"
@@ -54,16 +53,8 @@ func Test_CloudWatch_CallResource_Integration_Test(t *testing.T) {
return &api
}
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{
AWSDatasourceSettings: awsds.AWSDatasourceSettings{
Region: "us-east-1",
},
}}, nil
})
t.Run("Should handle dimension value request and return values from the api", func(t *testing.T) {
pageLimit := 100
im := testInstanceManager(100)
api = mocks.FakeMetricsAPI{Metrics: []*cloudwatch.Metric{
{MetricName: aws.String("Test_MetricName1"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName1"), Value: aws.String("Value1")}, {Name: aws.String("Test_DimensionName2"), Value: aws.String("Value2")}}},
{MetricName: aws.String("Test_MetricName2"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName1"), Value: aws.String("Value3")}}},
@@ -76,7 +67,7 @@ func Test_CloudWatch_CallResource_Integration_Test(t *testing.T) {
{MetricName: aws.String("Test_MetricName8"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName4"), Value: aws.String("Value1")}}},
{MetricName: aws.String("Test_MetricName9"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName1"), Value: aws.String("Value2")}}},
}, MetricsPerPage: 100}
executor := newExecutor(im, &setting.Cfg{AWSListMetricsPageLimit: pageLimit}, &fakeSessionCache{})
executor := newExecutor(im, &fakeSessionCache{})
req := &backend.CallResourceRequest{
Method: "GET",
@@ -99,7 +90,7 @@ func Test_CloudWatch_CallResource_Integration_Test(t *testing.T) {
})
t.Run("Should handle dimension key filter query and return keys from the api", func(t *testing.T) {
pageLimit := 3
im := testInstanceManager(3)
api = mocks.FakeMetricsAPI{Metrics: []*cloudwatch.Metric{
{MetricName: aws.String("Test_MetricName1"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName1")}, {Name: aws.String("Test_DimensionName2")}}},
{MetricName: aws.String("Test_MetricName2"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName1")}}},
@@ -112,8 +103,7 @@ func Test_CloudWatch_CallResource_Integration_Test(t *testing.T) {
{MetricName: aws.String("Test_MetricName8"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName4")}}},
{MetricName: aws.String("Test_MetricName9"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName1")}}},
}, MetricsPerPage: 2}
executor := newExecutor(im, &setting.Cfg{AWSListMetricsPageLimit: pageLimit}, &fakeSessionCache{})
executor := newExecutor(im, &fakeSessionCache{})
req := &backend.CallResourceRequest{
Method: "GET",
Path: `/dimension-keys?region=us-east-2&namespace=AWS/EC2&metricName=CPUUtilization&dimensionFilters={"NodeID":["Shared"],"stage":["QueryCommit"]}`,
@@ -135,8 +125,9 @@ func Test_CloudWatch_CallResource_Integration_Test(t *testing.T) {
})
t.Run("Should handle standard dimension key query and return hard coded keys", func(t *testing.T) {
im := defaultTestInstanceManager()
api = mocks.FakeMetricsAPI{}
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(im, &fakeSessionCache{})
req := &backend.CallResourceRequest{
Method: "GET",
@@ -159,9 +150,9 @@ func Test_CloudWatch_CallResource_Integration_Test(t *testing.T) {
})
t.Run("Should handle custom namespace dimension key query and return hard coded keys", func(t *testing.T) {
im := defaultTestInstanceManager()
api = mocks.FakeMetricsAPI{}
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(im, &fakeSessionCache{})
req := &backend.CallResourceRequest{
Method: "GET",
Path: `/dimension-keys?region=us-east-2&namespace=AWS/CloudSearch&metricName=CPUUtilization`,
@@ -183,7 +174,7 @@ func Test_CloudWatch_CallResource_Integration_Test(t *testing.T) {
})
t.Run("Should handle custom namespace metrics query and return metrics from api", func(t *testing.T) {
pageLimit := 3
im := testInstanceManager(3)
api = mocks.FakeMetricsAPI{Metrics: []*cloudwatch.Metric{
{MetricName: aws.String("Test_MetricName1"), Namespace: aws.String("AWS/EC2"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName1")}, {Name: aws.String("Test_DimensionName2")}}},
{MetricName: aws.String("Test_MetricName2"), Namespace: aws.String("AWS/EC2"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName1")}}},
@@ -196,7 +187,7 @@ func Test_CloudWatch_CallResource_Integration_Test(t *testing.T) {
{MetricName: aws.String("Test_MetricName8"), Namespace: aws.String("AWS/EC2"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName4")}}},
{MetricName: aws.String("Test_MetricName9"), Namespace: aws.String("AWS/EC2"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName1")}}},
}, MetricsPerPage: 2}
executor := newExecutor(im, &setting.Cfg{AWSListMetricsPageLimit: pageLimit}, &fakeSessionCache{})
executor := newExecutor(im, &fakeSessionCache{})
req := &backend.CallResourceRequest{
Method: "GET",
@@ -219,6 +210,7 @@ func Test_CloudWatch_CallResource_Integration_Test(t *testing.T) {
})
t.Run("Should handle log group fields request", func(t *testing.T) {
im := defaultTestInstanceManager()
logApi = mocks.LogsAPI{}
logApi.On("GetLogGroupFieldsWithContext", mock.Anything).Return(&cloudwatchlogs.GetLogGroupFieldsOutput{
LogGroupFields: []*cloudwatchlogs.LogGroupField{
@@ -232,7 +224,7 @@ func Test_CloudWatch_CallResource_Integration_Test(t *testing.T) {
},
},
}, nil)
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(im, &fakeSessionCache{})
req := &backend.CallResourceRequest{
Method: "GET",
@@ -253,7 +245,8 @@ func Test_CloudWatch_CallResource_Integration_Test(t *testing.T) {
})
t.Run("Should handle region requests and return regions from the api", func(t *testing.T) {
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{})
im := defaultTestInstanceManager()
executor := newExecutor(im, &fakeSessionCache{})
req := &backend.CallResourceRequest{
Method: "GET",
Path: `/regions`,
@@ -275,10 +268,11 @@ func Test_CloudWatch_CallResource_Integration_Test(t *testing.T) {
imWithoutDefaultRegion := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{
AWSDatasourceSettings: awsds.AWSDatasourceSettings{},
GrafanaSettings: awsds.AuthSettings{ListMetricsPageLimit: 1000},
}}, nil
})
executor := newExecutor(imWithoutDefaultRegion, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(imWithoutDefaultRegion, &fakeSessionCache{})
req := &backend.CallResourceRequest{
Method: "GET",
Path: `/regions`,

View File

@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"testing"
"time"
"github.com/aws/aws-sdk-go/aws"
awsclient "github.com/aws/aws-sdk-go/aws/client"
@@ -16,6 +17,7 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend/datasource"
"github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
"github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt"
"github.com/grafana/grafana-plugin-sdk-go/backend/proxy"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/features"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/mocks"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models"
@@ -26,9 +28,11 @@ import (
)
func TestNewInstanceSettings(t *testing.T) {
ctxDuration := 10 * time.Minute
tests := []struct {
name string
settings backend.DataSourceInstanceSettings
settingCtx context.Context
expectedDS DataSource
Err require.ErrorAssertionFunc
}{
@@ -49,6 +53,14 @@ func TestNewInstanceSettings(t *testing.T) {
"secretKey": "secret",
},
},
settingCtx: backend.WithGrafanaConfig(context.Background(), backend.NewGrafanaCfg(map[string]string{
awsds.AllowedAuthProvidersEnvVarKeyName: "foo , bar,baz",
awsds.AssumeRoleEnabledEnvVarKeyName: "false",
awsds.SessionDurationEnvVarKeyName: "10m",
awsds.GrafanaAssumeRoleExternalIdKeyName: "mock_id",
awsds.ListMetricsPageLimitKeyName: "50",
proxy.PluginSecureSocksProxyEnabled: "true",
})),
expectedDS: DataSource{
Settings: models.CloudWatchSettings{
AWSDatasourceSettings: awsds.AWSDatasourceSettings{
@@ -62,6 +74,14 @@ func TestNewInstanceSettings(t *testing.T) {
SecretKey: "secret",
},
Namespace: "ns",
GrafanaSettings: awsds.AuthSettings{
AllowedAuthProviders: []string{"foo", "bar", "baz"},
AssumeRoleEnabled: false,
SessionDuration: &ctxDuration,
ExternalID: "mock_id",
ListMetricsPageLimit: 50,
SecureSocksDSProxyEnabled: true,
},
},
},
Err: require.NoError,
@@ -71,8 +91,9 @@ func TestNewInstanceSettings(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
f := NewInstanceSettings(httpclient.NewProvider())
model, err := f(context.Background(), tt.settings)
model, err := f(tt.settingCtx, tt.settings)
tt.Err(t, err)
assert.Equal(t, tt.expectedDS.Settings.GrafanaSettings, model.(DataSource).Settings.GrafanaSettings)
datasourceComparer := cmp.Comparer(func(d1 DataSource, d2 DataSource) bool {
return d1.Settings.Profile == d2.Settings.Profile &&
d1.Settings.Region == d2.Settings.Region &&
@@ -109,17 +130,11 @@ func Test_CheckHealth(t *testing.T) {
NewLogsAPI = func(sess *session.Session) models.CloudWatchLogsAPIProvider {
return client
}
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{
AWSDatasourceSettings: awsds.AWSDatasourceSettings{
Region: "us-east-1",
},
}}, nil
})
im := defaultTestInstanceManager()
t.Run("successfully query metrics and logs", func(t *testing.T) {
client = fakeCheckHealthClient{}
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(im, &fakeSessionCache{})
resp, err := executor.CheckHealth(context.Background(), &backend.CheckHealthRequest{
PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}},
@@ -138,7 +153,7 @@ func Test_CheckHealth(t *testing.T) {
return nil, fmt.Errorf("some logs query error")
}}
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(im, &fakeSessionCache{})
resp, err := executor.CheckHealth(context.Background(), &backend.CheckHealthRequest{
PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}},
@@ -157,7 +172,7 @@ func Test_CheckHealth(t *testing.T) {
return fmt.Errorf("some list metrics error")
}}
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(im, &fakeSessionCache{})
resp, err := executor.CheckHealth(context.Background(), &backend.CheckHealthRequest{
PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}},
@@ -173,7 +188,7 @@ func Test_CheckHealth(t *testing.T) {
t.Run("fail to get clients", func(t *testing.T) {
client = fakeCheckHealthClient{}
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{getSession: func(c awsds.SessionConfig) (*session.Session, error) {
executor := newExecutor(im, &fakeSessionCache{getSession: func(c awsds.SessionConfig) (*session.Session, error) {
return nil, fmt.Errorf("some sessions error")
}})
@@ -189,6 +204,37 @@ func Test_CheckHealth(t *testing.T) {
})
}
func TestNewSession_passes_authSettings(t *testing.T) {
ctxDuration := 15 * time.Minute
expectedSettings := awsds.AuthSettings{
AllowedAuthProviders: []string{"foo", "bar", "baz"},
AssumeRoleEnabled: false,
SessionDuration: &ctxDuration,
ExternalID: "mock_id",
ListMetricsPageLimit: 50,
SecureSocksDSProxyEnabled: true,
}
im := datasource.NewInstanceManager((func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{
AWSDatasourceSettings: awsds.AWSDatasourceSettings{
Region: "us-east-1",
},
GrafanaSettings: expectedSettings,
}}, nil
}))
executor := newExecutor(im, &fakeSessionCache{getSession: func(c awsds.SessionConfig) (*session.Session, error) {
assert.NotNil(t, c.AuthSettings)
assert.Equal(t, expectedSettings, *c.AuthSettings)
return &session.Session{
Config: &aws.Config{},
}, nil
}})
_, err := executor.newSession(context.Background(),
backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}}, "us-east-1")
require.NoError(t, err)
}
func TestQuery_ResourceRequest_DescribeLogGroups_with_CrossAccountQuerying(t *testing.T) {
sender := &mockedCallResourceResponseSenderForOauth{}
origNewMetricsAPI := NewMetricsAPI
@@ -210,13 +256,7 @@ func TestQuery_ResourceRequest_DescribeLogGroups_with_CrossAccountQuerying(t *te
return &logsApi
}
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{
AWSDatasourceSettings: awsds.AWSDatasourceSettings{
Region: "us-east-1",
},
}}, nil
})
im := defaultTestInstanceManager()
t.Run("maps log group api response to resource response of log-groups", func(t *testing.T) {
logsApi = mocks.LogsAPI{}
@@ -234,7 +274,7 @@ func TestQuery_ResourceRequest_DescribeLogGroups_with_CrossAccountQuerying(t *te
},
}
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(im, &fakeSessionCache{})
err := executor.CallResource(contextWithFeaturesEnabled(features.FlagCloudWatchCrossAccountQuerying), req, sender)
assert.NoError(t, err)

View File

@@ -16,7 +16,12 @@ import (
// getDimensionValues gets the actual dimension values for dimensions with a wildcard
func (e *cloudWatchExecutor) getDimensionValuesForWildcards(ctx context.Context, pluginCtx backend.PluginContext, region string,
client models.CloudWatchMetricsAPIProvider, origQueries []*models.CloudWatchQuery, tagValueCache *cache.Cache, logger log.Logger) ([]*models.CloudWatchQuery, error) {
metricsClient := clients.NewMetricsClient(client, e.cfg)
instance, err := e.getInstance(ctx, pluginCtx)
if err != nil {
return nil, err
}
metricsClient := clients.NewMetricsClient(client, instance.Settings.GrafanaSettings.ListMetricsPageLimit)
service := services.NewListMetricsService(metricsClient)
// create copies of the original query. All the fields besides Dimensions are primitives
queries := copyQueries(origQueries)

View File

@@ -17,7 +17,7 @@ import (
func TestGetDimensionValuesForWildcards(t *testing.T) {
logger := &logtest.Fake{}
executor := &cloudWatchExecutor{}
executor := &cloudWatchExecutor{im: defaultTestInstanceManager()}
ctx := context.Background()
pluginCtx := backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{ID: 1, Updated: time.Now()},

View File

@@ -90,7 +90,7 @@ func TestQuery_handleGetLogEvents_passes_nil_start_and_end_times_to_GetLogEvents
return DataSource{Settings: models.CloudWatchSettings{}}, nil
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(im, &fakeSessionCache{})
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{},
@@ -123,7 +123,7 @@ func TestQuery_GetLogEvents_returns_response_from_GetLogEvents_to_data_frame_fie
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(im, &fakeSessionCache{})
cli = &mocks.MockLogEvents{}
cli.On("GetLogEventsWithContext", mock.Anything, mock.Anything, mock.Anything).Return(&cloudwatchlogs.GetLogEventsOutput{
@@ -208,7 +208,7 @@ func TestQuery_StartQuery(t *testing.T) {
}}, nil
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(im, &fakeSessionCache{})
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{},
@@ -265,7 +265,7 @@ func TestQuery_StartQuery(t *testing.T) {
}}, nil
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(im, &fakeSessionCache{})
resp, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{},
@@ -322,7 +322,7 @@ func Test_executeStartQuery(t *testing.T) {
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(im, &fakeSessionCache{})
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}},
@@ -358,7 +358,7 @@ func Test_executeStartQuery(t *testing.T) {
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(im, &fakeSessionCache{})
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}},
@@ -384,7 +384,7 @@ func Test_executeStartQuery(t *testing.T) {
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(im, &fakeSessionCache{})
_, err := executor.QueryData(contextWithFeaturesEnabled(features.FlagCloudWatchCrossAccountQuerying), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}},
@@ -420,7 +420,7 @@ func Test_executeStartQuery(t *testing.T) {
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(im, &fakeSessionCache{})
_, err := executor.QueryData(contextWithFeaturesEnabled(features.FlagCloudWatchCrossAccountQuerying), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}},
@@ -456,7 +456,8 @@ func Test_executeStartQuery(t *testing.T) {
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(im, &fakeSessionCache{})
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}},
Queries: []backend.DataQuery{
@@ -491,7 +492,7 @@ func Test_executeStartQuery(t *testing.T) {
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(im, &fakeSessionCache{})
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}},
Queries: []backend.DataQuery{
@@ -525,7 +526,7 @@ func Test_executeStartQuery(t *testing.T) {
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(im, &fakeSessionCache{})
_, err := executor.QueryData(contextWithFeaturesEnabled(features.FlagCloudWatchCrossAccountQuerying), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}},
Queries: []backend.DataQuery{
@@ -596,7 +597,7 @@ func TestQuery_StopQuery(t *testing.T) {
To: time.Unix(1584700643, 0),
}
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(im, &fakeSessionCache{})
resp, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{},
@@ -686,7 +687,7 @@ func TestQuery_GetQueryResults(t *testing.T) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(im, &fakeSessionCache{})
resp, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{},

View File

@@ -40,7 +40,7 @@ func Test_executeSyncLogQuery(t *testing.T) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil
})
sess := fakeSessionCache{}
executor := newExecutor(im, newTestConfig(), &sess)
executor := newExecutor(im, &sess)
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
Headers: map[string]string{headerFromAlert: "some value"},
@@ -67,7 +67,7 @@ func Test_executeSyncLogQuery(t *testing.T) {
})
sess := fakeSessionCache{}
executor := newExecutor(im, newTestConfig(), &sess)
executor := newExecutor(im, &sess)
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
Headers: map[string]string{headerFromAlert: "some value"},
PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}},
@@ -124,7 +124,7 @@ func Test_executeSyncLogQuery(t *testing.T) {
})
sess := fakeSessionCache{}
executor := newExecutor(im, newTestConfig(), &sess)
executor := newExecutor(im, &sess)
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
Headers: tc.headers,
PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}},
@@ -167,7 +167,7 @@ func Test_executeSyncLogQuery(t *testing.T) {
})
sess := fakeSessionCache{}
executor := newExecutor(im, newTestConfig(), &sess)
executor := newExecutor(im, &sess)
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}},
Queries: []backend.DataQuery{
@@ -206,7 +206,7 @@ func Test_executeSyncLogQuery_handles_RefId_from_input_queries(t *testing.T) {
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(im, &fakeSessionCache{})
res, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
Headers: map[string]string{headerFromAlert: "some value"},
@@ -235,7 +235,7 @@ func Test_executeSyncLogQuery_handles_RefId_from_input_queries(t *testing.T) {
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(im, &fakeSessionCache{})
res, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
Headers: map[string]string{headerFromAlert: "some value"},
@@ -304,7 +304,7 @@ func Test_executeSyncLogQuery_handles_RefId_from_input_queries(t *testing.T) {
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(im, &fakeSessionCache{})
res, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
Headers: map[string]string{headerFromAlert: "some value"},
@@ -349,8 +349,7 @@ func Test_executeSyncLogQuery_handles_RefId_from_input_queries(t *testing.T) {
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{LogsTimeout: models.Duration{Duration: time.Millisecond}}}, nil
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(im, &fakeSessionCache{})
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
Headers: map[string]string{headerFromAlert: "some value"},
@@ -382,7 +381,7 @@ func Test_executeSyncLogQuery_handles_RefId_from_input_queries(t *testing.T) {
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(im, &fakeSessionCache{})
res, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
Headers: map[string]string{headerFromAlert: "some value"},

View File

@@ -26,7 +26,7 @@ func TestMetricDataInputBuilder(t *testing.T) {
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
executor := newExecutor(nil, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(nil, &fakeSessionCache{})
query := getBaseQuery()
query.TimezoneUTCOffset = tc.timezoneUTCOffset

View File

@@ -12,7 +12,7 @@ import (
func TestMetricDataQueryBuilder(t *testing.T) {
t.Run("buildMetricDataQuery", func(t *testing.T) {
t.Run("should use metric stat", func(t *testing.T) {
executor := newExecutor(nil, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(nil, &fakeSessionCache{})
query := getBaseQuery()
query.MetricEditorMode = models.MetricEditorModeBuilder
query.MetricQueryType = models.MetricQueryTypeSearch
@@ -24,7 +24,7 @@ func TestMetricDataQueryBuilder(t *testing.T) {
})
t.Run("should pass AccountId in metric stat query", func(t *testing.T) {
executor := newExecutor(nil, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(nil, &fakeSessionCache{})
query := getBaseQuery()
query.MetricEditorMode = models.MetricEditorModeBuilder
query.MetricQueryType = models.MetricQueryTypeSearch
@@ -35,7 +35,7 @@ func TestMetricDataQueryBuilder(t *testing.T) {
})
t.Run("should leave AccountId in metric stat query", func(t *testing.T) {
executor := newExecutor(nil, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(nil, &fakeSessionCache{})
query := getBaseQuery()
query.MetricEditorMode = models.MetricEditorModeBuilder
query.MetricQueryType = models.MetricQueryTypeSearch
@@ -45,7 +45,7 @@ func TestMetricDataQueryBuilder(t *testing.T) {
})
t.Run("should use custom built expression", func(t *testing.T) {
executor := newExecutor(nil, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(nil, &fakeSessionCache{})
query := getBaseQuery()
query.MetricEditorMode = models.MetricEditorModeBuilder
query.MetricQueryType = models.MetricQueryTypeSearch
@@ -57,7 +57,7 @@ func TestMetricDataQueryBuilder(t *testing.T) {
})
t.Run("should use sql expression", func(t *testing.T) {
executor := newExecutor(nil, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(nil, &fakeSessionCache{})
query := getBaseQuery()
query.MetricEditorMode = models.MetricEditorModeRaw
query.MetricQueryType = models.MetricQueryTypeQuery
@@ -69,7 +69,7 @@ func TestMetricDataQueryBuilder(t *testing.T) {
})
t.Run("should use user defined math expression", func(t *testing.T) {
executor := newExecutor(nil, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(nil, &fakeSessionCache{})
query := getBaseQuery()
query.MetricEditorMode = models.MetricEditorModeRaw
query.MetricQueryType = models.MetricQueryTypeSearch
@@ -81,7 +81,7 @@ func TestMetricDataQueryBuilder(t *testing.T) {
})
t.Run("should set period in user defined expression", func(t *testing.T) {
executor := newExecutor(nil, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(nil, &fakeSessionCache{})
query := getBaseQuery()
query.MetricEditorMode = models.MetricEditorModeRaw
query.MetricQueryType = models.MetricQueryTypeSearch
@@ -95,7 +95,7 @@ func TestMetricDataQueryBuilder(t *testing.T) {
})
t.Run("should set label", func(t *testing.T) {
executor := newExecutor(nil, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(nil, &fakeSessionCache{})
query := getBaseQuery()
query.Label = "some label"
@@ -107,7 +107,7 @@ func TestMetricDataQueryBuilder(t *testing.T) {
})
t.Run("should not set label for empty string query label", func(t *testing.T) {
executor := newExecutor(nil, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(nil, &fakeSessionCache{})
query := getBaseQuery()
query.Label = ""
@@ -118,7 +118,7 @@ func TestMetricDataQueryBuilder(t *testing.T) {
})
t.Run(`should not specify accountId when it is "all"`, func(t *testing.T) {
executor := newExecutor(nil, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(nil, &fakeSessionCache{})
query := &models.CloudWatchQuery{
Namespace: "AWS/EC2",
MetricName: "CPUUtilization",
@@ -136,7 +136,7 @@ func TestMetricDataQueryBuilder(t *testing.T) {
})
t.Run("should set accountId when it is specified", func(t *testing.T) {
executor := newExecutor(nil, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(nil, &fakeSessionCache{})
query := &models.CloudWatchQuery{
Namespace: "AWS/EC2",
MetricName: "CPUUtilization",

View File

@@ -47,10 +47,13 @@ func TestQuery_Regions(t *testing.T) {
}, nil)
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{AWSDatasourceSettings: awsds.AWSDatasourceSettings{Region: "us-east-2"}}}, nil
return DataSource{Settings: models.CloudWatchSettings{
AWSDatasourceSettings: awsds.AWSDatasourceSettings{Region: "us-east-2"},
GrafanaSettings: awsds.AuthSettings{ListMetricsPageLimit: 1000},
}}, nil
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(im, &fakeSessionCache{})
resp, err := executor.handleGetRegions(
context.Background(),
backend.PluginContext{
@@ -104,12 +107,15 @@ func Test_handleGetRegions_regionCache(t *testing.T) {
return &cli
}
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{AWSDatasourceSettings: awsds.AWSDatasourceSettings{Region: "us-east-2"}}}, nil
return DataSource{Settings: models.CloudWatchSettings{
AWSDatasourceSettings: awsds.AWSDatasourceSettings{Region: "us-east-2"},
GrafanaSettings: awsds.AuthSettings{ListMetricsPageLimit: 1000},
}}, nil
})
t.Run("AWS only called once for multiple calls to handleGetRegions", func(t *testing.T) {
cli.On("DescribeRegionsWithContext", mock.Anything, mock.Anything).Return(&ec2.DescribeRegionsOutput{}, nil)
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(im, &fakeSessionCache{})
_, err := executor.handleGetRegions(
context.Background(),
backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}}, nil)
@@ -165,7 +171,7 @@ func TestQuery_InstanceAttributes(t *testing.T) {
filterJson, err := json.Marshal(filterMap)
require.NoError(t, err)
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(im, &fakeSessionCache{})
resp, err := executor.handleGetEc2InstanceAttribute(
context.Background(),
backend.PluginContext{
@@ -243,7 +249,7 @@ func TestQuery_EBSVolumeIDs(t *testing.T) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(im, &fakeSessionCache{})
resp, err := executor.handleGetEbsVolumeIds(
context.Background(),
backend.PluginContext{
@@ -310,7 +316,7 @@ func TestQuery_ResourceARNs(t *testing.T) {
tagJson, err := json.Marshal(tagMap)
require.NoError(t, err)
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(im, &fakeSessionCache{})
resp, err := executor.handleGetResourceArns(
context.Background(),
backend.PluginContext{

View File

@@ -1,6 +1,7 @@
package models
import (
"context"
"encoding/json"
"fmt"
"time"
@@ -17,9 +18,12 @@ type CloudWatchSettings struct {
Namespace string `json:"customMetricsNamespaces"`
SecureSocksProxyEnabled bool `json:"enableSecureSocksProxy"` // this can be removed when https://github.com/grafana/grafana/issues/39089 is implemented
LogsTimeout Duration `json:"logsTimeout"`
// GrafanaSettings are fetched from the GrafanaCfg in the context
GrafanaSettings awsds.AuthSettings `json:"-"`
}
func LoadCloudWatchSettings(config backend.DataSourceInstanceSettings) (CloudWatchSettings, error) {
func LoadCloudWatchSettings(ctx context.Context, config backend.DataSourceInstanceSettings) (CloudWatchSettings, error) {
instance := CloudWatchSettings{}
if config.JSONData != nil && len(config.JSONData) > 1 {
if err := json.Unmarshal(config.JSONData, &instance); err != nil {
@@ -43,6 +47,7 @@ func LoadCloudWatchSettings(config backend.DataSourceInstanceSettings) (CloudWat
instance.AccessKey = config.DecryptedSecureJSONData["accessKey"]
instance.SecretKey = config.DecryptedSecureJSONData["secretKey"]
instance.GrafanaSettings = *awsds.ReadAuthSettings(ctx)
return instance, nil
}

View File

@@ -1,16 +1,23 @@
package models
import (
"context"
"testing"
"time"
"github.com/grafana/grafana-aws-sdk/pkg/awsds"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/backend/proxy"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func Test_Settings_LoadCloudWatchSettings(t *testing.T) {
settingCtx := backend.WithGrafanaConfig(context.Background(), backend.NewGrafanaCfg(map[string]string{
awsds.AllowedAuthProvidersEnvVarKeyName: "default,keys,credentials",
awsds.AssumeRoleEnabledEnvVarKeyName: "false",
awsds.SessionDurationEnvVarKeyName: "10m",
}))
t.Run("Should return error for invalid json", func(t *testing.T) {
settings := backend.DataSourceInstanceSettings{
ID: 33,
@@ -25,7 +32,7 @@ func Test_Settings_LoadCloudWatchSettings(t *testing.T) {
},
}
_, err := LoadCloudWatchSettings(settings)
_, err := LoadCloudWatchSettings(settingCtx, settings)
assert.Error(t, err)
})
@@ -47,7 +54,7 @@ func Test_Settings_LoadCloudWatchSettings(t *testing.T) {
},
}
s, err := LoadCloudWatchSettings(settings)
s, err := LoadCloudWatchSettings(settingCtx, settings)
require.NoError(t, err)
assert.Equal(t, awsds.AuthTypeKeys, s.AuthType)
assert.Equal(t, "arn:aws:iam::123456789012:role/grafana", s.AssumeRoleARN)
@@ -78,7 +85,7 @@ func Test_Settings_LoadCloudWatchSettings(t *testing.T) {
},
}
s, err := LoadCloudWatchSettings(settings)
s, err := LoadCloudWatchSettings(settingCtx, settings)
require.NoError(t, err)
assert.Equal(t, awsds.AuthTypeDefault, s.AuthType)
assert.Equal(t, "arn:aws:iam::123456789012:role/grafana", s.AssumeRoleARN)
@@ -103,7 +110,7 @@ func Test_Settings_LoadCloudWatchSettings(t *testing.T) {
},
}
s, err := LoadCloudWatchSettings(settings)
s, err := LoadCloudWatchSettings(settingCtx, settings)
require.NoError(t, err)
assert.Equal(t, time.Minute*30, s.LogsTimeout.Duration)
})
@@ -121,7 +128,7 @@ func Test_Settings_LoadCloudWatchSettings(t *testing.T) {
},
}
s, err := LoadCloudWatchSettings(settings)
s, err := LoadCloudWatchSettings(settingCtx, settings)
require.NoError(t, err)
assert.Equal(t, time.Minute*10, s.LogsTimeout.Duration)
})
@@ -139,7 +146,7 @@ func Test_Settings_LoadCloudWatchSettings(t *testing.T) {
},
}
s, err := LoadCloudWatchSettings(settings)
s, err := LoadCloudWatchSettings(settingCtx, settings)
require.NoError(t, err)
assert.Equal(t, time.Duration(1500000000), s.LogsTimeout.Duration)
})
@@ -157,7 +164,7 @@ func Test_Settings_LoadCloudWatchSettings(t *testing.T) {
},
}
s, err := LoadCloudWatchSettings(settings)
s, err := LoadCloudWatchSettings(settingCtx, settings)
require.NoError(t, err)
assert.Equal(t, 1500*time.Millisecond, s.LogsTimeout.Duration)
})
@@ -175,7 +182,7 @@ func Test_Settings_LoadCloudWatchSettings(t *testing.T) {
},
}
_, err := LoadCloudWatchSettings(settings)
_, err := LoadCloudWatchSettings(context.Background(), settings)
require.Error(t, err)
})
t.Run("Should throw error if logsTimeout is an invalid type", func(t *testing.T) {
@@ -192,7 +199,42 @@ func Test_Settings_LoadCloudWatchSettings(t *testing.T) {
},
}
_, err := LoadCloudWatchSettings(settings)
_, err := LoadCloudWatchSettings(settingCtx, settings)
require.Error(t, err)
})
t.Run("Should load settings from context", func(t *testing.T) {
settingCtx := backend.WithGrafanaConfig(context.Background(), backend.NewGrafanaCfg(map[string]string{
awsds.AllowedAuthProvidersEnvVarKeyName: "foo , bar,baz",
awsds.AssumeRoleEnabledEnvVarKeyName: "false",
awsds.SessionDurationEnvVarKeyName: "10m",
awsds.GrafanaAssumeRoleExternalIdKeyName: "mock_id",
awsds.ListMetricsPageLimitKeyName: "50",
proxy.PluginSecureSocksProxyEnabled: "true",
}))
settings := backend.DataSourceInstanceSettings{
ID: 33,
JSONData: []byte(`{
"authType": "arn",
"assumeRoleArn": "arn:aws:iam::123456789012:role/grafana"
}`),
DecryptedSecureJSONData: map[string]string{
"accessKey": "AKIAIOSFODNN7EXAMPLE",
"secretKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
},
}
s, err := LoadCloudWatchSettings(settingCtx, settings)
require.NoError(t, err)
ctxDuration := 10 * time.Minute
expectedGrafanaSettings := awsds.AuthSettings{
AllowedAuthProviders: []string{"foo", "bar", "baz"},
AssumeRoleEnabled: false,
SessionDuration: &ctxDuration,
ExternalID: "mock_id",
ListMetricsPageLimit: 50,
SecureSocksDSProxyEnabled: true,
}
assert.Equal(t, expectedGrafanaSettings, s.GrafanaSettings)
})
}

View File

@@ -17,8 +17,10 @@ import (
"github.com/aws/aws-sdk-go/service/resourcegroupstaggingapi/resourcegroupstaggingapiiface"
"github.com/grafana/grafana-aws-sdk/pkg/awsds"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/backend/datasource"
"github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt"
"github.com/grafana/grafana-plugin-sdk-go/experimental/featuretoggles"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models"
"github.com/stretchr/testify/mock"
)
@@ -214,8 +216,19 @@ func (c fakeCheckHealthClient) GetLogGroupFieldsWithContext(ctx context.Context,
return nil, nil
}
func newTestConfig() *setting.Cfg {
return &setting.Cfg{AWSAllowedAuthProviders: []string{"default"}, AWSAssumeRoleEnabled: true, AWSListMetricsPageLimit: 1000}
func testInstanceManager(pageLimit int) instancemgmt.InstanceManager {
return datasource.NewInstanceManager((func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{
AWSDatasourceSettings: awsds.AWSDatasourceSettings{
Region: "us-east-1",
},
GrafanaSettings: awsds.AuthSettings{ListMetricsPageLimit: pageLimit},
}}, nil
}))
}
func defaultTestInstanceManager() instancemgmt.InstanceManager {
return testInstanceManager(1000)
}
type mockSessionCache struct {

View File

@@ -26,7 +26,7 @@ import (
)
func TestTimeSeriesQuery(t *testing.T) {
executor := newExecutor(nil, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(nil, &fakeSessionCache{})
now := time.Now()
origNewCWClient := NewCWClient
@@ -50,11 +50,9 @@ func TestTimeSeriesQuery(t *testing.T) {
StatusCode: aws.String("Complete"), Id: aws.String("b"), Label: aws.String("NetworkIn"), Values: []*float64{aws.Float64(1.0)}, Timestamps: []*time.Time{&now},
}}}, nil)
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil
})
im := defaultTestInstanceManager()
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(im, &fakeSessionCache{})
resp, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{},
@@ -160,7 +158,7 @@ func Test_executeTimeSeriesQuery_getCWClient_is_called_once_per_region_and_GetMe
mockMetricClient = mocks.MetricsAPI{}
mockMetricClient.On("GetMetricDataWithContext", mock.Anything, mock.Anything, mock.Anything).Return(nil, nil)
executor := newExecutor(im, newTestConfig(), mockSessionCache)
executor := newExecutor(im, mockSessionCache)
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{},
@@ -211,7 +209,7 @@ func Test_executeTimeSeriesQuery_getCWClient_is_called_once_per_region_and_GetMe
mockMetricClient = mocks.MetricsAPI{}
mockMetricClient.On("GetMetricDataWithContext", mock.Anything, mock.Anything, mock.Anything).Return(nil, nil)
executor := newExecutor(im, newTestConfig(), sessionCache)
executor := newExecutor(im, sessionCache)
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{},
@@ -344,7 +342,7 @@ func Test_QueryData_timeSeriesQuery_GetMetricDataWithContext(t *testing.T) {
t.Run("passes query label as GetMetricData label", func(t *testing.T) {
api = mocks.MetricsAPI{}
api.On("GetMetricDataWithContext", mock.Anything, mock.Anything, mock.Anything).Return(&cloudwatch.GetMetricDataOutput{}, nil)
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(im, &fakeSessionCache{})
query := newTestQuery(t, queryParameters{
Label: aws.String("${PROP('Period')} some words ${PROP('Dim.InstanceId')}"),
})
@@ -383,7 +381,7 @@ func Test_QueryData_timeSeriesQuery_GetMetricDataWithContext(t *testing.T) {
t.Run(name, func(t *testing.T) {
api = mocks.MetricsAPI{}
api.On("GetMetricDataWithContext", mock.Anything, mock.Anything, mock.Anything).Return(&cloudwatch.GetMetricDataOutput{}, nil)
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(im, &fakeSessionCache{})
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}},
@@ -433,10 +431,8 @@ func Test_QueryData_response_data_frame_name_is_always_response_label(t *testing
Values: []*float64{aws.Float64(1.0)}, Timestamps: []*time.Time{{}}},
}}, nil)
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{})
im := defaultTestInstanceManager()
executor := newExecutor(im, &fakeSessionCache{})
t.Run("where user defines search expression", func(t *testing.T) {
query := newTestQuery(t, queryParameters{
@@ -588,14 +584,12 @@ func TestTimeSeriesQuery_CrossAccountQuerying(t *testing.T) {
NewCWClient = func(sess *session.Session) cloudwatchiface.CloudWatchAPI {
return &api
}
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil
})
im := defaultTestInstanceManager()
t.Run("should call GetMetricDataInput with AccountId nil when no AccountId is provided", func(t *testing.T) {
api = mocks.MetricsAPI{}
api.On("GetMetricDataWithContext", mock.Anything, mock.Anything, mock.Anything).Return(&cloudwatch.GetMetricDataOutput{}, nil)
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(im, &fakeSessionCache{})
_, err := executor.QueryData(contextWithFeaturesEnabled(features.FlagCloudWatchCrossAccountQuerying), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{
@@ -636,7 +630,7 @@ func TestTimeSeriesQuery_CrossAccountQuerying(t *testing.T) {
t.Run("should call GetMetricDataInput with AccountId nil when feature flag is false", func(t *testing.T) {
api = mocks.MetricsAPI{}
api.On("GetMetricDataWithContext", mock.Anything, mock.Anything, mock.Anything).Return(&cloudwatch.GetMetricDataOutput{}, nil)
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(im, &fakeSessionCache{})
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{},
@@ -677,7 +671,7 @@ func TestTimeSeriesQuery_CrossAccountQuerying(t *testing.T) {
t.Run("should call GetMetricDataInput with AccountId in a MetricStat query", func(t *testing.T) {
api = mocks.MetricsAPI{}
api.On("GetMetricDataWithContext", mock.Anything, mock.Anything, mock.Anything).Return(&cloudwatch.GetMetricDataOutput{}, nil)
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(im, &fakeSessionCache{})
_, err := executor.QueryData(contextWithFeaturesEnabled(features.FlagCloudWatchCrossAccountQuerying), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{},
@@ -718,7 +712,7 @@ func TestTimeSeriesQuery_CrossAccountQuerying(t *testing.T) {
t.Run("should GetMetricDataInput with AccountId in an inferred search expression query", func(t *testing.T) {
api = mocks.MetricsAPI{}
api.On("GetMetricDataWithContext", mock.Anything, mock.Anything, mock.Anything).Return(&cloudwatch.GetMetricDataOutput{}, nil)
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{})
executor := newExecutor(im, &fakeSessionCache{})
_, err := executor.QueryData(contextWithFeaturesEnabled(features.FlagCloudWatchCrossAccountQuerying), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{},