Skip to content

Commit a5fb2d4

Browse files
committed
wip: started apigateway api key
1 parent f53f262 commit a5fb2d4

File tree

6 files changed

+213
-2
lines changed

6 files changed

+213
-2
lines changed

adapters/apigateway-api-key.go

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
package adapters
2+
3+
import (
4+
"context"
5+
"github.com/aws/aws-sdk-go-v2/service/apigateway"
6+
"github.com/aws/aws-sdk-go-v2/service/apigateway/types"
7+
"github.com/overmindtech/aws-source/adapterhelpers"
8+
"github.com/overmindtech/sdp-go"
9+
"strings"
10+
)
11+
12+
// convertGetApiKeyOutputToApiKey converts a GetApiKeyOutput to an ApiKey
13+
func convertGetApiKeyOutputToApiKey(output *apigateway.GetApiKeyOutput) *types.ApiKey {
14+
return &types.ApiKey{
15+
Id: output.Id,
16+
Name: output.Name,
17+
Enabled: output.Enabled,
18+
CreatedDate: output.CreatedDate,
19+
LastUpdatedDate: output.LastUpdatedDate,
20+
StageKeys: output.StageKeys,
21+
Tags: output.Tags,
22+
}
23+
}
24+
25+
func apiKeyListFunc(ctx context.Context, client *apigateway.Client, _ string) ([]*types.ApiKey, error) {
26+
out, err := client.GetApiKeys(ctx, &apigateway.GetApiKeysInput{})
27+
if err != nil {
28+
return nil, err
29+
}
30+
31+
var items []*types.ApiKey
32+
for _, apiKey := range out.Items {
33+
items = append(items, &apiKey)
34+
}
35+
36+
return items, nil
37+
}
38+
39+
func apiKeyOutputMapper(scope string, awsItem *types.ApiKey) (*sdp.Item, error) {
40+
attributes, err := adapterhelpers.ToAttributesWithExclude(awsItem, "tags")
41+
if err != nil {
42+
return nil, err
43+
}
44+
45+
item := sdp.Item{
46+
Type: "apigateway-api-key",
47+
UniqueAttribute: "Id",
48+
Attributes: attributes,
49+
Scope: scope,
50+
Tags: awsItem.Tags,
51+
}
52+
53+
for _, key := range awsItem.StageKeys {
54+
// {restApiId}/{stage}
55+
restAPIID := strings.Split(key, "/")[0]
56+
if restAPIID != "" {
57+
item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{
58+
Query: &sdp.Query{
59+
Type: "apigateway-rest-api",
60+
Method: sdp.QueryMethod_GET,
61+
Query: restAPIID,
62+
Scope: scope,
63+
},
64+
BlastPropagation: &sdp.BlastPropagation{
65+
// They are tightly coupled, so we need to propagate both ways
66+
In: true,
67+
Out: true,
68+
},
69+
})
70+
}
71+
}
72+
73+
return &item, nil
74+
}
75+
76+
func NewAPIGatewayApiKeyAdapter(client *apigateway.Client, accountID string, region string) *adapterhelpers.GetListAdapter[*types.ApiKey, *apigateway.Client, *apigateway.Options] {
77+
return &adapterhelpers.GetListAdapter[*types.ApiKey, *apigateway.Client, *apigateway.Options]{
78+
ItemType: "apigateway-api-key",
79+
Client: client,
80+
AccountID: accountID,
81+
Region: region,
82+
AdapterMetadata: apiKeyAdapterMetadata,
83+
GetFunc: func(ctx context.Context, client *apigateway.Client, scope, query string) (*types.ApiKey, error) {
84+
out, err := client.GetApiKey(ctx, &apigateway.GetApiKeyInput{
85+
ApiKey: &query,
86+
})
87+
if err != nil {
88+
return nil, err
89+
}
90+
return convertGetApiKeyOutputToApiKey(out), nil
91+
},
92+
ListFunc: apiKeyListFunc,
93+
SearchFunc: func(ctx context.Context, client *apigateway.Client, scope string, query string) ([]*types.ApiKey, error) {
94+
out, err := client.GetApiKeys(ctx, &apigateway.GetApiKeysInput{
95+
NameQuery: &query,
96+
})
97+
if err != nil {
98+
return nil, err
99+
}
100+
101+
var items []*types.ApiKey
102+
for _, apiKey := range out.Items {
103+
items = append(items, &apiKey)
104+
}
105+
106+
return items, nil
107+
},
108+
ItemMapper: func(_, scope string, awsItem *types.ApiKey) (*sdp.Item, error) {
109+
return apiKeyOutputMapper(scope, awsItem)
110+
},
111+
}
112+
}
113+
114+
var apiKeyAdapterMetadata = Metadata.Register(&sdp.AdapterMetadata{
115+
Type: "apigateway-api-key",
116+
DescriptiveName: "API Key",
117+
Category: sdp.AdapterCategory_ADAPTER_CATEGORY_SECURITY,
118+
SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{
119+
Get: true,
120+
List: true,
121+
Search: true,
122+
GetDescription: "Get an API Key by ID",
123+
ListDescription: "List all API Keys",
124+
SearchDescription: "Search for API Keys by their name",
125+
},
126+
})

adapters/integration/apigateway/create.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,3 +168,30 @@ func createIntegration(ctx context.Context, logger *slog.Logger, client *apigate
168168

169169
return nil
170170
}
171+
172+
func createAPIKey(ctx context.Context, logger *slog.Logger, client *apigateway.Client, testID string) error {
173+
// check if an API key with the same name already exists
174+
id, err := findAPIKeyByName(ctx, client, integration.ResourceName(integration.APIGateway, apiKeySrc, testID))
175+
if err != nil {
176+
if errors.As(err, new(integration.NotFoundError)) {
177+
logger.InfoContext(ctx, "Creating API key")
178+
} else {
179+
return err
180+
}
181+
}
182+
183+
if id != nil {
184+
logger.InfoContext(ctx, "API key already exists")
185+
return nil
186+
}
187+
188+
_, err = client.CreateApiKey(ctx, &apigateway.CreateApiKeyInput{
189+
Name: adapterhelpers.PtrString(integration.ResourceName(integration.APIGateway, apiKeySrc, testID)),
190+
Tags: resourceTags(apiKeySrc, testID),
191+
})
192+
if err != nil {
193+
return err
194+
}
195+
196+
return nil
197+
}

adapters/integration/apigateway/delete.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package apigateway
22

33
import (
44
"context"
5-
65
"github.com/aws/aws-sdk-go-v2/service/apigateway"
76
"github.com/overmindtech/aws-source/adapterhelpers"
87
)
@@ -14,3 +13,14 @@ func deleteRestAPI(ctx context.Context, client *apigateway.Client, restAPIID str
1413

1514
return err
1615
}
16+
17+
func deleteAPIKeyByName(ctx context.Context, client *apigateway.Client, id *string) error {
18+
_, err := client.DeleteApiKey(ctx, &apigateway.DeleteApiKeyInput{
19+
ApiKey: id,
20+
})
21+
if err != nil {
22+
return err
23+
}
24+
25+
return nil
26+
}

adapters/integration/apigateway/find.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,3 +110,24 @@ func findIntegration(ctx context.Context, client *apigateway.Client, restAPIID,
110110

111111
return nil
112112
}
113+
114+
func findAPIKeyByName(ctx context.Context, client *apigateway.Client, name string) (*string, error) {
115+
result, err := client.GetApiKeys(ctx, &apigateway.GetApiKeysInput{
116+
NameQuery: &name,
117+
})
118+
if err != nil {
119+
return nil, err
120+
}
121+
122+
if len(result.Items) == 0 {
123+
return nil, integration.NewNotFoundError(integration.ResourceName(integration.APIGateway, apiKeySrc, name))
124+
}
125+
126+
for _, apiKey := range result.Items {
127+
if *apiKey.Name == name {
128+
return apiKey.Id, nil
129+
}
130+
}
131+
132+
return nil, integration.NewNotFoundError(integration.ResourceName(integration.APIGateway, apiKeySrc, name))
133+
}

adapters/integration/apigateway/setup.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const (
1414
methodSrc = "method"
1515
methodResponseSrc = "method-response"
1616
integrationSrc = "integration"
17+
apiKeySrc = "api-key"
1718
)
1819

1920
func setup(ctx context.Context, logger *slog.Logger, client *apigateway.Client) error {
@@ -55,5 +56,11 @@ func setup(ctx context.Context, logger *slog.Logger, client *apigateway.Client)
5556
return err
5657
}
5758

59+
// Create API Key
60+
err = createAPIKey(ctx, logger, client, testID)
61+
if err != nil {
62+
return err
63+
}
64+
5865
return nil
5966
}

adapters/integration/apigateway/teardown.go

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,31 @@ func teardown(ctx context.Context, logger *slog.Logger, client *apigateway.Clien
1414
if err != nil {
1515
if nf := integration.NewNotFoundError(restAPISrc); errors.As(err, &nf) {
1616
logger.WarnContext(ctx, "Rest API not found")
17+
} else {
18+
return err
19+
}
20+
} else {
21+
err = deleteRestAPI(ctx, client, *restAPIID)
22+
if err != nil {
23+
return err
24+
}
25+
}
26+
27+
keyName := integration.ResourceName(integration.APIGateway, apiKeySrc, integration.TestID())
28+
apiKeyID, err := findAPIKeyByName(ctx, client, keyName)
29+
if err != nil {
30+
if nf := integration.NewNotFoundError(apiKeySrc); errors.As(err, &nf) {
31+
logger.WarnContext(ctx, "API Key not found", "name", keyName)
1732
return nil
1833
} else {
1934
return err
2035
}
36+
} else {
37+
err = deleteAPIKeyByName(ctx, client, apiKeyID)
38+
if err != nil {
39+
return err
40+
}
2141
}
2242

23-
return deleteRestAPI(ctx, client, *restAPIID)
43+
return nil
2444
}

0 commit comments

Comments
 (0)