diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index 03a65ad5..823e96d6 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -51,7 +51,7 @@ jobs: fi - name: Vet - run: go vet + run: go vet ./... # get .golangci.yml from github.com/overmindtech/golangci-lint_config - name: Get .golangci.yml from github.com/overmindtech/golangci-lint_configs diff --git a/sources/always_get_source.go b/adapters/always_get_source.go similarity index 74% rename from sources/always_get_source.go rename to adapters/always_get_source.go index 4af50750..27d1b326 100644 --- a/sources/always_get_source.go +++ b/adapters/always_get_source.go @@ -1,4 +1,4 @@ -package sources +package adapters import ( "context" @@ -25,18 +25,19 @@ func (m MaxParallel) Value() int { return int(m) } -// AlwaysGetSource This source is designed for AWS APIs that have separate List +// AlwaysGetAdapter This adapter is designed for AWS APIs that have separate List // and Get functions. It also assumes that the results of the list function // cannot be converted directly into items as they do not contain enough // information, and therefore they always need to be passed to the Get function // before returning. An example is the `ListClusters` API in EKS which returns a // list of cluster names. -type AlwaysGetSource[ListInput InputType, ListOutput OutputType, GetInput InputType, GetOutput OutputType, ClientStruct ClientStructType, Options OptionsType] struct { - ItemType string // The type of items to return - Client ClientStruct // The AWS API client - AccountID string // The AWS account ID - Region string // The AWS region this is related to - MaxParallel MaxParallel // How many Get request to run in parallel for a single List request +type AlwaysGetAdapter[ListInput InputType, ListOutput OutputType, GetInput InputType, GetOutput OutputType, ClientStruct ClientStructType, Options OptionsType] struct { + ItemType string // The type of items to return + Client ClientStruct // The AWS API client + AccountID string // The AWS account ID + Region string // The AWS region this is related to + MaxParallel MaxParallel // How many Get request to run in parallel for a single List request + AdapterMetadata sdp.AdapterMetadata // Disables List(), meaning all calls will return empty results. This does // not affect Search() @@ -60,12 +61,12 @@ type AlwaysGetSource[ListInput InputType, ListOutput OutputType, GetInput InputT // Maps search terms from an SDP Search request into the relevant input for // the ListFunc. If this is not set, Search() will handle ARNs like most AWS - // sources. Note that this and `SearchGetInputMapper` are mutually exclusive + // adapters. Note that this and `SearchGetInputMapper` are mutually exclusive SearchInputMapper func(scope, query string) (ListInput, error) // Maps search terms from an SDP Search request into the relevant input for // the GetFunc. If this is not set, Search() will handle ARNs like most AWS - // sources. Note that this and `SearchInputMapper` are mutually exclusive + // adapters. Note that this and `SearchInputMapper` are mutually exclusive SearchGetInputMapper func(scope, query string) (GetInput, error) // A function that returns a paginator for the ListFunc @@ -77,11 +78,11 @@ type AlwaysGetSource[ListInput InputType, ListOutput OutputType, GetInput InputT ListFuncOutputMapper func(output ListOutput, input ListInput) ([]GetInput, error) CacheDuration time.Duration // How long to cache items for - cache *sdpcache.Cache // The sdpcache of this source + cache *sdpcache.Cache // The sdpcache of this adapter cacheInitMu sync.Mutex // Mutex to ensure cache is only initialised once } -func (s *AlwaysGetSource[ListInput, ListOutput, GetInput, GetOutput, ClientStruct, Options]) cacheDuration() time.Duration { +func (s *AlwaysGetAdapter[ListInput, ListOutput, GetInput, GetOutput, ClientStruct, Options]) cacheDuration() time.Duration { if s.CacheDuration == 0 { return DefaultCacheDuration } @@ -89,7 +90,7 @@ func (s *AlwaysGetSource[ListInput, ListOutput, GetInput, GetOutput, ClientStruc return s.CacheDuration } -func (s *AlwaysGetSource[ListInput, ListOutput, GetInput, GetOutput, ClientStruct, Options]) ensureCache() { +func (s *AlwaysGetAdapter[ListInput, ListOutput, GetInput, GetOutput, ClientStruct, Options]) ensureCache() { s.cacheInitMu.Lock() defer s.cacheInitMu.Unlock() @@ -98,13 +99,13 @@ func (s *AlwaysGetSource[ListInput, ListOutput, GetInput, GetOutput, ClientStruc } } -func (s *AlwaysGetSource[ListInput, ListOutput, GetInput, GetOutput, ClientStruct, Options]) Cache() *sdpcache.Cache { +func (s *AlwaysGetAdapter[ListInput, ListOutput, GetInput, GetOutput, ClientStruct, Options]) Cache() *sdpcache.Cache { s.ensureCache() return s.cache } -// Validate Checks that the source has been set up correctly -func (s *AlwaysGetSource[ListInput, ListOutput, GetInput, GetOutput, ClientStruct, Options]) Validate() error { +// Validate Checks that the adapter has been set up correctly +func (s *AlwaysGetAdapter[ListInput, ListOutput, GetInput, GetOutput, ClientStruct, Options]) Validate() error { if !s.DisableList { if s.ListFuncPaginatorBuilder == nil { return errors.New("ListFuncPaginatorBuilder is nil") @@ -130,27 +131,31 @@ func (s *AlwaysGetSource[ListInput, ListOutput, GetInput, GetOutput, ClientStruc return nil } -func (s *AlwaysGetSource[ListInput, ListOutput, GetInput, GetOutput, ClientStruct, Options]) Type() string { +func (s *AlwaysGetAdapter[ListInput, ListOutput, GetInput, GetOutput, ClientStruct, Options]) Type() string { return s.ItemType } -func (s *AlwaysGetSource[ListInput, ListOutput, GetInput, GetOutput, ClientStruct, Options]) Name() string { - return fmt.Sprintf("%v-source", s.ItemType) +func (s *AlwaysGetAdapter[ListInput, ListOutput, GetInput, GetOutput, ClientStruct, Options]) Name() string { + return fmt.Sprintf("%v-adapter", s.ItemType) } -// List of scopes that this source is capable of find items for. This will be +func (s *AlwaysGetAdapter[ListInput, ListOutput, GetInput, GetOutput, ClientStruct, Options]) Metadata() *sdp.AdapterMetadata { + return &s.AdapterMetadata +} + +// List of scopes that this adapter is capable of find items for. This will be // in the format {accountID}.{region} -func (s *AlwaysGetSource[ListInput, ListOutput, GetInput, GetOutput, ClientStruct, Options]) Scopes() []string { +func (s *AlwaysGetAdapter[ListInput, ListOutput, GetInput, GetOutput, ClientStruct, Options]) Scopes() []string { return []string{ FormatScope(s.AccountID, s.Region), } } -func (s *AlwaysGetSource[ListInput, ListOutput, GetInput, GetOutput, ClientStruct, Options]) Get(ctx context.Context, scope string, query string, ignoreCache bool) (*sdp.Item, error) { +func (s *AlwaysGetAdapter[ListInput, ListOutput, GetInput, GetOutput, ClientStruct, Options]) Get(ctx context.Context, scope string, query string, ignoreCache bool) (*sdp.Item, error) { if scope != s.Scopes()[0] { return nil, &sdp.QueryError{ ErrorType: sdp.QueryError_NOSCOPE, - ErrorString: fmt.Sprintf("requested scope %v does not match source scope %v", scope, s.Scopes()[0]), + ErrorString: fmt.Sprintf("requested scope %v does not match adapter scope %v", scope, s.Scopes()[0]), } } @@ -192,11 +197,11 @@ func (s *AlwaysGetSource[ListInput, ListOutput, GetInput, GetOutput, ClientStruc // List Lists all available items. This is done by running the ListFunc, then // passing these results to GetFunc in order to get the details -func (s *AlwaysGetSource[ListInput, ListOutput, GetInput, GetOutput, ClientStruct, Options]) List(ctx context.Context, scope string, ignoreCache bool) ([]*sdp.Item, error) { +func (s *AlwaysGetAdapter[ListInput, ListOutput, GetInput, GetOutput, ClientStruct, Options]) List(ctx context.Context, scope string, ignoreCache bool) ([]*sdp.Item, error) { if scope != s.Scopes()[0] { return nil, &sdp.QueryError{ ErrorType: sdp.QueryError_NOSCOPE, - ErrorString: fmt.Sprintf("requested scope %v does not match source scope %v", scope, s.Scopes()[0]), + ErrorString: fmt.Sprintf("requested scope %v does not match adapter scope %v", scope, s.Scopes()[0]), } } @@ -232,7 +237,7 @@ func (s *AlwaysGetSource[ListInput, ListOutput, GetInput, GetOutput, ClientStruc } // listInternal Accepts a ListInput and runs the List logic against it -func (s *AlwaysGetSource[ListInput, ListOutput, GetInput, GetOutput, ClientStruct, Options]) listInternal(ctx context.Context, scope string, input ListInput) ([]*sdp.Item, error) { +func (s *AlwaysGetAdapter[ListInput, ListOutput, GetInput, GetOutput, ClientStruct, Options]) listInternal(ctx context.Context, scope string, input ListInput) ([]*sdp.Item, error) { var output ListOutput var err error items := make([]*sdp.Item, 0) @@ -327,11 +332,11 @@ func (s *AlwaysGetSource[ListInput, ListOutput, GetInput, GetOutput, ClientStruc } // Search Searches for AWS resources by ARN -func (s *AlwaysGetSource[ListInput, ListOutput, GetInput, GetOutput, ClientStruct, Options]) Search(ctx context.Context, scope string, query string, ignoreCache bool) ([]*sdp.Item, error) { +func (s *AlwaysGetAdapter[ListInput, ListOutput, GetInput, GetOutput, ClientStruct, Options]) Search(ctx context.Context, scope string, query string, ignoreCache bool) ([]*sdp.Item, error) { if scope != s.Scopes()[0] { return nil, &sdp.QueryError{ ErrorType: sdp.QueryError_NOSCOPE, - ErrorString: fmt.Sprintf("requested scope %v does not match source scope %v", scope, s.Scopes()[0]), + ErrorString: fmt.Sprintf("requested scope %v does not match adapter scope %v", scope, s.Scopes()[0]), } } @@ -362,7 +367,7 @@ func (s *AlwaysGetSource[ListInput, ListOutput, GetInput, GetOutput, ClientStruc // SearchCustom Searches using custom mapping logic. The SearchInputMapper is // used to create an input for ListFunc, at which point the usual logic is used -func (s *AlwaysGetSource[ListInput, ListOutput, GetInput, GetOutput, ClientStruct, Options]) SearchCustom(ctx context.Context, scope string, query string, ignoreCache bool) ([]*sdp.Item, error) { +func (s *AlwaysGetAdapter[ListInput, ListOutput, GetInput, GetOutput, ClientStruct, Options]) SearchCustom(ctx context.Context, scope string, query string, ignoreCache bool) ([]*sdp.Item, error) { s.ensureCache() cacheHit, ck, cachedItems, qErr := s.cache.Lookup(ctx, s.Name(), sdp.QueryMethod_SEARCH, scope, s.ItemType, query, ignoreCache) if qErr != nil { @@ -420,7 +425,7 @@ func (s *AlwaysGetSource[ListInput, ListOutput, GetInput, GetOutput, ClientStruc return items, nil } -func (s *AlwaysGetSource[ListInput, ListOutput, GetInput, GetOutput, ClientStruct, Options]) SearchARN(ctx context.Context, scope string, query string, ignoreCache bool) ([]*sdp.Item, error) { +func (s *AlwaysGetAdapter[ListInput, ListOutput, GetInput, GetOutput, ClientStruct, Options]) SearchARN(ctx context.Context, scope string, query string, ignoreCache bool) ([]*sdp.Item, error) { // Parse the ARN a, err := ParseARN(query) @@ -448,6 +453,6 @@ func (s *AlwaysGetSource[ListInput, ListOutput, GetInput, GetOutput, ClientStruc // This is used to resolve conflicts where two sources of the same type // return an item for a GET request. In this instance only one item can be // seen on, so the one with the higher weight value will win. -func (s *AlwaysGetSource[ListInput, ListOutput, GetInput, GetOutput, ClientStruct, Options]) Weight() int { +func (s *AlwaysGetAdapter[ListInput, ListOutput, GetInput, GetOutput, ClientStruct, Options]) Weight() int { return 100 } diff --git a/sources/always_get_source_test.go b/adapters/always_get_source_test.go similarity index 93% rename from sources/always_get_source_test.go rename to adapters/always_get_source_test.go index 025837e2..49513b82 100644 --- a/sources/always_get_source_test.go +++ b/adapters/always_get_source_test.go @@ -1,4 +1,4 @@ -package sources +package adapters import ( "context" @@ -19,7 +19,7 @@ func TestMaxParallel(t *testing.T) { } func TestAlwaysGetSourceType(t *testing.T) { - lgs := AlwaysGetSource[any, any, any, any, any, any]{ + lgs := AlwaysGetAdapter[any, any, any, any, any, any]{ ItemType: "foo", } @@ -29,17 +29,17 @@ func TestAlwaysGetSourceType(t *testing.T) { } func TestAlwaysGetSourceName(t *testing.T) { - lgs := AlwaysGetSource[any, any, any, any, any, any]{ + lgs := AlwaysGetAdapter[any, any, any, any, any, any]{ ItemType: "foo", } - if lgs.Name() != "foo-source" { - t.Errorf("expected name to be foo-source, got %v", lgs.Name()) + if lgs.Name() != "foo-adapter" { + t.Errorf("expected name to be foo-adapter, got %v", lgs.Name()) } } func TestAlwaysGetSourceScopes(t *testing.T) { - lgs := AlwaysGetSource[any, any, any, any, any, any]{ + lgs := AlwaysGetAdapter[any, any, any, any, any, any]{ AccountID: "foo", Region: "bar", } @@ -51,7 +51,7 @@ func TestAlwaysGetSourceScopes(t *testing.T) { func TestAlwaysGetSourceGet(t *testing.T) { t.Run("with no errors", func(t *testing.T) { - lgs := AlwaysGetSource[string, string, string, string, struct{}, struct{}]{ + lgs := AlwaysGetAdapter[string, string, string, string, struct{}, struct{}]{ ItemType: "test", AccountID: "foo", Region: "bar", @@ -83,7 +83,7 @@ func TestAlwaysGetSourceGet(t *testing.T) { }) t.Run("with an error", func(t *testing.T) { - lgs := AlwaysGetSource[string, string, string, string, struct{}, struct{}]{ + lgs := AlwaysGetAdapter[string, string, string, string, struct{}, struct{}]{ ItemType: "test", AccountID: "foo", Region: "bar", @@ -117,7 +117,7 @@ func TestAlwaysGetSourceGet(t *testing.T) { func TestAlwaysGetSourceList(t *testing.T) { t.Run("with no errors", func(t *testing.T) { - lgs := AlwaysGetSource[string, string, string, string, struct{}, struct{}]{ + lgs := AlwaysGetAdapter[string, string, string, string, struct{}, struct{}]{ ItemType: "test", AccountID: "foo", Region: "bar", @@ -154,7 +154,7 @@ func TestAlwaysGetSourceList(t *testing.T) { }) t.Run("with a failing output mapper", func(t *testing.T) { - lgs := AlwaysGetSource[string, string, string, string, struct{}, struct{}]{ + lgs := AlwaysGetAdapter[string, string, string, string, struct{}, struct{}]{ ItemType: "test", AccountID: "foo", Region: "bar", @@ -196,7 +196,7 @@ func TestAlwaysGetSourceList(t *testing.T) { }) t.Run("with a failing GetFunc", func(t *testing.T) { - lgs := AlwaysGetSource[string, string, string, string, struct{}, struct{}]{ + lgs := AlwaysGetAdapter[string, string, string, string, struct{}, struct{}]{ ItemType: "test", AccountID: "foo", Region: "bar", @@ -236,7 +236,7 @@ func TestAlwaysGetSourceList(t *testing.T) { func TestAlwaysGetSourceSearch(t *testing.T) { t.Run("with ARN search", func(t *testing.T) { - lgs := AlwaysGetSource[string, string, string, string, struct{}, struct{}]{ + lgs := AlwaysGetAdapter[string, string, string, string, struct{}, struct{}]{ ItemType: "test", AccountID: "foo", Region: "bar", @@ -291,7 +291,7 @@ func TestAlwaysGetSourceSearch(t *testing.T) { }) t.Run("with Custom & ARN search", func(t *testing.T) { - lgs := AlwaysGetSource[string, string, string, string, struct{}, struct{}]{ + lgs := AlwaysGetAdapter[string, string, string, string, struct{}, struct{}]{ ItemType: "test", AccountID: "foo", Region: "bar", @@ -352,7 +352,7 @@ func TestAlwaysGetSourceSearch(t *testing.T) { t.Run("with custom search logic", func(t *testing.T) { var searchMapperCalled bool - lgs := AlwaysGetSource[string, string, string, string, struct{}, struct{}]{ + lgs := AlwaysGetAdapter[string, string, string, string, struct{}, struct{}]{ ItemType: "test", AccountID: "foo", Region: "bar", @@ -392,7 +392,7 @@ func TestAlwaysGetSourceSearch(t *testing.T) { }) t.Run("with SearchGetInputMapper", func(t *testing.T) { - ags := AlwaysGetSource[string, string, string, string, struct{}, struct{}]{ + ags := AlwaysGetAdapter[string, string, string, string, struct{}, struct{}]{ ItemType: "test", AccountID: "foo", Region: "bar", @@ -440,7 +440,7 @@ func TestAlwaysGetSourceSearch(t *testing.T) { func TestAlwaysGetSourceCaching(t *testing.T) { ctx := context.Background() generation := 0 - s := AlwaysGetSource[string, string, string, string, struct{}, struct{}]{ + s := AlwaysGetAdapter[string, string, string, string, struct{}, struct{}]{ ItemType: "test", AccountID: "foo", Region: "eu-west-2", diff --git a/sources/apigateway/resource.go b/adapters/apigateway/resource.go similarity index 71% rename from sources/apigateway/resource.go rename to adapters/apigateway/resource.go index 394db4d0..b957a33b 100644 --- a/sources/apigateway/resource.go +++ b/adapters/apigateway/resource.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/apigateway" "github.com/aws/aws-sdk-go-v2/service/apigateway/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -38,7 +38,7 @@ func resourceOutputMapper(query, scope string, awsItem *types.Resource) (*sdp.It } } - attributes, err := sources.ToAttributesWithExclude(awsItem, "tags") + attributes, err := adapters.ToAttributesWithExclude(awsItem, "tags") if err != nil { return nil, err } @@ -66,12 +66,13 @@ func resourceOutputMapper(query, scope string, awsItem *types.Resource) (*sdp.It // +overmind:group AWS // +overmind:terraform:queryMap aws_api_gateway_resource.id -func NewResourceSource(client *apigateway.Client, accountID string, region string) *sources.GetListSource[*types.Resource, *apigateway.Client, *apigateway.Options] { - return &sources.GetListSource[*types.Resource, *apigateway.Client, *apigateway.Options]{ - ItemType: "apigateway-resource", - Client: client, - AccountID: accountID, - Region: region, +func NewResourceAdapter(client *apigateway.Client, accountID string, region string) *adapters.GetListAdapter[*types.Resource, *apigateway.Client, *apigateway.Options] { + return &adapters.GetListAdapter[*types.Resource, *apigateway.Client, *apigateway.Options]{ + ItemType: "apigateway-resource", + Client: client, + AccountID: accountID, + Region: region, + AdapterMetadata: APIGatewayMetadata(), GetFunc: func(ctx context.Context, client *apigateway.Client, scope, query string) (*types.Resource, error) { f := strings.Split(query, "/") if len(f) != 2 { @@ -112,3 +113,20 @@ func NewResourceSource(client *apigateway.Client, accountID string, region strin }, } } + +func APIGatewayMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "apigateway-resource", + DescriptiveName: "API Gateway", + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_COMPUTE_APPLICATION, + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + Search: true, + GetDescription: "Get a Resource by rest-api-id/resource-id", + SearchDescription: "Search Resources by REST API ID", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_api_gateway_resource.id"}, + }, + } +} diff --git a/sources/apigateway/resource_test.go b/adapters/apigateway/resource_test.go similarity index 75% rename from sources/apigateway/resource_test.go rename to adapters/apigateway/resource_test.go index b6635767..8d8e0eb9 100644 --- a/sources/apigateway/resource_test.go +++ b/adapters/apigateway/resource_test.go @@ -6,7 +6,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/apigateway" "github.com/aws/aws-sdk-go-v2/service/apigateway/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" ) /* @@ -83,25 +83,25 @@ import ( func TestResourceOutputMapper(t *testing.T) { resource := &types.Resource{ - Id: sources.PtrString("test-id"), - ParentId: sources.PtrString("parent-id"), - Path: sources.PtrString("/test-path"), - PathPart: sources.PtrString("test-path-part"), + Id: adapters.PtrString("test-id"), + ParentId: adapters.PtrString("parent-id"), + Path: adapters.PtrString("/test-path"), + PathPart: adapters.PtrString("test-path-part"), ResourceMethods: map[string]types.Method{ "GET": { - ApiKeyRequired: sources.PtrBool(true), + ApiKeyRequired: adapters.PtrBool(true), AuthorizationScopes: []string{"scope1", "scope2"}, - AuthorizationType: sources.PtrString("NONE"), - AuthorizerId: sources.PtrString("authorizer-id"), - HttpMethod: sources.PtrString("GET"), + AuthorizationType: adapters.PtrString("NONE"), + AuthorizerId: adapters.PtrString("authorizer-id"), + HttpMethod: adapters.PtrString("GET"), MethodIntegration: &types.Integration{ CacheKeyParameters: []string{"param1", "param2"}, - CacheNamespace: sources.PtrString("namespace"), - ConnectionId: sources.PtrString("connection-id"), + CacheNamespace: adapters.PtrString("namespace"), + ConnectionId: adapters.PtrString("connection-id"), ConnectionType: types.ConnectionTypeInternet, ContentHandling: types.ContentHandlingStrategyConvertToBinary, - Credentials: sources.PtrString("credentials"), - HttpMethod: sources.PtrString("POST"), + Credentials: adapters.PtrString("credentials"), + HttpMethod: adapters.PtrString("POST"), IntegrationResponses: map[string]types.IntegrationResponse{ "200": { ContentHandling: types.ContentHandlingStrategyConvertToText, @@ -111,11 +111,11 @@ func TestResourceOutputMapper(t *testing.T) { ResponseTemplates: map[string]string{ "template1": "value1", }, - SelectionPattern: sources.PtrString("pattern"), - StatusCode: sources.PtrString("200"), + SelectionPattern: adapters.PtrString("pattern"), + StatusCode: adapters.PtrString("200"), }, }, - PassthroughBehavior: sources.PtrString("WHEN_NO_MATCH"), + PassthroughBehavior: adapters.PtrString("WHEN_NO_MATCH"), RequestParameters: map[string]string{ "param1": "value1", }, @@ -127,7 +127,7 @@ func TestResourceOutputMapper(t *testing.T) { InsecureSkipVerification: false, }, Type: types.IntegrationTypeAwsProxy, - Uri: sources.PtrString("uri"), + Uri: adapters.PtrString("uri"), }, MethodResponses: map[string]types.MethodResponse{ "200": { @@ -137,17 +137,17 @@ func TestResourceOutputMapper(t *testing.T) { ResponseParameters: map[string]bool{ "param1": true, }, - StatusCode: sources.PtrString("200"), + StatusCode: adapters.PtrString("200"), }, }, - OperationName: sources.PtrString("operation"), + OperationName: adapters.PtrString("operation"), RequestModels: map[string]string{ "model1": "value1", }, RequestParameters: map[string]bool{ "param1": true, }, - RequestValidatorId: sources.PtrString("validator-id"), + RequestValidatorId: adapters.PtrString("validator-id"), }, }, } @@ -162,15 +162,15 @@ func TestResourceOutputMapper(t *testing.T) { } } -func TestNewResourceSource(t *testing.T) { - config, account, region := sources.GetAutoConfig(t) +func TestNewResourceAdapter(t *testing.T) { + config, account, region := adapters.GetAutoConfig(t) client := apigateway.NewFromConfig(config) - source := NewResourceSource(client, account, region) + adapter := NewResourceAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, SkipList: true, } diff --git a/sources/apigateway/rest-api.go b/adapters/apigateway/rest-api.go similarity index 78% rename from sources/apigateway/rest-api.go rename to adapters/apigateway/rest-api.go index 2549daf7..ebd35625 100644 --- a/sources/apigateway/rest-api.go +++ b/adapters/apigateway/rest-api.go @@ -7,8 +7,8 @@ import ( "github.com/aws/aws-sdk-go-v2/service/apigateway" "github.com/aws/aws-sdk-go-v2/service/apigateway/types" "github.com/micahhausler/aws-iam-policy/policy" - "github.com/overmindtech/aws-source/sources" - "github.com/overmindtech/aws-source/sources/iam" + "github.com/overmindtech/aws-source/adapters" + "github.com/overmindtech/aws-source/adapters/iam" "github.com/overmindtech/sdp-go" log "github.com/sirupsen/logrus" @@ -49,7 +49,7 @@ func restApiListFunc(ctx context.Context, client *apigateway.Client, _ string) ( } func restApiOutputMapper(scope string, awsItem *types.RestApi) (*sdp.Item, error) { - attributes, err := sources.ToAttributesWithExclude(awsItem, "tags") + attributes, err := adapters.ToAttributesWithExclude(awsItem, "tags") if err != nil { return nil, err } @@ -75,7 +75,7 @@ func restApiOutputMapper(scope string, awsItem *types.RestApi) (*sdp.Item, error return nil, nil //nolint:nilerr } - attributes, err = sources.ToAttributesWithExclude(restApi, "tags") + attributes, err = adapters.ToAttributesWithExclude(restApi, "tags") if err != nil { return nil, err } @@ -154,12 +154,13 @@ func restApiOutputMapper(scope string, awsItem *types.RestApi) (*sdp.Item, error // +overmind:group AWS // +overmind:terraform:queryMap aws_api_gateway_rest_api.id -func NewRestApiSource(client *apigateway.Client, accountID string, region string) *sources.GetListSource[*types.RestApi, *apigateway.Client, *apigateway.Options] { - return &sources.GetListSource[*types.RestApi, *apigateway.Client, *apigateway.Options]{ - ItemType: "apigateway-rest-api", - Client: client, - AccountID: accountID, - Region: region, +func NewRestApiAdapter(client *apigateway.Client, accountID string, region string) *adapters.GetListAdapter[*types.RestApi, *apigateway.Client, *apigateway.Options] { + return &adapters.GetListAdapter[*types.RestApi, *apigateway.Client, *apigateway.Options]{ + ItemType: "apigateway-rest-api", + Client: client, + AccountID: accountID, + Region: region, + AdapterMetadata: RestAPIMetadata(), GetFunc: func(ctx context.Context, client *apigateway.Client, scope, query string) (*types.RestApi, error) { out, err := client.GetRestApi(ctx, &apigateway.GetRestApiInput{ RestApiId: &query, @@ -190,3 +191,23 @@ func NewRestApiSource(client *apigateway.Client, accountID string, region string }, } } + +func RestAPIMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "apigateway-rest-api", + DescriptiveName: "REST API", + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_COMPUTE_APPLICATION, + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a REST API by ID", + ListDescription: "List all REST APIs", + SearchDescription: "Search for REST APIs by their name", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_api_gateway_rest_api.id"}, + }, + PotentialLinks: []string{"ec2-vpc-endpoint", "apigateway-resource"}, + } +} diff --git a/sources/apigateway/rest-api_test.go b/adapters/apigateway/rest-api_test.go similarity index 70% rename from sources/apigateway/rest-api_test.go rename to adapters/apigateway/rest-api_test.go index b71202f1..c556acd0 100644 --- a/sources/apigateway/rest-api_test.go +++ b/adapters/apigateway/rest-api_test.go @@ -6,7 +6,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/apigateway" "github.com/aws/aws-sdk-go-v2/service/apigateway/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -38,22 +38,22 @@ func TestRestApiOutputMapper(t *testing.T) { output := &apigateway.GetRestApiOutput{ ApiKeySource: types.ApiKeySourceTypeHeader, BinaryMediaTypes: []string{"application/json"}, - CreatedDate: sources.PtrTime(time.Now()), - Description: sources.PtrString("Example API"), + CreatedDate: adapters.PtrTime(time.Now()), + Description: adapters.PtrString("Example API"), DisableExecuteApiEndpoint: false, EndpointConfiguration: &types.EndpointConfiguration{ Types: []types.EndpointType{types.EndpointTypePrivate}, VpcEndpointIds: []string{"vpce-12345678"}, }, - Id: sources.PtrString("abc123"), - MinimumCompressionSize: sources.PtrInt32(1024), - Name: sources.PtrString("ExampleAPI"), - Policy: sources.PtrString("{\"Version\": \"2012-10-17\", \"Statement\": [{\"Effect\": \"Allow\", \"Principal\": \"*\", \"Action\": \"execute-api:Invoke\", \"Resource\": \"*\"}]}"), - RootResourceId: sources.PtrString("root123"), + Id: adapters.PtrString("abc123"), + MinimumCompressionSize: adapters.PtrInt32(1024), + Name: adapters.PtrString("ExampleAPI"), + Policy: adapters.PtrString("{\"Version\": \"2012-10-17\", \"Statement\": [{\"Effect\": \"Allow\", \"Principal\": \"*\", \"Action\": \"execute-api:Invoke\", \"Resource\": \"*\"}]}"), + RootResourceId: adapters.PtrString("root123"), Tags: map[string]string{ "env": "production", }, - Version: sources.PtrString("v1"), + Version: adapters.PtrString("v1"), Warnings: []string{"This is a warning"}, } @@ -66,7 +66,7 @@ func TestRestApiOutputMapper(t *testing.T) { t.Error(err) } - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "ec2-vpc-endpoint", ExpectedMethod: sdp.QueryMethod_GET, @@ -90,15 +90,15 @@ func TestRestApiOutputMapper(t *testing.T) { tests.Execute(t, item) } -func TestNewRestApiSource(t *testing.T) { - config, account, region := sources.GetAutoConfig(t) +func TestNewRestApiAdapter(t *testing.T) { + config, account, region := adapters.GetAutoConfig(t) client := apigateway.NewFromConfig(config) - source := NewRestApiSource(client, account, region) + adapter := NewRestApiAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/autoscaling/auto_scaling_group.go b/adapters/autoscaling/auto_scaling_group.go similarity index 77% rename from sources/autoscaling/auto_scaling_group.go rename to adapters/autoscaling/auto_scaling_group.go index 4c6e7a18..d16d21c4 100644 --- a/sources/autoscaling/auto_scaling_group.go +++ b/adapters/autoscaling/auto_scaling_group.go @@ -4,7 +4,7 @@ import ( "context" "github.com/aws/aws-sdk-go-v2/service/autoscaling" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -16,7 +16,7 @@ func autoScalingGroupOutputMapper(_ context.Context, _ *autoscaling.Client, scop var err error for _, asg := range output.AutoScalingGroups { - attributes, err = sources.ToAttributesWithExclude(asg) + attributes, err = adapters.ToAttributesWithExclude(asg) if err != nil { return nil, err @@ -63,18 +63,18 @@ func autoScalingGroupOutputMapper(_ context.Context, _ *autoscaling.Client, scop } } - var a *sources.ARN + var a *adapters.ARN var err error for _, tgARN := range asg.TargetGroupARNs { - if a, err = sources.ParseARN(tgARN); err == nil { + if a, err = adapters.ParseARN(tgARN); err == nil { // +overmind:link elbv2-target-group item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "elbv2-target-group", Method: sdp.QueryMethod_SEARCH, Query: tgARN, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changes to a target group won't affect the ASG @@ -129,14 +129,14 @@ func autoScalingGroupOutputMapper(_ context.Context, _ *autoscaling.Client, scop } if asg.ServiceLinkedRoleARN != nil { - if a, err = sources.ParseARN(*asg.ServiceLinkedRoleARN); err == nil { + if a, err = adapters.ParseARN(*asg.ServiceLinkedRoleARN); err == nil { // +overmind:link iam-role item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "iam-role", Method: sdp.QueryMethod_SEARCH, Query: *asg.ServiceLinkedRoleARN, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changes to a role can affect the functioning of the @@ -220,12 +220,13 @@ func autoScalingGroupOutputMapper(_ context.Context, _ *autoscaling.Client, scop // +overmind:terraform:method SEARCH // //go:generate docgen ../../docs-data -func NewAutoScalingGroupSource(client *autoscaling.Client, accountID string, region string) *sources.DescribeOnlySource[*autoscaling.DescribeAutoScalingGroupsInput, *autoscaling.DescribeAutoScalingGroupsOutput, *autoscaling.Client, *autoscaling.Options] { - return &sources.DescribeOnlySource[*autoscaling.DescribeAutoScalingGroupsInput, *autoscaling.DescribeAutoScalingGroupsOutput, *autoscaling.Client, *autoscaling.Options]{ - ItemType: "autoscaling-auto-scaling-group", - AccountID: accountID, - Region: region, - Client: client, +func NewAutoScalingGroupAdapter(client *autoscaling.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*autoscaling.DescribeAutoScalingGroupsInput, *autoscaling.DescribeAutoScalingGroupsOutput, *autoscaling.Client, *autoscaling.Options] { + return &adapters.DescribeOnlyAdapter[*autoscaling.DescribeAutoScalingGroupsInput, *autoscaling.DescribeAutoScalingGroupsOutput, *autoscaling.Client, *autoscaling.Options]{ + ItemType: "autoscaling-auto-scaling-group", + AccountID: accountID, + Region: region, + Client: client, + AdapterMetadata: AutoScalingGroupMetadata(), InputMapperGet: func(scope, query string) (*autoscaling.DescribeAutoScalingGroupsInput, error) { return &autoscaling.DescribeAutoScalingGroupsInput{ AutoScalingGroupNames: []string{query}, @@ -234,7 +235,7 @@ func NewAutoScalingGroupSource(client *autoscaling.Client, accountID string, reg InputMapperList: func(scope string) (*autoscaling.DescribeAutoScalingGroupsInput, error) { return &autoscaling.DescribeAutoScalingGroupsInput{}, nil }, - PaginatorBuilder: func(client *autoscaling.Client, params *autoscaling.DescribeAutoScalingGroupsInput) sources.Paginator[*autoscaling.DescribeAutoScalingGroupsOutput, *autoscaling.Options] { + PaginatorBuilder: func(client *autoscaling.Client, params *autoscaling.DescribeAutoScalingGroupsInput) adapters.Paginator[*autoscaling.DescribeAutoScalingGroupsOutput, *autoscaling.Options] { return autoscaling.NewDescribeAutoScalingGroupsPaginator(client, params) }, DescribeFunc: func(ctx context.Context, client *autoscaling.Client, input *autoscaling.DescribeAutoScalingGroupsInput) (*autoscaling.DescribeAutoScalingGroupsOutput, error) { @@ -243,3 +244,26 @@ func NewAutoScalingGroupSource(client *autoscaling.Client, accountID string, reg OutputMapper: autoScalingGroupOutputMapper, } } + +func AutoScalingGroupMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "autoscaling-auto-scaling-group", + DescriptiveName: "Autoscaling Group", + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_CONFIGURATION, + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get an Autoscaling Group by name", + ListDescription: "List Autoscaling Groups", + SearchDescription: "Search for Autoscaling Groups by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + { + TerraformQueryMap: "aws_autoscaling_group.arn", + TerraformMethod: sdp.QueryMethod_SEARCH, + }, + }, + PotentialLinks: []string{"ec2-launch-template", "elbv2-target-group", "ec2-instance", "iam-role", "autoscaling-launch-configuration", "ec2-placement-group"}, + } +} diff --git a/adapters/autoscaling/auto_scaling_group_test.go b/adapters/autoscaling/auto_scaling_group_test.go new file mode 100644 index 00000000..9f8bb45f --- /dev/null +++ b/adapters/autoscaling/auto_scaling_group_test.go @@ -0,0 +1,225 @@ +package autoscaling + +import ( + "context" + "testing" + "time" + + "github.com/aws/aws-sdk-go-v2/service/autoscaling" + "github.com/aws/aws-sdk-go-v2/service/autoscaling/types" + "github.com/overmindtech/aws-source/adapters" + "github.com/overmindtech/sdp-go" +) + +func TestAutoScalingGroupOutputMapper(t *testing.T) { + t.Parallel() + + output := autoscaling.DescribeAutoScalingGroupsOutput{ + AutoScalingGroups: []types.AutoScalingGroup{ + { + AutoScalingGroupName: adapters.PtrString("eks-default-20230117110031319900000013-96c2dfb1-a11b-b5e4-6efb-0fea7e22855c"), + AutoScalingGroupARN: adapters.PtrString("arn:aws:autoscaling:eu-west-2:944651592624:autoScalingGroup:1cbb0e22-818f-4d8b-8662-77f73d3713ca:autoScalingGroupName/eks-default-20230117110031319900000013-96c2dfb1-a11b-b5e4-6efb-0fea7e22855c"), + MixedInstancesPolicy: &types.MixedInstancesPolicy{ + LaunchTemplate: &types.LaunchTemplate{ + LaunchTemplateSpecification: &types.LaunchTemplateSpecification{ + LaunchTemplateId: adapters.PtrString("lt-0174ff2b8909d0c75"), // link + LaunchTemplateName: adapters.PtrString("eks-96c2dfb1-a11b-b5e4-6efb-0fea7e22855c"), + Version: adapters.PtrString("1"), + }, + Overrides: []types.LaunchTemplateOverrides{ + { + InstanceType: adapters.PtrString("t3.large"), + }, + }, + }, + InstancesDistribution: &types.InstancesDistribution{ + OnDemandAllocationStrategy: adapters.PtrString("prioritized"), + OnDemandBaseCapacity: adapters.PtrInt32(0), + OnDemandPercentageAboveBaseCapacity: adapters.PtrInt32(100), + SpotAllocationStrategy: adapters.PtrString("lowest-price"), + SpotInstancePools: adapters.PtrInt32(2), + }, + }, + MinSize: adapters.PtrInt32(1), + MaxSize: adapters.PtrInt32(3), + DesiredCapacity: adapters.PtrInt32(1), + DefaultCooldown: adapters.PtrInt32(300), + AvailabilityZones: []string{ // link + "eu-west-2c", + "eu-west-2a", + "eu-west-2b", + }, + LoadBalancerNames: []string{}, // Ignored, classic load balancer + TargetGroupARNs: []string{ + "arn:partition:service:region:account-id:resource-type/resource-id", // link + }, + HealthCheckType: adapters.PtrString("EC2"), + HealthCheckGracePeriod: adapters.PtrInt32(15), + Instances: []types.Instance{ + { + InstanceId: adapters.PtrString("i-0be6c4fe789cb1b78"), // link + InstanceType: adapters.PtrString("t3.large"), + AvailabilityZone: adapters.PtrString("eu-west-2c"), + LifecycleState: types.LifecycleStateInService, + HealthStatus: adapters.PtrString("Healthy"), + LaunchTemplate: &types.LaunchTemplateSpecification{ + LaunchTemplateId: adapters.PtrString("lt-0174ff2b8909d0c75"), // Link + LaunchTemplateName: adapters.PtrString("eks-96c2dfb1-a11b-b5e4-6efb-0fea7e22855c"), + Version: adapters.PtrString("1"), + }, + ProtectedFromScaleIn: adapters.PtrBool(false), + }, + }, + CreatedTime: adapters.PtrTime(time.Now()), + SuspendedProcesses: []types.SuspendedProcess{}, + VPCZoneIdentifier: adapters.PtrString("subnet-0e234bef35fc4a9e1,subnet-09d5f6fa75b0b4569,subnet-0960234bbc4edca03"), + EnabledMetrics: []types.EnabledMetric{}, + Tags: []types.TagDescription{ + { + ResourceId: adapters.PtrString("eks-default-20230117110031319900000013-96c2dfb1-a11b-b5e4-6efb-0fea7e22855c"), + ResourceType: adapters.PtrString("auto-scaling-group"), + Key: adapters.PtrString("eks:cluster-name"), + Value: adapters.PtrString("dogfood"), + PropagateAtLaunch: adapters.PtrBool(true), + }, + { + ResourceId: adapters.PtrString("eks-default-20230117110031319900000013-96c2dfb1-a11b-b5e4-6efb-0fea7e22855c"), + ResourceType: adapters.PtrString("auto-scaling-group"), + Key: adapters.PtrString("eks:nodegroup-name"), + Value: adapters.PtrString("default-20230117110031319900000013"), + PropagateAtLaunch: adapters.PtrBool(true), + }, + { + ResourceId: adapters.PtrString("eks-default-20230117110031319900000013-96c2dfb1-a11b-b5e4-6efb-0fea7e22855c"), + ResourceType: adapters.PtrString("auto-scaling-group"), + Key: adapters.PtrString("k8s.io/cluster-autoscaler/dogfood"), + Value: adapters.PtrString("owned"), + PropagateAtLaunch: adapters.PtrBool(true), + }, + { + ResourceId: adapters.PtrString("eks-default-20230117110031319900000013-96c2dfb1-a11b-b5e4-6efb-0fea7e22855c"), + ResourceType: adapters.PtrString("auto-scaling-group"), + Key: adapters.PtrString("k8s.io/cluster-autoscaler/enabled"), + Value: adapters.PtrString("true"), + PropagateAtLaunch: adapters.PtrBool(true), + }, + { + ResourceId: adapters.PtrString("eks-default-20230117110031319900000013-96c2dfb1-a11b-b5e4-6efb-0fea7e22855c"), + ResourceType: adapters.PtrString("auto-scaling-group"), + Key: adapters.PtrString("kubernetes.io/cluster/dogfood"), + Value: adapters.PtrString("owned"), + PropagateAtLaunch: adapters.PtrBool(true), + }, + }, + TerminationPolicies: []string{ + "AllocationStrategy", + "OldestLaunchTemplate", + "OldestInstance", + }, + NewInstancesProtectedFromScaleIn: adapters.PtrBool(false), + ServiceLinkedRoleARN: adapters.PtrString("arn:aws:iam::944651592624:role/aws-service-role/autoscaling.amazonaws.com/AWSServiceRoleForAutoScaling"), // link + CapacityRebalance: adapters.PtrBool(true), + TrafficSources: []types.TrafficSourceIdentifier{ + { + Identifier: adapters.PtrString("arn:partition:service:region:account-id:resource-type/resource-id"), // We will skip this for now since it's related to VPC lattice groups which are still in preview + }, + }, + Context: adapters.PtrString("foo"), + DefaultInstanceWarmup: adapters.PtrInt32(10), + DesiredCapacityType: adapters.PtrString("foo"), + LaunchConfigurationName: adapters.PtrString("launchConfig"), // link + LaunchTemplate: &types.LaunchTemplateSpecification{ + LaunchTemplateId: adapters.PtrString("id"), // link + LaunchTemplateName: adapters.PtrString("launchTemplateName"), + }, + MaxInstanceLifetime: adapters.PtrInt32(30), + PlacementGroup: adapters.PtrString("placementGroup"), // link (ec2) + PredictedCapacity: adapters.PtrInt32(1), + Status: adapters.PtrString("OK"), + WarmPoolConfiguration: &types.WarmPoolConfiguration{ + InstanceReusePolicy: &types.InstanceReusePolicy{ + ReuseOnScaleIn: adapters.PtrBool(true), + }, + MaxGroupPreparedCapacity: adapters.PtrInt32(1), + MinSize: adapters.PtrInt32(1), + PoolState: types.WarmPoolStateHibernated, + Status: types.WarmPoolStatusPendingDelete, + }, + WarmPoolSize: adapters.PtrInt32(1), + }, + }, + } + + items, err := autoScalingGroupOutputMapper(context.Background(), nil, "foo", nil, &output) + + if err != nil { + t.Error(err) + } + + for _, item := range items { + if err := item.Validate(); err != nil { + t.Error(err) + } + } + + if len(items) != 1 { + t.Errorf("expected 1 item, got %v", len(items)) + } + + item := items[0] + + // It doesn't really make sense to test anything other than the linked items + // since the attributes are converted automatically + tests := adapters.QueryTests{ + { + ExpectedType: "ec2-launch-template", + ExpectedMethod: sdp.QueryMethod_GET, + ExpectedQuery: "lt-0174ff2b8909d0c75", + ExpectedScope: "foo", + }, + { + ExpectedType: "elbv2-target-group", + ExpectedMethod: sdp.QueryMethod_SEARCH, + ExpectedQuery: "arn:partition:service:region:account-id:resource-type/resource-id", + ExpectedScope: "account-id.region", + }, + { + ExpectedType: "ec2-instance", + ExpectedMethod: sdp.QueryMethod_GET, + ExpectedQuery: "i-0be6c4fe789cb1b78", + ExpectedScope: "foo", + }, + { + ExpectedType: "iam-role", + ExpectedMethod: sdp.QueryMethod_SEARCH, + ExpectedQuery: "arn:aws:iam::944651592624:role/aws-service-role/autoscaling.amazonaws.com/AWSServiceRoleForAutoScaling", + ExpectedScope: "944651592624", + }, + { + ExpectedType: "autoscaling-launch-configuration", + ExpectedMethod: sdp.QueryMethod_GET, + ExpectedQuery: "launchConfig", + ExpectedScope: "foo", + }, + { + ExpectedType: "ec2-launch-template", + ExpectedMethod: sdp.QueryMethod_GET, + ExpectedQuery: "id", + ExpectedScope: "foo", + }, + { + ExpectedType: "ec2-placement-group", + ExpectedMethod: sdp.QueryMethod_GET, + ExpectedQuery: "placementGroup", + ExpectedScope: "foo", + }, + { + ExpectedType: "ec2-launch-template", + ExpectedMethod: sdp.QueryMethod_GET, + ExpectedQuery: "lt-0174ff2b8909d0c75", + ExpectedScope: "foo", + }, + } + + tests.Execute(t, item) +} diff --git a/sources/cloudfront/cache_policy.go b/adapters/cloudfront/cache_policy.go similarity index 63% rename from sources/cloudfront/cache_policy.go rename to adapters/cloudfront/cache_policy.go index 3889799d..b7cb354b 100644 --- a/sources/cloudfront/cache_policy.go +++ b/adapters/cloudfront/cache_policy.go @@ -5,7 +5,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/cloudfront" "github.com/aws/aws-sdk-go-v2/service/cloudfront/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -45,12 +45,13 @@ func cachePolicyListFunc(ctx context.Context, client CloudFrontClient, scope str // +overmind:group AWS // +overmind:terraform:queryMap aws_cloudfront_cache_policy.id -func NewCachePolicySource(client CloudFrontClient, accountID string) *sources.GetListSource[*types.CachePolicy, CloudFrontClient, *cloudfront.Options] { - return &sources.GetListSource[*types.CachePolicy, CloudFrontClient, *cloudfront.Options]{ +func NewCachePolicyAdapter(client CloudFrontClient, accountID string) *adapters.GetListAdapter[*types.CachePolicy, CloudFrontClient, *cloudfront.Options] { + return &adapters.GetListAdapter[*types.CachePolicy, CloudFrontClient, *cloudfront.Options]{ ItemType: "cloudfront-cache-policy", Client: client, AccountID: accountID, - Region: "", // Cloudfront resources aren't tied to a region + Region: "", // Cloudfront resources aren't tied to a region + AdapterMetadata: CachePolicyMetadata(), SupportGlobalResources: true, // Some policies are global GetFunc: func(ctx context.Context, client CloudFrontClient, scope, query string) (*types.CachePolicy, error) { out, err := client.GetCachePolicy(ctx, &cloudfront.GetCachePolicyInput{ @@ -65,7 +66,7 @@ func NewCachePolicySource(client CloudFrontClient, accountID string) *sources.Ge }, ListFunc: cachePolicyListFunc, ItemMapper: func(_, scope string, awsItem *types.CachePolicy) (*sdp.Item, error) { - attributes, err := sources.ToAttributesWithExclude(awsItem) + attributes, err := adapters.ToAttributesWithExclude(awsItem) if err != nil { return nil, err @@ -82,3 +83,22 @@ func NewCachePolicySource(client CloudFrontClient, accountID string) *sources.Ge }, } } + +func CachePolicyMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "cloudfront-cache-policy", + DescriptiveName: "CloudFront Cache Policy", + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_CONFIGURATION, + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a CloudFront Cache Policy", + ListDescription: "List CloudFront Cache Policies", + SearchDescription: "Search CloudFront Cache Policies by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_cloudfront_cache_policy.id"}, + }, + } +} diff --git a/sources/cloudfront/cache_policy_test.go b/adapters/cloudfront/cache_policy_test.go similarity index 74% rename from sources/cloudfront/cache_policy_test.go rename to adapters/cloudfront/cache_policy_test.go index 88e56560..b05d4841 100644 --- a/sources/cloudfront/cache_policy_test.go +++ b/adapters/cloudfront/cache_policy_test.go @@ -7,33 +7,33 @@ import ( "github.com/aws/aws-sdk-go-v2/service/cloudfront" "github.com/aws/aws-sdk-go-v2/service/cloudfront/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" ) var testCachePolicy = &types.CachePolicy{ - Id: sources.PtrString("test-id"), - LastModifiedTime: sources.PtrTime(time.Now()), + Id: adapters.PtrString("test-id"), + LastModifiedTime: adapters.PtrTime(time.Now()), CachePolicyConfig: &types.CachePolicyConfig{ - MinTTL: sources.PtrInt64(1), - Name: sources.PtrString("test-name"), - Comment: sources.PtrString("test-comment"), - DefaultTTL: sources.PtrInt64(1), - MaxTTL: sources.PtrInt64(1), + MinTTL: adapters.PtrInt64(1), + Name: adapters.PtrString("test-name"), + Comment: adapters.PtrString("test-comment"), + DefaultTTL: adapters.PtrInt64(1), + MaxTTL: adapters.PtrInt64(1), ParametersInCacheKeyAndForwardedToOrigin: &types.ParametersInCacheKeyAndForwardedToOrigin{ CookiesConfig: &types.CachePolicyCookiesConfig{ CookieBehavior: types.CachePolicyCookieBehaviorAll, Cookies: &types.CookieNames{ - Quantity: sources.PtrInt32(1), + Quantity: adapters.PtrInt32(1), Items: []string{ "test-cookie", }, }, }, - EnableAcceptEncodingGzip: sources.PtrBool(true), + EnableAcceptEncodingGzip: adapters.PtrBool(true), HeadersConfig: &types.CachePolicyHeadersConfig{ HeaderBehavior: types.CachePolicyHeaderBehaviorWhitelist, Headers: &types.Headers{ - Quantity: sources.PtrInt32(1), + Quantity: adapters.PtrInt32(1), Items: []string{ "test-header", }, @@ -42,13 +42,13 @@ var testCachePolicy = &types.CachePolicy{ QueryStringsConfig: &types.CachePolicyQueryStringsConfig{ QueryStringBehavior: types.CachePolicyQueryStringBehaviorWhitelist, QueryStrings: &types.QueryStringNames{ - Quantity: sources.PtrInt32(1), + Quantity: adapters.PtrInt32(1), Items: []string{ "test-query-string", }, }, }, - EnableAcceptEncodingBrotli: sources.PtrBool(true), + EnableAcceptEncodingBrotli: adapters.PtrBool(true), }, }, } @@ -84,13 +84,13 @@ func TestCachePolicyListFunc(t *testing.T) { } } -func TestNewCachePolicySource(t *testing.T) { +func TestNewCachePolicyAdapter(t *testing.T) { client, account, _ := GetAutoConfig(t) - source := NewCachePolicySource(client, account) + adapter := NewCachePolicyAdapter(client, account) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/cloudfront/continuous_deployment_policy.go b/adapters/cloudfront/continuous_deployment_policy.go similarity index 71% rename from sources/cloudfront/continuous_deployment_policy.go rename to adapters/cloudfront/continuous_deployment_policy.go index f2ee5da2..75750805 100644 --- a/sources/cloudfront/continuous_deployment_policy.go +++ b/adapters/cloudfront/continuous_deployment_policy.go @@ -5,12 +5,12 @@ import ( "github.com/aws/aws-sdk-go-v2/service/cloudfront" "github.com/aws/aws-sdk-go-v2/service/cloudfront/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) func continuousDeploymentPolicyItemMapper(_, scope string, awsItem *types.ContinuousDeploymentPolicy) (*sdp.Item, error) { - attributes, err := sources.ToAttributesWithExclude(awsItem) + attributes, err := adapters.ToAttributesWithExclude(awsItem) if err != nil { return nil, err @@ -55,13 +55,14 @@ func continuousDeploymentPolicyItemMapper(_, scope string, awsItem *types.Contin // Terraform is not yet supported for this: https://github.com/hashicorp/terraform-provider-aws/issues/28920 -func NewContinuousDeploymentPolicySource(client *cloudfront.Client, accountID string) *sources.GetListSource[*types.ContinuousDeploymentPolicy, *cloudfront.Client, *cloudfront.Options] { - return &sources.GetListSource[*types.ContinuousDeploymentPolicy, *cloudfront.Client, *cloudfront.Options]{ +func NewContinuousDeploymentPolicyAdapter(client *cloudfront.Client, accountID string) *adapters.GetListAdapter[*types.ContinuousDeploymentPolicy, *cloudfront.Client, *cloudfront.Options] { + return &adapters.GetListAdapter[*types.ContinuousDeploymentPolicy, *cloudfront.Client, *cloudfront.Options]{ ItemType: "cloudfront-continuous-deployment-policy", Client: client, AccountID: accountID, Region: "", // Cloudfront resources aren't tied to a region SupportGlobalResources: true, // Some policies are global + AdapterMetadata: ContinuousDeploymentPolicyMetadata(), GetFunc: func(ctx context.Context, client *cloudfront.Client, scope, query string) (*types.ContinuousDeploymentPolicy, error) { out, err := client.GetContinuousDeploymentPolicy(ctx, &cloudfront.GetContinuousDeploymentPolicyInput{ Id: &query, @@ -91,3 +92,20 @@ func NewContinuousDeploymentPolicySource(client *cloudfront.Client, accountID st ItemMapper: continuousDeploymentPolicyItemMapper, } } + +func ContinuousDeploymentPolicyMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "cloudfront-continuous-deployment-policy", + DescriptiveName: "CloudFront Continuous Deployment Policy", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a CloudFront Continuous Deployment Policy by ID", + ListDescription: "List CloudFront Continuous Deployment Policies", + SearchDescription: "Search CloudFront Continuous Deployment Policies by ARN", + }, + PotentialLinks: []string{"dns"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_CONFIGURATION, + } +} diff --git a/sources/cloudfront/continuous_deployment_policy_test.go b/adapters/cloudfront/continuous_deployment_policy_test.go similarity index 65% rename from sources/cloudfront/continuous_deployment_policy_test.go rename to adapters/cloudfront/continuous_deployment_policy_test.go index 34aef541..31132de6 100644 --- a/sources/cloudfront/continuous_deployment_policy_test.go +++ b/adapters/cloudfront/continuous_deployment_policy_test.go @@ -5,18 +5,18 @@ import ( "time" "github.com/aws/aws-sdk-go-v2/service/cloudfront/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) func TestContinuousDeploymentPolicyItemMapper(t *testing.T) { item, err := continuousDeploymentPolicyItemMapper("", "test", &types.ContinuousDeploymentPolicy{ - Id: sources.PtrString("test-id"), - LastModifiedTime: sources.PtrTime(time.Now()), + Id: adapters.PtrString("test-id"), + LastModifiedTime: adapters.PtrTime(time.Now()), ContinuousDeploymentPolicyConfig: &types.ContinuousDeploymentPolicyConfig{ - Enabled: sources.PtrBool(true), + Enabled: adapters.PtrBool(true), StagingDistributionDnsNames: &types.StagingDistributionDnsNames{ - Quantity: sources.PtrInt32(1), + Quantity: adapters.PtrInt32(1), Items: []string{ "staging.test.com", // link }, @@ -24,14 +24,14 @@ func TestContinuousDeploymentPolicyItemMapper(t *testing.T) { TrafficConfig: &types.TrafficConfig{ Type: types.ContinuousDeploymentPolicyTypeSingleWeight, SingleHeaderConfig: &types.ContinuousDeploymentSingleHeaderConfig{ - Header: sources.PtrString("test-header"), - Value: sources.PtrString("test-value"), + Header: adapters.PtrString("test-header"), + Value: adapters.PtrString("test-value"), }, SingleWeightConfig: &types.ContinuousDeploymentSingleWeightConfig{ - Weight: sources.PtrFloat32(1), + Weight: adapters.PtrFloat32(1), SessionStickinessConfig: &types.SessionStickinessConfig{ - IdleTTL: sources.PtrInt32(1), - MaximumTTL: sources.PtrInt32(2), + IdleTTL: adapters.PtrInt32(1), + MaximumTTL: adapters.PtrInt32(2), }, }, }, @@ -46,7 +46,7 @@ func TestContinuousDeploymentPolicyItemMapper(t *testing.T) { t.Error(err) } - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "dns", ExpectedMethod: sdp.QueryMethod_SEARCH, @@ -58,13 +58,13 @@ func TestContinuousDeploymentPolicyItemMapper(t *testing.T) { tests.Execute(t, item) } -func TestNewContinuousDeploymentPolicySource(t *testing.T) { +func TestNewContinuousDeploymentPolicyAdapter(t *testing.T) { client, account, _ := GetAutoConfig(t) - source := NewContinuousDeploymentPolicySource(client, account) + adapter := NewContinuousDeploymentPolicyAdapter(client, account) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/cloudfront/distribution.go b/adapters/cloudfront/distribution.go similarity index 85% rename from sources/cloudfront/distribution.go rename to adapters/cloudfront/distribution.go index 19c65c96..4fd304dc 100644 --- a/sources/cloudfront/distribution.go +++ b/adapters/cloudfront/distribution.go @@ -5,7 +5,7 @@ import ( "regexp" "github.com/aws/aws-sdk-go-v2/service/cloudfront" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -37,10 +37,10 @@ func distributionGetFunc(ctx context.Context, client CloudFrontClient, scope str if err == nil { tags = tagsToMap(tagsOut.Tags) } else { - tags = sources.HandleTagsError(ctx, err) + tags = adapters.HandleTagsError(ctx, err) } - attributes, err := sources.ToAttributesWithExclude(d) + attributes, err := adapters.ToAttributesWithExclude(d) if err != nil { return nil, err @@ -215,14 +215,14 @@ func distributionGetFunc(ctx context.Context, client CloudFrontClient, scope str } if behavior.RealtimeLogConfigArn != nil { - if arn, err := sources.ParseARN(*behavior.RealtimeLogConfigArn); err == nil { + if arn, err := adapters.ParseARN(*behavior.RealtimeLogConfigArn); err == nil { // +overmind:link cloudfront-realtime-log-config item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "cloudfront-realtime-log-config", Method: sdp.QueryMethod_SEARCH, Query: *behavior.RealtimeLogConfigArn, - Scope: sources.FormatScope(arn.AccountID, arn.Region), + Scope: adapters.FormatScope(arn.AccountID, arn.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changing the config will affect the distribution @@ -275,14 +275,14 @@ func distributionGetFunc(ctx context.Context, client CloudFrontClient, scope str if behavior.FunctionAssociations != nil { for _, function := range behavior.FunctionAssociations.Items { if function.FunctionARN != nil { - if arn, err := sources.ParseARN(*function.FunctionARN); err == nil { + if arn, err := adapters.ParseARN(*function.FunctionARN); err == nil { // +overmind:link cloudfront-function item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "cloudfront-function", Method: sdp.QueryMethod_SEARCH, Query: *function.FunctionARN, - Scope: sources.FormatScope(arn.AccountID, arn.Region), + Scope: adapters.FormatScope(arn.AccountID, arn.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changing the function could affect the distribution @@ -298,14 +298,14 @@ func distributionGetFunc(ctx context.Context, client CloudFrontClient, scope str if behavior.LambdaFunctionAssociations != nil { for _, function := range behavior.LambdaFunctionAssociations.Items { - if arn, err := sources.ParseARN(*function.LambdaFunctionARN); err == nil { + if arn, err := adapters.ParseARN(*function.LambdaFunctionARN); err == nil { // +overmind:link lambda-function item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "lambda-function", Method: sdp.QueryMethod_SEARCH, Query: *function.LambdaFunctionARN, - Scope: sources.FormatScope(arn.AccountID, arn.Region), + Scope: adapters.FormatScope(arn.AccountID, arn.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changing the function could affect the distribution @@ -370,7 +370,7 @@ func distributionGetFunc(ctx context.Context, client CloudFrontClient, scope str Type: "s3-bucket", Method: sdp.QueryMethod_GET, Query: matches[1], - Scope: sources.FormatScope(scope, ""), // S3 buckets are global + Scope: adapters.FormatScope(scope, ""), // S3 buckets are global }, BlastPropagation: &sdp.BlastPropagation{ // Changing the bucket could affect the distribution @@ -459,14 +459,14 @@ func distributionGetFunc(ctx context.Context, client CloudFrontClient, scope str } if dc.DefaultCacheBehavior.RealtimeLogConfigArn != nil { - if arn, err := sources.ParseARN(*dc.DefaultCacheBehavior.RealtimeLogConfigArn); err == nil { + if arn, err := adapters.ParseARN(*dc.DefaultCacheBehavior.RealtimeLogConfigArn); err == nil { // +overmind:link cloudfront-realtime-log-config item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "cloudfront-realtime-log-config", Method: sdp.QueryMethod_GET, Query: *dc.DefaultCacheBehavior.RealtimeLogConfigArn, - Scope: sources.FormatScope(arn.AccountID, arn.Region), + Scope: adapters.FormatScope(arn.AccountID, arn.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changing the config will affect the distribution @@ -519,14 +519,14 @@ func distributionGetFunc(ctx context.Context, client CloudFrontClient, scope str if dc.DefaultCacheBehavior.FunctionAssociations != nil { for _, function := range dc.DefaultCacheBehavior.FunctionAssociations.Items { if function.FunctionARN != nil { - if arn, err := sources.ParseARN(*function.FunctionARN); err == nil { + if arn, err := adapters.ParseARN(*function.FunctionARN); err == nil { // +overmind:link cloudfront-function item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "cloudfront-function", Method: sdp.QueryMethod_SEARCH, Query: *function.FunctionARN, - Scope: sources.FormatScope(arn.AccountID, arn.Region), + Scope: adapters.FormatScope(arn.AccountID, arn.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changing the function could affect the distribution @@ -542,14 +542,14 @@ func distributionGetFunc(ctx context.Context, client CloudFrontClient, scope str if dc.DefaultCacheBehavior.LambdaFunctionAssociations != nil { for _, function := range dc.DefaultCacheBehavior.LambdaFunctionAssociations.Items { - if arn, err := sources.ParseARN(*function.LambdaFunctionARN); err == nil { + if arn, err := adapters.ParseARN(*function.LambdaFunctionARN); err == nil { // +overmind:link lambda-function item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "lambda-function", Method: sdp.QueryMethod_SEARCH, Query: *function.LambdaFunctionARN, - Scope: sources.FormatScope(arn.AccountID, arn.Region), + Scope: adapters.FormatScope(arn.AccountID, arn.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changing the function could affect the distribution @@ -582,14 +582,14 @@ func distributionGetFunc(ctx context.Context, client CloudFrontClient, scope str if dc.ViewerCertificate != nil { if dc.ViewerCertificate.ACMCertificateArn != nil { - if arn, err := sources.ParseARN(*dc.ViewerCertificate.ACMCertificateArn); err == nil { + if arn, err := adapters.ParseARN(*dc.ViewerCertificate.ACMCertificateArn); err == nil { // +overmind:link acm-certificate item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "acm-certificate", Method: sdp.QueryMethod_SEARCH, Query: *dc.ViewerCertificate.ACMCertificateArn, - Scope: sources.FormatScope(arn.AccountID, arn.Region), + Scope: adapters.FormatScope(arn.AccountID, arn.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changing the certificate could affect the distribution @@ -620,14 +620,14 @@ func distributionGetFunc(ctx context.Context, client CloudFrontClient, scope str } if dc.WebACLId != nil { - if arn, err := sources.ParseARN(*dc.WebACLId); err == nil { + if arn, err := adapters.ParseARN(*dc.WebACLId); err == nil { // +overmind:link wafv2-web-acl item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "wafv2-web-acl", Method: sdp.QueryMethod_SEARCH, Query: *dc.WebACLId, - Scope: sources.FormatScope(arn.AccountID, arn.Region), + Scope: adapters.FormatScope(arn.AccountID, arn.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changing the ACL could affect the distribution @@ -670,14 +670,15 @@ func distributionGetFunc(ctx context.Context, client CloudFrontClient, scope str // +overmind:terraform:queryMap aws_cloudfront_distribution.arn // +overmind:terraform:method SEARCH -func NewDistributionSource(client CloudFrontClient, accountID string) *sources.AlwaysGetSource[*cloudfront.ListDistributionsInput, *cloudfront.ListDistributionsOutput, *cloudfront.GetDistributionInput, *cloudfront.GetDistributionOutput, CloudFrontClient, *cloudfront.Options] { - return &sources.AlwaysGetSource[*cloudfront.ListDistributionsInput, *cloudfront.ListDistributionsOutput, *cloudfront.GetDistributionInput, *cloudfront.GetDistributionOutput, CloudFrontClient, *cloudfront.Options]{ - ItemType: "cloudfront-distribution", - Client: client, - AccountID: accountID, - Region: "", // Cloudfront resources aren't tied to a region - ListInput: &cloudfront.ListDistributionsInput{}, - ListFuncPaginatorBuilder: func(client CloudFrontClient, input *cloudfront.ListDistributionsInput) sources.Paginator[*cloudfront.ListDistributionsOutput, *cloudfront.Options] { +func NewDistributionAdapter(client CloudFrontClient, accountID string) *adapters.AlwaysGetAdapter[*cloudfront.ListDistributionsInput, *cloudfront.ListDistributionsOutput, *cloudfront.GetDistributionInput, *cloudfront.GetDistributionOutput, CloudFrontClient, *cloudfront.Options] { + return &adapters.AlwaysGetAdapter[*cloudfront.ListDistributionsInput, *cloudfront.ListDistributionsOutput, *cloudfront.GetDistributionInput, *cloudfront.GetDistributionOutput, CloudFrontClient, *cloudfront.Options]{ + ItemType: "cloudfront-distribution", + Client: client, + AccountID: accountID, + AdapterMetadata: DistributionMetadata(), + Region: "", // Cloudfront resources aren't tied to a region + ListInput: &cloudfront.ListDistributionsInput{}, + ListFuncPaginatorBuilder: func(client CloudFrontClient, input *cloudfront.ListDistributionsInput) adapters.Paginator[*cloudfront.ListDistributionsOutput, *cloudfront.Options] { return cloudfront.NewListDistributionsPaginator(client, input) }, GetInputMapper: func(scope, query string) *cloudfront.GetDistributionInput { @@ -699,3 +700,39 @@ func NewDistributionSource(client CloudFrontClient, accountID string) *sources.A GetFunc: distributionGetFunc, } } + +func DistributionMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "cloudfront-distribution", + DescriptiveName: "CloudFront Distribution", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Search: true, + Get: true, + List: true, + GetDescription: "Get a distribution by ID", + ListDescription: "List all distributions", + SearchDescription: "Search distributions by ARN", + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + TerraformMappings: []*sdp.TerraformMapping{ + { + TerraformQueryMap: "aws_cloudfront_distribution.arn", + TerraformMethod: sdp.QueryMethod_SEARCH, + }, + }, + PotentialLinks: []string{ + "cloudfront-key-group", + "cloudfront-cloud-front-origin-access-identity", + "cloudfront-continuous-deployment-policy", + "cloudfront-cache-policy", + "cloudfront-field-level-encryption", + "cloudfront-function", + "cloudfront-origin-request-policy", + "cloudfront-realtime-log-config", + "cloudfront-response-headers-policy", + "dns", + "lambda-function", + "s3-bucket", + }, + } +} diff --git a/sources/cloudfront/distribution_test.go b/adapters/cloudfront/distribution_test.go similarity index 59% rename from sources/cloudfront/distribution_test.go rename to adapters/cloudfront/distribution_test.go index 2d4cd283..a07c731f 100644 --- a/sources/cloudfront/distribution_test.go +++ b/adapters/cloudfront/distribution_test.go @@ -7,27 +7,27 @@ import ( "github.com/aws/aws-sdk-go-v2/service/cloudfront" "github.com/aws/aws-sdk-go-v2/service/cloudfront/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) func (t TestCloudFrontClient) GetDistribution(ctx context.Context, params *cloudfront.GetDistributionInput, optFns ...func(*cloudfront.Options)) (*cloudfront.GetDistributionOutput, error) { return &cloudfront.GetDistributionOutput{ Distribution: &types.Distribution{ - ARN: sources.PtrString("arn:aws:cloudfront::123456789012:distribution/test-id"), - DomainName: sources.PtrString("d111111abcdef8.cloudfront.net"), // link - Id: sources.PtrString("test-id"), - InProgressInvalidationBatches: sources.PtrInt32(1), - LastModifiedTime: sources.PtrTime(time.Now()), - Status: sources.PtrString("Deployed"), // health: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/distribution-web-values-returned.html + ARN: adapters.PtrString("arn:aws:cloudfront::123456789012:distribution/test-id"), + DomainName: adapters.PtrString("d111111abcdef8.cloudfront.net"), // link + Id: adapters.PtrString("test-id"), + InProgressInvalidationBatches: adapters.PtrInt32(1), + LastModifiedTime: adapters.PtrTime(time.Now()), + Status: adapters.PtrString("Deployed"), // health: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/distribution-web-values-returned.html ActiveTrustedKeyGroups: &types.ActiveTrustedKeyGroups{ - Enabled: sources.PtrBool(true), - Quantity: sources.PtrInt32(1), + Enabled: adapters.PtrBool(true), + Quantity: adapters.PtrInt32(1), Items: []types.KGKeyPairIds{ { - KeyGroupId: sources.PtrString("key-group-1"), // link + KeyGroupId: adapters.PtrString("key-group-1"), // link KeyPairIds: &types.KeyPairIds{ - Quantity: sources.PtrInt32(1), + Quantity: adapters.PtrInt32(1), Items: []string{ "123456789", }, @@ -36,13 +36,13 @@ func (t TestCloudFrontClient) GetDistribution(ctx context.Context, params *cloud }, }, ActiveTrustedSigners: &types.ActiveTrustedSigners{ - Enabled: sources.PtrBool(true), - Quantity: sources.PtrInt32(1), + Enabled: adapters.PtrBool(true), + Quantity: adapters.PtrInt32(1), Items: []types.Signer{ { - AwsAccountNumber: sources.PtrString("123456789"), + AwsAccountNumber: adapters.PtrString("123456789"), KeyPairIds: &types.KeyPairIds{ - Quantity: sources.PtrInt32(1), + Quantity: adapters.PtrInt32(1), Items: []string{ "123456789", }, @@ -52,54 +52,54 @@ func (t TestCloudFrontClient) GetDistribution(ctx context.Context, params *cloud }, AliasICPRecordals: []types.AliasICPRecordal{ { - CNAME: sources.PtrString("something.foo.bar.com"), // link + CNAME: adapters.PtrString("something.foo.bar.com"), // link ICPRecordalStatus: types.ICPRecordalStatusApproved, }, }, DistributionConfig: &types.DistributionConfig{ - CallerReference: sources.PtrString("test-caller-reference"), - Comment: sources.PtrString("test-comment"), - Enabled: sources.PtrBool(true), + CallerReference: adapters.PtrString("test-caller-reference"), + Comment: adapters.PtrString("test-comment"), + Enabled: adapters.PtrBool(true), Aliases: &types.Aliases{ - Quantity: sources.PtrInt32(1), + Quantity: adapters.PtrInt32(1), Items: []string{ "www.example.com", // link }, }, - Staging: sources.PtrBool(true), - ContinuousDeploymentPolicyId: sources.PtrString("test-continuous-deployment-policy-id"), // link + Staging: adapters.PtrBool(true), + ContinuousDeploymentPolicyId: adapters.PtrString("test-continuous-deployment-policy-id"), // link CacheBehaviors: &types.CacheBehaviors{ - Quantity: sources.PtrInt32(1), + Quantity: adapters.PtrInt32(1), Items: []types.CacheBehavior{ { - PathPattern: sources.PtrString("/foo"), - TargetOriginId: sources.PtrString("CustomOriginConfig"), + PathPattern: adapters.PtrString("/foo"), + TargetOriginId: adapters.PtrString("CustomOriginConfig"), ViewerProtocolPolicy: types.ViewerProtocolPolicyHttpsOnly, AllowedMethods: &types.AllowedMethods{ Items: []types.Method{ types.MethodGet, }, }, - CachePolicyId: sources.PtrString("test-cache-policy-id"), // link - Compress: sources.PtrBool(true), - DefaultTTL: sources.PtrInt64(1), - FieldLevelEncryptionId: sources.PtrString("test-field-level-encryption-id"), // link - MaxTTL: sources.PtrInt64(1), - MinTTL: sources.PtrInt64(1), - OriginRequestPolicyId: sources.PtrString("test-origin-request-policy-id"), // link - RealtimeLogConfigArn: sources.PtrString("arn:aws:logs:us-east-1:123456789012:realtime-log-config/test-id"), // link - ResponseHeadersPolicyId: sources.PtrString("test-response-headers-policy-id"), // link - SmoothStreaming: sources.PtrBool(true), + CachePolicyId: adapters.PtrString("test-cache-policy-id"), // link + Compress: adapters.PtrBool(true), + DefaultTTL: adapters.PtrInt64(1), + FieldLevelEncryptionId: adapters.PtrString("test-field-level-encryption-id"), // link + MaxTTL: adapters.PtrInt64(1), + MinTTL: adapters.PtrInt64(1), + OriginRequestPolicyId: adapters.PtrString("test-origin-request-policy-id"), // link + RealtimeLogConfigArn: adapters.PtrString("arn:aws:logs:us-east-1:123456789012:realtime-log-config/test-id"), // link + ResponseHeadersPolicyId: adapters.PtrString("test-response-headers-policy-id"), // link + SmoothStreaming: adapters.PtrBool(true), TrustedKeyGroups: &types.TrustedKeyGroups{ - Enabled: sources.PtrBool(true), - Quantity: sources.PtrInt32(1), + Enabled: adapters.PtrBool(true), + Quantity: adapters.PtrInt32(1), Items: []string{ "key-group-1", // link }, }, TrustedSigners: &types.TrustedSigners{ - Enabled: sources.PtrBool(true), - Quantity: sources.PtrInt32(1), + Enabled: adapters.PtrBool(true), + Quantity: adapters.PtrInt32(1), Items: []string{ "123456789", }, @@ -108,42 +108,42 @@ func (t TestCloudFrontClient) GetDistribution(ctx context.Context, params *cloud Cookies: &types.CookiePreference{ Forward: types.ItemSelectionWhitelist, WhitelistedNames: &types.CookieNames{ - Quantity: sources.PtrInt32(1), + Quantity: adapters.PtrInt32(1), Items: []string{ "cookie_123", }, }, }, - QueryString: sources.PtrBool(true), + QueryString: adapters.PtrBool(true), Headers: &types.Headers{ - Quantity: sources.PtrInt32(1), + Quantity: adapters.PtrInt32(1), Items: []string{ "X-Customer-Header", }, }, QueryStringCacheKeys: &types.QueryStringCacheKeys{ - Quantity: sources.PtrInt32(1), + Quantity: adapters.PtrInt32(1), Items: []string{ "test-query-string-cache-key", }, }, }, FunctionAssociations: &types.FunctionAssociations{ - Quantity: sources.PtrInt32(1), + Quantity: adapters.PtrInt32(1), Items: []types.FunctionAssociation{ { EventType: types.EventTypeOriginRequest, - FunctionARN: sources.PtrString("arn:aws:cloudfront::123412341234:function/1234"), // link + FunctionARN: adapters.PtrString("arn:aws:cloudfront::123412341234:function/1234"), // link }, }, }, LambdaFunctionAssociations: &types.LambdaFunctionAssociations{ - Quantity: sources.PtrInt32(1), + Quantity: adapters.PtrInt32(1), Items: []types.LambdaFunctionAssociation{ { EventType: types.EventTypeOriginResponse, - LambdaFunctionARN: sources.PtrString("arn:aws:lambda:us-east-1:123456789012:function:test-function"), // link - IncludeBody: sources.PtrBool(true), + LambdaFunctionARN: adapters.PtrString("arn:aws:lambda:us-east-1:123456789012:function:test-function"), // link + IncludeBody: adapters.PtrBool(true), }, }, }, @@ -153,107 +153,107 @@ func (t TestCloudFrontClient) GetDistribution(ctx context.Context, params *cloud Origins: &types.Origins{ Items: []types.Origin{ { - DomainName: sources.PtrString("DOC-EXAMPLE-BUCKET.s3.us-west-2.amazonaws.com"), // link - Id: sources.PtrString("CustomOriginConfig"), - ConnectionAttempts: sources.PtrInt32(3), - ConnectionTimeout: sources.PtrInt32(10), + DomainName: adapters.PtrString("DOC-EXAMPLE-BUCKET.s3.us-west-2.amazonaws.com"), // link + Id: adapters.PtrString("CustomOriginConfig"), + ConnectionAttempts: adapters.PtrInt32(3), + ConnectionTimeout: adapters.PtrInt32(10), CustomHeaders: &types.CustomHeaders{ - Quantity: sources.PtrInt32(1), + Quantity: adapters.PtrInt32(1), Items: []types.OriginCustomHeader{ { - HeaderName: sources.PtrString("test-header-name"), - HeaderValue: sources.PtrString("test-header-value"), + HeaderName: adapters.PtrString("test-header-name"), + HeaderValue: adapters.PtrString("test-header-value"), }, }, }, CustomOriginConfig: &types.CustomOriginConfig{ - HTTPPort: sources.PtrInt32(80), - HTTPSPort: sources.PtrInt32(443), + HTTPPort: adapters.PtrInt32(80), + HTTPSPort: adapters.PtrInt32(443), OriginProtocolPolicy: types.OriginProtocolPolicyMatchViewer, - OriginKeepaliveTimeout: sources.PtrInt32(5), - OriginReadTimeout: sources.PtrInt32(30), + OriginKeepaliveTimeout: adapters.PtrInt32(5), + OriginReadTimeout: adapters.PtrInt32(30), OriginSslProtocols: &types.OriginSslProtocols{ Items: types.SslProtocolSSLv3.Values(), }, }, - OriginAccessControlId: sources.PtrString("test-origin-access-control-id"), // link - OriginPath: sources.PtrString("/foo"), + OriginAccessControlId: adapters.PtrString("test-origin-access-control-id"), // link + OriginPath: adapters.PtrString("/foo"), OriginShield: &types.OriginShield{ - Enabled: sources.PtrBool(true), - OriginShieldRegion: sources.PtrString("eu-west-1"), + Enabled: adapters.PtrBool(true), + OriginShieldRegion: adapters.PtrString("eu-west-1"), }, S3OriginConfig: &types.S3OriginConfig{ - OriginAccessIdentity: sources.PtrString("test-origin-access-identity"), // link + OriginAccessIdentity: adapters.PtrString("test-origin-access-identity"), // link }, }, }, }, DefaultCacheBehavior: &types.DefaultCacheBehavior{ - TargetOriginId: sources.PtrString("CustomOriginConfig"), + TargetOriginId: adapters.PtrString("CustomOriginConfig"), ViewerProtocolPolicy: types.ViewerProtocolPolicyHttpsOnly, - CachePolicyId: sources.PtrString("test-cache-policy-id"), // link - Compress: sources.PtrBool(true), - DefaultTTL: sources.PtrInt64(1), - FieldLevelEncryptionId: sources.PtrString("test-field-level-encryption-id"), // link - MaxTTL: sources.PtrInt64(1), - MinTTL: sources.PtrInt64(1), - OriginRequestPolicyId: sources.PtrString("test-origin-request-policy-id"), // link - RealtimeLogConfigArn: sources.PtrString("arn:aws:logs:us-east-1:123456789012:realtime-log-config/test-id"), // link - ResponseHeadersPolicyId: sources.PtrString("test-response-headers-policy-id"), // link - SmoothStreaming: sources.PtrBool(true), + CachePolicyId: adapters.PtrString("test-cache-policy-id"), // link + Compress: adapters.PtrBool(true), + DefaultTTL: adapters.PtrInt64(1), + FieldLevelEncryptionId: adapters.PtrString("test-field-level-encryption-id"), // link + MaxTTL: adapters.PtrInt64(1), + MinTTL: adapters.PtrInt64(1), + OriginRequestPolicyId: adapters.PtrString("test-origin-request-policy-id"), // link + RealtimeLogConfigArn: adapters.PtrString("arn:aws:logs:us-east-1:123456789012:realtime-log-config/test-id"), // link + ResponseHeadersPolicyId: adapters.PtrString("test-response-headers-policy-id"), // link + SmoothStreaming: adapters.PtrBool(true), ForwardedValues: &types.ForwardedValues{ Cookies: &types.CookiePreference{ Forward: types.ItemSelectionWhitelist, WhitelistedNames: &types.CookieNames{ - Quantity: sources.PtrInt32(1), + Quantity: adapters.PtrInt32(1), Items: []string{ "cooke_123", }, }, }, - QueryString: sources.PtrBool(true), + QueryString: adapters.PtrBool(true), Headers: &types.Headers{ - Quantity: sources.PtrInt32(1), + Quantity: adapters.PtrInt32(1), Items: []string{ "X-Customer-Header", }, }, QueryStringCacheKeys: &types.QueryStringCacheKeys{ - Quantity: sources.PtrInt32(1), + Quantity: adapters.PtrInt32(1), Items: []string{ "test-query-string-cache-key", }, }, }, FunctionAssociations: &types.FunctionAssociations{ - Quantity: sources.PtrInt32(1), + Quantity: adapters.PtrInt32(1), Items: []types.FunctionAssociation{ { EventType: types.EventTypeViewerRequest, - FunctionARN: sources.PtrString("arn:aws:cloudfront::123412341234:function/1234"), // link + FunctionARN: adapters.PtrString("arn:aws:cloudfront::123412341234:function/1234"), // link }, }, }, LambdaFunctionAssociations: &types.LambdaFunctionAssociations{ - Quantity: sources.PtrInt32(1), + Quantity: adapters.PtrInt32(1), Items: []types.LambdaFunctionAssociation{ { EventType: types.EventTypeOriginRequest, - LambdaFunctionARN: sources.PtrString("arn:aws:lambda:us-east-1:123456789012:function:test-function"), // link - IncludeBody: sources.PtrBool(true), + LambdaFunctionARN: adapters.PtrString("arn:aws:lambda:us-east-1:123456789012:function:test-function"), // link + IncludeBody: adapters.PtrBool(true), }, }, }, TrustedKeyGroups: &types.TrustedKeyGroups{ - Enabled: sources.PtrBool(true), - Quantity: sources.PtrInt32(1), + Enabled: adapters.PtrBool(true), + Quantity: adapters.PtrInt32(1), Items: []string{ "key-group-1", // link }, }, TrustedSigners: &types.TrustedSigners{ - Enabled: sources.PtrBool(true), - Quantity: sources.PtrInt32(1), + Enabled: adapters.PtrBool(true), + Quantity: adapters.PtrInt32(1), Items: []string{ "123456789", }, @@ -262,7 +262,7 @@ func (t TestCloudFrontClient) GetDistribution(ctx context.Context, params *cloud Items: []types.Method{ types.MethodGet, }, - Quantity: sources.PtrInt32(1), + Quantity: adapters.PtrInt32(1), CachedMethods: &types.CachedMethods{ Items: []types.Method{ types.MethodGet, @@ -271,27 +271,27 @@ func (t TestCloudFrontClient) GetDistribution(ctx context.Context, params *cloud }, }, CustomErrorResponses: &types.CustomErrorResponses{ - Quantity: sources.PtrInt32(1), + Quantity: adapters.PtrInt32(1), Items: []types.CustomErrorResponse{ { - ErrorCode: sources.PtrInt32(404), - ErrorCachingMinTTL: sources.PtrInt64(1), - ResponseCode: sources.PtrString("200"), - ResponsePagePath: sources.PtrString("/foo"), + ErrorCode: adapters.PtrInt32(404), + ErrorCachingMinTTL: adapters.PtrInt64(1), + ResponseCode: adapters.PtrString("200"), + ResponsePagePath: adapters.PtrString("/foo"), }, }, }, - DefaultRootObject: sources.PtrString("index.html"), + DefaultRootObject: adapters.PtrString("index.html"), HttpVersion: types.HttpVersionHttp11, - IsIPV6Enabled: sources.PtrBool(true), + IsIPV6Enabled: adapters.PtrBool(true), Logging: &types.LoggingConfig{ - Bucket: sources.PtrString("aws-cf-access-logs.s3.amazonaws.com"), // link - Enabled: sources.PtrBool(true), - IncludeCookies: sources.PtrBool(true), - Prefix: sources.PtrString("test-prefix"), + Bucket: adapters.PtrString("aws-cf-access-logs.s3.amazonaws.com"), // link + Enabled: adapters.PtrBool(true), + IncludeCookies: adapters.PtrBool(true), + Prefix: adapters.PtrString("test-prefix"), }, OriginGroups: &types.OriginGroups{ - Quantity: sources.PtrInt32(1), + Quantity: adapters.PtrInt32(1), Items: []types.OriginGroup{ { FailoverCriteria: &types.OriginGroupFailoverCriteria{ @@ -299,15 +299,15 @@ func (t TestCloudFrontClient) GetDistribution(ctx context.Context, params *cloud Items: []int32{ 404, }, - Quantity: sources.PtrInt32(1), + Quantity: adapters.PtrInt32(1), }, }, - Id: sources.PtrString("test-id"), + Id: adapters.PtrString("test-id"), Members: &types.OriginGroupMembers{ - Quantity: sources.PtrInt32(1), + Quantity: adapters.PtrInt32(1), Items: []types.OriginGroupMember{ { - OriginId: sources.PtrString("CustomOriginConfig"), + OriginId: adapters.PtrString("CustomOriginConfig"), }, }, }, @@ -317,7 +317,7 @@ func (t TestCloudFrontClient) GetDistribution(ctx context.Context, params *cloud PriceClass: types.PriceClassPriceClass200, Restrictions: &types.Restrictions{ GeoRestriction: &types.GeoRestriction{ - Quantity: sources.PtrInt32(1), + Quantity: adapters.PtrInt32(1), RestrictionType: types.GeoRestrictionTypeWhitelist, Items: []string{ "US", @@ -325,16 +325,16 @@ func (t TestCloudFrontClient) GetDistribution(ctx context.Context, params *cloud }, }, ViewerCertificate: &types.ViewerCertificate{ - ACMCertificateArn: sources.PtrString("arn:aws:acm:us-east-1:123456789012:certificate/test-id"), // link - Certificate: sources.PtrString("test-certificate"), + ACMCertificateArn: adapters.PtrString("arn:aws:acm:us-east-1:123456789012:certificate/test-id"), // link + Certificate: adapters.PtrString("test-certificate"), CertificateSource: types.CertificateSourceAcm, - CloudFrontDefaultCertificate: sources.PtrBool(true), - IAMCertificateId: sources.PtrString("test-iam-certificate-id"), // link + CloudFrontDefaultCertificate: adapters.PtrBool(true), + IAMCertificateId: adapters.PtrString("test-iam-certificate-id"), // link MinimumProtocolVersion: types.MinimumProtocolVersion(types.SslProtocolSSLv3), SSLSupportMethod: types.SSLSupportMethodSniOnly, }, // Note this can also be in the format: 473e64fd-f30b-4765-81a0-62ad96dd167a for WAF Classic - WebACLId: sources.PtrString("arn:aws:wafv2:us-east-1:123456789012:global/webacl/ExampleWebACL/473e64fd-f30b-4765-81a0-62ad96dd167a"), // link + WebACLId: adapters.PtrString("arn:aws:wafv2:us-east-1:123456789012:global/webacl/ExampleWebACL/473e64fd-f30b-4765-81a0-62ad96dd167a"), // link }, }, }, nil @@ -343,10 +343,10 @@ func (t TestCloudFrontClient) GetDistribution(ctx context.Context, params *cloud func (t TestCloudFrontClient) ListDistributions(ctx context.Context, params *cloudfront.ListDistributionsInput, optFns ...func(*cloudfront.Options)) (*cloudfront.ListDistributionsOutput, error) { return &cloudfront.ListDistributionsOutput{ DistributionList: &types.DistributionList{ - IsTruncated: sources.PtrBool(false), + IsTruncated: adapters.PtrBool(false), Items: []types.DistributionSummary{ { - Id: sources.PtrString("test-id"), + Id: adapters.PtrString("test-id"), }, }, }, @@ -369,7 +369,7 @@ func TestDistributionGetFunc(t *testing.T) { t.Errorf("expected health to be HEALTH_OK, got %s", item.GetHealth()) } - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "dns", ExpectedMethod: sdp.QueryMethod_SEARCH, @@ -495,14 +495,14 @@ func TestDistributionGetFunc(t *testing.T) { tests.Execute(t, item) } -func TestNewDistributionSource(t *testing.T) { - config, account, _ := sources.GetAutoConfig(t) +func TestNewDistributionAdapter(t *testing.T) { + config, account, _ := adapters.GetAutoConfig(t) client := cloudfront.NewFromConfig(config) - source := NewDistributionSource(client, account) + adapter := NewDistributionAdapter(client, account) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/cloudfront/function.go b/adapters/cloudfront/function.go similarity index 57% rename from sources/cloudfront/function.go rename to adapters/cloudfront/function.go index 504fa8cb..f2d0d749 100644 --- a/sources/cloudfront/function.go +++ b/adapters/cloudfront/function.go @@ -5,12 +5,12 @@ import ( "github.com/aws/aws-sdk-go-v2/service/cloudfront" "github.com/aws/aws-sdk-go-v2/service/cloudfront/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) func functionItemMapper(_, scope string, awsItem *types.FunctionSummary) (*sdp.Item, error) { - attributes, err := sources.ToAttributesWithExclude(awsItem) + attributes, err := adapters.ToAttributesWithExclude(awsItem) if err != nil { return nil, err @@ -35,12 +35,13 @@ func functionItemMapper(_, scope string, awsItem *types.FunctionSummary) (*sdp.I // +overmind:group AWS // +overmind:terraform:queryMap aws_cloudfront_function.name -func NewFunctionSource(client *cloudfront.Client, accountID string) *sources.GetListSource[*types.FunctionSummary, *cloudfront.Client, *cloudfront.Options] { - return &sources.GetListSource[*types.FunctionSummary, *cloudfront.Client, *cloudfront.Options]{ - ItemType: "cloudfront-function", - Client: client, - AccountID: accountID, - Region: "", // Cloudfront resources aren't tied to a region +func NewFunctionAdapter(client *cloudfront.Client, accountID string) *adapters.GetListAdapter[*types.FunctionSummary, *cloudfront.Client, *cloudfront.Options] { + return &adapters.GetListAdapter[*types.FunctionSummary, *cloudfront.Client, *cloudfront.Options]{ + ItemType: "cloudfront-function", + Client: client, + AccountID: accountID, + Region: "", // Cloudfront resources aren't tied to a region + AdapterMetadata: FunctionMetadata(), GetFunc: func(ctx context.Context, client *cloudfront.Client, scope, query string) (*types.FunctionSummary, error) { out, err := client.DescribeFunction(ctx, &cloudfront.DescribeFunctionInput{ Name: &query, @@ -72,3 +73,22 @@ func NewFunctionSource(client *cloudfront.Client, accountID string) *sources.Get ItemMapper: functionItemMapper, } } + +func FunctionMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "cloudfront-function", + DescriptiveName: "CloudFront Function", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a CloudFront Function by name", + ListDescription: "List CloudFront Functions", + SearchDescription: "Search CloudFront Functions by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_cloudfront_function.name"}, + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_COMPUTE_APPLICATION, + } +} diff --git a/sources/cloudfront/function_test.go b/adapters/cloudfront/function_test.go similarity index 54% rename from sources/cloudfront/function_test.go rename to adapters/cloudfront/function_test.go index 8ee1e97c..a4e4fdda 100644 --- a/sources/cloudfront/function_test.go +++ b/adapters/cloudfront/function_test.go @@ -5,23 +5,23 @@ import ( "time" "github.com/aws/aws-sdk-go-v2/service/cloudfront/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" ) func TestFunctionItemMapper(t *testing.T) { summary := types.FunctionSummary{ FunctionConfig: &types.FunctionConfig{ - Comment: sources.PtrString("test-comment"), + Comment: adapters.PtrString("test-comment"), Runtime: types.FunctionRuntimeCloudfrontJs20, }, FunctionMetadata: &types.FunctionMetadata{ - FunctionARN: sources.PtrString("arn:aws:cloudfront::123456789012:function/test-function"), - LastModifiedTime: sources.PtrTime(time.Now()), - CreatedTime: sources.PtrTime(time.Now()), + FunctionARN: adapters.PtrString("arn:aws:cloudfront::123456789012:function/test-function"), + LastModifiedTime: adapters.PtrTime(time.Now()), + CreatedTime: adapters.PtrTime(time.Now()), Stage: types.FunctionStageLive, }, - Name: sources.PtrString("test-function"), - Status: sources.PtrString("test-status"), + Name: adapters.PtrString("test-function"), + Status: adapters.PtrString("test-status"), } item, err := functionItemMapper("", "test", &summary) @@ -35,13 +35,13 @@ func TestFunctionItemMapper(t *testing.T) { } } -func TestNewFunctionSource(t *testing.T) { +func TestNewFunctionAdapter(t *testing.T) { client, account, _ := GetAutoConfig(t) - source := NewFunctionSource(client, account) + adapter := NewFunctionAdapter(client, account) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/cloudfront/key_group.go b/adapters/cloudfront/key_group.go similarity index 56% rename from sources/cloudfront/key_group.go rename to adapters/cloudfront/key_group.go index 3858de27..c8396f65 100644 --- a/sources/cloudfront/key_group.go +++ b/adapters/cloudfront/key_group.go @@ -5,12 +5,12 @@ import ( "github.com/aws/aws-sdk-go-v2/service/cloudfront" "github.com/aws/aws-sdk-go-v2/service/cloudfront/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) func KeyGroupItemMapper(_, scope string, awsItem *types.KeyGroup) (*sdp.Item, error) { - attributes, err := sources.ToAttributesWithExclude(awsItem) + attributes, err := adapters.ToAttributesWithExclude(awsItem) if err != nil { return nil, err @@ -35,12 +35,13 @@ func KeyGroupItemMapper(_, scope string, awsItem *types.KeyGroup) (*sdp.Item, er // +overmind:group AWS // +overmind:terraform:queryMap aws_cloudfront_key_group.id -func NewKeyGroupSource(client *cloudfront.Client, accountID string) *sources.GetListSource[*types.KeyGroup, *cloudfront.Client, *cloudfront.Options] { - return &sources.GetListSource[*types.KeyGroup, *cloudfront.Client, *cloudfront.Options]{ - ItemType: "cloudfront-key-group", - Client: client, - AccountID: accountID, - Region: "", // Cloudfront resources aren't tied to a region +func NewKeyGroupAdapter(client *cloudfront.Client, accountID string) *adapters.GetListAdapter[*types.KeyGroup, *cloudfront.Client, *cloudfront.Options] { + return &adapters.GetListAdapter[*types.KeyGroup, *cloudfront.Client, *cloudfront.Options]{ + ItemType: "cloudfront-key-group", + Client: client, + AccountID: accountID, + Region: "", // Cloudfront resources aren't tied to a region + AdapterMetadata: KeyGroupMetadata(), GetFunc: func(ctx context.Context, client *cloudfront.Client, scope, query string) (*types.KeyGroup, error) { out, err := client.GetKeyGroup(ctx, &cloudfront.GetKeyGroupInput{ Id: &query, @@ -70,3 +71,22 @@ func NewKeyGroupSource(client *cloudfront.Client, accountID string) *sources.Get ItemMapper: KeyGroupItemMapper, } } + +func KeyGroupMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "cloudfront-key-group", + DescriptiveName: "CloudFront Key Group", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a CloudFront Key Group by ID", + ListDescription: "List CloudFront Key Groups", + SearchDescription: "Search CloudFront Key Groups by ARN", + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_CONFIGURATION, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_cloudfront_key_group.id"}, + }, + } +} diff --git a/sources/cloudfront/key_group_test.go b/adapters/cloudfront/key_group_test.go similarity index 58% rename from sources/cloudfront/key_group_test.go rename to adapters/cloudfront/key_group_test.go index aa37e1e7..d6f7d7c0 100644 --- a/sources/cloudfront/key_group_test.go +++ b/adapters/cloudfront/key_group_test.go @@ -5,20 +5,20 @@ import ( "time" "github.com/aws/aws-sdk-go-v2/service/cloudfront/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" ) func TestKeyGroupItemMapper(t *testing.T) { group := types.KeyGroup{ - Id: sources.PtrString("test-id"), + Id: adapters.PtrString("test-id"), KeyGroupConfig: &types.KeyGroupConfig{ Items: []string{ "some-identity", }, - Name: sources.PtrString("test-name"), - Comment: sources.PtrString("test-comment"), + Name: adapters.PtrString("test-name"), + Comment: adapters.PtrString("test-comment"), }, - LastModifiedTime: sources.PtrTime(time.Now()), + LastModifiedTime: adapters.PtrTime(time.Now()), } item, err := KeyGroupItemMapper("", "test", &group) @@ -32,13 +32,13 @@ func TestKeyGroupItemMapper(t *testing.T) { } } -func TestNewKeyGroupSource(t *testing.T) { +func TestNewKeyGroupAdapter(t *testing.T) { client, account, _ := GetAutoConfig(t) - source := NewKeyGroupSource(client, account) + adapter := NewKeyGroupAdapter(client, account) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/cloudfront/origin_access_control.go b/adapters/cloudfront/origin_access_control.go similarity index 65% rename from sources/cloudfront/origin_access_control.go rename to adapters/cloudfront/origin_access_control.go index ab9bd022..4d7efa7d 100644 --- a/sources/cloudfront/origin_access_control.go +++ b/adapters/cloudfront/origin_access_control.go @@ -5,7 +5,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/cloudfront" "github.com/aws/aws-sdk-go-v2/service/cloudfront/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -38,7 +38,7 @@ func originAccessControlListFunc(ctx context.Context, client *cloudfront.Client, } func originAccessControlItemMapper(_, scope string, awsItem *types.OriginAccessControl) (*sdp.Item, error) { - attributes, err := sources.ToAttributesWithExclude(awsItem) + attributes, err := adapters.ToAttributesWithExclude(awsItem) if err != nil { return nil, err @@ -63,12 +63,13 @@ func originAccessControlItemMapper(_, scope string, awsItem *types.OriginAccessC // +overmind:group AWS // +overmind:terraform:queryMap aws_cloudfront_origin_access_control.id -func NewOriginAccessControlSource(client *cloudfront.Client, accountID string) *sources.GetListSource[*types.OriginAccessControl, *cloudfront.Client, *cloudfront.Options] { - return &sources.GetListSource[*types.OriginAccessControl, *cloudfront.Client, *cloudfront.Options]{ - ItemType: "cloudfront-origin-access-control", - Client: client, - AccountID: accountID, - Region: "", // Cloudfront resources aren't tied to a region +func NewOriginAccessControlAdapter(client *cloudfront.Client, accountID string) *adapters.GetListAdapter[*types.OriginAccessControl, *cloudfront.Client, *cloudfront.Options] { + return &adapters.GetListAdapter[*types.OriginAccessControl, *cloudfront.Client, *cloudfront.Options]{ + ItemType: "cloudfront-origin-access-control", + Client: client, + AccountID: accountID, + Region: "", // Cloudfront resources aren't tied to a region + AdapterMetadata: OriginAccessControlMetadata(), GetFunc: func(ctx context.Context, client *cloudfront.Client, scope, query string) (*types.OriginAccessControl, error) { out, err := client.GetOriginAccessControl(ctx, &cloudfront.GetOriginAccessControlInput{ Id: &query, @@ -84,3 +85,22 @@ func NewOriginAccessControlSource(client *cloudfront.Client, accountID string) * ItemMapper: originAccessControlItemMapper, } } + +func OriginAccessControlMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "cloudfront-origin-access-control", + DescriptiveName: "Cloudfront Origin Access Control", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get Origin Access Control by ID", + ListDescription: "List Origin Access Controls", + SearchDescription: "Origin Access Control by ARN", + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_SECURITY, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_cloudfront_origin_access_control.id"}, + }, + } +} diff --git a/sources/cloudfront/origin_access_control_test.go b/adapters/cloudfront/origin_access_control_test.go similarity index 66% rename from sources/cloudfront/origin_access_control_test.go rename to adapters/cloudfront/origin_access_control_test.go index bda3c5e2..c5643f12 100644 --- a/sources/cloudfront/origin_access_control_test.go +++ b/adapters/cloudfront/origin_access_control_test.go @@ -5,18 +5,18 @@ import ( "time" "github.com/aws/aws-sdk-go-v2/service/cloudfront/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" ) func TestOriginAccessControlItemMapper(t *testing.T) { x := types.OriginAccessControl{ - Id: sources.PtrString("test"), + Id: adapters.PtrString("test"), OriginAccessControlConfig: &types.OriginAccessControlConfig{ - Name: sources.PtrString("example-name"), + Name: adapters.PtrString("example-name"), OriginAccessControlOriginType: types.OriginAccessControlOriginTypesS3, SigningBehavior: types.OriginAccessControlSigningBehaviorsAlways, SigningProtocol: types.OriginAccessControlSigningProtocolsSigv4, - Description: sources.PtrString("example-description"), + Description: adapters.PtrString("example-description"), }, } @@ -31,13 +31,13 @@ func TestOriginAccessControlItemMapper(t *testing.T) { } } -func TestNewOriginAccessControlSource(t *testing.T) { +func TestNewOriginAccessControlAdapter(t *testing.T) { client, account, _ := GetAutoConfig(t) - source := NewOriginAccessControlSource(client, account) + adapter := NewOriginAccessControlAdapter(client, account) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/cloudfront/origin_request_policy.go b/adapters/cloudfront/origin_request_policy.go similarity index 57% rename from sources/cloudfront/origin_request_policy.go rename to adapters/cloudfront/origin_request_policy.go index 7073ca4c..5c37a222 100644 --- a/sources/cloudfront/origin_request_policy.go +++ b/adapters/cloudfront/origin_request_policy.go @@ -5,12 +5,12 @@ import ( "github.com/aws/aws-sdk-go-v2/service/cloudfront" "github.com/aws/aws-sdk-go-v2/service/cloudfront/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) func originRequestPolicyItemMapper(_, scope string, awsItem *types.OriginRequestPolicy) (*sdp.Item, error) { - attributes, err := sources.ToAttributesWithExclude(awsItem) + attributes, err := adapters.ToAttributesWithExclude(awsItem) if err != nil { return nil, err @@ -35,12 +35,13 @@ func originRequestPolicyItemMapper(_, scope string, awsItem *types.OriginRequest // +overmind:group AWS // +overmind:terraform:queryMap aws_cloudfront_origin_request_policy.id -func NewOriginRequestPolicySource(client *cloudfront.Client, accountID string) *sources.GetListSource[*types.OriginRequestPolicy, *cloudfront.Client, *cloudfront.Options] { - return &sources.GetListSource[*types.OriginRequestPolicy, *cloudfront.Client, *cloudfront.Options]{ - ItemType: "cloudfront-origin-request-policy", - Client: client, - AccountID: accountID, - Region: "", // Cloudfront resources aren't tied to a region +func NewOriginRequestPolicyAdapter(client *cloudfront.Client, accountID string) *adapters.GetListAdapter[*types.OriginRequestPolicy, *cloudfront.Client, *cloudfront.Options] { + return &adapters.GetListAdapter[*types.OriginRequestPolicy, *cloudfront.Client, *cloudfront.Options]{ + ItemType: "cloudfront-origin-request-policy", + Client: client, + AccountID: accountID, + Region: "", // Cloudfront resources aren't tied to a region + AdapterMetadata: OriginRequestPolicySourceMetadata(), GetFunc: func(ctx context.Context, client *cloudfront.Client, scope, query string) (*types.OriginRequestPolicy, error) { out, err := client.GetOriginRequestPolicy(ctx, &cloudfront.GetOriginRequestPolicyInput{ Id: &query, @@ -70,3 +71,22 @@ func NewOriginRequestPolicySource(client *cloudfront.Client, accountID string) * ItemMapper: originRequestPolicyItemMapper, } } + +func OriginRequestPolicySourceMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "cloudfront-origin-request-policy", + DescriptiveName: "CloudFront Origin Request Policy", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get Origin Request Policy by ID", + ListDescription: "List Origin Request Policies", + SearchDescription: "Origin Request Policy by ARN", + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_cloudfront_origin_request_policy.id"}, + }, + } +} diff --git a/sources/cloudfront/origin_request_policy_test.go b/adapters/cloudfront/origin_request_policy_test.go similarity index 69% rename from sources/cloudfront/origin_request_policy_test.go rename to adapters/cloudfront/origin_request_policy_test.go index 545d8cca..46308371 100644 --- a/sources/cloudfront/origin_request_policy_test.go +++ b/adapters/cloudfront/origin_request_policy_test.go @@ -5,34 +5,34 @@ import ( "time" "github.com/aws/aws-sdk-go-v2/service/cloudfront/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" ) func TestOriginRequestPolicyItemMapper(t *testing.T) { x := types.OriginRequestPolicy{ - Id: sources.PtrString("test"), - LastModifiedTime: sources.PtrTime(time.Now()), + Id: adapters.PtrString("test"), + LastModifiedTime: adapters.PtrTime(time.Now()), OriginRequestPolicyConfig: &types.OriginRequestPolicyConfig{ - Name: sources.PtrString("example-policy"), - Comment: sources.PtrString("example comment"), + Name: adapters.PtrString("example-policy"), + Comment: adapters.PtrString("example comment"), QueryStringsConfig: &types.OriginRequestPolicyQueryStringsConfig{ QueryStringBehavior: types.OriginRequestPolicyQueryStringBehaviorAllExcept, QueryStrings: &types.QueryStringNames{ - Quantity: sources.PtrInt32(1), + Quantity: adapters.PtrInt32(1), Items: []string{"test"}, }, }, CookiesConfig: &types.OriginRequestPolicyCookiesConfig{ CookieBehavior: types.OriginRequestPolicyCookieBehaviorAll, Cookies: &types.CookieNames{ - Quantity: sources.PtrInt32(1), + Quantity: adapters.PtrInt32(1), Items: []string{"test"}, }, }, HeadersConfig: &types.OriginRequestPolicyHeadersConfig{ HeaderBehavior: types.OriginRequestPolicyHeaderBehaviorAllViewer, Headers: &types.Headers{ - Quantity: sources.PtrInt32(1), + Quantity: adapters.PtrInt32(1), Items: []string{"test"}, }, }, @@ -50,13 +50,13 @@ func TestOriginRequestPolicyItemMapper(t *testing.T) { } } -func TestNewOriginRequestPolicySource(t *testing.T) { +func TestNewOriginRequestPolicyAdapter(t *testing.T) { client, account, _ := GetAutoConfig(t) - source := NewOriginRequestPolicySource(client, account) + adapter := NewOriginRequestPolicyAdapter(client, account) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/cloudfront/realtime_log_configs.go b/adapters/cloudfront/realtime_log_configs.go similarity index 63% rename from sources/cloudfront/realtime_log_configs.go rename to adapters/cloudfront/realtime_log_configs.go index a208f6e6..fd67f107 100644 --- a/sources/cloudfront/realtime_log_configs.go +++ b/adapters/cloudfront/realtime_log_configs.go @@ -5,12 +5,12 @@ import ( "github.com/aws/aws-sdk-go-v2/service/cloudfront" "github.com/aws/aws-sdk-go-v2/service/cloudfront/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) func realtimeLogConfigsItemMapper(_, scope string, awsItem *types.RealtimeLogConfig) (*sdp.Item, error) { - attributes, err := sources.ToAttributesWithExclude(awsItem) + attributes, err := adapters.ToAttributesWithExclude(awsItem) if err != nil { return nil, err @@ -26,14 +26,14 @@ func realtimeLogConfigsItemMapper(_, scope string, awsItem *types.RealtimeLogCon for _, endpoint := range awsItem.EndPoints { if endpoint.KinesisStreamConfig != nil { if endpoint.KinesisStreamConfig.RoleARN != nil { - if arn, err := sources.ParseARN(*endpoint.KinesisStreamConfig.RoleARN); err == nil { + if arn, err := adapters.ParseARN(*endpoint.KinesisStreamConfig.RoleARN); err == nil { // +overmind:link iam-role item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "iam-role", Method: sdp.QueryMethod_SEARCH, Query: *endpoint.KinesisStreamConfig.RoleARN, - Scope: sources.FormatScope(arn.AccountID, arn.Region), + Scope: adapters.FormatScope(arn.AccountID, arn.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changes to the role will affect us @@ -46,14 +46,14 @@ func realtimeLogConfigsItemMapper(_, scope string, awsItem *types.RealtimeLogCon } if endpoint.KinesisStreamConfig.StreamARN != nil { - if arn, err := sources.ParseARN(*endpoint.KinesisStreamConfig.StreamARN); err == nil { + if arn, err := adapters.ParseARN(*endpoint.KinesisStreamConfig.StreamARN); err == nil { // +overmind:link kinesis-stream item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "kinesis-stream", Method: sdp.QueryMethod_SEARCH, Query: *endpoint.KinesisStreamConfig.StreamARN, - Scope: sources.FormatScope(arn.AccountID, arn.Region), + Scope: adapters.FormatScope(arn.AccountID, arn.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changes to this will affect the stream @@ -80,12 +80,13 @@ func realtimeLogConfigsItemMapper(_, scope string, awsItem *types.RealtimeLogCon // +overmind:terraform:queryMap aws_cloudfront_realtime_log_config.arn // +overmind:terraform:method SEARCH -func NewRealtimeLogConfigsSource(client *cloudfront.Client, accountID string) *sources.GetListSource[*types.RealtimeLogConfig, *cloudfront.Client, *cloudfront.Options] { - return &sources.GetListSource[*types.RealtimeLogConfig, *cloudfront.Client, *cloudfront.Options]{ - ItemType: "cloudfront-realtime-log-config", - Client: client, - AccountID: accountID, - Region: "", // Cloudfront resources aren't tied to a region +func NewRealtimeLogConfigsAdapter(client *cloudfront.Client, accountID string) *adapters.GetListAdapter[*types.RealtimeLogConfig, *cloudfront.Client, *cloudfront.Options] { + return &adapters.GetListAdapter[*types.RealtimeLogConfig, *cloudfront.Client, *cloudfront.Options]{ + ItemType: "cloudfront-realtime-log-config", + Client: client, + AccountID: accountID, + Region: "", // Cloudfront resources aren't tied to a region + AdapterMetadata: RealtimeLogConfigsMetadata(), GetFunc: func(ctx context.Context, client *cloudfront.Client, scope, query string) (*types.RealtimeLogConfig, error) { out, err := client.GetRealtimeLogConfig(ctx, &cloudfront.GetRealtimeLogConfigInput{ Name: &query, @@ -115,3 +116,25 @@ func NewRealtimeLogConfigsSource(client *cloudfront.Client, accountID string) *s ItemMapper: realtimeLogConfigsItemMapper, } } + +func RealtimeLogConfigsMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "cloudfront-realtime-log-config", + DescriptiveName: "CloudFront Realtime Log Config", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get Realtime Log Config by Name", + ListDescription: "List Realtime Log Configs", + SearchDescription: "Search Realtime Log Configs by ARN", + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_CONFIGURATION, + TerraformMappings: []*sdp.TerraformMapping{ + { + TerraformQueryMap: "aws_cloudfront_realtime_log_config.arn", + TerraformMethod: sdp.QueryMethod_SEARCH, + }, + }, + } +} diff --git a/sources/cloudfront/realtime_log_configs_test.go b/adapters/cloudfront/realtime_log_configs_test.go similarity index 59% rename from sources/cloudfront/realtime_log_configs_test.go rename to adapters/cloudfront/realtime_log_configs_test.go index 1942441a..22a5d148 100644 --- a/sources/cloudfront/realtime_log_configs_test.go +++ b/adapters/cloudfront/realtime_log_configs_test.go @@ -5,21 +5,21 @@ import ( "time" "github.com/aws/aws-sdk-go-v2/service/cloudfront/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) func TestRealtimeLogConfigsItemMapper(t *testing.T) { x := types.RealtimeLogConfig{ - Name: sources.PtrString("test"), - SamplingRate: sources.PtrInt64(100), - ARN: sources.PtrString("arn:aws:cloudfront::123456789012:realtime-log-config/12345678-1234-1234-1234-123456789012"), + Name: adapters.PtrString("test"), + SamplingRate: adapters.PtrInt64(100), + ARN: adapters.PtrString("arn:aws:cloudfront::123456789012:realtime-log-config/12345678-1234-1234-1234-123456789012"), EndPoints: []types.EndPoint{ { - StreamType: sources.PtrString("Kinesis"), + StreamType: adapters.PtrString("Kinesis"), KinesisStreamConfig: &types.KinesisStreamConfig{ - RoleARN: sources.PtrString("arn:aws:iam::123456789012:role/CloudFront_Logger"), // link - StreamARN: sources.PtrString("arn:aws:kinesis:us-east-1:123456789012:stream/cloudfront-logs"), // link + RoleARN: adapters.PtrString("arn:aws:iam::123456789012:role/CloudFront_Logger"), // link + StreamARN: adapters.PtrString("arn:aws:kinesis:us-east-1:123456789012:stream/cloudfront-logs"), // link }, }, }, @@ -38,7 +38,7 @@ func TestRealtimeLogConfigsItemMapper(t *testing.T) { t.Error(err) } - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "iam-role", ExpectedQuery: "arn:aws:iam::123456789012:role/CloudFront_Logger", @@ -56,13 +56,13 @@ func TestRealtimeLogConfigsItemMapper(t *testing.T) { tests.Execute(t, item) } -func TestNewRealtimeLogConfigsSource(t *testing.T) { +func TestNewRealtimeLogConfigsAdapter(t *testing.T) { client, account, _ := GetAutoConfig(t) - source := NewRealtimeLogConfigsSource(client, account) + adapter := NewRealtimeLogConfigsAdapter(client, account) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/cloudfront/response_headers_policy.go b/adapters/cloudfront/response_headers_policy.go similarity index 57% rename from sources/cloudfront/response_headers_policy.go rename to adapters/cloudfront/response_headers_policy.go index 623fd95b..b7c94261 100644 --- a/sources/cloudfront/response_headers_policy.go +++ b/adapters/cloudfront/response_headers_policy.go @@ -5,12 +5,12 @@ import ( "github.com/aws/aws-sdk-go-v2/service/cloudfront" "github.com/aws/aws-sdk-go-v2/service/cloudfront/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) func ResponseHeadersPolicyItemMapper(_, scope string, awsItem *types.ResponseHeadersPolicy) (*sdp.Item, error) { - attributes, err := sources.ToAttributesWithExclude(awsItem) + attributes, err := adapters.ToAttributesWithExclude(awsItem) if err != nil { return nil, err @@ -35,12 +35,13 @@ func ResponseHeadersPolicyItemMapper(_, scope string, awsItem *types.ResponseHea // +overmind:group AWS // +overmind:terraform:queryMap aws_cloudfront_response_headers_policy.id -func NewResponseHeadersPolicySource(client *cloudfront.Client, accountID string) *sources.GetListSource[*types.ResponseHeadersPolicy, *cloudfront.Client, *cloudfront.Options] { - return &sources.GetListSource[*types.ResponseHeadersPolicy, *cloudfront.Client, *cloudfront.Options]{ - ItemType: "cloudfront-response-headers-policy", - Client: client, - AccountID: accountID, - Region: "", // Cloudfront resources aren't tied to a region +func NewResponseHeadersPolicyAdapter(client *cloudfront.Client, accountID string) *adapters.GetListAdapter[*types.ResponseHeadersPolicy, *cloudfront.Client, *cloudfront.Options] { + return &adapters.GetListAdapter[*types.ResponseHeadersPolicy, *cloudfront.Client, *cloudfront.Options]{ + ItemType: "cloudfront-response-headers-policy", + Client: client, + AccountID: accountID, + Region: "", // Cloudfront resources aren't tied to a region + AdapterMetadata: ResponseHeadersPolicyMetadata(), GetFunc: func(ctx context.Context, client *cloudfront.Client, scope, query string) (*types.ResponseHeadersPolicy, error) { out, err := client.GetResponseHeadersPolicy(ctx, &cloudfront.GetResponseHeadersPolicyInput{ Id: &query, @@ -70,3 +71,22 @@ func NewResponseHeadersPolicySource(client *cloudfront.Client, accountID string) ItemMapper: ResponseHeadersPolicyItemMapper, } } + +func ResponseHeadersPolicyMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "cloudfront-response-headers-policy", + DescriptiveName: "CloudFront Response Headers Policy", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get Response Headers Policy by ID", + ListDescription: "List Response Headers Policies", + SearchDescription: "Search Response Headers Policy by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_cloudfront_response_headers_policy.id"}, + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + } +} diff --git a/sources/cloudfront/response_headers_policy_test.go b/adapters/cloudfront/response_headers_policy_test.go similarity index 53% rename from sources/cloudfront/response_headers_policy_test.go rename to adapters/cloudfront/response_headers_policy_test.go index 9bb95f1f..e0121a7f 100644 --- a/sources/cloudfront/response_headers_policy_test.go +++ b/adapters/cloudfront/response_headers_policy_test.go @@ -5,73 +5,73 @@ import ( "time" "github.com/aws/aws-sdk-go-v2/service/cloudfront/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" ) func TestResponseHeadersPolicyItemMapper(t *testing.T) { x := types.ResponseHeadersPolicy{ - Id: sources.PtrString("test"), - LastModifiedTime: sources.PtrTime(time.Now()), + Id: adapters.PtrString("test"), + LastModifiedTime: adapters.PtrTime(time.Now()), ResponseHeadersPolicyConfig: &types.ResponseHeadersPolicyConfig{ - Name: sources.PtrString("example-policy"), - Comment: sources.PtrString("example comment"), + Name: adapters.PtrString("example-policy"), + Comment: adapters.PtrString("example comment"), CorsConfig: &types.ResponseHeadersPolicyCorsConfig{ - AccessControlAllowCredentials: sources.PtrBool(true), + AccessControlAllowCredentials: adapters.PtrBool(true), AccessControlAllowHeaders: &types.ResponseHeadersPolicyAccessControlAllowHeaders{ Items: []string{"X-Customer-Header"}, - Quantity: sources.PtrInt32(1), + Quantity: adapters.PtrInt32(1), }, }, CustomHeadersConfig: &types.ResponseHeadersPolicyCustomHeadersConfig{ - Quantity: sources.PtrInt32(1), + Quantity: adapters.PtrInt32(1), Items: []types.ResponseHeadersPolicyCustomHeader{ { - Header: sources.PtrString("X-Customer-Header"), - Override: sources.PtrBool(true), - Value: sources.PtrString("test"), + Header: adapters.PtrString("X-Customer-Header"), + Override: adapters.PtrBool(true), + Value: adapters.PtrString("test"), }, }, }, RemoveHeadersConfig: &types.ResponseHeadersPolicyRemoveHeadersConfig{ - Quantity: sources.PtrInt32(1), + Quantity: adapters.PtrInt32(1), Items: []types.ResponseHeadersPolicyRemoveHeader{ { - Header: sources.PtrString("X-Private-Header"), + Header: adapters.PtrString("X-Private-Header"), }, }, }, SecurityHeadersConfig: &types.ResponseHeadersPolicySecurityHeadersConfig{ ContentSecurityPolicy: &types.ResponseHeadersPolicyContentSecurityPolicy{ - ContentSecurityPolicy: sources.PtrString("default-src 'none';"), - Override: sources.PtrBool(true), + ContentSecurityPolicy: adapters.PtrString("default-src 'none';"), + Override: adapters.PtrBool(true), }, ContentTypeOptions: &types.ResponseHeadersPolicyContentTypeOptions{ - Override: sources.PtrBool(true), + Override: adapters.PtrBool(true), }, FrameOptions: &types.ResponseHeadersPolicyFrameOptions{ FrameOption: types.FrameOptionsListDeny, - Override: sources.PtrBool(true), + Override: adapters.PtrBool(true), }, ReferrerPolicy: &types.ResponseHeadersPolicyReferrerPolicy{ - Override: sources.PtrBool(true), + Override: adapters.PtrBool(true), ReferrerPolicy: types.ReferrerPolicyListNoReferrer, }, StrictTransportSecurity: &types.ResponseHeadersPolicyStrictTransportSecurity{ - AccessControlMaxAgeSec: sources.PtrInt32(86400), - Override: sources.PtrBool(true), - IncludeSubdomains: sources.PtrBool(true), - Preload: sources.PtrBool(true), + AccessControlMaxAgeSec: adapters.PtrInt32(86400), + Override: adapters.PtrBool(true), + IncludeSubdomains: adapters.PtrBool(true), + Preload: adapters.PtrBool(true), }, XSSProtection: &types.ResponseHeadersPolicyXSSProtection{ - Override: sources.PtrBool(true), - Protection: sources.PtrBool(true), - ModeBlock: sources.PtrBool(true), - ReportUri: sources.PtrString("https://example.com/report"), + Override: adapters.PtrBool(true), + Protection: adapters.PtrBool(true), + ModeBlock: adapters.PtrBool(true), + ReportUri: adapters.PtrString("https://example.com/report"), }, }, ServerTimingHeadersConfig: &types.ResponseHeadersPolicyServerTimingHeadersConfig{ - Enabled: sources.PtrBool(true), - SamplingRate: sources.PtrFloat64(0.1), + Enabled: adapters.PtrBool(true), + SamplingRate: adapters.PtrFloat64(0.1), }, }, } @@ -87,13 +87,13 @@ func TestResponseHeadersPolicyItemMapper(t *testing.T) { } } -func TestNewResponseHeadersPolicySource(t *testing.T) { +func TestNewResponseHeadersPolicyAdapter(t *testing.T) { client, account, _ := GetAutoConfig(t) - source := NewResponseHeadersPolicySource(client, account) + adapter := NewResponseHeadersPolicyAdapter(client, account) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/cloudfront/shared.go b/adapters/cloudfront/shared.go similarity index 100% rename from sources/cloudfront/shared.go rename to adapters/cloudfront/shared.go diff --git a/sources/cloudfront/shared_test.go b/adapters/cloudfront/shared_test.go similarity index 79% rename from sources/cloudfront/shared_test.go rename to adapters/cloudfront/shared_test.go index 422cde74..9e762f85 100644 --- a/sources/cloudfront/shared_test.go +++ b/adapters/cloudfront/shared_test.go @@ -6,7 +6,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/cloudfront" "github.com/aws/aws-sdk-go-v2/service/cloudfront/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" ) func (c TestCloudFrontClient) ListTagsForResource(ctx context.Context, params *cloudfront.ListTagsForResourceInput, optFns ...func(*cloudfront.Options)) (*cloudfront.ListTagsForResourceOutput, error) { @@ -14,8 +14,8 @@ func (c TestCloudFrontClient) ListTagsForResource(ctx context.Context, params *c Tags: &types.Tags{ Items: []types.Tag{ { - Key: sources.PtrString("foo"), - Value: sources.PtrString("bar"), + Key: adapters.PtrString("foo"), + Value: adapters.PtrString("bar"), }, }, }, @@ -25,7 +25,7 @@ func (c TestCloudFrontClient) ListTagsForResource(ctx context.Context, params *c type TestCloudFrontClient struct{} func GetAutoConfig(t *testing.T) (*cloudfront.Client, string, string) { - config, account, region := sources.GetAutoConfig(t) + config, account, region := adapters.GetAutoConfig(t) client := cloudfront.NewFromConfig(config) return client, account, region diff --git a/sources/cloudfront/streaming_distribution.go b/adapters/cloudfront/streaming_distribution.go similarity index 72% rename from sources/cloudfront/streaming_distribution.go rename to adapters/cloudfront/streaming_distribution.go index a8fd015c..5853852d 100644 --- a/sources/cloudfront/streaming_distribution.go +++ b/adapters/cloudfront/streaming_distribution.go @@ -5,7 +5,7 @@ import ( "fmt" "github.com/aws/aws-sdk-go-v2/service/cloudfront" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -35,14 +35,14 @@ func streamingDistributionGetFunc(ctx context.Context, client CloudFrontClient, if err == nil { tags = tagsToMap(tagsOut.Tags) } else { - tags = sources.HandleTagsError(ctx, err) + tags = adapters.HandleTagsError(ctx, err) } if err != nil { return nil, fmt.Errorf("failed to get tags for streaming distribution %v: %w", *d.Id, err) } - attributes, err := sources.ToAttributesWithExclude(d) + attributes, err := adapters.ToAttributesWithExclude(d) if err != nil { return nil, err @@ -170,14 +170,15 @@ func streamingDistributionGetFunc(ctx context.Context, client CloudFrontClient, // +overmind:terraform:queryMap aws_cloudfront_Streamingdistribution.arn // +overmind:terraform:method SEARCH -func NewStreamingDistributionSource(client CloudFrontClient, accountID string) *sources.AlwaysGetSource[*cloudfront.ListStreamingDistributionsInput, *cloudfront.ListStreamingDistributionsOutput, *cloudfront.GetStreamingDistributionInput, *cloudfront.GetStreamingDistributionOutput, CloudFrontClient, *cloudfront.Options] { - return &sources.AlwaysGetSource[*cloudfront.ListStreamingDistributionsInput, *cloudfront.ListStreamingDistributionsOutput, *cloudfront.GetStreamingDistributionInput, *cloudfront.GetStreamingDistributionOutput, CloudFrontClient, *cloudfront.Options]{ - ItemType: "cloudfront-streaming-distribution", - Client: client, - AccountID: accountID, - Region: "", // Cloudfront resources aren't tied to a region - ListInput: &cloudfront.ListStreamingDistributionsInput{}, - ListFuncPaginatorBuilder: func(client CloudFrontClient, input *cloudfront.ListStreamingDistributionsInput) sources.Paginator[*cloudfront.ListStreamingDistributionsOutput, *cloudfront.Options] { +func NewStreamingDistributionAdapter(client CloudFrontClient, accountID string) *adapters.AlwaysGetAdapter[*cloudfront.ListStreamingDistributionsInput, *cloudfront.ListStreamingDistributionsOutput, *cloudfront.GetStreamingDistributionInput, *cloudfront.GetStreamingDistributionOutput, CloudFrontClient, *cloudfront.Options] { + return &adapters.AlwaysGetAdapter[*cloudfront.ListStreamingDistributionsInput, *cloudfront.ListStreamingDistributionsOutput, *cloudfront.GetStreamingDistributionInput, *cloudfront.GetStreamingDistributionOutput, CloudFrontClient, *cloudfront.Options]{ + ItemType: "cloudfront-streaming-distribution", + Client: client, + AccountID: accountID, + Region: "", // Cloudfront resources aren't tied to a region + AdapterMetadata: StreamingDistributionMetadata(), + ListInput: &cloudfront.ListStreamingDistributionsInput{}, + ListFuncPaginatorBuilder: func(client CloudFrontClient, input *cloudfront.ListStreamingDistributionsInput) adapters.Paginator[*cloudfront.ListStreamingDistributionsOutput, *cloudfront.Options] { return cloudfront.NewListStreamingDistributionsPaginator(client, input) }, GetInputMapper: func(scope, query string) *cloudfront.GetStreamingDistributionInput { @@ -199,3 +200,24 @@ func NewStreamingDistributionSource(client CloudFrontClient, accountID string) * GetFunc: streamingDistributionGetFunc, } } + +func StreamingDistributionMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + DescriptiveName: "CloudFront Streaming Distribution", + Type: "cloudfront-streaming-distribution", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Search: true, + Get: true, + List: true, + GetDescription: "Get a Streaming Distribution by ID", + }, + TerraformMappings: []*sdp.TerraformMapping{ + { + TerraformMethod: sdp.QueryMethod_SEARCH, + TerraformQueryMap: "aws_cloudfront_Streamingdistribution.arn", + }, + }, + PotentialLinks: []string{"dns"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + } +} diff --git a/sources/cloudfront/streaming_distribution_test.go b/adapters/cloudfront/streaming_distribution_test.go similarity index 58% rename from sources/cloudfront/streaming_distribution_test.go rename to adapters/cloudfront/streaming_distribution_test.go index b4f892bb..d64a1444 100644 --- a/sources/cloudfront/streaming_distribution_test.go +++ b/adapters/cloudfront/streaming_distribution_test.go @@ -7,27 +7,27 @@ import ( "github.com/aws/aws-sdk-go-v2/service/cloudfront" "github.com/aws/aws-sdk-go-v2/service/cloudfront/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) func (t TestCloudFrontClient) GetStreamingDistribution(ctx context.Context, params *cloudfront.GetStreamingDistributionInput, optFns ...func(*cloudfront.Options)) (*cloudfront.GetStreamingDistributionOutput, error) { return &cloudfront.GetStreamingDistributionOutput{ - ETag: sources.PtrString("E2QWRUHAPOMQZL"), + ETag: adapters.PtrString("E2QWRUHAPOMQZL"), StreamingDistribution: &types.StreamingDistribution{ - ARN: sources.PtrString("arn:aws:cloudfront::123456789012:streaming-distribution/EDFDVBD632BHDS5"), - DomainName: sources.PtrString("d111111abcdef8.cloudfront.net"), // link - Id: sources.PtrString("EDFDVBD632BHDS5"), - Status: sources.PtrString("Deployed"), // health - LastModifiedTime: sources.PtrTime(time.Now()), + ARN: adapters.PtrString("arn:aws:cloudfront::123456789012:streaming-distribution/EDFDVBD632BHDS5"), + DomainName: adapters.PtrString("d111111abcdef8.cloudfront.net"), // link + Id: adapters.PtrString("EDFDVBD632BHDS5"), + Status: adapters.PtrString("Deployed"), // health + LastModifiedTime: adapters.PtrTime(time.Now()), ActiveTrustedSigners: &types.ActiveTrustedSigners{ - Enabled: sources.PtrBool(true), - Quantity: sources.PtrInt32(1), + Enabled: adapters.PtrBool(true), + Quantity: adapters.PtrInt32(1), Items: []types.Signer{ { - AwsAccountNumber: sources.PtrString("123456789012"), + AwsAccountNumber: adapters.PtrString("123456789012"), KeyPairIds: &types.KeyPairIds{ - Quantity: sources.PtrInt32(1), + Quantity: adapters.PtrInt32(1), Items: []string{ "APKAJDGKZRVEXAMPLE", }, @@ -36,30 +36,30 @@ func (t TestCloudFrontClient) GetStreamingDistribution(ctx context.Context, para }, }, StreamingDistributionConfig: &types.StreamingDistributionConfig{ - CallerReference: sources.PtrString("test"), - Comment: sources.PtrString("test"), - Enabled: sources.PtrBool(true), + CallerReference: adapters.PtrString("test"), + Comment: adapters.PtrString("test"), + Enabled: adapters.PtrBool(true), S3Origin: &types.S3Origin{ - DomainName: sources.PtrString("myawsbucket.s3.amazonaws.com"), // link - OriginAccessIdentity: sources.PtrString("origin-access-identity/cloudfront/E127EXAMPLE51Z"), // link + DomainName: adapters.PtrString("myawsbucket.s3.amazonaws.com"), // link + OriginAccessIdentity: adapters.PtrString("origin-access-identity/cloudfront/E127EXAMPLE51Z"), // link }, TrustedSigners: &types.TrustedSigners{ - Enabled: sources.PtrBool(true), - Quantity: sources.PtrInt32(1), + Enabled: adapters.PtrBool(true), + Quantity: adapters.PtrInt32(1), Items: []string{ "self", }, }, Aliases: &types.Aliases{ - Quantity: sources.PtrInt32(1), + Quantity: adapters.PtrInt32(1), Items: []string{ "example.com", // link }, }, Logging: &types.StreamingLoggingConfig{ - Bucket: sources.PtrString("myawslogbucket.s3.amazonaws.com"), // link - Enabled: sources.PtrBool(true), - Prefix: sources.PtrString("myprefix"), + Bucket: adapters.PtrString("myawslogbucket.s3.amazonaws.com"), // link + Enabled: adapters.PtrBool(true), + Prefix: adapters.PtrString("myprefix"), }, PriceClass: types.PriceClassPriceClassAll, }, @@ -70,10 +70,10 @@ func (t TestCloudFrontClient) GetStreamingDistribution(ctx context.Context, para func (t TestCloudFrontClient) ListStreamingDistributions(ctx context.Context, params *cloudfront.ListStreamingDistributionsInput, optFns ...func(*cloudfront.Options)) (*cloudfront.ListStreamingDistributionsOutput, error) { return &cloudfront.ListStreamingDistributionsOutput{ StreamingDistributionList: &types.StreamingDistributionList{ - IsTruncated: sources.PtrBool(false), + IsTruncated: adapters.PtrBool(false), Items: []types.StreamingDistributionSummary{ { - Id: sources.PtrString("test-id"), + Id: adapters.PtrString("test-id"), }, }, }, @@ -95,7 +95,7 @@ func TestStreamingDistributionGetFunc(t *testing.T) { t.Errorf("expected health to be HEALTH_OK, got %s", item.GetHealth()) } - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "dns", ExpectedMethod: sdp.QueryMethod_SEARCH, @@ -107,14 +107,14 @@ func TestStreamingDistributionGetFunc(t *testing.T) { tests.Execute(t, item) } -func TestNewStreamingDistributionSource(t *testing.T) { - config, account, _ := sources.GetAutoConfig(t) +func TestNewStreamingDistributionAdapter(t *testing.T) { + config, account, _ := adapters.GetAutoConfig(t) client := cloudfront.NewFromConfig(config) - source := NewStreamingDistributionSource(client, account) + adapter := NewStreamingDistributionAdapter(client, account) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/cloudwatch/alarm.go b/adapters/cloudwatch/alarm.go similarity index 84% rename from sources/cloudwatch/alarm.go rename to adapters/cloudwatch/alarm.go index b85fa855..b5e33136 100644 --- a/sources/cloudwatch/alarm.go +++ b/adapters/cloudwatch/alarm.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/cloudwatch" "github.com/aws/aws-sdk-go-v2/service/cloudwatch/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -73,11 +73,11 @@ func alarmOutputMapper(ctx context.Context, client CloudwatchClient, scope strin var arn *string if alarm.Metric != nil { - attrs, err = sources.ToAttributesWithExclude(alarm.Metric) + attrs, err = adapters.ToAttributesWithExclude(alarm.Metric) arn = alarm.Metric.AlarmArn } if alarm.Composite != nil { - attrs, err = sources.ToAttributesWithExclude(alarm.Composite) + attrs, err = adapters.ToAttributesWithExclude(alarm.Composite) arn = alarm.Composite.AlarmArn } @@ -95,7 +95,7 @@ func alarmOutputMapper(ctx context.Context, client CloudwatchClient, scope strin if err == nil { tags = tagsToMap(tagsOut.Tags) } else { - tags = sources.HandleTagsError(ctx, err) + tags = adapters.HandleTagsError(ctx, err) } if err != nil { @@ -149,14 +149,14 @@ func alarmOutputMapper(ctx context.Context, client CloudwatchClient, scope strin // Link to the suppressor alarm if alarm.Composite != nil && alarm.Composite.ActionsSuppressor != nil { - if arn, err := sources.ParseARN(*alarm.Composite.ActionsSuppressor); err == nil { + if arn, err := adapters.ParseARN(*alarm.Composite.ActionsSuppressor); err == nil { // +overmind:link cloudwatch-alarm item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "cloudwatch-alarm", Method: sdp.QueryMethod_GET, Query: arn.ResourceID(), - Scope: sources.FormatScope(arn.AccountID, arn.Region), + Scope: adapters.FormatScope(arn.AccountID, arn.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changes to the suppressor alarm will affect this alarm @@ -215,13 +215,14 @@ func alarmOutputMapper(ctx context.Context, client CloudwatchClient, scope strin // +overmind:group AWS // +overmind:terraform:queryMap aws_cloudwatch_metric_alarm.alarm_name -func NewAlarmSource(client *cloudwatch.Client, accountID string, region string) *sources.DescribeOnlySource[*cloudwatch.DescribeAlarmsInput, *cloudwatch.DescribeAlarmsOutput, CloudwatchClient, *cloudwatch.Options] { - return &sources.DescribeOnlySource[*cloudwatch.DescribeAlarmsInput, *cloudwatch.DescribeAlarmsOutput, CloudwatchClient, *cloudwatch.Options]{ - ItemType: "cloudwatch-alarm", - Client: client, - Region: region, - AccountID: accountID, - PaginatorBuilder: func(client CloudwatchClient, params *cloudwatch.DescribeAlarmsInput) sources.Paginator[*cloudwatch.DescribeAlarmsOutput, *cloudwatch.Options] { +func NewAlarmAdapter(client *cloudwatch.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*cloudwatch.DescribeAlarmsInput, *cloudwatch.DescribeAlarmsOutput, CloudwatchClient, *cloudwatch.Options] { + return &adapters.DescribeOnlyAdapter[*cloudwatch.DescribeAlarmsInput, *cloudwatch.DescribeAlarmsOutput, CloudwatchClient, *cloudwatch.Options]{ + ItemType: "cloudwatch-alarm", + Client: client, + Region: region, + AccountID: accountID, + AdapterMetadata: AlarmMetadata(), + PaginatorBuilder: func(client CloudwatchClient, params *cloudwatch.DescribeAlarmsInput) adapters.Paginator[*cloudwatch.DescribeAlarmsOutput, *cloudwatch.Options] { return cloudwatch.NewDescribeAlarmsPaginator(client, params) }, DescribeFunc: func(ctx context.Context, client CloudwatchClient, input *cloudwatch.DescribeAlarmsInput) (*cloudwatch.DescribeAlarmsOutput, error) { @@ -266,6 +267,28 @@ func NewAlarmSource(client *cloudwatch.Client, accountID string, region string) } } +func AlarmMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + DescriptiveName: "CloudWatch Alarm", + Type: "cloudwatch-alarm", + PotentialLinks: []string{"cloudwatch-metric"}, + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get an alarm by name", + ListDescription: "List all alarms", + SearchDescription: "Search for alarms. This accepts JSON in the format of `cloudwatch.DescribeAlarmsForMetricInput`", + }, + TerraformMappings: []*sdp.TerraformMapping{ + { + TerraformQueryMap: "aws_cloudwatch_metric_alarm.alarm_name", + }, + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_OBSERVABILITY, + } +} + // actionToLink converts an action string to a link to the resource that the // action refers to. The actions to execute when this alarm transitions to the // ALARM state from any other state. Each action is specified as an Amazon @@ -304,7 +327,7 @@ func NewAlarmSource(client *cloudwatch.Client, accountID string, region string) // // * arn:aws:ssm-incidents::account-id:responseplan/response-plan-name func actionToLink(action string) (*sdp.LinkedItemQuery, error) { - arn, err := sources.ParseARN(action) + arn, err := adapters.ParseARN(action) if err != nil { return nil, err @@ -318,7 +341,7 @@ func actionToLink(action string) (*sdp.LinkedItemQuery, error) { Type: "autoscaling-policy", Method: sdp.QueryMethod_SEARCH, Query: action, - Scope: sources.FormatScope(arn.AccountID, arn.Region), + Scope: adapters.FormatScope(arn.AccountID, arn.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changes to the policy won't affect the alarm @@ -334,7 +357,7 @@ func actionToLink(action string) (*sdp.LinkedItemQuery, error) { Type: "sns-topic", Method: sdp.QueryMethod_SEARCH, Query: action, - Scope: sources.FormatScope(arn.AccountID, arn.Region), + Scope: adapters.FormatScope(arn.AccountID, arn.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changes to the topic won't affect the alarm @@ -350,7 +373,7 @@ func actionToLink(action string) (*sdp.LinkedItemQuery, error) { Type: "ssm-ops-item", Method: sdp.QueryMethod_SEARCH, Query: action, - Scope: sources.FormatScope(arn.AccountID, arn.Region), + Scope: adapters.FormatScope(arn.AccountID, arn.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changes to an ops item won't affect the alarm @@ -366,7 +389,7 @@ func actionToLink(action string) (*sdp.LinkedItemQuery, error) { Type: "ssm-incidents-response-plan", Method: sdp.QueryMethod_SEARCH, Query: action, - Scope: sources.FormatScope(arn.AccountID, arn.Region), + Scope: adapters.FormatScope(arn.AccountID, arn.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changes to a response plan won't affect the alarm diff --git a/sources/cloudwatch/alarm_test.go b/adapters/cloudwatch/alarm_test.go similarity index 51% rename from sources/cloudwatch/alarm_test.go rename to adapters/cloudwatch/alarm_test.go index 8636c7fe..5edcc99d 100644 --- a/sources/cloudwatch/alarm_test.go +++ b/adapters/cloudwatch/alarm_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/cloudwatch" "github.com/aws/aws-sdk-go-v2/service/cloudwatch/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -17,8 +17,8 @@ func (c testCloudwatchClient) ListTagsForResource(ctx context.Context, params *c return &cloudwatch.ListTagsForResourceOutput{ Tags: []types.Tag{ { - Key: sources.PtrString("Name"), - Value: sources.PtrString("example"), + Key: adapters.PtrString("Name"), + Value: adapters.PtrString("example"), }, }, }, nil @@ -36,11 +36,11 @@ func TestAlarmOutputMapper(t *testing.T) { output := &cloudwatch.DescribeAlarmsOutput{ MetricAlarms: []types.MetricAlarm{ { - AlarmName: sources.PtrString("TargetTracking-table/dylan-tfstate-AlarmHigh-14069c4a-6dcc-48a2-bfe6-b5547c90c43d"), - AlarmArn: sources.PtrString("arn:aws:cloudwatch:eu-west-2:052392120703:alarm:TargetTracking-table/dylan-tfstate-AlarmHigh-14069c4a-6dcc-48a2-bfe6-b5547c90c43d"), - AlarmDescription: sources.PtrString("DO NOT EDIT OR DELETE. For TargetTrackingScaling policy arn:aws:autoscaling:eu-west-2:052392120703:scalingPolicy:32f3f053-dc75-46fa-9cd4-8e8c34c47b37:resource/dynamodb/table/dylan-tfstate:policyName/$dylan-tfstate-scaling-policy:createdBy/e5bd51d8-94a8-461e-a989-08f4d10b326b."), - AlarmConfigurationUpdatedTimestamp: sources.PtrTime(time.Now()), - ActionsEnabled: sources.PtrBool(true), + AlarmName: adapters.PtrString("TargetTracking-table/dylan-tfstate-AlarmHigh-14069c4a-6dcc-48a2-bfe6-b5547c90c43d"), + AlarmArn: adapters.PtrString("arn:aws:cloudwatch:eu-west-2:052392120703:alarm:TargetTracking-table/dylan-tfstate-AlarmHigh-14069c4a-6dcc-48a2-bfe6-b5547c90c43d"), + AlarmDescription: adapters.PtrString("DO NOT EDIT OR DELETE. For TargetTrackingScaling policy arn:aws:autoscaling:eu-west-2:052392120703:scalingPolicy:32f3f053-dc75-46fa-9cd4-8e8c34c47b37:resource/dynamodb/table/dylan-tfstate:policyName/$dylan-tfstate-scaling-policy:createdBy/e5bd51d8-94a8-461e-a989-08f4d10b326b."), + AlarmConfigurationUpdatedTimestamp: adapters.PtrTime(time.Now()), + ActionsEnabled: adapters.PtrBool(true), OKActions: []string{ "arn:aws:autoscaling:eu-west-2:052392120703:scalingPolicy:32f3f053-dc75-46fa-9cd4-8e8c34c47b37:resource/dynamodb/table/dylan-tfstate:policyName/$dylan-tfstate-scaling-policy:createdBy/e5bd51d8-94a8-461e-a989-08f4d10b326b", }, @@ -51,32 +51,32 @@ func TestAlarmOutputMapper(t *testing.T) { "arn:aws:autoscaling:eu-west-2:052392120703:scalingPolicy:32f3f053-dc75-46fa-9cd4-8e8c34c47b37:resource/dynamodb/table/dylan-tfstate:policyName/$dylan-tfstate-scaling-policy:createdBy/e5bd51d8-94a8-461e-a989-08f4d10b326b", }, StateValue: types.StateValueOk, - StateReason: sources.PtrString("Threshold Crossed: 2 datapoints [0.0 (09/01/23 14:02:00), 1.0 (09/01/23 14:01:00)] were not greater than the threshold (42.0)."), - StateReasonData: sources.PtrString("{\"version\":\"1.0\",\"queryDate\":\"2023-01-09T14:07:25.504+0000\",\"startDate\":\"2023-01-09T14:01:00.000+0000\",\"statistic\":\"Sum\",\"period\":60,\"recentDatapoints\":[1.0,0.0],\"threshold\":42.0,\"evaluatedDatapoints\":[{\"timestamp\":\"2023-01-09T14:02:00.000+0000\",\"sampleCount\":1.0,\"value\":0.0}]}"), - StateUpdatedTimestamp: sources.PtrTime(time.Now()), - MetricName: sources.PtrString("ConsumedWriteCapacityUnits"), - Namespace: sources.PtrString("AWS/DynamoDB"), + StateReason: adapters.PtrString("Threshold Crossed: 2 datapoints [0.0 (09/01/23 14:02:00), 1.0 (09/01/23 14:01:00)] were not greater than the threshold (42.0)."), + StateReasonData: adapters.PtrString("{\"version\":\"1.0\",\"queryDate\":\"2023-01-09T14:07:25.504+0000\",\"startDate\":\"2023-01-09T14:01:00.000+0000\",\"statistic\":\"Sum\",\"period\":60,\"recentDatapoints\":[1.0,0.0],\"threshold\":42.0,\"evaluatedDatapoints\":[{\"timestamp\":\"2023-01-09T14:02:00.000+0000\",\"sampleCount\":1.0,\"value\":0.0}]}"), + StateUpdatedTimestamp: adapters.PtrTime(time.Now()), + MetricName: adapters.PtrString("ConsumedWriteCapacityUnits"), + Namespace: adapters.PtrString("AWS/DynamoDB"), Statistic: types.StatisticSum, Dimensions: []types.Dimension{ { - Name: sources.PtrString("TableName"), - Value: sources.PtrString("dylan-tfstate"), + Name: adapters.PtrString("TableName"), + Value: adapters.PtrString("dylan-tfstate"), }, }, - Period: sources.PtrInt32(60), - EvaluationPeriods: sources.PtrInt32(2), - Threshold: sources.PtrFloat64(42.0), + Period: adapters.PtrInt32(60), + EvaluationPeriods: adapters.PtrInt32(2), + Threshold: adapters.PtrFloat64(42.0), ComparisonOperator: types.ComparisonOperatorGreaterThanThreshold, - StateTransitionedTimestamp: sources.PtrTime(time.Now()), + StateTransitionedTimestamp: adapters.PtrTime(time.Now()), }, }, CompositeAlarms: []types.CompositeAlarm{ { - AlarmName: sources.PtrString("TargetTracking2-table/dylan-tfstate-AlarmHigh-14069c4a-6dcc-48a2-bfe6-b5547c90c43d"), - AlarmArn: sources.PtrString("arn:aws:cloudwatch:eu-west-2:052392120703:alarm:TargetTracking2-table/dylan-tfstate-AlarmHigh-14069c4a-6dcc-48a2-bfe6-b5547c90c43d"), - AlarmDescription: sources.PtrString("DO NOT EDIT OR DELETE. For TargetTrackingScaling policy arn:aws:autoscaling:eu-west-2:052392120703:scalingPolicy:32f3f053-dc75-46fa-9cd4-8e8c34c47b37:resource/dynamodb/table/dylan-tfstate:policyName/$dylan-tfstate-scaling-policy:createdBy/e5bd51d8-94a8-461e-a989-08f4d10b326b."), - AlarmConfigurationUpdatedTimestamp: sources.PtrTime(time.Now()), - ActionsEnabled: sources.PtrBool(true), + AlarmName: adapters.PtrString("TargetTracking2-table/dylan-tfstate-AlarmHigh-14069c4a-6dcc-48a2-bfe6-b5547c90c43d"), + AlarmArn: adapters.PtrString("arn:aws:cloudwatch:eu-west-2:052392120703:alarm:TargetTracking2-table/dylan-tfstate-AlarmHigh-14069c4a-6dcc-48a2-bfe6-b5547c90c43d"), + AlarmDescription: adapters.PtrString("DO NOT EDIT OR DELETE. For TargetTrackingScaling policy arn:aws:autoscaling:eu-west-2:052392120703:scalingPolicy:32f3f053-dc75-46fa-9cd4-8e8c34c47b37:resource/dynamodb/table/dylan-tfstate:policyName/$dylan-tfstate-scaling-policy:createdBy/e5bd51d8-94a8-461e-a989-08f4d10b326b."), + AlarmConfigurationUpdatedTimestamp: adapters.PtrTime(time.Now()), + ActionsEnabled: adapters.PtrBool(true), OKActions: []string{ "arn:aws:autoscaling:eu-west-2:052392120703:scalingPolicy:32f3f053-dc75-46fa-9cd4-8e8c34c47b37:resource/dynamodb/table/dylan-tfstate:policyName/$dylan-tfstate-scaling-policy:createdBy/e5bd51d8-94a8-461e-a989-08f4d10b326b", }, @@ -87,17 +87,17 @@ func TestAlarmOutputMapper(t *testing.T) { "arn:aws:autoscaling:eu-west-2:052392120703:scalingPolicy:32f3f053-dc75-46fa-9cd4-8e8c34c47b37:resource/dynamodb/table/dylan-tfstate:policyName/$dylan-tfstate-scaling-policy:createdBy/e5bd51d8-94a8-461e-a989-08f4d10b326b", }, StateValue: types.StateValueOk, - StateReason: sources.PtrString("Threshold Crossed: 2 datapoints [0.0 (09/01/23 14:02:00), 1.0 (09/01/23 14:01:00)] were not greater than the threshold (42.0)."), - StateReasonData: sources.PtrString("{\"version\":\"1.0\",\"queryDate\":\"2023-01-09T14:07:25.504+0000\",\"startDate\":\"2023-01-09T14:01:00.000+0000\",\"statistic\":\"Sum\",\"period\":60,\"recentDatapoints\":[1.0,0.0],\"threshold\":42.0,\"evaluatedDatapoints\":[{\"timestamp\":\"2023-01-09T14:02:00.000+0000\",\"sampleCount\":1.0,\"value\":0.0}]}"), - StateUpdatedTimestamp: sources.PtrTime(time.Now()), - StateTransitionedTimestamp: sources.PtrTime(time.Now()), + StateReason: adapters.PtrString("Threshold Crossed: 2 datapoints [0.0 (09/01/23 14:02:00), 1.0 (09/01/23 14:01:00)] were not greater than the threshold (42.0)."), + StateReasonData: adapters.PtrString("{\"version\":\"1.0\",\"queryDate\":\"2023-01-09T14:07:25.504+0000\",\"startDate\":\"2023-01-09T14:01:00.000+0000\",\"statistic\":\"Sum\",\"period\":60,\"recentDatapoints\":[1.0,0.0],\"threshold\":42.0,\"evaluatedDatapoints\":[{\"timestamp\":\"2023-01-09T14:02:00.000+0000\",\"sampleCount\":1.0,\"value\":0.0}]}"), + StateUpdatedTimestamp: adapters.PtrTime(time.Now()), + StateTransitionedTimestamp: adapters.PtrTime(time.Now()), ActionsSuppressedBy: types.ActionsSuppressedByAlarm, - ActionsSuppressedReason: sources.PtrString("Alarm is in INSUFFICIENT_DATA state"), + ActionsSuppressedReason: adapters.PtrString("Alarm is in INSUFFICIENT_DATA state"), // link - ActionsSuppressor: sources.PtrString("arn:aws:cloudwatch:eu-west-2:052392120703:alarm:TargetTracking2-table/dylan-tfstate-AlarmHigh-14069c4a-6dcc-48a2-bfe6-b5547c90c43d"), - ActionsSuppressorExtensionPeriod: sources.PtrInt32(0), - ActionsSuppressorWaitPeriod: sources.PtrInt32(0), - AlarmRule: sources.PtrString("ALARM TargetTracking2-table/dylan-tfstate-AlarmHigh-14069c4a-6dcc-48a2-bfe6-b5547c90c43d"), + ActionsSuppressor: adapters.PtrString("arn:aws:cloudwatch:eu-west-2:052392120703:alarm:TargetTracking2-table/dylan-tfstate-AlarmHigh-14069c4a-6dcc-48a2-bfe6-b5547c90c43d"), + ActionsSuppressorExtensionPeriod: adapters.PtrInt32(0), + ActionsSuppressorWaitPeriod: adapters.PtrInt32(0), + AlarmRule: adapters.PtrString("ALARM TargetTracking2-table/dylan-tfstate-AlarmHigh-14069c4a-6dcc-48a2-bfe6-b5547c90c43d"), }, }, } @@ -123,7 +123,7 @@ func TestAlarmOutputMapper(t *testing.T) { t.Errorf("Expected tag Name to be example, got %s", item.GetTags()["Name"]) } - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "cloudwatch-alarm", ExpectedMethod: sdp.QueryMethod_GET, @@ -140,7 +140,7 @@ func TestAlarmOutputMapper(t *testing.T) { t.Error(err) } - tests = sources.QueryTests{ + tests = adapters.QueryTests{ { ExpectedType: "dynamodb-table", ExpectedMethod: sdp.QueryMethod_GET, @@ -152,14 +152,14 @@ func TestAlarmOutputMapper(t *testing.T) { tests.Execute(t, item) } -func TestNewAlarmSource(t *testing.T) { - config, account, region := sources.GetAutoConfig(t) +func TestNewAlarmAdapter(t *testing.T) { + config, account, region := adapters.GetAutoConfig(t) client := cloudwatch.NewFromConfig(config) - source := NewAlarmSource(client, account, region) + adapter := NewAlarmAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/cloudwatch/metric_links.go b/adapters/cloudwatch/metric_links.go similarity index 97% rename from sources/cloudwatch/metric_links.go rename to adapters/cloudwatch/metric_links.go index a0faf0df..6f09b97e 100644 --- a/sources/cloudwatch/metric_links.go +++ b/adapters/cloudwatch/metric_links.go @@ -5,7 +5,7 @@ import ( "strings" "github.com/aws/aws-sdk-go-v2/service/cloudwatch/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -32,7 +32,7 @@ func SuggestedQuery(namespace string, scope string, dimensions []types.Dimension Out: true, } - accountID, _, err := sources.ParseScope(scope) + accountID, _, err := adapters.ParseScope(scope) if err != nil { return nil, err @@ -206,7 +206,7 @@ func SuggestedQuery(namespace string, scope string, dimensions []types.Dimension Type: "s3-bucket", Method: sdp.QueryMethod_GET, Query: *d.Value, - Scope: sources.FormatScope(accountID, ""), + Scope: adapters.FormatScope(accountID, ""), } } case "AWS/NATGateway": diff --git a/sources/cloudwatch/metric_links_test.go b/adapters/cloudwatch/metric_links_test.go similarity index 100% rename from sources/cloudwatch/metric_links_test.go rename to adapters/cloudwatch/metric_links_test.go diff --git a/sources/describe_source.go b/adapters/describe_source.go similarity index 72% rename from sources/describe_source.go rename to adapters/describe_source.go index 75d76856..5a4e6e8a 100644 --- a/sources/describe_source.go +++ b/adapters/describe_source.go @@ -1,4 +1,4 @@ -package sources +package adapters import ( "context" @@ -14,20 +14,21 @@ import ( const DefaultCacheDuration = 1 * time.Hour -// DescribeOnlySource Generates a source for AWS APIs that only use a `Describe` +// DescribeOnlyAdapter Generates a adapter for AWS APIs that only use a `Describe` // function for both List and Get operations. EC2 is a good example of this, // where running Describe with no params returns everything, but params can be // supplied to reduce the number of results. -type DescribeOnlySource[Input InputType, Output OutputType, ClientStruct ClientStructType, Options OptionsType] struct { +type DescribeOnlyAdapter[Input InputType, Output OutputType, ClientStruct ClientStructType, Options OptionsType] struct { MaxResultsPerPage int32 // Max results per page when making API queries ItemType string // The type of items that will be returned + AdapterMetadata sdp.AdapterMetadata CacheDuration time.Duration // How long to cache items for - cache *sdpcache.Cache // The sdpcache of this source + cache *sdpcache.Cache // The sdpcache of this adapter cacheInitMu sync.Mutex // Mutex to ensure cache is only initialised once // The function that should be used to describe the resources that this - // source is related to + // adapter is related to DescribeFunc func(ctx context.Context, client ClientStruct, input Input) (Output, error) // A function that returns the input object that will be passed to @@ -53,9 +54,9 @@ type DescribeOnlySource[Input InputType, Output OutputType, ClientStruct ClientS // create new items for each result OutputMapper func(ctx context.Context, client ClientStruct, scope string, input Input, output Output) ([]*sdp.Item, error) - // The region that this source is configured in, each source can only be + // The region that this adapter is configured in, each adapter can only be // configured for one region. Getting data from many regions requires a - // source per region. This is used in the scope of returned resources + // adapter per region. This is used in the scope of returned resources Region string // AccountID The id of the account that is being used. This is used by @@ -65,21 +66,21 @@ type DescribeOnlySource[Input InputType, Output OutputType, ClientStruct ClientS // Client The AWS client to use when making requests Client ClientStruct - // UseListForGet If true, the source will use the List function to get items + // UseListForGet If true, the adapter will use the List function to get items // This option should be used when the Describe function does not support - // getting a single item by ID. The source will then filter the items + // getting a single item by ID. The adapter will then filter the items // itself. // InputMapperGet should still be defined. It will be used to create the // input for the List function. The output of the List function will be - // filtered by the source to find the item with the matching ID. - // See the directconnect-virtual-gateway source for an example of this. + // filtered by the adapter to find the item with the matching ID. + // See the directconnect-virtual-gateway adapter for an example of this. UseListForGet bool } // Returns the duration that items should be cached for. This will use the -// `CacheDuration` for this source if set, otherwise it will use the default +// `CacheDuration` for this adapter if set, otherwise it will use the default // duration of 1 hour -func (s *DescribeOnlySource[Input, Output, ClientStruct, Options]) cacheDuration() time.Duration { +func (s *DescribeOnlyAdapter[Input, Output, ClientStruct, Options]) cacheDuration() time.Duration { if s.CacheDuration == 0 { return DefaultCacheDuration } @@ -87,7 +88,7 @@ func (s *DescribeOnlySource[Input, Output, ClientStruct, Options]) cacheDuration return s.CacheDuration } -func (s *DescribeOnlySource[Input, Output, ClientStruct, Options]) ensureCache() { +func (s *DescribeOnlyAdapter[Input, Output, ClientStruct, Options]) ensureCache() { s.cacheInitMu.Lock() defer s.cacheInitMu.Unlock() @@ -96,16 +97,16 @@ func (s *DescribeOnlySource[Input, Output, ClientStruct, Options]) ensureCache() } } -func (s *DescribeOnlySource[Input, Output, ClientStruct, Options]) Cache() *sdpcache.Cache { +func (s *DescribeOnlyAdapter[Input, Output, ClientStruct, Options]) Cache() *sdpcache.Cache { s.ensureCache() return s.cache } -// Validate Checks that the source is correctly set up and returns an error if +// Validate Checks that the adapter is correctly set up and returns an error if // not -func (s *DescribeOnlySource[Input, Output, ClientStruct, Options]) Validate() error { +func (s *DescribeOnlyAdapter[Input, Output, ClientStruct, Options]) Validate() error { if s.DescribeFunc == nil { - return errors.New("source describe func is nil") + return errors.New("adapter describe func is nil") } if s.MaxResultsPerPage == 0 { @@ -113,32 +114,36 @@ func (s *DescribeOnlySource[Input, Output, ClientStruct, Options]) Validate() er } if s.InputMapperGet == nil { - return errors.New("source get input mapper is nil") + return errors.New("adapter get input mapper is nil") } if s.OutputMapper == nil { - return errors.New("source output mapper is nil") + return errors.New("adapter output mapper is nil") } return nil } -// Paginated returns whether or not this source is using a paginated API -func (s *DescribeOnlySource[Input, Output, ClientStruct, Options]) Paginated() bool { +// Paginated returns whether or not this adapter is using a paginated API +func (s *DescribeOnlyAdapter[Input, Output, ClientStruct, Options]) Paginated() bool { return s.PaginatorBuilder != nil } -func (s *DescribeOnlySource[Input, Output, ClientStruct, Options]) Type() string { +func (s *DescribeOnlyAdapter[Input, Output, ClientStruct, Options]) Type() string { return s.ItemType } -func (s *DescribeOnlySource[Input, Output, ClientStruct, Options]) Name() string { - return fmt.Sprintf("%v-source", s.ItemType) +func (s *DescribeOnlyAdapter[Input, Output, ClientStruct, Options]) Name() string { + return fmt.Sprintf("%v-adapter", s.ItemType) } -// List of scopes that this source is capable of find items for. This will be +func (s *DescribeOnlyAdapter[Input, Output, ClientStruct, Options]) Metadata() *sdp.AdapterMetadata { + return &s.AdapterMetadata +} + +// List of scopes that this adapter is capable of find items for. This will be // in the format {accountID}.{region} -func (s *DescribeOnlySource[Input, Output, ClientStruct, Options]) Scopes() []string { +func (s *DescribeOnlyAdapter[Input, Output, ClientStruct, Options]) Scopes() []string { return []string{ FormatScope(s.AccountID, s.Region), } @@ -147,13 +152,13 @@ func (s *DescribeOnlySource[Input, Output, ClientStruct, Options]) Scopes() []st // Get Get a single item with a given scope and query. The item returned // should have a UniqueAttributeValue that matches the `query` parameter. The // ctx parameter contains a golang context object which should be used to allow -// this source to timeout or be cancelled when executing potentially +// this adapter to timeout or be cancelled when executing potentially // long-running actions -func (s *DescribeOnlySource[Input, Output, ClientStruct, Options]) Get(ctx context.Context, scope string, query string, ignoreCache bool) (*sdp.Item, error) { +func (s *DescribeOnlyAdapter[Input, Output, ClientStruct, Options]) Get(ctx context.Context, scope string, query string, ignoreCache bool) (*sdp.Item, error) { if scope != s.Scopes()[0] { return nil, &sdp.QueryError{ ErrorType: sdp.QueryError_NOSCOPE, - ErrorString: fmt.Sprintf("requested scope %v does not match source scope %v", scope, s.Scopes()[0]), + ErrorString: fmt.Sprintf("requested scope %v does not match adapter scope %v", scope, s.Scopes()[0]), } } @@ -244,11 +249,11 @@ func (s *DescribeOnlySource[Input, Output, ClientStruct, Options]) Get(ctx conte } // List Lists all items in a given scope -func (s *DescribeOnlySource[Input, Output, ClientStruct, Options]) List(ctx context.Context, scope string, ignoreCache bool) ([]*sdp.Item, error) { +func (s *DescribeOnlyAdapter[Input, Output, ClientStruct, Options]) List(ctx context.Context, scope string, ignoreCache bool) ([]*sdp.Item, error) { if scope != s.Scopes()[0] { return nil, &sdp.QueryError{ ErrorType: sdp.QueryError_NOSCOPE, - ErrorString: fmt.Sprintf("requested scope %v does not match source scope %v", scope, s.Scopes()[0]), + ErrorString: fmt.Sprintf("requested scope %v does not match adapter scope %v", scope, s.Scopes()[0]), } } @@ -295,11 +300,11 @@ func (s *DescribeOnlySource[Input, Output, ClientStruct, Options]) List(ctx cont } // Search Searches for AWS resources by ARN -func (s *DescribeOnlySource[Input, Output, ClientStruct, Options]) Search(ctx context.Context, scope string, query string, ignoreCache bool) ([]*sdp.Item, error) { +func (s *DescribeOnlyAdapter[Input, Output, ClientStruct, Options]) Search(ctx context.Context, scope string, query string, ignoreCache bool) ([]*sdp.Item, error) { if scope != s.Scopes()[0] { return nil, &sdp.QueryError{ ErrorType: sdp.QueryError_NOSCOPE, - ErrorString: fmt.Sprintf("requested scope %v does not match source scope %v", scope, s.Scopes()[0]), + ErrorString: fmt.Sprintf("requested scope %v does not match adapter scope %v", scope, s.Scopes()[0]), } } @@ -310,7 +315,7 @@ func (s *DescribeOnlySource[Input, Output, ClientStruct, Options]) Search(ctx co } } -func (s *DescribeOnlySource[Input, Output, ClientStruct, Options]) searchARN(ctx context.Context, scope string, query string, ignoreCache bool) ([]*sdp.Item, error) { +func (s *DescribeOnlyAdapter[Input, Output, ClientStruct, Options]) searchARN(ctx context.Context, scope string, query string, ignoreCache bool) ([]*sdp.Item, error) { // Parse the ARN a, err := ParseARN(query) @@ -336,7 +341,7 @@ func (s *DescribeOnlySource[Input, Output, ClientStruct, Options]) searchARN(ctx } // searchCustom Runs custom search logic using the `InputMapperSearch` function -func (s *DescribeOnlySource[Input, Output, ClientStruct, Options]) searchCustom(ctx context.Context, scope string, query string, ignoreCache bool) ([]*sdp.Item, error) { +func (s *DescribeOnlyAdapter[Input, Output, ClientStruct, Options]) searchCustom(ctx context.Context, scope string, query string, ignoreCache bool) ([]*sdp.Item, error) { // We need to cache here since this is the only place it'll be called s.ensureCache() cacheHit, ck, cachedItems, qErr := s.cache.Lookup(ctx, s.Name(), sdp.QueryMethod_SEARCH, scope, s.ItemType, query, ignoreCache) @@ -368,7 +373,7 @@ func (s *DescribeOnlySource[Input, Output, ClientStruct, Options]) searchCustom( // Processes an error returned by the AWS API so that it can be handled by // Overmind. This includes extracting the correct error type, wrapping in an SDP // error, and caching that error if it is non-transient (like a 404) -func (s *DescribeOnlySource[Input, Output, ClientStruct, Options]) processError(err error, cacheKey sdpcache.CacheKey) error { +func (s *DescribeOnlyAdapter[Input, Output, ClientStruct, Options]) processError(err error, cacheKey sdpcache.CacheKey) error { var sdpErr *sdp.QueryError if err != nil { @@ -385,7 +390,7 @@ func (s *DescribeOnlySource[Input, Output, ClientStruct, Options]) processError( // describe Runs describe on the given input, intelligently choosing whether to // run the paginated or unpaginated query -func (s *DescribeOnlySource[Input, Output, ClientStruct, Options]) describe(ctx context.Context, input Input, scope string) ([]*sdp.Item, error) { +func (s *DescribeOnlyAdapter[Input, Output, ClientStruct, Options]) describe(ctx context.Context, input Input, scope string) ([]*sdp.Item, error) { var output Output var err error var newItems []*sdp.Item @@ -423,10 +428,10 @@ func (s *DescribeOnlySource[Input, Output, ClientStruct, Options]) describe(ctx return items, nil } -// Weight Returns the priority weighting of items returned by this source. +// Weight Returns the priority weighting of items returned by this adapter. // This is used to resolve conflicts where two sources of the same type // return an item for a GET request. In this instance only one item can be // seen on, so the one with the higher weight value will win. -func (s *DescribeOnlySource[Input, Output, ClientStruct, Options]) Weight() int { +func (s *DescribeOnlyAdapter[Input, Output, ClientStruct, Options]) Weight() int { return 100 } diff --git a/sources/describe_source_test.go b/adapters/describe_source_test.go similarity index 94% rename from sources/describe_source_test.go rename to adapters/describe_source_test.go index 0f8cbabd..0018e251 100644 --- a/sources/describe_source_test.go +++ b/adapters/describe_source_test.go @@ -1,4 +1,4 @@ -package sources +package adapters import ( "context" @@ -19,7 +19,7 @@ func TestMain(m *testing.M) { } func TestType(t *testing.T) { - s := DescribeOnlySource[string, string, struct{}, struct{}]{ + s := DescribeOnlyAdapter[string, string, struct{}, struct{}]{ ItemType: "foo", } @@ -30,7 +30,7 @@ func TestType(t *testing.T) { func TestName(t *testing.T) { // Basically just test that it's not empty. It doesn't matter what it is - s := DescribeOnlySource[string, string, struct{}, struct{}]{ + s := DescribeOnlyAdapter[string, string, struct{}, struct{}]{ ItemType: "foo", } @@ -40,7 +40,7 @@ func TestName(t *testing.T) { } func TestScopes(t *testing.T) { - s := DescribeOnlySource[string, string, struct{}, struct{}]{ + s := DescribeOnlyAdapter[string, string, struct{}, struct{}]{ Region: "outer-space", AccountID: "mars", } @@ -62,7 +62,7 @@ func TestGet(t *testing.T) { var outputMapperCalled bool var describeFuncCalled bool - s := DescribeOnlySource[string, string, struct{}, struct{}]{ + s := DescribeOnlyAdapter[string, string, struct{}, struct{}]{ Region: "eu-west-2", AccountID: "foo", InputMapperGet: func(scope, query string) (string, error) { @@ -115,7 +115,7 @@ func TestGet(t *testing.T) { var outputMapperCalled bool var describeFuncCalled bool - s := DescribeOnlySource[string, string, struct{}, struct{}]{ + s := DescribeOnlyAdapter[string, string, struct{}, struct{}]{ Region: "eu-west-2", AccountID: "foo", InputMapperGet: func(scope, query string) (string, error) { @@ -181,7 +181,7 @@ func TestGet(t *testing.T) { }) t.Run("with too many results", func(t *testing.T) { - s := DescribeOnlySource[string, string, struct{}, struct{}]{ + s := DescribeOnlyAdapter[string, string, struct{}, struct{}]{ Region: "eu-west-2", AccountID: "foo", InputMapperGet: func(scope, query string) (string, error) { @@ -210,7 +210,7 @@ func TestGet(t *testing.T) { }) t.Run("with no results", func(t *testing.T) { - s := DescribeOnlySource[string, string, struct{}, struct{}]{ + s := DescribeOnlyAdapter[string, string, struct{}, struct{}]{ Region: "eu-west-2", AccountID: "foo", InputMapperGet: func(scope, query string) (string, error) { @@ -236,7 +236,7 @@ func TestGet(t *testing.T) { } func TestSearchARN(t *testing.T) { - s := DescribeOnlySource[string, string, struct{}, struct{}]{ + s := DescribeOnlyAdapter[string, string, struct{}, struct{}]{ Region: "region", AccountID: "account-id", InputMapperGet: func(scope, query string) (string, error) { @@ -267,7 +267,7 @@ func TestSearchARN(t *testing.T) { } func TestSearchCustom(t *testing.T) { - s := DescribeOnlySource[string, string, struct{}, struct{}]{ + s := DescribeOnlyAdapter[string, string, struct{}, struct{}]{ Region: "region", AccountID: "account-id", InputMapperGet: func(scope, query string) (string, error) { @@ -315,7 +315,7 @@ func TestSearchCustom(t *testing.T) { } func TestNoInputMapper(t *testing.T) { - s := DescribeOnlySource[string, string, struct{}, struct{}]{ + s := DescribeOnlyAdapter[string, string, struct{}, struct{}]{ Region: "eu-west-2", AccountID: "foo", OutputMapper: func(_ context.Context, _ struct{}, scope, input, output string) ([]*sdp.Item, error) { @@ -346,7 +346,7 @@ func TestNoInputMapper(t *testing.T) { } func TestNoOutputMapper(t *testing.T) { - s := DescribeOnlySource[string, string, struct{}, struct{}]{ + s := DescribeOnlyAdapter[string, string, struct{}, struct{}]{ Region: "eu-west-2", AccountID: "foo", InputMapperGet: func(scope, query string) (string, error) { @@ -378,7 +378,7 @@ func TestNoOutputMapper(t *testing.T) { } func TestNoDescribeFunc(t *testing.T) { - s := DescribeOnlySource[string, string, struct{}, struct{}]{ + s := DescribeOnlyAdapter[string, string, struct{}, struct{}]{ Region: "eu-west-2", AccountID: "foo", InputMapperGet: func(scope, query string) (string, error) { @@ -412,7 +412,7 @@ func TestNoDescribeFunc(t *testing.T) { } func TestFailingInputMapper(t *testing.T) { - s := DescribeOnlySource[string, string, struct{}, struct{}]{ + s := DescribeOnlyAdapter[string, string, struct{}, struct{}]{ Region: "eu-west-2", AccountID: "foo", InputMapperGet: func(scope, query string) (string, error) { @@ -459,7 +459,7 @@ func TestFailingInputMapper(t *testing.T) { } func TestFailingOutputMapper(t *testing.T) { - s := DescribeOnlySource[string, string, struct{}, struct{}]{ + s := DescribeOnlyAdapter[string, string, struct{}, struct{}]{ Region: "eu-west-2", AccountID: "foo", InputMapperGet: func(scope, query string) (string, error) { @@ -504,7 +504,7 @@ func TestFailingOutputMapper(t *testing.T) { } func TestFailingDescribeFunc(t *testing.T) { - s := DescribeOnlySource[string, string, struct{}, struct{}]{ + s := DescribeOnlyAdapter[string, string, struct{}, struct{}]{ Region: "eu-west-2", AccountID: "foo", InputMapperGet: func(scope, query string) (string, error) { @@ -572,7 +572,7 @@ func (t *TestPaginator) NextPage(context.Context, ...func(struct{})) (string, er } func TestPaginated(t *testing.T) { - s := DescribeOnlySource[string, string, struct{}, struct{}]{ + s := DescribeOnlyAdapter[string, string, struct{}, struct{}]{ MaxResultsPerPage: 1, Region: "eu-west-2", AccountID: "foo", @@ -623,7 +623,7 @@ func TestPaginated(t *testing.T) { func TestDescribeOnlySourceCaching(t *testing.T) { ctx := context.Background() generation := 0 - s := DescribeOnlySource[string, string, struct{}, struct{}]{ + s := DescribeOnlyAdapter[string, string, struct{}, struct{}]{ ItemType: "test-type", MaxResultsPerPage: 1, Region: "eu-west-2", diff --git a/sources/directconnect/connection.go b/adapters/directconnect/connection.go similarity index 71% rename from sources/directconnect/connection.go rename to adapters/directconnect/connection.go index 8344bfc4..4c565e9c 100644 --- a/sources/directconnect/connection.go +++ b/adapters/directconnect/connection.go @@ -4,7 +4,7 @@ import ( "context" "github.com/aws/aws-sdk-go-v2/service/directconnect" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -12,7 +12,7 @@ func connectionOutputMapper(_ context.Context, _ *directconnect.Client, scope st items := make([]*sdp.Item, 0) for _, connection := range output.Connections { - attributes, err := sources.ToAttributesWithExclude(connection, "tags") + attributes, err := adapters.ToAttributesWithExclude(connection, "tags") if err != nil { return nil, err } @@ -111,12 +111,13 @@ func connectionOutputMapper(_ context.Context, _ *directconnect.Client, scope st // +overmind:group AWS // +overmind:terraform:queryMap aws_dx_connection.id -func NewConnectionSource(client *directconnect.Client, accountID string, region string) *sources.DescribeOnlySource[*directconnect.DescribeConnectionsInput, *directconnect.DescribeConnectionsOutput, *directconnect.Client, *directconnect.Options] { - return &sources.DescribeOnlySource[*directconnect.DescribeConnectionsInput, *directconnect.DescribeConnectionsOutput, *directconnect.Client, *directconnect.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "directconnect-connection", +func NewConnectionAdapter(client *directconnect.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*directconnect.DescribeConnectionsInput, *directconnect.DescribeConnectionsOutput, *directconnect.Client, *directconnect.Options] { + return &adapters.DescribeOnlyAdapter[*directconnect.DescribeConnectionsInput, *directconnect.DescribeConnectionsOutput, *directconnect.Client, *directconnect.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "directconnect-connection", + AdapterMetadata: ConnectionMetadata(), DescribeFunc: func(ctx context.Context, client *directconnect.Client, input *directconnect.DescribeConnectionsInput) (*directconnect.DescribeConnectionsOutput, error) { return client.DescribeConnections(ctx, input) }, @@ -131,3 +132,25 @@ func NewConnectionSource(client *directconnect.Client, accountID string, region OutputMapper: connectionOutputMapper, } } + +func ConnectionMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "directconnect-connection", + DescriptiveName: "Connection", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a connection by ID", + ListDescription: "List all connections", + SearchDescription: "Search connection by ARN", + }, + PotentialLinks: []string{"directconnect-lag", "directconnect-location", "directconnect-loa", "directconnect-virtual-interface"}, + TerraformMappings: []*sdp.TerraformMapping{ + { + TerraformQueryMap: "aws_dx_connection.id", + }, + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + } +} diff --git a/sources/directconnect/connection_test.go b/adapters/directconnect/connection_test.go similarity index 57% rename from sources/directconnect/connection_test.go rename to adapters/directconnect/connection_test.go index 15dcc8d7..3a9cf078 100644 --- a/sources/directconnect/connection_test.go +++ b/adapters/directconnect/connection_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/directconnect" "github.com/aws/aws-sdk-go-v2/service/directconnect/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -15,26 +15,26 @@ func TestConnectionOutputMapper(t *testing.T) { output := &directconnect.DescribeConnectionsOutput{ Connections: []types.Connection{ { - AwsDeviceV2: sources.PtrString("EqDC2-123h49s71dabc"), - AwsLogicalDeviceId: sources.PtrString("device-1"), - Bandwidth: sources.PtrString("1Gbps"), - ConnectionId: sources.PtrString("dxcon-fguhmqlc"), - ConnectionName: sources.PtrString("My_Connection"), + AwsDeviceV2: adapters.PtrString("EqDC2-123h49s71dabc"), + AwsLogicalDeviceId: adapters.PtrString("device-1"), + Bandwidth: adapters.PtrString("1Gbps"), + ConnectionId: adapters.PtrString("dxcon-fguhmqlc"), + ConnectionName: adapters.PtrString("My_Connection"), ConnectionState: "down", - EncryptionMode: sources.PtrString("must_encrypt"), + EncryptionMode: adapters.PtrString("must_encrypt"), HasLogicalRedundancy: "unknown", - JumboFrameCapable: sources.PtrBool(true), - LagId: sources.PtrString("dxlag-ffrz71kw"), - LoaIssueTime: sources.PtrTime(time.Now()), - Location: sources.PtrString("EqDC2"), - Region: sources.PtrString("us-east-1"), - ProviderName: sources.PtrString("provider-1"), - OwnerAccount: sources.PtrString("123456789012"), - PartnerName: sources.PtrString("partner-1"), + JumboFrameCapable: adapters.PtrBool(true), + LagId: adapters.PtrString("dxlag-ffrz71kw"), + LoaIssueTime: adapters.PtrTime(time.Now()), + Location: adapters.PtrString("EqDC2"), + Region: adapters.PtrString("us-east-1"), + ProviderName: adapters.PtrString("provider-1"), + OwnerAccount: adapters.PtrString("123456789012"), + PartnerName: adapters.PtrString("partner-1"), Tags: []types.Tag{ { - Key: sources.PtrString("foo"), - Value: sources.PtrString("bar"), + Key: adapters.PtrString("foo"), + Value: adapters.PtrString("bar"), }, }, }, @@ -58,7 +58,7 @@ func TestConnectionOutputMapper(t *testing.T) { item := items[0] - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "directconnect-lag", ExpectedMethod: sdp.QueryMethod_GET, @@ -88,13 +88,13 @@ func TestConnectionOutputMapper(t *testing.T) { tests.Execute(t, item) } -func TestNewConnectionSource(t *testing.T) { +func TestNewConnectionAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewConnectionSource(client, account, region) + adapter := NewConnectionAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/directconnect/customer-metadata.go b/adapters/directconnect/customer-metadata.go similarity index 57% rename from sources/directconnect/customer-metadata.go rename to adapters/directconnect/customer-metadata.go index ca2d2318..1418e345 100644 --- a/sources/directconnect/customer-metadata.go +++ b/adapters/directconnect/customer-metadata.go @@ -4,7 +4,7 @@ import ( "context" "github.com/aws/aws-sdk-go-v2/service/directconnect" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -12,7 +12,7 @@ func customerMetadataOutputMapper(_ context.Context, _ *directconnect.Client, sc items := make([]*sdp.Item, 0) for _, agreement := range output.Agreements { - attributes, err := sources.ToAttributesWithExclude(agreement, "tags") + attributes, err := adapters.ToAttributesWithExclude(agreement, "tags") if err != nil { return nil, err } @@ -38,12 +38,13 @@ func customerMetadataOutputMapper(_ context.Context, _ *directconnect.Client, sc // +overmind:search Search Customer Agreements by ARN // +overmind:group AWS -func NewCustomerMetadataSource(client *directconnect.Client, accountID string, region string) *sources.DescribeOnlySource[*directconnect.DescribeCustomerMetadataInput, *directconnect.DescribeCustomerMetadataOutput, *directconnect.Client, *directconnect.Options] { - return &sources.DescribeOnlySource[*directconnect.DescribeCustomerMetadataInput, *directconnect.DescribeCustomerMetadataOutput, *directconnect.Client, *directconnect.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "directconnect-customer-metadata", +func NewCustomerMetadataAdapter(client *directconnect.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*directconnect.DescribeCustomerMetadataInput, *directconnect.DescribeCustomerMetadataOutput, *directconnect.Client, *directconnect.Options] { + return &adapters.DescribeOnlyAdapter[*directconnect.DescribeCustomerMetadataInput, *directconnect.DescribeCustomerMetadataOutput, *directconnect.Client, *directconnect.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "directconnect-customer-metadata", + AdapterMetadata: CustomerMetadata(), DescribeFunc: func(ctx context.Context, client *directconnect.Client, input *directconnect.DescribeCustomerMetadataInput) (*directconnect.DescribeCustomerMetadataOutput, error) { return client.DescribeCustomerMetadata(ctx, input) }, @@ -58,3 +59,19 @@ func NewCustomerMetadataSource(client *directconnect.Client, accountID string, r OutputMapper: customerMetadataOutputMapper, } } + +func CustomerMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "directconnect-customer-metadata", + DescriptiveName: "Customer Metadata", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a customer agreement by name", + ListDescription: "List all customer agreements", + SearchDescription: "Search customer agreements by ARN", + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_CONFIGURATION, + } +} diff --git a/sources/directconnect/customer-metadata_test.go b/adapters/directconnect/customer-metadata_test.go similarity index 69% rename from sources/directconnect/customer-metadata_test.go rename to adapters/directconnect/customer-metadata_test.go index 1723d8f5..a24325e3 100644 --- a/sources/directconnect/customer-metadata_test.go +++ b/adapters/directconnect/customer-metadata_test.go @@ -7,15 +7,15 @@ import ( "github.com/aws/aws-sdk-go-v2/service/directconnect" "github.com/aws/aws-sdk-go-v2/service/directconnect/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" ) func TestCustomerMetadataOutputMapper(t *testing.T) { output := &directconnect.DescribeCustomerMetadataOutput{ Agreements: []types.CustomerAgreement{ { - AgreementName: sources.PtrString("example-customer-agreement"), - Status: sources.PtrString("signed"), + AgreementName: adapters.PtrString("example-customer-agreement"), + Status: adapters.PtrString("signed"), }, }, } @@ -36,13 +36,13 @@ func TestCustomerMetadataOutputMapper(t *testing.T) { } } -func TestNewCustomerMetadataSource(t *testing.T) { +func TestNewCustomerMetadataAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewCustomerMetadataSource(client, account, region) + adapter := NewCustomerMetadataAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/directconnect/direct-connect-gateway-association-proposal.go b/adapters/directconnect/direct-connect-gateway-association-proposal.go similarity index 62% rename from sources/directconnect/direct-connect-gateway-association-proposal.go rename to adapters/directconnect/direct-connect-gateway-association-proposal.go index efc8e029..243a2c8f 100644 --- a/sources/directconnect/direct-connect-gateway-association-proposal.go +++ b/adapters/directconnect/direct-connect-gateway-association-proposal.go @@ -5,7 +5,7 @@ import ( "fmt" "github.com/aws/aws-sdk-go-v2/service/directconnect" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -13,7 +13,7 @@ func directConnectGatewayAssociationProposalOutputMapper(_ context.Context, _ *d items := make([]*sdp.Item, 0) for _, associationProposal := range output.DirectConnectGatewayAssociationProposals { - attributes, err := sources.ToAttributesWithExclude(associationProposal, "tags") + attributes, err := adapters.ToAttributesWithExclude(associationProposal, "tags") if err != nil { return nil, err } @@ -59,12 +59,13 @@ func directConnectGatewayAssociationProposalOutputMapper(_ context.Context, _ *d // +overmind:group AWS // +overmind:terraform:queryMap aws_dx_gateway_association_proposal.id -func NewDirectConnectGatewayAssociationProposalSource(client *directconnect.Client, accountID string, region string) *sources.DescribeOnlySource[*directconnect.DescribeDirectConnectGatewayAssociationProposalsInput, *directconnect.DescribeDirectConnectGatewayAssociationProposalsOutput, *directconnect.Client, *directconnect.Options] { - return &sources.DescribeOnlySource[*directconnect.DescribeDirectConnectGatewayAssociationProposalsInput, *directconnect.DescribeDirectConnectGatewayAssociationProposalsOutput, *directconnect.Client, *directconnect.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "directconnect-direct-connect-gateway-association-proposal", +func NewDirectConnectGatewayAssociationProposalAdapter(client *directconnect.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*directconnect.DescribeDirectConnectGatewayAssociationProposalsInput, *directconnect.DescribeDirectConnectGatewayAssociationProposalsOutput, *directconnect.Client, *directconnect.Options] { + return &adapters.DescribeOnlyAdapter[*directconnect.DescribeDirectConnectGatewayAssociationProposalsInput, *directconnect.DescribeDirectConnectGatewayAssociationProposalsOutput, *directconnect.Client, *directconnect.Options]{ + Region: region, + Client: client, + AccountID: accountID, + AdapterMetadata: DirectConnectGatewayAssociationProposalMetadata(), + ItemType: "directconnect-direct-connect-gateway-association-proposal", DescribeFunc: func(ctx context.Context, client *directconnect.Client, input *directconnect.DescribeDirectConnectGatewayAssociationProposalsInput) (*directconnect.DescribeDirectConnectGatewayAssociationProposalsOutput, error) { return client.DescribeDirectConnectGatewayAssociationProposals(ctx, input) }, @@ -79,3 +80,23 @@ func NewDirectConnectGatewayAssociationProposalSource(client *directconnect.Clie OutputMapper: directConnectGatewayAssociationProposalOutputMapper, } } + +func DirectConnectGatewayAssociationProposalMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + DescriptiveName: "Direct Connect Gateway Association Proposal", + Type: "directconnect-direct-connect-gateway-association-proposal", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a Direct Connect Gateway Association Proposal by ID", + ListDescription: "List all Direct Connect Gateway Association Proposals", + SearchDescription: "Search Direct Connect Gateway Association Proposals by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_dx_gateway_association_proposal.id"}, + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_CONFIGURATION, + PotentialLinks: []string{"directconnect-direct-connect-gateway-association"}, + } +} diff --git a/sources/directconnect/direct-connect-gateway-association-proposal_test.go b/adapters/directconnect/direct-connect-gateway-association-proposal_test.go similarity index 65% rename from sources/directconnect/direct-connect-gateway-association-proposal_test.go rename to adapters/directconnect/direct-connect-gateway-association-proposal_test.go index 25f9fd5c..41ca8319 100644 --- a/sources/directconnect/direct-connect-gateway-association-proposal_test.go +++ b/adapters/directconnect/direct-connect-gateway-association-proposal_test.go @@ -8,7 +8,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/directconnect" "github.com/aws/aws-sdk-go-v2/service/directconnect/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -16,27 +16,27 @@ func TestDirectConnectGatewayAssociationProposalOutputMapper(t *testing.T) { output := &directconnect.DescribeDirectConnectGatewayAssociationProposalsOutput{ DirectConnectGatewayAssociationProposals: []types.DirectConnectGatewayAssociationProposal{ { - ProposalId: sources.PtrString("c2ede9b4-bbc6-4d33-923c-bc4feEXAMPLE"), - DirectConnectGatewayId: sources.PtrString("5f294f92-bafb-4011-916d-9b0bexample"), - DirectConnectGatewayOwnerAccount: sources.PtrString("123456789012"), + ProposalId: adapters.PtrString("c2ede9b4-bbc6-4d33-923c-bc4feEXAMPLE"), + DirectConnectGatewayId: adapters.PtrString("5f294f92-bafb-4011-916d-9b0bexample"), + DirectConnectGatewayOwnerAccount: adapters.PtrString("123456789012"), ProposalState: types.DirectConnectGatewayAssociationProposalStateRequested, AssociatedGateway: &types.AssociatedGateway{ - Id: sources.PtrString("tgw-02f776b1a7EXAMPLE"), + Id: adapters.PtrString("tgw-02f776b1a7EXAMPLE"), Type: types.GatewayTypeTransitGateway, - OwnerAccount: sources.PtrString("111122223333"), - Region: sources.PtrString("us-east-1"), + OwnerAccount: adapters.PtrString("111122223333"), + Region: adapters.PtrString("us-east-1"), }, ExistingAllowedPrefixesToDirectConnectGateway: []types.RouteFilterPrefix{ { - Cidr: sources.PtrString("192.168.2.0/30"), + Cidr: adapters.PtrString("192.168.2.0/30"), }, { - Cidr: sources.PtrString("192.168.1.0/30"), + Cidr: adapters.PtrString("192.168.1.0/30"), }, }, RequestedAllowedPrefixesToDirectConnectGateway: []types.RouteFilterPrefix{ { - Cidr: sources.PtrString("192.168.1.0/30"), + Cidr: adapters.PtrString("192.168.1.0/30"), }, }, }, @@ -60,7 +60,7 @@ func TestDirectConnectGatewayAssociationProposalOutputMapper(t *testing.T) { item := items[0] - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "directconnect-direct-connect-gateway-association", ExpectedMethod: sdp.QueryMethod_GET, @@ -72,13 +72,13 @@ func TestDirectConnectGatewayAssociationProposalOutputMapper(t *testing.T) { tests.Execute(t, item) } -func TestNewDirectConnectGatewayAssociationProposalSource(t *testing.T) { +func TestNewDirectConnectGatewayAssociationProposalAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewDirectConnectGatewayAssociationProposalSource(client, account, region) + adapter := NewDirectConnectGatewayAssociationProposalAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/directconnect/direct-connect-gateway-association.go b/adapters/directconnect/direct-connect-gateway-association.go similarity index 76% rename from sources/directconnect/direct-connect-gateway-association.go rename to adapters/directconnect/direct-connect-gateway-association.go index 5c092315..8dcc7bb8 100644 --- a/sources/directconnect/direct-connect-gateway-association.go +++ b/adapters/directconnect/direct-connect-gateway-association.go @@ -6,7 +6,7 @@ import ( "strings" "github.com/aws/aws-sdk-go-v2/service/directconnect" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -19,7 +19,7 @@ func directConnectGatewayAssociationOutputMapper(_ context.Context, _ *directcon items := make([]*sdp.Item, 0) for _, association := range output.DirectConnectGatewayAssociations { - attributes, err := sources.ToAttributesWithExclude(association, "tags") + attributes, err := adapters.ToAttributesWithExclude(association, "tags") if err != nil { return nil, err } @@ -88,12 +88,13 @@ func directConnectGatewayAssociationOutputMapper(_ context.Context, _ *directcon // +overmind:group AWS // +overmind:terraform:queryMap aws_dx_gateway_association.id -func NewDirectConnectGatewayAssociationSource(client *directconnect.Client, accountID string, region string) *sources.DescribeOnlySource[*directconnect.DescribeDirectConnectGatewayAssociationsInput, *directconnect.DescribeDirectConnectGatewayAssociationsOutput, *directconnect.Client, *directconnect.Options] { - return &sources.DescribeOnlySource[*directconnect.DescribeDirectConnectGatewayAssociationsInput, *directconnect.DescribeDirectConnectGatewayAssociationsOutput, *directconnect.Client, *directconnect.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "directconnect-direct-connect-gateway-association", +func NewDirectConnectGatewayAssociationAdapter(client *directconnect.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*directconnect.DescribeDirectConnectGatewayAssociationsInput, *directconnect.DescribeDirectConnectGatewayAssociationsOutput, *directconnect.Client, *directconnect.Options] { + return &adapters.DescribeOnlyAdapter[*directconnect.DescribeDirectConnectGatewayAssociationsInput, *directconnect.DescribeDirectConnectGatewayAssociationsOutput, *directconnect.Client, *directconnect.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "directconnect-direct-connect-gateway-association", + AdapterMetadata: DirectConnectGatewayAssociationMetadata(), DescribeFunc: func(ctx context.Context, client *directconnect.Client, input *directconnect.DescribeDirectConnectGatewayAssociationsInput) (*directconnect.DescribeDirectConnectGatewayAssociationsOutput, error) { return client.DescribeDirectConnectGatewayAssociations(ctx, input) }, @@ -135,6 +136,24 @@ func NewDirectConnectGatewayAssociationSource(client *directconnect.Client, acco } } +func DirectConnectGatewayAssociationMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + DescriptiveName: "Direct Connect Gateway Association", + Type: "directconnect-direct-connect-gateway-association", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + Search: true, + GetDescription: "Get a direct connect gateway association by direct connect gateway ID and virtual gateway ID", + SearchDescription: "Search direct connect gateway associations by direct connect gateway ID", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_dx_gateway_association.id"}, + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + PotentialLinks: []string{"directconnect-direct-connect-gateway"}, + } +} + // parseDirectConnectGatewayAssociationGetInputQuery expects a query: // - in the format of "directConnectGatewayID/virtualGatewayID" // - virtualGatewayID => associatedGatewayID diff --git a/sources/directconnect/direct-connect-gateway-association_test.go b/adapters/directconnect/direct-connect-gateway-association_test.go similarity index 72% rename from sources/directconnect/direct-connect-gateway-association_test.go rename to adapters/directconnect/direct-connect-gateway-association_test.go index f5a542e3..4eaec0d4 100644 --- a/sources/directconnect/direct-connect-gateway-association_test.go +++ b/adapters/directconnect/direct-connect-gateway-association_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/directconnect" "github.com/aws/aws-sdk-go-v2/service/directconnect/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -16,10 +16,10 @@ func TestDirectConnectGatewayAssociationOutputMapper_Health_OK(t *testing.T) { DirectConnectGatewayAssociations: []types.DirectConnectGatewayAssociation{ { AssociationState: types.DirectConnectGatewayAssociationStateAssociating, - AssociationId: sources.PtrString("cf68415c-f4ae-48f2-87a7-3b52cexample"), - VirtualGatewayOwnerAccount: sources.PtrString("123456789012"), - DirectConnectGatewayId: sources.PtrString("5f294f92-bafb-4011-916d-9b0bexample"), - VirtualGatewayId: sources.PtrString("vgw-6efe725e"), + AssociationId: adapters.PtrString("cf68415c-f4ae-48f2-87a7-3b52cexample"), + VirtualGatewayOwnerAccount: adapters.PtrString("123456789012"), + DirectConnectGatewayId: adapters.PtrString("5f294f92-bafb-4011-916d-9b0bexample"), + VirtualGatewayId: adapters.PtrString("vgw-6efe725e"), }, }, } @@ -45,7 +45,7 @@ func TestDirectConnectGatewayAssociationOutputMapper_Health_OK(t *testing.T) { t.Fatalf("expected health to be OK, got: %v", item.GetHealth()) } - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "directconnect-direct-connect-gateway", ExpectedMethod: sdp.QueryMethod_GET, @@ -68,11 +68,11 @@ func TestDirectConnectGatewayAssociationOutputMapper_Health_Error(t *testing.T) DirectConnectGatewayAssociations: []types.DirectConnectGatewayAssociation{ { AssociationState: types.DirectConnectGatewayAssociationStateAssociating, - AssociationId: sources.PtrString("cf68415c-f4ae-48f2-87a7-3b52cexample"), - VirtualGatewayOwnerAccount: sources.PtrString("123456789012"), - DirectConnectGatewayId: sources.PtrString("5f294f92-bafb-4011-916d-9b0bexample"), - VirtualGatewayId: sources.PtrString("vgw-6efe725e"), - StateChangeError: sources.PtrString("something went wrong"), + AssociationId: adapters.PtrString("cf68415c-f4ae-48f2-87a7-3b52cexample"), + VirtualGatewayOwnerAccount: adapters.PtrString("123456789012"), + DirectConnectGatewayId: adapters.PtrString("5f294f92-bafb-4011-916d-9b0bexample"), + VirtualGatewayId: adapters.PtrString("vgw-6efe725e"), + StateChangeError: adapters.PtrString("something went wrong"), }, }, } @@ -98,7 +98,7 @@ func TestDirectConnectGatewayAssociationOutputMapper_Health_Error(t *testing.T) t.Fatalf("expected health to be ERROR, got: %v", item.GetHealth()) } - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "directconnect-direct-connect-gateway", ExpectedMethod: sdp.QueryMethod_GET, @@ -116,13 +116,13 @@ func TestDirectConnectGatewayAssociationOutputMapper_Health_Error(t *testing.T) tests.Execute(t, item) } -func TestNewDirectConnectGatewayAssociationSource(t *testing.T) { +func TestNewDirectConnectGatewayAssociationAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewDirectConnectGatewayAssociationSource(client, account, region) + adapter := NewDirectConnectGatewayAssociationAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, SkipList: true, } diff --git a/sources/directconnect/direct-connect-gateway-attachment.go b/adapters/directconnect/direct-connect-gateway-attachment.go similarity index 76% rename from sources/directconnect/direct-connect-gateway-attachment.go rename to adapters/directconnect/direct-connect-gateway-attachment.go index 583a855a..4b330870 100644 --- a/sources/directconnect/direct-connect-gateway-attachment.go +++ b/adapters/directconnect/direct-connect-gateway-attachment.go @@ -6,7 +6,7 @@ import ( "strings" "github.com/aws/aws-sdk-go-v2/service/directconnect" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -14,7 +14,7 @@ func directConnectGatewayAttachmentOutputMapper(_ context.Context, _ *directconn items := make([]*sdp.Item, 0) for _, attachment := range output.DirectConnectGatewayAttachments { - attributes, err := sources.ToAttributesWithExclude(attachment, "tags") + attributes, err := adapters.ToAttributesWithExclude(attachment, "tags") if err != nil { return nil, err } @@ -91,12 +91,13 @@ func directConnectGatewayAttachmentOutputMapper(_ context.Context, _ *directconn // +overmind:search Search direct connect gateway attachments for given VirtualInterfaceId // +overmind:group AWS -func NewDirectConnectGatewayAttachmentSource(client *directconnect.Client, accountID string, region string) *sources.DescribeOnlySource[*directconnect.DescribeDirectConnectGatewayAttachmentsInput, *directconnect.DescribeDirectConnectGatewayAttachmentsOutput, *directconnect.Client, *directconnect.Options] { - return &sources.DescribeOnlySource[*directconnect.DescribeDirectConnectGatewayAttachmentsInput, *directconnect.DescribeDirectConnectGatewayAttachmentsOutput, *directconnect.Client, *directconnect.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "directconnect-direct-connect-gateway-attachment", +func NewDirectConnectGatewayAttachmentAdapter(client *directconnect.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*directconnect.DescribeDirectConnectGatewayAttachmentsInput, *directconnect.DescribeDirectConnectGatewayAttachmentsOutput, *directconnect.Client, *directconnect.Options] { + return &adapters.DescribeOnlyAdapter[*directconnect.DescribeDirectConnectGatewayAttachmentsInput, *directconnect.DescribeDirectConnectGatewayAttachmentsOutput, *directconnect.Client, *directconnect.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "directconnect-direct-connect-gateway-attachment", + AdapterMetadata: DirectConnectGatewayAttachmentMetadata(), DescribeFunc: func(ctx context.Context, client *directconnect.Client, input *directconnect.DescribeDirectConnectGatewayAttachmentsInput) (*directconnect.DescribeDirectConnectGatewayAttachmentsOutput, error) { return client.DescribeDirectConnectGatewayAttachments(ctx, input) }, @@ -128,6 +129,21 @@ func NewDirectConnectGatewayAttachmentSource(client *directconnect.Client, accou } } +func DirectConnectGatewayAttachmentMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "directconnect-direct-connect-gateway-attachment", + DescriptiveName: "Direct Connect Gateway Attachment", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + Search: true, + GetDescription: "Get a direct connect gateway attachment by DirectConnectGatewayId/VirtualInterfaceId", + SearchDescription: "Search direct connect gateway attachments for given VirtualInterfaceId", + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + PotentialLinks: []string{"directconnect-direct-connect-gateway", "directconnect-virtual-interface"}, + } +} + // parseGatewayIDVirtualInterfaceID expects a query in the format of "gatewayID/virtualInterfaceID" // First returned item is gatewayID, second is virtualInterfaceID func parseGatewayIDVirtualInterfaceID(query string) (string, string, error) { diff --git a/sources/directconnect/direct-connect-gateway-attachment_test.go b/adapters/directconnect/direct-connect-gateway-attachment_test.go similarity index 72% rename from sources/directconnect/direct-connect-gateway-attachment_test.go rename to adapters/directconnect/direct-connect-gateway-attachment_test.go index 64b0ee95..ae4dc2fa 100644 --- a/sources/directconnect/direct-connect-gateway-attachment_test.go +++ b/adapters/directconnect/direct-connect-gateway-attachment_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/directconnect" "github.com/aws/aws-sdk-go-v2/service/directconnect/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -15,10 +15,10 @@ func TestDirectConnectGatewayAttachmentOutputMapper_Health_OK(t *testing.T) { output := &directconnect.DescribeDirectConnectGatewayAttachmentsOutput{ DirectConnectGatewayAttachments: []types.DirectConnectGatewayAttachment{ { - VirtualInterfaceOwnerAccount: sources.PtrString("123456789012"), - VirtualInterfaceRegion: sources.PtrString("us-east-2"), - VirtualInterfaceId: sources.PtrString("dxvif-ffhhk74f"), - DirectConnectGatewayId: sources.PtrString("cf68415c-f4ae-48f2-87a7-3b52cexample"), + VirtualInterfaceOwnerAccount: adapters.PtrString("123456789012"), + VirtualInterfaceRegion: adapters.PtrString("us-east-2"), + VirtualInterfaceId: adapters.PtrString("dxvif-ffhhk74f"), + DirectConnectGatewayId: adapters.PtrString("cf68415c-f4ae-48f2-87a7-3b52cexample"), AttachmentState: "detaching", }, }, @@ -45,7 +45,7 @@ func TestDirectConnectGatewayAttachmentOutputMapper_Health_OK(t *testing.T) { t.Fatalf("expected health to be OK, got: %v", item.GetHealth()) } - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "directconnect-direct-connect-gateway", ExpectedMethod: sdp.QueryMethod_GET, @@ -67,12 +67,12 @@ func TestDirectConnectGatewayAttachmentOutputMapper_Health_Error(t *testing.T) { output := &directconnect.DescribeDirectConnectGatewayAttachmentsOutput{ DirectConnectGatewayAttachments: []types.DirectConnectGatewayAttachment{ { - VirtualInterfaceOwnerAccount: sources.PtrString("123456789012"), - VirtualInterfaceRegion: sources.PtrString("us-east-2"), - VirtualInterfaceId: sources.PtrString("dxvif-ffhhk74f"), - DirectConnectGatewayId: sources.PtrString("cf68415c-f4ae-48f2-87a7-3b52cexample"), + VirtualInterfaceOwnerAccount: adapters.PtrString("123456789012"), + VirtualInterfaceRegion: adapters.PtrString("us-east-2"), + VirtualInterfaceId: adapters.PtrString("dxvif-ffhhk74f"), + DirectConnectGatewayId: adapters.PtrString("cf68415c-f4ae-48f2-87a7-3b52cexample"), AttachmentState: "detaching", - StateChangeError: sources.PtrString("error"), + StateChangeError: adapters.PtrString("error"), }, }, } @@ -98,7 +98,7 @@ func TestDirectConnectGatewayAttachmentOutputMapper_Health_Error(t *testing.T) { t.Fatalf("expected health to be ERROR, got: %v", item.GetHealth()) } - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "directconnect-direct-connect-gateway", ExpectedMethod: sdp.QueryMethod_GET, @@ -116,13 +116,13 @@ func TestDirectConnectGatewayAttachmentOutputMapper_Health_Error(t *testing.T) { tests.Execute(t, item) } -func TestNewDirectConnectGatewayAttachmentSource(t *testing.T) { +func TestNewDirectConnectGatewayAttachmentAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewDirectConnectGatewayAttachmentSource(client, account, region) + adapter := NewDirectConnectGatewayAttachmentAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, SkipList: true, } diff --git a/sources/directconnect/direct-connect-gateway.go b/adapters/directconnect/direct-connect-gateway.go similarity index 69% rename from sources/directconnect/direct-connect-gateway.go rename to adapters/directconnect/direct-connect-gateway.go index 3a870f61..115c11c1 100644 --- a/sources/directconnect/direct-connect-gateway.go +++ b/adapters/directconnect/direct-connect-gateway.go @@ -6,7 +6,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/directconnect" "github.com/aws/aws-sdk-go-v2/service/directconnect/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -37,7 +37,7 @@ func directConnectGatewayOutputMapper(ctx context.Context, cli *directconnect.Cl items := make([]*sdp.Item, 0) for _, directConnectGateway := range output.DirectConnectGateways { - attributes, err := sources.ToAttributesWithExclude(directConnectGateway, "tags") + attributes, err := adapters.ToAttributesWithExclude(directConnectGateway, "tags") if err != nil { return nil, err } @@ -82,12 +82,13 @@ func arn(region, accountID, gatewayID string) string { // +overmind:group AWS // +overmind:terraform:queryMap aws_dx_gateway.id -func NewDirectConnectGatewaySource(client *directconnect.Client, accountID string, region string) *sources.DescribeOnlySource[*directconnect.DescribeDirectConnectGatewaysInput, *directconnect.DescribeDirectConnectGatewaysOutput, *directconnect.Client, *directconnect.Options] { - return &sources.DescribeOnlySource[*directconnect.DescribeDirectConnectGatewaysInput, *directconnect.DescribeDirectConnectGatewaysOutput, *directconnect.Client, *directconnect.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "directconnect-direct-connect-gateway", +func NewDirectConnectGatewayAdapter(client *directconnect.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*directconnect.DescribeDirectConnectGatewaysInput, *directconnect.DescribeDirectConnectGatewaysOutput, *directconnect.Client, *directconnect.Options] { + return &adapters.DescribeOnlyAdapter[*directconnect.DescribeDirectConnectGatewaysInput, *directconnect.DescribeDirectConnectGatewaysOutput, *directconnect.Client, *directconnect.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "directconnect-direct-connect-gateway", + AdapterMetadata: DirectConnectGatewayMetadata(), DescribeFunc: func(ctx context.Context, client *directconnect.Client, input *directconnect.DescribeDirectConnectGatewaysInput) (*directconnect.DescribeDirectConnectGatewaysOutput, error) { return client.DescribeDirectConnectGateways(ctx, input) }, @@ -102,3 +103,24 @@ func NewDirectConnectGatewaySource(client *directconnect.Client, accountID strin OutputMapper: directConnectGatewayOutputMapper, } } + +func DirectConnectGatewayMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "directconnect-direct-connect-gateway", + DescriptiveName: "Direct Connect Gateway", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a direct connect gateway by ID", + ListDescription: "List all direct connect gateways", + SearchDescription: "Search direct connect gateway by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + { + TerraformQueryMap: "aws_dx_gateway.id", + }, + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + } +} diff --git a/sources/directconnect/direct-connect-gateway_test.go b/adapters/directconnect/direct-connect-gateway_test.go similarity index 75% rename from sources/directconnect/direct-connect-gateway_test.go rename to adapters/directconnect/direct-connect-gateway_test.go index 05ffcf0b..80de1c2f 100644 --- a/sources/directconnect/direct-connect-gateway_test.go +++ b/adapters/directconnect/direct-connect-gateway_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/directconnect" "github.com/aws/aws-sdk-go-v2/service/directconnect/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -15,10 +15,10 @@ func TestDirectConnectGatewayOutputMapper_Health_OK(t *testing.T) { output := &directconnect.DescribeDirectConnectGatewaysOutput{ DirectConnectGateways: []types.DirectConnectGateway{ { - AmazonSideAsn: sources.PtrInt64(64512), - DirectConnectGatewayId: sources.PtrString("cf68415c-f4ae-48f2-87a7-3b52cexample"), - OwnerAccount: sources.PtrString("123456789012"), - DirectConnectGatewayName: sources.PtrString("DxGateway2"), + AmazonSideAsn: adapters.PtrInt64(64512), + DirectConnectGatewayId: adapters.PtrString("cf68415c-f4ae-48f2-87a7-3b52cexample"), + OwnerAccount: adapters.PtrString("123456789012"), + DirectConnectGatewayName: adapters.PtrString("DxGateway2"), DirectConnectGatewayState: types.DirectConnectGatewayStateAvailable, }, }, @@ -48,12 +48,12 @@ func TestDirectConnectGatewayOutputMapper_Health_ERROR(t *testing.T) { output := &directconnect.DescribeDirectConnectGatewaysOutput{ DirectConnectGateways: []types.DirectConnectGateway{ { - AmazonSideAsn: sources.PtrInt64(64512), - DirectConnectGatewayId: sources.PtrString("cf68415c-f4ae-48f2-87a7-3b52cexample"), - OwnerAccount: sources.PtrString("123456789012"), - DirectConnectGatewayName: sources.PtrString("DxGateway2"), + AmazonSideAsn: adapters.PtrInt64(64512), + DirectConnectGatewayId: adapters.PtrString("cf68415c-f4ae-48f2-87a7-3b52cexample"), + OwnerAccount: adapters.PtrString("123456789012"), + DirectConnectGatewayName: adapters.PtrString("DxGateway2"), DirectConnectGatewayState: types.DirectConnectGatewayStateAvailable, - StateChangeError: sources.PtrString("error"), + StateChangeError: adapters.PtrString("error"), }, }, } @@ -78,13 +78,13 @@ func TestDirectConnectGatewayOutputMapper_Health_ERROR(t *testing.T) { } } -func TestNewDirectConnectGatewaySource(t *testing.T) { +func TestNewDirectConnectGatewayAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewDirectConnectGatewaySource(client, account, region) + adapter := NewDirectConnectGatewayAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/directconnect/hosted-connection.go b/adapters/directconnect/hosted-connection.go similarity index 72% rename from sources/directconnect/hosted-connection.go rename to adapters/directconnect/hosted-connection.go index 2272b34d..5fdada1c 100644 --- a/sources/directconnect/hosted-connection.go +++ b/adapters/directconnect/hosted-connection.go @@ -4,7 +4,7 @@ import ( "context" "github.com/aws/aws-sdk-go-v2/service/directconnect" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -12,7 +12,7 @@ func hostedConnectionOutputMapper(_ context.Context, _ *directconnect.Client, sc items := make([]*sdp.Item, 0) for _, connection := range output.Connections { - attributes, err := sources.ToAttributesWithExclude(connection, "tags") + attributes, err := adapters.ToAttributesWithExclude(connection, "tags") if err != nil { return nil, err } @@ -109,12 +109,13 @@ func hostedConnectionOutputMapper(_ context.Context, _ *directconnect.Client, sc // +overmind:group AWS // +overmind:terraform:queryMap aws_dx_hosted_connection.id -func NewHostedConnectionSource(client *directconnect.Client, accountID string, region string) *sources.DescribeOnlySource[*directconnect.DescribeHostedConnectionsInput, *directconnect.DescribeHostedConnectionsOutput, *directconnect.Client, *directconnect.Options] { - return &sources.DescribeOnlySource[*directconnect.DescribeHostedConnectionsInput, *directconnect.DescribeHostedConnectionsOutput, *directconnect.Client, *directconnect.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "directconnect-hosted-connection", +func NewHostedConnectionAdapter(client *directconnect.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*directconnect.DescribeHostedConnectionsInput, *directconnect.DescribeHostedConnectionsOutput, *directconnect.Client, *directconnect.Options] { + return &adapters.DescribeOnlyAdapter[*directconnect.DescribeHostedConnectionsInput, *directconnect.DescribeHostedConnectionsOutput, *directconnect.Client, *directconnect.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "directconnect-hosted-connection", + AdapterMetadata: HostedConnectionMetadata(), DescribeFunc: func(ctx context.Context, client *directconnect.Client, input *directconnect.DescribeHostedConnectionsInput) (*directconnect.DescribeHostedConnectionsOutput, error) { return client.DescribeHostedConnections(ctx, input) }, @@ -134,3 +135,21 @@ func NewHostedConnectionSource(client *directconnect.Client, accountID string, r OutputMapper: hostedConnectionOutputMapper, } } + +func HostedConnectionMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "directconnect-hosted-connection", + DescriptiveName: "Hosted Connection", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + Search: true, + GetDescription: "Get a Hosted Connection by connection ID", + SearchDescription: "Search Hosted Connections by Interconnect or LAG ID", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_dx_hosted_connection.id"}, + }, + PotentialLinks: []string{"directconnect-lag", "directconnect-location", "directconnect-loa", "directconnect-virtual-interface"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + } +} diff --git a/sources/directconnect/hosted-connection_test.go b/adapters/directconnect/hosted-connection_test.go similarity index 57% rename from sources/directconnect/hosted-connection_test.go rename to adapters/directconnect/hosted-connection_test.go index cd975831..d2577789 100644 --- a/sources/directconnect/hosted-connection_test.go +++ b/adapters/directconnect/hosted-connection_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/directconnect" "github.com/aws/aws-sdk-go-v2/service/directconnect/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -15,26 +15,26 @@ func TestHostedConnectionOutputMapper(t *testing.T) { output := &directconnect.DescribeHostedConnectionsOutput{ Connections: []types.Connection{ { - AwsDeviceV2: sources.PtrString("EqDC2-123h49s71dabc"), - AwsLogicalDeviceId: sources.PtrString("device-1"), - Bandwidth: sources.PtrString("1Gbps"), - ConnectionId: sources.PtrString("dxcon-fguhmqlc"), - ConnectionName: sources.PtrString("My_Connection"), + AwsDeviceV2: adapters.PtrString("EqDC2-123h49s71dabc"), + AwsLogicalDeviceId: adapters.PtrString("device-1"), + Bandwidth: adapters.PtrString("1Gbps"), + ConnectionId: adapters.PtrString("dxcon-fguhmqlc"), + ConnectionName: adapters.PtrString("My_Connection"), ConnectionState: "down", - EncryptionMode: sources.PtrString("must_encrypt"), + EncryptionMode: adapters.PtrString("must_encrypt"), HasLogicalRedundancy: "unknown", - JumboFrameCapable: sources.PtrBool(true), - LagId: sources.PtrString("dxlag-ffrz71kw"), - LoaIssueTime: sources.PtrTime(time.Now()), - Location: sources.PtrString("EqDC2"), - Region: sources.PtrString("us-east-1"), - ProviderName: sources.PtrString("provider-1"), - OwnerAccount: sources.PtrString("123456789012"), - PartnerName: sources.PtrString("partner-1"), + JumboFrameCapable: adapters.PtrBool(true), + LagId: adapters.PtrString("dxlag-ffrz71kw"), + LoaIssueTime: adapters.PtrTime(time.Now()), + Location: adapters.PtrString("EqDC2"), + Region: adapters.PtrString("us-east-1"), + ProviderName: adapters.PtrString("provider-1"), + OwnerAccount: adapters.PtrString("123456789012"), + PartnerName: adapters.PtrString("partner-1"), Tags: []types.Tag{ { - Key: sources.PtrString("foo"), - Value: sources.PtrString("bar"), + Key: adapters.PtrString("foo"), + Value: adapters.PtrString("bar"), }, }, }, @@ -58,7 +58,7 @@ func TestHostedConnectionOutputMapper(t *testing.T) { item := items[0] - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "directconnect-lag", ExpectedMethod: sdp.QueryMethod_GET, @@ -88,13 +88,13 @@ func TestHostedConnectionOutputMapper(t *testing.T) { tests.Execute(t, item) } -func TestNewHostedConnectionSource(t *testing.T) { +func TestNewHostedConnectionAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewHostedConnectionSource(client, account, region) + adapter := NewHostedConnectionAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, SkipList: true, } diff --git a/sources/directconnect/interconnect.go b/adapters/directconnect/interconnect.go similarity index 76% rename from sources/directconnect/interconnect.go rename to adapters/directconnect/interconnect.go index 2a228129..fa30bf13 100644 --- a/sources/directconnect/interconnect.go +++ b/adapters/directconnect/interconnect.go @@ -6,7 +6,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/directconnect/types" "github.com/aws/aws-sdk-go-v2/service/directconnect" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -14,7 +14,7 @@ func interconnectOutputMapper(_ context.Context, _ *directconnect.Client, scope items := make([]*sdp.Item, 0) for _, interconnect := range output.Interconnects { - attributes, err := sources.ToAttributesWithExclude(interconnect, "tags") + attributes, err := adapters.ToAttributesWithExclude(interconnect, "tags") if err != nil { return nil, err } @@ -130,12 +130,13 @@ func interconnectOutputMapper(_ context.Context, _ *directconnect.Client, scope // +overmind:search Search Interconnects by ARN // +overmind:group AWS -func NewInterconnectSource(client *directconnect.Client, accountID string, region string) *sources.DescribeOnlySource[*directconnect.DescribeInterconnectsInput, *directconnect.DescribeInterconnectsOutput, *directconnect.Client, *directconnect.Options] { - return &sources.DescribeOnlySource[*directconnect.DescribeInterconnectsInput, *directconnect.DescribeInterconnectsOutput, *directconnect.Client, *directconnect.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "directconnect-interconnect", +func NewInterconnectAdapter(client *directconnect.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*directconnect.DescribeInterconnectsInput, *directconnect.DescribeInterconnectsOutput, *directconnect.Client, *directconnect.Options] { + return &adapters.DescribeOnlyAdapter[*directconnect.DescribeInterconnectsInput, *directconnect.DescribeInterconnectsOutput, *directconnect.Client, *directconnect.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "directconnect-interconnect", + AdapterMetadata: InterconnectMetadata(), DescribeFunc: func(ctx context.Context, client *directconnect.Client, input *directconnect.DescribeInterconnectsInput) (*directconnect.DescribeInterconnectsOutput, error) { return client.DescribeInterconnects(ctx, input) }, @@ -150,3 +151,20 @@ func NewInterconnectSource(client *directconnect.Client, accountID string, regio OutputMapper: interconnectOutputMapper, } } + +func InterconnectMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "directconnect-interconnect", + DescriptiveName: "Interconnect", + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + PotentialLinks: []string{"directconnect-hosted-connection", "directconnect-lag", "directconnect-loa", "directconnect-location"}, + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a Interconnect by InterconnectId", + ListDescription: "List all Interconnects", + SearchDescription: "Search Interconnects by ARN", + }, + } +} diff --git a/sources/directconnect/interconnect_test.go b/adapters/directconnect/interconnect_test.go similarity index 75% rename from sources/directconnect/interconnect_test.go rename to adapters/directconnect/interconnect_test.go index c833087c..572c75da 100644 --- a/sources/directconnect/interconnect_test.go +++ b/adapters/directconnect/interconnect_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/directconnect" "github.com/aws/aws-sdk-go-v2/service/directconnect/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -15,23 +15,23 @@ func TestInterconnectOutputMapper(t *testing.T) { output := &directconnect.DescribeInterconnectsOutput{ Interconnects: []types.Interconnect{ { - AwsDeviceV2: sources.PtrString("EqDC2-123h49s71dabc"), - AwsLogicalDeviceId: sources.PtrString("device-1"), - Bandwidth: sources.PtrString("1Gbps"), + AwsDeviceV2: adapters.PtrString("EqDC2-123h49s71dabc"), + AwsLogicalDeviceId: adapters.PtrString("device-1"), + Bandwidth: adapters.PtrString("1Gbps"), HasLogicalRedundancy: types.HasLogicalRedundancyUnknown, - InterconnectId: sources.PtrString("dxcon-fguhmqlc"), - InterconnectName: sources.PtrString("interconnect-1"), + InterconnectId: adapters.PtrString("dxcon-fguhmqlc"), + InterconnectName: adapters.PtrString("interconnect-1"), InterconnectState: types.InterconnectStateAvailable, - JumboFrameCapable: sources.PtrBool(true), - LagId: sources.PtrString("dxlag-ffrz71kw"), - LoaIssueTime: sources.PtrTime(time.Now()), - Location: sources.PtrString("EqDC2"), - Region: sources.PtrString("us-east-1"), - ProviderName: sources.PtrString("provider-1"), + JumboFrameCapable: adapters.PtrBool(true), + LagId: adapters.PtrString("dxlag-ffrz71kw"), + LoaIssueTime: adapters.PtrTime(time.Now()), + Location: adapters.PtrString("EqDC2"), + Region: adapters.PtrString("us-east-1"), + ProviderName: adapters.PtrString("provider-1"), Tags: []types.Tag{ { - Key: sources.PtrString("foo"), - Value: sources.PtrString("bar"), + Key: adapters.PtrString("foo"), + Value: adapters.PtrString("bar"), }, }, }, @@ -55,7 +55,7 @@ func TestInterconnectOutputMapper(t *testing.T) { item := items[0] - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "directconnect-lag", ExpectedMethod: sdp.QueryMethod_GET, @@ -125,7 +125,7 @@ func TestInterconnectHealth(t *testing.T) { Interconnects: []types.Interconnect{ { InterconnectState: c.state, - LagId: sources.PtrString("dxlag-fgsu9erb"), + LagId: adapters.PtrString("dxlag-fgsu9erb"), }, }, } @@ -147,13 +147,13 @@ func TestInterconnectHealth(t *testing.T) { } } -func TestNewInterconnectSource(t *testing.T) { +func TestNewInterconnectAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewInterconnectSource(client, account, region) + adapter := NewInterconnectAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, // Listing these in our test account gives "An error occurred // (DirectConnectClientException) when calling the DescribeInterconnects diff --git a/sources/directconnect/lag.go b/adapters/directconnect/lag.go similarity index 73% rename from sources/directconnect/lag.go rename to adapters/directconnect/lag.go index e61ce8cb..9f39e19c 100644 --- a/sources/directconnect/lag.go +++ b/adapters/directconnect/lag.go @@ -6,7 +6,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/directconnect/types" "github.com/aws/aws-sdk-go-v2/service/directconnect" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -14,7 +14,7 @@ func lagOutputMapper(_ context.Context, _ *directconnect.Client, scope string, _ items := make([]*sdp.Item, 0) for _, lag := range output.Lags { - attributes, err := sources.ToAttributesWithExclude(lag, "tags") + attributes, err := adapters.ToAttributesWithExclude(lag, "tags") if err != nil { return nil, err } @@ -116,12 +116,13 @@ func lagOutputMapper(_ context.Context, _ *directconnect.Client, scope string, _ // +overmind:group AWS // +overmind:terraform:queryMap aws_dx_lag.id -func NewLagSource(client *directconnect.Client, accountID string, region string) *sources.DescribeOnlySource[*directconnect.DescribeLagsInput, *directconnect.DescribeLagsOutput, *directconnect.Client, *directconnect.Options] { - return &sources.DescribeOnlySource[*directconnect.DescribeLagsInput, *directconnect.DescribeLagsOutput, *directconnect.Client, *directconnect.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "directconnect-lag", +func NewLagAdapter(client *directconnect.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*directconnect.DescribeLagsInput, *directconnect.DescribeLagsOutput, *directconnect.Client, *directconnect.Options] { + return &adapters.DescribeOnlyAdapter[*directconnect.DescribeLagsInput, *directconnect.DescribeLagsOutput, *directconnect.Client, *directconnect.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "directconnect-lag", + AdapterMetadata: LagMetadata(), DescribeFunc: func(ctx context.Context, client *directconnect.Client, input *directconnect.DescribeLagsInput) (*directconnect.DescribeLagsOutput, error) { return client.DescribeLags(ctx, input) }, @@ -136,3 +137,23 @@ func NewLagSource(client *directconnect.Client, accountID string, region string) OutputMapper: lagOutputMapper, } } + +func LagMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "directconnect-lag", + DescriptiveName: "Link Aggregation Group", + PotentialLinks: []string{"directconnect-connection", "directconnect-hosted-connection", "directconnect-location"}, + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a Link Aggregation Group by ID", + ListDescription: "List all Link Aggregation Groups", + SearchDescription: "Search Link Aggregation Group by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_dx_lag.id"}, + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + } +} diff --git a/sources/directconnect/lag_test.go b/adapters/directconnect/lag_test.go similarity index 65% rename from sources/directconnect/lag_test.go rename to adapters/directconnect/lag_test.go index ac6f3d54..41859866 100644 --- a/sources/directconnect/lag_test.go +++ b/adapters/directconnect/lag_test.go @@ -5,11 +5,11 @@ import ( "testing" "time" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" "github.com/aws/aws-sdk-go-v2/service/directconnect" "github.com/aws/aws-sdk-go-v2/service/directconnect/types" - "github.com/overmindtech/aws-source/sources" ) func TestLagHealth(t *testing.T) { @@ -52,7 +52,7 @@ func TestLagHealth(t *testing.T) { Lags: []types.Lag{ { LagState: c.state, - LagId: sources.PtrString("dxlag-fgsu9erb"), + LagId: adapters.PtrString("dxlag-fgsu9erb"), }, }, } @@ -78,38 +78,38 @@ func TestLagOutputMapper(t *testing.T) { output := &directconnect.DescribeLagsOutput{ Lags: []types.Lag{ { - AwsDeviceV2: sources.PtrString("EqDC2-19y7z3m17xpuz"), + AwsDeviceV2: adapters.PtrString("EqDC2-19y7z3m17xpuz"), NumberOfConnections: int32(2), LagState: types.LagStateAvailable, - OwnerAccount: sources.PtrString("123456789012"), - LagName: sources.PtrString("DA-LAG"), + OwnerAccount: adapters.PtrString("123456789012"), + LagName: adapters.PtrString("DA-LAG"), Connections: []types.Connection{ { - OwnerAccount: sources.PtrString("123456789012"), - ConnectionId: sources.PtrString("dxcon-ffnikghc"), - LagId: sources.PtrString("dxlag-fgsu9erb"), + OwnerAccount: adapters.PtrString("123456789012"), + ConnectionId: adapters.PtrString("dxcon-ffnikghc"), + LagId: adapters.PtrString("dxlag-fgsu9erb"), ConnectionState: "requested", - Bandwidth: sources.PtrString("10Gbps"), - Location: sources.PtrString("EqDC2"), - ConnectionName: sources.PtrString("Requested Connection 1 for Lag dxlag-fgsu9erb"), - Region: sources.PtrString("us-east-1"), + Bandwidth: adapters.PtrString("10Gbps"), + Location: adapters.PtrString("EqDC2"), + ConnectionName: adapters.PtrString("Requested Connection 1 for Lag dxlag-fgsu9erb"), + Region: adapters.PtrString("us-east-1"), }, { - OwnerAccount: sources.PtrString("123456789012"), - ConnectionId: sources.PtrString("dxcon-fglgbdea"), - LagId: sources.PtrString("dxlag-fgsu9erb"), + OwnerAccount: adapters.PtrString("123456789012"), + ConnectionId: adapters.PtrString("dxcon-fglgbdea"), + LagId: adapters.PtrString("dxlag-fgsu9erb"), ConnectionState: "requested", - Bandwidth: sources.PtrString("10Gbps"), - Location: sources.PtrString("EqDC2"), - ConnectionName: sources.PtrString("Requested Connection 2 for Lag dxlag-fgsu9erb"), - Region: sources.PtrString("us-east-1"), + Bandwidth: adapters.PtrString("10Gbps"), + Location: adapters.PtrString("EqDC2"), + ConnectionName: adapters.PtrString("Requested Connection 2 for Lag dxlag-fgsu9erb"), + Region: adapters.PtrString("us-east-1"), }, }, - LagId: sources.PtrString("dxlag-fgsu9erb"), + LagId: adapters.PtrString("dxlag-fgsu9erb"), MinimumLinks: int32(0), - ConnectionsBandwidth: sources.PtrString("10Gbps"), - Region: sources.PtrString("us-east-1"), - Location: sources.PtrString("EqDC2"), + ConnectionsBandwidth: adapters.PtrString("10Gbps"), + Region: adapters.PtrString("us-east-1"), + Location: adapters.PtrString("EqDC2"), }, }, } @@ -135,7 +135,7 @@ func TestLagOutputMapper(t *testing.T) { t.Fatalf("expected health to be OK, got: %v", item.GetHealth()) } - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "directconnect-connection", ExpectedMethod: sdp.QueryMethod_GET, @@ -165,13 +165,13 @@ func TestLagOutputMapper(t *testing.T) { tests.Execute(t, item) } -func TestNewLagSource(t *testing.T) { +func TestNewLagAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewLagSource(client, account, region) + adapter := NewLagAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/directconnect/location.go b/adapters/directconnect/location.go similarity index 55% rename from sources/directconnect/location.go rename to adapters/directconnect/location.go index da5c04bf..75d1f80e 100644 --- a/sources/directconnect/location.go +++ b/adapters/directconnect/location.go @@ -4,7 +4,7 @@ import ( "context" "github.com/aws/aws-sdk-go-v2/service/directconnect" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -12,7 +12,7 @@ func locationOutputMapper(_ context.Context, _ *directconnect.Client, scope stri items := make([]*sdp.Item, 0) for _, location := range output.Locations { - attributes, err := sources.ToAttributesWithExclude(location, "tags") + attributes, err := adapters.ToAttributesWithExclude(location, "tags") if err != nil { return nil, err } @@ -39,12 +39,13 @@ func locationOutputMapper(_ context.Context, _ *directconnect.Client, scope stri // +overmind:group AWS // +overmind:terraform:queryMap aws_dx_location.location_code -func NewLocationSource(client *directconnect.Client, accountID string, region string) *sources.DescribeOnlySource[*directconnect.DescribeLocationsInput, *directconnect.DescribeLocationsOutput, *directconnect.Client, *directconnect.Options] { - return &sources.DescribeOnlySource[*directconnect.DescribeLocationsInput, *directconnect.DescribeLocationsOutput, *directconnect.Client, *directconnect.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "directconnect-location", +func NewLocationAdapter(client *directconnect.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*directconnect.DescribeLocationsInput, *directconnect.DescribeLocationsOutput, *directconnect.Client, *directconnect.Options] { + return &adapters.DescribeOnlyAdapter[*directconnect.DescribeLocationsInput, *directconnect.DescribeLocationsOutput, *directconnect.Client, *directconnect.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "directconnect-location", + AdapterMetadata: LocationMetadata(), DescribeFunc: func(ctx context.Context, client *directconnect.Client, input *directconnect.DescribeLocationsInput) (*directconnect.DescribeLocationsOutput, error) { return client.DescribeLocations(ctx, input) }, @@ -59,3 +60,22 @@ func NewLocationSource(client *directconnect.Client, accountID string, region st OutputMapper: locationOutputMapper, } } + +func LocationMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "directconnect-location", + DescriptiveName: "Direct Connect Location", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a Location by its code", + ListDescription: "List all Direct Connect Locations", + SearchDescription: "Search Direct Connect Locations by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_dx_location.location_code"}, + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + } +} diff --git a/sources/directconnect/location_test.go b/adapters/directconnect/location_test.go similarity index 69% rename from sources/directconnect/location_test.go rename to adapters/directconnect/location_test.go index 8c5cdb9f..b937a8a1 100644 --- a/sources/directconnect/location_test.go +++ b/adapters/directconnect/location_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/directconnect" "github.com/aws/aws-sdk-go-v2/service/directconnect/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" ) func TestLocationOutputMapper(t *testing.T) { @@ -17,9 +17,9 @@ func TestLocationOutputMapper(t *testing.T) { AvailableMacSecPortSpeeds: []string{"1 Gbps", "10 Gbps"}, AvailablePortSpeeds: []string{"50 Mbps", "100 Mbps", "1 Gbps", "10 Gbps"}, AvailableProviders: []string{"ProviderA", "ProviderB", "ProviderC"}, - LocationName: sources.PtrString("NAP do Brasil, Barueri, Sao Paulo"), - LocationCode: sources.PtrString("TNDB"), - Region: sources.PtrString("us-east-1"), + LocationName: adapters.PtrString("NAP do Brasil, Barueri, Sao Paulo"), + LocationCode: adapters.PtrString("TNDB"), + Region: adapters.PtrString("us-east-1"), }, }, } @@ -40,13 +40,13 @@ func TestLocationOutputMapper(t *testing.T) { } } -func TestNewLocationSource(t *testing.T) { +func TestNewLocationAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewLocationSource(client, account, region) + adapter := NewLocationAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/directconnect/router-configuration.go b/adapters/directconnect/router-configuration.go similarity index 57% rename from sources/directconnect/router-configuration.go rename to adapters/directconnect/router-configuration.go index ecefe558..da175262 100644 --- a/sources/directconnect/router-configuration.go +++ b/adapters/directconnect/router-configuration.go @@ -4,7 +4,7 @@ import ( "context" "github.com/aws/aws-sdk-go-v2/service/directconnect" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -13,7 +13,7 @@ func routerConfigurationOutputMapper(_ context.Context, _ *directconnect.Client, return nil, nil } - attributes, err := sources.ToAttributesWithExclude(output, "tags") + attributes, err := adapters.ToAttributesWithExclude(output, "tags") if err != nil { return nil, err } @@ -55,12 +55,13 @@ func routerConfigurationOutputMapper(_ context.Context, _ *directconnect.Client, // +overmind:group AWS // +overmind:terraform:queryMap aws_dx_router_configuration.virtual_interface_id -func NewRouterConfigurationSource(client *directconnect.Client, accountID string, region string) *sources.DescribeOnlySource[*directconnect.DescribeRouterConfigurationInput, *directconnect.DescribeRouterConfigurationOutput, *directconnect.Client, *directconnect.Options] { - return &sources.DescribeOnlySource[*directconnect.DescribeRouterConfigurationInput, *directconnect.DescribeRouterConfigurationOutput, *directconnect.Client, *directconnect.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "directconnect-router-configuration", +func NewRouterConfigurationAdapter(client *directconnect.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*directconnect.DescribeRouterConfigurationInput, *directconnect.DescribeRouterConfigurationOutput, *directconnect.Client, *directconnect.Options] { + return &adapters.DescribeOnlyAdapter[*directconnect.DescribeRouterConfigurationInput, *directconnect.DescribeRouterConfigurationOutput, *directconnect.Client, *directconnect.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "directconnect-router-configuration", + AdapterMetadata: RouterConfigurationSourceMetadata(), DescribeFunc: func(ctx context.Context, client *directconnect.Client, input *directconnect.DescribeRouterConfigurationInput) (*directconnect.DescribeRouterConfigurationOutput, error) { return client.DescribeRouterConfiguration(ctx, input) }, @@ -72,3 +73,21 @@ func NewRouterConfigurationSource(client *directconnect.Client, accountID string OutputMapper: routerConfigurationOutputMapper, } } + +func RouterConfigurationSourceMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "directconnect-router-configuration", + DescriptiveName: "Router Configuration", + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_CONFIGURATION, + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + Search: true, + GetDescription: "Get a Router Configuration by Virtual Interface ID", + SearchDescription: "Search Router Configuration by ARN", + }, + PotentialLinks: []string{"directconnect-virtual-interface"}, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_dx_router_configuration.virtual_interface_id"}, + }, + } +} diff --git a/sources/directconnect/router-configuration_test.go b/adapters/directconnect/router-configuration_test.go similarity index 53% rename from sources/directconnect/router-configuration_test.go rename to adapters/directconnect/router-configuration_test.go index db6f32ad..2535bdc9 100644 --- a/sources/directconnect/router-configuration_test.go +++ b/adapters/directconnect/router-configuration_test.go @@ -7,23 +7,23 @@ import ( "github.com/aws/aws-sdk-go-v2/service/directconnect" "github.com/aws/aws-sdk-go-v2/service/directconnect/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) func TestRouterConfigurationOutputMapper(t *testing.T) { output := &directconnect.DescribeRouterConfigurationOutput{ - CustomerRouterConfig: sources.PtrString("some config"), + CustomerRouterConfig: adapters.PtrString("some config"), Router: &types.RouterType{ - Platform: sources.PtrString("2900 Series Routers"), - RouterTypeIdentifier: sources.PtrString("CiscoSystemsInc-2900SeriesRouters-IOS124"), - Software: sources.PtrString("IOS 12.4+"), - Vendor: sources.PtrString("Cisco Systems, Inc."), - XsltTemplateName: sources.PtrString("customer-router-cisco-generic.xslt"), - XsltTemplateNameForMacSec: sources.PtrString(""), + Platform: adapters.PtrString("2900 Series Routers"), + RouterTypeIdentifier: adapters.PtrString("CiscoSystemsInc-2900SeriesRouters-IOS124"), + Software: adapters.PtrString("IOS 12.4+"), + Vendor: adapters.PtrString("Cisco Systems, Inc."), + XsltTemplateName: adapters.PtrString("customer-router-cisco-generic.xslt"), + XsltTemplateNameForMacSec: adapters.PtrString(""), }, - VirtualInterfaceId: sources.PtrString("dxvif-ffhhk74f"), - VirtualInterfaceName: sources.PtrString("PrivateVirtualInterface"), + VirtualInterfaceId: adapters.PtrString("dxvif-ffhhk74f"), + VirtualInterfaceName: adapters.PtrString("PrivateVirtualInterface"), } items, err := routerConfigurationOutputMapper(context.Background(), nil, "foo", nil, output) @@ -43,7 +43,7 @@ func TestRouterConfigurationOutputMapper(t *testing.T) { item := items[0] - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "directconnect-virtual-interface", ExpectedMethod: sdp.QueryMethod_GET, @@ -55,13 +55,13 @@ func TestRouterConfigurationOutputMapper(t *testing.T) { tests.Execute(t, item) } -func TestNewRouterConfigurationSource(t *testing.T) { +func TestNewRouterConfigurationAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewRouterConfigurationSource(client, account, region) + adapter := NewRouterConfigurationAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, SkipList: true, } diff --git a/sources/directconnect/shared.go b/adapters/directconnect/shared.go similarity index 100% rename from sources/directconnect/shared.go rename to adapters/directconnect/shared.go diff --git a/sources/directconnect/shared_test.go b/adapters/directconnect/shared_test.go similarity index 71% rename from sources/directconnect/shared_test.go rename to adapters/directconnect/shared_test.go index 3671f946..600d4fd1 100644 --- a/sources/directconnect/shared_test.go +++ b/adapters/directconnect/shared_test.go @@ -4,11 +4,11 @@ import ( "testing" "github.com/aws/aws-sdk-go-v2/service/directconnect" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" ) func GetAutoConfig(t *testing.T) (*directconnect.Client, string, string) { - config, account, region := sources.GetAutoConfig(t) + config, account, region := adapters.GetAutoConfig(t) client := directconnect.NewFromConfig(config) return client, account, region diff --git a/sources/directconnect/virtual-gateway.go b/adapters/directconnect/virtual-gateway.go similarity index 57% rename from sources/directconnect/virtual-gateway.go rename to adapters/directconnect/virtual-gateway.go index 8171ade8..21293815 100644 --- a/sources/directconnect/virtual-gateway.go +++ b/adapters/directconnect/virtual-gateway.go @@ -4,7 +4,7 @@ import ( "context" "github.com/aws/aws-sdk-go-v2/service/directconnect" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -12,7 +12,7 @@ func virtualGatewayOutputMapper(_ context.Context, _ *directconnect.Client, scop items := make([]*sdp.Item, 0) for _, virtualGateway := range output.VirtualGateways { - attributes, err := sources.ToAttributesWithExclude(virtualGateway, "tags") + attributes, err := adapters.ToAttributesWithExclude(virtualGateway, "tags") if err != nil { return nil, err } @@ -38,12 +38,13 @@ func virtualGatewayOutputMapper(_ context.Context, _ *directconnect.Client, scop // +overmind:search Search virtual gateways by ARN // +overmind:group AWS -func NewVirtualGatewaySource(client *directconnect.Client, accountID string, region string) *sources.DescribeOnlySource[*directconnect.DescribeVirtualGatewaysInput, *directconnect.DescribeVirtualGatewaysOutput, *directconnect.Client, *directconnect.Options] { - return &sources.DescribeOnlySource[*directconnect.DescribeVirtualGatewaysInput, *directconnect.DescribeVirtualGatewaysOutput, *directconnect.Client, *directconnect.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "directconnect-virtual-gateway", +func NewVirtualGatewayAdapter(client *directconnect.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*directconnect.DescribeVirtualGatewaysInput, *directconnect.DescribeVirtualGatewaysOutput, *directconnect.Client, *directconnect.Options] { + return &adapters.DescribeOnlyAdapter[*directconnect.DescribeVirtualGatewaysInput, *directconnect.DescribeVirtualGatewaysOutput, *directconnect.Client, *directconnect.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "directconnect-virtual-gateway", + AdapterMetadata: VirtualGatewayMetadata(), DescribeFunc: func(ctx context.Context, client *directconnect.Client, input *directconnect.DescribeVirtualGatewaysInput) (*directconnect.DescribeVirtualGatewaysOutput, error) { return client.DescribeVirtualGateways(ctx, input) }, @@ -58,3 +59,19 @@ func NewVirtualGatewaySource(client *directconnect.Client, accountID string, reg OutputMapper: virtualGatewayOutputMapper, } } + +func VirtualGatewayMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "directconnect-virtual-gateway", + DescriptiveName: "Direct Connect Virtual Gateway", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a virtual gateway by ID", + ListDescription: "List all virtual gateways", + SearchDescription: "Search virtual gateways by ARN", + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + } +} diff --git a/sources/directconnect/virtual-gateway_test.go b/adapters/directconnect/virtual-gateway_test.go similarity index 68% rename from sources/directconnect/virtual-gateway_test.go rename to adapters/directconnect/virtual-gateway_test.go index 6abaf18a..7a39cf31 100644 --- a/sources/directconnect/virtual-gateway_test.go +++ b/adapters/directconnect/virtual-gateway_test.go @@ -7,15 +7,15 @@ import ( "github.com/aws/aws-sdk-go-v2/service/directconnect" "github.com/aws/aws-sdk-go-v2/service/directconnect/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" ) func TestVirtualGatewayOutputMapper(t *testing.T) { output := &directconnect.DescribeVirtualGatewaysOutput{ VirtualGateways: []types.VirtualGateway{ { - VirtualGatewayId: sources.PtrString("cf68415c-f4ae-48f2-87a7-3b52cexample"), - VirtualGatewayState: sources.PtrString("available"), + VirtualGatewayId: adapters.PtrString("cf68415c-f4ae-48f2-87a7-3b52cexample"), + VirtualGatewayState: adapters.PtrString("available"), }, }, } @@ -36,13 +36,13 @@ func TestVirtualGatewayOutputMapper(t *testing.T) { } } -func TestNewVirtualGatewaySource(t *testing.T) { +func TestNewVirtualGatewayAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewVirtualGatewaySource(client, account, region) + adapter := NewVirtualGatewayAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/directconnect/virtual-interface.go b/adapters/directconnect/virtual-interface.go similarity index 77% rename from sources/directconnect/virtual-interface.go rename to adapters/directconnect/virtual-interface.go index 45db715b..0f9a1f82 100644 --- a/sources/directconnect/virtual-interface.go +++ b/adapters/directconnect/virtual-interface.go @@ -5,7 +5,7 @@ import ( "fmt" "github.com/aws/aws-sdk-go-v2/service/directconnect" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -15,7 +15,7 @@ func virtualInterfaceOutputMapper(_ context.Context, _ *directconnect.Client, sc items := make([]*sdp.Item, 0) for _, virtualInterface := range output.VirtualInterfaces { - attributes, err := sources.ToAttributesWithExclude(virtualInterface, "tags") + attributes, err := adapters.ToAttributesWithExclude(virtualInterface, "tags") if err != nil { return nil, err } @@ -157,12 +157,13 @@ func virtualInterfaceOutputMapper(_ context.Context, _ *directconnect.Client, sc // +overmind:terraform:queryMap aws_dx_public_virtual_interface.id // +overmind:terraform:queryMap aws_dx_transit_virtual_interface.id -func NewVirtualInterfaceSource(client *directconnect.Client, accountID string, region string) *sources.DescribeOnlySource[*directconnect.DescribeVirtualInterfacesInput, *directconnect.DescribeVirtualInterfacesOutput, *directconnect.Client, *directconnect.Options] { - return &sources.DescribeOnlySource[*directconnect.DescribeVirtualInterfacesInput, *directconnect.DescribeVirtualInterfacesOutput, *directconnect.Client, *directconnect.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "directconnect-virtual-interface", +func NewVirtualInterfaceAdapter(client *directconnect.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*directconnect.DescribeVirtualInterfacesInput, *directconnect.DescribeVirtualInterfacesOutput, *directconnect.Client, *directconnect.Options] { + return &adapters.DescribeOnlyAdapter[*directconnect.DescribeVirtualInterfacesInput, *directconnect.DescribeVirtualInterfacesOutput, *directconnect.Client, *directconnect.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "directconnect-virtual-interface", + AdapterMetadata: VirtualInterfaceMetadata(), DescribeFunc: func(ctx context.Context, client *directconnect.Client, input *directconnect.DescribeVirtualInterfacesInput) (*directconnect.DescribeVirtualInterfacesOutput, error) { return client.DescribeVirtualInterfaces(ctx, input) }, @@ -182,3 +183,25 @@ func NewVirtualInterfaceSource(client *directconnect.Client, accountID string, r }, } } + +func VirtualInterfaceMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "directconnect-virtual-interface", + DescriptiveName: "Virtual Interface", + PotentialLinks: []string{"directconnect-connection", "directconnect-direct-connect-gateway", "rdap-ip-network", "directconnect-direct-connect-gateway-attachment", "directconnect-virtual-interface"}, + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a virtual interface by ID", + ListDescription: "List all virtual interfaces", + SearchDescription: "Search virtual interfaces by connection ID", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_dx_private_virtual_interface.id"}, + {TerraformQueryMap: "aws_dx_public_virtual_interface.id"}, + {TerraformQueryMap: "aws_dx_transit_virtual_interface.id"}, + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + } +} diff --git a/sources/directconnect/virtual-interface_test.go b/adapters/directconnect/virtual-interface_test.go similarity index 73% rename from sources/directconnect/virtual-interface_test.go rename to adapters/directconnect/virtual-interface_test.go index 19b44715..ecf09945 100644 --- a/sources/directconnect/virtual-interface_test.go +++ b/adapters/directconnect/virtual-interface_test.go @@ -8,7 +8,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/directconnect" "github.com/aws/aws-sdk-go-v2/service/directconnect/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -16,14 +16,14 @@ func TestVirtualInterfaceOutputMapper(t *testing.T) { output := &directconnect.DescribeVirtualInterfacesOutput{ VirtualInterfaces: []types.VirtualInterface{ { - VirtualInterfaceId: sources.PtrString("dxvif-ffhhk74f"), - ConnectionId: sources.PtrString("dxcon-fguhmqlc"), + VirtualInterfaceId: adapters.PtrString("dxvif-ffhhk74f"), + ConnectionId: adapters.PtrString("dxcon-fguhmqlc"), VirtualInterfaceState: "verifying", - CustomerAddress: sources.PtrString("192.168.1.2/30"), - AmazonAddress: sources.PtrString("192.168.1.1/30"), - VirtualInterfaceType: sources.PtrString("private"), - VirtualInterfaceName: sources.PtrString("PrivateVirtualInterface"), - DirectConnectGatewayId: sources.PtrString("cf68415c-f4ae-48f2-87a7-3b52cexample"), + CustomerAddress: adapters.PtrString("192.168.1.2/30"), + AmazonAddress: adapters.PtrString("192.168.1.1/30"), + VirtualInterfaceType: adapters.PtrString("private"), + VirtualInterfaceName: adapters.PtrString("PrivateVirtualInterface"), + DirectConnectGatewayId: adapters.PtrString("cf68415c-f4ae-48f2-87a7-3b52cexample"), }, }, } @@ -45,7 +45,7 @@ func TestVirtualInterfaceOutputMapper(t *testing.T) { item := items[0] - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "directconnect-connection", ExpectedMethod: sdp.QueryMethod_GET, @@ -87,13 +87,13 @@ func TestVirtualInterfaceOutputMapper(t *testing.T) { tests.Execute(t, item) } -func TestNewVirtualInterfaceSource(t *testing.T) { +func TestNewVirtualInterfaceAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewVirtualInterfaceSource(client, account, region) + adapter := NewVirtualInterfaceAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/dynamodb/backup.go b/adapters/dynamodb/backup.go similarity index 83% rename from sources/dynamodb/backup.go rename to adapters/dynamodb/backup.go index c8dc3ceb..92bc3dd9 100644 --- a/sources/dynamodb/backup.go +++ b/adapters/dynamodb/backup.go @@ -5,7 +5,7 @@ import ( "fmt" "github.com/aws/aws-sdk-go-v2/service/dynamodb" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -32,7 +32,7 @@ func backupGetFunc(ctx context.Context, client Client, scope string, input *dyna details := out.BackupDescription.BackupDetails - attributes, err := sources.ToAttributesWithExclude(details) + attributes, err := adapters.ToAttributesWithExclude(details) if err != nil { return nil, err @@ -77,18 +77,19 @@ func backupGetFunc(ctx context.Context, client Client, scope string, input *dyna // +overmind:search Search for a DynamoDB backup by table name // +overmind:group AWS -// NewBackupSource This source is a bit strange. This is the only thing I've +// NewBackupAdapter This adapter is a bit strange. This is the only thing I've // found so far that can only be queries by ARN for Get. For this reason I'm // going to just disable GET. LIST works fine and allows it to be linked to the // table so this is enough for me at the moment -func NewBackupSource(client Client, accountID string, region string) *sources.AlwaysGetSource[*dynamodb.ListBackupsInput, *dynamodb.ListBackupsOutput, *dynamodb.DescribeBackupInput, *dynamodb.DescribeBackupOutput, Client, *dynamodb.Options] { - return &sources.AlwaysGetSource[*dynamodb.ListBackupsInput, *dynamodb.ListBackupsOutput, *dynamodb.DescribeBackupInput, *dynamodb.DescribeBackupOutput, Client, *dynamodb.Options]{ - ItemType: "dynamodb-backup", - Client: client, - AccountID: accountID, - Region: region, - GetFunc: backupGetFunc, - ListInput: &dynamodb.ListBackupsInput{}, +func NewBackupAdapter(client Client, accountID string, region string) *adapters.AlwaysGetAdapter[*dynamodb.ListBackupsInput, *dynamodb.ListBackupsOutput, *dynamodb.DescribeBackupInput, *dynamodb.DescribeBackupOutput, Client, *dynamodb.Options] { + return &adapters.AlwaysGetAdapter[*dynamodb.ListBackupsInput, *dynamodb.ListBackupsOutput, *dynamodb.DescribeBackupInput, *dynamodb.DescribeBackupOutput, Client, *dynamodb.Options]{ + ItemType: "dynamodb-backup", + Client: client, + AccountID: accountID, + Region: region, + GetFunc: backupGetFunc, + ListInput: &dynamodb.ListBackupsInput{}, + AdapterMetadata: BackupMetadata(), GetInputMapper: func(scope, query string) *dynamodb.DescribeBackupInput { // Get is not supported since you can't search by name return nil @@ -106,7 +107,7 @@ func NewBackupSource(client Client, accountID string, region string) *sources.Al return inputs, nil }, - ListFuncPaginatorBuilder: func(client Client, input *dynamodb.ListBackupsInput) sources.Paginator[*dynamodb.ListBackupsOutput, *dynamodb.Options] { + ListFuncPaginatorBuilder: func(client Client, input *dynamodb.ListBackupsInput) adapters.Paginator[*dynamodb.ListBackupsOutput, *dynamodb.Options] { return NewListBackupsPaginator(client, input) }, SearchInputMapper: func(scope, query string) (*dynamodb.ListBackupsInput, error) { @@ -118,6 +119,21 @@ func NewBackupSource(client Client, accountID string, region string) *sources.Al } } +func BackupMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "dynamodb-backup", + DescriptiveName: "DynamoDB Backup", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + List: true, + Search: true, + ListDescription: "List all DynamoDB backups", + SearchDescription: "Search for a DynamoDB backup by table name", + }, + PotentialLinks: []string{"dynamodb-table"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_DATABASE, + } +} + // Another AWS API that doesn't provide a paginator *and* does pagination // completely differently from everything else? You don't say. // diff --git a/sources/dynamodb/backup_test.go b/adapters/dynamodb/backup_test.go similarity index 54% rename from sources/dynamodb/backup_test.go rename to adapters/dynamodb/backup_test.go index 9c1f6dcc..d96f84fc 100644 --- a/sources/dynamodb/backup_test.go +++ b/adapters/dynamodb/backup_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/dynamodb" "github.com/aws/aws-sdk-go-v2/service/dynamodb/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -15,43 +15,43 @@ func (t *TestClient) DescribeBackup(ctx context.Context, params *dynamodb.Descri return &dynamodb.DescribeBackupOutput{ BackupDescription: &types.BackupDescription{ BackupDetails: &types.BackupDetails{ - BackupArn: sources.PtrString("arn:aws:dynamodb:eu-west-1:052392120703:table/test2/backup/01673461724486-a6007753"), - BackupName: sources.PtrString("test2-backup"), - BackupSizeBytes: sources.PtrInt64(0), + BackupArn: adapters.PtrString("arn:aws:dynamodb:eu-west-1:052392120703:table/test2/backup/01673461724486-a6007753"), + BackupName: adapters.PtrString("test2-backup"), + BackupSizeBytes: adapters.PtrInt64(0), BackupStatus: types.BackupStatusAvailable, BackupType: types.BackupTypeUser, - BackupCreationDateTime: sources.PtrTime(time.Now()), + BackupCreationDateTime: adapters.PtrTime(time.Now()), }, SourceTableDetails: &types.SourceTableDetails{ - TableName: sources.PtrString("test2"), // link - TableId: sources.PtrString("12670f3b-8ca1-463b-b15e-f2e27eaf70b0"), - TableArn: sources.PtrString("arn:aws:dynamodb:eu-west-1:052392120703:table/test2"), - TableSizeBytes: sources.PtrInt64(0), + TableName: adapters.PtrString("test2"), // link + TableId: adapters.PtrString("12670f3b-8ca1-463b-b15e-f2e27eaf70b0"), + TableArn: adapters.PtrString("arn:aws:dynamodb:eu-west-1:052392120703:table/test2"), + TableSizeBytes: adapters.PtrInt64(0), KeySchema: []types.KeySchemaElement{ { - AttributeName: sources.PtrString("ArtistId"), + AttributeName: adapters.PtrString("ArtistId"), KeyType: types.KeyTypeHash, }, { - AttributeName: sources.PtrString("Concert"), + AttributeName: adapters.PtrString("Concert"), KeyType: types.KeyTypeRange, }, }, - TableCreationDateTime: sources.PtrTime(time.Now()), + TableCreationDateTime: adapters.PtrTime(time.Now()), ProvisionedThroughput: &types.ProvisionedThroughput{ - ReadCapacityUnits: sources.PtrInt64(5), - WriteCapacityUnits: sources.PtrInt64(5), + ReadCapacityUnits: adapters.PtrInt64(5), + WriteCapacityUnits: adapters.PtrInt64(5), }, - ItemCount: sources.PtrInt64(0), + ItemCount: adapters.PtrInt64(0), BillingMode: types.BillingModeProvisioned, }, SourceTableFeatureDetails: &types.SourceTableFeatureDetails{ GlobalSecondaryIndexes: []types.GlobalSecondaryIndexInfo{ { - IndexName: sources.PtrString("GSI"), + IndexName: adapters.PtrString("GSI"), KeySchema: []types.KeySchemaElement{ { - AttributeName: sources.PtrString("TicketSales"), + AttributeName: adapters.PtrString("TicketSales"), KeyType: types.KeyTypeHash, }, }, @@ -59,8 +59,8 @@ func (t *TestClient) DescribeBackup(ctx context.Context, params *dynamodb.Descri ProjectionType: types.ProjectionTypeKeysOnly, }, ProvisionedThroughput: &types.ProvisionedThroughput{ - ReadCapacityUnits: sources.PtrInt64(5), - WriteCapacityUnits: sources.PtrInt64(5), + ReadCapacityUnits: adapters.PtrInt64(5), + WriteCapacityUnits: adapters.PtrInt64(5), }, }, }, @@ -73,15 +73,15 @@ func (t *TestClient) ListBackups(ctx context.Context, params *dynamodb.ListBacku return &dynamodb.ListBackupsOutput{ BackupSummaries: []types.BackupSummary{ { - TableName: sources.PtrString("test2"), - TableId: sources.PtrString("12670f3b-8ca1-463b-b15e-f2e27eaf70b0"), - TableArn: sources.PtrString("arn:aws:dynamodb:eu-west-1:052392120703:table/test2"), - BackupArn: sources.PtrString("arn:aws:dynamodb:eu-west-1:052392120703:table/test2/backup/01673461724486-a6007753"), - BackupName: sources.PtrString("test2-backup"), - BackupCreationDateTime: sources.PtrTime(time.Now()), + TableName: adapters.PtrString("test2"), + TableId: adapters.PtrString("12670f3b-8ca1-463b-b15e-f2e27eaf70b0"), + TableArn: adapters.PtrString("arn:aws:dynamodb:eu-west-1:052392120703:table/test2"), + BackupArn: adapters.PtrString("arn:aws:dynamodb:eu-west-1:052392120703:table/test2/backup/01673461724486-a6007753"), + BackupName: adapters.PtrString("test2-backup"), + BackupCreationDateTime: adapters.PtrTime(time.Now()), BackupStatus: types.BackupStatusAvailable, BackupType: types.BackupTypeUser, - BackupSizeBytes: sources.PtrInt64(10), + BackupSizeBytes: adapters.PtrInt64(10), }, }, }, nil @@ -98,7 +98,7 @@ func TestBackupGetFunc(t *testing.T) { t.Error(err) } - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "dynamodb-table", ExpectedMethod: sdp.QueryMethod_GET, @@ -110,14 +110,14 @@ func TestBackupGetFunc(t *testing.T) { tests.Execute(t, item) } -func TestNewBackupSource(t *testing.T) { - config, account, region := sources.GetAutoConfig(t) +func TestNewBackupAdapter(t *testing.T) { + config, account, region := adapters.GetAutoConfig(t) client := dynamodb.NewFromConfig(config) - source := NewBackupSource(client, account, region) + adapter := NewBackupAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, SkipGet: true, } diff --git a/sources/dynamodb/shared.go b/adapters/dynamodb/shared.go similarity index 100% rename from sources/dynamodb/shared.go rename to adapters/dynamodb/shared.go diff --git a/sources/dynamodb/shared_test.go b/adapters/dynamodb/shared_test.go similarity index 100% rename from sources/dynamodb/shared_test.go rename to adapters/dynamodb/shared_test.go diff --git a/sources/dynamodb/table.go b/adapters/dynamodb/table.go similarity index 69% rename from sources/dynamodb/table.go rename to adapters/dynamodb/table.go index 471a2dce..1e06847f 100644 --- a/sources/dynamodb/table.go +++ b/adapters/dynamodb/table.go @@ -5,7 +5,7 @@ import ( "errors" "github.com/aws/aws-sdk-go-v2/service/dynamodb" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -33,7 +33,7 @@ func tableGetFunc(ctx context.Context, client Client, scope string, input *dynam }) if err != nil { - tagsMap = sources.HandleTagsError(ctx, err) + tagsMap = adapters.HandleTagsError(ctx, err) break } @@ -51,7 +51,7 @@ func tableGetFunc(ctx context.Context, client Client, scope string, input *dynam } } - attributes, err := sources.ToAttributesWithExclude(table) + attributes, err := adapters.ToAttributesWithExclude(table) if err != nil { return nil, err @@ -65,7 +65,7 @@ func tableGetFunc(ctx context.Context, client Client, scope string, input *dynam Tags: tagsMap, } - var a *sources.ARN + var a *adapters.ARN streamsOut, err := client.DescribeKinesisStreamingDestination(ctx, &dynamodb.DescribeKinesisStreamingDestinationInput{ TableName: table.TableName, @@ -74,14 +74,14 @@ func tableGetFunc(ctx context.Context, client Client, scope string, input *dynam if err == nil { for _, dest := range streamsOut.KinesisDataStreamDestinations { if dest.StreamArn != nil { - if a, err = sources.ParseARN(*dest.StreamArn); err == nil { + if a, err = adapters.ParseARN(*dest.StreamArn); err == nil { // +overmind:link kinesis-stream item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "kinesis-stream", Method: sdp.QueryMethod_SEARCH, Query: *dest.StreamArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // If you change the stream, it could mean the table @@ -99,14 +99,14 @@ func tableGetFunc(ctx context.Context, client Client, scope string, input *dynam if table.RestoreSummary != nil { if table.RestoreSummary.SourceBackupArn != nil { - if a, err = sources.ParseARN(*table.RestoreSummary.SourceBackupArn); err == nil { + if a, err = adapters.ParseARN(*table.RestoreSummary.SourceBackupArn); err == nil { // +overmind:link backup-recovery-point item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "backup-recovery-point", Method: sdp.QueryMethod_SEARCH, Query: *table.RestoreSummary.SourceBackupArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // The backup is just the source from which the table @@ -121,14 +121,14 @@ func tableGetFunc(ctx context.Context, client Client, scope string, input *dynam } if table.RestoreSummary.SourceTableArn != nil { - if a, err = sources.ParseARN(*table.RestoreSummary.SourceTableArn); err == nil { + if a, err = adapters.ParseARN(*table.RestoreSummary.SourceTableArn); err == nil { // +overmind:link dynamodb-table item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "dynamodb-table", Method: sdp.QueryMethod_SEARCH, Query: *table.RestoreSummary.SourceTableArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // If the table was restored from another table, and @@ -145,14 +145,14 @@ func tableGetFunc(ctx context.Context, client Client, scope string, input *dynam if table.SSEDescription != nil { if table.SSEDescription.KMSMasterKeyArn != nil { - if a, err = sources.ParseARN(*table.SSEDescription.KMSMasterKeyArn); err == nil { + if a, err = adapters.ParseARN(*table.SSEDescription.KMSMasterKeyArn); err == nil { // +overmind:link kms-key item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "kms-key", Method: sdp.QueryMethod_SEARCH, Query: *table.SSEDescription.KMSMasterKeyArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changing the key could affect the table @@ -178,20 +178,21 @@ func tableGetFunc(ctx context.Context, client Client, scope string, input *dynam // +overmind:terraform:queryMap aws_dynamodb_table.arn // +overmind:terraform:method SEARCH -func NewTableSource(client Client, accountID string, region string) *sources.AlwaysGetSource[*dynamodb.ListTablesInput, *dynamodb.ListTablesOutput, *dynamodb.DescribeTableInput, *dynamodb.DescribeTableOutput, Client, *dynamodb.Options] { - return &sources.AlwaysGetSource[*dynamodb.ListTablesInput, *dynamodb.ListTablesOutput, *dynamodb.DescribeTableInput, *dynamodb.DescribeTableOutput, Client, *dynamodb.Options]{ - ItemType: "dynamodb-table", - Client: client, - AccountID: accountID, - Region: region, - GetFunc: tableGetFunc, - ListInput: &dynamodb.ListTablesInput{}, +func NewTableAdapter(client Client, accountID string, region string) *adapters.AlwaysGetAdapter[*dynamodb.ListTablesInput, *dynamodb.ListTablesOutput, *dynamodb.DescribeTableInput, *dynamodb.DescribeTableOutput, Client, *dynamodb.Options] { + return &adapters.AlwaysGetAdapter[*dynamodb.ListTablesInput, *dynamodb.ListTablesOutput, *dynamodb.DescribeTableInput, *dynamodb.DescribeTableOutput, Client, *dynamodb.Options]{ + ItemType: "dynamodb-table", + Client: client, + AccountID: accountID, + Region: region, + GetFunc: tableGetFunc, + ListInput: &dynamodb.ListTablesInput{}, + AdapterMetadata: TableMetadata(), GetInputMapper: func(scope, query string) *dynamodb.DescribeTableInput { return &dynamodb.DescribeTableInput{ TableName: &query, } }, - ListFuncPaginatorBuilder: func(client Client, input *dynamodb.ListTablesInput) sources.Paginator[*dynamodb.ListTablesOutput, *dynamodb.Options] { + ListFuncPaginatorBuilder: func(client Client, input *dynamodb.ListTablesInput) adapters.Paginator[*dynamodb.ListTablesOutput, *dynamodb.Options] { return dynamodb.NewListTablesPaginator(client, input) }, ListFuncOutputMapper: func(output *dynamodb.ListTablesOutput, input *dynamodb.ListTablesInput) ([]*dynamodb.DescribeTableInput, error) { @@ -211,3 +212,23 @@ func NewTableSource(client Client, accountID string, region string) *sources.Alw }, } } + +func TableMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "dynamodb-table", + DescriptiveName: "DynamoDB Table", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a DynamoDB table by name", + ListDescription: "List all DynamoDB tables", + SearchDescription: "Search for DynamoDB tables by ARN", + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_DATABASE, + PotentialLinks: []string{"kinesis-stream", "backup-recovery-point", "dynamodb-table", "kms-key"}, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformMethod: sdp.QueryMethod_SEARCH, TerraformQueryMap: "aws_dynamodb_table.arn"}, + }, + } +} diff --git a/sources/dynamodb/table_test.go b/adapters/dynamodb/table_test.go similarity index 58% rename from sources/dynamodb/table_test.go rename to adapters/dynamodb/table_test.go index 3f79711a..b70e0fd5 100644 --- a/sources/dynamodb/table_test.go +++ b/adapters/dynamodb/table_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/dynamodb" "github.com/aws/aws-sdk-go-v2/service/dynamodb/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -16,46 +16,46 @@ func (t *TestClient) DescribeTable(context.Context, *dynamodb.DescribeTableInput Table: &types.TableDescription{ AttributeDefinitions: []types.AttributeDefinition{ { - AttributeName: sources.PtrString("ArtistId"), + AttributeName: adapters.PtrString("ArtistId"), AttributeType: types.ScalarAttributeTypeS, }, { - AttributeName: sources.PtrString("Concert"), + AttributeName: adapters.PtrString("Concert"), AttributeType: types.ScalarAttributeTypeS, }, { - AttributeName: sources.PtrString("TicketSales"), + AttributeName: adapters.PtrString("TicketSales"), AttributeType: types.ScalarAttributeTypeS, }, }, - TableName: sources.PtrString("test-DDBTable-1X52D7BWAAB2H"), + TableName: adapters.PtrString("test-DDBTable-1X52D7BWAAB2H"), KeySchema: []types.KeySchemaElement{ { - AttributeName: sources.PtrString("ArtistId"), + AttributeName: adapters.PtrString("ArtistId"), KeyType: types.KeyTypeHash, }, { - AttributeName: sources.PtrString("Concert"), + AttributeName: adapters.PtrString("Concert"), KeyType: types.KeyTypeRange, }, }, TableStatus: types.TableStatusActive, - CreationDateTime: sources.PtrTime(time.Now()), + CreationDateTime: adapters.PtrTime(time.Now()), ProvisionedThroughput: &types.ProvisionedThroughputDescription{ - NumberOfDecreasesToday: sources.PtrInt64(0), - ReadCapacityUnits: sources.PtrInt64(5), - WriteCapacityUnits: sources.PtrInt64(5), + NumberOfDecreasesToday: adapters.PtrInt64(0), + ReadCapacityUnits: adapters.PtrInt64(5), + WriteCapacityUnits: adapters.PtrInt64(5), }, - TableSizeBytes: sources.PtrInt64(0), - ItemCount: sources.PtrInt64(0), - TableArn: sources.PtrString("arn:aws:dynamodb:eu-west-1:052392120703:table/test-DDBTable-1X52D7BWAAB2H"), - TableId: sources.PtrString("32ef65bf-d6f3-4508-a3db-f201df09e437"), + TableSizeBytes: adapters.PtrInt64(0), + ItemCount: adapters.PtrInt64(0), + TableArn: adapters.PtrString("arn:aws:dynamodb:eu-west-1:052392120703:table/test-DDBTable-1X52D7BWAAB2H"), + TableId: adapters.PtrString("32ef65bf-d6f3-4508-a3db-f201df09e437"), GlobalSecondaryIndexes: []types.GlobalSecondaryIndexDescription{ { - IndexName: sources.PtrString("GSI"), + IndexName: adapters.PtrString("GSI"), KeySchema: []types.KeySchemaElement{ { - AttributeName: sources.PtrString("TicketSales"), + AttributeName: adapters.PtrString("TicketSales"), KeyType: types.KeyTypeHash, }, }, @@ -64,35 +64,35 @@ func (t *TestClient) DescribeTable(context.Context, *dynamodb.DescribeTableInput }, IndexStatus: types.IndexStatusActive, ProvisionedThroughput: &types.ProvisionedThroughputDescription{ - NumberOfDecreasesToday: sources.PtrInt64(0), - ReadCapacityUnits: sources.PtrInt64(5), - WriteCapacityUnits: sources.PtrInt64(5), + NumberOfDecreasesToday: adapters.PtrInt64(0), + ReadCapacityUnits: adapters.PtrInt64(5), + WriteCapacityUnits: adapters.PtrInt64(5), }, - IndexSizeBytes: sources.PtrInt64(0), - ItemCount: sources.PtrInt64(0), - IndexArn: sources.PtrString("arn:aws:dynamodb:eu-west-1:052392120703:table/test-DDBTable-1X52D7BWAAB2H/index/GSI"), // no link, t + IndexSizeBytes: adapters.PtrInt64(0), + ItemCount: adapters.PtrInt64(0), + IndexArn: adapters.PtrString("arn:aws:dynamodb:eu-west-1:052392120703:table/test-DDBTable-1X52D7BWAAB2H/index/GSI"), // no link, t }, }, ArchivalSummary: &types.ArchivalSummary{ - ArchivalBackupArn: sources.PtrString("arn:aws:backups:eu-west-1:052392120703:some-backup/one"), // link - ArchivalDateTime: sources.PtrTime(time.Now()), - ArchivalReason: sources.PtrString("fear"), + ArchivalBackupArn: adapters.PtrString("arn:aws:backups:eu-west-1:052392120703:some-backup/one"), // link + ArchivalDateTime: adapters.PtrTime(time.Now()), + ArchivalReason: adapters.PtrString("fear"), }, BillingModeSummary: &types.BillingModeSummary{ BillingMode: types.BillingModePayPerRequest, }, - GlobalTableVersion: sources.PtrString("1"), - LatestStreamArn: sources.PtrString("arn:aws:dynamodb:eu-west-1:052392120703:table/test-DDBTable-1X52D7BWAAB2H/stream/2023-01-11T16:53:02.371"), // This doesn't get linked because there is no more data to get - LatestStreamLabel: sources.PtrString("2023-01-11T16:53:02.371"), + GlobalTableVersion: adapters.PtrString("1"), + LatestStreamArn: adapters.PtrString("arn:aws:dynamodb:eu-west-1:052392120703:table/test-DDBTable-1X52D7BWAAB2H/stream/2023-01-11T16:53:02.371"), // This doesn't get linked because there is no more data to get + LatestStreamLabel: adapters.PtrString("2023-01-11T16:53:02.371"), LocalSecondaryIndexes: []types.LocalSecondaryIndexDescription{ { - IndexArn: sources.PtrString("arn:aws:dynamodb:eu-west-1:052392120703:table/test-DDBTable-1X52D7BWAAB2H/index/GSX"), // no link - IndexName: sources.PtrString("GSX"), - IndexSizeBytes: sources.PtrInt64(29103), - ItemCount: sources.PtrInt64(234234), + IndexArn: adapters.PtrString("arn:aws:dynamodb:eu-west-1:052392120703:table/test-DDBTable-1X52D7BWAAB2H/index/GSX"), // no link + IndexName: adapters.PtrString("GSX"), + IndexSizeBytes: adapters.PtrInt64(29103), + ItemCount: adapters.PtrInt64(234234), KeySchema: []types.KeySchemaElement{ { - AttributeName: sources.PtrString("TicketSales"), + AttributeName: adapters.PtrString("TicketSales"), KeyType: types.KeyTypeHash, }, }, @@ -108,11 +108,11 @@ func (t *TestClient) DescribeTable(context.Context, *dynamodb.DescribeTableInput { GlobalSecondaryIndexes: []types.ReplicaGlobalSecondaryIndexDescription{ { - IndexName: sources.PtrString("name"), + IndexName: adapters.PtrString("name"), }, }, - KMSMasterKeyId: sources.PtrString("keyID"), - RegionName: sources.PtrString("eu-west-2"), // link + KMSMasterKeyId: adapters.PtrString("keyID"), + RegionName: adapters.PtrString("eu-west-2"), // link ReplicaStatus: types.ReplicaStatusActive, ReplicaTableClassSummary: &types.TableClassSummary{ TableClass: types.TableClassStandard, @@ -120,23 +120,23 @@ func (t *TestClient) DescribeTable(context.Context, *dynamodb.DescribeTableInput }, }, RestoreSummary: &types.RestoreSummary{ - RestoreDateTime: sources.PtrTime(time.Now()), - RestoreInProgress: sources.PtrBool(false), - SourceBackupArn: sources.PtrString("arn:aws:backup:eu-west-1:052392120703:recovery-point:89d0f956-d3a6-42fd-abbd-7d397766bc7e"), // link - SourceTableArn: sources.PtrString("arn:aws:dynamodb:eu-west-1:052392120703:table/test-DDBTable-1X52D7BWAAB2H"), // link + RestoreDateTime: adapters.PtrTime(time.Now()), + RestoreInProgress: adapters.PtrBool(false), + SourceBackupArn: adapters.PtrString("arn:aws:backup:eu-west-1:052392120703:recovery-point:89d0f956-d3a6-42fd-abbd-7d397766bc7e"), // link + SourceTableArn: adapters.PtrString("arn:aws:dynamodb:eu-west-1:052392120703:table/test-DDBTable-1X52D7BWAAB2H"), // link }, SSEDescription: &types.SSEDescription{ - InaccessibleEncryptionDateTime: sources.PtrTime(time.Now()), - KMSMasterKeyArn: sources.PtrString("arn:aws:service:region:account:type/id"), // link + InaccessibleEncryptionDateTime: adapters.PtrTime(time.Now()), + KMSMasterKeyArn: adapters.PtrString("arn:aws:service:region:account:type/id"), // link SSEType: types.SSETypeAes256, Status: types.SSEStatusDisabling, }, StreamSpecification: &types.StreamSpecification{ - StreamEnabled: sources.PtrBool(true), + StreamEnabled: adapters.PtrBool(true), StreamViewType: types.StreamViewTypeKeysOnly, }, TableClassSummary: &types.TableClassSummary{ - LastUpdateDateTime: sources.PtrTime(time.Now()), + LastUpdateDateTime: adapters.PtrTime(time.Now()), TableClass: types.TableClassStandard, }, }, @@ -156,8 +156,8 @@ func (t *TestClient) DescribeKinesisStreamingDestination(ctx context.Context, pa KinesisDataStreamDestinations: []types.KinesisDataStreamDestination{ { DestinationStatus: types.DestinationStatusActive, - DestinationStatusDescription: sources.PtrString("description"), - StreamArn: sources.PtrString("arn:aws:kinesis:eu-west-1:052392120703:stream/test"), + DestinationStatusDescription: adapters.PtrString("description"), + StreamArn: adapters.PtrString("arn:aws:kinesis:eu-west-1:052392120703:stream/test"), }, }, }, nil @@ -167,8 +167,8 @@ func (t *TestClient) ListTagsOfResource(context.Context, *dynamodb.ListTagsOfRes return &dynamodb.ListTagsOfResourceOutput{ Tags: []types.Tag{ { - Key: sources.PtrString("key"), - Value: sources.PtrString("value"), + Key: adapters.PtrString("key"), + Value: adapters.PtrString("value"), }, }, NextToken: nil, @@ -190,7 +190,7 @@ func TestTableGetFunc(t *testing.T) { t.Error(err) } - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "kinesis-stream", ExpectedMethod: sdp.QueryMethod_SEARCH, @@ -220,14 +220,14 @@ func TestTableGetFunc(t *testing.T) { tests.Execute(t, item) } -func TestNewTableSource(t *testing.T) { - config, account, region := sources.GetAutoConfig(t) +func TestNewTableAdapter(t *testing.T) { + config, account, region := adapters.GetAutoConfig(t) client := dynamodb.NewFromConfig(config) - source := NewTableSource(client, account, region) + adapter := NewTableAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/ec2/address.go b/adapters/ec2/address.go similarity index 71% rename from sources/ec2/address.go rename to adapters/ec2/address.go index ed0f42fd..7e67bac9 100644 --- a/sources/ec2/address.go +++ b/adapters/ec2/address.go @@ -5,11 +5,11 @@ import ( "errors" "github.com/aws/aws-sdk-go-v2/service/ec2" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) -// AddressInputMapperGet Maps source calls to the correct input for the AZ API +// AddressInputMapperGet Maps adapter calls to the correct input for the AZ API func addressInputMapperGet(scope, query string) (*ec2.DescribeAddressesInput, error) { return &ec2.DescribeAddressesInput{ PublicIps: []string{ @@ -18,7 +18,7 @@ func addressInputMapperGet(scope, query string) (*ec2.DescribeAddressesInput, er }, nil } -// AddressInputMapperList Maps source calls to the correct input for the AZ API +// AddressInputMapperList Maps adapter calls to the correct input for the AZ API func addressInputMapperList(scope string) (*ec2.DescribeAddressesInput, error) { return &ec2.DescribeAddressesInput{}, nil } @@ -42,7 +42,7 @@ func addressOutputMapper(_ context.Context, _ *ec2.Client, scope string, _ *ec2. } for _, address := range output.Addresses { - attrs, err = sources.ToAttributesWithExclude(address, "tags") + attrs, err = adapters.ToAttributesWithExclude(address, "tags") if err != nil { return nil, err @@ -148,13 +148,14 @@ func addressOutputMapper(_ context.Context, _ *ec2.Client, scope string, _ *ec2. // +overmind:terraform:queryMap aws_eip.public_ip // +overmind:terraform:queryMap aws_eip_association.public_ip -// NewAddressSource Creates a new source for aws-Address resources -func NewAddressSource(client *ec2.Client, accountID string, region string) *sources.DescribeOnlySource[*ec2.DescribeAddressesInput, *ec2.DescribeAddressesOutput, *ec2.Client, *ec2.Options] { - return &sources.DescribeOnlySource[*ec2.DescribeAddressesInput, *ec2.DescribeAddressesOutput, *ec2.Client, *ec2.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "ec2-address", +// NewAddressAdapter Creates a new adapter for aws-Address resources +func NewAddressAdapter(client *ec2.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*ec2.DescribeAddressesInput, *ec2.DescribeAddressesOutput, *ec2.Client, *ec2.Options] { + return &adapters.DescribeOnlyAdapter[*ec2.DescribeAddressesInput, *ec2.DescribeAddressesOutput, *ec2.Client, *ec2.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "ec2-address", + AdapterMetadata: AddressMetadata(), DescribeFunc: func(ctx context.Context, client *ec2.Client, input *ec2.DescribeAddressesInput) (*ec2.DescribeAddressesOutput, error) { return client.DescribeAddresses(ctx, input) }, @@ -163,3 +164,24 @@ func NewAddressSource(client *ec2.Client, accountID string, region string) *sour OutputMapper: addressOutputMapper, } } + +func AddressMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "ec2-address", + DescriptiveName: "EC2 Address", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get an EC2 address by Public IP", + ListDescription: "List EC2 addresses", + SearchDescription: "Search for EC2 addresses by ARN", + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_eip.public_ip"}, + {TerraformQueryMap: "aws_eip_association.public_ip"}, + }, + PotentialLinks: []string{"ec2-instance", "ip", "ec2-network-interface"}, + } +} diff --git a/sources/ec2/address_test.go b/adapters/ec2/address_test.go similarity index 77% rename from sources/ec2/address_test.go rename to adapters/ec2/address_test.go index cc69a682..d2ce9e53 100644 --- a/sources/ec2/address_test.go +++ b/adapters/ec2/address_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/aws/aws-sdk-go-v2/service/ec2/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -43,16 +43,16 @@ func TestAddressOutputMapper(t *testing.T) { output := ec2.DescribeAddressesOutput{ Addresses: []types.Address{ { - PublicIp: sources.PtrString("3.11.82.6"), - AllocationId: sources.PtrString("eipalloc-030a6f43bc6086267"), + PublicIp: adapters.PtrString("3.11.82.6"), + AllocationId: adapters.PtrString("eipalloc-030a6f43bc6086267"), Domain: types.DomainTypeVpc, - PublicIpv4Pool: sources.PtrString("amazon"), - NetworkBorderGroup: sources.PtrString("eu-west-2"), - InstanceId: sources.PtrString("instance"), - CarrierIp: sources.PtrString("3.11.82.7"), - CustomerOwnedIp: sources.PtrString("3.11.82.8"), - NetworkInterfaceId: sources.PtrString("foo"), - PrivateIpAddress: sources.PtrString("3.11.82.9"), + PublicIpv4Pool: adapters.PtrString("amazon"), + NetworkBorderGroup: adapters.PtrString("eu-west-2"), + InstanceId: adapters.PtrString("instance"), + CarrierIp: adapters.PtrString("3.11.82.7"), + CustomerOwnedIp: adapters.PtrString("3.11.82.8"), + NetworkInterfaceId: adapters.PtrString("foo"), + PrivateIpAddress: adapters.PtrString("3.11.82.9"), }, }, } @@ -77,7 +77,7 @@ func TestAddressOutputMapper(t *testing.T) { // It doesn't really make sense to test anything other than the linked items // since the attributes are converted automatically - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "ip", ExpectedMethod: sdp.QueryMethod_GET, @@ -119,13 +119,13 @@ func TestAddressOutputMapper(t *testing.T) { tests.Execute(t, item) } -func TestNewAddressSource(t *testing.T) { +func TestNewAddressAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewAddressSource(client, account, region) + adapter := NewAddressAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/ec2/capacity_reservation.go b/adapters/ec2/capacity_reservation.go similarity index 64% rename from sources/ec2/capacity_reservation.go rename to adapters/ec2/capacity_reservation.go index c85d295b..e22e7597 100644 --- a/sources/ec2/capacity_reservation.go +++ b/adapters/ec2/capacity_reservation.go @@ -4,7 +4,7 @@ import ( "context" "github.com/aws/aws-sdk-go-v2/service/ec2" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -12,7 +12,7 @@ func capacityReservationOutputMapper(_ context.Context, _ *ec2.Client, scope str items := make([]*sdp.Item, 0) for _, cr := range output.CapacityReservations { - attributes, err := sources.ToAttributesWithExclude(cr, "tags") + attributes, err := adapters.ToAttributesWithExclude(cr, "tags") if err != nil { return nil, err @@ -45,14 +45,14 @@ func capacityReservationOutputMapper(_ context.Context, _ *ec2.Client, scope str } if cr.OutpostArn != nil { - if arn, err := sources.ParseARN(*cr.OutpostArn); err == nil { + if arn, err := adapters.ParseARN(*cr.OutpostArn); err == nil { // +overmind:link outposts-outpost item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "outposts-outpost", Method: sdp.QueryMethod_SEARCH, Query: *cr.OutpostArn, - Scope: sources.FormatScope(arn.AccountID, arn.Region), + Scope: adapters.FormatScope(arn.AccountID, arn.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changes to the outpost will affect this @@ -65,14 +65,14 @@ func capacityReservationOutputMapper(_ context.Context, _ *ec2.Client, scope str } if cr.PlacementGroupArn != nil { - if arn, err := sources.ParseARN(*cr.PlacementGroupArn); err == nil { + if arn, err := adapters.ParseARN(*cr.PlacementGroupArn); err == nil { // +overmind:link ec2-placement-group item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "ec2-placement-group", Method: sdp.QueryMethod_SEARCH, Query: *cr.PlacementGroupArn, - Scope: sources.FormatScope(arn.AccountID, arn.Region), + Scope: adapters.FormatScope(arn.AccountID, arn.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changes to the placement group will affect this @@ -99,12 +99,13 @@ func capacityReservationOutputMapper(_ context.Context, _ *ec2.Client, scope str // +overmind:group AWS // +overmind:terraform:queryMap aws_ec2_capacity_reservation.id -func NewCapacityReservationSource(client *ec2.Client, accountID string, region string) *sources.DescribeOnlySource[*ec2.DescribeCapacityReservationsInput, *ec2.DescribeCapacityReservationsOutput, *ec2.Client, *ec2.Options] { - return &sources.DescribeOnlySource[*ec2.DescribeCapacityReservationsInput, *ec2.DescribeCapacityReservationsOutput, *ec2.Client, *ec2.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "ec2-capacity-reservation", +func NewCapacityReservationAdapter(client *ec2.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*ec2.DescribeCapacityReservationsInput, *ec2.DescribeCapacityReservationsOutput, *ec2.Client, *ec2.Options] { + return &adapters.DescribeOnlyAdapter[*ec2.DescribeCapacityReservationsInput, *ec2.DescribeCapacityReservationsOutput, *ec2.Client, *ec2.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "ec2-capacity-reservation", + AdapterMetadata: CapacityReservationMetadata(), DescribeFunc: func(ctx context.Context, client *ec2.Client, input *ec2.DescribeCapacityReservationsInput) (*ec2.DescribeCapacityReservationsOutput, error) { return client.DescribeCapacityReservations(ctx, input) }, @@ -116,9 +117,29 @@ func NewCapacityReservationSource(client *ec2.Client, accountID string, region s InputMapperList: func(scope string) (*ec2.DescribeCapacityReservationsInput, error) { return &ec2.DescribeCapacityReservationsInput{}, nil }, - PaginatorBuilder: func(client *ec2.Client, params *ec2.DescribeCapacityReservationsInput) sources.Paginator[*ec2.DescribeCapacityReservationsOutput, *ec2.Options] { + PaginatorBuilder: func(client *ec2.Client, params *ec2.DescribeCapacityReservationsInput) adapters.Paginator[*ec2.DescribeCapacityReservationsOutput, *ec2.Options] { return ec2.NewDescribeCapacityReservationsPaginator(client, params) }, OutputMapper: capacityReservationOutputMapper, } } + +func CapacityReservationMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "ec2-capacity-reservation", + DescriptiveName: "Capacity Reservation", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a capacity reservation fleet by ID", + ListDescription: "List capacity reservation fleets", + SearchDescription: "Search capacity reservation fleets by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_ec2_capacity_reservation_fleet.id"}, + }, + PotentialLinks: []string{"outposts-outpost", "ec2-placement-group", "ec2-capacity-reservation-fleet"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_CONFIGURATION, + } +} diff --git a/sources/ec2/capacity_reservation_fleet.go b/adapters/ec2/capacity_reservation_fleet.go similarity index 70% rename from sources/ec2/capacity_reservation_fleet.go rename to adapters/ec2/capacity_reservation_fleet.go index fb290fd7..54201c8c 100644 --- a/sources/ec2/capacity_reservation_fleet.go +++ b/adapters/ec2/capacity_reservation_fleet.go @@ -5,7 +5,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/aws/aws-sdk-go-v2/service/ec2/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -13,7 +13,7 @@ func capacityReservationFleetOutputMapper(_ context.Context, _ *ec2.Client, scop items := make([]*sdp.Item, 0) for _, cr := range output.CapacityReservationFleets { - attributes, err := sources.ToAttributesWithExclude(cr, "tags") + attributes, err := adapters.ToAttributesWithExclude(cr, "tags") if err != nil { return nil, err @@ -82,12 +82,13 @@ func capacityReservationFleetOutputMapper(_ context.Context, _ *ec2.Client, scop // +overmind:search Search capacity reservation fleets by ARN // +overmind:group AWS -func NewCapacityReservationFleetSource(client *ec2.Client, accountID string, region string) *sources.DescribeOnlySource[*ec2.DescribeCapacityReservationFleetsInput, *ec2.DescribeCapacityReservationFleetsOutput, *ec2.Client, *ec2.Options] { - return &sources.DescribeOnlySource[*ec2.DescribeCapacityReservationFleetsInput, *ec2.DescribeCapacityReservationFleetsOutput, *ec2.Client, *ec2.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "ec2-capacity-reservation-fleet", +func NewCapacityReservationFleetAdapter(client *ec2.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*ec2.DescribeCapacityReservationFleetsInput, *ec2.DescribeCapacityReservationFleetsOutput, *ec2.Client, *ec2.Options] { + return &adapters.DescribeOnlyAdapter[*ec2.DescribeCapacityReservationFleetsInput, *ec2.DescribeCapacityReservationFleetsOutput, *ec2.Client, *ec2.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "ec2-capacity-reservation-fleet", + AdapterMetadata: CapacityReservationFleetMetadata(), DescribeFunc: func(ctx context.Context, client *ec2.Client, input *ec2.DescribeCapacityReservationFleetsInput) (*ec2.DescribeCapacityReservationFleetsOutput, error) { return client.DescribeCapacityReservationFleets(ctx, input) }, @@ -99,9 +100,26 @@ func NewCapacityReservationFleetSource(client *ec2.Client, accountID string, reg InputMapperList: func(scope string) (*ec2.DescribeCapacityReservationFleetsInput, error) { return &ec2.DescribeCapacityReservationFleetsInput{}, nil }, - PaginatorBuilder: func(client *ec2.Client, params *ec2.DescribeCapacityReservationFleetsInput) sources.Paginator[*ec2.DescribeCapacityReservationFleetsOutput, *ec2.Options] { + PaginatorBuilder: func(client *ec2.Client, params *ec2.DescribeCapacityReservationFleetsInput) adapters.Paginator[*ec2.DescribeCapacityReservationFleetsOutput, *ec2.Options] { return ec2.NewDescribeCapacityReservationFleetsPaginator(client, params) }, OutputMapper: capacityReservationFleetOutputMapper, } } + +func CapacityReservationFleetMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "ec2-capacity-reservation-fleet", + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_CONFIGURATION, + DescriptiveName: "Capacity Reservation Fleet", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a capacity reservation fleet by ID", + ListDescription: "List capacity reservation fleets", + SearchDescription: "Search capacity reservation fleets by ARN", + }, + PotentialLinks: []string{"ec2-capacity-reservation"}, + } +} diff --git a/sources/ec2/capacity_reservation_fleet_test.go b/adapters/ec2/capacity_reservation_fleet_test.go similarity index 53% rename from sources/ec2/capacity_reservation_fleet_test.go rename to adapters/ec2/capacity_reservation_fleet_test.go index 61200e08..d36c29f3 100644 --- a/sources/ec2/capacity_reservation_fleet_test.go +++ b/adapters/ec2/capacity_reservation_fleet_test.go @@ -7,38 +7,38 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/aws/aws-sdk-go-v2/service/ec2/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" ) func TestCapacityReservationFleetOutputMapper(t *testing.T) { output := &ec2.DescribeCapacityReservationFleetsOutput{ CapacityReservationFleets: []types.CapacityReservationFleet{ { - AllocationStrategy: sources.PtrString("prioritized"), - CapacityReservationFleetArn: sources.PtrString("arn:aws:ec2:us-east-1:123456789012:capacity-reservation/fleet/crf-1234567890abcdef0"), - CapacityReservationFleetId: sources.PtrString("crf-1234567890abcdef0"), - CreateTime: sources.PtrTime(time.Now()), + AllocationStrategy: adapters.PtrString("prioritized"), + CapacityReservationFleetArn: adapters.PtrString("arn:aws:ec2:us-east-1:123456789012:capacity-reservation/fleet/crf-1234567890abcdef0"), + CapacityReservationFleetId: adapters.PtrString("crf-1234567890abcdef0"), + CreateTime: adapters.PtrTime(time.Now()), EndDate: nil, InstanceMatchCriteria: types.FleetInstanceMatchCriteriaOpen, InstanceTypeSpecifications: []types.FleetCapacityReservation{ { - AvailabilityZone: sources.PtrString("us-east-1a"), // link - AvailabilityZoneId: sources.PtrString("use1-az1"), - CapacityReservationId: sources.PtrString("cr-1234567890abcdef0"), // link - CreateDate: sources.PtrTime(time.Now()), - EbsOptimized: sources.PtrBool(true), - FulfilledCapacity: sources.PtrFloat64(1), + AvailabilityZone: adapters.PtrString("us-east-1a"), // link + AvailabilityZoneId: adapters.PtrString("use1-az1"), + CapacityReservationId: adapters.PtrString("cr-1234567890abcdef0"), // link + CreateDate: adapters.PtrTime(time.Now()), + EbsOptimized: adapters.PtrBool(true), + FulfilledCapacity: adapters.PtrFloat64(1), InstancePlatform: types.CapacityReservationInstancePlatformLinuxUnix, InstanceType: types.InstanceTypeA12xlarge, - Priority: sources.PtrInt32(1), - TotalInstanceCount: sources.PtrInt32(1), - Weight: sources.PtrFloat64(1), + Priority: adapters.PtrInt32(1), + TotalInstanceCount: adapters.PtrInt32(1), + Weight: adapters.PtrFloat64(1), }, }, State: types.CapacityReservationFleetStateActive, // health Tenancy: types.FleetCapacityReservationTenancyDefault, - TotalFulfilledCapacity: sources.PtrFloat64(1), - TotalTargetCapacity: sources.PtrInt32(1), + TotalFulfilledCapacity: adapters.PtrFloat64(1), + TotalTargetCapacity: adapters.PtrInt32(1), }, }, } @@ -63,19 +63,19 @@ func TestCapacityReservationFleetOutputMapper(t *testing.T) { // It doesn't really make sense to test anything other than the linked items // since the attributes are converted automatically - tests := sources.QueryTests{} + tests := adapters.QueryTests{} tests.Execute(t, item) } -func TestNewCapacityReservationFleetSource(t *testing.T) { +func TestNewCapacityReservationFleetAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewCapacityReservationFleetSource(client, account, region) + adapter := NewCapacityReservationFleetAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/ec2/capacity_reservation_test.go b/adapters/ec2/capacity_reservation_test.go similarity index 59% rename from sources/ec2/capacity_reservation_test.go rename to adapters/ec2/capacity_reservation_test.go index 4cd04be5..ec9d85d5 100644 --- a/sources/ec2/capacity_reservation_test.go +++ b/adapters/ec2/capacity_reservation_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/aws/aws-sdk-go-v2/service/ec2/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -15,30 +15,30 @@ func TestCapacityReservationOutputMapper(t *testing.T) { output := &ec2.DescribeCapacityReservationsOutput{ CapacityReservations: []types.CapacityReservation{ { - AvailabilityZone: sources.PtrString("us-east-1a"), // links - AvailabilityZoneId: sources.PtrString("use1-az1"), - AvailableInstanceCount: sources.PtrInt32(1), - CapacityReservationArn: sources.PtrString("arn:aws:ec2:us-east-1:123456789012:capacity-reservation/cr-1234567890abcdef0"), - CapacityReservationId: sources.PtrString("cr-1234567890abcdef0"), - CapacityReservationFleetId: sources.PtrString("crf-1234567890abcdef0"), // link - CreateDate: sources.PtrTime(time.Now()), - EbsOptimized: sources.PtrBool(true), + AvailabilityZone: adapters.PtrString("us-east-1a"), // links + AvailabilityZoneId: adapters.PtrString("use1-az1"), + AvailableInstanceCount: adapters.PtrInt32(1), + CapacityReservationArn: adapters.PtrString("arn:aws:ec2:us-east-1:123456789012:capacity-reservation/cr-1234567890abcdef0"), + CapacityReservationId: adapters.PtrString("cr-1234567890abcdef0"), + CapacityReservationFleetId: adapters.PtrString("crf-1234567890abcdef0"), // link + CreateDate: adapters.PtrTime(time.Now()), + EbsOptimized: adapters.PtrBool(true), EndDateType: types.EndDateTypeUnlimited, EndDate: nil, InstanceMatchCriteria: types.InstanceMatchCriteriaTargeted, InstancePlatform: types.CapacityReservationInstancePlatformLinuxUnix, - InstanceType: sources.PtrString("t2.micro"), - OutpostArn: sources.PtrString("arn:aws:ec2:us-east-1:123456789012:outpost/op-1234567890abcdef0"), // link - OwnerId: sources.PtrString("123456789012"), - PlacementGroupArn: sources.PtrString("arn:aws:ec2:us-east-1:123456789012:placement-group/pg-1234567890abcdef0"), // link - StartDate: sources.PtrTime(time.Now()), + InstanceType: adapters.PtrString("t2.micro"), + OutpostArn: adapters.PtrString("arn:aws:ec2:us-east-1:123456789012:outpost/op-1234567890abcdef0"), // link + OwnerId: adapters.PtrString("123456789012"), + PlacementGroupArn: adapters.PtrString("arn:aws:ec2:us-east-1:123456789012:placement-group/pg-1234567890abcdef0"), // link + StartDate: adapters.PtrTime(time.Now()), State: types.CapacityReservationStateActive, Tenancy: types.CapacityReservationTenancyDefault, - TotalInstanceCount: sources.PtrInt32(1), + TotalInstanceCount: adapters.PtrInt32(1), CapacityAllocations: []types.CapacityAllocation{ { AllocationType: types.AllocationTypeUsed, - Count: sources.PtrInt32(1), + Count: adapters.PtrInt32(1), }, }, }, @@ -65,7 +65,7 @@ func TestCapacityReservationOutputMapper(t *testing.T) { // It doesn't really make sense to test anything other than the linked items // since the attributes are converted automatically - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "ec2-capacity-reservation-fleet", ExpectedMethod: sdp.QueryMethod_GET, @@ -90,13 +90,13 @@ func TestCapacityReservationOutputMapper(t *testing.T) { } -func TestNewCapacityReservationSource(t *testing.T) { +func TestNewCapacityReservationAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewCapacityReservationSource(client, account, region) + adapter := NewCapacityReservationAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/ec2/egress_internet_gateway.go b/adapters/ec2/egress_internet_gateway.go similarity index 64% rename from sources/ec2/egress_internet_gateway.go rename to adapters/ec2/egress_internet_gateway.go index a8c71bf4..1d2d4fa6 100644 --- a/sources/ec2/egress_internet_gateway.go +++ b/adapters/ec2/egress_internet_gateway.go @@ -4,7 +4,7 @@ import ( "context" "github.com/aws/aws-sdk-go-v2/service/ec2" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -26,7 +26,7 @@ func egressOnlyInternetGatewayOutputMapper(_ context.Context, _ *ec2.Client, sco for _, gw := range output.EgressOnlyInternetGateways { var err error var attrs *sdp.ItemAttributes - attrs, err = sources.ToAttributesWithExclude(gw, "tags") + attrs, err = adapters.ToAttributesWithExclude(gw, "tags") if err != nil { return nil, &sdp.QueryError{ @@ -79,20 +79,41 @@ func egressOnlyInternetGatewayOutputMapper(_ context.Context, _ *ec2.Client, sco // +overmind:group AWS // +overmind:terraform:queryMap egress_only_internet_gateway.id -func NewEgressOnlyInternetGatewaySource(client *ec2.Client, accountID string, region string) *sources.DescribeOnlySource[*ec2.DescribeEgressOnlyInternetGatewaysInput, *ec2.DescribeEgressOnlyInternetGatewaysOutput, *ec2.Client, *ec2.Options] { - return &sources.DescribeOnlySource[*ec2.DescribeEgressOnlyInternetGatewaysInput, *ec2.DescribeEgressOnlyInternetGatewaysOutput, *ec2.Client, *ec2.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "ec2-egress-only-internet-gateway", +func NewEgressOnlyInternetGatewayAdapter(client *ec2.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*ec2.DescribeEgressOnlyInternetGatewaysInput, *ec2.DescribeEgressOnlyInternetGatewaysOutput, *ec2.Client, *ec2.Options] { + return &adapters.DescribeOnlyAdapter[*ec2.DescribeEgressOnlyInternetGatewaysInput, *ec2.DescribeEgressOnlyInternetGatewaysOutput, *ec2.Client, *ec2.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "ec2-egress-only-internet-gateway", + AdapterMetadata: EgressInternetGatewayMetadata(), DescribeFunc: func(ctx context.Context, client *ec2.Client, input *ec2.DescribeEgressOnlyInternetGatewaysInput) (*ec2.DescribeEgressOnlyInternetGatewaysOutput, error) { return client.DescribeEgressOnlyInternetGateways(ctx, input) }, InputMapperGet: egressOnlyInternetGatewayInputMapperGet, InputMapperList: egressOnlyInternetGatewayInputMapperList, - PaginatorBuilder: func(client *ec2.Client, params *ec2.DescribeEgressOnlyInternetGatewaysInput) sources.Paginator[*ec2.DescribeEgressOnlyInternetGatewaysOutput, *ec2.Options] { + PaginatorBuilder: func(client *ec2.Client, params *ec2.DescribeEgressOnlyInternetGatewaysInput) adapters.Paginator[*ec2.DescribeEgressOnlyInternetGatewaysOutput, *ec2.Options] { return ec2.NewDescribeEgressOnlyInternetGatewaysPaginator(client, params) }, OutputMapper: egressOnlyInternetGatewayOutputMapper, } } + +func EgressInternetGatewayMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "ec2-egress-only-internet-gateway", + DescriptiveName: "Egress Only Internet Gateway", + PotentialLinks: []string{"ec2-vpc"}, + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get an egress only internet gateway by ID", + ListDescription: "List all egress only internet gateways", + SearchDescription: "Search egress only internet gateways by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "egress_only_internet_gateway.id"}, + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + } +} diff --git a/sources/ec2/egress_internet_gateway_test.go b/adapters/ec2/egress_internet_gateway_test.go similarity index 83% rename from sources/ec2/egress_internet_gateway_test.go rename to adapters/ec2/egress_internet_gateway_test.go index 0edbf9de..5eec464e 100644 --- a/sources/ec2/egress_internet_gateway_test.go +++ b/adapters/ec2/egress_internet_gateway_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/aws/aws-sdk-go-v2/service/ec2/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -46,10 +46,10 @@ func TestEgressOnlyInternetGatewayOutputMapper(t *testing.T) { Attachments: []types.InternetGatewayAttachment{ { State: types.AttachmentStatusAttached, - VpcId: sources.PtrString("vpc-0d7892e00e573e701"), + VpcId: adapters.PtrString("vpc-0d7892e00e573e701"), }, }, - EgressOnlyInternetGatewayId: sources.PtrString("eigw-0ff50f360e066777a"), + EgressOnlyInternetGatewayId: adapters.PtrString("eigw-0ff50f360e066777a"), }, }, } @@ -74,7 +74,7 @@ func TestEgressOnlyInternetGatewayOutputMapper(t *testing.T) { // It doesn't really make sense to test anything other than the linked items // since the attributes are converted automatically - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "ec2-vpc", ExpectedMethod: sdp.QueryMethod_GET, @@ -87,13 +87,13 @@ func TestEgressOnlyInternetGatewayOutputMapper(t *testing.T) { } -func TestNewEgressOnlyInternetGatewaySource(t *testing.T) { +func TestNewEgressOnlyInternetGatewayAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewEgressOnlyInternetGatewaySource(client, account, region) + adapter := NewEgressOnlyInternetGatewayAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/ec2/iam_instance_profile_association.go b/adapters/ec2/iam_instance_profile_association.go similarity index 62% rename from sources/ec2/iam_instance_profile_association.go rename to adapters/ec2/iam_instance_profile_association.go index 3f825951..392ed693 100644 --- a/sources/ec2/iam_instance_profile_association.go +++ b/adapters/ec2/iam_instance_profile_association.go @@ -4,7 +4,7 @@ import ( "context" "github.com/aws/aws-sdk-go-v2/service/ec2" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -12,7 +12,7 @@ func iamInstanceProfileAssociationOutputMapper(_ context.Context, _ *ec2.Client, items := make([]*sdp.Item, 0) for _, assoc := range output.IamInstanceProfileAssociations { - attributes, err := sources.ToAttributesWithExclude(assoc) + attributes, err := adapters.ToAttributesWithExclude(assoc) if err != nil { return nil, err @@ -26,14 +26,14 @@ func iamInstanceProfileAssociationOutputMapper(_ context.Context, _ *ec2.Client, } if assoc.IamInstanceProfile != nil && assoc.IamInstanceProfile.Arn != nil { - if arn, err := sources.ParseARN(*assoc.IamInstanceProfile.Arn); err == nil { + if arn, err := adapters.ParseARN(*assoc.IamInstanceProfile.Arn); err == nil { // +overmind:link iam-instance-profile item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "iam-instance-profile", Method: sdp.QueryMethod_SEARCH, Query: *assoc.IamInstanceProfile.Arn, - Scope: sources.FormatScope(arn.AccountID, arn.Region), + Scope: adapters.FormatScope(arn.AccountID, arn.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changes to the profile will affect this @@ -77,13 +77,14 @@ func iamInstanceProfileAssociationOutputMapper(_ context.Context, _ *ec2.Client, // +overmind:search Search IAM Instance Profile Associations by ARN // +overmind:group AWS -// NewIamInstanceProfileAssociationSource Creates a new source for aws-IamInstanceProfileAssociation resources -func NewIamInstanceProfileAssociationSource(client *ec2.Client, accountID string, region string) *sources.DescribeOnlySource[*ec2.DescribeIamInstanceProfileAssociationsInput, *ec2.DescribeIamInstanceProfileAssociationsOutput, *ec2.Client, *ec2.Options] { - return &sources.DescribeOnlySource[*ec2.DescribeIamInstanceProfileAssociationsInput, *ec2.DescribeIamInstanceProfileAssociationsOutput, *ec2.Client, *ec2.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "ec2-iam-instance-profile-association", +// NewIamInstanceProfileAssociationAdapter Creates a new adapter for aws-IamInstanceProfileAssociation resources +func NewIamInstanceProfileAssociationAdapter(client *ec2.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*ec2.DescribeIamInstanceProfileAssociationsInput, *ec2.DescribeIamInstanceProfileAssociationsOutput, *ec2.Client, *ec2.Options] { + return &adapters.DescribeOnlyAdapter[*ec2.DescribeIamInstanceProfileAssociationsInput, *ec2.DescribeIamInstanceProfileAssociationsOutput, *ec2.Client, *ec2.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "ec2-iam-instance-profile-association", + AdapterMetadata: IamInstanceProfileAssociationMetadata(), DescribeFunc: func(ctx context.Context, client *ec2.Client, input *ec2.DescribeIamInstanceProfileAssociationsInput) (*ec2.DescribeIamInstanceProfileAssociationsOutput, error) { return client.DescribeIamInstanceProfileAssociations(ctx, input) }, @@ -98,3 +99,20 @@ func NewIamInstanceProfileAssociationSource(client *ec2.Client, accountID string OutputMapper: iamInstanceProfileAssociationOutputMapper, } } + +func IamInstanceProfileAssociationMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "ec2-iam-instance-profile-association", + DescriptiveName: "IAM Instance Profile Association", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get an IAM Instance Profile Association by ID", + ListDescription: "List all IAM Instance Profile Associations", + SearchDescription: "Search IAM Instance Profile Associations by ARN", + }, + PotentialLinks: []string{"iam-instance-profile", "ec2-instance"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_SECURITY, + } +} diff --git a/sources/ec2/iam_instance_profile_association_test.go b/adapters/ec2/iam_instance_profile_association_test.go similarity index 71% rename from sources/ec2/iam_instance_profile_association_test.go rename to adapters/ec2/iam_instance_profile_association_test.go index d756835d..345618d7 100644 --- a/sources/ec2/iam_instance_profile_association_test.go +++ b/adapters/ec2/iam_instance_profile_association_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/aws/aws-sdk-go-v2/service/ec2/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -15,14 +15,14 @@ func TestIamInstanceProfileAssociationOutputMapper(t *testing.T) { output := ec2.DescribeIamInstanceProfileAssociationsOutput{ IamInstanceProfileAssociations: []types.IamInstanceProfileAssociation{ { - AssociationId: sources.PtrString("eipassoc-1234567890abcdef0"), + AssociationId: adapters.PtrString("eipassoc-1234567890abcdef0"), IamInstanceProfile: &types.IamInstanceProfile{ - Arn: sources.PtrString("arn:aws:iam::123456789012:instance-profile/webserver"), // link - Id: sources.PtrString("AIDACKCEVSQ6C2EXAMPLE"), + Arn: adapters.PtrString("arn:aws:iam::123456789012:instance-profile/webserver"), // link + Id: adapters.PtrString("AIDACKCEVSQ6C2EXAMPLE"), }, - InstanceId: sources.PtrString("i-1234567890abcdef0"), // link + InstanceId: adapters.PtrString("i-1234567890abcdef0"), // link State: types.IamInstanceProfileAssociationStateAssociated, - Timestamp: sources.PtrTime(time.Now()), + Timestamp: adapters.PtrTime(time.Now()), }, }, } @@ -47,7 +47,7 @@ func TestIamInstanceProfileAssociationOutputMapper(t *testing.T) { // It doesn't really make sense to test anything other than the linked items // since the attributes are converted automatically - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "iam-instance-profile", ExpectedQuery: "arn:aws:iam::123456789012:instance-profile/webserver", @@ -65,13 +65,13 @@ func TestIamInstanceProfileAssociationOutputMapper(t *testing.T) { tests.Execute(t, item) } -func TestNewIamInstanceProfileAssociationSource(t *testing.T) { +func TestNewIamInstanceProfileAssociationAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewIamInstanceProfileAssociationSource(client, account, region) + adapter := NewIamInstanceProfileAssociationAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/ec2/image.go b/adapters/ec2/image.go similarity index 65% rename from sources/ec2/image.go rename to adapters/ec2/image.go index e9d020df..6bb5f976 100644 --- a/sources/ec2/image.go +++ b/adapters/ec2/image.go @@ -4,7 +4,7 @@ import ( "context" "github.com/aws/aws-sdk-go-v2/service/ec2" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -37,7 +37,7 @@ func imageOutputMapper(_ context.Context, _ *ec2.Client, scope string, _ *ec2.De for _, image := range output.Images { var err error var attrs *sdp.ItemAttributes - attrs, err = sources.ToAttributesWithExclude(image, "tags") + attrs, err = adapters.ToAttributesWithExclude(image, "tags") if err != nil { return nil, &sdp.QueryError{ @@ -70,12 +70,13 @@ func imageOutputMapper(_ context.Context, _ *ec2.Client, scope string, _ *ec2.De // +overmind:group AWS // +overmind:terraform:queryMap aws_ami.id -func NewImageSource(client *ec2.Client, accountID string, region string) *sources.DescribeOnlySource[*ec2.DescribeImagesInput, *ec2.DescribeImagesOutput, *ec2.Client, *ec2.Options] { - return &sources.DescribeOnlySource[*ec2.DescribeImagesInput, *ec2.DescribeImagesOutput, *ec2.Client, *ec2.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "ec2-image", +func NewImageAdapter(client *ec2.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*ec2.DescribeImagesInput, *ec2.DescribeImagesOutput, *ec2.Client, *ec2.Options] { + return &adapters.DescribeOnlyAdapter[*ec2.DescribeImagesInput, *ec2.DescribeImagesOutput, *ec2.Client, *ec2.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "ec2-image", + AdapterMetadata: ImageMetadata(), DescribeFunc: func(ctx context.Context, client *ec2.Client, input *ec2.DescribeImagesInput) (*ec2.DescribeImagesOutput, error) { return client.DescribeImages(ctx, input) }, @@ -84,3 +85,22 @@ func NewImageSource(client *ec2.Client, accountID string, region string) *source OutputMapper: imageOutputMapper, } } + +func ImageMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "ec2-image", + DescriptiveName: "Amazon Machine Image (AMI)", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get an AMI by ID", + ListDescription: "List all AMIs", + SearchDescription: "Search AMIs by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_ami.id"}, + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_COMPUTE_APPLICATION, + } +} diff --git a/sources/ec2/image_test.go b/adapters/ec2/image_test.go similarity index 62% rename from sources/ec2/image_test.go rename to adapters/ec2/image_test.go index 88aa82c9..80c0d6b8 100644 --- a/sources/ec2/image_test.go +++ b/adapters/ec2/image_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/aws/aws-sdk-go-v2/service/ec2/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" ) func TestImageInputMapperGet(t *testing.T) { @@ -44,38 +44,38 @@ func TestImageOutputMapper(t *testing.T) { Images: []types.Image{ { Architecture: "x86_64", - CreationDate: sources.PtrString("2022-12-16T19:37:36.000Z"), - ImageId: sources.PtrString("ami-0ed3646be6ecd97c5"), - ImageLocation: sources.PtrString("052392120703/test"), + CreationDate: adapters.PtrString("2022-12-16T19:37:36.000Z"), + ImageId: adapters.PtrString("ami-0ed3646be6ecd97c5"), + ImageLocation: adapters.PtrString("052392120703/test"), ImageType: types.ImageTypeValuesMachine, - Public: sources.PtrBool(false), - OwnerId: sources.PtrString("052392120703"), - PlatformDetails: sources.PtrString("Linux/UNIX"), - UsageOperation: sources.PtrString("RunInstances"), + Public: adapters.PtrBool(false), + OwnerId: adapters.PtrString("052392120703"), + PlatformDetails: adapters.PtrString("Linux/UNIX"), + UsageOperation: adapters.PtrString("RunInstances"), State: types.ImageStateAvailable, BlockDeviceMappings: []types.BlockDeviceMapping{ { - DeviceName: sources.PtrString("/dev/xvda"), + DeviceName: adapters.PtrString("/dev/xvda"), Ebs: &types.EbsBlockDevice{ - DeleteOnTermination: sources.PtrBool(true), - SnapshotId: sources.PtrString("snap-0efd796ecbd599f8d"), - VolumeSize: sources.PtrInt32(8), + DeleteOnTermination: adapters.PtrBool(true), + SnapshotId: adapters.PtrString("snap-0efd796ecbd599f8d"), + VolumeSize: adapters.PtrInt32(8), VolumeType: types.VolumeTypeGp2, - Encrypted: sources.PtrBool(false), + Encrypted: adapters.PtrBool(false), }, }, }, - EnaSupport: sources.PtrBool(true), + EnaSupport: adapters.PtrBool(true), Hypervisor: types.HypervisorTypeXen, - Name: sources.PtrString("test"), - RootDeviceName: sources.PtrString("/dev/xvda"), + Name: adapters.PtrString("test"), + RootDeviceName: adapters.PtrString("/dev/xvda"), RootDeviceType: types.DeviceTypeEbs, - SriovNetSupport: sources.PtrString("simple"), + SriovNetSupport: adapters.PtrString("simple"), VirtualizationType: types.VirtualizationTypeHvm, Tags: []types.Tag{ { - Key: sources.PtrString("Name"), - Value: sources.PtrString("test"), + Key: adapters.PtrString("Name"), + Value: adapters.PtrString("test"), }, }, }, @@ -105,13 +105,13 @@ func TestImageOutputMapper(t *testing.T) { } } -func TestNewImageSource(t *testing.T) { +func TestNewImageAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewImageSource(client, account, region) + adapter := NewImageAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/ec2/instance.go b/adapters/ec2/instance.go similarity index 85% rename from sources/ec2/instance.go rename to adapters/ec2/instance.go index a061de3f..d7af0011 100644 --- a/sources/ec2/instance.go +++ b/adapters/ec2/instance.go @@ -6,7 +6,7 @@ import ( "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/ec2" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -36,7 +36,7 @@ func instanceOutputMapper(_ context.Context, _ *ec2.Client, scope string, _ *ec2 for _, reservation := range output.Reservations { for _, instance := range reservation.Instances { - attrs, err := sources.ToAttributesWithExclude(instance, "tags") + attrs, err := adapters.ToAttributesWithExclude(instance, "tags") if err != nil { return nil, &sdp.QueryError{ @@ -88,14 +88,14 @@ func instanceOutputMapper(_ context.Context, _ *ec2.Client, scope string, _ *ec2 if instance.IamInstanceProfile != nil { // Prefer the ARN if instance.IamInstanceProfile.Arn != nil { - if arn, err := sources.ParseARN(*instance.IamInstanceProfile.Arn); err == nil { + if arn, err := adapters.ParseARN(*instance.IamInstanceProfile.Arn); err == nil { // +overmind:link iam-instance-profile item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "iam-instance-profile", Method: sdp.QueryMethod_SEARCH, Query: *instance.IamInstanceProfile.Arn, - Scope: sources.FormatScope(arn.AccountID, arn.Region), + Scope: adapters.FormatScope(arn.AccountID, arn.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changes to the profile will affect this instance @@ -164,14 +164,14 @@ func instanceOutputMapper(_ context.Context, _ *ec2.Client, scope string, _ *ec2 for _, assoc := range instance.ElasticInferenceAcceleratorAssociations { if assoc.ElasticInferenceAcceleratorArn != nil { - if arn, err := sources.ParseARN(*assoc.ElasticInferenceAcceleratorArn); err == nil { + if arn, err := adapters.ParseARN(*assoc.ElasticInferenceAcceleratorArn); err == nil { // +overmind:link elastic-inference-accelerator item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "elastic-inference-accelerator", Method: sdp.QueryMethod_SEARCH, Query: *assoc.ElasticInferenceAcceleratorArn, - Scope: sources.FormatScope(arn.AccountID, arn.Region), + Scope: adapters.FormatScope(arn.AccountID, arn.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changing the accelerator will affect the instance @@ -186,14 +186,14 @@ func instanceOutputMapper(_ context.Context, _ *ec2.Client, scope string, _ *ec2 for _, license := range instance.Licenses { if license.LicenseConfigurationArn != nil { - if arn, err := sources.ParseARN(*license.LicenseConfigurationArn); err == nil { + if arn, err := adapters.ParseARN(*license.LicenseConfigurationArn); err == nil { // +overmind:link license-manager-license-configuration item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "license-manager-license-configuration", Method: sdp.QueryMethod_SEARCH, Query: *license.LicenseConfigurationArn, - Scope: sources.FormatScope(arn.AccountID, arn.Region), + Scope: adapters.FormatScope(arn.AccountID, arn.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changing the license will affect the instance @@ -207,14 +207,14 @@ func instanceOutputMapper(_ context.Context, _ *ec2.Client, scope string, _ *ec2 } if instance.OutpostArn != nil { - if arn, err := sources.ParseARN(*instance.OutpostArn); err == nil { + if arn, err := adapters.ParseARN(*instance.OutpostArn); err == nil { // +overmind:link outposts-outpost item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "outposts-outpost", Method: sdp.QueryMethod_SEARCH, Query: *instance.OutpostArn, - Scope: sources.FormatScope(arn.AccountID, arn.Region), + Scope: adapters.FormatScope(arn.AccountID, arn.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changing the outpost will affect the instance @@ -489,20 +489,48 @@ func instanceOutputMapper(_ context.Context, _ *ec2.Client, scope string, _ *ec2 // +overmind:group AWS // +overmind:terraform:queryMap aws_instance.id -func NewInstanceSource(client *ec2.Client, accountID string, region string) *sources.DescribeOnlySource[*ec2.DescribeInstancesInput, *ec2.DescribeInstancesOutput, *ec2.Client, *ec2.Options] { - return &sources.DescribeOnlySource[*ec2.DescribeInstancesInput, *ec2.DescribeInstancesOutput, *ec2.Client, *ec2.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "ec2-instance", +func NewInstanceAdapter(client *ec2.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*ec2.DescribeInstancesInput, *ec2.DescribeInstancesOutput, *ec2.Client, *ec2.Options] { + return &adapters.DescribeOnlyAdapter[*ec2.DescribeInstancesInput, *ec2.DescribeInstancesOutput, *ec2.Client, *ec2.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "ec2-instance", + AdapterMetadata: InstanceMetadata(), DescribeFunc: func(ctx context.Context, client *ec2.Client, input *ec2.DescribeInstancesInput) (*ec2.DescribeInstancesOutput, error) { return client.DescribeInstances(ctx, input) }, InputMapperGet: instanceInputMapperGet, InputMapperList: instanceInputMapperList, - PaginatorBuilder: func(client *ec2.Client, params *ec2.DescribeInstancesInput) sources.Paginator[*ec2.DescribeInstancesOutput, *ec2.Options] { + PaginatorBuilder: func(client *ec2.Client, params *ec2.DescribeInstancesInput) adapters.Paginator[*ec2.DescribeInstancesOutput, *ec2.Options] { return ec2.NewDescribeInstancesPaginator(client, params) }, OutputMapper: instanceOutputMapper, } } + +func InstanceMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "ec2-instance", + DescriptiveName: "EC2 Instance", + PotentialLinks: []string{"ec2-instance-status", "iam-instance-profile", "ec2-capacity-reservation", "ec2-elastic-gpu", "elastic-inference-accelerator", "license-manager-license-configuration", "outposts-outpost", "ec2-spot-instance-request", "ec2-image", "ec2-key-pair", "ec2-placement-group", "ip", "ec2-subnet", "ec2-vpc", "dns", "ec2-security-group", "ec2-volume"}, + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get an EC2 instance by ID", + ListDescription: "List all EC2 instances", + SearchDescription: "Search EC2 instances by ARN", + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_COMPUTE_APPLICATION, + TerraformMappings: []*sdp.TerraformMapping{ + { + TerraformMethod: sdp.QueryMethod_GET, + TerraformQueryMap: "aws_instance.id", + }, + { + TerraformMethod: sdp.QueryMethod_SEARCH, + TerraformQueryMap: "aws_instance.arn", + }, + }, + } +} diff --git a/sources/ec2/instance_event_window.go b/adapters/ec2/instance_event_window.go similarity index 68% rename from sources/ec2/instance_event_window.go rename to adapters/ec2/instance_event_window.go index 31321337..4fe0cccb 100644 --- a/sources/ec2/instance_event_window.go +++ b/adapters/ec2/instance_event_window.go @@ -4,7 +4,7 @@ import ( "context" "github.com/aws/aws-sdk-go-v2/service/ec2" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -24,7 +24,7 @@ func instanceEventWindowOutputMapper(_ context.Context, _ *ec2.Client, scope str items := make([]*sdp.Item, 0) for _, ew := range output.InstanceEventWindows { - attrs, err := sources.ToAttributesWithExclude(ew, "tags") + attrs, err := adapters.ToAttributesWithExclude(ew, "tags") if err != nil { return nil, &sdp.QueryError{ @@ -94,20 +94,38 @@ func instanceEventWindowOutputMapper(_ context.Context, _ *ec2.Client, scope str // +overmind:search Search for event windows by ARN // +overmind:group AWS -func NewInstanceEventWindowSource(client *ec2.Client, accountID string, region string) *sources.DescribeOnlySource[*ec2.DescribeInstanceEventWindowsInput, *ec2.DescribeInstanceEventWindowsOutput, *ec2.Client, *ec2.Options] { - return &sources.DescribeOnlySource[*ec2.DescribeInstanceEventWindowsInput, *ec2.DescribeInstanceEventWindowsOutput, *ec2.Client, *ec2.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "ec2-instance-event-window", +func NewInstanceEventWindowAdapter(client *ec2.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*ec2.DescribeInstanceEventWindowsInput, *ec2.DescribeInstanceEventWindowsOutput, *ec2.Client, *ec2.Options] { + return &adapters.DescribeOnlyAdapter[*ec2.DescribeInstanceEventWindowsInput, *ec2.DescribeInstanceEventWindowsOutput, *ec2.Client, *ec2.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "ec2-instance-event-window", + AdapterMetadata: InstanceEventWindowMetadata(), DescribeFunc: func(ctx context.Context, client *ec2.Client, input *ec2.DescribeInstanceEventWindowsInput) (*ec2.DescribeInstanceEventWindowsOutput, error) { return client.DescribeInstanceEventWindows(ctx, input) }, InputMapperGet: instanceEventWindowInputMapperGet, InputMapperList: instanceEventWindowInputMapperList, - PaginatorBuilder: func(client *ec2.Client, params *ec2.DescribeInstanceEventWindowsInput) sources.Paginator[*ec2.DescribeInstanceEventWindowsOutput, *ec2.Options] { + PaginatorBuilder: func(client *ec2.Client, params *ec2.DescribeInstanceEventWindowsInput) adapters.Paginator[*ec2.DescribeInstanceEventWindowsOutput, *ec2.Options] { return ec2.NewDescribeInstanceEventWindowsPaginator(client, params) }, OutputMapper: instanceEventWindowOutputMapper, } } + +func InstanceEventWindowMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "ec2-instance-event-window", + DescriptiveName: "EC2 Instance Event Window", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get an event window by ID", + ListDescription: "List all event windows", + SearchDescription: "Search for event windows by ARN", + }, + PotentialLinks: []string{"ec2-host", "ec2-instance"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_CONFIGURATION, + } +} diff --git a/sources/ec2/instance_event_window_test.go b/adapters/ec2/instance_event_window_test.go similarity index 82% rename from sources/ec2/instance_event_window_test.go rename to adapters/ec2/instance_event_window_test.go index 2cee81f9..f5df0d1d 100644 --- a/sources/ec2/instance_event_window_test.go +++ b/adapters/ec2/instance_event_window_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/aws/aws-sdk-go-v2/service/ec2/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -51,14 +51,14 @@ func TestInstanceEventWindowOutputMapper(t *testing.T) { "instance", }, }, - CronExpression: sources.PtrString("something"), - InstanceEventWindowId: sources.PtrString("window-123"), - Name: sources.PtrString("test"), + CronExpression: adapters.PtrString("something"), + InstanceEventWindowId: adapters.PtrString("window-123"), + Name: adapters.PtrString("test"), State: types.InstanceEventWindowStateActive, TimeRanges: []types.InstanceEventWindowTimeRange{ { - StartHour: sources.PtrInt32(1), - EndHour: sources.PtrInt32(2), + StartHour: adapters.PtrInt32(1), + EndHour: adapters.PtrInt32(2), EndWeekDay: types.WeekDayFriday, StartWeekDay: types.WeekDayMonday, }, @@ -88,7 +88,7 @@ func TestInstanceEventWindowOutputMapper(t *testing.T) { // It doesn't really make sense to test anything other than the linked items // since the attributes are converted automatically - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "ec2-host", ExpectedMethod: sdp.QueryMethod_GET, @@ -107,13 +107,13 @@ func TestInstanceEventWindowOutputMapper(t *testing.T) { } -func TestNewInstanceEventWindowSource(t *testing.T) { +func TestNewInstanceEventWindowAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewInstanceEventWindowSource(client, account, region) + adapter := NewInstanceEventWindowAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/ec2/instance_status.go b/adapters/ec2/instance_status.go similarity index 68% rename from sources/ec2/instance_status.go rename to adapters/ec2/instance_status.go index c39926fc..8eff4b63 100644 --- a/sources/ec2/instance_status.go +++ b/adapters/ec2/instance_status.go @@ -5,7 +5,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/aws/aws-sdk-go-v2/service/ec2/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -25,7 +25,7 @@ func instanceStatusOutputMapper(_ context.Context, _ *ec2.Client, scope string, items := make([]*sdp.Item, 0) for _, instanceStatus := range output.InstanceStatuses { - attrs, err := sources.ToAttributesWithExclude(instanceStatus) + attrs, err := adapters.ToAttributesWithExclude(instanceStatus) if err != nil { return nil, &sdp.QueryError{ @@ -85,20 +85,37 @@ func instanceStatusOutputMapper(_ context.Context, _ *ec2.Client, scope string, // +overmind:search Search EC2 instance statuses by ARN // +overmind:group AWS -func NewInstanceStatusSource(client *ec2.Client, accountID string, region string) *sources.DescribeOnlySource[*ec2.DescribeInstanceStatusInput, *ec2.DescribeInstanceStatusOutput, *ec2.Client, *ec2.Options] { - return &sources.DescribeOnlySource[*ec2.DescribeInstanceStatusInput, *ec2.DescribeInstanceStatusOutput, *ec2.Client, *ec2.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "ec2-instance-status", +func NewInstanceStatusAdapter(client *ec2.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*ec2.DescribeInstanceStatusInput, *ec2.DescribeInstanceStatusOutput, *ec2.Client, *ec2.Options] { + return &adapters.DescribeOnlyAdapter[*ec2.DescribeInstanceStatusInput, *ec2.DescribeInstanceStatusOutput, *ec2.Client, *ec2.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "ec2-instance-status", + AdapterMetadata: InstanceStatusMetadata(), DescribeFunc: func(ctx context.Context, client *ec2.Client, input *ec2.DescribeInstanceStatusInput) (*ec2.DescribeInstanceStatusOutput, error) { return client.DescribeInstanceStatus(ctx, input) }, InputMapperGet: instanceStatusInputMapperGet, InputMapperList: instanceStatusInputMapperList, - PaginatorBuilder: func(client *ec2.Client, params *ec2.DescribeInstanceStatusInput) sources.Paginator[*ec2.DescribeInstanceStatusOutput, *ec2.Options] { + PaginatorBuilder: func(client *ec2.Client, params *ec2.DescribeInstanceStatusInput) adapters.Paginator[*ec2.DescribeInstanceStatusOutput, *ec2.Options] { return ec2.NewDescribeInstanceStatusPaginator(client, params) }, OutputMapper: instanceStatusOutputMapper, } } + +func InstanceStatusMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "ec2-instance-status", + DescriptiveName: "EC2 Instance Status", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get an EC2 instance status by Instance ID", + ListDescription: "List all EC2 instance statuses", + SearchDescription: "Search EC2 instance statuses by ARN", + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_OBSERVABILITY, + } +} diff --git a/sources/ec2/instance_status_test.go b/adapters/ec2/instance_status_test.go similarity index 84% rename from sources/ec2/instance_status_test.go rename to adapters/ec2/instance_status_test.go index 4588666c..e9b98128 100644 --- a/sources/ec2/instance_status_test.go +++ b/adapters/ec2/instance_status_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/aws/aws-sdk-go-v2/service/ec2/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -43,10 +43,10 @@ func TestInstanceStatusOutputMapper(t *testing.T) { output := &ec2.DescribeInstanceStatusOutput{ InstanceStatuses: []types.InstanceStatus{ { - AvailabilityZone: sources.PtrString("eu-west-2c"), // link - InstanceId: sources.PtrString("i-022bdccde30270570"), // link + AvailabilityZone: adapters.PtrString("eu-west-2c"), // link + InstanceId: adapters.PtrString("i-022bdccde30270570"), // link InstanceState: &types.InstanceState{ - Code: sources.PtrInt32(16), + Code: adapters.PtrInt32(16), Name: types.InstanceStateNameRunning, }, InstanceStatus: &types.InstanceStatusSummary{ @@ -91,7 +91,7 @@ func TestInstanceStatusOutputMapper(t *testing.T) { // It doesn't really make sense to test anything other than the linked items // since the attributes are converted automatically - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "ec2-instance", ExpectedMethod: sdp.QueryMethod_GET, @@ -104,13 +104,13 @@ func TestInstanceStatusOutputMapper(t *testing.T) { } -func TestNewInstanceStatusSource(t *testing.T) { +func TestNewInstanceStatusAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewInstanceStatusSource(client, account, region) + adapter := NewInstanceStatusAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/ec2/instance_test.go b/adapters/ec2/instance_test.go similarity index 58% rename from sources/ec2/instance_test.go rename to adapters/ec2/instance_test.go index a014ed99..575697eb 100644 --- a/sources/ec2/instance_test.go +++ b/adapters/ec2/instance_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/aws/aws-sdk-go-v2/service/ec2/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -45,171 +45,171 @@ func TestInstanceOutputMapper(t *testing.T) { { Instances: []types.Instance{ { - AmiLaunchIndex: sources.PtrInt32(0), - PublicIpAddress: sources.PtrString("43.5.36.7"), - ImageId: sources.PtrString("ami-04706e771f950937f"), - InstanceId: sources.PtrString("i-04c7b2794f7bc3d6a"), + AmiLaunchIndex: adapters.PtrInt32(0), + PublicIpAddress: adapters.PtrString("43.5.36.7"), + ImageId: adapters.PtrString("ami-04706e771f950937f"), + InstanceId: adapters.PtrString("i-04c7b2794f7bc3d6a"), IamInstanceProfile: &types.IamInstanceProfile{ - Arn: sources.PtrString("arn:aws:iam::052392120703:instance-profile/test"), - Id: sources.PtrString("AIDAJQEAZVQ7Y2EYQ2Z6Q"), + Arn: adapters.PtrString("arn:aws:iam::052392120703:instance-profile/test"), + Id: adapters.PtrString("AIDAJQEAZVQ7Y2EYQ2Z6Q"), }, BootMode: types.BootModeValuesLegacyBios, CurrentInstanceBootMode: types.InstanceBootModeValuesLegacyBios, ElasticGpuAssociations: []types.ElasticGpuAssociation{ { - ElasticGpuAssociationId: sources.PtrString("ega-0a1b2c3d4e5f6g7h8"), - ElasticGpuAssociationState: sources.PtrString("associated"), - ElasticGpuAssociationTime: sources.PtrString("now"), - ElasticGpuId: sources.PtrString("egp-0a1b2c3d4e5f6g7h8"), + ElasticGpuAssociationId: adapters.PtrString("ega-0a1b2c3d4e5f6g7h8"), + ElasticGpuAssociationState: adapters.PtrString("associated"), + ElasticGpuAssociationTime: adapters.PtrString("now"), + ElasticGpuId: adapters.PtrString("egp-0a1b2c3d4e5f6g7h8"), }, }, - CapacityReservationId: sources.PtrString("cr-0a1b2c3d4e5f6g7h8"), + CapacityReservationId: adapters.PtrString("cr-0a1b2c3d4e5f6g7h8"), InstanceType: types.InstanceTypeT2Micro, ElasticInferenceAcceleratorAssociations: []types.ElasticInferenceAcceleratorAssociation{ { - ElasticInferenceAcceleratorArn: sources.PtrString("arn:aws:elastic-inference:us-east-1:052392120703:accelerator/eia-0a1b2c3d4e5f6g7h8"), - ElasticInferenceAcceleratorAssociationId: sources.PtrString("eiaa-0a1b2c3d4e5f6g7h8"), - ElasticInferenceAcceleratorAssociationState: sources.PtrString("associated"), - ElasticInferenceAcceleratorAssociationTime: sources.PtrTime(time.Now()), + ElasticInferenceAcceleratorArn: adapters.PtrString("arn:aws:elastic-inference:us-east-1:052392120703:accelerator/eia-0a1b2c3d4e5f6g7h8"), + ElasticInferenceAcceleratorAssociationId: adapters.PtrString("eiaa-0a1b2c3d4e5f6g7h8"), + ElasticInferenceAcceleratorAssociationState: adapters.PtrString("associated"), + ElasticInferenceAcceleratorAssociationTime: adapters.PtrTime(time.Now()), }, }, InstanceLifecycle: types.InstanceLifecycleTypeScheduled, - Ipv6Address: sources.PtrString("2001:db8:3333:4444:5555:6666:7777:8888"), - KeyName: sources.PtrString("dylan.ratcliffe"), - KernelId: sources.PtrString("aki-0a1b2c3d4e5f6g7h8"), + Ipv6Address: adapters.PtrString("2001:db8:3333:4444:5555:6666:7777:8888"), + KeyName: adapters.PtrString("dylan.ratcliffe"), + KernelId: adapters.PtrString("aki-0a1b2c3d4e5f6g7h8"), Licenses: []types.LicenseConfiguration{ { - LicenseConfigurationArn: sources.PtrString("arn:aws:license-manager:us-east-1:052392120703:license-configuration:lic-0a1b2c3d4e5f6g7h8"), + LicenseConfigurationArn: adapters.PtrString("arn:aws:license-manager:us-east-1:052392120703:license-configuration:lic-0a1b2c3d4e5f6g7h8"), }, }, - OutpostArn: sources.PtrString("arn:aws:outposts:us-east-1:052392120703:outpost/op-0a1b2c3d4e5f6g7h8"), + OutpostArn: adapters.PtrString("arn:aws:outposts:us-east-1:052392120703:outpost/op-0a1b2c3d4e5f6g7h8"), Platform: types.PlatformValuesWindows, - RamdiskId: sources.PtrString("ari-0a1b2c3d4e5f6g7h8"), - SpotInstanceRequestId: sources.PtrString("sir-0a1b2c3d4e5f6g7h8"), - SriovNetSupport: sources.PtrString("simple"), + RamdiskId: adapters.PtrString("ari-0a1b2c3d4e5f6g7h8"), + SpotInstanceRequestId: adapters.PtrString("sir-0a1b2c3d4e5f6g7h8"), + SriovNetSupport: adapters.PtrString("simple"), StateReason: &types.StateReason{ - Code: sources.PtrString("foo"), - Message: sources.PtrString("bar"), + Code: adapters.PtrString("foo"), + Message: adapters.PtrString("bar"), }, - TpmSupport: sources.PtrString("foo"), - LaunchTime: sources.PtrTime(time.Now()), + TpmSupport: adapters.PtrString("foo"), + LaunchTime: adapters.PtrTime(time.Now()), Monitoring: &types.Monitoring{ State: types.MonitoringStateDisabled, }, Placement: &types.Placement{ - AvailabilityZone: sources.PtrString("eu-west-2c"), // link - GroupName: sources.PtrString(""), - GroupId: sources.PtrString("groupId"), + AvailabilityZone: adapters.PtrString("eu-west-2c"), // link + GroupName: adapters.PtrString(""), + GroupId: adapters.PtrString("groupId"), Tenancy: types.TenancyDefault, }, - PrivateDnsName: sources.PtrString("ip-172-31-95-79.eu-west-2.compute.internal"), - PrivateIpAddress: sources.PtrString("172.31.95.79"), + PrivateDnsName: adapters.PtrString("ip-172-31-95-79.eu-west-2.compute.internal"), + PrivateIpAddress: adapters.PtrString("172.31.95.79"), ProductCodes: []types.ProductCode{}, - PublicDnsName: sources.PtrString(""), + PublicDnsName: adapters.PtrString(""), State: &types.InstanceState{ - Code: sources.PtrInt32(16), + Code: adapters.PtrInt32(16), Name: types.InstanceStateNameRunning, }, - StateTransitionReason: sources.PtrString(""), - SubnetId: sources.PtrString("subnet-0450a637af9984235"), - VpcId: sources.PtrString("vpc-0d7892e00e573e701"), + StateTransitionReason: adapters.PtrString(""), + SubnetId: adapters.PtrString("subnet-0450a637af9984235"), + VpcId: adapters.PtrString("vpc-0d7892e00e573e701"), Architecture: types.ArchitectureValuesX8664, BlockDeviceMappings: []types.InstanceBlockDeviceMapping{ { - DeviceName: sources.PtrString("/dev/xvda"), + DeviceName: adapters.PtrString("/dev/xvda"), Ebs: &types.EbsInstanceBlockDevice{ - AttachTime: sources.PtrTime(time.Now()), - DeleteOnTermination: sources.PtrBool(true), + AttachTime: adapters.PtrTime(time.Now()), + DeleteOnTermination: adapters.PtrBool(true), Status: types.AttachmentStatusAttached, - VolumeId: sources.PtrString("vol-06c7211d9e79a355e"), + VolumeId: adapters.PtrString("vol-06c7211d9e79a355e"), }, }, }, - ClientToken: sources.PtrString("eafad400-29e0-4b5c-a0fc-ef74c77659c4"), - EbsOptimized: sources.PtrBool(false), - EnaSupport: sources.PtrBool(true), + ClientToken: adapters.PtrString("eafad400-29e0-4b5c-a0fc-ef74c77659c4"), + EbsOptimized: adapters.PtrBool(false), + EnaSupport: adapters.PtrBool(true), Hypervisor: types.HypervisorTypeXen, NetworkInterfaces: []types.InstanceNetworkInterface{ { Attachment: &types.InstanceNetworkInterfaceAttachment{ - AttachTime: sources.PtrTime(time.Now()), - AttachmentId: sources.PtrString("eni-attach-02b19215d0dd9c7be"), - DeleteOnTermination: sources.PtrBool(true), - DeviceIndex: sources.PtrInt32(0), + AttachTime: adapters.PtrTime(time.Now()), + AttachmentId: adapters.PtrString("eni-attach-02b19215d0dd9c7be"), + DeleteOnTermination: adapters.PtrBool(true), + DeviceIndex: adapters.PtrInt32(0), Status: types.AttachmentStatusAttached, - NetworkCardIndex: sources.PtrInt32(0), + NetworkCardIndex: adapters.PtrInt32(0), }, - Description: sources.PtrString(""), + Description: adapters.PtrString(""), Groups: []types.GroupIdentifier{ { - GroupName: sources.PtrString("default"), - GroupId: sources.PtrString("sg-094e151c9fc5da181"), + GroupName: adapters.PtrString("default"), + GroupId: adapters.PtrString("sg-094e151c9fc5da181"), }, }, Ipv6Addresses: []types.InstanceIpv6Address{}, - MacAddress: sources.PtrString("02:8c:61:38:6f:c2"), - NetworkInterfaceId: sources.PtrString("eni-09711a69e6d511358"), - OwnerId: sources.PtrString("052392120703"), - PrivateDnsName: sources.PtrString("ip-172-31-95-79.eu-west-2.compute.internal"), - PrivateIpAddress: sources.PtrString("172.31.95.79"), + MacAddress: adapters.PtrString("02:8c:61:38:6f:c2"), + NetworkInterfaceId: adapters.PtrString("eni-09711a69e6d511358"), + OwnerId: adapters.PtrString("052392120703"), + PrivateDnsName: adapters.PtrString("ip-172-31-95-79.eu-west-2.compute.internal"), + PrivateIpAddress: adapters.PtrString("172.31.95.79"), PrivateIpAddresses: []types.InstancePrivateIpAddress{ { - Primary: sources.PtrBool(true), - PrivateDnsName: sources.PtrString("ip-172-31-95-79.eu-west-2.compute.internal"), - PrivateIpAddress: sources.PtrString("172.31.95.79"), + Primary: adapters.PtrBool(true), + PrivateDnsName: adapters.PtrString("ip-172-31-95-79.eu-west-2.compute.internal"), + PrivateIpAddress: adapters.PtrString("172.31.95.79"), }, }, - SourceDestCheck: sources.PtrBool(true), + SourceDestCheck: adapters.PtrBool(true), Status: types.NetworkInterfaceStatusInUse, - SubnetId: sources.PtrString("subnet-0450a637af9984235"), - VpcId: sources.PtrString("vpc-0d7892e00e573e701"), - InterfaceType: sources.PtrString("interface"), + SubnetId: adapters.PtrString("subnet-0450a637af9984235"), + VpcId: adapters.PtrString("vpc-0d7892e00e573e701"), + InterfaceType: adapters.PtrString("interface"), }, }, - RootDeviceName: sources.PtrString("/dev/xvda"), + RootDeviceName: adapters.PtrString("/dev/xvda"), RootDeviceType: types.DeviceTypeEbs, SecurityGroups: []types.GroupIdentifier{ { - GroupName: sources.PtrString("default"), - GroupId: sources.PtrString("sg-094e151c9fc5da181"), + GroupName: adapters.PtrString("default"), + GroupId: adapters.PtrString("sg-094e151c9fc5da181"), }, }, - SourceDestCheck: sources.PtrBool(true), + SourceDestCheck: adapters.PtrBool(true), Tags: []types.Tag{ { - Key: sources.PtrString("Name"), - Value: sources.PtrString("test"), + Key: adapters.PtrString("Name"), + Value: adapters.PtrString("test"), }, }, VirtualizationType: types.VirtualizationTypeHvm, CpuOptions: &types.CpuOptions{ - CoreCount: sources.PtrInt32(1), - ThreadsPerCore: sources.PtrInt32(1), + CoreCount: adapters.PtrInt32(1), + ThreadsPerCore: adapters.PtrInt32(1), }, CapacityReservationSpecification: &types.CapacityReservationSpecificationResponse{ CapacityReservationPreference: types.CapacityReservationPreferenceOpen, }, HibernationOptions: &types.HibernationOptions{ - Configured: sources.PtrBool(false), + Configured: adapters.PtrBool(false), }, MetadataOptions: &types.InstanceMetadataOptionsResponse{ State: types.InstanceMetadataOptionsStateApplied, HttpTokens: types.HttpTokensStateOptional, - HttpPutResponseHopLimit: sources.PtrInt32(1), + HttpPutResponseHopLimit: adapters.PtrInt32(1), HttpEndpoint: types.InstanceMetadataEndpointStateEnabled, HttpProtocolIpv6: types.InstanceMetadataProtocolStateDisabled, InstanceMetadataTags: types.InstanceMetadataTagsStateDisabled, }, EnclaveOptions: &types.EnclaveOptions{ - Enabled: sources.PtrBool(false), + Enabled: adapters.PtrBool(false), }, - PlatformDetails: sources.PtrString("Linux/UNIX"), - UsageOperation: sources.PtrString("RunInstances"), - UsageOperationUpdateTime: sources.PtrTime(time.Now()), + PlatformDetails: adapters.PtrString("Linux/UNIX"), + UsageOperation: adapters.PtrString("RunInstances"), + UsageOperationUpdateTime: adapters.PtrTime(time.Now()), PrivateDnsNameOptions: &types.PrivateDnsNameOptionsResponse{ HostnameType: types.HostnameTypeIpName, - EnableResourceNameDnsARecord: sources.PtrBool(true), - EnableResourceNameDnsAAAARecord: sources.PtrBool(false), + EnableResourceNameDnsARecord: adapters.PtrBool(true), + EnableResourceNameDnsAAAARecord: adapters.PtrBool(false), }, MaintenanceOptions: &types.InstanceMaintenanceOptions{ AutoRecovery: types.InstanceAutoRecoveryStateDefault, @@ -240,7 +240,7 @@ func TestInstanceOutputMapper(t *testing.T) { // It doesn't really make sense to test anything other than the linked items // since the attributes are converted automatically - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "ec2-image", ExpectedMethod: sdp.QueryMethod_GET, @@ -349,13 +349,13 @@ func TestInstanceOutputMapper(t *testing.T) { } -func TestNewInstanceSource(t *testing.T) { +func TestNewInstanceAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewInstanceSource(client, account, region) + adapter := NewInstanceAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/ec2/internet_gateway.go b/adapters/ec2/internet_gateway.go similarity index 64% rename from sources/ec2/internet_gateway.go rename to adapters/ec2/internet_gateway.go index 2a2634dd..f09d9306 100644 --- a/sources/ec2/internet_gateway.go +++ b/adapters/ec2/internet_gateway.go @@ -4,7 +4,7 @@ import ( "context" "github.com/aws/aws-sdk-go-v2/service/ec2" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -26,7 +26,7 @@ func internetGatewayOutputMapper(_ context.Context, _ *ec2.Client, scope string, for _, gw := range output.InternetGateways { var err error var attrs *sdp.ItemAttributes - attrs, err = sources.ToAttributesWithExclude(gw, "tags") + attrs, err = adapters.ToAttributesWithExclude(gw, "tags") if err != nil { return nil, &sdp.QueryError{ @@ -80,20 +80,41 @@ func internetGatewayOutputMapper(_ context.Context, _ *ec2.Client, scope string, // +overmind:group AWS // +overmind:terraform:queryMap aws_internet_gateway.id -func NewInternetGatewaySource(client *ec2.Client, accountID string, region string) *sources.DescribeOnlySource[*ec2.DescribeInternetGatewaysInput, *ec2.DescribeInternetGatewaysOutput, *ec2.Client, *ec2.Options] { - return &sources.DescribeOnlySource[*ec2.DescribeInternetGatewaysInput, *ec2.DescribeInternetGatewaysOutput, *ec2.Client, *ec2.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "ec2-internet-gateway", +func NewInternetGatewayAdapter(client *ec2.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*ec2.DescribeInternetGatewaysInput, *ec2.DescribeInternetGatewaysOutput, *ec2.Client, *ec2.Options] { + return &adapters.DescribeOnlyAdapter[*ec2.DescribeInternetGatewaysInput, *ec2.DescribeInternetGatewaysOutput, *ec2.Client, *ec2.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "ec2-internet-gateway", + AdapterMetadata: InternetGatewayMetadata(), DescribeFunc: func(ctx context.Context, client *ec2.Client, input *ec2.DescribeInternetGatewaysInput) (*ec2.DescribeInternetGatewaysOutput, error) { return client.DescribeInternetGateways(ctx, input) }, InputMapperGet: internetGatewayInputMapperGet, InputMapperList: internetGatewayInputMapperList, - PaginatorBuilder: func(client *ec2.Client, params *ec2.DescribeInternetGatewaysInput) sources.Paginator[*ec2.DescribeInternetGatewaysOutput, *ec2.Options] { + PaginatorBuilder: func(client *ec2.Client, params *ec2.DescribeInternetGatewaysInput) adapters.Paginator[*ec2.DescribeInternetGatewaysOutput, *ec2.Options] { return ec2.NewDescribeInternetGatewaysPaginator(client, params) }, OutputMapper: internetGatewayOutputMapper, } } + +func InternetGatewayMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "ec2-internet-gateway", + DescriptiveName: "Internet Gateway", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get an internet gateway by ID", + ListDescription: "List all internet gateways", + SearchDescription: "Search internet gateways by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_internet_gateway.id"}, + }, + PotentialLinks: []string{"ec2-vpc"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + } +} diff --git a/sources/ec2/internet_gateway_test.go b/adapters/ec2/internet_gateway_test.go similarity index 79% rename from sources/ec2/internet_gateway_test.go rename to adapters/ec2/internet_gateway_test.go index 0975a11d..e8fffa1d 100644 --- a/sources/ec2/internet_gateway_test.go +++ b/adapters/ec2/internet_gateway_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/aws/aws-sdk-go-v2/service/ec2/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -46,15 +46,15 @@ func TestInternetGatewayOutputMapper(t *testing.T) { Attachments: []types.InternetGatewayAttachment{ { State: types.AttachmentStatusAttached, - VpcId: sources.PtrString("vpc-0d7892e00e573e701"), + VpcId: adapters.PtrString("vpc-0d7892e00e573e701"), }, }, - InternetGatewayId: sources.PtrString("igw-03809416c9e2fcb66"), - OwnerId: sources.PtrString("052392120703"), + InternetGatewayId: adapters.PtrString("igw-03809416c9e2fcb66"), + OwnerId: adapters.PtrString("052392120703"), Tags: []types.Tag{ { - Key: sources.PtrString("Name"), - Value: sources.PtrString("test"), + Key: adapters.PtrString("Name"), + Value: adapters.PtrString("test"), }, }, }, @@ -81,7 +81,7 @@ func TestInternetGatewayOutputMapper(t *testing.T) { // It doesn't really make sense to test anything other than the linked items // since the attributes are converted automatically - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "ec2-vpc", ExpectedMethod: sdp.QueryMethod_GET, @@ -94,13 +94,13 @@ func TestInternetGatewayOutputMapper(t *testing.T) { } -func TestNewInternetGatewaySource(t *testing.T) { +func TestNewInternetGatewayAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewInternetGatewaySource(client, account, region) + adapter := NewInternetGatewayAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/ec2/key_pair.go b/adapters/ec2/key_pair.go similarity index 59% rename from sources/ec2/key_pair.go rename to adapters/ec2/key_pair.go index d3b28770..9377e929 100644 --- a/sources/ec2/key_pair.go +++ b/adapters/ec2/key_pair.go @@ -4,7 +4,7 @@ import ( "context" "github.com/aws/aws-sdk-go-v2/service/ec2" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -26,7 +26,7 @@ func keyPairOutputMapper(_ context.Context, _ *ec2.Client, scope string, _ *ec2. for _, gw := range output.KeyPairs { var err error var attrs *sdp.ItemAttributes - attrs, err = sources.ToAttributesWithExclude(gw, "tags") + attrs, err = adapters.ToAttributesWithExclude(gw, "tags") if err != nil { return nil, &sdp.QueryError{ @@ -59,12 +59,13 @@ func keyPairOutputMapper(_ context.Context, _ *ec2.Client, scope string, _ *ec2. // +overmind:group AWS // +overmind:terraform:queryMap aws_key_pair.id -func NewKeyPairSource(client *ec2.Client, accountID string, region string) *sources.DescribeOnlySource[*ec2.DescribeKeyPairsInput, *ec2.DescribeKeyPairsOutput, *ec2.Client, *ec2.Options] { - return &sources.DescribeOnlySource[*ec2.DescribeKeyPairsInput, *ec2.DescribeKeyPairsOutput, *ec2.Client, *ec2.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "ec2-key-pair", +func NewKeyPairAdapter(client *ec2.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*ec2.DescribeKeyPairsInput, *ec2.DescribeKeyPairsOutput, *ec2.Client, *ec2.Options] { + return &adapters.DescribeOnlyAdapter[*ec2.DescribeKeyPairsInput, *ec2.DescribeKeyPairsOutput, *ec2.Client, *ec2.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "ec2-key-pair", + AdapterMetadata: KeyPairMetadata(), DescribeFunc: func(ctx context.Context, client *ec2.Client, input *ec2.DescribeKeyPairsInput) (*ec2.DescribeKeyPairsOutput, error) { return client.DescribeKeyPairs(ctx, input) }, @@ -73,3 +74,22 @@ func NewKeyPairSource(client *ec2.Client, accountID string, region string) *sour OutputMapper: keyPairOutputMapper, } } + +func KeyPairMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "ec2-key-pair", + DescriptiveName: "Key Pair", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a key pair by name", + ListDescription: "List all key pairs", + SearchDescription: "Search for key pairs by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_key_pair.id"}, + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_SECURITY, + } +} diff --git a/sources/ec2/key_pair_test.go b/adapters/ec2/key_pair_test.go similarity index 72% rename from sources/ec2/key_pair_test.go rename to adapters/ec2/key_pair_test.go index 81c664cc..1ff70e34 100644 --- a/sources/ec2/key_pair_test.go +++ b/adapters/ec2/key_pair_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/aws/aws-sdk-go-v2/service/ec2/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" ) func TestKeyPairInputMapperGet(t *testing.T) { @@ -42,13 +42,13 @@ func TestKeyPairOutputMapper(t *testing.T) { output := &ec2.DescribeKeyPairsOutput{ KeyPairs: []types.KeyPairInfo{ { - KeyPairId: sources.PtrString("key-04d7068d3a33bf9b2"), - KeyFingerprint: sources.PtrString("df:73:bb:86:a7:cd:9e:18:16:10:50:79:fa:3b:4f:c7:1d:32:cf:58"), - KeyName: sources.PtrString("dylan.ratcliffe"), + KeyPairId: adapters.PtrString("key-04d7068d3a33bf9b2"), + KeyFingerprint: adapters.PtrString("df:73:bb:86:a7:cd:9e:18:16:10:50:79:fa:3b:4f:c7:1d:32:cf:58"), + KeyName: adapters.PtrString("dylan.ratcliffe"), KeyType: types.KeyTypeRsa, Tags: []types.Tag{}, - CreateTime: sources.PtrTime(time.Now()), - PublicKey: sources.PtrString("PUB"), + CreateTime: adapters.PtrTime(time.Now()), + PublicKey: adapters.PtrString("PUB"), }, }, } @@ -71,13 +71,13 @@ func TestKeyPairOutputMapper(t *testing.T) { } -func TestNewKeyPairSource(t *testing.T) { +func TestNewKeyPairAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewKeyPairSource(client, account, region) + adapter := NewKeyPairAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/ec2/launch_template.go b/adapters/ec2/launch_template.go similarity index 59% rename from sources/ec2/launch_template.go rename to adapters/ec2/launch_template.go index 67c6561b..3aabc4c8 100644 --- a/sources/ec2/launch_template.go +++ b/adapters/ec2/launch_template.go @@ -4,7 +4,7 @@ import ( "context" "github.com/aws/aws-sdk-go-v2/service/ec2" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -26,7 +26,7 @@ func launchTemplateOutputMapper(_ context.Context, _ *ec2.Client, scope string, for _, LaunchTemplate := range output.LaunchTemplates { var err error var attrs *sdp.ItemAttributes - attrs, err = sources.ToAttributesWithExclude(LaunchTemplate, "tags") + attrs, err = adapters.ToAttributesWithExclude(LaunchTemplate, "tags") if err != nil { return nil, &sdp.QueryError{ @@ -59,20 +59,40 @@ func launchTemplateOutputMapper(_ context.Context, _ *ec2.Client, scope string, // +overmind:group AWS // +overmind:terraform:queryMap aws_launch_template.id -func NewLaunchTemplateSource(client *ec2.Client, accountID string, region string) *sources.DescribeOnlySource[*ec2.DescribeLaunchTemplatesInput, *ec2.DescribeLaunchTemplatesOutput, *ec2.Client, *ec2.Options] { - return &sources.DescribeOnlySource[*ec2.DescribeLaunchTemplatesInput, *ec2.DescribeLaunchTemplatesOutput, *ec2.Client, *ec2.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "ec2-launch-template", +func NewLaunchTemplateAdapter(client *ec2.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*ec2.DescribeLaunchTemplatesInput, *ec2.DescribeLaunchTemplatesOutput, *ec2.Client, *ec2.Options] { + return &adapters.DescribeOnlyAdapter[*ec2.DescribeLaunchTemplatesInput, *ec2.DescribeLaunchTemplatesOutput, *ec2.Client, *ec2.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "ec2-launch-template", + AdapterMetadata: LaunchTemplateMetadata(), DescribeFunc: func(ctx context.Context, client *ec2.Client, input *ec2.DescribeLaunchTemplatesInput) (*ec2.DescribeLaunchTemplatesOutput, error) { return client.DescribeLaunchTemplates(ctx, input) }, InputMapperGet: launchTemplateInputMapperGet, InputMapperList: launchTemplateInputMapperList, - PaginatorBuilder: func(client *ec2.Client, params *ec2.DescribeLaunchTemplatesInput) sources.Paginator[*ec2.DescribeLaunchTemplatesOutput, *ec2.Options] { + PaginatorBuilder: func(client *ec2.Client, params *ec2.DescribeLaunchTemplatesInput) adapters.Paginator[*ec2.DescribeLaunchTemplatesOutput, *ec2.Options] { return ec2.NewDescribeLaunchTemplatesPaginator(client, params) }, OutputMapper: launchTemplateOutputMapper, } } + +func LaunchTemplateMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "ec2-launch-template", + DescriptiveName: "Launch Template", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a launch template by ID", + ListDescription: "List all launch templates", + SearchDescription: "Search for launch templates by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_launch_template.id"}, + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_COMPUTE_APPLICATION, + } +} diff --git a/sources/ec2/launch_template_test.go b/adapters/ec2/launch_template_test.go similarity index 71% rename from sources/ec2/launch_template_test.go rename to adapters/ec2/launch_template_test.go index fd62f391..41e0f4ad 100644 --- a/sources/ec2/launch_template_test.go +++ b/adapters/ec2/launch_template_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/aws/aws-sdk-go-v2/service/ec2/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" ) func TestLaunchTemplateInputMapperGet(t *testing.T) { @@ -42,12 +42,12 @@ func TestLaunchTemplateOutputMapper(t *testing.T) { output := &ec2.DescribeLaunchTemplatesOutput{ LaunchTemplates: []types.LaunchTemplate{ { - CreateTime: sources.PtrTime(time.Now()), - CreatedBy: sources.PtrString("me"), - DefaultVersionNumber: sources.PtrInt64(1), - LatestVersionNumber: sources.PtrInt64(10), - LaunchTemplateId: sources.PtrString("id"), - LaunchTemplateName: sources.PtrString("hello"), + CreateTime: adapters.PtrTime(time.Now()), + CreatedBy: adapters.PtrString("me"), + DefaultVersionNumber: adapters.PtrInt64(1), + LatestVersionNumber: adapters.PtrInt64(10), + LaunchTemplateId: adapters.PtrString("id"), + LaunchTemplateName: adapters.PtrString("hello"), Tags: []types.Tag{}, }, }, @@ -65,13 +65,13 @@ func TestLaunchTemplateOutputMapper(t *testing.T) { } -func TestNewLaunchTemplateSource(t *testing.T) { +func TestNewLaunchTemplateAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewLaunchTemplateSource(client, account, region) + adapter := NewLaunchTemplateAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/ec2/launch_template_version.go b/adapters/ec2/launch_template_version.go similarity index 85% rename from sources/ec2/launch_template_version.go rename to adapters/ec2/launch_template_version.go index f77a58d6..edf064b9 100644 --- a/sources/ec2/launch_template_version.go +++ b/adapters/ec2/launch_template_version.go @@ -7,7 +7,7 @@ import ( "strings" "github.com/aws/aws-sdk-go-v2/service/ec2" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -42,7 +42,7 @@ func launchTemplateVersionOutputMapper(_ context.Context, _ *ec2.Client, scope s for _, ltv := range output.LaunchTemplateVersions { var err error var attrs *sdp.ItemAttributes - attrs, err = sources.ToAttributesWithExclude(ltv) + attrs, err = adapters.ToAttributesWithExclude(ltv) if err != nil { return nil, &sdp.QueryError{ @@ -318,20 +318,38 @@ func launchTemplateVersionOutputMapper(_ context.Context, _ *ec2.Client, scope s // +overmind:search Search launch template versions by ARN // +overmind:group AWS -func NewLaunchTemplateVersionSource(client *ec2.Client, accountID string, region string) *sources.DescribeOnlySource[*ec2.DescribeLaunchTemplateVersionsInput, *ec2.DescribeLaunchTemplateVersionsOutput, *ec2.Client, *ec2.Options] { - return &sources.DescribeOnlySource[*ec2.DescribeLaunchTemplateVersionsInput, *ec2.DescribeLaunchTemplateVersionsOutput, *ec2.Client, *ec2.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "ec2-launch-template-version", +func NewLaunchTemplateVersionAdapter(client *ec2.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*ec2.DescribeLaunchTemplateVersionsInput, *ec2.DescribeLaunchTemplateVersionsOutput, *ec2.Client, *ec2.Options] { + return &adapters.DescribeOnlyAdapter[*ec2.DescribeLaunchTemplateVersionsInput, *ec2.DescribeLaunchTemplateVersionsOutput, *ec2.Client, *ec2.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "ec2-launch-template-version", + AdapterMetadata: LaunchTemplateVersionMetadata(), DescribeFunc: func(ctx context.Context, client *ec2.Client, input *ec2.DescribeLaunchTemplateVersionsInput) (*ec2.DescribeLaunchTemplateVersionsOutput, error) { return client.DescribeLaunchTemplateVersions(ctx, input) }, InputMapperGet: launchTemplateVersionInputMapperGet, InputMapperList: launchTemplateVersionInputMapperList, - PaginatorBuilder: func(client *ec2.Client, params *ec2.DescribeLaunchTemplateVersionsInput) sources.Paginator[*ec2.DescribeLaunchTemplateVersionsOutput, *ec2.Options] { + PaginatorBuilder: func(client *ec2.Client, params *ec2.DescribeLaunchTemplateVersionsInput) adapters.Paginator[*ec2.DescribeLaunchTemplateVersionsOutput, *ec2.Options] { return ec2.NewDescribeLaunchTemplateVersionsPaginator(client, params) }, OutputMapper: launchTemplateVersionOutputMapper, } } + +func LaunchTemplateVersionMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "ec2-launch-template-version", + DescriptiveName: "Launch Template Version", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a launch template version by {templateId}.{version}", + ListDescription: "List all launch template versions", + SearchDescription: "Search launch template versions by ARN", + }, + PotentialLinks: []string{"ec2-network-interface", "ec2-subnet", "ec2-security-group", "ec2-image", "ec2-key-pair", "ec2-snapshot", "ec2-capacity-reservation", "ec2-placement-group", "ec2-host", "ip"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_COMPUTE_APPLICATION, + } +} diff --git a/sources/ec2/launch_template_version_test.go b/adapters/ec2/launch_template_version_test.go similarity index 77% rename from sources/ec2/launch_template_version_test.go rename to adapters/ec2/launch_template_version_test.go index d93a2275..7d5f5a30 100644 --- a/sources/ec2/launch_template_version_test.go +++ b/adapters/ec2/launch_template_version_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/aws/aws-sdk-go-v2/service/ec2/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -47,48 +47,48 @@ func TestLaunchTemplateVersionOutputMapper(t *testing.T) { output := &ec2.DescribeLaunchTemplateVersionsOutput{ LaunchTemplateVersions: []types.LaunchTemplateVersion{ { - LaunchTemplateId: sources.PtrString("lt-015547202038ae102"), - LaunchTemplateName: sources.PtrString("test"), - VersionNumber: sources.PtrInt64(1), - CreateTime: sources.PtrTime(time.Now()), - CreatedBy: sources.PtrString("arn:aws:sts::052392120703:assumed-role/AWSReservedSSO_AWSAdministratorAccess_c1c3c9c54821c68a/dylan@overmind.tech"), - DefaultVersion: sources.PtrBool(true), + LaunchTemplateId: adapters.PtrString("lt-015547202038ae102"), + LaunchTemplateName: adapters.PtrString("test"), + VersionNumber: adapters.PtrInt64(1), + CreateTime: adapters.PtrTime(time.Now()), + CreatedBy: adapters.PtrString("arn:aws:sts::052392120703:assumed-role/AWSReservedSSO_AWSAdministratorAccess_c1c3c9c54821c68a/dylan@overmind.tech"), + DefaultVersion: adapters.PtrBool(true), LaunchTemplateData: &types.ResponseLaunchTemplateData{ NetworkInterfaces: []types.LaunchTemplateInstanceNetworkInterfaceSpecification{ { Ipv6Addresses: []types.InstanceIpv6Address{ { - Ipv6Address: sources.PtrString("ipv6"), + Ipv6Address: adapters.PtrString("ipv6"), }, }, - NetworkInterfaceId: sources.PtrString("networkInterface"), + NetworkInterfaceId: adapters.PtrString("networkInterface"), PrivateIpAddresses: []types.PrivateIpAddressSpecification{ { - Primary: sources.PtrBool(true), - PrivateIpAddress: sources.PtrString("ip"), + Primary: adapters.PtrBool(true), + PrivateIpAddress: adapters.PtrString("ip"), }, }, - SubnetId: sources.PtrString("subnet"), - DeviceIndex: sources.PtrInt32(0), + SubnetId: adapters.PtrString("subnet"), + DeviceIndex: adapters.PtrInt32(0), Groups: []string{ "sg-094e151c9fc5da181", }, }, }, - ImageId: sources.PtrString("ami-084e8c05825742534"), + ImageId: adapters.PtrString("ami-084e8c05825742534"), InstanceType: types.InstanceTypeT1Micro, - KeyName: sources.PtrString("dylan.ratcliffe"), + KeyName: adapters.PtrString("dylan.ratcliffe"), BlockDeviceMappings: []types.LaunchTemplateBlockDeviceMapping{ { Ebs: &types.LaunchTemplateEbsBlockDevice{ - SnapshotId: sources.PtrString("snap"), + SnapshotId: adapters.PtrString("snap"), }, }, }, CapacityReservationSpecification: &types.LaunchTemplateCapacityReservationSpecificationResponse{ CapacityReservationPreference: types.CapacityReservationPreferenceNone, CapacityReservationTarget: &types.CapacityReservationTargetResponse{ - CapacityReservationId: sources.PtrString("cap"), + CapacityReservationId: adapters.PtrString("cap"), }, }, CpuOptions: &types.LaunchTemplateCpuOptions{}, @@ -97,9 +97,9 @@ func TestLaunchTemplateVersionOutputMapper(t *testing.T) { EnclaveOptions: &types.LaunchTemplateEnclaveOptions{}, ElasticInferenceAccelerators: []types.LaunchTemplateElasticInferenceAcceleratorResponse{}, Placement: &types.LaunchTemplatePlacement{ - AvailabilityZone: sources.PtrString("foo"), - GroupId: sources.PtrString("placement"), - HostId: sources.PtrString("host"), + AvailabilityZone: adapters.PtrString("foo"), + GroupId: adapters.PtrString("placement"), + HostId: adapters.PtrString("host"), }, SecurityGroupIds: []string{ "secGroup", @@ -123,7 +123,7 @@ func TestLaunchTemplateVersionOutputMapper(t *testing.T) { // It doesn't really make sense to test anything other than the linked items // since the attributes are converted automatically - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "ip", ExpectedMethod: sdp.QueryMethod_GET, @@ -202,13 +202,13 @@ func TestLaunchTemplateVersionOutputMapper(t *testing.T) { } -func TestNewLaunchTemplateVersionSource(t *testing.T) { +func TestNewLaunchTemplateVersionAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewLaunchTemplateVersionSource(client, account, region) + adapter := NewLaunchTemplateVersionAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, SkipNotFoundCheck: true, } diff --git a/sources/ec2/nat_gateway.go b/adapters/ec2/nat_gateway.go similarity index 75% rename from sources/ec2/nat_gateway.go rename to adapters/ec2/nat_gateway.go index 03744c8a..c65a2165 100644 --- a/sources/ec2/nat_gateway.go +++ b/adapters/ec2/nat_gateway.go @@ -4,7 +4,7 @@ import ( "context" "github.com/aws/aws-sdk-go-v2/service/ec2" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -26,7 +26,7 @@ func natGatewayOutputMapper(_ context.Context, _ *ec2.Client, scope string, _ *e for _, ng := range output.NatGateways { var err error var attrs *sdp.ItemAttributes - attrs, err = sources.ToAttributesWithExclude(ng, "tags") + attrs, err = adapters.ToAttributesWithExclude(ng, "tags") if err != nil { return nil, &sdp.QueryError{ @@ -150,20 +150,41 @@ func natGatewayOutputMapper(_ context.Context, _ *ec2.Client, scope string, _ *e // +overmind:group AWS // +overmind:terraform:queryMap aws_nat_gateway.id -func NewNatGatewaySource(client *ec2.Client, accountID string, region string) *sources.DescribeOnlySource[*ec2.DescribeNatGatewaysInput, *ec2.DescribeNatGatewaysOutput, *ec2.Client, *ec2.Options] { - return &sources.DescribeOnlySource[*ec2.DescribeNatGatewaysInput, *ec2.DescribeNatGatewaysOutput, *ec2.Client, *ec2.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "ec2-nat-gateway", +func NewNatGatewayAdapter(client *ec2.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*ec2.DescribeNatGatewaysInput, *ec2.DescribeNatGatewaysOutput, *ec2.Client, *ec2.Options] { + return &adapters.DescribeOnlyAdapter[*ec2.DescribeNatGatewaysInput, *ec2.DescribeNatGatewaysOutput, *ec2.Client, *ec2.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "ec2-nat-gateway", + AdapterMetadata: NatGatewayMetadata(), DescribeFunc: func(ctx context.Context, client *ec2.Client, input *ec2.DescribeNatGatewaysInput) (*ec2.DescribeNatGatewaysOutput, error) { return client.DescribeNatGateways(ctx, input) }, InputMapperGet: natGatewayInputMapperGet, InputMapperList: natGatewayInputMapperList, - PaginatorBuilder: func(client *ec2.Client, params *ec2.DescribeNatGatewaysInput) sources.Paginator[*ec2.DescribeNatGatewaysOutput, *ec2.Options] { + PaginatorBuilder: func(client *ec2.Client, params *ec2.DescribeNatGatewaysInput) adapters.Paginator[*ec2.DescribeNatGatewaysOutput, *ec2.Options] { return ec2.NewDescribeNatGatewaysPaginator(client, params) }, OutputMapper: natGatewayOutputMapper, } } + +func NatGatewayMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "ec2-nat-gateway", + DescriptiveName: "NAT Gateway", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a NAT Gateway by ID", + ListDescription: "List all NAT gateways", + SearchDescription: "Search for NAT gateways by ARN", + }, + PotentialLinks: []string{"ec2-vpc", "ec2-subnet", "ec2-network-interface", "ip"}, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_nat_gateway.id"}, + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + } +} diff --git a/sources/ec2/nat_gateway_test.go b/adapters/ec2/nat_gateway_test.go similarity index 63% rename from sources/ec2/nat_gateway_test.go rename to adapters/ec2/nat_gateway_test.go index eda9face..49784522 100644 --- a/sources/ec2/nat_gateway_test.go +++ b/adapters/ec2/nat_gateway_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/aws/aws-sdk-go-v2/service/ec2/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -43,47 +43,47 @@ func TestNatGatewayOutputMapper(t *testing.T) { output := &ec2.DescribeNatGatewaysOutput{ NatGateways: []types.NatGateway{ { - CreateTime: sources.PtrTime(time.Now()), - DeleteTime: sources.PtrTime(time.Now()), - FailureCode: sources.PtrString("Gateway.NotAttached"), - FailureMessage: sources.PtrString("Network vpc-0d7892e00e573e701 has no Internet gateway attached"), + CreateTime: adapters.PtrTime(time.Now()), + DeleteTime: adapters.PtrTime(time.Now()), + FailureCode: adapters.PtrString("Gateway.NotAttached"), + FailureMessage: adapters.PtrString("Network vpc-0d7892e00e573e701 has no Internet gateway attached"), NatGatewayAddresses: []types.NatGatewayAddress{ { - AllocationId: sources.PtrString("eipalloc-000a9739291350592"), - NetworkInterfaceId: sources.PtrString("eni-0c59532b8e10343ae"), - PrivateIp: sources.PtrString("172.31.89.23"), + AllocationId: adapters.PtrString("eipalloc-000a9739291350592"), + NetworkInterfaceId: adapters.PtrString("eni-0c59532b8e10343ae"), + PrivateIp: adapters.PtrString("172.31.89.23"), }, }, - NatGatewayId: sources.PtrString("nat-0e4e73d7ac46af25e"), + NatGatewayId: adapters.PtrString("nat-0e4e73d7ac46af25e"), State: types.NatGatewayStateFailed, - SubnetId: sources.PtrString("subnet-0450a637af9984235"), - VpcId: sources.PtrString("vpc-0d7892e00e573e701"), + SubnetId: adapters.PtrString("subnet-0450a637af9984235"), + VpcId: adapters.PtrString("vpc-0d7892e00e573e701"), Tags: []types.Tag{ { - Key: sources.PtrString("Name"), - Value: sources.PtrString("test"), + Key: adapters.PtrString("Name"), + Value: adapters.PtrString("test"), }, }, ConnectivityType: types.ConnectivityTypePublic, }, { - CreateTime: sources.PtrTime(time.Now()), + CreateTime: adapters.PtrTime(time.Now()), NatGatewayAddresses: []types.NatGatewayAddress{ { - AllocationId: sources.PtrString("eipalloc-000a9739291350592"), - NetworkInterfaceId: sources.PtrString("eni-0b4652e6f2aa36d78"), - PrivateIp: sources.PtrString("172.31.35.98"), - PublicIp: sources.PtrString("18.170.133.9"), + AllocationId: adapters.PtrString("eipalloc-000a9739291350592"), + NetworkInterfaceId: adapters.PtrString("eni-0b4652e6f2aa36d78"), + PrivateIp: adapters.PtrString("172.31.35.98"), + PublicIp: adapters.PtrString("18.170.133.9"), }, }, - NatGatewayId: sources.PtrString("nat-0e07f7530ef076766"), + NatGatewayId: adapters.PtrString("nat-0e07f7530ef076766"), State: types.NatGatewayStateAvailable, - SubnetId: sources.PtrString("subnet-0d8ae4b4e07647efa"), - VpcId: sources.PtrString("vpc-0d7892e00e573e701"), + SubnetId: adapters.PtrString("subnet-0d8ae4b4e07647efa"), + VpcId: adapters.PtrString("vpc-0d7892e00e573e701"), Tags: []types.Tag{ { - Key: sources.PtrString("Name"), - Value: sources.PtrString("test"), + Key: adapters.PtrString("Name"), + Value: adapters.PtrString("test"), }, }, ConnectivityType: types.ConnectivityTypePublic, @@ -111,7 +111,7 @@ func TestNatGatewayOutputMapper(t *testing.T) { // It doesn't really make sense to test anything other than the linked items // since the attributes are converted automatically - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "ec2-network-interface", ExpectedMethod: sdp.QueryMethod_GET, @@ -148,13 +148,13 @@ func TestNatGatewayOutputMapper(t *testing.T) { } -func TestNewNatGatewaySource(t *testing.T) { +func TestNewNatGatewayAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewNatGatewaySource(client, account, region) + adapter := NewNatGatewayAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/ec2/network_acl.go b/adapters/ec2/network_acl.go similarity index 68% rename from sources/ec2/network_acl.go rename to adapters/ec2/network_acl.go index 6357f773..bdf89c56 100644 --- a/sources/ec2/network_acl.go +++ b/adapters/ec2/network_acl.go @@ -4,7 +4,7 @@ import ( "context" "github.com/aws/aws-sdk-go-v2/service/ec2" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -26,7 +26,7 @@ func networkAclOutputMapper(_ context.Context, _ *ec2.Client, scope string, _ *e for _, networkAcl := range output.NetworkAcls { var err error var attrs *sdp.ItemAttributes - attrs, err = sources.ToAttributesWithExclude(networkAcl, "tags") + attrs, err = adapters.ToAttributesWithExclude(networkAcl, "tags") if err != nil { return nil, &sdp.QueryError{ @@ -97,20 +97,41 @@ func networkAclOutputMapper(_ context.Context, _ *ec2.Client, scope string, _ *e // +overmind:group AWS // +overmind:terraform:queryMap aws_network_acl.id -func NewNetworkAclSource(client *ec2.Client, accountID string, region string) *sources.DescribeOnlySource[*ec2.DescribeNetworkAclsInput, *ec2.DescribeNetworkAclsOutput, *ec2.Client, *ec2.Options] { - return &sources.DescribeOnlySource[*ec2.DescribeNetworkAclsInput, *ec2.DescribeNetworkAclsOutput, *ec2.Client, *ec2.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "ec2-network-acl", +func NewNetworkAclAdapter(client *ec2.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*ec2.DescribeNetworkAclsInput, *ec2.DescribeNetworkAclsOutput, *ec2.Client, *ec2.Options] { + return &adapters.DescribeOnlyAdapter[*ec2.DescribeNetworkAclsInput, *ec2.DescribeNetworkAclsOutput, *ec2.Client, *ec2.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "ec2-network-acl", + AdapterMetadata: NetworkAclMetadata(), DescribeFunc: func(ctx context.Context, client *ec2.Client, input *ec2.DescribeNetworkAclsInput) (*ec2.DescribeNetworkAclsOutput, error) { return client.DescribeNetworkAcls(ctx, input) }, InputMapperGet: networkAclInputMapperGet, InputMapperList: networkAclInputMapperList, - PaginatorBuilder: func(client *ec2.Client, params *ec2.DescribeNetworkAclsInput) sources.Paginator[*ec2.DescribeNetworkAclsOutput, *ec2.Options] { + PaginatorBuilder: func(client *ec2.Client, params *ec2.DescribeNetworkAclsInput) adapters.Paginator[*ec2.DescribeNetworkAclsOutput, *ec2.Options] { return ec2.NewDescribeNetworkAclsPaginator(client, params) }, OutputMapper: networkAclOutputMapper, } } + +func NetworkAclMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "ec2-network-acl", + DescriptiveName: "Network ACL", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a network ACL", + ListDescription: "List all network ACLs", + SearchDescription: "Search for network ACLs by ARN", + }, + PotentialLinks: []string{"ec2-subnet", "ec2-vpc"}, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_network_acl.id"}, + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_SECURITY, + } +} diff --git a/sources/ec2/network_acl_test.go b/adapters/ec2/network_acl_test.go similarity index 60% rename from sources/ec2/network_acl_test.go rename to adapters/ec2/network_acl_test.go index 3fe86396..2f8bd24e 100644 --- a/sources/ec2/network_acl_test.go +++ b/adapters/ec2/network_acl_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/aws/aws-sdk-go-v2/service/ec2/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -45,42 +45,42 @@ func TestNetworkAclOutputMapper(t *testing.T) { { Associations: []types.NetworkAclAssociation{ { - NetworkAclAssociationId: sources.PtrString("aclassoc-0f85f8b1fde0a5939"), - NetworkAclId: sources.PtrString("acl-0a346e8e6f5a9ad91"), - SubnetId: sources.PtrString("subnet-0450a637af9984235"), + NetworkAclAssociationId: adapters.PtrString("aclassoc-0f85f8b1fde0a5939"), + NetworkAclId: adapters.PtrString("acl-0a346e8e6f5a9ad91"), + SubnetId: adapters.PtrString("subnet-0450a637af9984235"), }, { - NetworkAclAssociationId: sources.PtrString("aclassoc-064b78003a2d309a4"), - NetworkAclId: sources.PtrString("acl-0a346e8e6f5a9ad91"), - SubnetId: sources.PtrString("subnet-06c0dea0437180c61"), + NetworkAclAssociationId: adapters.PtrString("aclassoc-064b78003a2d309a4"), + NetworkAclId: adapters.PtrString("acl-0a346e8e6f5a9ad91"), + SubnetId: adapters.PtrString("subnet-06c0dea0437180c61"), }, { - NetworkAclAssociationId: sources.PtrString("aclassoc-0575080579a7381f5"), - NetworkAclId: sources.PtrString("acl-0a346e8e6f5a9ad91"), - SubnetId: sources.PtrString("subnet-0d8ae4b4e07647efa"), + NetworkAclAssociationId: adapters.PtrString("aclassoc-0575080579a7381f5"), + NetworkAclId: adapters.PtrString("acl-0a346e8e6f5a9ad91"), + SubnetId: adapters.PtrString("subnet-0d8ae4b4e07647efa"), }, }, Entries: []types.NetworkAclEntry{ { - CidrBlock: sources.PtrString("0.0.0.0/0"), - Egress: sources.PtrBool(true), - Protocol: sources.PtrString("-1"), + CidrBlock: adapters.PtrString("0.0.0.0/0"), + Egress: adapters.PtrBool(true), + Protocol: adapters.PtrString("-1"), RuleAction: types.RuleActionAllow, - RuleNumber: sources.PtrInt32(100), + RuleNumber: adapters.PtrInt32(100), }, { - CidrBlock: sources.PtrString("0.0.0.0/0"), - Egress: sources.PtrBool(true), - Protocol: sources.PtrString("-1"), + CidrBlock: adapters.PtrString("0.0.0.0/0"), + Egress: adapters.PtrBool(true), + Protocol: adapters.PtrString("-1"), RuleAction: types.RuleActionDeny, - RuleNumber: sources.PtrInt32(32767), + RuleNumber: adapters.PtrInt32(32767), }, }, - IsDefault: sources.PtrBool(true), - NetworkAclId: sources.PtrString("acl-0a346e8e6f5a9ad91"), + IsDefault: adapters.PtrBool(true), + NetworkAclId: adapters.PtrString("acl-0a346e8e6f5a9ad91"), Tags: []types.Tag{}, - VpcId: sources.PtrString("vpc-0d7892e00e573e701"), - OwnerId: sources.PtrString("052392120703"), + VpcId: adapters.PtrString("vpc-0d7892e00e573e701"), + OwnerId: adapters.PtrString("052392120703"), }, }, } @@ -99,7 +99,7 @@ func TestNetworkAclOutputMapper(t *testing.T) { // It doesn't really make sense to test anything other than the linked items // since the attributes are converted automatically - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "ec2-subnet", ExpectedMethod: sdp.QueryMethod_GET, @@ -130,13 +130,13 @@ func TestNetworkAclOutputMapper(t *testing.T) { } -func TestNewNetworkAclSource(t *testing.T) { +func TestNewNetworkAclAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewNetworkAclSource(client, account, region) + adapter := NewNetworkAclAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/ec2/network_interface.go b/adapters/ec2/network_interface.go similarity index 82% rename from sources/ec2/network_interface.go rename to adapters/ec2/network_interface.go index f88d92ea..84b5e72f 100644 --- a/sources/ec2/network_interface.go +++ b/adapters/ec2/network_interface.go @@ -4,7 +4,7 @@ import ( "context" "github.com/aws/aws-sdk-go-v2/service/ec2" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -26,7 +26,7 @@ func networkInterfaceOutputMapper(_ context.Context, _ *ec2.Client, scope string for _, ni := range output.NetworkInterfaces { var err error var attrs *sdp.ItemAttributes - attrs, err = sources.ToAttributesWithExclude(ni, "tagSet") + attrs, err = adapters.ToAttributesWithExclude(ni, "tagSet") if err != nil { return nil, &sdp.QueryError{ @@ -261,20 +261,41 @@ func networkInterfaceOutputMapper(_ context.Context, _ *ec2.Client, scope string // +overmind:group AWS // +overmind:terraform:queryMap aws_network_interface.id -func NewNetworkInterfaceSource(client *ec2.Client, accountID string, region string) *sources.DescribeOnlySource[*ec2.DescribeNetworkInterfacesInput, *ec2.DescribeNetworkInterfacesOutput, *ec2.Client, *ec2.Options] { - return &sources.DescribeOnlySource[*ec2.DescribeNetworkInterfacesInput, *ec2.DescribeNetworkInterfacesOutput, *ec2.Client, *ec2.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "ec2-network-interface", +func NewNetworkInterfaceAdapter(client *ec2.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*ec2.DescribeNetworkInterfacesInput, *ec2.DescribeNetworkInterfacesOutput, *ec2.Client, *ec2.Options] { + return &adapters.DescribeOnlyAdapter[*ec2.DescribeNetworkInterfacesInput, *ec2.DescribeNetworkInterfacesOutput, *ec2.Client, *ec2.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "ec2-network-interface", + AdapterMetadata: NetworkInterfaceMetadata(), DescribeFunc: func(ctx context.Context, client *ec2.Client, input *ec2.DescribeNetworkInterfacesInput) (*ec2.DescribeNetworkInterfacesOutput, error) { return client.DescribeNetworkInterfaces(ctx, input) }, InputMapperGet: networkInterfaceInputMapperGet, InputMapperList: networkInterfaceInputMapperList, - PaginatorBuilder: func(client *ec2.Client, params *ec2.DescribeNetworkInterfacesInput) sources.Paginator[*ec2.DescribeNetworkInterfacesOutput, *ec2.Options] { + PaginatorBuilder: func(client *ec2.Client, params *ec2.DescribeNetworkInterfacesInput) adapters.Paginator[*ec2.DescribeNetworkInterfacesOutput, *ec2.Options] { return ec2.NewDescribeNetworkInterfacesPaginator(client, params) }, OutputMapper: networkInterfaceOutputMapper, } } + +func NetworkInterfaceMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "ec2-network-interface", + DescriptiveName: "EC2 Network Interface", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a network interface by ID", + ListDescription: "List all network interfaces", + SearchDescription: "Search network interfaces by ARN", + }, + PotentialLinks: []string{"ec2-instance", "ec2-security-group", "ip", "dns", "ec2-subnet", "ec2-vpc"}, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_network_interface.id"}, + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + } +} diff --git a/sources/ec2/network_interface_permissions.go b/adapters/ec2/network_interface_permissions.go similarity index 64% rename from sources/ec2/network_interface_permissions.go rename to adapters/ec2/network_interface_permissions.go index 9880e56d..948f762f 100644 --- a/sources/ec2/network_interface_permissions.go +++ b/adapters/ec2/network_interface_permissions.go @@ -4,7 +4,7 @@ import ( "context" "github.com/aws/aws-sdk-go-v2/service/ec2" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -26,7 +26,7 @@ func networkInterfacePermissionOutputMapper(_ context.Context, _ *ec2.Client, sc for _, ni := range output.NetworkInterfacePermissions { var err error var attrs *sdp.ItemAttributes - attrs, err = sources.ToAttributesWithExclude(ni) + attrs, err = adapters.ToAttributesWithExclude(ni) if err != nil { return nil, &sdp.QueryError{ @@ -74,20 +74,38 @@ func networkInterfacePermissionOutputMapper(_ context.Context, _ *ec2.Client, sc // +overmind:search Search network interface permissions by ARN // +overmind:group AWS -func NewNetworkInterfacePermissionSource(client *ec2.Client, accountID string, region string) *sources.DescribeOnlySource[*ec2.DescribeNetworkInterfacePermissionsInput, *ec2.DescribeNetworkInterfacePermissionsOutput, *ec2.Client, *ec2.Options] { - return &sources.DescribeOnlySource[*ec2.DescribeNetworkInterfacePermissionsInput, *ec2.DescribeNetworkInterfacePermissionsOutput, *ec2.Client, *ec2.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "ec2-network-interface-permission", +func NewNetworkInterfacePermissionAdapter(client *ec2.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*ec2.DescribeNetworkInterfacePermissionsInput, *ec2.DescribeNetworkInterfacePermissionsOutput, *ec2.Client, *ec2.Options] { + return &adapters.DescribeOnlyAdapter[*ec2.DescribeNetworkInterfacePermissionsInput, *ec2.DescribeNetworkInterfacePermissionsOutput, *ec2.Client, *ec2.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "ec2-network-interface-permission", + AdapterMetadata: NetworkInterfacePermissionMetadata(), DescribeFunc: func(ctx context.Context, client *ec2.Client, input *ec2.DescribeNetworkInterfacePermissionsInput) (*ec2.DescribeNetworkInterfacePermissionsOutput, error) { return client.DescribeNetworkInterfacePermissions(ctx, input) }, InputMapperGet: networkInterfacePermissionInputMapperGet, InputMapperList: networkInterfacePermissionInputMapperList, - PaginatorBuilder: func(client *ec2.Client, params *ec2.DescribeNetworkInterfacePermissionsInput) sources.Paginator[*ec2.DescribeNetworkInterfacePermissionsOutput, *ec2.Options] { + PaginatorBuilder: func(client *ec2.Client, params *ec2.DescribeNetworkInterfacePermissionsInput) adapters.Paginator[*ec2.DescribeNetworkInterfacePermissionsOutput, *ec2.Options] { return ec2.NewDescribeNetworkInterfacePermissionsPaginator(client, params) }, OutputMapper: networkInterfacePermissionOutputMapper, } } + +func NetworkInterfacePermissionMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "ec2-network-interface-permission", + DescriptiveName: "Network Interface Permission", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a network interface permission by ID", + ListDescription: "List all network interface permissions", + SearchDescription: "Search network interface permissions by ARN", + }, + PotentialLinks: []string{"ec2-network-interface"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_SECURITY, + } +} diff --git a/sources/ec2/network_interface_permissions_test.go b/adapters/ec2/network_interface_permissions_test.go similarity index 80% rename from sources/ec2/network_interface_permissions_test.go rename to adapters/ec2/network_interface_permissions_test.go index b1e83cf2..d6e551cb 100644 --- a/sources/ec2/network_interface_permissions_test.go +++ b/adapters/ec2/network_interface_permissions_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/aws/aws-sdk-go-v2/service/ec2/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -43,9 +43,9 @@ func TestNetworkInterfacePermissionOutputMapper(t *testing.T) { output := &ec2.DescribeNetworkInterfacePermissionsOutput{ NetworkInterfacePermissions: []types.NetworkInterfacePermission{ { - NetworkInterfacePermissionId: sources.PtrString("eni-perm-0b6211455242c105e"), - NetworkInterfaceId: sources.PtrString("eni-07f8f3d404036c833"), - AwsService: sources.PtrString("routing.hyperplane.eu-west-2.amazonaws.com"), + NetworkInterfacePermissionId: adapters.PtrString("eni-perm-0b6211455242c105e"), + NetworkInterfaceId: adapters.PtrString("eni-07f8f3d404036c833"), + AwsService: adapters.PtrString("routing.hyperplane.eu-west-2.amazonaws.com"), Permission: types.InterfacePermissionTypeInstanceAttach, PermissionState: &types.NetworkInterfacePermissionState{ State: types.NetworkInterfacePermissionStateCodeGranted, @@ -74,7 +74,7 @@ func TestNetworkInterfacePermissionOutputMapper(t *testing.T) { // It doesn't really make sense to test anything other than the linked items // since the attributes are converted automatically - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "ec2-network-interface", ExpectedMethod: sdp.QueryMethod_GET, @@ -87,13 +87,13 @@ func TestNetworkInterfacePermissionOutputMapper(t *testing.T) { } -func TestNewNetworkInterfacePermissionSource(t *testing.T) { +func TestNewNetworkInterfacePermissionAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewNetworkInterfacePermissionSource(client, account, region) + adapter := NewNetworkInterfacePermissionAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/ec2/network_interface_test.go b/adapters/ec2/network_interface_test.go similarity index 60% rename from sources/ec2/network_interface_test.go rename to adapters/ec2/network_interface_test.go index ea3c4d81..a1390a28 100644 --- a/sources/ec2/network_interface_test.go +++ b/adapters/ec2/network_interface_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/aws/aws-sdk-go-v2/service/ec2/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -44,62 +44,62 @@ func TestNetworkInterfaceOutputMapper(t *testing.T) { NetworkInterfaces: []types.NetworkInterface{ { Association: &types.NetworkInterfaceAssociation{ - AllocationId: sources.PtrString("eipalloc-000a9739291350592"), - AssociationId: sources.PtrString("eipassoc-049cda1f947e5efe6"), - IpOwnerId: sources.PtrString("052392120703"), - PublicDnsName: sources.PtrString("ec2-18-170-133-9.eu-west-2.compute.amazonaws.com"), - PublicIp: sources.PtrString("18.170.133.9"), + AllocationId: adapters.PtrString("eipalloc-000a9739291350592"), + AssociationId: adapters.PtrString("eipassoc-049cda1f947e5efe6"), + IpOwnerId: adapters.PtrString("052392120703"), + PublicDnsName: adapters.PtrString("ec2-18-170-133-9.eu-west-2.compute.amazonaws.com"), + PublicIp: adapters.PtrString("18.170.133.9"), }, Attachment: &types.NetworkInterfaceAttachment{ - AttachmentId: sources.PtrString("ela-attach-03e560efca8c9e5d8"), - DeleteOnTermination: sources.PtrBool(false), - DeviceIndex: sources.PtrInt32(1), - InstanceOwnerId: sources.PtrString("amazon-aws"), + AttachmentId: adapters.PtrString("ela-attach-03e560efca8c9e5d8"), + DeleteOnTermination: adapters.PtrBool(false), + DeviceIndex: adapters.PtrInt32(1), + InstanceOwnerId: adapters.PtrString("amazon-aws"), Status: types.AttachmentStatusAttached, - InstanceId: sources.PtrString("foo"), + InstanceId: adapters.PtrString("foo"), }, - AvailabilityZone: sources.PtrString("eu-west-2b"), - Description: sources.PtrString("Interface for NAT Gateway nat-0e07f7530ef076766"), + AvailabilityZone: adapters.PtrString("eu-west-2b"), + Description: adapters.PtrString("Interface for NAT Gateway nat-0e07f7530ef076766"), Groups: []types.GroupIdentifier{ { - GroupId: sources.PtrString("group-123"), - GroupName: sources.PtrString("something"), + GroupId: adapters.PtrString("group-123"), + GroupName: adapters.PtrString("something"), }, }, InterfaceType: types.NetworkInterfaceTypeNatGateway, Ipv6Addresses: []types.NetworkInterfaceIpv6Address{ { - Ipv6Address: sources.PtrString("2001:db8:1234:0000:0000:0000:0000:0000"), + Ipv6Address: adapters.PtrString("2001:db8:1234:0000:0000:0000:0000:0000"), }, }, - MacAddress: sources.PtrString("0a:f4:55:b0:6c:be"), - NetworkInterfaceId: sources.PtrString("eni-0b4652e6f2aa36d78"), - OwnerId: sources.PtrString("052392120703"), - PrivateDnsName: sources.PtrString("ip-172-31-35-98.eu-west-2.compute.internal"), - PrivateIpAddress: sources.PtrString("172.31.35.98"), + MacAddress: adapters.PtrString("0a:f4:55:b0:6c:be"), + NetworkInterfaceId: adapters.PtrString("eni-0b4652e6f2aa36d78"), + OwnerId: adapters.PtrString("052392120703"), + PrivateDnsName: adapters.PtrString("ip-172-31-35-98.eu-west-2.compute.internal"), + PrivateIpAddress: adapters.PtrString("172.31.35.98"), PrivateIpAddresses: []types.NetworkInterfacePrivateIpAddress{ { Association: &types.NetworkInterfaceAssociation{ - AllocationId: sources.PtrString("eipalloc-000a9739291350592"), - AssociationId: sources.PtrString("eipassoc-049cda1f947e5efe6"), - IpOwnerId: sources.PtrString("052392120703"), - PublicDnsName: sources.PtrString("ec2-18-170-133-9.eu-west-2.compute.amazonaws.com"), - PublicIp: sources.PtrString("18.170.133.9"), - CarrierIp: sources.PtrString("18.170.133.10"), - CustomerOwnedIp: sources.PtrString("18.170.133.11"), + AllocationId: adapters.PtrString("eipalloc-000a9739291350592"), + AssociationId: adapters.PtrString("eipassoc-049cda1f947e5efe6"), + IpOwnerId: adapters.PtrString("052392120703"), + PublicDnsName: adapters.PtrString("ec2-18-170-133-9.eu-west-2.compute.amazonaws.com"), + PublicIp: adapters.PtrString("18.170.133.9"), + CarrierIp: adapters.PtrString("18.170.133.10"), + CustomerOwnedIp: adapters.PtrString("18.170.133.11"), }, - Primary: sources.PtrBool(true), - PrivateDnsName: sources.PtrString("ip-172-31-35-98.eu-west-2.compute.internal"), - PrivateIpAddress: sources.PtrString("172.31.35.98"), + Primary: adapters.PtrBool(true), + PrivateDnsName: adapters.PtrString("ip-172-31-35-98.eu-west-2.compute.internal"), + PrivateIpAddress: adapters.PtrString("172.31.35.98"), }, }, - RequesterId: sources.PtrString("440527171281"), - RequesterManaged: sources.PtrBool(true), - SourceDestCheck: sources.PtrBool(false), + RequesterId: adapters.PtrString("440527171281"), + RequesterManaged: adapters.PtrBool(true), + SourceDestCheck: adapters.PtrBool(false), Status: types.NetworkInterfaceStatusInUse, - SubnetId: sources.PtrString("subnet-0d8ae4b4e07647efa"), + SubnetId: adapters.PtrString("subnet-0d8ae4b4e07647efa"), TagSet: []types.Tag{}, - VpcId: sources.PtrString("vpc-0d7892e00e573e701"), + VpcId: adapters.PtrString("vpc-0d7892e00e573e701"), }, }, } @@ -124,7 +124,7 @@ func TestNetworkInterfaceOutputMapper(t *testing.T) { // It doesn't really make sense to test anything other than the linked items // since the attributes are converted automatically - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "ec2-instance", ExpectedMethod: sdp.QueryMethod_GET, @@ -197,13 +197,13 @@ func TestNetworkInterfaceOutputMapper(t *testing.T) { } -func TestNewNetworkInterfaceSource(t *testing.T) { +func TestNewNetworkInterfaceAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewNetworkInterfaceSource(client, account, region) + adapter := NewNetworkInterfaceAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/ec2/placement_group.go b/adapters/ec2/placement_group.go similarity index 59% rename from sources/ec2/placement_group.go rename to adapters/ec2/placement_group.go index 410117a0..7d5bb352 100644 --- a/sources/ec2/placement_group.go +++ b/adapters/ec2/placement_group.go @@ -4,7 +4,7 @@ import ( "context" "github.com/aws/aws-sdk-go-v2/service/ec2" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -26,7 +26,7 @@ func placementGroupOutputMapper(_ context.Context, _ *ec2.Client, scope string, for _, ng := range output.PlacementGroups { var err error var attrs *sdp.ItemAttributes - attrs, err = sources.ToAttributesWithExclude(ng, "tags") + attrs, err = adapters.ToAttributesWithExclude(ng, "tags") if err != nil { return nil, &sdp.QueryError{ @@ -59,12 +59,13 @@ func placementGroupOutputMapper(_ context.Context, _ *ec2.Client, scope string, // +overmind:group AWS // +overmind:terraform:queryMap aws_placement_group.id -func NewPlacementGroupSource(client *ec2.Client, accountID string, region string) *sources.DescribeOnlySource[*ec2.DescribePlacementGroupsInput, *ec2.DescribePlacementGroupsOutput, *ec2.Client, *ec2.Options] { - return &sources.DescribeOnlySource[*ec2.DescribePlacementGroupsInput, *ec2.DescribePlacementGroupsOutput, *ec2.Client, *ec2.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "ec2-placement-group", +func NewPlacementGroupAdapter(client *ec2.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*ec2.DescribePlacementGroupsInput, *ec2.DescribePlacementGroupsOutput, *ec2.Client, *ec2.Options] { + return &adapters.DescribeOnlyAdapter[*ec2.DescribePlacementGroupsInput, *ec2.DescribePlacementGroupsOutput, *ec2.Client, *ec2.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "ec2-placement-group", + AdapterMetadata: PlacementGroupMetadata(), DescribeFunc: func(ctx context.Context, client *ec2.Client, input *ec2.DescribePlacementGroupsInput) (*ec2.DescribePlacementGroupsOutput, error) { return client.DescribePlacementGroups(ctx, input) }, @@ -73,3 +74,22 @@ func NewPlacementGroupSource(client *ec2.Client, accountID string, region string OutputMapper: placementGroupOutputMapper, } } + +func PlacementGroupMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "ec2-placement-group", + DescriptiveName: "Placement Group", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a placement group by ID", + ListDescription: "List all placement groups", + SearchDescription: "Search for placement groups by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_placement_group.id"}, + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_COMPUTE_APPLICATION, + } +} diff --git a/sources/ec2/placement_group_test.go b/adapters/ec2/placement_group_test.go similarity index 79% rename from sources/ec2/placement_group_test.go rename to adapters/ec2/placement_group_test.go index 57c5a8e5..7b23e492 100644 --- a/sources/ec2/placement_group_test.go +++ b/adapters/ec2/placement_group_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/aws/aws-sdk-go-v2/service/ec2/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" ) func TestPlacementGroupInputMapperGet(t *testing.T) { @@ -42,13 +42,13 @@ func TestPlacementGroupOutputMapper(t *testing.T) { output := &ec2.DescribePlacementGroupsOutput{ PlacementGroups: []types.PlacementGroup{ { - GroupArn: sources.PtrString("arn"), - GroupId: sources.PtrString("id"), - GroupName: sources.PtrString("name"), + GroupArn: adapters.PtrString("arn"), + GroupId: adapters.PtrString("id"), + GroupName: adapters.PtrString("name"), SpreadLevel: types.SpreadLevelHost, State: types.PlacementGroupStateAvailable, Strategy: types.PlacementStrategyCluster, - PartitionCount: sources.PtrInt32(1), + PartitionCount: adapters.PtrInt32(1), Tags: []types.Tag{}, }, }, @@ -72,13 +72,13 @@ func TestPlacementGroupOutputMapper(t *testing.T) { } -func TestNewPlacementGroupSource(t *testing.T) { +func TestNewPlacementGroupAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewPlacementGroupSource(client, account, region) + adapter := NewPlacementGroupAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/ec2/reserved_instance.go b/adapters/ec2/reserved_instance.go similarity index 60% rename from sources/ec2/reserved_instance.go rename to adapters/ec2/reserved_instance.go index 78447eca..3abb6b18 100644 --- a/sources/ec2/reserved_instance.go +++ b/adapters/ec2/reserved_instance.go @@ -4,7 +4,7 @@ import ( "context" "github.com/aws/aws-sdk-go-v2/service/ec2" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -24,7 +24,7 @@ func reservedInstanceOutputMapper(_ context.Context, _ *ec2.Client, scope string items := make([]*sdp.Item, 0) for _, reservation := range output.ReservedInstances { - attrs, err := sources.ToAttributesWithExclude(reservation, "tags") + attrs, err := adapters.ToAttributesWithExclude(reservation, "tags") if err != nil { return nil, &sdp.QueryError{ @@ -56,12 +56,13 @@ func reservedInstanceOutputMapper(_ context.Context, _ *ec2.Client, scope string // +overmind:search Search reserved EC2 instances by ARN // +overmind:group AWS -func NewReservedInstanceSource(client *ec2.Client, accountID string, region string) *sources.DescribeOnlySource[*ec2.DescribeReservedInstancesInput, *ec2.DescribeReservedInstancesOutput, *ec2.Client, *ec2.Options] { - return &sources.DescribeOnlySource[*ec2.DescribeReservedInstancesInput, *ec2.DescribeReservedInstancesOutput, *ec2.Client, *ec2.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "ec2-reserved-instance", +func NewReservedInstanceAdapter(client *ec2.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*ec2.DescribeReservedInstancesInput, *ec2.DescribeReservedInstancesOutput, *ec2.Client, *ec2.Options] { + return &adapters.DescribeOnlyAdapter[*ec2.DescribeReservedInstancesInput, *ec2.DescribeReservedInstancesOutput, *ec2.Client, *ec2.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "ec2-reserved-instance", + AdapterMetadata: ReservedInstanceMetadata(), DescribeFunc: func(ctx context.Context, client *ec2.Client, input *ec2.DescribeReservedInstancesInput) (*ec2.DescribeReservedInstancesOutput, error) { return client.DescribeReservedInstances(ctx, input) }, @@ -70,3 +71,19 @@ func NewReservedInstanceSource(client *ec2.Client, accountID string, region stri OutputMapper: reservedInstanceOutputMapper, } } + +func ReservedInstanceMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "ec2-reserved-instance", + DescriptiveName: "Reserved EC2 Instance", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a reserved EC2 instance by ID", + ListDescription: "List all reserved EC2 instances", + SearchDescription: "Search reserved EC2 instances by ARN", + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_COMPUTE_APPLICATION, + } +} diff --git a/sources/ec2/reserved_instance_test.go b/adapters/ec2/reserved_instance_test.go similarity index 75% rename from sources/ec2/reserved_instance_test.go rename to adapters/ec2/reserved_instance_test.go index 4bd4fa45..0097ea8a 100644 --- a/sources/ec2/reserved_instance_test.go +++ b/adapters/ec2/reserved_instance_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/aws/aws-sdk-go-v2/service/ec2/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" ) func TestReservedInstanceInputMapperGet(t *testing.T) { @@ -42,12 +42,12 @@ func TestReservedInstanceOutputMapper(t *testing.T) { output := &ec2.DescribeReservedInstancesOutput{ ReservedInstances: []types.ReservedInstances{ { - AvailabilityZone: sources.PtrString("az"), + AvailabilityZone: adapters.PtrString("az"), CurrencyCode: types.CurrencyCodeValuesUsd, - Duration: sources.PtrInt64(100), - End: sources.PtrTime(time.Now()), - FixedPrice: sources.PtrFloat32(1.23), - InstanceCount: sources.PtrInt32(1), + Duration: adapters.PtrInt64(100), + End: adapters.PtrTime(time.Now()), + FixedPrice: adapters.PtrFloat32(1.23), + InstanceCount: adapters.PtrInt32(1), InstanceTenancy: types.TenancyDedicated, InstanceType: types.InstanceTypeA14xlarge, OfferingClass: types.OfferingClassTypeConvertible, @@ -55,15 +55,15 @@ func TestReservedInstanceOutputMapper(t *testing.T) { ProductDescription: types.RIProductDescription("foo"), RecurringCharges: []types.RecurringCharge{ { - Amount: sources.PtrFloat64(1.111), + Amount: adapters.PtrFloat64(1.111), Frequency: types.RecurringChargeFrequencyHourly, }, }, - ReservedInstancesId: sources.PtrString("id"), + ReservedInstancesId: adapters.PtrString("id"), Scope: types.ScopeAvailabilityZone, - Start: sources.PtrTime(time.Now()), + Start: adapters.PtrTime(time.Now()), State: types.ReservedInstanceStateActive, - UsagePrice: sources.PtrFloat32(99.00000001), + UsagePrice: adapters.PtrFloat32(99.00000001), }, }, } @@ -88,19 +88,19 @@ func TestReservedInstanceOutputMapper(t *testing.T) { // It doesn't really make sense to test anything other than the linked items // since the attributes are converted automatically - tests := sources.QueryTests{} + tests := adapters.QueryTests{} tests.Execute(t, item) } -func TestNewReservedInstanceSource(t *testing.T) { +func TestNewReservedInstanceAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewReservedInstanceSource(client, account, region) + adapter := NewReservedInstanceAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/ec2/route_table.go b/adapters/ec2/route_table.go similarity index 81% rename from sources/ec2/route_table.go rename to adapters/ec2/route_table.go index c3654679..21d5819c 100644 --- a/sources/ec2/route_table.go +++ b/adapters/ec2/route_table.go @@ -5,7 +5,7 @@ import ( "strings" "github.com/aws/aws-sdk-go-v2/service/ec2" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -27,7 +27,7 @@ func routeTableOutputMapper(_ context.Context, _ *ec2.Client, scope string, _ *e for _, rt := range output.RouteTables { var err error var attrs *sdp.ItemAttributes - attrs, err = sources.ToAttributesWithExclude(rt, "tags") + attrs, err = adapters.ToAttributesWithExclude(rt, "tags") if err != nil { return nil, &sdp.QueryError{ @@ -272,20 +272,44 @@ func routeTableOutputMapper(_ context.Context, _ *ec2.Client, scope string, _ *e // +overmind:terraform:queryMap aws_default_route_table.default_route_table_id // +overmind:terraform:queryMap aws_route.route_table_id -func NewRouteTableSource(client *ec2.Client, accountID string, region string) *sources.DescribeOnlySource[*ec2.DescribeRouteTablesInput, *ec2.DescribeRouteTablesOutput, *ec2.Client, *ec2.Options] { - return &sources.DescribeOnlySource[*ec2.DescribeRouteTablesInput, *ec2.DescribeRouteTablesOutput, *ec2.Client, *ec2.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "ec2-route-table", +func NewRouteTableAdapter(client *ec2.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*ec2.DescribeRouteTablesInput, *ec2.DescribeRouteTablesOutput, *ec2.Client, *ec2.Options] { + return &adapters.DescribeOnlyAdapter[*ec2.DescribeRouteTablesInput, *ec2.DescribeRouteTablesOutput, *ec2.Client, *ec2.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "ec2-route-table", + AdapterMetadata: RouteTableMetadata(), DescribeFunc: func(ctx context.Context, client *ec2.Client, input *ec2.DescribeRouteTablesInput) (*ec2.DescribeRouteTablesOutput, error) { return client.DescribeRouteTables(ctx, input) }, InputMapperGet: routeTableInputMapperGet, InputMapperList: routeTableInputMapperList, - PaginatorBuilder: func(client *ec2.Client, params *ec2.DescribeRouteTablesInput) sources.Paginator[*ec2.DescribeRouteTablesOutput, *ec2.Options] { + PaginatorBuilder: func(client *ec2.Client, params *ec2.DescribeRouteTablesInput) adapters.Paginator[*ec2.DescribeRouteTablesOutput, *ec2.Options] { return ec2.NewDescribeRouteTablesPaginator(client, params) }, OutputMapper: routeTableOutputMapper, } } + +func RouteTableMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "ec2-route-table", + DescriptiveName: "Route Table", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a route table by ID", + ListDescription: "List all route tables", + SearchDescription: "Search route tables by ARN", + }, + PotentialLinks: []string{"ec2-vpc", "ec2-subnet", "ec2-internet-gateway", "ec2-vpc-endpoint", "ec2-carrier-gateway", "ec2-egress-only-internet-gateway", "ec2-instance", "ec2-local-gateway", "ec2-nat-gateway", "ec2-network-interface", "ec2-transit-gateway", "ec2-vpc-peering-connection"}, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_route_table.id"}, + {TerraformQueryMap: "aws_route_table_association.route_table_id"}, + {TerraformQueryMap: "aws_default_route_table.default_route_table_id"}, + {TerraformQueryMap: "aws_route.route_table_id"}, + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + } +} diff --git a/sources/ec2/route_table_test.go b/adapters/ec2/route_table_test.go similarity index 71% rename from sources/ec2/route_table_test.go rename to adapters/ec2/route_table_test.go index d5796c67..2239d820 100644 --- a/sources/ec2/route_table_test.go +++ b/adapters/ec2/route_table_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/aws/aws-sdk-go-v2/service/ec2/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -45,11 +45,11 @@ func TestRouteTableOutputMapper(t *testing.T) { { Associations: []types.RouteTableAssociation{ { - Main: sources.PtrBool(false), - RouteTableAssociationId: sources.PtrString("rtbassoc-0aa1442039abff3db"), - RouteTableId: sources.PtrString("rtb-00b1197fa95a6b35f"), - SubnetId: sources.PtrString("subnet-06c0dea0437180c61"), - GatewayId: sources.PtrString("ID"), + Main: adapters.PtrBool(false), + RouteTableAssociationId: adapters.PtrString("rtbassoc-0aa1442039abff3db"), + RouteTableId: adapters.PtrString("rtb-00b1197fa95a6b35f"), + SubnetId: adapters.PtrString("subnet-06c0dea0437180c61"), + GatewayId: adapters.PtrString("ID"), AssociationState: &types.RouteTableAssociationState{ State: types.RouteTableAssociationStateCodeAssociated, }, @@ -57,35 +57,35 @@ func TestRouteTableOutputMapper(t *testing.T) { }, PropagatingVgws: []types.PropagatingVgw{ { - GatewayId: sources.PtrString("goo"), + GatewayId: adapters.PtrString("goo"), }, }, - RouteTableId: sources.PtrString("rtb-00b1197fa95a6b35f"), + RouteTableId: adapters.PtrString("rtb-00b1197fa95a6b35f"), Routes: []types.Route{ { - DestinationCidrBlock: sources.PtrString("172.31.0.0/16"), - GatewayId: sources.PtrString("igw-12345"), + DestinationCidrBlock: adapters.PtrString("172.31.0.0/16"), + GatewayId: adapters.PtrString("igw-12345"), Origin: types.RouteOriginCreateRouteTable, State: types.RouteStateActive, }, { - DestinationPrefixListId: sources.PtrString("pl-7ca54015"), - GatewayId: sources.PtrString("vpce-09fcbac4dcf142db3"), + DestinationPrefixListId: adapters.PtrString("pl-7ca54015"), + GatewayId: adapters.PtrString("vpce-09fcbac4dcf142db3"), Origin: types.RouteOriginCreateRoute, State: types.RouteStateActive, - CarrierGatewayId: sources.PtrString("id"), - EgressOnlyInternetGatewayId: sources.PtrString("id"), - InstanceId: sources.PtrString("id"), - InstanceOwnerId: sources.PtrString("id"), - LocalGatewayId: sources.PtrString("id"), - NatGatewayId: sources.PtrString("id"), - NetworkInterfaceId: sources.PtrString("id"), - TransitGatewayId: sources.PtrString("id"), - VpcPeeringConnectionId: sources.PtrString("id"), + CarrierGatewayId: adapters.PtrString("id"), + EgressOnlyInternetGatewayId: adapters.PtrString("id"), + InstanceId: adapters.PtrString("id"), + InstanceOwnerId: adapters.PtrString("id"), + LocalGatewayId: adapters.PtrString("id"), + NatGatewayId: adapters.PtrString("id"), + NetworkInterfaceId: adapters.PtrString("id"), + TransitGatewayId: adapters.PtrString("id"), + VpcPeeringConnectionId: adapters.PtrString("id"), }, }, - VpcId: sources.PtrString("vpc-0d7892e00e573e701"), - OwnerId: sources.PtrString("052392120703"), + VpcId: adapters.PtrString("vpc-0d7892e00e573e701"), + OwnerId: adapters.PtrString("052392120703"), }, }, } @@ -110,7 +110,7 @@ func TestRouteTableOutputMapper(t *testing.T) { // It doesn't really make sense to test anything other than the linked items // since the attributes are converted automatically - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "ec2-subnet", ExpectedMethod: sdp.QueryMethod_GET, @@ -195,13 +195,13 @@ func TestRouteTableOutputMapper(t *testing.T) { } -func TestNewRouteTableSource(t *testing.T) { +func TestNewRouteTableAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewRouteTableSource(client, account, region) + adapter := NewRouteTableAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/ec2/sg.go b/adapters/ec2/sg.go similarity index 71% rename from sources/ec2/sg.go rename to adapters/ec2/sg.go index 43b3ce11..15f12579 100644 --- a/sources/ec2/sg.go +++ b/adapters/ec2/sg.go @@ -5,7 +5,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/aws/aws-sdk-go-v2/service/ec2/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -27,7 +27,7 @@ func securityGroupOutputMapper(_ context.Context, _ *ec2.Client, scope string, _ for _, securityGroup := range output.SecurityGroups { var err error var attrs *sdp.ItemAttributes - attrs, err = sources.ToAttributesWithExclude(securityGroup, "tags") + attrs, err = adapters.ToAttributesWithExclude(securityGroup, "tags") if err != nil { return nil, &sdp.QueryError{ @@ -83,18 +83,19 @@ func securityGroupOutputMapper(_ context.Context, _ *ec2.Client, scope string, _ // +overmind:terraform:queryMap aws_security_group.id // +overmind:terraform:queryMap aws_security_group_rule.security_group_id -func NewSecurityGroupSource(client *ec2.Client, accountID string, region string) *sources.DescribeOnlySource[*ec2.DescribeSecurityGroupsInput, *ec2.DescribeSecurityGroupsOutput, *ec2.Client, *ec2.Options] { - return &sources.DescribeOnlySource[*ec2.DescribeSecurityGroupsInput, *ec2.DescribeSecurityGroupsOutput, *ec2.Client, *ec2.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "ec2-security-group", +func NewSecurityGroupAdapter(client *ec2.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*ec2.DescribeSecurityGroupsInput, *ec2.DescribeSecurityGroupsOutput, *ec2.Client, *ec2.Options] { + return &adapters.DescribeOnlyAdapter[*ec2.DescribeSecurityGroupsInput, *ec2.DescribeSecurityGroupsOutput, *ec2.Client, *ec2.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "ec2-security-group", + AdapterMetadata: SecurityGroupMetadata(), DescribeFunc: func(ctx context.Context, client *ec2.Client, input *ec2.DescribeSecurityGroupsInput) (*ec2.DescribeSecurityGroupsOutput, error) { return client.DescribeSecurityGroups(ctx, input) }, InputMapperGet: securityGroupInputMapperGet, InputMapperList: securityGroupInputMapperList, - PaginatorBuilder: func(client *ec2.Client, params *ec2.DescribeSecurityGroupsInput) sources.Paginator[*ec2.DescribeSecurityGroupsOutput, *ec2.Options] { + PaginatorBuilder: func(client *ec2.Client, params *ec2.DescribeSecurityGroupsInput) adapters.Paginator[*ec2.DescribeSecurityGroupsOutput, *ec2.Options] { return ec2.NewDescribeSecurityGroupsPaginator(client, params) }, OutputMapper: securityGroupOutputMapper, @@ -106,10 +107,31 @@ func NewSecurityGroupSource(client *ec2.Client, accountID string, region string) } } +func SecurityGroupMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "ec2-security-group", + DescriptiveName: "Security Group", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a security group by ID", + ListDescription: "List all security groups", + SearchDescription: "Search for security groups by ARN", + }, + PotentialLinks: []string{"ec2-vpc"}, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_security_group.id"}, + {TerraformQueryMap: "aws_security_group_rule.security_group_id"}, + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_SECURITY, + } +} + // extractLinkedSecurityGroups Extracts related security groups from IP // permissions func extractLinkedSecurityGroups(permissions []types.IpPermission, scope string) []*sdp.LinkedItemQuery { - currentAccount, region, err := sources.ParseScope(scope) + currentAccount, region, err := adapters.ParseScope(scope) requests := make([]*sdp.LinkedItemQuery, 0) var relatedAccount string @@ -131,7 +153,7 @@ func extractLinkedSecurityGroups(permissions []types.IpPermission, scope string) Type: "ec2-security-group", Method: sdp.QueryMethod_GET, Query: *idGroup.GroupId, - Scope: sources.FormatScope(relatedAccount, region), + Scope: adapters.FormatScope(relatedAccount, region), }, BlastPropagation: &sdp.BlastPropagation{ // Linked security groups affect each other diff --git a/sources/ec2/sg_rule.go b/adapters/ec2/sg_rule.go similarity index 66% rename from sources/ec2/sg_rule.go rename to adapters/ec2/sg_rule.go index 5be9bb99..31dc597b 100644 --- a/sources/ec2/sg_rule.go +++ b/adapters/ec2/sg_rule.go @@ -4,7 +4,7 @@ import ( "context" "github.com/aws/aws-sdk-go-v2/service/ec2" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -26,7 +26,7 @@ func securityGroupRuleOutputMapper(_ context.Context, _ *ec2.Client, scope strin for _, securityGroupRule := range output.SecurityGroupRules { var err error var attrs *sdp.ItemAttributes - attrs, err = sources.ToAttributesWithExclude(securityGroupRule, "tags") + attrs, err = adapters.ToAttributesWithExclude(securityGroupRule, "tags") if err != nil { return nil, &sdp.QueryError{ @@ -97,20 +97,43 @@ func securityGroupRuleOutputMapper(_ context.Context, _ *ec2.Client, scope strin // +overmind:terraform:queryMap aws_vpc_security_group_ingress_rule.security_group_rule_id // +overmind:terraform:queryMap aws_vpc_security_group_egress_rule.security_group_rule_id -func NewSecurityGroupRuleSource(client *ec2.Client, accountID string, region string) *sources.DescribeOnlySource[*ec2.DescribeSecurityGroupRulesInput, *ec2.DescribeSecurityGroupRulesOutput, *ec2.Client, *ec2.Options] { - return &sources.DescribeOnlySource[*ec2.DescribeSecurityGroupRulesInput, *ec2.DescribeSecurityGroupRulesOutput, *ec2.Client, *ec2.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "ec2-security-group-rule", +func NewSecurityGroupRuleAdapter(client *ec2.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*ec2.DescribeSecurityGroupRulesInput, *ec2.DescribeSecurityGroupRulesOutput, *ec2.Client, *ec2.Options] { + return &adapters.DescribeOnlyAdapter[*ec2.DescribeSecurityGroupRulesInput, *ec2.DescribeSecurityGroupRulesOutput, *ec2.Client, *ec2.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "ec2-security-group-rule", + AdapterMetadata: SecurityGroupRuleMetadata(), DescribeFunc: func(ctx context.Context, client *ec2.Client, input *ec2.DescribeSecurityGroupRulesInput) (*ec2.DescribeSecurityGroupRulesOutput, error) { return client.DescribeSecurityGroupRules(ctx, input) }, InputMapperGet: securityGroupRuleInputMapperGet, InputMapperList: securityGroupRuleInputMapperList, - PaginatorBuilder: func(client *ec2.Client, params *ec2.DescribeSecurityGroupRulesInput) sources.Paginator[*ec2.DescribeSecurityGroupRulesOutput, *ec2.Options] { + PaginatorBuilder: func(client *ec2.Client, params *ec2.DescribeSecurityGroupRulesInput) adapters.Paginator[*ec2.DescribeSecurityGroupRulesOutput, *ec2.Options] { return ec2.NewDescribeSecurityGroupRulesPaginator(client, params) }, OutputMapper: securityGroupRuleOutputMapper, } } + +func SecurityGroupRuleMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "ec2-security-group-rule", + DescriptiveName: "Security Group Rule", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a security group rule by ID", + ListDescription: "List all security group rules", + SearchDescription: "Search security group rules by ARN", + }, + PotentialLinks: []string{"ec2-security-group"}, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_security_group_rule.security_group_rule_id"}, + {TerraformQueryMap: "aws_vpc_security_group_ingress_rule.security_group_rule_id"}, + {TerraformQueryMap: "aws_vpc_security_group_egress_rule.security_group_rule_id"}, + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_SECURITY, + } +} diff --git a/sources/ec2/sg_rule_test.go b/adapters/ec2/sg_rule_test.go similarity index 58% rename from sources/ec2/sg_rule_test.go rename to adapters/ec2/sg_rule_test.go index 158076fa..59cb265b 100644 --- a/sources/ec2/sg_rule_test.go +++ b/adapters/ec2/sg_rule_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/aws/aws-sdk-go-v2/service/ec2/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -43,33 +43,33 @@ func TestSecurityGroupRuleOutputMapper(t *testing.T) { output := &ec2.DescribeSecurityGroupRulesOutput{ SecurityGroupRules: []types.SecurityGroupRule{ { - SecurityGroupRuleId: sources.PtrString("sgr-0b0e42d1431e832bd"), - GroupId: sources.PtrString("sg-0814766e46f201c22"), - GroupOwnerId: sources.PtrString("052392120703"), - IsEgress: sources.PtrBool(false), - IpProtocol: sources.PtrString("tcp"), - FromPort: sources.PtrInt32(2049), - ToPort: sources.PtrInt32(2049), + SecurityGroupRuleId: adapters.PtrString("sgr-0b0e42d1431e832bd"), + GroupId: adapters.PtrString("sg-0814766e46f201c22"), + GroupOwnerId: adapters.PtrString("052392120703"), + IsEgress: adapters.PtrBool(false), + IpProtocol: adapters.PtrString("tcp"), + FromPort: adapters.PtrInt32(2049), + ToPort: adapters.PtrInt32(2049), ReferencedGroupInfo: &types.ReferencedSecurityGroup{ - GroupId: sources.PtrString("sg-09371b4a54fe7ab38"), - UserId: sources.PtrString("052392120703"), + GroupId: adapters.PtrString("sg-09371b4a54fe7ab38"), + UserId: adapters.PtrString("052392120703"), }, - Description: sources.PtrString("Created by the LIW for EFS at 2022-12-16T19:14:27.033Z"), + Description: adapters.PtrString("Created by the LIW for EFS at 2022-12-16T19:14:27.033Z"), Tags: []types.Tag{}, }, { - SecurityGroupRuleId: sources.PtrString("sgr-04b583a90b4fa4ada"), - GroupId: sources.PtrString("sg-09371b4a54fe7ab38"), - GroupOwnerId: sources.PtrString("052392120703"), - IsEgress: sources.PtrBool(true), - IpProtocol: sources.PtrString("tcp"), - FromPort: sources.PtrInt32(2049), - ToPort: sources.PtrInt32(2049), + SecurityGroupRuleId: adapters.PtrString("sgr-04b583a90b4fa4ada"), + GroupId: adapters.PtrString("sg-09371b4a54fe7ab38"), + GroupOwnerId: adapters.PtrString("052392120703"), + IsEgress: adapters.PtrBool(true), + IpProtocol: adapters.PtrString("tcp"), + FromPort: adapters.PtrInt32(2049), + ToPort: adapters.PtrInt32(2049), ReferencedGroupInfo: &types.ReferencedSecurityGroup{ - GroupId: sources.PtrString("sg-0814766e46f201c22"), - UserId: sources.PtrString("052392120703"), + GroupId: adapters.PtrString("sg-0814766e46f201c22"), + UserId: adapters.PtrString("052392120703"), }, - Description: sources.PtrString("Created by the LIW for EFS at 2022-12-16T19:14:27.349Z"), + Description: adapters.PtrString("Created by the LIW for EFS at 2022-12-16T19:14:27.349Z"), Tags: []types.Tag{}, }, }, @@ -89,7 +89,7 @@ func TestSecurityGroupRuleOutputMapper(t *testing.T) { // It doesn't really make sense to test anything other than the linked items // since the attributes are converted automatically - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "ec2-security-group", ExpectedMethod: sdp.QueryMethod_GET, @@ -108,13 +108,13 @@ func TestSecurityGroupRuleOutputMapper(t *testing.T) { } -func TestNewSecurityGroupRuleSource(t *testing.T) { +func TestNewSecurityGroupRuleAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewSecurityGroupRuleSource(client, account, region) + adapter := NewSecurityGroupRuleAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/ec2/sg_test.go b/adapters/ec2/sg_test.go similarity index 75% rename from sources/ec2/sg_test.go rename to adapters/ec2/sg_test.go index 702515be..ebfee72b 100644 --- a/sources/ec2/sg_test.go +++ b/adapters/ec2/sg_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/aws/aws-sdk-go-v2/service/ec2/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -43,30 +43,30 @@ func TestSecurityGroupOutputMapper(t *testing.T) { output := &ec2.DescribeSecurityGroupsOutput{ SecurityGroups: []types.SecurityGroup{ { - Description: sources.PtrString("default VPC security group"), - GroupName: sources.PtrString("default"), + Description: adapters.PtrString("default VPC security group"), + GroupName: adapters.PtrString("default"), IpPermissions: []types.IpPermission{ { - IpProtocol: sources.PtrString("-1"), + IpProtocol: adapters.PtrString("-1"), IpRanges: []types.IpRange{}, Ipv6Ranges: []types.Ipv6Range{}, PrefixListIds: []types.PrefixListId{}, UserIdGroupPairs: []types.UserIdGroupPair{ { - GroupId: sources.PtrString("sg-094e151c9fc5da181"), - UserId: sources.PtrString("052392120704"), + GroupId: adapters.PtrString("sg-094e151c9fc5da181"), + UserId: adapters.PtrString("052392120704"), }, }, }, }, - OwnerId: sources.PtrString("052392120703"), - GroupId: sources.PtrString("sg-094e151c9fc5da181"), + OwnerId: adapters.PtrString("052392120703"), + GroupId: adapters.PtrString("sg-094e151c9fc5da181"), IpPermissionsEgress: []types.IpPermission{ { - IpProtocol: sources.PtrString("-1"), + IpProtocol: adapters.PtrString("-1"), IpRanges: []types.IpRange{ { - CidrIp: sources.PtrString("0.0.0.0/0"), + CidrIp: adapters.PtrString("0.0.0.0/0"), }, }, Ipv6Ranges: []types.Ipv6Range{}, @@ -74,7 +74,7 @@ func TestSecurityGroupOutputMapper(t *testing.T) { UserIdGroupPairs: []types.UserIdGroupPair{}, }, }, - VpcId: sources.PtrString("vpc-0d7892e00e573e701"), + VpcId: adapters.PtrString("vpc-0d7892e00e573e701"), }, }, } @@ -93,7 +93,7 @@ func TestSecurityGroupOutputMapper(t *testing.T) { // It doesn't really make sense to test anything other than the linked items // since the attributes are converted automatically - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "ec2-vpc", ExpectedMethod: sdp.QueryMethod_GET, @@ -112,13 +112,13 @@ func TestSecurityGroupOutputMapper(t *testing.T) { } -func TestNewSecurityGroupSource(t *testing.T) { +func TestNewSecurityGroupAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewSecurityGroupSource(client, account, region) + adapter := NewSecurityGroupAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/ec2/shared.go b/adapters/ec2/shared.go similarity index 100% rename from sources/ec2/shared.go rename to adapters/ec2/shared.go diff --git a/sources/ec2/shared_test.go b/adapters/ec2/shared_test.go similarity index 68% rename from sources/ec2/shared_test.go rename to adapters/ec2/shared_test.go index ac0a308a..c86075b8 100644 --- a/sources/ec2/shared_test.go +++ b/adapters/ec2/shared_test.go @@ -4,11 +4,11 @@ import ( "testing" "github.com/aws/aws-sdk-go-v2/service/ec2" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" ) func GetAutoConfig(t *testing.T) (*ec2.Client, string, string) { - config, account, region := sources.GetAutoConfig(t) + config, account, region := adapters.GetAutoConfig(t) client := ec2.NewFromConfig(config) return client, account, region diff --git a/sources/ec2/snapshot.go b/adapters/ec2/snapshot.go similarity index 69% rename from sources/ec2/snapshot.go rename to adapters/ec2/snapshot.go index 5cad6644..8c0d8ebc 100644 --- a/sources/ec2/snapshot.go +++ b/adapters/ec2/snapshot.go @@ -4,7 +4,7 @@ import ( "context" "github.com/aws/aws-sdk-go-v2/service/ec2" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -32,7 +32,7 @@ func snapshotOutputMapper(_ context.Context, _ *ec2.Client, scope string, _ *ec2 for _, snapshot := range output.Snapshots { var err error var attrs *sdp.ItemAttributes - attrs, err = sources.ToAttributesWithExclude(snapshot, "tags") + attrs, err = adapters.ToAttributesWithExclude(snapshot, "tags") if err != nil { return nil, &sdp.QueryError{ @@ -87,20 +87,38 @@ func snapshotOutputMapper(_ context.Context, _ *ec2.Client, scope string, _ *ec2 // +overmind:search Search snapshots by ARN // +overmind:group AWS -func NewSnapshotSource(client *ec2.Client, accountID string, region string) *sources.DescribeOnlySource[*ec2.DescribeSnapshotsInput, *ec2.DescribeSnapshotsOutput, *ec2.Client, *ec2.Options] { - return &sources.DescribeOnlySource[*ec2.DescribeSnapshotsInput, *ec2.DescribeSnapshotsOutput, *ec2.Client, *ec2.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "ec2-snapshot", +func NewSnapshotAdapter(client *ec2.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*ec2.DescribeSnapshotsInput, *ec2.DescribeSnapshotsOutput, *ec2.Client, *ec2.Options] { + return &adapters.DescribeOnlyAdapter[*ec2.DescribeSnapshotsInput, *ec2.DescribeSnapshotsOutput, *ec2.Client, *ec2.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "ec2-snapshot", + AdapterMetadata: SnapshotMetadata(), DescribeFunc: func(ctx context.Context, client *ec2.Client, input *ec2.DescribeSnapshotsInput) (*ec2.DescribeSnapshotsOutput, error) { return client.DescribeSnapshots(ctx, input) }, InputMapperGet: snapshotInputMapperGet, InputMapperList: snapshotInputMapperList, - PaginatorBuilder: func(client *ec2.Client, params *ec2.DescribeSnapshotsInput) sources.Paginator[*ec2.DescribeSnapshotsOutput, *ec2.Options] { + PaginatorBuilder: func(client *ec2.Client, params *ec2.DescribeSnapshotsInput) adapters.Paginator[*ec2.DescribeSnapshotsOutput, *ec2.Options] { return ec2.NewDescribeSnapshotsPaginator(client, params) }, OutputMapper: snapshotOutputMapper, } } + +func SnapshotMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "ec2-snapshot", + DescriptiveName: "EC2 Snapshot", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a snapshot by ID", + ListDescription: "List all snapshots", + SearchDescription: "Search snapshots by ARN", + }, + PotentialLinks: []string{"ec2-volume"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_STORAGE, + } +} diff --git a/sources/ec2/snapshot_test.go b/adapters/ec2/snapshot_test.go similarity index 63% rename from sources/ec2/snapshot_test.go rename to adapters/ec2/snapshot_test.go index d5081815..c25c991d 100644 --- a/sources/ec2/snapshot_test.go +++ b/adapters/ec2/snapshot_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/aws/aws-sdk-go-v2/service/ec2/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -43,23 +43,23 @@ func TestSnapshotOutputMapper(t *testing.T) { output := &ec2.DescribeSnapshotsOutput{ Snapshots: []types.Snapshot{ { - DataEncryptionKeyId: sources.PtrString("ek"), - KmsKeyId: sources.PtrString("key"), - SnapshotId: sources.PtrString("id"), - Description: sources.PtrString("foo"), - Encrypted: sources.PtrBool(false), - OutpostArn: sources.PtrString("something"), - OwnerAlias: sources.PtrString("something"), - OwnerId: sources.PtrString("owner"), - Progress: sources.PtrString("50%"), - RestoreExpiryTime: sources.PtrTime(time.Now()), - StartTime: sources.PtrTime(time.Now()), + DataEncryptionKeyId: adapters.PtrString("ek"), + KmsKeyId: adapters.PtrString("key"), + SnapshotId: adapters.PtrString("id"), + Description: adapters.PtrString("foo"), + Encrypted: adapters.PtrBool(false), + OutpostArn: adapters.PtrString("something"), + OwnerAlias: adapters.PtrString("something"), + OwnerId: adapters.PtrString("owner"), + Progress: adapters.PtrString("50%"), + RestoreExpiryTime: adapters.PtrTime(time.Now()), + StartTime: adapters.PtrTime(time.Now()), State: types.SnapshotStatePending, - StateMessage: sources.PtrString("pending"), + StateMessage: adapters.PtrString("pending"), StorageTier: types.StorageTierArchive, Tags: []types.Tag{}, - VolumeId: sources.PtrString("volumeId"), - VolumeSize: sources.PtrInt32(1024), + VolumeId: adapters.PtrString("volumeId"), + VolumeSize: adapters.PtrInt32(1024), }, }, } @@ -78,7 +78,7 @@ func TestSnapshotOutputMapper(t *testing.T) { // It doesn't really make sense to test anything other than the linked items // since the attributes are converted automatically - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "ec2-volume", ExpectedMethod: sdp.QueryMethod_GET, @@ -91,13 +91,13 @@ func TestSnapshotOutputMapper(t *testing.T) { } -func TestNewSnapshotSource(t *testing.T) { +func TestNewSnapshotAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewSnapshotSource(client, account, region) + adapter := NewSnapshotAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/ec2/subnet.go b/adapters/ec2/subnet.go similarity index 63% rename from sources/ec2/subnet.go rename to adapters/ec2/subnet.go index ee084063..dfc516c4 100644 --- a/sources/ec2/subnet.go +++ b/adapters/ec2/subnet.go @@ -4,7 +4,7 @@ import ( "context" "github.com/aws/aws-sdk-go-v2/service/ec2" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -26,7 +26,7 @@ func subnetOutputMapper(_ context.Context, _ *ec2.Client, scope string, _ *ec2.D for _, subnet := range output.Subnets { var err error var attrs *sdp.ItemAttributes - attrs, err = sources.ToAttributesWithExclude(subnet, "tags") + attrs, err = adapters.ToAttributesWithExclude(subnet, "tags") if err != nil { return nil, &sdp.QueryError{ @@ -78,20 +78,42 @@ func subnetOutputMapper(_ context.Context, _ *ec2.Client, scope string, _ *ec2.D // +overmind:terraform:queryMap aws_route_table_association.subnet_id // +overmind:terraform:queryMap aws_subnet.id -func NewSubnetSource(client *ec2.Client, accountID string, region string) *sources.DescribeOnlySource[*ec2.DescribeSubnetsInput, *ec2.DescribeSubnetsOutput, *ec2.Client, *ec2.Options] { - return &sources.DescribeOnlySource[*ec2.DescribeSubnetsInput, *ec2.DescribeSubnetsOutput, *ec2.Client, *ec2.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "ec2-subnet", +func NewSubnetAdapter(client *ec2.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*ec2.DescribeSubnetsInput, *ec2.DescribeSubnetsOutput, *ec2.Client, *ec2.Options] { + return &adapters.DescribeOnlyAdapter[*ec2.DescribeSubnetsInput, *ec2.DescribeSubnetsOutput, *ec2.Client, *ec2.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "ec2-subnet", + AdapterMetadata: SubnetMetadata(), DescribeFunc: func(ctx context.Context, client *ec2.Client, input *ec2.DescribeSubnetsInput) (*ec2.DescribeSubnetsOutput, error) { return client.DescribeSubnets(ctx, input) }, InputMapperGet: subnetInputMapperGet, InputMapperList: subnetInputMapperList, - PaginatorBuilder: func(client *ec2.Client, params *ec2.DescribeSubnetsInput) sources.Paginator[*ec2.DescribeSubnetsOutput, *ec2.Options] { + PaginatorBuilder: func(client *ec2.Client, params *ec2.DescribeSubnetsInput) adapters.Paginator[*ec2.DescribeSubnetsOutput, *ec2.Options] { return ec2.NewDescribeSubnetsPaginator(client, params) }, OutputMapper: subnetOutputMapper, } } + +func SubnetMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "ec2-subnet", + DescriptiveName: "EC2 Subnet", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a subnet by ID", + ListDescription: "List all subnets", + SearchDescription: "Search for subnets by ARN", + }, + PotentialLinks: []string{"ec2-vpc"}, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_route_table_association.subnet_id"}, + {TerraformQueryMap: "aws_subnet.id"}, + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + } +} diff --git a/sources/ec2/subnet_test.go b/adapters/ec2/subnet_test.go similarity index 59% rename from sources/ec2/subnet_test.go rename to adapters/ec2/subnet_test.go index 9e00c8ad..549d1d08 100644 --- a/sources/ec2/subnet_test.go +++ b/adapters/ec2/subnet_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/aws/aws-sdk-go-v2/service/ec2/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -43,36 +43,36 @@ func TestSubnetOutputMapper(t *testing.T) { output := &ec2.DescribeSubnetsOutput{ Subnets: []types.Subnet{ { - AvailabilityZone: sources.PtrString("eu-west-2c"), - AvailabilityZoneId: sources.PtrString("euw2-az1"), - AvailableIpAddressCount: sources.PtrInt32(4091), - CidrBlock: sources.PtrString("172.31.80.0/20"), - DefaultForAz: sources.PtrBool(false), - MapPublicIpOnLaunch: sources.PtrBool(false), - MapCustomerOwnedIpOnLaunch: sources.PtrBool(false), + AvailabilityZone: adapters.PtrString("eu-west-2c"), + AvailabilityZoneId: adapters.PtrString("euw2-az1"), + AvailableIpAddressCount: adapters.PtrInt32(4091), + CidrBlock: adapters.PtrString("172.31.80.0/20"), + DefaultForAz: adapters.PtrBool(false), + MapPublicIpOnLaunch: adapters.PtrBool(false), + MapCustomerOwnedIpOnLaunch: adapters.PtrBool(false), State: types.SubnetStateAvailable, - SubnetId: sources.PtrString("subnet-0450a637af9984235"), - VpcId: sources.PtrString("vpc-0d7892e00e573e701"), - OwnerId: sources.PtrString("052392120703"), - AssignIpv6AddressOnCreation: sources.PtrBool(false), + SubnetId: adapters.PtrString("subnet-0450a637af9984235"), + VpcId: adapters.PtrString("vpc-0d7892e00e573e701"), + OwnerId: adapters.PtrString("052392120703"), + AssignIpv6AddressOnCreation: adapters.PtrBool(false), Ipv6CidrBlockAssociationSet: []types.SubnetIpv6CidrBlockAssociation{ { - AssociationId: sources.PtrString("id-1234"), - Ipv6CidrBlock: sources.PtrString("something"), + AssociationId: adapters.PtrString("id-1234"), + Ipv6CidrBlock: adapters.PtrString("something"), Ipv6CidrBlockState: &types.SubnetCidrBlockState{ State: types.SubnetCidrBlockStateCodeAssociated, - StatusMessage: sources.PtrString("something here"), + StatusMessage: adapters.PtrString("something here"), }, }, }, Tags: []types.Tag{}, - SubnetArn: sources.PtrString("arn:aws:ec2:eu-west-2:052392120703:subnet/subnet-0450a637af9984235"), - EnableDns64: sources.PtrBool(false), - Ipv6Native: sources.PtrBool(false), + SubnetArn: adapters.PtrString("arn:aws:ec2:eu-west-2:052392120703:subnet/subnet-0450a637af9984235"), + EnableDns64: adapters.PtrBool(false), + Ipv6Native: adapters.PtrBool(false), PrivateDnsNameOptionsOnLaunch: &types.PrivateDnsNameOptionsOnLaunch{ HostnameType: types.HostnameTypeIpName, - EnableResourceNameDnsARecord: sources.PtrBool(false), - EnableResourceNameDnsAAAARecord: sources.PtrBool(false), + EnableResourceNameDnsARecord: adapters.PtrBool(false), + EnableResourceNameDnsAAAARecord: adapters.PtrBool(false), }, }, }, @@ -98,7 +98,7 @@ func TestSubnetOutputMapper(t *testing.T) { // It doesn't really make sense to test anything other than the linked items // since the attributes are converted automatically - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "ec2-vpc", ExpectedMethod: sdp.QueryMethod_GET, @@ -111,13 +111,13 @@ func TestSubnetOutputMapper(t *testing.T) { } -func TestNewSubnetSource(t *testing.T) { +func TestNewSubnetAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewSubnetSource(client, account, region) + adapter := NewSubnetAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/ec2/volume.go b/adapters/ec2/volume.go similarity index 64% rename from sources/ec2/volume.go rename to adapters/ec2/volume.go index 94b673c6..72b92038 100644 --- a/sources/ec2/volume.go +++ b/adapters/ec2/volume.go @@ -4,7 +4,7 @@ import ( "context" "github.com/aws/aws-sdk-go-v2/service/ec2" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -26,7 +26,7 @@ func volumeOutputMapper(_ context.Context, _ *ec2.Client, scope string, _ *ec2.D for _, volume := range output.Volumes { var err error var attrs *sdp.ItemAttributes - attrs, err = sources.ToAttributesWithExclude(volume, "tags") + attrs, err = adapters.ToAttributesWithExclude(volume, "tags") if err != nil { return nil, &sdp.QueryError{ @@ -76,20 +76,41 @@ func volumeOutputMapper(_ context.Context, _ *ec2.Client, scope string, _ *ec2.D // +overmind:group AWS // +overmind:terraform:queryMap aws_ebs_volume.id -func NewVolumeSource(client *ec2.Client, accountID string, region string) *sources.DescribeOnlySource[*ec2.DescribeVolumesInput, *ec2.DescribeVolumesOutput, *ec2.Client, *ec2.Options] { - return &sources.DescribeOnlySource[*ec2.DescribeVolumesInput, *ec2.DescribeVolumesOutput, *ec2.Client, *ec2.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "ec2-volume", +func NewVolumeAdapter(client *ec2.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*ec2.DescribeVolumesInput, *ec2.DescribeVolumesOutput, *ec2.Client, *ec2.Options] { + return &adapters.DescribeOnlyAdapter[*ec2.DescribeVolumesInput, *ec2.DescribeVolumesOutput, *ec2.Client, *ec2.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "ec2-volume", + AdapterMetadata: VolumeMetadata(), DescribeFunc: func(ctx context.Context, client *ec2.Client, input *ec2.DescribeVolumesInput) (*ec2.DescribeVolumesOutput, error) { return client.DescribeVolumes(ctx, input) }, InputMapperGet: volumeInputMapperGet, InputMapperList: volumeInputMapperList, - PaginatorBuilder: func(client *ec2.Client, params *ec2.DescribeVolumesInput) sources.Paginator[*ec2.DescribeVolumesOutput, *ec2.Options] { + PaginatorBuilder: func(client *ec2.Client, params *ec2.DescribeVolumesInput) adapters.Paginator[*ec2.DescribeVolumesOutput, *ec2.Options] { return ec2.NewDescribeVolumesPaginator(client, params) }, OutputMapper: volumeOutputMapper, } } + +func VolumeMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "ec2-volume", + DescriptiveName: "EC2 Volume", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a volume by ID", + ListDescription: "List all volumes", + SearchDescription: "Search volumes by ARN", + }, + PotentialLinks: []string{"ec2-instance"}, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_ebs_volume.id"}, + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_STORAGE, + } +} diff --git a/sources/ec2/volume_status.go b/adapters/ec2/volume_status.go similarity index 71% rename from sources/ec2/volume_status.go rename to adapters/ec2/volume_status.go index e102857e..1e2c02f0 100644 --- a/sources/ec2/volume_status.go +++ b/adapters/ec2/volume_status.go @@ -5,7 +5,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/aws/aws-sdk-go-v2/service/ec2/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -27,7 +27,7 @@ func volumeStatusOutputMapper(_ context.Context, _ *ec2.Client, scope string, _ for _, volume := range output.VolumeStatuses { var err error var attrs *sdp.ItemAttributes - attrs, err = sources.ToAttributesWithExclude(volume) + attrs, err = adapters.ToAttributesWithExclude(volume) if err != nil { return nil, &sdp.QueryError{ @@ -104,20 +104,37 @@ func volumeStatusOutputMapper(_ context.Context, _ *ec2.Client, scope string, _ // +overmind:search Search for volume statuses by ARN // +overmind:group AWS -func NewVolumeStatusSource(client *ec2.Client, accountID string, region string) *sources.DescribeOnlySource[*ec2.DescribeVolumeStatusInput, *ec2.DescribeVolumeStatusOutput, *ec2.Client, *ec2.Options] { - return &sources.DescribeOnlySource[*ec2.DescribeVolumeStatusInput, *ec2.DescribeVolumeStatusOutput, *ec2.Client, *ec2.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "ec2-volume-status", +func NewVolumeStatusAdapter(client *ec2.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*ec2.DescribeVolumeStatusInput, *ec2.DescribeVolumeStatusOutput, *ec2.Client, *ec2.Options] { + return &adapters.DescribeOnlyAdapter[*ec2.DescribeVolumeStatusInput, *ec2.DescribeVolumeStatusOutput, *ec2.Client, *ec2.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "ec2-volume-status", + AdapterMetadata: VolumeStatusMetadata(), DescribeFunc: func(ctx context.Context, client *ec2.Client, input *ec2.DescribeVolumeStatusInput) (*ec2.DescribeVolumeStatusOutput, error) { return client.DescribeVolumeStatus(ctx, input) }, InputMapperGet: volumeStatusInputMapperGet, InputMapperList: volumeStatusInputMapperList, - PaginatorBuilder: func(client *ec2.Client, params *ec2.DescribeVolumeStatusInput) sources.Paginator[*ec2.DescribeVolumeStatusOutput, *ec2.Options] { + PaginatorBuilder: func(client *ec2.Client, params *ec2.DescribeVolumeStatusInput) adapters.Paginator[*ec2.DescribeVolumeStatusOutput, *ec2.Options] { return ec2.NewDescribeVolumeStatusPaginator(client, params) }, OutputMapper: volumeStatusOutputMapper, } } +func VolumeStatusMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "ec2-volume-status", + DescriptiveName: "EC2 Volume Status", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a volume status by volume ID", + ListDescription: "List all volume statuses", + SearchDescription: "Search for volume statuses by ARN", + }, + PotentialLinks: []string{"ec2-instance"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_OBSERVABILITY, + } +} diff --git a/sources/ec2/volume_status_test.go b/adapters/ec2/volume_status_test.go similarity index 69% rename from sources/ec2/volume_status_test.go rename to adapters/ec2/volume_status_test.go index 70c8a57f..370b3668 100644 --- a/sources/ec2/volume_status_test.go +++ b/adapters/ec2/volume_status_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/aws/aws-sdk-go-v2/service/ec2/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -45,33 +45,33 @@ func TestVolumeStatusOutputMapper(t *testing.T) { { Actions: []types.VolumeStatusAction{ { - Code: sources.PtrString("enable-volume-io"), - Description: sources.PtrString("Enable volume I/O"), - EventId: sources.PtrString("12"), - EventType: sources.PtrString("io-enabled"), + Code: adapters.PtrString("enable-volume-io"), + Description: adapters.PtrString("Enable volume I/O"), + EventId: adapters.PtrString("12"), + EventType: adapters.PtrString("io-enabled"), }, }, - AvailabilityZone: sources.PtrString("eu-west-2c"), + AvailabilityZone: adapters.PtrString("eu-west-2c"), Events: []types.VolumeStatusEvent{ { - Description: sources.PtrString("The volume is operating normally"), - EventId: sources.PtrString("12"), - EventType: sources.PtrString("io-enabled"), - InstanceId: sources.PtrString("i-0667d3ca802741e30"), // link - NotAfter: sources.PtrTime(time.Now()), - NotBefore: sources.PtrTime(time.Now()), + Description: adapters.PtrString("The volume is operating normally"), + EventId: adapters.PtrString("12"), + EventType: adapters.PtrString("io-enabled"), + InstanceId: adapters.PtrString("i-0667d3ca802741e30"), // link + NotAfter: adapters.PtrTime(time.Now()), + NotBefore: adapters.PtrTime(time.Now()), }, }, - VolumeId: sources.PtrString("vol-0a38796ac85e21c11"), // link + VolumeId: adapters.PtrString("vol-0a38796ac85e21c11"), // link VolumeStatus: &types.VolumeStatusInfo{ Details: []types.VolumeStatusDetails{ { Name: types.VolumeStatusNameIoEnabled, - Status: sources.PtrString("passed"), + Status: adapters.PtrString("passed"), }, { Name: types.VolumeStatusNameIoPerformance, - Status: sources.PtrString("not-applicable"), + Status: adapters.PtrString("not-applicable"), }, }, Status: types.VolumeStatusInfoStatusOk, @@ -100,7 +100,7 @@ func TestVolumeStatusOutputMapper(t *testing.T) { // It doesn't really make sense to test anything other than the linked items // since the attributes are converted automatically - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "ec2-instance", ExpectedMethod: sdp.QueryMethod_GET, @@ -118,13 +118,13 @@ func TestVolumeStatusOutputMapper(t *testing.T) { tests.Execute(t, item) } -func TestNewVolumeStatusSource(t *testing.T) { +func TestNewVolumeStatusAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewVolumeSource(client, account, region) + adapter := NewVolumeAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/ec2/volume_test.go b/adapters/ec2/volume_test.go similarity index 65% rename from sources/ec2/volume_test.go rename to adapters/ec2/volume_test.go index 89270256..6a228c27 100644 --- a/sources/ec2/volume_test.go +++ b/adapters/ec2/volume_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/aws/aws-sdk-go-v2/service/ec2/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -45,24 +45,24 @@ func TestVolumeOutputMapper(t *testing.T) { { Attachments: []types.VolumeAttachment{ { - AttachTime: sources.PtrTime(time.Now()), - Device: sources.PtrString("/dev/sdb"), - InstanceId: sources.PtrString("i-0667d3ca802741e30"), + AttachTime: adapters.PtrTime(time.Now()), + Device: adapters.PtrString("/dev/sdb"), + InstanceId: adapters.PtrString("i-0667d3ca802741e30"), State: types.VolumeAttachmentStateAttaching, - VolumeId: sources.PtrString("vol-0eae6976b359d8825"), - DeleteOnTermination: sources.PtrBool(false), + VolumeId: adapters.PtrString("vol-0eae6976b359d8825"), + DeleteOnTermination: adapters.PtrBool(false), }, }, - AvailabilityZone: sources.PtrString("eu-west-2c"), - CreateTime: sources.PtrTime(time.Now()), - Encrypted: sources.PtrBool(false), - Size: sources.PtrInt32(8), + AvailabilityZone: adapters.PtrString("eu-west-2c"), + CreateTime: adapters.PtrTime(time.Now()), + Encrypted: adapters.PtrBool(false), + Size: adapters.PtrInt32(8), State: types.VolumeStateInUse, - VolumeId: sources.PtrString("vol-0eae6976b359d8825"), - Iops: sources.PtrInt32(3000), + VolumeId: adapters.PtrString("vol-0eae6976b359d8825"), + Iops: adapters.PtrInt32(3000), VolumeType: types.VolumeTypeGp3, - MultiAttachEnabled: sources.PtrBool(false), - Throughput: sources.PtrInt32(125), + MultiAttachEnabled: adapters.PtrBool(false), + Throughput: adapters.PtrInt32(125), }, }, } @@ -87,7 +87,7 @@ func TestVolumeOutputMapper(t *testing.T) { // It doesn't really make sense to test anything other than the linked items // since the attributes are converted automatically - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "ec2-instance", ExpectedMethod: sdp.QueryMethod_GET, @@ -100,13 +100,13 @@ func TestVolumeOutputMapper(t *testing.T) { } -func TestNewVolumeSource(t *testing.T) { +func TestNewVolumeAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewVolumeSource(client, account, region) + adapter := NewVolumeAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/ec2/vpc.go b/adapters/ec2/vpc.go similarity index 60% rename from sources/ec2/vpc.go rename to adapters/ec2/vpc.go index 44e821d5..10df89e8 100644 --- a/sources/ec2/vpc.go +++ b/adapters/ec2/vpc.go @@ -4,7 +4,7 @@ import ( "context" "github.com/aws/aws-sdk-go-v2/service/ec2" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -26,7 +26,7 @@ func vpcOutputMapper(_ context.Context, _ *ec2.Client, scope string, _ *ec2.Desc for _, vpc := range output.Vpcs { var err error var attrs *sdp.ItemAttributes - attrs, err = sources.ToAttributesWithExclude(vpc, "tags") + attrs, err = adapters.ToAttributesWithExclude(vpc, "tags") if err != nil { return nil, &sdp.QueryError{ @@ -58,20 +58,38 @@ func vpcOutputMapper(_ context.Context, _ *ec2.Client, scope string, _ *ec2.Desc // +overmind:group AWS // +overmind:terraform:queryMap aws_vpc.id -func NewVpcSource(client *ec2.Client, accountID string, region string) *sources.DescribeOnlySource[*ec2.DescribeVpcsInput, *ec2.DescribeVpcsOutput, *ec2.Client, *ec2.Options] { - return &sources.DescribeOnlySource[*ec2.DescribeVpcsInput, *ec2.DescribeVpcsOutput, *ec2.Client, *ec2.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "ec2-vpc", +func NewVpcAdapter(client *ec2.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*ec2.DescribeVpcsInput, *ec2.DescribeVpcsOutput, *ec2.Client, *ec2.Options] { + return &adapters.DescribeOnlyAdapter[*ec2.DescribeVpcsInput, *ec2.DescribeVpcsOutput, *ec2.Client, *ec2.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "ec2-vpc", + AdapterMetadata: VpcMetadata(), DescribeFunc: func(ctx context.Context, client *ec2.Client, input *ec2.DescribeVpcsInput) (*ec2.DescribeVpcsOutput, error) { return client.DescribeVpcs(ctx, input) }, InputMapperGet: vpcInputMapperGet, InputMapperList: vpcInputMapperList, - PaginatorBuilder: func(client *ec2.Client, params *ec2.DescribeVpcsInput) sources.Paginator[*ec2.DescribeVpcsOutput, *ec2.Options] { + PaginatorBuilder: func(client *ec2.Client, params *ec2.DescribeVpcsInput) adapters.Paginator[*ec2.DescribeVpcsOutput, *ec2.Options] { return ec2.NewDescribeVpcsPaginator(client, params) }, OutputMapper: vpcOutputMapper, } } + +func VpcMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + DescriptiveName: "VPC", + Type: "ec2-vpc", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + GetDescription: "Get a VPC by ID", + ListDescription: "List all VPCs", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_vpc.id"}, + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + } +} diff --git a/sources/ec2/vpc_endpoint.go b/adapters/ec2/vpc_endpoint.go similarity index 82% rename from sources/ec2/vpc_endpoint.go rename to adapters/ec2/vpc_endpoint.go index 3d7517f1..f171b2b4 100644 --- a/sources/ec2/vpc_endpoint.go +++ b/adapters/ec2/vpc_endpoint.go @@ -7,8 +7,8 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/aws/aws-sdk-go-v2/service/ec2/types" "github.com/micahhausler/aws-iam-policy/policy" - "github.com/overmindtech/aws-source/sources" - "github.com/overmindtech/aws-source/sources/iam" + "github.com/overmindtech/aws-source/adapters" + "github.com/overmindtech/aws-source/adapters/iam" "github.com/overmindtech/sdp-go" ) @@ -47,7 +47,7 @@ func vpcEndpointOutputMapper(_ context.Context, _ *ec2.Client, scope string, _ * endpointWithPolicy.PolicyDocument = parsedPolicy } - attrs, err = sources.ToAttributesWithExclude(endpointWithPolicy, "tags") + attrs, err = adapters.ToAttributesWithExclude(endpointWithPolicy, "tags") if err != nil { return nil, &sdp.QueryError{ @@ -221,20 +221,40 @@ func vpcEndpointOutputMapper(_ context.Context, _ *ec2.Client, scope string, _ * // +overmind:group AWS // +overmind:terraform:queryMap aws_vpc_endpoint.id -func NewVpcEndpointSource(client *ec2.Client, accountID string, region string) *sources.DescribeOnlySource[*ec2.DescribeVpcEndpointsInput, *ec2.DescribeVpcEndpointsOutput, *ec2.Client, *ec2.Options] { - return &sources.DescribeOnlySource[*ec2.DescribeVpcEndpointsInput, *ec2.DescribeVpcEndpointsOutput, *ec2.Client, *ec2.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "ec2-vpc-endpoint", +func NewVpcEndpointAdapter(client *ec2.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*ec2.DescribeVpcEndpointsInput, *ec2.DescribeVpcEndpointsOutput, *ec2.Client, *ec2.Options] { + return &adapters.DescribeOnlyAdapter[*ec2.DescribeVpcEndpointsInput, *ec2.DescribeVpcEndpointsOutput, *ec2.Client, *ec2.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "ec2-vpc-endpoint", + AdapterMetadata: VpcEndpointMetadata(), DescribeFunc: func(ctx context.Context, client *ec2.Client, input *ec2.DescribeVpcEndpointsInput) (*ec2.DescribeVpcEndpointsOutput, error) { return client.DescribeVpcEndpoints(ctx, input) }, InputMapperGet: vpcEndpointInputMapperGet, InputMapperList: vpcEndpointInputMapperList, - PaginatorBuilder: func(client *ec2.Client, params *ec2.DescribeVpcEndpointsInput) sources.Paginator[*ec2.DescribeVpcEndpointsOutput, *ec2.Options] { + PaginatorBuilder: func(client *ec2.Client, params *ec2.DescribeVpcEndpointsInput) adapters.Paginator[*ec2.DescribeVpcEndpointsOutput, *ec2.Options] { return ec2.NewDescribeVpcEndpointsPaginator(client, params) }, OutputMapper: vpcEndpointOutputMapper, } } + +func VpcEndpointMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "ec2-vpc-endpoint", + DescriptiveName: "VPC Endpoint", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a VPC Endpoint by ID", + ListDescription: "List all VPC Endpoints", + SearchDescription: "Search VPC Endpoints by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_vpc_endpoint.id"}, + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + } +} diff --git a/sources/ec2/vpc_endpoint_test.go b/adapters/ec2/vpc_endpoint_test.go similarity index 64% rename from sources/ec2/vpc_endpoint_test.go rename to adapters/ec2/vpc_endpoint_test.go index 50433a40..5d80de7a 100644 --- a/sources/ec2/vpc_endpoint_test.go +++ b/adapters/ec2/vpc_endpoint_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/aws/aws-sdk-go-v2/service/ec2/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -31,13 +31,13 @@ func TestVpcEndpointOutputMapper(t *testing.T) { output := &ec2.DescribeVpcEndpointsOutput{ VpcEndpoints: []types.VpcEndpoint{ { - VpcEndpointId: sources.PtrString("vpce-0d7892e00e573e701"), + VpcEndpointId: adapters.PtrString("vpce-0d7892e00e573e701"), VpcEndpointType: types.VpcEndpointTypeInterface, - CreationTimestamp: sources.PtrTime(time.Now()), - VpcId: sources.PtrString("vpc-0d7892e00e573e701"), // link - ServiceName: sources.PtrString("com.amazonaws.us-east-1.s3"), + CreationTimestamp: adapters.PtrTime(time.Now()), + VpcId: adapters.PtrString("vpc-0d7892e00e573e701"), // link + ServiceName: adapters.PtrString("com.amazonaws.us-east-1.s3"), State: types.StateAvailable, - PolicyDocument: sources.PtrString("{\"Version\":\"2012-10-17\",\"Statement\":[{\"Action\":\"*\",\"Resource\":\"*\",\"Effect\":\"Allow\",\"Principal\":\"*\"},{\"Condition\":{\"StringNotEquals\":{\"aws:PrincipalAccount\":\"944651592624\"}},\"Action\":\"*\",\"Resource\":\"*\",\"Effect\":\"Deny\",\"Principal\":\"*\"}]}"), // parse this + PolicyDocument: adapters.PtrString("{\"Version\":\"2012-10-17\",\"Statement\":[{\"Action\":\"*\",\"Resource\":\"*\",\"Effect\":\"Allow\",\"Principal\":\"*\"},{\"Condition\":{\"StringNotEquals\":{\"aws:PrincipalAccount\":\"944651592624\"}},\"Action\":\"*\",\"Resource\":\"*\",\"Effect\":\"Deny\",\"Principal\":\"*\"}]}"), // parse this RouteTableIds: []string{ "rtb-0d7892e00e573e701", // link }, @@ -46,35 +46,35 @@ func TestVpcEndpointOutputMapper(t *testing.T) { }, Groups: []types.SecurityGroupIdentifier{ { - GroupId: sources.PtrString("sg-0d7892e00e573e701"), // link - GroupName: sources.PtrString("default"), + GroupId: adapters.PtrString("sg-0d7892e00e573e701"), // link + GroupName: adapters.PtrString("default"), }, }, IpAddressType: types.IpAddressTypeIpv4, - PrivateDnsEnabled: sources.PtrBool(true), - RequesterManaged: sources.PtrBool(false), + PrivateDnsEnabled: adapters.PtrBool(true), + RequesterManaged: adapters.PtrBool(false), DnsEntries: []types.DnsEntry{ { - DnsName: sources.PtrString("vpce-0d7892e00e573e701-123456789012.us-east-1.vpce.amazonaws.com"), // link - HostedZoneId: sources.PtrString("Z2F56UZL2M1ACD"), // link + DnsName: adapters.PtrString("vpce-0d7892e00e573e701-123456789012.us-east-1.vpce.amazonaws.com"), // link + HostedZoneId: adapters.PtrString("Z2F56UZL2M1ACD"), // link }, }, DnsOptions: &types.DnsOptions{ DnsRecordIpType: types.DnsRecordIpTypeDualstack, - PrivateDnsOnlyForInboundResolverEndpoint: sources.PtrBool(false), + PrivateDnsOnlyForInboundResolverEndpoint: adapters.PtrBool(false), }, LastError: &types.LastError{ - Code: sources.PtrString("Client::ValidationException"), - Message: sources.PtrString("The security group 'sg-0d7892e00e573e701' does not exist"), + Code: adapters.PtrString("Client::ValidationException"), + Message: adapters.PtrString("The security group 'sg-0d7892e00e573e701' does not exist"), }, NetworkInterfaceIds: []string{ "eni-0d7892e00e573e701", // link }, - OwnerId: sources.PtrString("052392120703"), + OwnerId: adapters.PtrString("052392120703"), Tags: []types.Tag{ { - Key: sources.PtrString("Name"), - Value: sources.PtrString("my-vpce"), + Key: adapters.PtrString("Name"), + Value: adapters.PtrString("my-vpce"), }, }, }, @@ -97,7 +97,7 @@ func TestVpcEndpointOutputMapper(t *testing.T) { t.Fatalf("expected 1 item, got %v", len(items)) } - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "ec2-vpc", ExpectedMethod: sdp.QueryMethod_GET, @@ -145,13 +145,13 @@ func TestVpcEndpointOutputMapper(t *testing.T) { tests.Execute(t, items[0]) } -func TestNewVpcEndpointSource(t *testing.T) { +func TestNewVpcEndpointAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewVpcEndpointSource(client, account, region) + adapter := NewVpcEndpointAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/ec2/vpc_peering_connection.go b/adapters/ec2/vpc_peering_connection.go similarity index 71% rename from sources/ec2/vpc_peering_connection.go rename to adapters/ec2/vpc_peering_connection.go index 5c64bf65..8e9cbad1 100644 --- a/sources/ec2/vpc_peering_connection.go +++ b/adapters/ec2/vpc_peering_connection.go @@ -5,7 +5,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/aws/aws-sdk-go-v2/service/ec2/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -13,7 +13,7 @@ func vpcPeeringConnectionOutputMapper(_ context.Context, _ *ec2.Client, scope st items := make([]*sdp.Item, 0) for _, connection := range output.VpcPeeringConnections { - attributes, err := sources.ToAttributesWithExclude(connection, "tags") + attributes, err := adapters.ToAttributesWithExclude(connection, "tags") if err != nil { return nil, err @@ -53,7 +53,7 @@ func vpcPeeringConnectionOutputMapper(_ context.Context, _ *ec2.Client, scope st if connection.AccepterVpcInfo != nil { if connection.AccepterVpcInfo.Region != nil { if connection.AccepterVpcInfo.VpcId != nil && connection.AccepterVpcInfo.OwnerId != nil { - pairedScope := sources.FormatScope(*connection.AccepterVpcInfo.OwnerId, *connection.AccepterVpcInfo.Region) + pairedScope := adapters.FormatScope(*connection.AccepterVpcInfo.OwnerId, *connection.AccepterVpcInfo.Region) // +overmind:link ec2-vpc item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ @@ -78,7 +78,7 @@ func vpcPeeringConnectionOutputMapper(_ context.Context, _ *ec2.Client, scope st if connection.RequesterVpcInfo != nil { if connection.RequesterVpcInfo.Region != nil { if connection.RequesterVpcInfo.VpcId != nil && connection.RequesterVpcInfo.OwnerId != nil { - pairedScope := sources.FormatScope(*connection.RequesterVpcInfo.OwnerId, *connection.RequesterVpcInfo.Region) + pairedScope := adapters.FormatScope(*connection.RequesterVpcInfo.OwnerId, *connection.RequesterVpcInfo.Region) // +overmind:link ec2-vpc item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ @@ -116,12 +116,13 @@ func vpcPeeringConnectionOutputMapper(_ context.Context, _ *ec2.Client, scope st // +overmind:terraform:queryMap aws_vpc_peering_connection_accepter.id // +overmind:terraform:queryMap aws_vpc_peering_connection_options.vpc_peering_connection_id -func NewVpcPeeringConnectionSource(client *ec2.Client, accountID string, region string) *sources.DescribeOnlySource[*ec2.DescribeVpcPeeringConnectionsInput, *ec2.DescribeVpcPeeringConnectionsOutput, *ec2.Client, *ec2.Options] { - return &sources.DescribeOnlySource[*ec2.DescribeVpcPeeringConnectionsInput, *ec2.DescribeVpcPeeringConnectionsOutput, *ec2.Client, *ec2.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "ec2-vpc-peering-connection", +func NewVpcPeeringConnectionAdapter(client *ec2.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*ec2.DescribeVpcPeeringConnectionsInput, *ec2.DescribeVpcPeeringConnectionsOutput, *ec2.Client, *ec2.Options] { + return &adapters.DescribeOnlyAdapter[*ec2.DescribeVpcPeeringConnectionsInput, *ec2.DescribeVpcPeeringConnectionsOutput, *ec2.Client, *ec2.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "ec2-vpc-peering-connection", + AdapterMetadata: VpcPeeringConnectionMetadata(), DescribeFunc: func(ctx context.Context, client *ec2.Client, input *ec2.DescribeVpcPeeringConnectionsInput) (*ec2.DescribeVpcPeeringConnectionsOutput, error) { return client.DescribeVpcPeeringConnections(ctx, input) }, @@ -133,9 +134,30 @@ func NewVpcPeeringConnectionSource(client *ec2.Client, accountID string, region InputMapperList: func(scope string) (*ec2.DescribeVpcPeeringConnectionsInput, error) { return &ec2.DescribeVpcPeeringConnectionsInput{}, nil }, - PaginatorBuilder: func(client *ec2.Client, params *ec2.DescribeVpcPeeringConnectionsInput) sources.Paginator[*ec2.DescribeVpcPeeringConnectionsOutput, *ec2.Options] { + PaginatorBuilder: func(client *ec2.Client, params *ec2.DescribeVpcPeeringConnectionsInput) adapters.Paginator[*ec2.DescribeVpcPeeringConnectionsOutput, *ec2.Options] { return ec2.NewDescribeVpcPeeringConnectionsPaginator(client, params) }, OutputMapper: vpcPeeringConnectionOutputMapper, } } + +func VpcPeeringConnectionMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "ec2-vpc-peering-connection", + DescriptiveName: "VPC Peering Connection", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a VPC Peering Connection by ID", + ListDescription: "List all VPC Peering Connections", + }, + PotentialLinks: []string{"ec2-vpc"}, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_vpc_peering_connection.id"}, + {TerraformQueryMap: "aws_vpc_peering_connection_accepter.id"}, + {TerraformQueryMap: "aws_vpc_peering_connection_options.vpc_peering_connection_id"}, + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + } +} diff --git a/sources/ec2/vpc_peering_connection_test.go b/adapters/ec2/vpc_peering_connection_test.go similarity index 63% rename from sources/ec2/vpc_peering_connection_test.go rename to adapters/ec2/vpc_peering_connection_test.go index 63b35e69..8cc9d23e 100644 --- a/sources/ec2/vpc_peering_connection_test.go +++ b/adapters/ec2/vpc_peering_connection_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/aws/aws-sdk-go-v2/service/ec2/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -15,48 +15,48 @@ func TestVpcPeeringConnectionOutputMapper(t *testing.T) { output := &ec2.DescribeVpcPeeringConnectionsOutput{ VpcPeeringConnections: []types.VpcPeeringConnection{ { - VpcPeeringConnectionId: sources.PtrString("pcx-1234567890"), + VpcPeeringConnectionId: adapters.PtrString("pcx-1234567890"), Status: &types.VpcPeeringConnectionStateReason{ Code: types.VpcPeeringConnectionStateReasonCodeActive, // health - Message: sources.PtrString("message"), + Message: adapters.PtrString("message"), }, AccepterVpcInfo: &types.VpcPeeringConnectionVpcInfo{ - CidrBlock: sources.PtrString("10.0.0.1/24"), + CidrBlock: adapters.PtrString("10.0.0.1/24"), CidrBlockSet: []types.CidrBlock{ { - CidrBlock: sources.PtrString("10.0.2.1/24"), + CidrBlock: adapters.PtrString("10.0.2.1/24"), }, }, Ipv6CidrBlockSet: []types.Ipv6CidrBlock{ { - Ipv6CidrBlock: sources.PtrString("::/64"), + Ipv6CidrBlock: adapters.PtrString("::/64"), }, }, - OwnerId: sources.PtrString("123456789012"), - Region: sources.PtrString("eu-west-2"), // link - VpcId: sources.PtrString("vpc-1234567890"), // link + OwnerId: adapters.PtrString("123456789012"), + Region: adapters.PtrString("eu-west-2"), // link + VpcId: adapters.PtrString("vpc-1234567890"), // link PeeringOptions: &types.VpcPeeringConnectionOptionsDescription{ - AllowDnsResolutionFromRemoteVpc: sources.PtrBool(true), + AllowDnsResolutionFromRemoteVpc: adapters.PtrBool(true), }, }, RequesterVpcInfo: &types.VpcPeeringConnectionVpcInfo{ - CidrBlock: sources.PtrString("10.0.0.1/24"), + CidrBlock: adapters.PtrString("10.0.0.1/24"), CidrBlockSet: []types.CidrBlock{ { - CidrBlock: sources.PtrString("10.0.2.1/24"), + CidrBlock: adapters.PtrString("10.0.2.1/24"), }, }, Ipv6CidrBlockSet: []types.Ipv6CidrBlock{ { - Ipv6CidrBlock: sources.PtrString("::/64"), + Ipv6CidrBlock: adapters.PtrString("::/64"), }, }, - OwnerId: sources.PtrString("987654321098"), + OwnerId: adapters.PtrString("987654321098"), PeeringOptions: &types.VpcPeeringConnectionOptionsDescription{ - AllowDnsResolutionFromRemoteVpc: sources.PtrBool(true), + AllowDnsResolutionFromRemoteVpc: adapters.PtrBool(true), }, - Region: sources.PtrString("eu-west-5"), // link - VpcId: sources.PtrString("vpc-9887654321"), // link + Region: adapters.PtrString("eu-west-5"), // link + VpcId: adapters.PtrString("vpc-9887654321"), // link }, }, }, @@ -82,7 +82,7 @@ func TestVpcPeeringConnectionOutputMapper(t *testing.T) { // It doesn't really make sense to test anything other than the linked items // since the attributes are converted automatically - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "ec2-vpc", ExpectedMethod: sdp.QueryMethod_GET, @@ -101,13 +101,13 @@ func TestVpcPeeringConnectionOutputMapper(t *testing.T) { } -func TestNewVpcPeeringConnectionSource(t *testing.T) { +func TestNewVpcPeeringConnectionAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewVpcPeeringConnectionSource(client, account, region) + adapter := NewVpcPeeringConnectionAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/ec2/vpc_test.go b/adapters/ec2/vpc_test.go similarity index 55% rename from sources/ec2/vpc_test.go rename to adapters/ec2/vpc_test.go index 34e5c38f..aad6d904 100644 --- a/sources/ec2/vpc_test.go +++ b/adapters/ec2/vpc_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/aws/aws-sdk-go-v2/service/ec2/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" ) func TestVpcInputMapperGet(t *testing.T) { @@ -42,38 +42,38 @@ func TestVpcOutputMapper(t *testing.T) { output := &ec2.DescribeVpcsOutput{ Vpcs: []types.Vpc{ { - CidrBlock: sources.PtrString("172.31.0.0/16"), - DhcpOptionsId: sources.PtrString("dopt-0959b838bf4a4c7b8"), + CidrBlock: adapters.PtrString("172.31.0.0/16"), + DhcpOptionsId: adapters.PtrString("dopt-0959b838bf4a4c7b8"), State: types.VpcStateAvailable, - VpcId: sources.PtrString("vpc-0d7892e00e573e701"), - OwnerId: sources.PtrString("052392120703"), + VpcId: adapters.PtrString("vpc-0d7892e00e573e701"), + OwnerId: adapters.PtrString("052392120703"), InstanceTenancy: types.TenancyDefault, CidrBlockAssociationSet: []types.VpcCidrBlockAssociation{ { - AssociationId: sources.PtrString("vpc-cidr-assoc-0b77866f37f500af6"), - CidrBlock: sources.PtrString("172.31.0.0/16"), + AssociationId: adapters.PtrString("vpc-cidr-assoc-0b77866f37f500af6"), + CidrBlock: adapters.PtrString("172.31.0.0/16"), CidrBlockState: &types.VpcCidrBlockState{ State: types.VpcCidrBlockStateCodeAssociated, }, }, }, - IsDefault: sources.PtrBool(false), + IsDefault: adapters.PtrBool(false), Tags: []types.Tag{ { - Key: sources.PtrString("aws:cloudformation:logical-id"), - Value: sources.PtrString("VPC"), + Key: adapters.PtrString("aws:cloudformation:logical-id"), + Value: adapters.PtrString("VPC"), }, { - Key: sources.PtrString("aws:cloudformation:stack-id"), - Value: sources.PtrString("arn:aws:cloudformation:eu-west-2:052392120703:stack/StackSet-AWSControlTowerBP-VPC-ACCOUNT-FACTORY-V1-8c2a9348-a30c-4ac3-94c2-8279157c9243/ccde3240-7afa-11ed-81ff-02845d4c2702"), + Key: adapters.PtrString("aws:cloudformation:stack-id"), + Value: adapters.PtrString("arn:aws:cloudformation:eu-west-2:052392120703:stack/StackSet-AWSControlTowerBP-VPC-ACCOUNT-FACTORY-V1-8c2a9348-a30c-4ac3-94c2-8279157c9243/ccde3240-7afa-11ed-81ff-02845d4c2702"), }, { - Key: sources.PtrString("aws:cloudformation:stack-name"), - Value: sources.PtrString("StackSet-AWSControlTowerBP-VPC-ACCOUNT-FACTORY-V1-8c2a9348-a30c-4ac3-94c2-8279157c9243"), + Key: adapters.PtrString("aws:cloudformation:stack-name"), + Value: adapters.PtrString("StackSet-AWSControlTowerBP-VPC-ACCOUNT-FACTORY-V1-8c2a9348-a30c-4ac3-94c2-8279157c9243"), }, { - Key: sources.PtrString("Name"), - Value: sources.PtrString("aws-controltower-VPC"), + Key: adapters.PtrString("Name"), + Value: adapters.PtrString("aws-controltower-VPC"), }, }, }, @@ -97,13 +97,13 @@ func TestVpcOutputMapper(t *testing.T) { } } -func TestNewVpcSource(t *testing.T) { +func TestNewVpcAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewVpcSource(client, account, region) + adapter := NewVpcAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/ecs/capacity_provider.go b/adapters/ecs/capacity_provider.go similarity index 74% rename from sources/ecs/capacity_provider.go rename to adapters/ecs/capacity_provider.go index 1f522a82..88ddf738 100644 --- a/sources/ecs/capacity_provider.go +++ b/adapters/ecs/capacity_provider.go @@ -6,7 +6,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ecs" "github.com/aws/aws-sdk-go-v2/service/ecs/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -18,7 +18,7 @@ func capacityProviderOutputMapper(_ context.Context, _ ECSClient, scope string, items := make([]*sdp.Item, 0) for _, provider := range output.CapacityProviders { - attributes, err := sources.ToAttributesWithExclude(provider, "tags") + attributes, err := adapters.ToAttributesWithExclude(provider, "tags") if err != nil { return nil, err @@ -34,14 +34,14 @@ func capacityProviderOutputMapper(_ context.Context, _ ECSClient, scope string, if provider.AutoScalingGroupProvider != nil { if provider.AutoScalingGroupProvider.AutoScalingGroupArn != nil { - if a, err := sources.ParseARN(*provider.AutoScalingGroupProvider.AutoScalingGroupArn); err == nil { + if a, err := adapters.ParseARN(*provider.AutoScalingGroupProvider.AutoScalingGroupArn); err == nil { // +overmind:link autoscaling-auto-scaling-group item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "autoscaling-auto-scaling-group", Method: sdp.QueryMethod_SEARCH, Query: *provider.AutoScalingGroupProvider.AutoScalingGroupArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // These are tightly linked @@ -69,12 +69,13 @@ func capacityProviderOutputMapper(_ context.Context, _ ECSClient, scope string, // +overmind:terraform:queryMap aws_ecs_capacity_provider.arn // +overmind:terraform:method SEARCH -func NewCapacityProviderSource(client ECSClient, accountID string, region string) *sources.DescribeOnlySource[*ecs.DescribeCapacityProvidersInput, *ecs.DescribeCapacityProvidersOutput, ECSClient, *ecs.Options] { - return &sources.DescribeOnlySource[*ecs.DescribeCapacityProvidersInput, *ecs.DescribeCapacityProvidersOutput, ECSClient, *ecs.Options]{ - ItemType: "ecs-capacity-provider", - Region: region, - AccountID: accountID, - Client: client, +func NewCapacityProviderAdapter(client ECSClient, accountID string, region string) *adapters.DescribeOnlyAdapter[*ecs.DescribeCapacityProvidersInput, *ecs.DescribeCapacityProvidersOutput, ECSClient, *ecs.Options] { + return &adapters.DescribeOnlyAdapter[*ecs.DescribeCapacityProvidersInput, *ecs.DescribeCapacityProvidersOutput, ECSClient, *ecs.Options]{ + ItemType: "ecs-capacity-provider", + Region: region, + AccountID: accountID, + Client: client, + AdapterMetadata: CapacityProviderMetadata(), DescribeFunc: func(ctx context.Context, client ECSClient, input *ecs.DescribeCapacityProvidersInput) (*ecs.DescribeCapacityProvidersOutput, error) { return client.DescribeCapacityProviders(ctx, input) }, @@ -91,13 +92,33 @@ func NewCapacityProviderSource(client ECSClient, accountID string, region string Include: CapacityProviderIncludeFields, }, nil }, - PaginatorBuilder: func(client ECSClient, params *ecs.DescribeCapacityProvidersInput) sources.Paginator[*ecs.DescribeCapacityProvidersOutput, *ecs.Options] { + PaginatorBuilder: func(client ECSClient, params *ecs.DescribeCapacityProvidersInput) adapters.Paginator[*ecs.DescribeCapacityProvidersOutput, *ecs.Options] { return NewDescribeCapacityProvidersPaginator(client, params) }, OutputMapper: capacityProviderOutputMapper, } } +func CapacityProviderMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "ecs-capacity-provider", + DescriptiveName: "Capacity Provider", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + }, + TerraformMappings: []*sdp.TerraformMapping{ + { + TerraformQueryMap: "aws_ecs_capacity_provider.arn", + TerraformMethod: sdp.QueryMethod_SEARCH, + }, + }, + PotentialLinks: []string{"autoscaling-auto-scaling-group"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_CONFIGURATION, + } +} + // Incredibly annoyingly the go package doesn't provide a paginator builder for // DescribeCapacityProviders despite the fact that it's paginated, so I'm going // to create one myself below diff --git a/sources/ecs/capacity_provider_test.go b/adapters/ecs/capacity_provider_test.go similarity index 56% rename from sources/ecs/capacity_provider_test.go rename to adapters/ecs/capacity_provider_test.go index eb43b264..5da605ea 100644 --- a/sources/ecs/capacity_provider_test.go +++ b/adapters/ecs/capacity_provider_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ecs" "github.com/aws/aws-sdk-go-v2/service/ecs/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -16,42 +16,42 @@ func (t *TestClient) DescribeCapacityProviders(ctx context.Context, params *ecs. "": { CapacityProviders: []types.CapacityProvider{ { - CapacityProviderArn: sources.PtrString("arn:aws:ecs:eu-west-2:052392120703:capacity-provider/FARGATE"), - Name: sources.PtrString("FARGATE"), + CapacityProviderArn: adapters.PtrString("arn:aws:ecs:eu-west-2:052392120703:capacity-provider/FARGATE"), + Name: adapters.PtrString("FARGATE"), Status: types.CapacityProviderStatusActive, }, }, - NextToken: sources.PtrString("one"), + NextToken: adapters.PtrString("one"), }, "one": { CapacityProviders: []types.CapacityProvider{ { - CapacityProviderArn: sources.PtrString("arn:aws:ecs:eu-west-2:052392120703:capacity-provider/FARGATE_SPOT"), - Name: sources.PtrString("FARGATE_SPOT"), + CapacityProviderArn: adapters.PtrString("arn:aws:ecs:eu-west-2:052392120703:capacity-provider/FARGATE_SPOT"), + Name: adapters.PtrString("FARGATE_SPOT"), Status: types.CapacityProviderStatusActive, }, }, - NextToken: sources.PtrString("two"), + NextToken: adapters.PtrString("two"), }, "two": { CapacityProviders: []types.CapacityProvider{ { - CapacityProviderArn: sources.PtrString("arn:aws:ecs:eu-west-2:052392120703:capacity-provider/test"), - Name: sources.PtrString("test"), + CapacityProviderArn: adapters.PtrString("arn:aws:ecs:eu-west-2:052392120703:capacity-provider/test"), + Name: adapters.PtrString("test"), Status: types.CapacityProviderStatusActive, AutoScalingGroupProvider: &types.AutoScalingGroupProvider{ - AutoScalingGroupArn: sources.PtrString("arn:aws:autoscaling:eu-west-2:052392120703:autoScalingGroup:9df90815-98c1-4136-a12a-90abef1c4e4e:autoScalingGroupName/ecs-test"), + AutoScalingGroupArn: adapters.PtrString("arn:aws:autoscaling:eu-west-2:052392120703:autoScalingGroup:9df90815-98c1-4136-a12a-90abef1c4e4e:autoScalingGroupName/ecs-test"), ManagedScaling: &types.ManagedScaling{ Status: types.ManagedScalingStatusEnabled, - TargetCapacity: sources.PtrInt32(80), - MinimumScalingStepSize: sources.PtrInt32(1), - MaximumScalingStepSize: sources.PtrInt32(10000), - InstanceWarmupPeriod: sources.PtrInt32(300), + TargetCapacity: adapters.PtrInt32(80), + MinimumScalingStepSize: adapters.PtrInt32(1), + MaximumScalingStepSize: adapters.PtrInt32(10000), + InstanceWarmupPeriod: adapters.PtrInt32(300), }, ManagedTerminationProtection: types.ManagedTerminationProtectionDisabled, }, UpdateStatus: types.CapacityProviderUpdateStatusDeleteComplete, - UpdateStatusReason: sources.PtrString("reason"), + UpdateStatusReason: adapters.PtrString("reason"), }, }, }, @@ -75,22 +75,22 @@ func TestCapacityProviderOutputMapper(t *testing.T) { &ecs.DescribeCapacityProvidersOutput{ CapacityProviders: []types.CapacityProvider{ { - CapacityProviderArn: sources.PtrString("arn:aws:ecs:eu-west-2:052392120703:capacity-provider/test"), - Name: sources.PtrString("test"), + CapacityProviderArn: adapters.PtrString("arn:aws:ecs:eu-west-2:052392120703:capacity-provider/test"), + Name: adapters.PtrString("test"), Status: types.CapacityProviderStatusActive, AutoScalingGroupProvider: &types.AutoScalingGroupProvider{ - AutoScalingGroupArn: sources.PtrString("arn:aws:autoscaling:eu-west-2:052392120703:autoScalingGroup:9df90815-98c1-4136-a12a-90abef1c4e4e:autoScalingGroupName/ecs-test"), + AutoScalingGroupArn: adapters.PtrString("arn:aws:autoscaling:eu-west-2:052392120703:autoScalingGroup:9df90815-98c1-4136-a12a-90abef1c4e4e:autoScalingGroupName/ecs-test"), ManagedScaling: &types.ManagedScaling{ Status: types.ManagedScalingStatusEnabled, - TargetCapacity: sources.PtrInt32(80), - MinimumScalingStepSize: sources.PtrInt32(1), - MaximumScalingStepSize: sources.PtrInt32(10000), - InstanceWarmupPeriod: sources.PtrInt32(300), + TargetCapacity: adapters.PtrInt32(80), + MinimumScalingStepSize: adapters.PtrInt32(1), + MaximumScalingStepSize: adapters.PtrInt32(10000), + InstanceWarmupPeriod: adapters.PtrInt32(300), }, ManagedTerminationProtection: types.ManagedTerminationProtectionDisabled, }, UpdateStatus: types.CapacityProviderUpdateStatusDeleteComplete, - UpdateStatusReason: sources.PtrString("reason"), + UpdateStatusReason: adapters.PtrString("reason"), }, }, }, @@ -110,7 +110,7 @@ func TestCapacityProviderOutputMapper(t *testing.T) { t.Error(err) } - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "autoscaling-auto-scaling-group", ExpectedMethod: sdp.QueryMethod_SEARCH, @@ -122,10 +122,10 @@ func TestCapacityProviderOutputMapper(t *testing.T) { tests.Execute(t, item) } -func TestCapacityProviderSource(t *testing.T) { - src := NewCapacityProviderSource(&TestClient{}, "", "") +func TestCapacityProviderAdapter(t *testing.T) { + adapter := NewCapacityProviderAdapter(&TestClient{}, "", "") - items, err := src.List(context.Background(), "", false) + items, err := adapter.List(context.Background(), "", false) if err != nil { t.Error(err) @@ -136,14 +136,14 @@ func TestCapacityProviderSource(t *testing.T) { } } -func TestNewCapacityProviderSource(t *testing.T) { - config, account, region := sources.GetAutoConfig(t) +func TestNewCapacityProviderAdapter(t *testing.T) { + config, account, region := adapters.GetAutoConfig(t) client := ecs.NewFromConfig(config) - source := NewCapacityProviderSource(client, account, region) + adapter := NewCapacityProviderAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/ecs/cluster.go b/adapters/ecs/cluster.go similarity index 79% rename from sources/ecs/cluster.go rename to adapters/ecs/cluster.go index 86400de8..2491fffb 100644 --- a/sources/ecs/cluster.go +++ b/adapters/ecs/cluster.go @@ -6,7 +6,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ecs" "github.com/aws/aws-sdk-go-v2/service/ecs/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -26,7 +26,7 @@ func clusterGetFunc(ctx context.Context, client ECSClient, scope string, input * return nil, err } - accountID, _, err := sources.ParseScope(scope) + accountID, _, err := adapters.ParseScope(scope) if err != nil { return nil, err @@ -53,7 +53,7 @@ func clusterGetFunc(ctx context.Context, client ECSClient, scope string, input * cluster := out.Clusters[0] - attributes, err := sources.ToAttributesWithExclude(cluster, "tags") + attributes, err := adapters.ToAttributesWithExclude(cluster, "tags") if err != nil { return nil, err @@ -177,7 +177,7 @@ func clusterGetFunc(ctx context.Context, client ECSClient, scope string, input * Type: "s3-bucket", Method: sdp.QueryMethod_GET, Query: *cluster.Configuration.ExecuteCommandConfiguration.LogConfiguration.S3BucketName, - Scope: sources.FormatScope(accountID, ""), + Scope: adapters.FormatScope(accountID, ""), }, BlastPropagation: &sdp.BlastPropagation{ // These are tightly linked @@ -220,13 +220,14 @@ func clusterGetFunc(ctx context.Context, client ECSClient, scope string, input * // +overmind:terraform:queryMap aws_ecs_cluster.arn // +overmind:terraform:method SEARCH -func NewClusterSource(client ECSClient, accountID string, region string) *sources.AlwaysGetSource[*ecs.ListClustersInput, *ecs.ListClustersOutput, *ecs.DescribeClustersInput, *ecs.DescribeClustersOutput, ECSClient, *ecs.Options] { - return &sources.AlwaysGetSource[*ecs.ListClustersInput, *ecs.ListClustersOutput, *ecs.DescribeClustersInput, *ecs.DescribeClustersOutput, ECSClient, *ecs.Options]{ - ItemType: "ecs-cluster", - Client: client, - AccountID: accountID, - Region: region, - GetFunc: clusterGetFunc, +func NewClusterAdapter(client ECSClient, accountID string, region string) *adapters.AlwaysGetAdapter[*ecs.ListClustersInput, *ecs.ListClustersOutput, *ecs.DescribeClustersInput, *ecs.DescribeClustersOutput, ECSClient, *ecs.Options] { + return &adapters.AlwaysGetAdapter[*ecs.ListClustersInput, *ecs.ListClustersOutput, *ecs.DescribeClustersInput, *ecs.DescribeClustersOutput, ECSClient, *ecs.Options]{ + ItemType: "ecs-cluster", + Client: client, + AccountID: accountID, + Region: region, + GetFunc: clusterGetFunc, + AdapterMetadata: ClusterMetadata(), GetInputMapper: func(scope, query string) *ecs.DescribeClustersInput { return &ecs.DescribeClustersInput{ Clusters: []string{ @@ -236,17 +237,17 @@ func NewClusterSource(client ECSClient, accountID string, region string) *source } }, ListInput: &ecs.ListClustersInput{}, - ListFuncPaginatorBuilder: func(client ECSClient, input *ecs.ListClustersInput) sources.Paginator[*ecs.ListClustersOutput, *ecs.Options] { + ListFuncPaginatorBuilder: func(client ECSClient, input *ecs.ListClustersInput) adapters.Paginator[*ecs.ListClustersOutput, *ecs.Options] { return ecs.NewListClustersPaginator(client, input) }, ListFuncOutputMapper: func(output *ecs.ListClustersOutput, input *ecs.ListClustersInput) ([]*ecs.DescribeClustersInput, error) { inputs := make([]*ecs.DescribeClustersInput, 0) - var a *sources.ARN + var a *adapters.ARN var err error for _, arn := range output.ClusterArns { - a, err = sources.ParseARN(arn) + a, err = adapters.ParseARN(arn) if err != nil { continue @@ -264,3 +265,26 @@ func NewClusterSource(client ECSClient, accountID string, region string) *source }, } } + +func ClusterMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "ecs-cluster", + DescriptiveName: "ECS Cluster", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a cluster by name", + ListDescription: "List all clusters", + SearchDescription: "Search for a cluster by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + { + TerraformQueryMap: "aws_ecs_cluster.arn", + TerraformMethod: sdp.QueryMethod_SEARCH, + }, + }, + PotentialLinks: []string{"ecs-container-instance", "ecs-service", "ecs-task", "ecs-capacity-provider"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_COMPUTE_APPLICATION, + } +} diff --git a/sources/ecs/cluster_test.go b/adapters/ecs/cluster_test.go similarity index 67% rename from sources/ecs/cluster_test.go rename to adapters/ecs/cluster_test.go index f3c3cf3e..f71e7146 100644 --- a/sources/ecs/cluster_test.go +++ b/adapters/ecs/cluster_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ecs" "github.com/aws/aws-sdk-go-v2/service/ecs/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -15,24 +15,24 @@ func (t *TestClient) DescribeClusters(ctx context.Context, params *ecs.DescribeC return &ecs.DescribeClustersOutput{ Clusters: []types.Cluster{ { - ClusterArn: sources.PtrString("arn:aws:ecs:eu-west-2:052392120703:cluster/default"), - ClusterName: sources.PtrString("default"), - Status: sources.PtrString("ACTIVE"), + ClusterArn: adapters.PtrString("arn:aws:ecs:eu-west-2:052392120703:cluster/default"), + ClusterName: adapters.PtrString("default"), + Status: adapters.PtrString("ACTIVE"), RegisteredContainerInstancesCount: 0, RunningTasksCount: 1, PendingTasksCount: 0, ActiveServicesCount: 1, Statistics: []types.KeyValuePair{ { - Name: sources.PtrString("key"), - Value: sources.PtrString("value"), + Name: adapters.PtrString("key"), + Value: adapters.PtrString("value"), }, }, Tags: []types.Tag{}, Settings: []types.ClusterSetting{ { Name: types.ClusterSettingNameContainerInsights, - Value: sources.PtrString("ENABLED"), + Value: adapters.PtrString("ENABLED"), }, }, CapacityProviders: []string{ @@ -40,43 +40,43 @@ func (t *TestClient) DescribeClusters(ctx context.Context, params *ecs.DescribeC }, DefaultCapacityProviderStrategy: []types.CapacityProviderStrategyItem{ { - CapacityProvider: sources.PtrString("provider"), + CapacityProvider: adapters.PtrString("provider"), Base: 10, Weight: 100, }, }, Attachments: []types.Attachment{ { - Id: sources.PtrString("1c1f9cf4-461c-4072-aab2-e2dd346c53e1"), - Type: sources.PtrString("as_policy"), - Status: sources.PtrString("CREATED"), + Id: adapters.PtrString("1c1f9cf4-461c-4072-aab2-e2dd346c53e1"), + Type: adapters.PtrString("as_policy"), + Status: adapters.PtrString("CREATED"), Details: []types.KeyValuePair{ { - Name: sources.PtrString("capacityProviderName"), - Value: sources.PtrString("test"), + Name: adapters.PtrString("capacityProviderName"), + Value: adapters.PtrString("test"), }, { - Name: sources.PtrString("scalingPolicyName"), - Value: sources.PtrString("ECSManagedAutoScalingPolicy-d2f110eb-20a6-4278-9c1c-47d98e21b1ed"), + Name: adapters.PtrString("scalingPolicyName"), + Value: adapters.PtrString("ECSManagedAutoScalingPolicy-d2f110eb-20a6-4278-9c1c-47d98e21b1ed"), }, }, }, }, - AttachmentsStatus: sources.PtrString("UPDATE_COMPLETE"), + AttachmentsStatus: adapters.PtrString("UPDATE_COMPLETE"), Configuration: &types.ClusterConfiguration{ ExecuteCommandConfiguration: &types.ExecuteCommandConfiguration{ - KmsKeyId: sources.PtrString("id"), + KmsKeyId: adapters.PtrString("id"), LogConfiguration: &types.ExecuteCommandLogConfiguration{ CloudWatchEncryptionEnabled: true, - CloudWatchLogGroupName: sources.PtrString("cloud-watch-name"), - S3BucketName: sources.PtrString("s3-name"), + CloudWatchLogGroupName: adapters.PtrString("cloud-watch-name"), + S3BucketName: adapters.PtrString("s3-name"), S3EncryptionEnabled: true, - S3KeyPrefix: sources.PtrString("prod"), + S3KeyPrefix: adapters.PtrString("prod"), }, }, }, ServiceConnectDefaults: &types.ClusterServiceConnectDefaults{ - Namespace: sources.PtrString("prod"), + Namespace: adapters.PtrString("prod"), }, }, }, @@ -103,7 +103,7 @@ func TestClusterGetFunc(t *testing.T) { t.Error(err) } - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "kms-key", ExpectedMethod: sdp.QueryMethod_GET, @@ -145,13 +145,13 @@ func TestClusterGetFunc(t *testing.T) { tests.Execute(t, item) } -func TestNewClusterSource(t *testing.T) { +func TestNewClusterAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewClusterSource(client, account, region) + adapter := NewClusterAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/ecs/container_instance.go b/adapters/ecs/container_instance.go similarity index 70% rename from sources/ecs/container_instance.go rename to adapters/ecs/container_instance.go index 1d2ec353..f73f07dc 100644 --- a/sources/ecs/container_instance.go +++ b/adapters/ecs/container_instance.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ecs" "github.com/aws/aws-sdk-go-v2/service/ecs/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -30,7 +30,7 @@ func containerInstanceGetFunc(ctx context.Context, client ECSClient, scope strin containerInstance := out.ContainerInstances[0] - attributes, err := sources.ToAttributesWithExclude(containerInstance, "tags") + attributes, err := adapters.ToAttributesWithExclude(containerInstance, "tags") if err != nil { return nil, err @@ -39,7 +39,7 @@ func containerInstanceGetFunc(ctx context.Context, client ECSClient, scope strin // Create an ID param since they don't have anything that uniquely // identifies them. This is {clusterName}/{id} // ecs-template-ECSCluster-8nS0WOLbs3nZ/50e9bf71ed57450ca56293cc5a042886 - if a, err := sources.ParseARN(*containerInstance.ContainerInstanceArn); err == nil { + if a, err := adapters.ParseARN(*containerInstance.ContainerInstanceArn); err == nil { attributes.Set("Id", a.Resource) } @@ -87,11 +87,11 @@ func containerInstanceGetFunc(ctx context.Context, client ECSClient, scope strin func containerInstanceListFuncOutputMapper(output *ecs.ListContainerInstancesOutput, input *ecs.ListContainerInstancesInput) ([]*ecs.DescribeContainerInstancesInput, error) { inputs := make([]*ecs.DescribeContainerInstancesInput, 0) - var a *sources.ARN + var a *adapters.ARN var err error for _, arn := range output.ContainerInstanceArns { - a, err = sources.ParseARN(arn) + a, err = adapters.ParseARN(arn) if err != nil { continue @@ -123,13 +123,14 @@ func containerInstanceListFuncOutputMapper(output *ecs.ListContainerInstancesOut // +overmind:search Search for container instances by cluster // +overmind:group AWS -func NewContainerInstanceSource(client ECSClient, accountID string, region string) *sources.AlwaysGetSource[*ecs.ListContainerInstancesInput, *ecs.ListContainerInstancesOutput, *ecs.DescribeContainerInstancesInput, *ecs.DescribeContainerInstancesOutput, ECSClient, *ecs.Options] { - return &sources.AlwaysGetSource[*ecs.ListContainerInstancesInput, *ecs.ListContainerInstancesOutput, *ecs.DescribeContainerInstancesInput, *ecs.DescribeContainerInstancesOutput, ECSClient, *ecs.Options]{ - ItemType: "ecs-container-instance", - Client: client, - AccountID: accountID, - Region: region, - GetFunc: containerInstanceGetFunc, +func NewContainerInstanceAdapter(client ECSClient, accountID string, region string) *adapters.AlwaysGetAdapter[*ecs.ListContainerInstancesInput, *ecs.ListContainerInstancesOutput, *ecs.DescribeContainerInstancesInput, *ecs.DescribeContainerInstancesOutput, ECSClient, *ecs.Options] { + return &adapters.AlwaysGetAdapter[*ecs.ListContainerInstancesInput, *ecs.ListContainerInstancesOutput, *ecs.DescribeContainerInstancesInput, *ecs.DescribeContainerInstancesOutput, ECSClient, *ecs.Options]{ + ItemType: "ecs-container-instance", + Client: client, + AccountID: accountID, + Region: region, + GetFunc: containerInstanceGetFunc, + AdapterMetadata: ContainerInstanceMetadata(), GetInputMapper: func(scope, query string) *ecs.DescribeContainerInstancesInput { // We are using a custom id of {clusterName}/{id} e.g. // ecs-template-ECSCluster-8nS0WOLbs3nZ/50e9bf71ed57450ca56293cc5a042886 @@ -149,15 +150,32 @@ func NewContainerInstanceSource(client ECSClient, accountID string, region strin }, ListInput: &ecs.ListContainerInstancesInput{}, DisableList: true, // Tou can't list without a cluster - ListFuncPaginatorBuilder: func(client ECSClient, input *ecs.ListContainerInstancesInput) sources.Paginator[*ecs.ListContainerInstancesOutput, *ecs.Options] { + ListFuncPaginatorBuilder: func(client ECSClient, input *ecs.ListContainerInstancesInput) adapters.Paginator[*ecs.ListContainerInstancesOutput, *ecs.Options] { return ecs.NewListContainerInstancesPaginator(client, input) }, SearchInputMapper: func(scope, query string) (*ecs.ListContainerInstancesInput, error) { // Custom search by cluster return &ecs.ListContainerInstancesInput{ - Cluster: sources.PtrString(query), + Cluster: adapters.PtrString(query), }, nil }, ListFuncOutputMapper: containerInstanceListFuncOutputMapper, } } + +func ContainerInstanceMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "ecs-container-instance", + DescriptiveName: "Container Instance", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a container instance by ID which consists of {clusterName}/{id}", + ListDescription: "List all container instances", + SearchDescription: "Search for container instances by cluster", + }, + PotentialLinks: []string{"ec2-instance"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_COMPUTE_APPLICATION, + } +} diff --git a/adapters/ecs/container_instance_test.go b/adapters/ecs/container_instance_test.go new file mode 100644 index 00000000..26510dae --- /dev/null +++ b/adapters/ecs/container_instance_test.go @@ -0,0 +1,362 @@ +package ecs + +import ( + "context" + "testing" + "time" + + "github.com/aws/aws-sdk-go-v2/service/ecs" + "github.com/aws/aws-sdk-go-v2/service/ecs/types" + "github.com/overmindtech/aws-source/adapters" + "github.com/overmindtech/sdp-go" +) + +func (t *TestClient) DescribeContainerInstances(ctx context.Context, params *ecs.DescribeContainerInstancesInput, optFns ...func(*ecs.Options)) (*ecs.DescribeContainerInstancesOutput, error) { + return &ecs.DescribeContainerInstancesOutput{ + ContainerInstances: []types.ContainerInstance{ + { + ContainerInstanceArn: adapters.PtrString("arn:aws:ecs:eu-west-1:052392120703:container-instance/ecs-template-ECSCluster-8nS0WOLbs3nZ/50e9bf71ed57450ca56293cc5a042886"), + Ec2InstanceId: adapters.PtrString("i-0e778f25705bc0c84"), // link + Version: 4, + VersionInfo: &types.VersionInfo{ + AgentVersion: adapters.PtrString("1.47.0"), + AgentHash: adapters.PtrString("1489adfa"), + DockerVersion: adapters.PtrString("DockerVersion: 19.03.6-ce"), + }, + RemainingResources: []types.Resource{ + { + Name: adapters.PtrString("CPU"), + Type: adapters.PtrString("INTEGER"), + DoubleValue: 0.0, + LongValue: 0, + IntegerValue: 2028, + }, + { + Name: adapters.PtrString("MEMORY"), + Type: adapters.PtrString("INTEGER"), + DoubleValue: 0.0, + LongValue: 0, + IntegerValue: 7474, + }, + { + Name: adapters.PtrString("PORTS"), + Type: adapters.PtrString("STRINGSET"), + DoubleValue: 0.0, + LongValue: 0, + IntegerValue: 0, + StringSetValue: []string{ + "22", + "2376", + "2375", + "51678", + "51679", + }, + }, + { + Name: adapters.PtrString("PORTS_UDP"), + Type: adapters.PtrString("STRINGSET"), + DoubleValue: 0.0, + LongValue: 0, + IntegerValue: 0, + StringSetValue: []string{}, + }, + }, + RegisteredResources: []types.Resource{ + { + Name: adapters.PtrString("CPU"), + Type: adapters.PtrString("INTEGER"), + DoubleValue: 0.0, + LongValue: 0, + IntegerValue: 2048, + }, + { + Name: adapters.PtrString("MEMORY"), + Type: adapters.PtrString("INTEGER"), + DoubleValue: 0.0, + LongValue: 0, + IntegerValue: 7974, + }, + { + Name: adapters.PtrString("PORTS"), + Type: adapters.PtrString("STRINGSET"), + DoubleValue: 0.0, + LongValue: 0, + IntegerValue: 0, + StringSetValue: []string{ + "22", + "2376", + "2375", + "51678", + "51679", + }, + }, + { + Name: adapters.PtrString("PORTS_UDP"), + Type: adapters.PtrString("STRINGSET"), + DoubleValue: 0.0, + LongValue: 0, + IntegerValue: 0, + StringSetValue: []string{}, + }, + }, + Status: adapters.PtrString("ACTIVE"), + AgentConnected: true, + RunningTasksCount: 1, + PendingTasksCount: 0, + Attributes: []types.Attribute{ + { + Name: adapters.PtrString("ecs.capability.secrets.asm.environment-variables"), + }, + { + Name: adapters.PtrString("ecs.capability.branch-cni-plugin-version"), + Value: adapters.PtrString("a21d3a41-"), + }, + { + Name: adapters.PtrString("ecs.ami-id"), + Value: adapters.PtrString("ami-0c9ef930279337028"), + }, + { + Name: adapters.PtrString("ecs.capability.secrets.asm.bootstrap.log-driver"), + }, + { + Name: adapters.PtrString("ecs.capability.task-eia.optimized-cpu"), + }, + { + Name: adapters.PtrString("com.amazonaws.ecs.capability.logging-driver.none"), + }, + { + Name: adapters.PtrString("ecs.capability.ecr-endpoint"), + }, + { + Name: adapters.PtrString("ecs.capability.docker-plugin.local"), + }, + { + Name: adapters.PtrString("ecs.capability.task-cpu-mem-limit"), + }, + { + Name: adapters.PtrString("ecs.capability.secrets.ssm.bootstrap.log-driver"), + }, + { + Name: adapters.PtrString("ecs.capability.efsAuth"), + }, + { + Name: adapters.PtrString("ecs.capability.full-sync"), + }, + { + Name: adapters.PtrString("com.amazonaws.ecs.capability.docker-remote-api.1.30"), + }, + { + Name: adapters.PtrString("com.amazonaws.ecs.capability.docker-remote-api.1.31"), + }, + { + Name: adapters.PtrString("com.amazonaws.ecs.capability.docker-remote-api.1.32"), + }, + { + Name: adapters.PtrString("com.amazonaws.ecs.capability.logging-driver.fluentd"), + }, + { + Name: adapters.PtrString("ecs.capability.firelens.options.config.file"), + }, + { + Name: adapters.PtrString("ecs.availability-zone"), + Value: adapters.PtrString("eu-west-1a"), + }, + { + Name: adapters.PtrString("ecs.capability.aws-appmesh"), + }, + { + Name: adapters.PtrString("com.amazonaws.ecs.capability.logging-driver.awslogs"), + }, + { + Name: adapters.PtrString("com.amazonaws.ecs.capability.docker-remote-api.1.24"), + }, + { + Name: adapters.PtrString("ecs.capability.task-eni-trunking"), + }, + { + Name: adapters.PtrString("com.amazonaws.ecs.capability.docker-remote-api.1.25"), + }, + { + Name: adapters.PtrString("com.amazonaws.ecs.capability.docker-remote-api.1.26"), + }, + { + Name: adapters.PtrString("com.amazonaws.ecs.capability.docker-remote-api.1.27"), + }, + { + Name: adapters.PtrString("com.amazonaws.ecs.capability.privileged-container"), + }, + { + Name: adapters.PtrString("com.amazonaws.ecs.capability.docker-remote-api.1.28"), + }, + { + Name: adapters.PtrString("com.amazonaws.ecs.capability.docker-remote-api.1.29"), + }, + { + Name: adapters.PtrString("ecs.cpu-architecture"), + Value: adapters.PtrString("x86_64"), + }, + { + Name: adapters.PtrString("com.amazonaws.ecs.capability.ecr-auth"), + }, + { + Name: adapters.PtrString("ecs.capability.firelens.fluentbit"), + }, + { + Name: adapters.PtrString("com.amazonaws.ecs.capability.docker-remote-api.1.20"), + }, + { + Name: adapters.PtrString("ecs.os-type"), + Value: adapters.PtrString("linux"), + }, + { + Name: adapters.PtrString("com.amazonaws.ecs.capability.docker-remote-api.1.21"), + }, + { + Name: adapters.PtrString("com.amazonaws.ecs.capability.docker-remote-api.1.22"), + }, + { + Name: adapters.PtrString("com.amazonaws.ecs.capability.docker-remote-api.1.23"), + }, + { + Name: adapters.PtrString("ecs.capability.task-eia"), + }, + { + Name: adapters.PtrString("ecs.capability.private-registry-authentication.secretsmanager"), + }, + { + Name: adapters.PtrString("com.amazonaws.ecs.capability.logging-driver.syslog"), + }, + { + Name: adapters.PtrString("com.amazonaws.ecs.capability.logging-driver.awsfirelens"), + }, + { + Name: adapters.PtrString("ecs.capability.firelens.options.config.s3"), + }, + { + Name: adapters.PtrString("com.amazonaws.ecs.capability.logging-driver.json-file"), + }, + { + Name: adapters.PtrString("ecs.capability.execution-role-awslogs"), + }, + { + Name: adapters.PtrString("ecs.vpc-id"), + Value: adapters.PtrString("vpc-0e120717a7263de70"), + }, + { + Name: adapters.PtrString("com.amazonaws.ecs.capability.docker-remote-api.1.17"), + }, + { + Name: adapters.PtrString("com.amazonaws.ecs.capability.docker-remote-api.1.18"), + }, + { + Name: adapters.PtrString("com.amazonaws.ecs.capability.docker-remote-api.1.19"), + }, + { + Name: adapters.PtrString("ecs.capability.docker-plugin.amazon-ecs-volume-plugin"), + }, + { + Name: adapters.PtrString("ecs.capability.task-eni"), + }, + { + Name: adapters.PtrString("ecs.capability.firelens.fluentd"), + }, + { + Name: adapters.PtrString("ecs.capability.efs"), + }, + { + Name: adapters.PtrString("ecs.capability.execution-role-ecr-pull"), + }, + { + Name: adapters.PtrString("ecs.capability.task-eni.ipv6"), + }, + { + Name: adapters.PtrString("ecs.capability.container-health-check"), + }, + { + Name: adapters.PtrString("ecs.subnet-id"), + Value: adapters.PtrString("subnet-0bfdb717a234c01b3"), + }, + { + Name: adapters.PtrString("ecs.instance-type"), + Value: adapters.PtrString("t2.large"), + }, + { + Name: adapters.PtrString("com.amazonaws.ecs.capability.task-iam-role-network-host"), + }, + { + Name: adapters.PtrString("ecs.capability.container-ordering"), + }, + { + Name: adapters.PtrString("ecs.capability.cni-plugin-version"), + Value: adapters.PtrString("55b2ae77-2020.09.0"), + }, + { + Name: adapters.PtrString("ecs.capability.env-files.s3"), + }, + { + Name: adapters.PtrString("ecs.capability.pid-ipc-namespace-sharing"), + }, + { + Name: adapters.PtrString("ecs.capability.secrets.ssm.environment-variables"), + }, + { + Name: adapters.PtrString("com.amazonaws.ecs.capability.task-iam-role"), + }, + }, + RegisteredAt: adapters.PtrTime(time.Now()), + Attachments: []types.Attachment{}, // There is probably an opportunity for some links here but I don't have example data + Tags: []types.Tag{}, + AgentUpdateStatus: types.AgentUpdateStatusFailed, + CapacityProviderName: adapters.PtrString("name"), + HealthStatus: &types.ContainerInstanceHealthStatus{ + OverallStatus: types.InstanceHealthCheckStateImpaired, + }, + }, + }, + }, nil +} + +func (t *TestClient) ListContainerInstances(context.Context, *ecs.ListContainerInstancesInput, ...func(*ecs.Options)) (*ecs.ListContainerInstancesOutput, error) { + return &ecs.ListContainerInstancesOutput{ + ContainerInstanceArns: []string{ + "arn:aws:ecs:eu-west-1:052392120703:container-instance/ecs-template-ECSCluster-8nS0WOLbs3nZ/50e9bf71ed57450ca56293cc5a042886", + }, + }, nil +} + +func TestContainerInstanceGetFunc(t *testing.T) { + item, err := containerInstanceGetFunc(context.Background(), &TestClient{}, "foo", &ecs.DescribeContainerInstancesInput{}) + + if err != nil { + t.Error(err) + } + + if err = item.Validate(); err != nil { + t.Error(err) + } + + tests := adapters.QueryTests{ + { + ExpectedType: "ec2-instance", + ExpectedMethod: sdp.QueryMethod_GET, + ExpectedQuery: "i-0e778f25705bc0c84", + ExpectedScope: "foo", + }, + } + + tests.Execute(t, item) +} + +func TestNewContainerInstanceAdapter(t *testing.T) { + client, account, region := GetAutoConfig(t) + + adapter := NewContainerInstanceAdapter(client, account, region) + + test := adapters.E2ETest{ + Adapter: adapter, + Timeout: 10 * time.Second, + SkipNotFoundCheck: true, + } + + test.Run(t) +} diff --git a/sources/ecs/service.go b/adapters/ecs/service.go similarity index 80% rename from sources/ecs/service.go rename to adapters/ecs/service.go index 85202dc2..8105861b 100644 --- a/sources/ecs/service.go +++ b/adapters/ecs/service.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ecs" "github.com/aws/aws-sdk-go-v2/service/ecs/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -48,14 +48,14 @@ func serviceGetFunc(ctx context.Context, client ECSClient, scope string, input * service.TaskSets = []types.TaskSet{} - attributes, err := sources.ToAttributesWithExclude(service, "tags") + attributes, err := adapters.ToAttributesWithExclude(service, "tags") if err != nil { return nil, err } if service.ServiceArn != nil { - if a, err := sources.ParseARN(*service.ServiceArn); err == nil { + if a, err := adapters.ParseARN(*service.ServiceArn); err == nil { attributes.Set("ServiceFullName", a.Resource) } } @@ -79,17 +79,17 @@ func serviceGetFunc(ctx context.Context, client ECSClient, scope string, input * } } - var a *sources.ARN + var a *adapters.ARN if service.ClusterArn != nil { - if a, err = sources.ParseARN(*service.ClusterArn); err == nil { + if a, err = adapters.ParseARN(*service.ClusterArn); err == nil { // +overmind:link ecs-cluster item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "ecs-cluster", Method: sdp.QueryMethod_SEARCH, Query: *service.ClusterArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changes to the cluster will affect the service @@ -103,14 +103,14 @@ func serviceGetFunc(ctx context.Context, client ECSClient, scope string, input * for _, lb := range service.LoadBalancers { if lb.TargetGroupArn != nil { - if a, err = sources.ParseARN(*lb.TargetGroupArn); err == nil { + if a, err = adapters.ParseARN(*lb.TargetGroupArn); err == nil { // +overmind:link elbv2-target-group item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "elbv2-target-group", Method: sdp.QueryMethod_SEARCH, Query: *lb.TargetGroupArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // These are tightly linked @@ -124,14 +124,14 @@ func serviceGetFunc(ctx context.Context, client ECSClient, scope string, input * for _, sr := range service.ServiceRegistries { if sr.RegistryArn != nil { - if a, err = sources.ParseARN(*sr.RegistryArn); err == nil { + if a, err = adapters.ParseARN(*sr.RegistryArn); err == nil { // +overmind:link servicediscovery-service item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "servicediscovery-service", Method: sdp.QueryMethod_SEARCH, Query: *sr.RegistryArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // These are tightly linked @@ -144,14 +144,14 @@ func serviceGetFunc(ctx context.Context, client ECSClient, scope string, input * } if service.TaskDefinition != nil { - if a, err = sources.ParseARN(*service.TaskDefinition); err == nil { + if a, err = adapters.ParseARN(*service.TaskDefinition); err == nil { // +overmind:link ecs-task-definition item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "ecs-task-definition", Method: sdp.QueryMethod_SEARCH, Query: *service.TaskDefinition, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changing the task definition will affect the service @@ -165,14 +165,14 @@ func serviceGetFunc(ctx context.Context, client ECSClient, scope string, input * for _, deployment := range service.Deployments { if deployment.TaskDefinition != nil { - if a, err = sources.ParseARN(*deployment.TaskDefinition); err == nil { + if a, err = adapters.ParseARN(*deployment.TaskDefinition); err == nil { // +overmind:link ecs-task-definition item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "ecs-task-definition", Method: sdp.QueryMethod_SEARCH, Query: *deployment.TaskDefinition, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changing the task definition will affect the service @@ -269,14 +269,14 @@ func serviceGetFunc(ctx context.Context, client ECSClient, scope string, input * for _, cr := range deployment.ServiceConnectResources { if cr.DiscoveryArn != nil { - if a, err = sources.ParseARN(*cr.DiscoveryArn); err == nil { + if a, err = adapters.ParseARN(*cr.DiscoveryArn); err == nil { // +overmind:link servicediscovery-service item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "servicediscovery-service", Method: sdp.QueryMethod_SEARCH, Query: *cr.DiscoveryArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // These are tightly linked @@ -352,11 +352,11 @@ func serviceGetFunc(ctx context.Context, client ECSClient, scope string, input * func serviceListFuncOutputMapper(output *ecs.ListServicesOutput, input *ecs.ListServicesInput) ([]*ecs.DescribeServicesInput, error) { inputs := make([]*ecs.DescribeServicesInput, 0) - var a *sources.ARN + var a *adapters.ARN var err error for _, arn := range output.ServiceArns { - a, err = sources.ParseARN(arn) + a, err = adapters.ParseARN(arn) if err != nil { continue @@ -390,14 +390,15 @@ func serviceListFuncOutputMapper(output *ecs.ListServicesOutput, input *ecs.List // +overmind:terraform:queryMap aws_ecs_service.cluster_name // +overmind:terraform:method SEARCH -func NewServiceSource(client ECSClient, accountID string, region string) *sources.AlwaysGetSource[*ecs.ListServicesInput, *ecs.ListServicesOutput, *ecs.DescribeServicesInput, *ecs.DescribeServicesOutput, ECSClient, *ecs.Options] { - return &sources.AlwaysGetSource[*ecs.ListServicesInput, *ecs.ListServicesOutput, *ecs.DescribeServicesInput, *ecs.DescribeServicesOutput, ECSClient, *ecs.Options]{ - ItemType: "ecs-service", - Client: client, - AccountID: accountID, - Region: region, - GetFunc: serviceGetFunc, - DisableList: true, +func NewServiceAdapter(client ECSClient, accountID string, region string) *adapters.AlwaysGetAdapter[*ecs.ListServicesInput, *ecs.ListServicesOutput, *ecs.DescribeServicesInput, *ecs.DescribeServicesOutput, ECSClient, *ecs.Options] { + return &adapters.AlwaysGetAdapter[*ecs.ListServicesInput, *ecs.ListServicesOutput, *ecs.DescribeServicesInput, *ecs.DescribeServicesOutput, ECSClient, *ecs.Options]{ + ItemType: "ecs-service", + Client: client, + AccountID: accountID, + Region: region, + GetFunc: serviceGetFunc, + DisableList: true, + AdapterMetadata: ServiceMetadata(), GetInputMapper: func(scope, query string) *ecs.DescribeServicesInput { // We are using a custom id of {clusterName}/{id} e.g. // ecs-template-ECSCluster-8nS0WOLbs3nZ/ecs-template-service-i0mQKzkhDI2C @@ -416,15 +417,38 @@ func NewServiceSource(client ECSClient, accountID string, region string) *source } }, ListInput: &ecs.ListServicesInput{}, - ListFuncPaginatorBuilder: func(client ECSClient, input *ecs.ListServicesInput) sources.Paginator[*ecs.ListServicesOutput, *ecs.Options] { + ListFuncPaginatorBuilder: func(client ECSClient, input *ecs.ListServicesInput) adapters.Paginator[*ecs.ListServicesOutput, *ecs.Options] { return ecs.NewListServicesPaginator(client, input) }, SearchInputMapper: func(scope, query string) (*ecs.ListServicesInput, error) { // Custom search by cluster return &ecs.ListServicesInput{ - Cluster: sources.PtrString(query), + Cluster: adapters.PtrString(query), }, nil }, ListFuncOutputMapper: serviceListFuncOutputMapper, } } + +func ServiceMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "ecs-service", + DescriptiveName: "ECS Service", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get an ECS service by full name ({clusterName}/{id})", + ListDescription: "List all ECS services", + SearchDescription: "Search for ECS services by cluster", + }, + TerraformMappings: []*sdp.TerraformMapping{ + { + TerraformMethod: sdp.QueryMethod_SEARCH, + TerraformQueryMap: "aws_ecs_service.cluster_name", + }, + }, + PotentialLinks: []string{"ecs-cluster", "elbv2-target-group", "servicediscovery-service", "ecs-task-definition", "ecs-capacity-provider", "ec2-subnet", "ecs-security-group", "dns"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_COMPUTE_APPLICATION, + } +} diff --git a/sources/ecs/service_test.go b/adapters/ecs/service_test.go similarity index 59% rename from sources/ecs/service_test.go rename to adapters/ecs/service_test.go index b1d404d7..d0e4074e 100644 --- a/sources/ecs/service_test.go +++ b/adapters/ecs/service_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ecs" "github.com/aws/aws-sdk-go-v2/service/ecs/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -16,37 +16,37 @@ func (t *TestClient) DescribeServices(ctx context.Context, params *ecs.DescribeS Failures: []types.Failure{}, Services: []types.Service{ { - ServiceArn: sources.PtrString("arn:aws:ecs:eu-west-1:052392120703:service/ecs-template-ECSCluster-8nS0WOLbs3nZ/ecs-template-service-i0mQKzkhDI2C"), - ServiceName: sources.PtrString("ecs-template-service-i0mQKzkhDI2C"), - ClusterArn: sources.PtrString("arn:aws:ecs:eu-west-1:052392120703:cluster/ecs-template-ECSCluster-8nS0WOLbs3nZ"), // link + ServiceArn: adapters.PtrString("arn:aws:ecs:eu-west-1:052392120703:service/ecs-template-ECSCluster-8nS0WOLbs3nZ/ecs-template-service-i0mQKzkhDI2C"), + ServiceName: adapters.PtrString("ecs-template-service-i0mQKzkhDI2C"), + ClusterArn: adapters.PtrString("arn:aws:ecs:eu-west-1:052392120703:cluster/ecs-template-ECSCluster-8nS0WOLbs3nZ"), // link LoadBalancers: []types.LoadBalancer{ { - TargetGroupArn: sources.PtrString("arn:aws:elasticloadbalancing:eu-west-1:052392120703:targetgroup/ECSTG/0c44b1cdb3437902"), // link - ContainerName: sources.PtrString("simple-app"), - ContainerPort: sources.PtrInt32(80), + TargetGroupArn: adapters.PtrString("arn:aws:elasticloadbalancing:eu-west-1:052392120703:targetgroup/ECSTG/0c44b1cdb3437902"), // link + ContainerName: adapters.PtrString("simple-app"), + ContainerPort: adapters.PtrInt32(80), }, }, ServiceRegistries: []types.ServiceRegistry{ { - ContainerName: sources.PtrString("name"), - ContainerPort: sources.PtrInt32(80), - Port: sources.PtrInt32(80), - RegistryArn: sources.PtrString("arn:aws:service:region:account:type:name"), // link + ContainerName: adapters.PtrString("name"), + ContainerPort: adapters.PtrInt32(80), + Port: adapters.PtrInt32(80), + RegistryArn: adapters.PtrString("arn:aws:service:region:account:type:name"), // link }, }, - Status: sources.PtrString("ACTIVE"), + Status: adapters.PtrString("ACTIVE"), DesiredCount: 1, RunningCount: 1, PendingCount: 0, LaunchType: types.LaunchTypeEc2, - TaskDefinition: sources.PtrString("arn:aws:ecs:eu-west-1:052392120703:task-definition/ecs-template-ecs-demo-app:1"), // link + TaskDefinition: adapters.PtrString("arn:aws:ecs:eu-west-1:052392120703:task-definition/ecs-template-ecs-demo-app:1"), // link DeploymentConfiguration: &types.DeploymentConfiguration{ DeploymentCircuitBreaker: &types.DeploymentCircuitBreaker{ Enable: false, Rollback: false, }, - MaximumPercent: sources.PtrInt32(200), - MinimumHealthyPercent: sources.PtrInt32(100), + MaximumPercent: adapters.PtrInt32(200), + MinimumHealthyPercent: adapters.PtrInt32(100), Alarms: &types.DeploymentAlarms{ AlarmNames: []string{ "foo", @@ -57,21 +57,21 @@ func (t *TestClient) DescribeServices(ctx context.Context, params *ecs.DescribeS }, Deployments: []types.Deployment{ { - Id: sources.PtrString("ecs-svc/6893472562508357546"), - Status: sources.PtrString("PRIMARY"), - TaskDefinition: sources.PtrString("arn:aws:ecs:eu-west-1:052392120703:task-definition/ecs-template-ecs-demo-app:1"), // link + Id: adapters.PtrString("ecs-svc/6893472562508357546"), + Status: adapters.PtrString("PRIMARY"), + TaskDefinition: adapters.PtrString("arn:aws:ecs:eu-west-1:052392120703:task-definition/ecs-template-ecs-demo-app:1"), // link DesiredCount: 1, PendingCount: 0, RunningCount: 1, FailedTasks: 0, - CreatedAt: sources.PtrTime(time.Now()), - UpdatedAt: sources.PtrTime(time.Now()), + CreatedAt: adapters.PtrTime(time.Now()), + UpdatedAt: adapters.PtrTime(time.Now()), LaunchType: types.LaunchTypeEc2, RolloutState: types.DeploymentRolloutStateCompleted, - RolloutStateReason: sources.PtrString("ECS deployment ecs-svc/6893472562508357546 completed."), + RolloutStateReason: adapters.PtrString("ECS deployment ecs-svc/6893472562508357546 completed."), CapacityProviderStrategy: []types.CapacityProviderStrategyItem{ { - CapacityProvider: sources.PtrString("provider"), // link + CapacityProvider: adapters.PtrString("provider"), // link Base: 10, Weight: 10, }, @@ -87,8 +87,8 @@ func (t *TestClient) DescribeServices(ctx context.Context, params *ecs.DescribeS }, }, }, - PlatformFamily: sources.PtrString("foo"), - PlatformVersion: sources.PtrString("LATEST"), + PlatformFamily: adapters.PtrString("foo"), + PlatformVersion: adapters.PtrString("LATEST"), ServiceConnectConfiguration: &types.ServiceConnectConfiguration{ Enabled: true, LogConfiguration: &types.LogConfiguration{ @@ -96,19 +96,19 @@ func (t *TestClient) DescribeServices(ctx context.Context, params *ecs.DescribeS Options: map[string]string{}, SecretOptions: []types.Secret{ { - Name: sources.PtrString("something"), - ValueFrom: sources.PtrString("somewhere"), + Name: adapters.PtrString("something"), + ValueFrom: adapters.PtrString("somewhere"), }, }, }, - Namespace: sources.PtrString("namespace"), + Namespace: adapters.PtrString("namespace"), Services: []types.ServiceConnectService{ { - PortName: sources.PtrString("http"), + PortName: adapters.PtrString("http"), ClientAliases: []types.ServiceConnectClientAlias{ { - Port: sources.PtrInt32(80), - DnsName: sources.PtrString("www.foo.com"), // link + Port: adapters.PtrInt32(80), + DnsName: adapters.PtrString("www.foo.com"), // link }, }, }, @@ -116,65 +116,65 @@ func (t *TestClient) DescribeServices(ctx context.Context, params *ecs.DescribeS }, ServiceConnectResources: []types.ServiceConnectServiceResource{ { - DiscoveryArn: sources.PtrString("arn:aws:service:region:account:layer:name:version"), // link - DiscoveryName: sources.PtrString("name"), + DiscoveryArn: adapters.PtrString("arn:aws:service:region:account:layer:name:version"), // link + DiscoveryName: adapters.PtrString("name"), }, }, }, }, - RoleArn: sources.PtrString("arn:aws:iam::052392120703:role/ecs-template-ECSServiceRole-1IL5CNMR1600J"), + RoleArn: adapters.PtrString("arn:aws:iam::052392120703:role/ecs-template-ECSServiceRole-1IL5CNMR1600J"), Events: []types.ServiceEvent{ { - Id: sources.PtrString("a727ef2a-8a38-4746-905e-b529c952edee"), - CreatedAt: sources.PtrTime(time.Now()), - Message: sources.PtrString("(service ecs-template-service-i0mQKzkhDI2C) has reached a steady state."), + Id: adapters.PtrString("a727ef2a-8a38-4746-905e-b529c952edee"), + CreatedAt: adapters.PtrTime(time.Now()), + Message: adapters.PtrString("(service ecs-template-service-i0mQKzkhDI2C) has reached a steady state."), }, { - Id: sources.PtrString("69489991-f8ee-42a2-94f2-db8ffeda1ee7"), - CreatedAt: sources.PtrTime(time.Now()), - Message: sources.PtrString("(service ecs-template-service-i0mQKzkhDI2C) (deployment ecs-svc/6893472562508357546) deployment completed."), + Id: adapters.PtrString("69489991-f8ee-42a2-94f2-db8ffeda1ee7"), + CreatedAt: adapters.PtrTime(time.Now()), + Message: adapters.PtrString("(service ecs-template-service-i0mQKzkhDI2C) (deployment ecs-svc/6893472562508357546) deployment completed."), }, { - Id: sources.PtrString("9ce65c4b-2993-477d-aa83-dbe98988f90b"), - CreatedAt: sources.PtrTime(time.Now()), - Message: sources.PtrString("(service ecs-template-service-i0mQKzkhDI2C) registered 1 targets in (target-group arn:aws:elasticloadbalancing:eu-west-1:052392120703:targetgroup/ECSTG/0c44b1cdb3437902)"), + Id: adapters.PtrString("9ce65c4b-2993-477d-aa83-dbe98988f90b"), + CreatedAt: adapters.PtrTime(time.Now()), + Message: adapters.PtrString("(service ecs-template-service-i0mQKzkhDI2C) registered 1 targets in (target-group arn:aws:elasticloadbalancing:eu-west-1:052392120703:targetgroup/ECSTG/0c44b1cdb3437902)"), }, { - Id: sources.PtrString("753e988a-9fb9-4907-b801-5f67369bc0de"), - CreatedAt: sources.PtrTime(time.Now()), - Message: sources.PtrString("(service ecs-template-service-i0mQKzkhDI2C) has started 1 tasks: (task 53074e0156204f30a3cea97e7bf32d31)."), + Id: adapters.PtrString("753e988a-9fb9-4907-b801-5f67369bc0de"), + CreatedAt: adapters.PtrTime(time.Now()), + Message: adapters.PtrString("(service ecs-template-service-i0mQKzkhDI2C) has started 1 tasks: (task 53074e0156204f30a3cea97e7bf32d31)."), }, { - Id: sources.PtrString("deb2400b-a776-4ebe-8c97-f94feef2b780"), - CreatedAt: sources.PtrTime(time.Now()), - Message: sources.PtrString("(service ecs-template-service-i0mQKzkhDI2C) was unable to place a task because no container instance met all of its requirements. Reason: No Container Instances were found in your cluster. For more information, see the Troubleshooting section of the Amazon ECS Developer Guide."), + Id: adapters.PtrString("deb2400b-a776-4ebe-8c97-f94feef2b780"), + CreatedAt: adapters.PtrTime(time.Now()), + Message: adapters.PtrString("(service ecs-template-service-i0mQKzkhDI2C) was unable to place a task because no container instance met all of its requirements. Reason: No Container Instances were found in your cluster. For more information, see the Troubleshooting section of the Amazon ECS Developer Guide."), }, }, - CreatedAt: sources.PtrTime(time.Now()), + CreatedAt: adapters.PtrTime(time.Now()), PlacementConstraints: []types.PlacementConstraint{ { - Expression: sources.PtrString("expression"), + Expression: adapters.PtrString("expression"), Type: types.PlacementConstraintTypeDistinctInstance, }, }, PlacementStrategy: []types.PlacementStrategy{ { - Field: sources.PtrString("field"), + Field: adapters.PtrString("field"), Type: types.PlacementStrategyTypeSpread, }, }, - HealthCheckGracePeriodSeconds: sources.PtrInt32(0), + HealthCheckGracePeriodSeconds: adapters.PtrInt32(0), SchedulingStrategy: types.SchedulingStrategyReplica, DeploymentController: &types.DeploymentController{ Type: types.DeploymentControllerTypeEcs, }, - CreatedBy: sources.PtrString("arn:aws:iam::052392120703:role/aws-reserved/sso.amazonaws.com/eu-west-2/AWSReservedSSO_AWSAdministratorAccess_c1c3c9c54821c68a"), + CreatedBy: adapters.PtrString("arn:aws:iam::052392120703:role/aws-reserved/sso.amazonaws.com/eu-west-2/AWSReservedSSO_AWSAdministratorAccess_c1c3c9c54821c68a"), EnableECSManagedTags: false, PropagateTags: types.PropagateTagsNone, EnableExecuteCommand: false, CapacityProviderStrategy: []types.CapacityProviderStrategyItem{ { - CapacityProvider: sources.PtrString("provider"), + CapacityProvider: adapters.PtrString("provider"), Base: 10, Weight: 10, }, @@ -190,15 +190,15 @@ func (t *TestClient) DescribeServices(ctx context.Context, params *ecs.DescribeS }, }, }, - PlatformFamily: sources.PtrString("family"), - PlatformVersion: sources.PtrString("LATEST"), + PlatformFamily: adapters.PtrString("family"), + PlatformVersion: adapters.PtrString("LATEST"), Tags: []types.Tag{}, TaskSets: []types.TaskSet{ // This seems to be able to return the *entire* task set, // which is redundant info. We should remove everything // other than the IDs { - Id: sources.PtrString("id"), // link, then remove + Id: adapters.PtrString("id"), // link, then remove }, }, }, @@ -225,7 +225,7 @@ func TestServiceGetFunc(t *testing.T) { t.Error(err) } - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "ecs-cluster", ExpectedMethod: sdp.QueryMethod_SEARCH, @@ -309,13 +309,13 @@ func TestServiceGetFunc(t *testing.T) { tests.Execute(t, item) } -func TestNewServiceSource(t *testing.T) { +func TestNewServiceAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewServiceSource(client, account, region) + adapter := NewServiceAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, SkipNotFoundCheck: true, } diff --git a/sources/ecs/shared.go b/adapters/ecs/shared.go similarity index 100% rename from sources/ecs/shared.go rename to adapters/ecs/shared.go diff --git a/sources/ecs/shared_test.go b/adapters/ecs/shared_test.go similarity index 70% rename from sources/ecs/shared_test.go rename to adapters/ecs/shared_test.go index 31bd61b6..1ad8eaac 100644 --- a/sources/ecs/shared_test.go +++ b/adapters/ecs/shared_test.go @@ -4,13 +4,13 @@ import ( "testing" "github.com/aws/aws-sdk-go-v2/service/ecs" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" ) type TestClient struct{} func GetAutoConfig(t *testing.T) (*ecs.Client, string, string) { - config, account, region := sources.GetAutoConfig(t) + config, account, region := adapters.GetAutoConfig(t) client := ecs.NewFromConfig(config) return client, account, region diff --git a/sources/ecs/task.go b/adapters/ecs/task.go similarity index 74% rename from sources/ecs/task.go rename to adapters/ecs/task.go index f463a068..9de5c8ee 100644 --- a/sources/ecs/task.go +++ b/adapters/ecs/task.go @@ -8,7 +8,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ecs" "github.com/aws/aws-sdk-go-v2/service/ecs/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -30,7 +30,7 @@ func taskGetFunc(ctx context.Context, client ECSClient, scope string, input *ecs task := out.Tasks[0] - attributes, err := sources.ToAttributesWithExclude(task, "tags") + attributes, err := adapters.ToAttributesWithExclude(task, "tags") if err != nil { return nil, err @@ -40,7 +40,7 @@ func taskGetFunc(ctx context.Context, client ECSClient, scope string, input *ecs return nil, errors.New("task has nil ARN") } - a, err := sources.ParseARN(*task.TaskArn) + a, err := adapters.ParseARN(*task.TaskArn) if err != nil { return nil, err @@ -91,14 +91,14 @@ func taskGetFunc(ctx context.Context, client ECSClient, scope string, input *ecs } if task.ClusterArn != nil { - if a, err = sources.ParseARN(*task.ClusterArn); err == nil { + if a, err = adapters.ParseARN(*task.ClusterArn); err == nil { // +overmind:link ecs-cluster item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "ecs-cluster", Method: sdp.QueryMethod_SEARCH, Query: *task.ClusterArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // The cluster can affect the task @@ -111,7 +111,7 @@ func taskGetFunc(ctx context.Context, client ECSClient, scope string, input *ecs } if task.ContainerInstanceArn != nil { - if a, err = sources.ParseARN(*task.ContainerInstanceArn); err == nil { + if a, err = adapters.ParseARN(*task.ContainerInstanceArn); err == nil { // +overmind:link ecs-container-instance item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ @@ -169,14 +169,14 @@ func taskGetFunc(ctx context.Context, client ECSClient, scope string, input *ecs } if task.TaskDefinitionArn != nil { - if a, err = sources.ParseARN(*task.TaskDefinitionArn); err == nil { + if a, err = adapters.ParseARN(*task.TaskDefinitionArn); err == nil { // +overmind:link ecs-task-definition item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "ecs-task-definition", Method: sdp.QueryMethod_SEARCH, Query: *task.TaskDefinitionArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // The task definition can affect the task @@ -203,7 +203,7 @@ func taskGetInputMapper(scope, query string) *ecs.DescribeTasksInput { Tasks: []string{ sections[1], }, - Cluster: sources.PtrString(sections[0]), + Cluster: adapters.PtrString(sections[0]), Include: TaskIncludeFields, } } @@ -212,7 +212,7 @@ func tasksListFuncOutputMapper(output *ecs.ListTasksOutput, input *ecs.ListTasks inputs := make([]*ecs.DescribeTasksInput, 0) for _, taskArn := range output.TaskArns { - if a, err := sources.ParseARN(taskArn); err == nil { + if a, err := adapters.ParseARN(taskArn); err == nil { // split the cluster name out sections := strings.Split(a.ResourceID(), "/") @@ -241,25 +241,43 @@ func tasksListFuncOutputMapper(output *ecs.ListTasksOutput, input *ecs.ListTasks // +overmind:search Search for ECS tasks by cluster // +overmind:group AWS -func NewTaskSource(client ECSClient, accountID string, region string) *sources.AlwaysGetSource[*ecs.ListTasksInput, *ecs.ListTasksOutput, *ecs.DescribeTasksInput, *ecs.DescribeTasksOutput, ECSClient, *ecs.Options] { - return &sources.AlwaysGetSource[*ecs.ListTasksInput, *ecs.ListTasksOutput, *ecs.DescribeTasksInput, *ecs.DescribeTasksOutput, ECSClient, *ecs.Options]{ - ItemType: "ecs-task", - Client: client, - AccountID: accountID, - Region: region, - GetFunc: taskGetFunc, - ListInput: &ecs.ListTasksInput{}, - GetInputMapper: taskGetInputMapper, - DisableList: true, +func NewTaskAdapter(client ECSClient, accountID string, region string) *adapters.AlwaysGetAdapter[*ecs.ListTasksInput, *ecs.ListTasksOutput, *ecs.DescribeTasksInput, *ecs.DescribeTasksOutput, ECSClient, *ecs.Options] { + return &adapters.AlwaysGetAdapter[*ecs.ListTasksInput, *ecs.ListTasksOutput, *ecs.DescribeTasksInput, *ecs.DescribeTasksOutput, ECSClient, *ecs.Options]{ + ItemType: "ecs-task", + Client: client, + AccountID: accountID, + Region: region, + GetFunc: taskGetFunc, + AdapterMetadata: TaskMetadata(), + ListInput: &ecs.ListTasksInput{}, + GetInputMapper: taskGetInputMapper, + DisableList: true, SearchInputMapper: func(scope, query string) (*ecs.ListTasksInput, error) { // Search by cluster return &ecs.ListTasksInput{ - Cluster: sources.PtrString(query), + Cluster: adapters.PtrString(query), }, nil }, - ListFuncPaginatorBuilder: func(client ECSClient, input *ecs.ListTasksInput) sources.Paginator[*ecs.ListTasksOutput, *ecs.Options] { + ListFuncPaginatorBuilder: func(client ECSClient, input *ecs.ListTasksInput) adapters.Paginator[*ecs.ListTasksOutput, *ecs.Options] { return ecs.NewListTasksPaginator(client, input) }, ListFuncOutputMapper: tasksListFuncOutputMapper, } } + +func TaskMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "ecs-task", + DescriptiveName: "ECS Task", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get an ECS task by ID", + ListDescription: "List all ECS tasks", + SearchDescription: "Search for ECS tasks by cluster", + }, + PotentialLinks: []string{"ecs-cluster", "ecs-container-instance", "ecs-task-definition", "ec2-network-interface", "ip"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_COMPUTE_APPLICATION, + } +} diff --git a/sources/ecs/task_definition.go b/adapters/ecs/task_definition.go similarity index 70% rename from sources/ecs/task_definition.go rename to adapters/ecs/task_definition.go index 5a2d454c..701c3999 100644 --- a/sources/ecs/task_definition.go +++ b/adapters/ecs/task_definition.go @@ -6,7 +6,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ecs" "github.com/aws/aws-sdk-go-v2/service/ecs/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -28,7 +28,7 @@ func taskDefinitionGetFunc(ctx context.Context, client ECSClient, scope string, td := out.TaskDefinition - attributes, err := sources.ToAttributesWithExclude(td) + attributes, err := adapters.ToAttributesWithExclude(td) if err != nil { return nil, err @@ -57,7 +57,7 @@ func taskDefinitionGetFunc(ctx context.Context, client ECSClient, scope string, item.Health = sdp.Health_HEALTH_WARNING.Enum() } - var a *sources.ARN + var a *adapters.ARN var link *sdp.LinkedItemQuery for _, cd := range td.ContainerDefinitions { @@ -86,14 +86,14 @@ func taskDefinitionGetFunc(ctx context.Context, client ECSClient, scope string, } if td.ExecutionRoleArn != nil { - if a, err = sources.ParseARN(*td.ExecutionRoleArn); err == nil { + if a, err = adapters.ParseARN(*td.ExecutionRoleArn); err == nil { // +overmind:link iam-role item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "iam-role", Method: sdp.QueryMethod_SEARCH, Query: *td.ExecutionRoleArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // The role can affect the task definition @@ -106,14 +106,14 @@ func taskDefinitionGetFunc(ctx context.Context, client ECSClient, scope string, } if td.TaskRoleArn != nil { - if a, err = sources.ParseARN(*td.TaskRoleArn); err == nil { + if a, err = adapters.ParseARN(*td.TaskRoleArn); err == nil { // +overmind:link iam-role item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "iam-role", Method: sdp.QueryMethod_SEARCH, Query: *td.TaskRoleArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // The role can affect the task definition @@ -132,10 +132,10 @@ func taskDefinitionGetFunc(ctx context.Context, client ECSClient, scope string, // secret is related to, if relevant func getSecretLinkedItem(secret types.Secret) *sdp.LinkedItemQuery { if secret.ValueFrom != nil { - if a, err := sources.ParseARN(*secret.ValueFrom); err == nil { + if a, err := adapters.ParseARN(*secret.ValueFrom); err == nil { // The secret can refer to either something from secrets // manager or SSN, so handle this - secretScope := sources.FormatScope(a.AccountID, a.Region) + secretScope := adapters.FormatScope(a.AccountID, a.Region) switch a.Service { case "secretsmanager": @@ -186,31 +186,32 @@ func getSecretLinkedItem(secret types.Secret) *sdp.LinkedItemQuery { // +overmind:group AWS // +overmind:terraform:queryMap aws_ecs_task_definition.family -func NewTaskDefinitionSource(client ECSClient, accountID string, region string) *sources.AlwaysGetSource[*ecs.ListTaskDefinitionsInput, *ecs.ListTaskDefinitionsOutput, *ecs.DescribeTaskDefinitionInput, *ecs.DescribeTaskDefinitionOutput, ECSClient, *ecs.Options] { - return &sources.AlwaysGetSource[*ecs.ListTaskDefinitionsInput, *ecs.ListTaskDefinitionsOutput, *ecs.DescribeTaskDefinitionInput, *ecs.DescribeTaskDefinitionOutput, ECSClient, *ecs.Options]{ - ItemType: "ecs-task-definition", - Client: client, - AccountID: accountID, - Region: region, - GetFunc: taskDefinitionGetFunc, - ListInput: &ecs.ListTaskDefinitionsInput{}, +func NewTaskDefinitionAdapter(client ECSClient, accountID string, region string) *adapters.AlwaysGetAdapter[*ecs.ListTaskDefinitionsInput, *ecs.ListTaskDefinitionsOutput, *ecs.DescribeTaskDefinitionInput, *ecs.DescribeTaskDefinitionOutput, ECSClient, *ecs.Options] { + return &adapters.AlwaysGetAdapter[*ecs.ListTaskDefinitionsInput, *ecs.ListTaskDefinitionsOutput, *ecs.DescribeTaskDefinitionInput, *ecs.DescribeTaskDefinitionOutput, ECSClient, *ecs.Options]{ + ItemType: "ecs-task-definition", + Client: client, + AccountID: accountID, + Region: region, + GetFunc: taskDefinitionGetFunc, + ListInput: &ecs.ListTaskDefinitionsInput{}, + AdapterMetadata: TaskDefinitionMetadata(), GetInputMapper: func(scope, query string) *ecs.DescribeTaskDefinitionInput { // AWS actually supports "family:revision" format as an input here // so we can just push it in directly return &ecs.DescribeTaskDefinitionInput{ - TaskDefinition: sources.PtrString(query), + TaskDefinition: adapters.PtrString(query), } }, - ListFuncPaginatorBuilder: func(client ECSClient, input *ecs.ListTaskDefinitionsInput) sources.Paginator[*ecs.ListTaskDefinitionsOutput, *ecs.Options] { + ListFuncPaginatorBuilder: func(client ECSClient, input *ecs.ListTaskDefinitionsInput) adapters.Paginator[*ecs.ListTaskDefinitionsOutput, *ecs.Options] { return ecs.NewListTaskDefinitionsPaginator(client, input) }, ListFuncOutputMapper: func(output *ecs.ListTaskDefinitionsOutput, input *ecs.ListTaskDefinitionsInput) ([]*ecs.DescribeTaskDefinitionInput, error) { getInputs := make([](*ecs.DescribeTaskDefinitionInput), 0) for _, arn := range output.TaskDefinitionArns { - if a, err := sources.ParseARN(arn); err == nil { + if a, err := adapters.ParseARN(arn); err == nil { getInputs = append(getInputs, &ecs.DescribeTaskDefinitionInput{ - TaskDefinition: sources.PtrString(a.ResourceID()), + TaskDefinition: adapters.PtrString(a.ResourceID()), }) } } @@ -219,3 +220,23 @@ func NewTaskDefinitionSource(client ECSClient, accountID string, region string) }, } } + +func TaskDefinitionMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "ecs-task-definition", + DescriptiveName: "Task Definition", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a task definition by revision name ({family}:{revision})", + ListDescription: "List all task definitions", + SearchDescription: "Search for task definitions by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_ecs_task_definition.family"}, + }, + PotentialLinks: []string{"iam-role", "secretsmanager-secret", "ssm-parameter"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_COMPUTE_APPLICATION, + } +} diff --git a/sources/ecs/task_definition_test.go b/adapters/ecs/task_definition_test.go similarity index 62% rename from sources/ecs/task_definition_test.go rename to adapters/ecs/task_definition_test.go index 5c2c7cdb..165ba57f 100644 --- a/sources/ecs/task_definition_test.go +++ b/adapters/ecs/task_definition_test.go @@ -7,67 +7,67 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ecs" "github.com/aws/aws-sdk-go-v2/service/ecs/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) func (t *TestClient) DescribeTaskDefinition(ctx context.Context, params *ecs.DescribeTaskDefinitionInput, optFns ...func(*ecs.Options)) (*ecs.DescribeTaskDefinitionOutput, error) { return &ecs.DescribeTaskDefinitionOutput{ TaskDefinition: &types.TaskDefinition{ - TaskDefinitionArn: sources.PtrString("arn:aws:ecs:eu-west-1:052392120703:task-definition/ecs-template-ecs-demo-app:1"), + TaskDefinitionArn: adapters.PtrString("arn:aws:ecs:eu-west-1:052392120703:task-definition/ecs-template-ecs-demo-app:1"), ContainerDefinitions: []types.ContainerDefinition{ { - Name: sources.PtrString("simple-app"), - Image: sources.PtrString("httpd:2.4"), + Name: adapters.PtrString("simple-app"), + Image: adapters.PtrString("httpd:2.4"), Cpu: 10, - Memory: sources.PtrInt32(300), + Memory: adapters.PtrInt32(300), Links: []string{}, PortMappings: []types.PortMapping{ { - ContainerPort: sources.PtrInt32(80), - HostPort: sources.PtrInt32(0), + ContainerPort: adapters.PtrInt32(80), + HostPort: adapters.PtrInt32(0), Protocol: types.TransportProtocolTcp, AppProtocol: types.ApplicationProtocolHttp, }, }, - Essential: sources.PtrBool(true), + Essential: adapters.PtrBool(true), EntryPoint: []string{}, Command: []string{}, Environment: []types.KeyValuePair{ { - Name: sources.PtrString("DATABASE_SERVER"), - Value: sources.PtrString("database01.my-company.com"), + Name: adapters.PtrString("DATABASE_SERVER"), + Value: adapters.PtrString("database01.my-company.com"), }, }, EnvironmentFiles: []types.EnvironmentFile{}, MountPoints: []types.MountPoint{ { - SourceVolume: sources.PtrString("my-vol"), - ContainerPath: sources.PtrString("/usr/local/apache2/htdocs"), - ReadOnly: sources.PtrBool(false), + SourceVolume: adapters.PtrString("my-vol"), + ContainerPath: adapters.PtrString("/usr/local/apache2/htdocs"), + ReadOnly: adapters.PtrBool(false), }, }, VolumesFrom: []types.VolumeFrom{ { - SourceContainer: sources.PtrString("container"), + SourceContainer: adapters.PtrString("container"), }, }, Secrets: []types.Secret{ { - Name: sources.PtrString("secrets-manager"), - ValueFrom: sources.PtrString("arn:aws:secretsmanager:us-west-2:123456789012:secret:my-path/my-secret-name-1a2b3c"), // link + Name: adapters.PtrString("secrets-manager"), + ValueFrom: adapters.PtrString("arn:aws:secretsmanager:us-west-2:123456789012:secret:my-path/my-secret-name-1a2b3c"), // link }, { - Name: sources.PtrString("ssm"), - ValueFrom: sources.PtrString("arn:aws:ssm:us-east-2:123456789012:parameter/prod-123"), // link + Name: adapters.PtrString("ssm"), + ValueFrom: adapters.PtrString("arn:aws:ssm:us-east-2:123456789012:parameter/prod-123"), // link }, }, DnsServers: []string{}, DnsSearchDomains: []string{}, ExtraHosts: []types.HostEntry{ { - Hostname: sources.PtrString("host"), - IpAddress: sources.PtrString("127.0.0.1"), + Hostname: adapters.PtrString("host"), + IpAddress: adapters.PtrString("127.0.0.1"), }, }, DockerSecurityOptions: []string{}, @@ -82,43 +82,43 @@ func (t *TestClient) DescribeTaskDefinition(ctx context.Context, params *ecs.Des }, SecretOptions: []types.Secret{ { - Name: sources.PtrString("secrets-manager"), - ValueFrom: sources.PtrString("arn:aws:secretsmanager:us-west-2:123456789012:secret:my-path/my-secret-name-1a2b3c"), // link + Name: adapters.PtrString("secrets-manager"), + ValueFrom: adapters.PtrString("arn:aws:secretsmanager:us-west-2:123456789012:secret:my-path/my-secret-name-1a2b3c"), // link }, { - Name: sources.PtrString("ssm"), - ValueFrom: sources.PtrString("arn:aws:ssm:us-east-2:123456789012:parameter/prod-123"), // link + Name: adapters.PtrString("ssm"), + ValueFrom: adapters.PtrString("arn:aws:ssm:us-east-2:123456789012:parameter/prod-123"), // link }, }, }, SystemControls: []types.SystemControl{}, DependsOn: []types.ContainerDependency{}, - DisableNetworking: sources.PtrBool(false), + DisableNetworking: adapters.PtrBool(false), FirelensConfiguration: &types.FirelensConfiguration{ Type: types.FirelensConfigurationTypeFluentd, Options: map[string]string{}, }, HealthCheck: &types.HealthCheck{}, - Hostname: sources.PtrString("hostname"), - Interactive: sources.PtrBool(false), + Hostname: adapters.PtrString("hostname"), + Interactive: adapters.PtrBool(false), LinuxParameters: &types.LinuxParameters{}, - MemoryReservation: sources.PtrInt32(100), - Privileged: sources.PtrBool(false), - PseudoTerminal: sources.PtrBool(false), - ReadonlyRootFilesystem: sources.PtrBool(false), + MemoryReservation: adapters.PtrInt32(100), + Privileged: adapters.PtrBool(false), + PseudoTerminal: adapters.PtrBool(false), + ReadonlyRootFilesystem: adapters.PtrBool(false), RepositoryCredentials: &types.RepositoryCredentials{}, // Skipping the link here for now, if you need it, add it in a PR ResourceRequirements: []types.ResourceRequirement{}, - StartTimeout: sources.PtrInt32(1), - StopTimeout: sources.PtrInt32(1), - User: sources.PtrString("foo"), - WorkingDirectory: sources.PtrString("/"), + StartTimeout: adapters.PtrInt32(1), + StopTimeout: adapters.PtrInt32(1), + User: adapters.PtrString("foo"), + WorkingDirectory: adapters.PtrString("/"), }, { - Name: sources.PtrString("busybox"), - Image: sources.PtrString("busybox"), + Name: adapters.PtrString("busybox"), + Image: adapters.PtrString("busybox"), Cpu: 10, - Memory: sources.PtrInt32(200), - Essential: sources.PtrBool(false), + Memory: adapters.PtrInt32(200), + Essential: adapters.PtrBool(false), EntryPoint: []string{ "sh", "-c", @@ -128,7 +128,7 @@ func (t *TestClient) DescribeTaskDefinition(ctx context.Context, params *ecs.Des }, VolumesFrom: []types.VolumeFrom{ { - SourceContainer: sources.PtrString("simple-app"), + SourceContainer: adapters.PtrString("simple-app"), }, }, DockerLabels: map[string]string{}, @@ -142,29 +142,29 @@ func (t *TestClient) DescribeTaskDefinition(ctx context.Context, params *ecs.Des }, }, }, - Family: sources.PtrString("ecs-template-ecs-demo-app"), + Family: adapters.PtrString("ecs-template-ecs-demo-app"), Revision: 1, Volumes: []types.Volume{ { - Name: sources.PtrString("my-vol"), + Name: adapters.PtrString("my-vol"), Host: &types.HostVolumeProperties{ - SourcePath: sources.PtrString("/"), + SourcePath: adapters.PtrString("/"), }, }, }, Status: types.TaskDefinitionStatusActive, RequiresAttributes: []types.Attribute{ { - Name: sources.PtrString("com.amazonaws.ecs.capability.logging-driver.awslogs"), + Name: adapters.PtrString("com.amazonaws.ecs.capability.logging-driver.awslogs"), }, { - Name: sources.PtrString("com.amazonaws.ecs.capability.docker-remote-api.1.19"), + Name: adapters.PtrString("com.amazonaws.ecs.capability.docker-remote-api.1.19"), }, { - Name: sources.PtrString("com.amazonaws.ecs.capability.docker-remote-api.1.17"), + Name: adapters.PtrString("com.amazonaws.ecs.capability.docker-remote-api.1.17"), }, { - Name: sources.PtrString("com.amazonaws.ecs.capability.docker-remote-api.1.18"), + Name: adapters.PtrString("com.amazonaws.ecs.capability.docker-remote-api.1.18"), }, }, PlacementConstraints: []types.TaskDefinitionPlacementConstraint{}, @@ -172,17 +172,17 @@ func (t *TestClient) DescribeTaskDefinition(ctx context.Context, params *ecs.Des "EXTERNAL", "EC2", }, - RegisteredAt: sources.PtrTime(time.Now()), - RegisteredBy: sources.PtrString("arn:aws:sts::052392120703:assumed-role/AWSReservedSSO_AWSAdministratorAccess_c1c3c9c54821c68a/dylan@overmind.tech"), - Cpu: sources.PtrString("cpu"), - DeregisteredAt: sources.PtrTime(time.Now()), + RegisteredAt: adapters.PtrTime(time.Now()), + RegisteredBy: adapters.PtrString("arn:aws:sts::052392120703:assumed-role/AWSReservedSSO_AWSAdministratorAccess_c1c3c9c54821c68a/dylan@overmind.tech"), + Cpu: adapters.PtrString("cpu"), + DeregisteredAt: adapters.PtrTime(time.Now()), EphemeralStorage: &types.EphemeralStorage{ SizeInGiB: 1, }, - ExecutionRoleArn: sources.PtrString("arn:aws:iam:us-east-2:123456789012:role/foo"), // link + ExecutionRoleArn: adapters.PtrString("arn:aws:iam:us-east-2:123456789012:role/foo"), // link InferenceAccelerators: []types.InferenceAccelerator{}, IpcMode: types.IpcModeHost, - Memory: sources.PtrString("memory"), + Memory: adapters.PtrString("memory"), NetworkMode: types.NetworkModeAwsvpc, PidMode: types.PidModeHost, ProxyConfiguration: nil, @@ -191,7 +191,7 @@ func (t *TestClient) DescribeTaskDefinition(ctx context.Context, params *ecs.Des CpuArchitecture: types.CPUArchitectureX8664, OperatingSystemFamily: types.OSFamilyLinux, }, - TaskRoleArn: sources.PtrString("arn:aws:iam:us-east-2:123456789012:role/bar"), // link + TaskRoleArn: adapters.PtrString("arn:aws:iam:us-east-2:123456789012:role/bar"), // link }, }, nil } @@ -206,7 +206,7 @@ func (t *TestClient) ListTaskDefinitions(context.Context, *ecs.ListTaskDefinitio func TestTaskDefinitionGetFunc(t *testing.T) { item, err := taskDefinitionGetFunc(context.Background(), &TestClient{}, "foo", &ecs.DescribeTaskDefinitionInput{ - TaskDefinition: sources.PtrString("ecs-template-ecs-demo-app:1"), + TaskDefinition: adapters.PtrString("ecs-template-ecs-demo-app:1"), }) if err != nil { @@ -217,7 +217,7 @@ func TestTaskDefinitionGetFunc(t *testing.T) { t.Error(err) } - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "secretsmanager-secret", ExpectedMethod: sdp.QueryMethod_SEARCH, @@ -253,13 +253,13 @@ func TestTaskDefinitionGetFunc(t *testing.T) { tests.Execute(t, item) } -func TestNewTaskDefinitionSource(t *testing.T) { +func TestNewTaskDefinitionAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewTaskDefinitionSource(client, account, region) + adapter := NewTaskDefinitionAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/ecs/task_test.go b/adapters/ecs/task_test.go similarity index 57% rename from sources/ecs/task_test.go rename to adapters/ecs/task_test.go index a4930412..e46fe95c 100644 --- a/sources/ecs/task_test.go +++ b/adapters/ecs/task_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ecs" "github.com/aws/aws-sdk-go-v2/service/ecs/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -17,90 +17,90 @@ func (t *TestClient) DescribeTasks(ctx context.Context, params *ecs.DescribeTask { Attachments: []types.Attachment{ { - Id: sources.PtrString("id"), // link? - Status: sources.PtrString("OK"), - Type: sources.PtrString("ElasticNetworkInterface"), + Id: adapters.PtrString("id"), // link? + Status: adapters.PtrString("OK"), + Type: adapters.PtrString("ElasticNetworkInterface"), }, }, Attributes: []types.Attribute{ { - Name: sources.PtrString("ecs.cpu-architecture"), - Value: sources.PtrString("x86_64"), + Name: adapters.PtrString("ecs.cpu-architecture"), + Value: adapters.PtrString("x86_64"), }, }, - AvailabilityZone: sources.PtrString("eu-west-1c"), - ClusterArn: sources.PtrString("arn:aws:ecs:eu-west-1:052392120703:cluster/test-ECSCluster-Bt4SqcM3CURk"), // link + AvailabilityZone: adapters.PtrString("eu-west-1c"), + ClusterArn: adapters.PtrString("arn:aws:ecs:eu-west-1:052392120703:cluster/test-ECSCluster-Bt4SqcM3CURk"), // link Connectivity: types.ConnectivityConnected, - ConnectivityAt: sources.PtrTime(time.Now()), - ContainerInstanceArn: sources.PtrString("arn:aws:ecs:eu-west-1:052392120703:container-instance/test-ECSCluster-Bt4SqcM3CURk/4b5c1d7dbb6746b38ada1b97b1866f6a"), // link + ConnectivityAt: adapters.PtrTime(time.Now()), + ContainerInstanceArn: adapters.PtrString("arn:aws:ecs:eu-west-1:052392120703:container-instance/test-ECSCluster-Bt4SqcM3CURk/4b5c1d7dbb6746b38ada1b97b1866f6a"), // link Containers: []types.Container{ { - ContainerArn: sources.PtrString("arn:aws:ecs:eu-west-1:052392120703:container/test-ECSCluster-Bt4SqcM3CURk/2ffd7ed376c841bcb0e6795ddb6e72e2/39a3ede1-1b28-472e-967a-d87d691f65e0"), - TaskArn: sources.PtrString("arn:aws:ecs:eu-west-1:052392120703:task/test-ECSCluster-Bt4SqcM3CURk/2ffd7ed376c841bcb0e6795ddb6e72e2"), - Name: sources.PtrString("busybox"), - Image: sources.PtrString("busybox"), - RuntimeId: sources.PtrString("7c158f5c2711416cbb6e653ad90997346489c9722c59d1115ad2121dd040748e"), - LastStatus: sources.PtrString("RUNNING"), + ContainerArn: adapters.PtrString("arn:aws:ecs:eu-west-1:052392120703:container/test-ECSCluster-Bt4SqcM3CURk/2ffd7ed376c841bcb0e6795ddb6e72e2/39a3ede1-1b28-472e-967a-d87d691f65e0"), + TaskArn: adapters.PtrString("arn:aws:ecs:eu-west-1:052392120703:task/test-ECSCluster-Bt4SqcM3CURk/2ffd7ed376c841bcb0e6795ddb6e72e2"), + Name: adapters.PtrString("busybox"), + Image: adapters.PtrString("busybox"), + RuntimeId: adapters.PtrString("7c158f5c2711416cbb6e653ad90997346489c9722c59d1115ad2121dd040748e"), + LastStatus: adapters.PtrString("RUNNING"), NetworkBindings: []types.NetworkBinding{}, NetworkInterfaces: []types.NetworkInterface{}, HealthStatus: types.HealthStatusUnknown, - Cpu: sources.PtrString("10"), - Memory: sources.PtrString("200"), + Cpu: adapters.PtrString("10"), + Memory: adapters.PtrString("200"), }, { - ContainerArn: sources.PtrString("arn:aws:ecs:eu-west-1:052392120703:container/test-ECSCluster-Bt4SqcM3CURk/2ffd7ed376c841bcb0e6795ddb6e72e2/8f3db814-6b39-4cc0-9d0a-a7d5702175eb"), - TaskArn: sources.PtrString("arn:aws:ecs:eu-west-1:052392120703:task/test-ECSCluster-Bt4SqcM3CURk/2ffd7ed376c841bcb0e6795ddb6e72e2"), - Name: sources.PtrString("simple-app"), - Image: sources.PtrString("httpd:2.4"), - RuntimeId: sources.PtrString("7316b64efb397cececce7cc5f39c6d48ab454f904cc80009aef5ed01ebdb1333"), - LastStatus: sources.PtrString("RUNNING"), + ContainerArn: adapters.PtrString("arn:aws:ecs:eu-west-1:052392120703:container/test-ECSCluster-Bt4SqcM3CURk/2ffd7ed376c841bcb0e6795ddb6e72e2/8f3db814-6b39-4cc0-9d0a-a7d5702175eb"), + TaskArn: adapters.PtrString("arn:aws:ecs:eu-west-1:052392120703:task/test-ECSCluster-Bt4SqcM3CURk/2ffd7ed376c841bcb0e6795ddb6e72e2"), + Name: adapters.PtrString("simple-app"), + Image: adapters.PtrString("httpd:2.4"), + RuntimeId: adapters.PtrString("7316b64efb397cececce7cc5f39c6d48ab454f904cc80009aef5ed01ebdb1333"), + LastStatus: adapters.PtrString("RUNNING"), NetworkBindings: []types.NetworkBinding{ { - BindIP: sources.PtrString("0.0.0.0"), // Link? NetworkSocket? - ContainerPort: sources.PtrInt32(80), - HostPort: sources.PtrInt32(32768), + BindIP: adapters.PtrString("0.0.0.0"), // Link? NetworkSocket? + ContainerPort: adapters.PtrInt32(80), + HostPort: adapters.PtrInt32(32768), Protocol: types.TransportProtocolTcp, }, }, NetworkInterfaces: []types.NetworkInterface{ { - AttachmentId: sources.PtrString("attachmentId"), - Ipv6Address: sources.PtrString("2001:db8:3333:4444:5555:6666:7777:8888"), // link - PrivateIpv4Address: sources.PtrString("10.0.0.1"), // link + AttachmentId: adapters.PtrString("attachmentId"), + Ipv6Address: adapters.PtrString("2001:db8:3333:4444:5555:6666:7777:8888"), // link + PrivateIpv4Address: adapters.PtrString("10.0.0.1"), // link }, }, HealthStatus: types.HealthStatusUnknown, - Cpu: sources.PtrString("10"), - Memory: sources.PtrString("300"), + Cpu: adapters.PtrString("10"), + Memory: adapters.PtrString("300"), }, }, - Cpu: sources.PtrString("20"), - CreatedAt: sources.PtrTime(time.Now()), - DesiredStatus: sources.PtrString("RUNNING"), + Cpu: adapters.PtrString("20"), + CreatedAt: adapters.PtrTime(time.Now()), + DesiredStatus: adapters.PtrString("RUNNING"), EnableExecuteCommand: false, - Group: sources.PtrString("service:test-service-lszmaXSqRKuF"), + Group: adapters.PtrString("service:test-service-lszmaXSqRKuF"), HealthStatus: types.HealthStatusUnknown, - LastStatus: sources.PtrString("RUNNING"), + LastStatus: adapters.PtrString("RUNNING"), LaunchType: types.LaunchTypeEc2, - Memory: sources.PtrString("500"), + Memory: adapters.PtrString("500"), Overrides: &types.TaskOverride{ ContainerOverrides: []types.ContainerOverride{ { - Name: sources.PtrString("busybox"), + Name: adapters.PtrString("busybox"), }, { - Name: sources.PtrString("simple-app"), + Name: adapters.PtrString("simple-app"), }, }, InferenceAcceleratorOverrides: []types.InferenceAcceleratorOverride{}, }, - PullStartedAt: sources.PtrTime(time.Now()), - PullStoppedAt: sources.PtrTime(time.Now()), - StartedAt: sources.PtrTime(time.Now()), - StartedBy: sources.PtrString("ecs-svc/0710912874193920929"), + PullStartedAt: adapters.PtrTime(time.Now()), + PullStoppedAt: adapters.PtrTime(time.Now()), + StartedAt: adapters.PtrTime(time.Now()), + StartedBy: adapters.PtrString("ecs-svc/0710912874193920929"), Tags: []types.Tag{}, - TaskArn: sources.PtrString("arn:aws:ecs:eu-west-1:052392120703:task/test-ECSCluster-Bt4SqcM3CURk/2ffd7ed376c841bcb0e6795ddb6e72e2"), - TaskDefinitionArn: sources.PtrString("arn:aws:ecs:eu-west-1:052392120703:task-definition/test-ecs-demo-app:1"), // link + TaskArn: adapters.PtrString("arn:aws:ecs:eu-west-1:052392120703:task/test-ECSCluster-Bt4SqcM3CURk/2ffd7ed376c841bcb0e6795ddb6e72e2"), + TaskDefinitionArn: adapters.PtrString("arn:aws:ecs:eu-west-1:052392120703:task-definition/test-ecs-demo-app:1"), // link Version: 3, EphemeralStorage: &types.EphemeralStorage{ SizeInGiB: 1, @@ -188,7 +188,7 @@ func TestTaskGetFunc(t *testing.T) { t.Error(err) } - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "ec2-network-interface", ExpectedMethod: sdp.QueryMethod_GET, @@ -230,13 +230,13 @@ func TestTaskGetFunc(t *testing.T) { tests.Execute(t, item) } -func TestNewTaskSource(t *testing.T) { +func TestNewTaskAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewTaskSource(client, account, region) + adapter := NewTaskAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, SkipNotFoundCheck: true, } diff --git a/sources/efs/access_point.go b/adapters/efs/access_point.go similarity index 62% rename from sources/efs/access_point.go rename to adapters/efs/access_point.go index e06f72e9..b4751058 100644 --- a/sources/efs/access_point.go +++ b/adapters/efs/access_point.go @@ -6,7 +6,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/efs" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -18,7 +18,7 @@ func AccessPointOutputMapper(_ context.Context, _ *efs.Client, scope string, inp items := make([]*sdp.Item, 0) for _, ap := range output.AccessPoints { - attrs, err := sources.ToAttributesWithExclude(ap, "tags") + attrs, err := adapters.ToAttributesWithExclude(ap, "tags") if err != nil { return nil, err @@ -64,16 +64,17 @@ func AccessPointOutputMapper(_ context.Context, _ *efs.Client, scope string, inp // +overmind:group AWS // +overmind:terraform:queryMap aws_efs_access_point.id -func NewAccessPointSource(client *efs.Client, accountID string, region string) *sources.DescribeOnlySource[*efs.DescribeAccessPointsInput, *efs.DescribeAccessPointsOutput, *efs.Client, *efs.Options] { - return &sources.DescribeOnlySource[*efs.DescribeAccessPointsInput, *efs.DescribeAccessPointsOutput, *efs.Client, *efs.Options]{ - ItemType: "efs-access-point", - Region: region, - Client: client, - AccountID: accountID, +func NewAccessPointAdapter(client *efs.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*efs.DescribeAccessPointsInput, *efs.DescribeAccessPointsOutput, *efs.Client, *efs.Options] { + return &adapters.DescribeOnlyAdapter[*efs.DescribeAccessPointsInput, *efs.DescribeAccessPointsOutput, *efs.Client, *efs.Options]{ + ItemType: "efs-access-point", + Region: region, + Client: client, + AccountID: accountID, + AdapterMetadata: AccessPointMetadata(), DescribeFunc: func(ctx context.Context, client *efs.Client, input *efs.DescribeAccessPointsInput) (*efs.DescribeAccessPointsOutput, error) { return client.DescribeAccessPoints(ctx, input) }, - PaginatorBuilder: func(client *efs.Client, params *efs.DescribeAccessPointsInput) sources.Paginator[*efs.DescribeAccessPointsOutput, *efs.Options] { + PaginatorBuilder: func(client *efs.Client, params *efs.DescribeAccessPointsInput) adapters.Paginator[*efs.DescribeAccessPointsOutput, *efs.Options] { return efs.NewDescribeAccessPointsPaginator(client, params) }, InputMapperGet: func(scope, query string) (*efs.DescribeAccessPointsInput, error) { @@ -87,3 +88,22 @@ func NewAccessPointSource(client *efs.Client, accountID string, region string) * OutputMapper: AccessPointOutputMapper, } } + +func AccessPointMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "efs-access-point", + DescriptiveName: "EFS Access Point", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get an access point by ID", + ListDescription: "List all access points", + SearchDescription: "Search for an access point by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_efs_access_point.id"}, + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + } +} diff --git a/sources/efs/access_point_test.go b/adapters/efs/access_point_test.go similarity index 56% rename from sources/efs/access_point_test.go rename to adapters/efs/access_point_test.go index 78276974..d712107e 100644 --- a/sources/efs/access_point_test.go +++ b/adapters/efs/access_point_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/efs" "github.com/aws/aws-sdk-go-v2/service/efs/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -15,32 +15,32 @@ func TestAccessPointOutputMapper(t *testing.T) { output := &efs.DescribeAccessPointsOutput{ AccessPoints: []types.AccessPointDescription{ { - AccessPointArn: sources.PtrString("arn:aws:elasticfilesystem:eu-west-2:944651592624:access-point/fsap-073b1534eafbc5ee2"), - AccessPointId: sources.PtrString("fsap-073b1534eafbc5ee2"), - ClientToken: sources.PtrString("pvc-66e4418c-edf5-4a0e-9834-5945598d51fe"), - FileSystemId: sources.PtrString("fs-0c6f2f41e957f42a9"), + AccessPointArn: adapters.PtrString("arn:aws:elasticfilesystem:eu-west-2:944651592624:access-point/fsap-073b1534eafbc5ee2"), + AccessPointId: adapters.PtrString("fsap-073b1534eafbc5ee2"), + ClientToken: adapters.PtrString("pvc-66e4418c-edf5-4a0e-9834-5945598d51fe"), + FileSystemId: adapters.PtrString("fs-0c6f2f41e957f42a9"), LifeCycleState: types.LifeCycleStateAvailable, - Name: sources.PtrString("example access point"), - OwnerId: sources.PtrString("944651592624"), + Name: adapters.PtrString("example access point"), + OwnerId: adapters.PtrString("944651592624"), PosixUser: &types.PosixUser{ - Gid: sources.PtrInt64(1000), - Uid: sources.PtrInt64(1000), + Gid: adapters.PtrInt64(1000), + Uid: adapters.PtrInt64(1000), SecondaryGids: []int64{ 1002, }, }, RootDirectory: &types.RootDirectory{ CreationInfo: &types.CreationInfo{ - OwnerGid: sources.PtrInt64(1000), - OwnerUid: sources.PtrInt64(1000), - Permissions: sources.PtrString("700"), + OwnerGid: adapters.PtrInt64(1000), + OwnerUid: adapters.PtrInt64(1000), + Permissions: adapters.PtrString("700"), }, - Path: sources.PtrString("/etc/foo"), + Path: adapters.PtrString("/etc/foo"), }, Tags: []types.Tag{ { - Key: sources.PtrString("Name"), - Value: sources.PtrString("example access point"), + Key: adapters.PtrString("Name"), + Value: adapters.PtrString("example access point"), }, }, }, @@ -67,7 +67,7 @@ func TestAccessPointOutputMapper(t *testing.T) { // It doesn't really make sense to test anything other than the linked items // since the attributes are converted automatically - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "efs-file-system", ExpectedMethod: sdp.QueryMethod_GET, @@ -80,13 +80,13 @@ func TestAccessPointOutputMapper(t *testing.T) { } -func TestNewAccessPointSource(t *testing.T) { +func TestNewAccessPointAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewAccessPointSource(client, account, region) + adapter := NewAccessPointAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/efs/backup_policy.go b/adapters/efs/backup_policy.go similarity index 59% rename from sources/efs/backup_policy.go rename to adapters/efs/backup_policy.go index 2375508e..0d6c7889 100644 --- a/sources/efs/backup_policy.go +++ b/adapters/efs/backup_policy.go @@ -6,7 +6,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/efs" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -27,7 +27,7 @@ func BackupPolicyOutputMapper(_ context.Context, _ *efs.Client, scope string, in return nil, errors.New("nil filesystem ID on input") } - attrs, err := sources.ToAttributesWithExclude(output) + attrs, err := adapters.ToAttributesWithExclude(output) if err != nil { return nil, err @@ -58,12 +58,13 @@ func BackupPolicyOutputMapper(_ context.Context, _ *efs.Client, scope string, in // +overmind:group AWS // +overmind:terraform:queryMap aws_efs_backup_policy.id -func NewBackupPolicySource(client *efs.Client, accountID string, region string) *sources.DescribeOnlySource[*efs.DescribeBackupPolicyInput, *efs.DescribeBackupPolicyOutput, *efs.Client, *efs.Options] { - return &sources.DescribeOnlySource[*efs.DescribeBackupPolicyInput, *efs.DescribeBackupPolicyOutput, *efs.Client, *efs.Options]{ - ItemType: "efs-backup-policy", - Region: region, - Client: client, - AccountID: accountID, +func NewBackupPolicyAdapter(client *efs.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*efs.DescribeBackupPolicyInput, *efs.DescribeBackupPolicyOutput, *efs.Client, *efs.Options] { + return &adapters.DescribeOnlyAdapter[*efs.DescribeBackupPolicyInput, *efs.DescribeBackupPolicyOutput, *efs.Client, *efs.Options]{ + ItemType: "efs-backup-policy", + Region: region, + Client: client, + AccountID: accountID, + AdapterMetadata: BackupPolicyMetadata(), DescribeFunc: func(ctx context.Context, client *efs.Client, input *efs.DescribeBackupPolicyInput) (*efs.DescribeBackupPolicyOutput, error) { return client.DescribeBackupPolicy(ctx, input) }, @@ -75,3 +76,20 @@ func NewBackupPolicySource(client *efs.Client, accountID string, region string) OutputMapper: BackupPolicyOutputMapper, } } + +func BackupPolicyMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "efs-backup-policy", + DescriptiveName: "EFS Backup Policy", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + Search: true, + GetDescription: "Get an Backup Policy by file system ID", + SearchDescription: "Search for an Backup Policy by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_efs_backup_policy.id"}, + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_STORAGE, + } +} diff --git a/sources/efs/backup_policy_test.go b/adapters/efs/backup_policy_test.go similarity index 87% rename from sources/efs/backup_policy_test.go rename to adapters/efs/backup_policy_test.go index 34d3c5e5..754d26f1 100644 --- a/sources/efs/backup_policy_test.go +++ b/adapters/efs/backup_policy_test.go @@ -6,7 +6,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/efs" "github.com/aws/aws-sdk-go-v2/service/efs/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" ) func TestBackupPolicyOutputMapper(t *testing.T) { @@ -17,7 +17,7 @@ func TestBackupPolicyOutputMapper(t *testing.T) { } items, err := BackupPolicyOutputMapper(context.Background(), nil, "foo", &efs.DescribeBackupPolicyInput{ - FileSystemId: sources.PtrString("fs-1234"), + FileSystemId: adapters.PtrString("fs-1234"), }, output) if err != nil { diff --git a/sources/efs/file_system.go b/adapters/efs/file_system.go similarity index 70% rename from sources/efs/file_system.go rename to adapters/efs/file_system.go index e438eda0..a4e9f4f9 100644 --- a/sources/efs/file_system.go +++ b/adapters/efs/file_system.go @@ -6,7 +6,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/efs" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -18,7 +18,7 @@ func FileSystemOutputMapper(_ context.Context, _ *efs.Client, scope string, inpu items := make([]*sdp.Item, 0) for _, fs := range output.FileSystems { - attrs, err := sources.ToAttributesWithExclude(fs, "tags") + attrs, err := adapters.ToAttributesWithExclude(fs, "tags") if err != nil { return nil, err @@ -69,13 +69,13 @@ func FileSystemOutputMapper(_ context.Context, _ *efs.Client, scope string, inpu if fs.KmsKeyId != nil { // KMS key ID is an ARN - if arn, err := sources.ParseARN(*fs.KmsKeyId); err == nil { + if arn, err := adapters.ParseARN(*fs.KmsKeyId); err == nil { item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "kms-key", Method: sdp.QueryMethod_SEARCH, Query: *fs.KmsKeyId, - Scope: sources.FormatScope(arn.AccountID, arn.Region), + Scope: adapters.FormatScope(arn.AccountID, arn.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changing the key will affect us @@ -102,16 +102,17 @@ func FileSystemOutputMapper(_ context.Context, _ *efs.Client, scope string, inpu // +overmind:group AWS // +overmind:terraform:queryMap aws_efs_file_system.id -func NewFileSystemSource(client *efs.Client, accountID string, region string) *sources.DescribeOnlySource[*efs.DescribeFileSystemsInput, *efs.DescribeFileSystemsOutput, *efs.Client, *efs.Options] { - return &sources.DescribeOnlySource[*efs.DescribeFileSystemsInput, *efs.DescribeFileSystemsOutput, *efs.Client, *efs.Options]{ - ItemType: "efs-file-system", - Region: region, - Client: client, - AccountID: accountID, +func NewFileSystemAdapter(client *efs.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*efs.DescribeFileSystemsInput, *efs.DescribeFileSystemsOutput, *efs.Client, *efs.Options] { + return &adapters.DescribeOnlyAdapter[*efs.DescribeFileSystemsInput, *efs.DescribeFileSystemsOutput, *efs.Client, *efs.Options]{ + ItemType: "efs-file-system", + Region: region, + Client: client, + AccountID: accountID, + AdapterMetadata: FileSystemMetadata(), DescribeFunc: func(ctx context.Context, client *efs.Client, input *efs.DescribeFileSystemsInput) (*efs.DescribeFileSystemsOutput, error) { return client.DescribeFileSystems(ctx, input) }, - PaginatorBuilder: func(client *efs.Client, params *efs.DescribeFileSystemsInput) sources.Paginator[*efs.DescribeFileSystemsOutput, *efs.Options] { + PaginatorBuilder: func(client *efs.Client, params *efs.DescribeFileSystemsInput) adapters.Paginator[*efs.DescribeFileSystemsOutput, *efs.Options] { return efs.NewDescribeFileSystemsPaginator(client, params) }, InputMapperGet: func(scope, query string) (*efs.DescribeFileSystemsInput, error) { @@ -125,3 +126,20 @@ func NewFileSystemSource(client *efs.Client, accountID string, region string) *s OutputMapper: FileSystemOutputMapper, } } + +func FileSystemMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "efs-file-system", + DescriptiveName: "EFS File System", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get an file system by ID", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_efs_file_system.id"}, + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_STORAGE, + } +} diff --git a/sources/efs/file_system_test.go b/adapters/efs/file_system_test.go similarity index 58% rename from sources/efs/file_system_test.go rename to adapters/efs/file_system_test.go index 4258830a..e8db46fe 100644 --- a/sources/efs/file_system_test.go +++ b/adapters/efs/file_system_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/efs" "github.com/aws/aws-sdk-go-v2/service/efs/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -15,32 +15,32 @@ func TestFileSystemOutputMapper(t *testing.T) { output := &efs.DescribeFileSystemsOutput{ FileSystems: []types.FileSystemDescription{ { - CreationTime: sources.PtrTime(time.Now()), - CreationToken: sources.PtrString("TOKEN"), - FileSystemId: sources.PtrString("fs-1231123123"), + CreationTime: adapters.PtrTime(time.Now()), + CreationToken: adapters.PtrString("TOKEN"), + FileSystemId: adapters.PtrString("fs-1231123123"), LifeCycleState: types.LifeCycleStateAvailable, NumberOfMountTargets: 10, - OwnerId: sources.PtrString("944651592624"), + OwnerId: adapters.PtrString("944651592624"), PerformanceMode: types.PerformanceModeGeneralPurpose, SizeInBytes: &types.FileSystemSize{ Value: 1024, - Timestamp: sources.PtrTime(time.Now()), - ValueInIA: sources.PtrInt64(2048), - ValueInStandard: sources.PtrInt64(128), + Timestamp: adapters.PtrTime(time.Now()), + ValueInIA: adapters.PtrInt64(2048), + ValueInStandard: adapters.PtrInt64(128), }, Tags: []types.Tag{ { - Key: sources.PtrString("foo"), - Value: sources.PtrString("bar"), + Key: adapters.PtrString("foo"), + Value: adapters.PtrString("bar"), }, }, - AvailabilityZoneId: sources.PtrString("use1-az1"), - AvailabilityZoneName: sources.PtrString("us-east-1"), - Encrypted: sources.PtrBool(true), - FileSystemArn: sources.PtrString("arn:aws:elasticfilesystem:eu-west-2:944651592624:file-system/fs-0c6f2f41e957f42a9"), - KmsKeyId: sources.PtrString("arn:aws:kms:eu-west-2:944651592624:key/be76a6fa-d307-41c2-a4e3-cbfba2440747"), - Name: sources.PtrString("test"), - ProvisionedThroughputInMibps: sources.PtrFloat64(64), + AvailabilityZoneId: adapters.PtrString("use1-az1"), + AvailabilityZoneName: adapters.PtrString("us-east-1"), + Encrypted: adapters.PtrBool(true), + FileSystemArn: adapters.PtrString("arn:aws:elasticfilesystem:eu-west-2:944651592624:file-system/fs-0c6f2f41e957f42a9"), + KmsKeyId: adapters.PtrString("arn:aws:kms:eu-west-2:944651592624:key/be76a6fa-d307-41c2-a4e3-cbfba2440747"), + Name: adapters.PtrString("test"), + ProvisionedThroughputInMibps: adapters.PtrFloat64(64), ThroughputMode: types.ThroughputModeBursting, }, }, @@ -66,7 +66,7 @@ func TestFileSystemOutputMapper(t *testing.T) { // It doesn't really make sense to test anything other than the linked items // since the attributes are converted automatically - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "efs-backup-policy", ExpectedMethod: sdp.QueryMethod_GET, @@ -91,13 +91,13 @@ func TestFileSystemOutputMapper(t *testing.T) { } -func TestNewFileSystemSource(t *testing.T) { +func TestNewFileSystemAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewFileSystemSource(client, account, region) + adapter := NewFileSystemAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/efs/integration/integration_test.go b/adapters/efs/integration/integration_test.go similarity index 96% rename from sources/efs/integration/integration_test.go rename to adapters/efs/integration/integration_test.go index ab7a4d1a..80d4f2d7 100644 --- a/sources/efs/integration/integration_test.go +++ b/adapters/efs/integration/integration_test.go @@ -18,7 +18,7 @@ func Teardown(logger *slog.Logger) error { return nil } -func TestIntegrationEFSSomeSource(t *testing.T) { +func TestIntegrationEFSSomeAdapter(t *testing.T) { slog.Info("Running EFS integration test TestSomeSource") } diff --git a/sources/efs/mount_target.go b/adapters/efs/mount_target.go similarity index 76% rename from sources/efs/mount_target.go rename to adapters/efs/mount_target.go index 1a5f1407..65033a1b 100644 --- a/sources/efs/mount_target.go +++ b/adapters/efs/mount_target.go @@ -6,7 +6,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/efs" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -18,7 +18,7 @@ func MountTargetOutputMapper(_ context.Context, _ *efs.Client, scope string, inp items := make([]*sdp.Item, 0) for _, mt := range output.MountTargets { - attrs, err := sources.ToAttributesWithExclude(mt) + attrs, err := adapters.ToAttributesWithExclude(mt) if err != nil { return nil, err @@ -130,12 +130,13 @@ func MountTargetOutputMapper(_ context.Context, _ *efs.Client, scope string, inp // +overmind:group AWS // +overmind:terraform:queryMap aws_efs_mount_target.id -func NewMountTargetSource(client *efs.Client, accountID string, region string) *sources.DescribeOnlySource[*efs.DescribeMountTargetsInput, *efs.DescribeMountTargetsOutput, *efs.Client, *efs.Options] { - return &sources.DescribeOnlySource[*efs.DescribeMountTargetsInput, *efs.DescribeMountTargetsOutput, *efs.Client, *efs.Options]{ - ItemType: "efs-mount-target", - Region: region, - Client: client, - AccountID: accountID, +func NewMountTargetAdapter(client *efs.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*efs.DescribeMountTargetsInput, *efs.DescribeMountTargetsOutput, *efs.Client, *efs.Options] { + return &adapters.DescribeOnlyAdapter[*efs.DescribeMountTargetsInput, *efs.DescribeMountTargetsOutput, *efs.Client, *efs.Options]{ + ItemType: "efs-mount-target", + Region: region, + Client: client, + AccountID: accountID, + AdapterMetadata: MountTargetMetadata(), DescribeFunc: func(ctx context.Context, client *efs.Client, input *efs.DescribeMountTargetsInput) (*efs.DescribeMountTargetsOutput, error) { return client.DescribeMountTargets(ctx, input) }, @@ -153,3 +154,20 @@ func NewMountTargetSource(client *efs.Client, accountID string, region string) * OutputMapper: MountTargetOutputMapper, } } + +func MountTargetMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "efs-mount-target", + DescriptiveName: "EFS Mount Target", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + Search: true, + GetDescription: "Get an mount target by ID", + SearchDescription: "Search for mount targets by file system ID", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_efs_mount_target.id"}, + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_STORAGE, + } +} diff --git a/sources/efs/mount_target_test.go b/adapters/efs/mount_target_test.go similarity index 71% rename from sources/efs/mount_target_test.go rename to adapters/efs/mount_target_test.go index 39332ed2..94cb9d2b 100644 --- a/sources/efs/mount_target_test.go +++ b/adapters/efs/mount_target_test.go @@ -6,7 +6,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/efs" "github.com/aws/aws-sdk-go-v2/service/efs/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -14,16 +14,16 @@ func TestMountTargetOutputMapper(t *testing.T) { output := &efs.DescribeMountTargetsOutput{ MountTargets: []types.MountTargetDescription{ { - FileSystemId: sources.PtrString("fs-1234567890"), + FileSystemId: adapters.PtrString("fs-1234567890"), LifeCycleState: types.LifeCycleStateAvailable, - MountTargetId: sources.PtrString("fsmt-01e86506d8165e43f"), - SubnetId: sources.PtrString("subnet-1234567"), - AvailabilityZoneId: sources.PtrString("use1-az1"), - AvailabilityZoneName: sources.PtrString("us-east-1"), - IpAddress: sources.PtrString("10.230.43.1"), - NetworkInterfaceId: sources.PtrString("eni-2345"), - OwnerId: sources.PtrString("234234"), - VpcId: sources.PtrString("vpc-23452345235"), + MountTargetId: adapters.PtrString("fsmt-01e86506d8165e43f"), + SubnetId: adapters.PtrString("subnet-1234567"), + AvailabilityZoneId: adapters.PtrString("use1-az1"), + AvailabilityZoneName: adapters.PtrString("us-east-1"), + IpAddress: adapters.PtrString("10.230.43.1"), + NetworkInterfaceId: adapters.PtrString("eni-2345"), + OwnerId: adapters.PtrString("234234"), + VpcId: adapters.PtrString("vpc-23452345235"), }, }, } @@ -48,7 +48,7 @@ func TestMountTargetOutputMapper(t *testing.T) { // It doesn't really make sense to test anything other than the linked items // since the attributes are converted automatically - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "efs-file-system", ExpectedMethod: sdp.QueryMethod_GET, diff --git a/sources/efs/replication_configuration.go b/adapters/efs/replication_configuration.go similarity index 70% rename from sources/efs/replication_configuration.go rename to adapters/efs/replication_configuration.go index 2b387324..38d04b88 100644 --- a/sources/efs/replication_configuration.go +++ b/adapters/efs/replication_configuration.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/efs" "github.com/aws/aws-sdk-go-v2/service/efs/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -19,7 +19,7 @@ func ReplicationConfigurationOutputMapper(_ context.Context, _ *efs.Client, scop items := make([]*sdp.Item, 0) for _, replication := range output.Replications { - attrs, err := sources.ToAttributesWithExclude(replication) + attrs, err := adapters.ToAttributesWithExclude(replication) if err != nil { return nil, err @@ -33,7 +33,7 @@ func ReplicationConfigurationOutputMapper(_ context.Context, _ *efs.Client, scop return nil, errors.New("efs-replication-configuration has nil SourceFileSystemRegion") } - accountID, _, err := sources.ParseScope(scope) + accountID, _, err := adapters.ParseScope(scope) if err != nil { return nil, err @@ -51,7 +51,7 @@ func ReplicationConfigurationOutputMapper(_ context.Context, _ *efs.Client, scop Type: "efs-file-system", Method: sdp.QueryMethod_GET, Query: *replication.SourceFileSystemId, - Scope: sources.FormatScope(accountID, *replication.SourceFileSystemRegion), + Scope: adapters.FormatScope(accountID, *replication.SourceFileSystemRegion), }, }, }, @@ -64,7 +64,7 @@ func ReplicationConfigurationOutputMapper(_ context.Context, _ *efs.Client, scop Type: "efs-file-system", Method: sdp.QueryMethod_GET, Query: *destination.FileSystemId, - Scope: sources.FormatScope(accountID, *destination.Region), + Scope: adapters.FormatScope(accountID, *destination.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changes to the destination shouldn't affect the source @@ -99,13 +99,13 @@ func ReplicationConfigurationOutputMapper(_ context.Context, _ *efs.Client, scop } if replication.OriginalSourceFileSystemArn != nil { - if arn, err := sources.ParseARN(*replication.OriginalSourceFileSystemArn); err == nil { + if arn, err := adapters.ParseARN(*replication.OriginalSourceFileSystemArn); err == nil { item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "efs-file-system", Method: sdp.QueryMethod_SEARCH, Query: *replication.OriginalSourceFileSystemArn, - Scope: sources.FormatScope(arn.AccountID, arn.Region), + Scope: adapters.FormatScope(arn.AccountID, arn.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changing the source file system will affect its replication @@ -133,12 +133,13 @@ func ReplicationConfigurationOutputMapper(_ context.Context, _ *efs.Client, scop // +overmind:group AWS // +overmind:terraform:queryMap aws_efs_replication_configuration.source_file_system_id -func NewReplicationConfigurationSource(client *efs.Client, accountID string, region string) *sources.DescribeOnlySource[*efs.DescribeReplicationConfigurationsInput, *efs.DescribeReplicationConfigurationsOutput, *efs.Client, *efs.Options] { - return &sources.DescribeOnlySource[*efs.DescribeReplicationConfigurationsInput, *efs.DescribeReplicationConfigurationsOutput, *efs.Client, *efs.Options]{ - ItemType: "efs-replication-configuration", - Region: region, - Client: client, - AccountID: accountID, +func NewReplicationConfigurationAdapter(client *efs.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*efs.DescribeReplicationConfigurationsInput, *efs.DescribeReplicationConfigurationsOutput, *efs.Client, *efs.Options] { + return &adapters.DescribeOnlyAdapter[*efs.DescribeReplicationConfigurationsInput, *efs.DescribeReplicationConfigurationsOutput, *efs.Client, *efs.Options]{ + ItemType: "efs-replication-configuration", + Region: region, + Client: client, + AccountID: accountID, + AdapterMetadata: ReplicationConfigurationMetadata(), DescribeFunc: func(ctx context.Context, client *efs.Client, input *efs.DescribeReplicationConfigurationsInput) (*efs.DescribeReplicationConfigurationsOutput, error) { return client.DescribeReplicationConfigurations(ctx, input) }, @@ -153,3 +154,22 @@ func NewReplicationConfigurationSource(client *efs.Client, accountID string, reg OutputMapper: ReplicationConfigurationOutputMapper, } } + +func ReplicationConfigurationMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "efs-replication-configuration", + DescriptiveName: "EFS Replication Configuration", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a replication configuration by file system ID", + ListDescription: "List all replication configurations", + SearchDescription: "Search for a replication configuration by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_efs_replication_configuration.source_file_system_id"}, + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_STORAGE, + } +} diff --git a/sources/efs/replication_configuration_test.go b/adapters/efs/replication_configuration_test.go similarity index 60% rename from sources/efs/replication_configuration_test.go rename to adapters/efs/replication_configuration_test.go index a7991f62..5903020b 100644 --- a/sources/efs/replication_configuration_test.go +++ b/adapters/efs/replication_configuration_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/efs" "github.com/aws/aws-sdk-go-v2/service/efs/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -15,31 +15,31 @@ func TestReplicationConfigurationOutputMapper(t *testing.T) { output := &efs.DescribeReplicationConfigurationsOutput{ Replications: []types.ReplicationConfigurationDescription{ { - CreationTime: sources.PtrTime(time.Now()), + CreationTime: adapters.PtrTime(time.Now()), Destinations: []types.Destination{ { - FileSystemId: sources.PtrString("fs-12345678"), - Region: sources.PtrString("eu-west-1"), + FileSystemId: adapters.PtrString("fs-12345678"), + Region: adapters.PtrString("eu-west-1"), Status: types.ReplicationStatusEnabled, - LastReplicatedTimestamp: sources.PtrTime(time.Now()), + LastReplicatedTimestamp: adapters.PtrTime(time.Now()), }, { - FileSystemId: sources.PtrString("fs-98765432"), - Region: sources.PtrString("us-west-2"), + FileSystemId: adapters.PtrString("fs-98765432"), + Region: adapters.PtrString("us-west-2"), Status: types.ReplicationStatusError, - LastReplicatedTimestamp: sources.PtrTime(time.Now()), + LastReplicatedTimestamp: adapters.PtrTime(time.Now()), }, }, - OriginalSourceFileSystemArn: sources.PtrString("arn:aws:elasticfilesystem:eu-west-2:944651592624:file-system/fs-0c6f2f41e957f42a9"), - SourceFileSystemArn: sources.PtrString("arn:aws:elasticfilesystem:eu-west-2:944651592624:file-system/fs-0c6f2f41e957f42a9"), - SourceFileSystemId: sources.PtrString("fs-748927493"), - SourceFileSystemRegion: sources.PtrString("us-east-1"), + OriginalSourceFileSystemArn: adapters.PtrString("arn:aws:elasticfilesystem:eu-west-2:944651592624:file-system/fs-0c6f2f41e957f42a9"), + SourceFileSystemArn: adapters.PtrString("arn:aws:elasticfilesystem:eu-west-2:944651592624:file-system/fs-0c6f2f41e957f42a9"), + SourceFileSystemId: adapters.PtrString("fs-748927493"), + SourceFileSystemRegion: adapters.PtrString("us-east-1"), }, }, } accountID := "1234" - items, err := ReplicationConfigurationOutputMapper(context.Background(), nil, sources.FormatScope(accountID, "eu-west-1"), nil, output) + items, err := ReplicationConfigurationOutputMapper(context.Background(), nil, adapters.FormatScope(accountID, "eu-west-1"), nil, output) if err != nil { t.Fatal(err) @@ -59,24 +59,24 @@ func TestReplicationConfigurationOutputMapper(t *testing.T) { // It doesn't really make sense to test anything other than the linked items // since the attributes are converted automatically - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "efs-file-system", ExpectedMethod: sdp.QueryMethod_GET, ExpectedQuery: "fs-748927493", - ExpectedScope: sources.FormatScope(accountID, "us-east-1"), + ExpectedScope: adapters.FormatScope(accountID, "us-east-1"), }, { ExpectedType: "efs-file-system", ExpectedMethod: sdp.QueryMethod_GET, ExpectedQuery: "fs-12345678", - ExpectedScope: sources.FormatScope(accountID, "eu-west-1"), + ExpectedScope: adapters.FormatScope(accountID, "eu-west-1"), }, { ExpectedType: "efs-file-system", ExpectedMethod: sdp.QueryMethod_GET, ExpectedQuery: "fs-98765432", - ExpectedScope: sources.FormatScope(accountID, "us-west-2"), + ExpectedScope: adapters.FormatScope(accountID, "us-west-2"), }, { ExpectedType: "efs-file-system", diff --git a/sources/efs/shared.go b/adapters/efs/shared.go similarity index 100% rename from sources/efs/shared.go rename to adapters/efs/shared.go diff --git a/sources/efs/shared_test.go b/adapters/efs/shared_test.go similarity index 68% rename from sources/efs/shared_test.go rename to adapters/efs/shared_test.go index 5fa4b527..a1536d70 100644 --- a/sources/efs/shared_test.go +++ b/adapters/efs/shared_test.go @@ -4,11 +4,11 @@ import ( "testing" "github.com/aws/aws-sdk-go-v2/service/efs" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" ) func GetAutoConfig(t *testing.T) (*efs.Client, string, string) { - config, account, region := sources.GetAutoConfig(t) + config, account, region := adapters.GetAutoConfig(t) client := efs.NewFromConfig(config) return client, account, region diff --git a/sources/eks/addon.go b/adapters/eks/addon.go similarity index 62% rename from sources/eks/addon.go rename to adapters/eks/addon.go index c3dc9910..4b25e147 100644 --- a/sources/eks/addon.go +++ b/adapters/eks/addon.go @@ -5,7 +5,7 @@ import ( "strings" "github.com/aws/aws-sdk-go-v2/service/eks" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -23,7 +23,7 @@ func addonGetFunc(ctx context.Context, client EKSClient, scope string, input *ek } } - attributes, err := sources.ToAttributesWithExclude(out.Addon) + attributes, err := adapters.ToAttributesWithExclude(out.Addon) if err != nil { return nil, err @@ -53,13 +53,14 @@ func addonGetFunc(ctx context.Context, client EKSClient, scope string, input *ek // +overmind:terraform:queryMap aws_eks_addon.arn // +overmind:terraform:method SEARCH -func NewAddonSource(client EKSClient, accountID string, region string) *sources.AlwaysGetSource[*eks.ListAddonsInput, *eks.ListAddonsOutput, *eks.DescribeAddonInput, *eks.DescribeAddonOutput, EKSClient, *eks.Options] { - return &sources.AlwaysGetSource[*eks.ListAddonsInput, *eks.ListAddonsOutput, *eks.DescribeAddonInput, *eks.DescribeAddonOutput, EKSClient, *eks.Options]{ - ItemType: "eks-addon", - Client: client, - AccountID: accountID, - Region: region, - DisableList: true, +func NewAddonAdapter(client EKSClient, accountID string, region string) *adapters.AlwaysGetAdapter[*eks.ListAddonsInput, *eks.ListAddonsOutput, *eks.DescribeAddonInput, *eks.DescribeAddonOutput, EKSClient, *eks.Options] { + return &adapters.AlwaysGetAdapter[*eks.ListAddonsInput, *eks.ListAddonsOutput, *eks.DescribeAddonInput, *eks.DescribeAddonOutput, EKSClient, *eks.Options]{ + ItemType: "eks-addon", + Client: client, + AccountID: accountID, + Region: region, + AdapterMetadata: AddonMetadata(), + DisableList: true, SearchInputMapper: func(scope, query string) (*eks.ListAddonsInput, error) { return &eks.ListAddonsInput{ ClusterName: &query, @@ -83,7 +84,7 @@ func NewAddonSource(client EKSClient, accountID string, region string) *sources. ClusterName: &clusterName, } }, - ListFuncPaginatorBuilder: func(client EKSClient, input *eks.ListAddonsInput) sources.Paginator[*eks.ListAddonsOutput, *eks.Options] { + ListFuncPaginatorBuilder: func(client EKSClient, input *eks.ListAddonsInput) adapters.Paginator[*eks.ListAddonsOutput, *eks.Options] { return eks.NewListAddonsPaginator(client, input) }, ListFuncOutputMapper: func(output *eks.ListAddonsOutput, input *eks.ListAddonsInput) ([]*eks.DescribeAddonInput, error) { @@ -101,3 +102,25 @@ func NewAddonSource(client EKSClient, accountID string, region string) *sources. GetFunc: addonGetFunc, } } + +func AddonMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "eks-addon", + DescriptiveName: "EKS Addon", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get an addon by unique name ({clusterName}/{addonName})", + ListDescription: "List all addons", + SearchDescription: "Search addons by cluster name", + }, + TerraformMappings: []*sdp.TerraformMapping{ + { + TerraformMethod: sdp.QueryMethod_SEARCH, + TerraformQueryMap: "aws_eks_addon.arn", + }, + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_COMPUTE_APPLICATION, + } +} diff --git a/adapters/eks/addon_test.go b/adapters/eks/addon_test.go new file mode 100644 index 00000000..7e5d9ecf --- /dev/null +++ b/adapters/eks/addon_test.go @@ -0,0 +1,62 @@ +package eks + +import ( + "context" + "testing" + "time" + + "github.com/aws/aws-sdk-go-v2/service/eks" + "github.com/aws/aws-sdk-go-v2/service/eks/types" + "github.com/overmindtech/aws-source/adapters" +) + +var AddonTestClient = TestClient{ + DescribeAddonOutput: &eks.DescribeAddonOutput{ + Addon: &types.Addon{ + AddonName: adapters.PtrString("aws-ebs-csi-driver"), + ClusterName: adapters.PtrString("dylan"), + Status: types.AddonStatusActive, + AddonVersion: adapters.PtrString("v1.13.0-eksbuild.3"), + ConfigurationValues: adapters.PtrString("values"), + MarketplaceInformation: &types.MarketplaceInformation{ + ProductId: adapters.PtrString("id"), + ProductUrl: adapters.PtrString("url"), + }, + Publisher: adapters.PtrString("publisher"), + Owner: adapters.PtrString("owner"), + Health: &types.AddonHealth{ + Issues: []types.AddonIssue{}, + }, + AddonArn: adapters.PtrString("arn:aws:eks:eu-west-2:801795385023:addon/dylan/aws-ebs-csi-driver/a2c29d0e-72c4-a702-7887-2f739f4fc189"), + CreatedAt: adapters.PtrTime(time.Now()), + ModifiedAt: adapters.PtrTime(time.Now()), + ServiceAccountRoleArn: adapters.PtrString("arn:aws:iam::801795385023:role/eks-csi-dylan"), + }, + }, +} + +func TestAddonGetFunc(t *testing.T) { + item, err := addonGetFunc(context.Background(), AddonTestClient, "foo", &eks.DescribeAddonInput{}) + + if err != nil { + t.Error(err) + } + + if err = item.Validate(); err != nil { + t.Error(err) + } +} + +func TestNewAddonAdapter(t *testing.T) { + client, account, region := GetAutoConfig(t) + + adapter := NewAddonAdapter(client, account, region) + + test := adapters.E2ETest{ + Adapter: adapter, + Timeout: 10 * time.Second, + SkipNotFoundCheck: true, + } + + test.Run(t) +} diff --git a/sources/eks/client.go b/adapters/eks/client.go similarity index 100% rename from sources/eks/client.go rename to adapters/eks/client.go diff --git a/sources/eks/client_test.go b/adapters/eks/client_test.go similarity index 100% rename from sources/eks/client_test.go rename to adapters/eks/client_test.go diff --git a/sources/eks/cluster.go b/adapters/eks/cluster.go similarity index 79% rename from sources/eks/cluster.go rename to adapters/eks/cluster.go index 51b52152..319ab010 100644 --- a/sources/eks/cluster.go +++ b/adapters/eks/cluster.go @@ -5,7 +5,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/eks" "github.com/aws/aws-sdk-go-v2/service/eks/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -25,7 +25,7 @@ func clusterGetFunc(ctx context.Context, client EKSClient, scope string, input * cluster := output.Cluster - attributes, err := sources.ToAttributesWithExclude(cluster, "clientRequestToken") + attributes, err := adapters.ToAttributesWithExclude(cluster, "clientRequestToken") if err != nil { return nil, err @@ -98,18 +98,18 @@ func clusterGetFunc(ctx context.Context, client EKSClient, scope string, input * item.Health = sdp.Health_HEALTH_PENDING.Enum() } - var a *sources.ARN + var a *adapters.ARN if cluster.ConnectorConfig != nil { if cluster.ConnectorConfig.RoleArn != nil { - if a, err = sources.ParseARN(*cluster.ConnectorConfig.RoleArn); err == nil { + if a, err = adapters.ParseARN(*cluster.ConnectorConfig.RoleArn); err == nil { // +overmind:link iam-role item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "iam-role", Method: sdp.QueryMethod_SEARCH, Query: *cluster.ConnectorConfig.RoleArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // The role can affect the cluster @@ -125,14 +125,14 @@ func clusterGetFunc(ctx context.Context, client EKSClient, scope string, input * for _, conf := range cluster.EncryptionConfig { if conf.Provider != nil { if conf.Provider.KeyArn != nil { - if a, err = sources.ParseARN(*conf.Provider.KeyArn); err == nil { + if a, err = adapters.ParseARN(*conf.Provider.KeyArn); err == nil { // +overmind:link kms-key item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "kms-key", Method: sdp.QueryMethod_SEARCH, Query: *conf.Provider.KeyArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // The key can affect the cluster @@ -238,14 +238,14 @@ func clusterGetFunc(ctx context.Context, client EKSClient, scope string, input * } if cluster.RoleArn != nil { - if a, err = sources.ParseARN(*cluster.RoleArn); err == nil { + if a, err = adapters.ParseARN(*cluster.RoleArn); err == nil { // +overmind:link iam-role item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "iam-role", Method: sdp.QueryMethod_SEARCH, Query: *cluster.RoleArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // The role can affect the cluster @@ -271,19 +271,20 @@ func clusterGetFunc(ctx context.Context, client EKSClient, scope string, input * // +overmind:terraform:queryMap aws_eks_cluster.arn // +overmind:terraform:method SEARCH -func NewClusterSource(client EKSClient, accountID string, region string) *sources.AlwaysGetSource[*eks.ListClustersInput, *eks.ListClustersOutput, *eks.DescribeClusterInput, *eks.DescribeClusterOutput, EKSClient, *eks.Options] { - return &sources.AlwaysGetSource[*eks.ListClustersInput, *eks.ListClustersOutput, *eks.DescribeClusterInput, *eks.DescribeClusterOutput, EKSClient, *eks.Options]{ - ItemType: "eks-cluster", - Client: client, - AccountID: accountID, - Region: region, - ListInput: &eks.ListClustersInput{}, +func NewClusterAdapter(client EKSClient, accountID string, region string) *adapters.AlwaysGetAdapter[*eks.ListClustersInput, *eks.ListClustersOutput, *eks.DescribeClusterInput, *eks.DescribeClusterOutput, EKSClient, *eks.Options] { + return &adapters.AlwaysGetAdapter[*eks.ListClustersInput, *eks.ListClustersOutput, *eks.DescribeClusterInput, *eks.DescribeClusterOutput, EKSClient, *eks.Options]{ + ItemType: "eks-cluster", + Client: client, + AccountID: accountID, + Region: region, + AdapterMetadata: ClusterMetadata(), + ListInput: &eks.ListClustersInput{}, GetInputMapper: func(scope, query string) *eks.DescribeClusterInput { return &eks.DescribeClusterInput{ Name: &query, } }, - ListFuncPaginatorBuilder: func(client EKSClient, input *eks.ListClustersInput) sources.Paginator[*eks.ListClustersOutput, *eks.Options] { + ListFuncPaginatorBuilder: func(client EKSClient, input *eks.ListClustersInput) adapters.Paginator[*eks.ListClustersOutput, *eks.Options] { return eks.NewListClustersPaginator(client, input) }, ListFuncOutputMapper: func(output *eks.ListClustersOutput, _ *eks.ListClustersInput) ([]*eks.DescribeClusterInput, error) { @@ -300,3 +301,25 @@ func NewClusterSource(client EKSClient, accountID string, region string) *source GetFunc: clusterGetFunc, } } + +func ClusterMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "eks-cluster", + DescriptiveName: "EKS Cluster", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a cluster by name", + ListDescription: "List all clusters", + SearchDescription: "Search for clusters by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + { + TerraformQueryMap: "aws_eks_cluster.arn", + TerraformMethod: sdp.QueryMethod_SEARCH, + }, + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_COMPUTE_APPLICATION, + } +} diff --git a/sources/eks/cluster_test.go b/adapters/eks/cluster_test.go similarity index 58% rename from sources/eks/cluster_test.go rename to adapters/eks/cluster_test.go index 450c25d8..11472c42 100644 --- a/sources/eks/cluster_test.go +++ b/adapters/eks/cluster_test.go @@ -7,38 +7,38 @@ import ( "github.com/aws/aws-sdk-go-v2/service/eks" "github.com/aws/aws-sdk-go-v2/service/eks/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) var ClusterClient = TestClient{ DescribeClusterOutput: &eks.DescribeClusterOutput{ Cluster: &types.Cluster{ - Name: sources.PtrString("dylan"), - Arn: sources.PtrString("arn:aws:eks:eu-west-2:801795385023:cluster/dylan"), - CreatedAt: sources.PtrTime(time.Now()), - Version: sources.PtrString("1.24"), - Endpoint: sources.PtrString("https://00D3FF4CC48CBAA9BBC070DAA80BD251.gr7.eu-west-2.eks.amazonaws.com"), - RoleArn: sources.PtrString("arn:aws:iam::801795385023:role/dylan-cluster-20221222134106992100000001"), - ClientRequestToken: sources.PtrString("token"), + Name: adapters.PtrString("dylan"), + Arn: adapters.PtrString("arn:aws:eks:eu-west-2:801795385023:cluster/dylan"), + CreatedAt: adapters.PtrTime(time.Now()), + Version: adapters.PtrString("1.24"), + Endpoint: adapters.PtrString("https://00D3FF4CC48CBAA9BBC070DAA80BD251.gr7.eu-west-2.eks.amazonaws.com"), + RoleArn: adapters.PtrString("arn:aws:iam::801795385023:role/dylan-cluster-20221222134106992100000001"), + ClientRequestToken: adapters.PtrString("token"), ConnectorConfig: &types.ConnectorConfigResponse{ - ActivationCode: sources.PtrString("code"), - ActivationExpiry: sources.PtrTime(time.Now()), - ActivationId: sources.PtrString("id"), - Provider: sources.PtrString("provider"), - RoleArn: sources.PtrString("arn:aws:iam::801795385023:role/dylan-cluster-20221222134106992100000002"), + ActivationCode: adapters.PtrString("code"), + ActivationExpiry: adapters.PtrTime(time.Now()), + ActivationId: adapters.PtrString("id"), + Provider: adapters.PtrString("provider"), + RoleArn: adapters.PtrString("arn:aws:iam::801795385023:role/dylan-cluster-20221222134106992100000002"), }, Health: &types.ClusterHealth{ Issues: []types.ClusterIssue{}, }, - Id: sources.PtrString("id"), + Id: adapters.PtrString("id"), OutpostConfig: &types.OutpostConfigResponse{ - ControlPlaneInstanceType: sources.PtrString("type"), + ControlPlaneInstanceType: adapters.PtrString("type"), OutpostArns: []string{ "arn1", }, ControlPlanePlacement: &types.ControlPlanePlacementResponse{ - GroupName: sources.PtrString("groupName"), + GroupName: adapters.PtrString("groupName"), }, }, ResourcesVpcConfig: &types.VpcConfigResponse{ @@ -50,8 +50,8 @@ var ClusterClient = TestClient{ SecurityGroupIds: []string{ "sg-0bf38eb7e14777399", }, - ClusterSecurityGroupId: sources.PtrString("sg-08df96f08566d4dda"), - VpcId: sources.PtrString("vpc-0c9152ce7ed2b7305"), + ClusterSecurityGroupId: adapters.PtrString("sg-08df96f08566d4dda"), + VpcId: adapters.PtrString("vpc-0c9152ce7ed2b7305"), EndpointPublicAccess: true, EndpointPrivateAccess: true, PublicAccessCidrs: []string{ @@ -59,9 +59,9 @@ var ClusterClient = TestClient{ }, }, KubernetesNetworkConfig: &types.KubernetesNetworkConfigResponse{ - ServiceIpv4Cidr: sources.PtrString("172.20.0.0/16"), + ServiceIpv4Cidr: adapters.PtrString("172.20.0.0/16"), IpFamily: types.IpFamilyIpv4, - ServiceIpv6Cidr: sources.PtrString("ipv6cidr"), + ServiceIpv6Cidr: adapters.PtrString("ipv6cidr"), }, Logging: &types.Logging{ ClusterLogging: []types.LogSetup{ @@ -72,26 +72,26 @@ var ClusterClient = TestClient{ "controllerManager", "scheduler", }, - Enabled: sources.PtrBool(true), + Enabled: adapters.PtrBool(true), }, { Types: []types.LogType{ "audit", }, - Enabled: sources.PtrBool(false), + Enabled: adapters.PtrBool(false), }, }, }, Identity: &types.Identity{ Oidc: &types.OIDC{ - Issuer: sources.PtrString("https://oidc.eks.eu-west-2.amazonaws.com/id/00D3FF4CC48CBAA9BBC070DAA80BD251"), + Issuer: adapters.PtrString("https://oidc.eks.eu-west-2.amazonaws.com/id/00D3FF4CC48CBAA9BBC070DAA80BD251"), }, }, Status: types.ClusterStatusActive, CertificateAuthority: &types.Certificate{ - Data: sources.PtrString("LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUMvakNDQWVhZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRJeU1USXlNakV6TkRZME5Gb1hEVE15TVRJeE9URXpORFkwTkZvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTC9tCkN6b25QdUZIUXM1a0xudzdCeXMrak9pNWJscEVCN2RhZUYvQzZqaEVTbkcwdVBVRjVWSFUzbmRyZHRKelBaemQKenM4U1pEMzRsKytGWmw0NFQrYWRqMGFYanpmZ0NTeFo4K0MvaWJUOWIzck5jWU9ZZ3FYT1lXc2JVYmpBSjRadgpnakFqdEl3dTBvUHNYT0JSZU5KTDlhRkl6VFFIcy9QL1hONWI5eGRlSHhwOXN4cnlEREYxQVNuQkxwajduUHMrCmgyNUtvd0hQV1luekV6WVd1T3NZbDQ2RjZacHh4aVhya2hnOGozckR4dXRWZGMvQVBFaVhUdHh3OU9CMjFDMkwKK1VpanpxS2RrZm5idVEvOHF0TTRqbFVGTkgzUG03STlkTEdIMTBTOFdhQkhpODNRMklCd3c0eE5RZ04xNC91dgpXWFZOWkxmM1EwbElkdmtxaCtrQ0F3RUFBYU5aTUZjd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0hRWURWUjBPQkJZRUZCa2wvVEJwNVNyMFJrVEk2V1dMVkR4MVdZYUxNQlVHQTFVZEVRUU8KTUF5Q0NtdDFZbVZ5Ym1WMFpYTXdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBQ0FCVWtZUWZSQXlRRFVsc2todgp2NTRZN3lFQ1lUSG00OWVtMWoyV2hyN0JPdXdlUkU4M3g1b0NhWEtjK2tMemlvOEVvY2hxOWN1a1FEYm1KNkpoCmRhUUlyaFFwaG5PMHZSd290YXlhWjdlV2IwTm50WmNxN1ZmNkp5ZU5CR3Y1NTJGdlNNcGprWnh0UXVpTTJ5TXoKbjJWWmtxMzJPb0RjTmxCMERhRVBCSjlIM2ZnbG1qcGdWL0NHZFdMNG1wNEpkb3VPNTFtNkJBMm1ET2JWYzh4VgppNFJIWE9KNG9hSGFTd1B6MHBuQUxabkJoUnpxV0Q1cGlycVlucjBxSlFDamJDWXF1TmJTU3d4c2JMYVFjanNFCjhiUXk0aGxXaEJNWno3UldOeDg1UTBZSjhWNEhKdXVCZ09MaVg1REFtNDZIbndWUy95MHJyN2JTWThoTXErM2QKTmtrPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg=="), + Data: adapters.PtrString("LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUMvakNDQWVhZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRJeU1USXlNakV6TkRZME5Gb1hEVE15TVRJeE9URXpORFkwTkZvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTC9tCkN6b25QdUZIUXM1a0xudzdCeXMrak9pNWJscEVCN2RhZUYvQzZqaEVTbkcwdVBVRjVWSFUzbmRyZHRKelBaemQKenM4U1pEMzRsKytGWmw0NFQrYWRqMGFYanpmZ0NTeFo4K0MvaWJUOWIzck5jWU9ZZ3FYT1lXc2JVYmpBSjRadgpnakFqdEl3dTBvUHNYT0JSZU5KTDlhRkl6VFFIcy9QL1hONWI5eGRlSHhwOXN4cnlEREYxQVNuQkxwajduUHMrCmgyNUtvd0hQV1luekV6WVd1T3NZbDQ2RjZacHh4aVhya2hnOGozckR4dXRWZGMvQVBFaVhUdHh3OU9CMjFDMkwKK1VpanpxS2RrZm5idVEvOHF0TTRqbFVGTkgzUG03STlkTEdIMTBTOFdhQkhpODNRMklCd3c0eE5RZ04xNC91dgpXWFZOWkxmM1EwbElkdmtxaCtrQ0F3RUFBYU5aTUZjd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0hRWURWUjBPQkJZRUZCa2wvVEJwNVNyMFJrVEk2V1dMVkR4MVdZYUxNQlVHQTFVZEVRUU8KTUF5Q0NtdDFZbVZ5Ym1WMFpYTXdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBQ0FCVWtZUWZSQXlRRFVsc2todgp2NTRZN3lFQ1lUSG00OWVtMWoyV2hyN0JPdXdlUkU4M3g1b0NhWEtjK2tMemlvOEVvY2hxOWN1a1FEYm1KNkpoCmRhUUlyaFFwaG5PMHZSd290YXlhWjdlV2IwTm50WmNxN1ZmNkp5ZU5CR3Y1NTJGdlNNcGprWnh0UXVpTTJ5TXoKbjJWWmtxMzJPb0RjTmxCMERhRVBCSjlIM2ZnbG1qcGdWL0NHZFdMNG1wNEpkb3VPNTFtNkJBMm1ET2JWYzh4VgppNFJIWE9KNG9hSGFTd1B6MHBuQUxabkJoUnpxV0Q1cGlycVlucjBxSlFDamJDWXF1TmJTU3d4c2JMYVFjanNFCjhiUXk0aGxXaEJNWno3UldOeDg1UTBZSjhWNEhKdXVCZ09MaVg1REFtNDZIbndWUy95MHJyN2JTWThoTXErM2QKTmtrPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg=="), }, - PlatformVersion: sources.PtrString("eks.3"), + PlatformVersion: adapters.PtrString("eks.3"), Tags: map[string]string{}, EncryptionConfig: []types.EncryptionConfig{ { @@ -99,7 +99,7 @@ var ClusterClient = TestClient{ "secrets", }, Provider: &types.Provider{ - KeyArn: sources.PtrString("arn:aws:kms:eu-west-2:801795385023:key/3a478539-9717-4c20-83a5-19989154dc32"), + KeyArn: adapters.PtrString("arn:aws:kms:eu-west-2:801795385023:key/3a478539-9717-4c20-83a5-19989154dc32"), }, }, }, @@ -120,7 +120,7 @@ func TestClusterGetFunc(t *testing.T) { // It doesn't really make sense to test anything other than the linked items // since the attributes are converted automatically - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "iam-role", ExpectedMethod: sdp.QueryMethod_SEARCH, @@ -204,13 +204,13 @@ func TestClusterGetFunc(t *testing.T) { tests.Execute(t, item) } -func TestNewClusterSource(t *testing.T) { +func TestNewClusterAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewClusterSource(client, account, region) + adapter := NewClusterAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/eks/fargate_profile.go b/adapters/eks/fargate_profile.go similarity index 70% rename from sources/eks/fargate_profile.go rename to adapters/eks/fargate_profile.go index 65aa3640..b4f5fec9 100644 --- a/sources/eks/fargate_profile.go +++ b/adapters/eks/fargate_profile.go @@ -5,7 +5,7 @@ import ( "strings" "github.com/aws/aws-sdk-go-v2/service/eks" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -23,7 +23,7 @@ func fargateProfileGetFunc(ctx context.Context, client EKSClient, scope string, } } - attributes, err := sources.ToAttributesWithExclude(out.FargateProfile) + attributes, err := adapters.ToAttributesWithExclude(out.FargateProfile) if err != nil { return nil, err @@ -42,14 +42,14 @@ func fargateProfileGetFunc(ctx context.Context, client EKSClient, scope string, } if out.FargateProfile.PodExecutionRoleArn != nil { - if a, err := sources.ParseARN(*out.FargateProfile.PodExecutionRoleArn); err == nil { + if a, err := adapters.ParseARN(*out.FargateProfile.PodExecutionRoleArn); err == nil { // +overmind:link iam-role item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "iam-role", Method: sdp.QueryMethod_SEARCH, Query: *out.FargateProfile.PodExecutionRoleArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // The execution role will affect the fargate profile @@ -92,14 +92,15 @@ func fargateProfileGetFunc(ctx context.Context, client EKSClient, scope string, // +overmind:terraform:queryMap aws_eks_fargate_profile.arn // +overmind:terraform:method SEARCH -func NewFargateProfileSource(client EKSClient, accountID string, region string) *sources.AlwaysGetSource[*eks.ListFargateProfilesInput, *eks.ListFargateProfilesOutput, *eks.DescribeFargateProfileInput, *eks.DescribeFargateProfileOutput, EKSClient, *eks.Options] { - return &sources.AlwaysGetSource[*eks.ListFargateProfilesInput, *eks.ListFargateProfilesOutput, *eks.DescribeFargateProfileInput, *eks.DescribeFargateProfileOutput, EKSClient, *eks.Options]{ +func NewFargateProfileAdapter(client EKSClient, accountID string, region string) *adapters.AlwaysGetAdapter[*eks.ListFargateProfilesInput, *eks.ListFargateProfilesOutput, *eks.DescribeFargateProfileInput, *eks.DescribeFargateProfileOutput, EKSClient, *eks.Options] { + return &adapters.AlwaysGetAdapter[*eks.ListFargateProfilesInput, *eks.ListFargateProfilesOutput, *eks.DescribeFargateProfileInput, *eks.DescribeFargateProfileOutput, EKSClient, *eks.Options]{ ItemType: "eks-fargate-profile", Client: client, AccountID: accountID, Region: region, DisableList: true, AlwaysSearchARNs: true, + AdapterMetadata: FargateProfileMetadata(), SearchInputMapper: func(scope, query string) (*eks.ListFargateProfilesInput, error) { return &eks.ListFargateProfilesInput{ ClusterName: &query, @@ -123,7 +124,7 @@ func NewFargateProfileSource(client EKSClient, accountID string, region string) ClusterName: &clusterName, } }, - ListFuncPaginatorBuilder: func(client EKSClient, input *eks.ListFargateProfilesInput) sources.Paginator[*eks.ListFargateProfilesOutput, *eks.Options] { + ListFuncPaginatorBuilder: func(client EKSClient, input *eks.ListFargateProfilesInput) adapters.Paginator[*eks.ListFargateProfilesOutput, *eks.Options] { return eks.NewListFargateProfilesPaginator(client, input) }, ListFuncOutputMapper: func(output *eks.ListFargateProfilesOutput, input *eks.ListFargateProfilesInput) ([]*eks.DescribeFargateProfileInput, error) { @@ -141,3 +142,26 @@ func NewFargateProfileSource(client EKSClient, accountID string, region string) GetFunc: fargateProfileGetFunc, } } + +func FargateProfileMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "eks-fargate-profile", + DescriptiveName: "Fargate Profile", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a fargate profile by unique name ({clusterName}/{FargateProfileName})", + ListDescription: "List all fargate profiles", + SearchDescription: "Search for fargate profiles by cluster name", + }, + TerraformMappings: []*sdp.TerraformMapping{ + { + TerraformQueryMap: "aws_eks_fargate_profile.arn", + TerraformMethod: sdp.QueryMethod_SEARCH, + }, + }, + PotentialLinks: []string{"iam-role", "ec2-subnet"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_CONFIGURATION, + } +} diff --git a/sources/eks/fargate_profile_test.go b/adapters/eks/fargate_profile_test.go similarity index 68% rename from sources/eks/fargate_profile_test.go rename to adapters/eks/fargate_profile_test.go index 959e6049..269d7d1f 100644 --- a/sources/eks/fargate_profile_test.go +++ b/adapters/eks/fargate_profile_test.go @@ -7,22 +7,22 @@ import ( "github.com/aws/aws-sdk-go-v2/service/eks" "github.com/aws/aws-sdk-go-v2/service/eks/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) var FargateTestClient = TestClient{ DescribeFargateProfileOutput: &eks.DescribeFargateProfileOutput{ FargateProfile: &types.FargateProfile{ - ClusterName: sources.PtrString("cluster"), - CreatedAt: sources.PtrTime(time.Now()), - FargateProfileArn: sources.PtrString("arn:partition:service:region:account-id:resource-type/resource-id"), - FargateProfileName: sources.PtrString("name"), - PodExecutionRoleArn: sources.PtrString("arn:partition:service::account-id:resource-type/resource-id"), + ClusterName: adapters.PtrString("cluster"), + CreatedAt: adapters.PtrTime(time.Now()), + FargateProfileArn: adapters.PtrString("arn:partition:service:region:account-id:resource-type/resource-id"), + FargateProfileName: adapters.PtrString("name"), + PodExecutionRoleArn: adapters.PtrString("arn:partition:service::account-id:resource-type/resource-id"), Selectors: []types.FargateProfileSelector{ { Labels: map[string]string{}, - Namespace: sources.PtrString("namespace"), + Namespace: adapters.PtrString("namespace"), }, }, Status: types.FargateProfileStatusActive, @@ -47,7 +47,7 @@ func TestFargateProfileGetFunc(t *testing.T) { // It doesn't really make sense to test anything other than the linked items // since the attributes are converted automatically - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "iam-role", ExpectedMethod: sdp.QueryMethod_SEARCH, @@ -65,13 +65,13 @@ func TestFargateProfileGetFunc(t *testing.T) { tests.Execute(t, item) } -func TestNewFargateProfileSource(t *testing.T) { +func TestNewFargateProfileAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewFargateProfileSource(client, account, region) + adapter := NewFargateProfileAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, SkipNotFoundCheck: true, } diff --git a/sources/eks/integration/integration_test.go b/adapters/eks/integration/integration_test.go similarity index 96% rename from sources/eks/integration/integration_test.go rename to adapters/eks/integration/integration_test.go index 33f13535..769fe17c 100644 --- a/sources/eks/integration/integration_test.go +++ b/adapters/eks/integration/integration_test.go @@ -18,7 +18,7 @@ func Teardown(logger *slog.Logger) error { return nil } -func TestIntegrationEKSSomeSource(t *testing.T) { +func TestIntegrationEKSSomeAdapter(t *testing.T) { slog.Info("Running EKS integration test TestSomeSource") } diff --git a/sources/eks/node_group.go b/adapters/eks/node_group.go similarity index 80% rename from sources/eks/node_group.go rename to adapters/eks/node_group.go index 868116be..7ace43dc 100644 --- a/sources/eks/node_group.go +++ b/adapters/eks/node_group.go @@ -5,7 +5,7 @@ import ( "strings" "github.com/aws/aws-sdk-go-v2/service/eks" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -23,7 +23,7 @@ func nodegroupGetFunc(ctx context.Context, client EKSClient, scope string, input } } - attributes, err := sources.ToAttributesWithExclude(out.Nodegroup) + attributes, err := adapters.ToAttributesWithExclude(out.Nodegroup) if err != nil { return nil, err @@ -183,14 +183,15 @@ func nodegroupGetFunc(ctx context.Context, client EKSClient, scope string, input // +overmind:terraform:queryMap aws_eks_node_group.arn // +overmind:terraform:method SEARCH -func NewNodegroupSource(client EKSClient, accountID string, region string) *sources.AlwaysGetSource[*eks.ListNodegroupsInput, *eks.ListNodegroupsOutput, *eks.DescribeNodegroupInput, *eks.DescribeNodegroupOutput, EKSClient, *eks.Options] { - return &sources.AlwaysGetSource[*eks.ListNodegroupsInput, *eks.ListNodegroupsOutput, *eks.DescribeNodegroupInput, *eks.DescribeNodegroupOutput, EKSClient, *eks.Options]{ +func NewNodegroupAdapter(client EKSClient, accountID string, region string) *adapters.AlwaysGetAdapter[*eks.ListNodegroupsInput, *eks.ListNodegroupsOutput, *eks.DescribeNodegroupInput, *eks.DescribeNodegroupOutput, EKSClient, *eks.Options] { + return &adapters.AlwaysGetAdapter[*eks.ListNodegroupsInput, *eks.ListNodegroupsOutput, *eks.DescribeNodegroupInput, *eks.DescribeNodegroupOutput, EKSClient, *eks.Options]{ ItemType: "eks-nodegroup", Client: client, AccountID: accountID, Region: region, DisableList: true, AlwaysSearchARNs: true, + AdapterMetadata: NodeGroupMetadata(), SearchInputMapper: func(scope, query string) (*eks.ListNodegroupsInput, error) { return &eks.ListNodegroupsInput{ ClusterName: &query, @@ -214,7 +215,7 @@ func NewNodegroupSource(client EKSClient, accountID string, region string) *sour ClusterName: &clusterName, } }, - ListFuncPaginatorBuilder: func(client EKSClient, input *eks.ListNodegroupsInput) sources.Paginator[*eks.ListNodegroupsOutput, *eks.Options] { + ListFuncPaginatorBuilder: func(client EKSClient, input *eks.ListNodegroupsInput) adapters.Paginator[*eks.ListNodegroupsOutput, *eks.Options] { return eks.NewListNodegroupsPaginator(client, input) }, ListFuncOutputMapper: func(output *eks.ListNodegroupsOutput, input *eks.ListNodegroupsInput) ([]*eks.DescribeNodegroupInput, error) { @@ -232,3 +233,26 @@ func NewNodegroupSource(client EKSClient, accountID string, region string) *sour GetFunc: nodegroupGetFunc, } } + +func NodeGroupMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "eks-nodegroup", + DescriptiveName: "EKS Nodegroup", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a node group by unique name ({clusterName}/{NodegroupName})", + ListDescription: "List all node groups", + SearchDescription: "Search for node groups by cluster name", + }, + TerraformMappings: []*sdp.TerraformMapping{ + { + TerraformQueryMap: "aws_eks_node_group.arn", + TerraformMethod: sdp.QueryMethod_SEARCH, + }, + }, + PotentialLinks: []string{"ec2-key-pair", "ec2-security-group", "ec2-subnet", "autoscaling-auto-scaling-group", "ec2-launch-template"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_COMPUTE_APPLICATION, + } +} diff --git a/sources/eks/node_group_test.go b/adapters/eks/node_group_test.go similarity index 63% rename from sources/eks/node_group_test.go rename to adapters/eks/node_group_test.go index ae6ba022..954cbf80 100644 --- a/sources/eks/node_group_test.go +++ b/adapters/eks/node_group_test.go @@ -7,33 +7,33 @@ import ( "github.com/aws/aws-sdk-go-v2/service/eks" "github.com/aws/aws-sdk-go-v2/service/eks/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) var NodeGroupClient = TestClient{ DescribeNodegroupOutput: &eks.DescribeNodegroupOutput{ Nodegroup: &types.Nodegroup{ - NodegroupName: sources.PtrString("default-2022122213523169820000001f"), - NodegroupArn: sources.PtrString("arn:aws:eks:eu-west-2:801795385023:nodegroup/dylan/default-2022122213523169820000001f/98c29d0d-b22a-aaa3-445e-ebf71d43f67c"), - ClusterName: sources.PtrString("dylan"), - Version: sources.PtrString("1.24"), - ReleaseVersion: sources.PtrString("1.24.7-20221112"), - CreatedAt: sources.PtrTime(time.Now()), - ModifiedAt: sources.PtrTime(time.Now()), + NodegroupName: adapters.PtrString("default-2022122213523169820000001f"), + NodegroupArn: adapters.PtrString("arn:aws:eks:eu-west-2:801795385023:nodegroup/dylan/default-2022122213523169820000001f/98c29d0d-b22a-aaa3-445e-ebf71d43f67c"), + ClusterName: adapters.PtrString("dylan"), + Version: adapters.PtrString("1.24"), + ReleaseVersion: adapters.PtrString("1.24.7-20221112"), + CreatedAt: adapters.PtrTime(time.Now()), + ModifiedAt: adapters.PtrTime(time.Now()), Status: types.NodegroupStatusActive, CapacityType: types.CapacityTypesOnDemand, - DiskSize: sources.PtrInt32(100), + DiskSize: adapters.PtrInt32(100), RemoteAccess: &types.RemoteAccessConfig{ - Ec2SshKey: sources.PtrString("key"), // link + Ec2SshKey: adapters.PtrString("key"), // link SourceSecurityGroups: []string{ "sg1", // link }, }, ScalingConfig: &types.NodegroupScalingConfig{ - MinSize: sources.PtrInt32(1), - MaxSize: sources.PtrInt32(3), - DesiredSize: sources.PtrInt32(1), + MinSize: adapters.PtrInt32(1), + MaxSize: adapters.PtrInt32(3), + DesiredSize: adapters.PtrInt32(1), }, InstanceTypes: []string{ "T3large", @@ -42,33 +42,33 @@ var NodeGroupClient = TestClient{ "subnet0d1fabfe6794b5543", // link }, AmiType: types.AMITypesAl2Arm64, - NodeRole: sources.PtrString("arn:aws:iam::801795385023:role/default-eks-node-group-20221222134106992000000003"), + NodeRole: adapters.PtrString("arn:aws:iam::801795385023:role/default-eks-node-group-20221222134106992000000003"), Labels: map[string]string{}, Taints: []types.Taint{ { Effect: types.TaintEffectNoSchedule, - Key: sources.PtrString("key"), - Value: sources.PtrString("value"), + Key: adapters.PtrString("key"), + Value: adapters.PtrString("value"), }, }, Resources: &types.NodegroupResources{ AutoScalingGroups: []types.AutoScalingGroup{ { - Name: sources.PtrString("eks-default-2022122213523169820000001f-98c29d0d-b22a-aaa3-445e-ebf71d43f67c"), // link + Name: adapters.PtrString("eks-default-2022122213523169820000001f-98c29d0d-b22a-aaa3-445e-ebf71d43f67c"), // link }, }, - RemoteAccessSecurityGroup: sources.PtrString("sg2"), // link + RemoteAccessSecurityGroup: adapters.PtrString("sg2"), // link }, Health: &types.NodegroupHealth{ Issues: []types.Issue{}, }, UpdateConfig: &types.NodegroupUpdateConfig{ - MaxUnavailablePercentage: sources.PtrInt32(33), + MaxUnavailablePercentage: adapters.PtrInt32(33), }, LaunchTemplate: &types.LaunchTemplateSpecification{ - Name: sources.PtrString("default-2022122213523100410000001d"), // link - Version: sources.PtrString("1"), - Id: sources.PtrString("lt-097e994ce7e14fcdc"), + Name: adapters.PtrString("default-2022122213523100410000001d"), // link + Version: adapters.PtrString("1"), + Id: adapters.PtrString("lt-097e994ce7e14fcdc"), }, Tags: map[string]string{}, }, @@ -88,7 +88,7 @@ func TestNodegroupGetFunc(t *testing.T) { // It doesn't really make sense to test anything other than the linked items // since the attributes are converted automatically - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "ec2-key-pair", ExpectedMethod: sdp.QueryMethod_GET, @@ -130,13 +130,13 @@ func TestNodegroupGetFunc(t *testing.T) { tests.Execute(t, item) } -func TestNewNodegroupSource(t *testing.T) { +func TestNewNodegroupAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewNodegroupSource(client, account, region) + adapter := NewNodegroupAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, SkipNotFoundCheck: true, } diff --git a/sources/eks/shared_test.go b/adapters/eks/shared_test.go similarity index 68% rename from sources/eks/shared_test.go rename to adapters/eks/shared_test.go index 2e1ef0bf..1f981c1c 100644 --- a/sources/eks/shared_test.go +++ b/adapters/eks/shared_test.go @@ -4,11 +4,11 @@ import ( "testing" "github.com/aws/aws-sdk-go-v2/service/eks" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" ) func GetAutoConfig(t *testing.T) (*eks.Client, string, string) { - config, account, region := sources.GetAutoConfig(t) + config, account, region := adapters.GetAutoConfig(t) client := eks.NewFromConfig(config) return client, account, region diff --git a/sources/elb/elb.go b/adapters/elb/elb.go similarity index 80% rename from sources/elb/elb.go rename to adapters/elb/elb.go index be2758f8..d2ba2b06 100644 --- a/sources/elb/elb.go +++ b/adapters/elb/elb.go @@ -5,7 +5,7 @@ import ( elb "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing" "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -54,7 +54,7 @@ func loadBalancerOutputMapper(ctx context.Context, client elbClient, scope strin } for _, desc := range output.LoadBalancerDescriptions { - attrs, err := sources.ToAttributesWithExclude(desc) + attrs, err := adapters.ToAttributesWithExclude(desc) if err != nil { return nil, err @@ -195,12 +195,13 @@ func loadBalancerOutputMapper(ctx context.Context, client elbClient, scope strin // +overmind:terraform:queryMap aws_elb.arn // +overmind:terraform:method SEARCH -func NewLoadBalancerSource(client elbClient, accountID string, region string) *sources.DescribeOnlySource[*elb.DescribeLoadBalancersInput, *elb.DescribeLoadBalancersOutput, elbClient, *elb.Options] { - return &sources.DescribeOnlySource[*elb.DescribeLoadBalancersInput, *elb.DescribeLoadBalancersOutput, elbClient, *elb.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "elb-load-balancer", +func NewLoadBalancerAdapter(client elbClient, accountID string, region string) *adapters.DescribeOnlyAdapter[*elb.DescribeLoadBalancersInput, *elb.DescribeLoadBalancersOutput, elbClient, *elb.Options] { + return &adapters.DescribeOnlyAdapter[*elb.DescribeLoadBalancersInput, *elb.DescribeLoadBalancersOutput, elbClient, *elb.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "elb-load-balancer", + AdapterMetadata: LoadBalancerMetadata(), DescribeFunc: func(ctx context.Context, client elbClient, input *elb.DescribeLoadBalancersInput) (*elb.DescribeLoadBalancersOutput, error) { return client.DescribeLoadBalancers(ctx, input) }, @@ -212,9 +213,32 @@ func NewLoadBalancerSource(client elbClient, accountID string, region string) *s InputMapperList: func(scope string) (*elb.DescribeLoadBalancersInput, error) { return &elb.DescribeLoadBalancersInput{}, nil }, - PaginatorBuilder: func(client elbClient, params *elb.DescribeLoadBalancersInput) sources.Paginator[*elb.DescribeLoadBalancersOutput, *elb.Options] { + PaginatorBuilder: func(client elbClient, params *elb.DescribeLoadBalancersInput) adapters.Paginator[*elb.DescribeLoadBalancersOutput, *elb.Options] { return elb.NewDescribeLoadBalancersPaginator(client, params) }, OutputMapper: loadBalancerOutputMapper, } } + +func LoadBalancerMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "elb-load-balancer", + DescriptiveName: "Classic Load Balancer", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a classic load balancer by name", + ListDescription: "List all classic load balancers", + SearchDescription: "Search for classic load balancers by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + { + TerraformQueryMap: "aws_elb.arn", + TerraformMethod: sdp.QueryMethod_SEARCH, + }, + }, + PotentialLinks: []string{"dns", "route53-hosted-zone", "ec2-subnet", "ec2-vpc", "ec2-instance", "elb-instance-health", "ec2-security-group"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + } +} diff --git a/sources/elb/elb_test.go b/adapters/elb/elb_test.go similarity index 68% rename from sources/elb/elb_test.go rename to adapters/elb/elb_test.go index f130e654..5dd7dc23 100644 --- a/sources/elb/elb_test.go +++ b/adapters/elb/elb_test.go @@ -7,7 +7,7 @@ import ( elb "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing" "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -17,11 +17,11 @@ func (m mockElbClient) DescribeTags(ctx context.Context, params *elb.DescribeTag return &elb.DescribeTagsOutput{ TagDescriptions: []types.TagDescription{ { - LoadBalancerName: sources.PtrString("a8c3c8851f0df43fda89797c8e941a91"), + LoadBalancerName: adapters.PtrString("a8c3c8851f0df43fda89797c8e941a91"), Tags: []types.Tag{ { - Key: sources.PtrString("foo"), - Value: sources.PtrString("bar"), + Key: adapters.PtrString("foo"), + Value: adapters.PtrString("bar"), }, }, }, @@ -37,35 +37,35 @@ func TestLoadBalancerOutputMapper(t *testing.T) { output := &elb.DescribeLoadBalancersOutput{ LoadBalancerDescriptions: []types.LoadBalancerDescription{ { - LoadBalancerName: sources.PtrString("a8c3c8851f0df43fda89797c8e941a91"), - DNSName: sources.PtrString("a8c3c8851f0df43fda89797c8e941a91-182843316.eu-west-2.elb.amazonaws.com"), // link - CanonicalHostedZoneName: sources.PtrString("a8c3c8851f0df43fda89797c8e941a91-182843316.eu-west-2.elb.amazonaws.com"), // link - CanonicalHostedZoneNameID: sources.PtrString("ZHURV8PSTC4K8"), // link + LoadBalancerName: adapters.PtrString("a8c3c8851f0df43fda89797c8e941a91"), + DNSName: adapters.PtrString("a8c3c8851f0df43fda89797c8e941a91-182843316.eu-west-2.elb.amazonaws.com"), // link + CanonicalHostedZoneName: adapters.PtrString("a8c3c8851f0df43fda89797c8e941a91-182843316.eu-west-2.elb.amazonaws.com"), // link + CanonicalHostedZoneNameID: adapters.PtrString("ZHURV8PSTC4K8"), // link ListenerDescriptions: []types.ListenerDescription{ { Listener: &types.Listener{ - Protocol: sources.PtrString("TCP"), + Protocol: adapters.PtrString("TCP"), LoadBalancerPort: 7687, - InstanceProtocol: sources.PtrString("TCP"), - InstancePort: sources.PtrInt32(30133), + InstanceProtocol: adapters.PtrString("TCP"), + InstancePort: adapters.PtrInt32(30133), }, PolicyNames: []string{}, }, { Listener: &types.Listener{ - Protocol: sources.PtrString("TCP"), + Protocol: adapters.PtrString("TCP"), LoadBalancerPort: 7473, - InstanceProtocol: sources.PtrString("TCP"), - InstancePort: sources.PtrInt32(31459), + InstanceProtocol: adapters.PtrString("TCP"), + InstancePort: adapters.PtrInt32(31459), }, PolicyNames: []string{}, }, { Listener: &types.Listener{ - Protocol: sources.PtrString("TCP"), + Protocol: adapters.PtrString("TCP"), LoadBalancerPort: 7474, - InstanceProtocol: sources.PtrString("TCP"), - InstancePort: sources.PtrInt32(30761), + InstanceProtocol: adapters.PtrString("TCP"), + InstancePort: adapters.PtrInt32(30761), }, PolicyNames: []string{}, }, @@ -73,21 +73,21 @@ func TestLoadBalancerOutputMapper(t *testing.T) { Policies: &types.Policies{ AppCookieStickinessPolicies: []types.AppCookieStickinessPolicy{ { - CookieName: sources.PtrString("foo"), - PolicyName: sources.PtrString("policy"), + CookieName: adapters.PtrString("foo"), + PolicyName: adapters.PtrString("policy"), }, }, LBCookieStickinessPolicies: []types.LBCookieStickinessPolicy{ { - CookieExpirationPeriod: sources.PtrInt64(10), - PolicyName: sources.PtrString("name"), + CookieExpirationPeriod: adapters.PtrInt64(10), + PolicyName: adapters.PtrString("name"), }, }, OtherPolicies: []string{}, }, BackendServerDescriptions: []types.BackendServerDescription{ { - InstancePort: sources.PtrInt32(443), + InstancePort: adapters.PtrInt32(443), PolicyNames: []string{}, }, }, @@ -101,28 +101,28 @@ func TestLoadBalancerOutputMapper(t *testing.T) { "subnet09d5f6fa75b0b4569", "subnet0e234bef35fc4a9e1", }, - VPCId: sources.PtrString("vpc-0c72199250cd479ea"), // link + VPCId: adapters.PtrString("vpc-0c72199250cd479ea"), // link Instances: []types.Instance{ { - InstanceId: sources.PtrString("i-0337802d908b4a81e"), // link *2 to ec2-instance and health + InstanceId: adapters.PtrString("i-0337802d908b4a81e"), // link *2 to ec2-instance and health }, }, HealthCheck: &types.HealthCheck{ - Target: sources.PtrString("HTTP:31151/healthz"), - Interval: sources.PtrInt32(10), - Timeout: sources.PtrInt32(5), - UnhealthyThreshold: sources.PtrInt32(6), - HealthyThreshold: sources.PtrInt32(2), + Target: adapters.PtrString("HTTP:31151/healthz"), + Interval: adapters.PtrInt32(10), + Timeout: adapters.PtrInt32(5), + UnhealthyThreshold: adapters.PtrInt32(6), + HealthyThreshold: adapters.PtrInt32(2), }, SourceSecurityGroup: &types.SourceSecurityGroup{ - OwnerAlias: sources.PtrString("944651592624"), - GroupName: sources.PtrString("k8s-elb-a8c3c8851f0df43fda89797c8e941a91"), // link + OwnerAlias: adapters.PtrString("944651592624"), + GroupName: adapters.PtrString("k8s-elb-a8c3c8851f0df43fda89797c8e941a91"), // link }, SecurityGroups: []string{ "sg097e3cfdfc6d53b77", // link }, - CreatedTime: sources.PtrTime(time.Now()), - Scheme: sources.PtrString("internet-facing"), + CreatedTime: adapters.PtrTime(time.Now()), + Scheme: adapters.PtrString("internet-facing"), }, }, } @@ -151,7 +151,7 @@ func TestLoadBalancerOutputMapper(t *testing.T) { // It doesn't really make sense to test anything other than the linked items // since the attributes are converted automatically - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "dns", ExpectedMethod: sdp.QueryMethod_SEARCH, diff --git a/sources/elb/instance_health.go b/adapters/elb/instance_health.go similarity index 74% rename from sources/elb/instance_health.go rename to adapters/elb/instance_health.go index ab86d60a..f5b808a3 100644 --- a/sources/elb/instance_health.go +++ b/adapters/elb/instance_health.go @@ -10,7 +10,7 @@ import ( elb "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing" "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -42,7 +42,7 @@ func instanceHealthOutputMapper(_ context.Context, _ *elb.Client, scope string, items := make([]*sdp.Item, 0) for _, is := range output.InstanceStates { - attrs, err := sources.ToAttributesWithExclude(is) + attrs, err := adapters.ToAttributesWithExclude(is) if err != nil { return nil, err @@ -96,12 +96,13 @@ func instanceHealthOutputMapper(_ context.Context, _ *elb.Client, scope string, // +overmind:list List all instance healths // +overmind:group AWS -func NewInstanceHealthSource(client *elasticloadbalancing.Client, accountID string, region string) *sources.DescribeOnlySource[*elb.DescribeInstanceHealthInput, *elb.DescribeInstanceHealthOutput, *elb.Client, *elb.Options] { - return &sources.DescribeOnlySource[*elb.DescribeInstanceHealthInput, *elb.DescribeInstanceHealthOutput, *elb.Client, *elb.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "elb-instance-health", +func NewInstanceHealthAdapter(client *elasticloadbalancing.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*elb.DescribeInstanceHealthInput, *elb.DescribeInstanceHealthOutput, *elb.Client, *elb.Options] { + return &adapters.DescribeOnlyAdapter[*elb.DescribeInstanceHealthInput, *elb.DescribeInstanceHealthOutput, *elb.Client, *elb.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "elb-instance-health", + AdapterMetadata: InstanceHealthMetadata(), DescribeFunc: func(ctx context.Context, client *elb.Client, input *elb.DescribeInstanceHealthInput) (*elb.DescribeInstanceHealthOutput, error) { return client.DescribeInstanceHealth(ctx, input) }, @@ -131,3 +132,18 @@ func NewInstanceHealthSource(client *elasticloadbalancing.Client, accountID stri OutputMapper: instanceHealthOutputMapper, } } + +func InstanceHealthMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "elb-instance-health", + DescriptiveName: "ELB Instance Health", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + GetDescription: "Get instance health by ID ({LoadBalancerName}/{InstanceId})", + ListDescription: "List all instance healths", + }, + PotentialLinks: []string{"ec2-instance"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_OBSERVABILITY, + } +} diff --git a/sources/elb/instance_health_test.go b/adapters/elb/instance_health_test.go similarity index 77% rename from sources/elb/instance_health_test.go rename to adapters/elb/instance_health_test.go index cbf8bdb1..e3bee93c 100644 --- a/sources/elb/instance_health_test.go +++ b/adapters/elb/instance_health_test.go @@ -6,7 +6,7 @@ import ( elb "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing" "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -15,10 +15,10 @@ func TestInstanceHealthOutputMapper(t *testing.T) { output := elb.DescribeInstanceHealthOutput{ InstanceStates: []types.InstanceState{ { - InstanceId: sources.PtrString("i-0337802d908b4a81e"), // link - State: sources.PtrString("InService"), - ReasonCode: sources.PtrString("N/A"), - Description: sources.PtrString("N/A"), + InstanceId: adapters.PtrString("i-0337802d908b4a81e"), // link + State: adapters.PtrString("InService"), + ReasonCode: adapters.PtrString("N/A"), + Description: adapters.PtrString("N/A"), }, }, } @@ -43,7 +43,7 @@ func TestInstanceHealthOutputMapper(t *testing.T) { // It doesn't really make sense to test anything other than the linked items // since the attributes are converted automatically - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "ec2-instance", ExpectedMethod: sdp.QueryMethod_GET, diff --git a/sources/elbv2/action.go b/adapters/elbv2/action.go similarity index 90% rename from sources/elbv2/action.go rename to adapters/elbv2/action.go index a9a4763f..30c58d00 100644 --- a/sources/elbv2/action.go +++ b/adapters/elbv2/action.go @@ -5,7 +5,7 @@ import ( "net/url" "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -14,13 +14,13 @@ func ActionToRequests(action types.Action) []*sdp.LinkedItemQuery { if action.AuthenticateCognitoConfig != nil { if action.AuthenticateCognitoConfig.UserPoolArn != nil { - if a, err := sources.ParseARN(*action.AuthenticateCognitoConfig.UserPoolArn); err == nil { + if a, err := adapters.ParseARN(*action.AuthenticateCognitoConfig.UserPoolArn); err == nil { requests = append(requests, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "cognito-idp-user-pool", Method: sdp.QueryMethod_SEARCH, Query: *action.AuthenticateCognitoConfig.UserPoolArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changing the user pool could affect the LB @@ -89,13 +89,13 @@ func ActionToRequests(action types.Action) []*sdp.LinkedItemQuery { if action.ForwardConfig != nil { for _, tg := range action.ForwardConfig.TargetGroups { if tg.TargetGroupArn != nil { - if a, err := sources.ParseARN(*tg.TargetGroupArn); err == nil { + if a, err := adapters.ParseARN(*tg.TargetGroupArn); err == nil { requests = append(requests, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "elbv2-target-group", Method: sdp.QueryMethod_SEARCH, Query: *tg.TargetGroupArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changing the target group could affect the LB @@ -154,13 +154,13 @@ func ActionToRequests(action types.Action) []*sdp.LinkedItemQuery { } if action.TargetGroupArn != nil { - if a, err := sources.ParseARN(*action.TargetGroupArn); err == nil { + if a, err := adapters.ParseARN(*action.TargetGroupArn); err == nil { requests = append(requests, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "elbv2-target-group", Method: sdp.QueryMethod_SEARCH, Query: *action.TargetGroupArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // These are closely linked diff --git a/sources/elbv2/action_test.go b/adapters/elbv2/action_test.go similarity index 54% rename from sources/elbv2/action_test.go rename to adapters/elbv2/action_test.go index a68eda78..280867ac 100644 --- a/sources/elbv2/action_test.go +++ b/adapters/elbv2/action_test.go @@ -4,66 +4,66 @@ import ( "testing" "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) func TestActionToRequests(t *testing.T) { action := types.Action{ Type: types.ActionTypeEnumFixedResponse, - Order: sources.PtrInt32(1), + Order: adapters.PtrInt32(1), FixedResponseConfig: &types.FixedResponseActionConfig{ - StatusCode: sources.PtrString("404"), - ContentType: sources.PtrString("text/plain"), - MessageBody: sources.PtrString("not found"), + StatusCode: adapters.PtrString("404"), + ContentType: adapters.PtrString("text/plain"), + MessageBody: adapters.PtrString("not found"), }, AuthenticateCognitoConfig: &types.AuthenticateCognitoActionConfig{ - UserPoolArn: sources.PtrString("arn:partition:service:region:account-id:resource-type:resource-id"), // link - UserPoolClientId: sources.PtrString("clientID"), - UserPoolDomain: sources.PtrString("domain.com"), + UserPoolArn: adapters.PtrString("arn:partition:service:region:account-id:resource-type:resource-id"), // link + UserPoolClientId: adapters.PtrString("clientID"), + UserPoolDomain: adapters.PtrString("domain.com"), AuthenticationRequestExtraParams: map[string]string{ "foo": "bar", }, OnUnauthenticatedRequest: types.AuthenticateCognitoActionConditionalBehaviorEnumAuthenticate, - Scope: sources.PtrString("foo"), - SessionCookieName: sources.PtrString("cookie"), - SessionTimeout: sources.PtrInt64(10), + Scope: adapters.PtrString("foo"), + SessionCookieName: adapters.PtrString("cookie"), + SessionTimeout: adapters.PtrInt64(10), }, AuthenticateOidcConfig: &types.AuthenticateOidcActionConfig{ - AuthorizationEndpoint: sources.PtrString("https://auth.somewhere.com/app1"), // link - ClientId: sources.PtrString("CLIENT-ID"), - Issuer: sources.PtrString("Someone"), - TokenEndpoint: sources.PtrString("https://auth.somewhere.com/app1/tokens"), // link - UserInfoEndpoint: sources.PtrString("https://auth.somewhere.com/app1/users"), // link + AuthorizationEndpoint: adapters.PtrString("https://auth.somewhere.com/app1"), // link + ClientId: adapters.PtrString("CLIENT-ID"), + Issuer: adapters.PtrString("Someone"), + TokenEndpoint: adapters.PtrString("https://auth.somewhere.com/app1/tokens"), // link + UserInfoEndpoint: adapters.PtrString("https://auth.somewhere.com/app1/users"), // link AuthenticationRequestExtraParams: map[string]string{}, - ClientSecret: sources.PtrString("secret"), // Redact + ClientSecret: adapters.PtrString("secret"), // Redact OnUnauthenticatedRequest: types.AuthenticateOidcActionConditionalBehaviorEnumAllow, - Scope: sources.PtrString("foo"), - SessionCookieName: sources.PtrString("cookie"), - SessionTimeout: sources.PtrInt64(10), - UseExistingClientSecret: sources.PtrBool(true), + Scope: adapters.PtrString("foo"), + SessionCookieName: adapters.PtrString("cookie"), + SessionTimeout: adapters.PtrInt64(10), + UseExistingClientSecret: adapters.PtrBool(true), }, ForwardConfig: &types.ForwardActionConfig{ TargetGroupStickinessConfig: &types.TargetGroupStickinessConfig{ - DurationSeconds: sources.PtrInt32(10), - Enabled: sources.PtrBool(true), + DurationSeconds: adapters.PtrInt32(10), + Enabled: adapters.PtrBool(true), }, TargetGroups: []types.TargetGroupTuple{ { - TargetGroupArn: sources.PtrString("arn:partition:service:region:account-id:resource-type:resource-id1"), // link - Weight: sources.PtrInt32(1), + TargetGroupArn: adapters.PtrString("arn:partition:service:region:account-id:resource-type:resource-id1"), // link + Weight: adapters.PtrInt32(1), }, }, }, RedirectConfig: &types.RedirectActionConfig{ StatusCode: types.RedirectActionStatusCodeEnumHttp302, - Host: sources.PtrString("somewhere.else.com"), // combine and link - Path: sources.PtrString("/login"), // combine and link - Port: sources.PtrString("8080"), // combine and link - Protocol: sources.PtrString("https"), // combine and link - Query: sources.PtrString("foo=bar"), // combine and link + Host: adapters.PtrString("somewhere.else.com"), // combine and link + Path: adapters.PtrString("/login"), // combine and link + Port: adapters.PtrString("8080"), // combine and link + Protocol: adapters.PtrString("https"), // combine and link + Query: adapters.PtrString("foo=bar"), // combine and link }, - TargetGroupArn: sources.PtrString("arn:partition:service:region:account-id:resource-type:resource-id2"), // link + TargetGroupArn: adapters.PtrString("arn:partition:service:region:account-id:resource-type:resource-id2"), // link } item := sdp.Item{ @@ -74,7 +74,7 @@ func TestActionToRequests(t *testing.T) { LinkedItemQueries: ActionToRequests(action), } - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "cognito-idp-user-pool", ExpectedMethod: sdp.QueryMethod_SEARCH, diff --git a/sources/elbv2/elb.go b/adapters/elbv2/elb.go similarity index 82% rename from sources/elbv2/elb.go rename to adapters/elbv2/elb.go index b6c09e11..706e6c34 100644 --- a/sources/elbv2/elb.go +++ b/adapters/elbv2/elb.go @@ -5,7 +5,7 @@ import ( elbv2 "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -24,7 +24,7 @@ func loadBalancerOutputMapper(ctx context.Context, client elbClient, scope strin tagsMap := getTagsMap(ctx, client, arns) for _, lb := range output.LoadBalancers { - attrs, err := sources.ToAttributesWithExclude(lb) + attrs, err := adapters.ToAttributesWithExclude(lb) if err != nil { return nil, err @@ -273,12 +273,13 @@ func loadBalancerOutputMapper(ctx context.Context, client elbClient, scope strin // +overmind:terraform:queryMap aws_lb.id // +overmind:terraform:method SEARCH -func NewLoadBalancerSource(client elbClient, accountID string, region string) *sources.DescribeOnlySource[*elbv2.DescribeLoadBalancersInput, *elbv2.DescribeLoadBalancersOutput, elbClient, *elbv2.Options] { - return &sources.DescribeOnlySource[*elbv2.DescribeLoadBalancersInput, *elbv2.DescribeLoadBalancersOutput, elbClient, *elbv2.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "elbv2-load-balancer", +func NewLoadBalancerAdapter(client elbClient, accountID string, region string) *adapters.DescribeOnlyAdapter[*elbv2.DescribeLoadBalancersInput, *elbv2.DescribeLoadBalancersOutput, elbClient, *elbv2.Options] { + return &adapters.DescribeOnlyAdapter[*elbv2.DescribeLoadBalancersInput, *elbv2.DescribeLoadBalancersOutput, elbClient, *elbv2.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "elbv2-load-balancer", + AdapterMetadata: LoadBalancerMetadata(), DescribeFunc: func(ctx context.Context, client elbClient, input *elbv2.DescribeLoadBalancersInput) (*elbv2.DescribeLoadBalancersOutput, error) { return client.DescribeLoadBalancers(ctx, input) }, @@ -295,9 +296,36 @@ func NewLoadBalancerSource(client elbClient, accountID string, region string) *s LoadBalancerArns: []string{query}, }, nil }, - PaginatorBuilder: func(client elbClient, params *elbv2.DescribeLoadBalancersInput) sources.Paginator[*elbv2.DescribeLoadBalancersOutput, *elbv2.Options] { + PaginatorBuilder: func(client elbClient, params *elbv2.DescribeLoadBalancersInput) adapters.Paginator[*elbv2.DescribeLoadBalancersOutput, *elbv2.Options] { return elbv2.NewDescribeLoadBalancersPaginator(client, params) }, OutputMapper: loadBalancerOutputMapper, } } + +func LoadBalancerMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "elbv2-load-balancer", + DescriptiveName: "Elastic Load Balancer", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get an ELB by name", + ListDescription: "List all ELBs", + SearchDescription: "Search for ELBs by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + { + TerraformQueryMap: "aws_lb.arn", + TerraformMethod: sdp.QueryMethod_SEARCH, + }, + { + TerraformQueryMap: "aws_lb.id", + TerraformMethod: sdp.QueryMethod_GET, + }, + }, + PotentialLinks: []string{"elbv2-target-group", "elbv2-listener", "dns", "route53-hosted-zone", "ec2-vpc", "ec2-subnet", "ec2-address", "ip", "ec2-security-group", "ec2-coip-pool"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + } +} diff --git a/sources/elbv2/elb_test.go b/adapters/elbv2/elb_test.go similarity index 73% rename from sources/elbv2/elb_test.go rename to adapters/elbv2/elb_test.go index 533da1b4..8d29ff12 100644 --- a/sources/elbv2/elb_test.go +++ b/adapters/elbv2/elb_test.go @@ -7,7 +7,7 @@ import ( elbv2 "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2" "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -15,38 +15,38 @@ func TestLoadBalancerOutputMapper(t *testing.T) { output := elbv2.DescribeLoadBalancersOutput{ LoadBalancers: []types.LoadBalancer{ { - LoadBalancerArn: sources.PtrString("arn:aws:elasticloadbalancing:eu-west-2:944651592624:loadbalancer/app/ingress/1bf10920c5bd199d"), - DNSName: sources.PtrString("ingress-1285969159.eu-west-2.elb.amazonaws.com"), // link - CanonicalHostedZoneId: sources.PtrString("ZHURV8PSTC4K8"), // link - CreatedTime: sources.PtrTime(time.Now()), - LoadBalancerName: sources.PtrString("ingress"), + LoadBalancerArn: adapters.PtrString("arn:aws:elasticloadbalancing:eu-west-2:944651592624:loadbalancer/app/ingress/1bf10920c5bd199d"), + DNSName: adapters.PtrString("ingress-1285969159.eu-west-2.elb.amazonaws.com"), // link + CanonicalHostedZoneId: adapters.PtrString("ZHURV8PSTC4K8"), // link + CreatedTime: adapters.PtrTime(time.Now()), + LoadBalancerName: adapters.PtrString("ingress"), Scheme: types.LoadBalancerSchemeEnumInternetFacing, - VpcId: sources.PtrString("vpc-0c72199250cd479ea"), // link + VpcId: adapters.PtrString("vpc-0c72199250cd479ea"), // link State: &types.LoadBalancerState{ Code: types.LoadBalancerStateEnumActive, - Reason: sources.PtrString("reason"), + Reason: adapters.PtrString("reason"), }, Type: types.LoadBalancerTypeEnumApplication, AvailabilityZones: []types.AvailabilityZone{ { - ZoneName: sources.PtrString("eu-west-2b"), // link - SubnetId: sources.PtrString("subnet-0960234bbc4edca03"), // link + ZoneName: adapters.PtrString("eu-west-2b"), // link + SubnetId: adapters.PtrString("subnet-0960234bbc4edca03"), // link LoadBalancerAddresses: []types.LoadBalancerAddress{ { - AllocationId: sources.PtrString("allocation-id"), // link? - IPv6Address: sources.PtrString(":::1"), // link - IpAddress: sources.PtrString("1.1.1.1"), // link - PrivateIPv4Address: sources.PtrString("10.0.0.1"), // link + AllocationId: adapters.PtrString("allocation-id"), // link? + IPv6Address: adapters.PtrString(":::1"), // link + IpAddress: adapters.PtrString("1.1.1.1"), // link + PrivateIPv4Address: adapters.PtrString("10.0.0.1"), // link }, }, - OutpostId: sources.PtrString("outpost-id"), + OutpostId: adapters.PtrString("outpost-id"), }, }, SecurityGroups: []string{ "sg-0b21edc8578ea3f93", // link }, IpAddressType: types.IpAddressTypeIpv4, - CustomerOwnedIpv4Pool: sources.PtrString("ipv4-pool"), // link + CustomerOwnedIpv4Pool: adapters.PtrString("ipv4-pool"), // link }, }, } @@ -75,7 +75,7 @@ func TestLoadBalancerOutputMapper(t *testing.T) { // It doesn't really make sense to test anything other than the linked items // since the attributes are converted automatically - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "elbv2-target-group", ExpectedMethod: sdp.QueryMethod_SEARCH, diff --git a/sources/elbv2/listener.go b/adapters/elbv2/listener.go similarity index 71% rename from sources/elbv2/listener.go rename to adapters/elbv2/listener.go index 35295bd0..49f27f3b 100644 --- a/sources/elbv2/listener.go +++ b/adapters/elbv2/listener.go @@ -8,7 +8,7 @@ import ( elbv2 "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -37,15 +37,15 @@ func listenerOutputMapper(ctx context.Context, client elbClient, scope string, _ sha := base64.URLEncoding.EncodeToString(h.Sum(nil)) if len(sha) > 12 { - action.AuthenticateOidcConfig.ClientSecret = sources.PtrString(fmt.Sprintf("REDACTED (Version: %v)", sha[:11])) + action.AuthenticateOidcConfig.ClientSecret = adapters.PtrString(fmt.Sprintf("REDACTED (Version: %v)", sha[:11])) } else { - action.AuthenticateOidcConfig.ClientSecret = sources.PtrString("[REDACTED]") + action.AuthenticateOidcConfig.ClientSecret = adapters.PtrString("[REDACTED]") } } } } - attrs, err := sources.ToAttributesWithExclude(listener) + attrs, err := adapters.ToAttributesWithExclude(listener) if err != nil { return nil, err @@ -66,14 +66,14 @@ func listenerOutputMapper(ctx context.Context, client elbClient, scope string, _ } if listener.LoadBalancerArn != nil { - if a, err := sources.ParseARN(*listener.LoadBalancerArn); err == nil { + if a, err := adapters.ParseARN(*listener.LoadBalancerArn); err == nil { // +overmind:link elbv2-load-balancer item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "elbv2-load-balancer", Method: sdp.QueryMethod_SEARCH, Query: *listener.LoadBalancerArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Load balancers and their listeners are tightly coupled @@ -87,7 +87,7 @@ func listenerOutputMapper(ctx context.Context, client elbClient, scope string, _ Type: "elbv2-rule", Method: sdp.QueryMethod_SEARCH, Query: *listener.ListenerArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Tightly coupled @@ -100,14 +100,14 @@ func listenerOutputMapper(ctx context.Context, client elbClient, scope string, _ for _, cert := range listener.Certificates { if cert.CertificateArn != nil { - if a, err := sources.ParseARN(*cert.CertificateArn); err == nil { + if a, err := adapters.ParseARN(*cert.CertificateArn); err == nil { // +overmind:link acm-certificate item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "acm-certificate", Method: sdp.QueryMethod_SEARCH, Query: *cert.CertificateArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changing the cert will affect the LB @@ -148,12 +148,13 @@ func listenerOutputMapper(ctx context.Context, client elbClient, scope string, _ // +overmind:terraform:queryMap aws_lb_listener.arn // +overmind:terraform:method SEARCH -func NewListenerSource(client elbClient, accountID string, region string) *sources.DescribeOnlySource[*elbv2.DescribeListenersInput, *elbv2.DescribeListenersOutput, elbClient, *elbv2.Options] { - return &sources.DescribeOnlySource[*elbv2.DescribeListenersInput, *elbv2.DescribeListenersOutput, elbClient, *elbv2.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "elbv2-listener", +func NewListenerAdapter(client elbClient, accountID string, region string) *adapters.DescribeOnlyAdapter[*elbv2.DescribeListenersInput, *elbv2.DescribeListenersOutput, elbClient, *elbv2.Options] { + return &adapters.DescribeOnlyAdapter[*elbv2.DescribeListenersInput, *elbv2.DescribeListenersOutput, elbClient, *elbv2.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "elbv2-listener", + AdapterMetadata: ListenerMetadata(), DescribeFunc: func(ctx context.Context, client elbClient, input *elbv2.DescribeListenersInput) (*elbv2.DescribeListenersOutput, error) { return client.DescribeListeners(ctx, input) }, @@ -174,9 +175,32 @@ func NewListenerSource(client elbClient, accountID string, region string) *sourc LoadBalancerArn: &query, }, nil }, - PaginatorBuilder: func(client elbClient, params *elbv2.DescribeListenersInput) sources.Paginator[*elbv2.DescribeListenersOutput, *elbv2.Options] { + PaginatorBuilder: func(client elbClient, params *elbv2.DescribeListenersInput) adapters.Paginator[*elbv2.DescribeListenersOutput, *elbv2.Options] { return elbv2.NewDescribeListenersPaginator(client, params) }, OutputMapper: listenerOutputMapper, } } + +func ListenerMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "elbv2-listener", + DescriptiveName: "ELB Listener", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + Search: true, + }, + TerraformMappings: []*sdp.TerraformMapping{ + { + TerraformMethod: sdp.QueryMethod_SEARCH, + TerraformQueryMap: "aws_alb_listener.arn", + }, + { + TerraformMethod: sdp.QueryMethod_SEARCH, + TerraformQueryMap: "aws_lb_listener.arn", + }, + }, + PotentialLinks: []string{"elbv2-load-balancer", "acm-certificate", "elbv2-rule", "cognito-idp-user-pool", "http", "elbv2-target-group"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + } +} diff --git a/sources/elbv2/listener_test.go b/adapters/elbv2/listener_test.go similarity index 74% rename from sources/elbv2/listener_test.go rename to adapters/elbv2/listener_test.go index 80bba123..5b40d0b0 100644 --- a/sources/elbv2/listener_test.go +++ b/adapters/elbv2/listener_test.go @@ -6,7 +6,7 @@ import ( elbv2 "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2" "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -14,17 +14,17 @@ func TestListenerOutputMapper(t *testing.T) { output := elbv2.DescribeListenersOutput{ Listeners: []types.Listener{ { - ListenerArn: sources.PtrString("arn:aws:elasticloadbalancing:eu-west-2:944651592624:listener/app/ingress/1bf10920c5bd199d/9d28f512be129134"), - LoadBalancerArn: sources.PtrString("arn:aws:elasticloadbalancing:eu-west-2:944651592624:loadbalancer/app/ingress/1bf10920c5bd199d"), // link - Port: sources.PtrInt32(443), + ListenerArn: adapters.PtrString("arn:aws:elasticloadbalancing:eu-west-2:944651592624:listener/app/ingress/1bf10920c5bd199d/9d28f512be129134"), + LoadBalancerArn: adapters.PtrString("arn:aws:elasticloadbalancing:eu-west-2:944651592624:loadbalancer/app/ingress/1bf10920c5bd199d"), // link + Port: adapters.PtrInt32(443), Protocol: types.ProtocolEnumHttps, Certificates: []types.Certificate{ { - CertificateArn: sources.PtrString("arn:aws:acm:eu-west-2:944651592624:certificate/acd84d34-fb78-4411-bd8a-43684a3477c5"), // link - IsDefault: sources.PtrBool(true), + CertificateArn: adapters.PtrString("arn:aws:acm:eu-west-2:944651592624:certificate/acd84d34-fb78-4411-bd8a-43684a3477c5"), // link + IsDefault: adapters.PtrBool(true), }, }, - SslPolicy: sources.PtrString("ELBSecurityPolicy-2016-08"), + SslPolicy: adapters.PtrString("ELBSecurityPolicy-2016-08"), AlpnPolicy: []string{ "policy1", }, @@ -59,7 +59,7 @@ func TestListenerOutputMapper(t *testing.T) { // It doesn't really make sense to test anything other than the linked items // since the attributes are converted automatically - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "elbv2-load-balancer", ExpectedMethod: sdp.QueryMethod_SEARCH, diff --git a/sources/elbv2/rule.go b/adapters/elbv2/rule.go similarity index 69% rename from sources/elbv2/rule.go rename to adapters/elbv2/rule.go index 826d0263..8cedb71a 100644 --- a/sources/elbv2/rule.go +++ b/adapters/elbv2/rule.go @@ -4,7 +4,7 @@ import ( "context" elbv2 "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -22,7 +22,7 @@ func ruleOutputMapper(ctx context.Context, client elbClient, scope string, _ *el tagsMap := getTagsMap(ctx, client, ruleArns) for _, rule := range output.Rules { - attrs, err := sources.ToAttributesWithExclude(rule) + attrs, err := adapters.ToAttributesWithExclude(rule) if err != nil { return nil, err @@ -85,12 +85,13 @@ func ruleOutputMapper(ctx context.Context, client elbClient, scope string, _ *el // +overmind:terraform:queryMap aws_lb_listener_rule.arn // +overmind:terraform:method SEARCH -func NewRuleSource(client elbClient, accountID string, region string) *sources.DescribeOnlySource[*elbv2.DescribeRulesInput, *elbv2.DescribeRulesOutput, elbClient, *elbv2.Options] { - return &sources.DescribeOnlySource[*elbv2.DescribeRulesInput, *elbv2.DescribeRulesOutput, elbClient, *elbv2.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "elbv2-rule", +func NewRuleAdapter(client elbClient, accountID string, region string) *adapters.DescribeOnlyAdapter[*elbv2.DescribeRulesInput, *elbv2.DescribeRulesOutput, elbClient, *elbv2.Options] { + return &adapters.DescribeOnlyAdapter[*elbv2.DescribeRulesInput, *elbv2.DescribeRulesOutput, elbClient, *elbv2.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "elbv2-rule", + AdapterMetadata: RuleMetadata(), DescribeFunc: func(ctx context.Context, client elbClient, input *elbv2.DescribeRulesInput) (*elbv2.DescribeRulesOutput, error) { return client.DescribeRules(ctx, input) }, @@ -114,3 +115,27 @@ func NewRuleSource(client elbClient, accountID string, region string) *sources.D OutputMapper: ruleOutputMapper, } } + +func RuleMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "elbv2-rule", + DescriptiveName: "ELB Rule", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + Search: true, + GetDescription: "Get a rule by ARN", + SearchDescription: "Search for rules by listener ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + { + TerraformQueryMap: "aws_alb_listener_rule.arn", + TerraformMethod: sdp.QueryMethod_SEARCH, + }, + { + TerraformQueryMap: "aws_lb_listener_rule.arn", + TerraformMethod: sdp.QueryMethod_SEARCH, + }, + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_CONFIGURATION, + } +} diff --git a/sources/elbv2/rule_test.go b/adapters/elbv2/rule_test.go similarity index 75% rename from sources/elbv2/rule_test.go rename to adapters/elbv2/rule_test.go index f4402714..c19d4e7b 100644 --- a/sources/elbv2/rule_test.go +++ b/adapters/elbv2/rule_test.go @@ -9,7 +9,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2" elbv2 "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2" "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -17,11 +17,11 @@ func TestRuleOutputMapper(t *testing.T) { output := elbv2.DescribeRulesOutput{ Rules: []types.Rule{ { - RuleArn: sources.PtrString("arn:aws:elasticloadbalancing:eu-west-2:944651592624:listener-rule/app/ingress/1bf10920c5bd199d/9d28f512be129134/0f73a74d21b008f7"), - Priority: sources.PtrString("1"), + RuleArn: adapters.PtrString("arn:aws:elasticloadbalancing:eu-west-2:944651592624:listener-rule/app/ingress/1bf10920c5bd199d/9d28f512be129134/0f73a74d21b008f7"), + Priority: adapters.PtrString("1"), Conditions: []types.RuleCondition{ { - Field: sources.PtrString("path-pattern"), + Field: adapters.PtrString("path-pattern"), Values: []string{ "/api/gateway", }, @@ -36,7 +36,7 @@ func TestRuleOutputMapper(t *testing.T) { }, }, HttpHeaderConfig: &types.HttpHeaderConditionConfig{ - HttpHeaderName: sources.PtrString("SOMETHING"), + HttpHeaderName: adapters.PtrString("SOMETHING"), Values: []string{ "foo", }, @@ -49,8 +49,8 @@ func TestRuleOutputMapper(t *testing.T) { QueryStringConfig: &types.QueryStringConditionConfig{ Values: []types.QueryStringKeyValuePair{ { - Key: sources.PtrString("foo"), - Value: sources.PtrString("bar"), + Key: adapters.PtrString("foo"), + Value: adapters.PtrString("bar"), }, }, }, @@ -64,7 +64,7 @@ func TestRuleOutputMapper(t *testing.T) { Actions: []types.Action{ // Tested in actions.go }, - IsDefault: sources.PtrBool(false), + IsDefault: adapters.PtrBool(false), }, }, } @@ -81,7 +81,7 @@ func TestRuleOutputMapper(t *testing.T) { item := items[0] - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "dns", ExpectedMethod: sdp.QueryMethod_SEARCH, @@ -93,13 +93,13 @@ func TestRuleOutputMapper(t *testing.T) { tests.Execute(t, item) } -func TestNewRuleSource(t *testing.T) { - config, account, region := sources.GetAutoConfig(t) +func TestNewRuleAdapter(t *testing.T) { + config, account, region := adapters.GetAutoConfig(t) client := elasticloadbalancingv2.NewFromConfig(config) - lbSource := NewLoadBalancerSource(client, account, region) - listenerSource := NewListenerSource(client, account, region) - ruleSource := NewRuleSource(client, account, region) + lbSource := NewLoadBalancerAdapter(client, account, region) + listenerSource := NewListenerAdapter(client, account, region) + ruleSource := NewRuleAdapter(client, account, region) lbs, err := lbSource.List(context.Background(), lbSource.Scopes()[0], false) if err != nil { @@ -131,8 +131,8 @@ func TestNewRuleSource(t *testing.T) { goodSearch := fmt.Sprint(listenerARN) - test := sources.E2ETest{ - Source: ruleSource, + test := adapters.E2ETest{ + Adapter: ruleSource, Timeout: 10 * time.Second, GoodSearchQuery: &goodSearch, SkipList: true, diff --git a/sources/elbv2/shared.go b/adapters/elbv2/shared.go similarity index 95% rename from sources/elbv2/shared.go rename to adapters/elbv2/shared.go index 24ab6dfe..f4a5c904 100644 --- a/sources/elbv2/shared.go +++ b/adapters/elbv2/shared.go @@ -5,7 +5,7 @@ import ( elbv2 "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2" "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" ) type elbClient interface { @@ -37,7 +37,7 @@ func getTagsMap(ctx context.Context, client elbClient, arns []string) map[string ResourceArns: arns, }) if err != nil { - tags := sources.HandleTagsError(ctx, err) + tags := adapters.HandleTagsError(ctx, err) // Set these tags for all ARNs for _, arn := range arns { diff --git a/sources/elbv2/shared_test.go b/adapters/elbv2/shared_test.go similarity index 92% rename from sources/elbv2/shared_test.go rename to adapters/elbv2/shared_test.go index db11d2c1..12f6af3f 100644 --- a/sources/elbv2/shared_test.go +++ b/adapters/elbv2/shared_test.go @@ -5,7 +5,7 @@ import ( elbv2 "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2" "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" ) type mockElbClient struct{} @@ -18,8 +18,8 @@ func (m mockElbClient) DescribeTags(ctx context.Context, params *elbv2.DescribeT ResourceArn: &arn, Tags: []types.Tag{ { - Key: sources.PtrString("foo"), - Value: sources.PtrString("bar"), + Key: adapters.PtrString("foo"), + Value: adapters.PtrString("bar"), }, }, }) diff --git a/sources/elbv2/target_group.go b/adapters/elbv2/target_group.go similarity index 70% rename from sources/elbv2/target_group.go rename to adapters/elbv2/target_group.go index c618842e..54422e1e 100644 --- a/sources/elbv2/target_group.go +++ b/adapters/elbv2/target_group.go @@ -5,7 +5,7 @@ import ( "fmt" elbv2 "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -23,7 +23,7 @@ func targetGroupOutputMapper(ctx context.Context, client elbClient, scope string tagsMap := getTagsMap(ctx, client, tgArns) for _, tg := range output.TargetGroups { - attrs, err := sources.ToAttributesWithExclude(tg) + attrs, err := adapters.ToAttributesWithExclude(tg) if err != nil { return nil, err @@ -79,14 +79,14 @@ func targetGroupOutputMapper(ctx context.Context, client elbClient, scope string } for _, lbArn := range tg.LoadBalancerArns { - if a, err := sources.ParseARN(lbArn); err == nil { + if a, err := adapters.ParseARN(lbArn); err == nil { // +overmind:link elbv2-load-balancer item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "elbv2-load-balancer", Method: sdp.QueryMethod_SEARCH, Query: lbArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Load balancers and their target groups are tightly coupled @@ -114,12 +114,13 @@ func targetGroupOutputMapper(ctx context.Context, client elbClient, scope string // +overmind:terraform:queryMap aws_lb_target_group.arn // +overmind:terraform:method SEARCH -func NewTargetGroupSource(client elbClient, accountID string, region string) *sources.DescribeOnlySource[*elbv2.DescribeTargetGroupsInput, *elbv2.DescribeTargetGroupsOutput, elbClient, *elbv2.Options] { - return &sources.DescribeOnlySource[*elbv2.DescribeTargetGroupsInput, *elbv2.DescribeTargetGroupsOutput, elbClient, *elbv2.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "elbv2-target-group", +func NewTargetGroupAdapter(client elbClient, accountID string, region string) *adapters.DescribeOnlyAdapter[*elbv2.DescribeTargetGroupsInput, *elbv2.DescribeTargetGroupsOutput, elbClient, *elbv2.Options] { + return &adapters.DescribeOnlyAdapter[*elbv2.DescribeTargetGroupsInput, *elbv2.DescribeTargetGroupsOutput, elbClient, *elbv2.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "elbv2-target-group", + AdapterMetadata: TargetGroupMetadata(), DescribeFunc: func(ctx context.Context, client elbClient, input *elbv2.DescribeTargetGroupsInput) (*elbv2.DescribeTargetGroupsOutput, error) { return client.DescribeTargetGroups(ctx, input) }, @@ -132,7 +133,7 @@ func NewTargetGroupSource(client elbClient, accountID string, region string) *so return &elbv2.DescribeTargetGroupsInput{}, nil }, InputMapperSearch: func(ctx context.Context, client elbClient, scope, query string) (*elbv2.DescribeTargetGroupsInput, error) { - arn, err := sources.ParseARN(query) + arn, err := adapters.ParseARN(query) if err != nil { return nil, err @@ -155,9 +156,36 @@ func NewTargetGroupSource(client elbClient, accountID string, region string) *so return nil, fmt.Errorf("unsupported resource type: %s", arn.Resource) } }, - PaginatorBuilder: func(client elbClient, params *elbv2.DescribeTargetGroupsInput) sources.Paginator[*elbv2.DescribeTargetGroupsOutput, *elbv2.Options] { + PaginatorBuilder: func(client elbClient, params *elbv2.DescribeTargetGroupsInput) adapters.Paginator[*elbv2.DescribeTargetGroupsOutput, *elbv2.Options] { return elbv2.NewDescribeTargetGroupsPaginator(client, params) }, OutputMapper: targetGroupOutputMapper, } } + +func TargetGroupMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "elbv2-target-group", + DescriptiveName: "Target Group", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a target group by name", + ListDescription: "List all target groups", + SearchDescription: "Search for target groups by load balancer ARN or target group ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + { + TerraformQueryMap: "aws_alb_target_group.arn", + TerraformMethod: sdp.QueryMethod_SEARCH, + }, + { + TerraformQueryMap: "aws_lb_target_group.arn", + TerraformMethod: sdp.QueryMethod_SEARCH, + }, + }, + PotentialLinks: []string{"ec2-vpc", "elbv2-load-balancer", "elbv2-target-health"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + } +} diff --git a/sources/elbv2/target_group_test.go b/adapters/elbv2/target_group_test.go similarity index 61% rename from sources/elbv2/target_group_test.go rename to adapters/elbv2/target_group_test.go index 156af9d0..fcdd91ee 100644 --- a/sources/elbv2/target_group_test.go +++ b/adapters/elbv2/target_group_test.go @@ -8,7 +8,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2" elbv2 "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2" "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -16,28 +16,28 @@ func TestTargetGroupOutputMapper(t *testing.T) { output := elbv2.DescribeTargetGroupsOutput{ TargetGroups: []types.TargetGroup{ { - TargetGroupArn: sources.PtrString("arn:aws:elasticloadbalancing:eu-west-2:944651592624:targetgroup/k8s-default-apiserve-d87e8f7010/559d207158e41222"), - TargetGroupName: sources.PtrString("k8s-default-apiserve-d87e8f7010"), + TargetGroupArn: adapters.PtrString("arn:aws:elasticloadbalancing:eu-west-2:944651592624:targetgroup/k8s-default-apiserve-d87e8f7010/559d207158e41222"), + TargetGroupName: adapters.PtrString("k8s-default-apiserve-d87e8f7010"), Protocol: types.ProtocolEnumHttp, - Port: sources.PtrInt32(8080), - VpcId: sources.PtrString("vpc-0c72199250cd479ea"), // link + Port: adapters.PtrInt32(8080), + VpcId: adapters.PtrString("vpc-0c72199250cd479ea"), // link HealthCheckProtocol: types.ProtocolEnumHttp, - HealthCheckPort: sources.PtrString("traffic-port"), - HealthCheckEnabled: sources.PtrBool(true), - HealthCheckIntervalSeconds: sources.PtrInt32(10), - HealthCheckTimeoutSeconds: sources.PtrInt32(10), - HealthyThresholdCount: sources.PtrInt32(10), - UnhealthyThresholdCount: sources.PtrInt32(10), - HealthCheckPath: sources.PtrString("/"), + HealthCheckPort: adapters.PtrString("traffic-port"), + HealthCheckEnabled: adapters.PtrBool(true), + HealthCheckIntervalSeconds: adapters.PtrInt32(10), + HealthCheckTimeoutSeconds: adapters.PtrInt32(10), + HealthyThresholdCount: adapters.PtrInt32(10), + UnhealthyThresholdCount: adapters.PtrInt32(10), + HealthCheckPath: adapters.PtrString("/"), Matcher: &types.Matcher{ - HttpCode: sources.PtrString("200"), - GrpcCode: sources.PtrString("code"), + HttpCode: adapters.PtrString("200"), + GrpcCode: adapters.PtrString("code"), }, LoadBalancerArns: []string{ "arn:aws:elasticloadbalancing:eu-west-2:944651592624:loadbalancer/app/ingress/1bf10920c5bd199d", // link }, TargetType: types.TargetTypeEnumIp, - ProtocolVersion: sources.PtrString("HTTP1"), + ProtocolVersion: adapters.PtrString("HTTP1"), IpAddressType: types.TargetGroupIpAddressTypeEnumIpv4, }, }, @@ -67,7 +67,7 @@ func TestTargetGroupOutputMapper(t *testing.T) { // It doesn't really make sense to test anything other than the linked items // since the attributes are converted automatically - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "ec2-vpc", ExpectedMethod: sdp.QueryMethod_GET, @@ -85,14 +85,14 @@ func TestTargetGroupOutputMapper(t *testing.T) { tests.Execute(t, item) } -func TestNewTargetGroupSource(t *testing.T) { - config, account, region := sources.GetAutoConfig(t) +func TestNewTargetGroupAdapter(t *testing.T) { + config, account, region := adapters.GetAutoConfig(t) client := elasticloadbalancingv2.NewFromConfig(config) - source := NewTargetGroupSource(client, account, region) + adapter := NewTargetGroupAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/elbv2/target_health.go b/adapters/elbv2/target_health.go similarity index 82% rename from sources/elbv2/target_health.go rename to adapters/elbv2/target_health.go index f9b00efb..0aee8e12 100644 --- a/sources/elbv2/target_health.go +++ b/adapters/elbv2/target_health.go @@ -10,7 +10,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2" elbv2 "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2" "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -79,7 +79,7 @@ func targetHealthOutputMapper(_ context.Context, _ *elbv2.Client, scope string, items := make([]*sdp.Item, 0) for _, desc := range output.TargetHealthDescriptions { - attrs, err := sources.ToAttributesWithExclude(desc) + attrs, err := adapters.ToAttributesWithExclude(desc) if err != nil { return nil, err @@ -140,7 +140,7 @@ func targetHealthOutputMapper(_ context.Context, _ *elbv2.Client, scope string, item.GetAttributes().Set("UniqueId", id.String()) // See if the ID is an ARN - a, err := sources.ParseARN(*desc.Target.Id) + a, err := adapters.ParseARN(*desc.Target.Id) if err == nil { switch a.Service { @@ -151,7 +151,7 @@ func targetHealthOutputMapper(_ context.Context, _ *elbv2.Client, scope string, Type: "lambda-function", Method: sdp.QueryMethod_SEARCH, Query: *desc.Target.Id, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Everything is tightly coupled with target health @@ -166,7 +166,7 @@ func targetHealthOutputMapper(_ context.Context, _ *elbv2.Client, scope string, Type: "elbv2-load-balancer", Method: sdp.QueryMethod_SEARCH, Query: *desc.Target.Id, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ In: true, @@ -223,12 +223,13 @@ func targetHealthOutputMapper(_ context.Context, _ *elbv2.Client, scope string, // +overmind:search Search for target health by target group ARN // +overmind:group AWS -func NewTargetHealthSource(client *elasticloadbalancingv2.Client, accountID string, region string) *sources.DescribeOnlySource[*elbv2.DescribeTargetHealthInput, *elbv2.DescribeTargetHealthOutput, *elbv2.Client, *elbv2.Options] { - return &sources.DescribeOnlySource[*elbv2.DescribeTargetHealthInput, *elbv2.DescribeTargetHealthOutput, *elbv2.Client, *elbv2.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "elbv2-target-health", +func NewTargetHealthAdapter(client *elasticloadbalancingv2.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*elbv2.DescribeTargetHealthInput, *elbv2.DescribeTargetHealthOutput, *elbv2.Client, *elbv2.Options] { + return &adapters.DescribeOnlyAdapter[*elbv2.DescribeTargetHealthInput, *elbv2.DescribeTargetHealthOutput, *elbv2.Client, *elbv2.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "elbv2-target-health", + AdapterMetadata: TargetHealthMetadata(), DescribeFunc: func(ctx context.Context, client *elbv2.Client, input *elbv2.DescribeTargetHealthInput) (*elbv2.DescribeTargetHealthOutput, error) { return client.DescribeTargetHealth(ctx, input) }, @@ -265,3 +266,18 @@ func NewTargetHealthSource(client *elasticloadbalancingv2.Client, accountID stri OutputMapper: targetHealthOutputMapper, } } + +func TargetHealthMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "elbv2-target-health", + DescriptiveName: "ELB Target Health", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + Search: true, + GetDescription: "Get target health by unique ID ({TargetGroupArn}|{Id}|{AvailabilityZone}|{Port})", + SearchDescription: "Search for target health by target group ARN", + }, + PotentialLinks: []string{"ec2-instance", "lambda-function", "ip", "elbv2-load-balancer"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_OBSERVABILITY, + } +} diff --git a/sources/elbv2/target_health_test.go b/adapters/elbv2/target_health_test.go similarity index 75% rename from sources/elbv2/target_health_test.go rename to adapters/elbv2/target_health_test.go index 76ae3502..2394fcd3 100644 --- a/sources/elbv2/target_health_test.go +++ b/adapters/elbv2/target_health_test.go @@ -6,7 +6,7 @@ import ( elbv2 "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2" "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -15,61 +15,61 @@ func TestTargetHealthOutputMapper(t *testing.T) { TargetHealthDescriptions: []types.TargetHealthDescription{ { Target: &types.TargetDescription{ - Id: sources.PtrString("10.0.6.64"), // link - Port: sources.PtrInt32(8080), - AvailabilityZone: sources.PtrString("eu-west-2c"), + Id: adapters.PtrString("10.0.6.64"), // link + Port: adapters.PtrInt32(8080), + AvailabilityZone: adapters.PtrString("eu-west-2c"), }, - HealthCheckPort: sources.PtrString("8080"), + HealthCheckPort: adapters.PtrString("8080"), TargetHealth: &types.TargetHealth{ State: types.TargetHealthStateEnumHealthy, Reason: types.TargetHealthReasonEnumDeregistrationInProgress, - Description: sources.PtrString("Health checks failed with these codes: [404]"), + Description: adapters.PtrString("Health checks failed with these codes: [404]"), }, }, { Target: &types.TargetDescription{ - Id: sources.PtrString("arn:aws:elasticloadbalancing:eu-west-2:944651592624:loadbalancer/app/ingress/1bf10920c5bd199d"), // link - Port: sources.PtrInt32(8080), - AvailabilityZone: sources.PtrString("eu-west-2c"), + Id: adapters.PtrString("arn:aws:elasticloadbalancing:eu-west-2:944651592624:loadbalancer/app/ingress/1bf10920c5bd199d"), // link + Port: adapters.PtrInt32(8080), + AvailabilityZone: adapters.PtrString("eu-west-2c"), }, - HealthCheckPort: sources.PtrString("8080"), + HealthCheckPort: adapters.PtrString("8080"), TargetHealth: &types.TargetHealth{ State: types.TargetHealthStateEnumHealthy, Reason: types.TargetHealthReasonEnumDeregistrationInProgress, - Description: sources.PtrString("Health checks failed with these codes: [404]"), + Description: adapters.PtrString("Health checks failed with these codes: [404]"), }, }, { Target: &types.TargetDescription{ - Id: sources.PtrString("i-foo"), // link - Port: sources.PtrInt32(8080), - AvailabilityZone: sources.PtrString("eu-west-2c"), + Id: adapters.PtrString("i-foo"), // link + Port: adapters.PtrInt32(8080), + AvailabilityZone: adapters.PtrString("eu-west-2c"), }, - HealthCheckPort: sources.PtrString("8080"), + HealthCheckPort: adapters.PtrString("8080"), TargetHealth: &types.TargetHealth{ State: types.TargetHealthStateEnumHealthy, Reason: types.TargetHealthReasonEnumDeregistrationInProgress, - Description: sources.PtrString("Health checks failed with these codes: [404]"), + Description: adapters.PtrString("Health checks failed with these codes: [404]"), }, }, { Target: &types.TargetDescription{ - Id: sources.PtrString("arn:aws:lambda:eu-west-2:944651592624:function/foobar"), // link - Port: sources.PtrInt32(8080), - AvailabilityZone: sources.PtrString("eu-west-2c"), + Id: adapters.PtrString("arn:aws:lambda:eu-west-2:944651592624:function/foobar"), // link + Port: adapters.PtrInt32(8080), + AvailabilityZone: adapters.PtrString("eu-west-2c"), }, - HealthCheckPort: sources.PtrString("8080"), + HealthCheckPort: adapters.PtrString("8080"), TargetHealth: &types.TargetHealth{ State: types.TargetHealthStateEnumHealthy, Reason: types.TargetHealthReasonEnumDeregistrationInProgress, - Description: sources.PtrString("Health checks failed with these codes: [404]"), + Description: adapters.PtrString("Health checks failed with these codes: [404]"), }, }, }, } items, err := targetHealthOutputMapper(context.Background(), nil, "foo", &elbv2.DescribeTargetHealthInput{ - TargetGroupArn: sources.PtrString("arn:aws:elasticloadbalancing:eu-west-2:944651592624:targetgroup/k8s-default-apiserve-d87e8f7010/559d207158e41222"), + TargetGroupArn: adapters.PtrString("arn:aws:elasticloadbalancing:eu-west-2:944651592624:targetgroup/k8s-default-apiserve-d87e8f7010/559d207158e41222"), }, &output) if err != nil { @@ -88,7 +88,7 @@ func TestTargetHealthOutputMapper(t *testing.T) { item := items[0] - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "ip", ExpectedMethod: sdp.QueryMethod_GET, @@ -101,7 +101,7 @@ func TestTargetHealthOutputMapper(t *testing.T) { item = items[1] - tests = sources.QueryTests{ + tests = adapters.QueryTests{ { ExpectedType: "elbv2-load-balancer", ExpectedMethod: sdp.QueryMethod_SEARCH, @@ -114,7 +114,7 @@ func TestTargetHealthOutputMapper(t *testing.T) { item = items[2] - tests = sources.QueryTests{ + tests = adapters.QueryTests{ { ExpectedType: "ec2-instance", ExpectedMethod: sdp.QueryMethod_GET, @@ -127,7 +127,7 @@ func TestTargetHealthOutputMapper(t *testing.T) { item = items[3] - tests = sources.QueryTests{ + tests = adapters.QueryTests{ { ExpectedType: "lambda-function", ExpectedMethod: sdp.QueryMethod_SEARCH, @@ -167,8 +167,8 @@ func TestTargetHealthUniqueID(t *testing.T) { id := TargetHealthUniqueID{ TargetGroupArn: "arn:aws:elasticloadbalancing:eu-west-2:944651592624:targetgroup/k8s-default-apiserve-d87e8f7010/559d207158e41222", Id: "10.0.0.1", - AvailabilityZone: sources.PtrString("eu-west-2"), - Port: sources.PtrInt32(8080), + AvailabilityZone: adapters.PtrString("eu-west-2"), + Port: adapters.PtrInt32(8080), } expected := "arn:aws:elasticloadbalancing:eu-west-2:944651592624:targetgroup/k8s-default-apiserve-d87e8f7010/559d207158e41222|10.0.0.1|eu-west-2|8080" @@ -192,7 +192,7 @@ func TestTargetHealthUniqueID(t *testing.T) { id := TargetHealthUniqueID{ TargetGroupArn: "arn:aws:elasticloadbalancing:eu-west-2:944651592624:targetgroup/k8s-default-apiserve-d87e8f7010/559d207158e41222", Id: "arn:partition:service:region:account-id:resource-type:resource-id", - Port: sources.PtrInt32(8080), + Port: adapters.PtrInt32(8080), } expected := "arn:aws:elasticloadbalancing:eu-west-2:944651592624:targetgroup/k8s-default-apiserve-d87e8f7010/559d207158e41222|arn:partition:service:region:account-id:resource-type:resource-id||8080" diff --git a/sources/get_list_source.go b/adapters/get_list_source.go similarity index 72% rename from sources/get_list_source.go rename to adapters/get_list_source.go index a2d834b1..4d3e64d1 100644 --- a/sources/get_list_source.go +++ b/adapters/get_list_source.go @@ -1,4 +1,4 @@ -package sources +package adapters import ( "context" @@ -11,17 +11,18 @@ import ( "github.com/overmindtech/sdpcache" ) -// GetListSource A source for AWS APIs where the Get and List functions both +// GetListAdapter A adapter for AWS APIs where the Get and List functions both // return the full item, such as many of the IAM APIs -type GetListSource[AWSItem AWSItemType, ClientStruct ClientStructType, Options OptionsType] struct { +type GetListAdapter[AWSItem AWSItemType, ClientStruct ClientStructType, Options OptionsType] struct { ItemType string // The type of items that will be returned Client ClientStruct // The AWS API client AccountID string // The AWS account ID Region string // The AWS region this is related to SupportGlobalResources bool // If true, this will also support resources in the "aws" scope which are global + AdapterMetadata sdp.AdapterMetadata CacheDuration time.Duration // How long to cache items for - cache *sdpcache.Cache // The sdpcache of this source + cache *sdpcache.Cache // The sdpcache of this adapter cacheInitMu sync.Mutex // Mutex to ensure cache is only initialised once // Disables List(), meaning all calls will return empty results. This does @@ -47,7 +48,7 @@ type GetListSource[AWSItem AWSItemType, ClientStruct ClientStructType, Options O ListTagsFunc func(context.Context, AWSItem, ClientStruct) (map[string]string, error) } -func (s *GetListSource[AWSItem, ClientStruct, Options]) cacheDuration() time.Duration { +func (s *GetListAdapter[AWSItem, ClientStruct, Options]) cacheDuration() time.Duration { if s.CacheDuration == 0 { return DefaultCacheDuration } @@ -55,7 +56,7 @@ func (s *GetListSource[AWSItem, ClientStruct, Options]) cacheDuration() time.Dur return s.CacheDuration } -func (s *GetListSource[AWSItem, ClientStruct, Options]) ensureCache() { +func (s *GetListAdapter[AWSItem, ClientStruct, Options]) ensureCache() { s.cacheInitMu.Lock() defer s.cacheInitMu.Unlock() @@ -64,13 +65,13 @@ func (s *GetListSource[AWSItem, ClientStruct, Options]) ensureCache() { } } -func (s *GetListSource[AWSItem, ClientStruct, Options]) Cache() *sdpcache.Cache { +func (s *GetListAdapter[AWSItem, ClientStruct, Options]) Cache() *sdpcache.Cache { s.ensureCache() return s.cache } -// Validate Checks that the source has been set up correctly -func (s *GetListSource[AWSItem, ClientStruct, Options]) Validate() error { +// Validate Checks that the adapter has been set up correctly +func (s *GetListAdapter[AWSItem, ClientStruct, Options]) Validate() error { if s.GetFunc == nil { return errors.New("GetFunc is nil") } @@ -88,17 +89,21 @@ func (s *GetListSource[AWSItem, ClientStruct, Options]) Validate() error { return nil } -func (s *GetListSource[AWSItem, ClientStruct, Options]) Type() string { +func (s *GetListAdapter[AWSItem, ClientStruct, Options]) Type() string { return s.ItemType } -func (s *GetListSource[AWSItem, ClientStruct, Options]) Name() string { - return fmt.Sprintf("%v-source", s.ItemType) +func (s *GetListAdapter[AWSItem, ClientStruct, Options]) Name() string { + return fmt.Sprintf("%v-adapter", s.ItemType) } -// List of scopes that this source is capable of find items for. This will be +func (s *GetListAdapter[AWSItem, ClientStruct, Options]) Metadata() *sdp.AdapterMetadata { + return &s.AdapterMetadata +} + +// List of scopes that this adapter is capable of find items for. This will be // in the format {accountID}.{region} -func (s *GetListSource[AWSItem, ClientStruct, Options]) Scopes() []string { +func (s *GetListAdapter[AWSItem, ClientStruct, Options]) Scopes() []string { scopes := make([]string, 0) scopes = append(scopes, FormatScope(s.AccountID, s.Region)) @@ -110,8 +115,8 @@ func (s *GetListSource[AWSItem, ClientStruct, Options]) Scopes() []string { return scopes } -// hasScope Returns whether or not this source has the given scope -func (s *GetListSource[AWSItem, ClientStruct, Options]) hasScope(scope string) bool { +// hasScope Returns whether or not this adapter has the given scope +func (s *GetListAdapter[AWSItem, ClientStruct, Options]) hasScope(scope string) bool { if scope == "aws" && s.SupportGlobalResources { // There is a special global "account" that is used for global resources // called "aws" @@ -127,14 +132,14 @@ func (s *GetListSource[AWSItem, ClientStruct, Options]) hasScope(scope string) b return false } -// Get retrieves an item from the source based on the provided scope, query, and +// Get retrieves an item from the adapter based on the provided scope, query, and // cache settings. It uses the defined `GetFunc`, `ItemMapper`, and // `ListTagsFunc` to retrieve and map the item. -func (s *GetListSource[AWSItem, ClientStruct, Options]) Get(ctx context.Context, scope string, query string, ignoreCache bool) (*sdp.Item, error) { +func (s *GetListAdapter[AWSItem, ClientStruct, Options]) Get(ctx context.Context, scope string, query string, ignoreCache bool) (*sdp.Item, error) { if !s.hasScope(scope) { return nil, &sdp.QueryError{ ErrorType: sdp.QueryError_NOSCOPE, - ErrorString: fmt.Sprintf("requested scope %v does not match source scope %v", scope, s.Scopes()[0]), + ErrorString: fmt.Sprintf("requested scope %v does not match adapter scope %v", scope, s.Scopes()[0]), } } @@ -181,11 +186,11 @@ func (s *GetListSource[AWSItem, ClientStruct, Options]) Get(ctx context.Context, // List Lists all available items. This is done by running the ListFunc, then // passing these results to GetFunc in order to get the details -func (s *GetListSource[AWSItem, ClientStruct, Options]) List(ctx context.Context, scope string, ignoreCache bool) ([]*sdp.Item, error) { +func (s *GetListAdapter[AWSItem, ClientStruct, Options]) List(ctx context.Context, scope string, ignoreCache bool) ([]*sdp.Item, error) { if !s.hasScope(scope) { return nil, &sdp.QueryError{ ErrorType: sdp.QueryError_NOSCOPE, - ErrorString: fmt.Sprintf("requested scope %v does not match source scope %v", scope, s.Scopes()[0]), + ErrorString: fmt.Sprintf("requested scope %v does not match adapter scope %v", scope, s.Scopes()[0]), } } @@ -231,12 +236,12 @@ func (s *GetListSource[AWSItem, ClientStruct, Options]) List(ctx context.Context // Search Searches for AWS resources, this can be implemented either as a // generic ARN search that tries to extract the globally unique name from the // ARN and pass this to a Get request, or a custom search function that can be -// used to search for items in a different, source-specific way -func (s *GetListSource[AWSItem, ClientStruct, Options]) Search(ctx context.Context, scope string, query string, ignoreCache bool) ([]*sdp.Item, error) { +// used to search for items in a different, adapter-specific way +func (s *GetListAdapter[AWSItem, ClientStruct, Options]) Search(ctx context.Context, scope string, query string, ignoreCache bool) ([]*sdp.Item, error) { if !s.hasScope(scope) { return nil, &sdp.QueryError{ ErrorType: sdp.QueryError_NOSCOPE, - ErrorString: fmt.Sprintf("requested scope %v does not match source scope %v", scope, s.Scopes()[0]), + ErrorString: fmt.Sprintf("requested scope %v does not match adapter scope %v", scope, s.Scopes()[0]), } } @@ -249,7 +254,7 @@ func (s *GetListSource[AWSItem, ClientStruct, Options]) Search(ctx context.Conte // Extracts the `ResourceID` and scope from the ARN, then calls `Get` with the // extracted `ResourceID` -func (s *GetListSource[AWSItem, ClientStruct, Options]) SearchARN(ctx context.Context, scope string, query string, ignoreCache bool) ([]*sdp.Item, error) { +func (s *GetListAdapter[AWSItem, ClientStruct, Options]) SearchARN(ctx context.Context, scope string, query string, ignoreCache bool) ([]*sdp.Item, error) { // Parse the ARN a, err := ParseARN(query) @@ -277,8 +282,8 @@ func (s *GetListSource[AWSItem, ClientStruct, Options]) SearchARN(ctx context.Co } // Custom search function that can be used to search for items in a different, -// source-specific way -func (s *GetListSource[AWSItem, ClientStruct, Options]) SearchCustom(ctx context.Context, scope string, query string, ignoreCache bool) ([]*sdp.Item, error) { +// adapter-specific way +func (s *GetListAdapter[AWSItem, ClientStruct, Options]) SearchCustom(ctx context.Context, scope string, query string, ignoreCache bool) ([]*sdp.Item, error) { // We need to cache here since this is the only place it'll be called s.ensureCache() cacheHit, ck, cachedItems, qErr := s.cache.Lookup(ctx, s.Name(), sdp.QueryMethod_SEARCH, scope, s.ItemType, query, ignoreCache) @@ -312,10 +317,10 @@ func (s *GetListSource[AWSItem, ClientStruct, Options]) SearchCustom(ctx context return items, nil } -// Weight Returns the priority weighting of items returned by this source. -// This is used to resolve conflicts where two sources of the same type +// Weight Returns the priority weighting of items returned by this adapter. +// This is used to resolve conflicts where two adapters of the same type // return an item for a GET request. In this instance only one item can be // seen on, so the one with the higher weight value will win. -func (s *GetListSource[AWSItem, ClientStruct, Options]) Weight() int { +func (s *GetListAdapter[AWSItem, ClientStruct, Options]) Weight() int { return 100 } diff --git a/sources/get_list_source_test.go b/adapters/get_list_source_test.go similarity index 94% rename from sources/get_list_source_test.go rename to adapters/get_list_source_test.go index d829611c..053375ea 100644 --- a/sources/get_list_source_test.go +++ b/adapters/get_list_source_test.go @@ -1,4 +1,4 @@ -package sources +package adapters import ( "context" @@ -11,7 +11,7 @@ import ( ) func TestGetListSourceType(t *testing.T) { - s := GetListSource[string, struct{}, struct{}]{ + s := GetListAdapter[string, struct{}, struct{}]{ ItemType: "foo", } @@ -21,17 +21,17 @@ func TestGetListSourceType(t *testing.T) { } func TestGetListSourceName(t *testing.T) { - s := GetListSource[string, struct{}, struct{}]{ + s := GetListAdapter[string, struct{}, struct{}]{ ItemType: "foo", } - if s.Name() != "foo-source" { - t.Errorf("expected type to be foo-source got %v", s.Name()) + if s.Name() != "foo-adapter" { + t.Errorf("expected type to be foo-adapter got %v", s.Name()) } } func TestGetListSourceScopes(t *testing.T) { - s := GetListSource[string, struct{}, struct{}]{ + s := GetListAdapter[string, struct{}, struct{}]{ AccountID: "foo", Region: "bar", } @@ -43,7 +43,7 @@ func TestGetListSourceScopes(t *testing.T) { func TestGetListSourceGet(t *testing.T) { t.Run("with no errors", func(t *testing.T) { - s := GetListSource[string, struct{}, struct{}]{ + s := GetListAdapter[string, struct{}, struct{}]{ ItemType: "person", Region: "eu-west-2", AccountID: "12345", @@ -74,7 +74,7 @@ func TestGetListSourceGet(t *testing.T) { }) t.Run("with an error in the GetFunc", func(t *testing.T) { - s := GetListSource[string, struct{}, struct{}]{ + s := GetListAdapter[string, struct{}, struct{}]{ ItemType: "person", Region: "eu-west-2", AccountID: "12345", @@ -95,7 +95,7 @@ func TestGetListSourceGet(t *testing.T) { }) t.Run("with an error in the mapper", func(t *testing.T) { - s := GetListSource[string, struct{}, struct{}]{ + s := GetListAdapter[string, struct{}, struct{}]{ ItemType: "person", Region: "eu-west-2", AccountID: "12345", @@ -118,7 +118,7 @@ func TestGetListSourceGet(t *testing.T) { func TestGetListSourceList(t *testing.T) { t.Run("with no errors", func(t *testing.T) { - s := GetListSource[string, struct{}, struct{}]{ + s := GetListAdapter[string, struct{}, struct{}]{ ItemType: "person", Region: "eu-west-2", AccountID: "12345", @@ -152,7 +152,7 @@ func TestGetListSourceList(t *testing.T) { }) t.Run("with an error in the ListFunc", func(t *testing.T) { - s := GetListSource[string, struct{}, struct{}]{ + s := GetListAdapter[string, struct{}, struct{}]{ ItemType: "person", Region: "eu-west-2", AccountID: "12345", @@ -173,7 +173,7 @@ func TestGetListSourceList(t *testing.T) { }) t.Run("with an error in the mapper", func(t *testing.T) { - s := GetListSource[string, struct{}, struct{}]{ + s := GetListAdapter[string, struct{}, struct{}]{ ItemType: "person", Region: "eu-west-2", AccountID: "12345", @@ -200,7 +200,7 @@ func TestGetListSourceList(t *testing.T) { func TestGetListSourceSearch(t *testing.T) { t.Run("with ARN search", func(t *testing.T) { - s := GetListSource[string, struct{}, struct{}]{ + s := GetListAdapter[string, struct{}, struct{}]{ ItemType: "person", Region: "eu-west-2", AccountID: "12345", @@ -243,7 +243,7 @@ func TestGetListSourceSearch(t *testing.T) { func TestGetListSourceCaching(t *testing.T) { ctx := context.Background() generation := 0 - s := GetListSource[string, struct{}, struct{}]{ + s := GetListAdapter[string, struct{}, struct{}]{ ItemType: "test-type", Region: "eu-west-2", AccountID: "foo", diff --git a/sources/iam/group.go b/adapters/iam/group.go similarity index 59% rename from sources/iam/group.go rename to adapters/iam/group.go index f82f0ebb..f69f302f 100644 --- a/sources/iam/group.go +++ b/adapters/iam/group.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/iam" "github.com/aws/aws-sdk-go-v2/service/iam/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -40,7 +40,7 @@ func groupListFunc(ctx context.Context, client *iam.Client, _ string) ([]*types. } func groupItemMapper(_, scope string, awsItem *types.Group) (*sdp.Item, error) { - attributes, err := sources.ToAttributesWithExclude(awsItem) + attributes, err := adapters.ToAttributesWithExclude(awsItem) if err != nil { return nil, err @@ -66,12 +66,13 @@ func groupItemMapper(_, scope string, awsItem *types.Group) (*sdp.Item, error) { // +overmind:terraform:queryMap aws_iam_group.arn // +overmind:terraform:method SEARCH -func NewGroupSource(client *iam.Client, accountID string, region string) *sources.GetListSource[*types.Group, *iam.Client, *iam.Options] { - return &sources.GetListSource[*types.Group, *iam.Client, *iam.Options]{ - ItemType: "iam-group", - Client: client, - CacheDuration: 3 * time.Hour, // IAM has very low rate limits, we need to cache for a long time - AccountID: accountID, +func NewGroupAdapter(client *iam.Client, accountID string, region string) *adapters.GetListAdapter[*types.Group, *iam.Client, *iam.Options] { + return &adapters.GetListAdapter[*types.Group, *iam.Client, *iam.Options]{ + ItemType: "iam-group", + Client: client, + CacheDuration: 3 * time.Hour, // IAM has very low rate limits, we need to cache for a long time + AccountID: accountID, + AdapterMetadata: GroupMetadata(), GetFunc: func(ctx context.Context, client *iam.Client, scope, query string) (*types.Group, error) { return groupGetFunc(ctx, client, scope, query) }, @@ -81,3 +82,25 @@ func NewGroupSource(client *iam.Client, accountID string, region string) *source ItemMapper: groupItemMapper, } } + +func GroupMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "iam-group", + DescriptiveName: "IAM Group", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a group by name", + ListDescription: "List all IAM groups", + SearchDescription: "Search for a group by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + { + TerraformMethod: sdp.QueryMethod_SEARCH, + TerraformQueryMap: "aws_iam_group.arn", + }, + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_SECURITY, + } +} diff --git a/sources/iam/group_test.go b/adapters/iam/group_test.go similarity index 52% rename from sources/iam/group_test.go rename to adapters/iam/group_test.go index 6946f094..4d2f2b20 100644 --- a/sources/iam/group_test.go +++ b/adapters/iam/group_test.go @@ -7,16 +7,16 @@ import ( "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/iam" "github.com/aws/aws-sdk-go-v2/service/iam/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" ) func TestGroupItemMapper(t *testing.T) { zone := types.Group{ - Path: sources.PtrString("/"), - GroupName: sources.PtrString("power-users"), - GroupId: sources.PtrString("AGPA3VLV2U27T6SSLJMDS"), - Arn: sources.PtrString("arn:aws:iam::801795385023:group/power-users"), - CreateDate: sources.PtrTime(time.Now()), + Path: adapters.PtrString("/"), + GroupName: adapters.PtrString("power-users"), + GroupId: adapters.PtrString("AGPA3VLV2U27T6SSLJMDS"), + Arn: adapters.PtrString("arn:aws:iam::801795385023:group/power-users"), + CreateDate: adapters.PtrTime(time.Now()), } item, err := groupItemMapper("", "foo", &zone) @@ -31,17 +31,17 @@ func TestGroupItemMapper(t *testing.T) { } -func TestNewGroupSource(t *testing.T) { - config, account, region := sources.GetAutoConfig(t) +func TestNewGroupAdapter(t *testing.T) { + config, account, region := adapters.GetAutoConfig(t) client := iam.NewFromConfig(config, func(o *iam.Options) { o.RetryMode = aws.RetryModeAdaptive o.RetryMaxAttempts = 10 }) - source := NewGroupSource(client, account, region) + adapter := NewGroupAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 30 * time.Second, } diff --git a/sources/iam/instance_profile.go b/adapters/iam/instance_profile.go similarity index 68% rename from sources/iam/instance_profile.go rename to adapters/iam/instance_profile.go index 4ed56ea0..5469c607 100644 --- a/sources/iam/instance_profile.go +++ b/adapters/iam/instance_profile.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/iam" "github.com/aws/aws-sdk-go-v2/service/iam/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -40,7 +40,7 @@ func instanceProfileListFunc(ctx context.Context, client *iam.Client, _ string) } func instanceProfileItemMapper(_, scope string, awsItem *types.InstanceProfile) (*sdp.Item, error) { - attributes, err := sources.ToAttributesWithExclude(awsItem) + attributes, err := adapters.ToAttributesWithExclude(awsItem) if err != nil { return nil, err @@ -54,14 +54,14 @@ func instanceProfileItemMapper(_, scope string, awsItem *types.InstanceProfile) } for _, role := range awsItem.Roles { - if arn, err := sources.ParseARN(*role.Arn); err == nil { + if arn, err := adapters.ParseARN(*role.Arn); err == nil { // +overmind:link iam-role item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "iam-role", Method: sdp.QueryMethod_SEARCH, Query: *role.Arn, - Scope: sources.FormatScope(arn.AccountID, arn.Region), + Scope: adapters.FormatScope(arn.AccountID, arn.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changes to the role will affect this @@ -73,14 +73,14 @@ func instanceProfileItemMapper(_, scope string, awsItem *types.InstanceProfile) } if role.PermissionsBoundary != nil { - if arn, err := sources.ParseARN(*role.PermissionsBoundary.PermissionsBoundaryArn); err == nil { + if arn, err := adapters.ParseARN(*role.PermissionsBoundary.PermissionsBoundaryArn); err == nil { // +overmind:link iam-policy item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "iam-policy", Method: sdp.QueryMethod_SEARCH, Query: *role.PermissionsBoundary.PermissionsBoundaryArn, - Scope: sources.FormatScope(arn.AccountID, arn.Region), + Scope: adapters.FormatScope(arn.AccountID, arn.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changes to the policy will affect this @@ -107,7 +107,7 @@ func instanceProfileListTagsFunc(ctx context.Context, ip *types.InstanceProfile, out, err := paginator.NextPage(ctx) if err != nil { - return sources.HandleTagsError(ctx, err) + return adapters.HandleTagsError(ctx, err) } for _, tag := range out.Tags { @@ -130,12 +130,13 @@ func instanceProfileListTagsFunc(ctx context.Context, ip *types.InstanceProfile, // +overmind:terraform:queryMap aws_iam_instance_profile.arn // +overmind:terraform:method SEARCH -func NewInstanceProfileSource(client *iam.Client, accountID string, region string) *sources.GetListSource[*types.InstanceProfile, *iam.Client, *iam.Options] { - return &sources.GetListSource[*types.InstanceProfile, *iam.Client, *iam.Options]{ - ItemType: "iam-instance-profile", - Client: client, - CacheDuration: 3 * time.Hour, // IAM has very low rate limits, we need to cache for a long time - AccountID: accountID, +func NewInstanceProfileAdapter(client *iam.Client, accountID string, region string) *adapters.GetListAdapter[*types.InstanceProfile, *iam.Client, *iam.Options] { + return &adapters.GetListAdapter[*types.InstanceProfile, *iam.Client, *iam.Options]{ + ItemType: "iam-instance-profile", + Client: client, + CacheDuration: 3 * time.Hour, // IAM has very low rate limits, we need to cache for a long time + AccountID: accountID, + AdapterMetadata: InstanceProfileMetadata(), GetFunc: func(ctx context.Context, client *iam.Client, scope, query string) (*types.InstanceProfile, error) { return instanceProfileGetFunc(ctx, client, scope, query) }, @@ -148,3 +149,26 @@ func NewInstanceProfileSource(client *iam.Client, accountID string, region strin ItemMapper: instanceProfileItemMapper, } } + +func InstanceProfileMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "iam-instance-profile", + DescriptiveName: "IAM Instance Profile", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get an IAM instance profile by name", + ListDescription: "List all IAM instance profiles", + SearchDescription: "Search IAM instance profiles by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + { + TerraformQueryMap: "aws_iam_instance_profile.arn", + TerraformMethod: sdp.QueryMethod_SEARCH, + }, + }, + PotentialLinks: []string{"iam-role", "iam-policy"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_SECURITY, + } +} diff --git a/adapters/iam/instance_profile_test.go b/adapters/iam/instance_profile_test.go new file mode 100644 index 00000000..b5137b62 --- /dev/null +++ b/adapters/iam/instance_profile_test.go @@ -0,0 +1,69 @@ +package iam + +import ( + "testing" + "time" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/iam" + "github.com/aws/aws-sdk-go-v2/service/iam/types" + "github.com/overmindtech/aws-source/adapters" +) + +func TestInstanceProfileItemMapper(t *testing.T) { + profile := types.InstanceProfile{ + Arn: adapters.PtrString("arn:aws:iam::123456789012:instance-profile/webserver"), + CreateDate: adapters.PtrTime(time.Now()), + InstanceProfileId: adapters.PtrString("AIDACKCEVSQ6C2EXAMPLE"), + InstanceProfileName: adapters.PtrString("webserver"), + Path: adapters.PtrString("/"), + Roles: []types.Role{ + { + Arn: adapters.PtrString("arn:aws:iam::123456789012:role/webserver"), // link + CreateDate: adapters.PtrTime(time.Now()), + Path: adapters.PtrString("/"), + RoleId: adapters.PtrString("AIDACKCEVSQ6C2EXAMPLE"), + RoleName: adapters.PtrString("webserver"), + AssumeRolePolicyDocument: adapters.PtrString(`{}`), + Description: adapters.PtrString("Allows EC2 instances to call AWS services on your behalf."), + MaxSessionDuration: adapters.PtrInt32(3600), + PermissionsBoundary: &types.AttachedPermissionsBoundary{ + PermissionsBoundaryArn: adapters.PtrString("arn:aws:iam::123456789012:policy/XCompanyBoundaries"), // link + PermissionsBoundaryType: types.PermissionsBoundaryAttachmentTypePolicy, + }, + RoleLastUsed: &types.RoleLastUsed{ + LastUsedDate: adapters.PtrTime(time.Now()), + Region: adapters.PtrString("us-east-1"), + }, + }, + }, + } + + item, err := instanceProfileItemMapper("", "foo", &profile) + + if err != nil { + t.Error(err) + } + + if err = item.Validate(); err != nil { + t.Error(err) + } + +} + +func TestNewInstanceProfileAdapter(t *testing.T) { + config, account, region := adapters.GetAutoConfig(t) + client := iam.NewFromConfig(config, func(o *iam.Options) { + o.RetryMode = aws.RetryModeAdaptive + o.RetryMaxAttempts = 10 + }) + + adapter := NewInstanceProfileAdapter(client, account, region) + + test := adapters.E2ETest{ + Adapter: adapter, + Timeout: 30 * time.Second, + } + + test.Run(t) +} diff --git a/sources/iam/policy.go b/adapters/iam/policy.go similarity index 83% rename from sources/iam/policy.go rename to adapters/iam/policy.go index c6c93f79..a5a4dfe6 100644 --- a/sources/iam/policy.go +++ b/adapters/iam/policy.go @@ -11,7 +11,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/iam" "github.com/aws/aws-sdk-go-v2/service/iam/types" "github.com/micahhausler/aws-iam-policy/policy" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" log "github.com/sirupsen/logrus" "github.com/sourcegraph/conc/iter" @@ -29,7 +29,7 @@ type PolicyDetails struct { func policyGetFunc(ctx context.Context, client IAMClient, scope, query string) (*PolicyDetails, error) { // Construct the ARN from the name etc. - a := sources.ARN{ + a := adapters.ARN{ ARN: arn.ARN{ Partition: "aws", Service: "iam", @@ -39,7 +39,7 @@ func policyGetFunc(ctx context.Context, client IAMClient, scope, query string) ( }, } out, err := client.GetPolicy(ctx, &iam.GetPolicyInput{ - PolicyArn: sources.PtrString(a.String()), + PolicyArn: adapters.PtrString(a.String()), }) if err != nil { return nil, err @@ -206,7 +206,7 @@ func policyItemMapper(_, scope string, awsItem *PolicyDetails) (*sdp.Item, error Policy: awsItem.Policy, Document: awsItem.Document, } - attributes, err := sources.ToAttributesWithExclude(finalAttributes) + attributes, err := adapters.ToAttributesWithExclude(finalAttributes) if err != nil { return nil, err @@ -305,7 +305,7 @@ func policyListTagsFunc(ctx context.Context, p *PolicyDetails, client IAMClient) out, err := paginator.NextPage(ctx) if err != nil { - return sources.HandleTagsError(ctx, err), nil + return adapters.HandleTagsError(ctx, err), nil } for _, tag := range out.Tags { @@ -327,23 +327,22 @@ func policyListTagsFunc(ctx context.Context, p *PolicyDetails, client IAMClient) // +overmind:group AWS // +overmind:terraform:queryMap aws_iam_policy.arn // +overmind:terraform:queryMap aws_iam_user_policy_attachment.policy_arn -// +overmind:terraform:queryMap aws_iam_role_policy_attachment.policy_arn // +overmind:terraform:method SEARCH -// NewPolicySource Note that this policy source only support polices that are +// NewPolicyAdapter Note that this policy adapter only support polices that are // user-created due to the fact that the AWS-created ones are basically "global" -// in scope. In order to get this to work I'd have to change the way the source +// in scope. In order to get this to work I'd have to change the way the adapter // is implemented so that it was mart enough to handle different scopes. This // has been added to the backlog: -// https://github.com/overmindtech/aws-source/issues/68 -func NewPolicySource(client *iam.Client, accountID string, _ string) *sources.GetListSource[*PolicyDetails, IAMClient, *iam.Options] { - return &sources.GetListSource[*PolicyDetails, IAMClient, *iam.Options]{ - ItemType: "iam-policy", - Client: client, - CacheDuration: 3 * time.Hour, // IAM has very low rate limits, we need to cache for a long time - AccountID: accountID, - Region: "", // IAM policies aren't tied to a region - +// https://github.com/overmindtech/aws-adapter/issues/68 +func NewPolicyAdapter(client *iam.Client, accountID string, _ string) *adapters.GetListAdapter[*PolicyDetails, IAMClient, *iam.Options] { + return &adapters.GetListAdapter[*PolicyDetails, IAMClient, *iam.Options]{ + ItemType: "iam-policy", + Client: client, + CacheDuration: 3 * time.Hour, // IAM has very low rate limits, we need to cache for a long time + AccountID: accountID, + Region: "", // IAM policies aren't tied to a region + AdapterMetadata: PolicyMetadata(), // Some IAM policies are global, this means that their ARN doesn't // contain an account name and instead just says "aws". Enabling this // setting means these also work @@ -358,3 +357,30 @@ func NewPolicySource(client *iam.Client, accountID string, _ string) *sources.Ge ItemMapper: policyItemMapper, } } + +func PolicyMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "iam-policy", + DescriptiveName: "IAM Policy", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get an IAM policy by policyFullName ({path} + {policyName})", + ListDescription: "List all IAM policies", + SearchDescription: "Search for IAM policies by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + { + TerraformQueryMap: "aws_iam_policy.arn", + TerraformMethod: sdp.QueryMethod_SEARCH, + }, + { + TerraformQueryMap: "aws_iam_user_policy_attachment.policy_arn", + TerraformMethod: sdp.QueryMethod_SEARCH, + }, + }, + PotentialLinks: []string{"iam-group", "iam-user", "iam-role"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_SECURITY, + } +} diff --git a/sources/iam/policy_test.go b/adapters/iam/policy_test.go similarity index 68% rename from sources/iam/policy_test.go rename to adapters/iam/policy_test.go index a1c2b6fc..4218426a 100644 --- a/sources/iam/policy_test.go +++ b/adapters/iam/policy_test.go @@ -9,23 +9,23 @@ import ( "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/iam" "github.com/aws/aws-sdk-go-v2/service/iam/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) func (t *TestIAMClient) GetPolicy(ctx context.Context, params *iam.GetPolicyInput, optFns ...func(*iam.Options)) (*iam.GetPolicyOutput, error) { return &iam.GetPolicyOutput{ Policy: &types.Policy{ - PolicyName: sources.PtrString("AWSControlTowerStackSetRolePolicy"), - PolicyId: sources.PtrString("ANPA3VLV2U277MP54R2OV"), - Arn: sources.PtrString("arn:aws:iam::801795385023:policy/service-role/AWSControlTowerStackSetRolePolicy"), - Path: sources.PtrString("/service-role/"), - DefaultVersionId: sources.PtrString("v1"), - AttachmentCount: sources.PtrInt32(1), - PermissionsBoundaryUsageCount: sources.PtrInt32(0), + PolicyName: adapters.PtrString("AWSControlTowerStackSetRolePolicy"), + PolicyId: adapters.PtrString("ANPA3VLV2U277MP54R2OV"), + Arn: adapters.PtrString("arn:aws:iam::801795385023:policy/service-role/AWSControlTowerStackSetRolePolicy"), + Path: adapters.PtrString("/service-role/"), + DefaultVersionId: adapters.PtrString("v1"), + AttachmentCount: adapters.PtrInt32(1), + PermissionsBoundaryUsageCount: adapters.PtrInt32(0), IsAttachable: true, - CreateDate: sources.PtrTime(time.Now()), - UpdateDate: sources.PtrTime(time.Now()), + CreateDate: adapters.PtrTime(time.Now()), + UpdateDate: adapters.PtrTime(time.Now()), }, }, nil } @@ -34,20 +34,20 @@ func (t *TestIAMClient) ListEntitiesForPolicy(context.Context, *iam.ListEntities return &iam.ListEntitiesForPolicyOutput{ PolicyGroups: []types.PolicyGroup{ { - GroupId: sources.PtrString("groupId"), - GroupName: sources.PtrString("groupName"), + GroupId: adapters.PtrString("groupId"), + GroupName: adapters.PtrString("groupName"), }, }, PolicyRoles: []types.PolicyRole{ { - RoleId: sources.PtrString("roleId"), - RoleName: sources.PtrString("roleName"), + RoleId: adapters.PtrString("roleId"), + RoleName: adapters.PtrString("roleName"), }, }, PolicyUsers: []types.PolicyUser{ { - UserId: sources.PtrString("userId"), - UserName: sources.PtrString("userName"), + UserId: adapters.PtrString("userId"), + UserName: adapters.PtrString("userName"), }, }, }, nil @@ -57,28 +57,28 @@ func (t *TestIAMClient) ListPolicies(context.Context, *iam.ListPoliciesInput, .. return &iam.ListPoliciesOutput{ Policies: []types.Policy{ { - PolicyName: sources.PtrString("AWSControlTowerAdminPolicy"), - PolicyId: sources.PtrString("ANPA3VLV2U2745H37HTHN"), - Arn: sources.PtrString("arn:aws:iam::801795385023:policy/service-role/AWSControlTowerAdminPolicy"), - Path: sources.PtrString("/service-role/"), - DefaultVersionId: sources.PtrString("v1"), - AttachmentCount: sources.PtrInt32(1), - PermissionsBoundaryUsageCount: sources.PtrInt32(0), + PolicyName: adapters.PtrString("AWSControlTowerAdminPolicy"), + PolicyId: adapters.PtrString("ANPA3VLV2U2745H37HTHN"), + Arn: adapters.PtrString("arn:aws:iam::801795385023:policy/service-role/AWSControlTowerAdminPolicy"), + Path: adapters.PtrString("/service-role/"), + DefaultVersionId: adapters.PtrString("v1"), + AttachmentCount: adapters.PtrInt32(1), + PermissionsBoundaryUsageCount: adapters.PtrInt32(0), IsAttachable: true, - CreateDate: sources.PtrTime(time.Now()), - UpdateDate: sources.PtrTime(time.Now()), + CreateDate: adapters.PtrTime(time.Now()), + UpdateDate: adapters.PtrTime(time.Now()), }, { - PolicyName: sources.PtrString("AWSControlTowerCloudTrailRolePolicy"), - PolicyId: sources.PtrString("ANPA3VLV2U27UOP7KSM6I"), - Arn: sources.PtrString("arn:aws:iam::801795385023:policy/service-role/AWSControlTowerCloudTrailRolePolicy"), - Path: sources.PtrString("/service-role/"), - DefaultVersionId: sources.PtrString("v1"), - AttachmentCount: sources.PtrInt32(1), - PermissionsBoundaryUsageCount: sources.PtrInt32(0), + PolicyName: adapters.PtrString("AWSControlTowerCloudTrailRolePolicy"), + PolicyId: adapters.PtrString("ANPA3VLV2U27UOP7KSM6I"), + Arn: adapters.PtrString("arn:aws:iam::801795385023:policy/service-role/AWSControlTowerCloudTrailRolePolicy"), + Path: adapters.PtrString("/service-role/"), + DefaultVersionId: adapters.PtrString("v1"), + AttachmentCount: adapters.PtrInt32(1), + PermissionsBoundaryUsageCount: adapters.PtrInt32(0), IsAttachable: true, - CreateDate: sources.PtrTime(time.Now()), - UpdateDate: sources.PtrTime(time.Now()), + CreateDate: adapters.PtrTime(time.Now()), + UpdateDate: adapters.PtrTime(time.Now()), }, }, }, nil @@ -88,8 +88,8 @@ func (t *TestIAMClient) ListPolicyTags(ctx context.Context, params *iam.ListPoli return &iam.ListPolicyTagsOutput{ Tags: []types.Tag{ { - Key: sources.PtrString("foo"), - Value: sources.PtrString("foo"), + Key: adapters.PtrString("foo"), + Value: adapters.PtrString("foo"), }, }, }, nil @@ -220,7 +220,7 @@ func TestPolicyListFunc(t *testing.T) { func TestPolicyListTagsFunc(t *testing.T) { tags, err := policyListTagsFunc(context.Background(), &PolicyDetails{ Policy: &types.Policy{ - Arn: sources.PtrString("arn:aws:iam::801795385023:policy/service-role/AWSControlTowerAdminPolicy"), + Arn: adapters.PtrString("arn:aws:iam::801795385023:policy/service-role/AWSControlTowerAdminPolicy"), }, }, &TestIAMClient{}) @@ -236,33 +236,33 @@ func TestPolicyListTagsFunc(t *testing.T) { func TestPolicyItemMapper(t *testing.T) { details := &PolicyDetails{ Policy: &types.Policy{ - PolicyName: sources.PtrString("AWSControlTowerAdminPolicy"), - PolicyId: sources.PtrString("ANPA3VLV2U2745H37HTHN"), - Arn: sources.PtrString("arn:aws:iam::801795385023:policy/service-role/AWSControlTowerAdminPolicy"), - Path: sources.PtrString("/service-role/"), - DefaultVersionId: sources.PtrString("v1"), - AttachmentCount: sources.PtrInt32(1), - PermissionsBoundaryUsageCount: sources.PtrInt32(0), + PolicyName: adapters.PtrString("AWSControlTowerAdminPolicy"), + PolicyId: adapters.PtrString("ANPA3VLV2U2745H37HTHN"), + Arn: adapters.PtrString("arn:aws:iam::801795385023:policy/service-role/AWSControlTowerAdminPolicy"), + Path: adapters.PtrString("/service-role/"), + DefaultVersionId: adapters.PtrString("v1"), + AttachmentCount: adapters.PtrInt32(1), + PermissionsBoundaryUsageCount: adapters.PtrInt32(0), IsAttachable: true, - CreateDate: sources.PtrTime(time.Now()), - UpdateDate: sources.PtrTime(time.Now()), + CreateDate: adapters.PtrTime(time.Now()), + UpdateDate: adapters.PtrTime(time.Now()), }, PolicyGroups: []types.PolicyGroup{ { - GroupId: sources.PtrString("groupId"), - GroupName: sources.PtrString("groupName"), + GroupId: adapters.PtrString("groupId"), + GroupName: adapters.PtrString("groupName"), }, }, PolicyRoles: []types.PolicyRole{ { - RoleId: sources.PtrString("roleId"), - RoleName: sources.PtrString("roleName"), + RoleId: adapters.PtrString("roleId"), + RoleName: adapters.PtrString("roleName"), }, }, PolicyUsers: []types.PolicyUser{ { - UserId: sources.PtrString("userId"), - UserName: sources.PtrString("userName"), + UserId: adapters.PtrString("userId"), + UserName: adapters.PtrString("userName"), }, }, } @@ -280,7 +280,7 @@ func TestPolicyItemMapper(t *testing.T) { t.Error(err) } - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "iam-group", ExpectedMethod: sdp.QueryMethod_GET, @@ -320,17 +320,17 @@ func TestPolicyItemMapper(t *testing.T) { } } -func TestNewPolicySource(t *testing.T) { - config, account, region := sources.GetAutoConfig(t) +func TestNewPolicyAdapter(t *testing.T) { + config, account, region := adapters.GetAutoConfig(t) client := iam.NewFromConfig(config, func(o *iam.Options) { o.RetryMode = aws.RetryModeAdaptive o.RetryMaxAttempts = 10 }) - source := NewPolicySource(client, account, region) + adapter := NewPolicyAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 30 * time.Second, } @@ -344,7 +344,7 @@ func TestNewPolicySource(t *testing.T) { t.Parallel() // This item shouldn't be found since it lives globally - _, err := source.Get(ctx, sources.FormatScope(account, ""), "ReadOnlyAccess", false) + _, err := adapter.Get(ctx, adapters.FormatScope(account, ""), "ReadOnlyAccess", false) if err == nil { t.Error("expected error, got nil") @@ -357,7 +357,7 @@ func TestNewPolicySource(t *testing.T) { t.Parallel() // This item shouldn't be found since it lives globally - item, err := source.Get(ctx, "aws", "ReadOnlyAccess", false) + item, err := adapter.Get(ctx, "aws", "ReadOnlyAccess", false) if err != nil { t.Error(err) @@ -372,7 +372,7 @@ func TestNewPolicySource(t *testing.T) { ctx, span := tracer.Start(context.Background(), t.Name()) defer span.End() - items, err := source.List(ctx, sources.FormatScope(account, ""), false) + items, err := adapter.List(ctx, adapters.FormatScope(account, ""), false) if err != nil { t.Error(err) @@ -385,7 +385,7 @@ func TestNewPolicySource(t *testing.T) { t.Errorf("expected item to have an arn attribute, got %v", err) } - arn, err := sources.ParseARN(arnString.(string)) + arn, err := adapters.ParseARN(arnString.(string)) if err != nil { t.Error(err) @@ -404,7 +404,7 @@ func TestNewPolicySource(t *testing.T) { arn, _ := items[0].GetAttributes().Get("Arn") - _, err := source.Search(ctx, sources.FormatScope(account, ""), arn.(string), false) + _, err := adapter.Search(ctx, adapters.FormatScope(account, ""), arn.(string), false) if err != nil { t.Error(err) @@ -419,7 +419,7 @@ func TestNewPolicySource(t *testing.T) { arn, _ := items[0].GetAttributes().Get("Arn") - _, err := source.Search(ctx, "aws", arn.(string), false) + _, err := adapter.Search(ctx, "aws", arn.(string), false) if err == nil { t.Error("expected error, got nil") @@ -431,7 +431,7 @@ func TestNewPolicySource(t *testing.T) { ctx, span := tracer.Start(context.Background(), t.Name()) defer span.End() - items, err := source.List(ctx, "aws", false) + items, err := adapter.List(ctx, "aws", false) if err != nil { t.Error(err) } @@ -447,7 +447,7 @@ func TestNewPolicySource(t *testing.T) { t.Errorf("expected item to have an arn attribute, got %v", err) } - arn, err := sources.ParseARN(arnString.(string)) + arn, err := adapters.ParseARN(arnString.(string)) if err != nil { t.Error(err) @@ -466,7 +466,7 @@ func TestNewPolicySource(t *testing.T) { arn, _ := items[0].GetAttributes().Get("Arn") - _, err := source.Search(ctx, sources.FormatScope(account, ""), arn.(string), false) + _, err := adapter.Search(ctx, adapters.FormatScope(account, ""), arn.(string), false) if err == nil { t.Error("expected error, got nil") @@ -481,7 +481,7 @@ func TestNewPolicySource(t *testing.T) { arn, _ := items[0].GetAttributes().Get("Arn") - _, err := source.Search(ctx, "aws", arn.(string), false) + _, err := adapter.Search(ctx, "aws", arn.(string), false) if err != nil { t.Error(err) diff --git a/sources/iam/role.go b/adapters/iam/role.go similarity index 84% rename from sources/iam/role.go rename to adapters/iam/role.go index 3c291825..6bf63bb5 100644 --- a/sources/iam/role.go +++ b/adapters/iam/role.go @@ -11,7 +11,7 @@ import ( "github.com/micahhausler/aws-iam-policy/policy" "go.opentelemetry.io/otel/attribute" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" "github.com/sourcegraph/conc/iter" ) @@ -220,7 +220,7 @@ func roleItemMapper(_, scope string, awsItem *RoleDetails) (*sdp.Item, error) { enrichedRole.AssumeRolePolicyDocument = policyDoc } - attributes, err := sources.ToAttributesWithExclude(enrichedRole) + attributes, err := adapters.ToAttributesWithExclude(enrichedRole) if err != nil { return nil, err @@ -235,14 +235,14 @@ func roleItemMapper(_, scope string, awsItem *RoleDetails) (*sdp.Item, error) { for _, policy := range awsItem.AttachedPolicies { if policy.PolicyArn != nil { - if a, err := sources.ParseARN(*policy.PolicyArn); err == nil { + if a, err := adapters.ParseARN(*policy.PolicyArn); err == nil { // +overmind:link iam-policy item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "iam-policy", Method: sdp.QueryMethod_SEARCH, Query: *policy.PolicyArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changing the policy will affect the role @@ -279,7 +279,7 @@ func roleListTagsFunc(ctx context.Context, r *RoleDetails, client IAMClient) (ma out, err := paginator.NextPage(ctx) if err != nil { - return sources.HandleTagsError(ctx, err), nil + return adapters.HandleTagsError(ctx, err), nil } for _, tag := range out.Tags { @@ -302,12 +302,13 @@ func roleListTagsFunc(ctx context.Context, r *RoleDetails, client IAMClient) (ma // +overmind:terraform:queryMap aws_iam_role.arn // +overmind:terraform:method SEARCH -func NewRoleSource(client *iam.Client, accountID string, region string) *sources.GetListSource[*RoleDetails, IAMClient, *iam.Options] { - return &sources.GetListSource[*RoleDetails, IAMClient, *iam.Options]{ - ItemType: "iam-role", - Client: client, - CacheDuration: 3 * time.Hour, // IAM has very low rate limits, we need to cache for a long time - AccountID: accountID, +func NewRoleAdapter(client *iam.Client, accountID string, region string) *adapters.GetListAdapter[*RoleDetails, IAMClient, *iam.Options] { + return &adapters.GetListAdapter[*RoleDetails, IAMClient, *iam.Options]{ + ItemType: "iam-role", + Client: client, + CacheDuration: 3 * time.Hour, // IAM has very low rate limits, we need to cache for a long time + AccountID: accountID, + AdapterMetadata: RoleMetadata(), GetFunc: func(ctx context.Context, client IAMClient, scope, query string) (*RoleDetails, error) { return roleGetFunc(ctx, client, scope, query) }, @@ -318,3 +319,26 @@ func NewRoleSource(client *iam.Client, accountID string, region string) *sources ItemMapper: roleItemMapper, } } + +func RoleMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "iam-role", + DescriptiveName: "IAM Role", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get an IAM role by name", + ListDescription: "List all IAM roles", + SearchDescription: "Search for IAM roles by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + { + TerraformQueryMap: "aws_iam_role.arn", + TerraformMethod: sdp.QueryMethod_SEARCH, + }, + }, + PotentialLinks: []string{"iam-policy"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_SECURITY, + } +} diff --git a/sources/iam/role_test.go b/adapters/iam/role_test.go similarity index 59% rename from sources/iam/role_test.go rename to adapters/iam/role_test.go index 86800abf..ee507691 100644 --- a/sources/iam/role_test.go +++ b/adapters/iam/role_test.go @@ -11,20 +11,20 @@ import ( "github.com/aws/aws-sdk-go-v2/service/iam" "github.com/aws/aws-sdk-go-v2/service/iam/types" "github.com/micahhausler/aws-iam-policy/policy" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) func (t *TestIAMClient) GetRole(ctx context.Context, params *iam.GetRoleInput, optFns ...func(*iam.Options)) (*iam.GetRoleOutput, error) { return &iam.GetRoleOutput{ Role: &types.Role{ - Path: sources.PtrString("/service-role/"), - RoleName: sources.PtrString("AWSControlTowerConfigAggregatorRoleForOrganizations"), - RoleId: sources.PtrString("AROA3VLV2U27YSTBFCGCJ"), - Arn: sources.PtrString("arn:aws:iam::801795385023:role/service-role/AWSControlTowerConfigAggregatorRoleForOrganizations"), - CreateDate: sources.PtrTime(time.Now()), - AssumeRolePolicyDocument: sources.PtrString("FOO"), - MaxSessionDuration: sources.PtrInt32(3600), + Path: adapters.PtrString("/service-role/"), + RoleName: adapters.PtrString("AWSControlTowerConfigAggregatorRoleForOrganizations"), + RoleId: adapters.PtrString("AROA3VLV2U27YSTBFCGCJ"), + Arn: adapters.PtrString("arn:aws:iam::801795385023:role/service-role/AWSControlTowerConfigAggregatorRoleForOrganizations"), + CreateDate: adapters.PtrTime(time.Now()), + AssumeRolePolicyDocument: adapters.PtrString("FOO"), + MaxSessionDuration: adapters.PtrInt32(3600), }, }, nil } @@ -42,13 +42,13 @@ func (t *TestIAMClient) ListRoles(context.Context, *iam.ListRolesInput, ...func( return &iam.ListRolesOutput{ Roles: []types.Role{ { - Path: sources.PtrString("/service-role/"), - RoleName: sources.PtrString("AWSControlTowerConfigAggregatorRoleForOrganizations"), - RoleId: sources.PtrString("AROA3VLV2U27YSTBFCGCJ"), - Arn: sources.PtrString("arn:aws:iam::801795385023:role/service-role/AWSControlTowerConfigAggregatorRoleForOrganizations"), - CreateDate: sources.PtrTime(time.Now()), - AssumeRolePolicyDocument: sources.PtrString("FOO"), - MaxSessionDuration: sources.PtrInt32(3600), + Path: adapters.PtrString("/service-role/"), + RoleName: adapters.PtrString("AWSControlTowerConfigAggregatorRoleForOrganizations"), + RoleId: adapters.PtrString("AROA3VLV2U27YSTBFCGCJ"), + Arn: adapters.PtrString("arn:aws:iam::801795385023:role/service-role/AWSControlTowerConfigAggregatorRoleForOrganizations"), + CreateDate: adapters.PtrTime(time.Now()), + AssumeRolePolicyDocument: adapters.PtrString("FOO"), + MaxSessionDuration: adapters.PtrInt32(3600), }, }, }, nil @@ -58,8 +58,8 @@ func (t *TestIAMClient) ListRoleTags(ctx context.Context, params *iam.ListRoleTa return &iam.ListRoleTagsOutput{ Tags: []types.Tag{ { - Key: sources.PtrString("foo"), - Value: sources.PtrString("bar"), + Key: adapters.PtrString("foo"), + Value: adapters.PtrString("bar"), }, }, }, nil @@ -68,7 +68,7 @@ func (t *TestIAMClient) ListRoleTags(ctx context.Context, params *iam.ListRoleTa func (t *TestIAMClient) GetRolePolicy(ctx context.Context, params *iam.GetRolePolicyInput, optFns ...func(*iam.Options)) (*iam.GetRolePolicyOutput, error) { return &iam.GetRolePolicyOutput{ PolicyName: params.PolicyName, - PolicyDocument: sources.PtrString(`{ + PolicyDocument: adapters.PtrString(`{ "Version": "2012-10-17", "Statement": [ { @@ -87,12 +87,12 @@ func (t *TestIAMClient) ListAttachedRolePolicies(ctx context.Context, params *ia return &iam.ListAttachedRolePoliciesOutput{ AttachedPolicies: []types.AttachedPolicy{ { - PolicyArn: sources.PtrString("arn:aws:iam::aws:policy/AdministratorAccess"), - PolicyName: sources.PtrString("AdministratorAccess"), + PolicyArn: adapters.PtrString("arn:aws:iam::aws:policy/AdministratorAccess"), + PolicyName: adapters.PtrString("AdministratorAccess"), }, { - PolicyArn: sources.PtrString("arn:aws:iam::aws:policy/AmazonS3FullAccess"), - PolicyName: sources.PtrString("AmazonS3FullAccess"), + PolicyArn: adapters.PtrString("arn:aws:iam::aws:policy/AmazonS3FullAccess"), + PolicyName: adapters.PtrString("AmazonS3FullAccess"), }, }, }, nil @@ -133,7 +133,7 @@ func TestRoleListFunc(t *testing.T) { func TestRoleListTagsFunc(t *testing.T) { tags, err := roleListTagsFunc(context.Background(), &RoleDetails{ Role: &types.Role{ - Arn: sources.PtrString("arn:aws:iam::801795385023:role/service-role/AWSControlTowerConfigAggregatorRoleForOrganizations"), + Arn: adapters.PtrString("arn:aws:iam::801795385023:role/service-role/AWSControlTowerConfigAggregatorRoleForOrganizations"), }, }, &TestIAMClient{}) @@ -167,21 +167,21 @@ func TestRoleItemMapper(t *testing.T) { role := RoleDetails{ Role: &types.Role{ - Path: sources.PtrString("/service-role/"), - RoleName: sources.PtrString("AWSControlTowerConfigAggregatorRoleForOrganizations"), - RoleId: sources.PtrString("AROA3VLV2U27YSTBFCGCJ"), - Arn: sources.PtrString("arn:aws:iam::801795385023:role/service-role/AWSControlTowerConfigAggregatorRoleForOrganizations"), - CreateDate: sources.PtrTime(time.Now()), - AssumeRolePolicyDocument: sources.PtrString(`%7B%22Version%22%3A%222012-10-17%22%2C%22Statement%22%3A%5B%7B%22Effect%22%3A%22Allow%22%2C%22Principal%22%3A%7B%22Service%22%3A%22config.amazonaws.com%22%7D%2C%22Action%22%3A%22sts%3AAssumeRole%22%7D%5D%7D`), - MaxSessionDuration: sources.PtrInt32(3600), - Description: sources.PtrString("description"), + Path: adapters.PtrString("/service-role/"), + RoleName: adapters.PtrString("AWSControlTowerConfigAggregatorRoleForOrganizations"), + RoleId: adapters.PtrString("AROA3VLV2U27YSTBFCGCJ"), + Arn: adapters.PtrString("arn:aws:iam::801795385023:role/service-role/AWSControlTowerConfigAggregatorRoleForOrganizations"), + CreateDate: adapters.PtrTime(time.Now()), + AssumeRolePolicyDocument: adapters.PtrString(`%7B%22Version%22%3A%222012-10-17%22%2C%22Statement%22%3A%5B%7B%22Effect%22%3A%22Allow%22%2C%22Principal%22%3A%7B%22Service%22%3A%22config.amazonaws.com%22%7D%2C%22Action%22%3A%22sts%3AAssumeRole%22%7D%5D%7D`), + MaxSessionDuration: adapters.PtrInt32(3600), + Description: adapters.PtrString("description"), PermissionsBoundary: &types.AttachedPermissionsBoundary{ - PermissionsBoundaryArn: sources.PtrString("arn:aws:iam::801795385023:role/service-role/AWSControlTowerConfigAggregatorRoleForOrganizations"), + PermissionsBoundaryArn: adapters.PtrString("arn:aws:iam::801795385023:role/service-role/AWSControlTowerConfigAggregatorRoleForOrganizations"), PermissionsBoundaryType: types.PermissionsBoundaryAttachmentTypePolicy, }, RoleLastUsed: &types.RoleLastUsed{ - LastUsedDate: sources.PtrTime(time.Now()), - Region: sources.PtrString("us-east-2"), + LastUsedDate: adapters.PtrTime(time.Now()), + Region: adapters.PtrString("us-east-2"), }, }, EmbeddedPolicies: []embeddedPolicy{ @@ -192,8 +192,8 @@ func TestRoleItemMapper(t *testing.T) { }, AttachedPolicies: []types.AttachedPolicy{ { - PolicyArn: sources.PtrString("arn:aws:iam::aws:policy/AdministratorAccess"), - PolicyName: sources.PtrString("AdministratorAccess"), + PolicyArn: adapters.PtrString("arn:aws:iam::aws:policy/AdministratorAccess"), + PolicyName: adapters.PtrString("AdministratorAccess"), }, }, } @@ -208,7 +208,7 @@ func TestRoleItemMapper(t *testing.T) { t.Fatal(err) } - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "iam-policy", ExpectedMethod: sdp.QueryMethod_SEARCH, @@ -222,17 +222,17 @@ func TestRoleItemMapper(t *testing.T) { fmt.Println(item.ToMap()) } -func TestNewRoleSource(t *testing.T) { - config, account, region := sources.GetAutoConfig(t) +func TestNewRoleAdapter(t *testing.T) { + config, account, region := adapters.GetAutoConfig(t) client := iam.NewFromConfig(config, func(o *iam.Options) { o.RetryMode = aws.RetryModeAdaptive o.RetryMaxAttempts = 10 }) - source := NewRoleSource(client, account, region) + adapter := NewRoleAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 30 * time.Hour, } diff --git a/sources/iam/shared.go b/adapters/iam/shared.go similarity index 94% rename from sources/iam/shared.go rename to adapters/iam/shared.go index 884eca38..c9c09e8e 100644 --- a/sources/iam/shared.go +++ b/adapters/iam/shared.go @@ -9,7 +9,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/iam" "github.com/micahhausler/aws-iam-policy/policy" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -39,7 +39,7 @@ type IAMClient interface { func LinksFromPolicy(document *policy.Policy) []*sdp.LinkedItemQuery { // We want to link all of the resources in the policy document, as long // as they have a valid ARN - var arn *sources.ARN + var arn *adapters.ARN var err error queries := make([]*sdp.LinkedItemQuery, 0) @@ -54,7 +54,7 @@ func LinksFromPolicy(document *policy.Policy) []*sdp.LinkedItemQuery { if awsPrincipal := statement.Principal.AWS(); awsPrincipal != nil { for _, value := range awsPrincipal.Values() { // These are in the format of ARN so we'll parse them - if arn, err := sources.ParseARN(value); err == nil { + if arn, err := adapters.ParseARN(value); err == nil { var typ string switch arn.Type() { case "role": @@ -69,7 +69,7 @@ func LinksFromPolicy(document *policy.Policy) []*sdp.LinkedItemQuery { Type: "iam-role", Method: sdp.QueryMethod_SEARCH, Query: arn.String(), - Scope: sources.FormatScope(arn.AccountID, arn.Region), + Scope: adapters.FormatScope(arn.AccountID, arn.Region), }, BlastPropagation: &sdp.BlastPropagation{ // If a user or role iex explicitly @@ -87,7 +87,7 @@ func LinksFromPolicy(document *policy.Policy) []*sdp.LinkedItemQuery { if statement.Resource != nil { for _, resource := range statement.Resource.Values() { - arn, err = sources.ParseARN(resource) + arn, err = adapters.ParseARN(resource) if err != nil { continue } @@ -104,7 +104,7 @@ func LinksFromPolicy(document *policy.Policy) []*sdp.LinkedItemQuery { scope := sdp.WILDCARD if arn.AccountID != "aws" { // If we have an account and region, then use those - scope = sources.FormatScope(arn.AccountID, arn.Region) + scope = adapters.FormatScope(arn.AccountID, arn.Region) } // It would be good here if we had a way to definitely know what diff --git a/sources/iam/shared_test.go b/adapters/iam/shared_test.go similarity index 100% rename from sources/iam/shared_test.go rename to adapters/iam/shared_test.go diff --git a/sources/iam/tracing.go b/adapters/iam/tracing.go similarity index 82% rename from sources/iam/tracing.go rename to adapters/iam/tracing.go index 5dc5c1d2..4de90254 100644 --- a/sources/iam/tracing.go +++ b/adapters/iam/tracing.go @@ -7,7 +7,7 @@ import ( ) const ( - instrumentationName = "github.com/overmindtech/aws-source/sources/iam" + instrumentationName = "github.com/overmindtech/aws-source/adapters/iam" instrumentationVersion = "0.0.1" ) diff --git a/sources/iam/user.go b/adapters/iam/user.go similarity index 76% rename from sources/iam/user.go rename to adapters/iam/user.go index 1e4fc6fa..259a866d 100644 --- a/sources/iam/user.go +++ b/adapters/iam/user.go @@ -8,7 +8,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/iam" "github.com/aws/aws-sdk-go-v2/service/iam/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -113,7 +113,7 @@ func userListFunc(ctx context.Context, client IAMClient, _ string) ([]*UserDetai } func userItemMapper(_, scope string, awsItem *UserDetails) (*sdp.Item, error) { - attributes, err := sources.ToAttributesWithExclude(awsItem.User) + attributes, err := adapters.ToAttributesWithExclude(awsItem.User) if err != nil { return nil, err @@ -158,7 +158,7 @@ func userListTagsFunc(ctx context.Context, u *UserDetails, client IAMClient) (ma out, err := paginator.NextPage(ctx) if err != nil { - return sources.HandleTagsError(ctx, err), nil + return adapters.HandleTagsError(ctx, err), nil } for _, tag := range out.Tags { @@ -181,13 +181,14 @@ func userListTagsFunc(ctx context.Context, u *UserDetails, client IAMClient) (ma // +overmind:terraform:queryMap aws_iam_user.arn // +overmind:terraform:method SEARCH -func NewUserSource(client *iam.Client, accountID string, region string) *sources.GetListSource[*UserDetails, IAMClient, *iam.Options] { - return &sources.GetListSource[*UserDetails, IAMClient, *iam.Options]{ - ItemType: "iam-user", - Client: client, - AccountID: accountID, - CacheDuration: 3 * time.Hour, // IAM has very low rate limits, we need to cache for a long time - Region: region, +func NewUserAdapter(client *iam.Client, accountID string, region string) *adapters.GetListAdapter[*UserDetails, IAMClient, *iam.Options] { + return &adapters.GetListAdapter[*UserDetails, IAMClient, *iam.Options]{ + ItemType: "iam-user", + Client: client, + AccountID: accountID, + CacheDuration: 3 * time.Hour, // IAM has very low rate limits, we need to cache for a long time + Region: region, + AdapterMetadata: UserMetadata(), GetFunc: func(ctx context.Context, client IAMClient, scope, query string) (*UserDetails, error) { return userGetFunc(ctx, client, scope, query) }, @@ -198,3 +199,26 @@ func NewUserSource(client *iam.Client, accountID string, region string) *sources ItemMapper: userItemMapper, } } + +func UserMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "iam-user", + DescriptiveName: "IAM User", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get an IAM user by name", + ListDescription: "List all IAM users", + SearchDescription: "Search for IAM users by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + { + TerraformQueryMap: "aws_iam_user.arn", + TerraformMethod: sdp.QueryMethod_SEARCH, + }, + }, + PotentialLinks: []string{"iam-group"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_SECURITY, + } +} diff --git a/sources/iam/user_test.go b/adapters/iam/user_test.go similarity index 64% rename from sources/iam/user_test.go rename to adapters/iam/user_test.go index e7802f44..45754565 100644 --- a/sources/iam/user_test.go +++ b/adapters/iam/user_test.go @@ -10,7 +10,7 @@ import ( "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/iam" "github.com/aws/aws-sdk-go-v2/service/iam/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -19,7 +19,7 @@ func (t *TestIAMClient) ListGroupsForUser(ctx context.Context, params *iam.ListG marker := params.Marker if marker == nil { - marker = sources.PtrString("0") + marker = adapters.PtrString("0") } // Get the current page @@ -32,17 +32,17 @@ func (t *TestIAMClient) ListGroupsForUser(ctx context.Context, params *iam.ListG isTruncated = false marker = nil } else { - marker = sources.PtrString(fmt.Sprint(markerInt)) + marker = adapters.PtrString(fmt.Sprint(markerInt)) } return &iam.ListGroupsForUserOutput{ Groups: []types.Group{ { - Arn: sources.PtrString("arn:aws:iam::801795385023:Group/something"), - CreateDate: sources.PtrTime(time.Now()), - GroupId: sources.PtrString("id"), - GroupName: sources.PtrString(fmt.Sprintf("group-%v", marker)), - Path: sources.PtrString("/"), + Arn: adapters.PtrString("arn:aws:iam::801795385023:Group/something"), + CreateDate: adapters.PtrTime(time.Now()), + GroupId: adapters.PtrString("id"), + GroupName: adapters.PtrString(fmt.Sprintf("group-%v", marker)), + Path: adapters.PtrString("/"), }, }, IsTruncated: isTruncated, @@ -53,11 +53,11 @@ func (t *TestIAMClient) ListGroupsForUser(ctx context.Context, params *iam.ListG func (t *TestIAMClient) GetUser(ctx context.Context, params *iam.GetUserInput, optFns ...func(*iam.Options)) (*iam.GetUserOutput, error) { return &iam.GetUserOutput{ User: &types.User{ - Path: sources.PtrString("/"), - UserName: sources.PtrString("power-users"), - UserId: sources.PtrString("AGPA3VLV2U27T6SSLJMDS"), - Arn: sources.PtrString("arn:aws:iam::801795385023:User/power-users"), - CreateDate: sources.PtrTime(time.Now()), + Path: adapters.PtrString("/"), + UserName: adapters.PtrString("power-users"), + UserId: adapters.PtrString("AGPA3VLV2U27T6SSLJMDS"), + Arn: adapters.PtrString("arn:aws:iam::801795385023:User/power-users"), + CreateDate: adapters.PtrTime(time.Now()), }, }, nil } @@ -67,7 +67,7 @@ func (t *TestIAMClient) ListUsers(ctx context.Context, params *iam.ListUsersInpu marker := params.Marker if marker == nil { - marker = sources.PtrString("0") + marker = adapters.PtrString("0") } // Get the current page @@ -80,17 +80,17 @@ func (t *TestIAMClient) ListUsers(ctx context.Context, params *iam.ListUsersInpu isTruncated = false marker = nil } else { - marker = sources.PtrString(fmt.Sprint(markerInt)) + marker = adapters.PtrString(fmt.Sprint(markerInt)) } return &iam.ListUsersOutput{ Users: []types.User{ { - Path: sources.PtrString("/"), - UserName: sources.PtrString(fmt.Sprintf("user-%v", marker)), - UserId: sources.PtrString("AGPA3VLV2U27T6SSLJMDS"), - Arn: sources.PtrString("arn:aws:iam::801795385023:User/power-users"), - CreateDate: sources.PtrTime(time.Now()), + Path: adapters.PtrString("/"), + UserName: adapters.PtrString(fmt.Sprintf("user-%v", marker)), + UserId: adapters.PtrString("AGPA3VLV2U27T6SSLJMDS"), + Arn: adapters.PtrString("arn:aws:iam::801795385023:User/power-users"), + CreateDate: adapters.PtrTime(time.Now()), }, }, IsTruncated: isTruncated, @@ -102,8 +102,8 @@ func (t *TestIAMClient) ListUserTags(context.Context, *iam.ListUserTagsInput, .. return &iam.ListUserTagsOutput{ Tags: []types.Tag{ { - Key: sources.PtrString("foo"), - Value: sources.PtrString("bar"), + Key: adapters.PtrString("foo"), + Value: adapters.PtrString("bar"), }, }, IsTruncated: false, @@ -112,7 +112,7 @@ func (t *TestIAMClient) ListUserTags(context.Context, *iam.ListUserTagsInput, .. } func TestGetUserGroups(t *testing.T) { - groups, err := getUserGroups(context.Background(), &TestIAMClient{}, sources.PtrString("foo")) + groups, err := getUserGroups(context.Background(), &TestIAMClient{}, adapters.PtrString("foo")) if err != nil { t.Error(err) @@ -161,7 +161,7 @@ func TestUserListFunc(t *testing.T) { func TestUserListTagsFunc(t *testing.T) { tags, err := userListTagsFunc(context.Background(), &UserDetails{ User: &types.User{ - UserName: sources.PtrString("foo"), + UserName: adapters.PtrString("foo"), }, }, &TestIAMClient{}) @@ -177,19 +177,19 @@ func TestUserListTagsFunc(t *testing.T) { func TestUserItemMapper(t *testing.T) { details := UserDetails{ User: &types.User{ - Path: sources.PtrString("/"), - UserName: sources.PtrString("power-users"), - UserId: sources.PtrString("AGPA3VLV2U27T6SSLJMDS"), - Arn: sources.PtrString("arn:aws:iam::801795385023:User/power-users"), - CreateDate: sources.PtrTime(time.Now()), + Path: adapters.PtrString("/"), + UserName: adapters.PtrString("power-users"), + UserId: adapters.PtrString("AGPA3VLV2U27T6SSLJMDS"), + Arn: adapters.PtrString("arn:aws:iam::801795385023:User/power-users"), + CreateDate: adapters.PtrTime(time.Now()), }, UserGroups: []types.Group{ { - Arn: sources.PtrString("arn:aws:iam::801795385023:Group/something"), - CreateDate: sources.PtrTime(time.Now()), - GroupId: sources.PtrString("id"), - GroupName: sources.PtrString("name"), - Path: sources.PtrString("/"), + Arn: adapters.PtrString("arn:aws:iam::801795385023:Group/something"), + CreateDate: adapters.PtrTime(time.Now()), + GroupId: adapters.PtrString("id"), + GroupName: adapters.PtrString("name"), + Path: adapters.PtrString("/"), }, }, } @@ -204,7 +204,7 @@ func TestUserItemMapper(t *testing.T) { t.Error(err) } - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "iam-group", ExpectedMethod: sdp.QueryMethod_GET, @@ -216,17 +216,17 @@ func TestUserItemMapper(t *testing.T) { tests.Execute(t, item) } -func TestNewUserSource(t *testing.T) { - config, account, region := sources.GetAutoConfig(t) +func TestNewUserAdapter(t *testing.T) { + config, account, region := adapters.GetAutoConfig(t) client := iam.NewFromConfig(config, func(o *iam.Options) { o.RetryMode = aws.RetryModeAdaptive o.RetryMaxAttempts = 10 }) - source := NewUserSource(client, account, region) + adapter := NewUserAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 30 * time.Second, } diff --git a/sources/integration/apigateway/apigateway_test.go b/adapters/integration/apigateway/apigateway_test.go similarity index 86% rename from sources/integration/apigateway/apigateway_test.go rename to adapters/integration/apigateway/apigateway_test.go index 5b891b4a..897d8128 100644 --- a/sources/integration/apigateway/apigateway_test.go +++ b/adapters/integration/apigateway/apigateway_test.go @@ -4,9 +4,9 @@ import ( "context" "testing" - "github.com/overmindtech/aws-source/sources" - "github.com/overmindtech/aws-source/sources/apigateway" - "github.com/overmindtech/aws-source/sources/integration" + "github.com/overmindtech/aws-source/adapters" + "github.com/overmindtech/aws-source/adapters/apigateway" + "github.com/overmindtech/aws-source/adapters/integration" "github.com/overmindtech/sdp-go" ) @@ -28,21 +28,21 @@ func APIGateway(t *testing.T) { t.Log("Running APIGateway integration test") - restApiSource := apigateway.NewRestApiSource(testClient, accountID, testAWSConfig.Region) + restApiSource := apigateway.NewRestApiAdapter(testClient, accountID, testAWSConfig.Region) err = restApiSource.Validate() if err != nil { - t.Fatalf("failed to validate APIGateway restApi source: %v", err) + t.Fatalf("failed to validate APIGateway restApi adapter: %v", err) } - resourceApiSource := apigateway.NewResourceSource(testClient, accountID, testAWSConfig.Region) + resourceApiSource := apigateway.NewResourceAdapter(testClient, accountID, testAWSConfig.Region) err = resourceApiSource.Validate() if err != nil { - t.Fatalf("failed to validate APIGateway resource source: %v", err) + t.Fatalf("failed to validate APIGateway resource adapter: %v", err) } - scope := sources.FormatScope(accountID, testAWSConfig.Region) + scope := adapters.FormatScope(accountID, testAWSConfig.Region) // List restApis restApis, err := restApiSource.List(ctx, scope, true) diff --git a/sources/integration/apigateway/create.go b/adapters/integration/apigateway/create.go similarity index 83% rename from sources/integration/apigateway/create.go rename to adapters/integration/apigateway/create.go index fd37f294..da99c48c 100644 --- a/sources/integration/apigateway/create.go +++ b/adapters/integration/apigateway/create.go @@ -6,8 +6,8 @@ import ( "log/slog" "github.com/aws/aws-sdk-go-v2/service/apigateway" - "github.com/overmindtech/aws-source/sources" - "github.com/overmindtech/aws-source/sources/integration" + "github.com/overmindtech/aws-source/adapters" + "github.com/overmindtech/aws-source/adapters/integration" ) func createRestAPI(ctx context.Context, logger *slog.Logger, client *apigateway.Client, testID string) (*string, error) { @@ -27,8 +27,8 @@ func createRestAPI(ctx context.Context, logger *slog.Logger, client *apigateway. } result, err := client.CreateRestApi(ctx, &apigateway.CreateRestApiInput{ - Name: sources.PtrString(integration.ResourceName(integration.APIGateway, restAPISrc, testID)), - Description: sources.PtrString("Test Rest API"), + Name: adapters.PtrString(integration.ResourceName(integration.APIGateway, restAPISrc, testID)), + Description: adapters.PtrString("Test Rest API"), Tags: resourceTags(restAPISrc, testID), }) if err != nil { @@ -57,7 +57,7 @@ func createResource(ctx context.Context, logger *slog.Logger, client *apigateway result, err := client.CreateResource(ctx, &apigateway.CreateResourceInput{ RestApiId: restAPIID, ParentId: parentID, - PathPart: sources.PtrString(path), + PathPart: adapters.PtrString(path), }) if err != nil { return nil, err diff --git a/sources/integration/apigateway/delete.go b/adapters/integration/apigateway/delete.go similarity index 75% rename from sources/integration/apigateway/delete.go rename to adapters/integration/apigateway/delete.go index 18c552f8..73154364 100644 --- a/sources/integration/apigateway/delete.go +++ b/adapters/integration/apigateway/delete.go @@ -4,12 +4,12 @@ import ( "context" "github.com/aws/aws-sdk-go-v2/service/apigateway" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" ) func deleteRestAPI(ctx context.Context, client *apigateway.Client, restAPIID string) error { _, err := client.DeleteRestApi(ctx, &apigateway.DeleteRestApiInput{ - RestApiId: sources.PtrString(restAPIID), + RestApiId: adapters.PtrString(restAPIID), }) return err diff --git a/sources/integration/apigateway/find.go b/adapters/integration/apigateway/find.go similarity index 94% rename from sources/integration/apigateway/find.go rename to adapters/integration/apigateway/find.go index 028b2462..fac36f3e 100644 --- a/sources/integration/apigateway/find.go +++ b/adapters/integration/apigateway/find.go @@ -4,7 +4,7 @@ import ( "context" "github.com/aws/aws-sdk-go-v2/service/apigateway" - "github.com/overmindtech/aws-source/sources/integration" + "github.com/overmindtech/aws-source/adapters/integration" ) func findRestAPIsByTags(ctx context.Context, client *apigateway.Client, additionalAttr ...string) (*string, error) { diff --git a/sources/integration/apigateway/main_test.go b/adapters/integration/apigateway/main_test.go similarity index 96% rename from sources/integration/apigateway/main_test.go rename to adapters/integration/apigateway/main_test.go index 0bcede5d..0eb5ec18 100644 --- a/sources/integration/apigateway/main_test.go +++ b/adapters/integration/apigateway/main_test.go @@ -8,7 +8,7 @@ import ( "testing" "github.com/aws/aws-sdk-go-v2/service/apigateway" - "github.com/overmindtech/aws-source/sources/integration" + "github.com/overmindtech/aws-source/adapters/integration" ) func TestMain(m *testing.M) { diff --git a/sources/integration/apigateway/setup.go b/adapters/integration/apigateway/setup.go similarity index 92% rename from sources/integration/apigateway/setup.go rename to adapters/integration/apigateway/setup.go index 458aac92..562b6405 100644 --- a/sources/integration/apigateway/setup.go +++ b/adapters/integration/apigateway/setup.go @@ -5,7 +5,7 @@ import ( "log/slog" "github.com/aws/aws-sdk-go-v2/service/apigateway" - "github.com/overmindtech/aws-source/sources/integration" + "github.com/overmindtech/aws-source/adapters/integration" ) const ( diff --git a/sources/integration/apigateway/teardown.go b/adapters/integration/apigateway/teardown.go similarity index 89% rename from sources/integration/apigateway/teardown.go rename to adapters/integration/apigateway/teardown.go index 45ec41fa..247f2f64 100644 --- a/sources/integration/apigateway/teardown.go +++ b/adapters/integration/apigateway/teardown.go @@ -6,7 +6,7 @@ import ( "log/slog" "github.com/aws/aws-sdk-go-v2/service/apigateway" - "github.com/overmindtech/aws-source/sources/integration" + "github.com/overmindtech/aws-source/adapters/integration" ) func teardown(ctx context.Context, logger *slog.Logger, client *apigateway.Client) error { diff --git a/sources/integration/apigateway/util.go b/adapters/integration/apigateway/util.go similarity index 91% rename from sources/integration/apigateway/util.go rename to adapters/integration/apigateway/util.go index b3df0ce2..0cb659ee 100644 --- a/sources/integration/apigateway/util.go +++ b/adapters/integration/apigateway/util.go @@ -1,7 +1,7 @@ package apigateway import ( - "github.com/overmindtech/aws-source/sources/integration" + "github.com/overmindtech/aws-source/adapters/integration" ) func resourceTags(resourceName, testID string, nameAdditionalAttr ...string) map[string]string { diff --git a/sources/integration/ec2/create.go b/adapters/integration/ec2/create.go similarity index 97% rename from sources/integration/ec2/create.go rename to adapters/integration/ec2/create.go index ec6d7331..ca86b310 100644 --- a/sources/integration/ec2/create.go +++ b/adapters/integration/ec2/create.go @@ -10,7 +10,7 @@ import ( "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/aws/aws-sdk-go-v2/service/ec2/types" - "github.com/overmindtech/aws-source/sources/integration" + "github.com/overmindtech/aws-source/adapters/integration" ) func createEC2Instance(ctx context.Context, logger *slog.Logger, client *ec2.Client, testID string) error { diff --git a/sources/integration/ec2/delete.go b/adapters/integration/ec2/delete.go similarity index 100% rename from sources/integration/ec2/delete.go rename to adapters/integration/ec2/delete.go diff --git a/sources/integration/ec2/find.go b/adapters/integration/ec2/find.go similarity index 95% rename from sources/integration/ec2/find.go rename to adapters/integration/ec2/find.go index f2eeccfb..7a771a0b 100644 --- a/sources/integration/ec2/find.go +++ b/adapters/integration/ec2/find.go @@ -5,7 +5,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/aws/aws-sdk-go-v2/service/ec2/types" - "github.com/overmindtech/aws-source/sources/integration" + "github.com/overmindtech/aws-source/adapters/integration" ) // findActiveInstanceIDByTags finds an instance by tags diff --git a/sources/integration/ec2/instance_test.go b/adapters/integration/ec2/instance_test.go similarity index 75% rename from sources/integration/ec2/instance_test.go rename to adapters/integration/ec2/instance_test.go index b5fb4868..43abe29f 100644 --- a/sources/integration/ec2/instance_test.go +++ b/adapters/integration/ec2/instance_test.go @@ -5,9 +5,9 @@ import ( "fmt" "testing" - "github.com/overmindtech/aws-source/sources" - "github.com/overmindtech/aws-source/sources/ec2" - "github.com/overmindtech/aws-source/sources/integration" + "github.com/overmindtech/aws-source/adapters" + "github.com/overmindtech/aws-source/adapters/ec2" + "github.com/overmindtech/aws-source/adapters/integration" "github.com/overmindtech/sdp-go" ) @@ -29,17 +29,17 @@ func EC2(t *testing.T) { t.Log("Running EC2 integration test") - instanceSource := ec2.NewInstanceSource(testClient, accountID, testAWSConfig.Region) + instanceAdapter := ec2.NewInstanceAdapter(testClient, accountID, testAWSConfig.Region) - err = instanceSource.Validate() + err = instanceAdapter.Validate() if err != nil { - t.Fatalf("failed to validate EC2 instance source: %v", err) + t.Fatalf("failed to validate EC2 instance adapter: %v", err) } - scope := sources.FormatScope(accountID, testAWSConfig.Region) + scope := adapters.FormatScope(accountID, testAWSConfig.Region) // List instances - sdpListInstances, err := instanceSource.List(context.Background(), scope, true) + sdpListInstances, err := instanceAdapter.List(context.Background(), scope, true) if err != nil { t.Fatalf("failed to list EC2 instances: %v", err) } @@ -61,7 +61,7 @@ func EC2(t *testing.T) { } // Get instance - sdpInstance, err := instanceSource.Get(context.Background(), scope, instanceID, true) + sdpInstance, err := instanceAdapter.Get(context.Background(), scope, instanceID, true) if err != nil { t.Fatalf("failed to get EC2 instance: %v", err) } @@ -77,7 +77,7 @@ func EC2(t *testing.T) { // Search instances instanceARN := fmt.Sprintf("arn:aws:ec2:%s:%s:instance/%s", testAWSConfig.Region, accountID, instanceID) - sdpSearchInstances, err := instanceSource.Search(context.Background(), scope, instanceARN, true) + sdpSearchInstances, err := instanceAdapter.Search(context.Background(), scope, instanceARN, true) if err != nil { t.Fatalf("failed to search EC2 instances: %v", err) } diff --git a/sources/integration/ec2/main_test.go b/adapters/integration/ec2/main_test.go similarity index 95% rename from sources/integration/ec2/main_test.go rename to adapters/integration/ec2/main_test.go index 2dad212e..d3240ff6 100644 --- a/sources/integration/ec2/main_test.go +++ b/adapters/integration/ec2/main_test.go @@ -8,7 +8,7 @@ import ( "testing" awsec2 "github.com/aws/aws-sdk-go-v2/service/ec2" - "github.com/overmindtech/aws-source/sources/integration" + "github.com/overmindtech/aws-source/adapters/integration" ) func TestMain(m *testing.M) { diff --git a/sources/integration/ec2/setup.go b/adapters/integration/ec2/setup.go similarity index 83% rename from sources/integration/ec2/setup.go rename to adapters/integration/ec2/setup.go index 7fbbe8af..84f2268f 100644 --- a/sources/integration/ec2/setup.go +++ b/adapters/integration/ec2/setup.go @@ -5,7 +5,7 @@ import ( "log/slog" "github.com/aws/aws-sdk-go-v2/service/ec2" - "github.com/overmindtech/aws-source/sources/integration" + "github.com/overmindtech/aws-source/adapters/integration" ) const instanceSrc = "instance" diff --git a/sources/integration/ec2/teardown.go b/adapters/integration/ec2/teardown.go similarity index 89% rename from sources/integration/ec2/teardown.go rename to adapters/integration/ec2/teardown.go index 248761a8..59a3804e 100644 --- a/sources/integration/ec2/teardown.go +++ b/adapters/integration/ec2/teardown.go @@ -6,7 +6,7 @@ import ( "log/slog" "github.com/aws/aws-sdk-go-v2/service/ec2" - "github.com/overmindtech/aws-source/sources/integration" + "github.com/overmindtech/aws-source/adapters/integration" ) func teardown(ctx context.Context, logger *slog.Logger, client *ec2.Client) error { diff --git a/sources/integration/ec2/util.go b/adapters/integration/ec2/util.go similarity index 94% rename from sources/integration/ec2/util.go rename to adapters/integration/ec2/util.go index 86dd7a81..12041515 100644 --- a/sources/integration/ec2/util.go +++ b/adapters/integration/ec2/util.go @@ -3,7 +3,7 @@ package ec2 import ( "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/ec2/types" - "github.com/overmindtech/aws-source/sources/integration" + "github.com/overmindtech/aws-source/adapters/integration" ) func resourceTags(resourceName, testID string, nameAdditionalAttr ...string) []types.Tag { diff --git a/sources/integration/errors.go b/adapters/integration/errors.go similarity index 100% rename from sources/integration/errors.go rename to adapters/integration/errors.go diff --git a/sources/integration/kms/create.go b/adapters/integration/kms/create.go similarity index 98% rename from sources/integration/kms/create.go rename to adapters/integration/kms/create.go index 3908b5e7..eecd1e5c 100644 --- a/sources/integration/kms/create.go +++ b/adapters/integration/kms/create.go @@ -8,7 +8,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/kms" "github.com/aws/aws-sdk-go-v2/service/kms/types" - "github.com/overmindtech/aws-source/sources/integration" + "github.com/overmindtech/aws-source/adapters/integration" ) func createKey(ctx context.Context, logger *slog.Logger, client *kms.Client, testID string) (*string, error) { diff --git a/sources/integration/kms/delete.go b/adapters/integration/kms/delete.go similarity index 100% rename from sources/integration/kms/delete.go rename to adapters/integration/kms/delete.go diff --git a/sources/integration/kms/find.go b/adapters/integration/kms/find.go similarity index 97% rename from sources/integration/kms/find.go rename to adapters/integration/kms/find.go index b1dec98b..50ef9ea0 100644 --- a/sources/integration/kms/find.go +++ b/adapters/integration/kms/find.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/kms" "github.com/aws/aws-sdk-go-v2/service/kms/types" "github.com/aws/smithy-go" - "github.com/overmindtech/aws-source/sources/integration" + "github.com/overmindtech/aws-source/adapters/integration" ) // findActiveKeyIDByTags finds a key by tags diff --git a/sources/integration/kms/kms_test.go b/adapters/integration/kms/kms_test.go similarity index 89% rename from sources/integration/kms/kms_test.go rename to adapters/integration/kms/kms_test.go index 5234f35b..80436c01 100644 --- a/sources/integration/kms/kms_test.go +++ b/adapters/integration/kms/kms_test.go @@ -6,9 +6,9 @@ import ( "strings" "testing" - "github.com/overmindtech/aws-source/sources" - "github.com/overmindtech/aws-source/sources/integration" - "github.com/overmindtech/aws-source/sources/kms" + "github.com/overmindtech/aws-source/adapters" + "github.com/overmindtech/aws-source/adapters/integration" + "github.com/overmindtech/aws-source/adapters/kms" "github.com/overmindtech/sdp-go" ) @@ -30,35 +30,35 @@ func KMS(t *testing.T) { t.Log("Running KMS integration test") - keySource := kms.NewKeySource(testClient, accountID, testAWSConfig.Region) + keySource := kms.NewKeyAdapter(testClient, accountID, testAWSConfig.Region) - aliasSource := kms.NewAliasSource(testClient, accountID, testAWSConfig.Region) + aliasSource := kms.NewAliasAdapter(testClient, accountID, testAWSConfig.Region) - grantSource := kms.NewGrantSource(testClient, accountID, testAWSConfig.Region) + grantSource := kms.NewGrantAdapter(testClient, accountID, testAWSConfig.Region) - keyPolicySource := kms.NewKeyPolicySource(testClient, accountID, testAWSConfig.Region) + keyPolicySource := kms.NewKeyPolicyAdapter(testClient, accountID, testAWSConfig.Region) err = keySource.Validate() if err != nil { - t.Fatalf("failed to validate KMS key source: %v", err) + t.Fatalf("failed to validate KMS key adapter: %v", err) } err = aliasSource.Validate() if err != nil { - t.Fatalf("failed to validate KMS alias source: %v", err) + t.Fatalf("failed to validate KMS alias adapter: %v", err) } err = grantSource.Validate() if err != nil { - t.Fatalf("failed to validate KMS grant source: %v", err) + t.Fatalf("failed to validate KMS grant adapter: %v", err) } err = keyPolicySource.Validate() if err != nil { - t.Fatalf("failed to validate KMS key policy source: %v", err) + t.Fatalf("failed to validate KMS key policy adapter: %v", err) } - scope := sources.FormatScope(accountID, testAWSConfig.Region) + scope := adapters.FormatScope(accountID, testAWSConfig.Region) // List keys sdpListKeys, err := keySource.List(context.Background(), scope, true) diff --git a/sources/integration/kms/main_test.go b/adapters/integration/kms/main_test.go similarity index 95% rename from sources/integration/kms/main_test.go rename to adapters/integration/kms/main_test.go index 98181547..692cd3fc 100644 --- a/sources/integration/kms/main_test.go +++ b/adapters/integration/kms/main_test.go @@ -8,7 +8,7 @@ import ( "testing" awskms "github.com/aws/aws-sdk-go-v2/service/kms" - "github.com/overmindtech/aws-source/sources/integration" + "github.com/overmindtech/aws-source/adapters/integration" ) func TestMain(m *testing.M) { diff --git a/sources/integration/kms/setup.go b/adapters/integration/kms/setup.go similarity index 93% rename from sources/integration/kms/setup.go rename to adapters/integration/kms/setup.go index f8b32395..3fd18e59 100644 --- a/sources/integration/kms/setup.go +++ b/adapters/integration/kms/setup.go @@ -6,7 +6,7 @@ import ( "log/slog" "github.com/aws/aws-sdk-go-v2/service/kms" - "github.com/overmindtech/aws-source/sources/integration" + "github.com/overmindtech/aws-source/adapters/integration" ) const ( diff --git a/sources/integration/kms/teardown.go b/adapters/integration/kms/teardown.go similarity index 95% rename from sources/integration/kms/teardown.go rename to adapters/integration/kms/teardown.go index 7e322b01..7048baa1 100644 --- a/sources/integration/kms/teardown.go +++ b/adapters/integration/kms/teardown.go @@ -7,7 +7,7 @@ import ( "log/slog" "github.com/aws/aws-sdk-go-v2/service/kms" - "github.com/overmindtech/aws-source/sources/integration" + "github.com/overmindtech/aws-source/adapters/integration" ) func teardown(ctx context.Context, logger *slog.Logger, client *kms.Client) error { diff --git a/sources/integration/kms/util.go b/adapters/integration/kms/util.go similarity index 94% rename from sources/integration/kms/util.go rename to adapters/integration/kms/util.go index b6306434..453dd002 100644 --- a/sources/integration/kms/util.go +++ b/adapters/integration/kms/util.go @@ -3,7 +3,7 @@ package kms import ( "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/kms/types" - "github.com/overmindtech/aws-source/sources/integration" + "github.com/overmindtech/aws-source/adapters/integration" ) func resourceTags(resourceName, testID string, nameAdditionalAttr ...string) []types.Tag { diff --git a/sources/integration/networkmanager/create.go b/adapters/integration/networkmanager/create.go similarity index 98% rename from sources/integration/networkmanager/create.go rename to adapters/integration/networkmanager/create.go index 7d88d5fc..f9192b15 100644 --- a/sources/integration/networkmanager/create.go +++ b/adapters/integration/networkmanager/create.go @@ -8,7 +8,7 @@ import ( "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/networkmanager" "github.com/aws/aws-sdk-go-v2/service/networkmanager/types" - "github.com/overmindtech/aws-source/sources/integration" + "github.com/overmindtech/aws-source/adapters/integration" ) func createGlobalNetwork(ctx context.Context, logger *slog.Logger, client *networkmanager.Client, testID string) (*string, error) { diff --git a/sources/integration/networkmanager/delete.go b/adapters/integration/networkmanager/delete.go similarity index 98% rename from sources/integration/networkmanager/delete.go rename to adapters/integration/networkmanager/delete.go index afef8706..9db5c716 100644 --- a/sources/integration/networkmanager/delete.go +++ b/adapters/integration/networkmanager/delete.go @@ -6,7 +6,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/networkmanager/types" "github.com/aws/smithy-go" - "github.com/overmindtech/aws-source/sources/integration" + "github.com/overmindtech/aws-source/adapters/integration" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/networkmanager" diff --git a/sources/integration/networkmanager/find.go b/adapters/integration/networkmanager/find.go similarity index 98% rename from sources/integration/networkmanager/find.go rename to adapters/integration/networkmanager/find.go index d9421e43..37b6cf34 100644 --- a/sources/integration/networkmanager/find.go +++ b/adapters/integration/networkmanager/find.go @@ -6,7 +6,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/networkmanager" "github.com/aws/aws-sdk-go-v2/service/networkmanager/types" - "github.com/overmindtech/aws-source/sources/integration" + "github.com/overmindtech/aws-source/adapters/integration" ) func findGlobalNetworkIDByTags(ctx context.Context, client *networkmanager.Client, requiredTags []types.Tag) (*string, error) { diff --git a/sources/integration/networkmanager/main_test.go b/adapters/integration/networkmanager/main_test.go similarity index 96% rename from sources/integration/networkmanager/main_test.go rename to adapters/integration/networkmanager/main_test.go index d39bb475..855abf58 100644 --- a/sources/integration/networkmanager/main_test.go +++ b/adapters/integration/networkmanager/main_test.go @@ -8,7 +8,7 @@ import ( "testing" awsnetworkmanager "github.com/aws/aws-sdk-go-v2/service/networkmanager" - "github.com/overmindtech/aws-source/sources/integration" + "github.com/overmindtech/aws-source/adapters/integration" ) func TestMain(m *testing.M) { diff --git a/sources/integration/networkmanager/networkmanager_test.go b/adapters/integration/networkmanager/networkmanager_test.go similarity index 91% rename from sources/integration/networkmanager/networkmanager_test.go rename to adapters/integration/networkmanager/networkmanager_test.go index f09d5c61..6924cb8e 100644 --- a/sources/integration/networkmanager/networkmanager_test.go +++ b/adapters/integration/networkmanager/networkmanager_test.go @@ -6,9 +6,9 @@ import ( "strings" "testing" - "github.com/overmindtech/aws-source/sources" - "github.com/overmindtech/aws-source/sources/integration" - "github.com/overmindtech/aws-source/sources/networkmanager" + "github.com/overmindtech/aws-source/adapters" + "github.com/overmindtech/aws-source/adapters/integration" + "github.com/overmindtech/aws-source/adapters/networkmanager" "github.com/overmindtech/sdp-go" ) @@ -30,37 +30,37 @@ func NetworkManager(t *testing.T) { t.Logf("Running NetworkManager integration tests") - globalNetworkSource := networkmanager.NewGlobalNetworkSource(testClient, accountID) + globalNetworkSource := networkmanager.NewGlobalNetworkAdapter(testClient, accountID) if err := globalNetworkSource.Validate(); err != nil { - t.Fatalf("failed to validate NetworkManager global network source: %v", err) + t.Fatalf("failed to validate NetworkManager global network adapter: %v", err) } - siteSource := networkmanager.NewSiteSource(testClient, accountID) + siteSource := networkmanager.NewSiteAdapter(testClient, accountID) if err := siteSource.Validate(); err != nil { - t.Fatalf("failed to validate NetworkManager site source: %v", err) + t.Fatalf("failed to validate NetworkManager site adapter: %v", err) } - linkSource := networkmanager.NewLinkSource(testClient, accountID) + linkSource := networkmanager.NewLinkAdapter(testClient, accountID) if err := linkSource.Validate(); err != nil { - t.Fatalf("failed to validate NetworkManager link source: %v", err) + t.Fatalf("failed to validate NetworkManager link adapter: %v", err) } - linkAssociationSource := networkmanager.NewLinkAssociationSource(testClient, accountID) + linkAssociationSource := networkmanager.NewLinkAssociationAdapter(testClient, accountID) if err := linkAssociationSource.Validate(); err != nil { - t.Fatalf("failed to validate NetworkManager link association source: %v", err) + t.Fatalf("failed to validate NetworkManager link association adapter: %v", err) } - connectionSource := networkmanager.NewConnectionSource(testClient, accountID) + connectionSource := networkmanager.NewConnectionAdapter(testClient, accountID) if err := connectionSource.Validate(); err != nil { - t.Fatalf("failed to validate NetworkManager connection source: %v", err) + t.Fatalf("failed to validate NetworkManager connection adapter: %v", err) } - deviceSource := networkmanager.NewDeviceSource(testClient, accountID) + deviceSource := networkmanager.NewDeviceAdapter(testClient, accountID) if err := deviceSource.Validate(); err != nil { - t.Fatalf("failed to validate NetworkManager device source: %v", err) + t.Fatalf("failed to validate NetworkManager device adapter: %v", err) } - globalScope := sources.FormatScope(accountID, "") + globalScope := adapters.FormatScope(accountID, "") t.Run("Global Network", func(t *testing.T) { // List global networks diff --git a/sources/integration/networkmanager/setup.go b/adapters/integration/networkmanager/setup.go similarity index 96% rename from sources/integration/networkmanager/setup.go rename to adapters/integration/networkmanager/setup.go index 759a8780..eac4f76f 100644 --- a/sources/integration/networkmanager/setup.go +++ b/adapters/integration/networkmanager/setup.go @@ -5,7 +5,7 @@ import ( "log/slog" "github.com/aws/aws-sdk-go-v2/service/networkmanager" - "github.com/overmindtech/aws-source/sources/integration" + "github.com/overmindtech/aws-source/adapters/integration" ) const ( diff --git a/sources/integration/networkmanager/tags.go b/adapters/integration/networkmanager/tags.go similarity index 94% rename from sources/integration/networkmanager/tags.go rename to adapters/integration/networkmanager/tags.go index 54bb37d7..d9e4ae46 100644 --- a/sources/integration/networkmanager/tags.go +++ b/adapters/integration/networkmanager/tags.go @@ -3,7 +3,7 @@ package networkmanager import ( "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/networkmanager/types" - "github.com/overmindtech/aws-source/sources/integration" + "github.com/overmindtech/aws-source/adapters/integration" ) func resourceTags(resourceName, testID string, additionalAttr ...string) []types.Tag { diff --git a/sources/integration/networkmanager/teardown.go b/adapters/integration/networkmanager/teardown.go similarity index 98% rename from sources/integration/networkmanager/teardown.go rename to adapters/integration/networkmanager/teardown.go index 8828f22c..c5ad1ece 100644 --- a/sources/integration/networkmanager/teardown.go +++ b/adapters/integration/networkmanager/teardown.go @@ -6,7 +6,7 @@ import ( "log/slog" "github.com/aws/aws-sdk-go-v2/service/networkmanager" - "github.com/overmindtech/aws-source/sources/integration" + "github.com/overmindtech/aws-source/adapters/integration" ) func teardown(ctx context.Context, logger *slog.Logger, client *networkmanager.Client) error { diff --git a/sources/integration/util.go b/adapters/integration/util.go similarity index 100% rename from sources/integration/util.go rename to adapters/integration/util.go diff --git a/sources/integration/util_test.go b/adapters/integration/util_test.go similarity index 100% rename from sources/integration/util_test.go rename to adapters/integration/util_test.go diff --git a/sources/kms/alias.go b/adapters/kms/alias.go similarity index 73% rename from sources/kms/alias.go rename to adapters/kms/alias.go index a3cc86ff..6b4f5580 100644 --- a/sources/kms/alias.go +++ b/adapters/kms/alias.go @@ -6,7 +6,7 @@ import ( "strings" "github.com/aws/aws-sdk-go-v2/service/kms" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -14,7 +14,7 @@ func aliasOutputMapper(_ context.Context, _ *kms.Client, scope string, _ *kms.Li items := make([]*sdp.Item, 0) for _, alias := range output.Aliases { - attributes, err := sources.ToAttributesWithExclude(alias, "tags") + attributes, err := adapters.ToAttributesWithExclude(alias, "tags") if err != nil { return nil, err } @@ -88,12 +88,13 @@ func aliasOutputMapper(_ context.Context, _ *kms.Client, scope string, _ *kms.Li // +overmind:group AWS // +overmind:terraform:queryMap aws_kms_alias.arn -func NewAliasSource(client *kms.Client, accountID string, region string) *sources.DescribeOnlySource[*kms.ListAliasesInput, *kms.ListAliasesOutput, *kms.Client, *kms.Options] { - return &sources.DescribeOnlySource[*kms.ListAliasesInput, *kms.ListAliasesOutput, *kms.Client, *kms.Options]{ - ItemType: "kms-alias", - Client: client, - AccountID: accountID, - Region: region, +func NewAliasAdapter(client *kms.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*kms.ListAliasesInput, *kms.ListAliasesOutput, *kms.Client, *kms.Options] { + return &adapters.DescribeOnlyAdapter[*kms.ListAliasesInput, *kms.ListAliasesOutput, *kms.Client, *kms.Options]{ + ItemType: "kms-alias", + Client: client, + AccountID: accountID, + Region: region, + AdapterMetadata: AliasMetadata(), DescribeFunc: func(ctx context.Context, client *kms.Client, input *kms.ListAliasesInput) (*kms.ListAliasesOutput, error) { return client.ListAliases(ctx, input) }, @@ -125,3 +126,25 @@ func NewAliasSource(client *kms.Client, accountID string, region string) *source OutputMapper: aliasOutputMapper, } } + +func AliasMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "kms-alias", + DescriptiveName: "KMS Alias", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get an alias by keyID/aliasName", + ListDescription: "List all aliases", + SearchDescription: "Search aliases by keyID", + }, + TerraformMappings: []*sdp.TerraformMapping{ + { + TerraformQueryMap: "aws_kms_alias.arn", + }, + }, + PotentialLinks: []string{"kms-key"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_SECURITY, + } +} diff --git a/sources/kms/alias_test.go b/adapters/kms/alias_test.go similarity index 59% rename from sources/kms/alias_test.go rename to adapters/kms/alias_test.go index 9773eca0..4f15f3a6 100644 --- a/sources/kms/alias_test.go +++ b/adapters/kms/alias_test.go @@ -5,22 +5,22 @@ import ( "testing" "time" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" "github.com/aws/aws-sdk-go-v2/service/kms" "github.com/aws/aws-sdk-go-v2/service/kms/types" - "github.com/overmindtech/aws-source/sources" ) func TestAliasOutputMapper(t *testing.T) { output := &kms.ListAliasesOutput{ Aliases: []types.AliasListEntry{ { - AliasName: sources.PtrString("alias/test-key"), - TargetKeyId: sources.PtrString("cf68415c-f4ae-48f2-87a7-3b52ce"), - AliasArn: sources.PtrString("arn:aws:kms:us-west-2:123456789012:alias/test-key"), - CreationDate: sources.PtrTime(time.Now()), - LastUpdatedDate: sources.PtrTime(time.Now()), + AliasName: adapters.PtrString("alias/test-key"), + TargetKeyId: adapters.PtrString("cf68415c-f4ae-48f2-87a7-3b52ce"), + AliasArn: adapters.PtrString("arn:aws:kms:us-west-2:123456789012:alias/test-key"), + CreationDate: adapters.PtrTime(time.Now()), + LastUpdatedDate: adapters.PtrTime(time.Now()), }, }, } @@ -42,7 +42,7 @@ func TestAliasOutputMapper(t *testing.T) { item := items[0] - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "kms-key", ExpectedMethod: sdp.QueryMethod_GET, @@ -54,14 +54,14 @@ func TestAliasOutputMapper(t *testing.T) { tests.Execute(t, item) } -func TestNewAliasSource(t *testing.T) { - config, account, region := sources.GetAutoConfig(t) +func TestNewAliasAdapter(t *testing.T) { + config, account, region := adapters.GetAutoConfig(t) client := kms.NewFromConfig(config) - source := NewAliasSource(client, account, region) + adapter := NewAliasAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/kms/custom-key-store.go b/adapters/kms/custom-key-store.go similarity index 71% rename from sources/kms/custom-key-store.go rename to adapters/kms/custom-key-store.go index 5d6a22c3..733ba11b 100644 --- a/sources/kms/custom-key-store.go +++ b/adapters/kms/custom-key-store.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/kms/types" "github.com/aws/aws-sdk-go-v2/service/kms" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -15,7 +15,7 @@ func customKeyStoreOutputMapper(_ context.Context, _ *kms.Client, scope string, items := make([]*sdp.Item, 0) for _, customKeyStore := range output.CustomKeyStores { - attributes, err := sources.ToAttributesWithExclude(customKeyStore, "tags") + attributes, err := adapters.ToAttributesWithExclude(customKeyStore, "tags") if err != nil { return nil, err } @@ -97,12 +97,13 @@ func customKeyStoreOutputMapper(_ context.Context, _ *kms.Client, scope string, // +overmind:group AWS // +overmind:terraform:queryMap aws_kms_custom_key_store.id -func NewCustomKeyStoreSource(client *kms.Client, accountID string, region string) *sources.DescribeOnlySource[*kms.DescribeCustomKeyStoresInput, *kms.DescribeCustomKeyStoresOutput, *kms.Client, *kms.Options] { - return &sources.DescribeOnlySource[*kms.DescribeCustomKeyStoresInput, *kms.DescribeCustomKeyStoresOutput, *kms.Client, *kms.Options]{ - Region: region, - Client: client, - AccountID: accountID, - ItemType: "kms-custom-key-store", +func NewCustomKeyStoreAdapter(client *kms.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*kms.DescribeCustomKeyStoresInput, *kms.DescribeCustomKeyStoresOutput, *kms.Client, *kms.Options] { + return &adapters.DescribeOnlyAdapter[*kms.DescribeCustomKeyStoresInput, *kms.DescribeCustomKeyStoresOutput, *kms.Client, *kms.Options]{ + Region: region, + Client: client, + AccountID: accountID, + ItemType: "kms-custom-key-store", + AdapterMetadata: CustomKeyStoreMetadata(), DescribeFunc: func(ctx context.Context, client *kms.Client, input *kms.DescribeCustomKeyStoresInput) (*kms.DescribeCustomKeyStoresOutput, error) { return client.DescribeCustomKeyStores(ctx, input) }, @@ -117,3 +118,26 @@ func NewCustomKeyStoreSource(client *kms.Client, accountID string, region string OutputMapper: customKeyStoreOutputMapper, } } + +func CustomKeyStoreMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + + Type: "kms-custom-key-store", + DescriptiveName: "Custom Key Store", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a custom key store by its ID", + ListDescription: "List all custom key stores", + SearchDescription: "Search custom key store by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + { + TerraformQueryMap: "aws_kms_custom_key_store.id", + }, + }, + PotentialLinks: []string{"cloudhsmv2-cluster", "ec2-vpc-endpoint-service"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_STORAGE, + } +} diff --git a/sources/kms/custom-key-store_test.go b/adapters/kms/custom-key-store_test.go similarity index 76% rename from sources/kms/custom-key-store_test.go rename to adapters/kms/custom-key-store_test.go index 71ea27fb..11276137 100644 --- a/sources/kms/custom-key-store_test.go +++ b/adapters/kms/custom-key-store_test.go @@ -8,7 +8,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/kms" "github.com/aws/aws-sdk-go-v2/service/kms/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -16,12 +16,12 @@ func TestCustomKeyStoreOutputMapper(t *testing.T) { output := &kms.DescribeCustomKeyStoresOutput{ CustomKeyStores: []types.CustomKeyStoresListEntry{ { - CustomKeyStoreId: sources.PtrString("custom-key-store-1"), - CreationDate: sources.PtrTime(time.Now()), - CloudHsmClusterId: sources.PtrString("cloud-hsm-cluster-1"), + CustomKeyStoreId: adapters.PtrString("custom-key-store-1"), + CreationDate: adapters.PtrTime(time.Now()), + CloudHsmClusterId: adapters.PtrString("cloud-hsm-cluster-1"), ConnectionState: types.ConnectionStateTypeConnected, - TrustAnchorCertificate: sources.PtrString("-----BEGIN CERTIFICATE-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwJ1z\n-----END CERTIFICATE-----"), - CustomKeyStoreName: sources.PtrString("key-store-1"), + TrustAnchorCertificate: adapters.PtrString("-----BEGIN CERTIFICATE-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwJ1z\n-----END CERTIFICATE-----"), + CustomKeyStoreName: adapters.PtrString("key-store-1"), }, }, } @@ -43,7 +43,7 @@ func TestCustomKeyStoreOutputMapper(t *testing.T) { item := items[0] - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "cloudhsmv2-cluster", ExpectedMethod: sdp.QueryMethod_GET, @@ -55,14 +55,14 @@ func TestCustomKeyStoreOutputMapper(t *testing.T) { tests.Execute(t, item) } -func TestNewCustomKeyStoreSource(t *testing.T) { - config, account, region := sources.GetAutoConfig(t) +func TestNewCustomKeyStoreAdapter(t *testing.T) { + config, account, region := adapters.GetAutoConfig(t) client := kms.NewFromConfig(config) - source := NewCustomKeyStoreSource(client, account, region) + adapter := NewCustomKeyStoreAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } @@ -81,7 +81,7 @@ func TestHealthState(t *testing.T) { output: &kms.DescribeCustomKeyStoresOutput{ CustomKeyStores: []types.CustomKeyStoresListEntry{ { - CustomKeyStoreId: sources.PtrString("custom-key-store-1"), + CustomKeyStoreId: adapters.PtrString("custom-key-store-1"), ConnectionState: types.ConnectionStateTypeConnected, }, }, @@ -93,7 +93,7 @@ func TestHealthState(t *testing.T) { output: &kms.DescribeCustomKeyStoresOutput{ CustomKeyStores: []types.CustomKeyStoresListEntry{ { - CustomKeyStoreId: sources.PtrString("custom-key-store-1"), + CustomKeyStoreId: adapters.PtrString("custom-key-store-1"), ConnectionState: types.ConnectionStateTypeConnecting, }, }, @@ -105,7 +105,7 @@ func TestHealthState(t *testing.T) { output: &kms.DescribeCustomKeyStoresOutput{ CustomKeyStores: []types.CustomKeyStoresListEntry{ { - CustomKeyStoreId: sources.PtrString("custom-key-store-1"), + CustomKeyStoreId: adapters.PtrString("custom-key-store-1"), ConnectionState: types.ConnectionStateTypeDisconnected, }, }, @@ -117,7 +117,7 @@ func TestHealthState(t *testing.T) { output: &kms.DescribeCustomKeyStoresOutput{ CustomKeyStores: []types.CustomKeyStoresListEntry{ { - CustomKeyStoreId: sources.PtrString("custom-key-store-1"), + CustomKeyStoreId: adapters.PtrString("custom-key-store-1"), ConnectionState: types.ConnectionStateTypeFailed, }, }, @@ -129,7 +129,7 @@ func TestHealthState(t *testing.T) { output: &kms.DescribeCustomKeyStoresOutput{ CustomKeyStores: []types.CustomKeyStoresListEntry{ { - CustomKeyStoreId: sources.PtrString("custom-key-store-1"), + CustomKeyStoreId: adapters.PtrString("custom-key-store-1"), ConnectionState: "unknown-state", }, }, diff --git a/sources/kms/grant.go b/adapters/kms/grant.go similarity index 77% rename from sources/kms/grant.go rename to adapters/kms/grant.go index 846634cb..8c4cab8e 100644 --- a/sources/kms/grant.go +++ b/adapters/kms/grant.go @@ -6,7 +6,7 @@ import ( "strings" "github.com/aws/aws-sdk-go-v2/service/kms" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" log "github.com/sirupsen/logrus" @@ -16,7 +16,7 @@ func grantOutputMapper(ctx context.Context, _ *kms.Client, scope string, _ *kms. items := make([]*sdp.Item, 0) for _, grant := range output.Grants { - attributes, err := sources.ToAttributesWithExclude(grant, "tags") + attributes, err := adapters.ToAttributesWithExclude(grant, "tags") if err != nil { return nil, err } @@ -29,7 +29,7 @@ func grantOutputMapper(ctx context.Context, _ *kms.Client, scope string, _ *kms. } } - arn, errA := sources.ParseARN(*grant.KeyId) + arn, errA := adapters.ParseARN(*grant.KeyId) if errA != nil { return nil, &sdp.QueryError{ ErrorType: sdp.QueryError_OTHER, @@ -53,7 +53,7 @@ func grantOutputMapper(ctx context.Context, _ *kms.Client, scope string, _ *kms. Scope: scope, } - scope = sources.FormatScope(arn.AccountID, arn.Region) + scope = adapters.FormatScope(arn.AccountID, arn.Region) // +overmind:link kms-key item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ @@ -120,7 +120,7 @@ func grantOutputMapper(ctx context.Context, _ *kms.Client, scope string, _ *kms. }, } - arn, errA := sources.ParseARN(principal) + arn, errA := adapters.ParseARN(principal) if errA != nil { log.WithFields(log.Fields{ "error": errA, @@ -133,8 +133,8 @@ func grantOutputMapper(ctx context.Context, _ *kms.Client, scope string, _ *kms. switch arn.Service { case "iam": - source, query := iamSourceAndQuery(arn.Resource) - switch source { + adapter, query := iamSourceAndQuery(arn.Resource) + switch adapter { case "user": // +overmind:link iam-user lIQ.Query.Type = "iam-user" @@ -147,7 +147,7 @@ func grantOutputMapper(ctx context.Context, _ *kms.Client, scope string, _ *kms. log.WithFields(log.Fields{ "input": principal, "scope": scope, - }).Warn("Error unsupported iam source") + }).Warn("Error unsupported iam adapter") continue } @@ -177,12 +177,13 @@ func grantOutputMapper(ctx context.Context, _ *kms.Client, scope string, _ *kms. // +overmind:group AWS // +overmind:terraform:queryMap aws_kms_grant.grant_id -func NewGrantSource(client *kms.Client, accountID string, region string) *sources.DescribeOnlySource[*kms.ListGrantsInput, *kms.ListGrantsOutput, *kms.Client, *kms.Options] { - return &sources.DescribeOnlySource[*kms.ListGrantsInput, *kms.ListGrantsOutput, *kms.Client, *kms.Options]{ - ItemType: "kms-grant", - Client: client, - AccountID: accountID, - Region: region, +func NewGrantAdapter(client *kms.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*kms.ListGrantsInput, *kms.ListGrantsOutput, *kms.Client, *kms.Options] { + return &adapters.DescribeOnlyAdapter[*kms.ListGrantsInput, *kms.ListGrantsOutput, *kms.Client, *kms.Options]{ + ItemType: "kms-grant", + Client: client, + AccountID: accountID, + Region: region, + AdapterMetadata: GrantMetadata(), DescribeFunc: func(ctx context.Context, client *kms.Client, input *kms.ListGrantsInput) (*kms.ListGrantsOutput, error) { return client.ListGrants(ctx, input) }, @@ -198,8 +199,8 @@ func NewGrantSource(client *kms.Client, accountID string, region string) *source } return &kms.ListGrantsInput{ - KeyId: &tmp[0], // keyID - GrantId: sources.PtrString(strings.Join(tmp[1:], "/")), // grantId + KeyId: &tmp[0], // keyID + GrantId: adapters.PtrString(strings.Join(tmp[1:], "/")), // grantId }, nil }, UseListForGet: true, @@ -218,12 +219,32 @@ func NewGrantSource(client *kms.Client, accountID string, region string) *source } } +func GrantMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "kms-grant", + DescriptiveName: "KMS Grant", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + Search: true, + GetDescription: "Get a grant by keyID/grantId", + SearchDescription: "Search grants by keyID", + }, + TerraformMappings: []*sdp.TerraformMapping{ + { + TerraformQueryMap: "aws_kms_grant.grant_id", + }, + }, + PotentialLinks: []string{"kms-key", "iam-user", "iam-role"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_SECURITY, + } +} + // example: user/user-name-with-path func iamSourceAndQuery(resource string) (string, string) { tmp := strings.Split(resource, "/") // [user, user-name-with-path] - source := tmp[0] + adapter := tmp[0] query := strings.Join(tmp[1:], "/") - return source, query // user, user-name-with-path + return adapter, query // user, user-name-with-path } diff --git a/sources/kms/grant_test.go b/adapters/kms/grant_test.go similarity index 73% rename from sources/kms/grant_test.go rename to adapters/kms/grant_test.go index d44ccfcc..19559a44 100644 --- a/sources/kms/grant_test.go +++ b/adapters/kms/grant_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/kms" "github.com/aws/aws-sdk-go-v2/service/kms/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -54,14 +54,14 @@ func TestGrantOutputMapper(t *testing.T) { "aws:dynamodb:tableName": "Services", }, }, - IssuingAccount: sources.PtrString("arn:aws:iam::123456789012:root"), - Name: sources.PtrString("8276b9a6-6cf0-46f1-b2f0-7993a7f8c89a"), + IssuingAccount: adapters.PtrString("arn:aws:iam::123456789012:root"), + Name: adapters.PtrString("8276b9a6-6cf0-46f1-b2f0-7993a7f8c89a"), Operations: []types.GrantOperation{"Decrypt", "Encrypt", "GenerateDataKey", "ReEncryptFrom", "ReEncryptTo", "RetireGrant", "DescribeKey"}, - GrantId: sources.PtrString("1667b97d27cf748cf05b487217dd4179526c949d14fb3903858e25193253fe59"), - KeyId: sources.PtrString("arn:aws:kms:us-west-2:123456789012:key/1234abcd-12ab-34cd-56ef-1234567890ab"), - RetiringPrincipal: sources.PtrString("arn:aws:iam::account:role/role-name-with-path"), - GranteePrincipal: sources.PtrString("arn:aws:iam::account:user/user-name-with-path"), - CreationDate: sources.PtrTime(time.Now()), + GrantId: adapters.PtrString("1667b97d27cf748cf05b487217dd4179526c949d14fb3903858e25193253fe59"), + KeyId: adapters.PtrString("arn:aws:kms:us-west-2:123456789012:key/1234abcd-12ab-34cd-56ef-1234567890ab"), + RetiringPrincipal: adapters.PtrString("arn:aws:iam::account:role/role-name-with-path"), + GranteePrincipal: adapters.PtrString("arn:aws:iam::account:user/user-name-with-path"), + CreationDate: adapters.PtrTime(time.Now()), }, }, } @@ -83,9 +83,9 @@ func TestGrantOutputMapper(t *testing.T) { item := items[0] - scope := sources.FormatScope("123456789012", "us-west-2") + scope := adapters.FormatScope("123456789012", "us-west-2") - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "kms-key", ExpectedMethod: sdp.QueryMethod_GET, @@ -109,14 +109,14 @@ func TestGrantOutputMapper(t *testing.T) { tests.Execute(t, item) } -func TestNewGrantSource(t *testing.T) { - config, account, region := sources.GetAutoConfig(t) +func TestNewGrantAdapter(t *testing.T) { + config, account, region := adapters.GetAutoConfig(t) client := kms.NewFromConfig(config) - source := NewGrantSource(client, account, region) + adapter := NewGrantAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, SkipList: true, } diff --git a/sources/kms/key-policy.go b/adapters/kms/key-policy.go similarity index 66% rename from sources/kms/key-policy.go rename to adapters/kms/key-policy.go index bff08e35..d493bf39 100644 --- a/sources/kms/key-policy.go +++ b/adapters/kms/key-policy.go @@ -5,8 +5,8 @@ import ( "github.com/aws/aws-sdk-go-v2/service/kms" "github.com/micahhausler/aws-iam-policy/policy" - "github.com/overmindtech/aws-source/sources" - "github.com/overmindtech/aws-source/sources/iam" + "github.com/overmindtech/aws-source/adapters" + "github.com/overmindtech/aws-source/adapters/iam" "github.com/overmindtech/sdp-go" log "github.com/sirupsen/logrus" @@ -50,7 +50,7 @@ func getKeyPolicyFunc(ctx context.Context, client keyPolicyClient, scope string, return nil, nil //nolint:nilerr } - attributes, err := sources.ToAttributesWithExclude(parsedPolicy) + attributes, err := adapters.ToAttributesWithExclude(parsedPolicy) if err != nil { return nil, err } @@ -93,13 +93,14 @@ func getKeyPolicyFunc(ctx context.Context, client keyPolicyClient, scope string, // +overmind:group AWS // +overmind:terraform:queryMap aws_kms_key_policy.key_id -func NewKeyPolicySource(client keyPolicyClient, accountID string, region string) *sources.AlwaysGetSource[*kms.ListKeyPoliciesInput, *kms.ListKeyPoliciesOutput, *kms.GetKeyPolicyInput, *kms.GetKeyPolicyOutput, keyPolicyClient, *kms.Options] { - return &sources.AlwaysGetSource[*kms.ListKeyPoliciesInput, *kms.ListKeyPoliciesOutput, *kms.GetKeyPolicyInput, *kms.GetKeyPolicyOutput, keyPolicyClient, *kms.Options]{ - ItemType: "kms-key-policy", - Client: client, - AccountID: accountID, - Region: region, - DisableList: true, // This source only supports listing by Key ID +func NewKeyPolicyAdapter(client keyPolicyClient, accountID string, region string) *adapters.AlwaysGetAdapter[*kms.ListKeyPoliciesInput, *kms.ListKeyPoliciesOutput, *kms.GetKeyPolicyInput, *kms.GetKeyPolicyOutput, keyPolicyClient, *kms.Options] { + return &adapters.AlwaysGetAdapter[*kms.ListKeyPoliciesInput, *kms.ListKeyPoliciesOutput, *kms.GetKeyPolicyInput, *kms.GetKeyPolicyOutput, keyPolicyClient, *kms.Options]{ + ItemType: "kms-key-policy", + Client: client, + AccountID: accountID, + Region: region, + DisableList: true, // This adapter only supports listing by Key ID + AdapterMetadata: KeyPolicyMetadata(), SearchInputMapper: func(scope, query string) (*kms.ListKeyPoliciesInput, error) { return &kms.ListKeyPoliciesInput{ KeyId: &query, @@ -110,7 +111,7 @@ func NewKeyPolicySource(client keyPolicyClient, accountID string, region string) KeyId: &query, } }, - ListFuncPaginatorBuilder: func(client keyPolicyClient, input *kms.ListKeyPoliciesInput) sources.Paginator[*kms.ListKeyPoliciesOutput, *kms.Options] { + ListFuncPaginatorBuilder: func(client keyPolicyClient, input *kms.ListKeyPoliciesInput) adapters.Paginator[*kms.ListKeyPoliciesOutput, *kms.Options] { return kms.NewListKeyPoliciesPaginator(client, input) }, ListFuncOutputMapper: func(output *kms.ListKeyPoliciesOutput, input *kms.ListKeyPoliciesInput) ([]*kms.GetKeyPolicyInput, error) { @@ -126,3 +127,21 @@ func NewKeyPolicySource(client keyPolicyClient, accountID string, region string) GetFunc: getKeyPolicyFunc, } } + +func KeyPolicyMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "kms-key-policy", + DescriptiveName: "KMS Key Policy", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + Search: true, + GetDescription: "Get a KMS key policy by its Key ID", + SearchDescription: "Search KMS key policies by Key ID", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_kms_key_policy.key_id"}, + }, + PotentialLinks: []string{"kms-key"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_SECURITY, + } +} diff --git a/sources/kms/key-policy_test.go b/adapters/kms/key-policy_test.go similarity index 84% rename from sources/kms/key-policy_test.go rename to adapters/kms/key-policy_test.go index 6547cc24..c3dde0df 100644 --- a/sources/kms/key-policy_test.go +++ b/adapters/kms/key-policy_test.go @@ -5,10 +5,10 @@ import ( "testing" "time" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" "github.com/aws/aws-sdk-go-v2/service/kms" - "github.com/overmindtech/aws-source/sources" ) /* @@ -44,7 +44,7 @@ type mockKeyPolicyClient struct{} func (m *mockKeyPolicyClient) GetKeyPolicy(ctx context.Context, params *kms.GetKeyPolicyInput, optFns ...func(*kms.Options)) (*kms.GetKeyPolicyOutput, error) { return &kms.GetKeyPolicyOutput{ - Policy: sources.PtrString(`{ + Policy: adapters.PtrString(`{ "Version" : "2012-10-17", "Id" : "key-default-1", "Statement" : [ @@ -68,7 +68,7 @@ func (m *mockKeyPolicyClient) GetKeyPolicy(ctx context.Context, params *kms.GetK } ] }`), - PolicyName: sources.PtrString("default"), + PolicyName: adapters.PtrString("default"), }, nil } @@ -83,7 +83,7 @@ func TestGetKeyPolicyFunc(t *testing.T) { cli := &mockKeyPolicyClient{} item, err := getKeyPolicyFunc(ctx, cli, "scope", &kms.GetKeyPolicyInput{ - KeyId: sources.PtrString("1234abcd-12ab-34cd-56ef-1234567890ab"), + KeyId: adapters.PtrString("1234abcd-12ab-34cd-56ef-1234567890ab"), }) if err != nil { t.Fatal(err) @@ -93,7 +93,7 @@ func TestGetKeyPolicyFunc(t *testing.T) { t.Fatal(err) } - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "kms-key", ExpectedMethod: sdp.QueryMethod_GET, @@ -105,15 +105,15 @@ func TestGetKeyPolicyFunc(t *testing.T) { tests.Execute(t, item) } -func TestNewKeyPolicySource(t *testing.T) { - config, account, region := sources.GetAutoConfig(t) +func TestNewKeyPolicyAdapter(t *testing.T) { + config, account, region := adapters.GetAutoConfig(t) client := kms.NewFromConfig(config) - source := NewKeyPolicySource(client, account, region) + adapter := NewKeyPolicyAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, SkipList: true, } diff --git a/sources/kms/key.go b/adapters/kms/key.go similarity index 74% rename from sources/kms/key.go rename to adapters/kms/key.go index 34c7b6f9..6d6f07b6 100644 --- a/sources/kms/key.go +++ b/adapters/kms/key.go @@ -6,7 +6,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/kms/types" "github.com/aws/aws-sdk-go-v2/service/kms" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -29,7 +29,7 @@ func getFunc(ctx context.Context, client kmsClient, scope string, input *kms.Des } } - attributes, err := sources.ToAttributesWithExclude(output.KeyMetadata) + attributes, err := adapters.ToAttributesWithExclude(output.KeyMetadata) if err != nil { return nil, err } @@ -41,7 +41,7 @@ func getFunc(ctx context.Context, client kmsClient, scope string, input *kms.Des var resourceTags map[string]string resourceTags, err = tags(ctx, client, *input.KeyId) if err != nil { - resourceTags = sources.HandleTagsError(ctx, err) + resourceTags = adapters.HandleTagsError(ctx, err) } item := &sdp.Item{ @@ -130,19 +130,20 @@ func getFunc(ctx context.Context, client kmsClient, scope string, input *kms.Des // +overmind:group AWS // +overmind:terraform:queryMap aws_kms_key.key_id -func NewKeySource(client kmsClient, accountID, region string) *sources.AlwaysGetSource[*kms.ListKeysInput, *kms.ListKeysOutput, *kms.DescribeKeyInput, *kms.DescribeKeyOutput, kmsClient, *kms.Options] { - return &sources.AlwaysGetSource[*kms.ListKeysInput, *kms.ListKeysOutput, *kms.DescribeKeyInput, *kms.DescribeKeyOutput, kmsClient, *kms.Options]{ - ItemType: "kms-key", - Client: client, - AccountID: accountID, - Region: region, - ListInput: &kms.ListKeysInput{}, +func NewKeyAdapter(client kmsClient, accountID, region string) *adapters.AlwaysGetAdapter[*kms.ListKeysInput, *kms.ListKeysOutput, *kms.DescribeKeyInput, *kms.DescribeKeyOutput, kmsClient, *kms.Options] { + return &adapters.AlwaysGetAdapter[*kms.ListKeysInput, *kms.ListKeysOutput, *kms.DescribeKeyInput, *kms.DescribeKeyOutput, kmsClient, *kms.Options]{ + ItemType: "kms-key", + Client: client, + AccountID: accountID, + Region: region, + ListInput: &kms.ListKeysInput{}, + AdapterMetadata: KeyMetadata(), GetInputMapper: func(scope, query string) *kms.DescribeKeyInput { return &kms.DescribeKeyInput{ KeyId: &query, } }, - ListFuncPaginatorBuilder: func(client kmsClient, input *kms.ListKeysInput) sources.Paginator[*kms.ListKeysOutput, *kms.Options] { + ListFuncPaginatorBuilder: func(client kmsClient, input *kms.ListKeysInput) adapters.Paginator[*kms.ListKeysOutput, *kms.Options] { return kms.NewListKeysPaginator(client, input) }, ListFuncOutputMapper: func(output *kms.ListKeysOutput, _ *kms.ListKeysInput) ([]*kms.DescribeKeyInput, error) { @@ -157,3 +158,25 @@ func NewKeySource(client kmsClient, accountID, region string) *sources.AlwaysGet GetFunc: getFunc, } } + +func KeyMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "kms-key", + DescriptiveName: "KMS Key", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a KMS Key by its ID", + ListDescription: "List all KMS Keys", + SearchDescription: "Search for KMS Keys by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + { + TerraformQueryMap: "aws_kms_key.key_id", + }, + }, + PotentialLinks: []string{"kms-custom-key-store", "kms-key-policy", "kms-grant"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_SECURITY, + } +} diff --git a/sources/kms/key_test.go b/adapters/kms/key_test.go similarity index 50% rename from sources/kms/key_test.go rename to adapters/kms/key_test.go index 1f91e8be..6435e9c0 100644 --- a/sources/kms/key_test.go +++ b/adapters/kms/key_test.go @@ -6,7 +6,7 @@ import ( "time" "github.com/aws/aws-sdk-go-v2/service/kms/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/aws/aws-sdk-go-v2/service/kms" ) @@ -16,12 +16,12 @@ type testClient struct{} func (t testClient) DescribeKey(ctx context.Context, params *kms.DescribeKeyInput, optFns ...func(*kms.Options)) (*kms.DescribeKeyOutput, error) { return &kms.DescribeKeyOutput{ KeyMetadata: &types.KeyMetadata{ - AWSAccountId: sources.PtrString("846764612917"), - KeyId: sources.PtrString("b8a9477d-836c-491f-857e-07937918959b"), - Arn: sources.PtrString("arn:aws:kms:us-west-2:846764612917:key/b8a9477d-836c-491f-857e-07937918959b"), - CreationDate: sources.PtrTime(time.Date(2017, 6, 30, 21, 44, 32, 140000000, time.UTC)), + AWSAccountId: adapters.PtrString("846764612917"), + KeyId: adapters.PtrString("b8a9477d-836c-491f-857e-07937918959b"), + Arn: adapters.PtrString("arn:aws:kms:us-west-2:846764612917:key/b8a9477d-836c-491f-857e-07937918959b"), + CreationDate: adapters.PtrTime(time.Date(2017, 6, 30, 21, 44, 32, 140000000, time.UTC)), Enabled: true, - Description: sources.PtrString("Default KMS key that protects my S3 objects when no other key is defined"), + Description: adapters.PtrString("Default KMS key that protects my S3 objects when no other key is defined"), KeyUsage: types.KeyUsageTypeEncryptDecrypt, KeyState: types.KeyStateEnabled, Origin: types.OriginTypeAwsKms, @@ -38,16 +38,16 @@ func (t testClient) ListKeys(context.Context, *kms.ListKeysInput, ...func(*kms.O return &kms.ListKeysOutput{ Keys: []types.KeyListEntry{ { - KeyArn: sources.PtrString("arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab"), - KeyId: sources.PtrString("1234abcd-12ab-34cd-56ef-1234567890ab"), + KeyArn: adapters.PtrString("arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab"), + KeyId: adapters.PtrString("1234abcd-12ab-34cd-56ef-1234567890ab"), }, { - KeyArn: sources.PtrString("arn:aws:kms:us-west-2:111122223333:key/0987dcba-09fe-87dc-65ba-ab0987654321"), - KeyId: sources.PtrString("0987dcba-09fe-87dc-65ba-ab0987654321"), + KeyArn: adapters.PtrString("arn:aws:kms:us-west-2:111122223333:key/0987dcba-09fe-87dc-65ba-ab0987654321"), + KeyId: adapters.PtrString("0987dcba-09fe-87dc-65ba-ab0987654321"), }, { - KeyArn: sources.PtrString("arn:aws:kms:us-east-2:111122223333:key/1a2b3c4d-5e6f-1a2b-3c4d-5e6f1a2b3c4d"), - KeyId: sources.PtrString("1a2b3c4d-5e6f-1a2b-3c4d-5e6f1a2b3c4d"), + KeyArn: adapters.PtrString("arn:aws:kms:us-east-2:111122223333:key/1a2b3c4d-5e6f-1a2b-3c4d-5e6f1a2b3c4d"), + KeyId: adapters.PtrString("1a2b3c4d-5e6f-1a2b-3c4d-5e6f1a2b3c4d"), }, }, }, nil @@ -57,16 +57,16 @@ func (t testClient) ListResourceTags(context.Context, *kms.ListResourceTagsInput return &kms.ListResourceTagsOutput{ Tags: []types.Tag{ { - TagKey: sources.PtrString("Dept"), - TagValue: sources.PtrString("IT"), + TagKey: adapters.PtrString("Dept"), + TagValue: adapters.PtrString("IT"), }, { - TagKey: sources.PtrString("Purpose"), - TagValue: sources.PtrString("Test"), + TagKey: adapters.PtrString("Purpose"), + TagValue: adapters.PtrString("Test"), }, { - TagKey: sources.PtrString("Name"), - TagValue: sources.PtrString("Test"), + TagKey: adapters.PtrString("Name"), + TagValue: adapters.PtrString("Test"), }, }, }, nil @@ -77,7 +77,7 @@ func TestGetFunc(t *testing.T) { cli := testClient{} item, err := getFunc(ctx, cli, "scope", &kms.DescribeKeyInput{ - KeyId: sources.PtrString("1234abcd-12ab-34cd-56ef-1234567890ab"), + KeyId: adapters.PtrString("1234abcd-12ab-34cd-56ef-1234567890ab"), }) if err != nil { t.Fatal(err) @@ -88,14 +88,14 @@ func TestGetFunc(t *testing.T) { } } -func TestNewKeySource(t *testing.T) { - config, account, region := sources.GetAutoConfig(t) +func TestNewKeyAdapter(t *testing.T) { + config, account, region := adapters.GetAutoConfig(t) client := kms.NewFromConfig(config) - source := NewKeySource(client, account, region) + adapter := NewKeyAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/kms/shared.go b/adapters/kms/shared.go similarity index 100% rename from sources/kms/shared.go rename to adapters/kms/shared.go diff --git a/sources/lambda/function.go b/adapters/lambda/function.go similarity index 83% rename from sources/lambda/function.go rename to adapters/lambda/function.go index ba944357..3472f656 100644 --- a/sources/lambda/function.go +++ b/adapters/lambda/function.go @@ -8,7 +8,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/lambda" "github.com/aws/aws-sdk-go-v2/service/lambda/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -100,7 +100,7 @@ func functionGetFunc(ctx context.Context, client LambdaClient, scope string, inp } } - attributes, err := sources.ToAttributesWithExclude(function, "resultMetadata") + attributes, err := adapters.ToAttributesWithExclude(function, "resultMetadata") if err != nil { return nil, err @@ -176,7 +176,7 @@ func functionGetFunc(ctx context.Context, client LambdaClient, scope string, inp } } - var a *sources.ARN + var a *adapters.ARN if function.Configuration != nil { switch function.Configuration.State { @@ -191,14 +191,14 @@ func functionGetFunc(ctx context.Context, client LambdaClient, scope string, inp } if function.Configuration.Role != nil { - if a, err = sources.ParseARN(*function.Configuration.Role); err == nil { + if a, err = adapters.ParseARN(*function.Configuration.Role); err == nil { // +overmind:link iam-role item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "iam-role", Method: sdp.QueryMethod_SEARCH, Query: *function.Configuration.Role, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changing the role will affect the function @@ -228,14 +228,14 @@ func functionGetFunc(ctx context.Context, client LambdaClient, scope string, inp for _, fsConfig := range function.Configuration.FileSystemConfigs { if fsConfig.Arn != nil { - if a, err = sources.ParseARN(*fsConfig.Arn); err == nil { + if a, err = adapters.ParseARN(*fsConfig.Arn); err == nil { // +overmind:link efs-access-point item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "efs-access-point", Method: sdp.QueryMethod_SEARCH, Query: *fsConfig.Arn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // These are really tightly linked @@ -248,14 +248,14 @@ func functionGetFunc(ctx context.Context, client LambdaClient, scope string, inp } if function.Configuration.KMSKeyArn != nil { - if a, err = sources.ParseARN(*function.Configuration.KMSKeyArn); err == nil { + if a, err = adapters.ParseARN(*function.Configuration.KMSKeyArn); err == nil { // +overmind:link kms-key item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "kms-key", Method: sdp.QueryMethod_SEARCH, Query: *function.Configuration.KMSKeyArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changing the key will affect the function @@ -269,7 +269,7 @@ func functionGetFunc(ctx context.Context, client LambdaClient, scope string, inp for _, layer := range function.Configuration.Layers { if layer.Arn != nil { - if a, err = sources.ParseARN(*layer.Arn); err == nil { + if a, err = adapters.ParseARN(*layer.Arn); err == nil { // Strip the leading "layer:" name := strings.TrimPrefix(a.Resource, "layer:") @@ -279,7 +279,7 @@ func functionGetFunc(ctx context.Context, client LambdaClient, scope string, inp Type: "lambda-layer-version", Method: sdp.QueryMethod_GET, Query: name, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // These are tightly linked @@ -291,14 +291,14 @@ func functionGetFunc(ctx context.Context, client LambdaClient, scope string, inp } if layer.SigningJobArn != nil { - if a, err = sources.ParseARN(*layer.SigningJobArn); err == nil { + if a, err = adapters.ParseARN(*layer.SigningJobArn); err == nil { // +overmind:link signer-signing-job item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "signer-signing-job", Method: sdp.QueryMethod_SEARCH, Query: *layer.SigningJobArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changing the signing will affect the function @@ -311,14 +311,14 @@ func functionGetFunc(ctx context.Context, client LambdaClient, scope string, inp } if layer.SigningProfileVersionArn != nil { - if a, err = sources.ParseARN(*layer.SigningProfileVersionArn); err == nil { + if a, err = adapters.ParseARN(*layer.SigningProfileVersionArn); err == nil { // +overmind:link signer-signing-profile item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "signer-signing-profile", Method: sdp.QueryMethod_SEARCH, Query: *layer.SigningProfileVersionArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changing the signing will affect the function @@ -332,14 +332,14 @@ func functionGetFunc(ctx context.Context, client LambdaClient, scope string, inp } if function.Configuration.MasterArn != nil { - if a, err = sources.ParseARN(*function.Configuration.MasterArn); err == nil { + if a, err = adapters.ParseARN(*function.Configuration.MasterArn); err == nil { // +overmind:link lambda-function item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "lambda-function", Method: sdp.QueryMethod_SEARCH, Query: *function.Configuration.MasterArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Tightly linked @@ -351,14 +351,14 @@ func functionGetFunc(ctx context.Context, client LambdaClient, scope string, inp } if function.Configuration.SigningJobArn != nil { - if a, err = sources.ParseARN(*function.Configuration.SigningJobArn); err == nil { + if a, err = adapters.ParseARN(*function.Configuration.SigningJobArn); err == nil { // +overmind:link signer-signing-job item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "signer-signing-job", Method: sdp.QueryMethod_SEARCH, Query: *function.Configuration.SigningJobArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changing the signing will affect the function @@ -371,14 +371,14 @@ func functionGetFunc(ctx context.Context, client LambdaClient, scope string, inp } if function.Configuration.SigningProfileVersionArn != nil { - if a, err = sources.ParseARN(*function.Configuration.SigningProfileVersionArn); err == nil { + if a, err = adapters.ParseARN(*function.Configuration.SigningProfileVersionArn); err == nil { // +overmind:link signer-signing-profile item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "signer-signing-profile", Method: sdp.QueryMethod_SEARCH, Query: *function.Configuration.SigningProfileVersionArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changing the signing will affect the function @@ -520,20 +520,20 @@ func ExtractLinksFromPolicy(policy *PolicyDocument) []*sdp.LinkedItemQuery { // that from the policy as the ARN doesn't contain the account that // the bucket is in queryType = "s3-bucket" - scope = sources.FormatScope(statement.Condition.StringEquals.AWSSourceAccount, "") + scope = adapters.FormatScope(statement.Condition.StringEquals.AWSSourceAccount, "") default: continue } if scope == "" { // If we don't have a scope set then extract it from the target ARN - parsedARN, err := sources.ParseARN(statement.Condition.ArnLike.AWSSourceArn) + parsedARN, err := adapters.ParseARN(statement.Condition.ArnLike.AWSSourceArn) if err != nil { continue } - scope = sources.FormatScope(parsedARN.AccountID, parsedARN.Region) + scope = adapters.FormatScope(parsedARN.AccountID, parsedARN.Region) } links = append(links, &sdp.LinkedItemQuery{ @@ -557,13 +557,13 @@ func ExtractLinksFromPolicy(policy *PolicyDocument) []*sdp.LinkedItemQuery { // GetEventLinkedItem Gets the linked item request for a given destination ARN func GetEventLinkedItem(destinationARN string) (*sdp.LinkedItemQuery, error) { - parsed, err := sources.ParseARN(destinationARN) + parsed, err := adapters.ParseARN(destinationARN) if err != nil { return nil, err } - scope := sources.FormatScope(parsed.AccountID, parsed.Region) + scope := adapters.FormatScope(parsed.AccountID, parsed.Region) switch parsed.Service { case "sns": @@ -640,20 +640,21 @@ func GetEventLinkedItem(destinationARN string) (*sdp.LinkedItemQuery, error) { // +overmind:terraform:queryMap aws_lambda_function_url.function_arn // +overmind:terraform:method SEARCH -func NewFunctionSource(client LambdaClient, accountID string, region string) *sources.AlwaysGetSource[*lambda.ListFunctionsInput, *lambda.ListFunctionsOutput, *lambda.GetFunctionInput, *lambda.GetFunctionOutput, LambdaClient, *lambda.Options] { - return &sources.AlwaysGetSource[*lambda.ListFunctionsInput, *lambda.ListFunctionsOutput, *lambda.GetFunctionInput, *lambda.GetFunctionOutput, LambdaClient, *lambda.Options]{ - ItemType: "lambda-function", - Client: client, - AccountID: accountID, - Region: region, - ListInput: &lambda.ListFunctionsInput{}, - GetFunc: functionGetFunc, +func NewFunctionAdapter(client LambdaClient, accountID string, region string) *adapters.AlwaysGetAdapter[*lambda.ListFunctionsInput, *lambda.ListFunctionsOutput, *lambda.GetFunctionInput, *lambda.GetFunctionOutput, LambdaClient, *lambda.Options] { + return &adapters.AlwaysGetAdapter[*lambda.ListFunctionsInput, *lambda.ListFunctionsOutput, *lambda.GetFunctionInput, *lambda.GetFunctionOutput, LambdaClient, *lambda.Options]{ + ItemType: "lambda-function", + Client: client, + AccountID: accountID, + Region: region, + ListInput: &lambda.ListFunctionsInput{}, + GetFunc: functionGetFunc, + AdapterMetadata: FunctionMetadata(), GetInputMapper: func(scope, query string) *lambda.GetFunctionInput { return &lambda.GetFunctionInput{ FunctionName: &query, } }, - ListFuncPaginatorBuilder: func(client LambdaClient, input *lambda.ListFunctionsInput) sources.Paginator[*lambda.ListFunctionsOutput, *lambda.Options] { + ListFuncPaginatorBuilder: func(client LambdaClient, input *lambda.ListFunctionsInput) adapters.Paginator[*lambda.ListFunctionsOutput, *lambda.Options] { return lambda.NewListFunctionsPaginator(client, input) }, ListFuncOutputMapper: func(output *lambda.ListFunctionsOutput, input *lambda.ListFunctionsInput) ([]*lambda.GetFunctionInput, error) { @@ -669,3 +670,25 @@ func NewFunctionSource(client LambdaClient, accountID string, region string) *so }, } } + +func FunctionMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "lambda-function", + DescriptiveName: "Lambda Function", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a lambda function by name", + ListDescription: "List all lambda functions", + SearchDescription: "Search for lambda functions by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_lambda_function.arn"}, + {TerraformQueryMap: "aws_lambda_function_event_invoke_config.id"}, + {TerraformQueryMap: "aws_lambda_function_url.function_arn"}, + }, + PotentialLinks: []string{"iam-role", "s3-bucket", "sns-topic", "sqs-queue", "lambda-function", "events-event-bus", "elbv2-target-group", "vpc-lattice-target-group", "logs-log-group"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_COMPUTE_APPLICATION, + } +} diff --git a/sources/lambda/function_test.go b/adapters/lambda/function_test.go similarity index 73% rename from sources/lambda/function_test.go rename to adapters/lambda/function_test.go index d8042296..9806bafe 100644 --- a/sources/lambda/function_test.go +++ b/adapters/lambda/function_test.go @@ -7,23 +7,23 @@ import ( "github.com/aws/aws-sdk-go-v2/service/lambda" "github.com/aws/aws-sdk-go-v2/service/lambda/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) var testFuncConfig = &types.FunctionConfiguration{ - FunctionName: sources.PtrString("aws-controltower-NotificationForwarder"), - FunctionArn: sources.PtrString("arn:aws:lambda:eu-west-2:052392120703:function:aws-controltower-NotificationForwarder"), + FunctionName: adapters.PtrString("aws-controltower-NotificationForwarder"), + FunctionArn: adapters.PtrString("arn:aws:lambda:eu-west-2:052392120703:function:aws-controltower-NotificationForwarder"), Runtime: types.RuntimePython39, - Role: sources.PtrString("arn:aws:iam::052392120703:role/aws-controltower-ForwardSnsNotificationRole"), // link - Handler: sources.PtrString("index.lambda_handler"), + Role: adapters.PtrString("arn:aws:iam::052392120703:role/aws-controltower-ForwardSnsNotificationRole"), // link + Handler: adapters.PtrString("index.lambda_handler"), CodeSize: 473, - Description: sources.PtrString("SNS message forwarding function for aggregating account notifications."), - Timeout: sources.PtrInt32(60), - MemorySize: sources.PtrInt32(128), - LastModified: sources.PtrString("2022-12-13T15:22:48.157+0000"), - CodeSha256: sources.PtrString("3zU7iYiZektHRaog6qOFvv34ggadB56rd/UMjnYms6A="), - Version: sources.PtrString("$LATEST"), + Description: adapters.PtrString("SNS message forwarding function for aggregating account notifications."), + Timeout: adapters.PtrInt32(60), + MemorySize: adapters.PtrInt32(128), + LastModified: adapters.PtrString("2022-12-13T15:22:48.157+0000"), + CodeSha256: adapters.PtrString("3zU7iYiZektHRaog6qOFvv34ggadB56rd/UMjnYms6A="), + Version: adapters.PtrString("$LATEST"), Environment: &types.EnvironmentResponse{ Variables: map[string]string{ "sns_arn": "arn:aws:sns:eu-west-2:347195421325:aws-controltower-AggregateSecurityNotifications", @@ -32,7 +32,7 @@ var testFuncConfig = &types.FunctionConfiguration{ TracingConfig: &types.TracingConfigResponse{ Mode: types.TracingModePassThrough, }, - RevisionId: sources.PtrString("b00dd2e6-eec3-48b0-abf1-f84406e00a3e"), + RevisionId: adapters.PtrString("b00dd2e6-eec3-48b0-abf1-f84406e00a3e"), State: types.StateActive, LastUpdateStatus: types.LastUpdateStatusSuccessful, PackageType: types.PackageTypeZip, @@ -40,47 +40,47 @@ var testFuncConfig = &types.FunctionConfiguration{ types.ArchitectureX8664, }, EphemeralStorage: &types.EphemeralStorage{ - Size: sources.PtrInt32(512), + Size: adapters.PtrInt32(512), }, DeadLetterConfig: &types.DeadLetterConfig{ - TargetArn: sources.PtrString("arn:aws:sns:us-east-2:444455556666:MyTopic"), // links + TargetArn: adapters.PtrString("arn:aws:sns:us-east-2:444455556666:MyTopic"), // links }, FileSystemConfigs: []types.FileSystemConfig{ { - Arn: sources.PtrString("arn:aws:service:region:account:type/id"), // links - LocalMountPath: sources.PtrString("/config"), + Arn: adapters.PtrString("arn:aws:service:region:account:type/id"), // links + LocalMountPath: adapters.PtrString("/config"), }, }, ImageConfigResponse: &types.ImageConfigResponse{ Error: &types.ImageConfigError{ - ErrorCode: sources.PtrString("500"), - Message: sources.PtrString("borked"), + ErrorCode: adapters.PtrString("500"), + Message: adapters.PtrString("borked"), }, ImageConfig: &types.ImageConfig{ Command: []string{"echo", "foo"}, EntryPoint: []string{"/bin"}, - WorkingDirectory: sources.PtrString("/"), + WorkingDirectory: adapters.PtrString("/"), }, }, - KMSKeyArn: sources.PtrString("arn:aws:service:region:account:type/id"), // link - LastUpdateStatusReason: sources.PtrString("reason"), + KMSKeyArn: adapters.PtrString("arn:aws:service:region:account:type/id"), // link + LastUpdateStatusReason: adapters.PtrString("reason"), LastUpdateStatusReasonCode: types.LastUpdateStatusReasonCodeDisabledKMSKey, Layers: []types.Layer{ { - Arn: sources.PtrString("arn:aws:service:region:account:layer:name:version"), // link + Arn: adapters.PtrString("arn:aws:service:region:account:layer:name:version"), // link CodeSize: 128, - SigningJobArn: sources.PtrString("arn:aws:service:region:account:type/id"), // link - SigningProfileVersionArn: sources.PtrString("arn:aws:service:region:account:type/id"), // link + SigningJobArn: adapters.PtrString("arn:aws:service:region:account:type/id"), // link + SigningProfileVersionArn: adapters.PtrString("arn:aws:service:region:account:type/id"), // link }, }, - MasterArn: sources.PtrString("arn:aws:service:region:account:type/id"), // link - SigningJobArn: sources.PtrString("arn:aws:service:region:account:type/id"), // link - SigningProfileVersionArn: sources.PtrString("arn:aws:service:region:account:type/id"), // link + MasterArn: adapters.PtrString("arn:aws:service:region:account:type/id"), // link + SigningJobArn: adapters.PtrString("arn:aws:service:region:account:type/id"), // link + SigningProfileVersionArn: adapters.PtrString("arn:aws:service:region:account:type/id"), // link SnapStart: &types.SnapStartResponse{ ApplyOn: types.SnapStartApplyOnPublishedVersions, OptimizationStatus: types.SnapStartOptimizationStatusOn, }, - StateReason: sources.PtrString("reason"), + StateReason: adapters.PtrString("reason"), StateReasonCode: types.StateReasonCodeCreating, VpcConfig: &types.VpcConfigResponse{ SecurityGroupIds: []string{ @@ -89,15 +89,15 @@ var testFuncConfig = &types.FunctionConfiguration{ SubnetIds: []string{ "id", // link }, - VpcId: sources.PtrString("id"), // link + VpcId: adapters.PtrString("id"), // link }, } var testFuncCode = &types.FunctionCodeLocation{ - RepositoryType: sources.PtrString("S3"), - Location: sources.PtrString("https://awslambda-eu-west-2-tasks.s3.eu-west-2.amazonaws.com/snapshots/052392120703/aws-controltower-NotificationForwarder-bcea303b-7721-4cf0-b8db-7a0e6dca76dd"), // link - ImageUri: sources.PtrString("https://foo"), // link - ResolvedImageUri: sources.PtrString("https://foo"), // link + RepositoryType: adapters.PtrString("S3"), + Location: adapters.PtrString("https://awslambda-eu-west-2-tasks.s3.eu-west-2.amazonaws.com/snapshots/052392120703/aws-controltower-NotificationForwarder-bcea303b-7721-4cf0-b8db-7a0e6dca76dd"), // link + ImageUri: adapters.PtrString("https://foo"), // link + ResolvedImageUri: adapters.PtrString("https://foo"), // link } func (t *TestLambdaClient) GetFunction(ctx context.Context, params *lambda.GetFunctionInput, optFns ...func(*lambda.Options)) (*lambda.GetFunctionOutput, error) { @@ -118,16 +118,16 @@ func (t *TestLambdaClient) ListFunctionEventInvokeConfigs(context.Context, *lamb { DestinationConfig: &types.DestinationConfig{ OnFailure: &types.OnFailure{ - Destination: sources.PtrString("arn:aws:events:region:account:event-bus/event-bus-name"), // link + Destination: adapters.PtrString("arn:aws:events:region:account:event-bus/event-bus-name"), // link }, OnSuccess: &types.OnSuccess{ - Destination: sources.PtrString("arn:aws:events:region:account:event-bus/event-bus-name"), // link + Destination: adapters.PtrString("arn:aws:events:region:account:event-bus/event-bus-name"), // link }, }, - FunctionArn: sources.PtrString("arn:aws:service:region:account:type/id"), - LastModified: sources.PtrTime(time.Now()), - MaximumEventAgeInSeconds: sources.PtrInt32(10), - MaximumRetryAttempts: sources.PtrInt32(20), + FunctionArn: adapters.PtrString("arn:aws:service:region:account:type/id"), + LastModified: adapters.PtrTime(time.Now()), + MaximumEventAgeInSeconds: adapters.PtrInt32(10), + MaximumRetryAttempts: adapters.PtrInt32(20), }, }, }, nil @@ -138,17 +138,17 @@ func (t *TestLambdaClient) ListFunctionUrlConfigs(context.Context, *lambda.ListF FunctionUrlConfigs: []types.FunctionUrlConfig{ { AuthType: types.FunctionUrlAuthTypeNone, - CreationTime: sources.PtrString("recently"), - FunctionArn: sources.PtrString("arn:aws:service:region:account:type/id"), - FunctionUrl: sources.PtrString("https://bar"), // link - LastModifiedTime: sources.PtrString("recently"), + CreationTime: adapters.PtrString("recently"), + FunctionArn: adapters.PtrString("arn:aws:service:region:account:type/id"), + FunctionUrl: adapters.PtrString("https://bar"), // link + LastModifiedTime: adapters.PtrString("recently"), Cors: &types.Cors{ - AllowCredentials: sources.PtrBool(true), + AllowCredentials: adapters.PtrBool(true), AllowHeaders: []string{"X-Forwarded-For"}, AllowMethods: []string{"GET"}, AllowOrigins: []string{"https://bar"}, ExposeHeaders: []string{"X-Authentication"}, - MaxAge: sources.PtrInt32(10), + MaxAge: adapters.PtrInt32(10), }, }, }, @@ -180,7 +180,7 @@ func TestFunctionGetFunc(t *testing.T) { t.Error(err) } - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "http", ExpectedMethod: sdp.QueryMethod_GET, @@ -373,13 +373,13 @@ func TestGetEventLinkedItem(t *testing.T) { } } -func TestNewFunctionSource(t *testing.T) { +func TestNewFunctionAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewFunctionSource(client, account, region) + adapter := NewFunctionAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/lambda/layer.go b/adapters/lambda/layer.go similarity index 66% rename from sources/lambda/layer.go rename to adapters/lambda/layer.go index d7661f83..e2d3911e 100644 --- a/sources/lambda/layer.go +++ b/adapters/lambda/layer.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/lambda" "github.com/aws/aws-sdk-go-v2/service/lambda/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -31,7 +31,7 @@ func layerListFunc(ctx context.Context, client *lambda.Client, scope string) ([] } func layerItemMapper(_, scope string, awsItem *types.LayersListItem) (*sdp.Item, error) { - attributes, err := sources.ToAttributesWithExclude(awsItem) + attributes, err := adapters.ToAttributesWithExclude(awsItem) if err != nil { return nil, err @@ -70,12 +70,13 @@ func layerItemMapper(_, scope string, awsItem *types.LayersListItem) (*sdp.Item, // +overmind:list List all lambda layers // +overmind:group AWS -func NewLayerSource(client *lambda.Client, accountID string, region string) *sources.GetListSource[*types.LayersListItem, *lambda.Client, *lambda.Options] { - return &sources.GetListSource[*types.LayersListItem, *lambda.Client, *lambda.Options]{ - ItemType: "lambda-layer", - Client: client, - AccountID: accountID, - Region: region, +func NewLayerAdapter(client *lambda.Client, accountID string, region string) *adapters.GetListAdapter[*types.LayersListItem, *lambda.Client, *lambda.Options] { + return &adapters.GetListAdapter[*types.LayersListItem, *lambda.Client, *lambda.Options]{ + ItemType: "lambda-layer", + Client: client, + AccountID: accountID, + Region: region, + AdapterMetadata: LayerMetadata(), GetFunc: func(_ context.Context, _ *lambda.Client, _, _ string) (*types.LayersListItem, error) { // Layers can only be listed return nil, errors.New("get is not supported for lambda-layers") @@ -84,3 +85,16 @@ func NewLayerSource(client *lambda.Client, accountID string, region string) *sou ItemMapper: layerItemMapper, } } + +func LayerMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "lambda-layer", + DescriptiveName: "Lambda Layer", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + List: true, + ListDescription: "List all lambda layers", + }, + PotentialLinks: []string{"lambda-layer-version"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_COMPUTE_APPLICATION, + } +} diff --git a/sources/lambda/layer_test.go b/adapters/lambda/layer_test.go similarity index 60% rename from sources/lambda/layer_test.go rename to adapters/lambda/layer_test.go index 7a06093d..7ee6bdb5 100644 --- a/sources/lambda/layer_test.go +++ b/adapters/lambda/layer_test.go @@ -5,7 +5,7 @@ import ( "time" "github.com/aws/aws-sdk-go-v2/service/lambda/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -19,14 +19,14 @@ func TestLayerItemMapper(t *testing.T) { CompatibleRuntimes: []types.Runtime{ types.RuntimeJava11, }, - CreatedDate: sources.PtrString("2018-11-27T15:10:45.123+0000"), - Description: sources.PtrString("description"), - LayerVersionArn: sources.PtrString("arn:aws:service:region:account:type/id"), - LicenseInfo: sources.PtrString("info"), + CreatedDate: adapters.PtrString("2018-11-27T15:10:45.123+0000"), + Description: adapters.PtrString("description"), + LayerVersionArn: adapters.PtrString("arn:aws:service:region:account:type/id"), + LicenseInfo: adapters.PtrString("info"), Version: 10, }, - LayerArn: sources.PtrString("arn:aws:service:region:account:type/id"), - LayerName: sources.PtrString("name"), + LayerArn: adapters.PtrString("arn:aws:service:region:account:type/id"), + LayerName: adapters.PtrString("name"), } item, err := layerItemMapper("", "foo", &layer) @@ -39,7 +39,7 @@ func TestLayerItemMapper(t *testing.T) { t.Error(err) } - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "lambda-layer-version", ExpectedMethod: sdp.QueryMethod_GET, @@ -51,13 +51,13 @@ func TestLayerItemMapper(t *testing.T) { tests.Execute(t, item) } -func TestNewLayerSource(t *testing.T) { +func TestNewLayerAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewLayerSource(client, account, region) + adapter := NewLayerAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, SkipGet: true, } diff --git a/sources/lambda/layer_version.go b/adapters/lambda/layer_version.go similarity index 59% rename from sources/lambda/layer_version.go rename to adapters/lambda/layer_version.go index cd97c833..713eca82 100644 --- a/sources/lambda/layer_version.go +++ b/adapters/lambda/layer_version.go @@ -7,7 +7,7 @@ import ( "strings" "github.com/aws/aws-sdk-go-v2/service/lambda" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -28,7 +28,7 @@ func layerVersionGetInputMapper(scope, query string) *lambda.GetLayerVersionInpu return &lambda.GetLayerVersionInput{ LayerName: &name, - VersionNumber: sources.PtrInt64(int64(versionInt)), + VersionNumber: adapters.PtrInt64(int64(versionInt)), } } @@ -46,7 +46,7 @@ func layerVersionGetFunc(ctx context.Context, client LambdaClient, scope string, return nil, err } - attributes, err := sources.ToAttributesWithExclude(out, "resultMetadata") + attributes, err := adapters.ToAttributesWithExclude(out, "resultMetadata") if err != nil { return nil, err @@ -65,18 +65,18 @@ func layerVersionGetFunc(ctx context.Context, client LambdaClient, scope string, Scope: scope, } - var a *sources.ARN + var a *adapters.ARN if out.Content != nil { if out.Content.SigningJobArn != nil { - if a, err = sources.ParseARN(*out.Content.SigningJobArn); err == nil { + if a, err = adapters.ParseARN(*out.Content.SigningJobArn); err == nil { // +overmind:link signer-signing-job item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "signer-signing-job", Method: sdp.QueryMethod_SEARCH, Query: *out.Content.SigningJobArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Signing jobs can affect layers @@ -89,14 +89,14 @@ func layerVersionGetFunc(ctx context.Context, client LambdaClient, scope string, } if out.Content.SigningProfileVersionArn != nil { - if a, err = sources.ParseARN(*out.Content.SigningProfileVersionArn); err == nil { + if a, err = adapters.ParseARN(*out.Content.SigningProfileVersionArn); err == nil { // +overmind:link signer-signing-profile item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "signer-signing-profile", Method: sdp.QueryMethod_SEARCH, Query: *out.Content.SigningProfileVersionArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Signing profiles can affect layers @@ -121,21 +121,40 @@ func layerVersionGetFunc(ctx context.Context, client LambdaClient, scope string, // +overmind:terraform:queryMap aws_lambda_layer_version.arn // +overmind:terraform:method SEARCH -func NewLayerVersionSource(client LambdaClient, accountID string, region string) *sources.AlwaysGetSource[*lambda.ListLayerVersionsInput, *lambda.ListLayerVersionsOutput, *lambda.GetLayerVersionInput, *lambda.GetLayerVersionOutput, LambdaClient, *lambda.Options] { - return &sources.AlwaysGetSource[*lambda.ListLayerVersionsInput, *lambda.ListLayerVersionsOutput, *lambda.GetLayerVersionInput, *lambda.GetLayerVersionOutput, LambdaClient, *lambda.Options]{ - ItemType: "lambda-layer-version", - Client: client, - AccountID: accountID, - Region: region, - DisableList: true, - GetInputMapper: layerVersionGetInputMapper, - GetFunc: layerVersionGetFunc, - ListInput: &lambda.ListLayerVersionsInput{}, +func NewLayerVersionAdapter(client LambdaClient, accountID string, region string) *adapters.AlwaysGetAdapter[*lambda.ListLayerVersionsInput, *lambda.ListLayerVersionsOutput, *lambda.GetLayerVersionInput, *lambda.GetLayerVersionOutput, LambdaClient, *lambda.Options] { + return &adapters.AlwaysGetAdapter[*lambda.ListLayerVersionsInput, *lambda.ListLayerVersionsOutput, *lambda.GetLayerVersionInput, *lambda.GetLayerVersionOutput, LambdaClient, *lambda.Options]{ + ItemType: "lambda-layer-version", + Client: client, + AccountID: accountID, + Region: region, + DisableList: true, + GetInputMapper: layerVersionGetInputMapper, + GetFunc: layerVersionGetFunc, + ListInput: &lambda.ListLayerVersionsInput{}, + AdapterMetadata: LayerVersionMetadata(), ListFuncOutputMapper: func(output *lambda.ListLayerVersionsOutput, input *lambda.ListLayerVersionsInput) ([]*lambda.GetLayerVersionInput, error) { return []*lambda.GetLayerVersionInput{}, nil }, - ListFuncPaginatorBuilder: func(client LambdaClient, input *lambda.ListLayerVersionsInput) sources.Paginator[*lambda.ListLayerVersionsOutput, *lambda.Options] { + ListFuncPaginatorBuilder: func(client LambdaClient, input *lambda.ListLayerVersionsInput) adapters.Paginator[*lambda.ListLayerVersionsOutput, *lambda.Options] { return lambda.NewListLayerVersionsPaginator(client, input) }, } } + +func LayerVersionMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "lambda-layer-version", + DescriptiveName: "Lambda Layer Version", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + Search: true, + GetDescription: "Get a layer version by full name ({layerName}:{versionNumber})", + SearchDescription: "Search for layer versions by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_lambda_layer_version.arn"}, + }, + PotentialLinks: []string{"signer-signing-job", "signer-signing-profile"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_COMPUTE_APPLICATION, + } +} diff --git a/sources/lambda/layer_version_test.go b/adapters/lambda/layer_version_test.go similarity index 71% rename from sources/lambda/layer_version_test.go rename to adapters/lambda/layer_version_test.go index 3ef245b1..8d9f29a1 100644 --- a/sources/lambda/layer_version_test.go +++ b/adapters/lambda/layer_version_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/lambda" "github.com/aws/aws-sdk-go-v2/service/lambda/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -62,17 +62,17 @@ func (t *TestLambdaClient) GetLayerVersion(ctx context.Context, params *lambda.G types.RuntimeDotnet6, }, Content: &types.LayerVersionContentOutput{ - CodeSha256: sources.PtrString("sha"), + CodeSha256: adapters.PtrString("sha"), CodeSize: 100, - Location: sources.PtrString("somewhere"), - SigningJobArn: sources.PtrString("arn:aws:service:region:account:type/id"), - SigningProfileVersionArn: sources.PtrString("arn:aws:service:region:account:type/id"), + Location: adapters.PtrString("somewhere"), + SigningJobArn: adapters.PtrString("arn:aws:service:region:account:type/id"), + SigningProfileVersionArn: adapters.PtrString("arn:aws:service:region:account:type/id"), }, - CreatedDate: sources.PtrString("YYYY-MM-DDThh:mm:ss.sTZD"), - Description: sources.PtrString("description"), - LayerArn: sources.PtrString("arn:aws:service:region:account:type/id"), - LayerVersionArn: sources.PtrString("arn:aws:service:region:account:type/id"), - LicenseInfo: sources.PtrString("info"), + CreatedDate: adapters.PtrString("YYYY-MM-DDThh:mm:ss.sTZD"), + Description: adapters.PtrString("description"), + LayerArn: adapters.PtrString("arn:aws:service:region:account:type/id"), + LayerVersionArn: adapters.PtrString("arn:aws:service:region:account:type/id"), + LicenseInfo: adapters.PtrString("info"), Version: *params.VersionNumber, }, nil } @@ -83,8 +83,8 @@ func (t *TestLambdaClient) ListLayerVersions(context.Context, *lambda.ListLayerV func TestLayerVersionGetFunc(t *testing.T) { item, err := layerVersionGetFunc(context.Background(), &TestLambdaClient{}, "foo", &lambda.GetLayerVersionInput{ - LayerName: sources.PtrString("layer"), - VersionNumber: sources.PtrInt64(999), + LayerName: adapters.PtrString("layer"), + VersionNumber: adapters.PtrInt64(999), }) if err != nil { @@ -95,7 +95,7 @@ func TestLayerVersionGetFunc(t *testing.T) { t.Error(err) } - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "signer-signing-job", ExpectedMethod: sdp.QueryMethod_SEARCH, @@ -113,13 +113,13 @@ func TestLayerVersionGetFunc(t *testing.T) { tests.Execute(t, item) } -func TestNewLayerVersionSource(t *testing.T) { +func TestNewLayerVersionAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewLayerVersionSource(client, account, region) + adapter := NewLayerVersionAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/lambda/policy_parser.go b/adapters/lambda/policy_parser.go similarity index 100% rename from sources/lambda/policy_parser.go rename to adapters/lambda/policy_parser.go diff --git a/sources/lambda/policy_parser_test.go b/adapters/lambda/policy_parser_test.go similarity index 100% rename from sources/lambda/policy_parser_test.go rename to adapters/lambda/policy_parser_test.go diff --git a/sources/lambda/shared.go b/adapters/lambda/shared.go similarity index 100% rename from sources/lambda/shared.go rename to adapters/lambda/shared.go diff --git a/sources/lambda/shared_test.go b/adapters/lambda/shared_test.go similarity index 72% rename from sources/lambda/shared_test.go rename to adapters/lambda/shared_test.go index 7560f464..d1a2ea5f 100644 --- a/sources/lambda/shared_test.go +++ b/adapters/lambda/shared_test.go @@ -4,13 +4,13 @@ import ( "testing" "github.com/aws/aws-sdk-go-v2/service/lambda" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" ) type TestLambdaClient struct{} func GetAutoConfig(t *testing.T) (*lambda.Client, string, string) { - config, account, region := sources.GetAutoConfig(t) + config, account, region := adapters.GetAutoConfig(t) client := lambda.NewFromConfig(config) return client, account, region diff --git a/sources/networkfirewall/firewall.go b/adapters/networkfirewall/firewall.go similarity index 80% rename from sources/networkfirewall/firewall.go rename to adapters/networkfirewall/firewall.go index 6a5df6c2..c4d016b9 100644 --- a/sources/networkfirewall/firewall.go +++ b/adapters/networkfirewall/firewall.go @@ -6,7 +6,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/networkfirewall" "github.com/aws/aws-sdk-go-v2/service/networkfirewall/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -67,7 +67,7 @@ func firewallGetFunc(ctx context.Context, client networkFirewallClient, scope st wg.Wait() - attributes, err := sources.ToAttributesWithExclude(uf) + attributes, err := adapters.ToAttributesWithExclude(uf) if err != nil { return nil, err @@ -181,14 +181,14 @@ func firewallGetFunc(ctx context.Context, client networkFirewallClient, scope st } if config.FirewallPolicyArn != nil { - if a, err := sources.ParseARN(*config.FirewallPolicyArn); err == nil { + if a, err := adapters.ParseARN(*config.FirewallPolicyArn); err == nil { //+overmind:link network-firewall-firewall-policy item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "network-firewall-firewall-policy", Method: sdp.QueryMethod_SEARCH, Query: *config.FirewallPolicyArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Policy will affect the firewall but not the other way around @@ -269,13 +269,14 @@ func firewallGetFunc(ctx context.Context, client networkFirewallClient, scope st // +overmind:group AWS // +overmind:terraform:queryMap aws_networkfirewall_firewall.name -func NewFirewallSource(client networkFirewallClient, accountID string, region string) *sources.AlwaysGetSource[*networkfirewall.ListFirewallsInput, *networkfirewall.ListFirewallsOutput, *networkfirewall.DescribeFirewallInput, *networkfirewall.DescribeFirewallOutput, networkFirewallClient, *networkfirewall.Options] { - return &sources.AlwaysGetSource[*networkfirewall.ListFirewallsInput, *networkfirewall.ListFirewallsOutput, *networkfirewall.DescribeFirewallInput, *networkfirewall.DescribeFirewallOutput, networkFirewallClient, *networkfirewall.Options]{ - ItemType: "network-firewall-firewall", - Client: client, - AccountID: accountID, - Region: region, - ListInput: &networkfirewall.ListFirewallsInput{}, +func NewFirewallAdapter(client networkFirewallClient, accountID string, region string) *adapters.AlwaysGetAdapter[*networkfirewall.ListFirewallsInput, *networkfirewall.ListFirewallsOutput, *networkfirewall.DescribeFirewallInput, *networkfirewall.DescribeFirewallOutput, networkFirewallClient, *networkfirewall.Options] { + return &adapters.AlwaysGetAdapter[*networkfirewall.ListFirewallsInput, *networkfirewall.ListFirewallsOutput, *networkfirewall.DescribeFirewallInput, *networkfirewall.DescribeFirewallOutput, networkFirewallClient, *networkfirewall.Options]{ + ItemType: "network-firewall-firewall", + Client: client, + AccountID: accountID, + Region: region, + ListInput: &networkfirewall.ListFirewallsInput{}, + AdapterMetadata: FirewallMetadata(), GetInputMapper: func(scope, query string) *networkfirewall.DescribeFirewallInput { return &networkfirewall.DescribeFirewallInput{ FirewallName: &query, @@ -286,7 +287,7 @@ func NewFirewallSource(client networkFirewallClient, accountID string, region st FirewallArn: &query, }, nil }, - ListFuncPaginatorBuilder: func(client networkFirewallClient, input *networkfirewall.ListFirewallsInput) sources.Paginator[*networkfirewall.ListFirewallsOutput, *networkfirewall.Options] { + ListFuncPaginatorBuilder: func(client networkFirewallClient, input *networkfirewall.ListFirewallsInput) adapters.Paginator[*networkfirewall.ListFirewallsOutput, *networkfirewall.Options] { return networkfirewall.NewListFirewallsPaginator(client, input) }, ListFuncOutputMapper: func(output *networkfirewall.ListFirewallsOutput, input *networkfirewall.ListFirewallsInput) ([]*networkfirewall.DescribeFirewallInput, error) { @@ -304,3 +305,23 @@ func NewFirewallSource(client networkFirewallClient, accountID string, region st }, } } + +func FirewallMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "network-firewall-firewall", + DescriptiveName: "Network Firewall", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a Network Firewall by name", + ListDescription: "List Network Firewalls", + SearchDescription: "Search for Network Firewalls by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_networkfirewall_firewall.name"}, + }, + PotentialLinks: []string{"network-firewall-firewall-policy", "ec2-subnet", "ec2-vpc", "logs-log-group", "s3-bucket", "firehose-delivery-stream", "iam-policy", "kms-key"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + } +} diff --git a/sources/networkfirewall/firewall_policy.go b/adapters/networkfirewall/firewall_policy.go similarity index 67% rename from sources/networkfirewall/firewall_policy.go rename to adapters/networkfirewall/firewall_policy.go index 8106b79f..bee11b7d 100644 --- a/sources/networkfirewall/firewall_policy.go +++ b/adapters/networkfirewall/firewall_policy.go @@ -5,7 +5,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/networkfirewall" "github.com/aws/aws-sdk-go-v2/service/networkfirewall/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -26,7 +26,7 @@ func firewallPolicyGetFunc(ctx context.Context, client networkFirewallClient, sc FirewallPolicy: resp.FirewallPolicy, } - attributes, err := sources.ToAttributesWithExclude(ufp) + attributes, err := adapters.ToAttributesWithExclude(ufp) if err != nil { return nil, err @@ -78,14 +78,14 @@ func firewallPolicyGetFunc(ctx context.Context, client networkFirewallClient, sc } for _, arn := range ruleGroupArns { - if a, err := sources.ParseARN(arn); err == nil { + if a, err := adapters.ParseARN(arn); err == nil { //+overmind:link network-firewall-rule-group item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "network-firewall-rule-group", Query: arn, Method: sdp.QueryMethod_SEARCH, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ In: true, @@ -96,14 +96,14 @@ func firewallPolicyGetFunc(ctx context.Context, client networkFirewallClient, sc } if resp.FirewallPolicy.TLSInspectionConfigurationArn != nil { - if a, err := sources.ParseARN(*resp.FirewallPolicy.TLSInspectionConfigurationArn); err == nil { + if a, err := adapters.ParseARN(*resp.FirewallPolicy.TLSInspectionConfigurationArn); err == nil { //+overmind:link network-firewall-tls-inspection-configuration item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "network-firewall-tls-inspection-configuration", Method: sdp.QueryMethod_SEARCH, Query: *resp.FirewallPolicy.TLSInspectionConfigurationArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ In: true, @@ -125,13 +125,14 @@ func firewallPolicyGetFunc(ctx context.Context, client networkFirewallClient, sc // +overmind:group AWS // +overmind:terraform:queryMap aws_networkfirewall_firewall_policy.name -func NewFirewallPolicySource(client networkFirewallClient, accountID string, region string) *sources.AlwaysGetSource[*networkfirewall.ListFirewallPoliciesInput, *networkfirewall.ListFirewallPoliciesOutput, *networkfirewall.DescribeFirewallPolicyInput, *networkfirewall.DescribeFirewallPolicyOutput, networkFirewallClient, *networkfirewall.Options] { - return &sources.AlwaysGetSource[*networkfirewall.ListFirewallPoliciesInput, *networkfirewall.ListFirewallPoliciesOutput, *networkfirewall.DescribeFirewallPolicyInput, *networkfirewall.DescribeFirewallPolicyOutput, networkFirewallClient, *networkfirewall.Options]{ - ItemType: "network-firewall-firewall-policy", - Client: client, - AccountID: accountID, - Region: region, - ListInput: &networkfirewall.ListFirewallPoliciesInput{}, +func NewFirewallPolicyAdapter(client networkFirewallClient, accountID string, region string) *adapters.AlwaysGetAdapter[*networkfirewall.ListFirewallPoliciesInput, *networkfirewall.ListFirewallPoliciesOutput, *networkfirewall.DescribeFirewallPolicyInput, *networkfirewall.DescribeFirewallPolicyOutput, networkFirewallClient, *networkfirewall.Options] { + return &adapters.AlwaysGetAdapter[*networkfirewall.ListFirewallPoliciesInput, *networkfirewall.ListFirewallPoliciesOutput, *networkfirewall.DescribeFirewallPolicyInput, *networkfirewall.DescribeFirewallPolicyOutput, networkFirewallClient, *networkfirewall.Options]{ + ItemType: "network-firewall-firewall-policy", + Client: client, + AccountID: accountID, + Region: region, + ListInput: &networkfirewall.ListFirewallPoliciesInput{}, + AdapterMetadata: FirewallPolicyMetadata(), GetInputMapper: func(scope, query string) *networkfirewall.DescribeFirewallPolicyInput { return &networkfirewall.DescribeFirewallPolicyInput{ FirewallPolicyName: &query, @@ -142,7 +143,7 @@ func NewFirewallPolicySource(client networkFirewallClient, accountID string, reg FirewallPolicyArn: &query, }, nil }, - ListFuncPaginatorBuilder: func(client networkFirewallClient, input *networkfirewall.ListFirewallPoliciesInput) sources.Paginator[*networkfirewall.ListFirewallPoliciesOutput, *networkfirewall.Options] { + ListFuncPaginatorBuilder: func(client networkFirewallClient, input *networkfirewall.ListFirewallPoliciesInput) adapters.Paginator[*networkfirewall.ListFirewallPoliciesOutput, *networkfirewall.Options] { return networkfirewall.NewListFirewallPoliciesPaginator(client, input) }, ListFuncOutputMapper: func(output *networkfirewall.ListFirewallPoliciesOutput, input *networkfirewall.ListFirewallPoliciesInput) ([]*networkfirewall.DescribeFirewallPolicyInput, error) { @@ -160,3 +161,23 @@ func NewFirewallPolicySource(client networkFirewallClient, accountID string, reg }, } } + +func FirewallPolicyMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "network-firewall-firewall-policy", + DescriptiveName: "Network Firewall Policy", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a Network Firewall Policy by name", + ListDescription: "List Network Firewall Policies", + SearchDescription: "Search for Network Firewall Policies by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_networkfirewall_firewall_policy.name"}, + }, + PotentialLinks: []string{"network-firewall-rule-group", "network-firewall-tls-inspection-configuration", "kms-key"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + } +} diff --git a/sources/networkfirewall/firewall_policy_test.go b/adapters/networkfirewall/firewall_policy_test.go similarity index 68% rename from sources/networkfirewall/firewall_policy_test.go rename to adapters/networkfirewall/firewall_policy_test.go index cd609a8e..e67ef337 100644 --- a/sources/networkfirewall/firewall_policy_test.go +++ b/adapters/networkfirewall/firewall_policy_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/networkfirewall" "github.com/aws/aws-sdk-go-v2/service/networkfirewall/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -15,23 +15,23 @@ func (c testNetworkFirewallClient) DescribeFirewallPolicy(ctx context.Context, p now := time.Now() return &networkfirewall.DescribeFirewallPolicyOutput{ FirewallPolicyResponse: &types.FirewallPolicyResponse{ - FirewallPolicyArn: sources.PtrString("arn:aws:network-firewall:us-east-1:123456789012:stateless-rulegroup/aws-network-firewall-DefaultStatelessRuleGroup-1J3Z3W2ZQXV3"), - FirewallPolicyId: sources.PtrString("test"), - FirewallPolicyName: sources.PtrString("test"), - ConsumedStatefulRuleCapacity: sources.PtrInt32(1), - ConsumedStatelessRuleCapacity: sources.PtrInt32(1), - Description: sources.PtrString("test"), + FirewallPolicyArn: adapters.PtrString("arn:aws:network-firewall:us-east-1:123456789012:stateless-rulegroup/aws-network-firewall-DefaultStatelessRuleGroup-1J3Z3W2ZQXV3"), + FirewallPolicyId: adapters.PtrString("test"), + FirewallPolicyName: adapters.PtrString("test"), + ConsumedStatefulRuleCapacity: adapters.PtrInt32(1), + ConsumedStatelessRuleCapacity: adapters.PtrInt32(1), + Description: adapters.PtrString("test"), EncryptionConfiguration: &types.EncryptionConfiguration{ Type: types.EncryptionTypeAwsOwnedKmsKey, - KeyId: sources.PtrString("arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012"), // link (this can be an ARN or ID) + KeyId: adapters.PtrString("arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012"), // link (this can be an ARN or ID) }, FirewallPolicyStatus: types.ResourceStatusActive, // health LastModifiedTime: &now, - NumberOfAssociations: sources.PtrInt32(1), + NumberOfAssociations: adapters.PtrInt32(1), Tags: []types.Tag{ { - Key: sources.PtrString("test"), - Value: sources.PtrString("test"), + Key: adapters.PtrString("test"), + Value: adapters.PtrString("test"), }, }, }, @@ -52,11 +52,11 @@ func (c testNetworkFirewallClient) DescribeFirewallPolicy(ctx context.Context, p }, StatefulRuleGroupReferences: []types.StatefulRuleGroupReference{ { - ResourceArn: sources.PtrString("arn:aws:network-firewall:us-east-1:123456789012:stateful-rulegroup/aws-network-firewall-DefaultStatefulRuleGroup-1J3Z3W2ZQXV3"), // link + ResourceArn: adapters.PtrString("arn:aws:network-firewall:us-east-1:123456789012:stateful-rulegroup/aws-network-firewall-DefaultStatefulRuleGroup-1J3Z3W2ZQXV3"), // link Override: &types.StatefulRuleGroupOverride{ Action: types.OverrideActionDropToAlert, }, - Priority: sources.PtrInt32(1), + Priority: adapters.PtrInt32(1), }, }, StatelessCustomActions: []types.CustomAction{ @@ -66,16 +66,16 @@ func (c testNetworkFirewallClient) DescribeFirewallPolicy(ctx context.Context, p Dimensions: []types.Dimension{}, }, }, - ActionName: sources.PtrString("test"), + ActionName: adapters.PtrString("test"), }, }, StatelessRuleGroupReferences: []types.StatelessRuleGroupReference{ { - Priority: sources.PtrInt32(1), - ResourceArn: sources.PtrString("arn:aws:network-firewall:us-east-1:123456789012:stateless-rulegroup/aws-network-firewall-DefaultStatelessRuleGroup-1J3Z3W2ZQXV3"), // link + Priority: adapters.PtrInt32(1), + ResourceArn: adapters.PtrString("arn:aws:network-firewall:us-east-1:123456789012:stateless-rulegroup/aws-network-firewall-DefaultStatelessRuleGroup-1J3Z3W2ZQXV3"), // link }, }, - TLSInspectionConfigurationArn: sources.PtrString("arn:aws:network-firewall:us-east-1:123456789012:tls-inspection-configuration/aws-network-firewall-DefaultTlsInspectionConfiguration-1J3Z3W2ZQXV3"), // link + TLSInspectionConfigurationArn: adapters.PtrString("arn:aws:network-firewall:us-east-1:123456789012:tls-inspection-configuration/aws-network-firewall-DefaultTlsInspectionConfiguration-1J3Z3W2ZQXV3"), // link }, }, nil } @@ -84,7 +84,7 @@ func (c testNetworkFirewallClient) ListFirewallPolicies(context.Context, *networ return &networkfirewall.ListFirewallPoliciesOutput{ FirewallPolicies: []types.FirewallPolicyMetadata{ { - Arn: sources.PtrString("arn:aws:network-firewall:us-east-1:123456789012:stateless-rulegroup/aws-network-firewall-DefaultStatelessRuleGroup-1J3Z3W2ZQXV3"), + Arn: adapters.PtrString("arn:aws:network-firewall:us-east-1:123456789012:stateless-rulegroup/aws-network-firewall-DefaultStatelessRuleGroup-1J3Z3W2ZQXV3"), }, }, }, nil @@ -101,7 +101,7 @@ func TestFirewallPolicyGetFunc(t *testing.T) { t.Fatal(err) } - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "kms-key", ExpectedMethod: sdp.QueryMethod_SEARCH, diff --git a/sources/networkfirewall/firewall_test.go b/adapters/networkfirewall/firewall_test.go similarity index 75% rename from sources/networkfirewall/firewall_test.go rename to adapters/networkfirewall/firewall_test.go index 3ad4a0dd..f09b3214 100644 --- a/sources/networkfirewall/firewall_test.go +++ b/adapters/networkfirewall/firewall_test.go @@ -6,36 +6,36 @@ import ( "github.com/aws/aws-sdk-go-v2/service/networkfirewall" "github.com/aws/aws-sdk-go-v2/service/networkfirewall/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) func (c testNetworkFirewallClient) DescribeFirewall(ctx context.Context, params *networkfirewall.DescribeFirewallInput, optFns ...func(*networkfirewall.Options)) (*networkfirewall.DescribeFirewallOutput, error) { return &networkfirewall.DescribeFirewallOutput{ Firewall: &types.Firewall{ - FirewallId: sources.PtrString("test"), - FirewallPolicyArn: sources.PtrString("arn:aws:network-firewall:us-east-1:123456789012:stateless-rulegroup/aws-network-firewall-DefaultStatelessRuleGroup-1J3Z3W2ZQXV3"), // link + FirewallId: adapters.PtrString("test"), + FirewallPolicyArn: adapters.PtrString("arn:aws:network-firewall:us-east-1:123456789012:stateless-rulegroup/aws-network-firewall-DefaultStatelessRuleGroup-1J3Z3W2ZQXV3"), // link SubnetMappings: []types.SubnetMapping{ { - SubnetId: sources.PtrString("subnet-12345678901234567"), // link + SubnetId: adapters.PtrString("subnet-12345678901234567"), // link IPAddressType: types.IPAddressTypeIpv4, }, }, - VpcId: sources.PtrString("vpc-12345678901234567"), // link + VpcId: adapters.PtrString("vpc-12345678901234567"), // link DeleteProtection: false, - Description: sources.PtrString("test"), + Description: adapters.PtrString("test"), EncryptionConfiguration: &types.EncryptionConfiguration{ Type: types.EncryptionTypeAwsOwnedKmsKey, - KeyId: sources.PtrString("arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012"), // link (this can be an ARN or ID) + KeyId: adapters.PtrString("arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012"), // link (this can be an ARN or ID) }, - FirewallArn: sources.PtrString("arn:aws:network-firewall:us-east-1:123456789012:firewall/aws-network-firewall-DefaultFirewall-1J3Z3W2ZQXV3"), - FirewallName: sources.PtrString("test"), + FirewallArn: adapters.PtrString("arn:aws:network-firewall:us-east-1:123456789012:firewall/aws-network-firewall-DefaultFirewall-1J3Z3W2ZQXV3"), + FirewallName: adapters.PtrString("test"), FirewallPolicyChangeProtection: false, SubnetChangeProtection: false, Tags: []types.Tag{ { - Key: sources.PtrString("test"), - Value: sources.PtrString("test"), + Key: adapters.PtrString("test"), + Value: adapters.PtrString("test"), }, }, }, @@ -44,22 +44,22 @@ func (c testNetworkFirewallClient) DescribeFirewall(ctx context.Context, params Status: types.FirewallStatusValueDeleting, CapacityUsageSummary: &types.CapacityUsageSummary{ CIDRs: &types.CIDRSummary{ - AvailableCIDRCount: sources.PtrInt32(1), + AvailableCIDRCount: adapters.PtrInt32(1), IPSetReferences: map[string]types.IPSetMetadata{ "test": { - ResolvedCIDRCount: sources.PtrInt32(1), + ResolvedCIDRCount: adapters.PtrInt32(1), }, }, - UtilizedCIDRCount: sources.PtrInt32(1), + UtilizedCIDRCount: adapters.PtrInt32(1), }, }, SyncStates: map[string]types.SyncState{ "test": { Attachment: &types.Attachment{ - EndpointId: sources.PtrString("test"), + EndpointId: adapters.PtrString("test"), Status: types.AttachmentStatusCreating, - StatusMessage: sources.PtrString("test"), - SubnetId: sources.PtrString("test"), // link, + StatusMessage: adapters.PtrString("test"), + SubnetId: adapters.PtrString("test"), // link, }, }, }, @@ -69,7 +69,7 @@ func (c testNetworkFirewallClient) DescribeFirewall(ctx context.Context, params func (c testNetworkFirewallClient) DescribeLoggingConfiguration(ctx context.Context, params *networkfirewall.DescribeLoggingConfigurationInput, optFns ...func(*networkfirewall.Options)) (*networkfirewall.DescribeLoggingConfigurationOutput, error) { return &networkfirewall.DescribeLoggingConfigurationOutput{ - FirewallArn: sources.PtrString("arn:aws:network-firewall:us-east-1:123456789012:firewall/aws-network-firewall-DefaultFirewall-1J3Z3W2ZQXV3"), + FirewallArn: adapters.PtrString("arn:aws:network-firewall:us-east-1:123456789012:firewall/aws-network-firewall-DefaultFirewall-1J3Z3W2ZQXV3"), LoggingConfiguration: &types.LoggingConfiguration{ LogDestinationConfigs: []types.LogDestinationConfig{ { @@ -101,7 +101,7 @@ func (c testNetworkFirewallClient) DescribeLoggingConfiguration(ctx context.Cont func (c testNetworkFirewallClient) DescribeResourcePolicy(ctx context.Context, params *networkfirewall.DescribeResourcePolicyInput, optFns ...func(*networkfirewall.Options)) (*networkfirewall.DescribeResourcePolicyOutput, error) { return &networkfirewall.DescribeResourcePolicyOutput{ - Policy: sources.PtrString("test"), // link + Policy: adapters.PtrString("test"), // link }, nil } @@ -109,7 +109,7 @@ func (c testNetworkFirewallClient) ListFirewalls(context.Context, *networkfirewa return &networkfirewall.ListFirewallsOutput{ Firewalls: []types.FirewallMetadata{ { - FirewallArn: sources.PtrString("arn:aws:network-firewall:us-east-1:123456789012:firewall/aws-network-firewall-DefaultFirewall-1J3Z3W2ZQXV3"), + FirewallArn: adapters.PtrString("arn:aws:network-firewall:us-east-1:123456789012:firewall/aws-network-firewall-DefaultFirewall-1J3Z3W2ZQXV3"), }, }, }, nil @@ -126,7 +126,7 @@ func TestFirewallGetFunc(t *testing.T) { t.Fatal(err) } - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "ec2-subnet", ExpectedMethod: sdp.QueryMethod_GET, diff --git a/sources/networkfirewall/rule_group.go b/adapters/networkfirewall/rule_group.go similarity index 66% rename from sources/networkfirewall/rule_group.go rename to adapters/networkfirewall/rule_group.go index f1775794..6403fedf 100644 --- a/sources/networkfirewall/rule_group.go +++ b/adapters/networkfirewall/rule_group.go @@ -6,7 +6,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/networkfirewall" "github.com/aws/aws-sdk-go-v2/service/networkfirewall/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -33,7 +33,7 @@ func ruleGroupGetFunc(ctx context.Context, client networkFirewallClient, scope s RuleGroup: resp.RuleGroup, } - attributes, err := sources.ToAttributesWithExclude(urg) + attributes, err := adapters.ToAttributesWithExclude(urg) if err != nil { return nil, err @@ -69,14 +69,14 @@ func ruleGroupGetFunc(ctx context.Context, client networkFirewallClient, scope s item.LinkedItemQueries = append(item.LinkedItemQueries, encryptionConfigurationLink(resp.RuleGroupResponse.EncryptionConfiguration, scope)) if resp.RuleGroupResponse.SnsTopic != nil { - if a, err := sources.ParseARN(*resp.RuleGroupResponse.SnsTopic); err == nil { + if a, err := adapters.ParseARN(*resp.RuleGroupResponse.SnsTopic); err == nil { //+overmind:link sns-topic item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "sns-topic", Method: sdp.QueryMethod_SEARCH, Query: *resp.RuleGroupResponse.SnsTopic, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ In: false, @@ -87,14 +87,14 @@ func ruleGroupGetFunc(ctx context.Context, client networkFirewallClient, scope s } if resp.RuleGroupResponse.SourceMetadata != nil && resp.RuleGroupResponse.SourceMetadata.SourceArn != nil { - if a, err := sources.ParseARN(*resp.RuleGroupResponse.SourceMetadata.SourceArn); err == nil { + if a, err := adapters.ParseARN(*resp.RuleGroupResponse.SourceMetadata.SourceArn); err == nil { //+overmind:link network-firewall-rule-group item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "network-firewall-rule-group", Method: sdp.QueryMethod_SEARCH, Query: *resp.RuleGroupResponse.SourceMetadata.SourceArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ In: false, @@ -116,13 +116,14 @@ func ruleGroupGetFunc(ctx context.Context, client networkFirewallClient, scope s // +overmind:group AWS // +overmind:terraform:queryMap aws_networkfirewall_rule_group.name -func NewRuleGroupSource(client networkFirewallClient, accountID string, region string) *sources.AlwaysGetSource[*networkfirewall.ListRuleGroupsInput, *networkfirewall.ListRuleGroupsOutput, *networkfirewall.DescribeRuleGroupInput, *networkfirewall.DescribeRuleGroupOutput, networkFirewallClient, *networkfirewall.Options] { - return &sources.AlwaysGetSource[*networkfirewall.ListRuleGroupsInput, *networkfirewall.ListRuleGroupsOutput, *networkfirewall.DescribeRuleGroupInput, *networkfirewall.DescribeRuleGroupOutput, networkFirewallClient, *networkfirewall.Options]{ - ItemType: "network-firewall-rule-group", - Client: client, - AccountID: accountID, - Region: region, - ListInput: &networkfirewall.ListRuleGroupsInput{}, +func NewRuleGroupAdapter(client networkFirewallClient, accountID string, region string) *adapters.AlwaysGetAdapter[*networkfirewall.ListRuleGroupsInput, *networkfirewall.ListRuleGroupsOutput, *networkfirewall.DescribeRuleGroupInput, *networkfirewall.DescribeRuleGroupOutput, networkFirewallClient, *networkfirewall.Options] { + return &adapters.AlwaysGetAdapter[*networkfirewall.ListRuleGroupsInput, *networkfirewall.ListRuleGroupsOutput, *networkfirewall.DescribeRuleGroupInput, *networkfirewall.DescribeRuleGroupOutput, networkFirewallClient, *networkfirewall.Options]{ + ItemType: "network-firewall-rule-group", + Client: client, + AccountID: accountID, + Region: region, + ListInput: &networkfirewall.ListRuleGroupsInput{}, + AdapterMetadata: RuleGroupMetadata(), GetInputMapper: func(scope, query string) *networkfirewall.DescribeRuleGroupInput { return &networkfirewall.DescribeRuleGroupInput{ RuleGroupName: &query, @@ -133,7 +134,7 @@ func NewRuleGroupSource(client networkFirewallClient, accountID string, region s RuleGroupArn: &query, }, nil }, - ListFuncPaginatorBuilder: func(client networkFirewallClient, input *networkfirewall.ListRuleGroupsInput) sources.Paginator[*networkfirewall.ListRuleGroupsOutput, *networkfirewall.Options] { + ListFuncPaginatorBuilder: func(client networkFirewallClient, input *networkfirewall.ListRuleGroupsInput) adapters.Paginator[*networkfirewall.ListRuleGroupsOutput, *networkfirewall.Options] { return networkfirewall.NewListRuleGroupsPaginator(client, input) }, ListFuncOutputMapper: func(output *networkfirewall.ListRuleGroupsOutput, input *networkfirewall.ListRuleGroupsInput) ([]*networkfirewall.DescribeRuleGroupInput, error) { @@ -151,3 +152,23 @@ func NewRuleGroupSource(client networkFirewallClient, accountID string, region s }, } } + +func RuleGroupMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "network-firewall-rule-group", + DescriptiveName: "Network Firewall Rule Group", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a Network Firewall Rule Group by name", + ListDescription: "List Network Firewall Rule Groups", + SearchDescription: "Search for Network Firewall Rule Groups by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_networkfirewall_rule_group.name"}, + }, + PotentialLinks: []string{"kms-key", "sns-topic", "network-firewall-rule-group"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_SECURITY, + } +} diff --git a/sources/networkfirewall/rule_group_test.go b/adapters/networkfirewall/rule_group_test.go similarity index 69% rename from sources/networkfirewall/rule_group_test.go rename to adapters/networkfirewall/rule_group_test.go index de451470..3bb5ea23 100644 --- a/sources/networkfirewall/rule_group_test.go +++ b/adapters/networkfirewall/rule_group_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/networkfirewall" "github.com/aws/aws-sdk-go-v2/service/networkfirewall/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -16,37 +16,37 @@ func (c testNetworkFirewallClient) DescribeRuleGroup(ctx context.Context, params return &networkfirewall.DescribeRuleGroupOutput{ RuleGroupResponse: &types.RuleGroupResponse{ - RuleGroupArn: sources.PtrString("arn:aws:network-firewall:us-east-1:123456789012:stateless-rulegroup/aws-network-firewall-DefaultStatelessRuleGroup-1J3Z3W2ZQXV3"), - RuleGroupId: sources.PtrString("test"), - RuleGroupName: sources.PtrString("test"), + RuleGroupArn: adapters.PtrString("arn:aws:network-firewall:us-east-1:123456789012:stateless-rulegroup/aws-network-firewall-DefaultStatelessRuleGroup-1J3Z3W2ZQXV3"), + RuleGroupId: adapters.PtrString("test"), + RuleGroupName: adapters.PtrString("test"), AnalysisResults: []types.AnalysisResult{ { - AnalysisDetail: sources.PtrString("test"), + AnalysisDetail: adapters.PtrString("test"), IdentifiedRuleIds: []string{ "test", }, IdentifiedType: types.IdentifiedTypeStatelessRuleContainsTcpFlags, }, }, - Capacity: sources.PtrInt32(1), - ConsumedCapacity: sources.PtrInt32(1), - Description: sources.PtrString("test"), + Capacity: adapters.PtrInt32(1), + ConsumedCapacity: adapters.PtrInt32(1), + Description: adapters.PtrString("test"), EncryptionConfiguration: &types.EncryptionConfiguration{ Type: types.EncryptionTypeAwsOwnedKmsKey, - KeyId: sources.PtrString("arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012"), // link (this can be an ARN or ID) + KeyId: adapters.PtrString("arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012"), // link (this can be an ARN or ID) }, LastModifiedTime: &now, - NumberOfAssociations: sources.PtrInt32(1), - RuleGroupStatus: types.ResourceStatusActive, // health - SnsTopic: sources.PtrString("arn:aws:sns:us-east-1:123456789012:aws-network-firewall-DefaultStatelessRuleGroup-1J3Z3W2ZQXV3"), // link + NumberOfAssociations: adapters.PtrInt32(1), + RuleGroupStatus: types.ResourceStatusActive, // health + SnsTopic: adapters.PtrString("arn:aws:sns:us-east-1:123456789012:aws-network-firewall-DefaultStatelessRuleGroup-1J3Z3W2ZQXV3"), // link SourceMetadata: &types.SourceMetadata{ - SourceArn: sources.PtrString("arn:aws:network-firewall:us-east-1:123456789012:firewall/aws-network-firewall-DefaultFirewall-1J3Z3W2ZQXV3"), // link - SourceUpdateToken: sources.PtrString("test"), + SourceArn: adapters.PtrString("arn:aws:network-firewall:us-east-1:123456789012:firewall/aws-network-firewall-DefaultFirewall-1J3Z3W2ZQXV3"), // link + SourceUpdateToken: adapters.PtrString("test"), }, Tags: []types.Tag{ { - Key: sources.PtrString("test"), - Value: sources.PtrString("test"), + Key: adapters.PtrString("test"), + Value: adapters.PtrString("test"), }, }, Type: types.RuleGroupTypeStateless, @@ -62,24 +62,24 @@ func (c testNetworkFirewallClient) DescribeRuleGroup(ctx context.Context, params "foo.bar.com", // link }, }, - RulesString: sources.PtrString("test"), + RulesString: adapters.PtrString("test"), StatefulRules: []types.StatefulRule{ { Action: types.StatefulActionAlert, Header: &types.Header{ - Destination: sources.PtrString("1.1.1.1"), - DestinationPort: sources.PtrString("8080"), + Destination: adapters.PtrString("1.1.1.1"), + DestinationPort: adapters.PtrString("8080"), Direction: types.StatefulRuleDirectionForward, Protocol: types.StatefulRuleProtocolDcerpc, - Source: sources.PtrString("test"), - SourcePort: sources.PtrString("8080"), + Source: adapters.PtrString("test"), + SourcePort: adapters.PtrString("8080"), }, }, }, StatelessRulesAndCustomActions: &types.StatelessRulesAndCustomActions{ StatelessRules: []types.StatelessRule{ { - Priority: sources.PtrInt32(1), + Priority: adapters.PtrInt32(1), RuleDefinition: &types.RuleDefinition{ Actions: []string{}, MatchAttributes: &types.MatchAttributes{ @@ -91,7 +91,7 @@ func (c testNetworkFirewallClient) DescribeRuleGroup(ctx context.Context, params }, Destinations: []types.Address{ { - AddressDefinition: sources.PtrString("1.1.1.1/1"), + AddressDefinition: adapters.PtrString("1.1.1.1/1"), }, }, Protocols: []int32{1}, @@ -122,12 +122,12 @@ func (c testNetworkFirewallClient) DescribeRuleGroup(ctx context.Context, params PublishMetricAction: &types.PublishMetricAction{ Dimensions: []types.Dimension{ { - Value: sources.PtrString("test"), + Value: adapters.PtrString("test"), }, }, }, }, - ActionName: sources.PtrString("test"), + ActionName: adapters.PtrString("test"), }, }, }, @@ -140,7 +140,7 @@ func (c testNetworkFirewallClient) ListRuleGroups(ctx context.Context, params *n return &networkfirewall.ListRuleGroupsOutput{ RuleGroups: []types.RuleGroupMetadata{ { - Arn: sources.PtrString("arn:aws:network-firewall:us-east-1:123456789012:stateless-rulegroup/aws-network-firewall-DefaultStatelessRuleGroup-1J3Z3W2ZQXV3"), + Arn: adapters.PtrString("arn:aws:network-firewall:us-east-1:123456789012:stateless-rulegroup/aws-network-firewall-DefaultStatelessRuleGroup-1J3Z3W2ZQXV3"), }, }, }, nil @@ -157,7 +157,7 @@ func TestRuleGroupGetFunc(t *testing.T) { t.Fatal(err) } - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "sns-topic", ExpectedMethod: sdp.QueryMethod_SEARCH, diff --git a/sources/networkfirewall/shared.go b/adapters/networkfirewall/shared.go similarity index 94% rename from sources/networkfirewall/shared.go rename to adapters/networkfirewall/shared.go index 712cb20c..a5c522cf 100644 --- a/sources/networkfirewall/shared.go +++ b/adapters/networkfirewall/shared.go @@ -5,7 +5,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/networkfirewall" "github.com/aws/aws-sdk-go-v2/service/networkfirewall/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -28,13 +28,13 @@ type networkFirewallClient interface { func encryptionConfigurationLink(config *types.EncryptionConfiguration, scope string) *sdp.LinkedItemQuery { // This can be an ARN or an ID if it's in the same account - if a, err := sources.ParseARN(*config.KeyId); err == nil { + if a, err := adapters.ParseARN(*config.KeyId); err == nil { return &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "kms-key", Method: sdp.QueryMethod_SEARCH, Query: *config.KeyId, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ In: true, diff --git a/sources/networkfirewall/shared_test.go b/adapters/networkfirewall/shared_test.go similarity index 100% rename from sources/networkfirewall/shared_test.go rename to adapters/networkfirewall/shared_test.go diff --git a/sources/networkfirewall/tls_inspection_configuration.go b/adapters/networkfirewall/tls_inspection_configuration.go similarity index 69% rename from sources/networkfirewall/tls_inspection_configuration.go rename to adapters/networkfirewall/tls_inspection_configuration.go index 14d5eafd..ca119fcf 100644 --- a/sources/networkfirewall/tls_inspection_configuration.go +++ b/adapters/networkfirewall/tls_inspection_configuration.go @@ -5,7 +5,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/networkfirewall" "github.com/aws/aws-sdk-go-v2/service/networkfirewall/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -38,7 +38,7 @@ func tlsInspectionConfigurationGetFunc(ctx context.Context, client networkFirewa TLSInspectionConfiguration: resp.TLSInspectionConfiguration, } - attributes, err := sources.ToAttributesWithExclude(utic) + attributes, err := adapters.ToAttributesWithExclude(utic) if err != nil { return nil, err @@ -72,14 +72,14 @@ func tlsInspectionConfigurationGetFunc(ctx context.Context, client networkFirewa if utic.Properties.CertificateAuthority != nil { if utic.Properties.CertificateAuthority.CertificateArn != nil { - if a, err := sources.ParseARN(*utic.Properties.CertificateAuthority.CertificateArn); err == nil { + if a, err := adapters.ParseARN(*utic.Properties.CertificateAuthority.CertificateArn); err == nil { //+overmind:link acm-pca-certificate-authority-certificate item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "acm-pca-certificate-authority-certificate", Method: sdp.QueryMethod_SEARCH, Query: *utic.Properties.CertificateAuthority.CertificateArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ In: true, @@ -92,14 +92,14 @@ func tlsInspectionConfigurationGetFunc(ctx context.Context, client networkFirewa for _, cert := range utic.Properties.Certificates { if cert.CertificateArn != nil { - if a, err := sources.ParseARN(*cert.CertificateArn); err == nil { + if a, err := adapters.ParseARN(*cert.CertificateArn); err == nil { //+overmind:link acm-certificate item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "acm-certificate", Method: sdp.QueryMethod_SEARCH, Query: *cert.CertificateArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ In: true, @@ -114,14 +114,14 @@ func tlsInspectionConfigurationGetFunc(ctx context.Context, client networkFirewa for _, config := range utic.TLSInspectionConfiguration.ServerCertificateConfigurations { if config.CertificateAuthorityArn != nil { - if a, err := sources.ParseARN(*config.CertificateAuthorityArn); err == nil { + if a, err := adapters.ParseARN(*config.CertificateAuthorityArn); err == nil { //+overmind:link acm-pca-certificate-authority item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "acm-pca-certificate-authority", Method: sdp.QueryMethod_SEARCH, Query: *config.CertificateAuthorityArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ In: true, @@ -133,14 +133,14 @@ func tlsInspectionConfigurationGetFunc(ctx context.Context, client networkFirewa for _, serverCert := range config.ServerCertificates { if serverCert.ResourceArn != nil { - if a, err := sources.ParseARN(*serverCert.ResourceArn); err == nil { + if a, err := adapters.ParseARN(*serverCert.ResourceArn); err == nil { //+overmind:link acm-certificate item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "acm-certificate", Method: sdp.QueryMethod_SEARCH, Query: *serverCert.ResourceArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ In: true, @@ -163,13 +163,14 @@ func tlsInspectionConfigurationGetFunc(ctx context.Context, client networkFirewa // +overmind:search Search for Network Firewall TLS Inspection Configurations by ARN // +overmind:group AWS -func NewTLSInspectionConfigurationSource(client networkFirewallClient, accountID string, region string) *sources.AlwaysGetSource[*networkfirewall.ListTLSInspectionConfigurationsInput, *networkfirewall.ListTLSInspectionConfigurationsOutput, *networkfirewall.DescribeTLSInspectionConfigurationInput, *networkfirewall.DescribeTLSInspectionConfigurationOutput, networkFirewallClient, *networkfirewall.Options] { - return &sources.AlwaysGetSource[*networkfirewall.ListTLSInspectionConfigurationsInput, *networkfirewall.ListTLSInspectionConfigurationsOutput, *networkfirewall.DescribeTLSInspectionConfigurationInput, *networkfirewall.DescribeTLSInspectionConfigurationOutput, networkFirewallClient, *networkfirewall.Options]{ - ItemType: "network-firewall-tls-inspection-configuration", - Client: client, - AccountID: accountID, - Region: region, - ListInput: &networkfirewall.ListTLSInspectionConfigurationsInput{}, +func NewTLSInspectionConfigurationAdapter(client networkFirewallClient, accountID string, region string) *adapters.AlwaysGetAdapter[*networkfirewall.ListTLSInspectionConfigurationsInput, *networkfirewall.ListTLSInspectionConfigurationsOutput, *networkfirewall.DescribeTLSInspectionConfigurationInput, *networkfirewall.DescribeTLSInspectionConfigurationOutput, networkFirewallClient, *networkfirewall.Options] { + return &adapters.AlwaysGetAdapter[*networkfirewall.ListTLSInspectionConfigurationsInput, *networkfirewall.ListTLSInspectionConfigurationsOutput, *networkfirewall.DescribeTLSInspectionConfigurationInput, *networkfirewall.DescribeTLSInspectionConfigurationOutput, networkFirewallClient, *networkfirewall.Options]{ + ItemType: "network-firewall-tls-inspection-configuration", + Client: client, + AccountID: accountID, + Region: region, + ListInput: &networkfirewall.ListTLSInspectionConfigurationsInput{}, + AdapterMetadata: TLSInspectionConfigurationMetadata(), GetInputMapper: func(scope, query string) *networkfirewall.DescribeTLSInspectionConfigurationInput { return &networkfirewall.DescribeTLSInspectionConfigurationInput{ TLSInspectionConfigurationName: &query, @@ -180,7 +181,7 @@ func NewTLSInspectionConfigurationSource(client networkFirewallClient, accountID TLSInspectionConfigurationArn: &query, }, nil }, - ListFuncPaginatorBuilder: func(client networkFirewallClient, input *networkfirewall.ListTLSInspectionConfigurationsInput) sources.Paginator[*networkfirewall.ListTLSInspectionConfigurationsOutput, *networkfirewall.Options] { + ListFuncPaginatorBuilder: func(client networkFirewallClient, input *networkfirewall.ListTLSInspectionConfigurationsInput) adapters.Paginator[*networkfirewall.ListTLSInspectionConfigurationsOutput, *networkfirewall.Options] { return networkfirewall.NewListTLSInspectionConfigurationsPaginator(client, input) }, ListFuncOutputMapper: func(output *networkfirewall.ListTLSInspectionConfigurationsOutput, input *networkfirewall.ListTLSInspectionConfigurationsInput) ([]*networkfirewall.DescribeTLSInspectionConfigurationInput, error) { @@ -198,3 +199,20 @@ func NewTLSInspectionConfigurationSource(client networkFirewallClient, accountID }, } } + +func TLSInspectionConfigurationMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "network-firewall-tls-inspection-configuration", + DescriptiveName: "Network Firewall TLS Inspection Configuration", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a Network Firewall TLS Inspection Configuration by name", + ListDescription: "List Network Firewall TLS Inspection Configurations", + SearchDescription: "Search for Network Firewall TLS Inspection Configurations by ARN", + }, + PotentialLinks: []string{"acm-certificate", "acm-pca-certificate-authority", "acm-pca-certificate-authority-certificate", "network-firewall-encryption-configuration"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_CONFIGURATION, + } +} diff --git a/sources/networkfirewall/tls_inspection_configuration_test.go b/adapters/networkfirewall/tls_inspection_configuration_test.go similarity index 67% rename from sources/networkfirewall/tls_inspection_configuration_test.go rename to adapters/networkfirewall/tls_inspection_configuration_test.go index 8db3c9ee..d57fb467 100644 --- a/sources/networkfirewall/tls_inspection_configuration_test.go +++ b/adapters/networkfirewall/tls_inspection_configuration_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/networkfirewall" "github.com/aws/aws-sdk-go-v2/service/networkfirewall/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -15,42 +15,42 @@ func (c testNetworkFirewallClient) DescribeTLSInspectionConfiguration(ctx contex now := time.Now() return &networkfirewall.DescribeTLSInspectionConfigurationOutput{ TLSInspectionConfigurationResponse: &types.TLSInspectionConfigurationResponse{ - TLSInspectionConfigurationArn: sources.PtrString("arn:aws:network-firewall:us-east-1:123456789012:tls-inspection-configuration/aws-network-firewall-DefaultTLSInspectionConfiguration-1J3Z3W2ZQXV3"), - TLSInspectionConfigurationId: sources.PtrString("test"), - TLSInspectionConfigurationName: sources.PtrString("test"), + TLSInspectionConfigurationArn: adapters.PtrString("arn:aws:network-firewall:us-east-1:123456789012:tls-inspection-configuration/aws-network-firewall-DefaultTLSInspectionConfiguration-1J3Z3W2ZQXV3"), + TLSInspectionConfigurationId: adapters.PtrString("test"), + TLSInspectionConfigurationName: adapters.PtrString("test"), CertificateAuthority: &types.TlsCertificateData{ - CertificateArn: sources.PtrString("arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012"), // link - CertificateSerial: sources.PtrString("test"), - Status: sources.PtrString("OK"), - StatusMessage: sources.PtrString("test"), + CertificateArn: adapters.PtrString("arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012"), // link + CertificateSerial: adapters.PtrString("test"), + Status: adapters.PtrString("OK"), + StatusMessage: adapters.PtrString("test"), }, Certificates: []types.TlsCertificateData{ { - CertificateArn: sources.PtrString("arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012"), // link - CertificateSerial: sources.PtrString("test"), - Status: sources.PtrString("OK"), - StatusMessage: sources.PtrString("test"), + CertificateArn: adapters.PtrString("arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012"), // link + CertificateSerial: adapters.PtrString("test"), + Status: adapters.PtrString("OK"), + StatusMessage: adapters.PtrString("test"), }, }, - Description: sources.PtrString("test"), + Description: adapters.PtrString("test"), EncryptionConfiguration: &types.EncryptionConfiguration{ Type: types.EncryptionTypeAwsOwnedKmsKey, - KeyId: sources.PtrString("arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012"), // link (this can be an ARN or ID) + KeyId: adapters.PtrString("arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012"), // link (this can be an ARN or ID) }, LastModifiedTime: &now, - NumberOfAssociations: sources.PtrInt32(1), + NumberOfAssociations: adapters.PtrInt32(1), TLSInspectionConfigurationStatus: types.ResourceStatusActive, // health Tags: []types.Tag{ { - Key: sources.PtrString("test"), - Value: sources.PtrString("test"), + Key: adapters.PtrString("test"), + Value: adapters.PtrString("test"), }, }, }, TLSInspectionConfiguration: &types.TLSInspectionConfiguration{ ServerCertificateConfigurations: []types.ServerCertificateConfiguration{ { - CertificateAuthorityArn: sources.PtrString("arn:aws:acm:us-east-1:123456789012:certificate-authority/12345678-1234-1234-1234-123456789012"), // link + CertificateAuthorityArn: adapters.PtrString("arn:aws:acm:us-east-1:123456789012:certificate-authority/12345678-1234-1234-1234-123456789012"), // link CheckCertificateRevocationStatus: &types.CheckCertificateRevocationStatusActions{ RevokedStatusAction: types.RevocationCheckActionPass, UnknownStatusAction: types.RevocationCheckActionPass, @@ -65,7 +65,7 @@ func (c testNetworkFirewallClient) DescribeTLSInspectionConfiguration(ctx contex }, Destinations: []types.Address{ { - AddressDefinition: sources.PtrString("test"), + AddressDefinition: adapters.PtrString("test"), }, }, Protocols: []int32{1}, @@ -77,14 +77,14 @@ func (c testNetworkFirewallClient) DescribeTLSInspectionConfiguration(ctx contex }, Sources: []types.Address{ { - AddressDefinition: sources.PtrString("test"), + AddressDefinition: adapters.PtrString("test"), }, }, }, }, ServerCertificates: []types.ServerCertificate{ { - ResourceArn: sources.PtrString("arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012"), // link + ResourceArn: adapters.PtrString("arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012"), // link }, }, }, @@ -97,7 +97,7 @@ func (c testNetworkFirewallClient) ListTLSInspectionConfigurations(ctx context.C return &networkfirewall.ListTLSInspectionConfigurationsOutput{ TLSInspectionConfigurations: []types.TLSInspectionConfigurationMetadata{ { - Arn: sources.PtrString("arn:aws:network-firewall:us-east-1:123456789012:tls-inspection-configuration/aws-network-firewall-DefaultTLSInspectionConfiguration-1J3Z3W2ZQXV3"), + Arn: adapters.PtrString("arn:aws:network-firewall:us-east-1:123456789012:tls-inspection-configuration/aws-network-firewall-DefaultTLSInspectionConfiguration-1J3Z3W2ZQXV3"), }, }, }, nil @@ -114,7 +114,7 @@ func TestTLSInspectionConfigurationGetFunc(t *testing.T) { t.Fatal(err) } - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "acm-pca-certificate-authority-certificate", ExpectedMethod: sdp.QueryMethod_SEARCH, diff --git a/sources/networkmanager/connect_attachment.go b/adapters/networkmanager/connect_attachment.go similarity index 69% rename from sources/networkmanager/connect_attachment.go rename to adapters/networkmanager/connect_attachment.go index 47aec2dd..cc4e2f4f 100644 --- a/sources/networkmanager/connect_attachment.go +++ b/adapters/networkmanager/connect_attachment.go @@ -6,7 +6,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/networkmanager" "github.com/aws/aws-sdk-go-v2/service/networkmanager/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -22,7 +22,7 @@ func connectAttachmentGetFunc(ctx context.Context, client *networkmanager.Client } func connectAttachmentItemMapper(_, scope string, ca *types.ConnectAttachment) (*sdp.Item, error) { - attributes, err := sources.ToAttributesWithExclude(ca) + attributes, err := adapters.ToAttributesWithExclude(ca) if err != nil { return nil, err @@ -59,14 +59,14 @@ func connectAttachmentItemMapper(_, scope string, ca *types.ConnectAttachment) ( } if ca.Attachment.CoreNetworkArn != nil { - if arn, err := sources.ParseARN(*ca.Attachment.CoreNetworkArn); err == nil { + if arn, err := adapters.ParseARN(*ca.Attachment.CoreNetworkArn); err == nil { item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ // +overmind:link networkmanager-core-network Type: "networkmanager-core-network", Method: sdp.QueryMethod_SEARCH, Query: *ca.Attachment.CoreNetworkArn, - Scope: sources.FormatScope(arn.AccountID, arn.Region), + Scope: adapters.FormatScope(arn.AccountID, arn.Region), }, BlastPropagation: &sdp.BlastPropagation{ In: true, @@ -88,12 +88,13 @@ func connectAttachmentItemMapper(_, scope string, ca *types.ConnectAttachment) ( // +overmind:group AWS // +overmind:terraform:queryMap aws_networkmanager_core_network.id -func NewConnectAttachmentSource(client *networkmanager.Client, accountID, region string) *sources.GetListSource[*types.ConnectAttachment, *networkmanager.Client, *networkmanager.Options] { - return &sources.GetListSource[*types.ConnectAttachment, *networkmanager.Client, *networkmanager.Options]{ - Client: client, - AccountID: accountID, - Region: region, - ItemType: "networkmanager-connect-attachment", +func NewConnectAttachmentAdapter(client *networkmanager.Client, accountID, region string) *adapters.GetListAdapter[*types.ConnectAttachment, *networkmanager.Client, *networkmanager.Options] { + return &adapters.GetListAdapter[*types.ConnectAttachment, *networkmanager.Client, *networkmanager.Options]{ + Client: client, + AccountID: accountID, + Region: region, + ItemType: "networkmanager-connect-attachment", + AdapterMetadata: ConnectAttachmentMetadata(), GetFunc: func(ctx context.Context, client *networkmanager.Client, scope string, query string) (*types.ConnectAttachment, error) { return connectAttachmentGetFunc(ctx, client, scope, query) }, @@ -106,3 +107,18 @@ func NewConnectAttachmentSource(client *networkmanager.Client, accountID, region }, } } + +func ConnectAttachmentMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "networkmanager-connect-attachment", + DescriptiveName: "Networkmanager Connect Attachment", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_networkmanager_core_network.id"}, + }, + PotentialLinks: []string{"networkmanager-core-network"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + } +} diff --git a/sources/networkmanager/connect_attachment_test.go b/adapters/networkmanager/connect_attachment_test.go similarity index 78% rename from sources/networkmanager/connect_attachment_test.go rename to adapters/networkmanager/connect_attachment_test.go index da4b7124..8439cbcd 100644 --- a/sources/networkmanager/connect_attachment_test.go +++ b/adapters/networkmanager/connect_attachment_test.go @@ -4,7 +4,7 @@ import ( "testing" "github.com/aws/aws-sdk-go-v2/service/networkmanager/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -13,9 +13,9 @@ func TestConnectAttachmentItemMapper(t *testing.T) { scope := "123456789012.eu-west-2" item, err := connectAttachmentItemMapper("", scope, &types.ConnectAttachment{ Attachment: &types.Attachment{ - AttachmentId: sources.PtrString("att-1"), - CoreNetworkId: sources.PtrString("cn-1"), - CoreNetworkArn: sources.PtrString("arn:aws:networkmanager:eu-west-2:123456789012:core-network/cn-1"), + AttachmentId: adapters.PtrString("att-1"), + CoreNetworkId: adapters.PtrString("cn-1"), + CoreNetworkArn: adapters.PtrString("arn:aws:networkmanager:eu-west-2:123456789012:core-network/cn-1"), }, }) if err != nil { @@ -32,7 +32,7 @@ func TestConnectAttachmentItemMapper(t *testing.T) { t.Fatalf("expected att-1, got %v", item.UniqueAttributeValue()) } - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "networkmanager-core-network", ExpectedMethod: sdp.QueryMethod_GET, diff --git a/sources/networkmanager/connect_peer.go b/adapters/networkmanager/connect_peer.go similarity index 77% rename from sources/networkmanager/connect_peer.go rename to adapters/networkmanager/connect_peer.go index c29ee1b1..12e09588 100644 --- a/sources/networkmanager/connect_peer.go +++ b/adapters/networkmanager/connect_peer.go @@ -6,7 +6,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/networkmanager" "github.com/aws/aws-sdk-go-v2/service/networkmanager/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -18,7 +18,7 @@ func connectPeerGetFunc(ctx context.Context, client NetworkManagerClient, scope cn := out.ConnectPeer - attributes, err := sources.ToAttributesWithExclude(cn, "tags") + attributes, err := adapters.ToAttributesWithExclude(cn, "tags") if err != nil { return nil, err @@ -149,14 +149,14 @@ func connectPeerGetFunc(ctx context.Context, client NetworkManagerClient, scope } if cn.SubnetArn != nil { - if arn, err := sources.ParseARN(*cn.SubnetArn); err == nil { + if arn, err := adapters.ParseARN(*cn.SubnetArn); err == nil { item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ //+overmind:link ec2-subnet Query: &sdp.Query{ Type: "ec2-subnet", Method: sdp.QueryMethod_SEARCH, Query: *cn.SubnetArn, - Scope: sources.FormatScope(arn.AccountID, arn.Region), + Scope: adapters.FormatScope(arn.AccountID, arn.Region), }, BlastPropagation: &sdp.BlastPropagation{ In: true, @@ -203,13 +203,14 @@ func connectPeerGetFunc(ctx context.Context, client NetworkManagerClient, scope // +overmind:group AWS // +overmind:terraform:queryMap aws_networkmanager_connect_peer.id -func NewConnectPeerSource(client NetworkManagerClient, accountID, region string) *sources.AlwaysGetSource[*networkmanager.ListConnectPeersInput, *networkmanager.ListConnectPeersOutput, *networkmanager.GetConnectPeerInput, *networkmanager.GetConnectPeerOutput, NetworkManagerClient, *networkmanager.Options] { - return &sources.AlwaysGetSource[*networkmanager.ListConnectPeersInput, *networkmanager.ListConnectPeersOutput, *networkmanager.GetConnectPeerInput, *networkmanager.GetConnectPeerOutput, NetworkManagerClient, *networkmanager.Options]{ - Client: client, - AccountID: accountID, - Region: region, - ItemType: "networkmanager-connect-peer", - ListInput: &networkmanager.ListConnectPeersInput{}, +func NewConnectPeerAdapter(client NetworkManagerClient, accountID, region string) *adapters.AlwaysGetAdapter[*networkmanager.ListConnectPeersInput, *networkmanager.ListConnectPeersOutput, *networkmanager.GetConnectPeerInput, *networkmanager.GetConnectPeerOutput, NetworkManagerClient, *networkmanager.Options] { + return &adapters.AlwaysGetAdapter[*networkmanager.ListConnectPeersInput, *networkmanager.ListConnectPeersOutput, *networkmanager.GetConnectPeerInput, *networkmanager.GetConnectPeerOutput, NetworkManagerClient, *networkmanager.Options]{ + Client: client, + AccountID: accountID, + Region: region, + ItemType: "networkmanager-connect-peer", + ListInput: &networkmanager.ListConnectPeersInput{}, + AdapterMetadata: ConnectPeerMetadata(), SearchInputMapper: func(scope, query string) (*networkmanager.ListConnectPeersInput, error) { // Search by CoreNetworkId return &networkmanager.ListConnectPeersInput{ @@ -221,7 +222,7 @@ func NewConnectPeerSource(client NetworkManagerClient, accountID, region string) ConnectPeerId: &query, } }, - ListFuncPaginatorBuilder: func(client NetworkManagerClient, input *networkmanager.ListConnectPeersInput) sources.Paginator[*networkmanager.ListConnectPeersOutput, *networkmanager.Options] { + ListFuncPaginatorBuilder: func(client NetworkManagerClient, input *networkmanager.ListConnectPeersInput) adapters.Paginator[*networkmanager.ListConnectPeersOutput, *networkmanager.Options] { return networkmanager.NewListConnectPeersPaginator(client, input) }, ListFuncOutputMapper: func(output *networkmanager.ListConnectPeersOutput, input *networkmanager.ListConnectPeersInput) ([]*networkmanager.GetConnectPeerInput, error) { @@ -239,3 +240,19 @@ func NewConnectPeerSource(client NetworkManagerClient, accountID, region string) GetFunc: connectPeerGetFunc, } } + +func ConnectPeerMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "networkmanager-connect-peer", + DescriptiveName: "Networkmanager Connect Peer", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + GetDescription: "Get a Networkmanager Connect Peer by id", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_networkmanager_connect_peer.id"}, + }, + PotentialLinks: []string{"networkmanager-core-network", "networkmanager-connect-attachment", "ip", "rdap-asn", "ec2-subnet"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + } +} diff --git a/sources/networkmanager/connect_peer_association.go b/adapters/networkmanager/connect_peer_association.go similarity index 75% rename from sources/networkmanager/connect_peer_association.go rename to adapters/networkmanager/connect_peer_association.go index c544b01d..2392de04 100644 --- a/sources/networkmanager/connect_peer_association.go +++ b/adapters/networkmanager/connect_peer_association.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/networkmanager" "github.com/aws/aws-sdk-go-v2/service/networkmanager/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -17,7 +17,7 @@ func connectPeerAssociationsOutputMapper(_ context.Context, _ *networkmanager.Cl for _, a := range output.ConnectPeerAssociations { var err error var attrs *sdp.ItemAttributes - attrs, err = sources.ToAttributesWithExclude(a) + attrs, err = adapters.ToAttributesWithExclude(a) if err != nil { return nil, &sdp.QueryError{ @@ -125,12 +125,13 @@ func connectPeerAssociationsOutputMapper(_ context.Context, _ *networkmanager.Cl // +overmind:search Search for Networkmanager ConnectPeerAssociations by GlobalNetworkId // +overmind:group AWS -func NewConnectPeerAssociationSource(client *networkmanager.Client, accountID string, region string) *sources.DescribeOnlySource[*networkmanager.GetConnectPeerAssociationsInput, *networkmanager.GetConnectPeerAssociationsOutput, *networkmanager.Client, *networkmanager.Options] { - return &sources.DescribeOnlySource[*networkmanager.GetConnectPeerAssociationsInput, *networkmanager.GetConnectPeerAssociationsOutput, *networkmanager.Client, *networkmanager.Options]{ - Client: client, - AccountID: accountID, - Region: region, - ItemType: "networkmanager-connect-peer-association", +func NewConnectPeerAssociationAdapter(client *networkmanager.Client, accountID string, region string) *adapters.DescribeOnlyAdapter[*networkmanager.GetConnectPeerAssociationsInput, *networkmanager.GetConnectPeerAssociationsOutput, *networkmanager.Client, *networkmanager.Options] { + return &adapters.DescribeOnlyAdapter[*networkmanager.GetConnectPeerAssociationsInput, *networkmanager.GetConnectPeerAssociationsOutput, *networkmanager.Client, *networkmanager.Options]{ + Client: client, + AccountID: accountID, + Region: region, + ItemType: "networkmanager-connect-peer-association", + AdapterMetadata: ConnectPeerAssociationMetadata(), DescribeFunc: func(ctx context.Context, client *networkmanager.Client, input *networkmanager.GetConnectPeerAssociationsInput) (*networkmanager.GetConnectPeerAssociationsOutput, error) { return client.GetConnectPeerAssociations(ctx, input) }, @@ -157,7 +158,7 @@ func NewConnectPeerAssociationSource(client *networkmanager.Client, accountID st ErrorString: "list not supported for networkmanager-connect-peer-association, use search", } }, - PaginatorBuilder: func(client *networkmanager.Client, params *networkmanager.GetConnectPeerAssociationsInput) sources.Paginator[*networkmanager.GetConnectPeerAssociationsOutput, *networkmanager.Options] { + PaginatorBuilder: func(client *networkmanager.Client, params *networkmanager.GetConnectPeerAssociationsInput) adapters.Paginator[*networkmanager.GetConnectPeerAssociationsOutput, *networkmanager.Options] { return networkmanager.NewGetConnectPeerAssociationsPaginator(client, params) }, OutputMapper: connectPeerAssociationsOutputMapper, @@ -169,3 +170,20 @@ func NewConnectPeerAssociationSource(client *networkmanager.Client, accountID st }, } } + +func ConnectPeerAssociationMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "networkmanager-connect-peer-association", + DescriptiveName: "Networkmanager Connect Peer Association", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a Networkmanager Connect Peer Association", + ListDescription: "List all Networkmanager Connect Peer Associations", + SearchDescription: "Search for Networkmanager ConnectPeerAssociations by GlobalNetworkId", + }, + PotentialLinks: []string{"networkmanager-global-network", "networkmanager-connect-peer", "networkmanager-device", "networkmanager-link"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + } +} diff --git a/sources/networkmanager/connect_peer_association_test.go b/adapters/networkmanager/connect_peer_association_test.go similarity index 85% rename from sources/networkmanager/connect_peer_association_test.go rename to adapters/networkmanager/connect_peer_association_test.go index a8ab7cf5..df9c63ba 100644 --- a/sources/networkmanager/connect_peer_association_test.go +++ b/adapters/networkmanager/connect_peer_association_test.go @@ -6,7 +6,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/networkmanager" "github.com/aws/aws-sdk-go-v2/service/networkmanager/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -14,10 +14,10 @@ func TestConnectPeerAssociationsOutputMapper(t *testing.T) { output := networkmanager.GetConnectPeerAssociationsOutput{ ConnectPeerAssociations: []types.ConnectPeerAssociation{ { - ConnectPeerId: sources.PtrString("cp-1"), - DeviceId: sources.PtrString("dvc-1"), - GlobalNetworkId: sources.PtrString("default"), - LinkId: sources.PtrString("link-1"), + ConnectPeerId: adapters.PtrString("cp-1"), + DeviceId: adapters.PtrString("dvc-1"), + GlobalNetworkId: adapters.PtrString("default"), + LinkId: adapters.PtrString("link-1"), }, }, } @@ -51,7 +51,7 @@ func TestConnectPeerAssociationsOutputMapper(t *testing.T) { t.Fatalf("expected default|cp-1, got %v", item.UniqueAttributeValue()) } - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "networkmanager-global-network", ExpectedMethod: sdp.QueryMethod_GET, diff --git a/sources/networkmanager/connect_peer_test.go b/adapters/networkmanager/connect_peer_test.go similarity index 76% rename from sources/networkmanager/connect_peer_test.go rename to adapters/networkmanager/connect_peer_test.go index 8405dd11..8efec515 100644 --- a/sources/networkmanager/connect_peer_test.go +++ b/adapters/networkmanager/connect_peer_test.go @@ -6,7 +6,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/networkmanager" "github.com/aws/aws-sdk-go-v2/service/networkmanager/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -16,21 +16,21 @@ func (n NetworkManagerTestClient) GetConnectPeer(ctx context.Context, params *ne Configuration: &types.ConnectPeerConfiguration{ BgpConfigurations: []types.ConnectPeerBgpConfiguration{ { - CoreNetworkAddress: sources.PtrString("1.4.2.4"), // link - CoreNetworkAsn: sources.PtrInt64(64512), // link - PeerAddress: sources.PtrString("123.123.123.123"), // link - PeerAsn: sources.PtrInt64(64513), // link + CoreNetworkAddress: adapters.PtrString("1.4.2.4"), // link + CoreNetworkAsn: adapters.PtrInt64(64512), // link + PeerAddress: adapters.PtrString("123.123.123.123"), // link + PeerAsn: adapters.PtrInt64(64513), // link }, }, - CoreNetworkAddress: sources.PtrString("1.1.1.3"), // link - PeerAddress: sources.PtrString("1.1.1.45"), // link + CoreNetworkAddress: adapters.PtrString("1.1.1.3"), // link + PeerAddress: adapters.PtrString("1.1.1.45"), // link }, - ConnectAttachmentId: sources.PtrString("ca-1"), // link - ConnectPeerId: sources.PtrString("cp-1"), - CoreNetworkId: sources.PtrString("cn-1"), // link - EdgeLocation: sources.PtrString("us-west-2"), + ConnectAttachmentId: adapters.PtrString("ca-1"), // link + ConnectPeerId: adapters.PtrString("cp-1"), + CoreNetworkId: adapters.PtrString("cn-1"), // link + EdgeLocation: adapters.PtrString("us-west-2"), State: types.ConnectPeerStateAvailable, - SubnetArn: sources.PtrString("arn:aws:ec2:us-west-2:123456789012:subnet/subnet-1"), // link + SubnetArn: adapters.PtrString("arn:aws:ec2:us-west-2:123456789012:subnet/subnet-1"), // link }, }, nil } @@ -55,7 +55,7 @@ func TestConnectPeerGetFunc(t *testing.T) { t.Fatalf("expected cp-1, got %v", item.UniqueAttributeValue()) } - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "ip", ExpectedMethod: sdp.QueryMethod_GET, diff --git a/sources/networkmanager/connection.go b/adapters/networkmanager/connection.go similarity index 81% rename from sources/networkmanager/connection.go rename to adapters/networkmanager/connection.go index 611bd5fb..220b345a 100644 --- a/sources/networkmanager/connection.go +++ b/adapters/networkmanager/connection.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/networkmanager" "github.com/aws/aws-sdk-go-v2/service/networkmanager/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -17,7 +17,7 @@ func connectionOutputMapper(_ context.Context, _ *networkmanager.Client, scope s for _, s := range output.Connections { var err error var attrs *sdp.ItemAttributes - attrs, err = sources.ToAttributesWithExclude(s, "tags") + attrs, err = adapters.ToAttributesWithExclude(s, "tags") if err != nil { return nil, &sdp.QueryError{ @@ -146,14 +146,15 @@ func connectionOutputMapper(_ context.Context, _ *networkmanager.Client, scope s // +overmind:terraform:queryMap aws_networkmanager_connection.arn // +overmind:terraform:method SEARCH -func NewConnectionSource(client *networkmanager.Client, accountID string) *sources.DescribeOnlySource[*networkmanager.GetConnectionsInput, *networkmanager.GetConnectionsOutput, *networkmanager.Client, *networkmanager.Options] { - return &sources.DescribeOnlySource[*networkmanager.GetConnectionsInput, *networkmanager.GetConnectionsOutput, *networkmanager.Client, *networkmanager.Options]{ +func NewConnectionAdapter(client *networkmanager.Client, accountID string) *adapters.DescribeOnlyAdapter[*networkmanager.GetConnectionsInput, *networkmanager.GetConnectionsOutput, *networkmanager.Client, *networkmanager.Options] { + return &adapters.DescribeOnlyAdapter[*networkmanager.GetConnectionsInput, *networkmanager.GetConnectionsOutput, *networkmanager.Client, *networkmanager.Options]{ Client: client, AccountID: accountID, ItemType: "networkmanager-connection", DescribeFunc: func(ctx context.Context, client *networkmanager.Client, input *networkmanager.GetConnectionsInput) (*networkmanager.GetConnectionsOutput, error) { return client.GetConnections(ctx, input) }, + AdapterMetadata: ConnectionMetadata(), InputMapperGet: func(scope, query string) (*networkmanager.GetConnectionsInput, error) { // We are using a custom id of {globalNetworkId}|{connectionId} sections := strings.Split(query, "|") @@ -177,7 +178,7 @@ func NewConnectionSource(client *networkmanager.Client, accountID string) *sourc ErrorString: "list not supported for networkmanager-connection, use search", } }, - PaginatorBuilder: func(client *networkmanager.Client, params *networkmanager.GetConnectionsInput) sources.Paginator[*networkmanager.GetConnectionsOutput, *networkmanager.Options] { + PaginatorBuilder: func(client *networkmanager.Client, params *networkmanager.GetConnectionsInput) adapters.Paginator[*networkmanager.GetConnectionsOutput, *networkmanager.Options] { return networkmanager.NewGetConnectionsPaginator(client, params) }, OutputMapper: connectionOutputMapper, @@ -205,3 +206,24 @@ func NewConnectionSource(client *networkmanager.Client, accountID string) *sourc }, } } + +func ConnectionMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "networkmanager-connection", + DescriptiveName: "Networkmanager Connection", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + Search: true, + GetDescription: "Get a Networkmanager Connection", + SearchDescription: "Search for Networkmanager Connections by GlobalNetworkId", + }, + TerraformMappings: []*sdp.TerraformMapping{ + { + TerraformQueryMap: "aws_networkmanager_connection.arn", + TerraformMethod: sdp.QueryMethod_SEARCH, + }, + }, + PotentialLinks: []string{"networkmanager-global-network", "networkmanager-link", "networkmanager-device"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + } +} diff --git a/sources/networkmanager/connection_test.go b/adapters/networkmanager/connection_test.go similarity index 81% rename from sources/networkmanager/connection_test.go rename to adapters/networkmanager/connection_test.go index 2d5e8180..41115a0c 100644 --- a/sources/networkmanager/connection_test.go +++ b/adapters/networkmanager/connection_test.go @@ -6,7 +6,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/networkmanager" "github.com/aws/aws-sdk-go-v2/service/networkmanager/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -14,12 +14,12 @@ func TestConnectionOutputMapper(t *testing.T) { output := networkmanager.GetConnectionsOutput{ Connections: []types.Connection{ { - GlobalNetworkId: sources.PtrString("default"), - ConnectionId: sources.PtrString("conn-1"), - DeviceId: sources.PtrString("dvc-1"), - ConnectedDeviceId: sources.PtrString("dvc-2"), - LinkId: sources.PtrString("link-1"), - ConnectedLinkId: sources.PtrString("link-2"), + GlobalNetworkId: adapters.PtrString("default"), + ConnectionId: adapters.PtrString("conn-1"), + DeviceId: adapters.PtrString("dvc-1"), + ConnectedDeviceId: adapters.PtrString("dvc-2"), + LinkId: adapters.PtrString("link-1"), + ConnectedLinkId: adapters.PtrString("link-2"), }, }, } @@ -53,7 +53,7 @@ func TestConnectionOutputMapper(t *testing.T) { t.Fatalf("expected default|conn-1, got %v", item.UniqueAttributeValue()) } - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "networkmanager-global-network", ExpectedMethod: sdp.QueryMethod_GET, diff --git a/sources/networkmanager/core_network.go b/adapters/networkmanager/core_network.go similarity index 69% rename from sources/networkmanager/core_network.go rename to adapters/networkmanager/core_network.go index ecfa644c..c6d5c865 100644 --- a/sources/networkmanager/core_network.go +++ b/adapters/networkmanager/core_network.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/networkmanager" "github.com/aws/aws-sdk-go-v2/service/networkmanager/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -23,7 +23,7 @@ func coreNetworkGetFunc(ctx context.Context, client NetworkManagerClient, scope cn := out.CoreNetwork - attributes, err := sources.ToAttributesWithExclude(cn) + attributes, err := adapters.ToAttributesWithExclude(cn) if err != nil { return nil, err @@ -120,20 +120,21 @@ func coreNetworkGetFunc(ctx context.Context, client NetworkManagerClient, scope // +overmind:group AWS // +overmind:terraform:queryMap aws_networkmanager_core_network.id -func NewCoreNetworkSource(client NetworkManagerClient, accountID, region string) *sources.AlwaysGetSource[*networkmanager.ListCoreNetworksInput, *networkmanager.ListCoreNetworksOutput, *networkmanager.GetCoreNetworkInput, *networkmanager.GetCoreNetworkOutput, NetworkManagerClient, *networkmanager.Options] { - return &sources.AlwaysGetSource[*networkmanager.ListCoreNetworksInput, *networkmanager.ListCoreNetworksOutput, *networkmanager.GetCoreNetworkInput, *networkmanager.GetCoreNetworkOutput, NetworkManagerClient, *networkmanager.Options]{ - Client: client, - AccountID: accountID, - Region: region, - GetFunc: coreNetworkGetFunc, - ItemType: "networkmanager-core-network", - ListInput: &networkmanager.ListCoreNetworksInput{}, +func NewCoreNetworkAdapter(client NetworkManagerClient, accountID, region string) *adapters.AlwaysGetAdapter[*networkmanager.ListCoreNetworksInput, *networkmanager.ListCoreNetworksOutput, *networkmanager.GetCoreNetworkInput, *networkmanager.GetCoreNetworkOutput, NetworkManagerClient, *networkmanager.Options] { + return &adapters.AlwaysGetAdapter[*networkmanager.ListCoreNetworksInput, *networkmanager.ListCoreNetworksOutput, *networkmanager.GetCoreNetworkInput, *networkmanager.GetCoreNetworkOutput, NetworkManagerClient, *networkmanager.Options]{ + Client: client, + AccountID: accountID, + Region: region, + GetFunc: coreNetworkGetFunc, + ItemType: "networkmanager-core-network", + ListInput: &networkmanager.ListCoreNetworksInput{}, + AdapterMetadata: CoreNetworkMetadata(), GetInputMapper: func(scope, query string) *networkmanager.GetCoreNetworkInput { return &networkmanager.GetCoreNetworkInput{ CoreNetworkId: &query, } }, - ListFuncPaginatorBuilder: func(client NetworkManagerClient, input *networkmanager.ListCoreNetworksInput) sources.Paginator[*networkmanager.ListCoreNetworksOutput, *networkmanager.Options] { + ListFuncPaginatorBuilder: func(client NetworkManagerClient, input *networkmanager.ListCoreNetworksInput) adapters.Paginator[*networkmanager.ListCoreNetworksOutput, *networkmanager.Options] { return networkmanager.NewListCoreNetworksPaginator(client, input) }, ListFuncOutputMapper: func(output *networkmanager.ListCoreNetworksOutput, input *networkmanager.ListCoreNetworksInput) ([]*networkmanager.GetCoreNetworkInput, error) { @@ -149,3 +150,19 @@ func NewCoreNetworkSource(client NetworkManagerClient, accountID, region string) }, } } + +func CoreNetworkMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "networkmanager-core-network", + DescriptiveName: "Networkmanager Core Network", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + GetDescription: "Get a Networkmanager Core Network by id", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_networkmanager_core_network.id"}, + }, + PotentialLinks: []string{"networkmanager-core-network-policy", "networkmanager-connect-peer"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + } +} diff --git a/sources/networkmanager/core_network_policy.go b/adapters/networkmanager/core_network_policy.go similarity index 64% rename from sources/networkmanager/core_network_policy.go rename to adapters/networkmanager/core_network_policy.go index ce5bf4f6..c1d9161f 100644 --- a/sources/networkmanager/core_network_policy.go +++ b/adapters/networkmanager/core_network_policy.go @@ -6,7 +6,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/networkmanager" "github.com/aws/aws-sdk-go-v2/service/networkmanager/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -22,7 +22,7 @@ func coreNetworkPolicyGetFunc(ctx context.Context, client *networkmanager.Client } func coreNetworkPolicyItemMapper(_, scope string, cn *types.CoreNetworkPolicy) (*sdp.Item, error) { - attributes, err := sources.ToAttributesWithExclude(cn) + attributes, err := adapters.ToAttributesWithExclude(cn) if err != nil { return nil, err } @@ -63,12 +63,13 @@ func coreNetworkPolicyItemMapper(_, scope string, cn *types.CoreNetworkPolicy) ( // +overmind:group AWS // +overmind:terraform:queryMap aws_networkmanager_core_network_policy.core_network_id -func NewCoreNetworkPolicySource(client *networkmanager.Client, accountID, region string) *sources.GetListSource[*types.CoreNetworkPolicy, *networkmanager.Client, *networkmanager.Options] { - return &sources.GetListSource[*types.CoreNetworkPolicy, *networkmanager.Client, *networkmanager.Options]{ - Client: client, - AccountID: accountID, - Region: region, - ItemType: "networkmanager-core-network-policy", +func NewCoreNetworkPolicyAdapter(client *networkmanager.Client, accountID, region string) *adapters.GetListAdapter[*types.CoreNetworkPolicy, *networkmanager.Client, *networkmanager.Options] { + return &adapters.GetListAdapter[*types.CoreNetworkPolicy, *networkmanager.Client, *networkmanager.Options]{ + Client: client, + AccountID: accountID, + Region: region, + ItemType: "networkmanager-core-network-policy", + AdapterMetadata: CoreNetworkPolicyMetadata(), GetFunc: func(ctx context.Context, client *networkmanager.Client, scope string, query string) (*types.CoreNetworkPolicy, error) { return coreNetworkPolicyGetFunc(ctx, client, scope, query) }, @@ -81,3 +82,19 @@ func NewCoreNetworkPolicySource(client *networkmanager.Client, accountID, region }, } } + +func CoreNetworkPolicyMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "networkmanager-core-network-policy", + DescriptiveName: "Networkmanager Core Network Policy", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + GetDescription: "Get a Networkmanager Core Network Policy by Core Network id", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_networkmanager_core_network_policy.core_network_id"}, + }, + PotentialLinks: []string{"networkmanager-core-network"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + } +} diff --git a/sources/networkmanager/core_network_policy_test.go b/adapters/networkmanager/core_network_policy_test.go similarity index 81% rename from sources/networkmanager/core_network_policy_test.go rename to adapters/networkmanager/core_network_policy_test.go index 0e1c7251..cf92feaf 100644 --- a/sources/networkmanager/core_network_policy_test.go +++ b/adapters/networkmanager/core_network_policy_test.go @@ -4,7 +4,7 @@ import ( "testing" "github.com/aws/aws-sdk-go-v2/service/networkmanager/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -12,8 +12,8 @@ func TestCoreNetworkPolicyItemMapper(t *testing.T) { scope := "123456789012.eu-west-2" item, err := coreNetworkPolicyItemMapper("", scope, &types.CoreNetworkPolicy{ - CoreNetworkId: sources.PtrString("cn-1"), - PolicyVersionId: sources.PtrInt32(1), + CoreNetworkId: adapters.PtrString("cn-1"), + PolicyVersionId: adapters.PtrInt32(1), }) if err != nil { t.Error(err) @@ -29,7 +29,7 @@ func TestCoreNetworkPolicyItemMapper(t *testing.T) { t.Fatalf("expected cn-1, got %v", item.UniqueAttributeValue()) } - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "networkmanager-core-network", ExpectedMethod: sdp.QueryMethod_GET, diff --git a/sources/networkmanager/core_network_test.go b/adapters/networkmanager/core_network_test.go similarity index 79% rename from sources/networkmanager/core_network_test.go rename to adapters/networkmanager/core_network_test.go index 4aed4242..e49a8638 100644 --- a/sources/networkmanager/core_network_test.go +++ b/adapters/networkmanager/core_network_test.go @@ -6,28 +6,28 @@ import ( "github.com/aws/aws-sdk-go-v2/service/networkmanager" "github.com/aws/aws-sdk-go-v2/service/networkmanager/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) func (n NetworkManagerTestClient) GetCoreNetwork(ctx context.Context, params *networkmanager.GetCoreNetworkInput, optFns ...func(*networkmanager.Options)) (*networkmanager.GetCoreNetworkOutput, error) { return &networkmanager.GetCoreNetworkOutput{ CoreNetwork: &types.CoreNetwork{ - CoreNetworkArn: sources.PtrString("arn:aws:networkmanager:us-west-2:123456789012:core-network/cn-1"), - CoreNetworkId: sources.PtrString("cn-1"), - GlobalNetworkId: sources.PtrString("default"), - Description: sources.PtrString("core network description"), + CoreNetworkArn: adapters.PtrString("arn:aws:networkmanager:us-west-2:123456789012:core-network/cn-1"), + CoreNetworkId: adapters.PtrString("cn-1"), + GlobalNetworkId: adapters.PtrString("default"), + Description: adapters.PtrString("core network description"), State: types.CoreNetworkStateAvailable, Edges: []types.CoreNetworkEdge{ { - Asn: sources.PtrInt64(64512), // link - EdgeLocation: sources.PtrString("us-west-2"), + Asn: adapters.PtrInt64(64512), // link + EdgeLocation: adapters.PtrString("us-west-2"), }, }, Segments: []types.CoreNetworkSegment{ { EdgeLocations: []string{"us-west-2"}, - Name: sources.PtrString("segment-1"), + Name: adapters.PtrString("segment-1"), }, }, }, @@ -58,7 +58,7 @@ func TestCoreNetworkItemMapper(t *testing.T) { t.Fatalf("expected cn-1, got %v", item.UniqueAttributeValue()) } - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "networkmanager-global-network", ExpectedMethod: sdp.QueryMethod_GET, diff --git a/sources/networkmanager/device.go b/adapters/networkmanager/device.go similarity index 79% rename from sources/networkmanager/device.go rename to adapters/networkmanager/device.go index 834fac4e..d6e1c65b 100644 --- a/sources/networkmanager/device.go +++ b/adapters/networkmanager/device.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/networkmanager" "github.com/aws/aws-sdk-go-v2/service/networkmanager/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -17,7 +17,7 @@ func deviceOutputMapper(_ context.Context, _ *networkmanager.Client, scope strin for _, s := range output.Devices { var err error var attrs *sdp.ItemAttributes - attrs, err = sources.ToAttributesWithExclude(s, "tags") + attrs, err = adapters.ToAttributesWithExclude(s, "tags") if err != nil { return nil, &sdp.QueryError{ @@ -140,14 +140,15 @@ func deviceOutputMapper(_ context.Context, _ *networkmanager.Client, scope strin // +overmind:terraform:queryMap aws_networkmanager_device.arn // +overmind:terraform:method SEARCH -func NewDeviceSource(client *networkmanager.Client, accountID string) *sources.DescribeOnlySource[*networkmanager.GetDevicesInput, *networkmanager.GetDevicesOutput, *networkmanager.Client, *networkmanager.Options] { - return &sources.DescribeOnlySource[*networkmanager.GetDevicesInput, *networkmanager.GetDevicesOutput, *networkmanager.Client, *networkmanager.Options]{ +func NewDeviceAdapter(client *networkmanager.Client, accountID string) *adapters.DescribeOnlyAdapter[*networkmanager.GetDevicesInput, *networkmanager.GetDevicesOutput, *networkmanager.Client, *networkmanager.Options] { + return &adapters.DescribeOnlyAdapter[*networkmanager.GetDevicesInput, *networkmanager.GetDevicesOutput, *networkmanager.Client, *networkmanager.Options]{ Client: client, AccountID: accountID, ItemType: "networkmanager-device", DescribeFunc: func(ctx context.Context, client *networkmanager.Client, input *networkmanager.GetDevicesInput) (*networkmanager.GetDevicesOutput, error) { return client.GetDevices(ctx, input) }, + AdapterMetadata: DeviceMetadata(), InputMapperGet: func(scope, query string) (*networkmanager.GetDevicesInput, error) { // We are using a custom id of {globalNetworkId}|{deviceId} sections := strings.Split(query, "|") @@ -171,7 +172,7 @@ func NewDeviceSource(client *networkmanager.Client, accountID string) *sources.D ErrorString: "list not supported for networkmanager-device, use search", } }, - PaginatorBuilder: func(client *networkmanager.Client, params *networkmanager.GetDevicesInput) sources.Paginator[*networkmanager.GetDevicesOutput, *networkmanager.Options] { + PaginatorBuilder: func(client *networkmanager.Client, params *networkmanager.GetDevicesInput) adapters.Paginator[*networkmanager.GetDevicesOutput, *networkmanager.Options] { return networkmanager.NewGetDevicesPaginator(client, params) }, OutputMapper: deviceOutputMapper, @@ -200,3 +201,24 @@ func NewDeviceSource(client *networkmanager.Client, accountID string) *sources.D }, } } + +func DeviceMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "networkmanager-device", + DescriptiveName: "Networkmanager Device", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + Search: true, + GetDescription: "Get a Networkmanager Device", + SearchDescription: "Search for Networkmanager Devices by GlobalNetworkId, or by GlobalNetworkId with SiteId", + }, + TerraformMappings: []*sdp.TerraformMapping{ + { + TerraformQueryMap: "aws_networkmanager_device.arn", + TerraformMethod: sdp.QueryMethod_SEARCH, + }, + }, + PotentialLinks: []string{"networkmanager-global-network", "networkmanager-site", "networkmanager-link-association", "networkmanager-connection", "networkmanager-network-resource-relationship"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + } +} diff --git a/sources/networkmanager/device_test.go b/adapters/networkmanager/device_test.go similarity index 84% rename from sources/networkmanager/device_test.go rename to adapters/networkmanager/device_test.go index b5aa26aa..36970de8 100644 --- a/sources/networkmanager/device_test.go +++ b/adapters/networkmanager/device_test.go @@ -6,7 +6,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/networkmanager" "github.com/aws/aws-sdk-go-v2/service/networkmanager/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -14,10 +14,10 @@ func TestDeviceOutputMapper(t *testing.T) { output := networkmanager.GetDevicesOutput{ Devices: []types.Device{ { - DeviceId: sources.PtrString("dvc-1"), - GlobalNetworkId: sources.PtrString("default"), - SiteId: sources.PtrString("site-1"), - DeviceArn: sources.PtrString("arn:aws:networkmanager:us-west-2:123456789012:device/dvc-1"), + DeviceId: adapters.PtrString("dvc-1"), + GlobalNetworkId: adapters.PtrString("default"), + SiteId: adapters.PtrString("site-1"), + DeviceArn: adapters.PtrString("arn:aws:networkmanager:us-west-2:123456789012:device/dvc-1"), }, }, } @@ -51,7 +51,7 @@ func TestDeviceOutputMapper(t *testing.T) { t.Fatalf("expected default|dvc-1, got %v", item.UniqueAttributeValue()) } - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "networkmanager-global-network", ExpectedMethod: sdp.QueryMethod_GET, diff --git a/sources/networkmanager/global_network.go b/adapters/networkmanager/global_network.go similarity index 75% rename from sources/networkmanager/global_network.go rename to adapters/networkmanager/global_network.go index 209b94a3..9a027aee 100644 --- a/sources/networkmanager/global_network.go +++ b/adapters/networkmanager/global_network.go @@ -6,7 +6,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/networkmanager" "github.com/aws/aws-sdk-go-v2/service/networkmanager/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -16,7 +16,7 @@ func globalNetworkOutputMapper(_ context.Context, client *networkmanager.Client, for _, gn := range output.GlobalNetworks { var err error var attrs *sdp.ItemAttributes - attrs, err = sources.ToAttributesWithExclude(gn, "tags") + attrs, err = adapters.ToAttributesWithExclude(gn, "tags") if err != nil { return nil, &sdp.QueryError{ @@ -178,11 +178,12 @@ func globalNetworkOutputMapper(_ context.Context, client *networkmanager.Client, // +overmind:terraform:queryMap aws_networkmanager_global_network.arn // +overmind:terraform:method SEARCH -func NewGlobalNetworkSource(client *networkmanager.Client, accountID string) *sources.DescribeOnlySource[*networkmanager.DescribeGlobalNetworksInput, *networkmanager.DescribeGlobalNetworksOutput, *networkmanager.Client, *networkmanager.Options] { - return &sources.DescribeOnlySource[*networkmanager.DescribeGlobalNetworksInput, *networkmanager.DescribeGlobalNetworksOutput, *networkmanager.Client, *networkmanager.Options]{ - ItemType: "networkmanager-global-network", - Client: client, - AccountID: accountID, +func NewGlobalNetworkAdapter(client *networkmanager.Client, accountID string) *adapters.DescribeOnlyAdapter[*networkmanager.DescribeGlobalNetworksInput, *networkmanager.DescribeGlobalNetworksOutput, *networkmanager.Client, *networkmanager.Options] { + return &adapters.DescribeOnlyAdapter[*networkmanager.DescribeGlobalNetworksInput, *networkmanager.DescribeGlobalNetworksOutput, *networkmanager.Client, *networkmanager.Options]{ + ItemType: "networkmanager-global-network", + Client: client, + AccountID: accountID, + AdapterMetadata: GlobalNetworkMetadata(), DescribeFunc: func(ctx context.Context, client *networkmanager.Client, input *networkmanager.DescribeGlobalNetworksInput) (*networkmanager.DescribeGlobalNetworksOutput, error) { return client.DescribeGlobalNetworks(ctx, input) }, @@ -194,13 +195,36 @@ func NewGlobalNetworkSource(client *networkmanager.Client, accountID string) *so InputMapperList: func(scope string) (*networkmanager.DescribeGlobalNetworksInput, error) { return &networkmanager.DescribeGlobalNetworksInput{}, nil }, - PaginatorBuilder: func(client *networkmanager.Client, params *networkmanager.DescribeGlobalNetworksInput) sources.Paginator[*networkmanager.DescribeGlobalNetworksOutput, *networkmanager.Options] { + PaginatorBuilder: func(client *networkmanager.Client, params *networkmanager.DescribeGlobalNetworksInput) adapters.Paginator[*networkmanager.DescribeGlobalNetworksOutput, *networkmanager.Options] { return networkmanager.NewDescribeGlobalNetworksPaginator(client, params) }, OutputMapper: globalNetworkOutputMapper, } } +func GlobalNetworkMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "networkmanager-global-network", + DescriptiveName: "Network Manager Global Network", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a global network by id", + ListDescription: "List all global networks", + SearchDescription: "Search for a global network by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + { + TerraformQueryMap: "aws_networkmanager_global_network.arn", + TerraformMethod: sdp.QueryMethod_SEARCH, + }, + }, + PotentialLinks: []string{"networkmanager-site", "networkmanager-transit-gateway-registration", "networkmanager-connect-peer-association", "networkmanager-transit-gateway-connect-peer-association", "networkmanager-network-resource", "networkmanager-network-resource-relationship", "networkmanager-link", "networkmanager-device", "networkmanager-connection"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + } +} + // idWithGlobalNetwork makes custom ID of given entity with global network ID and this entity ID/ARN func idWithGlobalNetwork(gn, idOrArn string) string { return fmt.Sprintf("%s|%s", gn, idOrArn) diff --git a/sources/networkmanager/global_network_test.go b/adapters/networkmanager/global_network_test.go similarity index 89% rename from sources/networkmanager/global_network_test.go rename to adapters/networkmanager/global_network_test.go index 7b2e56d6..32a3e9e7 100644 --- a/sources/networkmanager/global_network_test.go +++ b/adapters/networkmanager/global_network_test.go @@ -2,19 +2,20 @@ package networkmanager import ( "context" + "testing" + "github.com/aws/aws-sdk-go-v2/service/networkmanager" "github.com/aws/aws-sdk-go-v2/service/networkmanager/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" - "testing" ) func TestGlobalNetworkOutputMapper(t *testing.T) { output := networkmanager.DescribeGlobalNetworksOutput{ GlobalNetworks: []types.GlobalNetwork{ { - GlobalNetworkArn: sources.PtrString("arn:aws:networkmanager:eu-west-2:052392120703:networkmanager/global-network/default"), - GlobalNetworkId: sources.PtrString("default"), + GlobalNetworkArn: adapters.PtrString("arn:aws:networkmanager:eu-west-2:052392120703:networkmanager/global-network/default"), + GlobalNetworkId: adapters.PtrString("default"), }, }, } @@ -37,7 +38,7 @@ func TestGlobalNetworkOutputMapper(t *testing.T) { item := items[0] - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "networkmanager-site", ExpectedMethod: sdp.QueryMethod_SEARCH, diff --git a/sources/networkmanager/link.go b/adapters/networkmanager/link.go similarity index 77% rename from sources/networkmanager/link.go rename to adapters/networkmanager/link.go index ede19b67..1f80c489 100644 --- a/sources/networkmanager/link.go +++ b/adapters/networkmanager/link.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/networkmanager/types" "github.com/aws/aws-sdk-go-v2/service/networkmanager" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -17,7 +17,7 @@ func linkOutputMapper(_ context.Context, _ *networkmanager.Client, scope string, for _, s := range output.Links { var err error var attrs *sdp.ItemAttributes - attrs, err = sources.ToAttributesWithExclude(s, "tags") + attrs, err = adapters.ToAttributesWithExclude(s, "tags") if err != nil { return nil, &sdp.QueryError{ @@ -123,11 +123,12 @@ func linkOutputMapper(_ context.Context, _ *networkmanager.Client, scope string, // +overmind:terraform:queryMap aws_networkmanager_link.arn // +overmind:terraform:method SEARCH -func NewLinkSource(client *networkmanager.Client, accountID string) *sources.DescribeOnlySource[*networkmanager.GetLinksInput, *networkmanager.GetLinksOutput, *networkmanager.Client, *networkmanager.Options] { - return &sources.DescribeOnlySource[*networkmanager.GetLinksInput, *networkmanager.GetLinksOutput, *networkmanager.Client, *networkmanager.Options]{ - Client: client, - AccountID: accountID, - ItemType: "networkmanager-link", +func NewLinkAdapter(client *networkmanager.Client, accountID string) *adapters.DescribeOnlyAdapter[*networkmanager.GetLinksInput, *networkmanager.GetLinksOutput, *networkmanager.Client, *networkmanager.Options] { + return &adapters.DescribeOnlyAdapter[*networkmanager.GetLinksInput, *networkmanager.GetLinksOutput, *networkmanager.Client, *networkmanager.Options]{ + Client: client, + AccountID: accountID, + ItemType: "networkmanager-link", + AdapterMetadata: LinkMetadata(), DescribeFunc: func(ctx context.Context, client *networkmanager.Client, input *networkmanager.GetLinksInput) (*networkmanager.GetLinksOutput, error) { return client.GetLinks(ctx, input) }, @@ -154,7 +155,7 @@ func NewLinkSource(client *networkmanager.Client, accountID string) *sources.Des ErrorString: "list not supported for networkmanager-link, use search", } }, - PaginatorBuilder: func(client *networkmanager.Client, params *networkmanager.GetLinksInput) sources.Paginator[*networkmanager.GetLinksOutput, *networkmanager.Options] { + PaginatorBuilder: func(client *networkmanager.Client, params *networkmanager.GetLinksInput) adapters.Paginator[*networkmanager.GetLinksOutput, *networkmanager.Options] { return networkmanager.NewGetLinksPaginator(client, params) }, OutputMapper: linkOutputMapper, @@ -183,3 +184,24 @@ func NewLinkSource(client *networkmanager.Client, accountID string) *sources.Des }, } } + +func LinkMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "networkmanager-link", + DescriptiveName: "Networkmanager Link", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + Search: true, + GetDescription: "Get a Networkmanager Link", + SearchDescription: "Search for Networkmanager Links by GlobalNetworkId, or by GlobalNetworkId with SiteId", + }, + TerraformMappings: []*sdp.TerraformMapping{ + { + TerraformQueryMap: "aws_networkmanager_link.arn", + TerraformMethod: sdp.QueryMethod_SEARCH, + }, + }, + PotentialLinks: []string{"networkmanager-global-network", "networkmanager-link-association", "networkmanager-site", "networkmanager-network-resource-relationship"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + } +} diff --git a/sources/networkmanager/link_association.go b/adapters/networkmanager/link_association.go similarity index 79% rename from sources/networkmanager/link_association.go rename to adapters/networkmanager/link_association.go index f507c063..f4362eb4 100644 --- a/sources/networkmanager/link_association.go +++ b/adapters/networkmanager/link_association.go @@ -9,7 +9,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/networkmanager/types" "github.com/aws/aws-sdk-go-v2/service/networkmanager" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -19,7 +19,7 @@ func linkAssociationOutputMapper(_ context.Context, _ *networkmanager.Client, sc for _, s := range output.LinkAssociations { var err error var attrs *sdp.ItemAttributes - attrs, err = sources.ToAttributesWithExclude(s, "tags") + attrs, err = adapters.ToAttributesWithExclude(s, "tags") if err != nil { return nil, &sdp.QueryError{ @@ -109,11 +109,12 @@ func linkAssociationOutputMapper(_ context.Context, _ *networkmanager.Client, sc // +overmind:search Search for Networkmanager Link Associations by GlobalNetworkId and DeviceId or LinkId // +overmind:group AWS -func NewLinkAssociationSource(client *networkmanager.Client, accountID string) *sources.DescribeOnlySource[*networkmanager.GetLinkAssociationsInput, *networkmanager.GetLinkAssociationsOutput, *networkmanager.Client, *networkmanager.Options] { - return &sources.DescribeOnlySource[*networkmanager.GetLinkAssociationsInput, *networkmanager.GetLinkAssociationsOutput, *networkmanager.Client, *networkmanager.Options]{ - Client: client, - AccountID: accountID, - ItemType: "networkmanager-link-association", +func NewLinkAssociationAdapter(client *networkmanager.Client, accountID string) *adapters.DescribeOnlyAdapter[*networkmanager.GetLinkAssociationsInput, *networkmanager.GetLinkAssociationsOutput, *networkmanager.Client, *networkmanager.Options] { + return &adapters.DescribeOnlyAdapter[*networkmanager.GetLinkAssociationsInput, *networkmanager.GetLinkAssociationsOutput, *networkmanager.Client, *networkmanager.Options]{ + Client: client, + AccountID: accountID, + ItemType: "networkmanager-link-association", + AdapterMetadata: LinkAssociationMetadata(), DescribeFunc: func(ctx context.Context, client *networkmanager.Client, input *networkmanager.GetLinkAssociationsInput) (*networkmanager.GetLinkAssociationsOutput, error) { return client.GetLinkAssociations(ctx, input) }, @@ -140,7 +141,7 @@ func NewLinkAssociationSource(client *networkmanager.Client, accountID string) * ErrorString: "list not supported for networkmanager-link-association, use search", } }, - PaginatorBuilder: func(client *networkmanager.Client, params *networkmanager.GetLinkAssociationsInput) sources.Paginator[*networkmanager.GetLinkAssociationsOutput, *networkmanager.Options] { + PaginatorBuilder: func(client *networkmanager.Client, params *networkmanager.GetLinkAssociationsInput) adapters.Paginator[*networkmanager.GetLinkAssociationsOutput, *networkmanager.Options] { return networkmanager.NewGetLinkAssociationsPaginator(client, params) }, OutputMapper: linkAssociationOutputMapper, @@ -184,4 +185,20 @@ func NewLinkAssociationSource(client *networkmanager.Client, accountID string) * } }, } + +} + +func LinkAssociationMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "networkmanager-link-association", + DescriptiveName: "Networkmanager LinkAssociation", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + Search: true, + GetDescription: "Get a Networkmanager Link Association", + SearchDescription: "Search for Networkmanager Link Associations by GlobalNetworkId and DeviceId or LinkId", + }, + PotentialLinks: []string{"networkmanager-global-network", "networkmanager-link", "networkmanager-device"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + } } diff --git a/sources/networkmanager/link_association_test.go b/adapters/networkmanager/link_association_test.go similarity index 86% rename from sources/networkmanager/link_association_test.go rename to adapters/networkmanager/link_association_test.go index 5de2b120..6ecc9cdd 100644 --- a/sources/networkmanager/link_association_test.go +++ b/adapters/networkmanager/link_association_test.go @@ -6,7 +6,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/networkmanager" "github.com/aws/aws-sdk-go-v2/service/networkmanager/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -14,9 +14,9 @@ func TestLinkAssociationOutputMapper(t *testing.T) { output := networkmanager.GetLinkAssociationsOutput{ LinkAssociations: []types.LinkAssociation{ { - LinkId: sources.PtrString("link-1"), - GlobalNetworkId: sources.PtrString("default"), - DeviceId: sources.PtrString("dvc-1"), + LinkId: adapters.PtrString("link-1"), + GlobalNetworkId: adapters.PtrString("default"), + DeviceId: adapters.PtrString("dvc-1"), }, }, } @@ -50,7 +50,7 @@ func TestLinkAssociationOutputMapper(t *testing.T) { t.Fatalf("expected default|link-1|dvc-1, got %v", item.UniqueAttributeValue()) } - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "networkmanager-global-network", ExpectedMethod: sdp.QueryMethod_GET, diff --git a/sources/networkmanager/link_test.go b/adapters/networkmanager/link_test.go similarity index 83% rename from sources/networkmanager/link_test.go rename to adapters/networkmanager/link_test.go index eaf9b1c2..c66e08d7 100644 --- a/sources/networkmanager/link_test.go +++ b/adapters/networkmanager/link_test.go @@ -6,7 +6,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/networkmanager" "github.com/aws/aws-sdk-go-v2/service/networkmanager/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -14,10 +14,10 @@ func TestLinkOutputMapper(t *testing.T) { output := networkmanager.GetLinksOutput{ Links: []types.Link{ { - LinkId: sources.PtrString("link-1"), - GlobalNetworkId: sources.PtrString("default"), - SiteId: sources.PtrString("site-1"), - LinkArn: sources.PtrString("arn:aws:networkmanager:us-west-2:123456789012:link/link-1"), + LinkId: adapters.PtrString("link-1"), + GlobalNetworkId: adapters.PtrString("default"), + SiteId: adapters.PtrString("site-1"), + LinkArn: adapters.PtrString("arn:aws:networkmanager:us-west-2:123456789012:link/link-1"), }, }, } @@ -51,7 +51,7 @@ func TestLinkOutputMapper(t *testing.T) { t.Fatalf("expected default|link-1, got %v", item.UniqueAttributeValue()) } - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "networkmanager-global-network", ExpectedMethod: sdp.QueryMethod_GET, diff --git a/sources/networkmanager/network_resource_relationship.go b/adapters/networkmanager/network_resource_relationship.go similarity index 83% rename from sources/networkmanager/network_resource_relationship.go rename to adapters/networkmanager/network_resource_relationship.go index 5424feee..96c6bfac 100644 --- a/sources/networkmanager/network_resource_relationship.go +++ b/adapters/networkmanager/network_resource_relationship.go @@ -8,7 +8,7 @@ import ( "fmt" "github.com/aws/aws-sdk-go-v2/service/networkmanager" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -25,13 +25,13 @@ func networkResourceRelationshipOutputMapper(_ context.Context, _ *networkmanage } // Parse the ARNs - fromArn, err := sources.ParseARN(*relationship.From) + fromArn, err := adapters.ParseARN(*relationship.From) if err != nil { return nil, err } - toArn, err := sources.ParseARN(*relationship.To) + toArn, err := adapters.ParseARN(*relationship.To) if err != nil { return nil, err @@ -262,13 +262,14 @@ func networkResourceRelationshipOutputMapper(_ context.Context, _ *networkmanage // +overmind:search Search for Networkmanager NetworkResourceRelationships by GlobalNetworkId // +overmind:group AWS -func NewNetworkResourceRelationshipsSource(client *networkmanager.Client, accountID, region string) *sources.DescribeOnlySource[*networkmanager.GetNetworkResourceRelationshipsInput, *networkmanager.GetNetworkResourceRelationshipsOutput, *networkmanager.Client, *networkmanager.Options] { - return &sources.DescribeOnlySource[*networkmanager.GetNetworkResourceRelationshipsInput, *networkmanager.GetNetworkResourceRelationshipsOutput, *networkmanager.Client, *networkmanager.Options]{ - Client: client, - AccountID: accountID, - Region: region, - ItemType: "networkmanager-network-resource-relationship", - OutputMapper: networkResourceRelationshipOutputMapper, +func NewNetworkResourceRelationshipsAdapter(client *networkmanager.Client, accountID, region string) *adapters.DescribeOnlyAdapter[*networkmanager.GetNetworkResourceRelationshipsInput, *networkmanager.GetNetworkResourceRelationshipsOutput, *networkmanager.Client, *networkmanager.Options] { + return &adapters.DescribeOnlyAdapter[*networkmanager.GetNetworkResourceRelationshipsInput, *networkmanager.GetNetworkResourceRelationshipsOutput, *networkmanager.Client, *networkmanager.Options]{ + Client: client, + AccountID: accountID, + Region: region, + ItemType: "networkmanager-network-resource-relationship", + AdapterMetadata: NetworkResourceRelationshipMetadata(), + OutputMapper: networkResourceRelationshipOutputMapper, DescribeFunc: func(ctx context.Context, client *networkmanager.Client, input *networkmanager.GetNetworkResourceRelationshipsInput) (*networkmanager.GetNetworkResourceRelationshipsOutput, error) { return client.GetNetworkResourceRelationships(ctx, input) }, @@ -281,7 +282,7 @@ func NewNetworkResourceRelationshipsSource(client *networkmanager.Client, accoun ErrorString: "list not supported for networkmanager-network-resource-relationship, use search", } }, - PaginatorBuilder: func(client *networkmanager.Client, params *networkmanager.GetNetworkResourceRelationshipsInput) sources.Paginator[*networkmanager.GetNetworkResourceRelationshipsOutput, *networkmanager.Options] { + PaginatorBuilder: func(client *networkmanager.Client, params *networkmanager.GetNetworkResourceRelationshipsInput) adapters.Paginator[*networkmanager.GetNetworkResourceRelationshipsOutput, *networkmanager.Options] { return networkmanager.NewGetNetworkResourceRelationshipsPaginator(client, params) }, InputMapperSearch: func(ctx context.Context, client *networkmanager.Client, scope, query string) (*networkmanager.GetNetworkResourceRelationshipsInput, error) { @@ -292,3 +293,16 @@ func NewNetworkResourceRelationshipsSource(client *networkmanager.Client, accoun }, } } + +func NetworkResourceRelationshipMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "networkmanager-network-resource-relationship", + DescriptiveName: "Networkmanager Network Resource Relationships", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Search: true, + SearchDescription: "Search for Networkmanager NetworkResourceRelationships by GlobalNetworkId", + }, + PotentialLinks: []string{"networkmanager-connection", "networkmanager-device", "networkmanager-link", "networkmanager-site", "directconnect-connection", "directconnect-direct-connect-gateway", "directconnect-virtual-interface", "ec2-customer"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + } +} diff --git a/sources/networkmanager/network_resource_relationship_test.go b/adapters/networkmanager/network_resource_relationship_test.go similarity index 62% rename from sources/networkmanager/network_resource_relationship_test.go rename to adapters/networkmanager/network_resource_relationship_test.go index 84e5edca..87ab8124 100644 --- a/sources/networkmanager/network_resource_relationship_test.go +++ b/adapters/networkmanager/network_resource_relationship_test.go @@ -6,7 +6,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/networkmanager" "github.com/aws/aws-sdk-go-v2/service/networkmanager/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -16,81 +16,81 @@ func TestNetworkResourceRelationshipOutputMapper(t *testing.T) { name string input networkmanager.GetNetworkResourceRelationshipsInput output networkmanager.GetNetworkResourceRelationshipsOutput - tests []sources.QueryTests + tests []adapters.QueryTests }{ { name: "ok, one entity", input: networkmanager.GetNetworkResourceRelationshipsInput{ - GlobalNetworkId: sources.PtrString("default"), + GlobalNetworkId: adapters.PtrString("default"), }, output: networkmanager.GetNetworkResourceRelationshipsOutput{ Relationships: []types.Relationship{ // connection, device { - From: sources.PtrString("arn:aws:networkmanager:us-west-2:123456789012:connection/conn-1"), - To: sources.PtrString("arn:aws:networkmanager:us-west-2:123456789012:device/d-1"), + From: adapters.PtrString("arn:aws:networkmanager:us-west-2:123456789012:connection/conn-1"), + To: adapters.PtrString("arn:aws:networkmanager:us-west-2:123456789012:device/d-1"), }, { - To: sources.PtrString("arn:aws:networkmanager:us-west-2:123456789012:connection/conn-1"), - From: sources.PtrString("arn:aws:networkmanager:us-west-2:123456789012:device/d-1"), + To: adapters.PtrString("arn:aws:networkmanager:us-west-2:123456789012:connection/conn-1"), + From: adapters.PtrString("arn:aws:networkmanager:us-west-2:123456789012:device/d-1"), }, // link, site { - From: sources.PtrString("arn:aws:networkmanager:us-west-2:123456789012:link/link-1"), - To: sources.PtrString("arn:aws:networkmanager:us-west-2:123456789012:site/site-1"), + From: adapters.PtrString("arn:aws:networkmanager:us-west-2:123456789012:link/link-1"), + To: adapters.PtrString("arn:aws:networkmanager:us-west-2:123456789012:site/site-1"), }, { - To: sources.PtrString("arn:aws:networkmanager:us-west-2:123456789012:link/link-1"), - From: sources.PtrString("arn:aws:networkmanager:us-west-2:123456789012:site/site-1"), + To: adapters.PtrString("arn:aws:networkmanager:us-west-2:123456789012:link/link-1"), + From: adapters.PtrString("arn:aws:networkmanager:us-west-2:123456789012:site/site-1"), }, // directconnect-connection, directconnect-direct-connect-gateway { - From: sources.PtrString("arn:aws:directconnect:us-west-2:123456789012:connection/dxconn-1"), - To: sources.PtrString("arn:aws:directconnect:us-west-2:123456789012:direct-connect-gateway/gw-1"), + From: adapters.PtrString("arn:aws:directconnect:us-west-2:123456789012:connection/dxconn-1"), + To: adapters.PtrString("arn:aws:directconnect:us-west-2:123456789012:direct-connect-gateway/gw-1"), }, { - To: sources.PtrString("arn:aws:directconnect:us-west-2:123456789012:connection/dxconn-1"), - From: sources.PtrString("arn:aws:directconnect:us-west-2:123456789012:direct-connect-gateway/gw-1"), + To: adapters.PtrString("arn:aws:directconnect:us-west-2:123456789012:connection/dxconn-1"), + From: adapters.PtrString("arn:aws:directconnect:us-west-2:123456789012:direct-connect-gateway/gw-1"), }, // directconnect-virtual-interface, ec2-customer-gateway { - From: sources.PtrString("arn:aws:directconnect:us-west-2:123456789012:virtual-interface/vif-1"), - To: sources.PtrString("arn:aws:ec2:us-west-2:123456789012:customer-gateway/gw-1"), + From: adapters.PtrString("arn:aws:directconnect:us-west-2:123456789012:virtual-interface/vif-1"), + To: adapters.PtrString("arn:aws:ec2:us-west-2:123456789012:customer-gateway/gw-1"), }, { - To: sources.PtrString("arn:aws:directconnect:us-west-2:123456789012:virtual-interface/vif-1"), - From: sources.PtrString("arn:aws:ec2:us-west-2:123456789012:customer-gateway/gw-1"), + To: adapters.PtrString("arn:aws:directconnect:us-west-2:123456789012:virtual-interface/vif-1"), + From: adapters.PtrString("arn:aws:ec2:us-west-2:123456789012:customer-gateway/gw-1"), }, // ec2-transit-gateway, ec2-transit-gateway-attachment { - From: sources.PtrString("arn:aws:ec2:us-east-2:986543144159:transit-gateway/tgw-06910e97a1fbdf66a"), - To: sources.PtrString("arn:aws:ec2:us-west-2:123456789012:transit-gateway-attachment/tgwa-1"), + From: adapters.PtrString("arn:aws:ec2:us-east-2:986543144159:transit-gateway/tgw-06910e97a1fbdf66a"), + To: adapters.PtrString("arn:aws:ec2:us-west-2:123456789012:transit-gateway-attachment/tgwa-1"), }, { - To: sources.PtrString("arn:aws:ec2:us-east-2:986543144159:transit-gateway/tgw-06910e97a1fbdf66a"), - From: sources.PtrString("arn:aws:ec2:us-west-2:123456789012:transit-gateway-attachment/tgwa-1"), + To: adapters.PtrString("arn:aws:ec2:us-east-2:986543144159:transit-gateway/tgw-06910e97a1fbdf66a"), + From: adapters.PtrString("arn:aws:ec2:us-west-2:123456789012:transit-gateway-attachment/tgwa-1"), }, // ec2-transit-gateway-route-table, ec2-transit-gateway-connect-peer { - From: sources.PtrString("arn:aws:ec2:us-west-2:123456789012:transit-gateway-connect-peer/tgw-cnp-1"), - To: sources.PtrString("arn:aws:ec2:us-east-2:986543144159:transit-gateway-route-table/tgw-rtb-043b7b4c0db1e4833"), + From: adapters.PtrString("arn:aws:ec2:us-west-2:123456789012:transit-gateway-connect-peer/tgw-cnp-1"), + To: adapters.PtrString("arn:aws:ec2:us-east-2:986543144159:transit-gateway-route-table/tgw-rtb-043b7b4c0db1e4833"), }, { - To: sources.PtrString("arn:aws:ec2:us-west-2:123456789012:transit-gateway-connect-peer/tgw-cnp-1"), - From: sources.PtrString("arn:aws:ec2:us-east-2:986543144159:transit-gateway-route-table/tgw-rtb-043b7b4c0db1e4833"), + To: adapters.PtrString("arn:aws:ec2:us-west-2:123456789012:transit-gateway-connect-peer/tgw-cnp-1"), + From: adapters.PtrString("arn:aws:ec2:us-east-2:986543144159:transit-gateway-route-table/tgw-rtb-043b7b4c0db1e4833"), }, // connection, ec2-vpn-connection { - From: sources.PtrString("arn:aws:networkmanager:us-west-2:123456789012:connection/conn-1"), - To: sources.PtrString("arn:aws:ec2:us-west-2:123456789012:vpn-connection/conn-1"), + From: adapters.PtrString("arn:aws:networkmanager:us-west-2:123456789012:connection/conn-1"), + To: adapters.PtrString("arn:aws:ec2:us-west-2:123456789012:vpn-connection/conn-1"), }, { - To: sources.PtrString("arn:aws:networkmanager:us-west-2:123456789012:connection/conn-1"), - From: sources.PtrString("arn:aws:ec2:us-west-2:123456789012:vpn-connection/conn-1"), + To: adapters.PtrString("arn:aws:networkmanager:us-west-2:123456789012:connection/conn-1"), + From: adapters.PtrString("arn:aws:ec2:us-west-2:123456789012:vpn-connection/conn-1"), }, }, }, - tests: []sources.QueryTests{ + tests: []adapters.QueryTests{ // connection to device { { diff --git a/sources/networkmanager/shared.go b/adapters/networkmanager/shared.go similarity index 100% rename from sources/networkmanager/shared.go rename to adapters/networkmanager/shared.go diff --git a/sources/networkmanager/shared_test.go b/adapters/networkmanager/shared_test.go similarity index 100% rename from sources/networkmanager/shared_test.go rename to adapters/networkmanager/shared_test.go diff --git a/sources/networkmanager/site.go b/adapters/networkmanager/site.go similarity index 74% rename from sources/networkmanager/site.go rename to adapters/networkmanager/site.go index 2b646555..c0c3a9f5 100644 --- a/sources/networkmanager/site.go +++ b/adapters/networkmanager/site.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/networkmanager" "github.com/aws/aws-sdk-go-v2/service/networkmanager/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -17,7 +17,7 @@ func siteOutputMapper(_ context.Context, _ *networkmanager.Client, scope string, for _, s := range output.Sites { var err error var attrs *sdp.ItemAttributes - attrs, err = sources.ToAttributesWithExclude(s, "tags") + attrs, err = adapters.ToAttributesWithExclude(s, "tags") if err != nil { return nil, &sdp.QueryError{ @@ -107,11 +107,12 @@ func siteOutputMapper(_ context.Context, _ *networkmanager.Client, scope string, // +overmind:terraform:queryMap aws_networkmanager_site.arn // +overmind:terraform:method SEARCH -func NewSiteSource(client *networkmanager.Client, accountID string) *sources.DescribeOnlySource[*networkmanager.GetSitesInput, *networkmanager.GetSitesOutput, *networkmanager.Client, *networkmanager.Options] { - return &sources.DescribeOnlySource[*networkmanager.GetSitesInput, *networkmanager.GetSitesOutput, *networkmanager.Client, *networkmanager.Options]{ - Client: client, - AccountID: accountID, - ItemType: "networkmanager-site", +func NewSiteAdapter(client *networkmanager.Client, accountID string) *adapters.DescribeOnlyAdapter[*networkmanager.GetSitesInput, *networkmanager.GetSitesOutput, *networkmanager.Client, *networkmanager.Options] { + return &adapters.DescribeOnlyAdapter[*networkmanager.GetSitesInput, *networkmanager.GetSitesOutput, *networkmanager.Client, *networkmanager.Options]{ + Client: client, + AccountID: accountID, + ItemType: "networkmanager-site", + AdapterMetadata: SiteMetadata(), DescribeFunc: func(ctx context.Context, client *networkmanager.Client, input *networkmanager.GetSitesInput) (*networkmanager.GetSitesOutput, error) { return client.GetSites(ctx, input) }, @@ -138,7 +139,7 @@ func NewSiteSource(client *networkmanager.Client, accountID string) *sources.Des ErrorString: "list not supported for networkmanager-site, use search", } }, - PaginatorBuilder: func(client *networkmanager.Client, params *networkmanager.GetSitesInput) sources.Paginator[*networkmanager.GetSitesOutput, *networkmanager.Options] { + PaginatorBuilder: func(client *networkmanager.Client, params *networkmanager.GetSitesInput) adapters.Paginator[*networkmanager.GetSitesOutput, *networkmanager.Options] { return networkmanager.NewGetSitesPaginator(client, params) }, OutputMapper: siteOutputMapper, @@ -150,3 +151,24 @@ func NewSiteSource(client *networkmanager.Client, accountID string) *sources.Des }, } } + +func SiteMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "networkmanager-site", + DescriptiveName: "Networkmanager Site", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + Search: true, + GetDescription: "Get a Networkmanager Site", + SearchDescription: "Search for Networkmanager Sites by GlobalNetworkId", + }, + TerraformMappings: []*sdp.TerraformMapping{ + { + TerraformQueryMap: "aws_networkmanager_site.arn", + TerraformMethod: sdp.QueryMethod_SEARCH, + }, + }, + PotentialLinks: []string{"networkmanager-global-network", "networkmanager-link", "networkmanager-device"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + } +} diff --git a/sources/networkmanager/site_test.go b/adapters/networkmanager/site_test.go similarity index 88% rename from sources/networkmanager/site_test.go rename to adapters/networkmanager/site_test.go index a35b9025..fb06e95c 100644 --- a/sources/networkmanager/site_test.go +++ b/adapters/networkmanager/site_test.go @@ -6,7 +6,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/networkmanager" "github.com/aws/aws-sdk-go-v2/service/networkmanager/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -14,8 +14,8 @@ func TestSiteOutputMapper(t *testing.T) { output := networkmanager.GetSitesOutput{ Sites: []types.Site{ { - SiteId: sources.PtrString("site1"), - GlobalNetworkId: sources.PtrString("default"), + SiteId: adapters.PtrString("site1"), + GlobalNetworkId: adapters.PtrString("default"), }, }, } @@ -49,7 +49,7 @@ func TestSiteOutputMapper(t *testing.T) { t.Fatalf("expected default|site1, got %v", item.UniqueAttributeValue()) } - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "networkmanager-global-network", ExpectedMethod: sdp.QueryMethod_GET, diff --git a/sources/networkmanager/site_to_site_vpn_attachment.go b/adapters/networkmanager/site_to_site_vpn_attachment.go similarity index 72% rename from sources/networkmanager/site_to_site_vpn_attachment.go rename to adapters/networkmanager/site_to_site_vpn_attachment.go index 80af05dc..e2d18911 100644 --- a/sources/networkmanager/site_to_site_vpn_attachment.go +++ b/adapters/networkmanager/site_to_site_vpn_attachment.go @@ -5,7 +5,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/networkmanager" "github.com/aws/aws-sdk-go-v2/service/networkmanager/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -21,7 +21,7 @@ func getSiteToSiteVpnAttachmentGetFunc(ctx context.Context, client *networkmanag } func siteToSiteVpnAttachmentItemMapper(_, scope string, awsItem *types.SiteToSiteVpnAttachment) (*sdp.Item, error) { - attributes, err := sources.ToAttributesWithExclude(awsItem) + attributes, err := adapters.ToAttributesWithExclude(awsItem) if err != nil { return nil, err @@ -96,12 +96,13 @@ func siteToSiteVpnAttachmentItemMapper(_, scope string, awsItem *types.SiteToSit // +overmind:group AWS // +overmind:terraform:queryMap aws_networkmanager_site_to_site_vpn_attachment.id -func NewSiteToSiteVpnAttachmentSource(client *networkmanager.Client, accountID, region string) *sources.GetListSource[*types.SiteToSiteVpnAttachment, *networkmanager.Client, *networkmanager.Options] { - return &sources.GetListSource[*types.SiteToSiteVpnAttachment, *networkmanager.Client, *networkmanager.Options]{ - Client: client, - AccountID: accountID, - Region: region, - ItemType: "networkmanager-site-to-site-vpn-attachment", +func NewSiteToSiteVpnAttachmentAdapter(client *networkmanager.Client, accountID, region string) *adapters.GetListAdapter[*types.SiteToSiteVpnAttachment, *networkmanager.Client, *networkmanager.Options] { + return &adapters.GetListAdapter[*types.SiteToSiteVpnAttachment, *networkmanager.Client, *networkmanager.Options]{ + Client: client, + AccountID: accountID, + Region: region, + ItemType: "networkmanager-site-to-site-vpn-attachment", + AdapterMetadata: SiteToSiteVpnAttachmentMetadata(), GetFunc: func(ctx context.Context, client *networkmanager.Client, scope string, query string) (*types.SiteToSiteVpnAttachment, error) { return getSiteToSiteVpnAttachmentGetFunc(ctx, client, scope, query) }, @@ -114,3 +115,19 @@ func NewSiteToSiteVpnAttachmentSource(client *networkmanager.Client, accountID, }, } } + +func SiteToSiteVpnAttachmentMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "networkmanager-site-to-site-vpn-attachment", + DescriptiveName: "Networkmanager Site To Site Vpn Attachment", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + GetDescription: "Get a Networkmanager Site To Site Vpn Attachment by id", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_networkmanager_site_to_site_vpn_attachment.id"}, + }, + PotentialLinks: []string{"networkmanager-core-network", "ec2-vpn-connection"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + } +} diff --git a/sources/networkmanager/site_to_site_vpn_attachment_test.go b/adapters/networkmanager/site_to_site_vpn_attachment_test.go similarity index 82% rename from sources/networkmanager/site_to_site_vpn_attachment_test.go rename to adapters/networkmanager/site_to_site_vpn_attachment_test.go index 48fb2915..402b966b 100644 --- a/sources/networkmanager/site_to_site_vpn_attachment_test.go +++ b/adapters/networkmanager/site_to_site_vpn_attachment_test.go @@ -4,7 +4,7 @@ import ( "testing" "github.com/aws/aws-sdk-go-v2/service/networkmanager/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -15,21 +15,21 @@ func TestSiteToSiteVpnAttachmentOutputMapper(t *testing.T) { item *types.SiteToSiteVpnAttachment expectedHealth sdp.Health expectedAttr string - tests sources.QueryTests + tests adapters.QueryTests }{ { name: "ok", item: &types.SiteToSiteVpnAttachment{ Attachment: &types.Attachment{ - AttachmentId: sources.PtrString("stsa-1"), - CoreNetworkId: sources.PtrString("cn-1"), + AttachmentId: adapters.PtrString("stsa-1"), + CoreNetworkId: adapters.PtrString("cn-1"), State: types.AttachmentStateAvailable, }, - VpnConnectionArn: sources.PtrString("arn:aws:ec2:us-west-2:123456789012:vpn-connection/vpn-1234"), + VpnConnectionArn: adapters.PtrString("arn:aws:ec2:us-west-2:123456789012:vpn-connection/vpn-1234"), }, expectedHealth: sdp.Health_HEALTH_OK, expectedAttr: "stsa-1", - tests: sources.QueryTests{ + tests: adapters.QueryTests{ { ExpectedType: "networkmanager-core-network", ExpectedMethod: sdp.QueryMethod_GET, diff --git a/sources/networkmanager/transit_gateway_connect_peer_associations.go b/adapters/networkmanager/transit_gateway_connect_peer_associations.go similarity index 73% rename from sources/networkmanager/transit_gateway_connect_peer_associations.go rename to adapters/networkmanager/transit_gateway_connect_peer_associations.go index 473dbd42..05bdd736 100644 --- a/sources/networkmanager/transit_gateway_connect_peer_associations.go +++ b/adapters/networkmanager/transit_gateway_connect_peer_associations.go @@ -6,7 +6,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/networkmanager" "github.com/aws/aws-sdk-go-v2/service/networkmanager/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -16,7 +16,7 @@ func transitGatewayConnectPeerAssociationsOutputMapper(_ context.Context, _ *net for _, a := range output.TransitGatewayConnectPeerAssociations { var err error var attrs *sdp.ItemAttributes - attrs, err = sources.ToAttributesWithExclude(a, "tags") + attrs, err = adapters.ToAttributesWithExclude(a, "tags") if err != nil { return nil, &sdp.QueryError{ @@ -107,12 +107,13 @@ func transitGatewayConnectPeerAssociationsOutputMapper(_ context.Context, _ *net // +overmind:search Search for Networkmanager TransitGatewayConnectPeerAssociations by GlobalNetworkId // +overmind:group AWS -func NewTransitGatewayConnectPeerAssociationSource(client *networkmanager.Client, accountID, region string) *sources.DescribeOnlySource[*networkmanager.GetTransitGatewayConnectPeerAssociationsInput, *networkmanager.GetTransitGatewayConnectPeerAssociationsOutput, *networkmanager.Client, *networkmanager.Options] { - return &sources.DescribeOnlySource[*networkmanager.GetTransitGatewayConnectPeerAssociationsInput, *networkmanager.GetTransitGatewayConnectPeerAssociationsOutput, *networkmanager.Client, *networkmanager.Options]{ - Client: client, - AccountID: accountID, - Region: region, - ItemType: "networkmanager-transit-gateway-connect-peer-association", +func NewTransitGatewayConnectPeerAssociationAdapter(client *networkmanager.Client, accountID, region string) *adapters.DescribeOnlyAdapter[*networkmanager.GetTransitGatewayConnectPeerAssociationsInput, *networkmanager.GetTransitGatewayConnectPeerAssociationsOutput, *networkmanager.Client, *networkmanager.Options] { + return &adapters.DescribeOnlyAdapter[*networkmanager.GetTransitGatewayConnectPeerAssociationsInput, *networkmanager.GetTransitGatewayConnectPeerAssociationsOutput, *networkmanager.Client, *networkmanager.Options]{ + Client: client, + AccountID: accountID, + Region: region, + ItemType: "networkmanager-transit-gateway-connect-peer-association", + AdapterMetadata: TransitGatewayConnectPeerAssociationMetadata(), DescribeFunc: func(ctx context.Context, client *networkmanager.Client, input *networkmanager.GetTransitGatewayConnectPeerAssociationsInput) (*networkmanager.GetTransitGatewayConnectPeerAssociationsOutput, error) { return client.GetTransitGatewayConnectPeerAssociations(ctx, input) }, @@ -141,7 +142,7 @@ func NewTransitGatewayConnectPeerAssociationSource(client *networkmanager.Client ErrorString: "list not supported for networkmanager-transit-gateway-connect-peer-association, use search", } }, - PaginatorBuilder: func(client *networkmanager.Client, params *networkmanager.GetTransitGatewayConnectPeerAssociationsInput) sources.Paginator[*networkmanager.GetTransitGatewayConnectPeerAssociationsOutput, *networkmanager.Options] { + PaginatorBuilder: func(client *networkmanager.Client, params *networkmanager.GetTransitGatewayConnectPeerAssociationsInput) adapters.Paginator[*networkmanager.GetTransitGatewayConnectPeerAssociationsOutput, *networkmanager.Options] { return networkmanager.NewGetTransitGatewayConnectPeerAssociationsPaginator(client, params) }, OutputMapper: transitGatewayConnectPeerAssociationsOutputMapper, @@ -153,3 +154,20 @@ func NewTransitGatewayConnectPeerAssociationSource(client *networkmanager.Client }, } } + +func TransitGatewayConnectPeerAssociationMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "networkmanager-transit-gateway-connect-peer-association", + DescriptiveName: "Networkmanager Transit Gateway Connect Peer Association", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a Networkmanager Transit Gateway Connect Peer Association by id", + ListDescription: "List all Networkmanager Transit Gateway Connect Peer Associations", + SearchDescription: "Search for Networkmanager Transit Gateway Connect Peer Associations by GlobalNetworkId", + }, + PotentialLinks: []string{"networkmanager-global-network", "networkmanager-device", "networkmanager-link"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + } +} diff --git a/sources/networkmanager/transit_gateway_connect_peer_associations_test.go b/adapters/networkmanager/transit_gateway_connect_peer_associations_test.go similarity index 84% rename from sources/networkmanager/transit_gateway_connect_peer_associations_test.go rename to adapters/networkmanager/transit_gateway_connect_peer_associations_test.go index 24402b8e..8559be5f 100644 --- a/sources/networkmanager/transit_gateway_connect_peer_associations_test.go +++ b/adapters/networkmanager/transit_gateway_connect_peer_associations_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/networkmanager" "github.com/aws/aws-sdk-go-v2/service/networkmanager/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -18,24 +18,24 @@ func TestTransitGatewayConnectPeerAssociationsOutputMapper(t *testing.T) { out networkmanager.GetTransitGatewayConnectPeerAssociationsOutput expectedHealth sdp.Health expectedAttr string - tests sources.QueryTests + tests adapters.QueryTests }{ { name: "ok", out: networkmanager.GetTransitGatewayConnectPeerAssociationsOutput{ TransitGatewayConnectPeerAssociations: []types.TransitGatewayConnectPeerAssociation{ { - GlobalNetworkId: sources.PtrString("default"), - TransitGatewayConnectPeerArn: sources.PtrString("arn:aws:ec2:us-west-2:123456789012:transit-gateway-connect-peer-association/tgw-1234"), + GlobalNetworkId: adapters.PtrString("default"), + TransitGatewayConnectPeerArn: adapters.PtrString("arn:aws:ec2:us-west-2:123456789012:transit-gateway-connect-peer-association/tgw-1234"), State: types.TransitGatewayConnectPeerAssociationStateAvailable, - DeviceId: sources.PtrString("device-1"), - LinkId: sources.PtrString("link-1"), + DeviceId: adapters.PtrString("device-1"), + LinkId: adapters.PtrString("link-1"), }, }, }, expectedHealth: sdp.Health_HEALTH_OK, expectedAttr: "default|arn:aws:ec2:us-west-2:123456789012:transit-gateway-connect-peer-association/tgw-1234", - tests: sources.QueryTests{ + tests: adapters.QueryTests{ { ExpectedType: "networkmanager-global-network", ExpectedMethod: sdp.QueryMethod_GET, diff --git a/sources/networkmanager/transit_gateway_peering.go b/adapters/networkmanager/transit_gateway_peering.go similarity index 72% rename from sources/networkmanager/transit_gateway_peering.go rename to adapters/networkmanager/transit_gateway_peering.go index 360e2841..d0ae6df4 100644 --- a/sources/networkmanager/transit_gateway_peering.go +++ b/adapters/networkmanager/transit_gateway_peering.go @@ -5,7 +5,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/networkmanager" "github.com/aws/aws-sdk-go-v2/service/networkmanager/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -21,7 +21,7 @@ func getTransitGatewayPeeringGetFunc(ctx context.Context, client *networkmanager } func transitGatewayPeeringItemMapper(_, scope string, awsItem *types.TransitGatewayPeering) (*sdp.Item, error) { - attributes, err := sources.ToAttributesWithExclude(awsItem) + attributes, err := adapters.ToAttributesWithExclude(awsItem) if err != nil { return nil, err @@ -86,14 +86,14 @@ func transitGatewayPeeringItemMapper(_, scope string, awsItem *types.TransitGate // ARN example: "arn:aws:ec2:us-west-2:123456789012:transit-gateway/tgw-1234" if awsItem.TransitGatewayArn != nil { - if arn, err := sources.ParseARN(*awsItem.TransitGatewayArn); err == nil { + if arn, err := adapters.ParseARN(*awsItem.TransitGatewayArn); err == nil { item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ // +overmind:link ec2-transit-gateway Type: "ec2-transit-gateway", Method: sdp.QueryMethod_SEARCH, Query: *awsItem.TransitGatewayArn, - Scope: sources.FormatScope(arn.AccountID, arn.Region), + Scope: adapters.FormatScope(arn.AccountID, arn.Region), }, BlastPropagation: &sdp.BlastPropagation{ In: true, @@ -113,12 +113,13 @@ func transitGatewayPeeringItemMapper(_, scope string, awsItem *types.TransitGate // +overmind:group AWS // +overmind:terraform:queryMap aws_networkmanager_transit_gateway_peering.id -func NewTransitGatewayPeeringSource(client *networkmanager.Client, accountID, region string) *sources.GetListSource[*types.TransitGatewayPeering, *networkmanager.Client, *networkmanager.Options] { - return &sources.GetListSource[*types.TransitGatewayPeering, *networkmanager.Client, *networkmanager.Options]{ - Client: client, - AccountID: accountID, - Region: region, - ItemType: "networkmanager-transit-gateway-peering", +func NewTransitGatewayPeeringAdapter(client *networkmanager.Client, accountID, region string) *adapters.GetListAdapter[*types.TransitGatewayPeering, *networkmanager.Client, *networkmanager.Options] { + return &adapters.GetListAdapter[*types.TransitGatewayPeering, *networkmanager.Client, *networkmanager.Options]{ + Client: client, + AccountID: accountID, + Region: region, + ItemType: "networkmanager-transit-gateway-peering", + AdapterMetadata: TransitGatewayPeeringMetadata(), GetFunc: func(ctx context.Context, client *networkmanager.Client, scope string, query string) (*types.TransitGatewayPeering, error) { return getTransitGatewayPeeringGetFunc(ctx, client, scope, query) }, @@ -131,3 +132,19 @@ func NewTransitGatewayPeeringSource(client *networkmanager.Client, accountID, re }, } } + +func TransitGatewayPeeringMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "networkmanager-transit-gateway-peering", + DescriptiveName: "Networkmanager Transit Gateway Peering", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + GetDescription: "Get a Networkmanager Transit Gateway Peering by id", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_networkmanager_transit_gateway_peering.id"}, + }, + PotentialLinks: []string{"networkmanager-core-network", "ec2-transit-gateway-peering-attachment", "ec2-transit-gateway"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + } +} diff --git a/sources/networkmanager/transit_gateway_peering_test.go b/adapters/networkmanager/transit_gateway_peering_test.go similarity index 80% rename from sources/networkmanager/transit_gateway_peering_test.go rename to adapters/networkmanager/transit_gateway_peering_test.go index f654238a..6f65643e 100644 --- a/sources/networkmanager/transit_gateway_peering_test.go +++ b/adapters/networkmanager/transit_gateway_peering_test.go @@ -4,7 +4,7 @@ import ( "testing" "github.com/aws/aws-sdk-go-v2/service/networkmanager/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -15,22 +15,22 @@ func TestTransitGatewayPeeringOutputMapper(t *testing.T) { item *types.TransitGatewayPeering expectedHealth sdp.Health expectedAttr string - tests sources.QueryTests + tests adapters.QueryTests }{ { name: "ok", item: &types.TransitGatewayPeering{ Peering: &types.Peering{ - PeeringId: sources.PtrString("tgp-1"), - CoreNetworkId: sources.PtrString("cn-1"), + PeeringId: adapters.PtrString("tgp-1"), + CoreNetworkId: adapters.PtrString("cn-1"), State: types.PeeringStateAvailable, }, - TransitGatewayArn: sources.PtrString("arn:aws:ec2:us-west-2:123456789012:transit-gateway/tgw-1234"), - TransitGatewayPeeringAttachmentId: sources.PtrString("gpa-1"), + TransitGatewayArn: adapters.PtrString("arn:aws:ec2:us-west-2:123456789012:transit-gateway/tgw-1234"), + TransitGatewayPeeringAttachmentId: adapters.PtrString("gpa-1"), }, expectedHealth: sdp.Health_HEALTH_OK, expectedAttr: "tgp-1", - tests: sources.QueryTests{ + tests: adapters.QueryTests{ { ExpectedType: "networkmanager-core-network", ExpectedMethod: sdp.QueryMethod_GET, diff --git a/sources/networkmanager/transit_gateway_registration.go b/adapters/networkmanager/transit_gateway_registration.go similarity index 69% rename from sources/networkmanager/transit_gateway_registration.go rename to adapters/networkmanager/transit_gateway_registration.go index 46d6d39c..53a177c4 100644 --- a/sources/networkmanager/transit_gateway_registration.go +++ b/adapters/networkmanager/transit_gateway_registration.go @@ -6,7 +6,7 @@ import ( "strings" "github.com/aws/aws-sdk-go-v2/service/networkmanager" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -16,7 +16,7 @@ func transitGatewayRegistrationOutputMapper(_ context.Context, _ *networkmanager for _, r := range output.TransitGatewayRegistrations { var err error var attrs *sdp.ItemAttributes - attrs, err = sources.ToAttributesWithExclude(r) + attrs, err = adapters.ToAttributesWithExclude(r) if err != nil { return nil, &sdp.QueryError{ @@ -56,14 +56,14 @@ func transitGatewayRegistrationOutputMapper(_ context.Context, _ *networkmanager // ARN example: "arn:aws:ec2:us-west-2:123456789012:transit-gateway/tgw-1234" if r.TransitGatewayArn != nil { - if arn, err := sources.ParseARN(*r.TransitGatewayArn); err == nil { + if arn, err := adapters.ParseARN(*r.TransitGatewayArn); err == nil { item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ // +overmind:link ec2-transit-gateway Type: "ec2-transit-gateway", Method: sdp.QueryMethod_SEARCH, Query: *r.TransitGatewayArn, - Scope: sources.FormatScope(arn.AccountID, arn.Region), + Scope: adapters.FormatScope(arn.AccountID, arn.Region), }, BlastPropagation: &sdp.BlastPropagation{ In: true, @@ -87,12 +87,13 @@ func transitGatewayRegistrationOutputMapper(_ context.Context, _ *networkmanager // +overmind:search Search for Networkmanager Transit Gateway Registrations by GlobalNetworkId // +overmind:group AWS -func NewTransitGatewayRegistrationSource(client *networkmanager.Client, accountID, region string) *sources.DescribeOnlySource[*networkmanager.GetTransitGatewayRegistrationsInput, *networkmanager.GetTransitGatewayRegistrationsOutput, *networkmanager.Client, *networkmanager.Options] { - return &sources.DescribeOnlySource[*networkmanager.GetTransitGatewayRegistrationsInput, *networkmanager.GetTransitGatewayRegistrationsOutput, *networkmanager.Client, *networkmanager.Options]{ - Client: client, - AccountID: accountID, - Region: region, - ItemType: "networkmanager-transit-gateway-registration", +func NewTransitGatewayRegistrationAdapter(client *networkmanager.Client, accountID, region string) *adapters.DescribeOnlyAdapter[*networkmanager.GetTransitGatewayRegistrationsInput, *networkmanager.GetTransitGatewayRegistrationsOutput, *networkmanager.Client, *networkmanager.Options] { + return &adapters.DescribeOnlyAdapter[*networkmanager.GetTransitGatewayRegistrationsInput, *networkmanager.GetTransitGatewayRegistrationsOutput, *networkmanager.Client, *networkmanager.Options]{ + Client: client, + AccountID: accountID, + Region: region, + ItemType: "networkmanager-transit-gateway-registration", + AdapterMetadata: TransitGatewayRegistrationMetadata(), DescribeFunc: func(ctx context.Context, client *networkmanager.Client, input *networkmanager.GetTransitGatewayRegistrationsInput) (*networkmanager.GetTransitGatewayRegistrationsOutput, error) { return client.GetTransitGatewayRegistrations(ctx, input) }, @@ -118,7 +119,7 @@ func NewTransitGatewayRegistrationSource(client *networkmanager.Client, accountI ErrorString: "list not supported for networkmanager-transit-gateway-registration, use search", } }, - PaginatorBuilder: func(client *networkmanager.Client, params *networkmanager.GetTransitGatewayRegistrationsInput) sources.Paginator[*networkmanager.GetTransitGatewayRegistrationsOutput, *networkmanager.Options] { + PaginatorBuilder: func(client *networkmanager.Client, params *networkmanager.GetTransitGatewayRegistrationsInput) adapters.Paginator[*networkmanager.GetTransitGatewayRegistrationsOutput, *networkmanager.Options] { return networkmanager.NewGetTransitGatewayRegistrationsPaginator(client, params) }, OutputMapper: transitGatewayRegistrationOutputMapper, @@ -130,3 +131,20 @@ func NewTransitGatewayRegistrationSource(client *networkmanager.Client, accountI }, } } + +func TransitGatewayRegistrationMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "networkmanager-transit-gateway-registration", + DescriptiveName: "Networkmanager Transit Gateway Registrations", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a Networkmanager Transit Gateway Registrations", + ListDescription: "List all Networkmanager Transit Gateway Registrations", + SearchDescription: "Search for Networkmanager Transit Gateway Registrations by GlobalNetworkId", + }, + PotentialLinks: []string{"networkmanager-global-network", "ec2-transit-gateway"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + } +} diff --git a/sources/networkmanager/transit_gateway_registration_test.go b/adapters/networkmanager/transit_gateway_registration_test.go similarity index 85% rename from sources/networkmanager/transit_gateway_registration_test.go rename to adapters/networkmanager/transit_gateway_registration_test.go index 5a9d2c6f..07f91e09 100644 --- a/sources/networkmanager/transit_gateway_registration_test.go +++ b/adapters/networkmanager/transit_gateway_registration_test.go @@ -6,7 +6,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/networkmanager" "github.com/aws/aws-sdk-go-v2/service/networkmanager/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -16,15 +16,15 @@ func TestTransitGatewayRegistrationOutputMapper(t *testing.T) { name string out networkmanager.GetTransitGatewayRegistrationsOutput expectedAttr string - tests sources.QueryTests + tests adapters.QueryTests }{ { name: "ok", out: networkmanager.GetTransitGatewayRegistrationsOutput{ TransitGatewayRegistrations: []types.TransitGatewayRegistration{ { - GlobalNetworkId: sources.PtrString("default"), - TransitGatewayArn: sources.PtrString("arn:aws:ec2:us-west-2:123456789012:transit-gateway/tgw-1234"), + GlobalNetworkId: adapters.PtrString("default"), + TransitGatewayArn: adapters.PtrString("arn:aws:ec2:us-west-2:123456789012:transit-gateway/tgw-1234"), State: &types.TransitGatewayRegistrationStateReason{ Code: types.TransitGatewayRegistrationStateAvailable, }, @@ -32,7 +32,7 @@ func TestTransitGatewayRegistrationOutputMapper(t *testing.T) { }, }, expectedAttr: "default|arn:aws:ec2:us-west-2:123456789012:transit-gateway/tgw-1234", - tests: sources.QueryTests{ + tests: adapters.QueryTests{ { ExpectedType: "networkmanager-global-network", ExpectedMethod: sdp.QueryMethod_GET, @@ -52,8 +52,8 @@ func TestTransitGatewayRegistrationOutputMapper(t *testing.T) { out: networkmanager.GetTransitGatewayRegistrationsOutput{ TransitGatewayRegistrations: []types.TransitGatewayRegistration{ { - GlobalNetworkId: sources.PtrString("default"), - TransitGatewayArn: sources.PtrString("arn:aws:ec2:us-west-2:123456789012:transit-gateway/tgw-1234"), + GlobalNetworkId: adapters.PtrString("default"), + TransitGatewayArn: adapters.PtrString("arn:aws:ec2:us-west-2:123456789012:transit-gateway/tgw-1234"), State: &types.TransitGatewayRegistrationStateReason{ Code: types.TransitGatewayRegistrationStateDeleting, }, @@ -61,7 +61,7 @@ func TestTransitGatewayRegistrationOutputMapper(t *testing.T) { }, }, expectedAttr: "default|arn:aws:ec2:us-west-2:123456789012:transit-gateway/tgw-1234", - tests: sources.QueryTests{ + tests: adapters.QueryTests{ { ExpectedType: "networkmanager-global-network", ExpectedMethod: sdp.QueryMethod_GET, diff --git a/sources/networkmanager/transit_gateway_route_table_attachment.go b/adapters/networkmanager/transit_gateway_route_table_attachment.go similarity index 70% rename from sources/networkmanager/transit_gateway_route_table_attachment.go rename to adapters/networkmanager/transit_gateway_route_table_attachment.go index dd1e5e5a..95f006fb 100644 --- a/sources/networkmanager/transit_gateway_route_table_attachment.go +++ b/adapters/networkmanager/transit_gateway_route_table_attachment.go @@ -5,7 +5,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/networkmanager" "github.com/aws/aws-sdk-go-v2/service/networkmanager/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -21,7 +21,7 @@ func getTransitGatewayRouteTableAttachmentGetFunc(ctx context.Context, client *n } func transitGatewayRouteTableAttachmentItemMapper(_, scope string, awsItem *types.TransitGatewayRouteTableAttachment) (*sdp.Item, error) { - attributes, err := sources.ToAttributesWithExclude(awsItem) + attributes, err := adapters.ToAttributesWithExclude(awsItem) if err != nil { return nil, err @@ -74,14 +74,14 @@ func transitGatewayRouteTableAttachmentItemMapper(_, scope string, awsItem *type // ARN example: "arn:aws:ec2:us-west-2:123456789012:transit-gateway-route-table/tgw-rtb-9876543210123456" if awsItem.TransitGatewayRouteTableArn != nil { - if arn, err := sources.ParseARN(*awsItem.TransitGatewayRouteTableArn); err == nil { + if arn, err := adapters.ParseARN(*awsItem.TransitGatewayRouteTableArn); err == nil { item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ // +overmind:link ec2-transit-gateway-route-table Type: "ec2-transit-gateway-route-table", Method: sdp.QueryMethod_SEARCH, Query: *awsItem.TransitGatewayRouteTableArn, - Scope: sources.FormatScope(arn.AccountID, arn.Region), + Scope: adapters.FormatScope(arn.AccountID, arn.Region), }, BlastPropagation: &sdp.BlastPropagation{ In: true, @@ -101,11 +101,12 @@ func transitGatewayRouteTableAttachmentItemMapper(_, scope string, awsItem *type // +overmind:group AWS // +overmind:terraform:queryMap aws_networkmanager_transit_gateway_route_table_attachment.id -func NewTransitGatewayRouteTableAttachmentSource(client *networkmanager.Client, accountID, region string) *sources.GetListSource[*types.TransitGatewayRouteTableAttachment, *networkmanager.Client, *networkmanager.Options] { - return &sources.GetListSource[*types.TransitGatewayRouteTableAttachment, *networkmanager.Client, *networkmanager.Options]{ - Client: client, - AccountID: accountID, - ItemType: "networkmanager-transit-gateway-route-table-attachment", +func NewTransitGatewayRouteTableAttachmentAdapter(client *networkmanager.Client, accountID, region string) *adapters.GetListAdapter[*types.TransitGatewayRouteTableAttachment, *networkmanager.Client, *networkmanager.Options] { + return &adapters.GetListAdapter[*types.TransitGatewayRouteTableAttachment, *networkmanager.Client, *networkmanager.Options]{ + Client: client, + AccountID: accountID, + ItemType: "networkmanager-transit-gateway-route-table-attachment", + AdapterMetadata: TransitGatewayRouteTableAttachmentMetadata(), GetFunc: func(ctx context.Context, client *networkmanager.Client, scope string, query string) (*types.TransitGatewayRouteTableAttachment, error) { return getTransitGatewayRouteTableAttachmentGetFunc(ctx, client, scope, query) }, @@ -118,3 +119,19 @@ func NewTransitGatewayRouteTableAttachmentSource(client *networkmanager.Client, }, } } + +func TransitGatewayRouteTableAttachmentMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "networkmanager-transit-gateway-route-table-attachment", + DescriptiveName: "Networkmanager Transit Gateway Route Table Attachment", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + GetDescription: "Get a Networkmanager Transit Gateway Route Table Attachment by id", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_networkmanager_transit_gateway_route_table_attachment.id"}, + }, + PotentialLinks: []string{"networkmanager-core-network", "networkmanager-transit-gateway-peering", "ec2-transit-gateway-route-table"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + } +} diff --git a/sources/networkmanager/transit_gateway_route_table_attachment_test.go b/adapters/networkmanager/transit_gateway_route_table_attachment_test.go similarity index 73% rename from sources/networkmanager/transit_gateway_route_table_attachment_test.go rename to adapters/networkmanager/transit_gateway_route_table_attachment_test.go index 18e53efe..1109077a 100644 --- a/sources/networkmanager/transit_gateway_route_table_attachment_test.go +++ b/adapters/networkmanager/transit_gateway_route_table_attachment_test.go @@ -4,7 +4,7 @@ import ( "testing" "github.com/aws/aws-sdk-go-v2/service/networkmanager/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -14,20 +14,20 @@ func TestTransitGatewayRouteTableAttachmentItemMapper(t *testing.T) { name string input types.TransitGatewayRouteTableAttachment expectedAttr string - tests sources.QueryTests + tests adapters.QueryTests }{ { name: "ok", input: types.TransitGatewayRouteTableAttachment{ Attachment: &types.Attachment{ - AttachmentId: sources.PtrString("attachment1"), - CoreNetworkId: sources.PtrString("corenetwork1"), + AttachmentId: adapters.PtrString("attachment1"), + CoreNetworkId: adapters.PtrString("corenetwork1"), }, - TransitGatewayRouteTableArn: sources.PtrString("arn:aws:ec2:us-west-2:123456789012:transit-gateway-route-table/tgw-rtb-9876543210123456"), - PeeringId: sources.PtrString("peer1"), + TransitGatewayRouteTableArn: adapters.PtrString("arn:aws:ec2:us-west-2:123456789012:transit-gateway-route-table/tgw-rtb-9876543210123456"), + PeeringId: adapters.PtrString("peer1"), }, expectedAttr: "attachment1", - tests: sources.QueryTests{ + tests: adapters.QueryTests{ { ExpectedType: "networkmanager-core-network", ExpectedMethod: sdp.QueryMethod_GET, @@ -52,12 +52,12 @@ func TestTransitGatewayRouteTableAttachmentItemMapper(t *testing.T) { name: "missing ec2-transit-gateway-route-table", input: types.TransitGatewayRouteTableAttachment{ Attachment: &types.Attachment{ - AttachmentId: sources.PtrString("attachment1"), - CoreNetworkId: sources.PtrString("corenetwork1"), + AttachmentId: adapters.PtrString("attachment1"), + CoreNetworkId: adapters.PtrString("corenetwork1"), }, }, expectedAttr: "attachment1", - tests: sources.QueryTests{ + tests: adapters.QueryTests{ { ExpectedType: "networkmanager-core-network", ExpectedMethod: sdp.QueryMethod_GET, @@ -70,13 +70,13 @@ func TestTransitGatewayRouteTableAttachmentItemMapper(t *testing.T) { name: "invalid ec2-transit-gateway-route-table", input: types.TransitGatewayRouteTableAttachment{ Attachment: &types.Attachment{ - AttachmentId: sources.PtrString("attachment1"), - CoreNetworkId: sources.PtrString("corenetwork1"), + AttachmentId: adapters.PtrString("attachment1"), + CoreNetworkId: adapters.PtrString("corenetwork1"), }, - TransitGatewayRouteTableArn: sources.PtrString("arn:aws:ec2:us-west-2:123456789012:transit-gateway-route-table-tgw-rtb-9876543210123456"), + TransitGatewayRouteTableArn: adapters.PtrString("arn:aws:ec2:us-west-2:123456789012:transit-gateway-route-table-tgw-rtb-9876543210123456"), }, expectedAttr: "attachment1", - tests: sources.QueryTests{ + tests: adapters.QueryTests{ { ExpectedType: "networkmanager-core-network", ExpectedMethod: sdp.QueryMethod_GET, diff --git a/sources/networkmanager/vpc_attachment.go b/adapters/networkmanager/vpc_attachment.go similarity index 67% rename from sources/networkmanager/vpc_attachment.go rename to adapters/networkmanager/vpc_attachment.go index 1b542341..76410416 100644 --- a/sources/networkmanager/vpc_attachment.go +++ b/adapters/networkmanager/vpc_attachment.go @@ -5,7 +5,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/networkmanager" "github.com/aws/aws-sdk-go-v2/service/networkmanager/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -21,7 +21,7 @@ func vpcAttachmentGetFunc(ctx context.Context, client *networkmanager.Client, _, } func vpcAttachmentItemMapper(_, scope string, awsItem *types.VpcAttachment) (*sdp.Item, error) { - attributes, err := sources.ToAttributesWithExclude(awsItem) + attributes, err := adapters.ToAttributesWithExclude(awsItem) if err != nil { return nil, err @@ -67,12 +67,13 @@ func vpcAttachmentItemMapper(_, scope string, awsItem *types.VpcAttachment) (*sd // +overmind:group AWS // +overmind:terraform:queryMap aws_networkmanager_vpc_attachment.id -func NewVPCAttachmentSource(client *networkmanager.Client, accountID, region string) *sources.GetListSource[*types.VpcAttachment, *networkmanager.Client, *networkmanager.Options] { - return &sources.GetListSource[*types.VpcAttachment, *networkmanager.Client, *networkmanager.Options]{ - Client: client, - Region: region, - AccountID: accountID, - ItemType: "networkmanager-vpc-attachment", +func NewVPCAttachmentAdapter(client *networkmanager.Client, accountID, region string) *adapters.GetListAdapter[*types.VpcAttachment, *networkmanager.Client, *networkmanager.Options] { + return &adapters.GetListAdapter[*types.VpcAttachment, *networkmanager.Client, *networkmanager.Options]{ + Client: client, + Region: region, + AccountID: accountID, + ItemType: "networkmanager-vpc-attachment", + AdapterMetadata: VPCAttachmentMetadata(), GetFunc: func(ctx context.Context, client *networkmanager.Client, scope string, query string) (*types.VpcAttachment, error) { return vpcAttachmentGetFunc(ctx, client, scope, query) }, @@ -85,3 +86,19 @@ func NewVPCAttachmentSource(client *networkmanager.Client, accountID, region str }, } } + +func VPCAttachmentMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "networkmanager-vpc-attachment", + DescriptiveName: "Networkmanager VPC Attachment", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + GetDescription: "Get a Networkmanager VPC Attachment by id", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_networkmanager_vpc_attachment.id"}, + }, + PotentialLinks: []string{"networkmanager-core-network"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + } +} diff --git a/sources/networkmanager/vpc_attachment_test.go b/adapters/networkmanager/vpc_attachment_test.go similarity index 81% rename from sources/networkmanager/vpc_attachment_test.go rename to adapters/networkmanager/vpc_attachment_test.go index 2f6bfe04..efd5222b 100644 --- a/sources/networkmanager/vpc_attachment_test.go +++ b/adapters/networkmanager/vpc_attachment_test.go @@ -4,15 +4,15 @@ import ( "testing" "github.com/aws/aws-sdk-go-v2/service/networkmanager/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) func TestVPCAttachmentItemMapper(t *testing.T) { input := types.VpcAttachment{ Attachment: &types.Attachment{ - AttachmentId: sources.PtrString("attachment1"), - CoreNetworkId: sources.PtrString("corenetwork1"), + AttachmentId: adapters.PtrString("attachment1"), + CoreNetworkId: adapters.PtrString("corenetwork1"), }, } scope := "123456789012.eu-west-2" @@ -30,7 +30,7 @@ func TestVPCAttachmentItemMapper(t *testing.T) { t.Fatalf("expected %v, got %v", "attachment1", item.UniqueAttributeValue()) } - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "networkmanager-core-network", ExpectedMethod: sdp.QueryMethod_GET, diff --git a/sources/rds/db_cluster.go b/adapters/rds/db_cluster.go similarity index 79% rename from sources/rds/db_cluster.go rename to adapters/rds/db_cluster.go index f720c905..7e2ac3ec 100644 --- a/sources/rds/db_cluster.go +++ b/adapters/rds/db_cluster.go @@ -4,7 +4,7 @@ import ( "context" "github.com/aws/aws-sdk-go-v2/service/rds" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -22,10 +22,10 @@ func dBClusterOutputMapper(ctx context.Context, client rdsClient, scope string, if err == nil { tags = tagsToMap(tagsOut.TagList) } else { - tags = sources.HandleTagsError(ctx, err) + tags = adapters.HandleTagsError(ctx, err) } - attributes, err := sources.ToAttributesWithExclude(cluster) + attributes, err := adapters.ToAttributesWithExclude(cluster) if err != nil { return nil, err @@ -39,7 +39,7 @@ func dBClusterOutputMapper(ctx context.Context, client rdsClient, scope string, Tags: tags, } - var a *sources.ARN + var a *adapters.ARN if cluster.DBSubnetGroup != nil { // +overmind:link rds-db-subnet-group @@ -78,14 +78,14 @@ func dBClusterOutputMapper(ctx context.Context, client rdsClient, scope string, } for _, replica := range cluster.ReadReplicaIdentifiers { - if a, err = sources.ParseARN(replica); err == nil { + if a, err = adapters.ParseARN(replica); err == nil { // +overmind:link rds-db-cluster item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "rds-db-cluster", Method: sdp.QueryMethod_SEARCH, Query: replica, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Tightly coupled @@ -154,14 +154,14 @@ func dBClusterOutputMapper(ctx context.Context, client rdsClient, scope string, } if cluster.KmsKeyId != nil { - if a, err = sources.ParseARN(*cluster.KmsKeyId); err == nil { + if a, err = adapters.ParseARN(*cluster.KmsKeyId); err == nil { // +overmind:link kms-key item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "kms-key", Method: sdp.QueryMethod_SEARCH, Query: *cluster.KmsKeyId, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changes to the KMS key can affect the cluster @@ -230,14 +230,14 @@ func dBClusterOutputMapper(ctx context.Context, client rdsClient, scope string, if cluster.MasterUserSecret != nil { if cluster.MasterUserSecret.KmsKeyId != nil { - if a, err = sources.ParseARN(*cluster.MasterUserSecret.KmsKeyId); err == nil { + if a, err = adapters.ParseARN(*cluster.MasterUserSecret.KmsKeyId); err == nil { // +overmind:link kms-key item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "kms-key", Method: sdp.QueryMethod_SEARCH, Query: *cluster.MasterUserSecret.KmsKeyId, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changes to the KMS key can affect the cluster @@ -250,14 +250,14 @@ func dBClusterOutputMapper(ctx context.Context, client rdsClient, scope string, } if cluster.MasterUserSecret.SecretArn != nil { - if a, err = sources.ParseARN(*cluster.MasterUserSecret.SecretArn); err == nil { + if a, err = adapters.ParseARN(*cluster.MasterUserSecret.SecretArn); err == nil { // +overmind:link secretsmanager-secret item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "secretsmanager-secret", Method: sdp.QueryMethod_SEARCH, Query: *cluster.MasterUserSecret.SecretArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changes to the secret can affect the cluster @@ -271,14 +271,14 @@ func dBClusterOutputMapper(ctx context.Context, client rdsClient, scope string, } if cluster.MonitoringRoleArn != nil { - if a, err = sources.ParseARN(*cluster.MonitoringRoleArn); err == nil { + if a, err = adapters.ParseARN(*cluster.MonitoringRoleArn); err == nil { // +overmind:link iam-role item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "iam-role", Method: sdp.QueryMethod_SEARCH, Query: *cluster.MonitoringRoleArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changes to the IAM role can affect the cluster @@ -292,14 +292,14 @@ func dBClusterOutputMapper(ctx context.Context, client rdsClient, scope string, if cluster.PerformanceInsightsKMSKeyId != nil { // This is an ARN - if a, err = sources.ParseARN(*cluster.PerformanceInsightsKMSKeyId); err == nil { + if a, err = adapters.ParseARN(*cluster.PerformanceInsightsKMSKeyId); err == nil { // +overmind:link kms-key item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "kms-key", Method: sdp.QueryMethod_SEARCH, Query: *cluster.PerformanceInsightsKMSKeyId, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changes to the KMS key can affect the cluster @@ -312,14 +312,14 @@ func dBClusterOutputMapper(ctx context.Context, client rdsClient, scope string, } if cluster.ReplicationSourceIdentifier != nil { - if a, err = sources.ParseARN(*cluster.ReplicationSourceIdentifier); err == nil { + if a, err = adapters.ParseARN(*cluster.ReplicationSourceIdentifier); err == nil { // +overmind:link rds-db-cluster item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "rds-db-cluster", Method: sdp.QueryMethod_SEARCH, Query: *cluster.ReplicationSourceIdentifier, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Tightly coupled @@ -345,13 +345,14 @@ func dBClusterOutputMapper(ctx context.Context, client rdsClient, scope string, // +overmind:group AWS // +overmind:terraform:queryMap aws_rds_cluster.cluster_identifier -func NewDBClusterSource(client rdsClient, accountID string, region string) *sources.DescribeOnlySource[*rds.DescribeDBClustersInput, *rds.DescribeDBClustersOutput, rdsClient, *rds.Options] { - return &sources.DescribeOnlySource[*rds.DescribeDBClustersInput, *rds.DescribeDBClustersOutput, rdsClient, *rds.Options]{ - ItemType: "rds-db-cluster", - Region: region, - AccountID: accountID, - Client: client, - PaginatorBuilder: func(client rdsClient, params *rds.DescribeDBClustersInput) sources.Paginator[*rds.DescribeDBClustersOutput, *rds.Options] { +func NewDBClusterAdapter(client rdsClient, accountID string, region string) *adapters.DescribeOnlyAdapter[*rds.DescribeDBClustersInput, *rds.DescribeDBClustersOutput, rdsClient, *rds.Options] { + return &adapters.DescribeOnlyAdapter[*rds.DescribeDBClustersInput, *rds.DescribeDBClustersOutput, rdsClient, *rds.Options]{ + ItemType: "rds-db-cluster", + Region: region, + AccountID: accountID, + Client: client, + AdapterMetadata: DBClusterMetadata(), + PaginatorBuilder: func(client rdsClient, params *rds.DescribeDBClustersInput) adapters.Paginator[*rds.DescribeDBClustersOutput, *rds.Options] { return rds.NewDescribeDBClustersPaginator(client, params) }, DescribeFunc: func(ctx context.Context, client rdsClient, input *rds.DescribeDBClustersInput) (*rds.DescribeDBClustersOutput, error) { @@ -368,3 +369,23 @@ func NewDBClusterSource(client rdsClient, accountID string, region string) *sour OutputMapper: dBClusterOutputMapper, } } + +func DBClusterMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "rds-db-cluster", + DescriptiveName: "RDS Cluster", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a parameter group by name", + ListDescription: "List all RDS parameter groups", + SearchDescription: "Search for a parameter group by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_rds_cluster.cluster_identifier"}, + }, + PotentialLinks: []string{"rds-db-subnet-group", "dns", "rds-db-cluster", "ec2-security-group", "route53-hosted-zone", "kms-key", "kinesis-stream", "rds-option-group", "secretsmanager-secret", "iam-role"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_DATABASE, + } +} diff --git a/sources/rds/db_cluster_parameter_group.go b/adapters/rds/db_cluster_parameter_group.go similarity index 70% rename from sources/rds/db_cluster_parameter_group.go rename to adapters/rds/db_cluster_parameter_group.go index 41f97c3d..0823c82d 100644 --- a/sources/rds/db_cluster_parameter_group.go +++ b/adapters/rds/db_cluster_parameter_group.go @@ -6,7 +6,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/rds" "github.com/aws/aws-sdk-go-v2/service/rds/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -17,7 +17,7 @@ type ClusterParameterGroup struct { } func dBClusterParameterGroupItemMapper(_, scope string, awsItem *ClusterParameterGroup) (*sdp.Item, error) { - attributes, err := sources.ToAttributesWithExclude(awsItem) + attributes, err := adapters.ToAttributesWithExclude(awsItem) if err != nil { return nil, err @@ -43,12 +43,13 @@ func dBClusterParameterGroupItemMapper(_, scope string, awsItem *ClusterParamete // +overmind:terraform:queryMap aws_rds_cluster_parameter_group.arn // +overmind:terraform:method SEARCH -func NewDBClusterParameterGroupSource(client rdsClient, accountID string, region string) *sources.GetListSource[*ClusterParameterGroup, rdsClient, *rds.Options] { - return &sources.GetListSource[*ClusterParameterGroup, rdsClient, *rds.Options]{ - ItemType: "rds-db-cluster-parameter-group", - Client: client, - AccountID: accountID, - Region: region, +func NewDBClusterParameterGroupAdapter(client rdsClient, accountID string, region string) *adapters.GetListAdapter[*ClusterParameterGroup, rdsClient, *rds.Options] { + return &adapters.GetListAdapter[*ClusterParameterGroup, rdsClient, *rds.Options]{ + ItemType: "rds-db-cluster-parameter-group", + Client: client, + AccountID: accountID, + Region: region, + AdapterMetadata: DBClusterParameterGroupMetadata(), GetFunc: func(ctx context.Context, client rdsClient, scope, query string) (*ClusterParameterGroup, error) { out, err := client.DescribeDBClusterParameterGroups(ctx, &rds.DescribeDBClusterParameterGroupsInput{ DBClusterParameterGroupName: &query, @@ -115,3 +116,25 @@ func NewDBClusterParameterGroupSource(client rdsClient, accountID string, region ItemMapper: dBClusterParameterGroupItemMapper, } } + +func DBClusterParameterGroupMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "rds-db-cluster-parameter-group", + DescriptiveName: "RDS Cluster Parameter Group", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a parameter group by name", + ListDescription: "List all RDS parameter groups", + SearchDescription: "Search for a parameter group by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + { + TerraformQueryMap: "aws_rds_cluster_parameter_group.arn", + TerraformMethod: sdp.QueryMethod_SEARCH, + }, + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_DATABASE, + } +} diff --git a/adapters/rds/db_cluster_parameter_group_test.go b/adapters/rds/db_cluster_parameter_group_test.go new file mode 100644 index 00000000..3a87643f --- /dev/null +++ b/adapters/rds/db_cluster_parameter_group_test.go @@ -0,0 +1,98 @@ +package rds + +import ( + "testing" + "time" + + "github.com/aws/aws-sdk-go-v2/service/rds/types" + "github.com/overmindtech/aws-source/adapters" +) + +func TestDBClusterParameterGroupOutputMapper(t *testing.T) { + group := ClusterParameterGroup{ + DBClusterParameterGroup: types.DBClusterParameterGroup{ + DBClusterParameterGroupName: adapters.PtrString("default.aurora-mysql5.7"), + DBParameterGroupFamily: adapters.PtrString("aurora-mysql5.7"), + Description: adapters.PtrString("Default cluster parameter group for aurora-mysql5.7"), + DBClusterParameterGroupArn: adapters.PtrString("arn:aws:rds:eu-west-1:052392120703:cluster-pg:default.aurora-mysql5.7"), + }, + Parameters: []types.Parameter{ + { + ParameterName: adapters.PtrString("activate_all_roles_on_login"), + ParameterValue: adapters.PtrString("0"), + Description: adapters.PtrString("Automatically set all granted roles as active after the user has authenticated successfully."), + Source: adapters.PtrString("engine-default"), + ApplyType: adapters.PtrString("dynamic"), + DataType: adapters.PtrString("boolean"), + AllowedValues: adapters.PtrString("0,1"), + IsModifiable: adapters.PtrBool(true), + ApplyMethod: types.ApplyMethodPendingReboot, + SupportedEngineModes: []string{ + "provisioned", + }, + }, + { + ParameterName: adapters.PtrString("allow-suspicious-udfs"), + Description: adapters.PtrString("Controls whether user-defined functions that have only an xxx symbol for the main function can be loaded"), + Source: adapters.PtrString("engine-default"), + ApplyType: adapters.PtrString("static"), + DataType: adapters.PtrString("boolean"), + AllowedValues: adapters.PtrString("0,1"), + IsModifiable: adapters.PtrBool(false), + ApplyMethod: types.ApplyMethodPendingReboot, + SupportedEngineModes: []string{ + "provisioned", + }, + }, + { + ParameterName: adapters.PtrString("aurora_binlog_replication_max_yield_seconds"), + Description: adapters.PtrString("Controls the number of seconds that binary log dump thread waits up to for the current binlog file to be filled by transactions. This wait period avoids contention that can arise from replicating each binlog event individually."), + Source: adapters.PtrString("engine-default"), + ApplyType: adapters.PtrString("dynamic"), + DataType: adapters.PtrString("integer"), + AllowedValues: adapters.PtrString("0-36000"), + IsModifiable: adapters.PtrBool(true), + ApplyMethod: types.ApplyMethodPendingReboot, + SupportedEngineModes: []string{ + "provisioned", + }, + }, + { + ParameterName: adapters.PtrString("aurora_enable_staggered_replica_restart"), + Description: adapters.PtrString("Allow Aurora replicas to follow a staggered restart schedule to increase cluster availability."), + Source: adapters.PtrString("system"), + ApplyType: adapters.PtrString("dynamic"), + DataType: adapters.PtrString("boolean"), + AllowedValues: adapters.PtrString("0,1"), + IsModifiable: adapters.PtrBool(true), + ApplyMethod: types.ApplyMethodImmediate, + SupportedEngineModes: []string{ + "provisioned", + }, + }, + }, + } + + item, err := dBClusterParameterGroupItemMapper("", "foo", &group) + + if err != nil { + t.Fatal(err) + } + + if err = item.Validate(); err != nil { + t.Error(err) + } +} + +func TestNewDBClusterParameterGroupAdapter(t *testing.T) { + client, account, region := GetAutoConfig(t) + + adapter := NewDBClusterParameterGroupAdapter(client, account, region) + + test := adapters.E2ETest{ + Adapter: adapter, + Timeout: 10 * time.Second, + } + + test.Run(t) +} diff --git a/adapters/rds/db_cluster_test.go b/adapters/rds/db_cluster_test.go new file mode 100644 index 00000000..4a68da72 --- /dev/null +++ b/adapters/rds/db_cluster_test.go @@ -0,0 +1,265 @@ +package rds + +import ( + "context" + "testing" + "time" + + "github.com/aws/aws-sdk-go-v2/service/rds" + "github.com/aws/aws-sdk-go-v2/service/rds/types" + "github.com/overmindtech/aws-source/adapters" + "github.com/overmindtech/sdp-go" +) + +func TestDBClusterOutputMapper(t *testing.T) { + output := rds.DescribeDBClustersOutput{ + DBClusters: []types.DBCluster{ + { + AllocatedStorage: adapters.PtrInt32(100), + AvailabilityZones: []string{ + "eu-west-2c", // link + }, + BackupRetentionPeriod: adapters.PtrInt32(7), + DBClusterIdentifier: adapters.PtrString("database-2"), + DBClusterParameterGroup: adapters.PtrString("default.postgres13"), + DBSubnetGroup: adapters.PtrString("default-vpc-0d7892e00e573e701"), // link + Status: adapters.PtrString("available"), + EarliestRestorableTime: adapters.PtrTime(time.Now()), + Endpoint: adapters.PtrString("database-2.cluster-camcztjohmlj.eu-west-2.rds.amazonaws.com"), // link + ReaderEndpoint: adapters.PtrString("database-2.cluster-ro-camcztjohmlj.eu-west-2.rds.amazonaws.com"), // link + MultiAZ: adapters.PtrBool(true), + Engine: adapters.PtrString("postgres"), + EngineVersion: adapters.PtrString("13.7"), + LatestRestorableTime: adapters.PtrTime(time.Now()), + Port: adapters.PtrInt32(5432), // link + MasterUsername: adapters.PtrString("postgres"), + PreferredBackupWindow: adapters.PtrString("04:48-05:18"), + PreferredMaintenanceWindow: adapters.PtrString("fri:04:05-fri:04:35"), + ReadReplicaIdentifiers: []string{ + "arn:aws:rds:eu-west-1:052392120703:cluster:read-replica", // link + }, + DBClusterMembers: []types.DBClusterMember{ + { + DBInstanceIdentifier: adapters.PtrString("database-2-instance-3"), // link + IsClusterWriter: adapters.PtrBool(false), + DBClusterParameterGroupStatus: adapters.PtrString("in-sync"), + PromotionTier: adapters.PtrInt32(1), + }, + }, + VpcSecurityGroups: []types.VpcSecurityGroupMembership{ + { + VpcSecurityGroupId: adapters.PtrString("sg-094e151c9fc5da181"), // link + Status: adapters.PtrString("active"), + }, + }, + HostedZoneId: adapters.PtrString("Z1TTGA775OQIYO"), // link + StorageEncrypted: adapters.PtrBool(true), + KmsKeyId: adapters.PtrString("arn:aws:kms:eu-west-2:052392120703:key/9653cbdd-1590-464a-8456-67389cef6933"), // link + DbClusterResourceId: adapters.PtrString("cluster-2EW4PDVN7F7V57CUJPYOEAA74M"), + DBClusterArn: adapters.PtrString("arn:aws:rds:eu-west-2:052392120703:cluster:database-2"), + IAMDatabaseAuthenticationEnabled: adapters.PtrBool(false), + ClusterCreateTime: adapters.PtrTime(time.Now()), + EngineMode: adapters.PtrString("provisioned"), + DeletionProtection: adapters.PtrBool(false), + HttpEndpointEnabled: adapters.PtrBool(false), + ActivityStreamStatus: types.ActivityStreamStatusStopped, + CopyTagsToSnapshot: adapters.PtrBool(false), + CrossAccountClone: adapters.PtrBool(false), + DomainMemberships: []types.DomainMembership{}, + TagList: []types.Tag{}, + DBClusterInstanceClass: adapters.PtrString("db.m5d.large"), + StorageType: adapters.PtrString("io1"), + Iops: adapters.PtrInt32(1000), + PubliclyAccessible: adapters.PtrBool(true), + AutoMinorVersionUpgrade: adapters.PtrBool(true), + MonitoringInterval: adapters.PtrInt32(0), + PerformanceInsightsEnabled: adapters.PtrBool(false), + NetworkType: adapters.PtrString("IPV4"), + ActivityStreamKinesisStreamName: adapters.PtrString("aws-rds-das-db-AB1CDEFG23GHIJK4LMNOPQRST"), // link + ActivityStreamKmsKeyId: adapters.PtrString("ab12345e-1111-2bc3-12a3-ab1cd12345e"), // Not linking at the moment because there are too many possible formats. If you want to change this, submit a PR + ActivityStreamMode: types.ActivityStreamModeAsync, + AutomaticRestartTime: adapters.PtrTime(time.Now()), + AssociatedRoles: []types.DBClusterRole{}, // EC2 classic roles, ignore + BacktrackConsumedChangeRecords: adapters.PtrInt64(1), + BacktrackWindow: adapters.PtrInt64(2), + Capacity: adapters.PtrInt32(2), + CharacterSetName: adapters.PtrString("english"), + CloneGroupId: adapters.PtrString("id"), + CustomEndpoints: []string{ + "endpoint1", // link dns + }, + DBClusterOptionGroupMemberships: []types.DBClusterOptionGroupStatus{ + { + DBClusterOptionGroupName: adapters.PtrString("optionGroupName"), // link + Status: adapters.PtrString("good"), + }, + }, + DBSystemId: adapters.PtrString("systemId"), + DatabaseName: adapters.PtrString("databaseName"), + EarliestBacktrackTime: adapters.PtrTime(time.Now()), + EnabledCloudwatchLogsExports: []string{ + "logExport1", + }, + GlobalWriteForwardingRequested: adapters.PtrBool(true), + GlobalWriteForwardingStatus: types.WriteForwardingStatusDisabled, + MasterUserSecret: &types.MasterUserSecret{ + KmsKeyId: adapters.PtrString("arn:aws:kms:eu-west-2:052392120703:key/something"), // link + SecretArn: adapters.PtrString("arn:aws:service:region:account:type/id"), // link + SecretStatus: adapters.PtrString("okay"), + }, + MonitoringRoleArn: adapters.PtrString("arn:aws:service:region:account:type/id"), // link + PendingModifiedValues: &types.ClusterPendingModifiedValues{}, + PercentProgress: adapters.PtrString("99"), + PerformanceInsightsKMSKeyId: adapters.PtrString("arn:aws:service:region:account:type/id"), // link, assuming it's an ARN + PerformanceInsightsRetentionPeriod: adapters.PtrInt32(99), + ReplicationSourceIdentifier: adapters.PtrString("arn:aws:rds:eu-west-2:052392120703:cluster:database-1"), // link + ScalingConfigurationInfo: &types.ScalingConfigurationInfo{ + AutoPause: adapters.PtrBool(true), + MaxCapacity: adapters.PtrInt32(10), + MinCapacity: adapters.PtrInt32(1), + SecondsBeforeTimeout: adapters.PtrInt32(10), + SecondsUntilAutoPause: adapters.PtrInt32(10), + TimeoutAction: adapters.PtrString("error"), + }, + ServerlessV2ScalingConfiguration: &types.ServerlessV2ScalingConfigurationInfo{ + MaxCapacity: adapters.PtrFloat64(10), + MinCapacity: adapters.PtrFloat64(1), + }, + }, + }, + } + + items, err := dBClusterOutputMapper(context.Background(), mockRdsClient{}, "foo", nil, &output) + + if err != nil { + t.Fatal(err) + } + + if len(items) != 1 { + t.Fatalf("got %v items, expected 1", len(items)) + } + + item := items[0] + + if err = item.Validate(); err != nil { + t.Error(err) + } + + if item.GetTags()["key"] != "value" { + t.Errorf("expected tag key to be value, got %v", item.GetTags()["key"]) + } + + tests := adapters.QueryTests{ + { + ExpectedType: "rds-db-subnet-group", + ExpectedMethod: sdp.QueryMethod_GET, + ExpectedQuery: "default-vpc-0d7892e00e573e701", + ExpectedScope: "foo", + }, + { + ExpectedType: "dns", + ExpectedMethod: sdp.QueryMethod_SEARCH, + ExpectedQuery: "database-2.cluster-ro-camcztjohmlj.eu-west-2.rds.amazonaws.com", + ExpectedScope: "global", + }, + { + ExpectedType: "dns", + ExpectedMethod: sdp.QueryMethod_SEARCH, + ExpectedQuery: "database-2.cluster-camcztjohmlj.eu-west-2.rds.amazonaws.com", + ExpectedScope: "global", + }, + { + ExpectedType: "rds-db-cluster", + ExpectedMethod: sdp.QueryMethod_SEARCH, + ExpectedQuery: "arn:aws:rds:eu-west-1:052392120703:cluster:read-replica", + ExpectedScope: "052392120703.eu-west-1", + }, + { + ExpectedType: "rds-db-instance", + ExpectedMethod: sdp.QueryMethod_GET, + ExpectedQuery: "database-2-instance-3", + ExpectedScope: "foo", + }, + { + ExpectedType: "ec2-security-group", + ExpectedMethod: sdp.QueryMethod_GET, + ExpectedQuery: "sg-094e151c9fc5da181", + ExpectedScope: "foo", + }, + { + ExpectedType: "route53-hosted-zone", + ExpectedMethod: sdp.QueryMethod_GET, + ExpectedQuery: "Z1TTGA775OQIYO", + ExpectedScope: "foo", + }, + { + ExpectedType: "kms-key", + ExpectedMethod: sdp.QueryMethod_SEARCH, + ExpectedQuery: "arn:aws:kms:eu-west-2:052392120703:key/9653cbdd-1590-464a-8456-67389cef6933", + ExpectedScope: "052392120703.eu-west-2", + }, + { + ExpectedType: "kinesis-stream", + ExpectedMethod: sdp.QueryMethod_GET, + ExpectedQuery: "aws-rds-das-db-AB1CDEFG23GHIJK4LMNOPQRST", + ExpectedScope: "foo", + }, + { + ExpectedType: "dns", + ExpectedMethod: sdp.QueryMethod_SEARCH, + ExpectedQuery: "endpoint1", + ExpectedScope: "global", + }, + { + ExpectedType: "rds-option-group", + ExpectedMethod: sdp.QueryMethod_GET, + ExpectedQuery: "optionGroupName", + ExpectedScope: "foo", + }, + { + ExpectedType: "kms-key", + ExpectedMethod: sdp.QueryMethod_SEARCH, + ExpectedQuery: "arn:aws:kms:eu-west-2:052392120703:key/something", + ExpectedScope: "052392120703.eu-west-2", + }, + { + ExpectedType: "secretsmanager-secret", + ExpectedMethod: sdp.QueryMethod_SEARCH, + ExpectedQuery: "arn:aws:service:region:account:type/id", + ExpectedScope: "account.region", + }, + { + ExpectedType: "iam-role", + ExpectedMethod: sdp.QueryMethod_SEARCH, + ExpectedQuery: "arn:aws:service:region:account:type/id", + ExpectedScope: "account.region", + }, + { + ExpectedType: "kms-key", + ExpectedMethod: sdp.QueryMethod_SEARCH, + ExpectedQuery: "arn:aws:service:region:account:type/id", + ExpectedScope: "account.region", + }, + { + ExpectedType: "rds-db-cluster", + ExpectedMethod: sdp.QueryMethod_SEARCH, + ExpectedQuery: "arn:aws:rds:eu-west-2:052392120703:cluster:database-1", + ExpectedScope: "052392120703.eu-west-2", + }, + } + + tests.Execute(t, item) +} + +func TestNewDBClusterAdapter(t *testing.T) { + client, account, region := GetAutoConfig(t) + + adapter := NewDBClusterAdapter(client, account, region) + + test := adapters.E2ETest{ + Adapter: adapter, + Timeout: 10 * time.Second, + } + + test.Run(t) +} diff --git a/sources/rds/db_instance.go b/adapters/rds/db_instance.go similarity index 82% rename from sources/rds/db_instance.go rename to adapters/rds/db_instance.go index a98361c5..a17548cd 100644 --- a/sources/rds/db_instance.go +++ b/adapters/rds/db_instance.go @@ -4,7 +4,7 @@ import ( "context" "github.com/aws/aws-sdk-go-v2/service/rds" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -85,7 +85,7 @@ func dBInstanceOutputMapper(ctx context.Context, client rdsClient, scope string, if err == nil { tags = tagsToMap(tagsOut.TagList) } else { - tags = sources.HandleTagsError(ctx, err) + tags = adapters.HandleTagsError(ctx, err) } var dbSubnetGroup *string @@ -98,7 +98,7 @@ func dBInstanceOutputMapper(ctx context.Context, client rdsClient, scope string, instance.DBSubnetGroup = nil } - attributes, err := sources.ToAttributesWithExclude(instance) + attributes, err := adapters.ToAttributesWithExclude(instance) if err != nil { return nil, err @@ -116,7 +116,7 @@ func dBInstanceOutputMapper(ctx context.Context, client rdsClient, scope string, item.Health = statusToHealth(*instance.DBInstanceStatus) } - var a *sources.ARN + var a *adapters.ARN if instance.Endpoint != nil { if instance.Endpoint.Address != nil { @@ -232,14 +232,14 @@ func dBInstanceOutputMapper(ctx context.Context, client rdsClient, scope string, if instance.KmsKeyId != nil { // This actually uses the ARN not the id - if a, err = sources.ParseARN(*instance.KmsKeyId); err == nil { + if a, err = adapters.ParseARN(*instance.KmsKeyId); err == nil { // +overmind:link kms-key item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "kms-key", Method: sdp.QueryMethod_SEARCH, Query: *instance.KmsKeyId, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changing the KMS key can affect the instance @@ -252,14 +252,14 @@ func dBInstanceOutputMapper(ctx context.Context, client rdsClient, scope string, } if instance.EnhancedMonitoringResourceArn != nil { - if a, err = sources.ParseARN(*instance.EnhancedMonitoringResourceArn); err == nil { + if a, err = adapters.ParseARN(*instance.EnhancedMonitoringResourceArn); err == nil { // +overmind:link logs-log-stream item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "logs-log-stream", Method: sdp.QueryMethod_SEARCH, Query: *instance.EnhancedMonitoringResourceArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Tightly coupled @@ -271,14 +271,14 @@ func dBInstanceOutputMapper(ctx context.Context, client rdsClient, scope string, } if instance.MonitoringRoleArn != nil { - if a, err = sources.ParseARN(*instance.MonitoringRoleArn); err == nil { + if a, err = adapters.ParseARN(*instance.MonitoringRoleArn); err == nil { // +overmind:link iam-role item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "iam-role", Method: sdp.QueryMethod_SEARCH, Query: *instance.MonitoringRoleArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changing the role can affect the instance @@ -292,14 +292,14 @@ func dBInstanceOutputMapper(ctx context.Context, client rdsClient, scope string, if instance.PerformanceInsightsKMSKeyId != nil { // This is an ARN - if a, err = sources.ParseARN(*instance.PerformanceInsightsKMSKeyId); err == nil { + if a, err = adapters.ParseARN(*instance.PerformanceInsightsKMSKeyId); err == nil { // +overmind:link kms-key item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "kms-key", Method: sdp.QueryMethod_SEARCH, Query: *instance.PerformanceInsightsKMSKeyId, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changing the KMS key can affect the instance @@ -313,14 +313,14 @@ func dBInstanceOutputMapper(ctx context.Context, client rdsClient, scope string, for _, role := range instance.AssociatedRoles { if role.RoleArn != nil { - if a, err = sources.ParseARN(*role.RoleArn); err == nil { + if a, err = adapters.ParseARN(*role.RoleArn); err == nil { // +overmind:link iam-role item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "iam-role", Method: sdp.QueryMethod_SEARCH, Query: *role.RoleArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changing the role can affect the instance @@ -351,14 +351,14 @@ func dBInstanceOutputMapper(ctx context.Context, client rdsClient, scope string, } if instance.AwsBackupRecoveryPointArn != nil { - if a, err = sources.ParseARN(*instance.AwsBackupRecoveryPointArn); err == nil { + if a, err = adapters.ParseARN(*instance.AwsBackupRecoveryPointArn); err == nil { // +overmind:link backup-recovery-point item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "backup-recovery-point", Method: sdp.QueryMethod_SEARCH, Query: *instance.AwsBackupRecoveryPointArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Tightly coupled @@ -371,14 +371,14 @@ func dBInstanceOutputMapper(ctx context.Context, client rdsClient, scope string, if instance.CustomIamInstanceProfile != nil { // This is almost certainly an ARN since IAM basically always is - if a, err = sources.ParseARN(*instance.CustomIamInstanceProfile); err == nil { + if a, err = adapters.ParseARN(*instance.CustomIamInstanceProfile); err == nil { // +overmind:link iam-instance-profile item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "iam-instance-profile", Method: sdp.QueryMethod_SEARCH, Query: *instance.CustomIamInstanceProfile, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changing the instance profile can affect the instance @@ -392,14 +392,14 @@ func dBInstanceOutputMapper(ctx context.Context, client rdsClient, scope string, for _, replication := range instance.DBInstanceAutomatedBackupsReplications { if replication.DBInstanceAutomatedBackupsArn != nil { - if a, err = sources.ParseARN(*replication.DBInstanceAutomatedBackupsArn); err == nil { + if a, err = adapters.ParseARN(*replication.DBInstanceAutomatedBackupsArn); err == nil { // +overmind:link rds-db-instance-automated-backup item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "rds-db-instance-automated-backup", Method: sdp.QueryMethod_SEARCH, Query: *replication.DBInstanceAutomatedBackupsArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Tightly coupled @@ -468,14 +468,14 @@ func dBInstanceOutputMapper(ctx context.Context, client rdsClient, scope string, } if instance.MasterUserSecret.SecretArn != nil { - if a, err = sources.ParseARN(*instance.MasterUserSecret.SecretArn); err == nil { + if a, err = adapters.ParseARN(*instance.MasterUserSecret.SecretArn); err == nil { // +overmind:link secretsmanager-secret item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "secretsmanager-secret", Method: sdp.QueryMethod_SEARCH, Query: *instance.MasterUserSecret.SecretArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changing the secret can affect the instance @@ -504,13 +504,14 @@ func dBInstanceOutputMapper(ctx context.Context, client rdsClient, scope string, // +overmind:terraform:queryMap aws_db_instance.identifier // +overmind:terraform:queryMap aws_db_instance_role_association.db_instance_identifier -func NewDBInstanceSource(client rdsClient, accountID string, region string) *sources.DescribeOnlySource[*rds.DescribeDBInstancesInput, *rds.DescribeDBInstancesOutput, rdsClient, *rds.Options] { - return &sources.DescribeOnlySource[*rds.DescribeDBInstancesInput, *rds.DescribeDBInstancesOutput, rdsClient, *rds.Options]{ - ItemType: "rds-db-instance", - Region: region, - AccountID: accountID, - Client: client, - PaginatorBuilder: func(client rdsClient, params *rds.DescribeDBInstancesInput) sources.Paginator[*rds.DescribeDBInstancesOutput, *rds.Options] { +func NewDBInstanceAdapter(client rdsClient, accountID string, region string) *adapters.DescribeOnlyAdapter[*rds.DescribeDBInstancesInput, *rds.DescribeDBInstancesOutput, rdsClient, *rds.Options] { + return &adapters.DescribeOnlyAdapter[*rds.DescribeDBInstancesInput, *rds.DescribeDBInstancesOutput, rdsClient, *rds.Options]{ + ItemType: "rds-db-instance", + Region: region, + AccountID: accountID, + Client: client, + AdapterMetadata: DBInstanceMetadata(), + PaginatorBuilder: func(client rdsClient, params *rds.DescribeDBInstancesInput) adapters.Paginator[*rds.DescribeDBInstancesOutput, *rds.Options] { return rds.NewDescribeDBInstancesPaginator(client, params) }, DescribeFunc: func(ctx context.Context, client rdsClient, input *rds.DescribeDBInstancesInput) (*rds.DescribeDBInstancesOutput, error) { @@ -527,3 +528,24 @@ func NewDBInstanceSource(client rdsClient, accountID string, region string) *sou OutputMapper: dBInstanceOutputMapper, } } + +func DBInstanceMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "rds-db-instance", + DescriptiveName: "RDS Instance", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get an instance by ID", + ListDescription: "List all instances", + SearchDescription: "Search for instances by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_db_instance.identifier"}, + {TerraformQueryMap: "aws_db_instance_role_association.db_instance_identifier"}, + }, + PotentialLinks: []string{"dns", "route53-hosted-zone", "ec2-security-group", "rds-db-parameter-group", "rds-db-subnet-group", "rds-db-cluster", "kms-key", "logs-log-stream", "iam-role", "kinesis-stream", "backup-recovery-point", "iam-instance-profile", "rds-db-instance-automated-backup", "secretsmanager-secret"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_DATABASE, + } +} diff --git a/adapters/rds/db_instance_test.go b/adapters/rds/db_instance_test.go new file mode 100644 index 00000000..f9960584 --- /dev/null +++ b/adapters/rds/db_instance_test.go @@ -0,0 +1,323 @@ +package rds + +import ( + "context" + "testing" + "time" + + "github.com/aws/aws-sdk-go-v2/service/rds" + "github.com/aws/aws-sdk-go-v2/service/rds/types" + "github.com/overmindtech/aws-source/adapters" + "github.com/overmindtech/sdp-go" +) + +func TestDBInstanceOutputMapper(t *testing.T) { + output := &rds.DescribeDBInstancesOutput{ + DBInstances: []types.DBInstance{ + { + DBInstanceIdentifier: adapters.PtrString("database-1-instance-1"), + DBInstanceClass: adapters.PtrString("db.r6g.large"), + Engine: adapters.PtrString("aurora-mysql"), + DBInstanceStatus: adapters.PtrString("available"), + MasterUsername: adapters.PtrString("admin"), + Endpoint: &types.Endpoint{ + Address: adapters.PtrString("database-1-instance-1.camcztjohmlj.eu-west-2.rds.amazonaws.com"), // link + Port: adapters.PtrInt32(3306), // link + HostedZoneId: adapters.PtrString("Z1TTGA775OQIYO"), // link + }, + AllocatedStorage: adapters.PtrInt32(1), + InstanceCreateTime: adapters.PtrTime(time.Now()), + PreferredBackupWindow: adapters.PtrString("00:05-00:35"), + BackupRetentionPeriod: adapters.PtrInt32(1), + DBSecurityGroups: []types.DBSecurityGroupMembership{ + { + DBSecurityGroupName: adapters.PtrString("name"), // This is EC2Classic only so we're skipping this + }, + }, + VpcSecurityGroups: []types.VpcSecurityGroupMembership{ + { + VpcSecurityGroupId: adapters.PtrString("sg-094e151c9fc5da181"), // link + Status: adapters.PtrString("active"), + }, + }, + DBParameterGroups: []types.DBParameterGroupStatus{ + { + DBParameterGroupName: adapters.PtrString("default.aurora-mysql8.0"), // link + ParameterApplyStatus: adapters.PtrString("in-sync"), + }, + }, + AvailabilityZone: adapters.PtrString("eu-west-2a"), // link + DBSubnetGroup: &types.DBSubnetGroup{ + DBSubnetGroupName: adapters.PtrString("default-vpc-0d7892e00e573e701"), // link + DBSubnetGroupDescription: adapters.PtrString("Created from the RDS Management Console"), + VpcId: adapters.PtrString("vpc-0d7892e00e573e701"), // link + SubnetGroupStatus: adapters.PtrString("Complete"), + Subnets: []types.Subnet{ + { + SubnetIdentifier: adapters.PtrString("subnet-0d8ae4b4e07647efa"), // lnk + SubnetAvailabilityZone: &types.AvailabilityZone{ + Name: adapters.PtrString("eu-west-2b"), + }, + SubnetOutpost: &types.Outpost{ + Arn: adapters.PtrString("arn:aws:service:region:account:type/id"), // link + }, + SubnetStatus: adapters.PtrString("Active"), + }, + }, + }, + PreferredMaintenanceWindow: adapters.PtrString("fri:04:49-fri:05:19"), + PendingModifiedValues: &types.PendingModifiedValues{}, + MultiAZ: adapters.PtrBool(false), + EngineVersion: adapters.PtrString("8.0.mysql_aurora.3.02.0"), + AutoMinorVersionUpgrade: adapters.PtrBool(true), + ReadReplicaDBInstanceIdentifiers: []string{ + "read", + }, + LicenseModel: adapters.PtrString("general-public-license"), + OptionGroupMemberships: []types.OptionGroupMembership{ + { + OptionGroupName: adapters.PtrString("default:aurora-mysql-8-0"), + Status: adapters.PtrString("in-sync"), + }, + }, + PubliclyAccessible: adapters.PtrBool(false), + StorageType: adapters.PtrString("aurora"), + DbInstancePort: adapters.PtrInt32(0), + DBClusterIdentifier: adapters.PtrString("database-1"), // link + StorageEncrypted: adapters.PtrBool(true), + KmsKeyId: adapters.PtrString("arn:aws:kms:eu-west-2:052392120703:key/9653cbdd-1590-464a-8456-67389cef6933"), // link + DbiResourceId: adapters.PtrString("db-ET7CE5D5TQTK7MXNJGJNFQD52E"), + CACertificateIdentifier: adapters.PtrString("rds-ca-2019"), + DomainMemberships: []types.DomainMembership{ + { + Domain: adapters.PtrString("domain"), + FQDN: adapters.PtrString("fqdn"), + IAMRoleName: adapters.PtrString("role"), + Status: adapters.PtrString("enrolled"), + }, + }, + CopyTagsToSnapshot: adapters.PtrBool(false), + MonitoringInterval: adapters.PtrInt32(60), + EnhancedMonitoringResourceArn: adapters.PtrString("arn:aws:logs:eu-west-2:052392120703:log-group:RDSOSMetrics:log-stream:db-ET7CE5D5TQTK7MXNJGJNFQD52E"), // link + MonitoringRoleArn: adapters.PtrString("arn:aws:iam::052392120703:role/rds-monitoring-role"), // link + PromotionTier: adapters.PtrInt32(1), + DBInstanceArn: adapters.PtrString("arn:aws:rds:eu-west-2:052392120703:db:database-1-instance-1"), + IAMDatabaseAuthenticationEnabled: adapters.PtrBool(false), + PerformanceInsightsEnabled: adapters.PtrBool(true), + PerformanceInsightsKMSKeyId: adapters.PtrString("arn:aws:kms:eu-west-2:052392120703:key/9653cbdd-1590-464a-8456-67389cef6933"), // link + PerformanceInsightsRetentionPeriod: adapters.PtrInt32(7), + DeletionProtection: adapters.PtrBool(false), + AssociatedRoles: []types.DBInstanceRole{ + { + FeatureName: adapters.PtrString("something"), + RoleArn: adapters.PtrString("arn:aws:service:region:account:type/id"), // link + Status: adapters.PtrString("associated"), + }, + }, + TagList: []types.Tag{}, + CustomerOwnedIpEnabled: adapters.PtrBool(false), + BackupTarget: adapters.PtrString("region"), + NetworkType: adapters.PtrString("IPV4"), + StorageThroughput: adapters.PtrInt32(0), + ActivityStreamEngineNativeAuditFieldsIncluded: adapters.PtrBool(true), + ActivityStreamKinesisStreamName: adapters.PtrString("aws-rds-das-db-AB1CDEFG23GHIJK4LMNOPQRST"), // link + ActivityStreamKmsKeyId: adapters.PtrString("ab12345e-1111-2bc3-12a3-ab1cd12345e"), // Not linking at the moment because there are too many possible formats. If you want to change this, submit a PR + ActivityStreamMode: types.ActivityStreamModeAsync, + ActivityStreamPolicyStatus: types.ActivityStreamPolicyStatusLocked, + ActivityStreamStatus: types.ActivityStreamStatusStarted, + AutomaticRestartTime: adapters.PtrTime(time.Now()), + AutomationMode: types.AutomationModeAllPaused, + AwsBackupRecoveryPointArn: adapters.PtrString("arn:aws:service:region:account:type/id"), // link + CertificateDetails: &types.CertificateDetails{ + CAIdentifier: adapters.PtrString("id"), + ValidTill: adapters.PtrTime(time.Now()), + }, + CharacterSetName: adapters.PtrString("something"), + CustomIamInstanceProfile: adapters.PtrString("arn:aws:service:region:account:type/id"), // link? + DBInstanceAutomatedBackupsReplications: []types.DBInstanceAutomatedBackupsReplication{ + { + DBInstanceAutomatedBackupsArn: adapters.PtrString("arn:aws:service:region:account:type/id"), // link + }, + }, + DBName: adapters.PtrString("name"), + DBSystemId: adapters.PtrString("id"), + EnabledCloudwatchLogsExports: []string{}, + Iops: adapters.PtrInt32(10), + LatestRestorableTime: adapters.PtrTime(time.Now()), + ListenerEndpoint: &types.Endpoint{ + Address: adapters.PtrString("foo.bar.com"), // link + HostedZoneId: adapters.PtrString("id"), // link + Port: adapters.PtrInt32(5432), // link + }, + MasterUserSecret: &types.MasterUserSecret{ + KmsKeyId: adapters.PtrString("id"), // link + SecretArn: adapters.PtrString("arn:aws:service:region:account:type/id"), // link + SecretStatus: adapters.PtrString("okay"), + }, + MaxAllocatedStorage: adapters.PtrInt32(10), + NcharCharacterSetName: adapters.PtrString("english"), + ProcessorFeatures: []types.ProcessorFeature{}, + ReadReplicaDBClusterIdentifiers: []string{}, + ReadReplicaSourceDBInstanceIdentifier: adapters.PtrString("id"), + ReplicaMode: types.ReplicaModeMounted, + ResumeFullAutomationModeTime: adapters.PtrTime(time.Now()), + SecondaryAvailabilityZone: adapters.PtrString("eu-west-1"), // link + StatusInfos: []types.DBInstanceStatusInfo{}, + TdeCredentialArn: adapters.PtrString("arn:aws:service:region:account:type/id"), // I don't have a good example for this so skipping for now. PR if required + Timezone: adapters.PtrString("GB"), + }, + }, + } + + items, err := dBInstanceOutputMapper(context.Background(), mockRdsClient{}, "foo", nil, output) + + if err != nil { + t.Fatal(err) + } + + if len(items) != 1 { + t.Fatalf("got %v items, expected 1", len(items)) + } + + item := items[0] + + if err = item.Validate(); err != nil { + t.Error(err) + } + + if item.GetTags()["key"] != "value" { + t.Errorf("got %v, expected %v", item.GetTags()["key"], "value") + } + + tests := adapters.QueryTests{ + { + ExpectedType: "dns", + ExpectedMethod: sdp.QueryMethod_SEARCH, + ExpectedQuery: "database-1-instance-1.camcztjohmlj.eu-west-2.rds.amazonaws.com", + ExpectedScope: "global", + }, + { + ExpectedType: "route53-hosted-zone", + ExpectedMethod: sdp.QueryMethod_GET, + ExpectedQuery: "Z1TTGA775OQIYO", + ExpectedScope: "foo", + }, + { + ExpectedType: "ec2-security-group", + ExpectedMethod: sdp.QueryMethod_GET, + ExpectedQuery: "sg-094e151c9fc5da181", + ExpectedScope: "foo", + }, + { + ExpectedType: "rds-db-parameter-group", + ExpectedMethod: sdp.QueryMethod_GET, + ExpectedQuery: "default.aurora-mysql8.0", + ExpectedScope: "foo", + }, + { + ExpectedType: "rds-db-subnet-group", + ExpectedMethod: sdp.QueryMethod_GET, + ExpectedQuery: "default-vpc-0d7892e00e573e701", + ExpectedScope: "foo", + }, + { + ExpectedType: "rds-db-cluster", + ExpectedMethod: sdp.QueryMethod_GET, + ExpectedQuery: "database-1", + ExpectedScope: "foo", + }, + { + ExpectedType: "kms-key", + ExpectedMethod: sdp.QueryMethod_SEARCH, + ExpectedQuery: "arn:aws:kms:eu-west-2:052392120703:key/9653cbdd-1590-464a-8456-67389cef6933", + ExpectedScope: "052392120703.eu-west-2", + }, + { + ExpectedType: "logs-log-stream", + ExpectedMethod: sdp.QueryMethod_SEARCH, + ExpectedQuery: "arn:aws:logs:eu-west-2:052392120703:log-group:RDSOSMetrics:log-stream:db-ET7CE5D5TQTK7MXNJGJNFQD52E", + ExpectedScope: "052392120703.eu-west-2", + }, + { + ExpectedType: "iam-role", + ExpectedMethod: sdp.QueryMethod_SEARCH, + ExpectedQuery: "arn:aws:iam::052392120703:role/rds-monitoring-role", + ExpectedScope: "052392120703", + }, + { + ExpectedType: "kms-key", + ExpectedMethod: sdp.QueryMethod_SEARCH, + ExpectedQuery: "arn:aws:kms:eu-west-2:052392120703:key/9653cbdd-1590-464a-8456-67389cef6933", + ExpectedScope: "052392120703.eu-west-2", + }, + { + ExpectedType: "iam-role", + ExpectedMethod: sdp.QueryMethod_SEARCH, + ExpectedQuery: "arn:aws:service:region:account:type/id", + ExpectedScope: "account.region", + }, + { + ExpectedType: "kinesis-stream", + ExpectedMethod: sdp.QueryMethod_GET, + ExpectedQuery: "aws-rds-das-db-AB1CDEFG23GHIJK4LMNOPQRST", + ExpectedScope: "foo", + }, + { + ExpectedType: "backup-recovery-point", + ExpectedMethod: sdp.QueryMethod_SEARCH, + ExpectedQuery: "arn:aws:service:region:account:type/id", + ExpectedScope: "account.region", + }, + { + ExpectedType: "iam-instance-profile", + ExpectedMethod: sdp.QueryMethod_SEARCH, + ExpectedQuery: "arn:aws:service:region:account:type/id", + ExpectedScope: "account.region", + }, + { + ExpectedType: "rds-db-instance-automated-backup", + ExpectedMethod: sdp.QueryMethod_SEARCH, + ExpectedQuery: "arn:aws:service:region:account:type/id", + ExpectedScope: "account.region", + }, + { + ExpectedType: "dns", + ExpectedMethod: sdp.QueryMethod_SEARCH, + ExpectedQuery: "foo.bar.com", + ExpectedScope: "global", + }, + { + ExpectedType: "route53-hosted-zone", + ExpectedMethod: sdp.QueryMethod_GET, + ExpectedQuery: "id", + ExpectedScope: "foo", + }, + { + ExpectedType: "kms-key", + ExpectedMethod: sdp.QueryMethod_GET, + ExpectedQuery: "id", + ExpectedScope: "foo", + }, + { + ExpectedType: "secretsmanager-secret", + ExpectedMethod: sdp.QueryMethod_SEARCH, + ExpectedQuery: "arn:aws:service:region:account:type/id", + ExpectedScope: "account.region", + }, + } + + tests.Execute(t, item) +} + +func TestNewDBInstanceAdapter(t *testing.T) { + client, account, region := GetAutoConfig(t) + + adapter := NewDBInstanceAdapter(client, account, region) + + test := adapters.E2ETest{ + Adapter: adapter, + Timeout: 10 * time.Second, + } + + test.Run(t) +} diff --git a/sources/rds/db_parameter_group.go b/adapters/rds/db_parameter_group.go similarity index 69% rename from sources/rds/db_parameter_group.go rename to adapters/rds/db_parameter_group.go index b30f448d..5e5b2efd 100644 --- a/sources/rds/db_parameter_group.go +++ b/adapters/rds/db_parameter_group.go @@ -6,7 +6,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/rds" "github.com/aws/aws-sdk-go-v2/service/rds/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -17,7 +17,7 @@ type ParameterGroup struct { } func dBParameterGroupItemMapper(_, scope string, awsItem *ParameterGroup) (*sdp.Item, error) { - attributes, err := sources.ToAttributesWithExclude(awsItem) + attributes, err := adapters.ToAttributesWithExclude(awsItem) if err != nil { return nil, err @@ -43,17 +43,17 @@ func dBParameterGroupItemMapper(_, scope string, awsItem *ParameterGroup) (*sdp. // +overmind:terraform:queryMap aws_db_parameter_group.arn // +overmind:terraform:method SEARCH -func NewDBParameterGroupSource(client rdsClient, accountID string, region string) *sources.GetListSource[*ParameterGroup, rdsClient, *rds.Options] { - return &sources.GetListSource[*ParameterGroup, rdsClient, *rds.Options]{ - ItemType: "rds-db-parameter-group", - Client: client, - AccountID: accountID, - Region: region, +func NewDBParameterGroupAdapter(client rdsClient, accountID string, region string) *adapters.GetListAdapter[*ParameterGroup, rdsClient, *rds.Options] { + return &adapters.GetListAdapter[*ParameterGroup, rdsClient, *rds.Options]{ + ItemType: "rds-db-parameter-group", + Client: client, + AccountID: accountID, + Region: region, + AdapterMetadata: DBParameterGroupMetadata(), GetFunc: func(ctx context.Context, client rdsClient, scope, query string) (*ParameterGroup, error) { out, err := client.DescribeDBParameterGroups(ctx, &rds.DescribeDBParameterGroupsInput{ DBParameterGroupName: &query, }) - if err != nil { return nil, err } @@ -65,7 +65,6 @@ func NewDBParameterGroupSource(client rdsClient, accountID string, region string paramsOut, err := client.DescribeDBParameters(ctx, &rds.DescribeDBParametersInput{ DBParameterGroupName: out.DBParameterGroups[0].DBParameterGroupName, }) - if err != nil { return nil, err } @@ -77,7 +76,6 @@ func NewDBParameterGroupSource(client rdsClient, accountID string, region string }, ListFunc: func(ctx context.Context, client rdsClient, scope string) ([]*ParameterGroup, error) { out, err := client.DescribeDBParameterGroups(ctx, &rds.DescribeDBParameterGroupsInput{}) - if err != nil { return nil, err } @@ -88,7 +86,6 @@ func NewDBParameterGroupSource(client rdsClient, accountID string, region string paramsOut, err := client.DescribeDBParameters(ctx, &rds.DescribeDBParametersInput{ DBParameterGroupName: group.DBParameterGroupName, }) - if err != nil { return nil, err } @@ -105,7 +102,6 @@ func NewDBParameterGroupSource(client rdsClient, accountID string, region string out, err := c.ListTagsForResource(ctx, &rds.ListTagsForResourceInput{ ResourceName: pg.DBParameterGroupArn, }) - if err != nil { return nil, err } @@ -115,3 +111,25 @@ func NewDBParameterGroupSource(client rdsClient, accountID string, region string ItemMapper: dBParameterGroupItemMapper, } } + +func DBParameterGroupMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "rds-db-parameter-group", + DescriptiveName: "RDS Parameter Group", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a parameter group by name", + ListDescription: "List all parameter groups", + SearchDescription: "Search for a parameter group by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + { + TerraformMethod: sdp.QueryMethod_SEARCH, + TerraformQueryMap: "aws_db_parameter_group.arn", + }, + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_DATABASE, + } +} diff --git a/adapters/rds/db_parameter_group_test.go b/adapters/rds/db_parameter_group_test.go new file mode 100644 index 00000000..1df60430 --- /dev/null +++ b/adapters/rds/db_parameter_group_test.go @@ -0,0 +1,86 @@ +package rds + +import ( + "testing" + "time" + + "github.com/aws/aws-sdk-go-v2/service/rds/types" + "github.com/overmindtech/aws-source/adapters" +) + +func TestDBParameterGroupOutputMapper(t *testing.T) { + group := ParameterGroup{ + DBParameterGroup: types.DBParameterGroup{ + DBParameterGroupName: adapters.PtrString("default.aurora-mysql5.7"), + DBParameterGroupFamily: adapters.PtrString("aurora-mysql5.7"), + Description: adapters.PtrString("Default parameter group for aurora-mysql5.7"), + DBParameterGroupArn: adapters.PtrString("arn:aws:rds:eu-west-1:052392120703:pg:default.aurora-mysql5.7"), + }, + Parameters: []types.Parameter{ + { + ParameterName: adapters.PtrString("activate_all_roles_on_login"), + ParameterValue: adapters.PtrString("0"), + Description: adapters.PtrString("Automatically set all granted roles as active after the user has authenticated successfully."), + Source: adapters.PtrString("engine-default"), + ApplyType: adapters.PtrString("dynamic"), + DataType: adapters.PtrString("boolean"), + AllowedValues: adapters.PtrString("0,1"), + IsModifiable: adapters.PtrBool(true), + ApplyMethod: types.ApplyMethodPendingReboot, + }, + { + ParameterName: adapters.PtrString("allow-suspicious-udfs"), + Description: adapters.PtrString("Controls whether user-defined functions that have only an xxx symbol for the main function can be loaded"), + Source: adapters.PtrString("engine-default"), + ApplyType: adapters.PtrString("static"), + DataType: adapters.PtrString("boolean"), + AllowedValues: adapters.PtrString("0,1"), + IsModifiable: adapters.PtrBool(false), + ApplyMethod: types.ApplyMethodPendingReboot, + }, + { + ParameterName: adapters.PtrString("aurora_parallel_query"), + Description: adapters.PtrString("This parameter can be used to enable and disable Aurora Parallel Query."), + Source: adapters.PtrString("engine-default"), + ApplyType: adapters.PtrString("dynamic"), + DataType: adapters.PtrString("boolean"), + AllowedValues: adapters.PtrString("0,1"), + IsModifiable: adapters.PtrBool(true), + ApplyMethod: types.ApplyMethodPendingReboot, + }, + { + ParameterName: adapters.PtrString("autocommit"), + Description: adapters.PtrString("Sets the autocommit mode"), + Source: adapters.PtrString("engine-default"), + ApplyType: adapters.PtrString("dynamic"), + DataType: adapters.PtrString("boolean"), + AllowedValues: adapters.PtrString("0,1"), + IsModifiable: adapters.PtrBool(true), + ApplyMethod: types.ApplyMethodPendingReboot, + }, + }, + } + + item, err := dBParameterGroupItemMapper("", "foo", &group) + + if err != nil { + t.Fatal(err) + } + + if err = item.Validate(); err != nil { + t.Error(err) + } +} + +func TestNewDBParameterGroupAdapter(t *testing.T) { + client, account, region := GetAutoConfig(t) + + adapter := NewDBParameterGroupAdapter(client, account, region) + + test := adapters.E2ETest{ + Adapter: adapter, + Timeout: 10 * time.Second, + } + + test.Run(t) +} diff --git a/sources/rds/db_subnet_group.go b/adapters/rds/db_subnet_group.go similarity index 68% rename from sources/rds/db_subnet_group.go rename to adapters/rds/db_subnet_group.go index dea0d24d..46324cd6 100644 --- a/sources/rds/db_subnet_group.go +++ b/adapters/rds/db_subnet_group.go @@ -4,7 +4,7 @@ import ( "context" "github.com/aws/aws-sdk-go-v2/service/rds" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -22,10 +22,10 @@ func dBSubnetGroupOutputMapper(ctx context.Context, client rdsClient, scope stri if err == nil { tags = tagsToMap(tagsOut.TagList) } else { - tags = sources.HandleTagsError(ctx, err) + tags = adapters.HandleTagsError(ctx, err) } - attributes, err := sources.ToAttributesWithExclude(sg) + attributes, err := adapters.ToAttributesWithExclude(sg) if err != nil { return nil, err @@ -39,7 +39,7 @@ func dBSubnetGroupOutputMapper(ctx context.Context, client rdsClient, scope stri Tags: tags, } - var a *sources.ARN + var a *adapters.ARN if sg.VpcId != nil { // +overmind:link ec2-vpc @@ -80,14 +80,14 @@ func dBSubnetGroupOutputMapper(ctx context.Context, client rdsClient, scope stri if subnet.SubnetOutpost != nil { if subnet.SubnetOutpost.Arn != nil { - if a, err = sources.ParseARN(*subnet.SubnetOutpost.Arn); err == nil { + if a, err = adapters.ParseARN(*subnet.SubnetOutpost.Arn); err == nil { // +overmind:link outposts-outpost item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "outposts-outpost", Method: sdp.QueryMethod_SEARCH, Query: *subnet.SubnetOutpost.Arn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Changing the outpost can affect the subnet group @@ -117,13 +117,14 @@ func dBSubnetGroupOutputMapper(ctx context.Context, client rdsClient, scope stri // +overmind:terraform:queryMap aws_db_subnet_group.arn // +overmind:terraform:method SEARCH -func NewDBSubnetGroupSource(client rdsClient, accountID string, region string) *sources.DescribeOnlySource[*rds.DescribeDBSubnetGroupsInput, *rds.DescribeDBSubnetGroupsOutput, rdsClient, *rds.Options] { - return &sources.DescribeOnlySource[*rds.DescribeDBSubnetGroupsInput, *rds.DescribeDBSubnetGroupsOutput, rdsClient, *rds.Options]{ - ItemType: "rds-db-subnet-group", - Region: region, - AccountID: accountID, - Client: client, - PaginatorBuilder: func(client rdsClient, params *rds.DescribeDBSubnetGroupsInput) sources.Paginator[*rds.DescribeDBSubnetGroupsOutput, *rds.Options] { +func NewDBSubnetGroupAdapter(client rdsClient, accountID string, region string) *adapters.DescribeOnlyAdapter[*rds.DescribeDBSubnetGroupsInput, *rds.DescribeDBSubnetGroupsOutput, rdsClient, *rds.Options] { + return &adapters.DescribeOnlyAdapter[*rds.DescribeDBSubnetGroupsInput, *rds.DescribeDBSubnetGroupsOutput, rdsClient, *rds.Options]{ + ItemType: "rds-db-subnet-group", + Region: region, + AccountID: accountID, + Client: client, + AdapterMetadata: DBSubnetGroupMetadata(), + PaginatorBuilder: func(client rdsClient, params *rds.DescribeDBSubnetGroupsInput) adapters.Paginator[*rds.DescribeDBSubnetGroupsOutput, *rds.Options] { return rds.NewDescribeDBSubnetGroupsPaginator(client, params) }, DescribeFunc: func(ctx context.Context, client rdsClient, input *rds.DescribeDBSubnetGroupsInput) (*rds.DescribeDBSubnetGroupsOutput, error) { @@ -140,3 +141,26 @@ func NewDBSubnetGroupSource(client rdsClient, accountID string, region string) * OutputMapper: dBSubnetGroupOutputMapper, } } + +func DBSubnetGroupMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "rds-db-subnet-group", + DescriptiveName: "RDS Subnet Group", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a subnet group by name", + ListDescription: "List all subnet groups", + SearchDescription: "Search for subnet groups by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + { + TerraformQueryMap: "aws_db_subnet_group.arn", + TerraformMethod: sdp.QueryMethod_SEARCH, + }, + }, + PotentialLinks: []string{"ec2-vpc", "ec2-subnet", "outposts-outpost"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + } +} diff --git a/sources/rds/db_subnet_group_test.go b/adapters/rds/db_subnet_group_test.go similarity index 62% rename from sources/rds/db_subnet_group_test.go rename to adapters/rds/db_subnet_group_test.go index 32580799..ed78db88 100644 --- a/sources/rds/db_subnet_group_test.go +++ b/adapters/rds/db_subnet_group_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/rds" "github.com/aws/aws-sdk-go-v2/service/rds/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -15,23 +15,23 @@ func TestDBSubnetGroupOutputMapper(t *testing.T) { output := rds.DescribeDBSubnetGroupsOutput{ DBSubnetGroups: []types.DBSubnetGroup{ { - DBSubnetGroupName: sources.PtrString("default-vpc-0d7892e00e573e701"), - DBSubnetGroupDescription: sources.PtrString("Created from the RDS Management Console"), - VpcId: sources.PtrString("vpc-0d7892e00e573e701"), // link - SubnetGroupStatus: sources.PtrString("Complete"), + DBSubnetGroupName: adapters.PtrString("default-vpc-0d7892e00e573e701"), + DBSubnetGroupDescription: adapters.PtrString("Created from the RDS Management Console"), + VpcId: adapters.PtrString("vpc-0d7892e00e573e701"), // link + SubnetGroupStatus: adapters.PtrString("Complete"), Subnets: []types.Subnet{ { - SubnetIdentifier: sources.PtrString("subnet-0450a637af9984235"), // link + SubnetIdentifier: adapters.PtrString("subnet-0450a637af9984235"), // link SubnetAvailabilityZone: &types.AvailabilityZone{ - Name: sources.PtrString("eu-west-2c"), // link + Name: adapters.PtrString("eu-west-2c"), // link }, SubnetOutpost: &types.Outpost{ - Arn: sources.PtrString("arn:aws:service:region:account:type/id"), // link + Arn: adapters.PtrString("arn:aws:service:region:account:type/id"), // link }, - SubnetStatus: sources.PtrString("Active"), + SubnetStatus: adapters.PtrString("Active"), }, }, - DBSubnetGroupArn: sources.PtrString("arn:aws:rds:eu-west-2:052392120703:subgrp:default-vpc-0d7892e00e573e701"), + DBSubnetGroupArn: adapters.PtrString("arn:aws:rds:eu-west-2:052392120703:subgrp:default-vpc-0d7892e00e573e701"), SupportedNetworkTypes: []string{ "IPV4", }, @@ -59,7 +59,7 @@ func TestDBSubnetGroupOutputMapper(t *testing.T) { t.Errorf("expected key to be value, got %v", item.GetTags()["key"]) } - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "ec2-vpc", ExpectedMethod: sdp.QueryMethod_GET, @@ -83,13 +83,13 @@ func TestDBSubnetGroupOutputMapper(t *testing.T) { tests.Execute(t, item) } -func TestNewDBSubnetGroupSource(t *testing.T) { +func TestNewDBSubnetGroupAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewDBSubnetGroupSource(client, account, region) + adapter := NewDBSubnetGroupAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/rds/option_group.go b/adapters/rds/option_group.go similarity index 57% rename from sources/rds/option_group.go rename to adapters/rds/option_group.go index 26424470..a9ea06d6 100644 --- a/sources/rds/option_group.go +++ b/adapters/rds/option_group.go @@ -4,7 +4,7 @@ import ( "context" "github.com/aws/aws-sdk-go-v2/service/rds" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -22,10 +22,10 @@ func optionGroupOutputMapper(ctx context.Context, client rdsClient, scope string if err == nil { tags = tagsToMap(tagsOut.TagList) } else { - tags = sources.HandleTagsError(ctx, err) + tags = adapters.HandleTagsError(ctx, err) } - attributes, err := sources.ToAttributesWithExclude(group) + attributes, err := adapters.ToAttributesWithExclude(group) if err != nil { return nil, err @@ -55,13 +55,14 @@ func optionGroupOutputMapper(ctx context.Context, client rdsClient, scope string // +overmind:terraform:queryMap aws_db_option_group.arn // +overmind:terraform:method SEARCH -func NewOptionGroupSource(client rdsClient, accountID string, region string) *sources.DescribeOnlySource[*rds.DescribeOptionGroupsInput, *rds.DescribeOptionGroupsOutput, rdsClient, *rds.Options] { - return &sources.DescribeOnlySource[*rds.DescribeOptionGroupsInput, *rds.DescribeOptionGroupsOutput, rdsClient, *rds.Options]{ - ItemType: "rds-option-group", - Region: region, - AccountID: accountID, - Client: client, - PaginatorBuilder: func(client rdsClient, params *rds.DescribeOptionGroupsInput) sources.Paginator[*rds.DescribeOptionGroupsOutput, *rds.Options] { +func NewOptionGroupAdapter(client rdsClient, accountID string, region string) *adapters.DescribeOnlyAdapter[*rds.DescribeOptionGroupsInput, *rds.DescribeOptionGroupsOutput, rdsClient, *rds.Options] { + return &adapters.DescribeOnlyAdapter[*rds.DescribeOptionGroupsInput, *rds.DescribeOptionGroupsOutput, rdsClient, *rds.Options]{ + ItemType: "rds-option-group", + Region: region, + AccountID: accountID, + Client: client, + AdapterMetadata: OptionGroupMetadata(), + PaginatorBuilder: func(client rdsClient, params *rds.DescribeOptionGroupsInput) adapters.Paginator[*rds.DescribeOptionGroupsOutput, *rds.Options] { return rds.NewDescribeOptionGroupsPaginator(client, params) }, DescribeFunc: func(ctx context.Context, client rdsClient, input *rds.DescribeOptionGroupsInput) (*rds.DescribeOptionGroupsOutput, error) { @@ -78,3 +79,25 @@ func NewOptionGroupSource(client rdsClient, accountID string, region string) *so OutputMapper: optionGroupOutputMapper, } } + +func OptionGroupMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "rds-option-group", + DescriptiveName: "RDS Option Group", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get an option group by name", + ListDescription: "List all RDS option groups", + SearchDescription: "Search for an option group by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + { + TerraformQueryMap: "aws_db_option_group.arn", + TerraformMethod: sdp.QueryMethod_SEARCH, + }, + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_DATABASE, + } +} diff --git a/sources/rds/option_group_test.go b/adapters/rds/option_group_test.go similarity index 56% rename from sources/rds/option_group_test.go rename to adapters/rds/option_group_test.go index ceda8b0d..98e87d94 100644 --- a/sources/rds/option_group_test.go +++ b/adapters/rds/option_group_test.go @@ -6,20 +6,20 @@ import ( "github.com/aws/aws-sdk-go-v2/service/rds" "github.com/aws/aws-sdk-go-v2/service/rds/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" ) func TestOptionGroupOutputMapper(t *testing.T) { output := rds.DescribeOptionGroupsOutput{ OptionGroupsList: []types.OptionGroup{ { - OptionGroupName: sources.PtrString("default:aurora-mysql-8-0"), - OptionGroupDescription: sources.PtrString("Default option group for aurora-mysql 8.0"), - EngineName: sources.PtrString("aurora-mysql"), - MajorEngineVersion: sources.PtrString("8.0"), + OptionGroupName: adapters.PtrString("default:aurora-mysql-8-0"), + OptionGroupDescription: adapters.PtrString("Default option group for aurora-mysql 8.0"), + EngineName: adapters.PtrString("aurora-mysql"), + MajorEngineVersion: adapters.PtrString("8.0"), Options: []types.Option{}, - AllowsVpcAndNonVpcInstanceMemberships: sources.PtrBool(true), - OptionGroupArn: sources.PtrString("arn:aws:rds:eu-west-2:052392120703:og:default:aurora-mysql-8-0"), + AllowsVpcAndNonVpcInstanceMemberships: adapters.PtrBool(true), + OptionGroupArn: adapters.PtrString("arn:aws:rds:eu-west-2:052392120703:og:default:aurora-mysql-8-0"), }, }, } diff --git a/sources/rds/shared.go b/adapters/rds/shared.go similarity index 96% rename from sources/rds/shared.go rename to adapters/rds/shared.go index 6ca94aac..9e4e95ab 100644 --- a/sources/rds/shared.go +++ b/adapters/rds/shared.go @@ -5,7 +5,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/rds" "github.com/aws/aws-sdk-go-v2/service/rds/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" ) type rdsClient interface { @@ -34,8 +34,8 @@ func (m mockRdsClient) ListTagsForResource(ctx context.Context, params *rds.List return &rds.ListTagsForResourceOutput{ TagList: []types.Tag{ { - Key: sources.PtrString("key"), - Value: sources.PtrString("value"), + Key: adapters.PtrString("key"), + Value: adapters.PtrString("value"), }, }, }, nil diff --git a/sources/rds/shared_test.go b/adapters/rds/shared_test.go similarity index 68% rename from sources/rds/shared_test.go rename to adapters/rds/shared_test.go index 390ec1c0..4b2ee213 100644 --- a/sources/rds/shared_test.go +++ b/adapters/rds/shared_test.go @@ -4,11 +4,11 @@ import ( "testing" "github.com/aws/aws-sdk-go-v2/service/rds" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" ) func GetAutoConfig(t *testing.T) (*rds.Client, string, string) { - config, account, region := sources.GetAutoConfig(t) + config, account, region := adapters.GetAutoConfig(t) client := rds.NewFromConfig(config) return client, account, region diff --git a/sources/route53/health_check.go b/adapters/route53/health_check.go similarity index 73% rename from sources/route53/health_check.go rename to adapters/route53/health_check.go index 7ac55357..3f003fe5 100644 --- a/sources/route53/health_check.go +++ b/adapters/route53/health_check.go @@ -9,8 +9,8 @@ import ( cwtypes "github.com/aws/aws-sdk-go-v2/service/cloudwatch/types" "github.com/aws/aws-sdk-go-v2/service/route53" "github.com/aws/aws-sdk-go-v2/service/route53/types" - "github.com/overmindtech/aws-source/sources" - cw "github.com/overmindtech/aws-source/sources/cloudwatch" + "github.com/overmindtech/aws-source/adapters" + cw "github.com/overmindtech/aws-source/adapters/cloudwatch" "github.com/overmindtech/sdp-go" ) @@ -70,7 +70,7 @@ func healthCheckListFunc(ctx context.Context, client *route53.Client, scope stri } func healthCheckItemMapper(_, scope string, awsItem *HealthCheck) (*sdp.Item, error) { - attributes, err := sources.ToAttributesWithExclude(awsItem) + attributes, err := adapters.ToAttributesWithExclude(awsItem) if err != nil { return nil, err @@ -140,15 +140,16 @@ func healthCheckItemMapper(_, scope string, awsItem *HealthCheck) (*sdp.Item, er // +overmind:group AWS // +overmind:terraform:queryMap aws_route53_health_check.id -func NewHealthCheckSource(client *route53.Client, accountID string, region string) *sources.GetListSource[*HealthCheck, *route53.Client, *route53.Options] { - return &sources.GetListSource[*HealthCheck, *route53.Client, *route53.Options]{ - ItemType: "route53-health-check", - Client: client, - AccountID: accountID, - Region: region, - GetFunc: healthCheckGetFunc, - ListFunc: healthCheckListFunc, - ItemMapper: healthCheckItemMapper, +func NewHealthCheckAdapter(client *route53.Client, accountID string, region string) *adapters.GetListAdapter[*HealthCheck, *route53.Client, *route53.Options] { + return &adapters.GetListAdapter[*HealthCheck, *route53.Client, *route53.Options]{ + ItemType: "route53-health-check", + Client: client, + AccountID: accountID, + Region: region, + GetFunc: healthCheckGetFunc, + ListFunc: healthCheckListFunc, + ItemMapper: healthCheckItemMapper, + AdapterMetadata: HealthCheckMetadata(), ListTagsFunc: func(ctx context.Context, hc *HealthCheck, c *route53.Client) (map[string]string, error) { if hc.Id == nil { return nil, nil @@ -170,3 +171,23 @@ func NewHealthCheckSource(client *route53.Client, accountID string, region strin }, } } + +func HealthCheckMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "route53-health-check", + DescriptiveName: "Route53 Health Check", + PotentialLinks: []string{"cloudwatch-alarm"}, + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get health check by ID", + ListDescription: "List all health checks", + SearchDescription: "Search for health checks by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_route53_health_check.id"}, + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_OBSERVABILITY, + } +} diff --git a/adapters/route53/health_check_test.go b/adapters/route53/health_check_test.go new file mode 100644 index 00000000..0407a92d --- /dev/null +++ b/adapters/route53/health_check_test.go @@ -0,0 +1,84 @@ +package route53 + +import ( + "testing" + "time" + + "github.com/aws/aws-sdk-go-v2/service/route53/types" + "github.com/overmindtech/aws-source/adapters" + "github.com/overmindtech/sdp-go" +) + +func TestHealthCheckItemMapper(t *testing.T) { + hc := HealthCheck{ + HealthCheck: types.HealthCheck{ + Id: adapters.PtrString("d7ce5d72-6d1f-4147-8246-d0ca3fb505d6"), + CallerReference: adapters.PtrString("85d56b3f-873c-498b-a2dd-554ec13c5289"), + HealthCheckConfig: &types.HealthCheckConfig{ + IPAddress: adapters.PtrString("1.1.1.1"), + Port: adapters.PtrInt32(443), + Type: types.HealthCheckTypeHttps, + FullyQualifiedDomainName: adapters.PtrString("one.one.one.one"), + RequestInterval: adapters.PtrInt32(30), + FailureThreshold: adapters.PtrInt32(3), + MeasureLatency: adapters.PtrBool(false), + Inverted: adapters.PtrBool(false), + Disabled: adapters.PtrBool(false), + EnableSNI: adapters.PtrBool(true), + }, + HealthCheckVersion: adapters.PtrInt64(1), + }, + HealthCheckObservations: []types.HealthCheckObservation{ + { + Region: types.HealthCheckRegionApNortheast1, + IPAddress: adapters.PtrString("15.177.62.21"), + StatusReport: &types.StatusReport{ + Status: adapters.PtrString("Success: HTTP Status Code 200, OK"), + CheckedTime: adapters.PtrTime(time.Now()), + }, + }, + { + Region: types.HealthCheckRegionEuWest1, + IPAddress: adapters.PtrString("15.177.10.21"), + StatusReport: &types.StatusReport{ + Status: adapters.PtrString("Failure: Connection timed out. The endpoint or the internet connection is down, or requests are being blocked by your firewall. See https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/dns-failover-router-firewall-rules.html"), + CheckedTime: adapters.PtrTime(time.Now()), + }, + }, + }, + } + + item, err := healthCheckItemMapper("", "foo", &hc) + + if err != nil { + t.Error(err) + } + + if err = item.Validate(); err != nil { + t.Error(err) + } + + tests := adapters.QueryTests{ + { + ExpectedType: "cloudwatch-alarm", + ExpectedMethod: sdp.QueryMethod_SEARCH, + ExpectedQuery: "{\"MetricName\":\"HealthCheckStatus\",\"Namespace\":\"AWS/Route53\",\"Dimensions\":[{\"Name\":\"HealthCheckId\",\"Value\":\"d7ce5d72-6d1f-4147-8246-d0ca3fb505d6\"}],\"ExtendedStatistic\":null,\"Period\":null,\"Statistic\":\"\",\"Unit\":\"\"}", + ExpectedScope: "foo", + }, + } + + tests.Execute(t, item) +} + +func TestNewHealthCheckAdapter(t *testing.T) { + client, account, region := GetAutoConfig(t) + + adapter := NewHealthCheckAdapter(client, account, region) + + test := adapters.E2ETest{ + Adapter: adapter, + Timeout: 10 * time.Second, + } + + test.Run(t) +} diff --git a/sources/route53/hosted_zone.go b/adapters/route53/hosted_zone.go similarity index 64% rename from sources/route53/hosted_zone.go rename to adapters/route53/hosted_zone.go index fb60f504..24848b5c 100644 --- a/sources/route53/hosted_zone.go +++ b/adapters/route53/hosted_zone.go @@ -6,7 +6,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/route53" "github.com/aws/aws-sdk-go-v2/service/route53/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -39,7 +39,7 @@ func hostedZoneListFunc(ctx context.Context, client *route53.Client, scope strin } func hostedZoneItemMapper(_, scope string, awsItem *types.HostedZone) (*sdp.Item, error) { - attributes, err := sources.ToAttributesWithExclude(awsItem) + attributes, err := adapters.ToAttributesWithExclude(awsItem) if err != nil { return nil, err @@ -83,15 +83,16 @@ func hostedZoneItemMapper(_, scope string, awsItem *types.HostedZone) (*sdp.Item // +overmind:terraform:queryMap aws_route53_zone.zone_id // +overmind:terraform:queryMap aws_route53_zone_association.zone_id -func NewHostedZoneSource(client *route53.Client, accountID string, region string) *sources.GetListSource[*types.HostedZone, *route53.Client, *route53.Options] { - return &sources.GetListSource[*types.HostedZone, *route53.Client, *route53.Options]{ - ItemType: "route53-hosted-zone", - Client: client, - AccountID: accountID, - Region: region, - GetFunc: hostedZoneGetFunc, - ListFunc: hostedZoneListFunc, - ItemMapper: hostedZoneItemMapper, +func NewHostedZoneAdapter(client *route53.Client, accountID string, region string) *adapters.GetListAdapter[*types.HostedZone, *route53.Client, *route53.Options] { + return &adapters.GetListAdapter[*types.HostedZone, *route53.Client, *route53.Options]{ + ItemType: "route53-hosted-zone", + Client: client, + AccountID: accountID, + Region: region, + GetFunc: hostedZoneGetFunc, + ListFunc: hostedZoneListFunc, + ItemMapper: hostedZoneItemMapper, + AdapterMetadata: HostedZoneMetadata(), ListTagsFunc: func(ctx context.Context, hz *types.HostedZone, c *route53.Client) (map[string]string, error) { if hz.Id == nil { return nil, nil @@ -113,3 +114,25 @@ func NewHostedZoneSource(client *route53.Client, accountID string, region string }, } } + +func HostedZoneMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "route53-hosted-zone", + DescriptiveName: "Hosted Zone", + PotentialLinks: []string{"route53-resource-record-set"}, + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a hosted zone by ID", + ListDescription: "List all hosted zones", + SearchDescription: "Search for a hosted zone by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_route53_hosted_zone_dnssec.id"}, + {TerraformQueryMap: "aws_route53_zone.zone_id"}, + {TerraformQueryMap: "aws_route53_zone_association.zone_id"}, + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + } +} diff --git a/sources/route53/hosted_zone_test.go b/adapters/route53/hosted_zone_test.go similarity index 52% rename from sources/route53/hosted_zone_test.go rename to adapters/route53/hosted_zone_test.go index 7ad88e41..5ed3bb9e 100644 --- a/sources/route53/hosted_zone_test.go +++ b/adapters/route53/hosted_zone_test.go @@ -5,23 +5,23 @@ import ( "time" "github.com/aws/aws-sdk-go-v2/service/route53/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) func TestHostedZoneItemMapper(t *testing.T) { zone := types.HostedZone{ - Id: sources.PtrString("/hostedzone/Z08416862SZP5DJXIDB29"), - Name: sources.PtrString("overmind-demo.com."), - CallerReference: sources.PtrString("RISWorkflow-RD:144d3779-1574-42bf-9e75-f309838ea0a1"), + Id: adapters.PtrString("/hostedzone/Z08416862SZP5DJXIDB29"), + Name: adapters.PtrString("overmind-demo.com."), + CallerReference: adapters.PtrString("RISWorkflow-RD:144d3779-1574-42bf-9e75-f309838ea0a1"), Config: &types.HostedZoneConfig{ - Comment: sources.PtrString("HostedZone created by Route53 Registrar"), + Comment: adapters.PtrString("HostedZone created by Route53 Registrar"), PrivateZone: false, }, - ResourceRecordSetCount: sources.PtrInt64(3), + ResourceRecordSetCount: adapters.PtrInt64(3), LinkedService: &types.LinkedService{ - Description: sources.PtrString("service description"), - ServicePrincipal: sources.PtrString("principal"), + Description: adapters.PtrString("service description"), + ServicePrincipal: adapters.PtrString("principal"), }, } @@ -35,7 +35,7 @@ func TestHostedZoneItemMapper(t *testing.T) { t.Error(err) } - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "route53-resource-record-set", ExpectedMethod: sdp.QueryMethod_SEARCH, @@ -47,13 +47,13 @@ func TestHostedZoneItemMapper(t *testing.T) { tests.Execute(t, item) } -func TestNewHostedZoneSource(t *testing.T) { +func TestNewHostedZoneAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewHostedZoneSource(client, account, region) + adapter := NewHostedZoneAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/route53/resource_record_set.go b/adapters/route53/resource_record_set.go similarity index 68% rename from sources/route53/resource_record_set.go rename to adapters/route53/resource_record_set.go index 8b25dee8..1007c02a 100644 --- a/sources/route53/resource_record_set.go +++ b/adapters/route53/resource_record_set.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/route53" "github.com/aws/aws-sdk-go-v2/service/route53/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -52,7 +52,7 @@ func resourceRecordSetSearchFunc(ctx context.Context, client *route53.Client, sc } func resourceRecordSetItemMapper(_, scope string, awsItem *types.ResourceRecordSet) (*sdp.Item, error) { - attributes, err := sources.ToAttributesWithExclude(awsItem) + attributes, err := adapters.ToAttributesWithExclude(awsItem) if err != nil { return nil, err @@ -134,15 +134,37 @@ func resourceRecordSetItemMapper(_, scope string, awsItem *types.ResourceRecordS // +overmind:terraform:queryMap aws_route53_record.id // +overmind:terraform:method SEARCH -func NewResourceRecordSetSource(client *route53.Client, accountID string, region string) *sources.GetListSource[*types.ResourceRecordSet, *route53.Client, *route53.Options] { - return &sources.GetListSource[*types.ResourceRecordSet, *route53.Client, *route53.Options]{ - ItemType: "route53-resource-record-set", - Client: client, - DisableList: true, - AccountID: accountID, - Region: region, - GetFunc: resourceRecordSetGetFunc, - ItemMapper: resourceRecordSetItemMapper, - SearchFunc: resourceRecordSetSearchFunc, +func NewResourceRecordSetAdapter(client *route53.Client, accountID string, region string) *adapters.GetListAdapter[*types.ResourceRecordSet, *route53.Client, *route53.Options] { + return &adapters.GetListAdapter[*types.ResourceRecordSet, *route53.Client, *route53.Options]{ + ItemType: "route53-resource-record-set", + Client: client, + DisableList: true, + AccountID: accountID, + Region: region, + GetFunc: resourceRecordSetGetFunc, + ItemMapper: resourceRecordSetItemMapper, + SearchFunc: resourceRecordSetSearchFunc, + AdapterMetadata: ResourceRecordSetMetadata(), + } +} + +func ResourceRecordSetMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "route53-resource-record-set", + DescriptiveName: "Route53 Record Set", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get a Route53 record Set by name", + ListDescription: "List all record sets", + SearchDescription: "Search for a record set by hosted zone ID in the format \"/hostedzone/JJN928734JH7HV\" or \"JJN928734JH7HV\" or by terraform ID in the format \"{hostedZone}_{recordName}_{type}\"", + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + PotentialLinks: []string{"dns", "route53-health-check"}, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_route53_record.arn", TerraformMethod: sdp.QueryMethod_SEARCH}, + {TerraformQueryMap: "aws_route53_record.id", TerraformMethod: sdp.QueryMethod_SEARCH}, + }, } } diff --git a/sources/route53/resource_record_set_test.go b/adapters/route53/resource_record_set_test.go similarity index 62% rename from sources/route53/resource_record_set_test.go rename to adapters/route53/resource_record_set_test.go index 09d4b5c0..0e2899ba 100644 --- a/sources/route53/resource_record_set_test.go +++ b/adapters/route53/resource_record_set_test.go @@ -8,56 +8,56 @@ import ( "time" "github.com/aws/aws-sdk-go-v2/service/route53/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) func TestResourceRecordSetItemMapper(t *testing.T) { recordSet := types.ResourceRecordSet{ - Name: sources.PtrString("overmind-demo.com."), + Name: adapters.PtrString("overmind-demo.com."), Type: types.RRTypeNs, - TTL: sources.PtrInt64(172800), + TTL: adapters.PtrInt64(172800), GeoProximityLocation: &types.GeoProximityLocation{ - AWSRegion: sources.PtrString("us-east-1"), - Bias: sources.PtrInt32(100), + AWSRegion: adapters.PtrString("us-east-1"), + Bias: adapters.PtrInt32(100), Coordinates: &types.Coordinates{}, - LocalZoneGroup: sources.PtrString("group"), + LocalZoneGroup: adapters.PtrString("group"), }, ResourceRecords: []types.ResourceRecord{ { - Value: sources.PtrString("ns-1673.awsdns-17.co.uk."), // link + Value: adapters.PtrString("ns-1673.awsdns-17.co.uk."), // link }, { - Value: sources.PtrString("ns-1505.awsdns-60.org."), // link + Value: adapters.PtrString("ns-1505.awsdns-60.org."), // link }, { - Value: sources.PtrString("ns-955.awsdns-55.net."), // link + Value: adapters.PtrString("ns-955.awsdns-55.net."), // link }, { - Value: sources.PtrString("ns-276.awsdns-34.com."), // link + Value: adapters.PtrString("ns-276.awsdns-34.com."), // link }, }, AliasTarget: &types.AliasTarget{ - DNSName: sources.PtrString("foo.bar.com"), // link + DNSName: adapters.PtrString("foo.bar.com"), // link EvaluateTargetHealth: true, - HostedZoneId: sources.PtrString("id"), + HostedZoneId: adapters.PtrString("id"), }, CidrRoutingConfig: &types.CidrRoutingConfig{ - CollectionId: sources.PtrString("id"), - LocationName: sources.PtrString("somewhere"), + CollectionId: adapters.PtrString("id"), + LocationName: adapters.PtrString("somewhere"), }, Failover: types.ResourceRecordSetFailoverPrimary, GeoLocation: &types.GeoLocation{ - ContinentCode: sources.PtrString("GB"), - CountryCode: sources.PtrString("GB"), - SubdivisionCode: sources.PtrString("ENG"), + ContinentCode: adapters.PtrString("GB"), + CountryCode: adapters.PtrString("GB"), + SubdivisionCode: adapters.PtrString("ENG"), }, - HealthCheckId: sources.PtrString("id"), // link - MultiValueAnswer: sources.PtrBool(true), + HealthCheckId: adapters.PtrString("id"), // link + MultiValueAnswer: adapters.PtrBool(true), Region: types.ResourceRecordSetRegionApEast1, - SetIdentifier: sources.PtrString("identifier"), - TrafficPolicyInstanceId: sources.PtrString("id"), - Weight: sources.PtrInt64(100), + SetIdentifier: adapters.PtrString("identifier"), + TrafficPolicyInstanceId: adapters.PtrString("id"), + Weight: adapters.PtrInt64(100), } item, err := resourceRecordSetItemMapper("", "foo", &recordSet) @@ -70,7 +70,7 @@ func TestResourceRecordSetItemMapper(t *testing.T) { t.Error(err) } - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "dns", ExpectedMethod: sdp.QueryMethod_SEARCH, @@ -112,10 +112,10 @@ func TestResourceRecordSetItemMapper(t *testing.T) { tests.Execute(t, item) } -func TestNewResourceRecordSetSource(t *testing.T) { +func TestNewResourceRecordSetAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - zoneSource := NewHostedZoneSource(client, account, region) + zoneSource := NewHostedZoneAdapter(client, account, region) zones, err := zoneSource.List(context.Background(), zoneSource.Scopes()[0], true) if err != nil { @@ -126,11 +126,11 @@ func TestNewResourceRecordSetSource(t *testing.T) { t.Skip("no zones found") } - source := NewResourceRecordSetSource(client, account, region) + adapter := NewResourceRecordSetAdapter(client, account, region) search := zones[0].UniqueAttributeValue() - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, SkipGet: true, GoodSearchQuery: &search, @@ -138,7 +138,7 @@ func TestNewResourceRecordSetSource(t *testing.T) { test.Run(t) - items, err := source.Search(context.Background(), zoneSource.Scopes()[0], search, true) + items, err := adapter.Search(context.Background(), zoneSource.Scopes()[0], search, true) if err != nil { t.Fatal(err) } @@ -147,7 +147,7 @@ func TestNewResourceRecordSetSource(t *testing.T) { rawZone := strings.TrimPrefix(search, "/hostedzone/") - items, err = source.Search(context.Background(), zoneSource.Scopes()[0], rawZone, true) + items, err = adapter.Search(context.Background(), zoneSource.Scopes()[0], rawZone, true) if err != nil { t.Fatal(err) } @@ -164,7 +164,7 @@ func TestNewResourceRecordSetSource(t *testing.T) { typ, _ := item.GetAttributes().Get("Type") search = fmt.Sprintf("%s_%s_%s", rawZone, name, typ) - items, err := source.Search(context.Background(), zoneSource.Scopes()[0], search, true) + items, err := adapter.Search(context.Background(), zoneSource.Scopes()[0], search, true) if err != nil { t.Fatal(err) } diff --git a/sources/route53/shared.go b/adapters/route53/shared.go similarity index 100% rename from sources/route53/shared.go rename to adapters/route53/shared.go diff --git a/sources/route53/shared_test.go b/adapters/route53/shared_test.go similarity index 69% rename from sources/route53/shared_test.go rename to adapters/route53/shared_test.go index 4b22709a..4e573e22 100644 --- a/sources/route53/shared_test.go +++ b/adapters/route53/shared_test.go @@ -4,11 +4,11 @@ import ( "testing" "github.com/aws/aws-sdk-go-v2/service/route53" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" ) func GetAutoConfig(t *testing.T) (*route53.Client, string, string) { - config, account, region := sources.GetAutoConfig(t) + config, account, region := adapters.GetAutoConfig(t) client := route53.NewFromConfig(config) return client, account, region diff --git a/sources/s3/s3.go b/adapters/s3/s3.go similarity index 81% rename from sources/s3/s3.go rename to adapters/s3/s3.go index 3466f2ae..b537acf9 100644 --- a/sources/s3/s3.go +++ b/adapters/s3/s3.go @@ -10,18 +10,60 @@ import ( "github.com/aws/aws-sdk-go-v2/service/s3" "github.com/aws/aws-sdk-go-v2/service/s3/types" "github.com/getsentry/sentry-go" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" "github.com/overmindtech/sdpcache" ) const CacheDuration = 10 * time.Minute -// NewS3Source Creates a new S3 source -func NewS3Source(config aws.Config, accountID string) *S3Source { +// NewS3Source Creates a new S3 adapter +func NewS3Adapter(config aws.Config, accountID string) *S3Source { return &S3Source{ - config: config, - accountID: accountID, + config: config, + accountID: accountID, + AdapterMetadata: S3Metadata(), + } +} + +func S3Metadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "s3-bucket", + DescriptiveName: "S3 Bucket", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get an S3 bucket by name", + ListDescription: "List all S3 buckets", + SearchDescription: "Search for S3 buckets by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_s3_bucket_acl.bucket"}, + {TerraformQueryMap: "aws_s3_bucket_analytics_configuration.bucket"}, + {TerraformQueryMap: "aws_s3_bucket_cors_configuration.bucket"}, + {TerraformQueryMap: "aws_s3_bucket_intelligent_tiering_configuration.bucket"}, + {TerraformQueryMap: "aws_s3_bucket_inventory.bucket"}, + {TerraformQueryMap: "aws_s3_bucket_lifecycle_configuration.bucket"}, + {TerraformQueryMap: "aws_s3_bucket_logging.bucket"}, + {TerraformQueryMap: "aws_s3_bucket_metric.bucket"}, + {TerraformQueryMap: "aws_s3_bucket_notification.bucket"}, + {TerraformQueryMap: "aws_s3_bucket_object_lock_configuration.bucket"}, + {TerraformQueryMap: "aws_s3_bucket_object.bucket"}, + {TerraformQueryMap: "aws_s3_bucket_ownership_controls.bucket"}, + {TerraformQueryMap: "aws_s3_bucket_policy.bucket"}, + {TerraformQueryMap: "aws_s3_bucket_public_access_block.bucket"}, + {TerraformQueryMap: "aws_s3_bucket_replication_configuration.bucket"}, + {TerraformQueryMap: "aws_s3_bucket_request_payment_configuration.bucket"}, + {TerraformQueryMap: "aws_s3_bucket_server_side_encryption_configuration.bucket"}, + {TerraformQueryMap: "aws_s3_bucket_versioning.bucket"}, + {TerraformQueryMap: "aws_s3_bucket_website_configuration.bucket"}, + {TerraformQueryMap: "aws_s3_bucket.id"}, + {TerraformQueryMap: "aws_s3_object_copy.bucket"}, + {TerraformQueryMap: "aws_s3_object.bucket"}, + }, + PotentialLinks: []string{"lambda-function", "sqs-queue", "sns-topic", "s3-bucket"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_STORAGE, } } @@ -63,12 +105,13 @@ type S3Source struct { accountID string // client The AWS client to use when making requests - client *s3.Client - clientCreated bool - clientMutex sync.Mutex + client *s3.Client + clientCreated bool + clientMutex sync.Mutex + AdapterMetadata sdp.AdapterMetadata CacheDuration time.Duration // How long to cache items for - cache *sdpcache.Cache // The sdpcache of this source + cache *sdpcache.Cache // The sdpcache of this adapter cacheInitMu sync.Mutex // Mutex to ensure cache is only initialised once } @@ -102,22 +145,26 @@ func (s *S3Source) Client() *s3.Client { return s.client } -// Type The type of items that this source is capable of finding +// Type The type of items that this adapter is capable of finding func (s *S3Source) Type() string { // +overmind:type s3-bucket return "s3-bucket" } -// Descriptive name for the source, used in logging and metadata +// Descriptive name for the adapter, used in logging and metadata func (s *S3Source) Name() string { - return "aws-s3-source" + return "aws-s3-adapter" +} + +func (s *S3Source) Metadata() *sdp.AdapterMetadata { + return &s.AdapterMetadata } -// List of scopes that this source is capable of find items for. This will be +// List of scopes that this adapter is capable of find items for. This will be // in the format {accountID} since S3 endpoint is global func (s *S3Source) Scopes() []string { return []string{ - sources.FormatScope(s.accountID, ""), + adapters.FormatScope(s.accountID, ""), } } @@ -174,13 +221,13 @@ type Bucket struct { // Get Get a single item with a given scope and query. The item returned // should have a UniqueAttributeValue that matches the `query` parameter. The // ctx parameter contains a golang context object which should be used to allow -// this source to timeout or be cancelled when executing potentially +// this adapter to timeout or be cancelled when executing potentially // long-running actions func (s *S3Source) Get(ctx context.Context, scope string, query string, ignoreCache bool) (*sdp.Item, error) { if scope != s.Scopes()[0] { return nil, &sdp.QueryError{ ErrorType: sdp.QueryError_NOSCOPE, - ErrorString: fmt.Sprintf("requested scope %v does not match source scope %v", scope, s.Scopes()[0]), + ErrorString: fmt.Sprintf("requested scope %v does not match adapter scope %v", scope, s.Scopes()[0]), Scope: scope, } } @@ -190,7 +237,7 @@ func (s *S3Source) Get(ctx context.Context, scope string, query string, ignoreCa } func getImpl(ctx context.Context, cache *sdpcache.Cache, client S3Client, scope string, query string, ignoreCache bool) (*sdp.Item, error) { - cacheHit, ck, cachedItems, qErr := cache.Lookup(ctx, "aws-s3-source", sdp.QueryMethod_GET, scope, "s3-bucket", query, ignoreCache) + cacheHit, ck, cachedItems, qErr := cache.Lookup(ctx, "aws-s3-adapter", sdp.QueryMethod_GET, scope, "s3-bucket", query, ignoreCache) if qErr != nil { return nil, qErr } @@ -206,14 +253,14 @@ func getImpl(ctx context.Context, cache *sdpcache.Cache, client S3Client, scope var wg sync.WaitGroup var err error - bucketName := sources.PtrString(query) + bucketName := adapters.PtrString(query) location, err = client.GetBucketLocation(ctx, &s3.GetBucketLocationInput{ Bucket: bucketName, }) if err != nil { - err = sources.WrapAWSError(err) + err = adapters.WrapAWSError(err) cache.StoreError(err, CacheDuration, ck) return nil, err } @@ -378,7 +425,7 @@ func getImpl(ctx context.Context, cache *sdpcache.Cache, client S3Client, scope // Wait for all requests to complete wg.Wait() - attributes, err := sources.ToAttributesWithExclude(bucket) + attributes, err := adapters.ToAttributesWithExclude(bucket) if err != nil { err = &sdp.QueryError{ @@ -437,18 +484,18 @@ func getImpl(ctx context.Context, cache *sdpcache.Cache, client S3Client, scope } } - var a *sources.ARN + var a *adapters.ARN for _, lambdaConfig := range bucket.LambdaFunctionConfigurations { if lambdaConfig.LambdaFunctionArn != nil { - if a, err = sources.ParseARN(*lambdaConfig.LambdaFunctionArn); err == nil { + if a, err = adapters.ParseARN(*lambdaConfig.LambdaFunctionArn); err == nil { // +overmind:link lambda-function item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "lambda-function", Method: sdp.QueryMethod_SEARCH, Query: *lambdaConfig.LambdaFunctionArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Tightly coupled @@ -462,14 +509,14 @@ func getImpl(ctx context.Context, cache *sdpcache.Cache, client S3Client, scope for _, q := range bucket.QueueConfigurations { if q.QueueArn != nil { - if a, err = sources.ParseARN(*q.QueueArn); err == nil { + if a, err = adapters.ParseARN(*q.QueueArn); err == nil { // +overmind:link sqs-queue item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "sqs-queue", Method: sdp.QueryMethod_SEARCH, Query: *q.QueueArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Tightly coupled @@ -483,14 +530,14 @@ func getImpl(ctx context.Context, cache *sdpcache.Cache, client S3Client, scope for _, topic := range bucket.TopicConfigurations { if topic.TopicArn != nil { - if a, err = sources.ParseARN(*topic.TopicArn); err == nil { + if a, err = adapters.ParseARN(*topic.TopicArn); err == nil { // +overmind:link sns-topic item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "sns-topic", Method: sdp.QueryMethod_SEARCH, Query: *topic.TopicArn, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Tightly coupled @@ -525,14 +572,14 @@ func getImpl(ctx context.Context, cache *sdpcache.Cache, client S3Client, scope if bucket.InventoryConfiguration.Destination != nil { if bucket.InventoryConfiguration.Destination.S3BucketDestination != nil { if bucket.InventoryConfiguration.Destination.S3BucketDestination.Bucket != nil { - if a, err = sources.ParseARN(*bucket.InventoryConfiguration.Destination.S3BucketDestination.Bucket); err == nil { + if a, err = adapters.ParseARN(*bucket.InventoryConfiguration.Destination.S3BucketDestination.Bucket); err == nil { // +overmind:link s3-bucket item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "s3-bucket", Method: sdp.QueryMethod_SEARCH, Query: *bucket.InventoryConfiguration.Destination.S3BucketDestination.Bucket, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Tightly coupled @@ -554,14 +601,14 @@ func getImpl(ctx context.Context, cache *sdpcache.Cache, client S3Client, scope if bucket.AnalyticsConfiguration.StorageClassAnalysis.DataExport.Destination != nil { if bucket.AnalyticsConfiguration.StorageClassAnalysis.DataExport.Destination.S3BucketDestination != nil { if bucket.AnalyticsConfiguration.StorageClassAnalysis.DataExport.Destination.S3BucketDestination.Bucket != nil { - if a, err = sources.ParseARN(*bucket.AnalyticsConfiguration.StorageClassAnalysis.DataExport.Destination.S3BucketDestination.Bucket); err == nil { + if a, err = adapters.ParseARN(*bucket.AnalyticsConfiguration.StorageClassAnalysis.DataExport.Destination.S3BucketDestination.Bucket); err == nil { // +overmind:link s3-bucket item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "s3-bucket", Method: sdp.QueryMethod_SEARCH, Query: *bucket.AnalyticsConfiguration.StorageClassAnalysis.DataExport.Destination.S3BucketDestination.Bucket, - Scope: sources.FormatScope(a.AccountID, a.Region), + Scope: adapters.FormatScope(a.AccountID, a.Region), }, BlastPropagation: &sdp.BlastPropagation{ // Tightly coupled @@ -587,7 +634,7 @@ func (s *S3Source) List(ctx context.Context, scope string, ignoreCache bool) ([] if scope != s.Scopes()[0] { return nil, &sdp.QueryError{ ErrorType: sdp.QueryError_NOSCOPE, - ErrorString: fmt.Sprintf("requested scope %v does not match source scope %v", scope, s.Scopes()[0]), + ErrorString: fmt.Sprintf("requested scope %v does not match adapter scope %v", scope, s.Scopes()[0]), Scope: scope, } } @@ -597,7 +644,7 @@ func (s *S3Source) List(ctx context.Context, scope string, ignoreCache bool) ([] } func listImpl(ctx context.Context, cache *sdpcache.Cache, client S3Client, scope string, ignoreCache bool) ([]*sdp.Item, error) { - cacheHit, ck, cachedItems, qErr := cache.Lookup(ctx, "aws-s3-source", sdp.QueryMethod_LIST, scope, "s3-bucket", "", ignoreCache) + cacheHit, ck, cachedItems, qErr := cache.Lookup(ctx, "aws-s3-adapter", sdp.QueryMethod_LIST, scope, "s3-bucket", "", ignoreCache) if qErr != nil { return nil, qErr } @@ -640,7 +687,7 @@ func (s *S3Source) Search(ctx context.Context, scope string, query string, ignor if scope != s.Scopes()[0] { return nil, &sdp.QueryError{ ErrorType: sdp.QueryError_NOSCOPE, - ErrorString: fmt.Sprintf("requested scope %v does not match source scope %v", scope, s.Scopes()[0]), + ErrorString: fmt.Sprintf("requested scope %v does not match adapter scope %v", scope, s.Scopes()[0]), Scope: scope, } } @@ -651,16 +698,16 @@ func (s *S3Source) Search(ctx context.Context, scope string, query string, ignor func searchImpl(ctx context.Context, cache *sdpcache.Cache, client S3Client, scope string, query string, ignoreCache bool) ([]*sdp.Item, error) { // Parse the ARN - a, err := sources.ParseARN(query) + a, err := adapters.ParseARN(query) if err != nil { return nil, sdp.NewQueryError(err) } - if arnScope := sources.FormatScope(a.AccountID, a.Region); arnScope != scope { + if arnScope := adapters.FormatScope(a.AccountID, a.Region); arnScope != scope { return nil, &sdp.QueryError{ ErrorType: sdp.QueryError_NOSCOPE, - ErrorString: fmt.Sprintf("ARN scope %v does not match source scope %v", arnScope, scope), + ErrorString: fmt.Sprintf("ARN scope %v does not match adapters scope %v", arnScope, scope), Scope: scope, } } @@ -674,7 +721,7 @@ func searchImpl(ctx context.Context, cache *sdpcache.Cache, client S3Client, sco return []*sdp.Item{item}, nil } -// Weight Returns the priority weighting of items returned by this source. +// Weight Returns the priority weighting of items returned by this adapter. // This is used to resolve conflicts where two sources of the same type // return an item for a GET request. In this instance only one item can be // seen on, so the one with the higher weight value will win. diff --git a/sources/s3/s3_test.go b/adapters/s3/s3_test.go similarity index 86% rename from sources/s3/s3_test.go rename to adapters/s3/s3_test.go index 10e44d07..27d831eb 100644 --- a/sources/s3/s3_test.go +++ b/adapters/s3/s3_test.go @@ -8,7 +8,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/s3" "github.com/aws/aws-sdk-go-v2/service/s3/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" "github.com/overmindtech/sdpcache" ) @@ -81,7 +81,7 @@ func TestS3GetImpl(t *testing.T) { t.Fatal(err) } - tests := sources.QueryTests{ + tests := adapters.QueryTests{ { ExpectedType: "http", ExpectedMethod: sdp.QueryMethod_GET, @@ -161,8 +161,8 @@ func TestS3SourceCaching(t *testing.T) { } var owner = types.Owner{ - DisplayName: sources.PtrString("dylan"), - ID: sources.PtrString("id"), + DisplayName: adapters.PtrString("dylan"), + ID: adapters.PtrString("id"), } // TestS3Client A client that returns example data @@ -172,8 +172,8 @@ func (t TestS3Client) ListBuckets(ctx context.Context, params *s3.ListBucketsInp return &s3.ListBucketsOutput{ Buckets: []types.Bucket{ { - CreationDate: sources.PtrTime(time.Now()), - Name: sources.PtrString("foo"), + CreationDate: adapters.PtrTime(time.Now()), + Name: adapters.PtrString("foo"), }, }, Owner: &owner, @@ -186,10 +186,10 @@ func (t TestS3Client) GetBucketAcl(ctx context.Context, params *s3.GetBucketAclI { Grantee: &types.Grantee{ Type: types.TypeAmazonCustomerByEmail, - DisplayName: sources.PtrString("dylan"), - EmailAddress: sources.PtrString("dylan@company.com"), - ID: sources.PtrString("id"), - URI: sources.PtrString("uri"), + DisplayName: adapters.PtrString("dylan"), + EmailAddress: adapters.PtrString("dylan@company.com"), + ID: adapters.PtrString("id"), + URI: adapters.PtrString("uri"), }, }, }, @@ -200,15 +200,15 @@ func (t TestS3Client) GetBucketAcl(ctx context.Context, params *s3.GetBucketAclI func (t TestS3Client) GetBucketAnalyticsConfiguration(ctx context.Context, params *s3.GetBucketAnalyticsConfigurationInput, optFns ...func(*s3.Options)) (*s3.GetBucketAnalyticsConfigurationOutput, error) { return &s3.GetBucketAnalyticsConfigurationOutput{ AnalyticsConfiguration: &types.AnalyticsConfiguration{ - Id: sources.PtrString("id"), + Id: adapters.PtrString("id"), StorageClassAnalysis: &types.StorageClassAnalysis{ DataExport: &types.StorageClassAnalysisDataExport{ Destination: &types.AnalyticsExportDestination{ S3BucketDestination: &types.AnalyticsS3BucketDestination{ - Bucket: sources.PtrString("arn:partition:service:region:account-id:resource-type:resource-id"), + Bucket: adapters.PtrString("arn:partition:service:region:account-id:resource-type:resource-id"), Format: types.AnalyticsS3ExportFileFormatCsv, - BucketAccountId: sources.PtrString("id"), - Prefix: sources.PtrString("pre"), + BucketAccountId: adapters.PtrString("id"), + Prefix: adapters.PtrString("pre"), }, }, OutputSchemaVersion: types.StorageClassAnalysisSchemaVersionV1, @@ -234,8 +234,8 @@ func (t TestS3Client) GetBucketCors(ctx context.Context, params *s3.GetBucketCor ExposeHeaders: []string{ "foo", }, - ID: sources.PtrString("id"), - MaxAgeSeconds: sources.PtrInt32(10), + ID: adapters.PtrString("id"), + MaxAgeSeconds: adapters.PtrInt32(10), }, }, }, nil @@ -248,9 +248,9 @@ func (t TestS3Client) GetBucketEncryption(ctx context.Context, params *s3.GetBuc { ApplyServerSideEncryptionByDefault: &types.ServerSideEncryptionByDefault{ SSEAlgorithm: types.ServerSideEncryptionAes256, - KMSMasterKeyID: sources.PtrString("id"), + KMSMasterKeyID: adapters.PtrString("id"), }, - BucketKeyEnabled: sources.PtrBool(true), + BucketKeyEnabled: adapters.PtrBool(true), }, }, }, @@ -260,12 +260,12 @@ func (t TestS3Client) GetBucketEncryption(ctx context.Context, params *s3.GetBuc func (t TestS3Client) GetBucketIntelligentTieringConfiguration(ctx context.Context, params *s3.GetBucketIntelligentTieringConfigurationInput, optFns ...func(*s3.Options)) (*s3.GetBucketIntelligentTieringConfigurationOutput, error) { return &s3.GetBucketIntelligentTieringConfigurationOutput{ IntelligentTieringConfiguration: &types.IntelligentTieringConfiguration{ - Id: sources.PtrString("id"), + Id: adapters.PtrString("id"), Status: types.IntelligentTieringStatusEnabled, Tierings: []types.Tiering{ { AccessTier: types.IntelligentTieringAccessTierDeepArchiveAccess, - Days: sources.PtrInt32(100), + Days: adapters.PtrInt32(100), }, }, Filter: &types.IntelligentTieringFilter{}, @@ -278,20 +278,20 @@ func (t TestS3Client) GetBucketInventoryConfiguration(ctx context.Context, param InventoryConfiguration: &types.InventoryConfiguration{ Destination: &types.InventoryDestination{ S3BucketDestination: &types.InventoryS3BucketDestination{ - Bucket: sources.PtrString("arn:partition:service:region:account-id:resource-type:resource-id"), + Bucket: adapters.PtrString("arn:partition:service:region:account-id:resource-type:resource-id"), Format: types.InventoryFormatCsv, - AccountId: sources.PtrString("id"), + AccountId: adapters.PtrString("id"), Encryption: &types.InventoryEncryption{ SSEKMS: &types.SSEKMS{ - KeyId: sources.PtrString("key"), + KeyId: adapters.PtrString("key"), }, }, - Prefix: sources.PtrString("pre"), + Prefix: adapters.PtrString("pre"), }, }, - Id: sources.PtrString("id"), + Id: adapters.PtrString("id"), IncludedObjectVersions: types.InventoryIncludedObjectVersionsAll, - IsEnabled: sources.PtrBool(true), + IsEnabled: adapters.PtrBool(true), Schedule: &types.InventorySchedule{ Frequency: types.InventoryFrequencyDaily, }, @@ -305,30 +305,30 @@ func (t TestS3Client) GetBucketLifecycleConfiguration(ctx context.Context, param { Status: types.ExpirationStatusEnabled, AbortIncompleteMultipartUpload: &types.AbortIncompleteMultipartUpload{ - DaysAfterInitiation: sources.PtrInt32(1), + DaysAfterInitiation: adapters.PtrInt32(1), }, Expiration: &types.LifecycleExpiration{ - Date: sources.PtrTime(time.Now()), - Days: sources.PtrInt32(3), - ExpiredObjectDeleteMarker: sources.PtrBool(true), + Date: adapters.PtrTime(time.Now()), + Days: adapters.PtrInt32(3), + ExpiredObjectDeleteMarker: adapters.PtrBool(true), }, - ID: sources.PtrString("id"), + ID: adapters.PtrString("id"), NoncurrentVersionExpiration: &types.NoncurrentVersionExpiration{ - NewerNoncurrentVersions: sources.PtrInt32(3), - NoncurrentDays: sources.PtrInt32(1), + NewerNoncurrentVersions: adapters.PtrInt32(3), + NoncurrentDays: adapters.PtrInt32(1), }, NoncurrentVersionTransitions: []types.NoncurrentVersionTransition{ { - NewerNoncurrentVersions: sources.PtrInt32(1), - NoncurrentDays: sources.PtrInt32(1), + NewerNoncurrentVersions: adapters.PtrInt32(1), + NoncurrentDays: adapters.PtrInt32(1), StorageClass: types.TransitionStorageClassGlacierIr, }, }, - Prefix: sources.PtrString("pre"), + Prefix: adapters.PtrString("pre"), Transitions: []types.Transition{ { - Date: sources.PtrTime(time.Now()), - Days: sources.PtrInt32(12), + Date: adapters.PtrTime(time.Now()), + Days: adapters.PtrInt32(12), StorageClass: types.TransitionStorageClassGlacierIr, }, }, @@ -346,13 +346,13 @@ func (t TestS3Client) GetBucketLocation(ctx context.Context, params *s3.GetBucke func (t TestS3Client) GetBucketLogging(ctx context.Context, params *s3.GetBucketLoggingInput, optFns ...func(*s3.Options)) (*s3.GetBucketLoggingOutput, error) { return &s3.GetBucketLoggingOutput{ LoggingEnabled: &types.LoggingEnabled{ - TargetBucket: sources.PtrString("bucket"), - TargetPrefix: sources.PtrString("pre"), + TargetBucket: adapters.PtrString("bucket"), + TargetPrefix: adapters.PtrString("pre"), TargetGrants: []types.TargetGrant{ { Grantee: &types.Grantee{ Type: types.TypeGroup, - ID: sources.PtrString("id"), + ID: adapters.PtrString("id"), }, }, }, @@ -363,7 +363,7 @@ func (t TestS3Client) GetBucketLogging(ctx context.Context, params *s3.GetBucket func (t TestS3Client) GetBucketMetricsConfiguration(ctx context.Context, params *s3.GetBucketMetricsConfigurationInput, optFns ...func(*s3.Options)) (*s3.GetBucketMetricsConfigurationOutput, error) { return &s3.GetBucketMetricsConfigurationOutput{ MetricsConfiguration: &types.MetricsConfiguration{ - Id: sources.PtrString("id"), + Id: adapters.PtrString("id"), }, }, nil } @@ -373,43 +373,43 @@ func (t TestS3Client) GetBucketNotificationConfiguration(ctx context.Context, pa LambdaFunctionConfigurations: []types.LambdaFunctionConfiguration{ { Events: []types.Event{}, - LambdaFunctionArn: sources.PtrString("arn:partition:service:region:account-id:resource-type:resource-id"), - Id: sources.PtrString("id"), + LambdaFunctionArn: adapters.PtrString("arn:partition:service:region:account-id:resource-type:resource-id"), + Id: adapters.PtrString("id"), }, }, EventBridgeConfiguration: &types.EventBridgeConfiguration{}, QueueConfigurations: []types.QueueConfiguration{ { Events: []types.Event{}, - QueueArn: sources.PtrString("arn:partition:service:region:account-id:resource-type:resource-id"), + QueueArn: adapters.PtrString("arn:partition:service:region:account-id:resource-type:resource-id"), Filter: &types.NotificationConfigurationFilter{ Key: &types.S3KeyFilter{ FilterRules: []types.FilterRule{ { Name: types.FilterRuleNamePrefix, - Value: sources.PtrString("foo"), + Value: adapters.PtrString("foo"), }, }, }, }, - Id: sources.PtrString("id"), + Id: adapters.PtrString("id"), }, }, TopicConfigurations: []types.TopicConfiguration{ { Events: []types.Event{}, - TopicArn: sources.PtrString("arn:partition:service:region:account-id:resource-type:resource-id"), + TopicArn: adapters.PtrString("arn:partition:service:region:account-id:resource-type:resource-id"), Filter: &types.NotificationConfigurationFilter{ Key: &types.S3KeyFilter{ FilterRules: []types.FilterRule{ { Name: types.FilterRuleNameSuffix, - Value: sources.PtrString("fix"), + Value: adapters.PtrString("fix"), }, }, }, }, - Id: sources.PtrString("id"), + Id: adapters.PtrString("id"), }, }, }, nil @@ -429,14 +429,14 @@ func (t TestS3Client) GetBucketOwnershipControls(ctx context.Context, params *s3 func (t TestS3Client) GetBucketPolicy(ctx context.Context, params *s3.GetBucketPolicyInput, optFns ...func(*s3.Options)) (*s3.GetBucketPolicyOutput, error) { return &s3.GetBucketPolicyOutput{ - Policy: sources.PtrString("policy"), + Policy: adapters.PtrString("policy"), }, nil } func (t TestS3Client) GetBucketPolicyStatus(ctx context.Context, params *s3.GetBucketPolicyStatusInput, optFns ...func(*s3.Options)) (*s3.GetBucketPolicyStatusOutput, error) { return &s3.GetBucketPolicyStatusOutput{ PolicyStatus: &types.PolicyStatus{ - IsPublic: sources.PtrBool(true), + IsPublic: adapters.PtrBool(true), }, }, nil } @@ -444,28 +444,28 @@ func (t TestS3Client) GetBucketPolicyStatus(ctx context.Context, params *s3.GetB func (t TestS3Client) GetBucketReplication(ctx context.Context, params *s3.GetBucketReplicationInput, optFns ...func(*s3.Options)) (*s3.GetBucketReplicationOutput, error) { return &s3.GetBucketReplicationOutput{ ReplicationConfiguration: &types.ReplicationConfiguration{ - Role: sources.PtrString("role"), + Role: adapters.PtrString("role"), Rules: []types.ReplicationRule{ { Destination: &types.Destination{ - Bucket: sources.PtrString("bucket"), + Bucket: adapters.PtrString("bucket"), AccessControlTranslation: &types.AccessControlTranslation{ Owner: types.OwnerOverrideDestination, }, - Account: sources.PtrString("account"), + Account: adapters.PtrString("account"), EncryptionConfiguration: &types.EncryptionConfiguration{ - ReplicaKmsKeyID: sources.PtrString("keyId"), + ReplicaKmsKeyID: adapters.PtrString("keyId"), }, Metrics: &types.Metrics{ Status: types.MetricsStatusEnabled, EventThreshold: &types.ReplicationTimeValue{ - Minutes: sources.PtrInt32(1), + Minutes: adapters.PtrInt32(1), }, }, ReplicationTime: &types.ReplicationTime{ Status: types.ReplicationTimeStatusEnabled, Time: &types.ReplicationTimeValue{ - Minutes: sources.PtrInt32(1), + Minutes: adapters.PtrInt32(1), }, }, StorageClass: types.StorageClassGlacier, @@ -498,23 +498,23 @@ func (t TestS3Client) GetBucketVersioning(ctx context.Context, params *s3.GetBuc func (t TestS3Client) GetBucketWebsite(ctx context.Context, params *s3.GetBucketWebsiteInput, optFns ...func(*s3.Options)) (*s3.GetBucketWebsiteOutput, error) { return &s3.GetBucketWebsiteOutput{ ErrorDocument: &types.ErrorDocument{ - Key: sources.PtrString("key"), + Key: adapters.PtrString("key"), }, IndexDocument: &types.IndexDocument{ - Suffix: sources.PtrString("html"), + Suffix: adapters.PtrString("html"), }, RedirectAllRequestsTo: &types.RedirectAllRequestsTo{ - HostName: sources.PtrString("hostname"), + HostName: adapters.PtrString("hostname"), Protocol: types.ProtocolHttps, }, RoutingRules: []types.RoutingRule{ { Redirect: &types.Redirect{ - HostName: sources.PtrString("hostname"), - HttpRedirectCode: sources.PtrString("303"), + HostName: adapters.PtrString("hostname"), + HttpRedirectCode: adapters.PtrString("303"), Protocol: types.ProtocolHttp, - ReplaceKeyPrefixWith: sources.PtrString("pre"), - ReplaceKeyWith: sources.PtrString("key"), + ReplaceKeyPrefixWith: adapters.PtrString("pre"), + ReplaceKeyWith: adapters.PtrString("key"), }, }, }, @@ -662,13 +662,13 @@ func (t TestS3FailClient) PutObject(ctx context.Context, params *s3.PutObjectInp return nil, errors.New("failed to put object") } -func TestNewS3Source(t *testing.T) { - config, account, _ := sources.GetAutoConfig(t) +func TestNewS3Adapter(t *testing.T) { + config, account, _ := adapters.GetAutoConfig(t) - source := NewS3Source(config, account) + adapter := NewS3Adapter(config, account) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/shared_tests.go b/adapters/shared_tests.go similarity index 99% rename from sources/shared_tests.go rename to adapters/shared_tests.go index 3cdac2ac..69c1fc5b 100644 --- a/sources/shared_tests.go +++ b/adapters/shared_tests.go @@ -1,4 +1,4 @@ -package sources +package adapters import ( "context" diff --git a/sources/sns/data_protection_policy.go b/adapters/sns/data_protection_policy.go similarity index 61% rename from sources/sns/data_protection_policy.go rename to adapters/sns/data_protection_policy.go index 2ed43628..643f5cc6 100644 --- a/sources/sns/data_protection_policy.go +++ b/adapters/sns/data_protection_policy.go @@ -4,7 +4,8 @@ import ( "context" "github.com/aws/aws-sdk-go-v2/service/sns" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" + "github.com/overmindtech/sdp-go" ) @@ -30,7 +31,7 @@ func getDataProtectionPolicyFunc(ctx context.Context, client dataProtectionPolic "TopicArn": *input.ResourceArn, } - attributes, err := sources.ToAttributesWithExclude(attr) + attributes, err := adapters.ToAttributesWithExclude(attr) if err != nil { return nil, err } @@ -71,13 +72,14 @@ func getDataProtectionPolicyFunc(ctx context.Context, client dataProtectionPolic // +overmind:group AWS // +overmind:terraform:queryMap aws_sns_topic_data_protection_policy.arn -func NewDataProtectionPolicySource(client dataProtectionPolicyClient, accountID string, region string) *sources.AlwaysGetSource[any, any, *sns.GetDataProtectionPolicyInput, *sns.GetDataProtectionPolicyOutput, dataProtectionPolicyClient, *sns.Options] { - return &sources.AlwaysGetSource[any, any, *sns.GetDataProtectionPolicyInput, *sns.GetDataProtectionPolicyOutput, dataProtectionPolicyClient, *sns.Options]{ - ItemType: "sns-data-protection-policy", - Client: client, - AccountID: accountID, - Region: region, - DisableList: true, +func NewDataProtectionPolicyAdapter(client dataProtectionPolicyClient, accountID string, region string) *adapters.AlwaysGetAdapter[any, any, *sns.GetDataProtectionPolicyInput, *sns.GetDataProtectionPolicyOutput, dataProtectionPolicyClient, *sns.Options] { + return &adapters.AlwaysGetAdapter[any, any, *sns.GetDataProtectionPolicyInput, *sns.GetDataProtectionPolicyOutput, dataProtectionPolicyClient, *sns.Options]{ + ItemType: "sns-data-protection-policy", + Client: client, + AccountID: accountID, + Region: region, + DisableList: true, + AdapterMetadata: DataProtectionPolicyMetadata(), GetInputMapper: func(scope, query string) *sns.GetDataProtectionPolicyInput { return &sns.GetDataProtectionPolicyInput{ ResourceArn: &query, @@ -86,3 +88,21 @@ func NewDataProtectionPolicySource(client dataProtectionPolicyClient, accountID GetFunc: getDataProtectionPolicyFunc, } } + +func DataProtectionPolicyMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "sns-data-protection-policy", + DescriptiveName: "SNS Data Protection Policy", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + Search: true, + GetDescription: "Get an SNS data protection policy by associated topic ARN", + SearchDescription: "Search SNS data protection policies by its ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_sns_topic_data_protection_policy.arn"}, + }, + PotentialLinks: []string{"sns-topic"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_CONFIGURATION, + } +} diff --git a/sources/sns/data_protection_policy_test.go b/adapters/sns/data_protection_policy_test.go similarity index 57% rename from sources/sns/data_protection_policy_test.go rename to adapters/sns/data_protection_policy_test.go index edee687c..84c24fb2 100644 --- a/sources/sns/data_protection_policy_test.go +++ b/adapters/sns/data_protection_policy_test.go @@ -6,14 +6,14 @@ import ( "time" "github.com/aws/aws-sdk-go-v2/service/sns" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" ) type mockDataProtectionPolicyClient struct{} func (m mockDataProtectionPolicyClient) GetDataProtectionPolicy(ctx context.Context, params *sns.GetDataProtectionPolicyInput, optFns ...func(*sns.Options)) (*sns.GetDataProtectionPolicyOutput, error) { return &sns.GetDataProtectionPolicyOutput{ - DataProtectionPolicy: sources.PtrString("{\"Name\":\"data_protection_policy\",\"Description\":\"Example data protection policy\",\"Version\":\"2021-06-01\",\"Statement\":[{\"DataDirection\":\"Inbound\",\"Principal\":[\"*\"],\"DataIdentifier\":[\"arn:aws:dataprotection::aws:data-identifier/CreditCardNumber\"],\"Operation\":{\"Deny\":{}}}]}"), + DataProtectionPolicy: adapters.PtrString("{\"Name\":\"data_protection_policy\",\"Description\":\"Example data protection policy\",\"Version\":\"2021-06-01\",\"Statement\":[{\"DataDirection\":\"Inbound\",\"Principal\":[\"*\"],\"DataIdentifier\":[\"arn:aws:dataprotection::aws:data-identifier/CreditCardNumber\"],\"Operation\":{\"Deny\":{}}}]}"), }, nil } @@ -22,7 +22,7 @@ func TestGetDataProtectionPolicyFunc(t *testing.T) { cli := &mockDataProtectionPolicyClient{} item, err := getDataProtectionPolicyFunc(ctx, cli, "scope", &sns.GetDataProtectionPolicyInput{ - ResourceArn: sources.PtrString("arn:aws:sns:us-east-1:123456789012:mytopic"), + ResourceArn: adapters.PtrString("arn:aws:sns:us-east-1:123456789012:mytopic"), }) if err != nil { t.Fatal(err) @@ -33,13 +33,13 @@ func TestGetDataProtectionPolicyFunc(t *testing.T) { } } -func TestNewDataProtectionPolicySource(t *testing.T) { +func TestNewDataProtectionPolicyAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewDataProtectionPolicySource(client, account, region) + adapter := NewDataProtectionPolicyAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, SkipList: true, SkipGet: true, diff --git a/sources/sns/endpoint.go b/adapters/sns/endpoint.go similarity index 64% rename from sources/sns/endpoint.go rename to adapters/sns/endpoint.go index 6a2629c8..a6142eea 100644 --- a/sources/sns/endpoint.go +++ b/adapters/sns/endpoint.go @@ -4,7 +4,7 @@ import ( "context" "github.com/aws/aws-sdk-go-v2/service/sns" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -27,7 +27,7 @@ func getEndpointFunc(ctx context.Context, client endpointClient, scope string, i } } - attributes, err := sources.ToAttributesWithExclude(output.Attributes) + attributes, err := adapters.ToAttributesWithExclude(output.Attributes) if err != nil { return nil, err } @@ -58,13 +58,14 @@ func getEndpointFunc(ctx context.Context, client endpointClient, scope string, i // +overmind:search Search SNS endpoints by associated Platform Application ARN // +overmind:group AWS -func NewEndpointSource(client endpointClient, accountID string, region string) *sources.AlwaysGetSource[*sns.ListEndpointsByPlatformApplicationInput, *sns.ListEndpointsByPlatformApplicationOutput, *sns.GetEndpointAttributesInput, *sns.GetEndpointAttributesOutput, endpointClient, *sns.Options] { - return &sources.AlwaysGetSource[*sns.ListEndpointsByPlatformApplicationInput, *sns.ListEndpointsByPlatformApplicationOutput, *sns.GetEndpointAttributesInput, *sns.GetEndpointAttributesOutput, endpointClient, *sns.Options]{ - ItemType: "sns-endpoint", - Client: client, - AccountID: accountID, - Region: region, - DisableList: true, // This source only supports listing by platform application ARN +func NewEndpointAdapter(client endpointClient, accountID string, region string) *adapters.AlwaysGetAdapter[*sns.ListEndpointsByPlatformApplicationInput, *sns.ListEndpointsByPlatformApplicationOutput, *sns.GetEndpointAttributesInput, *sns.GetEndpointAttributesOutput, endpointClient, *sns.Options] { + return &adapters.AlwaysGetAdapter[*sns.ListEndpointsByPlatformApplicationInput, *sns.ListEndpointsByPlatformApplicationOutput, *sns.GetEndpointAttributesInput, *sns.GetEndpointAttributesOutput, endpointClient, *sns.Options]{ + ItemType: "sns-endpoint", + Client: client, + AccountID: accountID, + Region: region, + DisableList: true, // This source only supports listing by platform application ARN + AdapterMetadata: EndpointMetadata(), SearchInputMapper: func(scope, query string) (*sns.ListEndpointsByPlatformApplicationInput, error) { return &sns.ListEndpointsByPlatformApplicationInput{ PlatformApplicationArn: &query, @@ -75,7 +76,7 @@ func NewEndpointSource(client endpointClient, accountID string, region string) * EndpointArn: &query, } }, - ListFuncPaginatorBuilder: func(client endpointClient, input *sns.ListEndpointsByPlatformApplicationInput) sources.Paginator[*sns.ListEndpointsByPlatformApplicationOutput, *sns.Options] { + ListFuncPaginatorBuilder: func(client endpointClient, input *sns.ListEndpointsByPlatformApplicationInput) adapters.Paginator[*sns.ListEndpointsByPlatformApplicationOutput, *sns.Options] { return sns.NewListEndpointsByPlatformApplicationPaginator(client, input) }, ListFuncOutputMapper: func(output *sns.ListEndpointsByPlatformApplicationOutput, input *sns.ListEndpointsByPlatformApplicationInput) ([]*sns.GetEndpointAttributesInput, error) { @@ -90,3 +91,17 @@ func NewEndpointSource(client endpointClient, accountID string, region string) * GetFunc: getEndpointFunc, } } + +func EndpointMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "sns-endpoint", + DescriptiveName: "SNS Endpoint", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + Search: true, + GetDescription: "Get an SNS endpoint by its ARN", + SearchDescription: "Search SNS endpoints by associated Platform Application ARN", + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_CONFIGURATION, + } +} diff --git a/sources/sns/endpoint_test.go b/adapters/sns/endpoint_test.go similarity index 82% rename from sources/sns/endpoint_test.go rename to adapters/sns/endpoint_test.go index 558df5b1..b18af737 100644 --- a/sources/sns/endpoint_test.go +++ b/adapters/sns/endpoint_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/sns" "github.com/aws/aws-sdk-go-v2/service/sns/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" ) type mockEndpointClient struct{} @@ -44,7 +44,7 @@ func TestGetEndpointFunc(t *testing.T) { cli := &mockEndpointClient{} item, err := getEndpointFunc(ctx, cli, "scope", &sns.GetEndpointAttributesInput{ - EndpointArn: sources.PtrString("arn:aws:sns:us-west-2:123456789012:endpoint/GCM/MyApplication/12345678-abcd-9012-efgh-345678901234"), + EndpointArn: adapters.PtrString("arn:aws:sns:us-west-2:123456789012:endpoint/GCM/MyApplication/12345678-abcd-9012-efgh-345678901234"), }) if err != nil { t.Fatal(err) @@ -55,13 +55,13 @@ func TestGetEndpointFunc(t *testing.T) { } } -func TestNewEndpointSource(t *testing.T) { +func TestNewEndpointAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewEndpointSource(client, account, region) + adapter := NewEndpointAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, SkipList: true, } diff --git a/sources/sns/platform_application.go b/adapters/sns/platform_application.go similarity index 64% rename from sources/sns/platform_application.go rename to adapters/sns/platform_application.go index dc9033f2..50505cba 100644 --- a/sources/sns/platform_application.go +++ b/adapters/sns/platform_application.go @@ -4,7 +4,7 @@ import ( "context" "github.com/aws/aws-sdk-go-v2/service/sns" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -27,7 +27,7 @@ func getPlatformApplicationFunc(ctx context.Context, client platformApplicationC } } - attributes, err := sources.ToAttributesWithExclude(output.Attributes) + attributes, err := adapters.ToAttributesWithExclude(output.Attributes) if err != nil { return nil, err } @@ -76,19 +76,20 @@ func getPlatformApplicationFunc(ctx context.Context, client platformApplicationC // +overmind:group AWS // +overmind:terraform:queryMap aws_sns_platform_application.id -func NewPlatformApplicationSource(client platformApplicationClient, accountID string, region string) *sources.AlwaysGetSource[*sns.ListPlatformApplicationsInput, *sns.ListPlatformApplicationsOutput, *sns.GetPlatformApplicationAttributesInput, *sns.GetPlatformApplicationAttributesOutput, platformApplicationClient, *sns.Options] { - return &sources.AlwaysGetSource[*sns.ListPlatformApplicationsInput, *sns.ListPlatformApplicationsOutput, *sns.GetPlatformApplicationAttributesInput, *sns.GetPlatformApplicationAttributesOutput, platformApplicationClient, *sns.Options]{ - ItemType: "sns-platform-application", - Client: client, - AccountID: accountID, - Region: region, - ListInput: &sns.ListPlatformApplicationsInput{}, +func NewPlatformApplicationAdapter(client platformApplicationClient, accountID string, region string) *adapters.AlwaysGetAdapter[*sns.ListPlatformApplicationsInput, *sns.ListPlatformApplicationsOutput, *sns.GetPlatformApplicationAttributesInput, *sns.GetPlatformApplicationAttributesOutput, platformApplicationClient, *sns.Options] { + return &adapters.AlwaysGetAdapter[*sns.ListPlatformApplicationsInput, *sns.ListPlatformApplicationsOutput, *sns.GetPlatformApplicationAttributesInput, *sns.GetPlatformApplicationAttributesOutput, platformApplicationClient, *sns.Options]{ + ItemType: "sns-platform-application", + Client: client, + AccountID: accountID, + Region: region, + ListInput: &sns.ListPlatformApplicationsInput{}, + AdapterMetadata: PlatformApplicationMetadata(), GetInputMapper: func(scope, query string) *sns.GetPlatformApplicationAttributesInput { return &sns.GetPlatformApplicationAttributesInput{ PlatformApplicationArn: &query, } }, - ListFuncPaginatorBuilder: func(client platformApplicationClient, input *sns.ListPlatformApplicationsInput) sources.Paginator[*sns.ListPlatformApplicationsOutput, *sns.Options] { + ListFuncPaginatorBuilder: func(client platformApplicationClient, input *sns.ListPlatformApplicationsInput) adapters.Paginator[*sns.ListPlatformApplicationsOutput, *sns.Options] { return sns.NewListPlatformApplicationsPaginator(client, input) }, ListFuncOutputMapper: func(output *sns.ListPlatformApplicationsOutput, input *sns.ListPlatformApplicationsInput) ([]*sns.GetPlatformApplicationAttributesInput, error) { @@ -103,3 +104,23 @@ func NewPlatformApplicationSource(client platformApplicationClient, accountID st GetFunc: getPlatformApplicationFunc, } } + +func PlatformApplicationMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "sns-platform-application", + DescriptiveName: "SNS Platform Application", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get an SNS platform application by its ARN", + ListDescription: "List all SNS platform applications", + SearchDescription: "Search SNS platform applications by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_sns_platform_application.id"}, + }, + PotentialLinks: []string{"sns-endpoint"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_CONFIGURATION, + } +} diff --git a/sources/sns/platform_application_test.go b/adapters/sns/platform_application_test.go similarity index 73% rename from sources/sns/platform_application_test.go rename to adapters/sns/platform_application_test.go index 58f3c127..5bfb806d 100644 --- a/sources/sns/platform_application_test.go +++ b/adapters/sns/platform_application_test.go @@ -5,10 +5,9 @@ import ( "testing" "time" - "github.com/overmindtech/aws-source/sources" - "github.com/aws/aws-sdk-go-v2/service/sns" "github.com/aws/aws-sdk-go-v2/service/sns/types" + "github.com/overmindtech/aws-source/adapters" ) type mockPlatformApplicationClient struct{} @@ -16,8 +15,8 @@ type mockPlatformApplicationClient struct{} func (m mockPlatformApplicationClient) ListTagsForResource(ctx context.Context, input *sns.ListTagsForResourceInput, f ...func(*sns.Options)) (*sns.ListTagsForResourceOutput, error) { return &sns.ListTagsForResourceOutput{ Tags: []types.Tag{ - {Key: sources.PtrString("tag1"), Value: sources.PtrString("value1")}, - {Key: sources.PtrString("tag2"), Value: sources.PtrString("value2")}, + {Key: adapters.PtrString("tag1"), Value: adapters.PtrString("value1")}, + {Key: adapters.PtrString("tag2"), Value: adapters.PtrString("value2")}, }, }, nil } @@ -35,14 +34,14 @@ func (m mockPlatformApplicationClient) ListPlatformApplications(ctx context.Cont return &sns.ListPlatformApplicationsOutput{ PlatformApplications: []types.PlatformApplication{ { - PlatformApplicationArn: sources.PtrString("arn:aws:sns:us-west-2:123456789012:app/ADM/MyApplication"), + PlatformApplicationArn: adapters.PtrString("arn:aws:sns:us-west-2:123456789012:app/ADM/MyApplication"), Attributes: map[string]string{ "SuccessFeedbackSampleRate": "100", "Enabled": "true", }, }, { - PlatformApplicationArn: sources.PtrString("arn:aws:sns:us-west-2:123456789012:app/MPNS/MyOtherApplication"), + PlatformApplicationArn: adapters.PtrString("arn:aws:sns:us-west-2:123456789012:app/MPNS/MyOtherApplication"), Attributes: map[string]string{ "SuccessFeedbackSampleRate": "100", "Enabled": "true", @@ -57,7 +56,7 @@ func TestGetPlatformApplicationFunc(t *testing.T) { cli := mockPlatformApplicationClient{} item, err := getPlatformApplicationFunc(ctx, cli, "scope", &sns.GetPlatformApplicationAttributesInput{ - PlatformApplicationArn: sources.PtrString("arn:aws:sns:us-west-2:123456789012:my-topic"), + PlatformApplicationArn: adapters.PtrString("arn:aws:sns:us-west-2:123456789012:my-topic"), }) if err != nil { t.Fatal(err) @@ -68,13 +67,13 @@ func TestGetPlatformApplicationFunc(t *testing.T) { } } -func TestNewPlatformApplicationSource(t *testing.T) { +func TestNewPlatformApplicationAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewPlatformApplicationSource(client, account, region) + adapter := NewPlatformApplicationAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/sns/shared.go b/adapters/sns/shared.go similarity index 100% rename from sources/sns/shared.go rename to adapters/sns/shared.go diff --git a/sources/sns/shared_test.go b/adapters/sns/shared_test.go similarity index 68% rename from sources/sns/shared_test.go rename to adapters/sns/shared_test.go index d1f42f84..66e18b74 100644 --- a/sources/sns/shared_test.go +++ b/adapters/sns/shared_test.go @@ -4,11 +4,11 @@ import ( "testing" "github.com/aws/aws-sdk-go-v2/service/sns" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" ) func GetAutoConfig(t *testing.T) (*sns.Client, string, string) { - config, account, region := sources.GetAutoConfig(t) + config, account, region := adapters.GetAutoConfig(t) client := sns.NewFromConfig(config) return client, account, region diff --git a/sources/sns/subscription.go b/adapters/sns/subscription.go similarity index 66% rename from sources/sns/subscription.go rename to adapters/sns/subscription.go index 37b632e2..c9a4b9bf 100644 --- a/sources/sns/subscription.go +++ b/adapters/sns/subscription.go @@ -5,7 +5,7 @@ import ( "fmt" "github.com/aws/aws-sdk-go-v2/service/sns" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -28,7 +28,7 @@ func getSubsFunc(ctx context.Context, client subsCli, scope string, input *sns.G } } - attributes, err := sources.ToAttributesWithExclude(output.Attributes) + attributes, err := adapters.ToAttributesWithExclude(output.Attributes) if err != nil { return nil, err } @@ -63,14 +63,14 @@ func getSubsFunc(ctx context.Context, client subsCli, scope string, input *sns.G } if subsRoleArn, err := attributes.Get("subscriptionRoleArn"); err == nil { - if arn, err := sources.ParseARN(fmt.Sprint(subsRoleArn)); err == nil { + if arn, err := adapters.ParseARN(fmt.Sprint(subsRoleArn)); err == nil { // +overmind:link iam-role item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ Query: &sdp.Query{ Type: "iam-role", Method: sdp.QueryMethod_GET, Query: arn.ResourceID(), - Scope: sources.FormatScope(arn.AccountID, arn.Region), + Scope: adapters.FormatScope(arn.AccountID, arn.Region), }, BlastPropagation: &sdp.BlastPropagation{ // If role is not healthy, subscription will not work @@ -94,19 +94,20 @@ func getSubsFunc(ctx context.Context, client subsCli, scope string, input *sns.G // +overmind:group AWS // +overmind:terraform:queryMap aws_sns_topic_subscription.id -func NewSubscriptionSource(client subsCli, accountID string, region string) *sources.AlwaysGetSource[*sns.ListSubscriptionsInput, *sns.ListSubscriptionsOutput, *sns.GetSubscriptionAttributesInput, *sns.GetSubscriptionAttributesOutput, subsCli, *sns.Options] { - return &sources.AlwaysGetSource[*sns.ListSubscriptionsInput, *sns.ListSubscriptionsOutput, *sns.GetSubscriptionAttributesInput, *sns.GetSubscriptionAttributesOutput, subsCli, *sns.Options]{ - ItemType: "sns-subscription", - Client: client, - AccountID: accountID, - Region: region, - ListInput: &sns.ListSubscriptionsInput{}, +func NewSubscriptionAdapter(client subsCli, accountID string, region string) *adapters.AlwaysGetAdapter[*sns.ListSubscriptionsInput, *sns.ListSubscriptionsOutput, *sns.GetSubscriptionAttributesInput, *sns.GetSubscriptionAttributesOutput, subsCli, *sns.Options] { + return &adapters.AlwaysGetAdapter[*sns.ListSubscriptionsInput, *sns.ListSubscriptionsOutput, *sns.GetSubscriptionAttributesInput, *sns.GetSubscriptionAttributesOutput, subsCli, *sns.Options]{ + ItemType: "sns-subscription", + Client: client, + AccountID: accountID, + Region: region, + ListInput: &sns.ListSubscriptionsInput{}, + AdapterMetadata: SubscriptionMetadata(), GetInputMapper: func(scope, query string) *sns.GetSubscriptionAttributesInput { return &sns.GetSubscriptionAttributesInput{ SubscriptionArn: &query, } }, - ListFuncPaginatorBuilder: func(client subsCli, input *sns.ListSubscriptionsInput) sources.Paginator[*sns.ListSubscriptionsOutput, *sns.Options] { + ListFuncPaginatorBuilder: func(client subsCli, input *sns.ListSubscriptionsInput) adapters.Paginator[*sns.ListSubscriptionsOutput, *sns.Options] { return sns.NewListSubscriptionsPaginator(client, input) }, ListFuncOutputMapper: func(output *sns.ListSubscriptionsOutput, _ *sns.ListSubscriptionsInput) ([]*sns.GetSubscriptionAttributesInput, error) { @@ -121,3 +122,23 @@ func NewSubscriptionSource(client subsCli, accountID string, region string) *sou GetFunc: getSubsFunc, } } + +func SubscriptionMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "sns-subscription", + DescriptiveName: "SNS Subscription", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get an SNS subscription by its ARN", + SearchDescription: "Search SNS subscription by ARN", + ListDescription: "List all SNS subscriptions", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_sns_topic_subscription.id"}, + }, + PotentialLinks: []string{"sns-topic", "iam-role"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_CONFIGURATION, + } +} diff --git a/sources/sns/subscription_test.go b/adapters/sns/subscription_test.go similarity index 67% rename from sources/sns/subscription_test.go rename to adapters/sns/subscription_test.go index d8a585de..399e606e 100644 --- a/sources/sns/subscription_test.go +++ b/adapters/sns/subscription_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/sns" "github.com/aws/aws-sdk-go-v2/service/sns/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" ) type testClient struct{} @@ -29,11 +29,11 @@ func (t testClient) ListSubscriptions(context.Context, *sns.ListSubscriptionsInp return &sns.ListSubscriptionsOutput{ Subscriptions: []types.Subscription{ { - Owner: sources.PtrString("123456789012"), - Endpoint: sources.PtrString("my-email@example.com"), - Protocol: sources.PtrString("email"), - TopicArn: sources.PtrString("arn:aws:sns:us-west-2:123456789012:my-topic"), - SubscriptionArn: sources.PtrString("arn:aws:sns:us-west-2:123456789012:my-topic:8a21d249-4329-4871-acc6-7be709c6ea7f"), + Owner: adapters.PtrString("123456789012"), + Endpoint: adapters.PtrString("my-email@example.com"), + Protocol: adapters.PtrString("email"), + TopicArn: adapters.PtrString("arn:aws:sns:us-west-2:123456789012:my-topic"), + SubscriptionArn: adapters.PtrString("arn:aws:sns:us-west-2:123456789012:my-topic:8a21d249-4329-4871-acc6-7be709c6ea7f"), }, }, }, nil @@ -42,8 +42,8 @@ func (t testClient) ListSubscriptions(context.Context, *sns.ListSubscriptionsInp func (t testClient) ListTagsForResource(context.Context, *sns.ListTagsForResourceInput, ...func(*sns.Options)) (*sns.ListTagsForResourceOutput, error) { return &sns.ListTagsForResourceOutput{ Tags: []types.Tag{ - {Key: sources.PtrString("tag1"), Value: sources.PtrString("value1")}, - {Key: sources.PtrString("tag2"), Value: sources.PtrString("value2")}, + {Key: adapters.PtrString("tag1"), Value: adapters.PtrString("value1")}, + {Key: adapters.PtrString("tag2"), Value: adapters.PtrString("value2")}, }, }, nil } @@ -53,7 +53,7 @@ func TestGetFunc(t *testing.T) { cli := testClient{} item, err := getSubsFunc(ctx, cli, "scope", &sns.GetSubscriptionAttributesInput{ - SubscriptionArn: sources.PtrString("arn:aws:sns:us-west-2:123456789012:my-topic:8a21d249-4329-4871-acc6-7be709c6ea7f"), + SubscriptionArn: adapters.PtrString("arn:aws:sns:us-west-2:123456789012:my-topic:8a21d249-4329-4871-acc6-7be709c6ea7f"), }) if err != nil { t.Fatal(err) @@ -64,13 +64,13 @@ func TestGetFunc(t *testing.T) { } } -func TestNewSubscriptionSource(t *testing.T) { +func TestNewSubscriptionAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewSubscriptionSource(client, account, region) + adapter := NewSubscriptionAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/sns/topic.go b/adapters/sns/topic.go similarity index 65% rename from sources/sns/topic.go rename to adapters/sns/topic.go index 9f9ed6fd..ae881dfd 100644 --- a/sources/sns/topic.go +++ b/adapters/sns/topic.go @@ -5,7 +5,7 @@ import ( "fmt" "github.com/aws/aws-sdk-go-v2/service/sns" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -28,7 +28,7 @@ func getTopicFunc(ctx context.Context, client topicClient, scope string, input * } } - attributes, err := sources.ToAttributesWithExclude(output.Attributes) + attributes, err := adapters.ToAttributesWithExclude(output.Attributes) if err != nil { return nil, err } @@ -74,19 +74,20 @@ func getTopicFunc(ctx context.Context, client topicClient, scope string, input * // +overmind:group AWS // +overmind:terraform:queryMap aws_sns_topic.id -func NewTopicSource(client topicClient, accountID string, region string) *sources.AlwaysGetSource[*sns.ListTopicsInput, *sns.ListTopicsOutput, *sns.GetTopicAttributesInput, *sns.GetTopicAttributesOutput, topicClient, *sns.Options] { - return &sources.AlwaysGetSource[*sns.ListTopicsInput, *sns.ListTopicsOutput, *sns.GetTopicAttributesInput, *sns.GetTopicAttributesOutput, topicClient, *sns.Options]{ - ItemType: "sns-topic", - Client: client, - AccountID: accountID, - Region: region, - ListInput: &sns.ListTopicsInput{}, +func NewTopicAdapter(client topicClient, accountID string, region string) *adapters.AlwaysGetAdapter[*sns.ListTopicsInput, *sns.ListTopicsOutput, *sns.GetTopicAttributesInput, *sns.GetTopicAttributesOutput, topicClient, *sns.Options] { + return &adapters.AlwaysGetAdapter[*sns.ListTopicsInput, *sns.ListTopicsOutput, *sns.GetTopicAttributesInput, *sns.GetTopicAttributesOutput, topicClient, *sns.Options]{ + ItemType: "sns-topic", + Client: client, + AccountID: accountID, + Region: region, + ListInput: &sns.ListTopicsInput{}, + AdapterMetadata: TopicMetadata(), GetInputMapper: func(scope, query string) *sns.GetTopicAttributesInput { return &sns.GetTopicAttributesInput{ TopicArn: &query, } }, - ListFuncPaginatorBuilder: func(client topicClient, input *sns.ListTopicsInput) sources.Paginator[*sns.ListTopicsOutput, *sns.Options] { + ListFuncPaginatorBuilder: func(client topicClient, input *sns.ListTopicsInput) adapters.Paginator[*sns.ListTopicsOutput, *sns.Options] { return sns.NewListTopicsPaginator(client, input) }, ListFuncOutputMapper: func(output *sns.ListTopicsOutput, input *sns.ListTopicsInput) ([]*sns.GetTopicAttributesInput, error) { @@ -101,3 +102,23 @@ func NewTopicSource(client topicClient, accountID string, region string) *source GetFunc: getTopicFunc, } } + +func TopicMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "sns-topic", + DescriptiveName: "SNS Topic", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get an SNS topic by its ARN", + SearchDescription: "Search SNS topic by ARN", + ListDescription: "List all SNS topics", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_sns_topic.id"}, + }, + PotentialLinks: []string{"kms-key"}, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_CONFIGURATION, + } +} diff --git a/sources/sns/topic_test.go b/adapters/sns/topic_test.go similarity index 82% rename from sources/sns/topic_test.go rename to adapters/sns/topic_test.go index 96c85eaa..a37b3049 100644 --- a/sources/sns/topic_test.go +++ b/adapters/sns/topic_test.go @@ -7,7 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/sns" "github.com/aws/aws-sdk-go-v2/service/sns/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" ) type testTopicClient struct{} @@ -30,7 +30,7 @@ func (t testTopicClient) ListTopics(context.Context, *sns.ListTopicsInput, ...fu return &sns.ListTopicsOutput{ Topics: []types.Topic{ { - TopicArn: sources.PtrString("arn:aws:sns:us-west-2:123456789012:my-topic"), + TopicArn: adapters.PtrString("arn:aws:sns:us-west-2:123456789012:my-topic"), }, }, }, nil @@ -39,8 +39,8 @@ func (t testTopicClient) ListTopics(context.Context, *sns.ListTopicsInput, ...fu func (t testTopicClient) ListTagsForResource(context.Context, *sns.ListTagsForResourceInput, ...func(*sns.Options)) (*sns.ListTagsForResourceOutput, error) { return &sns.ListTagsForResourceOutput{ Tags: []types.Tag{ - {Key: sources.PtrString("tag1"), Value: sources.PtrString("value1")}, - {Key: sources.PtrString("tag2"), Value: sources.PtrString("value2")}, + {Key: adapters.PtrString("tag1"), Value: adapters.PtrString("value1")}, + {Key: adapters.PtrString("tag2"), Value: adapters.PtrString("value2")}, }, }, nil } @@ -50,7 +50,7 @@ func TestGetTopicFunc(t *testing.T) { cli := testTopicClient{} item, err := getTopicFunc(ctx, cli, "scope", &sns.GetTopicAttributesInput{ - TopicArn: sources.PtrString("arn:aws:sns:us-west-2:123456789012:my-topic"), + TopicArn: adapters.PtrString("arn:aws:sns:us-west-2:123456789012:my-topic"), }) if err != nil { t.Fatal(err) @@ -61,13 +61,13 @@ func TestGetTopicFunc(t *testing.T) { } } -func TestNewTopicSource(t *testing.T) { +func TestNewTopicAdapter(t *testing.T) { client, account, region := GetAutoConfig(t) - source := NewTopicSource(client, account, region) + adapter := NewTopicAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/sources.go b/adapters/sources.go similarity index 99% rename from sources/sources.go rename to adapters/sources.go index e4633e67..c96d7dfa 100644 --- a/sources/sources.go +++ b/adapters/sources.go @@ -1,4 +1,4 @@ -package sources +package adapters import "context" diff --git a/sources/sqs/queue.go b/adapters/sqs/queue.go similarity index 64% rename from sources/sqs/queue.go rename to adapters/sqs/queue.go index b716ddb1..5bf343b7 100644 --- a/sources/sqs/queue.go +++ b/adapters/sqs/queue.go @@ -5,7 +5,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/sqs" "github.com/aws/aws-sdk-go-v2/service/sqs/types" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" "github.com/overmindtech/sdp-go" ) @@ -28,7 +28,7 @@ func getFunc(ctx context.Context, client sqsClient, scope string, input *sqs.Get } } - attributes, err := sources.ToAttributesWithExclude(output.Attributes) + attributes, err := adapters.ToAttributesWithExclude(output.Attributes) if err != nil { return nil, err } @@ -64,13 +64,14 @@ func getFunc(ctx context.Context, client sqsClient, scope string, input *sqs.Get // +overmind:group AWS // +overmind:terraform:queryMap aws_sqs_queue.id -func NewQueueSource(client sqsClient, accountID string, region string) *sources.AlwaysGetSource[*sqs.ListQueuesInput, *sqs.ListQueuesOutput, *sqs.GetQueueAttributesInput, *sqs.GetQueueAttributesOutput, sqsClient, *sqs.Options] { - return &sources.AlwaysGetSource[*sqs.ListQueuesInput, *sqs.ListQueuesOutput, *sqs.GetQueueAttributesInput, *sqs.GetQueueAttributesOutput, sqsClient, *sqs.Options]{ - ItemType: "sqs-queue", - Client: client, - AccountID: accountID, - Region: region, - ListInput: &sqs.ListQueuesInput{}, +func NewQueueAdapter(client sqsClient, accountID string, region string) *adapters.AlwaysGetAdapter[*sqs.ListQueuesInput, *sqs.ListQueuesOutput, *sqs.GetQueueAttributesInput, *sqs.GetQueueAttributesOutput, sqsClient, *sqs.Options] { + return &adapters.AlwaysGetAdapter[*sqs.ListQueuesInput, *sqs.ListQueuesOutput, *sqs.GetQueueAttributesInput, *sqs.GetQueueAttributesOutput, sqsClient, *sqs.Options]{ + ItemType: "sqs-queue", + Client: client, + AccountID: accountID, + Region: region, + ListInput: &sqs.ListQueuesInput{}, + AdapterMetadata: QueueMetadata(), GetInputMapper: func(scope, query string) *sqs.GetQueueAttributesInput { return &sqs.GetQueueAttributesInput{ QueueUrl: &query, @@ -78,7 +79,7 @@ func NewQueueSource(client sqsClient, accountID string, region string) *sources. AttributeNames: []types.QueueAttributeName{"All"}, } }, - ListFuncPaginatorBuilder: func(client sqsClient, input *sqs.ListQueuesInput) sources.Paginator[*sqs.ListQueuesOutput, *sqs.Options] { + ListFuncPaginatorBuilder: func(client sqsClient, input *sqs.ListQueuesInput) adapters.Paginator[*sqs.ListQueuesOutput, *sqs.Options] { return sqs.NewListQueuesPaginator(client, input) }, ListFuncOutputMapper: func(output *sqs.ListQueuesOutput, _ *sqs.ListQueuesInput) ([]*sqs.GetQueueAttributesInput, error) { @@ -93,3 +94,22 @@ func NewQueueSource(client sqsClient, accountID string, region string) *sources. GetFunc: getFunc, } } + +func QueueMetadata() sdp.AdapterMetadata { + return sdp.AdapterMetadata{ + Type: "sqs-queue", + DescriptiveName: "SQS Queue", + SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{ + Get: true, + List: true, + Search: true, + GetDescription: "Get an SQS queue attributes by its URL", + ListDescription: "List all SQS queue URLs", + SearchDescription: "Search SQS queue by ARN", + }, + TerraformMappings: []*sdp.TerraformMapping{ + {TerraformQueryMap: "aws_sqs_queue.id"}, + }, + Category: sdp.AdapterCategory_ADAPTER_CATEGORY_COMPUTE_APPLICATION, + } +} diff --git a/sources/sqs/queue_test.go b/adapters/sqs/queue_test.go similarity index 86% rename from sources/sqs/queue_test.go rename to adapters/sqs/queue_test.go index b4695771..b4fa9606 100644 --- a/sources/sqs/queue_test.go +++ b/adapters/sqs/queue_test.go @@ -6,7 +6,7 @@ import ( "time" "github.com/aws/aws-sdk-go-v2/service/sqs" - "github.com/overmindtech/aws-source/sources" + "github.com/overmindtech/aws-source/adapters" ) type testClient struct{} @@ -53,7 +53,7 @@ func TestGetFunc(t *testing.T) { cli := testClient{} item, err := getFunc(ctx, cli, "scope", &sqs.GetQueueAttributesInput{ - QueueUrl: sources.PtrString("https://sqs.us-west-2.amazonaws.com/123456789012/MyQueue"), + QueueUrl: adapters.PtrString("https://sqs.us-west-2.amazonaws.com/123456789012/MyQueue"), }) if err != nil { t.Fatal(err) @@ -64,14 +64,14 @@ func TestGetFunc(t *testing.T) { } } -func TestNewQueueSource(t *testing.T) { - config, account, region := sources.GetAutoConfig(t) +func TestNewQueueAdapter(t *testing.T) { + config, account, region := adapters.GetAutoConfig(t) client := sqs.NewFromConfig(config) - source := NewQueueSource(client, account, region) + adapter := NewQueueAdapter(client, account, region) - test := sources.E2ETest{ - Source: source, + test := adapters.E2ETest{ + Adapter: adapter, Timeout: 10 * time.Second, } diff --git a/sources/sqs/shared.go b/adapters/sqs/shared.go similarity index 100% rename from sources/sqs/shared.go rename to adapters/sqs/shared.go diff --git a/sources/util.go b/adapters/util.go similarity index 88% rename from sources/util.go rename to adapters/util.go index eb7995f7..89288f86 100644 --- a/sources/util.go +++ b/adapters/util.go @@ -1,4 +1,4 @@ -package sources +package adapters import ( "context" @@ -118,7 +118,7 @@ func WrapAWSError(err error) *sdp.QueryError { if errors.As(err, &responseErr) { // If the input is bad, access is denied, or the thing wasn't found then - // we should assume that it is not exist for this source + // we should assume that it is not exist for this adapter if slices.Contains([]int{400, 403, 404}, responseErr.HTTPStatusCode()) { return &sdp.QueryError{ ErrorType: sdp.QueryError_NOTFOUND, @@ -151,13 +151,13 @@ func HandleTagsError(ctx context.Context, err error) map[string]string { } } -// E2ETest A struct that runs end to end tests on a fully configured source. +// E2ETest A struct that runs end to end tests on a fully configured adapters. // These tests aren't particularly detailed, but they are designed to ensure // that there aren't any really obvious error when it's actually configured with // AWS credentials type E2ETest struct { - // The source to test - Source discovery.Source + // The adapter to test + Adapter discovery.Adapter // A search query that should return > 0 results GoodSearchQuery *string @@ -185,26 +185,26 @@ func (e E2ETest) Run(t *testing.T) { Validate() error } - if v, ok := e.Source.(Validator); ok { + if v, ok := e.Adapter.(Validator); ok { if err := v.Validate(); err != nil { - t.Fatalf("source failed validation: %v", err) + t.Fatalf("adapter failed validation: %v", err) } } // Determine the scope so that we can use this for all queries - scopes := e.Source.Scopes() + scopes := e.Adapter.Scopes() if len(scopes) == 0 { t.Fatalf("some scopes, got %v", len(scopes)) } scope := scopes[0] - t.Run(fmt.Sprintf("Source: %v", e.Source.Name()), func(t *testing.T) { + t.Run(fmt.Sprintf("Adapter: %v", e.Adapter.Name()), func(t *testing.T) { if e.GoodSearchQuery != nil { - var searchSrc discovery.SearchableSource + var searchSrc discovery.SearchableAdapter var ok bool - if searchSrc, ok = e.Source.(discovery.SearchableSource); !ok { - t.Errorf("source is not searchable") + if searchSrc, ok = e.Adapter.(discovery.SearchableAdapter); !ok { + t.Errorf("adapter is not searchable") } t.Run(fmt.Sprintf("Good search query: %v", e.GoodSearchQuery), func(t *testing.T) { @@ -225,8 +225,8 @@ func (e E2ETest) Run(t *testing.T) { t.Error(err) } - if item.GetType() != e.Source.Type() { - t.Errorf("mismatched item type \"%v\" and source type \"%v\"", item.GetType(), e.Source.Type()) + if item.GetType() != e.Adapter.Type() { + t.Errorf("mismatched item type \"%v\" and adapter type \"%v\"", item.GetType(), e.Adapter.Type()) } } }) @@ -240,7 +240,7 @@ func (e E2ETest) Run(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), e.Timeout) defer cancel() - items, err := e.Source.List(ctx, scope, false) + items, err := e.Adapter.List(ctx, scope, false) if err != nil { t.Error(err) } @@ -258,8 +258,8 @@ func (e E2ETest) Run(t *testing.T) { t.Error(err) } - if item.GetType() != e.Source.Type() { - t.Errorf("mismatched item type \"%v\" and source type \"%v\"", item.GetType(), e.Source.Type()) + if item.GetType() != e.Adapter.Type() { + t.Errorf("mismatched item type \"%v\" and adapter type \"%v\"", item.GetType(), e.Adapter.Type()) } } @@ -275,7 +275,7 @@ func (e E2ETest) Run(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), e.Timeout) defer cancel() - item, err := e.Source.Get(ctx, scope, query, false) + item, err := e.Adapter.Get(ctx, scope, query, false) if err != nil { t.Fatal(err) } @@ -284,8 +284,8 @@ func (e E2ETest) Run(t *testing.T) { t.Fatal(err) } - if item.GetType() != e.Source.Type() { - t.Errorf("mismatched item type \"%v\" and source type \"%v\"", item.GetType(), e.Source.Type()) + if item.GetType() != e.Adapter.Type() { + t.Errorf("mismatched item type \"%v\" and adapter type \"%v\"", item.GetType(), e.Adapter.Type()) } }) } @@ -299,7 +299,7 @@ func (e E2ETest) Run(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), e.Timeout) defer cancel() - _, err := e.Source.Get(ctx, scope, "this is a known bad get query", false) + _, err := e.Adapter.Get(ctx, scope, "this is a known bad get query", false) if err == nil { t.Error("expected error, got nil") diff --git a/sources/util_test.go b/adapters/util_test.go similarity index 99% rename from sources/util_test.go rename to adapters/util_test.go index a5897293..a56c7b81 100644 --- a/sources/util_test.go +++ b/adapters/util_test.go @@ -1,4 +1,4 @@ -package sources +package adapters import ( "testing" diff --git a/cmd/root.go b/cmd/root.go index e1371bcb..b6a35e9c 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -15,6 +15,28 @@ import ( "github.com/google/uuid" "github.com/nats-io/jwt/v2" "github.com/nats-io/nkeys" + "github.com/overmindtech/aws-source/adapters/apigateway" + "github.com/overmindtech/aws-source/adapters/autoscaling" + "github.com/overmindtech/aws-source/adapters/cloudfront" + "github.com/overmindtech/aws-source/adapters/cloudwatch" + "github.com/overmindtech/aws-source/adapters/directconnect" + "github.com/overmindtech/aws-source/adapters/dynamodb" + "github.com/overmindtech/aws-source/adapters/ec2" + "github.com/overmindtech/aws-source/adapters/ecs" + "github.com/overmindtech/aws-source/adapters/efs" + "github.com/overmindtech/aws-source/adapters/eks" + "github.com/overmindtech/aws-source/adapters/elb" + "github.com/overmindtech/aws-source/adapters/elbv2" + "github.com/overmindtech/aws-source/adapters/iam" + "github.com/overmindtech/aws-source/adapters/kms" + "github.com/overmindtech/aws-source/adapters/lambda" + "github.com/overmindtech/aws-source/adapters/networkfirewall" + "github.com/overmindtech/aws-source/adapters/networkmanager" + "github.com/overmindtech/aws-source/adapters/rds" + "github.com/overmindtech/aws-source/adapters/route53" + "github.com/overmindtech/aws-source/adapters/s3" + "github.com/overmindtech/aws-source/adapters/sns" + "github.com/overmindtech/aws-source/adapters/sqs" "github.com/overmindtech/aws-source/proc" "github.com/overmindtech/aws-source/tracing" "github.com/overmindtech/discovery" @@ -256,7 +278,6 @@ var rootCmd = &cobra.Command{ os.Exit(1) } - log.Info("Stopped") os.Exit(0) @@ -273,6 +294,7 @@ func Execute() { } func init() { + rootCmd.AddCommand(docJSONCmd) cobra.OnInitialize(initConfig) // Here you will define your flags and configuration settings. @@ -437,3 +459,149 @@ func (t TerminationLogHook) Fire(e *log.Entry) error { return err } + +// documentation subcommand for generating json +var docJSONCmd = &cobra.Command{ + Use: "docs", + Short: "Generate JSON documentation", + Long: `Generate JSON documentation for the source`, + Run: func(cmd *cobra.Command, args []string) { + allMetadata := []sdp.AdapterMetadata{ + apigateway.APIGatewayMetadata(), + apigateway.RestAPIMetadata(), + autoscaling.AutoScalingGroupMetadata(), + cloudfront.CachePolicyMetadata(), + cloudfront.ContinuousDeploymentPolicyMetadata(), + cloudfront.DistributionMetadata(), + cloudfront.FunctionMetadata(), + cloudfront.KeyGroupMetadata(), + cloudfront.OriginAccessControlMetadata(), + cloudfront.OriginRequestPolicySourceMetadata(), + cloudfront.RealtimeLogConfigsMetadata(), + cloudfront.ResponseHeadersPolicyMetadata(), + cloudfront.StreamingDistributionMetadata(), + cloudwatch.AlarmMetadata(), + directconnect.ConnectionMetadata(), + directconnect.CustomerMetadata(), + directconnect.DirectConnectGatewayAssociationMetadata(), + directconnect.DirectConnectGatewayAssociationProposalMetadata(), + directconnect.DirectConnectGatewayAttachmentMetadata(), + directconnect.DirectConnectGatewayMetadata(), + directconnect.HostedConnectionMetadata(), + directconnect.InterconnectMetadata(), + directconnect.LagMetadata(), + directconnect.LocationMetadata(), + directconnect.RouterConfigurationSourceMetadata(), + directconnect.VirtualGatewayMetadata(), + directconnect.VirtualInterfaceMetadata(), + dynamodb.BackupMetadata(), + dynamodb.TableMetadata(), + ec2.AddressMetadata(), + ec2.CapacityReservationFleetMetadata(), + ec2.CapacityReservationMetadata(), + ec2.EgressInternetGatewayMetadata(), + ec2.IamInstanceProfileAssociationMetadata(), + ec2.ImageMetadata(), + ec2.InstanceEventWindowMetadata(), + ec2.InstanceStatusMetadata(), + ec2.InstanceMetadata(), + ec2.InternetGatewayMetadata(), + ec2.KeyPairMetadata(), + ec2.LaunchTemplateVersionMetadata(), + ec2.LaunchTemplateMetadata(), + ec2.NatGatewayMetadata(), + ec2.NetworkAclMetadata(), + ec2.NetworkInterfacePermissionMetadata(), + ec2.NetworkInterfaceMetadata(), + ec2.PlacementGroupMetadata(), + ec2.ReservedInstanceMetadata(), + ec2.RouteTableMetadata(), + ec2.SecurityGroupRuleMetadata(), + ec2.SecurityGroupMetadata(), + ec2.SnapshotMetadata(), + ec2.SubnetMetadata(), + ec2.VolumeStatusMetadata(), + ec2.VolumeMetadata(), + ec2.VpcEndpointMetadata(), + ec2.VpcPeeringConnectionMetadata(), + ec2.VpcMetadata(), + ecs.CapacityProviderMetadata(), + ecs.ClusterMetadata(), + ecs.ContainerInstanceMetadata(), + ecs.ServiceMetadata(), + ecs.TaskDefinitionMetadata(), + ecs.TaskMetadata(), + efs.AccessPointMetadata(), + efs.BackupPolicyMetadata(), + efs.FileSystemMetadata(), + efs.MountTargetMetadata(), + efs.ReplicationConfigurationMetadata(), + eks.AddonMetadata(), + eks.ClusterMetadata(), + eks.FargateProfileMetadata(), + eks.NodeGroupMetadata(), + elb.LoadBalancerMetadata(), + elb.InstanceHealthMetadata(), + elbv2.LoadBalancerMetadata(), + elbv2.ListenerMetadata(), + elbv2.RuleMetadata(), + elbv2.TargetGroupMetadata(), + elbv2.TargetHealthMetadata(), + iam.GroupMetadata(), + iam.InstanceProfileMetadata(), + iam.PolicyMetadata(), + iam.RoleMetadata(), + iam.UserMetadata(), + kms.AliasMetadata(), + kms.CustomKeyStoreMetadata(), + kms.GrantMetadata(), + kms.KeyMetadata(), + kms.KeyPolicyMetadata(), + lambda.FunctionMetadata(), + lambda.LayerVersionMetadata(), + lambda.LayerMetadata(), + networkfirewall.FirewallPolicyMetadata(), + networkfirewall.FirewallMetadata(), + networkfirewall.RuleGroupMetadata(), + networkfirewall.TLSInspectionConfigurationMetadata(), + networkmanager.ConnectAttachmentMetadata(), + networkmanager.ConnectPeerAssociationMetadata(), + networkmanager.ConnectPeerMetadata(), + networkmanager.ConnectionMetadata(), + networkmanager.CoreNetworkPolicyMetadata(), + networkmanager.CoreNetworkMetadata(), + networkmanager.DeviceMetadata(), + networkmanager.GlobalNetworkMetadata(), + networkmanager.LinkAssociationMetadata(), + networkmanager.LinkMetadata(), + networkmanager.NetworkResourceRelationshipMetadata(), + networkmanager.SiteToSiteVpnAttachmentMetadata(), + networkmanager.SiteMetadata(), + networkmanager.TransitGatewayConnectPeerAssociationMetadata(), + networkmanager.TransitGatewayPeeringMetadata(), + networkmanager.TransitGatewayRegistrationMetadata(), + networkmanager.TransitGatewayRouteTableAttachmentMetadata(), + networkmanager.VPCAttachmentMetadata(), + rds.DBClusterParameterGroupMetadata(), + rds.DBClusterMetadata(), + rds.DBInstanceMetadata(), + rds.DBParameterGroupMetadata(), + rds.DBSubnetGroupMetadata(), + rds.OptionGroupMetadata(), + route53.HealthCheckMetadata(), + route53.HostedZoneMetadata(), + route53.ResourceRecordSetMetadata(), + s3.S3Metadata(), + sns.DataProtectionPolicyMetadata(), + sns.EndpointMetadata(), + sns.PlatformApplicationMetadata(), + sns.SubscriptionMetadata(), + sns.TopicMetadata(), + sqs.QueueMetadata(), + } + err := discovery.AdapterMetadataToJSONFile(allMetadata, "docs-data") + if err != nil { + log.WithError(err).Fatal("Could not generate JSON documentation") + } + }, +} diff --git a/docs-data/iam-policy.json b/docs-data/iam-policy.json index 62b69424..bd228222 100644 --- a/docs-data/iam-policy.json +++ b/docs-data/iam-policy.json @@ -7,7 +7,6 @@ "group": "AWS", "terraformQuery": [ "aws_iam_policy.arn", - "aws_iam_role_policy_attachment.policy_arn", "aws_iam_user_policy_attachment.policy_arn" ], "terraformMethod": "SEARCH", diff --git a/go.mod b/go.mod index a5f901bd..4584bb35 100644 --- a/go.mod +++ b/go.mod @@ -36,8 +36,8 @@ require ( github.com/micahhausler/aws-iam-policy v0.4.2 github.com/nats-io/jwt/v2 v2.7.2 github.com/nats-io/nkeys v0.4.7 - github.com/overmindtech/discovery v0.28.2 - github.com/overmindtech/sdp-go v0.94.2 + github.com/overmindtech/discovery v0.29.1 + github.com/overmindtech/sdp-go v0.95.0 github.com/overmindtech/sdpcache v1.6.4 github.com/sirupsen/logrus v1.9.3 github.com/sourcegraph/conc v0.3.0 diff --git a/go.sum b/go.sum index aab34661..4bf848eb 100644 --- a/go.sum +++ b/go.sum @@ -156,8 +156,12 @@ github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/overmindtech/discovery v0.28.2 h1:Jn+BtH1iQx0B6iJFx2P5RN2cwTeZEEnpTNtj4378H1c= github.com/overmindtech/discovery v0.28.2/go.mod h1:pidT4aYOTDbgfX1Y3Hq4/7eT5lZJrwZlK+sTpL39xIg= +github.com/overmindtech/discovery v0.29.1 h1:QoEtsiEjuoDCAMZRYtfNhqaF1nL3lzzSCByJzEYVdMs= +github.com/overmindtech/discovery v0.29.1/go.mod h1:WzTpStMxdAhsjSU5EP+2iRsMIKQWSJiVS5wzJ/mRatA= github.com/overmindtech/sdp-go v0.94.2 h1:RucLSekUcrM8bwx05hveXy9TQ0zCoLKrXvSrYjLvfMg= github.com/overmindtech/sdp-go v0.94.2/go.mod h1:ZGzQIHbdDaAmAuaeiw8CxoQImnFcibpEBFIT1eYIsSk= +github.com/overmindtech/sdp-go v0.95.0 h1:B7jkQUM8kqQhxWMp3nuApRmxue0ebwTM8b4YO14zhF4= +github.com/overmindtech/sdp-go v0.95.0/go.mod h1:ZGzQIHbdDaAmAuaeiw8CxoQImnFcibpEBFIT1eYIsSk= github.com/overmindtech/sdpcache v1.6.4 h1:MJoYBDqDE3s8FrRzZ0RPgFiH39HWI/Mv2ImH1NdLT8k= github.com/overmindtech/sdpcache v1.6.4/go.mod h1:/F9XStVdntRJEQjlZ86BPuB1Y7VPo1PFcsCNiU1IoGE= github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= diff --git a/proc/proc.go b/proc/proc.go index 2b2d6117..57d47cf0 100644 --- a/proc/proc.go +++ b/proc/proc.go @@ -40,28 +40,28 @@ import ( "github.com/aws/aws-sdk-go-v2/credentials" stscredsv2 "github.com/aws/aws-sdk-go-v2/credentials/stscreds" "github.com/aws/aws-sdk-go-v2/service/sts" - "github.com/overmindtech/aws-source/sources/apigateway" - "github.com/overmindtech/aws-source/sources/autoscaling" - "github.com/overmindtech/aws-source/sources/cloudfront" - "github.com/overmindtech/aws-source/sources/cloudwatch" - "github.com/overmindtech/aws-source/sources/directconnect" - "github.com/overmindtech/aws-source/sources/dynamodb" - "github.com/overmindtech/aws-source/sources/ec2" - "github.com/overmindtech/aws-source/sources/ecs" - "github.com/overmindtech/aws-source/sources/efs" - "github.com/overmindtech/aws-source/sources/eks" - "github.com/overmindtech/aws-source/sources/elb" - "github.com/overmindtech/aws-source/sources/elbv2" - "github.com/overmindtech/aws-source/sources/iam" - "github.com/overmindtech/aws-source/sources/kms" - "github.com/overmindtech/aws-source/sources/lambda" - "github.com/overmindtech/aws-source/sources/networkfirewall" - "github.com/overmindtech/aws-source/sources/networkmanager" - "github.com/overmindtech/aws-source/sources/rds" - "github.com/overmindtech/aws-source/sources/route53" - "github.com/overmindtech/aws-source/sources/s3" - "github.com/overmindtech/aws-source/sources/sns" - "github.com/overmindtech/aws-source/sources/sqs" + "github.com/overmindtech/aws-source/adapters/apigateway" + "github.com/overmindtech/aws-source/adapters/autoscaling" + "github.com/overmindtech/aws-source/adapters/cloudfront" + "github.com/overmindtech/aws-source/adapters/cloudwatch" + "github.com/overmindtech/aws-source/adapters/directconnect" + "github.com/overmindtech/aws-source/adapters/dynamodb" + "github.com/overmindtech/aws-source/adapters/ec2" + "github.com/overmindtech/aws-source/adapters/ecs" + "github.com/overmindtech/aws-source/adapters/efs" + "github.com/overmindtech/aws-source/adapters/eks" + "github.com/overmindtech/aws-source/adapters/elb" + "github.com/overmindtech/aws-source/adapters/elbv2" + "github.com/overmindtech/aws-source/adapters/iam" + "github.com/overmindtech/aws-source/adapters/kms" + "github.com/overmindtech/aws-source/adapters/lambda" + "github.com/overmindtech/aws-source/adapters/networkfirewall" + "github.com/overmindtech/aws-source/adapters/networkmanager" + "github.com/overmindtech/aws-source/adapters/rds" + "github.com/overmindtech/aws-source/adapters/route53" + "github.com/overmindtech/aws-source/adapters/s3" + "github.com/overmindtech/aws-source/adapters/sns" + "github.com/overmindtech/aws-source/adapters/sqs" "github.com/overmindtech/discovery" "github.com/overmindtech/sdp-go/auth" log "github.com/sirupsen/logrus" @@ -357,192 +357,192 @@ func InitializeAwsSourceEngine(ctx context.Context, name string, version string, o.RetryMode = aws.RetryModeAdaptive }) - sources := []discovery.Source{ + adapters := []discovery.Adapter{ // EC2 - ec2.NewAddressSource(ec2Client, *callerID.Account, cfg.Region), - ec2.NewCapacityReservationFleetSource(ec2Client, *callerID.Account, cfg.Region), - ec2.NewCapacityReservationSource(ec2Client, *callerID.Account, cfg.Region), - ec2.NewEgressOnlyInternetGatewaySource(ec2Client, *callerID.Account, cfg.Region), - ec2.NewIamInstanceProfileAssociationSource(ec2Client, *callerID.Account, cfg.Region), - ec2.NewImageSource(ec2Client, *callerID.Account, cfg.Region), - ec2.NewInstanceEventWindowSource(ec2Client, *callerID.Account, cfg.Region), - ec2.NewInstanceSource(ec2Client, *callerID.Account, cfg.Region), - ec2.NewInstanceStatusSource(ec2Client, *callerID.Account, cfg.Region), - ec2.NewInternetGatewaySource(ec2Client, *callerID.Account, cfg.Region), - ec2.NewKeyPairSource(ec2Client, *callerID.Account, cfg.Region), - ec2.NewLaunchTemplateSource(ec2Client, *callerID.Account, cfg.Region), - ec2.NewLaunchTemplateVersionSource(ec2Client, *callerID.Account, cfg.Region), - ec2.NewNatGatewaySource(ec2Client, *callerID.Account, cfg.Region), - ec2.NewNetworkAclSource(ec2Client, *callerID.Account, cfg.Region), - ec2.NewNetworkInterfacePermissionSource(ec2Client, *callerID.Account, cfg.Region), - ec2.NewNetworkInterfaceSource(ec2Client, *callerID.Account, cfg.Region), - ec2.NewPlacementGroupSource(ec2Client, *callerID.Account, cfg.Region), - ec2.NewReservedInstanceSource(ec2Client, *callerID.Account, cfg.Region), - ec2.NewRouteTableSource(ec2Client, *callerID.Account, cfg.Region), - ec2.NewSecurityGroupRuleSource(ec2Client, *callerID.Account, cfg.Region), - ec2.NewSecurityGroupSource(ec2Client, *callerID.Account, cfg.Region), - ec2.NewSnapshotSource(ec2Client, *callerID.Account, cfg.Region), - ec2.NewSubnetSource(ec2Client, *callerID.Account, cfg.Region), - ec2.NewVolumeSource(ec2Client, *callerID.Account, cfg.Region), - ec2.NewVolumeStatusSource(ec2Client, *callerID.Account, cfg.Region), - ec2.NewVpcEndpointSource(ec2Client, *callerID.Account, cfg.Region), - ec2.NewVpcPeeringConnectionSource(ec2Client, *callerID.Account, cfg.Region), - ec2.NewVpcSource(ec2Client, *callerID.Account, cfg.Region), + ec2.NewAddressAdapter(ec2Client, *callerID.Account, cfg.Region), + ec2.NewCapacityReservationFleetAdapter(ec2Client, *callerID.Account, cfg.Region), + ec2.NewCapacityReservationAdapter(ec2Client, *callerID.Account, cfg.Region), + ec2.NewEgressOnlyInternetGatewayAdapter(ec2Client, *callerID.Account, cfg.Region), + ec2.NewIamInstanceProfileAssociationAdapter(ec2Client, *callerID.Account, cfg.Region), + ec2.NewImageAdapter(ec2Client, *callerID.Account, cfg.Region), + ec2.NewInstanceEventWindowAdapter(ec2Client, *callerID.Account, cfg.Region), + ec2.NewInstanceAdapter(ec2Client, *callerID.Account, cfg.Region), + ec2.NewInstanceStatusAdapter(ec2Client, *callerID.Account, cfg.Region), + ec2.NewInternetGatewayAdapter(ec2Client, *callerID.Account, cfg.Region), + ec2.NewKeyPairAdapter(ec2Client, *callerID.Account, cfg.Region), + ec2.NewLaunchTemplateAdapter(ec2Client, *callerID.Account, cfg.Region), + ec2.NewLaunchTemplateVersionAdapter(ec2Client, *callerID.Account, cfg.Region), + ec2.NewNatGatewayAdapter(ec2Client, *callerID.Account, cfg.Region), + ec2.NewNetworkAclAdapter(ec2Client, *callerID.Account, cfg.Region), + ec2.NewNetworkInterfacePermissionAdapter(ec2Client, *callerID.Account, cfg.Region), + ec2.NewNetworkInterfaceAdapter(ec2Client, *callerID.Account, cfg.Region), + ec2.NewPlacementGroupAdapter(ec2Client, *callerID.Account, cfg.Region), + ec2.NewReservedInstanceAdapter(ec2Client, *callerID.Account, cfg.Region), + ec2.NewRouteTableAdapter(ec2Client, *callerID.Account, cfg.Region), + ec2.NewSecurityGroupRuleAdapter(ec2Client, *callerID.Account, cfg.Region), + ec2.NewSecurityGroupAdapter(ec2Client, *callerID.Account, cfg.Region), + ec2.NewSnapshotAdapter(ec2Client, *callerID.Account, cfg.Region), + ec2.NewSubnetAdapter(ec2Client, *callerID.Account, cfg.Region), + ec2.NewVolumeAdapter(ec2Client, *callerID.Account, cfg.Region), + ec2.NewVolumeStatusAdapter(ec2Client, *callerID.Account, cfg.Region), + ec2.NewVpcEndpointAdapter(ec2Client, *callerID.Account, cfg.Region), + ec2.NewVpcPeeringConnectionAdapter(ec2Client, *callerID.Account, cfg.Region), + ec2.NewVpcAdapter(ec2Client, *callerID.Account, cfg.Region), // EFS (I'm assuming it shares its rate limit with EC2)) - efs.NewAccessPointSource(efsClient, *callerID.Account, cfg.Region), - efs.NewBackupPolicySource(efsClient, *callerID.Account, cfg.Region), - efs.NewFileSystemSource(efsClient, *callerID.Account, cfg.Region), - efs.NewMountTargetSource(efsClient, *callerID.Account, cfg.Region), - efs.NewReplicationConfigurationSource(efsClient, *callerID.Account, cfg.Region), + efs.NewAccessPointAdapter(efsClient, *callerID.Account, cfg.Region), + efs.NewBackupPolicyAdapter(efsClient, *callerID.Account, cfg.Region), + efs.NewFileSystemAdapter(efsClient, *callerID.Account, cfg.Region), + efs.NewMountTargetAdapter(efsClient, *callerID.Account, cfg.Region), + efs.NewReplicationConfigurationAdapter(efsClient, *callerID.Account, cfg.Region), // EKS - eks.NewAddonSource(eksClient, *callerID.Account, cfg.Region), - eks.NewClusterSource(eksClient, *callerID.Account, cfg.Region), - eks.NewFargateProfileSource(eksClient, *callerID.Account, cfg.Region), - eks.NewNodegroupSource(eksClient, *callerID.Account, cfg.Region), + eks.NewAddonAdapter(eksClient, *callerID.Account, cfg.Region), + eks.NewClusterAdapter(eksClient, *callerID.Account, cfg.Region), + eks.NewFargateProfileAdapter(eksClient, *callerID.Account, cfg.Region), + eks.NewNodegroupAdapter(eksClient, *callerID.Account, cfg.Region), // Route 53 - route53.NewHealthCheckSource(route53Client, *callerID.Account, cfg.Region), - route53.NewHostedZoneSource(route53Client, *callerID.Account, cfg.Region), - route53.NewResourceRecordSetSource(route53Client, *callerID.Account, cfg.Region), + route53.NewHealthCheckAdapter(route53Client, *callerID.Account, cfg.Region), + route53.NewHostedZoneAdapter(route53Client, *callerID.Account, cfg.Region), + route53.NewResourceRecordSetAdapter(route53Client, *callerID.Account, cfg.Region), // Cloudwatch - cloudwatch.NewAlarmSource(cloudwatchClient, *callerID.Account, cfg.Region), + cloudwatch.NewAlarmAdapter(cloudwatchClient, *callerID.Account, cfg.Region), // IAM - iam.NewGroupSource(iamClient, *callerID.Account, cfg.Region), - iam.NewInstanceProfileSource(iamClient, *callerID.Account, cfg.Region), - iam.NewPolicySource(iamClient, *callerID.Account, cfg.Region), - iam.NewRoleSource(iamClient, *callerID.Account, cfg.Region), - iam.NewUserSource(iamClient, *callerID.Account, cfg.Region), + iam.NewGroupAdapter(iamClient, *callerID.Account, cfg.Region), + iam.NewInstanceProfileAdapter(iamClient, *callerID.Account, cfg.Region), + iam.NewPolicyAdapter(iamClient, *callerID.Account, cfg.Region), + iam.NewRoleAdapter(iamClient, *callerID.Account, cfg.Region), + iam.NewUserAdapter(iamClient, *callerID.Account, cfg.Region), // Lambda - lambda.NewFunctionSource(lambdaClient, *callerID.Account, cfg.Region), - lambda.NewLayerSource(lambdaClient, *callerID.Account, cfg.Region), - lambda.NewLayerVersionSource(lambdaClient, *callerID.Account, cfg.Region), + lambda.NewFunctionAdapter(lambdaClient, *callerID.Account, cfg.Region), + lambda.NewLayerAdapter(lambdaClient, *callerID.Account, cfg.Region), + lambda.NewLayerVersionAdapter(lambdaClient, *callerID.Account, cfg.Region), // ECS - ecs.NewCapacityProviderSource(ecsClient, *callerID.Account, cfg.Region), - ecs.NewClusterSource(ecsClient, *callerID.Account, cfg.Region), - ecs.NewContainerInstanceSource(ecsClient, *callerID.Account, cfg.Region), - ecs.NewServiceSource(ecsClient, *callerID.Account, cfg.Region), - ecs.NewTaskDefinitionSource(ecsClient, *callerID.Account, cfg.Region), - ecs.NewTaskSource(ecsClient, *callerID.Account, cfg.Region), + ecs.NewCapacityProviderAdapter(ecsClient, *callerID.Account, cfg.Region), + ecs.NewClusterAdapter(ecsClient, *callerID.Account, cfg.Region), + ecs.NewContainerInstanceAdapter(ecsClient, *callerID.Account, cfg.Region), + ecs.NewServiceAdapter(ecsClient, *callerID.Account, cfg.Region), + ecs.NewTaskDefinitionAdapter(ecsClient, *callerID.Account, cfg.Region), + ecs.NewTaskAdapter(ecsClient, *callerID.Account, cfg.Region), // DynamoDB - dynamodb.NewBackupSource(dynamodbClient, *callerID.Account, cfg.Region), - dynamodb.NewTableSource(dynamodbClient, *callerID.Account, cfg.Region), + dynamodb.NewBackupAdapter(dynamodbClient, *callerID.Account, cfg.Region), + dynamodb.NewTableAdapter(dynamodbClient, *callerID.Account, cfg.Region), // RDS - rds.NewDBClusterParameterGroupSource(rdsClient, *callerID.Account, cfg.Region), - rds.NewDBClusterSource(rdsClient, *callerID.Account, cfg.Region), - rds.NewDBInstanceSource(rdsClient, *callerID.Account, cfg.Region), - rds.NewDBParameterGroupSource(rdsClient, *callerID.Account, cfg.Region), - rds.NewDBSubnetGroupSource(rdsClient, *callerID.Account, cfg.Region), - rds.NewOptionGroupSource(rdsClient, *callerID.Account, cfg.Region), + rds.NewDBClusterParameterGroupAdapter(rdsClient, *callerID.Account, cfg.Region), + rds.NewDBClusterAdapter(rdsClient, *callerID.Account, cfg.Region), + rds.NewDBInstanceAdapter(rdsClient, *callerID.Account, cfg.Region), + rds.NewDBParameterGroupAdapter(rdsClient, *callerID.Account, cfg.Region), + rds.NewDBSubnetGroupAdapter(rdsClient, *callerID.Account, cfg.Region), + rds.NewOptionGroupAdapter(rdsClient, *callerID.Account, cfg.Region), // Autoscaling - autoscaling.NewAutoScalingGroupSource(autoscalingClient, *callerID.Account, cfg.Region), + autoscaling.NewAutoScalingGroupAdapter(autoscalingClient, *callerID.Account, cfg.Region), // ELB - elb.NewInstanceHealthSource(elbClient, *callerID.Account, cfg.Region), - elb.NewLoadBalancerSource(elbClient, *callerID.Account, cfg.Region), + elb.NewInstanceHealthAdapter(elbClient, *callerID.Account, cfg.Region), + elb.NewLoadBalancerAdapter(elbClient, *callerID.Account, cfg.Region), // ELBv2 - elbv2.NewListenerSource(elbv2Client, *callerID.Account, cfg.Region), - elbv2.NewLoadBalancerSource(elbv2Client, *callerID.Account, cfg.Region), - elbv2.NewRuleSource(elbv2Client, *callerID.Account, cfg.Region), - elbv2.NewTargetGroupSource(elbv2Client, *callerID.Account, cfg.Region), - elbv2.NewTargetHealthSource(elbv2Client, *callerID.Account, cfg.Region), + elbv2.NewListenerAdapter(elbv2Client, *callerID.Account, cfg.Region), + elbv2.NewLoadBalancerAdapter(elbv2Client, *callerID.Account, cfg.Region), + elbv2.NewRuleAdapter(elbv2Client, *callerID.Account, cfg.Region), + elbv2.NewTargetGroupAdapter(elbv2Client, *callerID.Account, cfg.Region), + elbv2.NewTargetHealthAdapter(elbv2Client, *callerID.Account, cfg.Region), // Network Firewall - networkfirewall.NewFirewallSource(networkfirewallClient, *callerID.Account, cfg.Region), - networkfirewall.NewFirewallPolicySource(networkfirewallClient, *callerID.Account, cfg.Region), - networkfirewall.NewRuleGroupSource(networkfirewallClient, *callerID.Account, cfg.Region), - networkfirewall.NewTLSInspectionConfigurationSource(networkfirewallClient, *callerID.Account, cfg.Region), + networkfirewall.NewFirewallAdapter(networkfirewallClient, *callerID.Account, cfg.Region), + networkfirewall.NewFirewallPolicyAdapter(networkfirewallClient, *callerID.Account, cfg.Region), + networkfirewall.NewRuleGroupAdapter(networkfirewallClient, *callerID.Account, cfg.Region), + networkfirewall.NewTLSInspectionConfigurationAdapter(networkfirewallClient, *callerID.Account, cfg.Region), // Direct Connect - directconnect.NewDirectConnectGatewaySource(directconnectClient, *callerID.Account, cfg.Region), - directconnect.NewDirectConnectGatewayAssociationSource(directconnectClient, *callerID.Account, cfg.Region), - directconnect.NewDirectConnectGatewayAssociationProposalSource(directconnectClient, *callerID.Account, cfg.Region), - directconnect.NewConnectionSource(directconnectClient, *callerID.Account, cfg.Region), - directconnect.NewDirectConnectGatewayAttachmentSource(directconnectClient, *callerID.Account, cfg.Region), - directconnect.NewVirtualInterfaceSource(directconnectClient, *callerID.Account, cfg.Region), - directconnect.NewVirtualGatewaySource(directconnectClient, *callerID.Account, cfg.Region), - directconnect.NewCustomerMetadataSource(directconnectClient, *callerID.Account, cfg.Region), - directconnect.NewLagSource(directconnectClient, *callerID.Account, cfg.Region), - directconnect.NewLocationSource(directconnectClient, *callerID.Account, cfg.Region), - directconnect.NewHostedConnectionSource(directconnectClient, *callerID.Account, cfg.Region), - directconnect.NewInterconnectSource(directconnectClient, *callerID.Account, cfg.Region), - directconnect.NewRouterConfigurationSource(directconnectClient, *callerID.Account, cfg.Region), + directconnect.NewDirectConnectGatewayAdapter(directconnectClient, *callerID.Account, cfg.Region), + directconnect.NewDirectConnectGatewayAssociationAdapter(directconnectClient, *callerID.Account, cfg.Region), + directconnect.NewDirectConnectGatewayAssociationProposalAdapter(directconnectClient, *callerID.Account, cfg.Region), + directconnect.NewConnectionAdapter(directconnectClient, *callerID.Account, cfg.Region), + directconnect.NewDirectConnectGatewayAttachmentAdapter(directconnectClient, *callerID.Account, cfg.Region), + directconnect.NewVirtualInterfaceAdapter(directconnectClient, *callerID.Account, cfg.Region), + directconnect.NewVirtualGatewayAdapter(directconnectClient, *callerID.Account, cfg.Region), + directconnect.NewCustomerMetadataAdapter(directconnectClient, *callerID.Account, cfg.Region), + directconnect.NewLagAdapter(directconnectClient, *callerID.Account, cfg.Region), + directconnect.NewLocationAdapter(directconnectClient, *callerID.Account, cfg.Region), + directconnect.NewHostedConnectionAdapter(directconnectClient, *callerID.Account, cfg.Region), + directconnect.NewInterconnectAdapter(directconnectClient, *callerID.Account, cfg.Region), + directconnect.NewRouterConfigurationAdapter(directconnectClient, *callerID.Account, cfg.Region), // Network Manager - networkmanager.NewConnectAttachmentSource(networkmanagerClient, *callerID.Account, cfg.Region), - networkmanager.NewConnectPeerAssociationSource(networkmanagerClient, *callerID.Account, cfg.Region), - networkmanager.NewConnectPeerSource(networkmanagerClient, *callerID.Account, cfg.Region), - networkmanager.NewCoreNetworkPolicySource(networkmanagerClient, *callerID.Account, cfg.Region), - networkmanager.NewCoreNetworkSource(networkmanagerClient, *callerID.Account, cfg.Region), - networkmanager.NewNetworkResourceRelationshipsSource(networkmanagerClient, *callerID.Account, cfg.Region), - networkmanager.NewSiteToSiteVpnAttachmentSource(networkmanagerClient, *callerID.Account, cfg.Region), - networkmanager.NewTransitGatewayConnectPeerAssociationSource(networkmanagerClient, *callerID.Account, cfg.Region), - networkmanager.NewTransitGatewayPeeringSource(networkmanagerClient, *callerID.Account, cfg.Region), - networkmanager.NewTransitGatewayRegistrationSource(networkmanagerClient, *callerID.Account, cfg.Region), - networkmanager.NewTransitGatewayRouteTableAttachmentSource(networkmanagerClient, *callerID.Account, cfg.Region), - networkmanager.NewVPCAttachmentSource(networkmanagerClient, *callerID.Account, cfg.Region), + networkmanager.NewConnectAttachmentAdapter(networkmanagerClient, *callerID.Account, cfg.Region), + networkmanager.NewConnectPeerAssociationAdapter(networkmanagerClient, *callerID.Account, cfg.Region), + networkmanager.NewConnectPeerAdapter(networkmanagerClient, *callerID.Account, cfg.Region), + networkmanager.NewCoreNetworkPolicyAdapter(networkmanagerClient, *callerID.Account, cfg.Region), + networkmanager.NewCoreNetworkAdapter(networkmanagerClient, *callerID.Account, cfg.Region), + networkmanager.NewNetworkResourceRelationshipsAdapter(networkmanagerClient, *callerID.Account, cfg.Region), + networkmanager.NewSiteToSiteVpnAttachmentAdapter(networkmanagerClient, *callerID.Account, cfg.Region), + networkmanager.NewTransitGatewayConnectPeerAssociationAdapter(networkmanagerClient, *callerID.Account, cfg.Region), + networkmanager.NewTransitGatewayPeeringAdapter(networkmanagerClient, *callerID.Account, cfg.Region), + networkmanager.NewTransitGatewayRegistrationAdapter(networkmanagerClient, *callerID.Account, cfg.Region), + networkmanager.NewTransitGatewayRouteTableAttachmentAdapter(networkmanagerClient, *callerID.Account, cfg.Region), + networkmanager.NewVPCAttachmentAdapter(networkmanagerClient, *callerID.Account, cfg.Region), // SQS - sqs.NewQueueSource(sqsClient, *callerID.Account, cfg.Region), + sqs.NewQueueAdapter(sqsClient, *callerID.Account, cfg.Region), // SNS - sns.NewSubscriptionSource(snsClient, *callerID.Account, cfg.Region), - sns.NewTopicSource(snsClient, *callerID.Account, cfg.Region), - sns.NewPlatformApplicationSource(snsClient, *callerID.Account, cfg.Region), - sns.NewEndpointSource(snsClient, *callerID.Account, cfg.Region), - sns.NewDataProtectionPolicySource(snsClient, *callerID.Account, cfg.Region), + sns.NewSubscriptionAdapter(snsClient, *callerID.Account, cfg.Region), + sns.NewTopicAdapter(snsClient, *callerID.Account, cfg.Region), + sns.NewPlatformApplicationAdapter(snsClient, *callerID.Account, cfg.Region), + sns.NewEndpointAdapter(snsClient, *callerID.Account, cfg.Region), + sns.NewDataProtectionPolicyAdapter(snsClient, *callerID.Account, cfg.Region), // KMS - kms.NewKeySource(kmsClient, *callerID.Account, cfg.Region), - kms.NewCustomKeyStoreSource(kmsClient, *callerID.Account, cfg.Region), - kms.NewAliasSource(kmsClient, *callerID.Account, cfg.Region), - kms.NewGrantSource(kmsClient, *callerID.Account, cfg.Region), - kms.NewKeyPolicySource(kmsClient, *callerID.Account, cfg.Region), + kms.NewKeyAdapter(kmsClient, *callerID.Account, cfg.Region), + kms.NewCustomKeyStoreAdapter(kmsClient, *callerID.Account, cfg.Region), + kms.NewAliasAdapter(kmsClient, *callerID.Account, cfg.Region), + kms.NewGrantAdapter(kmsClient, *callerID.Account, cfg.Region), + kms.NewKeyPolicyAdapter(kmsClient, *callerID.Account, cfg.Region), // ApiGateway - apigateway.NewRestApiSource(apigatewayClient, *callerID.Account, cfg.Region), - apigateway.NewResourceSource(apigatewayClient, *callerID.Account, cfg.Region), + apigateway.NewRestApiAdapter(apigatewayClient, *callerID.Account, cfg.Region), + apigateway.NewResourceAdapter(apigatewayClient, *callerID.Account, cfg.Region), } - e.AddSources(sources...) + e.AddAdapters(adapters...) // Add "global" sources (those that aren't tied to a region, like // cloudfront). but only do this once for the first region. For // these APIs it doesn't matter which region we call them from, we // get global results if globalDone.CompareAndSwap(false, true) { - e.AddSources( + e.AddAdapters( // Cloudfront - cloudfront.NewCachePolicySource(cloudfrontClient, *callerID.Account), - cloudfront.NewContinuousDeploymentPolicySource(cloudfrontClient, *callerID.Account), - cloudfront.NewDistributionSource(cloudfrontClient, *callerID.Account), - cloudfront.NewFunctionSource(cloudfrontClient, *callerID.Account), - cloudfront.NewKeyGroupSource(cloudfrontClient, *callerID.Account), - cloudfront.NewOriginAccessControlSource(cloudfrontClient, *callerID.Account), - cloudfront.NewOriginRequestPolicySource(cloudfrontClient, *callerID.Account), - cloudfront.NewResponseHeadersPolicySource(cloudfrontClient, *callerID.Account), - cloudfront.NewRealtimeLogConfigsSource(cloudfrontClient, *callerID.Account), - cloudfront.NewStreamingDistributionSource(cloudfrontClient, *callerID.Account), + cloudfront.NewCachePolicyAdapter(cloudfrontClient, *callerID.Account), + cloudfront.NewContinuousDeploymentPolicyAdapter(cloudfrontClient, *callerID.Account), + cloudfront.NewDistributionAdapter(cloudfrontClient, *callerID.Account), + cloudfront.NewFunctionAdapter(cloudfrontClient, *callerID.Account), + cloudfront.NewKeyGroupAdapter(cloudfrontClient, *callerID.Account), + cloudfront.NewOriginAccessControlAdapter(cloudfrontClient, *callerID.Account), + cloudfront.NewOriginRequestPolicyAdapter(cloudfrontClient, *callerID.Account), + cloudfront.NewResponseHeadersPolicyAdapter(cloudfrontClient, *callerID.Account), + cloudfront.NewRealtimeLogConfigsAdapter(cloudfrontClient, *callerID.Account), + cloudfront.NewStreamingDistributionAdapter(cloudfrontClient, *callerID.Account), // S3 - s3.NewS3Source(cfg, *callerID.Account), + s3.NewS3Adapter(cfg, *callerID.Account), // Networkmanager - networkmanager.NewGlobalNetworkSource(networkmanagerClient, *callerID.Account), - networkmanager.NewSiteSource(networkmanagerClient, *callerID.Account), - networkmanager.NewLinkSource(networkmanagerClient, *callerID.Account), - networkmanager.NewDeviceSource(networkmanagerClient, *callerID.Account), - networkmanager.NewLinkAssociationSource(networkmanagerClient, *callerID.Account), - networkmanager.NewConnectionSource(networkmanagerClient, *callerID.Account), + networkmanager.NewGlobalNetworkAdapter(networkmanagerClient, *callerID.Account), + networkmanager.NewSiteAdapter(networkmanagerClient, *callerID.Account), + networkmanager.NewLinkAdapter(networkmanagerClient, *callerID.Account), + networkmanager.NewDeviceAdapter(networkmanagerClient, *callerID.Account), + networkmanager.NewLinkAssociationAdapter(networkmanagerClient, *callerID.Account), + networkmanager.NewConnectionAdapter(networkmanagerClient, *callerID.Account), ) } return nil diff --git a/sources/autoscaling/auto_scaling_group_test.go b/sources/autoscaling/auto_scaling_group_test.go deleted file mode 100644 index e124e014..00000000 --- a/sources/autoscaling/auto_scaling_group_test.go +++ /dev/null @@ -1,225 +0,0 @@ -package autoscaling - -import ( - "context" - "testing" - "time" - - "github.com/aws/aws-sdk-go-v2/service/autoscaling" - "github.com/aws/aws-sdk-go-v2/service/autoscaling/types" - "github.com/overmindtech/aws-source/sources" - "github.com/overmindtech/sdp-go" -) - -func TestAutoScalingGroupOutputMapper(t *testing.T) { - t.Parallel() - - output := autoscaling.DescribeAutoScalingGroupsOutput{ - AutoScalingGroups: []types.AutoScalingGroup{ - { - AutoScalingGroupName: sources.PtrString("eks-default-20230117110031319900000013-96c2dfb1-a11b-b5e4-6efb-0fea7e22855c"), - AutoScalingGroupARN: sources.PtrString("arn:aws:autoscaling:eu-west-2:944651592624:autoScalingGroup:1cbb0e22-818f-4d8b-8662-77f73d3713ca:autoScalingGroupName/eks-default-20230117110031319900000013-96c2dfb1-a11b-b5e4-6efb-0fea7e22855c"), - MixedInstancesPolicy: &types.MixedInstancesPolicy{ - LaunchTemplate: &types.LaunchTemplate{ - LaunchTemplateSpecification: &types.LaunchTemplateSpecification{ - LaunchTemplateId: sources.PtrString("lt-0174ff2b8909d0c75"), // link - LaunchTemplateName: sources.PtrString("eks-96c2dfb1-a11b-b5e4-6efb-0fea7e22855c"), - Version: sources.PtrString("1"), - }, - Overrides: []types.LaunchTemplateOverrides{ - { - InstanceType: sources.PtrString("t3.large"), - }, - }, - }, - InstancesDistribution: &types.InstancesDistribution{ - OnDemandAllocationStrategy: sources.PtrString("prioritized"), - OnDemandBaseCapacity: sources.PtrInt32(0), - OnDemandPercentageAboveBaseCapacity: sources.PtrInt32(100), - SpotAllocationStrategy: sources.PtrString("lowest-price"), - SpotInstancePools: sources.PtrInt32(2), - }, - }, - MinSize: sources.PtrInt32(1), - MaxSize: sources.PtrInt32(3), - DesiredCapacity: sources.PtrInt32(1), - DefaultCooldown: sources.PtrInt32(300), - AvailabilityZones: []string{ // link - "eu-west-2c", - "eu-west-2a", - "eu-west-2b", - }, - LoadBalancerNames: []string{}, // Ignored, classic load balancer - TargetGroupARNs: []string{ - "arn:partition:service:region:account-id:resource-type/resource-id", // link - }, - HealthCheckType: sources.PtrString("EC2"), - HealthCheckGracePeriod: sources.PtrInt32(15), - Instances: []types.Instance{ - { - InstanceId: sources.PtrString("i-0be6c4fe789cb1b78"), // link - InstanceType: sources.PtrString("t3.large"), - AvailabilityZone: sources.PtrString("eu-west-2c"), - LifecycleState: types.LifecycleStateInService, - HealthStatus: sources.PtrString("Healthy"), - LaunchTemplate: &types.LaunchTemplateSpecification{ - LaunchTemplateId: sources.PtrString("lt-0174ff2b8909d0c75"), // Link - LaunchTemplateName: sources.PtrString("eks-96c2dfb1-a11b-b5e4-6efb-0fea7e22855c"), - Version: sources.PtrString("1"), - }, - ProtectedFromScaleIn: sources.PtrBool(false), - }, - }, - CreatedTime: sources.PtrTime(time.Now()), - SuspendedProcesses: []types.SuspendedProcess{}, - VPCZoneIdentifier: sources.PtrString("subnet-0e234bef35fc4a9e1,subnet-09d5f6fa75b0b4569,subnet-0960234bbc4edca03"), - EnabledMetrics: []types.EnabledMetric{}, - Tags: []types.TagDescription{ - { - ResourceId: sources.PtrString("eks-default-20230117110031319900000013-96c2dfb1-a11b-b5e4-6efb-0fea7e22855c"), - ResourceType: sources.PtrString("auto-scaling-group"), - Key: sources.PtrString("eks:cluster-name"), - Value: sources.PtrString("dogfood"), - PropagateAtLaunch: sources.PtrBool(true), - }, - { - ResourceId: sources.PtrString("eks-default-20230117110031319900000013-96c2dfb1-a11b-b5e4-6efb-0fea7e22855c"), - ResourceType: sources.PtrString("auto-scaling-group"), - Key: sources.PtrString("eks:nodegroup-name"), - Value: sources.PtrString("default-20230117110031319900000013"), - PropagateAtLaunch: sources.PtrBool(true), - }, - { - ResourceId: sources.PtrString("eks-default-20230117110031319900000013-96c2dfb1-a11b-b5e4-6efb-0fea7e22855c"), - ResourceType: sources.PtrString("auto-scaling-group"), - Key: sources.PtrString("k8s.io/cluster-autoscaler/dogfood"), - Value: sources.PtrString("owned"), - PropagateAtLaunch: sources.PtrBool(true), - }, - { - ResourceId: sources.PtrString("eks-default-20230117110031319900000013-96c2dfb1-a11b-b5e4-6efb-0fea7e22855c"), - ResourceType: sources.PtrString("auto-scaling-group"), - Key: sources.PtrString("k8s.io/cluster-autoscaler/enabled"), - Value: sources.PtrString("true"), - PropagateAtLaunch: sources.PtrBool(true), - }, - { - ResourceId: sources.PtrString("eks-default-20230117110031319900000013-96c2dfb1-a11b-b5e4-6efb-0fea7e22855c"), - ResourceType: sources.PtrString("auto-scaling-group"), - Key: sources.PtrString("kubernetes.io/cluster/dogfood"), - Value: sources.PtrString("owned"), - PropagateAtLaunch: sources.PtrBool(true), - }, - }, - TerminationPolicies: []string{ - "AllocationStrategy", - "OldestLaunchTemplate", - "OldestInstance", - }, - NewInstancesProtectedFromScaleIn: sources.PtrBool(false), - ServiceLinkedRoleARN: sources.PtrString("arn:aws:iam::944651592624:role/aws-service-role/autoscaling.amazonaws.com/AWSServiceRoleForAutoScaling"), // link - CapacityRebalance: sources.PtrBool(true), - TrafficSources: []types.TrafficSourceIdentifier{ - { - Identifier: sources.PtrString("arn:partition:service:region:account-id:resource-type/resource-id"), // We will skip this for now since it's related to VPC lattice groups which are still in preview - }, - }, - Context: sources.PtrString("foo"), - DefaultInstanceWarmup: sources.PtrInt32(10), - DesiredCapacityType: sources.PtrString("foo"), - LaunchConfigurationName: sources.PtrString("launchConfig"), // link - LaunchTemplate: &types.LaunchTemplateSpecification{ - LaunchTemplateId: sources.PtrString("id"), // link - LaunchTemplateName: sources.PtrString("launchTemplateName"), - }, - MaxInstanceLifetime: sources.PtrInt32(30), - PlacementGroup: sources.PtrString("placementGroup"), // link (ec2) - PredictedCapacity: sources.PtrInt32(1), - Status: sources.PtrString("OK"), - WarmPoolConfiguration: &types.WarmPoolConfiguration{ - InstanceReusePolicy: &types.InstanceReusePolicy{ - ReuseOnScaleIn: sources.PtrBool(true), - }, - MaxGroupPreparedCapacity: sources.PtrInt32(1), - MinSize: sources.PtrInt32(1), - PoolState: types.WarmPoolStateHibernated, - Status: types.WarmPoolStatusPendingDelete, - }, - WarmPoolSize: sources.PtrInt32(1), - }, - }, - } - - items, err := autoScalingGroupOutputMapper(context.Background(), nil, "foo", nil, &output) - - if err != nil { - t.Error(err) - } - - for _, item := range items { - if err := item.Validate(); err != nil { - t.Error(err) - } - } - - if len(items) != 1 { - t.Errorf("expected 1 item, got %v", len(items)) - } - - item := items[0] - - // It doesn't really make sense to test anything other than the linked items - // since the attributes are converted automatically - tests := sources.QueryTests{ - { - ExpectedType: "ec2-launch-template", - ExpectedMethod: sdp.QueryMethod_GET, - ExpectedQuery: "lt-0174ff2b8909d0c75", - ExpectedScope: "foo", - }, - { - ExpectedType: "elbv2-target-group", - ExpectedMethod: sdp.QueryMethod_SEARCH, - ExpectedQuery: "arn:partition:service:region:account-id:resource-type/resource-id", - ExpectedScope: "account-id.region", - }, - { - ExpectedType: "ec2-instance", - ExpectedMethod: sdp.QueryMethod_GET, - ExpectedQuery: "i-0be6c4fe789cb1b78", - ExpectedScope: "foo", - }, - { - ExpectedType: "iam-role", - ExpectedMethod: sdp.QueryMethod_SEARCH, - ExpectedQuery: "arn:aws:iam::944651592624:role/aws-service-role/autoscaling.amazonaws.com/AWSServiceRoleForAutoScaling", - ExpectedScope: "944651592624", - }, - { - ExpectedType: "autoscaling-launch-configuration", - ExpectedMethod: sdp.QueryMethod_GET, - ExpectedQuery: "launchConfig", - ExpectedScope: "foo", - }, - { - ExpectedType: "ec2-launch-template", - ExpectedMethod: sdp.QueryMethod_GET, - ExpectedQuery: "id", - ExpectedScope: "foo", - }, - { - ExpectedType: "ec2-placement-group", - ExpectedMethod: sdp.QueryMethod_GET, - ExpectedQuery: "placementGroup", - ExpectedScope: "foo", - }, - { - ExpectedType: "ec2-launch-template", - ExpectedMethod: sdp.QueryMethod_GET, - ExpectedQuery: "lt-0174ff2b8909d0c75", - ExpectedScope: "foo", - }, - } - - tests.Execute(t, item) -} diff --git a/sources/ecs/container_instance_test.go b/sources/ecs/container_instance_test.go deleted file mode 100644 index 8d190f6d..00000000 --- a/sources/ecs/container_instance_test.go +++ /dev/null @@ -1,362 +0,0 @@ -package ecs - -import ( - "context" - "testing" - "time" - - "github.com/aws/aws-sdk-go-v2/service/ecs" - "github.com/aws/aws-sdk-go-v2/service/ecs/types" - "github.com/overmindtech/aws-source/sources" - "github.com/overmindtech/sdp-go" -) - -func (t *TestClient) DescribeContainerInstances(ctx context.Context, params *ecs.DescribeContainerInstancesInput, optFns ...func(*ecs.Options)) (*ecs.DescribeContainerInstancesOutput, error) { - return &ecs.DescribeContainerInstancesOutput{ - ContainerInstances: []types.ContainerInstance{ - { - ContainerInstanceArn: sources.PtrString("arn:aws:ecs:eu-west-1:052392120703:container-instance/ecs-template-ECSCluster-8nS0WOLbs3nZ/50e9bf71ed57450ca56293cc5a042886"), - Ec2InstanceId: sources.PtrString("i-0e778f25705bc0c84"), // link - Version: 4, - VersionInfo: &types.VersionInfo{ - AgentVersion: sources.PtrString("1.47.0"), - AgentHash: sources.PtrString("1489adfa"), - DockerVersion: sources.PtrString("DockerVersion: 19.03.6-ce"), - }, - RemainingResources: []types.Resource{ - { - Name: sources.PtrString("CPU"), - Type: sources.PtrString("INTEGER"), - DoubleValue: 0.0, - LongValue: 0, - IntegerValue: 2028, - }, - { - Name: sources.PtrString("MEMORY"), - Type: sources.PtrString("INTEGER"), - DoubleValue: 0.0, - LongValue: 0, - IntegerValue: 7474, - }, - { - Name: sources.PtrString("PORTS"), - Type: sources.PtrString("STRINGSET"), - DoubleValue: 0.0, - LongValue: 0, - IntegerValue: 0, - StringSetValue: []string{ - "22", - "2376", - "2375", - "51678", - "51679", - }, - }, - { - Name: sources.PtrString("PORTS_UDP"), - Type: sources.PtrString("STRINGSET"), - DoubleValue: 0.0, - LongValue: 0, - IntegerValue: 0, - StringSetValue: []string{}, - }, - }, - RegisteredResources: []types.Resource{ - { - Name: sources.PtrString("CPU"), - Type: sources.PtrString("INTEGER"), - DoubleValue: 0.0, - LongValue: 0, - IntegerValue: 2048, - }, - { - Name: sources.PtrString("MEMORY"), - Type: sources.PtrString("INTEGER"), - DoubleValue: 0.0, - LongValue: 0, - IntegerValue: 7974, - }, - { - Name: sources.PtrString("PORTS"), - Type: sources.PtrString("STRINGSET"), - DoubleValue: 0.0, - LongValue: 0, - IntegerValue: 0, - StringSetValue: []string{ - "22", - "2376", - "2375", - "51678", - "51679", - }, - }, - { - Name: sources.PtrString("PORTS_UDP"), - Type: sources.PtrString("STRINGSET"), - DoubleValue: 0.0, - LongValue: 0, - IntegerValue: 0, - StringSetValue: []string{}, - }, - }, - Status: sources.PtrString("ACTIVE"), - AgentConnected: true, - RunningTasksCount: 1, - PendingTasksCount: 0, - Attributes: []types.Attribute{ - { - Name: sources.PtrString("ecs.capability.secrets.asm.environment-variables"), - }, - { - Name: sources.PtrString("ecs.capability.branch-cni-plugin-version"), - Value: sources.PtrString("a21d3a41-"), - }, - { - Name: sources.PtrString("ecs.ami-id"), - Value: sources.PtrString("ami-0c9ef930279337028"), - }, - { - Name: sources.PtrString("ecs.capability.secrets.asm.bootstrap.log-driver"), - }, - { - Name: sources.PtrString("ecs.capability.task-eia.optimized-cpu"), - }, - { - Name: sources.PtrString("com.amazonaws.ecs.capability.logging-driver.none"), - }, - { - Name: sources.PtrString("ecs.capability.ecr-endpoint"), - }, - { - Name: sources.PtrString("ecs.capability.docker-plugin.local"), - }, - { - Name: sources.PtrString("ecs.capability.task-cpu-mem-limit"), - }, - { - Name: sources.PtrString("ecs.capability.secrets.ssm.bootstrap.log-driver"), - }, - { - Name: sources.PtrString("ecs.capability.efsAuth"), - }, - { - Name: sources.PtrString("ecs.capability.full-sync"), - }, - { - Name: sources.PtrString("com.amazonaws.ecs.capability.docker-remote-api.1.30"), - }, - { - Name: sources.PtrString("com.amazonaws.ecs.capability.docker-remote-api.1.31"), - }, - { - Name: sources.PtrString("com.amazonaws.ecs.capability.docker-remote-api.1.32"), - }, - { - Name: sources.PtrString("com.amazonaws.ecs.capability.logging-driver.fluentd"), - }, - { - Name: sources.PtrString("ecs.capability.firelens.options.config.file"), - }, - { - Name: sources.PtrString("ecs.availability-zone"), - Value: sources.PtrString("eu-west-1a"), - }, - { - Name: sources.PtrString("ecs.capability.aws-appmesh"), - }, - { - Name: sources.PtrString("com.amazonaws.ecs.capability.logging-driver.awslogs"), - }, - { - Name: sources.PtrString("com.amazonaws.ecs.capability.docker-remote-api.1.24"), - }, - { - Name: sources.PtrString("ecs.capability.task-eni-trunking"), - }, - { - Name: sources.PtrString("com.amazonaws.ecs.capability.docker-remote-api.1.25"), - }, - { - Name: sources.PtrString("com.amazonaws.ecs.capability.docker-remote-api.1.26"), - }, - { - Name: sources.PtrString("com.amazonaws.ecs.capability.docker-remote-api.1.27"), - }, - { - Name: sources.PtrString("com.amazonaws.ecs.capability.privileged-container"), - }, - { - Name: sources.PtrString("com.amazonaws.ecs.capability.docker-remote-api.1.28"), - }, - { - Name: sources.PtrString("com.amazonaws.ecs.capability.docker-remote-api.1.29"), - }, - { - Name: sources.PtrString("ecs.cpu-architecture"), - Value: sources.PtrString("x86_64"), - }, - { - Name: sources.PtrString("com.amazonaws.ecs.capability.ecr-auth"), - }, - { - Name: sources.PtrString("ecs.capability.firelens.fluentbit"), - }, - { - Name: sources.PtrString("com.amazonaws.ecs.capability.docker-remote-api.1.20"), - }, - { - Name: sources.PtrString("ecs.os-type"), - Value: sources.PtrString("linux"), - }, - { - Name: sources.PtrString("com.amazonaws.ecs.capability.docker-remote-api.1.21"), - }, - { - Name: sources.PtrString("com.amazonaws.ecs.capability.docker-remote-api.1.22"), - }, - { - Name: sources.PtrString("com.amazonaws.ecs.capability.docker-remote-api.1.23"), - }, - { - Name: sources.PtrString("ecs.capability.task-eia"), - }, - { - Name: sources.PtrString("ecs.capability.private-registry-authentication.secretsmanager"), - }, - { - Name: sources.PtrString("com.amazonaws.ecs.capability.logging-driver.syslog"), - }, - { - Name: sources.PtrString("com.amazonaws.ecs.capability.logging-driver.awsfirelens"), - }, - { - Name: sources.PtrString("ecs.capability.firelens.options.config.s3"), - }, - { - Name: sources.PtrString("com.amazonaws.ecs.capability.logging-driver.json-file"), - }, - { - Name: sources.PtrString("ecs.capability.execution-role-awslogs"), - }, - { - Name: sources.PtrString("ecs.vpc-id"), - Value: sources.PtrString("vpc-0e120717a7263de70"), - }, - { - Name: sources.PtrString("com.amazonaws.ecs.capability.docker-remote-api.1.17"), - }, - { - Name: sources.PtrString("com.amazonaws.ecs.capability.docker-remote-api.1.18"), - }, - { - Name: sources.PtrString("com.amazonaws.ecs.capability.docker-remote-api.1.19"), - }, - { - Name: sources.PtrString("ecs.capability.docker-plugin.amazon-ecs-volume-plugin"), - }, - { - Name: sources.PtrString("ecs.capability.task-eni"), - }, - { - Name: sources.PtrString("ecs.capability.firelens.fluentd"), - }, - { - Name: sources.PtrString("ecs.capability.efs"), - }, - { - Name: sources.PtrString("ecs.capability.execution-role-ecr-pull"), - }, - { - Name: sources.PtrString("ecs.capability.task-eni.ipv6"), - }, - { - Name: sources.PtrString("ecs.capability.container-health-check"), - }, - { - Name: sources.PtrString("ecs.subnet-id"), - Value: sources.PtrString("subnet-0bfdb717a234c01b3"), - }, - { - Name: sources.PtrString("ecs.instance-type"), - Value: sources.PtrString("t2.large"), - }, - { - Name: sources.PtrString("com.amazonaws.ecs.capability.task-iam-role-network-host"), - }, - { - Name: sources.PtrString("ecs.capability.container-ordering"), - }, - { - Name: sources.PtrString("ecs.capability.cni-plugin-version"), - Value: sources.PtrString("55b2ae77-2020.09.0"), - }, - { - Name: sources.PtrString("ecs.capability.env-files.s3"), - }, - { - Name: sources.PtrString("ecs.capability.pid-ipc-namespace-sharing"), - }, - { - Name: sources.PtrString("ecs.capability.secrets.ssm.environment-variables"), - }, - { - Name: sources.PtrString("com.amazonaws.ecs.capability.task-iam-role"), - }, - }, - RegisteredAt: sources.PtrTime(time.Now()), - Attachments: []types.Attachment{}, // There is probably an opportunity for some links here but I don't have example data - Tags: []types.Tag{}, - AgentUpdateStatus: types.AgentUpdateStatusFailed, - CapacityProviderName: sources.PtrString("name"), - HealthStatus: &types.ContainerInstanceHealthStatus{ - OverallStatus: types.InstanceHealthCheckStateImpaired, - }, - }, - }, - }, nil -} - -func (t *TestClient) ListContainerInstances(context.Context, *ecs.ListContainerInstancesInput, ...func(*ecs.Options)) (*ecs.ListContainerInstancesOutput, error) { - return &ecs.ListContainerInstancesOutput{ - ContainerInstanceArns: []string{ - "arn:aws:ecs:eu-west-1:052392120703:container-instance/ecs-template-ECSCluster-8nS0WOLbs3nZ/50e9bf71ed57450ca56293cc5a042886", - }, - }, nil -} - -func TestContainerInstanceGetFunc(t *testing.T) { - item, err := containerInstanceGetFunc(context.Background(), &TestClient{}, "foo", &ecs.DescribeContainerInstancesInput{}) - - if err != nil { - t.Error(err) - } - - if err = item.Validate(); err != nil { - t.Error(err) - } - - tests := sources.QueryTests{ - { - ExpectedType: "ec2-instance", - ExpectedMethod: sdp.QueryMethod_GET, - ExpectedQuery: "i-0e778f25705bc0c84", - ExpectedScope: "foo", - }, - } - - tests.Execute(t, item) -} - -func TestNewContainerInstanceSource(t *testing.T) { - client, account, region := GetAutoConfig(t) - - source := NewContainerInstanceSource(client, account, region) - - test := sources.E2ETest{ - Source: source, - Timeout: 10 * time.Second, - SkipNotFoundCheck: true, - } - - test.Run(t) -} diff --git a/sources/eks/addon_test.go b/sources/eks/addon_test.go deleted file mode 100644 index e9455c4c..00000000 --- a/sources/eks/addon_test.go +++ /dev/null @@ -1,62 +0,0 @@ -package eks - -import ( - "context" - "testing" - "time" - - "github.com/aws/aws-sdk-go-v2/service/eks" - "github.com/aws/aws-sdk-go-v2/service/eks/types" - "github.com/overmindtech/aws-source/sources" -) - -var AddonTestClient = TestClient{ - DescribeAddonOutput: &eks.DescribeAddonOutput{ - Addon: &types.Addon{ - AddonName: sources.PtrString("aws-ebs-csi-driver"), - ClusterName: sources.PtrString("dylan"), - Status: types.AddonStatusActive, - AddonVersion: sources.PtrString("v1.13.0-eksbuild.3"), - ConfigurationValues: sources.PtrString("values"), - MarketplaceInformation: &types.MarketplaceInformation{ - ProductId: sources.PtrString("id"), - ProductUrl: sources.PtrString("url"), - }, - Publisher: sources.PtrString("publisher"), - Owner: sources.PtrString("owner"), - Health: &types.AddonHealth{ - Issues: []types.AddonIssue{}, - }, - AddonArn: sources.PtrString("arn:aws:eks:eu-west-2:801795385023:addon/dylan/aws-ebs-csi-driver/a2c29d0e-72c4-a702-7887-2f739f4fc189"), - CreatedAt: sources.PtrTime(time.Now()), - ModifiedAt: sources.PtrTime(time.Now()), - ServiceAccountRoleArn: sources.PtrString("arn:aws:iam::801795385023:role/eks-csi-dylan"), - }, - }, -} - -func TestAddonGetFunc(t *testing.T) { - item, err := addonGetFunc(context.Background(), AddonTestClient, "foo", &eks.DescribeAddonInput{}) - - if err != nil { - t.Error(err) - } - - if err = item.Validate(); err != nil { - t.Error(err) - } -} - -func TestNewAddonSource(t *testing.T) { - client, account, region := GetAutoConfig(t) - - source := NewAddonSource(client, account, region) - - test := sources.E2ETest{ - Source: source, - Timeout: 10 * time.Second, - SkipNotFoundCheck: true, - } - - test.Run(t) -} diff --git a/sources/iam/instance_profile_test.go b/sources/iam/instance_profile_test.go deleted file mode 100644 index d2102d01..00000000 --- a/sources/iam/instance_profile_test.go +++ /dev/null @@ -1,69 +0,0 @@ -package iam - -import ( - "testing" - "time" - - "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/service/iam" - "github.com/aws/aws-sdk-go-v2/service/iam/types" - "github.com/overmindtech/aws-source/sources" -) - -func TestInstanceProfileItemMapper(t *testing.T) { - profile := types.InstanceProfile{ - Arn: sources.PtrString("arn:aws:iam::123456789012:instance-profile/webserver"), - CreateDate: sources.PtrTime(time.Now()), - InstanceProfileId: sources.PtrString("AIDACKCEVSQ6C2EXAMPLE"), - InstanceProfileName: sources.PtrString("webserver"), - Path: sources.PtrString("/"), - Roles: []types.Role{ - { - Arn: sources.PtrString("arn:aws:iam::123456789012:role/webserver"), // link - CreateDate: sources.PtrTime(time.Now()), - Path: sources.PtrString("/"), - RoleId: sources.PtrString("AIDACKCEVSQ6C2EXAMPLE"), - RoleName: sources.PtrString("webserver"), - AssumeRolePolicyDocument: sources.PtrString(`{}`), - Description: sources.PtrString("Allows EC2 instances to call AWS services on your behalf."), - MaxSessionDuration: sources.PtrInt32(3600), - PermissionsBoundary: &types.AttachedPermissionsBoundary{ - PermissionsBoundaryArn: sources.PtrString("arn:aws:iam::123456789012:policy/XCompanyBoundaries"), // link - PermissionsBoundaryType: types.PermissionsBoundaryAttachmentTypePolicy, - }, - RoleLastUsed: &types.RoleLastUsed{ - LastUsedDate: sources.PtrTime(time.Now()), - Region: sources.PtrString("us-east-1"), - }, - }, - }, - } - - item, err := instanceProfileItemMapper("", "foo", &profile) - - if err != nil { - t.Error(err) - } - - if err = item.Validate(); err != nil { - t.Error(err) - } - -} - -func TestNewInstanceProfileSource(t *testing.T) { - config, account, region := sources.GetAutoConfig(t) - client := iam.NewFromConfig(config, func(o *iam.Options) { - o.RetryMode = aws.RetryModeAdaptive - o.RetryMaxAttempts = 10 - }) - - source := NewInstanceProfileSource(client, account, region) - - test := sources.E2ETest{ - Source: source, - Timeout: 30 * time.Second, - } - - test.Run(t) -} diff --git a/sources/rds/db_cluster_parameter_group_test.go b/sources/rds/db_cluster_parameter_group_test.go deleted file mode 100644 index 60a31542..00000000 --- a/sources/rds/db_cluster_parameter_group_test.go +++ /dev/null @@ -1,98 +0,0 @@ -package rds - -import ( - "testing" - "time" - - "github.com/aws/aws-sdk-go-v2/service/rds/types" - "github.com/overmindtech/aws-source/sources" -) - -func TestDBClusterParameterGroupOutputMapper(t *testing.T) { - group := ClusterParameterGroup{ - DBClusterParameterGroup: types.DBClusterParameterGroup{ - DBClusterParameterGroupName: sources.PtrString("default.aurora-mysql5.7"), - DBParameterGroupFamily: sources.PtrString("aurora-mysql5.7"), - Description: sources.PtrString("Default cluster parameter group for aurora-mysql5.7"), - DBClusterParameterGroupArn: sources.PtrString("arn:aws:rds:eu-west-1:052392120703:cluster-pg:default.aurora-mysql5.7"), - }, - Parameters: []types.Parameter{ - { - ParameterName: sources.PtrString("activate_all_roles_on_login"), - ParameterValue: sources.PtrString("0"), - Description: sources.PtrString("Automatically set all granted roles as active after the user has authenticated successfully."), - Source: sources.PtrString("engine-default"), - ApplyType: sources.PtrString("dynamic"), - DataType: sources.PtrString("boolean"), - AllowedValues: sources.PtrString("0,1"), - IsModifiable: sources.PtrBool(true), - ApplyMethod: types.ApplyMethodPendingReboot, - SupportedEngineModes: []string{ - "provisioned", - }, - }, - { - ParameterName: sources.PtrString("allow-suspicious-udfs"), - Description: sources.PtrString("Controls whether user-defined functions that have only an xxx symbol for the main function can be loaded"), - Source: sources.PtrString("engine-default"), - ApplyType: sources.PtrString("static"), - DataType: sources.PtrString("boolean"), - AllowedValues: sources.PtrString("0,1"), - IsModifiable: sources.PtrBool(false), - ApplyMethod: types.ApplyMethodPendingReboot, - SupportedEngineModes: []string{ - "provisioned", - }, - }, - { - ParameterName: sources.PtrString("aurora_binlog_replication_max_yield_seconds"), - Description: sources.PtrString("Controls the number of seconds that binary log dump thread waits up to for the current binlog file to be filled by transactions. This wait period avoids contention that can arise from replicating each binlog event individually."), - Source: sources.PtrString("engine-default"), - ApplyType: sources.PtrString("dynamic"), - DataType: sources.PtrString("integer"), - AllowedValues: sources.PtrString("0-36000"), - IsModifiable: sources.PtrBool(true), - ApplyMethod: types.ApplyMethodPendingReboot, - SupportedEngineModes: []string{ - "provisioned", - }, - }, - { - ParameterName: sources.PtrString("aurora_enable_staggered_replica_restart"), - Description: sources.PtrString("Allow Aurora replicas to follow a staggered restart schedule to increase cluster availability."), - Source: sources.PtrString("system"), - ApplyType: sources.PtrString("dynamic"), - DataType: sources.PtrString("boolean"), - AllowedValues: sources.PtrString("0,1"), - IsModifiable: sources.PtrBool(true), - ApplyMethod: types.ApplyMethodImmediate, - SupportedEngineModes: []string{ - "provisioned", - }, - }, - }, - } - - item, err := dBClusterParameterGroupItemMapper("", "foo", &group) - - if err != nil { - t.Fatal(err) - } - - if err = item.Validate(); err != nil { - t.Error(err) - } -} - -func TestNewDBClusterParameterGroupSource(t *testing.T) { - client, account, region := GetAutoConfig(t) - - source := NewDBClusterParameterGroupSource(client, account, region) - - test := sources.E2ETest{ - Source: source, - Timeout: 10 * time.Second, - } - - test.Run(t) -} diff --git a/sources/rds/db_cluster_test.go b/sources/rds/db_cluster_test.go deleted file mode 100644 index 6aa0657c..00000000 --- a/sources/rds/db_cluster_test.go +++ /dev/null @@ -1,265 +0,0 @@ -package rds - -import ( - "context" - "testing" - "time" - - "github.com/aws/aws-sdk-go-v2/service/rds" - "github.com/aws/aws-sdk-go-v2/service/rds/types" - "github.com/overmindtech/aws-source/sources" - "github.com/overmindtech/sdp-go" -) - -func TestDBClusterOutputMapper(t *testing.T) { - output := rds.DescribeDBClustersOutput{ - DBClusters: []types.DBCluster{ - { - AllocatedStorage: sources.PtrInt32(100), - AvailabilityZones: []string{ - "eu-west-2c", // link - }, - BackupRetentionPeriod: sources.PtrInt32(7), - DBClusterIdentifier: sources.PtrString("database-2"), - DBClusterParameterGroup: sources.PtrString("default.postgres13"), - DBSubnetGroup: sources.PtrString("default-vpc-0d7892e00e573e701"), // link - Status: sources.PtrString("available"), - EarliestRestorableTime: sources.PtrTime(time.Now()), - Endpoint: sources.PtrString("database-2.cluster-camcztjohmlj.eu-west-2.rds.amazonaws.com"), // link - ReaderEndpoint: sources.PtrString("database-2.cluster-ro-camcztjohmlj.eu-west-2.rds.amazonaws.com"), // link - MultiAZ: sources.PtrBool(true), - Engine: sources.PtrString("postgres"), - EngineVersion: sources.PtrString("13.7"), - LatestRestorableTime: sources.PtrTime(time.Now()), - Port: sources.PtrInt32(5432), // link - MasterUsername: sources.PtrString("postgres"), - PreferredBackupWindow: sources.PtrString("04:48-05:18"), - PreferredMaintenanceWindow: sources.PtrString("fri:04:05-fri:04:35"), - ReadReplicaIdentifiers: []string{ - "arn:aws:rds:eu-west-1:052392120703:cluster:read-replica", // link - }, - DBClusterMembers: []types.DBClusterMember{ - { - DBInstanceIdentifier: sources.PtrString("database-2-instance-3"), // link - IsClusterWriter: sources.PtrBool(false), - DBClusterParameterGroupStatus: sources.PtrString("in-sync"), - PromotionTier: sources.PtrInt32(1), - }, - }, - VpcSecurityGroups: []types.VpcSecurityGroupMembership{ - { - VpcSecurityGroupId: sources.PtrString("sg-094e151c9fc5da181"), // link - Status: sources.PtrString("active"), - }, - }, - HostedZoneId: sources.PtrString("Z1TTGA775OQIYO"), // link - StorageEncrypted: sources.PtrBool(true), - KmsKeyId: sources.PtrString("arn:aws:kms:eu-west-2:052392120703:key/9653cbdd-1590-464a-8456-67389cef6933"), // link - DbClusterResourceId: sources.PtrString("cluster-2EW4PDVN7F7V57CUJPYOEAA74M"), - DBClusterArn: sources.PtrString("arn:aws:rds:eu-west-2:052392120703:cluster:database-2"), - IAMDatabaseAuthenticationEnabled: sources.PtrBool(false), - ClusterCreateTime: sources.PtrTime(time.Now()), - EngineMode: sources.PtrString("provisioned"), - DeletionProtection: sources.PtrBool(false), - HttpEndpointEnabled: sources.PtrBool(false), - ActivityStreamStatus: types.ActivityStreamStatusStopped, - CopyTagsToSnapshot: sources.PtrBool(false), - CrossAccountClone: sources.PtrBool(false), - DomainMemberships: []types.DomainMembership{}, - TagList: []types.Tag{}, - DBClusterInstanceClass: sources.PtrString("db.m5d.large"), - StorageType: sources.PtrString("io1"), - Iops: sources.PtrInt32(1000), - PubliclyAccessible: sources.PtrBool(true), - AutoMinorVersionUpgrade: sources.PtrBool(true), - MonitoringInterval: sources.PtrInt32(0), - PerformanceInsightsEnabled: sources.PtrBool(false), - NetworkType: sources.PtrString("IPV4"), - ActivityStreamKinesisStreamName: sources.PtrString("aws-rds-das-db-AB1CDEFG23GHIJK4LMNOPQRST"), // link - ActivityStreamKmsKeyId: sources.PtrString("ab12345e-1111-2bc3-12a3-ab1cd12345e"), // Not linking at the moment because there are too many possible formats. If you want to change this, submit a PR - ActivityStreamMode: types.ActivityStreamModeAsync, - AutomaticRestartTime: sources.PtrTime(time.Now()), - AssociatedRoles: []types.DBClusterRole{}, // EC2 classic roles, ignore - BacktrackConsumedChangeRecords: sources.PtrInt64(1), - BacktrackWindow: sources.PtrInt64(2), - Capacity: sources.PtrInt32(2), - CharacterSetName: sources.PtrString("english"), - CloneGroupId: sources.PtrString("id"), - CustomEndpoints: []string{ - "endpoint1", // link dns - }, - DBClusterOptionGroupMemberships: []types.DBClusterOptionGroupStatus{ - { - DBClusterOptionGroupName: sources.PtrString("optionGroupName"), // link - Status: sources.PtrString("good"), - }, - }, - DBSystemId: sources.PtrString("systemId"), - DatabaseName: sources.PtrString("databaseName"), - EarliestBacktrackTime: sources.PtrTime(time.Now()), - EnabledCloudwatchLogsExports: []string{ - "logExport1", - }, - GlobalWriteForwardingRequested: sources.PtrBool(true), - GlobalWriteForwardingStatus: types.WriteForwardingStatusDisabled, - MasterUserSecret: &types.MasterUserSecret{ - KmsKeyId: sources.PtrString("arn:aws:kms:eu-west-2:052392120703:key/something"), // link - SecretArn: sources.PtrString("arn:aws:service:region:account:type/id"), // link - SecretStatus: sources.PtrString("okay"), - }, - MonitoringRoleArn: sources.PtrString("arn:aws:service:region:account:type/id"), // link - PendingModifiedValues: &types.ClusterPendingModifiedValues{}, - PercentProgress: sources.PtrString("99"), - PerformanceInsightsKMSKeyId: sources.PtrString("arn:aws:service:region:account:type/id"), // link, assuming it's an ARN - PerformanceInsightsRetentionPeriod: sources.PtrInt32(99), - ReplicationSourceIdentifier: sources.PtrString("arn:aws:rds:eu-west-2:052392120703:cluster:database-1"), // link - ScalingConfigurationInfo: &types.ScalingConfigurationInfo{ - AutoPause: sources.PtrBool(true), - MaxCapacity: sources.PtrInt32(10), - MinCapacity: sources.PtrInt32(1), - SecondsBeforeTimeout: sources.PtrInt32(10), - SecondsUntilAutoPause: sources.PtrInt32(10), - TimeoutAction: sources.PtrString("error"), - }, - ServerlessV2ScalingConfiguration: &types.ServerlessV2ScalingConfigurationInfo{ - MaxCapacity: sources.PtrFloat64(10), - MinCapacity: sources.PtrFloat64(1), - }, - }, - }, - } - - items, err := dBClusterOutputMapper(context.Background(), mockRdsClient{}, "foo", nil, &output) - - if err != nil { - t.Fatal(err) - } - - if len(items) != 1 { - t.Fatalf("got %v items, expected 1", len(items)) - } - - item := items[0] - - if err = item.Validate(); err != nil { - t.Error(err) - } - - if item.GetTags()["key"] != "value" { - t.Errorf("expected tag key to be value, got %v", item.GetTags()["key"]) - } - - tests := sources.QueryTests{ - { - ExpectedType: "rds-db-subnet-group", - ExpectedMethod: sdp.QueryMethod_GET, - ExpectedQuery: "default-vpc-0d7892e00e573e701", - ExpectedScope: "foo", - }, - { - ExpectedType: "dns", - ExpectedMethod: sdp.QueryMethod_SEARCH, - ExpectedQuery: "database-2.cluster-ro-camcztjohmlj.eu-west-2.rds.amazonaws.com", - ExpectedScope: "global", - }, - { - ExpectedType: "dns", - ExpectedMethod: sdp.QueryMethod_SEARCH, - ExpectedQuery: "database-2.cluster-camcztjohmlj.eu-west-2.rds.amazonaws.com", - ExpectedScope: "global", - }, - { - ExpectedType: "rds-db-cluster", - ExpectedMethod: sdp.QueryMethod_SEARCH, - ExpectedQuery: "arn:aws:rds:eu-west-1:052392120703:cluster:read-replica", - ExpectedScope: "052392120703.eu-west-1", - }, - { - ExpectedType: "rds-db-instance", - ExpectedMethod: sdp.QueryMethod_GET, - ExpectedQuery: "database-2-instance-3", - ExpectedScope: "foo", - }, - { - ExpectedType: "ec2-security-group", - ExpectedMethod: sdp.QueryMethod_GET, - ExpectedQuery: "sg-094e151c9fc5da181", - ExpectedScope: "foo", - }, - { - ExpectedType: "route53-hosted-zone", - ExpectedMethod: sdp.QueryMethod_GET, - ExpectedQuery: "Z1TTGA775OQIYO", - ExpectedScope: "foo", - }, - { - ExpectedType: "kms-key", - ExpectedMethod: sdp.QueryMethod_SEARCH, - ExpectedQuery: "arn:aws:kms:eu-west-2:052392120703:key/9653cbdd-1590-464a-8456-67389cef6933", - ExpectedScope: "052392120703.eu-west-2", - }, - { - ExpectedType: "kinesis-stream", - ExpectedMethod: sdp.QueryMethod_GET, - ExpectedQuery: "aws-rds-das-db-AB1CDEFG23GHIJK4LMNOPQRST", - ExpectedScope: "foo", - }, - { - ExpectedType: "dns", - ExpectedMethod: sdp.QueryMethod_SEARCH, - ExpectedQuery: "endpoint1", - ExpectedScope: "global", - }, - { - ExpectedType: "rds-option-group", - ExpectedMethod: sdp.QueryMethod_GET, - ExpectedQuery: "optionGroupName", - ExpectedScope: "foo", - }, - { - ExpectedType: "kms-key", - ExpectedMethod: sdp.QueryMethod_SEARCH, - ExpectedQuery: "arn:aws:kms:eu-west-2:052392120703:key/something", - ExpectedScope: "052392120703.eu-west-2", - }, - { - ExpectedType: "secretsmanager-secret", - ExpectedMethod: sdp.QueryMethod_SEARCH, - ExpectedQuery: "arn:aws:service:region:account:type/id", - ExpectedScope: "account.region", - }, - { - ExpectedType: "iam-role", - ExpectedMethod: sdp.QueryMethod_SEARCH, - ExpectedQuery: "arn:aws:service:region:account:type/id", - ExpectedScope: "account.region", - }, - { - ExpectedType: "kms-key", - ExpectedMethod: sdp.QueryMethod_SEARCH, - ExpectedQuery: "arn:aws:service:region:account:type/id", - ExpectedScope: "account.region", - }, - { - ExpectedType: "rds-db-cluster", - ExpectedMethod: sdp.QueryMethod_SEARCH, - ExpectedQuery: "arn:aws:rds:eu-west-2:052392120703:cluster:database-1", - ExpectedScope: "052392120703.eu-west-2", - }, - } - - tests.Execute(t, item) -} - -func TestNewDBClusterSource(t *testing.T) { - client, account, region := GetAutoConfig(t) - - source := NewDBClusterSource(client, account, region) - - test := sources.E2ETest{ - Source: source, - Timeout: 10 * time.Second, - } - - test.Run(t) -} diff --git a/sources/rds/db_instance_test.go b/sources/rds/db_instance_test.go deleted file mode 100644 index 4bf45ce6..00000000 --- a/sources/rds/db_instance_test.go +++ /dev/null @@ -1,323 +0,0 @@ -package rds - -import ( - "context" - "testing" - "time" - - "github.com/aws/aws-sdk-go-v2/service/rds" - "github.com/aws/aws-sdk-go-v2/service/rds/types" - "github.com/overmindtech/aws-source/sources" - "github.com/overmindtech/sdp-go" -) - -func TestDBInstanceOutputMapper(t *testing.T) { - output := &rds.DescribeDBInstancesOutput{ - DBInstances: []types.DBInstance{ - { - DBInstanceIdentifier: sources.PtrString("database-1-instance-1"), - DBInstanceClass: sources.PtrString("db.r6g.large"), - Engine: sources.PtrString("aurora-mysql"), - DBInstanceStatus: sources.PtrString("available"), - MasterUsername: sources.PtrString("admin"), - Endpoint: &types.Endpoint{ - Address: sources.PtrString("database-1-instance-1.camcztjohmlj.eu-west-2.rds.amazonaws.com"), // link - Port: sources.PtrInt32(3306), // link - HostedZoneId: sources.PtrString("Z1TTGA775OQIYO"), // link - }, - AllocatedStorage: sources.PtrInt32(1), - InstanceCreateTime: sources.PtrTime(time.Now()), - PreferredBackupWindow: sources.PtrString("00:05-00:35"), - BackupRetentionPeriod: sources.PtrInt32(1), - DBSecurityGroups: []types.DBSecurityGroupMembership{ - { - DBSecurityGroupName: sources.PtrString("name"), // This is EC2Classic only so we're skipping this - }, - }, - VpcSecurityGroups: []types.VpcSecurityGroupMembership{ - { - VpcSecurityGroupId: sources.PtrString("sg-094e151c9fc5da181"), // link - Status: sources.PtrString("active"), - }, - }, - DBParameterGroups: []types.DBParameterGroupStatus{ - { - DBParameterGroupName: sources.PtrString("default.aurora-mysql8.0"), // link - ParameterApplyStatus: sources.PtrString("in-sync"), - }, - }, - AvailabilityZone: sources.PtrString("eu-west-2a"), // link - DBSubnetGroup: &types.DBSubnetGroup{ - DBSubnetGroupName: sources.PtrString("default-vpc-0d7892e00e573e701"), // link - DBSubnetGroupDescription: sources.PtrString("Created from the RDS Management Console"), - VpcId: sources.PtrString("vpc-0d7892e00e573e701"), // link - SubnetGroupStatus: sources.PtrString("Complete"), - Subnets: []types.Subnet{ - { - SubnetIdentifier: sources.PtrString("subnet-0d8ae4b4e07647efa"), // lnk - SubnetAvailabilityZone: &types.AvailabilityZone{ - Name: sources.PtrString("eu-west-2b"), - }, - SubnetOutpost: &types.Outpost{ - Arn: sources.PtrString("arn:aws:service:region:account:type/id"), // link - }, - SubnetStatus: sources.PtrString("Active"), - }, - }, - }, - PreferredMaintenanceWindow: sources.PtrString("fri:04:49-fri:05:19"), - PendingModifiedValues: &types.PendingModifiedValues{}, - MultiAZ: sources.PtrBool(false), - EngineVersion: sources.PtrString("8.0.mysql_aurora.3.02.0"), - AutoMinorVersionUpgrade: sources.PtrBool(true), - ReadReplicaDBInstanceIdentifiers: []string{ - "read", - }, - LicenseModel: sources.PtrString("general-public-license"), - OptionGroupMemberships: []types.OptionGroupMembership{ - { - OptionGroupName: sources.PtrString("default:aurora-mysql-8-0"), - Status: sources.PtrString("in-sync"), - }, - }, - PubliclyAccessible: sources.PtrBool(false), - StorageType: sources.PtrString("aurora"), - DbInstancePort: sources.PtrInt32(0), - DBClusterIdentifier: sources.PtrString("database-1"), // link - StorageEncrypted: sources.PtrBool(true), - KmsKeyId: sources.PtrString("arn:aws:kms:eu-west-2:052392120703:key/9653cbdd-1590-464a-8456-67389cef6933"), // link - DbiResourceId: sources.PtrString("db-ET7CE5D5TQTK7MXNJGJNFQD52E"), - CACertificateIdentifier: sources.PtrString("rds-ca-2019"), - DomainMemberships: []types.DomainMembership{ - { - Domain: sources.PtrString("domain"), - FQDN: sources.PtrString("fqdn"), - IAMRoleName: sources.PtrString("role"), - Status: sources.PtrString("enrolled"), - }, - }, - CopyTagsToSnapshot: sources.PtrBool(false), - MonitoringInterval: sources.PtrInt32(60), - EnhancedMonitoringResourceArn: sources.PtrString("arn:aws:logs:eu-west-2:052392120703:log-group:RDSOSMetrics:log-stream:db-ET7CE5D5TQTK7MXNJGJNFQD52E"), // link - MonitoringRoleArn: sources.PtrString("arn:aws:iam::052392120703:role/rds-monitoring-role"), // link - PromotionTier: sources.PtrInt32(1), - DBInstanceArn: sources.PtrString("arn:aws:rds:eu-west-2:052392120703:db:database-1-instance-1"), - IAMDatabaseAuthenticationEnabled: sources.PtrBool(false), - PerformanceInsightsEnabled: sources.PtrBool(true), - PerformanceInsightsKMSKeyId: sources.PtrString("arn:aws:kms:eu-west-2:052392120703:key/9653cbdd-1590-464a-8456-67389cef6933"), // link - PerformanceInsightsRetentionPeriod: sources.PtrInt32(7), - DeletionProtection: sources.PtrBool(false), - AssociatedRoles: []types.DBInstanceRole{ - { - FeatureName: sources.PtrString("something"), - RoleArn: sources.PtrString("arn:aws:service:region:account:type/id"), // link - Status: sources.PtrString("associated"), - }, - }, - TagList: []types.Tag{}, - CustomerOwnedIpEnabled: sources.PtrBool(false), - BackupTarget: sources.PtrString("region"), - NetworkType: sources.PtrString("IPV4"), - StorageThroughput: sources.PtrInt32(0), - ActivityStreamEngineNativeAuditFieldsIncluded: sources.PtrBool(true), - ActivityStreamKinesisStreamName: sources.PtrString("aws-rds-das-db-AB1CDEFG23GHIJK4LMNOPQRST"), // link - ActivityStreamKmsKeyId: sources.PtrString("ab12345e-1111-2bc3-12a3-ab1cd12345e"), // Not linking at the moment because there are too many possible formats. If you want to change this, submit a PR - ActivityStreamMode: types.ActivityStreamModeAsync, - ActivityStreamPolicyStatus: types.ActivityStreamPolicyStatusLocked, - ActivityStreamStatus: types.ActivityStreamStatusStarted, - AutomaticRestartTime: sources.PtrTime(time.Now()), - AutomationMode: types.AutomationModeAllPaused, - AwsBackupRecoveryPointArn: sources.PtrString("arn:aws:service:region:account:type/id"), // link - CertificateDetails: &types.CertificateDetails{ - CAIdentifier: sources.PtrString("id"), - ValidTill: sources.PtrTime(time.Now()), - }, - CharacterSetName: sources.PtrString("something"), - CustomIamInstanceProfile: sources.PtrString("arn:aws:service:region:account:type/id"), // link? - DBInstanceAutomatedBackupsReplications: []types.DBInstanceAutomatedBackupsReplication{ - { - DBInstanceAutomatedBackupsArn: sources.PtrString("arn:aws:service:region:account:type/id"), // link - }, - }, - DBName: sources.PtrString("name"), - DBSystemId: sources.PtrString("id"), - EnabledCloudwatchLogsExports: []string{}, - Iops: sources.PtrInt32(10), - LatestRestorableTime: sources.PtrTime(time.Now()), - ListenerEndpoint: &types.Endpoint{ - Address: sources.PtrString("foo.bar.com"), // link - HostedZoneId: sources.PtrString("id"), // link - Port: sources.PtrInt32(5432), // link - }, - MasterUserSecret: &types.MasterUserSecret{ - KmsKeyId: sources.PtrString("id"), // link - SecretArn: sources.PtrString("arn:aws:service:region:account:type/id"), // link - SecretStatus: sources.PtrString("okay"), - }, - MaxAllocatedStorage: sources.PtrInt32(10), - NcharCharacterSetName: sources.PtrString("english"), - ProcessorFeatures: []types.ProcessorFeature{}, - ReadReplicaDBClusterIdentifiers: []string{}, - ReadReplicaSourceDBInstanceIdentifier: sources.PtrString("id"), - ReplicaMode: types.ReplicaModeMounted, - ResumeFullAutomationModeTime: sources.PtrTime(time.Now()), - SecondaryAvailabilityZone: sources.PtrString("eu-west-1"), // link - StatusInfos: []types.DBInstanceStatusInfo{}, - TdeCredentialArn: sources.PtrString("arn:aws:service:region:account:type/id"), // I don't have a good example for this so skipping for now. PR if required - Timezone: sources.PtrString("GB"), - }, - }, - } - - items, err := dBInstanceOutputMapper(context.Background(), mockRdsClient{}, "foo", nil, output) - - if err != nil { - t.Fatal(err) - } - - if len(items) != 1 { - t.Fatalf("got %v items, expected 1", len(items)) - } - - item := items[0] - - if err = item.Validate(); err != nil { - t.Error(err) - } - - if item.GetTags()["key"] != "value" { - t.Errorf("got %v, expected %v", item.GetTags()["key"], "value") - } - - tests := sources.QueryTests{ - { - ExpectedType: "dns", - ExpectedMethod: sdp.QueryMethod_SEARCH, - ExpectedQuery: "database-1-instance-1.camcztjohmlj.eu-west-2.rds.amazonaws.com", - ExpectedScope: "global", - }, - { - ExpectedType: "route53-hosted-zone", - ExpectedMethod: sdp.QueryMethod_GET, - ExpectedQuery: "Z1TTGA775OQIYO", - ExpectedScope: "foo", - }, - { - ExpectedType: "ec2-security-group", - ExpectedMethod: sdp.QueryMethod_GET, - ExpectedQuery: "sg-094e151c9fc5da181", - ExpectedScope: "foo", - }, - { - ExpectedType: "rds-db-parameter-group", - ExpectedMethod: sdp.QueryMethod_GET, - ExpectedQuery: "default.aurora-mysql8.0", - ExpectedScope: "foo", - }, - { - ExpectedType: "rds-db-subnet-group", - ExpectedMethod: sdp.QueryMethod_GET, - ExpectedQuery: "default-vpc-0d7892e00e573e701", - ExpectedScope: "foo", - }, - { - ExpectedType: "rds-db-cluster", - ExpectedMethod: sdp.QueryMethod_GET, - ExpectedQuery: "database-1", - ExpectedScope: "foo", - }, - { - ExpectedType: "kms-key", - ExpectedMethod: sdp.QueryMethod_SEARCH, - ExpectedQuery: "arn:aws:kms:eu-west-2:052392120703:key/9653cbdd-1590-464a-8456-67389cef6933", - ExpectedScope: "052392120703.eu-west-2", - }, - { - ExpectedType: "logs-log-stream", - ExpectedMethod: sdp.QueryMethod_SEARCH, - ExpectedQuery: "arn:aws:logs:eu-west-2:052392120703:log-group:RDSOSMetrics:log-stream:db-ET7CE5D5TQTK7MXNJGJNFQD52E", - ExpectedScope: "052392120703.eu-west-2", - }, - { - ExpectedType: "iam-role", - ExpectedMethod: sdp.QueryMethod_SEARCH, - ExpectedQuery: "arn:aws:iam::052392120703:role/rds-monitoring-role", - ExpectedScope: "052392120703", - }, - { - ExpectedType: "kms-key", - ExpectedMethod: sdp.QueryMethod_SEARCH, - ExpectedQuery: "arn:aws:kms:eu-west-2:052392120703:key/9653cbdd-1590-464a-8456-67389cef6933", - ExpectedScope: "052392120703.eu-west-2", - }, - { - ExpectedType: "iam-role", - ExpectedMethod: sdp.QueryMethod_SEARCH, - ExpectedQuery: "arn:aws:service:region:account:type/id", - ExpectedScope: "account.region", - }, - { - ExpectedType: "kinesis-stream", - ExpectedMethod: sdp.QueryMethod_GET, - ExpectedQuery: "aws-rds-das-db-AB1CDEFG23GHIJK4LMNOPQRST", - ExpectedScope: "foo", - }, - { - ExpectedType: "backup-recovery-point", - ExpectedMethod: sdp.QueryMethod_SEARCH, - ExpectedQuery: "arn:aws:service:region:account:type/id", - ExpectedScope: "account.region", - }, - { - ExpectedType: "iam-instance-profile", - ExpectedMethod: sdp.QueryMethod_SEARCH, - ExpectedQuery: "arn:aws:service:region:account:type/id", - ExpectedScope: "account.region", - }, - { - ExpectedType: "rds-db-instance-automated-backup", - ExpectedMethod: sdp.QueryMethod_SEARCH, - ExpectedQuery: "arn:aws:service:region:account:type/id", - ExpectedScope: "account.region", - }, - { - ExpectedType: "dns", - ExpectedMethod: sdp.QueryMethod_SEARCH, - ExpectedQuery: "foo.bar.com", - ExpectedScope: "global", - }, - { - ExpectedType: "route53-hosted-zone", - ExpectedMethod: sdp.QueryMethod_GET, - ExpectedQuery: "id", - ExpectedScope: "foo", - }, - { - ExpectedType: "kms-key", - ExpectedMethod: sdp.QueryMethod_GET, - ExpectedQuery: "id", - ExpectedScope: "foo", - }, - { - ExpectedType: "secretsmanager-secret", - ExpectedMethod: sdp.QueryMethod_SEARCH, - ExpectedQuery: "arn:aws:service:region:account:type/id", - ExpectedScope: "account.region", - }, - } - - tests.Execute(t, item) -} - -func TestNewDBInstanceSource(t *testing.T) { - client, account, region := GetAutoConfig(t) - - source := NewDBInstanceSource(client, account, region) - - test := sources.E2ETest{ - Source: source, - Timeout: 10 * time.Second, - } - - test.Run(t) -} diff --git a/sources/rds/db_parameter_group_test.go b/sources/rds/db_parameter_group_test.go deleted file mode 100644 index 81fa0b16..00000000 --- a/sources/rds/db_parameter_group_test.go +++ /dev/null @@ -1,86 +0,0 @@ -package rds - -import ( - "testing" - "time" - - "github.com/aws/aws-sdk-go-v2/service/rds/types" - "github.com/overmindtech/aws-source/sources" -) - -func TestDBParameterGroupOutputMapper(t *testing.T) { - group := ParameterGroup{ - DBParameterGroup: types.DBParameterGroup{ - DBParameterGroupName: sources.PtrString("default.aurora-mysql5.7"), - DBParameterGroupFamily: sources.PtrString("aurora-mysql5.7"), - Description: sources.PtrString("Default parameter group for aurora-mysql5.7"), - DBParameterGroupArn: sources.PtrString("arn:aws:rds:eu-west-1:052392120703:pg:default.aurora-mysql5.7"), - }, - Parameters: []types.Parameter{ - { - ParameterName: sources.PtrString("activate_all_roles_on_login"), - ParameterValue: sources.PtrString("0"), - Description: sources.PtrString("Automatically set all granted roles as active after the user has authenticated successfully."), - Source: sources.PtrString("engine-default"), - ApplyType: sources.PtrString("dynamic"), - DataType: sources.PtrString("boolean"), - AllowedValues: sources.PtrString("0,1"), - IsModifiable: sources.PtrBool(true), - ApplyMethod: types.ApplyMethodPendingReboot, - }, - { - ParameterName: sources.PtrString("allow-suspicious-udfs"), - Description: sources.PtrString("Controls whether user-defined functions that have only an xxx symbol for the main function can be loaded"), - Source: sources.PtrString("engine-default"), - ApplyType: sources.PtrString("static"), - DataType: sources.PtrString("boolean"), - AllowedValues: sources.PtrString("0,1"), - IsModifiable: sources.PtrBool(false), - ApplyMethod: types.ApplyMethodPendingReboot, - }, - { - ParameterName: sources.PtrString("aurora_parallel_query"), - Description: sources.PtrString("This parameter can be used to enable and disable Aurora Parallel Query."), - Source: sources.PtrString("engine-default"), - ApplyType: sources.PtrString("dynamic"), - DataType: sources.PtrString("boolean"), - AllowedValues: sources.PtrString("0,1"), - IsModifiable: sources.PtrBool(true), - ApplyMethod: types.ApplyMethodPendingReboot, - }, - { - ParameterName: sources.PtrString("autocommit"), - Description: sources.PtrString("Sets the autocommit mode"), - Source: sources.PtrString("engine-default"), - ApplyType: sources.PtrString("dynamic"), - DataType: sources.PtrString("boolean"), - AllowedValues: sources.PtrString("0,1"), - IsModifiable: sources.PtrBool(true), - ApplyMethod: types.ApplyMethodPendingReboot, - }, - }, - } - - item, err := dBParameterGroupItemMapper("", "foo", &group) - - if err != nil { - t.Fatal(err) - } - - if err = item.Validate(); err != nil { - t.Error(err) - } -} - -func TestNewDBParameterGroupSource(t *testing.T) { - client, account, region := GetAutoConfig(t) - - source := NewDBParameterGroupSource(client, account, region) - - test := sources.E2ETest{ - Source: source, - Timeout: 10 * time.Second, - } - - test.Run(t) -} diff --git a/sources/route53/health_check_test.go b/sources/route53/health_check_test.go deleted file mode 100644 index 94e18ba3..00000000 --- a/sources/route53/health_check_test.go +++ /dev/null @@ -1,84 +0,0 @@ -package route53 - -import ( - "testing" - "time" - - "github.com/aws/aws-sdk-go-v2/service/route53/types" - "github.com/overmindtech/aws-source/sources" - "github.com/overmindtech/sdp-go" -) - -func TestHealthCheckItemMapper(t *testing.T) { - hc := HealthCheck{ - HealthCheck: types.HealthCheck{ - Id: sources.PtrString("d7ce5d72-6d1f-4147-8246-d0ca3fb505d6"), - CallerReference: sources.PtrString("85d56b3f-873c-498b-a2dd-554ec13c5289"), - HealthCheckConfig: &types.HealthCheckConfig{ - IPAddress: sources.PtrString("1.1.1.1"), - Port: sources.PtrInt32(443), - Type: types.HealthCheckTypeHttps, - FullyQualifiedDomainName: sources.PtrString("one.one.one.one"), - RequestInterval: sources.PtrInt32(30), - FailureThreshold: sources.PtrInt32(3), - MeasureLatency: sources.PtrBool(false), - Inverted: sources.PtrBool(false), - Disabled: sources.PtrBool(false), - EnableSNI: sources.PtrBool(true), - }, - HealthCheckVersion: sources.PtrInt64(1), - }, - HealthCheckObservations: []types.HealthCheckObservation{ - { - Region: types.HealthCheckRegionApNortheast1, - IPAddress: sources.PtrString("15.177.62.21"), - StatusReport: &types.StatusReport{ - Status: sources.PtrString("Success: HTTP Status Code 200, OK"), - CheckedTime: sources.PtrTime(time.Now()), - }, - }, - { - Region: types.HealthCheckRegionEuWest1, - IPAddress: sources.PtrString("15.177.10.21"), - StatusReport: &types.StatusReport{ - Status: sources.PtrString("Failure: Connection timed out. The endpoint or the internet connection is down, or requests are being blocked by your firewall. See https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/dns-failover-router-firewall-rules.html"), - CheckedTime: sources.PtrTime(time.Now()), - }, - }, - }, - } - - item, err := healthCheckItemMapper("", "foo", &hc) - - if err != nil { - t.Error(err) - } - - if err = item.Validate(); err != nil { - t.Error(err) - } - - tests := sources.QueryTests{ - { - ExpectedType: "cloudwatch-alarm", - ExpectedMethod: sdp.QueryMethod_SEARCH, - ExpectedQuery: "{\"MetricName\":\"HealthCheckStatus\",\"Namespace\":\"AWS/Route53\",\"Dimensions\":[{\"Name\":\"HealthCheckId\",\"Value\":\"d7ce5d72-6d1f-4147-8246-d0ca3fb505d6\"}],\"ExtendedStatistic\":null,\"Period\":null,\"Statistic\":\"\",\"Unit\":\"\"}", - ExpectedScope: "foo", - }, - } - - tests.Execute(t, item) -} - -func TestNewHealthCheckSource(t *testing.T) { - client, account, region := GetAutoConfig(t) - - source := NewHealthCheckSource(client, account, region) - - test := sources.E2ETest{ - Source: source, - Timeout: 10 * time.Second, - } - - test.Run(t) -}