grafana/pkg/tsdb/cloudwatch/services/accounts.go
Shabeeb Khalid df41378472
CloudWatch: Use context in aws ListSinks and ListAttachedLinks (#77083)
* Use context in aws ListSinks and ListAttachedLinks

In the current way, ListSinks and ListAttachedLinks is used which doesn't
allow cancelling the request if the context changes.
Using ListSinksWithContext and ListAttachedLinksWithContext is the
preferred way. Adding context for GetAccountsForCurrentUserOrRole
is required to pass it to ListSinks method.
2023-10-27 11:49:37 +03:00

91 lines
2.3 KiB
Go

package services
import (
"context"
"errors"
"fmt"
"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"
)
var ErrAccessDeniedException = errors.New("access denied. please check your IAM policy")
type AccountsService struct {
models.OAMAPIProvider
}
func NewAccountsService(oamClient models.OAMAPIProvider) models.AccountsProvider {
return &AccountsService{oamClient}
}
func (a *AccountsService) GetAccountsForCurrentUserOrRole(ctx context.Context) ([]resources.ResourceResponse[resources.Account], error) {
var nextToken *string
sinks := []*oam.ListSinksItem{}
for {
response, err := a.ListSinksWithContext(ctx, &oam.ListSinksInput{NextToken: nextToken})
if err != nil {
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)
}
sinks = append(sinks, response.Items...)
if response.NextToken == nil {
break
}
nextToken = response.NextToken
}
if len(sinks) == 0 {
return nil, nil
}
sinkIdentifier := sinks[0].Arn
response := []resources.Account{{
Id: getAccountId(*sinkIdentifier),
Label: *sinks[0].Name,
Arn: *sinkIdentifier,
IsMonitoringAccount: true,
}}
nextToken = nil
for {
links, err := a.ListAttachedLinksWithContext(ctx, &oam.ListAttachedLinksInput{
SinkIdentifier: sinkIdentifier,
NextToken: nextToken,
})
if err != nil {
return nil, fmt.Errorf("ListAttachedLinks error: %w", err)
}
for _, link := range links.Items {
arn := *link.LinkArn
response = append(response, resources.Account{
Id: getAccountId(arn),
Label: *link.Label,
Arn: arn,
IsMonitoringAccount: false,
})
}
if links.NextToken == nil {
break
}
nextToken = links.NextToken
}
return valuesToListMetricRespone(response), nil
}