From 7a3b5bd86a4b316655c791aa0d9d18e929f273a5 Mon Sep 17 00:00:00 2001 From: Arcturus Date: Wed, 18 Nov 2020 00:16:26 +0800 Subject: [PATCH] Update `azurerm_linux|windows_virtual_machine` - Support `extensions_time_budget` (#9257) --- .../compute/linux_virtual_machine_resource.go | 20 ++++ ...nux_virtual_machine_resource_other_test.go | 93 ++++++++++++++++++ ...ows_virtual_machine_resource_other_test.go | 97 +++++++++++++++++++ .../windows_virtual_machine_resource.go | 20 ++++ .../r/linux_virtual_machine.html.markdown | 2 + .../r/windows_virtual_machine.html.markdown | 2 + 6 files changed, 234 insertions(+) diff --git a/azurerm/internal/services/compute/linux_virtual_machine_resource.go b/azurerm/internal/services/compute/linux_virtual_machine_resource.go index 8eca554486d6..aa8b74e55e2a 100644 --- a/azurerm/internal/services/compute/linux_virtual_machine_resource.go +++ b/azurerm/internal/services/compute/linux_virtual_machine_resource.go @@ -15,6 +15,7 @@ import ( "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/suppress" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" + azValidate "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/validate" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/locks" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/compute/parse" @@ -167,6 +168,13 @@ func resourceLinuxVirtualMachine() *schema.Resource { }, false), }, + "extensions_time_budget": { + Type: schema.TypeString, + Optional: true, + Default: "PT1H30M", + ValidateFunc: azValidate.ISO8601DurationBetween("PT15M", "PT2H"), + }, + "identity": virtualMachineIdentitySchema(), "max_bid_price": { @@ -388,6 +396,7 @@ func resourceLinuxVirtualMachineCreate(d *schema.ResourceData, meta interface{}) // Optional AdditionalCapabilities: additionalCapabilities, DiagnosticsProfile: bootDiagnostics, + ExtensionsTimeBudget: utils.String(d.Get("extensions_time_budget").(string)), }, Tags: tags.Expand(t), } @@ -552,6 +561,12 @@ func resourceLinuxVirtualMachineRead(d *schema.ResourceData, meta interface{}) e d.Set("size", string(profile.VMSize)) } + extensionsTimeBudget := "PT1H30M" + if props.ExtensionsTimeBudget != nil { + extensionsTimeBudget = *props.ExtensionsTimeBudget + } + d.Set("extensions_time_budget", extensionsTimeBudget) + // defaulted since BillingProfile isn't returned if it's unset maxBidPrice := float64(-1.0) if props.BillingProfile != nil && props.BillingProfile.MaxPrice != nil { @@ -755,6 +770,11 @@ func resourceLinuxVirtualMachineUpdate(d *schema.ResourceData, meta interface{}) } } + if d.HasChange("extensions_time_budget") { + shouldUpdate = true + update.ExtensionsTimeBudget = utils.String(d.Get("extensions_time_budget").(string)) + } + if d.HasChange("max_bid_price") { shouldUpdate = true diff --git a/azurerm/internal/services/compute/tests/linux_virtual_machine_resource_other_test.go b/azurerm/internal/services/compute/tests/linux_virtual_machine_resource_other_test.go index 8a55e2c00ee1..535d4f305fa2 100644 --- a/azurerm/internal/services/compute/tests/linux_virtual_machine_resource_other_test.go +++ b/azurerm/internal/services/compute/tests/linux_virtual_machine_resource_other_test.go @@ -105,6 +105,62 @@ func TestAccLinuxVirtualMachine_otherAllowExtensionOperationsUpdatedWithoutVmAge }) } +func TestAccLinuxVirtualMachine_otherExtensionsTimeBudget(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_linux_virtual_machine", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: checkLinuxVirtualMachineIsDestroyed, + Steps: []resource.TestStep{ + { + Config: testLinuxVirtualMachine_otherExtensionsTimeBudget(data, "PT30M"), + Check: resource.ComposeTestCheckFunc( + checkLinuxVirtualMachineExists(data.ResourceName), + resource.TestCheckResourceAttr(data.ResourceName, "extensions_time_budget", "PT30M"), + ), + }, + data.ImportStep(), + }, + }) +} + +func TestAccLinuxVirtualMachine_otherExtensionsTimeBudgetUpdate(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_linux_virtual_machine", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: checkLinuxVirtualMachineIsDestroyed, + Steps: []resource.TestStep{ + { + Config: testLinuxVirtualMachine_otherExtensionsTimeBudget(data, "PT30M"), + Check: resource.ComposeTestCheckFunc( + checkLinuxVirtualMachineExists(data.ResourceName), + resource.TestCheckResourceAttr(data.ResourceName, "extensions_time_budget", "PT30M"), + ), + }, + data.ImportStep(), + { + Config: testLinuxVirtualMachine_otherExtensionsTimeBudget(data, "PT50M"), + Check: resource.ComposeTestCheckFunc( + checkLinuxVirtualMachineExists(data.ResourceName), + resource.TestCheckResourceAttr(data.ResourceName, "extensions_time_budget", "PT50M"), + ), + }, + data.ImportStep(), + { + Config: testLinuxVirtualMachine_otherExtensionsTimeBudget(data, "PT30M"), + Check: resource.ComposeTestCheckFunc( + checkLinuxVirtualMachineExists(data.ResourceName), + resource.TestCheckResourceAttr(data.ResourceName, "extensions_time_budget", "PT30M"), + ), + }, + data.ImportStep(), + }, + }) +} + func TestAccLinuxVirtualMachine_otherBootDiagnostics(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_linux_virtual_machine", "test") @@ -702,6 +758,43 @@ resource "azurerm_linux_virtual_machine" "test" { `, template, data.RandomInteger) } +func testLinuxVirtualMachine_otherExtensionsTimeBudget(data acceptance.TestData, duration string) string { + template := testLinuxVirtualMachine_template(data) + return fmt.Sprintf(` +%s + +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" + network_interface_ids = [ + azurerm_network_interface.test.id, + ] + + admin_ssh_key { + username = "adminuser" + public_key = local.first_public_key + } + + os_disk { + caching = "ReadWrite" + storage_account_type = "Standard_LRS" + } + + source_image_reference { + publisher = "Canonical" + offer = "UbuntuServer" + sku = "16.04-LTS" + version = "latest" + } + + extensions_time_budget = "%s" +} +`, template, data.RandomInteger, duration) +} + func testLinuxVirtualMachine_otherBootDiagnostics(data acceptance.TestData) string { template := testLinuxVirtualMachine_otherBootDiagnosticsTemplate(data) return fmt.Sprintf(` diff --git a/azurerm/internal/services/compute/tests/windows_virtual_machine_resource_other_test.go b/azurerm/internal/services/compute/tests/windows_virtual_machine_resource_other_test.go index 6ca3f9444560..1a9e5e415bac 100644 --- a/azurerm/internal/services/compute/tests/windows_virtual_machine_resource_other_test.go +++ b/azurerm/internal/services/compute/tests/windows_virtual_machine_resource_other_test.go @@ -241,6 +241,70 @@ func TestAccWindowsVirtualMachine_otherAllowExtensionOperationsUpdatedWithoutVmA }) } +func TestAccWindowsVirtualMachine_otherExtensionsTimeBudget(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_windows_virtual_machine", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: checkWindowsVirtualMachineIsDestroyed, + Steps: []resource.TestStep{ + { + Config: testWindowsVirtualMachine_otherExtensionsTimeBudget(data, "PT30M"), + Check: resource.ComposeTestCheckFunc( + checkWindowsVirtualMachineExists(data.ResourceName), + resource.TestCheckResourceAttr(data.ResourceName, "extensions_time_budget", "PT30M"), + ), + }, + data.ImportStep( + "admin_password", + ), + }, + }) +} + +func TestAccWindowsVirtualMachine_otherExtensionsTimeBudgetUpdate(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_windows_virtual_machine", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: checkWindowsVirtualMachineIsDestroyed, + Steps: []resource.TestStep{ + { + Config: testWindowsVirtualMachine_otherExtensionsTimeBudget(data, "PT30M"), + Check: resource.ComposeTestCheckFunc( + checkWindowsVirtualMachineExists(data.ResourceName), + resource.TestCheckResourceAttr(data.ResourceName, "extensions_time_budget", "PT30M"), + ), + }, + data.ImportStep( + "admin_password", + ), + { + Config: testWindowsVirtualMachine_otherExtensionsTimeBudget(data, "PT50M"), + Check: resource.ComposeTestCheckFunc( + checkWindowsVirtualMachineExists(data.ResourceName), + resource.TestCheckResourceAttr(data.ResourceName, "extensions_time_budget", "PT50M"), + ), + }, + data.ImportStep( + "admin_password", + ), + { + Config: testWindowsVirtualMachine_otherExtensionsTimeBudget(data, "PT30M"), + Check: resource.ComposeTestCheckFunc( + checkWindowsVirtualMachineExists(data.ResourceName), + resource.TestCheckResourceAttr(data.ResourceName, "extensions_time_budget", "PT30M"), + ), + }, + data.ImportStep( + "admin_password", + ), + }, + }) +} + func TestAccWindowsVirtualMachine_otherBootDiagnostics(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_windows_virtual_machine", "test") @@ -1225,6 +1289,39 @@ resource "azurerm_windows_virtual_machine" "test" { `, template) } +func testWindowsVirtualMachine_otherExtensionsTimeBudget(data acceptance.TestData, duration string) string { + template := testWindowsVirtualMachine_template(data) + return fmt.Sprintf(` +%s + +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!" + network_interface_ids = [ + azurerm_network_interface.test.id, + ] + + os_disk { + caching = "ReadWrite" + storage_account_type = "Standard_LRS" + } + + source_image_reference { + publisher = "MicrosoftWindowsServer" + offer = "WindowsServer" + sku = "2016-Datacenter" + version = "latest" + } + + extensions_time_budget = "%s" +} +`, template, duration) +} + func testWindowsVirtualMachine_otherBootDiagnostics(data acceptance.TestData) string { template := testWindowsVirtualMachine_otherBootDiagnosticsTemplate(data) return fmt.Sprintf(` diff --git a/azurerm/internal/services/compute/windows_virtual_machine_resource.go b/azurerm/internal/services/compute/windows_virtual_machine_resource.go index 0ede151cbf72..34fda7288386 100644 --- a/azurerm/internal/services/compute/windows_virtual_machine_resource.go +++ b/azurerm/internal/services/compute/windows_virtual_machine_resource.go @@ -16,6 +16,7 @@ import ( "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/suppress" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/validate" + azValidate "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/validate" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/locks" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/compute/parse" @@ -169,6 +170,13 @@ func resourceWindowsVirtualMachine() *schema.Resource { }, false), }, + "extensions_time_budget": { + Type: schema.TypeString, + Optional: true, + Default: "PT1H30M", + ValidateFunc: azValidate.ISO8601DurationBetween("PT15M", "PT2H"), + }, + "identity": virtualMachineIdentitySchema(), "license_type": { @@ -433,6 +441,7 @@ func resourceWindowsVirtualMachineCreate(d *schema.ResourceData, meta interface{ // Optional AdditionalCapabilities: additionalCapabilities, DiagnosticsProfile: bootDiagnostics, + ExtensionsTimeBudget: utils.String(d.Get("extensions_time_budget").(string)), }, Tags: tags.Expand(t), } @@ -598,6 +607,12 @@ func resourceWindowsVirtualMachineRead(d *schema.ResourceData, meta interface{}) } d.Set("license_type", props.LicenseType) + extensionsTimeBudget := "PT1H30M" + if props.ExtensionsTimeBudget != nil { + extensionsTimeBudget = *props.ExtensionsTimeBudget + } + d.Set("extensions_time_budget", extensionsTimeBudget) + // defaulted since BillingProfile isn't returned if it's unset maxBidPrice := float64(-1.0) if props.BillingProfile != nil && props.BillingProfile.MaxPrice != nil { @@ -836,6 +851,11 @@ func resourceWindowsVirtualMachineUpdate(d *schema.ResourceData, meta interface{ } } + if d.HasChange("extensions_time_budget") { + shouldUpdate = true + update.ExtensionsTimeBudget = utils.String(d.Get("extensions_time_budget").(string)) + } + if d.HasChange("max_bid_price") { shouldUpdate = true diff --git a/website/docs/r/linux_virtual_machine.html.markdown b/website/docs/r/linux_virtual_machine.html.markdown index 880ac18d686c..c559787c24b1 100644 --- a/website/docs/r/linux_virtual_machine.html.markdown +++ b/website/docs/r/linux_virtual_machine.html.markdown @@ -146,6 +146,8 @@ The following arguments are supported: -> **NOTE:** This can only be configured when `priority` is set to `Spot`. +* `extensions_time_budget` - (Optional) Specifies the duration allocated for all extensions to start. The time duration should be between 15 minutes and 120 minutes (inclusive) and should be specified in ISO 8601 format. Defaults to 90 minutes (`PT1H30M`). + * `identity` - (Optional) An `identity` block as defined below. * `max_bid_price` - (Optional) The maximum price you're willing to pay for this Virtual Machine, in US Dollars; which must be greater than the current spot price. If this bid price falls below the current spot price the Virtual Machine will be evicted using the `eviction_policy`. Defaults to `-1`, which means that the Virtual Machine should not be evicted for price reasons. diff --git a/website/docs/r/windows_virtual_machine.html.markdown b/website/docs/r/windows_virtual_machine.html.markdown index 846e5e2dc63a..3e71370bc85c 100644 --- a/website/docs/r/windows_virtual_machine.html.markdown +++ b/website/docs/r/windows_virtual_machine.html.markdown @@ -133,6 +133,8 @@ The following arguments are supported: -> **NOTE:** This can only be configured when `priority` is set to `Spot`. +* `extensions_time_budget` - (Optional) Specifies the duration allocated for all extensions to start. The time duration should be between 15 minutes and 120 minutes (inclusive) and should be specified in ISO 8601 format. Defaults to 90 minutes (`PT1H30M`). + * `identity` - (Optional) An `identity` block as defined below. * `license_type` - (Optional) Specifies the type of on-premise license (also known as [Azure Hybrid Use Benefit](https://docs.microsoft.com/azure/virtual-machines/virtual-machines-windows-hybrid-use-benefit-licensing)) which should be used for this Virtual Machine. Possible values are `None`, `Windows_Client` and `Windows_Server`.