mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
move describe log groups to resource api (#55485)
This commit is contained in:
parent
79a5e3e802
commit
28ebdf1641
@ -56,7 +56,7 @@ exports[`no enzyme tests`] = {
|
||||
"public/app/features/dimensions/editors/ThresholdsEditor/ThresholdsEditor.test.tsx:145048794": [
|
||||
[0, 17, 13, "RegExp match", "2409514259"]
|
||||
],
|
||||
"public/app/plugins/datasource/cloudwatch/components/ConfigEditor.test.tsx:2210656642": [
|
||||
"public/app/plugins/datasource/cloudwatch/components/ConfigEditor.test.tsx:2983010995": [
|
||||
[1, 19, 13, "RegExp match", "2409514259"]
|
||||
]
|
||||
}`
|
||||
@ -5890,15 +5890,6 @@ exports[`better eslint`] = {
|
||||
"public/app/plugins/datasource/cloudwatch/__mocks__/monarch/Monaco.ts:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||
],
|
||||
"public/app/plugins/datasource/cloudwatch/api.ts:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "2"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "3"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "4"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "5"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "6"]
|
||||
],
|
||||
"public/app/plugins/datasource/cloudwatch/components/ConfigEditor.test.tsx:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||
],
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"time"
|
||||
|
||||
@ -82,7 +83,6 @@ const (
|
||||
|
||||
var plog = log.New("tsdb.cloudwatch")
|
||||
var aliasFormat = regexp.MustCompile(`\{\{\s*(.+?)\s*\}\}`)
|
||||
var baseLimit = int64(1)
|
||||
|
||||
func ProvideService(cfg *setting.Cfg, httpClientProvider httpclient.Provider, features featuremgmt.FeatureToggles) *CloudWatchService {
|
||||
plog.Debug("initing")
|
||||
@ -203,17 +203,12 @@ func (e *cloudWatchExecutor) checkHealthMetrics(pluginCtx backend.PluginContext)
|
||||
return err
|
||||
}
|
||||
|
||||
func (e *cloudWatchExecutor) checkHealthLogs(ctx context.Context, pluginCtx backend.PluginContext) error {
|
||||
logsClient, err := e.getCWLogsClient(pluginCtx, defaultRegion)
|
||||
if err != nil {
|
||||
return err
|
||||
func (e *cloudWatchExecutor) checkHealthLogs(pluginCtx backend.PluginContext) error {
|
||||
parameters := url.Values{
|
||||
"limit": []string{"1"},
|
||||
}
|
||||
|
||||
parameters := LogQueryJson{
|
||||
Limit: &baseLimit,
|
||||
}
|
||||
|
||||
_, err = e.handleDescribeLogGroups(ctx, logsClient, parameters)
|
||||
_, err := e.handleGetLogGroups(pluginCtx, parameters)
|
||||
return err
|
||||
}
|
||||
|
||||
@ -228,7 +223,7 @@ func (e *cloudWatchExecutor) CheckHealth(ctx context.Context, req *backend.Check
|
||||
metricsTest = fmt.Sprintf("CloudWatch metrics query failed: %s", err.Error())
|
||||
}
|
||||
|
||||
err = e.checkHealthLogs(ctx, req.PluginContext)
|
||||
err = e.checkHealthLogs(req.PluginContext)
|
||||
if err != nil {
|
||||
status = backend.HealthStatusError
|
||||
logsTest = fmt.Sprintf("CloudWatch logs query failed: %s", err.Error())
|
||||
|
@ -4,11 +4,11 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
awsrequest "github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/cloudwatch"
|
||||
"github.com/aws/aws-sdk-go/service/cloudwatch/cloudwatchiface"
|
||||
@ -124,8 +124,7 @@ func Test_CheckHealth(t *testing.T) {
|
||||
|
||||
t.Run("successfully queries metrics, fails during logs query", func(t *testing.T) {
|
||||
client = fakeCheckHealthClient{
|
||||
describeLogGroupsWithContext: func(ctx aws.Context, input *cloudwatchlogs.DescribeLogGroupsInput,
|
||||
options ...awsrequest.Option) (*cloudwatchlogs.DescribeLogGroupsOutput, error) {
|
||||
describeLogGroups: func(input *cloudwatchlogs.DescribeLogGroupsInput) (*cloudwatchlogs.DescribeLogGroupsOutput, error) {
|
||||
return nil, fmt.Errorf("some logs query error")
|
||||
}}
|
||||
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
@ -248,3 +247,140 @@ func Test_executeLogAlertQuery(t *testing.T) {
|
||||
assert.Equal(t, []string{"instance manager's region"}, sess.calledRegions)
|
||||
})
|
||||
}
|
||||
|
||||
func TestQuery_ResourceRequest_DescribeLogGroups(t *testing.T) {
|
||||
origNewCWLogsClient := NewCWLogsClient
|
||||
t.Cleanup(func() {
|
||||
NewCWLogsClient = origNewCWLogsClient
|
||||
})
|
||||
|
||||
var cli fakeCWLogsClient
|
||||
|
||||
NewCWLogsClient = func(sess *session.Session) cloudwatchlogsiface.CloudWatchLogsAPI {
|
||||
return &cli
|
||||
}
|
||||
|
||||
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return datasourceInfo{}, nil
|
||||
})
|
||||
|
||||
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}, featuremgmt.WithFeatures())
|
||||
sender := &mockedCallResourceResponseSenderForOauth{}
|
||||
|
||||
t.Run("Should map log groups to SuggestData response", func(t *testing.T) {
|
||||
cli = fakeCWLogsClient{
|
||||
logGroups: []cloudwatchlogs.DescribeLogGroupsOutput{
|
||||
{LogGroups: []*cloudwatchlogs.LogGroup{
|
||||
{
|
||||
LogGroupName: aws.String("group_a"),
|
||||
},
|
||||
{
|
||||
LogGroupName: aws.String("group_b"),
|
||||
},
|
||||
{
|
||||
LogGroupName: aws.String("group_c"),
|
||||
},
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
req := &backend.CallResourceRequest{
|
||||
Method: "GET",
|
||||
Path: "/log-groups",
|
||||
PluginContext: backend.PluginContext{
|
||||
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{
|
||||
ID: 0,
|
||||
},
|
||||
PluginID: "cloudwatch",
|
||||
},
|
||||
}
|
||||
err := executor.CallResource(context.Background(), req, sender)
|
||||
|
||||
require.NoError(t, err)
|
||||
sent := sender.Response
|
||||
require.NotNil(t, sent)
|
||||
require.Equal(t, http.StatusOK, sent.Status)
|
||||
|
||||
suggestDataResponse := []suggestData{}
|
||||
err = json.Unmarshal(sent.Body, &suggestDataResponse)
|
||||
require.Nil(t, err)
|
||||
|
||||
assert.Equal(t, []suggestData{
|
||||
{Text: "group_a", Value: "group_a", Label: "group_a"}, {Text: "group_b", Value: "group_b", Label: "group_b"}, {Text: "group_c", Value: "group_c", Label: "group_c"}}, suggestDataResponse)
|
||||
})
|
||||
|
||||
t.Run("Should call api with LogGroupNamePrefix if passed in resource call", func(t *testing.T) {
|
||||
cli = fakeCWLogsClient{
|
||||
logGroups: []cloudwatchlogs.DescribeLogGroupsOutput{
|
||||
{LogGroups: []*cloudwatchlogs.LogGroup{}},
|
||||
},
|
||||
}
|
||||
|
||||
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return datasourceInfo{}, nil
|
||||
})
|
||||
|
||||
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}, featuremgmt.WithFeatures())
|
||||
|
||||
req := &backend.CallResourceRequest{
|
||||
Method: "GET",
|
||||
Path: "/log-groups?logGroupNamePrefix=test",
|
||||
PluginContext: backend.PluginContext{
|
||||
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{
|
||||
ID: 0,
|
||||
},
|
||||
PluginID: "cloudwatch",
|
||||
},
|
||||
}
|
||||
err := executor.CallResource(context.Background(), req, sender)
|
||||
|
||||
require.NoError(t, err)
|
||||
sent := sender.Response
|
||||
require.NotNil(t, sent)
|
||||
require.Equal(t, http.StatusOK, sent.Status)
|
||||
|
||||
assert.Equal(t, []*cloudwatchlogs.DescribeLogGroupsInput{
|
||||
{
|
||||
Limit: aws.Int64(defaultLogGroupLimit),
|
||||
LogGroupNamePrefix: aws.String("test"),
|
||||
},
|
||||
}, cli.calls.describeLogGroups)
|
||||
})
|
||||
|
||||
t.Run("Should call api without LogGroupNamePrefix if not passed in resource call", func(t *testing.T) {
|
||||
cli = fakeCWLogsClient{
|
||||
logGroups: []cloudwatchlogs.DescribeLogGroupsOutput{
|
||||
{LogGroups: []*cloudwatchlogs.LogGroup{}},
|
||||
},
|
||||
}
|
||||
|
||||
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return datasourceInfo{}, nil
|
||||
})
|
||||
|
||||
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}, featuremgmt.WithFeatures())
|
||||
|
||||
req := &backend.CallResourceRequest{
|
||||
Method: "GET",
|
||||
Path: "/log-groups?limit=100",
|
||||
PluginContext: backend.PluginContext{
|
||||
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{
|
||||
ID: 0,
|
||||
},
|
||||
PluginID: "cloudwatch",
|
||||
},
|
||||
}
|
||||
err := executor.CallResource(context.Background(), req, sender)
|
||||
|
||||
require.NoError(t, err)
|
||||
sent := sender.Response
|
||||
require.NotNil(t, sent)
|
||||
require.Equal(t, http.StatusOK, sent.Status)
|
||||
|
||||
assert.Equal(t, []*cloudwatchlogs.DescribeLogGroupsInput{
|
||||
{
|
||||
Limit: aws.Int64(100),
|
||||
},
|
||||
}, cli.calls.describeLogGroups)
|
||||
})
|
||||
}
|
||||
|
@ -126,8 +126,6 @@ func (e *cloudWatchExecutor) executeLogAction(ctx context.Context, model LogQuer
|
||||
|
||||
var data *data.Frame = nil
|
||||
switch model.SubType {
|
||||
case "DescribeLogGroups":
|
||||
data, err = e.handleDescribeLogGroups(ctx, logsClient, model)
|
||||
case "DescribeAllLogGroups":
|
||||
data, err = e.handleDescribeAllLogGroups(ctx, logsClient, model)
|
||||
case "GetLogGroupFields":
|
||||
@ -203,40 +201,6 @@ func (e *cloudWatchExecutor) handleGetLogEvents(ctx context.Context, logsClient
|
||||
return data.NewFrame("logEvents", timestampField, messageField), nil
|
||||
}
|
||||
|
||||
func (e *cloudWatchExecutor) handleDescribeLogGroups(ctx context.Context,
|
||||
logsClient cloudwatchlogsiface.CloudWatchLogsAPI, parameters LogQueryJson) (*data.Frame, error) {
|
||||
logGroupLimit := defaultLogGroupLimit
|
||||
if parameters.Limit != nil && *parameters.Limit != 0 {
|
||||
logGroupLimit = *parameters.Limit
|
||||
}
|
||||
|
||||
var response *cloudwatchlogs.DescribeLogGroupsOutput = nil
|
||||
var err error
|
||||
if len(parameters.LogGroupNamePrefix) == 0 {
|
||||
response, err = logsClient.DescribeLogGroupsWithContext(ctx, &cloudwatchlogs.DescribeLogGroupsInput{
|
||||
Limit: aws.Int64(logGroupLimit),
|
||||
})
|
||||
} else {
|
||||
response, err = logsClient.DescribeLogGroupsWithContext(ctx, &cloudwatchlogs.DescribeLogGroupsInput{
|
||||
Limit: aws.Int64(logGroupLimit),
|
||||
LogGroupNamePrefix: aws.String(parameters.LogGroupNamePrefix),
|
||||
})
|
||||
}
|
||||
if err != nil || response == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
logGroupNames := make([]*string, 0)
|
||||
for _, logGroup := range response.LogGroups {
|
||||
logGroupNames = append(logGroupNames, logGroup.LogGroupName)
|
||||
}
|
||||
|
||||
groupNamesField := data.NewField("logGroupName", nil, logGroupNames)
|
||||
frame := data.NewFrame("logGroups", groupNamesField)
|
||||
|
||||
return frame, nil
|
||||
}
|
||||
|
||||
func (e *cloudWatchExecutor) handleDescribeAllLogGroups(ctx context.Context, logsClient cloudwatchlogsiface.CloudWatchLogsAPI, parameters LogQueryJson) (*data.Frame, error) {
|
||||
var namePrefix, nextToken *string
|
||||
if len(parameters.LogGroupNamePrefix) != 0 {
|
||||
|
@ -106,133 +106,6 @@ func TestQuery_GetLogEvents(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestQuery_DescribeLogGroups(t *testing.T) {
|
||||
origNewCWLogsClient := NewCWLogsClient
|
||||
t.Cleanup(func() {
|
||||
NewCWLogsClient = origNewCWLogsClient
|
||||
})
|
||||
|
||||
var cli fakeCWLogsClient
|
||||
|
||||
NewCWLogsClient = func(sess *session.Session) cloudwatchlogsiface.CloudWatchLogsAPI {
|
||||
return &cli
|
||||
}
|
||||
|
||||
t.Run("Empty log group name prefix", func(t *testing.T) {
|
||||
cli = fakeCWLogsClient{
|
||||
logGroups: []cloudwatchlogs.DescribeLogGroupsOutput{
|
||||
{LogGroups: []*cloudwatchlogs.LogGroup{
|
||||
{
|
||||
LogGroupName: aws.String("group_a"),
|
||||
},
|
||||
{
|
||||
LogGroupName: aws.String("group_b"),
|
||||
},
|
||||
{
|
||||
LogGroupName: aws.String("group_c"),
|
||||
},
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return datasourceInfo{}, nil
|
||||
})
|
||||
|
||||
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}, featuremgmt.WithFeatures())
|
||||
resp, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
|
||||
PluginContext: backend.PluginContext{
|
||||
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{},
|
||||
},
|
||||
Queries: []backend.DataQuery{
|
||||
{
|
||||
JSON: json.RawMessage(`{
|
||||
"type": "logAction",
|
||||
"subtype": "DescribeLogGroups",
|
||||
"limit": 50
|
||||
}`),
|
||||
},
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, resp)
|
||||
|
||||
assert.Equal(t, &backend.QueryDataResponse{Responses: backend.Responses{
|
||||
"": backend.DataResponse{
|
||||
Frames: data.Frames{
|
||||
&data.Frame{
|
||||
Name: "logGroups",
|
||||
Fields: []*data.Field{
|
||||
data.NewField("logGroupName", nil, []*string{
|
||||
aws.String("group_a"), aws.String("group_b"), aws.String("group_c"),
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}, resp)
|
||||
})
|
||||
|
||||
t.Run("Non-empty log group name prefix", func(t *testing.T) {
|
||||
cli = fakeCWLogsClient{
|
||||
logGroups: []cloudwatchlogs.DescribeLogGroupsOutput{
|
||||
{LogGroups: []*cloudwatchlogs.LogGroup{
|
||||
{
|
||||
LogGroupName: aws.String("group_a"),
|
||||
},
|
||||
{
|
||||
LogGroupName: aws.String("group_b"),
|
||||
},
|
||||
{
|
||||
LogGroupName: aws.String("group_c"),
|
||||
},
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return datasourceInfo{}, nil
|
||||
})
|
||||
|
||||
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}, featuremgmt.WithFeatures())
|
||||
resp, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
|
||||
PluginContext: backend.PluginContext{
|
||||
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{},
|
||||
},
|
||||
Queries: []backend.DataQuery{
|
||||
{
|
||||
JSON: json.RawMessage(`{
|
||||
"type": "logAction",
|
||||
"subtype": "DescribeLogGroups",
|
||||
"limit": 50,
|
||||
"region": "default",
|
||||
"logGroupNamePrefix": "g"
|
||||
}`),
|
||||
},
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, resp)
|
||||
|
||||
assert.Equal(t, &backend.QueryDataResponse{Responses: backend.Responses{
|
||||
"": backend.DataResponse{
|
||||
Frames: data.Frames{
|
||||
&data.Frame{
|
||||
Name: "logGroups",
|
||||
Fields: []*data.Field{
|
||||
data.NewField("logGroupName", nil, []*string{
|
||||
aws.String("group_a"), aws.String("group_b"), aws.String("group_c"),
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}, resp)
|
||||
})
|
||||
}
|
||||
|
||||
func TestQuery_DescribeAllLogGroups(t *testing.T) {
|
||||
origNewCWLogsClient := NewCWLogsClient
|
||||
t.Cleanup(func() {
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"net/url"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
@ -14,6 +15,7 @@ import (
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awsutil"
|
||||
"github.com/aws/aws-sdk-go/service/cloudwatch"
|
||||
"github.com/aws/aws-sdk-go/service/cloudwatchlogs"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/aws/aws-sdk-go/service/resourcegroupstaggingapi"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
@ -649,6 +651,41 @@ func (e *cloudWatchExecutor) getDimensionsForCustomMetrics(region, namespace str
|
||||
return customMetricsDimensionsMap[dsInfo.profile][dsInfo.region][namespace].Cache, nil
|
||||
}
|
||||
|
||||
func (e *cloudWatchExecutor) handleGetLogGroups(pluginCtx backend.PluginContext, parameters url.Values) ([]suggestData, error) {
|
||||
region := parameters.Get("region")
|
||||
limit := parameters.Get("limit")
|
||||
logGroupNamePrefix := parameters.Get("logGroupNamePrefix")
|
||||
|
||||
logsClient, err := e.getCWLogsClient(pluginCtx, region)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
logGroupLimit := defaultLogGroupLimit
|
||||
intLimit, err := strconv.ParseInt(limit, 10, 64)
|
||||
if err == nil && intLimit > 0 {
|
||||
logGroupLimit = intLimit
|
||||
}
|
||||
|
||||
var response *cloudwatchlogs.DescribeLogGroupsOutput = nil
|
||||
input := &cloudwatchlogs.DescribeLogGroupsInput{Limit: aws.Int64(logGroupLimit)}
|
||||
if len(logGroupNamePrefix) > 0 {
|
||||
input.LogGroupNamePrefix = aws.String(logGroupNamePrefix)
|
||||
}
|
||||
response, err = logsClient.DescribeLogGroups(input)
|
||||
if err != nil || response == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make([]suggestData, 0)
|
||||
for _, logGroup := range response.LogGroups {
|
||||
logGroupName := *logGroup.LogGroupName
|
||||
result = append(result, suggestData{Text: logGroupName, Value: logGroupName, Label: logGroupName})
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func isDuplicate(nameList []string, target string) bool {
|
||||
for _, name := range nameList {
|
||||
if name == target {
|
||||
|
@ -21,6 +21,7 @@ func (e *cloudWatchExecutor) newResourceMux() *http.ServeMux {
|
||||
mux.HandleFunc("/ebs-volume-ids", handleResourceReq(e.handleGetEbsVolumeIds))
|
||||
mux.HandleFunc("/ec2-instance-attribute", handleResourceReq(e.handleGetEc2InstanceAttribute))
|
||||
mux.HandleFunc("/resource-arns", handleResourceReq(e.handleGetResourceArns))
|
||||
mux.HandleFunc("/log-groups", handleResourceReq(e.handleGetLogGroups))
|
||||
return mux
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
"github.com/aws/aws-sdk-go/service/resourcegroupstaggingapi"
|
||||
"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/pkg/setting"
|
||||
)
|
||||
|
||||
@ -33,6 +34,7 @@ type fakeCWLogsClient struct {
|
||||
type logsQueryCalls struct {
|
||||
startQueryWithContext []*cloudwatchlogs.StartQueryInput
|
||||
getEventsWithContext []*cloudwatchlogs.GetLogEventsInput
|
||||
describeLogGroups []*cloudwatchlogs.DescribeLogGroupsInput
|
||||
}
|
||||
|
||||
func (m *fakeCWLogsClient) GetQueryResultsWithContext(ctx context.Context, input *cloudwatchlogs.GetQueryResultsInput, option ...request.Option) (*cloudwatchlogs.GetQueryResultsOutput, error) {
|
||||
@ -53,6 +55,13 @@ func (m *fakeCWLogsClient) StopQueryWithContext(ctx context.Context, input *clou
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m *fakeCWLogsClient) DescribeLogGroups(input *cloudwatchlogs.DescribeLogGroupsInput) (*cloudwatchlogs.DescribeLogGroupsOutput, error) {
|
||||
m.calls.describeLogGroups = append(m.calls.describeLogGroups, input)
|
||||
output := &m.logGroups[m.logGroupsIndex]
|
||||
m.logGroupsIndex++
|
||||
return output, nil
|
||||
}
|
||||
|
||||
func (m *fakeCWLogsClient) DescribeLogGroupsWithContext(ctx context.Context, input *cloudwatchlogs.DescribeLogGroupsInput, option ...request.Option) (*cloudwatchlogs.DescribeLogGroupsOutput, error) {
|
||||
output := &m.logGroups[m.logGroupsIndex]
|
||||
m.logGroupsIndex++
|
||||
@ -192,9 +201,8 @@ type fakeCheckHealthClient struct {
|
||||
cloudwatchiface.CloudWatchAPI
|
||||
cloudwatchlogsiface.CloudWatchLogsAPI
|
||||
|
||||
listMetricsPages func(input *cloudwatch.ListMetricsInput, fn func(*cloudwatch.ListMetricsOutput, bool) bool) error
|
||||
describeLogGroupsWithContext func(ctx aws.Context, input *cloudwatchlogs.DescribeLogGroupsInput,
|
||||
options ...request.Option) (*cloudwatchlogs.DescribeLogGroupsOutput, error)
|
||||
listMetricsPages func(input *cloudwatch.ListMetricsInput, fn func(*cloudwatch.ListMetricsOutput, bool) bool) error
|
||||
describeLogGroups func(input *cloudwatchlogs.DescribeLogGroupsInput) (*cloudwatchlogs.DescribeLogGroupsOutput, error)
|
||||
}
|
||||
|
||||
func (c fakeCheckHealthClient) ListMetricsPages(input *cloudwatch.ListMetricsInput, fn func(*cloudwatch.ListMetricsOutput, bool) bool) error {
|
||||
@ -204,9 +212,9 @@ func (c fakeCheckHealthClient) ListMetricsPages(input *cloudwatch.ListMetricsInp
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c fakeCheckHealthClient) DescribeLogGroupsWithContext(ctx aws.Context, input *cloudwatchlogs.DescribeLogGroupsInput, options ...request.Option) (*cloudwatchlogs.DescribeLogGroupsOutput, error) {
|
||||
if c.describeLogGroupsWithContext != nil {
|
||||
return c.describeLogGroupsWithContext(ctx, input, options...)
|
||||
func (c fakeCheckHealthClient) DescribeLogGroups(input *cloudwatchlogs.DescribeLogGroupsInput) (*cloudwatchlogs.DescribeLogGroupsOutput, error) {
|
||||
if c.describeLogGroups != nil {
|
||||
return c.describeLogGroups(input)
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
@ -247,3 +255,12 @@ func (s *fakeSessionCache) GetSession(c awsds.SessionConfig) (*session.Session,
|
||||
Config: &aws.Config{},
|
||||
}, nil
|
||||
}
|
||||
|
||||
type mockedCallResourceResponseSenderForOauth struct {
|
||||
Response *backend.CallResourceResponse
|
||||
}
|
||||
|
||||
func (s *mockedCallResourceResponseSenderForOauth) Send(resp *backend.CallResourceResponse) error {
|
||||
s.Response = resp
|
||||
return nil
|
||||
}
|
||||
|
29
public/app/plugins/datasource/cloudwatch/__mocks__/API.ts
Normal file
29
public/app/plugins/datasource/cloudwatch/__mocks__/API.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import { getBackendSrv, setBackendSrv } from '@grafana/runtime';
|
||||
import { getTimeSrv } from 'app/features/dashboard/services/TimeSrv';
|
||||
import { TemplateSrv } from 'app/features/templating/template_srv';
|
||||
import { CustomVariableModel } from 'app/features/variables/types';
|
||||
|
||||
import { CloudWatchAPI } from '../api';
|
||||
|
||||
import { CloudWatchSettings, setupMockedTemplateService } from './CloudWatchDataSource';
|
||||
|
||||
export function setupMockedAPI({
|
||||
variables,
|
||||
response,
|
||||
}: {
|
||||
response?: Array<{ text: string; label: string; value: string }>;
|
||||
variables?: CustomVariableModel[];
|
||||
mockGetVariableName?: boolean;
|
||||
} = {}) {
|
||||
let templateService = variables ? setupMockedTemplateService(variables) : new TemplateSrv();
|
||||
|
||||
const timeSrv = getTimeSrv();
|
||||
const api = new CloudWatchAPI(CloudWatchSettings, templateService);
|
||||
const resourceRequestMock = jest.fn().mockReturnValue(response);
|
||||
setBackendSrv({
|
||||
...getBackendSrv(),
|
||||
get: resourceRequestMock,
|
||||
});
|
||||
|
||||
return { api, resourceRequestMock, templateService, timeSrv };
|
||||
}
|
@ -76,7 +76,7 @@ export function setupMockedDataSource({
|
||||
const timeSrv = getTimeSrv();
|
||||
const datasource = new CloudWatchDatasource(CloudWatchSettings, templateService, timeSrv);
|
||||
datasource.getVariables = () => ['test'];
|
||||
|
||||
datasource.api.describeLogGroups = jest.fn().mockResolvedValue([]);
|
||||
datasource.api.getNamespaces = jest.fn().mockResolvedValue([]);
|
||||
datasource.api.getRegions = jest.fn().mockResolvedValue([]);
|
||||
datasource.logsQueryRunner.defaultLogGroups = [];
|
||||
@ -84,6 +84,7 @@ export function setupMockedDataSource({
|
||||
setBackendSrv({
|
||||
...getBackendSrv(),
|
||||
fetch: fetchMock,
|
||||
get: jest.fn(),
|
||||
});
|
||||
|
||||
return { datasource, fetchMock, templateService, timeSrv };
|
||||
|
55
public/app/plugins/datasource/cloudwatch/api.test.ts
Normal file
55
public/app/plugins/datasource/cloudwatch/api.test.ts
Normal file
@ -0,0 +1,55 @@
|
||||
import { setupMockedAPI } from './__mocks__/API';
|
||||
|
||||
describe('describeLogGroup', () => {
|
||||
it('replaces region correctly in the query', async () => {
|
||||
const { api, resourceRequestMock } = setupMockedAPI();
|
||||
await api.describeLogGroups({ region: 'default' });
|
||||
expect(resourceRequestMock.mock.calls[0][1].region).toBe('us-west-1');
|
||||
|
||||
await api.describeLogGroups({ region: 'eu-east' });
|
||||
expect(resourceRequestMock.mock.calls[1][1].region).toBe('eu-east');
|
||||
});
|
||||
|
||||
it('should return log groups as an array of options', async () => {
|
||||
const response = [
|
||||
{
|
||||
text: '/aws/containerinsights/dev303-workshop/application',
|
||||
value: '/aws/containerinsights/dev303-workshop/application',
|
||||
label: '/aws/containerinsights/dev303-workshop/application',
|
||||
},
|
||||
{
|
||||
text: '/aws/containerinsights/dev303-workshop/flowlogs',
|
||||
value: '/aws/containerinsights/dev303-workshop/flowlogs',
|
||||
label: '/aws/containerinsights/dev303-workshop/flowlogs',
|
||||
},
|
||||
{
|
||||
text: '/aws/containerinsights/dev303-workshop/dataplane',
|
||||
value: '/aws/containerinsights/dev303-workshop/dataplane',
|
||||
label: '/aws/containerinsights/dev303-workshop/dataplane',
|
||||
},
|
||||
];
|
||||
|
||||
const { api } = setupMockedAPI({ response });
|
||||
const expectedLogGroups = [
|
||||
{
|
||||
text: '/aws/containerinsights/dev303-workshop/application',
|
||||
value: '/aws/containerinsights/dev303-workshop/application',
|
||||
label: '/aws/containerinsights/dev303-workshop/application',
|
||||
},
|
||||
{
|
||||
text: '/aws/containerinsights/dev303-workshop/flowlogs',
|
||||
value: '/aws/containerinsights/dev303-workshop/flowlogs',
|
||||
label: '/aws/containerinsights/dev303-workshop/flowlogs',
|
||||
},
|
||||
{
|
||||
text: '/aws/containerinsights/dev303-workshop/dataplane',
|
||||
value: '/aws/containerinsights/dev303-workshop/dataplane',
|
||||
label: '/aws/containerinsights/dev303-workshop/dataplane',
|
||||
},
|
||||
];
|
||||
|
||||
const logGroups = await api.describeLogGroups({ region: 'default' });
|
||||
|
||||
expect(logGroups).toEqual(expectedLogGroups);
|
||||
});
|
||||
});
|
@ -1,25 +1,30 @@
|
||||
import { DataSourceInstanceSettings } from '@grafana/data';
|
||||
import { getBackendSrv, BackendSrv } from '@grafana/runtime';
|
||||
import { DataSourceInstanceSettings, SelectableValue } from '@grafana/data';
|
||||
import { getBackendSrv } from '@grafana/runtime';
|
||||
import { TemplateSrv } from 'app/features/templating/template_srv';
|
||||
|
||||
import { CloudWatchRequest } from './query-runner/CloudWatchRequest';
|
||||
import { CloudWatchJsonData, Dimensions } from './types';
|
||||
import { CloudWatchJsonData, DescribeLogGroupsRequest, Dimensions, MultiFilters } from './types';
|
||||
|
||||
export interface SelectableResourceValue extends SelectableValue<string> {
|
||||
text: string;
|
||||
}
|
||||
|
||||
export class CloudWatchAPI extends CloudWatchRequest {
|
||||
private backendSrv: BackendSrv;
|
||||
constructor(instanceSettings: DataSourceInstanceSettings<CloudWatchJsonData>, templateSrv: TemplateSrv) {
|
||||
super(instanceSettings, templateSrv);
|
||||
this.backendSrv = getBackendSrv();
|
||||
}
|
||||
|
||||
resourceRequest(subtype: string, parameters?: any): Promise<Array<{ text: any; label: any; value: any }>> {
|
||||
return this.backendSrv.get(`/api/datasources/${this.instanceSettings.id}/resources/${subtype}`, parameters);
|
||||
resourceRequest(
|
||||
subtype: string,
|
||||
parameters?: Record<string, string | string[] | number>
|
||||
): Promise<SelectableResourceValue[]> {
|
||||
return getBackendSrv().get(`/api/datasources/${this.instanceSettings.id}/resources/${subtype}`, parameters);
|
||||
}
|
||||
|
||||
getRegions(): Promise<Array<{ label: string; value: string; text: string }>> {
|
||||
return this.resourceRequest('regions').then((regions: any) => [
|
||||
getRegions() {
|
||||
return this.resourceRequest('regions').then((regions) => [
|
||||
{ label: 'default', value: 'default', text: 'default' },
|
||||
...regions,
|
||||
...regions.filter((r) => r.value),
|
||||
]);
|
||||
}
|
||||
|
||||
@ -27,6 +32,13 @@ export class CloudWatchAPI extends CloudWatchRequest {
|
||||
return this.resourceRequest('namespaces');
|
||||
}
|
||||
|
||||
async describeLogGroups(params: DescribeLogGroupsRequest) {
|
||||
return this.resourceRequest('log-groups', {
|
||||
...params,
|
||||
region: this.templateSrv.replace(this.getActualRegion(params.region)),
|
||||
});
|
||||
}
|
||||
|
||||
async getMetrics(namespace: string | undefined, region?: string) {
|
||||
if (!namespace) {
|
||||
return [];
|
||||
@ -38,7 +50,7 @@ export class CloudWatchAPI extends CloudWatchRequest {
|
||||
});
|
||||
}
|
||||
|
||||
async getAllMetrics(region: string): Promise<Array<{ metricName: string; namespace: string }>> {
|
||||
async getAllMetrics(region: string): Promise<Array<{ metricName?: string; namespace: string }>> {
|
||||
const values = await this.resourceRequest('all-metrics', {
|
||||
region: this.templateSrv.replace(this.getActualRegion(region)),
|
||||
});
|
||||
@ -93,7 +105,7 @@ export class CloudWatchAPI extends CloudWatchRequest {
|
||||
});
|
||||
}
|
||||
|
||||
getEc2InstanceAttribute(region: string, attributeName: string, filters: any) {
|
||||
getEc2InstanceAttribute(region: string, attributeName: string, filters: MultiFilters) {
|
||||
return this.resourceRequest('ec2-instance-attribute', {
|
||||
region: this.templateSrv.replace(this.getActualRegion(region)),
|
||||
attributeName: this.templateSrv.replace(attributeName),
|
||||
@ -101,7 +113,7 @@ export class CloudWatchAPI extends CloudWatchRequest {
|
||||
});
|
||||
}
|
||||
|
||||
getResourceARNs(region: string, resourceType: string, tags: any) {
|
||||
getResourceARNs(region: string, resourceType: string, tags: MultiFilters) {
|
||||
return this.resourceRequest('resource-arns', {
|
||||
region: this.templateSrv.replace(this.getActualRegion(region)),
|
||||
resourceType: this.templateSrv.replace(resourceType),
|
||||
|
@ -116,11 +116,11 @@ export class SQLCompletionItemProvider extends CompletionItemProvider {
|
||||
this.templateSrv.replace(namespaceToken?.value.replace(/\"/g, '')),
|
||||
this.templateSrv.replace(this.region)
|
||||
);
|
||||
metrics.map((m) => addSuggestion(m.value));
|
||||
metrics.forEach((m) => m.value && addSuggestion(m.value));
|
||||
} else {
|
||||
// If no namespace is specified in the query, just list all metrics
|
||||
const metrics = await this.api.getAllMetrics(this.templateSrv.replace(this.region));
|
||||
uniq(metrics.map((m) => m.metricName)).map((m) => addSuggestion(m, { insertText: m }));
|
||||
uniq(metrics.map((m) => m.metricName)).forEach((m) => m && addSuggestion(m, { insertText: m }));
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -186,8 +186,8 @@ export class SQLCompletionItemProvider extends CompletionItemProvider {
|
||||
metricNameToken?.value ?? ''
|
||||
);
|
||||
keys.map((m) => {
|
||||
const key = /[\s\.-]/.test(m.value) ? `"${m.value}"` : m.value;
|
||||
addSuggestion(key);
|
||||
const key = /[\s\.-]/.test(m.value ?? '') ? `"${m.value}"` : m.value;
|
||||
key && addSuggestion(key);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import React from 'react';
|
||||
import selectEvent from 'react-select-event';
|
||||
|
||||
import { AwsAuthType } from '@grafana/aws-sdk';
|
||||
import { toOption } from '@grafana/data';
|
||||
|
||||
import { setupMockedDataSource } from '../__mocks__/CloudWatchDataSource';
|
||||
|
||||
@ -13,6 +14,7 @@ jest.mock('app/features/plugins/datasource_srv', () => ({
|
||||
getDatasourceSrv: () => ({
|
||||
loadDatasource: jest.fn().mockResolvedValue({
|
||||
api: {
|
||||
describeLogGroups: jest.fn().mockResolvedValue(['logGroup-foo', 'logGroup-bar'].map(toOption)),
|
||||
getRegions: jest.fn().mockResolvedValue([
|
||||
{
|
||||
label: 'ap-east-1',
|
||||
@ -22,9 +24,6 @@ jest.mock('app/features/plugins/datasource_srv', () => ({
|
||||
},
|
||||
getActualRegion: jest.fn().mockReturnValue('ap-east-1'),
|
||||
getVariables: jest.fn().mockReturnValue([]),
|
||||
logsQueryRunner: {
|
||||
describeLogGroups: jest.fn().mockResolvedValue(['logGroup-foo', 'logGroup-bar']),
|
||||
},
|
||||
}),
|
||||
}),
|
||||
}));
|
||||
|
@ -16,6 +16,7 @@ import { createWarningNotification } from 'app/core/copy/appNotification';
|
||||
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
|
||||
import { store } from 'app/store/store';
|
||||
|
||||
import { SelectableResourceValue } from '../api';
|
||||
import { CloudWatchDatasource } from '../datasource';
|
||||
import { CloudWatchJsonData, CloudWatchSecureJsonData } from '../types';
|
||||
|
||||
@ -63,7 +64,16 @@ export const ConfigEditor: FC<Props> = (props: Props) => {
|
||||
{...props}
|
||||
loadRegions={
|
||||
datasource &&
|
||||
(() => datasource.api.getRegions().then((r) => r.filter((r) => r.value !== 'default').map((v) => v.value)))
|
||||
(async () => {
|
||||
return datasource.api
|
||||
.getRegions()
|
||||
.then((regions) =>
|
||||
regions.reduce(
|
||||
(acc: string[], curr: SelectableResourceValue) => (curr.value ? [...acc, curr.value] : acc),
|
||||
[]
|
||||
)
|
||||
);
|
||||
})
|
||||
}
|
||||
>
|
||||
<InlineField label="Namespaces of Custom Metrics" labelWidth={28} tooltip="Namespaces of Custom Metrics.">
|
||||
|
@ -4,6 +4,8 @@ import lodash from 'lodash'; // eslint-disable-line lodash/import-scope
|
||||
import React from 'react';
|
||||
import { openMenu, select } from 'react-select-event';
|
||||
|
||||
import { toOption } from '@grafana/data';
|
||||
|
||||
import { setupMockedDataSource } from '../__mocks__/CloudWatchDataSource';
|
||||
import { DescribeLogGroupsRequest } from '../types';
|
||||
|
||||
@ -25,15 +27,13 @@ describe('LogGroupSelector', () => {
|
||||
});
|
||||
|
||||
it('updates upstream query log groups on region change', async () => {
|
||||
ds.datasource.logsQueryRunner.describeLogGroups = jest
|
||||
.fn()
|
||||
.mockImplementation(async (params: DescribeLogGroupsRequest) => {
|
||||
if (params.region === 'region1') {
|
||||
return Promise.resolve(['log_group_1']);
|
||||
} else {
|
||||
return Promise.resolve(['log_group_2']);
|
||||
}
|
||||
});
|
||||
ds.datasource.api.describeLogGroups = jest.fn().mockImplementation(async (params: DescribeLogGroupsRequest) => {
|
||||
if (params.region === 'region1') {
|
||||
return Promise.resolve(['log_group_1'].map(toOption));
|
||||
} else {
|
||||
return Promise.resolve(['log_group_2'].map(toOption));
|
||||
}
|
||||
});
|
||||
const props = {
|
||||
...defaultProps,
|
||||
selectedLogGroups: ['log_group_1'],
|
||||
@ -50,15 +50,13 @@ describe('LogGroupSelector', () => {
|
||||
});
|
||||
|
||||
it('does not update upstream query log groups if saved is false', async () => {
|
||||
ds.datasource.logsQueryRunner.describeLogGroups = jest
|
||||
.fn()
|
||||
.mockImplementation(async (params: DescribeLogGroupsRequest) => {
|
||||
if (params.region === 'region1') {
|
||||
return Promise.resolve(['log_group_1']);
|
||||
} else {
|
||||
return Promise.resolve(['log_group_2']);
|
||||
}
|
||||
});
|
||||
ds.datasource.api.describeLogGroups = jest.fn().mockImplementation(async (params: DescribeLogGroupsRequest) => {
|
||||
if (params.region === 'region1') {
|
||||
return Promise.resolve(['log_group_1'].map(toOption));
|
||||
} else {
|
||||
return Promise.resolve(['log_group_2'].map(toOption));
|
||||
}
|
||||
});
|
||||
const props = {
|
||||
...defaultProps,
|
||||
selectedLogGroups: ['log_group_1'],
|
||||
@ -98,14 +96,12 @@ describe('LogGroupSelector', () => {
|
||||
];
|
||||
const testLimit = 10;
|
||||
|
||||
ds.datasource.logsQueryRunner.describeLogGroups = jest
|
||||
.fn()
|
||||
.mockImplementation(async (params: DescribeLogGroupsRequest) => {
|
||||
const theLogGroups = allLogGroups
|
||||
.filter((logGroupName) => logGroupName.startsWith(params.logGroupNamePrefix ?? ''))
|
||||
.slice(0, Math.max(params.limit ?? testLimit, testLimit));
|
||||
return Promise.resolve(theLogGroups);
|
||||
});
|
||||
ds.datasource.api.describeLogGroups = jest.fn().mockImplementation(async (params: DescribeLogGroupsRequest) => {
|
||||
const theLogGroups = allLogGroups
|
||||
.filter((logGroupName) => logGroupName.startsWith(params.logGroupNamePrefix ?? ''))
|
||||
.slice(0, Math.max(params.limit ?? testLimit, testLimit));
|
||||
return Promise.resolve(theLogGroups.map(toOption));
|
||||
});
|
||||
const props = {
|
||||
...defaultProps,
|
||||
};
|
||||
@ -129,7 +125,7 @@ describe('LogGroupSelector', () => {
|
||||
|
||||
it('should render template variables a selectable option', async () => {
|
||||
lodash.debounce = jest.fn().mockImplementation((fn) => fn);
|
||||
ds.datasource.logsQueryRunner.describeLogGroups = jest.fn().mockResolvedValue([]);
|
||||
ds.datasource.api.describeLogGroups = jest.fn().mockResolvedValue([]);
|
||||
const onChange = jest.fn();
|
||||
const props = {
|
||||
...defaultProps,
|
||||
|
@ -52,12 +52,12 @@ export const LogGroupSelector: React.FC<LogGroupSelectorProps> = ({
|
||||
return [];
|
||||
}
|
||||
try {
|
||||
const logGroups: string[] = await datasource.logsQueryRunner.describeLogGroups({
|
||||
const logGroups = await datasource.api.describeLogGroups({
|
||||
refId,
|
||||
region,
|
||||
logGroupNamePrefix,
|
||||
});
|
||||
return logGroups.map(toOption);
|
||||
return logGroups;
|
||||
} catch (err) {
|
||||
dispatch(notifyApp(createErrorNotification(typeof err === 'string' ? err : JSON.stringify(err))));
|
||||
return [];
|
||||
@ -98,7 +98,7 @@ export const LogGroupSelector: React.FC<LogGroupSelectorProps> = ({
|
||||
}
|
||||
|
||||
setLoadingLogGroups(true);
|
||||
return fetchLogGroupOptions(datasource.getActualRegion(region) ?? '')
|
||||
return fetchLogGroupOptions(datasource.getActualRegion(region))
|
||||
.then((logGroups) => {
|
||||
const newSelectedLogGroups = intersection(
|
||||
selectedLogGroups,
|
||||
|
@ -48,7 +48,6 @@ export class CloudWatchDatasource
|
||||
|
||||
private metricsQueryRunner: CloudWatchMetricsQueryRunner;
|
||||
private annotationQueryRunner: CloudWatchAnnotationQueryRunner;
|
||||
// this member should be private too, but we need to fix https://github.com/grafana/grafana/issues/55243 to enable that
|
||||
logsQueryRunner: CloudWatchLogsQueryRunner;
|
||||
api: CloudWatchAPI;
|
||||
|
||||
@ -170,7 +169,7 @@ export class CloudWatchDatasource
|
||||
|
||||
getActualRegion(region?: string) {
|
||||
if (region === 'default' || region === undefined || region === '') {
|
||||
return this.defaultRegion;
|
||||
return this.defaultRegion ?? '';
|
||||
}
|
||||
return region;
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { interval, lastValueFrom, of } from 'rxjs';
|
||||
|
||||
import { LogRowModel, MutableDataFrame, FieldType, LogLevel, dataFrameToJSON, DataQueryErrorType } from '@grafana/data';
|
||||
import { BackendDataSourceResponse } from '@grafana/runtime';
|
||||
|
||||
import { genMockFrames, setupMockedLogsQueryRunner } from '../__mocks__/LogsQueryRunner';
|
||||
import { validLogsQuery } from '../__mocks__/queries';
|
||||
@ -14,114 +13,6 @@ describe('CloudWatchLogsQueryRunner', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
describe('describeLogGroup', () => {
|
||||
it('replaces region correctly in the query', async () => {
|
||||
const { runner, fetchMock } = setupMockedLogsQueryRunner();
|
||||
await runner.describeLogGroups({ region: 'default' });
|
||||
expect(fetchMock.mock.calls[0][0].data.queries[0].region).toBe('us-west-1');
|
||||
|
||||
await runner.describeLogGroups({ region: 'eu-east' });
|
||||
expect(fetchMock.mock.calls[1][0].data.queries[0].region).toBe('eu-east');
|
||||
});
|
||||
|
||||
it('should return log groups as an array of strings', async () => {
|
||||
const data: BackendDataSourceResponse = {
|
||||
results: {
|
||||
A: {
|
||||
frames: [
|
||||
{
|
||||
schema: {
|
||||
name: 'logGroups',
|
||||
refId: 'A',
|
||||
fields: [{ name: 'logGroupName', type: FieldType.string }],
|
||||
},
|
||||
data: {
|
||||
values: [
|
||||
[
|
||||
'/aws/containerinsights/dev303-workshop/application',
|
||||
'/aws/containerinsights/dev303-workshop/dataplane',
|
||||
'/aws/containerinsights/dev303-workshop/flowlogs',
|
||||
'/aws/containerinsights/dev303-workshop/host',
|
||||
'/aws/containerinsights/dev303-workshop/performance',
|
||||
'/aws/containerinsights/dev303-workshop/prometheus',
|
||||
'/aws/containerinsights/ecommerce-sockshop/application',
|
||||
'/aws/containerinsights/ecommerce-sockshop/dataplane',
|
||||
'/aws/containerinsights/ecommerce-sockshop/host',
|
||||
'/aws/containerinsights/ecommerce-sockshop/performance',
|
||||
'/aws/containerinsights/watchdemo-perf/application',
|
||||
'/aws/containerinsights/watchdemo-perf/dataplane',
|
||||
'/aws/containerinsights/watchdemo-perf/host',
|
||||
'/aws/containerinsights/watchdemo-perf/performance',
|
||||
'/aws/containerinsights/watchdemo-perf/prometheus',
|
||||
'/aws/containerinsights/watchdemo-prod-us-east-1/performance',
|
||||
'/aws/containerinsights/watchdemo-staging/application',
|
||||
'/aws/containerinsights/watchdemo-staging/dataplane',
|
||||
'/aws/containerinsights/watchdemo-staging/host',
|
||||
'/aws/containerinsights/watchdemo-staging/performance',
|
||||
'/aws/ecs/containerinsights/bugbash-ec2/performance',
|
||||
'/aws/ecs/containerinsights/ecs-demoworkshop/performance',
|
||||
'/aws/ecs/containerinsights/ecs-workshop-dev/performance',
|
||||
'/aws/eks/dev303-workshop/cluster',
|
||||
'/aws/events/cloudtrail',
|
||||
'/aws/events/ecs',
|
||||
'/aws/lambda/cwsyn-mycanary-fac97ded-f134-499a-9d71-4c3be1f63182',
|
||||
'/aws/lambda/cwsyn-watch-linkchecks-ef7ef273-5da2-4663-af54-d2f52d55b060',
|
||||
'/ecs/ecs-cwagent-daemon-service',
|
||||
'/ecs/ecs-demo-limitTask',
|
||||
'CloudTrail/DefaultLogGroup',
|
||||
'container-insights-prometheus-beta',
|
||||
'container-insights-prometheus-demo',
|
||||
],
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const { runner } = setupMockedLogsQueryRunner({ data });
|
||||
const expectedLogGroups = [
|
||||
'/aws/containerinsights/dev303-workshop/application',
|
||||
'/aws/containerinsights/dev303-workshop/dataplane',
|
||||
'/aws/containerinsights/dev303-workshop/flowlogs',
|
||||
'/aws/containerinsights/dev303-workshop/host',
|
||||
'/aws/containerinsights/dev303-workshop/performance',
|
||||
'/aws/containerinsights/dev303-workshop/prometheus',
|
||||
'/aws/containerinsights/ecommerce-sockshop/application',
|
||||
'/aws/containerinsights/ecommerce-sockshop/dataplane',
|
||||
'/aws/containerinsights/ecommerce-sockshop/host',
|
||||
'/aws/containerinsights/ecommerce-sockshop/performance',
|
||||
'/aws/containerinsights/watchdemo-perf/application',
|
||||
'/aws/containerinsights/watchdemo-perf/dataplane',
|
||||
'/aws/containerinsights/watchdemo-perf/host',
|
||||
'/aws/containerinsights/watchdemo-perf/performance',
|
||||
'/aws/containerinsights/watchdemo-perf/prometheus',
|
||||
'/aws/containerinsights/watchdemo-prod-us-east-1/performance',
|
||||
'/aws/containerinsights/watchdemo-staging/application',
|
||||
'/aws/containerinsights/watchdemo-staging/dataplane',
|
||||
'/aws/containerinsights/watchdemo-staging/host',
|
||||
'/aws/containerinsights/watchdemo-staging/performance',
|
||||
'/aws/ecs/containerinsights/bugbash-ec2/performance',
|
||||
'/aws/ecs/containerinsights/ecs-demoworkshop/performance',
|
||||
'/aws/ecs/containerinsights/ecs-workshop-dev/performance',
|
||||
'/aws/eks/dev303-workshop/cluster',
|
||||
'/aws/events/cloudtrail',
|
||||
'/aws/events/ecs',
|
||||
'/aws/lambda/cwsyn-mycanary-fac97ded-f134-499a-9d71-4c3be1f63182',
|
||||
'/aws/lambda/cwsyn-watch-linkchecks-ef7ef273-5da2-4663-af54-d2f52d55b060',
|
||||
'/ecs/ecs-cwagent-daemon-service',
|
||||
'/ecs/ecs-demo-limitTask',
|
||||
'CloudTrail/DefaultLogGroup',
|
||||
'container-insights-prometheus-beta',
|
||||
'container-insights-prometheus-demo',
|
||||
];
|
||||
|
||||
const logGroups = await runner.describeLogGroups({ region: 'default' });
|
||||
|
||||
expect(logGroups).toEqual(expectedLogGroups);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getLogRowContext', () => {
|
||||
it('replaces parameters correctly in the query', async () => {
|
||||
|
@ -425,13 +425,6 @@ export class CloudWatchLogsQueryRunner extends CloudWatchRequest {
|
||||
};
|
||||
};
|
||||
|
||||
async describeLogGroups(params: DescribeLogGroupsRequest): Promise<string[]> {
|
||||
const dataFrames = await lastValueFrom(this.makeLogActionRequest('DescribeLogGroups', [params]));
|
||||
|
||||
const logGroupNames = dataFrames[0]?.fields[0]?.values.toArray() ?? [];
|
||||
return logGroupNames;
|
||||
}
|
||||
|
||||
async describeAllLogGroups(params: DescribeLogGroupsRequest): Promise<string[]> {
|
||||
const dataFrames = await lastValueFrom(this.makeLogActionRequest('DescribeAllLogGroups', [params]));
|
||||
|
||||
|
@ -68,7 +68,7 @@ export class CloudWatchVariableSupport extends CustomVariableSupport<CloudWatchD
|
||||
|
||||
async handleRegionsQuery() {
|
||||
const regions = await this.api.getRegions();
|
||||
return regions.map((s: { label: string; value: string }) => ({
|
||||
return regions.map((s) => ({
|
||||
text: s.label,
|
||||
value: s.value,
|
||||
expandable: true,
|
||||
@ -77,7 +77,7 @@ export class CloudWatchVariableSupport extends CustomVariableSupport<CloudWatchD
|
||||
|
||||
async handleNamespacesQuery() {
|
||||
const namespaces = await this.api.getNamespaces();
|
||||
return namespaces.map((s: { label: string; value: string }) => ({
|
||||
return namespaces.map((s) => ({
|
||||
text: s.label,
|
||||
value: s.value,
|
||||
expandable: true,
|
||||
@ -86,7 +86,7 @@ export class CloudWatchVariableSupport extends CustomVariableSupport<CloudWatchD
|
||||
|
||||
async handleMetricsQuery({ namespace, region }: VariableQuery) {
|
||||
const metrics = await this.api.getMetrics(namespace, region);
|
||||
return metrics.map((s: { label: string; value: string }) => ({
|
||||
return metrics.map((s) => ({
|
||||
text: s.label,
|
||||
value: s.value,
|
||||
expandable: true,
|
||||
@ -95,7 +95,7 @@ export class CloudWatchVariableSupport extends CustomVariableSupport<CloudWatchD
|
||||
|
||||
async handleDimensionKeysQuery({ namespace, region }: VariableQuery) {
|
||||
const keys = await this.api.getDimensionKeys(namespace, region);
|
||||
return keys.map((s: { label: string; value: string }) => ({
|
||||
return keys.map((s) => ({
|
||||
text: s.label,
|
||||
value: s.value,
|
||||
expandable: true,
|
||||
@ -107,7 +107,7 @@ export class CloudWatchVariableSupport extends CustomVariableSupport<CloudWatchD
|
||||
return [];
|
||||
}
|
||||
const keys = await this.api.getDimensionValues(region, namespace, metricName, dimensionKey, dimensionFilters ?? {});
|
||||
return keys.map((s: { label: string; value: string }) => ({
|
||||
return keys.map((s) => ({
|
||||
text: s.label,
|
||||
value: s.value,
|
||||
expandable: true,
|
||||
@ -119,7 +119,7 @@ export class CloudWatchVariableSupport extends CustomVariableSupport<CloudWatchD
|
||||
return [];
|
||||
}
|
||||
const ids = await this.api.getEbsVolumeIds(region, instanceID);
|
||||
return ids.map((s: { label: string; value: string }) => ({
|
||||
return ids.map((s) => ({
|
||||
text: s.label,
|
||||
value: s.value,
|
||||
expandable: true,
|
||||
@ -131,7 +131,7 @@ export class CloudWatchVariableSupport extends CustomVariableSupport<CloudWatchD
|
||||
return [];
|
||||
}
|
||||
const values = await this.api.getEc2InstanceAttribute(region, attributeName, ec2Filters ?? {});
|
||||
return values.map((s: { label: string; value: string }) => ({
|
||||
return values.map((s) => ({
|
||||
text: s.label,
|
||||
value: s.value,
|
||||
expandable: true,
|
||||
@ -143,7 +143,7 @@ export class CloudWatchVariableSupport extends CustomVariableSupport<CloudWatchD
|
||||
return [];
|
||||
}
|
||||
const keys = await this.api.getResourceARNs(region, resourceType, tags ?? {});
|
||||
return keys.map((s: { label: string; value: string }) => ({
|
||||
return keys.map((s) => ({
|
||||
text: s.label,
|
||||
value: s.value,
|
||||
expandable: true,
|
||||
|
Loading…
Reference in New Issue
Block a user