Cloudwatch: Revert aws sdk go v2 (#103644)

* Revert "CloudWatch: Import new grafana-aws-sdk with PDC fix (#103249)"

This reverts commit f2b5b4e0c0.

* Revert "CloudWatch: Migrate to aws-sdk-go-v2 (#103106)"

This reverts commit a65cc0df93.

* make update-workspace
This commit is contained in:
Isabella Siu
2025-04-08 15:40:15 -04:00
committed by GitHub
parent 27e9422f24
commit 13534a7d98
60 changed files with 1599 additions and 1483 deletions
+14 -9
View File
@@ -4,10 +4,9 @@ import (
"context"
"errors"
"fmt"
"strings"
oam "github.com/aws/aws-sdk-go-v2/service/oam"
oamtypes "github.com/aws/aws-sdk-go-v2/service/oam/types"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/service/oam"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models/resources"
)
@@ -24,14 +23,20 @@ func NewAccountsService(oamClient models.OAMAPIProvider) models.AccountsProvider
func (a *AccountsService) GetAccountsForCurrentUserOrRole(ctx context.Context) ([]resources.ResourceResponse[resources.Account], error) {
var nextToken *string
sinks := []oamtypes.ListSinksItem{}
sinks := []*oam.ListSinksItem{}
for {
response, err := a.ListSinks(ctx, &oam.ListSinksInput{NextToken: nextToken})
response, err := a.ListSinksWithContext(ctx, &oam.ListSinksInput{NextToken: nextToken})
if err != nil {
// TODO: this is a bit hacky, figure out how to do it right in v2
if strings.Contains(err.Error(), "AccessDeniedException") {
return nil, fmt.Errorf("%w: %s", ErrAccessDeniedException, err.Error())
var aerr awserr.Error
if errors.As(err, &aerr) {
switch aerr.Code() {
// unlike many other services, OAM doesn't define this error code. however, it's returned in case calling role/user has insufficient permissions
case "AccessDeniedException":
return nil, fmt.Errorf("%w: %s", ErrAccessDeniedException, aerr.Message())
}
}
}
if err != nil {
return nil, fmt.Errorf("ListSinks error: %w", err)
}
@@ -57,7 +62,7 @@ func (a *AccountsService) GetAccountsForCurrentUserOrRole(ctx context.Context) (
nextToken = nil
for {
links, err := a.ListAttachedLinks(ctx, &oam.ListAttachedLinksInput{
links, err := a.ListAttachedLinksWithContext(ctx, &oam.ListAttachedLinksInput{
SinkIdentifier: sinkIdentifier,
NextToken: nextToken,
})
+33 -34
View File
@@ -2,14 +2,12 @@ package services
import (
"context"
"errors"
"fmt"
"testing"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/oam"
oamtypes "github.com/aws/aws-sdk-go-v2/service/oam/types"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/service/oam"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/mocks"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models/resources"
"github.com/stretchr/testify/assert"
@@ -20,20 +18,21 @@ import (
func TestHandleGetAccounts(t *testing.T) {
t.Run("Should return an error in case of insufficient permissions from ListSinks", func(t *testing.T) {
fakeOAMClient := &mocks.FakeOAMClient{}
fakeOAMClient.On("ListSinks", mock.Anything).Return(&oam.ListSinksOutput{}, errors.New("AccessDeniedException"))
fakeOAMClient.On("ListSinksWithContext", mock.Anything).Return(&oam.ListSinksOutput{}, awserr.New("AccessDeniedException",
"AWS message", nil))
accounts := NewAccountsService(fakeOAMClient)
resp, err := accounts.GetAccountsForCurrentUserOrRole(context.Background())
assert.Error(t, err)
assert.Nil(t, resp)
assert.Equal(t, "access denied. please check your IAM policy: AccessDeniedException", err.Error())
assert.Equal(t, err.Error(), "access denied. please check your IAM policy: AWS message")
assert.ErrorIs(t, err, ErrAccessDeniedException)
})
t.Run("Should return an error in case of any error from ListSinks", func(t *testing.T) {
fakeOAMClient := &mocks.FakeOAMClient{}
fakeOAMClient.On("ListSinks", mock.Anything).Return(&oam.ListSinksOutput{}, fmt.Errorf("some error"))
fakeOAMClient.On("ListSinksWithContext", mock.Anything).Return(&oam.ListSinksOutput{}, fmt.Errorf("some error"))
accounts := NewAccountsService(fakeOAMClient)
resp, err := accounts.GetAccountsForCurrentUserOrRole(context.Background())
@@ -45,7 +44,7 @@ func TestHandleGetAccounts(t *testing.T) {
t.Run("Should return empty array in case no monitoring account exists", func(t *testing.T) {
fakeOAMClient := &mocks.FakeOAMClient{}
fakeOAMClient.On("ListSinks", mock.Anything).Return(&oam.ListSinksOutput{}, nil)
fakeOAMClient.On("ListSinksWithContext", mock.Anything).Return(&oam.ListSinksOutput{}, nil)
accounts := NewAccountsService(fakeOAMClient)
resp, err := accounts.GetAccountsForCurrentUserOrRole(context.Background())
@@ -56,26 +55,26 @@ func TestHandleGetAccounts(t *testing.T) {
t.Run("Should return one monitoring account (the first) even though ListSinks returns multiple sinks", func(t *testing.T) {
fakeOAMClient := &mocks.FakeOAMClient{}
fakeOAMClient.On("ListSinks", mock.Anything).Return(&oam.ListSinksOutput{
Items: []oamtypes.ListSinksItem{
fakeOAMClient.On("ListSinksWithContext", mock.Anything).Return(&oam.ListSinksOutput{
Items: []*oam.ListSinksItem{
{Name: aws.String("Account 1"), Arn: aws.String("arn:aws:logs:us-east-1:123456789012:log-group:my-log-group1")},
{Name: aws.String("Account 2"), Arn: aws.String("arn:aws:logs:us-east-1:123456789012:log-group:my-log-group2")},
},
NextToken: new(string),
}, nil).Once()
fakeOAMClient.On("ListSinks", mock.Anything).Return(&oam.ListSinksOutput{
Items: []oamtypes.ListSinksItem{
fakeOAMClient.On("ListSinksWithContext", mock.Anything).Return(&oam.ListSinksOutput{
Items: []*oam.ListSinksItem{
{Name: aws.String("Account 3"), Arn: aws.String("arn:aws:logs:us-east-1:123456789012:log-group:my-log-group3")},
},
NextToken: nil,
}, nil)
fakeOAMClient.On("ListAttachedLinks", mock.Anything).Return(&oam.ListAttachedLinksOutput{}, nil)
fakeOAMClient.On("ListAttachedLinksWithContext", mock.Anything).Return(&oam.ListAttachedLinksOutput{}, nil)
accounts := NewAccountsService(fakeOAMClient)
resp, err := accounts.GetAccountsForCurrentUserOrRole(context.Background())
assert.NoError(t, err)
fakeOAMClient.AssertNumberOfCalls(t, "ListSinks", 2)
fakeOAMClient.AssertNumberOfCalls(t, "ListSinksWithContext", 2)
require.Len(t, resp, 1)
assert.True(t, resp[0].Value.IsMonitoringAccount)
assert.Equal(t, "Account 1", resp[0].Value.Label)
@@ -84,28 +83,28 @@ func TestHandleGetAccounts(t *testing.T) {
t.Run("Should merge the first sink with attached links", func(t *testing.T) {
fakeOAMClient := &mocks.FakeOAMClient{}
fakeOAMClient.On("ListSinks", mock.Anything).Return(&oam.ListSinksOutput{
Items: []oamtypes.ListSinksItem{
fakeOAMClient.On("ListSinksWithContext", mock.Anything).Return(&oam.ListSinksOutput{
Items: []*oam.ListSinksItem{
{Name: aws.String("Account 1"), Arn: aws.String("arn:aws:logs:us-east-1:123456789012:log-group:my-log-group1")},
{Name: aws.String("Account 2"), Arn: aws.String("arn:aws:logs:us-east-1:123456789012:log-group:my-log-group2")},
},
NextToken: new(string),
}, nil).Once()
fakeOAMClient.On("ListSinks", mock.Anything).Return(&oam.ListSinksOutput{
Items: []oamtypes.ListSinksItem{
fakeOAMClient.On("ListSinksWithContext", mock.Anything).Return(&oam.ListSinksOutput{
Items: []*oam.ListSinksItem{
{Name: aws.String("Account 3"), Arn: aws.String("arn:aws:logs:us-east-1:123456789012:log-group:my-log-group3")},
},
NextToken: nil,
}, nil)
fakeOAMClient.On("ListAttachedLinks", mock.Anything).Return(&oam.ListAttachedLinksOutput{
Items: []oamtypes.ListAttachedLinksItem{
fakeOAMClient.On("ListAttachedLinksWithContext", mock.Anything).Return(&oam.ListAttachedLinksOutput{
Items: []*oam.ListAttachedLinksItem{
{Label: aws.String("Account 10"), LinkArn: aws.String("arn:aws:logs:us-east-1:123456789013:log-group:my-log-group10")},
{Label: aws.String("Account 11"), LinkArn: aws.String("arn:aws:logs:us-east-1:123456789014:log-group:my-log-group11")},
},
NextToken: new(string),
}, nil).Once()
fakeOAMClient.On("ListAttachedLinks", mock.Anything).Return(&oam.ListAttachedLinksOutput{
Items: []oamtypes.ListAttachedLinksItem{
fakeOAMClient.On("ListAttachedLinksWithContext", mock.Anything).Return(&oam.ListAttachedLinksOutput{
Items: []*oam.ListAttachedLinksItem{
{Label: aws.String("Account 12"), LinkArn: aws.String("arn:aws:logs:us-east-1:123456789012:log-group:my-log-group12")},
},
NextToken: nil,
@@ -115,8 +114,8 @@ func TestHandleGetAccounts(t *testing.T) {
resp, err := accounts.GetAccountsForCurrentUserOrRole(context.Background())
assert.NoError(t, err)
fakeOAMClient.AssertNumberOfCalls(t, "ListSinks", 2)
fakeOAMClient.AssertNumberOfCalls(t, "ListAttachedLinks", 2)
fakeOAMClient.AssertNumberOfCalls(t, "ListSinksWithContext", 2)
fakeOAMClient.AssertNumberOfCalls(t, "ListAttachedLinksWithContext", 2)
expectedAccounts := []resources.ResourceResponse[resources.Account]{
{Value: resources.Account{Id: "123456789012", Label: "Account 1", Arn: "arn:aws:logs:us-east-1:123456789012:log-group:my-log-group1", IsMonitoringAccount: true}},
{Value: resources.Account{Id: "123456789013", Label: "Account 10", Arn: "arn:aws:logs:us-east-1:123456789013:log-group:my-log-group10", IsMonitoringAccount: false}},
@@ -128,34 +127,34 @@ func TestHandleGetAccounts(t *testing.T) {
t.Run("Should call ListAttachedLinks with arn of first sink", func(t *testing.T) {
fakeOAMClient := &mocks.FakeOAMClient{}
fakeOAMClient.On("ListSinks", mock.Anything).Return(&oam.ListSinksOutput{
Items: []oamtypes.ListSinksItem{
fakeOAMClient.On("ListSinksWithContext", mock.Anything).Return(&oam.ListSinksOutput{
Items: []*oam.ListSinksItem{
{Name: aws.String("Account 1"), Arn: aws.String("arn:aws:logs:us-east-1:123456789012:log-group:my-log-group1")},
},
NextToken: new(string),
}, nil).Once()
fakeOAMClient.On("ListSinks", mock.Anything).Return(&oam.ListSinksOutput{
Items: []oamtypes.ListSinksItem{
fakeOAMClient.On("ListSinksWithContext", mock.Anything).Return(&oam.ListSinksOutput{
Items: []*oam.ListSinksItem{
{Name: aws.String("Account 3"), Arn: aws.String("arn:aws:logs:us-east-1:123456789012:log-group:my-log-group3")},
},
NextToken: nil,
}, nil).Once()
fakeOAMClient.On("ListAttachedLinks", mock.Anything).Return(&oam.ListAttachedLinksOutput{}, nil)
fakeOAMClient.On("ListAttachedLinksWithContext", mock.Anything).Return(&oam.ListAttachedLinksOutput{}, nil)
accounts := NewAccountsService(fakeOAMClient)
_, _ = accounts.GetAccountsForCurrentUserOrRole(context.Background())
fakeOAMClient.AssertCalled(t, "ListAttachedLinks", &oam.ListAttachedLinksInput{
fakeOAMClient.AssertCalled(t, "ListAttachedLinksWithContext", &oam.ListAttachedLinksInput{
SinkIdentifier: aws.String("arn:aws:logs:us-east-1:123456789012:log-group:my-log-group1"),
})
})
t.Run("Should return an error in case of any error from ListAttachedLinks", func(t *testing.T) {
fakeOAMClient := &mocks.FakeOAMClient{}
fakeOAMClient.On("ListSinks", mock.Anything).Return(&oam.ListSinksOutput{
Items: []oamtypes.ListSinksItem{{Name: aws.String("Account 1"), Arn: aws.String("arn:aws:logs:us-east-1:123456789012:log-group:my-log-group1")}},
fakeOAMClient.On("ListSinksWithContext", mock.Anything).Return(&oam.ListSinksOutput{
Items: []*oam.ListSinksItem{{Name: aws.String("Account 1"), Arn: aws.String("arn:aws:logs:us-east-1:123456789012:log-group:my-log-group1")}},
}, nil)
fakeOAMClient.On("ListAttachedLinks", mock.Anything).Return(&oam.ListAttachedLinksOutput{}, fmt.Errorf("some error")).Once()
fakeOAMClient.On("ListAttachedLinksWithContext", mock.Anything).Return(&oam.ListAttachedLinksOutput{}, fmt.Errorf("some error")).Once()
accounts := NewAccountsService(fakeOAMClient)
resp, err := accounts.GetAccountsForCurrentUserOrRole(context.Background())
+15 -17
View File
@@ -5,10 +5,8 @@ import (
"fmt"
"sort"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/cloudwatch"
cloudwatchtypes "github.com/aws/aws-sdk-go-v2/service/cloudwatch/types"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/cloudwatch"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models/resources"
)
@@ -32,7 +30,7 @@ func (l *ListMetricsService) GetDimensionKeysByDimensionFilter(ctx context.Conte
setDimensionFilter(input, r.DimensionFilter)
setAccount(input, r.ResourceRequest)
accountMetrics, err := l.ListMetricsWithPageLimit(ctx, input)
metrics, err := l.ListMetricsWithPageLimit(ctx, input)
if err != nil {
return nil, fmt.Errorf("%v: %w", "unable to call AWS API", err)
}
@@ -40,8 +38,8 @@ func (l *ListMetricsService) GetDimensionKeysByDimensionFilter(ctx context.Conte
response := []resources.ResourceResponse[string]{}
// remove duplicates
dupCheck := make(map[string]struct{})
for _, accountMetric := range accountMetrics {
for _, dim := range accountMetric.Metric.Dimensions {
for _, metric := range metrics {
for _, dim := range metric.Dimensions {
if _, exists := dupCheck[*dim.Name]; exists {
continue
}
@@ -60,7 +58,7 @@ func (l *ListMetricsService) GetDimensionKeysByDimensionFilter(ctx context.Conte
}
dupCheck[*dim.Name] = struct{}{}
response = append(response, resources.ResourceResponse[string]{AccountId: accountMetric.AccountId, Value: *dim.Name})
response = append(response, resources.ResourceResponse[string]{AccountId: metric.AccountId, Value: *dim.Name})
}
}
@@ -75,15 +73,15 @@ func (l *ListMetricsService) GetDimensionValuesByDimensionFilter(ctx context.Con
setDimensionFilter(input, r.DimensionFilter)
setAccount(input, r.ResourceRequest)
accountMetrics, err := l.ListMetricsWithPageLimit(ctx, input)
metrics, err := l.ListMetricsWithPageLimit(ctx, input)
if err != nil {
return nil, fmt.Errorf("%v: %w", "unable to call AWS API", err)
}
response := []resources.ResourceResponse[string]{}
dupCheck := make(map[string]bool)
for _, metric := range accountMetrics {
for _, dim := range metric.Metric.Dimensions {
for _, metric := range metrics {
for _, dim := range metric.Dimensions {
if *dim.Name == r.DimensionKey {
if _, exists := dupCheck[*dim.Value]; exists {
continue
@@ -104,19 +102,19 @@ func (l *ListMetricsService) GetDimensionValuesByDimensionFilter(ctx context.Con
func (l *ListMetricsService) GetMetricsByNamespace(ctx context.Context, r resources.MetricsRequest) ([]resources.ResourceResponse[resources.Metric], error) {
input := &cloudwatch.ListMetricsInput{Namespace: aws.String(r.Namespace)}
setAccount(input, r.ResourceRequest)
accountMetrics, err := l.ListMetricsWithPageLimit(ctx, input)
metrics, err := l.ListMetricsWithPageLimit(ctx, input)
if err != nil {
return nil, err
}
response := []resources.ResourceResponse[resources.Metric]{}
dupCheck := make(map[string]struct{})
for _, accountMetric := range accountMetrics {
if _, exists := dupCheck[*accountMetric.Metric.MetricName]; exists {
for _, metric := range metrics {
if _, exists := dupCheck[*metric.MetricName]; exists {
continue
}
dupCheck[*accountMetric.Metric.MetricName] = struct{}{}
response = append(response, resources.ResourceResponse[resources.Metric]{AccountId: accountMetric.AccountId, Value: resources.Metric{Name: *accountMetric.Metric.MetricName, Namespace: *accountMetric.Metric.Namespace}})
dupCheck[*metric.MetricName] = struct{}{}
response = append(response, resources.ResourceResponse[resources.Metric]{AccountId: metric.AccountId, Value: resources.Metric{Name: *metric.MetricName, Namespace: *metric.Namespace}})
}
return response, nil
@@ -124,7 +122,7 @@ func (l *ListMetricsService) GetMetricsByNamespace(ctx context.Context, r resour
func setDimensionFilter(input *cloudwatch.ListMetricsInput, dimensionFilter []*resources.Dimension) {
for _, dimension := range dimensionFilter {
df := cloudwatchtypes.DimensionFilter{
df := &cloudwatch.DimensionFilter{
Name: aws.String(dimension.Name),
}
if dimension.Value != "" {
@@ -4,10 +4,8 @@ import (
"context"
"testing"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/cloudwatch"
cloudwatchtypes "github.com/aws/aws-sdk-go-v2/service/cloudwatch/types"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/cloudwatch"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/mocks"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models/resources"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/utils"
@@ -20,20 +18,20 @@ const useLinkedAccountsId = "all"
var metricResponse = []resources.MetricResponse{
{
Metric: cloudwatchtypes.Metric{
Metric: &cloudwatch.Metric{
MetricName: aws.String("CPUUtilization"),
Namespace: aws.String("AWS/EC2"),
Dimensions: []cloudwatchtypes.Dimension{
Dimensions: []*cloudwatch.Dimension{
{Name: aws.String("InstanceId"), Value: aws.String("i-1234567890abcdef0")},
{Name: aws.String("InstanceType"), Value: aws.String("t2.micro")},
},
},
},
{
Metric: cloudwatchtypes.Metric{
Metric: &cloudwatch.Metric{
MetricName: aws.String("CPUUtilization"),
Namespace: aws.String("AWS/EC2"),
Dimensions: []cloudwatchtypes.Dimension{
Dimensions: []*cloudwatch.Dimension{
{Name: aws.String("InstanceId"), Value: aws.String("i-5234567890abcdef0")},
{Name: aws.String("InstanceType"), Value: aws.String("t2.micro")},
{Name: aws.String("AutoScalingGroupName"), Value: aws.String("my-asg")},
@@ -41,10 +39,10 @@ var metricResponse = []resources.MetricResponse{
},
},
{
Metric: cloudwatchtypes.Metric{
Metric: &cloudwatch.Metric{
MetricName: aws.String("CPUUtilization"),
Namespace: aws.String("AWS/EC2"),
Dimensions: []cloudwatchtypes.Dimension{
Dimensions: []*cloudwatch.Dimension{
{Name: aws.String("InstanceId"), Value: aws.String("i-64234567890abcdef0")},
{Name: aws.String("InstanceType"), Value: aws.String("t3.micro")},
{Name: aws.String("AutoScalingGroupName"), Value: aws.String("my-asg2")},
@@ -88,7 +86,7 @@ func TestListMetricsService_GetDimensionKeysByDimensionFilter(t *testing.T) {
listMetricsWithPageLimitInput: &cloudwatch.ListMetricsInput{
MetricName: aws.String("CPUUtilization"),
Namespace: aws.String("AWS/EC2"),
Dimensions: []cloudwatchtypes.DimensionFilter{{Name: aws.String("InstanceId")}},
Dimensions: []*cloudwatch.DimensionFilter{{Name: aws.String("InstanceId")}},
IncludeLinkedAccounts: aws.Bool(true),
},
},
@@ -103,7 +101,7 @@ func TestListMetricsService_GetDimensionKeysByDimensionFilter(t *testing.T) {
listMetricsWithPageLimitInput: &cloudwatch.ListMetricsInput{
MetricName: aws.String("CPUUtilization"),
Namespace: aws.String("AWS/EC2"),
Dimensions: []cloudwatchtypes.DimensionFilter{{Name: aws.String("InstanceId")}},
Dimensions: []*cloudwatch.DimensionFilter{{Name: aws.String("InstanceId")}},
IncludeLinkedAccounts: aws.Bool(true),
OwningAccount: aws.String("1234567890"),
},
@@ -116,7 +114,7 @@ func TestListMetricsService_GetDimensionKeysByDimensionFilter(t *testing.T) {
MetricName: "",
DimensionFilter: []*resources.Dimension{{Name: "InstanceId", Value: ""}},
},
listMetricsWithPageLimitInput: &cloudwatch.ListMetricsInput{Dimensions: []cloudwatchtypes.DimensionFilter{{Name: aws.String("InstanceId")}}},
listMetricsWithPageLimitInput: &cloudwatch.ListMetricsInput{Dimensions: []*cloudwatch.DimensionFilter{{Name: aws.String("InstanceId")}}},
},
}
@@ -165,7 +163,7 @@ func TestListMetricsService_GetDimensionValuesByDimensionFilter(t *testing.T) {
listMetricsWithPageLimitInput: &cloudwatch.ListMetricsInput{
MetricName: aws.String("CPUUtilization"),
Namespace: aws.String("AWS/EC2"),
Dimensions: []cloudwatchtypes.DimensionFilter{{Name: aws.String("InstanceId")}},
Dimensions: []*cloudwatch.DimensionFilter{{Name: aws.String("InstanceId")}},
IncludeLinkedAccounts: aws.Bool(true),
},
},
@@ -180,7 +178,7 @@ func TestListMetricsService_GetDimensionValuesByDimensionFilter(t *testing.T) {
listMetricsWithPageLimitInput: &cloudwatch.ListMetricsInput{
MetricName: aws.String("CPUUtilization"),
Namespace: aws.String("AWS/EC2"),
Dimensions: []cloudwatchtypes.DimensionFilter{{Name: aws.String("InstanceId")}},
Dimensions: []*cloudwatch.DimensionFilter{{Name: aws.String("InstanceId")}},
IncludeLinkedAccounts: aws.Bool(true),
OwningAccount: aws.String("1234567890"),
},
+10 -10
View File
@@ -3,9 +3,9 @@ package services
import (
"context"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/service/cloudwatchlogs"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models/resources"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/utils"
@@ -20,9 +20,9 @@ func NewLogGroupsService(logsClient models.CloudWatchLogsAPIProvider, isCrossAcc
return &LogGroupsService{logGroupsAPI: logsClient, isCrossAccountEnabled: isCrossAccountEnabled}
}
func (s *LogGroupsService) GetLogGroups(ctx context.Context, req resources.LogGroupsRequest) ([]resources.ResourceResponse[resources.LogGroup], error) {
func (s *LogGroupsService) GetLogGroupsWithContext(ctx context.Context, req resources.LogGroupsRequest) ([]resources.ResourceResponse[resources.LogGroup], error) {
input := &cloudwatchlogs.DescribeLogGroupsInput{
Limit: aws.Int32(req.Limit),
Limit: aws.Int64(req.Limit),
LogGroupNamePrefix: req.LogGroupNamePrefix,
}
@@ -33,13 +33,13 @@ func (s *LogGroupsService) GetLogGroups(ctx context.Context, req resources.LogGr
}
if !req.IsTargetingAllAccounts() {
// TODO: accept more than one account id in search
input.AccountIdentifiers = []string{*req.AccountId}
input.AccountIdentifiers = []*string{req.AccountId}
}
}
result := []resources.ResourceResponse[resources.LogGroup]{}
for {
response, err := s.logGroupsAPI.DescribeLogGroups(ctx, input)
response, err := s.logGroupsAPI.DescribeLogGroupsWithContext(ctx, input)
if err != nil || response == nil {
return nil, err
}
@@ -63,7 +63,7 @@ func (s *LogGroupsService) GetLogGroups(ctx context.Context, req resources.LogGr
return result, nil
}
func (s *LogGroupsService) GetLogGroupFields(ctx context.Context, request resources.LogGroupFieldsRequest) ([]resources.ResourceResponse[resources.LogGroupField], error) {
func (s *LogGroupsService) GetLogGroupFieldsWithContext(ctx context.Context, request resources.LogGroupFieldsRequest, option ...request.Option) ([]resources.ResourceResponse[resources.LogGroupField], error) {
input := &cloudwatchlogs.GetLogGroupFieldsInput{
LogGroupName: aws.String(request.LogGroupName),
}
@@ -73,7 +73,7 @@ func (s *LogGroupsService) GetLogGroupFields(ctx context.Context, request resour
// input.LogGroupName = nil
// }
getLogGroupFieldsOutput, err := s.logGroupsAPI.GetLogGroupFields(ctx, input)
getLogGroupFieldsOutput, err := s.logGroupsAPI.GetLogGroupFieldsWithContext(ctx, input)
if err != nil {
return nil, err
}
@@ -83,7 +83,7 @@ func (s *LogGroupsService) GetLogGroupFields(ctx context.Context, request resour
result = append(result, resources.ResourceResponse[resources.LogGroupField]{
Value: resources.LogGroupField{
Name: *logGroupField.Name,
Percent: int64(logGroupField.Percent),
Percent: *logGroupField.Percent,
},
})
}
+73 -76
View File
@@ -5,14 +5,11 @@ import (
"fmt"
"testing"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs"
cloudwatchlogstypes "github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs/types"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/cloudwatchlogs"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/mocks"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models/resources"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/utils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
@@ -20,9 +17,9 @@ import (
func TestGetLogGroups(t *testing.T) {
t.Run("Should map log groups response", func(t *testing.T) {
mockLogsAPI := &mocks.LogsAPI{}
mockLogsAPI.On("DescribeLogGroups", mock.Anything).Return(
mockLogsAPI.On("DescribeLogGroupsWithContext", mock.Anything).Return(
&cloudwatchlogs.DescribeLogGroupsOutput{
LogGroups: []cloudwatchlogstypes.LogGroup{
LogGroups: []*cloudwatchlogs.LogGroup{
{Arn: utils.Pointer("arn:aws:logs:us-east-1:111:log-group:group_a"), LogGroupName: utils.Pointer("group_a")},
{Arn: utils.Pointer("arn:aws:logs:us-east-1:222:log-group:group_b"), LogGroupName: utils.Pointer("group_b")},
{Arn: utils.Pointer("arn:aws:logs:us-east-1:333:log-group:group_c"), LogGroupName: utils.Pointer("group_c")},
@@ -30,7 +27,7 @@ func TestGetLogGroups(t *testing.T) {
}, nil)
service := NewLogGroupsService(mockLogsAPI, false)
resp, err := service.GetLogGroups(context.Background(), resources.LogGroupsRequest{})
resp, err := service.GetLogGroupsWithContext(context.Background(), resources.LogGroupsRequest{})
assert.NoError(t, err)
assert.Equal(t, []resources.ResourceResponse[resources.LogGroup]{
@@ -51,10 +48,10 @@ func TestGetLogGroups(t *testing.T) {
t.Run("Should return an empty error if api doesn't return any data", func(t *testing.T) {
mockLogsAPI := &mocks.LogsAPI{}
mockLogsAPI.On("DescribeLogGroups", mock.Anything).Return(&cloudwatchlogs.DescribeLogGroupsOutput{}, nil)
mockLogsAPI.On("DescribeLogGroupsWithContext", mock.Anything).Return(&cloudwatchlogs.DescribeLogGroupsOutput{}, nil)
service := NewLogGroupsService(mockLogsAPI, false)
resp, err := service.GetLogGroups(context.Background(), resources.LogGroupsRequest{})
resp, err := service.GetLogGroupsWithContext(context.Background(), resources.LogGroupsRequest{})
assert.NoError(t, err)
assert.Equal(t, []resources.ResourceResponse[resources.LogGroup]{}, resp)
@@ -63,41 +60,41 @@ func TestGetLogGroups(t *testing.T) {
t.Run("Should only use LogGroupNamePrefix even if LogGroupNamePattern passed in resource call", func(t *testing.T) {
// TODO: use LogGroupNamePattern when we have accounted for its behavior, still a little unexpected at the moment
mockLogsAPI := &mocks.LogsAPI{}
mockLogsAPI.On("DescribeLogGroups", mock.Anything).Return(&cloudwatchlogs.DescribeLogGroupsOutput{}, nil)
mockLogsAPI.On("DescribeLogGroupsWithContext", mock.Anything).Return(&cloudwatchlogs.DescribeLogGroupsOutput{}, nil)
service := NewLogGroupsService(mockLogsAPI, false)
_, err := service.GetLogGroups(context.Background(), resources.LogGroupsRequest{
_, err := service.GetLogGroupsWithContext(context.Background(), resources.LogGroupsRequest{
Limit: 0,
LogGroupNamePrefix: utils.Pointer("test"),
})
assert.NoError(t, err)
mockLogsAPI.AssertCalled(t, "DescribeLogGroups", &cloudwatchlogs.DescribeLogGroupsInput{
Limit: aws.Int32(0),
mockLogsAPI.AssertCalled(t, "DescribeLogGroupsWithContext", &cloudwatchlogs.DescribeLogGroupsInput{
Limit: utils.Pointer(int64(0)),
LogGroupNamePrefix: utils.Pointer("test"),
})
})
t.Run("Should call api without LogGroupNamePrefix nor LogGroupNamePattern if not passed in resource call", func(t *testing.T) {
mockLogsAPI := &mocks.LogsAPI{}
mockLogsAPI.On("DescribeLogGroups", mock.Anything).Return(&cloudwatchlogs.DescribeLogGroupsOutput{}, nil)
mockLogsAPI.On("DescribeLogGroupsWithContext", mock.Anything).Return(&cloudwatchlogs.DescribeLogGroupsOutput{}, nil)
service := NewLogGroupsService(mockLogsAPI, false)
_, err := service.GetLogGroups(context.Background(), resources.LogGroupsRequest{})
_, err := service.GetLogGroupsWithContext(context.Background(), resources.LogGroupsRequest{})
assert.NoError(t, err)
mockLogsAPI.AssertCalled(t, "DescribeLogGroups", &cloudwatchlogs.DescribeLogGroupsInput{
Limit: aws.Int32(0),
mockLogsAPI.AssertCalled(t, "DescribeLogGroupsWithContext", &cloudwatchlogs.DescribeLogGroupsInput{
Limit: utils.Pointer(int64(0)),
})
})
t.Run("Should return an error when API returns error", func(t *testing.T) {
mockLogsAPI := &mocks.LogsAPI{}
mockLogsAPI.On("DescribeLogGroups", mock.Anything).Return(&cloudwatchlogs.DescribeLogGroupsOutput{},
mockLogsAPI.On("DescribeLogGroupsWithContext", mock.Anything).Return(&cloudwatchlogs.DescribeLogGroupsOutput{},
fmt.Errorf("some error"))
service := NewLogGroupsService(mockLogsAPI, false)
_, err := service.GetLogGroups(context.Background(), resources.LogGroupsRequest{})
_, err := service.GetLogGroupsWithContext(context.Background(), resources.LogGroupsRequest{})
assert.Error(t, err)
assert.Equal(t, "some error", err.Error())
@@ -111,21 +108,21 @@ func TestGetLogGroups(t *testing.T) {
ListAllLogGroups: false,
}
mockLogsAPI.On("DescribeLogGroups", &cloudwatchlogs.DescribeLogGroupsInput{
Limit: aws.Int32(req.Limit),
mockLogsAPI.On("DescribeLogGroupsWithContext", &cloudwatchlogs.DescribeLogGroupsInput{
Limit: aws.Int64(req.Limit),
LogGroupNamePrefix: req.LogGroupNamePrefix,
}).Return(&cloudwatchlogs.DescribeLogGroupsOutput{
LogGroups: []cloudwatchlogstypes.LogGroup{
LogGroups: []*cloudwatchlogs.LogGroup{
{Arn: utils.Pointer("arn:aws:logs:us-east-1:111:log-group:group_a"), LogGroupName: utils.Pointer("group_a")},
},
NextToken: aws.String("next_token"),
}, nil)
service := NewLogGroupsService(mockLogsAPI, false)
resp, err := service.GetLogGroups(context.Background(), req)
resp, err := service.GetLogGroupsWithContext(context.Background(), req)
assert.NoError(t, err)
mockLogsAPI.AssertNumberOfCalls(t, "DescribeLogGroups", 1)
mockLogsAPI.AssertNumberOfCalls(t, "DescribeLogGroupsWithContext", 1)
assert.Equal(t, []resources.ResourceResponse[resources.LogGroup]{
{
AccountId: utils.Pointer("111"),
@@ -143,30 +140,30 @@ func TestGetLogGroups(t *testing.T) {
}
// first call
mockLogsAPI.On("DescribeLogGroups", &cloudwatchlogs.DescribeLogGroupsInput{
Limit: aws.Int32(req.Limit),
mockLogsAPI.On("DescribeLogGroupsWithContext", &cloudwatchlogs.DescribeLogGroupsInput{
Limit: aws.Int64(req.Limit),
LogGroupNamePrefix: req.LogGroupNamePrefix,
}).Return(&cloudwatchlogs.DescribeLogGroupsOutput{
LogGroups: []cloudwatchlogstypes.LogGroup{
LogGroups: []*cloudwatchlogs.LogGroup{
{Arn: utils.Pointer("arn:aws:logs:us-east-1:111:log-group:group_a"), LogGroupName: utils.Pointer("group_a")},
},
NextToken: utils.Pointer("token"),
}, nil)
// second call
mockLogsAPI.On("DescribeLogGroups", &cloudwatchlogs.DescribeLogGroupsInput{
Limit: aws.Int32(req.Limit),
mockLogsAPI.On("DescribeLogGroupsWithContext", &cloudwatchlogs.DescribeLogGroupsInput{
Limit: aws.Int64(req.Limit),
LogGroupNamePrefix: req.LogGroupNamePrefix,
NextToken: utils.Pointer("token"),
}).Return(&cloudwatchlogs.DescribeLogGroupsOutput{
LogGroups: []cloudwatchlogstypes.LogGroup{
LogGroups: []*cloudwatchlogs.LogGroup{
{Arn: utils.Pointer("arn:aws:logs:us-east-1:222:log-group:group_b"), LogGroupName: utils.Pointer("group_b")},
},
}, nil)
service := NewLogGroupsService(mockLogsAPI, false)
resp, err := service.GetLogGroups(context.Background(), req)
resp, err := service.GetLogGroupsWithContext(context.Background(), req)
assert.NoError(t, err)
mockLogsAPI.AssertNumberOfCalls(t, "DescribeLogGroups", 2)
mockLogsAPI.AssertNumberOfCalls(t, "DescribeLogGroupsWithContext", 2)
assert.Equal(t, []resources.ResourceResponse[resources.LogGroup]{
{
AccountId: utils.Pointer("111"),
@@ -183,36 +180,36 @@ func TestGetLogGroups(t *testing.T) {
func TestGetLogGroupsCrossAccountQuerying(t *testing.T) {
t.Run("Should not includeLinkedAccounts or accountId if isCrossAccountEnabled is set to false", func(t *testing.T) {
mockLogsAPI := &mocks.LogsAPI{}
mockLogsAPI.On("DescribeLogGroups", mock.Anything).Return(&cloudwatchlogs.DescribeLogGroupsOutput{}, nil)
mockLogsAPI.On("DescribeLogGroupsWithContext", mock.Anything).Return(&cloudwatchlogs.DescribeLogGroupsOutput{}, nil)
service := NewLogGroupsService(mockLogsAPI, false)
_, err := service.GetLogGroups(context.Background(), resources.LogGroupsRequest{
_, err := service.GetLogGroupsWithContext(context.Background(), resources.LogGroupsRequest{
ResourceRequest: resources.ResourceRequest{AccountId: utils.Pointer("accountId")},
LogGroupNamePrefix: utils.Pointer("prefix"),
})
assert.NoError(t, err)
mockLogsAPI.AssertCalled(t, "DescribeLogGroups", &cloudwatchlogs.DescribeLogGroupsInput{
Limit: aws.Int32(0),
mockLogsAPI.AssertCalled(t, "DescribeLogGroupsWithContext", &cloudwatchlogs.DescribeLogGroupsInput{
Limit: utils.Pointer(int64(0)),
LogGroupNamePrefix: utils.Pointer("prefix"),
})
})
t.Run("Should replace LogGroupNamePrefix if LogGroupNamePattern passed in resource call", func(t *testing.T) {
mockLogsAPI := &mocks.LogsAPI{}
mockLogsAPI.On("DescribeLogGroups", mock.Anything).Return(&cloudwatchlogs.DescribeLogGroupsOutput{}, nil)
mockLogsAPI.On("DescribeLogGroupsWithContext", mock.Anything).Return(&cloudwatchlogs.DescribeLogGroupsOutput{}, nil)
service := NewLogGroupsService(mockLogsAPI, true)
_, err := service.GetLogGroups(context.Background(), resources.LogGroupsRequest{
_, err := service.GetLogGroupsWithContext(context.Background(), resources.LogGroupsRequest{
ResourceRequest: resources.ResourceRequest{AccountId: utils.Pointer("accountId")},
LogGroupNamePrefix: utils.Pointer("prefix"),
LogGroupNamePattern: utils.Pointer("pattern"),
})
assert.NoError(t, err)
mockLogsAPI.AssertCalled(t, "DescribeLogGroups", &cloudwatchlogs.DescribeLogGroupsInput{
AccountIdentifiers: []string{"accountId"},
Limit: aws.Int32(0),
mockLogsAPI.AssertCalled(t, "DescribeLogGroupsWithContext", &cloudwatchlogs.DescribeLogGroupsInput{
AccountIdentifiers: []*string{utils.Pointer("accountId")},
Limit: utils.Pointer(int64(0)),
LogGroupNamePrefix: utils.Pointer("pattern"),
IncludeLinkedAccounts: utils.Pointer(true),
})
@@ -220,34 +217,34 @@ func TestGetLogGroupsCrossAccountQuerying(t *testing.T) {
t.Run("Should includeLinkedAccounts,and accountId if isCrossAccountEnabled is set to true", func(t *testing.T) {
mockLogsAPI := &mocks.LogsAPI{}
mockLogsAPI.On("DescribeLogGroups", mock.Anything).Return(&cloudwatchlogs.DescribeLogGroupsOutput{}, nil)
mockLogsAPI.On("DescribeLogGroupsWithContext", mock.Anything).Return(&cloudwatchlogs.DescribeLogGroupsOutput{}, nil)
service := NewLogGroupsService(mockLogsAPI, true)
_, err := service.GetLogGroups(context.Background(), resources.LogGroupsRequest{
_, err := service.GetLogGroupsWithContext(context.Background(), resources.LogGroupsRequest{
ResourceRequest: resources.ResourceRequest{AccountId: utils.Pointer("accountId")},
})
assert.NoError(t, err)
mockLogsAPI.AssertCalled(t, "DescribeLogGroups", &cloudwatchlogs.DescribeLogGroupsInput{
Limit: aws.Int32(0),
mockLogsAPI.AssertCalled(t, "DescribeLogGroupsWithContext", &cloudwatchlogs.DescribeLogGroupsInput{
Limit: utils.Pointer(int64(0)),
IncludeLinkedAccounts: utils.Pointer(true),
AccountIdentifiers: []string{"accountId"},
AccountIdentifiers: []*string{utils.Pointer("accountId")},
})
})
t.Run("Should should not override prefix is there is no logGroupNamePattern", func(t *testing.T) {
mockLogsAPI := &mocks.LogsAPI{}
mockLogsAPI.On("DescribeLogGroups", mock.Anything).Return(&cloudwatchlogs.DescribeLogGroupsOutput{}, nil)
mockLogsAPI.On("DescribeLogGroupsWithContext", mock.Anything).Return(&cloudwatchlogs.DescribeLogGroupsOutput{}, nil)
service := NewLogGroupsService(mockLogsAPI, true)
_, err := service.GetLogGroups(context.Background(), resources.LogGroupsRequest{
_, err := service.GetLogGroupsWithContext(context.Background(), resources.LogGroupsRequest{
ResourceRequest: resources.ResourceRequest{AccountId: utils.Pointer("accountId")},
LogGroupNamePrefix: utils.Pointer("prefix"),
})
assert.NoError(t, err)
mockLogsAPI.AssertCalled(t, "DescribeLogGroups", &cloudwatchlogs.DescribeLogGroupsInput{
AccountIdentifiers: []string{"accountId"},
Limit: aws.Int32(0),
mockLogsAPI.AssertCalled(t, "DescribeLogGroupsWithContext", &cloudwatchlogs.DescribeLogGroupsInput{
AccountIdentifiers: []*string{utils.Pointer("accountId")},
Limit: utils.Pointer(int64(0)),
LogGroupNamePrefix: utils.Pointer("prefix"),
IncludeLinkedAccounts: utils.Pointer(true),
})
@@ -255,26 +252,26 @@ func TestGetLogGroupsCrossAccountQuerying(t *testing.T) {
t.Run("Should not includeLinkedAccounts, or accountId if accountId is nil", func(t *testing.T) {
mockLogsAPI := &mocks.LogsAPI{}
mockLogsAPI.On("DescribeLogGroups", mock.Anything).Return(&cloudwatchlogs.DescribeLogGroupsOutput{}, nil)
mockLogsAPI.On("DescribeLogGroupsWithContext", mock.Anything).Return(&cloudwatchlogs.DescribeLogGroupsOutput{}, nil)
service := NewLogGroupsService(mockLogsAPI, true)
_, err := service.GetLogGroups(context.Background(), resources.LogGroupsRequest{
_, err := service.GetLogGroupsWithContext(context.Background(), resources.LogGroupsRequest{
LogGroupNamePrefix: utils.Pointer("prefix"),
})
assert.NoError(t, err)
mockLogsAPI.AssertCalled(t, "DescribeLogGroups", &cloudwatchlogs.DescribeLogGroupsInput{
Limit: aws.Int32(0),
mockLogsAPI.AssertCalled(t, "DescribeLogGroupsWithContext", &cloudwatchlogs.DescribeLogGroupsInput{
Limit: utils.Pointer(int64(0)),
LogGroupNamePrefix: utils.Pointer("prefix"),
})
})
t.Run("Should should not override prefix is there is no logGroupNamePattern", func(t *testing.T) {
mockLogsAPI := &mocks.LogsAPI{}
mockLogsAPI.On("DescribeLogGroups", mock.Anything).Return(&cloudwatchlogs.DescribeLogGroupsOutput{}, nil)
mockLogsAPI.On("DescribeLogGroupsWithContext", mock.Anything).Return(&cloudwatchlogs.DescribeLogGroupsOutput{}, nil)
service := NewLogGroupsService(mockLogsAPI, true)
_, err := service.GetLogGroups(context.Background(), resources.LogGroupsRequest{
_, err := service.GetLogGroupsWithContext(context.Background(), resources.LogGroupsRequest{
ResourceRequest: resources.ResourceRequest{
AccountId: utils.Pointer("accountId"),
},
@@ -282,10 +279,10 @@ func TestGetLogGroupsCrossAccountQuerying(t *testing.T) {
})
assert.NoError(t, err)
mockLogsAPI.AssertCalled(t, "DescribeLogGroups", &cloudwatchlogs.DescribeLogGroupsInput{
AccountIdentifiers: []string{"accountId"},
mockLogsAPI.AssertCalled(t, "DescribeLogGroupsWithContext", &cloudwatchlogs.DescribeLogGroupsInput{
AccountIdentifiers: []*string{utils.Pointer("accountId")},
IncludeLinkedAccounts: utils.Pointer(true),
Limit: aws.Int32(0),
Limit: utils.Pointer(int64(0)),
LogGroupNamePrefix: utils.Pointer("prefix"),
})
})
@@ -294,24 +291,24 @@ func TestGetLogGroupsCrossAccountQuerying(t *testing.T) {
func TestGetLogGroupFields(t *testing.T) {
t.Run("Should map log group fields response", func(t *testing.T) {
mockLogsAPI := &mocks.LogsAPI{}
mockLogsAPI.On("GetLogGroupFields", mock.Anything).Return(
mockLogsAPI.On("GetLogGroupFieldsWithContext", mock.Anything).Return(
&cloudwatchlogs.GetLogGroupFieldsOutput{
LogGroupFields: []cloudwatchlogstypes.LogGroupField{
LogGroupFields: []*cloudwatchlogs.LogGroupField{
{
Name: aws.String("field1"),
Percent: 10,
Name: utils.Pointer("field1"),
Percent: utils.Pointer(int64(10)),
}, {
Name: aws.String("field2"),
Percent: 10,
Name: utils.Pointer("field2"),
Percent: utils.Pointer(int64(10)),
}, {
Name: aws.String("field3"),
Percent: 10,
Name: utils.Pointer("field3"),
Percent: utils.Pointer(int64(10)),
},
},
}, nil)
service := NewLogGroupsService(mockLogsAPI, false)
resp, err := service.GetLogGroupFields(context.Background(), resources.LogGroupFieldsRequest{})
resp, err := service.GetLogGroupFieldsWithContext(context.Background(), resources.LogGroupFieldsRequest{})
assert.NoError(t, err)
assert.Equal(t, []resources.ResourceResponse[resources.LogGroupField]{
@@ -359,16 +356,16 @@ func TestGetLogGroupFields(t *testing.T) {
// remove this test once the above test is uncommented
t.Run("Should only set LogGroupName as api input in case both LogGroupName and LogGroupARN are specified", func(t *testing.T) {
mockLogsAPI := &mocks.LogsAPI{}
mockLogsAPI.On("GetLogGroupFields", mock.Anything).Return(
mockLogsAPI.On("GetLogGroupFieldsWithContext", mock.Anything).Return(
&cloudwatchlogs.GetLogGroupFieldsOutput{}, nil)
service := NewLogGroupsService(mockLogsAPI, false)
resp, err := service.GetLogGroupFields(context.Background(), resources.LogGroupFieldsRequest{
resp, err := service.GetLogGroupFieldsWithContext(context.Background(), resources.LogGroupFieldsRequest{
LogGroupName: "logGroupName",
LogGroupARN: "logGroupARN",
})
mockLogsAPI.AssertCalled(t, "GetLogGroupFields", &cloudwatchlogs.GetLogGroupFieldsInput{
mockLogsAPI.AssertCalled(t, "GetLogGroupFieldsWithContext", &cloudwatchlogs.GetLogGroupFieldsInput{
LogGroupIdentifier: nil,
LogGroupName: utils.Pointer("logGroupName"),
})
@@ -378,16 +375,16 @@ func TestGetLogGroupFields(t *testing.T) {
t.Run("Should only set LogGroupName as api input in case only LogGroupName is specified", func(t *testing.T) {
mockLogsAPI := &mocks.LogsAPI{}
mockLogsAPI.On("GetLogGroupFields", mock.Anything).Return(
mockLogsAPI.On("GetLogGroupFieldsWithContext", mock.Anything).Return(
&cloudwatchlogs.GetLogGroupFieldsOutput{}, nil)
service := NewLogGroupsService(mockLogsAPI, false)
resp, err := service.GetLogGroupFields(context.Background(), resources.LogGroupFieldsRequest{
resp, err := service.GetLogGroupFieldsWithContext(context.Background(), resources.LogGroupFieldsRequest{
LogGroupName: "logGroupName",
LogGroupARN: "",
})
mockLogsAPI.AssertCalled(t, "GetLogGroupFields", &cloudwatchlogs.GetLogGroupFieldsInput{
mockLogsAPI.AssertCalled(t, "GetLogGroupFieldsWithContext", &cloudwatchlogs.GetLogGroupFieldsInput{
LogGroupIdentifier: nil,
LogGroupName: utils.Pointer("logGroupName"),
})
+4 -8
View File
@@ -4,9 +4,7 @@ import (
"context"
"sort"
"github.com/aws/aws-sdk-go-v2/service/ec2"
ec2types "github.com/aws/aws-sdk-go-v2/service/ec2/types"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/constants"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models"
@@ -25,7 +23,7 @@ func NewRegionsService(ec2client models.EC2APIProvider, logger log.Logger) model
}
}
func mergeEC2RegionsAndConstantRegions(regions map[string]struct{}, ec2Regions []ec2types.Region) {
func mergeEC2RegionsAndConstantRegions(regions map[string]struct{}, ec2Regions []*ec2.Region) {
for _, region := range ec2Regions {
if _, ok := regions[*region.RegionName]; !ok {
regions[*region.RegionName] = struct{}{}
@@ -38,7 +36,7 @@ func (r *RegionsService) GetRegions(ctx context.Context) ([]resources.ResourceRe
result := make([]resources.ResourceResponse[resources.Region], 0)
ec2Regions, err := r.DescribeRegions(ctx, &ec2.DescribeRegionsInput{})
ec2Regions, err := r.DescribeRegionsWithContext(ctx, &ec2.DescribeRegionsInput{})
// we ignore this error and always send default regions
// we only fetch incase a user has enabled additional regions
// but we still log it in case the user is expecting to fetch regions specific to their account and are unable to
@@ -46,9 +44,7 @@ func (r *RegionsService) GetRegions(ctx context.Context) ([]resources.ResourceRe
r.Error("Failed to get regions: ", "error", err)
}
if ec2Regions != nil {
mergeEC2RegionsAndConstantRegions(regions, ec2Regions.Regions)
}
mergeEC2RegionsAndConstantRegions(regions, ec2Regions.Regions)
for region := range regions {
result = append(result, resources.ResourceResponse[resources.Region]{
+5 -7
View File
@@ -4,9 +4,7 @@ import (
"context"
"testing"
"github.com/aws/aws-sdk-go-v2/service/ec2"
ec2types "github.com/aws/aws-sdk-go-v2/service/ec2/types"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/mocks"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models/resources"
@@ -19,14 +17,14 @@ var testLogger = log.New().With("logger", "test.logger")
func TestRegions(t *testing.T) {
t.Run("returns regions from the api and merges them with default regions", func(t *testing.T) {
mockRegions := &ec2.DescribeRegionsOutput{
Regions: []ec2types.Region{
Regions: []*ec2.Region{
{
RegionName: utils.Pointer("earth-1"),
},
},
}
ec2Mock := &mocks.EC2Mock{}
ec2Mock.On("DescribeRegions").Return(mockRegions, nil)
ec2Mock.On("DescribeRegionsWithContext").Return(mockRegions, nil)
regions, err := NewRegionsService(ec2Mock, testLogger).GetRegions(context.Background())
assert.NoError(t, err)
assert.Contains(t, regions, resources.ResourceResponse[resources.Region]{
@@ -44,9 +42,9 @@ func TestRegions(t *testing.T) {
t.Run("always returns default regions, even if fetch fails", func(t *testing.T) {
ec2Mock := &mocks.EC2Mock{}
mockRegions := &ec2.DescribeRegionsOutput{
Regions: []ec2types.Region{},
Regions: []*ec2.Region{},
}
ec2Mock.On("DescribeRegions").Return(mockRegions, assert.AnError)
ec2Mock.On("DescribeRegionsWithContext").Return(mockRegions, assert.AnError)
regions, err := NewRegionsService(ec2Mock, testLogger).GetRegions(context.Background())
assert.NoError(t, err)
assert.Contains(t, regions, resources.ResourceResponse[resources.Region]{