From 7ff57092138d6f3cbdf688d244266b718e37a8f1 Mon Sep 17 00:00:00 2001 From: Zhenhua Hu Date: Sun, 4 Feb 2024 14:50:04 +0800 Subject: [PATCH 1/2] add code --- .../compute/linux_virtual_machine_resource.go | 13 +- ...tual_machine_resource_orchestrated_test.go | 148 ++++++++++++++++++ .../windows_virtual_machine_resource.go | 13 +- ...tual_machine_resource_orchestrated_test.go | 146 +++++++++++++++++ .../r/linux_virtual_machine.html.markdown | 2 +- .../r/windows_virtual_machine.html.markdown | 2 +- 6 files changed, 320 insertions(+), 4 deletions(-) diff --git a/internal/services/compute/linux_virtual_machine_resource.go b/internal/services/compute/linux_virtual_machine_resource.go index 1493cb62dfb4..b455324b7b82 100644 --- a/internal/services/compute/linux_virtual_machine_resource.go +++ b/internal/services/compute/linux_virtual_machine_resource.go @@ -330,7 +330,6 @@ func resourceLinuxVirtualMachine() *pluginsdk.Resource { "virtual_machine_scale_set_id": { Type: pluginsdk.TypeString, Optional: true, - ForceNew: true, ConflictsWith: []string{ "availability_set_id", }, @@ -1194,6 +1193,18 @@ func resourceLinuxVirtualMachineUpdate(d *pluginsdk.ResourceData, meta interface } } + if d.HasChange("virtual_machine_scale_set_id") { + shouldUpdate = true + + if vmssIDRaw, ok := d.GetOk("virtual_machine_scale_set_id"); ok { + update.VirtualMachineProperties.VirtualMachineScaleSet = &compute.SubResource{ + ID: utils.String(vmssIDRaw.(string)), + } + } else { + update.VirtualMachineProperties.VirtualMachineScaleSet = &compute.SubResource{} + } + } + if d.HasChange("proximity_placement_group_id") { shouldUpdate = true diff --git a/internal/services/compute/linux_virtual_machine_resource_orchestrated_test.go b/internal/services/compute/linux_virtual_machine_resource_orchestrated_test.go index 9707ae79d25d..5e03afb3c91b 100644 --- a/internal/services/compute/linux_virtual_machine_resource_orchestrated_test.go +++ b/internal/services/compute/linux_virtual_machine_resource_orchestrated_test.go @@ -101,6 +101,35 @@ func TestAccLinuxVirtualMachine_orchestratedMultipleNonZonal(t *testing.T) { }) } +func TestAccLinuxVirtualMachine_orchestratedIdUpdate(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_linux_virtual_machine", "test") + r := LinuxVirtualMachineResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.orchestratedIdUnAttached(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("admin_password"), + { + Config: r.orchestratedIdAttached(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("admin_password"), + { + Config: r.orchestratedIdUnAttached(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("admin_password"), + }) +} + func (r LinuxVirtualMachineResource) orchestratedZonal(data acceptance.TestData) string { return fmt.Sprintf(` %s @@ -161,6 +190,125 @@ resource "azurerm_linux_virtual_machine" "test" { `, r.templateBaseForOchestratedVMSS(data), data.RandomInteger, data.RandomInteger, data.RandomInteger) } +func (r LinuxVirtualMachineResource) orchestratedIdUnAttached(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_network_interface" "test" { + name = "acctestnic-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + + ip_configuration { + name = "internal" + subnet_id = azurerm_subnet.test.id + private_ip_address_allocation = "Dynamic" + } +} + +resource "azurerm_orchestrated_virtual_machine_scale_set" "test" { + name = "acctestVMO-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + + platform_fault_domain_count = 1 + + zones = ["1"] + + tags = { + ENV = "Test" + } +} + +resource "azurerm_linux_virtual_machine" "test" { + name = "acctestVM-%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + size = "Standard_F2" + admin_username = "adminuser" + admin_password = "P@ssw0rd1234!" + disable_password_authentication = false + network_interface_ids = [ + azurerm_network_interface.test.id, + ] + + source_image_reference { + publisher = "Canonical" + offer = "0001-com-ubuntu-server-jammy" + sku = "22_04-lts" + version = "latest" + } + + os_disk { + storage_account_type = "Standard_LRS" + caching = "ReadWrite" + } + + zone = tolist(azurerm_orchestrated_virtual_machine_scale_set.test.zones)[0] +} +`, r.templateBaseForOchestratedVMSS(data), data.RandomInteger, data.RandomInteger, data.RandomInteger) +} + +func (r LinuxVirtualMachineResource) orchestratedIdAttached(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_network_interface" "test" { + name = "acctestnic-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + + ip_configuration { + name = "internal" + subnet_id = azurerm_subnet.test.id + private_ip_address_allocation = "Dynamic" + } +} + +resource "azurerm_orchestrated_virtual_machine_scale_set" "test" { + name = "acctestVMO-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + + platform_fault_domain_count = 1 + + zones = ["1"] + + tags = { + ENV = "Test" + } +} + +resource "azurerm_linux_virtual_machine" "test" { + name = "acctestVM-%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + size = "Standard_F2" + admin_username = "adminuser" + admin_password = "P@ssw0rd1234!" + disable_password_authentication = false + network_interface_ids = [ + azurerm_network_interface.test.id, + ] + + source_image_reference { + publisher = "Canonical" + offer = "0001-com-ubuntu-server-jammy" + sku = "22_04-lts" + version = "latest" + } + + os_disk { + storage_account_type = "Standard_LRS" + caching = "ReadWrite" + } + + virtual_machine_scale_set_id = azurerm_orchestrated_virtual_machine_scale_set.test.id + zone = tolist(azurerm_orchestrated_virtual_machine_scale_set.test.zones)[0] +} +`, r.templateBaseForOchestratedVMSS(data), data.RandomInteger, data.RandomInteger, data.RandomInteger) +} + func (r LinuxVirtualMachineResource) orchestratedWithPlatformFaultDomain(data acceptance.TestData) string { return fmt.Sprintf(` %s diff --git a/internal/services/compute/windows_virtual_machine_resource.go b/internal/services/compute/windows_virtual_machine_resource.go index b05a7ccb2d10..4ca9b55b3cae 100644 --- a/internal/services/compute/windows_virtual_machine_resource.go +++ b/internal/services/compute/windows_virtual_machine_resource.go @@ -359,7 +359,6 @@ func resourceWindowsVirtualMachine() *pluginsdk.Resource { "virtual_machine_scale_set_id": { Type: pluginsdk.TypeString, Optional: true, - ForceNew: true, ConflictsWith: []string{ "availability_set_id", }, @@ -1355,6 +1354,18 @@ func resourceWindowsVirtualMachineUpdate(d *pluginsdk.ResourceData, meta interfa } } + if d.HasChange("virtual_machine_scale_set_id") { + shouldUpdate = true + + if vmssIDRaw, ok := d.GetOk("virtual_machine_scale_set_id"); ok { + update.VirtualMachineProperties.VirtualMachineScaleSet = &compute.SubResource{ + ID: utils.String(vmssIDRaw.(string)), + } + } else { + update.VirtualMachineProperties.VirtualMachineScaleSet = &compute.SubResource{} + } + } + if d.HasChange("proximity_placement_group_id") { shouldUpdate = true diff --git a/internal/services/compute/windows_virtual_machine_resource_orchestrated_test.go b/internal/services/compute/windows_virtual_machine_resource_orchestrated_test.go index 001a0029d8c8..5bebb1194860 100644 --- a/internal/services/compute/windows_virtual_machine_resource_orchestrated_test.go +++ b/internal/services/compute/windows_virtual_machine_resource_orchestrated_test.go @@ -101,6 +101,35 @@ func TestAccWindowsVirtualMachine_orchestratedMultipleNoneZonal(t *testing.T) { }) } +func TestAccWindowsVirtualMachine_orchestratedIdUpdate(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_windows_virtual_machine", "test") + r := WindowsVirtualMachineResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.orchestratedIdUnAttached(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("admin_password"), + { + Config: r.orchestratedIdAttached(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("admin_password"), + { + Config: r.orchestratedIdUnAttached(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("admin_password"), + }) +} + func (r WindowsVirtualMachineResource) orchestratedZonal(data acceptance.TestData) string { return fmt.Sprintf(` %s @@ -160,6 +189,123 @@ resource "azurerm_windows_virtual_machine" "test" { `, r.templateBaseForOchestratedVMSS(data), data.RandomInteger, data.RandomInteger) } +func (r WindowsVirtualMachineResource) orchestratedIdUnAttached(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_network_interface" "test" { + name = "acctestnic-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + + ip_configuration { + name = "internal" + subnet_id = azurerm_subnet.test.id + private_ip_address_allocation = "Dynamic" + } +} + +resource "azurerm_orchestrated_virtual_machine_scale_set" "test" { + name = "acctestVMO-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + + platform_fault_domain_count = 1 + + zones = ["1"] + + tags = { + ENV = "Test" + } +} + +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@ssw0rd1234!" + network_interface_ids = [ + azurerm_network_interface.test.id, + ] + + source_image_reference { + publisher = "MicrosoftWindowsServer" + offer = "WindowsServer" + sku = "2016-Datacenter" + version = "latest" + } + + os_disk { + storage_account_type = "Standard_LRS" + caching = "ReadWrite" + } + + zone = tolist(azurerm_orchestrated_virtual_machine_scale_set.test.zones)[0] +} +`, r.templateBaseForOchestratedVMSS(data), data.RandomInteger, data.RandomInteger) +} + +func (r WindowsVirtualMachineResource) orchestratedIdAttached(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_network_interface" "test" { + name = "acctestnic-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + + ip_configuration { + name = "internal" + subnet_id = azurerm_subnet.test.id + private_ip_address_allocation = "Dynamic" + } +} + +resource "azurerm_orchestrated_virtual_machine_scale_set" "test" { + name = "acctestVMO-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + + platform_fault_domain_count = 1 + + zones = ["1"] + + tags = { + ENV = "Test" + } +} + +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@ssw0rd1234!" + network_interface_ids = [ + azurerm_network_interface.test.id, + ] + + source_image_reference { + publisher = "MicrosoftWindowsServer" + offer = "WindowsServer" + sku = "2016-Datacenter" + version = "latest" + } + + os_disk { + storage_account_type = "Standard_LRS" + caching = "ReadWrite" + } + + virtual_machine_scale_set_id = azurerm_orchestrated_virtual_machine_scale_set.test.id + zone = tolist(azurerm_orchestrated_virtual_machine_scale_set.test.zones)[0] +} +`, r.templateBaseForOchestratedVMSS(data), data.RandomInteger, data.RandomInteger) +} + func (r WindowsVirtualMachineResource) orchestratedWithPlatformFaultDomain(data acceptance.TestData) string { return fmt.Sprintf(` %s diff --git a/website/docs/r/linux_virtual_machine.html.markdown b/website/docs/r/linux_virtual_machine.html.markdown index c6e638189d71..5b7f5aa095bb 100644 --- a/website/docs/r/linux_virtual_machine.html.markdown +++ b/website/docs/r/linux_virtual_machine.html.markdown @@ -210,7 +210,7 @@ The following arguments are supported: * `vtpm_enabled` - (Optional) Specifies whether vTPM should be enabled on the virtual machine. Changing this forces a new resource to be created. -* `virtual_machine_scale_set_id` - (Optional) Specifies the Orchestrated Virtual Machine Scale Set that this Virtual Machine should be created within. Changing this forces a new resource to be created. +* `virtual_machine_scale_set_id` - (Optional) Specifies the Orchestrated Virtual Machine Scale Set that this Virtual Machine should be created within. ~> **NOTE:** Orchestrated Virtual Machine Scale Sets can be provisioned using [the `azurerm_orchestrated_virtual_machine_scale_set` resource](/docs/providers/azurerm/r/orchestrated_virtual_machine_scale_set.html). diff --git a/website/docs/r/windows_virtual_machine.html.markdown b/website/docs/r/windows_virtual_machine.html.markdown index d7465ead241a..da4732fbdbc1 100644 --- a/website/docs/r/windows_virtual_machine.html.markdown +++ b/website/docs/r/windows_virtual_machine.html.markdown @@ -205,7 +205,7 @@ The following arguments are supported: * `user_data` - (Optional) The Base64-Encoded User Data which should be used for this Virtual Machine. -* `virtual_machine_scale_set_id` - (Optional) Specifies the Orchestrated Virtual Machine Scale Set that this Virtual Machine should be created within. Changing this forces a new resource to be created. +* `virtual_machine_scale_set_id` - (Optional) Specifies the Orchestrated Virtual Machine Scale Set that this Virtual Machine should be created within. ~> **NOTE:** Orchestrated Virtual Machine Scale Sets can be provisioned using [the `azurerm_orchestrated_virtual_machine_scale_set` resource](/docs/providers/azurerm/r/orchestrated_virtual_machine_scale_set.html). From 5cca1e04c9782a6e162342849c5f1f47a36fa9a6 Mon Sep 17 00:00:00 2001 From: Zhenhua Hu Date: Sun, 18 Feb 2024 13:17:52 +0800 Subject: [PATCH 2/2] add notes for enabling the preview feature --- website/docs/r/linux_virtual_machine.html.markdown | 2 ++ website/docs/r/windows_virtual_machine.html.markdown | 2 ++ 2 files changed, 4 insertions(+) diff --git a/website/docs/r/linux_virtual_machine.html.markdown b/website/docs/r/linux_virtual_machine.html.markdown index 5b7f5aa095bb..8a99b4eb0798 100644 --- a/website/docs/r/linux_virtual_machine.html.markdown +++ b/website/docs/r/linux_virtual_machine.html.markdown @@ -212,6 +212,8 @@ The following arguments are supported: * `virtual_machine_scale_set_id` - (Optional) Specifies the Orchestrated Virtual Machine Scale Set that this Virtual Machine should be created within. +-> **NOTE:** To update `virtual_machine_scale_set_id` the Preview Feature `Microsoft.Compute/SingleFDAttachDetachVMToVmss` needs to be enabled, see [the documentation](https://review.learn.microsoft.com/azure/virtual-machine-scale-sets/virtual-machine-scale-sets-attach-detach-vm#enroll-in-the-preview) for more information. + ~> **NOTE:** Orchestrated Virtual Machine Scale Sets can be provisioned using [the `azurerm_orchestrated_virtual_machine_scale_set` resource](/docs/providers/azurerm/r/orchestrated_virtual_machine_scale_set.html). * `zone` - (Optional) Specifies the Availability Zones in which this Linux Virtual Machine should be located. Changing this forces a new Linux Virtual Machine to be created. diff --git a/website/docs/r/windows_virtual_machine.html.markdown b/website/docs/r/windows_virtual_machine.html.markdown index da4732fbdbc1..e859c5f0aa24 100644 --- a/website/docs/r/windows_virtual_machine.html.markdown +++ b/website/docs/r/windows_virtual_machine.html.markdown @@ -207,6 +207,8 @@ The following arguments are supported: * `virtual_machine_scale_set_id` - (Optional) Specifies the Orchestrated Virtual Machine Scale Set that this Virtual Machine should be created within. +-> **NOTE:** To update `virtual_machine_scale_set_id` the Preview Feature `Microsoft.Compute/SingleFDAttachDetachVMToVmss` needs to be enabled, see [the documentation](https://review.learn.microsoft.com/azure/virtual-machine-scale-sets/virtual-machine-scale-sets-attach-detach-vm#enroll-in-the-preview) for more information. + ~> **NOTE:** Orchestrated Virtual Machine Scale Sets can be provisioned using [the `azurerm_orchestrated_virtual_machine_scale_set` resource](/docs/providers/azurerm/r/orchestrated_virtual_machine_scale_set.html). * `vtpm_enabled` - (Optional) Specifies if vTPM (virtual Trusted Platform Module) and Trusted Launch is enabled for the Virtual Machine. Changing this forces a new resource to be created.