Skip to content

Commit 2e87167

Browse files
authored
Merge pull request #44232 from hashicorp/f-aws_sns_publish_message
New action: `aws_sns_publish`
2 parents a292302 + ccb5a5f commit 2e87167

File tree

5 files changed

+564
-0
lines changed

5 files changed

+564
-0
lines changed

.changelog/44232.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:new-action
2+
aws_sns_publish
3+
```
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package sns
5+
6+
import (
7+
"context"
8+
"fmt"
9+
10+
"github.com/aws/aws-sdk-go-v2/aws"
11+
"github.com/aws/aws-sdk-go-v2/service/sns"
12+
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
13+
"github.com/hashicorp/terraform-plugin-framework/action"
14+
"github.com/hashicorp/terraform-plugin-framework/action/schema"
15+
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
16+
"github.com/hashicorp/terraform-plugin-framework/types"
17+
"github.com/hashicorp/terraform-plugin-log/tflog"
18+
"github.com/hashicorp/terraform-provider-aws/internal/framework"
19+
fwflex "github.com/hashicorp/terraform-provider-aws/internal/framework/flex"
20+
fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types"
21+
"github.com/hashicorp/terraform-provider-aws/names"
22+
)
23+
24+
// @Action(aws_sns_publish, name="Publish")
25+
func newPublishAction(_ context.Context) (action.ActionWithConfigure, error) {
26+
return &publishAction{}, nil
27+
}
28+
29+
var (
30+
_ action.Action = (*publishAction)(nil)
31+
)
32+
33+
type publishAction struct {
34+
framework.ActionWithModel[publishActionModel]
35+
}
36+
37+
type publishActionModel struct {
38+
framework.WithRegionModel
39+
TopicArn types.String `tfsdk:"topic_arn"`
40+
Message types.String `tfsdk:"message"`
41+
Subject types.String `tfsdk:"subject"`
42+
MessageStructure types.String `tfsdk:"message_structure"`
43+
MessageAttributes fwtypes.ListNestedObjectValueOf[messageAttributeModel] `tfsdk:"message_attributes"`
44+
}
45+
46+
type messageAttributeModel struct {
47+
MapBlockKey types.String `tfsdk:"map_block_key"`
48+
DataType types.String `tfsdk:"data_type"`
49+
StringValue types.String `tfsdk:"string_value"`
50+
}
51+
52+
func (a *publishAction) Schema(ctx context.Context, req action.SchemaRequest, resp *action.SchemaResponse) {
53+
resp.Schema = schema.Schema{
54+
Description: "Publishes a message to an Amazon SNS topic. This action allows for imperative message publishing with full control over message attributes and structure.",
55+
Attributes: map[string]schema.Attribute{
56+
names.AttrMessage: schema.StringAttribute{
57+
Description: "The message to publish. For JSON message structure, this should be a JSON object with protocol-specific messages.",
58+
Required: true,
59+
},
60+
names.AttrTopicARN: schema.StringAttribute{
61+
Description: "The ARN of the SNS topic to publish the message to.",
62+
Required: true,
63+
},
64+
"message_structure": schema.StringAttribute{
65+
Description: "Set to 'json' if you want to send different messages for each protocol. If not specified, the message will be sent as-is to all protocols.",
66+
Optional: true,
67+
Validators: []validator.String{
68+
stringvalidator.OneOf(names.AttrJSON),
69+
},
70+
},
71+
"subject": schema.StringAttribute{
72+
Description: "Optional subject for the message. Only used for email and email-json protocols.",
73+
Optional: true,
74+
},
75+
},
76+
Blocks: map[string]schema.Block{
77+
"message_attributes": schema.ListNestedBlock{
78+
Description: "Message attributes to include with the message. Each block represents one attribute where map_block_key becomes the attribute name.",
79+
CustomType: fwtypes.NewListNestedObjectTypeOf[messageAttributeModel](ctx),
80+
NestedObject: schema.NestedBlockObject{
81+
Attributes: map[string]schema.Attribute{ // nosemgrep:ci.semgrep.framework.map_block_key-meaningful-names
82+
"data_type": schema.StringAttribute{
83+
Description: "The data type of the message attribute. Valid values are String, Number, and Binary.",
84+
Required: true,
85+
Validators: []validator.String{
86+
stringvalidator.OneOf("String", "Number", "Binary"),
87+
},
88+
},
89+
"map_block_key": schema.StringAttribute{
90+
Description: "The name of the message attribute (used as map key).",
91+
Required: true,
92+
},
93+
"string_value": schema.StringAttribute{
94+
Description: "The value of the message attribute.",
95+
Required: true,
96+
},
97+
},
98+
},
99+
},
100+
},
101+
}
102+
}
103+
104+
func (a *publishAction) Invoke(ctx context.Context, req action.InvokeRequest, resp *action.InvokeResponse) {
105+
var config publishActionModel
106+
107+
resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
108+
if resp.Diagnostics.HasError() {
109+
return
110+
}
111+
112+
conn := a.Meta().SNSClient(ctx)
113+
114+
topicArn := config.TopicArn.ValueString()
115+
message := config.Message.ValueString()
116+
117+
tflog.Info(ctx, "Starting SNS publish message action", map[string]any{
118+
names.AttrTopicARN: topicArn,
119+
"message_length": len(message),
120+
"has_subject": !config.Subject.IsNull(),
121+
})
122+
123+
resp.SendProgress(action.InvokeProgressEvent{
124+
Message: fmt.Sprintf("Publishing message to SNS topic %s...", topicArn),
125+
})
126+
127+
input := &sns.PublishInput{}
128+
resp.Diagnostics.Append(fwflex.Expand(ctx, config, input)...)
129+
if resp.Diagnostics.HasError() {
130+
return
131+
}
132+
133+
// Ensure required fields are set (AutoFlex should handle these, but being explicit)
134+
input.TopicArn = aws.String(topicArn)
135+
input.Message = aws.String(message)
136+
137+
output, err := conn.Publish(ctx, input)
138+
if err != nil {
139+
resp.Diagnostics.AddError(
140+
"Failed to Publish SNS Message",
141+
fmt.Sprintf("Could not publish message to SNS topic %s: %s", topicArn, err),
142+
)
143+
return
144+
}
145+
146+
messageId := aws.ToString(output.MessageId)
147+
resp.SendProgress(action.InvokeProgressEvent{
148+
Message: fmt.Sprintf("Message published successfully to SNS topic %s (Message ID: %s)", topicArn, messageId),
149+
})
150+
151+
tflog.Info(ctx, "SNS publish message action completed successfully", map[string]any{
152+
names.AttrTopicARN: topicArn,
153+
"message_id": messageId,
154+
})
155+
}

0 commit comments

Comments
 (0)