Skip to content

Commit 0b7107a

Browse files
New Resource: azurerm_eventgrid_namespace_topic closes #28077 (#30104)
Co-authored-by: sreallymatt <106555974+sreallymatt@users.noreply.github.com>
1 parent ed0d90f commit 0b7107a

File tree

6 files changed

+505
-3
lines changed

6 files changed

+505
-3
lines changed

internal/services/eventgrid/client/client.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,16 @@ import (
88

99
"github.com/hashicorp/go-azure-sdk/resource-manager/eventgrid/2023-12-15-preview/namespaces"
1010
eventgrid_v2025_02_15 "github.com/hashicorp/go-azure-sdk/resource-manager/eventgrid/2025-02-15"
11+
"github.com/hashicorp/go-azure-sdk/resource-manager/eventgrid/2025-02-15/namespacetopics"
1112
"github.com/hashicorp/go-azure-sdk/sdk/client/resourcemanager"
1213
"github.com/hashicorp/terraform-provider-azurerm/internal/common"
1314
)
1415

1516
type Client struct {
1617
*eventgrid_v2025_02_15.Client
1718

18-
NamespacesClient *namespaces.NamespacesClient
19+
NamespacesClient *namespaces.NamespacesClient
20+
NamespaceTopicsClient *namespacetopics.NamespaceTopicsClient
1921
}
2022

2123
func NewClient(o *common.ClientOptions) (*Client, error) {
@@ -25,14 +27,21 @@ func NewClient(o *common.ClientOptions) (*Client, error) {
2527
}
2628
o.Configure(NamespacesClient.Client, o.Authorizers.ResourceManager)
2729

30+
NamespaceTopicsClient, err := namespacetopics.NewNamespaceTopicsClientWithBaseURI(o.Environment.ResourceManager)
31+
if err != nil {
32+
return nil, fmt.Errorf("building Namespace Topics Client: %+v", err)
33+
}
34+
o.Configure(NamespaceTopicsClient.Client, o.Authorizers.ResourceManager)
35+
2836
client, err := eventgrid_v2025_02_15.NewClientWithBaseURI(o.Environment.ResourceManager, func(c *resourcemanager.Client) {
2937
o.Configure(c, o.Authorizers.ResourceManager)
3038
})
3139
if err != nil {
3240
return nil, fmt.Errorf("building EventGrid client: %+v", err)
3341
}
3442
return &Client{
35-
NamespacesClient: NamespacesClient,
36-
Client: client,
43+
NamespacesClient: NamespacesClient,
44+
NamespaceTopicsClient: NamespaceTopicsClient,
45+
Client: client,
3746
}, nil
3847
}
Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package eventgrid
5+
6+
import (
7+
"context"
8+
"fmt"
9+
"regexp"
10+
"time"
11+
12+
"github.com/hashicorp/go-azure-helpers/lang/pointer"
13+
"github.com/hashicorp/go-azure-helpers/lang/response"
14+
"github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids"
15+
"github.com/hashicorp/go-azure-sdk/resource-manager/eventgrid/2025-02-15/namespaces"
16+
"github.com/hashicorp/go-azure-sdk/resource-manager/eventgrid/2025-02-15/namespacetopics"
17+
"github.com/hashicorp/terraform-provider-azurerm/internal/sdk"
18+
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk"
19+
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation"
20+
)
21+
22+
//go:generate go run ../../tools/generator-tests resourceidentity -resource-name eventgrid_namespace_topic -properties "name" -compare-values "subscription_id:eventgrid_namespace_id,resource_group_name:eventgrid_namespace_id,namespace_name:eventgrid_namespace_id"
23+
24+
var (
25+
_ sdk.ResourceWithUpdate = EventGridNamespaceTopicResource{}
26+
_ sdk.ResourceWithIdentity = EventGridNamespaceTopicResource{}
27+
)
28+
29+
type EventGridNamespaceTopicResource struct{}
30+
31+
type EventGridNamespaceTopicResourceModel struct {
32+
Name string `tfschema:"name"`
33+
EventgridNamespaceId string `tfschema:"eventgrid_namespace_id"`
34+
EventRetentionInDays int64 `tfschema:"event_retention_in_days"`
35+
}
36+
37+
func (r EventGridNamespaceTopicResource) Arguments() map[string]*pluginsdk.Schema {
38+
return map[string]*pluginsdk.Schema{
39+
"name": {
40+
Type: pluginsdk.TypeString,
41+
Required: true,
42+
ForceNew: true,
43+
ValidateFunc: validation.All(
44+
validation.StringIsNotEmpty,
45+
validation.StringMatch(
46+
regexp.MustCompile("^[a-zA-Z0-9-]{3,50}$"),
47+
"Event Grid Namespace Topic name must be 3 - 50 characters long, contain only letters, numbers and hyphens.",
48+
),
49+
),
50+
},
51+
52+
"eventgrid_namespace_id": {
53+
Type: pluginsdk.TypeString,
54+
Required: true,
55+
ForceNew: true,
56+
ValidateFunc: namespacetopics.ValidateNamespaceID,
57+
},
58+
59+
"event_retention_in_days": {
60+
Type: pluginsdk.TypeInt,
61+
Optional: true,
62+
Default: 7,
63+
ValidateFunc: validation.IntBetween(1, 7),
64+
},
65+
}
66+
}
67+
68+
func (r EventGridNamespaceTopicResource) ModelObject() interface{} {
69+
return &EventGridNamespaceTopicResourceModel{}
70+
}
71+
72+
func (r EventGridNamespaceTopicResource) ResourceType() string {
73+
return "azurerm_eventgrid_namespace_topic"
74+
}
75+
76+
func (r EventGridNamespaceTopicResource) Attributes() map[string]*pluginsdk.Schema {
77+
return map[string]*pluginsdk.Schema{}
78+
}
79+
80+
func (r EventGridNamespaceTopicResource) Create() sdk.ResourceFunc {
81+
return sdk.ResourceFunc{
82+
Timeout: 30 * time.Minute,
83+
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
84+
client := metadata.Client.EventGrid.NamespaceTopicsClient
85+
86+
var model EventGridNamespaceTopicResourceModel
87+
if err := metadata.Decode(&model); err != nil {
88+
return fmt.Errorf("decoding: %+v", err)
89+
}
90+
91+
namespaceId, err := namespaces.ParseNamespaceID(model.EventgridNamespaceId)
92+
if err != nil {
93+
return err
94+
}
95+
96+
id := namespacetopics.NewNamespaceTopicID(namespaceId.SubscriptionId, namespaceId.ResourceGroupName, namespaceId.NamespaceName, model.Name)
97+
98+
existing, err := client.Get(ctx, id)
99+
if err != nil {
100+
if !response.WasNotFound(existing.HttpResponse) {
101+
return fmt.Errorf("checking for presence of existing %s: %s", id, err)
102+
}
103+
}
104+
105+
if !response.WasNotFound(existing.HttpResponse) {
106+
return metadata.ResourceRequiresImport(r.ResourceType(), id)
107+
}
108+
109+
namespaceTopic := namespacetopics.NamespaceTopic{
110+
Name: pointer.To(model.Name),
111+
Properties: &namespacetopics.NamespaceTopicProperties{
112+
EventRetentionInDays: pointer.To(model.EventRetentionInDays),
113+
InputSchema: pointer.To(namespacetopics.EventInputSchemaCloudEventSchemaVOneZero),
114+
PublisherType: pointer.To(namespacetopics.PublisherTypeCustom),
115+
},
116+
}
117+
118+
if err = client.CreateOrUpdateThenPoll(ctx, id, namespaceTopic); err != nil {
119+
return fmt.Errorf("creating %s: %+v", id, err)
120+
}
121+
122+
metadata.SetID(id)
123+
return pluginsdk.SetResourceIdentityData(metadata.ResourceData, &id)
124+
},
125+
}
126+
}
127+
128+
func (r EventGridNamespaceTopicResource) Update() sdk.ResourceFunc {
129+
return sdk.ResourceFunc{
130+
Timeout: 30 * time.Minute,
131+
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
132+
client := metadata.Client.EventGrid.NamespaceTopicsClient
133+
134+
var model EventGridNamespaceTopicResourceModel
135+
if err := metadata.Decode(&model); err != nil {
136+
return fmt.Errorf("decoding: %+v", err)
137+
}
138+
139+
id, err := namespacetopics.ParseNamespaceTopicID(metadata.ResourceData.Id())
140+
if err != nil {
141+
return err
142+
}
143+
144+
payload := namespacetopics.NamespaceTopicUpdateParameters{
145+
Properties: &namespacetopics.NamespaceTopicUpdateParameterProperties{},
146+
}
147+
148+
if metadata.ResourceData.HasChange("event_retention_in_days") {
149+
payload.Properties.EventRetentionInDays = pointer.To(model.EventRetentionInDays)
150+
}
151+
152+
if err = client.UpdateThenPoll(ctx, *id, payload); err != nil {
153+
return fmt.Errorf("updating %s: %+v", id, err)
154+
}
155+
156+
return nil
157+
},
158+
}
159+
}
160+
161+
func (r EventGridNamespaceTopicResource) Read() sdk.ResourceFunc {
162+
return sdk.ResourceFunc{
163+
Timeout: 5 * time.Minute,
164+
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
165+
client := metadata.Client.EventGrid.NamespaceTopicsClient
166+
167+
id, err := namespacetopics.ParseNamespaceTopicID(metadata.ResourceData.Id())
168+
if err != nil {
169+
return err
170+
}
171+
172+
resp, err := client.Get(ctx, *id)
173+
if err != nil {
174+
if response.WasNotFound(resp.HttpResponse) {
175+
return metadata.MarkAsGone(id)
176+
}
177+
return fmt.Errorf("retrieving %s: %+v", *id, err)
178+
}
179+
180+
state := EventGridNamespaceTopicResourceModel{
181+
Name: id.TopicName,
182+
EventgridNamespaceId: namespacetopics.NewNamespaceID(id.SubscriptionId, id.ResourceGroupName, id.NamespaceName).ID(),
183+
}
184+
185+
if model := resp.Model; model != nil {
186+
if props := model.Properties; props != nil {
187+
state.EventRetentionInDays = pointer.From(props.EventRetentionInDays)
188+
}
189+
}
190+
191+
if err := pluginsdk.SetResourceIdentityData(metadata.ResourceData, id); err != nil {
192+
return err
193+
}
194+
195+
return metadata.Encode(&state)
196+
},
197+
}
198+
}
199+
200+
func (r EventGridNamespaceTopicResource) Delete() sdk.ResourceFunc {
201+
return sdk.ResourceFunc{
202+
Timeout: 30 * time.Minute,
203+
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
204+
client := metadata.Client.EventGrid.NamespaceTopicsClient
205+
206+
id, err := namespacetopics.ParseNamespaceTopicID(metadata.ResourceData.Id())
207+
if err != nil {
208+
return err
209+
}
210+
211+
if err := client.DeleteThenPoll(ctx, *id); err != nil {
212+
return fmt.Errorf("deleting %s: %v", *id, err)
213+
}
214+
215+
return nil
216+
},
217+
}
218+
}
219+
220+
func (r EventGridNamespaceTopicResource) IDValidationFunc() pluginsdk.SchemaValidateFunc {
221+
return namespacetopics.ValidateNamespaceTopicID
222+
}
223+
224+
func (r EventGridNamespaceTopicResource) Identity() resourceids.ResourceId {
225+
return new(namespacetopics.NamespaceTopicId)
226+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Copyright IBM Corp. 2014, 2025
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package eventgrid_test
5+
6+
import (
7+
"testing"
8+
9+
"github.com/hashicorp/terraform-plugin-testing/statecheck"
10+
"github.com/hashicorp/terraform-plugin-testing/tfjsonpath"
11+
"github.com/hashicorp/terraform-provider-azurerm/internal/acceptance"
12+
customstatecheck "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/statecheck"
13+
)
14+
15+
func TestAccEventgridNamespaceTopic_resourceIdentity(t *testing.T) {
16+
data := acceptance.BuildTestData(t, "azurerm_eventgrid_namespace_topic", "test")
17+
r := EventgridNamespaceTopicResource{}
18+
19+
checkedFields := map[string]struct{}{
20+
"name": {},
21+
"namespace_name": {},
22+
"resource_group_name": {},
23+
"subscription_id": {},
24+
}
25+
26+
data.ResourceIdentityTest(t, []acceptance.TestStep{
27+
{
28+
Config: r.basic(data),
29+
ConfigStateChecks: []statecheck.StateCheck{
30+
customstatecheck.ExpectAllIdentityFieldsAreChecked("azurerm_eventgrid_namespace_topic.test", checkedFields),
31+
statecheck.ExpectIdentityValueMatchesStateAtPath("azurerm_eventgrid_namespace_topic.test", tfjsonpath.New("name"), tfjsonpath.New("name")),
32+
customstatecheck.ExpectStateContainsIdentityValueAtPath("azurerm_eventgrid_namespace_topic.test", tfjsonpath.New("namespace_name"), tfjsonpath.New("eventgrid_namespace_id")),
33+
customstatecheck.ExpectStateContainsIdentityValueAtPath("azurerm_eventgrid_namespace_topic.test", tfjsonpath.New("resource_group_name"), tfjsonpath.New("eventgrid_namespace_id")),
34+
customstatecheck.ExpectStateContainsIdentityValueAtPath("azurerm_eventgrid_namespace_topic.test", tfjsonpath.New("subscription_id"), tfjsonpath.New("eventgrid_namespace_id")),
35+
},
36+
},
37+
data.ImportBlockWithResourceIdentityStep(false),
38+
data.ImportBlockWithIDStep(false),
39+
}, false)
40+
}

0 commit comments

Comments
 (0)