Skip to content

Commit 090efd0

Browse files
authored
azurerm_nat_gateway_public_ip_prefix_association - support associating IPv6 Public IP Prefixes (hashicorp#32195)
[ENHANCEMENT] * `azurerm_nat_gateway_public_ip_prefix_association` - add support for IPv6 public IP prefixes
1 parent 0206725 commit 090efd0

26 files changed

+295
-1249
lines changed

internal/services/network/nat_gateway_public_ip_prefix_association_resource.go

Lines changed: 97 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ import (
1212
"github.com/hashicorp/go-azure-helpers/lang/pointer"
1313
"github.com/hashicorp/go-azure-helpers/lang/response"
1414
"github.com/hashicorp/go-azure-helpers/resourcemanager/commonids"
15-
"github.com/hashicorp/go-azure-sdk/resource-manager/network/2023-09-01/publicipprefixes"
1615
"github.com/hashicorp/go-azure-sdk/resource-manager/network/2025-01-01/natgateways"
16+
"github.com/hashicorp/go-azure-sdk/resource-manager/network/2025-01-01/publicipprefixes"
1717
"github.com/hashicorp/terraform-provider-azurerm/helpers/tf"
1818
"github.com/hashicorp/terraform-provider-azurerm/internal/clients"
1919
"github.com/hashicorp/terraform-provider-azurerm/internal/locks"
@@ -71,8 +71,8 @@ func resourceNATGatewayPublicIpPrefixAssociationCreate(d *pluginsdk.ResourceData
7171
return err
7272
}
7373

74-
locks.ByName(natGatewayId.NatGatewayName, natGatewayResourceName)
75-
defer locks.UnlockByName(natGatewayId.NatGatewayName, natGatewayResourceName)
74+
locks.ByID(natGatewayId.ID())
75+
defer locks.UnlockByID(natGatewayId.ID())
7676

7777
natGateway, err := client.Get(ctx, *natGatewayId, natgateways.DefaultGetOperationOptions())
7878
if err != nil {
@@ -89,27 +89,42 @@ func resourceNATGatewayPublicIpPrefixAssociationCreate(d *pluginsdk.ResourceData
8989
return fmt.Errorf("retrieving %s: `properties` was nil", natGatewayId)
9090
}
9191

92-
id := commonids.NewCompositeResourceID(natGatewayId, publicIpPrefixId)
93-
94-
publicIpPrefixes := make([]natgateways.SubResource, 0)
95-
if natGateway.Model.Properties.PublicIPPrefixes != nil {
96-
for _, existingPublicIPPrefix := range *natGateway.Model.Properties.PublicIPPrefixes {
97-
if existingPublicIPPrefix.Id == nil {
98-
continue
99-
}
92+
publicIpPrefix, err := meta.(*clients.Client).Network.PublicIPPrefixes.Get(ctx, *publicIpPrefixId, publicipprefixes.DefaultGetOperationOptions())
93+
if err != nil {
94+
if response.WasNotFound(publicIpPrefix.HttpResponse) {
95+
return fmt.Errorf("%s was not found", publicIpPrefixId)
96+
}
97+
return fmt.Errorf("retrieving %s: %+v", publicIpPrefixId, err)
98+
}
99+
if publicIpPrefix.Model == nil {
100+
return fmt.Errorf("retrieving %s: `model` was nil", publicIpPrefixId)
101+
}
102+
if publicIpPrefix.Model.Properties == nil {
103+
return fmt.Errorf("retrieving %s: `properties` was nil", publicIpPrefixId)
104+
}
100105

101-
if strings.EqualFold(*existingPublicIPPrefix.Id, publicIpPrefixId.ID()) {
102-
return tf.ImportAsExistsError("azurerm_nat_gateway_public_ip_prefix_association", id.ID())
103-
}
106+
isIPv6 := pointer.From(publicIpPrefix.Model.Properties.PublicIPAddressVersion) == publicipprefixes.IPVersionIPvSix
107+
id := commonids.NewCompositeResourceID(natGatewayId, publicIpPrefixId)
104108

105-
publicIpPrefixes = append(publicIpPrefixes, existingPublicIPPrefix)
109+
gatewayProperties := natGateway.Model.Properties
110+
publicIpPrefixes := pointer.From(gatewayProperties.PublicIPPrefixes)
111+
if isIPv6 {
112+
publicIpPrefixes = pointer.From(gatewayProperties.PublicIPPrefixesV6)
113+
}
114+
for _, existingPublicIPPrefix := range publicIpPrefixes {
115+
if strings.EqualFold(pointer.From(existingPublicIPPrefix.Id), publicIpPrefixId.ID()) {
116+
return tf.ImportAsExistsError("azurerm_nat_gateway_public_ip_prefix_association", id.ID())
106117
}
107118
}
108119

109120
publicIpPrefixes = append(publicIpPrefixes, natgateways.SubResource{
110121
Id: pointer.To(publicIpPrefixId.ID()),
111122
})
112-
natGateway.Model.Properties.PublicIPPrefixes = &publicIpPrefixes
123+
if isIPv6 {
124+
gatewayProperties.PublicIPPrefixesV6 = pointer.To(publicIpPrefixes)
125+
} else {
126+
gatewayProperties.PublicIPPrefixes = pointer.To(publicIpPrefixes)
127+
}
113128

114129
if err := client.CreateOrUpdateThenPoll(ctx, *natGatewayId, *natGateway.Model); err != nil {
115130
return fmt.Errorf("updating %s: %+v", natGatewayId, err)
@@ -140,32 +155,16 @@ func resourceNATGatewayPublicIpPrefixAssociationRead(d *pluginsdk.ResourceData,
140155
return fmt.Errorf("retrieving %s: %+v", id.First, err)
141156
}
142157

143-
if model := natGateway.Model; model != nil {
144-
if props := model.Properties; props != nil {
145-
if props.PublicIPPrefixes == nil {
146-
log.Printf("[DEBUG] %s doesn't have any Public IP Prefixes - removing from state!", id.First)
147-
d.SetId("")
148-
return nil
149-
}
150-
151-
publicIPPrefixId := ""
152-
for _, pipp := range *props.PublicIPPrefixes {
153-
if pipp.Id == nil {
154-
continue
155-
}
156-
157-
if strings.EqualFold(*pipp.Id, id.Second.ID()) {
158-
publicIPPrefixId = *pipp.Id
159-
break
160-
}
161-
}
162-
163-
if publicIPPrefixId == "" {
164-
log.Printf("[DEBUG] Association between %s and %s was not found - removing from state", id.First, id.Second)
165-
d.SetId("")
166-
return nil
167-
}
168-
}
158+
if natGateway.Model == nil {
159+
return fmt.Errorf("retrieving %s: `model` was nil", id.First)
160+
}
161+
if natGateway.Model.Properties == nil {
162+
return fmt.Errorf("retrieving %s: `properties` was nil", id.First)
163+
}
164+
if !natGatewayPublicIpPrefixAssociationExists(natGateway.Model.Properties, id.Second.ID()) {
165+
log.Printf("[DEBUG] Association between %s and %s was not found - removing from state", id.First, id.Second)
166+
d.SetId("")
167+
return nil
169168
}
170169

171170
d.Set("nat_gateway_id", id.First.ID())
@@ -184,8 +183,8 @@ func resourceNATGatewayPublicIpPrefixAssociationDelete(d *pluginsdk.ResourceData
184183
return err
185184
}
186185

187-
locks.ByName(id.First.NatGatewayName, natGatewayResourceName)
188-
defer locks.UnlockByName(id.First.NatGatewayName, natGatewayResourceName)
186+
locks.ByID(id.First.ID())
187+
defer locks.UnlockByID(id.First.ID())
189188

190189
natGateway, err := client.Get(ctx, *id.First, natgateways.DefaultGetOperationOptions())
191190
if err != nil {
@@ -202,23 +201,64 @@ func resourceNATGatewayPublicIpPrefixAssociationDelete(d *pluginsdk.ResourceData
202201
return fmt.Errorf("retrieving %s: `properties` was nil", id.First)
203202
}
204203

205-
publicIpPrefixes := make([]natgateways.SubResource, 0)
206-
if publicIPPrefixes := natGateway.Model.Properties.PublicIPPrefixes; publicIPPrefixes != nil {
207-
for _, publicIPPrefix := range *publicIPPrefixes {
208-
if publicIPPrefix.Id == nil {
209-
continue
210-
}
211-
212-
if !strings.EqualFold(*publicIPPrefix.Id, id.Second.ID()) {
213-
publicIpPrefixes = append(publicIpPrefixes, publicIPPrefix)
214-
}
215-
}
204+
if !removeNATGatewayPublicIpPrefixAssociation(natGateway.Model.Properties, id.Second.ID()) {
205+
return nil
216206
}
217-
natGateway.Model.Properties.PublicIPPrefixes = &publicIpPrefixes
218207

219208
if err := client.CreateOrUpdateThenPoll(ctx, *id.First, *natGateway.Model); err != nil {
220-
return fmt.Errorf("removing association between %s and %s: %+v", id.First, id.Second, err)
209+
return fmt.Errorf("deleting %s: %+v", id, err)
221210
}
222211

223212
return nil
224213
}
214+
215+
func natGatewayPublicIpPrefixAssociationExists(properties *natgateways.NatGatewayPropertiesFormat, publicIpPrefixId string) bool {
216+
if properties == nil {
217+
return false
218+
}
219+
220+
for _, publicIpPrefix := range pointer.From(properties.PublicIPPrefixes) {
221+
if strings.EqualFold(pointer.From(publicIpPrefix.Id), publicIpPrefixId) {
222+
return true
223+
}
224+
}
225+
226+
for _, publicIpPrefix := range pointer.From(properties.PublicIPPrefixesV6) {
227+
if strings.EqualFold(pointer.From(publicIpPrefix.Id), publicIpPrefixId) {
228+
return true
229+
}
230+
}
231+
232+
return false
233+
}
234+
235+
func removeNATGatewayPublicIpPrefixAssociation(properties *natgateways.NatGatewayPropertiesFormat, publicIpPrefixId string) bool {
236+
if properties == nil {
237+
return false
238+
}
239+
240+
removed := false
241+
updatedIPv4Prefixes := make([]natgateways.SubResource, 0)
242+
for _, publicIpPrefix := range pointer.From(properties.PublicIPPrefixes) {
243+
if strings.EqualFold(pointer.From(publicIpPrefix.Id), publicIpPrefixId) {
244+
removed = true
245+
continue
246+
}
247+
248+
updatedIPv4Prefixes = append(updatedIPv4Prefixes, publicIpPrefix)
249+
}
250+
properties.PublicIPPrefixes = pointer.To(updatedIPv4Prefixes)
251+
252+
updatedIPv6Prefixes := make([]natgateways.SubResource, 0)
253+
for _, publicIpPrefix := range pointer.From(properties.PublicIPPrefixesV6) {
254+
if strings.EqualFold(pointer.From(publicIpPrefix.Id), publicIpPrefixId) {
255+
removed = true
256+
continue
257+
}
258+
259+
updatedIPv6Prefixes = append(updatedIPv6Prefixes, publicIpPrefix)
260+
}
261+
properties.PublicIPPrefixesV6 = pointer.To(updatedIPv6Prefixes)
262+
263+
return removed
264+
}

0 commit comments

Comments
 (0)