Skip to content

Commit 62e3bed

Browse files
author
Marcin Belczewski
committed
feat: implement notification configuration, event rule, email channel
1 parent 04c8334 commit 62e3bed

25 files changed

+2836
-2
lines changed

.changelog/42575.txt

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
```release-note:new-resource
2+
aws_notifications_notification_configuration
3+
```
4+
5+
```release-note:new-resource
6+
aws_notifications_event_rule
7+
```
8+
9+
```release-note:new-resource
10+
aws_notifications_contacts_email
11+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package notifications
5+
6+
import (
7+
"context"
8+
"errors"
9+
"fmt"
10+
"slices"
11+
12+
"github.com/aws/aws-sdk-go-v2/aws"
13+
"github.com/aws/aws-sdk-go-v2/service/notifications"
14+
awstypes "github.com/aws/aws-sdk-go-v2/service/notifications/types"
15+
"github.com/hashicorp/terraform-plugin-framework/path"
16+
"github.com/hashicorp/terraform-plugin-framework/resource"
17+
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
18+
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
19+
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
20+
"github.com/hashicorp/terraform-plugin-framework/types"
21+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry"
22+
"github.com/hashicorp/terraform-provider-aws/internal/conns"
23+
"github.com/hashicorp/terraform-provider-aws/internal/create"
24+
"github.com/hashicorp/terraform-provider-aws/internal/errs"
25+
"github.com/hashicorp/terraform-provider-aws/internal/errs/fwdiag"
26+
intflex "github.com/hashicorp/terraform-provider-aws/internal/flex"
27+
"github.com/hashicorp/terraform-provider-aws/internal/framework"
28+
"github.com/hashicorp/terraform-provider-aws/internal/framework/flex"
29+
"github.com/hashicorp/terraform-provider-aws/internal/sweep"
30+
sweepfw "github.com/hashicorp/terraform-provider-aws/internal/sweep/framework"
31+
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
32+
"github.com/hashicorp/terraform-provider-aws/names"
33+
)
34+
35+
// Function annotations are used for resource registration to the Provider. DO NOT EDIT.
36+
// @FrameworkResource("aws_notifications_channel_association", name="Channel Association")
37+
func newResourceChannelAssociation(_ context.Context) (resource.ResourceWithConfigure, error) {
38+
r := &resourceChannelAssociation{}
39+
40+
return r, nil
41+
}
42+
43+
const (
44+
ResNameChannelAssociation = "Channel Association"
45+
ChannelAssociationsARNsCount = 2
46+
)
47+
48+
type resourceChannelAssociation struct {
49+
framework.ResourceWithConfigure
50+
framework.WithNoOpUpdate[resourceChannelAssociationModel]
51+
}
52+
53+
func (r *resourceChannelAssociation) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
54+
resp.Schema = schema.Schema{
55+
Attributes: map[string]schema.Attribute{
56+
names.AttrARN: schema.StringAttribute{
57+
Required: true,
58+
PlanModifiers: []planmodifier.String{
59+
stringplanmodifier.RequiresReplace(),
60+
},
61+
},
62+
"notification_configuration_arn": schema.StringAttribute{
63+
Required: true,
64+
PlanModifiers: []planmodifier.String{
65+
stringplanmodifier.RequiresReplace(),
66+
},
67+
},
68+
},
69+
}
70+
}
71+
72+
func (r *resourceChannelAssociation) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
73+
conn := r.Meta().NotificationsClient(ctx)
74+
75+
var plan resourceChannelAssociationModel
76+
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
77+
if resp.Diagnostics.HasError() {
78+
return
79+
}
80+
81+
var input notifications.AssociateChannelInput
82+
resp.Diagnostics.Append(flex.Expand(ctx, plan, &input)...)
83+
if resp.Diagnostics.HasError() {
84+
return
85+
}
86+
87+
out, err := conn.AssociateChannel(ctx, &input)
88+
if err != nil {
89+
resp.Diagnostics.AddError(
90+
create.ProblemStandardMessage(names.Notifications, create.ErrActionCreating, ResNameChannelAssociation, plan.NotificationConfigurationARN.String(), err),
91+
err.Error(),
92+
)
93+
return
94+
}
95+
if out == nil {
96+
resp.Diagnostics.AddError(
97+
create.ProblemStandardMessage(names.Notifications, create.ErrActionCreating, ResNameChannelAssociation, plan.NotificationConfigurationARN.String(), nil),
98+
errors.New("empty output").Error(),
99+
)
100+
return
101+
}
102+
103+
resp.Diagnostics.Append(resp.State.Set(ctx, plan)...)
104+
}
105+
106+
func (r *resourceChannelAssociation) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
107+
conn := r.Meta().NotificationsClient(ctx)
108+
109+
var state resourceChannelAssociationModel
110+
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
111+
if resp.Diagnostics.HasError() {
112+
return
113+
}
114+
115+
exists, err := findChannelAssociationByARNs(ctx, conn, state.ARN.ValueString(), state.NotificationConfigurationARN.ValueString())
116+
if !exists {
117+
resp.Diagnostics.Append(fwdiag.NewResourceNotFoundWarningDiagnostic(err))
118+
resp.State.RemoveResource(ctx)
119+
return
120+
}
121+
if err != nil {
122+
resp.Diagnostics.AddError(
123+
create.ProblemStandardMessage(names.Notifications, create.ErrActionReading, ResNameChannelAssociation, state.NotificationConfigurationARN.String(), err),
124+
err.Error(),
125+
)
126+
return
127+
}
128+
129+
resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
130+
}
131+
132+
func (r *resourceChannelAssociation) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
133+
conn := r.Meta().NotificationsClient(ctx)
134+
135+
var state resourceChannelAssociationModel
136+
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
137+
if resp.Diagnostics.HasError() {
138+
return
139+
}
140+
141+
input := notifications.DisassociateChannelInput{
142+
Arn: state.ARN.ValueStringPointer(),
143+
NotificationConfigurationArn: state.NotificationConfigurationARN.ValueStringPointer(),
144+
}
145+
146+
_, err := conn.DisassociateChannel(ctx, &input)
147+
if err != nil {
148+
if errs.IsA[*awstypes.ResourceNotFoundException](err) {
149+
return
150+
}
151+
152+
resp.Diagnostics.AddError(
153+
create.ProblemStandardMessage(names.Notifications, create.ErrActionDeleting, ResNameChannelAssociation, state.NotificationConfigurationARN.String(), err),
154+
err.Error(),
155+
)
156+
return
157+
}
158+
}
159+
160+
func (r *resourceChannelAssociation) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
161+
parts, err := intflex.ExpandResourceId(req.ID, ChannelAssociationsARNsCount, false)
162+
if err != nil {
163+
resp.Diagnostics.AddError(
164+
"Unexpected Import Identifier",
165+
fmt.Sprintf("Expected import identifier with format: channel_arn,notification_configuration_arn. Got: %q", req.ID),
166+
)
167+
return
168+
}
169+
170+
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root(names.AttrARN), parts[0])...)
171+
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("notification_configuration_arn"), parts[1])...)
172+
}
173+
174+
func findChannelAssociationByARNs(ctx context.Context, conn *notifications.Client, arn string, notificationConfigurationArn string) (bool, error) {
175+
input := notifications.ListChannelsInput{
176+
NotificationConfigurationArn: aws.String(notificationConfigurationArn),
177+
}
178+
179+
out, err := conn.ListChannels(ctx, &input)
180+
if err != nil {
181+
return false, err
182+
}
183+
184+
if out == nil || out.Channels == nil || len(out.Channels) == 0 {
185+
return false, tfresource.NewEmptyResultError(&input)
186+
}
187+
188+
if slices.Contains(out.Channels, arn) {
189+
return true, nil
190+
}
191+
192+
return false, &retry.NotFoundError{
193+
LastError: fmt.Errorf("association of channel %q to notification configuration %q not found", arn, notificationConfigurationArn),
194+
LastRequest: &input,
195+
}
196+
}
197+
198+
type resourceChannelAssociationModel struct {
199+
ARN types.String `tfsdk:"arn"`
200+
NotificationConfigurationARN types.String `tfsdk:"notification_configuration_arn"`
201+
}
202+
203+
func sweepChannelAssociations(ctx context.Context, client *conns.AWSClient) ([]sweep.Sweepable, error) {
204+
input := notifications.ListChannelsInput{}
205+
conn := client.NotificationsClient(ctx)
206+
var sweepResources []sweep.Sweepable
207+
208+
pages := notifications.NewListChannelsPaginator(conn, &input)
209+
for pages.HasMorePages() {
210+
page, err := pages.NextPage(ctx)
211+
if err != nil {
212+
return nil, err
213+
}
214+
215+
for _, arn := range page.Channels {
216+
sweepResources = append(sweepResources, sweepfw.NewSweepResource(newResourceChannelAssociation, client,
217+
sweepfw.NewAttribute(names.AttrARN, arn)),
218+
)
219+
}
220+
}
221+
222+
return sweepResources, nil
223+
}

0 commit comments

Comments
 (0)