Skip to content

Commit 9754ffa

Browse files
tomasdembellidylanratcliffe
authored andcommitted
add apigateway stage adapter
1 parent a102a72 commit 9754ffa

File tree

3 files changed

+228
-0
lines changed

3 files changed

+228
-0
lines changed

adapters/apigateway-stage.go

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
package adapters
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"strings"
7+
8+
"github.com/aws/aws-sdk-go-v2/service/apigateway"
9+
"github.com/aws/aws-sdk-go-v2/service/apigateway/types"
10+
"github.com/overmindtech/aws-source/adapterhelpers"
11+
"github.com/overmindtech/sdp-go"
12+
)
13+
14+
func convertGetStageOutputToStage(output *apigateway.GetStageOutput) *types.Stage {
15+
return &types.Stage{
16+
DeploymentId: output.DeploymentId,
17+
StageName: output.StageName,
18+
Description: output.Description,
19+
CreatedDate: output.CreatedDate,
20+
LastUpdatedDate: output.LastUpdatedDate,
21+
Variables: output.Variables,
22+
AccessLogSettings: output.AccessLogSettings,
23+
CacheClusterEnabled: output.CacheClusterEnabled,
24+
CacheClusterSize: output.CacheClusterSize,
25+
CacheClusterStatus: output.CacheClusterStatus,
26+
CanarySettings: output.CanarySettings,
27+
ClientCertificateId: output.ClientCertificateId,
28+
DocumentationVersion: output.DocumentationVersion,
29+
MethodSettings: output.MethodSettings,
30+
TracingEnabled: output.TracingEnabled,
31+
WebAclArn: output.WebAclArn,
32+
Tags: output.Tags,
33+
}
34+
}
35+
36+
func stageOutputMapper(query, scope string, awsItem *types.Stage) (*sdp.Item, error) {
37+
attributes, err := adapterhelpers.ToAttributesWithExclude(awsItem, "tags")
38+
if err != nil {
39+
return nil, err
40+
}
41+
42+
// if it is `GET`, the query will be: rest-api-id/stage-name
43+
// if it is `SEARCH`, the query will be: rest-api-id/deployment-id or rest-api-id
44+
restAPIID := strings.Split(query, "/")[0]
45+
46+
err = attributes.Set("UniqueAttribute", fmt.Sprintf("%s/%s", restAPIID, *awsItem.StageName))
47+
48+
item := sdp.Item{
49+
Type: "apigateway-stage",
50+
UniqueAttribute: "StageName",
51+
Attributes: attributes,
52+
Scope: scope,
53+
Tags: awsItem.Tags,
54+
}
55+
56+
if awsItem.DeploymentId != nil {
57+
item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{
58+
Query: &sdp.Query{
59+
Type: "apigateway-deployment",
60+
Method: sdp.QueryMethod_GET,
61+
Query: fmt.Sprintf("%s/%s", restAPIID, *awsItem.DeploymentId),
62+
Scope: scope,
63+
},
64+
BlastPropagation: &sdp.BlastPropagation{
65+
// Deleting a deployment will impact the stage
66+
In: true,
67+
// Deleting a stage won't impact the deployment
68+
Out: false,
69+
},
70+
})
71+
}
72+
73+
return &item, nil
74+
}
75+
76+
func NewAPIGatewayStageAdapter(client *apigateway.Client, accountID string, region string) *adapterhelpers.GetListAdapter[*types.Stage, *apigateway.Client, *apigateway.Options] {
77+
return &adapterhelpers.GetListAdapter[*types.Stage, *apigateway.Client, *apigateway.Options]{
78+
ItemType: "apigateway-stage",
79+
Client: client,
80+
AccountID: accountID,
81+
Region: region,
82+
AdapterMetadata: stageAdapterMetadata,
83+
GetFunc: func(ctx context.Context, client *apigateway.Client, scope, query string) (*types.Stage, error) {
84+
f := strings.Split(query, "/")
85+
if len(f) != 2 {
86+
return nil, &sdp.QueryError{
87+
ErrorType: sdp.QueryError_NOTFOUND,
88+
ErrorString: fmt.Sprintf("query must be in the format of: the rest-api-id/stage-name, but found: %s", query),
89+
}
90+
}
91+
out, err := client.GetStage(ctx, &apigateway.GetStageInput{
92+
RestApiId: &f[0],
93+
StageName: &f[1],
94+
})
95+
if err != nil {
96+
return nil, err
97+
}
98+
return convertGetStageOutputToStage(out), nil
99+
},
100+
DisableList: true,
101+
SearchFunc: func(ctx context.Context, client *apigateway.Client, scope string, query string) ([]*types.Stage, error) {
102+
f := strings.Split(query, "/")
103+
var restAPIID string
104+
var deploymentID string
105+
106+
switch len(f) {
107+
case 1:
108+
restAPIID = f[0]
109+
case 2:
110+
restAPIID = f[0]
111+
deploymentID = f[1]
112+
default:
113+
return nil, &sdp.QueryError{
114+
ErrorType: sdp.QueryError_NOTFOUND,
115+
ErrorString: fmt.Sprintf(
116+
"query must be in the format of: the rest-api-id/deployment-id or rest-api-id, but found: %s",
117+
query,
118+
),
119+
}
120+
}
121+
122+
out, err := client.GetStages(ctx, &apigateway.GetStagesInput{
123+
RestApiId: &restAPIID,
124+
DeploymentId: &deploymentID,
125+
})
126+
if err != nil {
127+
return nil, err
128+
}
129+
130+
var items []*types.Stage
131+
for _, stage := range out.Item {
132+
items = append(items, &stage)
133+
}
134+
135+
return items, nil
136+
},
137+
ItemMapper: func(query, scope string, awsItem *types.Stage) (*sdp.Item, error) {
138+
return stageOutputMapper(query, scope, awsItem)
139+
},
140+
}
141+
}
142+
143+
var stageAdapterMetadata = Metadata.Register(&sdp.AdapterMetadata{
144+
Type: "apigateway-stage",
145+
DescriptiveName: "API Gateway Stage",
146+
Category: sdp.AdapterCategory_ADAPTER_CATEGORY_CONFIGURATION,
147+
SupportedQueryMethods: &sdp.AdapterSupportedQueryMethods{
148+
Get: true,
149+
Search: true,
150+
GetDescription: "Get an API Gateway Stage by its rest API ID and stage name: rest-api-id/stage-name",
151+
SearchDescription: "Search for API Gateway Stages by their rest API ID or with rest API ID and their stage name: rest-api-id/stage-name",
152+
},
153+
PotentialLinks: []string{"wafv2-web-acl"},
154+
})

adapters/apigateway-stage_test.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package adapters
2+
3+
import (
4+
"github.com/overmindtech/sdp-go"
5+
"testing"
6+
"time"
7+
8+
"github.com/aws/aws-sdk-go-v2/aws"
9+
"github.com/aws/aws-sdk-go-v2/service/apigateway"
10+
"github.com/aws/aws-sdk-go-v2/service/apigateway/types"
11+
"github.com/overmindtech/aws-source/adapterhelpers"
12+
)
13+
14+
func TestStageOutputMapper(t *testing.T) {
15+
awsItem := &types.Stage{
16+
DeploymentId: aws.String("deployment-id"),
17+
StageName: aws.String("stage-name"),
18+
Description: aws.String("description"),
19+
CreatedDate: aws.Time(time.Now()),
20+
LastUpdatedDate: aws.Time(time.Now()),
21+
Variables: map[string]string{"key": "value"},
22+
AccessLogSettings: &types.AccessLogSettings{},
23+
CacheClusterEnabled: true,
24+
CacheClusterSize: "0.5",
25+
CacheClusterStatus: types.CacheClusterStatusAvailable,
26+
CanarySettings: &types.CanarySettings{},
27+
ClientCertificateId: aws.String("client-cert-id"),
28+
DocumentationVersion: aws.String("1.0"),
29+
MethodSettings: map[string]types.MethodSetting{},
30+
TracingEnabled: true,
31+
WebAclArn: aws.String("web-acl-arn"),
32+
Tags: map[string]string{"tag-key": "tag-value"},
33+
}
34+
35+
queries := []string{"rest-api-id/stage-name", "rest-api-id/deployment-id", "rest-api-id"}
36+
for _, query := range queries {
37+
item, err := stageOutputMapper(query, "scope", awsItem)
38+
if err != nil {
39+
t.Fatalf("unexpected error: %v", err)
40+
}
41+
42+
if err := item.Validate(); err != nil {
43+
t.Error(err)
44+
}
45+
46+
tests := adapterhelpers.QueryTests{
47+
{
48+
ExpectedType: "apigateway-deployment",
49+
ExpectedMethod: sdp.QueryMethod_GET,
50+
ExpectedQuery: "rest-api-id/deployment-id",
51+
ExpectedScope: "scope",
52+
},
53+
}
54+
55+
tests.Execute(t, item)
56+
}
57+
}
58+
59+
func TestNewAPIGatewayStageAdapter(t *testing.T) {
60+
config, account, region := adapterhelpers.GetAutoConfig(t)
61+
62+
client := apigateway.NewFromConfig(config)
63+
64+
adapter := NewAPIGatewayStageAdapter(client, account, region)
65+
66+
test := adapterhelpers.E2ETest{
67+
Adapter: adapter,
68+
Timeout: 10 * time.Second,
69+
SkipList: true,
70+
}
71+
72+
test.Run(t)
73+
}

proc/proc.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,7 @@ func InitializeAwsSourceEngine(ctx context.Context, ec *discovery.EngineConfig,
486486
adapters.NewAPIGatewayApiKeyAdapter(apigatewayClient, *callerID.Account, cfg.Region),
487487
adapters.NewAPIGatewayAuthorizerAdapter(apigatewayClient, *callerID.Account, cfg.Region),
488488
adapters.NewAPIGatewayDeploymentAdapter(apigatewayClient, *callerID.Account, cfg.Region),
489+
adapters.NewAPIGatewayStageAdapter(apigatewayClient, *callerID.Account, cfg.Region),
489490

490491
// SSM
491492
adapters.NewSSMParameterAdapter(ssmClient, *callerID.Account, cfg.Region),

0 commit comments

Comments
 (0)