Skip to content

Commit ef59148

Browse files
jramosfmisraved
andauthored
Add table_aws_sesv2_suppressed_destination (#2631)
Co-authored-by: Ved misra <[email protected]>
1 parent efa45aa commit ef59148

File tree

6 files changed

+403
-3
lines changed

6 files changed

+403
-3
lines changed

aws/plugin.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -697,6 +697,7 @@ func Plugin(ctx context.Context) *plugin.Plugin {
697697
"aws_ses_domain_identity": tableAwsSESDomainIdentity(ctx),
698698
"aws_ses_email_identity": tableAwsSESEmailIdentity(ctx),
699699
"aws_ses_template": tableAwsSESTemplate(ctx),
700+
"aws_sesv2_suppressed_destination": tableAwsSesV2SuppressedDestination(ctx),
700701
"aws_sfn_state_machine_execution_history": tableAwsStepFunctionsStateMachineExecutionHistory(ctx),
701702
"aws_sfn_state_machine_execution": tableAwsStepFunctionsStateMachineExecution(ctx),
702703
"aws_sfn_state_machine": tableAwsStepFunctionsStateMachine(ctx),

aws/service.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ import (
138138
"github.com/aws/aws-sdk-go-v2/service/servicediscovery"
139139
"github.com/aws/aws-sdk-go-v2/service/servicequotas"
140140
"github.com/aws/aws-sdk-go-v2/service/ses"
141+
"github.com/aws/aws-sdk-go-v2/service/sesv2"
141142
"github.com/aws/aws-sdk-go-v2/service/sfn"
142143
"github.com/aws/aws-sdk-go-v2/service/shield"
143144
"github.com/aws/aws-sdk-go-v2/service/simspaceweaver"
@@ -1562,6 +1563,17 @@ func SESClient(ctx context.Context, d *plugin.QueryData) (*ses.Client, error) {
15621563
return ses.NewFromConfig(*cfg), nil
15631564
}
15641565

1566+
func SESV2Client(ctx context.Context, d *plugin.QueryData) (*sesv2.Client, error) {
1567+
cfg, err := getClientForQuerySupportedRegion(ctx, d, AWS_EMAIL_SERVICE_ID)
1568+
if err != nil {
1569+
return nil, err
1570+
}
1571+
if cfg == nil {
1572+
return nil, nil
1573+
}
1574+
return sesv2.NewFromConfig(*cfg), nil
1575+
}
1576+
15651577
func ServerlessApplicationRepositoryClient(ctx context.Context, d *plugin.QueryData) (*serverlessapplicationrepository.Client, error) {
15661578
cfg, err := getClientForQuerySupportedRegion(ctx, d, AWS_SERVERLESSREPO_SERVICE_ID)
15671579
if err != nil {
Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
package aws
2+
3+
import (
4+
"context"
5+
"errors"
6+
7+
"github.com/aws/aws-sdk-go-v2/service/sesv2"
8+
"github.com/aws/aws-sdk-go-v2/service/sesv2/types"
9+
10+
"github.com/turbot/steampipe-plugin-sdk/v5/grpc/proto"
11+
"github.com/turbot/steampipe-plugin-sdk/v5/plugin"
12+
"github.com/turbot/steampipe-plugin-sdk/v5/plugin/transform"
13+
)
14+
15+
func tableAwsSesV2SuppressedDestination(_ context.Context) *plugin.Table {
16+
return &plugin.Table{
17+
Name: "aws_sesv2_suppressed_destination",
18+
Description: "Lists the email addresses that are on the suppression list for your account.",
19+
Get: &plugin.GetConfig{
20+
KeyColumns: plugin.SingleColumn("email_address"),
21+
Hydrate: getSuppressedDestination,
22+
Tags: map[string]string{"service": "sesv2", "action": "GetSuppressedDestination"},
23+
},
24+
List: &plugin.ListConfig{
25+
Hydrate: listSesSuppressedDestinations,
26+
Tags: map[string]string{"service": "sesv2", "action": "ListSuppressedDestinations"},
27+
KeyColumns: []*plugin.KeyColumn{
28+
{
29+
Name: "reason",
30+
Require: plugin.Optional,
31+
},
32+
{
33+
Name: "start_date",
34+
Require: plugin.Optional,
35+
Operators: []string{"="},
36+
},
37+
{
38+
Name: "end_date",
39+
Require: plugin.Optional,
40+
Operators: []string{"="},
41+
},
42+
},
43+
},
44+
HydrateConfig: []plugin.HydrateConfig{
45+
{
46+
Func: getSuppressedDestination,
47+
Tags: map[string]string{"service": "sesv2", "action": "GetSuppressedDestination"},
48+
},
49+
},
50+
GetMatrixItemFunc: SupportedRegionMatrix(AWS_EMAIL_SERVICE_ID),
51+
Columns: awsRegionalColumns([]*plugin.Column{
52+
{
53+
Name: "email_address",
54+
Description: "The email address that is on the suppression list for your account.",
55+
Type: proto.ColumnType_STRING,
56+
},
57+
{
58+
Name: "reason",
59+
Description: "The reason that the address was added to the suppression list for your account.",
60+
Type: proto.ColumnType_STRING,
61+
},
62+
{
63+
Name: "last_update_time",
64+
Description: "The date and time when the suppressed destination was last updated.",
65+
Type: proto.ColumnType_TIMESTAMP,
66+
},
67+
{
68+
Name: "start_date",
69+
Description: "Used to filter the list of suppressed email addresses so that it only includes addresses that were added to the list after the specified date.",
70+
Type: proto.ColumnType_TIMESTAMP,
71+
Transform: transform.FromQual("start_date"),
72+
},
73+
{
74+
Name: "end_date",
75+
Description: "Used to filter the list of suppressed email addresses so that it only includes addresses that were added to the list before the specified date.",
76+
Type: proto.ColumnType_TIMESTAMP,
77+
Transform: transform.FromQual("end_date"),
78+
},
79+
80+
// Hydrated columns from GetSuppressedDestination
81+
{
82+
Name: "suppressed_destination_attributes",
83+
Description: "An object that contains additional attributes that are related to a suppressed destination.",
84+
Type: proto.ColumnType_JSON,
85+
Hydrate: getSuppressedDestination,
86+
},
87+
{
88+
Name: "message_tag",
89+
Description: "A unique identifier that's generated when an email address is added to the suppression list for your account.",
90+
Type: proto.ColumnType_STRING,
91+
Hydrate: getSuppressedDestination,
92+
Transform: transform.FromField("Attributes.MessageTag"),
93+
},
94+
{
95+
Name: "feedback_id",
96+
Description: "The unique identifier of the email message that caused the email address to be added to the suppression list for your account.",
97+
Type: proto.ColumnType_STRING,
98+
Hydrate: getSuppressedDestination,
99+
Transform: transform.FromField("Attributes.FeedbackId"),
100+
},
101+
102+
// Steampipe standard columns
103+
{
104+
Name: "title",
105+
Description: resourceInterfaceDescription("title"),
106+
Type: proto.ColumnType_STRING,
107+
Transform: transform.FromField("EmailAddress"),
108+
},
109+
}),
110+
}
111+
}
112+
113+
//// LIST FUNCTION
114+
func listSesSuppressedDestinations(ctx context.Context, d *plugin.QueryData, _ *plugin.HydrateData) (interface{}, error) {
115+
svc, err := SESV2Client(ctx, d)
116+
if err != nil {
117+
plugin.Logger(ctx).Error("aws_sesv2_suppressed_destination.listSesSuppressedDestinations", "client_error", err)
118+
return nil, err
119+
}
120+
121+
maxItems := int32(1000)
122+
params := &sesv2.ListSuppressedDestinationsInput{}
123+
124+
// Handle optional qualifiers
125+
if d.EqualsQuals["reason"] != nil {
126+
reasonStr := d.EqualsQualString("reason")
127+
if reasonStr != "" {
128+
// Convert string to SuppressionListReason enum
129+
switch reasonStr {
130+
case "BOUNCE":
131+
params.Reasons = []types.SuppressionListReason{types.SuppressionListReasonBounce}
132+
case "COMPLAINT":
133+
params.Reasons = []types.SuppressionListReason{types.SuppressionListReasonComplaint}
134+
default:
135+
plugin.Logger(ctx).Warn("aws_sesv2_suppressed_destination.listSesSuppressedDestinations", "invalid_reason", reasonStr)
136+
}
137+
}
138+
}
139+
140+
if d.EqualsQuals["start_date"] != nil {
141+
if d.EqualsQuals["start_date"].GetTimestampValue() != nil {
142+
startDate := d.EqualsQuals["start_date"].GetTimestampValue().AsTime()
143+
params.StartDate = &startDate
144+
}
145+
}
146+
147+
if d.EqualsQuals["end_date"] != nil {
148+
if d.EqualsQuals["end_date"].GetTimestampValue() != nil {
149+
endDate := d.EqualsQuals["end_date"].GetTimestampValue().AsTime()
150+
params.EndDate = &endDate
151+
}
152+
}
153+
154+
if d.QueryContext.Limit != nil {
155+
limit := int32(*d.QueryContext.Limit)
156+
if limit < maxItems {
157+
params.PageSize = &limit
158+
}
159+
}
160+
161+
paginator := sesv2.NewListSuppressedDestinationsPaginator(svc, params, func(o *sesv2.ListSuppressedDestinationsPaginatorOptions) {
162+
o.Limit = maxItems
163+
o.StopOnDuplicateToken = true
164+
})
165+
166+
for paginator.HasMorePages() {
167+
d.WaitForListRateLimit(ctx)
168+
output, err := paginator.NextPage(ctx)
169+
if err != nil {
170+
plugin.Logger(ctx).Error("aws_sesv2_suppressed_destination.listSesSuppressedDestinations", "api_error", err)
171+
return nil, err
172+
}
173+
174+
for _, item := range output.SuppressedDestinationSummaries {
175+
d.StreamListItem(ctx, item)
176+
177+
// Context may get cancelled due to manual cancellation or if the limit has been reached
178+
if d.RowsRemaining(ctx) == 0 {
179+
return nil, nil
180+
}
181+
}
182+
}
183+
184+
return nil, nil
185+
}
186+
187+
//// HYDRATE FUNCTION
188+
func getSuppressedDestination(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) {
189+
svc, err := SESV2Client(ctx, d)
190+
if err != nil {
191+
plugin.Logger(ctx).Error("aws_sesv2_suppressed_destination.getSuppressedDestination", "client_error", err)
192+
return nil, err
193+
}
194+
195+
var emailAddress string
196+
if h.Item != nil {
197+
// Called from list - extract email address from the list item
198+
if item, ok := h.Item.(types.SuppressedDestinationSummary); ok {
199+
if item.EmailAddress != nil {
200+
emailAddress = *item.EmailAddress
201+
}
202+
}
203+
} else {
204+
// Called from get - extract email address from key columns
205+
emailAddress = d.EqualsQualString("email_address")
206+
}
207+
208+
if emailAddress == "" {
209+
plugin.Logger(ctx).Error("aws_sesv2_suppressed_destination.getSuppressedDestination", "missing_email_address")
210+
return nil, nil
211+
}
212+
213+
params := &sesv2.GetSuppressedDestinationInput{
214+
EmailAddress: &emailAddress,
215+
}
216+
217+
d.WaitForListRateLimit(ctx)
218+
output, err := svc.GetSuppressedDestination(ctx, params)
219+
if err != nil {
220+
var notFoundErr *types.NotFoundException
221+
if errors.As(err, &notFoundErr) {
222+
plugin.Logger(ctx).Debug("aws_sesv2_suppressed_destination.getSuppressedDestination", "email_not_found", emailAddress)
223+
}
224+
225+
plugin.Logger(ctx).Error("aws_sesv2_suppressed_destination.getSuppressedDestination", "api_error", err)
226+
return nil, err
227+
}
228+
229+
return output.SuppressedDestination, nil
230+
}

0 commit comments

Comments
 (0)