Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update azurerm_linux|windows_virtual_machine - Support extensions_time_budget #9257

Merged
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -168,6 +169,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": {
Expand Down Expand Up @@ -389,6 +397,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),
}
Expand Down Expand Up @@ -553,6 +562,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 {
Expand Down Expand Up @@ -741,6 +756,11 @@ func resourceLinuxVirtualMachineUpdate(d *schema.ResourceData, meta interface{})
update.Identity = identity
}

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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")

Expand Down Expand Up @@ -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(`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,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")

Expand Down Expand Up @@ -1020,6 +1084,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(`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -170,6 +171,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": {
Expand Down Expand Up @@ -419,6 +427,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),
}
Expand Down Expand Up @@ -584,6 +593,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 {
Expand Down Expand Up @@ -622,6 +637,7 @@ func resourceWindowsVirtualMachineRead(d *schema.ResourceData, meta interface{})
d.Set("enable_automatic_updates", config.EnableAutomaticUpdates)

d.Set("provision_vm_agent", config.ProvisionVMAgent)

d.Set("timezone", config.TimeZone)

if err := d.Set("winrm_listener", flattenWinRMListener(config.WinRM)); err != nil {
Expand Down Expand Up @@ -786,6 +802,11 @@ func resourceWindowsVirtualMachineUpdate(d *schema.ResourceData, meta interface{
update.Identity = identity
}

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

Expand Down
2 changes: 2 additions & 0 deletions website/docs/r/linux_virtual_machine.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 2 additions & 0 deletions website/docs/r/windows_virtual_machine.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand Down