Cloudwatch: Revert aws sdk go v2 (#103644)
* Revert "CloudWatch: Import new grafana-aws-sdk with PDC fix (#103249)" This reverts commitf2b5b4e0c0. * Revert "CloudWatch: Migrate to aws-sdk-go-v2 (#103106)" This reverts commita65cc0df93. * make update-workspace
This commit is contained in:
@@ -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,
|
||||
})
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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"),
|
||||
},
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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,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]{
|
||||
|
||||
@@ -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]{
|
||||
|
||||
Reference in New Issue
Block a user