Skip to content

Commit e24f3c0

Browse files
authored
New Resource: azurerm_network_manager_ipam_pool (hashicorp#28695)
* network manager ipam pool * fix doc * fix test * fix test * fix test * fix name validation * fix error message * fix code * fix * fix
1 parent a8fd980 commit e24f3c0

File tree

7 files changed

+640
-1
lines changed

7 files changed

+640
-1
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package custompollers
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/hashicorp/go-azure-helpers/lang/response"
8+
"github.com/hashicorp/go-azure-sdk/resource-manager/network/2024-05-01/ipampools"
9+
"github.com/hashicorp/go-azure-sdk/sdk/client/pollers"
10+
)
11+
12+
var _ pollers.PollerType = &networkManagerIPAMPoolDeletePoller{}
13+
14+
type networkManagerIPAMPoolDeletePoller struct {
15+
client *ipampools.IPamPoolsClient
16+
id ipampools.IPamPoolId
17+
}
18+
19+
func NewNetworkManagerIPAMPoolDeletePoller(client *ipampools.IPamPoolsClient, id ipampools.IPamPoolId) *networkManagerIPAMPoolDeletePoller {
20+
return &networkManagerIPAMPoolDeletePoller{
21+
client: client,
22+
id: id,
23+
}
24+
}
25+
26+
func (p networkManagerIPAMPoolDeletePoller) Poll(ctx context.Context) (*pollers.PollResult, error) {
27+
resp, err := p.client.Get(ctx, p.id)
28+
if err != nil {
29+
if response.WasNotFound(resp.HttpResponse) {
30+
return &pollingSuccess, nil
31+
}
32+
return nil, fmt.Errorf("retrieving %s: %+v", p.id, err)
33+
}
34+
35+
return &pollingInProgress, nil
36+
}

internal/services/network/network_manager_data_source_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ func testAccNetworkManagerDataSource_complete(t *testing.T) {
2222
Check: acceptance.ComposeTestCheckFunc(
2323
check.That(data.ResourceName).Key("location").IsNotEmpty(),
2424
check.That(data.ResourceName).Key("description").IsNotEmpty(),
25-
check.That(data.ResourceName).Key("scope_accesses.#").HasValue("2"),
25+
check.That(data.ResourceName).Key("scope_accesses.#").HasValue("3"),
2626
check.That(data.ResourceName).Key("scope_accesses.0").HasValue("Connectivity"),
2727
check.That(data.ResourceName).Key("scope.#").HasValue("1"),
2828
check.That(data.ResourceName).Key("scope.0.subscription_ids.#").HasValue("1"),
Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
package network
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"regexp"
7+
"time"
8+
9+
"github.com/hashicorp/go-azure-helpers/lang/pointer"
10+
"github.com/hashicorp/go-azure-helpers/lang/response"
11+
"github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema"
12+
"github.com/hashicorp/go-azure-helpers/resourcemanager/location"
13+
"github.com/hashicorp/go-azure-sdk/resource-manager/network/2024-05-01/ipampools"
14+
"github.com/hashicorp/go-azure-sdk/sdk/client/pollers"
15+
"github.com/hashicorp/terraform-provider-azurerm/internal/sdk"
16+
"github.com/hashicorp/terraform-provider-azurerm/internal/services/network/custompollers"
17+
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk"
18+
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation"
19+
)
20+
21+
var _ sdk.ResourceWithUpdate = ManagerIpamPoolResource{}
22+
23+
type ManagerIpamPoolResource struct{}
24+
25+
func (ManagerIpamPoolResource) IDValidationFunc() pluginsdk.SchemaValidateFunc {
26+
return ipampools.ValidateIPamPoolID
27+
}
28+
29+
func (ManagerIpamPoolResource) ResourceType() string {
30+
return "azurerm_network_manager_ipam_pool"
31+
}
32+
33+
func (ManagerIpamPoolResource) ModelObject() interface{} {
34+
return &ManagerIpamPoolResourceModel{}
35+
}
36+
37+
type ManagerIpamPoolResourceModel struct {
38+
AddressPrefixes []string `tfschema:"address_prefixes"`
39+
Description string `tfschema:"description"`
40+
DisplayName string `tfschema:"display_name"`
41+
Location string `tfschema:"location"`
42+
Name string `tfschema:"name"`
43+
NetworkManagerId string `tfschema:"network_manager_id"`
44+
ParentPoolName string `tfschema:"parent_pool_name"`
45+
Tags map[string]string `tfschema:"tags"`
46+
}
47+
48+
func (ManagerIpamPoolResource) Arguments() map[string]*pluginsdk.Schema {
49+
return map[string]*pluginsdk.Schema{
50+
"name": {
51+
Type: pluginsdk.TypeString,
52+
Required: true,
53+
ForceNew: true,
54+
ValidateFunc: validation.StringMatch(
55+
regexp.MustCompile(`^[a-zA-Z0-9\_\.\-]{1,64}$`),
56+
"`name` must be between 1 and 64 characters long and can only contain letters, numbers, underscores(_), periods(.), and hyphens(-).",
57+
),
58+
},
59+
60+
"network_manager_id": commonschema.ResourceIDReferenceRequiredForceNew(&ipampools.NetworkManagerId{}),
61+
62+
"location": commonschema.Location(),
63+
64+
"display_name": {
65+
Type: pluginsdk.TypeString,
66+
Required: true,
67+
ValidateFunc: validation.StringMatch(
68+
regexp.MustCompile(`^[a-zA-Z0-9\_\.\-]{1,64}$`),
69+
"`display_name` must be between 1 and 64 characters long and can only contain letters, numbers, underscores(_), periods(.), and hyphens(-).",
70+
),
71+
},
72+
73+
"address_prefixes": {
74+
Type: pluginsdk.TypeList,
75+
Required: true,
76+
ForceNew: true,
77+
Elem: &pluginsdk.Schema{
78+
Type: pluginsdk.TypeString,
79+
ValidateFunc: validation.IsCIDR,
80+
},
81+
},
82+
83+
"parent_pool_name": {
84+
Type: pluginsdk.TypeString,
85+
Optional: true,
86+
ForceNew: true,
87+
ValidateFunc: validation.StringMatch(
88+
regexp.MustCompile(`^[a-zA-Z0-9\_\.\-]{1,64}$`),
89+
"`parent_pool_name` must be between 1 and 64 characters long and can only contain letters, numbers, underscores(_), periods(.), and hyphens(-).",
90+
),
91+
},
92+
93+
"description": {
94+
Type: pluginsdk.TypeString,
95+
Optional: true,
96+
ValidateFunc: validation.StringIsNotEmpty,
97+
},
98+
99+
"tags": commonschema.Tags(),
100+
}
101+
}
102+
103+
func (ManagerIpamPoolResource) Attributes() map[string]*pluginsdk.Schema {
104+
return map[string]*pluginsdk.Schema{}
105+
}
106+
107+
func (r ManagerIpamPoolResource) Create() sdk.ResourceFunc {
108+
return sdk.ResourceFunc{
109+
Timeout: 30 * time.Minute,
110+
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
111+
client := metadata.Client.Network.IPamPools
112+
subscriptionId := metadata.Client.Account.SubscriptionId
113+
114+
var config ManagerIpamPoolResourceModel
115+
if err := metadata.Decode(&config); err != nil {
116+
return fmt.Errorf("decoding: %+v", err)
117+
}
118+
119+
networkManagerId, err := ipampools.ParseNetworkManagerID(config.NetworkManagerId)
120+
if err != nil {
121+
return err
122+
}
123+
124+
id := ipampools.NewIPamPoolID(subscriptionId, networkManagerId.ResourceGroupName, networkManagerId.NetworkManagerName, config.Name)
125+
126+
existing, err := client.Get(ctx, id)
127+
if err != nil && !response.WasNotFound(existing.HttpResponse) {
128+
return fmt.Errorf("checking for presence of existing %s: %+v", id, err)
129+
}
130+
if !response.WasNotFound(existing.HttpResponse) {
131+
return metadata.ResourceRequiresImport(r.ResourceType(), id)
132+
}
133+
134+
payload := ipampools.IPamPool{
135+
Name: pointer.To(config.Name),
136+
Location: location.Normalize(config.Location),
137+
Tags: pointer.To(config.Tags),
138+
Properties: ipampools.IPamPoolProperties{
139+
AddressPrefixes: config.AddressPrefixes,
140+
Description: pointer.To(config.Description),
141+
DisplayName: pointer.To(config.DisplayName),
142+
ParentPoolName: pointer.To(config.ParentPoolName),
143+
},
144+
}
145+
146+
if err := client.CreateThenPoll(ctx, id, payload); err != nil {
147+
return fmt.Errorf("creating %s: %+v", id, err)
148+
}
149+
150+
metadata.SetID(id)
151+
152+
return nil
153+
},
154+
}
155+
}
156+
157+
func (r ManagerIpamPoolResource) Read() sdk.ResourceFunc {
158+
return sdk.ResourceFunc{
159+
Timeout: 5 * time.Minute,
160+
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
161+
client := metadata.Client.Network.IPamPools
162+
163+
id, err := ipampools.ParseIPamPoolID(metadata.ResourceData.Id())
164+
if err != nil {
165+
return err
166+
}
167+
168+
resp, err := client.Get(ctx, *id)
169+
if err != nil {
170+
if response.WasNotFound(resp.HttpResponse) {
171+
return metadata.MarkAsGone(id)
172+
}
173+
174+
return fmt.Errorf("retrieving %s: %+v", id, err)
175+
}
176+
177+
networkManagerId := ipampools.NewNetworkManagerID(id.SubscriptionId, id.ResourceGroupName, id.NetworkManagerName).ID()
178+
schema := ManagerIpamPoolResourceModel{
179+
Name: id.IpamPoolName,
180+
NetworkManagerId: networkManagerId,
181+
}
182+
183+
if model := resp.Model; model != nil {
184+
schema.Location = location.Normalize(model.Location)
185+
schema.Tags = pointer.From(model.Tags)
186+
187+
props := model.Properties
188+
schema.AddressPrefixes = props.AddressPrefixes
189+
schema.Description = pointer.From(props.Description)
190+
schema.DisplayName = pointer.From(props.DisplayName)
191+
schema.ParentPoolName = pointer.From(props.ParentPoolName)
192+
}
193+
194+
return metadata.Encode(&schema)
195+
},
196+
}
197+
}
198+
199+
func (r ManagerIpamPoolResource) Update() sdk.ResourceFunc {
200+
return sdk.ResourceFunc{
201+
Timeout: 30 * time.Minute,
202+
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
203+
client := metadata.Client.Network.IPamPools
204+
205+
id, err := ipampools.ParseIPamPoolID(metadata.ResourceData.Id())
206+
if err != nil {
207+
return err
208+
}
209+
210+
var model ManagerIpamPoolResourceModel
211+
if err := metadata.Decode(&model); err != nil {
212+
return fmt.Errorf("decoding: %+v", err)
213+
}
214+
215+
parameters := ipampools.IPamPoolUpdate{
216+
Properties: &ipampools.IPamPoolUpdateProperties{},
217+
}
218+
219+
if metadata.ResourceData.HasChange("tags") {
220+
parameters.Tags = pointer.To(model.Tags)
221+
}
222+
223+
if metadata.ResourceData.HasChange("description") {
224+
parameters.Properties.Description = pointer.To(model.Description)
225+
}
226+
227+
if metadata.ResourceData.HasChange("display_name") {
228+
parameters.Properties.DisplayName = pointer.To(model.DisplayName)
229+
}
230+
231+
if _, err := client.Update(ctx, *id, parameters); err != nil {
232+
return fmt.Errorf("updating %s: %+v", id, err)
233+
}
234+
return nil
235+
},
236+
}
237+
}
238+
239+
func (r ManagerIpamPoolResource) Delete() sdk.ResourceFunc {
240+
return sdk.ResourceFunc{
241+
Timeout: 30 * time.Minute,
242+
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
243+
client := metadata.Client.Network.IPamPools
244+
245+
id, err := ipampools.ParseIPamPoolID(metadata.ResourceData.Id())
246+
if err != nil {
247+
return err
248+
}
249+
250+
if err := client.DeleteThenPoll(ctx, *id); err != nil {
251+
return fmt.Errorf("deleting %s: %+v", id, err)
252+
}
253+
254+
// https://github.com/Azure/azure-rest-api-specs/issues/31688
255+
pollerType := custompollers.NewNetworkManagerIPAMPoolDeletePoller(client, *id)
256+
poller := pollers.NewPoller(pollerType, 10*time.Second, pollers.DefaultNumberOfDroppedConnectionsToAllow)
257+
if err := poller.PollUntilDone(ctx); err != nil {
258+
return err
259+
}
260+
261+
return nil
262+
},
263+
}
264+
}

0 commit comments

Comments
 (0)