Skip to content

Commit

Permalink
fix zones behavior change
Browse files Browse the repository at this point in the history
  • Loading branch information
ms-henglu committed May 28, 2021
1 parent 292f34e commit 69d79a8
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 7 deletions.
30 changes: 30 additions & 0 deletions azurerm/internal/services/network/availability_zone.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package network

import (
"context"

"github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2020-06-01/resources"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure"
)

func getZones(ctx context.Context, client *resources.ProvidersClient, resourceType, location string) (*[]string, error) {
provider, err := client.Get(ctx, "Microsoft.Network", "")
if err != nil {
return nil, err
}
normalizedLocation := azure.NormalizeLocation(location)
for _, resource := range *provider.ResourceTypes {
if resource.ResourceType == nil || *resource.ResourceType != resourceType {
continue
}
if resource.ZoneMappings == nil {
continue
}
for _, zone := range *resource.ZoneMappings {
if zone.Location != nil && azure.NormalizeLocation(*zone.Location) == normalizedLocation {
return zone.Zones, nil
}
}
}
return nil, nil
}
35 changes: 34 additions & 1 deletion azurerm/internal/services/network/public_ip_prefix_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package network
import (
"fmt"
"log"
"strings"
"time"

"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2020-11-01/network"
Expand Down Expand Up @@ -103,6 +104,20 @@ func resourcePublicIpPrefixCreateUpdate(d *pluginsdk.ResourceData, meta interfac
t := d.Get("tags").(map[string]interface{})
zones := azure.ExpandZones(d.Get("zones").([]interface{}))

// TODO: remove in 3.0
// to address this breaking change : https://azure.microsoft.com/en-us/updates/zone-behavior-change/, by setting a location's available zone list as default value to keep the behavior unchanged,
// to create a non-zonal resource, user can set zones to ["no_zone"]
if zones == nil || len(*zones) == 0 {
allZones, err := getZones(ctx, meta.(*clients.Client).Resource.ResourceProvidersClient, "publicIPPrefixes", location)
if err != nil {
return fmt.Errorf("failed to get available zones for resourceType: publicIPAddresses, location: %s:%+v", location, err)
} else {
zones = allZones
}
} else if (*zones)[0] == "no_zone" {
zones = nil
}

publicIpPrefix := network.PublicIPPrefix{
Location: &location,
Sku: &network.PublicIPPrefixSku{
Expand Down Expand Up @@ -151,7 +166,25 @@ func resourcePublicIpPrefixRead(d *pluginsdk.ResourceData, meta interface{}) err

d.Set("name", id.PublicIPPrefixeName)
d.Set("resource_group_name", id.ResourceGroup)
d.Set("zones", resp.Zones)
// TODO: remove in 3.0
zones := make([]string, 0)
if resp.Location != nil && resp.Sku != nil && strings.EqualFold(string(resp.Sku.Name), "standard") {
allZones, err := getZones(ctx, meta.(*clients.Client).Resource.ResourceProvidersClient, "publicIPPrefixes", *resp.Location)
if err != nil {
return fmt.Errorf("failed to get available zones for resourceType: publicIPPrefixes, location: %s:%+v", *resp.Location, err)
}
switch {
case allZones == nil || len(*allZones) == 0:
zones = make([]string, 0)
case resp.Zones == nil || len(*resp.Zones) == 0:
zones = append(zones, "no_zone")
case len(*resp.Zones) == 1:
zones = append(zones, (*resp.Zones)[0])
default:
zones = make([]string, 0)
}
}
d.Set("zones", &zones)
if location := resp.Location; location != nil {
d.Set("location", azure.NormalizeLocation(*location))
}
Expand Down
36 changes: 34 additions & 2 deletions azurerm/internal/services/network/public_ip_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,21 @@ func resourcePublicIpCreateUpdate(d *pluginsdk.ResourceData, meta interface{}) e
return tf.ImportAsExistsError("azurerm_public_ip", id.ID())
}
}

// TODO: remove in 3.0
// to address this breaking change : https://azure.microsoft.com/en-us/updates/zone-behavior-change/, by setting a location's available zone list as default value to keep the behavior unchanged,
// to create a non-zonal resource, user can set zones to ["no_zone"]
if strings.EqualFold(sku, "standard") {
if zones == nil || len(*zones) == 0 {
allZones, err := getZones(ctx, meta.(*clients.Client).Resource.ResourceProvidersClient, "publicIPAddresses", location)
if err != nil {
return fmt.Errorf("failed to get available zones for resourceType: publicIPAddresses, location: %s:%+v", location, err)
} else {
zones = allZones
}
} else if (*zones)[0] == "no_zone" {
zones = nil
}
}
publicIp := network.PublicIPAddress{
Name: utils.String(id.Name),
Location: &location,
Expand Down Expand Up @@ -267,7 +281,25 @@ func resourcePublicIpRead(d *pluginsdk.ResourceData, meta interface{}) error {

d.Set("name", id.Name)
d.Set("resource_group_name", id.ResourceGroup)
d.Set("zones", resp.Zones)
// TODO: remove in 3.0
zones := make([]string, 0)
if resp.Location != nil && resp.Sku != nil && strings.EqualFold(string(resp.Sku.Name), "standard") {
allZones, err := getZones(ctx, meta.(*clients.Client).Resource.ResourceProvidersClient, "publicIPAddresses", *resp.Location)
if err != nil {
return fmt.Errorf("failed to get available zones for resourceType: publicIPAddresses, location: %s:%+v", *resp.Location, err)
}
switch {
case allZones == nil || len(*allZones) == 0:
zones = make([]string, 0)
case resp.Zones == nil || len(*resp.Zones) == 0:
zones = append(zones, "no_zone")
case len(*resp.Zones) == 1:
zones = append(zones, (*resp.Zones)[0])
default:
zones = make([]string, 0)
}
}
d.Set("zones", &zones)
if location := resp.Location; location != nil {
d.Set("location", azure.NormalizeLocation(*location))
}
Expand Down
4 changes: 2 additions & 2 deletions azurerm/internal/services/network/public_ip_resource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -771,9 +771,9 @@ resource "azurerm_public_ip" "test" {
resource_group_name = azurerm_resource_group.test.name
allocation_method = "Static"
domain_name_label = "k2345678-1-2345678-2-2345678-3-2345678-4-2345678-5-2345678-6-23"
domain_name_label = "%s"
}
`, data.RandomInteger, data.Locations.Primary, data.RandomInteger)
`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomStringOfLength(63))
}

func (PublicIPResource) standard_IpTags(data acceptance.TestData) string {
Expand Down
6 changes: 6 additions & 0 deletions azurerm/internal/services/resource/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ type Client struct {
GroupsClient *resources.GroupsClient
LocksClient *locks.ManagementLocksClient
ProvidersClient *providers.ProvidersClient
ResourceProvidersClient *resources.ProvidersClient
ResourcesClient *resources.Client
TemplateSpecsVersionsClient *templatespecs.VersionsClient
}
Expand All @@ -31,6 +32,10 @@ func NewClient(o *common.ClientOptions) *Client {
providersClient := providers.NewProvidersClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId)
o.ConfigureClient(&providersClient.Client, o.ResourceManagerAuthorizer)

// add a secondary ProvidersClient to use latest resources sdk
resourceProvidersClient := resources.NewProvidersClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId)
o.ConfigureClient(&resourceProvidersClient.Client, o.ResourceManagerAuthorizer)

resourcesClient := resources.NewClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId)
o.ConfigureClient(&resourcesClient.Client, o.ResourceManagerAuthorizer)

Expand All @@ -42,6 +47,7 @@ func NewClient(o *common.ClientOptions) *Client {
DeploymentsClient: &deploymentsClient,
LocksClient: &locksClient,
ProvidersClient: &providersClient,
ResourceProvidersClient: &resourceProvidersClient,
ResourcesClient: &resourcesClient,
TemplateSpecsVersionsClient: &templatespecsVersionsClient,
}
Expand Down
2 changes: 1 addition & 1 deletion website/docs/r/public_ip.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ The following arguments are supported:

* `zones` - (Optional) A collection containing the availability zone to allocate the Public IP in.

-> **Please Note**: Availability Zones are only supported with a [Standard SKU](https://docs.microsoft.com/en-us/azure/virtual-network/virtual-network-ip-addresses-overview-arm#standard) and [in select regions](https://docs.microsoft.com/en-us/azure/availability-zones/az-overview) at this time. Standard SKU Public IP Addresses that do not specify a zone are zone redundant by default.
-> **Please Note**: Availability Zones are only supported with a [Standard SKU](https://docs.microsoft.com/en-us/azure/virtual-network/virtual-network-ip-addresses-overview-arm#standard) and [in select regions](https://docs.microsoft.com/en-us/azure/availability-zones/az-overview) at this time. Standard SKU Public IP Addresses that do not specify a zone are zone redundant by default. Set it to `no_zone` to create a non-zonal resource.

## Attributes Reference

Expand Down
2 changes: 1 addition & 1 deletion website/docs/r/public_ip_prefix.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ The following arguments are supported:

* `zones` - (Optional) A collection containing the availability zone to allocate the Public IP Prefix in.

-> **Please Note**: Availability Zones are [only supported in several regions at this time](https://docs.microsoft.com/en-us/azure/availability-zones/az-overview).
-> **Please Note**: Availability Zones are [only supported in several regions at this time](https://docs.microsoft.com/en-us/azure/availability-zones/az-overview). Set it to `no_zone` to create a non-zonal resource.

## Attributes Reference

Expand Down

0 comments on commit 69d79a8

Please sign in to comment.