diff --git a/internal/services/compute/edge_zone.go b/internal/services/compute/edge_zone.go new file mode 100644 index 000000000000..b689d5b99696 --- /dev/null +++ b/internal/services/compute/edge_zone.go @@ -0,0 +1,26 @@ +package compute + +import ( + "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2021-11-01/compute" + "github.com/hashicorp/go-azure-helpers/resourcemanager/edgezones" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +func expandEdgeZone(input string) *compute.ExtendedLocation { + normalized := edgezones.Normalize(input) + if normalized == "" { + return nil + } + + return &compute.ExtendedLocation{ + Name: utils.String(normalized), + Type: compute.ExtendedLocationTypesEdgeZone, + } +} + +func flattenEdgeZone(input *compute.ExtendedLocation) string { + if input == nil || input.Type != compute.ExtendedLocationTypesEdgeZone || input.Name == nil { + return "" + } + return edgezones.NormalizeNilable(input.Name) +} diff --git a/internal/services/compute/linux_virtual_machine_resource.go b/internal/services/compute/linux_virtual_machine_resource.go index 010bb9b9a1fd..16aa11918bdc 100644 --- a/internal/services/compute/linux_virtual_machine_resource.go +++ b/internal/services/compute/linux_virtual_machine_resource.go @@ -7,6 +7,8 @@ import ( "strings" "time" + "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2021-11-01/compute" "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" @@ -166,6 +168,8 @@ func resourceLinuxVirtualMachine() *pluginsdk.Resource { Default: true, }, + "edge_zone": commonschema.EdgeZoneOptionalForceNew(), + "encryption_at_host_enabled": { Type: pluginsdk.TypeBool, Optional: true, @@ -424,10 +428,11 @@ func resourceLinuxVirtualMachineCreate(d *pluginsdk.ResourceData, meta interface sshKeys := ExpandSSHKeys(sshKeysRaw) params := compute.VirtualMachine{ - Name: utils.String(id.Name), - Location: utils.String(location), - Identity: identity, - Plan: plan, + Name: utils.String(id.Name), + ExtendedLocation: expandEdgeZone(d.Get("edge_zone").(string)), + Location: utils.String(location), + Identity: identity, + Plan: plan, VirtualMachineProperties: &compute.VirtualMachineProperties{ HardwareProfile: &compute.HardwareProfile{ VMSize: compute.VirtualMachineSizeTypes(size), @@ -466,13 +471,9 @@ func resourceLinuxVirtualMachineCreate(d *pluginsdk.ResourceData, meta interface Tags: tags.Expand(t), } - if v, ok := d.GetOk("patch_mode"); ok { - if v == string(compute.LinuxVMGuestPatchModeAutomaticByPlatform) && !provisionVMAgent { - return fmt.Errorf("%q cannot be set to %q when %q is set to %q", "patch_mode", "AutomaticByPlatform", "provision_vm_agent", "false") - } - - params.VirtualMachineProperties.OsProfile.LinuxConfiguration.PatchSettings = &compute.LinuxPatchSettings{ - PatchMode: compute.LinuxVMGuestPatchMode(v.(string)), + if encryptionAtHostEnabled, ok := d.GetOk("encryption_at_host_enabled"); ok { + params.VirtualMachineProperties.SecurityProfile = &compute.SecurityProfile{ + EncryptionAtHost: utils.Bool(encryptionAtHostEnabled.(bool)), } } @@ -480,9 +481,13 @@ func resourceLinuxVirtualMachineCreate(d *pluginsdk.ResourceData, meta interface params.VirtualMachineProperties.LicenseType = utils.String(v.(string)) } - if encryptionAtHostEnabled, ok := d.GetOk("encryption_at_host_enabled"); ok { - params.VirtualMachineProperties.SecurityProfile = &compute.SecurityProfile{ - EncryptionAtHost: utils.Bool(encryptionAtHostEnabled.(bool)), + if v, ok := d.GetOk("patch_mode"); ok { + if v.(string) == string(compute.LinuxVMGuestPatchModeAutomaticByPlatform) && !provisionVMAgent { + return fmt.Errorf("%q cannot be set to %q when %q is set to %q", "patch_mode", "AutomaticByPlatform", "provision_vm_agent", "false") + } + + params.VirtualMachineProperties.OsProfile.LinuxConfiguration.PatchSettings = &compute.LinuxPatchSettings{ + PatchMode: compute.LinuxVMGuestPatchMode(v.(string)), } } @@ -632,9 +637,8 @@ func resourceLinuxVirtualMachineRead(d *pluginsdk.ResourceData, meta interface{} d.Set("name", id.Name) d.Set("resource_group_name", id.ResourceGroup) - if location := resp.Location; location != nil { - d.Set("location", azure.NormalizeLocation(*location)) - } + d.Set("location", location.NormalizeNilable(resp.Location)) + d.Set("edge_zone", flattenEdgeZone(resp.ExtendedLocation)) identity, err := flattenVirtualMachineIdentity(resp.Identity) if err != nil { diff --git a/internal/services/compute/linux_virtual_machine_resource_other_test.go b/internal/services/compute/linux_virtual_machine_resource_other_test.go index 768e433a369d..f9d2f6427f06 100644 --- a/internal/services/compute/linux_virtual_machine_resource_other_test.go +++ b/internal/services/compute/linux_virtual_machine_resource_other_test.go @@ -261,6 +261,21 @@ func TestAccLinuxVirtualMachine_otherCustomData(t *testing.T) { }) } +func TestAccLinuxVirtualMachine_otherEdgeZone(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_linux_virtual_machine", "test") + r := LinuxVirtualMachineResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.otherEdgeZone(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + func TestAccLinuxVirtualMachine_otherUserData(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_linux_virtual_machine", "test") r := LinuxVirtualMachineResource{} @@ -1142,6 +1157,49 @@ resource "azurerm_linux_virtual_machine" "test" { `, r.template(data), data.RandomInteger) } +func (r LinuxVirtualMachineResource) otherEdgeZone(data acceptance.TestData) string { + // @tombuildsstuff: WestUS has an edge zone available - so hard-code to that for now + data.Locations.Primary = "westus" + + return fmt.Sprintf(` +%[1]s + +data "azurerm_extended_locations" "test" { + location = azurerm_resource_group.test.location +} + +resource "azurerm_linux_virtual_machine" "test" { + name = "acctestVM-%[2]d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + size = "Standard_D2s_v3" # intentional for premium/edgezones + admin_username = "adminuser" + network_interface_ids = [ + azurerm_network_interface.test.id, + ] + + edge_zone = data.azurerm_extended_locations.test.extended_locations[0] + + admin_ssh_key { + username = "adminuser" + public_key = local.first_public_key + } + + os_disk { + caching = "ReadWrite" + storage_account_type = "Premium_LRS" + } + + source_image_reference { + publisher = "Canonical" + offer = "UbuntuServer" + sku = "18.04-LTS" + version = "latest" + } +} +`, r.otherBootDiagnosticsTemplate(data), data.RandomInteger) +} + func (r LinuxVirtualMachineResource) otherUserData(data acceptance.TestData, userData string) string { return fmt.Sprintf(` %s diff --git a/internal/services/compute/linux_virtual_machine_scale_set_other_resource_test.go b/internal/services/compute/linux_virtual_machine_scale_set_other_resource_test.go index b6afd8eb3da1..8ecd413c613b 100644 --- a/internal/services/compute/linux_virtual_machine_scale_set_other_resource_test.go +++ b/internal/services/compute/linux_virtual_machine_scale_set_other_resource_test.go @@ -130,6 +130,21 @@ func TestAccLinuxVirtualMachineScaleSet_otherCustomData(t *testing.T) { }) } +func TestAccLinuxVirtualMachineScaleSet_otherEdgeZone(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_linux_virtual_machine_scale_set", "test") + r := LinuxVirtualMachineScaleSetResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.otherEdgeZone(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("admin_password"), + }) +} + func TestAccLinuxVirtualMachineScaleSet_otherUserData(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_linux_virtual_machine_scale_set", "test") r := LinuxVirtualMachineScaleSetResource{} @@ -910,9 +925,16 @@ resource "azurerm_linux_virtual_machine_scale_set" "test" { `, r.template(data), data.RandomInteger, customData) } -func (r LinuxVirtualMachineScaleSetResource) otherUserData(data acceptance.TestData, userData string) string { +func (r LinuxVirtualMachineScaleSetResource) otherEdgeZone(data acceptance.TestData) string { + // @tombuildsstuff: WestUS has an edge zone available - so hard-code to that for now + data.Locations.Primary = "westus" + return fmt.Sprintf(` -%s +%[1]s + +data "azurerm_extended_locations" "test" { + location = azurerm_resource_group.test.location +} resource "azurerm_linux_virtual_machine_scale_set" "test" { name = "acctestvmss-%d" @@ -922,19 +944,19 @@ resource "azurerm_linux_virtual_machine_scale_set" "test" { instances = 1 admin_username = "adminuser" admin_password = "P@ssword1234!" - user_data = base64encode(%q) + edge_zone = data.azurerm_extended_locations.test.extended_locations[0] disable_password_authentication = false source_image_reference { publisher = "Canonical" offer = "UbuntuServer" - sku = "16.04-LTS" + sku = "18.04-LTS" version = "latest" } os_disk { - storage_account_type = "Standard_LRS" + storage_account_type = "Premium_LRS" caching = "ReadWrite" } @@ -949,7 +971,7 @@ resource "azurerm_linux_virtual_machine_scale_set" "test" { } } } -`, r.template(data), data.RandomInteger, userData) +`, r.template(data), data.RandomInteger) } func (r LinuxVirtualMachineScaleSetResource) otherForceDelete(data acceptance.TestData) string { @@ -1542,6 +1564,48 @@ resource "azurerm_linux_virtual_machine_scale_set" "test" { `, r.template(data), data.RandomInteger) } +func (r LinuxVirtualMachineScaleSetResource) otherUserData(data acceptance.TestData, userData string) string { + return fmt.Sprintf(` +%s + +resource "azurerm_linux_virtual_machine_scale_set" "test" { + name = "acctestvmss-%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + sku = "Standard_F2" + instances = 1 + admin_username = "adminuser" + admin_password = "P@ssword1234!" + user_data = base64encode(%q) + + disable_password_authentication = false + + source_image_reference { + publisher = "Canonical" + offer = "UbuntuServer" + sku = "16.04-LTS" + version = "latest" + } + + os_disk { + storage_account_type = "Standard_LRS" + caching = "ReadWrite" + } + + network_interface { + name = "example" + primary = true + + ip_configuration { + name = "internal" + primary = true + subnet_id = azurerm_subnet.test.id + } + } +} +`, r.template(data), data.RandomInteger, userData) +} + func (r LinuxVirtualMachineScaleSetResource) otherVMAgent(data acceptance.TestData, enabled bool) string { return fmt.Sprintf(` %s diff --git a/internal/services/compute/linux_virtual_machine_scale_set_resource.go b/internal/services/compute/linux_virtual_machine_scale_set_resource.go index a711ceabdd1f..668349812817 100644 --- a/internal/services/compute/linux_virtual_machine_scale_set_resource.go +++ b/internal/services/compute/linux_virtual_machine_scale_set_resource.go @@ -130,6 +130,8 @@ func resourceLinuxVirtualMachineScaleSet() *pluginsdk.Resource { Default: false, }, + "edge_zone": commonschema.EdgeZoneOptionalForceNew(), + "encryption_at_host_enabled": { Type: pluginsdk.TypeBool, Optional: true, @@ -534,7 +536,8 @@ func resourceLinuxVirtualMachineScaleSetCreate(d *pluginsdk.ResourceData, meta i automaticRepairsPolicy := ExpandVirtualMachineScaleSetAutomaticRepairsPolicy(automaticRepairsPolicyRaw) props := compute.VirtualMachineScaleSet{ - Location: utils.String(location), + ExtendedLocation: expandEdgeZone(d.Get("edge_zone").(string)), + Location: utils.String(location), Sku: &compute.Sku{ Name: utils.String(d.Get("sku").(string)), Capacity: utils.Int64(int64(d.Get("instances").(int))), @@ -944,6 +947,7 @@ func resourceLinuxVirtualMachineScaleSetRead(d *pluginsdk.ResourceData, meta int d.Set("name", id.Name) d.Set("resource_group_name", id.ResourceGroup) d.Set("location", location.NormalizeNilable(resp.Location)) + d.Set("edge_zone", flattenEdgeZone(resp.ExtendedLocation)) d.Set("zones", zones.Flatten(resp.Zones)) var skuName *string diff --git a/internal/services/compute/managed_disk_resource.go b/internal/services/compute/managed_disk_resource.go index 91b7af6dacb0..2c0ec5856c1c 100644 --- a/internal/services/compute/managed_disk_resource.go +++ b/internal/services/compute/managed_disk_resource.go @@ -84,6 +84,8 @@ func resourceManagedDisk() *pluginsdk.Resource { }, false), }, + "edge_zone": commonschema.EdgeZoneOptionalForceNew(), + "logical_sector_size": { Type: pluginsdk.TypeInt, Optional: true, @@ -464,9 +466,10 @@ func resourceManagedDiskCreate(d *pluginsdk.ResourceData, meta interface{}) erro } createDisk := compute.Disk{ - Name: &name, - Location: &location, - DiskProperties: props, + Name: &name, + ExtendedLocation: expandEdgeZone(d.Get("edge_zone").(string)), + Location: &location, + DiskProperties: props, Sku: &compute.DiskSku{ Name: skuName, }, @@ -823,8 +826,9 @@ func resourceManagedDiskRead(d *pluginsdk.ResourceData, meta interface{}) error d.Set("name", resp.Name) d.Set("resource_group_name", id.ResourceGroup) - d.Set("location", location.NormalizeNilable(resp.Location)) + d.Set("edge_zone", flattenEdgeZone(resp.ExtendedLocation)) + if features.ThreePointOhBeta() { zone := "" if resp.Zones != nil && len(*resp.Zones) > 0 { diff --git a/internal/services/compute/managed_disk_resource_test.go b/internal/services/compute/managed_disk_resource_test.go index e201f5e65ff6..3604f63881e2 100644 --- a/internal/services/compute/managed_disk_resource_test.go +++ b/internal/services/compute/managed_disk_resource_test.go @@ -618,6 +618,21 @@ func TestAccManagedDisk_create_withHyperVGeneration(t *testing.T) { }) } +func TestAccManagedDisk_edgeZone(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_managed_disk", "test") + r := ManagedDiskResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.edgeZone(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + func (ManagedDiskResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { id, err := parse.ManagedDiskID(state.ID) if err != nil { @@ -2275,3 +2290,38 @@ resource "azurerm_managed_disk" "test" { } `, data.RandomInteger, data.Locations.Primary, data.RandomInteger) } + +func (ManagedDiskResource) edgeZone(data acceptance.TestData) string { + // @tombuildsstuff: WestUS has an edge zone available - so hard-code to that for now + data.Locations.Primary = "westus" + + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +data "azurerm_extended_locations" "test" { + location = azurerm_resource_group.test.location +} + +resource "azurerm_managed_disk" "test" { + name = "acctestd-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + storage_account_type = "Premium_LRS" + create_option = "Empty" + disk_size_gb = "1" + edge_zone = data.azurerm_extended_locations.test.extended_locations[0] + + tags = { + environment = "acctest" + cost-center = "ops" + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger) +} diff --git a/internal/services/compute/windows_virtual_machine_resource.go b/internal/services/compute/windows_virtual_machine_resource.go index 1ceac782b9ca..32c183f9adcf 100644 --- a/internal/services/compute/windows_virtual_machine_resource.go +++ b/internal/services/compute/windows_virtual_machine_resource.go @@ -7,6 +7,8 @@ import ( "strings" "time" + "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2021-11-01/compute" "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" @@ -161,6 +163,8 @@ func resourceWindowsVirtualMachine() *pluginsdk.Resource { }, }, + "edge_zone": commonschema.EdgeZoneOptionalForceNew(), + // TODO 4.0: change this from enable_* to *_enabled "enable_automatic_updates": { Type: pluginsdk.TypeBool, @@ -458,10 +462,11 @@ func resourceWindowsVirtualMachineCreate(d *pluginsdk.ResourceData, meta interfa winRmListeners := expandWinRMListener(winRmListenersRaw) params := compute.VirtualMachine{ - Name: utils.String(id.Name), - Location: utils.String(location), - Identity: identity, - Plan: plan, + Name: utils.String(id.Name), + ExtendedLocation: expandEdgeZone(d.Get("edge_zone").(string)), + Location: utils.String(location), + Identity: identity, + Plan: plan, VirtualMachineProperties: &compute.VirtualMachineProperties{ HardwareProfile: &compute.HardwareProfile{ VMSize: compute.VirtualMachineSizeTypes(size), @@ -700,9 +705,8 @@ func resourceWindowsVirtualMachineRead(d *pluginsdk.ResourceData, meta interface d.Set("name", id.Name) d.Set("resource_group_name", id.ResourceGroup) - if location := resp.Location; location != nil { - d.Set("location", azure.NormalizeLocation(*location)) - } + d.Set("location", location.NormalizeNilable(resp.Location)) + d.Set("edge_zone", flattenEdgeZone(resp.ExtendedLocation)) identity, err := flattenVirtualMachineIdentity(resp.Identity) if err != nil { diff --git a/internal/services/compute/windows_virtual_machine_resource_other_test.go b/internal/services/compute/windows_virtual_machine_resource_other_test.go index 0d896866f2c2..eb2254dee98e 100644 --- a/internal/services/compute/windows_virtual_machine_resource_other_test.go +++ b/internal/services/compute/windows_virtual_machine_resource_other_test.go @@ -352,6 +352,21 @@ func TestAccWindowsVirtualMachine_otherCustomData(t *testing.T) { }) } +func TestAccWindowsVirtualMachine_otherEdgeZone(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_windows_virtual_machine", "test") + r := WindowsVirtualMachineResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.otherEdgeZone(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("admin_password"), + }) +} + func TestAccWindowsVirtualMachine_otherUserData(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_windows_virtual_machine", "test") r := WindowsVirtualMachineResource{} @@ -1517,6 +1532,44 @@ resource "azurerm_windows_virtual_machine" "test" { `, r.template(data)) } +func (r WindowsVirtualMachineResource) otherEdgeZone(data acceptance.TestData) string { + // @tombuildsstuff: WestUS has an edge zone available - so hard-code to that for now + data.Locations.Primary = "westus" + + return fmt.Sprintf(` +%[1]s + +data "azurerm_extended_locations" "test" { + location = azurerm_resource_group.test.location +} + +resource "azurerm_windows_virtual_machine" "test" { + name = local.vm_name + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + size = "Standard_F2" + admin_username = "adminuser" + admin_password = "P@$$w0rd1234!" + edge_zone = data.azurerm_extended_locations.test.extended_locations[0] + network_interface_ids = [ + azurerm_network_interface.test.id, + ] + + os_disk { + caching = "ReadWrite" + storage_account_type = "Premium_LRS" + } + + source_image_reference { + publisher = "MicrosoftWindowsServer" + offer = "WindowsServer" + sku = "2016-Datacenter" + version = "latest" + } +} +`, r.template(data)) +} + func (r WindowsVirtualMachineResource) otherUserData(data acceptance.TestData, userData string) string { return fmt.Sprintf(` %s diff --git a/internal/services/compute/windows_virtual_machine_scale_set_other_resource_test.go b/internal/services/compute/windows_virtual_machine_scale_set_other_resource_test.go index 92ec34252b36..b4d841898e8a 100644 --- a/internal/services/compute/windows_virtual_machine_scale_set_other_resource_test.go +++ b/internal/services/compute/windows_virtual_machine_scale_set_other_resource_test.go @@ -157,6 +157,23 @@ func TestAccWindowsVirtualMachineScaleSet_otherCustomData(t *testing.T) { }) } +func TestAccWindowsVirtualMachineScaleSet_otherEdgeZone(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_windows_virtual_machine_scale_set", "test") + r := WindowsVirtualMachineScaleSetResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.otherEdgeZone(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep( + "admin_password", + ), + }) +} + func TestAccWindowsVirtualMachineScaleSet_otherUserData(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_windows_virtual_machine_scale_set", "test") r := WindowsVirtualMachineScaleSetResource{} @@ -1081,6 +1098,53 @@ resource "azurerm_windows_virtual_machine_scale_set" "test" { `, r.template(data), customData) } +func (r WindowsVirtualMachineScaleSetResource) otherEdgeZone(data acceptance.TestData) string { + // @tombuildsstuff: WestUS has an edge zone available - so hard-code to that for now + data.Locations.Primary = "westus" + + return fmt.Sprintf(` +%[1]s + +data "azurerm_extended_locations" "test" { + location = azurerm_resource_group.test.location +} + +resource "azurerm_windows_virtual_machine_scale_set" "test" { + name = local.vm_name + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + sku = "Standard_F2" + instances = 1 + admin_username = "adminuser" + admin_password = "P@ssword1234!" + edge_zone = data.azurerm_extended_locations.test.extended_locations[0] + + source_image_reference { + publisher = "MicrosoftWindowsServer" + offer = "WindowsServer" + sku = "2019-Datacenter" + version = "latest" + } + + os_disk { + storage_account_type = "Premium_LRS" + caching = "ReadWrite" + } + + network_interface { + name = "example" + primary = true + + ip_configuration { + name = "internal" + primary = true + subnet_id = azurerm_subnet.test.id + } + } +} +`, r.template(data)) +} + func (r WindowsVirtualMachineScaleSetResource) otherUserData(data acceptance.TestData, userData string) string { return fmt.Sprintf(` %s diff --git a/internal/services/compute/windows_virtual_machine_scale_set_resource.go b/internal/services/compute/windows_virtual_machine_scale_set_resource.go index 97f058240c86..77daf4034dc6 100644 --- a/internal/services/compute/windows_virtual_machine_scale_set_resource.go +++ b/internal/services/compute/windows_virtual_machine_scale_set_resource.go @@ -128,6 +128,8 @@ func resourceWindowsVirtualMachineScaleSet() *pluginsdk.Resource { Default: false, }, + "edge_zone": commonschema.EdgeZoneOptionalForceNew(), + // TODO 4.0: change this from enable_* to *_enabled "enable_automatic_updates": { Type: pluginsdk.TypeBool, @@ -574,7 +576,8 @@ func resourceWindowsVirtualMachineScaleSetCreate(d *pluginsdk.ResourceData, meta automaticRepairsPolicy := ExpandVirtualMachineScaleSetAutomaticRepairsPolicy(automaticRepairsPolicyRaw) props := compute.VirtualMachineScaleSet{ - Location: utils.String(location), + ExtendedLocation: expandEdgeZone(d.Get("edge_zone").(string)), + Location: utils.String(location), Sku: &compute.Sku{ Name: utils.String(d.Get("sku").(string)), Capacity: utils.Int64(int64(d.Get("instances").(int))), @@ -995,6 +998,7 @@ func resourceWindowsVirtualMachineScaleSetRead(d *pluginsdk.ResourceData, meta i d.Set("name", id.Name) d.Set("resource_group_name", id.ResourceGroup) d.Set("location", location.NormalizeNilable(resp.Location)) + d.Set("edge_zone", flattenEdgeZone(resp.ExtendedLocation)) d.Set("zones", zones.Flatten(resp.Zones)) var skuName *string diff --git a/internal/services/loadbalancer/loadbalancer_resource.go b/internal/services/loadbalancer/loadbalancer_resource.go index dd331d9b696a..f4cce725245f 100644 --- a/internal/services/loadbalancer/loadbalancer_resource.go +++ b/internal/services/loadbalancer/loadbalancer_resource.go @@ -7,6 +7,9 @@ import ( "strings" "time" + "github.com/hashicorp/go-azure-helpers/resourcemanager/edgezones" + "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" "github.com/hashicorp/go-azure-helpers/resourcemanager/zones" "github.com/hashicorp/terraform-provider-azurerm/internal/services/loadbalancer/validate" @@ -119,6 +122,7 @@ func resourceArmLoadBalancerCreateUpdate(d *pluginsdk.ResourceData, meta interfa loadBalancer := network.LoadBalancer{ Name: utils.String(id.Name), + ExtendedLocation: expandEdgeZone(d.Get("edge_zone").(string)), Location: utils.String(location), Tags: expandedTags, Sku: &sku, @@ -160,9 +164,8 @@ func resourceArmLoadBalancerRead(d *pluginsdk.ResourceData, meta interface{}) er d.Set("name", id.Name) d.Set("resource_group_name", id.ResourceGroup) - if location := resp.Location; location != nil { - d.Set("location", azure.NormalizeLocation(*location)) - } + d.Set("location", location.NormalizeNilable(resp.Location)) + d.Set("edge_zone", flattenEdgeZone(resp.ExtendedLocation)) if sku := resp.Sku; sku != nil { d.Set("sku", string(sku.Name)) @@ -446,6 +449,9 @@ func resourceArmLoadBalancerSchema() map[string]*pluginsdk.Schema { "location": azure.SchemaLocation(), "resource_group_name": azure.SchemaResourceGroupName(), + + "edge_zone": commonschema.EdgeZoneOptionalForceNew(), + "sku": { Type: pluginsdk.TypeString, Optional: true, @@ -628,3 +634,22 @@ func resourceArmLoadBalancerSchema() map[string]*pluginsdk.Schema { return out } + +func expandEdgeZone(input string) *network.ExtendedLocation { + normalized := edgezones.Normalize(input) + if normalized == "" { + return nil + } + + return &network.ExtendedLocation{ + Name: utils.String(normalized), + Type: network.ExtendedLocationTypesEdgeZone, + } +} + +func flattenEdgeZone(input *network.ExtendedLocation) string { + if input == nil || input.Type != network.ExtendedLocationTypesEdgeZone || input.Name == nil { + return "" + } + return edgezones.NormalizeNilable(input.Name) +} diff --git a/internal/services/loadbalancer/loadbalancer_resource_test.go b/internal/services/loadbalancer/loadbalancer_resource_test.go index c8896242e170..e3644dc99142 100644 --- a/internal/services/loadbalancer/loadbalancer_resource_test.go +++ b/internal/services/loadbalancer/loadbalancer_resource_test.go @@ -311,6 +311,21 @@ func TestAccAzureRMLoadBalancer_PointToGatewayLB(t *testing.T) { }) } +func TestAccAzureRMLoadBalancer_edgeZone(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_lb", "test") + r := LoadBalancer{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.edgeZone(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + func (r LoadBalancer) Exists(ctx context.Context, client *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { loadBalancerName := state.Attributes["name"] resourceGroup := state.Attributes["resource_group_name"] @@ -939,3 +954,35 @@ resource "azurerm_lb" "consumer" { } `, data.RandomInteger, data.Locations.Primary) } + +func (r LoadBalancer) edgeZone(data acceptance.TestData) string { + // @tombuildsstuff: WestUS has an edge zone available - so hard-code to that for now + data.Locations.Primary = "westus" + + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-lb-%d" + location = "%s" +} + +data "azurerm_extended_locations" "test" { + location = azurerm_resource_group.test.location +} + +resource "azurerm_lb" "test" { + name = "acctest-loadbalancer-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + edge_zone = data.azurerm_extended_locations.test.extended_locations[0] + + tags = { + Environment = "production" + Purpose = "AcceptanceTests" + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger) +} diff --git a/internal/services/network/edge_zone.go b/internal/services/network/edge_zone.go new file mode 100644 index 000000000000..f60588a15501 --- /dev/null +++ b/internal/services/network/edge_zone.go @@ -0,0 +1,26 @@ +package network + +import ( + "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2021-05-01/network" + "github.com/hashicorp/go-azure-helpers/resourcemanager/edgezones" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +func expandEdgeZone(input string) *network.ExtendedLocation { + normalized := edgezones.Normalize(input) + if normalized == "" { + return nil + } + + return &network.ExtendedLocation{ + Name: utils.String(normalized), + Type: network.ExtendedLocationTypesEdgeZone, + } +} + +func flattenEdgeZone(input *network.ExtendedLocation) string { + if input == nil || input.Type != network.ExtendedLocationTypesEdgeZone || input.Name == nil { + return "" + } + return edgezones.NormalizeNilable(input.Name) +} diff --git a/internal/services/network/network_interface_resource.go b/internal/services/network/network_interface_resource.go index 6a4e5b158128..cf0dae8926be 100644 --- a/internal/services/network/network_interface_resource.go +++ b/internal/services/network/network_interface_resource.go @@ -5,6 +5,9 @@ import ( "log" "time" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2021-05-01/network" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" @@ -119,6 +122,7 @@ func resourceNetworkInterface() *pluginsdk.Resource { }, }, + // Optional "dns_servers": { Type: pluginsdk.TypeList, Optional: true, @@ -129,6 +133,8 @@ func resourceNetworkInterface() *pluginsdk.Resource { }, }, + "edge_zone": commonschema.EdgeZoneOptionalForceNew(), + // TODO 4.0: change this from enable_* to *_enabled "enable_accelerated_networking": { Type: pluginsdk.TypeBool, @@ -262,6 +268,7 @@ func resourceNetworkInterfaceCreate(d *pluginsdk.ResourceData, meta interface{}) iface := network.Interface{ Name: utils.String(id.Name), + ExtendedLocation: expandEdgeZone(d.Get("edge_zone").(string)), Location: utils.String(location), InterfacePropertiesFormat: &properties, Tags: tags.Expand(t), @@ -308,8 +315,9 @@ func resourceNetworkInterfaceUpdate(d *pluginsdk.ResourceData, meta interface{}) location := azure.NormalizeLocation(d.Get("location").(string)) update := network.Interface{ - Name: utils.String(id.Name), - Location: utils.String(location), + Name: utils.String(id.Name), + ExtendedLocation: expandEdgeZone(d.Get("edge_zone").(string)), + Location: utils.String(location), InterfacePropertiesFormat: &network.InterfacePropertiesFormat{ EnableAcceleratedNetworking: utils.Bool(d.Get("enable_accelerated_networking").(bool)), DNSSettings: &network.InterfaceDNSSettings{}, @@ -401,9 +409,8 @@ func resourceNetworkInterfaceRead(d *pluginsdk.ResourceData, meta interface{}) e d.Set("name", id.Name) d.Set("resource_group_name", id.ResourceGroup) - if location := resp.Location; location != nil { - d.Set("location", azure.NormalizeLocation(*location)) - } + d.Set("location", location.NormalizeNilable(resp.Location)) + d.Set("edge_zone", flattenEdgeZone(resp.ExtendedLocation)) if props := resp.InterfacePropertiesFormat; props != nil { primaryPrivateIPAddress := "" diff --git a/internal/services/network/network_interface_resource_test.go b/internal/services/network/network_interface_resource_test.go index 665cb5d6aec7..0c12b31112dc 100644 --- a/internal/services/network/network_interface_resource_test.go +++ b/internal/services/network/network_interface_resource_test.go @@ -61,6 +61,20 @@ func TestAccNetworkInterface_dnsServers(t *testing.T) { }) } +func TestAccNetworkInterface_edgeZone(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_network_interface", "test") + r := NetworkInterfaceResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.edgeZone(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + func TestAccNetworkInterface_enableAcceleratedNetworking(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_network_interface", "test") r := NetworkInterfaceResource{} @@ -478,6 +492,32 @@ resource "azurerm_network_interface" "test" { `, r.template(data), data.RandomInteger) } +func (r NetworkInterfaceResource) edgeZone(data acceptance.TestData) string { + // @tombuildsstuff: WestUS has an edge zone available - so hard-code to that for now + data.Locations.Primary = "westus" + + return fmt.Sprintf(` +%[1]s + +data "azurerm_extended_locations" "test" { + location = azurerm_resource_group.test.location +} + +resource "azurerm_network_interface" "test" { + name = "acctestni-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + edge_zone = data.azurerm_extended_locations.test.extended_locations[0] + + ip_configuration { + name = "primary" + subnet_id = azurerm_subnet.test.id + private_ip_address_allocation = "Dynamic" + } +} +`, r.template(data), data.RandomInteger) +} + func (r NetworkInterfaceResource) enableAcceleratedNetworking(data acceptance.TestData, enabled bool) string { return fmt.Sprintf(` %s diff --git a/internal/services/network/public_ip_resource.go b/internal/services/network/public_ip_resource.go index 96de3356242b..0f36daa958ea 100644 --- a/internal/services/network/public_ip_resource.go +++ b/internal/services/network/public_ip_resource.go @@ -66,6 +66,9 @@ func resourcePublicIp() *pluginsdk.Resource { }, false), }, + // Optional + "edge_zone": commonschema.EdgeZoneOptionalForceNew(), + "ip_version": { Type: pluginsdk.TypeString, Optional: true, @@ -228,8 +231,9 @@ func resourcePublicIpCreateUpdate(d *pluginsdk.ResourceData, meta interface{}) e } publicIp := network.PublicIPAddress{ - Name: utils.String(id.Name), - Location: &location, + Name: utils.String(id.Name), + ExtendedLocation: expandEdgeZone(d.Get("edge_zone").(string)), + Location: &location, Sku: &network.PublicIPAddressSku{ Name: network.PublicIPAddressSkuName(sku), Tier: network.PublicIPAddressSkuTier(sku_tier), @@ -365,8 +369,8 @@ func resourcePublicIpRead(d *pluginsdk.ResourceData, meta interface{}) error { d.Set("name", id.Name) d.Set("resource_group_name", id.ResourceGroup) - d.Set("location", location.NormalizeNilable(resp.Location)) + d.Set("edge_zone", flattenEdgeZone(resp.ExtendedLocation)) if features.ThreePointOhBeta() { d.Set("zones", zones.Flatten(resp.Zones)) diff --git a/internal/services/network/public_ip_resource_test.go b/internal/services/network/public_ip_resource_test.go index 998730544a5c..cc34763ef2ac 100644 --- a/internal/services/network/public_ip_resource_test.go +++ b/internal/services/network/public_ip_resource_test.go @@ -77,6 +77,7 @@ func TestAccPublicIp_zonesSingle(t *testing.T) { data.ImportStep(), }) } + func TestAccPublicIp_zonesMultiple(t *testing.T) { if !features.ThreePointOhBeta() { t.Skip("this test requires 3.0 mode") @@ -521,6 +522,21 @@ func TestAccPublicIpStatic_regionalTier(t *testing.T) { }) } +func TestAccPublicIpStatic_edgeZone(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_public_ip", "test") + r := PublicIPResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.edgeZone(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + func (t PublicIPResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { id, err := parse.PublicIpAddressID(state.ID) if err != nil { @@ -1053,3 +1069,32 @@ resource "azurerm_public_ip" "test" { } `, data.RandomInteger, data.Locations.Primary) } + +func (PublicIPResource) edgeZone(data acceptance.TestData) string { + // @tombuildsstuff: WestUS has an edge zone available - so hard-code to that for now + data.Locations.Primary = "westus" + + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +data "azurerm_extended_locations" "test" { + location = azurerm_resource_group.test.location +} + +resource "azurerm_public_ip" "test" { + name = "acctestpublicip-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + allocation_method = "Static" + sku = "Standard" + edge_zone = data.azurerm_extended_locations.test.extended_locations[0] +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger) +} diff --git a/internal/services/network/virtual_network_gateway_resource.go b/internal/services/network/virtual_network_gateway_resource.go index 0aad9d44fe37..f3a6364410f8 100644 --- a/internal/services/network/virtual_network_gateway_resource.go +++ b/internal/services/network/virtual_network_gateway_resource.go @@ -6,6 +6,9 @@ import ( "log" "time" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2021-05-01/network" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" @@ -79,6 +82,8 @@ func resourceVirtualNetworkGatewaySchema() map[string]*pluginsdk.Schema { }, !features.ThreePointOhBeta()), }, + "edge_zone": commonschema.EdgeZoneOptionalForceNew(), + // TODO 4.0: change this from enable_* to *_enabled "enable_bgp": { Type: pluginsdk.TypeBool, @@ -458,6 +463,7 @@ func resourceVirtualNetworkGatewayCreateUpdate(d *pluginsdk.ResourceData, meta i gateway := network.VirtualNetworkGateway{ Name: &id.Name, + ExtendedLocation: expandEdgeZone(d.Get("edge_zone").(string)), Location: &location, Tags: tags.Expand(t), VirtualNetworkGatewayPropertiesFormat: properties, @@ -498,9 +504,8 @@ func resourceVirtualNetworkGatewayRead(d *pluginsdk.ResourceData, meta interface d.Set("name", id.Name) d.Set("resource_group_name", id.ResourceGroup) - if location := resp.Location; location != nil { - d.Set("location", azure.NormalizeLocation(*location)) - } + d.Set("location", location.NormalizeNilable(resp.Location)) + d.Set("edge_zone", flattenEdgeZone(resp.ExtendedLocation)) if gw := resp.VirtualNetworkGatewayPropertiesFormat; gw != nil { d.Set("type", string(gw.GatewayType)) diff --git a/internal/services/network/virtual_network_gateway_resource_test.go b/internal/services/network/virtual_network_gateway_resource_test.go index 4b700f304b2b..8f69c6affae0 100644 --- a/internal/services/network/virtual_network_gateway_resource_test.go +++ b/internal/services/network/virtual_network_gateway_resource_test.go @@ -357,6 +357,21 @@ func TestAccVirtualNetworkGateway_customRoute(t *testing.T) { }) } +func TestAccVirtualNetworkGateway_edgeZone(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_virtual_network_gateway", "test") + r := VirtualNetworkGatewayResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.edgeZone(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + func (t VirtualNetworkGatewayResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { gatewayName := state.Attributes["name"] resourceGroup := state.Attributes["resource_group_name"] @@ -1539,3 +1554,61 @@ resource "azurerm_virtual_network_gateway" "test" { } `, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.Client().TenantID, data.Client().TenantID) } + +func (VirtualNetworkGatewayResource) edgeZone(data acceptance.TestData) string { + // @tombuildsstuff: WestUS has an edge zone available - so hard-code to that for now + data.Locations.Primary = "westus" + + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_virtual_network" "test" { + name = "acctestvn-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + address_space = ["10.0.0.0/16"] +} + +resource "azurerm_subnet" "test" { + name = "GatewaySubnet" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefix = "10.0.1.0/24" +} + +resource "azurerm_public_ip" "test" { + name = "acctestpip-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + allocation_method = "Dynamic" +} + +data "azurerm_extended_locations" "test" { + location = azurerm_resource_group.test.location +} + +resource "azurerm_virtual_network_gateway" "test" { + name = "acctestvng-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + edge_zone = data.azurerm_extended_locations.test.extended_locations[0] + + type = "Vpn" + vpn_type = "RouteBased" + sku = "Basic" + + ip_configuration { + public_ip_address_id = azurerm_public_ip.test.id + private_ip_address_allocation = "Dynamic" + subnet_id = azurerm_subnet.test.id + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger) +} diff --git a/internal/services/network/virtual_network_resource.go b/internal/services/network/virtual_network_resource.go index 4bf12206407c..0d6363d6042d 100644 --- a/internal/services/network/virtual_network_resource.go +++ b/internal/services/network/virtual_network_resource.go @@ -8,6 +8,9 @@ import ( "net/http" "time" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2021-05-01/network" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" @@ -70,6 +73,7 @@ func resourceVirtualNetworkSchema() map[string]*pluginsdk.Schema { }, }, + // Optional "bgp_community": { Type: pluginsdk.TypeString, Optional: true, @@ -106,6 +110,8 @@ func resourceVirtualNetworkSchema() map[string]*pluginsdk.Schema { }, }, + "edge_zone": commonschema.EdgeZoneOptionalForceNew(), + "flow_timeout_in_minutes": { Type: pluginsdk.TypeInt, Optional: true, @@ -195,6 +201,7 @@ func resourceVirtualNetworkCreateUpdate(d *pluginsdk.ResourceData, meta interfac vnet := network.VirtualNetwork{ Name: utils.String(id.Name), + ExtendedLocation: expandEdgeZone(d.Get("edge_zone").(string)), Location: utils.String(location), VirtualNetworkPropertiesFormat: vnetProperties, Tags: tags.Expand(t), @@ -269,9 +276,8 @@ func resourceVirtualNetworkRead(d *pluginsdk.ResourceData, meta interface{}) err d.Set("name", id.Name) d.Set("resource_group_name", id.ResourceGroup) - if location := resp.Location; location != nil { - d.Set("location", azure.NormalizeLocation(*location)) - } + d.Set("location", location.NormalizeNilable(resp.Location)) + d.Set("edge_zone", flattenEdgeZone(resp.ExtendedLocation)) if props := resp.VirtualNetworkPropertiesFormat; props != nil { d.Set("guid", props.ResourceGUID) diff --git a/internal/services/network/virtual_network_resource_test.go b/internal/services/network/virtual_network_resource_test.go index 14ab9ccd9cd4..96895c41de73 100644 --- a/internal/services/network/virtual_network_resource_test.go +++ b/internal/services/network/virtual_network_resource_test.go @@ -243,6 +243,36 @@ func TestAccVirtualNetwork_bgpCommunity(t *testing.T) { }) } +func TestAccVirtualNetwork_edgeZone(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_virtual_network", "test") + r := VirtualNetworkResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.edgeZone(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestVirtualNetworkResource_tagCount(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_virtual_network", "test") + r := VirtualNetworkResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.tagCount(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + func (t VirtualNetworkResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { id, err := parse.VirtualNetworkID(state.ID) if err != nil { @@ -302,20 +332,7 @@ resource "azurerm_virtual_network" "test" { } `, data.RandomInteger, data.Locations.Primary, data.RandomInteger) } -func TestVirtualNetworkResource_tagCount(t *testing.T) { - data := acceptance.BuildTestData(t, "azurerm_virtual_network", "test") - r := VirtualNetworkResource{} - data.ResourceTest(t, r, []acceptance.TestStep{ - { - Config: r.tagCount(data), - Check: acceptance.ComposeTestCheckFunc( - check.That(data.ResourceName).ExistsInAzure(r), - ), - }, - data.ImportStep(), - }) -} func (r VirtualNetworkResource) tagCount(data acceptance.TestData) string { tags := "" for i := 0; i < 50; i++ { @@ -564,3 +581,31 @@ resource "azurerm_virtual_network" "test" { } `, data.RandomInteger, data.Locations.Primary, data.RandomInteger, flowTimeout) } + +func (VirtualNetworkResource) edgeZone(data acceptance.TestData) string { + // @tombuildsstuff: WestUS has an edge zone available - so hard-code to that for now + data.Locations.Primary = "westus" + + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +data "azurerm_extended_locations" "test" { + location = azurerm_resource_group.test.location +} + +resource "azurerm_virtual_network" "test" { + name = "acctestvirtnet%d" + address_space = ["10.0.0.0/16"] + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + edge_zone = data.azurerm_extended_locations.test.extended_locations[0] +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger) +} diff --git a/internal/services/storage/storage_account_resource.go b/internal/services/storage/storage_account_resource.go index 03016b7d784c..d58700499433 100644 --- a/internal/services/storage/storage_account_resource.go +++ b/internal/services/storage/storage_account_resource.go @@ -8,6 +8,9 @@ import ( "strings" "time" + "github.com/hashicorp/go-azure-helpers/resourcemanager/edgezones" + "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + "github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2021-04-01/storage" azautorest "github.com/Azure/go-autorest/autorest" autorestAzure "github.com/Azure/go-autorest/autorest/azure" @@ -259,6 +262,8 @@ func resourceStorageAccount() *pluginsdk.Resource { }, }, + "edge_zone": commonschema.EdgeZoneOptionalForceNew(), + // TODO 4.0: change this from enable_* to *_enabled "enable_https_traffic_only": { Type: pluginsdk.TypeBool, @@ -1031,7 +1036,8 @@ func resourceStorageAccountCreate(d *pluginsdk.ResourceData, meta interface{}) e storageType := fmt.Sprintf("%s_%s", accountTier, replicationType) parameters := storage.AccountCreateParameters{ - Location: &location, + ExtendedLocation: expandEdgeZone(d.Get("edge_zone").(string)), + Location: &location, Sku: &storage.Sku{ Name: storage.SkuName(storageType), }, @@ -1750,9 +1756,8 @@ func resourceStorageAccountRead(d *pluginsdk.ResourceData, meta interface{}) err d.Set("name", id.Name) d.Set("resource_group_name", id.ResourceGroup) - if location := resp.Location; location != nil { - d.Set("location", azure.NormalizeLocation(*location)) - } + d.Set("location", location.NormalizeNilable(resp.Location)) + d.Set("edge_zone", flattenEdgeZone(resp.ExtendedLocation)) d.Set("account_kind", resp.Kind) if sku := resp.Sku; sku != nil { @@ -3302,3 +3307,22 @@ func getDefaultAllowBlobPublicAccessName() string { } return "allow_blob_public_access" } + +func expandEdgeZone(input string) *storage.ExtendedLocation { + normalized := edgezones.Normalize(input) + if normalized == "" { + return nil + } + + return &storage.ExtendedLocation{ + Name: utils.String(normalized), + Type: storage.ExtendedLocationTypesEdgeZone, + } +} + +func flattenEdgeZone(input *storage.ExtendedLocation) string { + if input == nil || input.Type != storage.ExtendedLocationTypesEdgeZone || input.Name == nil { + return "" + } + return edgezones.NormalizeNilable(input.Name) +} diff --git a/internal/services/storage/storage_account_resource_test.go b/internal/services/storage/storage_account_resource_test.go index 5302c62422e3..651640140537 100644 --- a/internal/services/storage/storage_account_resource_test.go +++ b/internal/services/storage/storage_account_resource_test.go @@ -1175,6 +1175,21 @@ func TestAccStorageAccount_customerManagedKeyRemoteKeyVault(t *testing.T) { }) } +func TestAccStorageAccount_edgeZone(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_storage_account", "test") + r := StorageAccountResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.edgeZone(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + func (r StorageAccountResource) Exists(ctx context.Context, client *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { id, err := parse.StorageAccountID(state.ID) if err != nil { @@ -3738,3 +3753,32 @@ resource "azurerm_storage_account" "test" { } `, clientData.SubscriptionIDAlt, clientData.TenantID, data.RandomInteger, data.Locations.Primary, data.RandomString, data.RandomString, clientData.TenantID, data.RandomInteger, data.Locations.Primary, data.RandomString) } + +func (r StorageAccountResource) edgeZone(data acceptance.TestData) string { + // @tombuildsstuff: WestUS has an edge zone available - so hard-code to that for now + data.Locations.Primary = "westus" + + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-storage-%d" + location = "%s" +} + +resource "azurerm_storage_account" "test" { + name = "unlikely23exst2acct%s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + account_tier = "Premium" + account_replication_type = "LRS" + edge_zone = data.azurerm_extended_locations.test.extended_locations[0] + + tags = { + environment = "production" + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomString) +} diff --git a/website/docs/r/lb.html.markdown b/website/docs/r/lb.html.markdown index 8306820921da..c15295c45139 100644 --- a/website/docs/r/lb.html.markdown +++ b/website/docs/r/lb.html.markdown @@ -42,14 +42,23 @@ resource "azurerm_lb" "example" { The following arguments are supported: * `name` - (Required) Specifies the name of the Load Balancer. + * `resource_group_name` - (Required) The name of the Resource Group in which to create the Load Balancer. + * `location` - (Required) Specifies the supported Azure Region where the Load Balancer should be created. + +--- + +* `edge_zone` - (Optional) Specifies the Edge Zone within the Azure Region where this Load Balancer should exist. Changing this forces a new Load Balancer to be created. + * `frontend_ip_configuration` - (Optional) One or multiple `frontend_ip_configuration` blocks as documented below. + * `sku` - (Optional) The SKU of the Azure Load Balancer. Accepted values are `Basic`, `Standard` and `Gateway`. Defaults to `Basic`. -> **NOTE:** The `Microsoft.Network/AllowGatewayLoadBalancer` feature is required to be registered in order to use the `Gateway` SKU. The feature can only be registered by the Azure service team, please submit an [Azure support ticket](https://azure.microsoft.com/en-us/support/create-ticket/) for that. * `sku_tier` - (Optional) `sku_tier` - (Optional) The Sku Tier of this Load Balancer. Possible values are `Global` and `Regional`. Defaults to `Regional`. Changing this forces a new resource to be created. +* * `tags` - (Optional) A mapping of tags to assign to the resource. `frontend_ip_configuration` supports the following: diff --git a/website/docs/r/linux_virtual_machine.html.markdown b/website/docs/r/linux_virtual_machine.html.markdown index 08bfa60e9387..9dff55dbe243 100644 --- a/website/docs/r/linux_virtual_machine.html.markdown +++ b/website/docs/r/linux_virtual_machine.html.markdown @@ -27,10 +27,6 @@ Manages a Linux Virtual Machine. This example provisions a basic Linux Virtual Machine on an internal network. Additional examples of how to use the `azurerm_linux_virtual_machine` resource can be found [in the ./examples/virtual-machines/linux directory within the Github Repository](https://github.com/hashicorp/terraform-provider-azurerm/tree/main/examples/virtual-machines/linux). ```hcl -provider "azurerm" { - features {} -} - resource "azurerm_resource_group" "example" { name = "example-resources" location = "West Europe" @@ -144,6 +140,8 @@ The following arguments are supported: -> **NOTE:** When an `admin_password` is specified `disable_password_authentication` must be set to `false`. +* `edge_zone` - (Optional) Specifies the Edge Zone within the Azure Region where this Linux Virtual Machine should exist. Changing this forces a new Linux Virtual Machine to be created. + * `encryption_at_host_enabled` - (Optional) Should all of the disks (including the temp disk) attached to this Virtual Machine be encrypted by enabling Encryption at Host? * `eviction_policy` - (Optional) Specifies what should happen when the Virtual Machine is evicted for price reasons when using a Spot instance. At this time the only supported value is `Deallocate`. Changing this forces a new resource to be created. diff --git a/website/docs/r/linux_virtual_machine_scale_set.html.markdown b/website/docs/r/linux_virtual_machine_scale_set.html.markdown index dcc9cc8b52c3..2e7b3112170f 100644 --- a/website/docs/r/linux_virtual_machine_scale_set.html.markdown +++ b/website/docs/r/linux_virtual_machine_scale_set.html.markdown @@ -144,6 +144,8 @@ The following arguments are supported: * `do_not_run_extensions_on_overprovisioned_machines` - (Optional) Should Virtual Machine Extensions be run on Overprovisioned Virtual Machines in the Scale Set? Defaults to `false`. +* `edge_zone` - (Optional) Specifies the Edge Zone within the Azure Region where this Linux Virtual Machine Scale Set should exist. Changing this forces a new Linux Virtual Machine Scale Set to be created. + * `encryption_at_host_enabled` - (Optional) Should all of the disks (including the temp disk) attached to this Virtual Machine be encrypted by enabling Encryption at Host? * `extension` - (Optional) One or more `extension` blocks as defined below diff --git a/website/docs/r/managed_disk.html.markdown b/website/docs/r/managed_disk.html.markdown index 719ff156fb5d..0f819e9308ac 100644 --- a/website/docs/r/managed_disk.html.markdown +++ b/website/docs/r/managed_disk.html.markdown @@ -109,6 +109,8 @@ The following arguments are supported: ~> **NOTE:** Changing this value is disruptive if the disk is attached to a Virtual Machine. The VM will be shut down and de-allocated as required by Azure to action the change. Terraform will attempt to start the machine again after the update if it was in a `running` state when the apply was started. +* `edge_zone` - (Optional) Specifies the Edge Zone within the Azure Region where this Managed Disk should exist. Changing this forces a new Managed Disk to be created. + * `encryption_settings` - (Optional) A `encryption_settings` block as defined below. * `hyper_v_generation` - (Optional) The HyperV Generation of the Disk when the source of an `Import` or `Copy` operation targets a source that contains an operating system. Possible values are `V1` and `V2`. Changing this forces a new resource to be created. diff --git a/website/docs/r/network_interface.html.markdown b/website/docs/r/network_interface.html.markdown index 193cf316dc41..4ea8d3ddfeba 100644 --- a/website/docs/r/network_interface.html.markdown +++ b/website/docs/r/network_interface.html.markdown @@ -64,6 +64,8 @@ The following arguments are supported: -> **Note:** Configuring DNS Servers on the Network Interface will override the DNS Servers defined on the Virtual Network. +* `edge_zone` - (Optional) Specifies the Edge Zone within the Azure Region where this Network Interface should exist. Changing this forces a new Network Interface to be created. + * `enable_ip_forwarding` - (Optional) Should IP Forwarding be enabled? Defaults to `false`. * `enable_accelerated_networking` - (Optional) Should Accelerated Networking be enabled? Defaults to `false`. diff --git a/website/docs/r/public_ip.html.markdown b/website/docs/r/public_ip.html.markdown index 796fc1b0693e..a8d59360311f 100644 --- a/website/docs/r/public_ip.html.markdown +++ b/website/docs/r/public_ip.html.markdown @@ -34,45 +34,47 @@ resource "azurerm_public_ip" "example" { The following arguments are supported: -* `name` - (Required) Specifies the name of the Public IP resource . Changing this forces a - new resource to be created. +* `name` - (Required) Specifies the name of the Public IP. Changing this forces a new Public IP to be created. -* `resource_group_name` - (Required) The name of the resource group in which to - create the public ip. +* `resource_group_name` - (Required) The name of the Resource Group where this Public IP should exist. Changing this forces a new Public IP to be created. -* `location` - (Required) Specifies the supported Azure location where the resource exists. Changing this forces a new resource to be created. +* `location` - (Required) Specifies the supported Azure location where the Public IP should exist. Changing this forces a new resource to be created. -* `sku` - (Optional) The SKU of the Public IP. Accepted values are `Basic` and `Standard`. Defaults to `Basic`. +* `allocation_method` - (Required) Defines the allocation method for this IP address. Possible values are `Static` or `Dynamic`. --> **Note** Public IP Standard SKUs require `allocation_method` to be set to `Static`. +~> **Note** `Dynamic` Public IP Addresses aren't allocated until they're assigned to a resource (such as a Virtual Machine or a Load Balancer) by design within Azure - [more information is available below](#ip_address). -* `sku_tier` - (Optional) The SKU Tier that should be used for the Public IP. Possible values are `Regional` and `Global`. Defaults to `Regional`. +--- --> **Note** When `sku_tier` is set to `Global`, `sku` must be set to `Standard`. +* `availability_zone` - (Optional) The availability zone to allocate the Public IP in. Possible values are `Zone-Redundant`, `1`, `2`, `3`, and `No-Zone`. Defaults to `Zone-Redundant`. -* `allocation_method` - (Required) Defines the allocation method for this IP address. Possible values are `Static` or `Dynamic`. +-> **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. -~> **Note** `Dynamic` Public IP Addresses aren't allocated until they're assigned to a resource (such as a Virtual Machine or a Load Balancer) by design within Azure - [more information is available below](#ip_address). +* `domain_name_label` - (Optional) Label for the Domain Name. Will be used to make up the FQDN. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system. -* `availability_zone` - (Optional) The availability zone to allocate the Public IP in. Possible values are `Zone-Redundant`, `1`, `2`, `3`, and `No-Zone`. Defaults to `Zone-Redundant`. +* `edge_zone` - (Optional) Specifies the Edge Zone within the Azure Region where this Public IP should exist. Changing this forces a new Public IP to be created. --> **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. +* `idle_timeout_in_minutes` - (Optional) Specifies the timeout for the TCP idle connection. The value can be set between 4 and 30 minutes. + +* `ip_tags` - (Optional) A mapping of IP tags to assign to the public IP. + +-> **Note** IP Tag `RoutingPreference` requires multiple `zones` and `Standard` SKU to be set. * `ip_version` - (Optional) The IP Version to use, IPv6 or IPv4. -> **Note** Only `static` IP address allocation is supported for IPv6. -* `idle_timeout_in_minutes` - (Optional) Specifies the timeout for the TCP idle connection. The value can be set between 4 and 30 minutes. - -* `domain_name_label` - (Optional) Label for the Domain Name. Will be used to make up the FQDN. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system. +* `public_ip_prefix_id` - (Optional) If specified then public IP address allocated will be provided from the public IP prefix resource. * `reverse_fqdn` - (Optional) A fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN. -* `public_ip_prefix_id` - (Optional) If specified then public IP address allocated will be provided from the public IP prefix resource. +* `sku` - (Optional) The SKU of the Public IP. Accepted values are `Basic` and `Standard`. Defaults to `Basic`. -* `ip_tags` - (Optional) A mapping of IP tags to assign to the public IP. +-> **Note** Public IP Standard SKUs require `allocation_method` to be set to `Static`. --> **Note** IP Tag `RoutingPreference` requires multiple `zones` and `Standard` SKU to be set. +* `sku_tier` - (Optional) The SKU Tier that should be used for the Public IP. Possible values are `Regional` and `Global`. Defaults to `Regional`. + +-> **Note** When `sku_tier` is set to `Global`, `sku` must be set to `Standard`. * `tags` - (Optional) A mapping of tags to assign to the resource. @@ -80,7 +82,8 @@ The following arguments are supported: The following attributes are exported: -* `id` - The Public IP ID. +* `id` - The ID of this Public IP. + * `ip_address` - The IP address value that was allocated. ~> **Note** `Dynamic` Public IP Addresses aren't allocated until they're attached to a device (e.g. a Virtual Machine/Load Balancer). Instead you can obtain the IP Address once the Public IP has been assigned via the [`azurerm_public_ip` Data Source](../d/public_ip.html). diff --git a/website/docs/r/storage_account.html.markdown b/website/docs/r/storage_account.html.markdown index 28b9f017cd14..977b7a38f336 100644 --- a/website/docs/r/storage_account.html.markdown +++ b/website/docs/r/storage_account.html.markdown @@ -96,6 +96,8 @@ The following arguments are supported: * `access_tier` - (Optional) Defines the access tier for `BlobStorage`, `FileStorage` and `StorageV2` accounts. Valid options are `Hot` and `Cool`, defaults to `Hot`. +* `edge_zone` - (Optional) Specifies the Edge Zone within the Azure Region where this Storage Account should exist. Changing this forces a new Storage Account to be created. + * `enable_https_traffic_only` - (Optional) Boolean flag which forces HTTPS if enabled, see [here](https://docs.microsoft.com/en-us/azure/storage/storage-require-secure-transfer/) for more information. Defaults to `true`. diff --git a/website/docs/r/virtual_network.html.markdown b/website/docs/r/virtual_network.html.markdown index 917ff9cd7158..a831f8a34540 100644 --- a/website/docs/r/virtual_network.html.markdown +++ b/website/docs/r/virtual_network.html.markdown @@ -67,6 +67,8 @@ The following arguments are supported: * `location` - (Required) The location/region where the virtual network is created. Changing this forces a new resource to be created. +--- + * `bgp_community` - (Optional) The BGP community attribute in format `:`. -> **NOTE** The `as-number` segment is the Microsoft ASN, which is always `12076` for now. @@ -77,6 +79,8 @@ The following arguments are supported: -> **NOTE** Since `dns_servers` can be configured both inline and via the separate `azurerm_virtual_network_dns_servers` resource, we have to explicitly set it to empty slice (`[]`) to remove it. +* `edge_zone` - (Optional) Specifies the Edge Zone within the Azure Region where this Virtual Network should exist. Changing this forces a new Virtual Network to be created. + * `flow_timeout_in_minutes` - (Optional) The flow timeout in minutes for the Virtual Network, which is used to enable connection tracking for intra-VM flows. Possible values are between `4` and `30` minutes. * `subnet` - (Optional) Can be specified multiple times to define multiple subnets. Each `subnet` block supports fields documented below. diff --git a/website/docs/r/virtual_network_gateway.html.markdown b/website/docs/r/virtual_network_gateway.html.markdown index 3334b8904f1a..4c8a0df9722d 100644 --- a/website/docs/r/virtual_network_gateway.html.markdown +++ b/website/docs/r/virtual_network_gateway.html.markdown @@ -104,31 +104,42 @@ EOF The following arguments are supported: +* `ip_configuration` (Required) One, two or three `ip_configuration` blocks documented below. + An active-standby gateway requires exactly one `ip_configuration` block, + an active-active gateway requires exactly two `ip_configuration` blocks whereas + an active-active zone redundant gateway with P2S configuration requires exactly three `ip_configuration` blocks. + +* `location` - (Required) The location/region where the Virtual Network Gateway is + located. Changing the location/region forces a new resource to be created. + * `name` - (Required) The name of the Virtual Network Gateway. Changing the name - forces a new resource to be created. + forces a new resource to be created. * `resource_group_name` - (Required) The name of the resource group in which to - create the Virtual Network Gateway. Changing the resource group name forces - a new resource to be created. + create the Virtual Network Gateway. Changing the resource group name forces + a new resource to be created. -* `location` - (Required) The location/region where the Virtual Network Gateway is - located. Changing the location/region forces a new resource to be created. +* `sku` - (Required) Configuration of the size and capacity of the virtual network + gateway. Valid options are `Basic`, `Standard`, `HighPerformance`, `UltraPerformance`, + `ErGw1AZ`, `ErGw2AZ`, `ErGw3AZ`, `VpnGw1`, `VpnGw2`, `VpnGw3`, `VpnGw4`,`VpnGw5`, `VpnGw1AZ`, + `VpnGw2AZ`, `VpnGw3AZ`,`VpnGw4AZ` and `VpnGw5AZ` and depend on the `type`, `vpn_type` and + `generation` arguments. + A `PolicyBased` gateway only supports the `Basic` sku. Further, the `UltraPerformance` + sku is only supported by an `ExpressRoute` gateway. -* `type` - (Required) The type of the Virtual Network Gateway. Valid options are - `Vpn` or `ExpressRoute`. Changing the type forces a new resource to be created. +~> **NOTE:** To build a UltraPerformance ExpressRoute Virtual Network gateway, the associated Public IP needs to be sku "Basic" not "Standard" -* `vpn_type` - (Optional) The routing type of the Virtual Network Gateway. Valid - options are `RouteBased` or `PolicyBased`. Defaults to `RouteBased`. +~> **NOTE:** Not all skus (e.g. `ErGw1AZ`) are available in all regions. If you see `StatusCode=400 -- Original Error: Code="InvalidGatewaySkuSpecifiedForGatewayDeploymentType"` please try another region. -* `enable_bgp` - (Optional) If `true`, BGP (Border Gateway Protocol) will be enabled - for this Virtual Network Gateway. Defaults to `false`. +* `type` - (Required) The type of the Virtual Network Gateway. Valid options are + `Vpn` or `ExpressRoute`. Changing the type forces a new resource to be created. -* `active_active` - (Optional) If `true`, an active-active Virtual Network Gateway - will be created. An active-active gateway requires a `HighPerformance` or an - `UltraPerformance` sku. If `false`, an active-standby gateway will be created. - Defaults to `false`. +--- -* `private_ip_address_enabled` - (Optional) Should private IP be enabled on this gateway for connections? Changing this forces a new resource to be created. +* `active_active` - (Optional) If `true`, an active-active Virtual Network Gateway + will be created. An active-active gateway requires a `HighPerformance` or an + `UltraPerformance` sku. If `false`, an active-standby gateway will be created. + Defaults to `false`. * `default_local_network_gateway_id` - (Optional) The ID of the local network gateway through which outbound Internet traffic from the virtual network in which the @@ -136,32 +147,25 @@ The following arguments are supported: [Azure documentation on forced tunnelling](https://docs.microsoft.com/en-us/azure/vpn-gateway/vpn-gateway-forced-tunneling-rm). If not specified, forced tunnelling is disabled. -* `sku` - (Required) Configuration of the size and capacity of the virtual network - gateway. Valid options are `Basic`, `Standard`, `HighPerformance`, `UltraPerformance`, - `ErGw1AZ`, `ErGw2AZ`, `ErGw3AZ`, `VpnGw1`, `VpnGw2`, `VpnGw3`, `VpnGw4`,`VpnGw5`, `VpnGw1AZ`, - `VpnGw2AZ`, `VpnGw3AZ`,`VpnGw4AZ` and `VpnGw5AZ` and depend on the `type`, `vpn_type` and - `generation` arguments. - A `PolicyBased` gateway only supports the `Basic` sku. Further, the `UltraPerformance` - sku is only supported by an `ExpressRoute` gateway. - -~> **NOTE:** To build a UltraPerformance ExpressRoute Virtual Network gateway, the associated Public IP needs to be sku "Basic" not "Standard" +* `edge_zone` - (Optional) Specifies the Edge Zone within the Azure Region where this Virtual Network Gateway should exist. Changing this forces a new Virtual Network Gateway to be created. -~> **NOTE:** Not all skus (e.g. `ErGw1AZ`) are available in all regions. If you see `StatusCode=400 -- Original Error: Code="InvalidGatewaySkuSpecifiedForGatewayDeploymentType"` please try another region. +* `enable_bgp` - (Optional) If `true`, BGP (Border Gateway Protocol) will be enabled + for this Virtual Network Gateway. Defaults to `false`. * `generation` - (Optional) The Generation of the Virtual Network gateway. Possible values include `Generation1`, `Generation2` or `None`. -> **NOTE:** The available values depend on the `type` and `sku` arguments - where `Generation2` is only value for a `sku` larger than `VpnGw2` or `VpnGw2AZ`. -* `ip_configuration` (Required) One, two or three `ip_configuration` blocks documented below. - An active-standby gateway requires exactly one `ip_configuration` block, - an active-active gateway requires exactly two `ip_configuration` blocks whereas - an active-active zone redundant gateway with P2S configuration requires exactly three `ip_configuration` blocks. +* `private_ip_address_enabled` - (Optional) Should private IP be enabled on this gateway for connections? Changing this forces a new resource to be created. + +* `tags` - (Optional) A mapping of tags to assign to the resource. * `vpn_client_configuration` (Optional) A `vpn_client_configuration` block which - is documented below. In this block the Virtual Network Gateway can be configured - to accept IPSec point-to-site connections. + is documented below. In this block the Virtual Network Gateway can be configured + to accept IPSec point-to-site connections. -* `tags` - (Optional) A mapping of tags to assign to the resource. +* `vpn_type` - (Optional) The routing type of the Virtual Network Gateway. Valid + options are `RouteBased` or `PolicyBased`. Defaults to `RouteBased`. --- diff --git a/website/docs/r/windows_virtual_machine.html.markdown b/website/docs/r/windows_virtual_machine.html.markdown index 2f39c9eb0e92..13f8990e9f78 100644 --- a/website/docs/r/windows_virtual_machine.html.markdown +++ b/website/docs/r/windows_virtual_machine.html.markdown @@ -127,6 +127,8 @@ The following arguments are supported: * `dedicated_host_group_id` - (Optional) The ID of a Dedicated Host Group that this Windows Virtual Machine should be run within. Conflicts with `dedicated_host_id`. +* `edge_zone` - (Optional) Specifies the Edge Zone within the Azure Region where this Windows Virtual Machine should exist. Changing this forces a new Windows Virtual Machine to be created. + * `enable_automatic_updates` - (Optional) Specifies if Automatic Updates are Enabled for the Windows Virtual Machine. Changing this forces a new resource to be created. * `encryption_at_host_enabled` - (Optional) Should all of the disks (including the temp disk) attached to this Virtual Machine be encrypted by enabling Encryption at Host? diff --git a/website/docs/r/windows_virtual_machine_scale_set.html.markdown b/website/docs/r/windows_virtual_machine_scale_set.html.markdown index ce2a872d5cd9..611e784bb87b 100644 --- a/website/docs/r/windows_virtual_machine_scale_set.html.markdown +++ b/website/docs/r/windows_virtual_machine_scale_set.html.markdown @@ -130,6 +130,8 @@ The following arguments are supported: * `do_not_run_extensions_on_overprovisioned_machines` - (Optional) Should Virtual Machine Extensions be run on Overprovisioned Virtual Machines in the Scale Set? Defaults to `false`. +* `edge_zone` - (Optional) Specifies the Edge Zone within the Azure Region where this Windows Virtual Machine Scale Set should exist. Changing this forces a new Windows Virtual Machine Scale Set to be created. + * `enable_automatic_updates` - (Optional) Are automatic updates enabled for this Virtual Machine? Defaults to `true`. * `encryption_at_host_enabled` - (Optional) Should all of the disks (including the temp disk) attached to this Virtual Machine be encrypted by enabling Encryption at Host?