2025-04-01 10:38:02 +09: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
}