From b358aa19af39a107f7ecd7994a9d8e4c4e4c98f6 Mon Sep 17 00:00:00 2001 From: Zhenhua Hu Date: Tue, 27 Feb 2024 15:25:10 +0800 Subject: [PATCH] `azurerm_linux_virtual_machine`,`azurerm_windows_virtual_machine` - Support `automatic_upgrade_enabled`,`disk_controller_type`,`os_image_notification`,`treat_failure_as_deployment_failure_enabled` and `vm_agent_platform_updates_enabled` (#23394) * support `automatic_upgrade_enabled` * support `treat_failure_as_deployment_failure_enabled` * support `vm_agent_platform_updates_enabled` * support `os_image_notification` * support `disk_controller_type` * fix lint * bug fix * add comment * resolve comments * remove version limitation --- .../compute/linux_virtual_machine_resource.go | 96 ++++++++- ...x_virtual_machine_resource_disk_os_test.go | 101 ++++++++++ ...nux_virtual_machine_resource_other_test.go | 184 +++++++++++++++++- internal/services/compute/virtual_machine.go | 121 +++++++++--- .../windows_virtual_machine_resource.go | 104 +++++++++- ...s_virtual_machine_resource_disk_os_test.go | 93 +++++++++ ...ows_virtual_machine_resource_other_test.go | 182 +++++++++++++++-- .../r/linux_virtual_machine.html.markdown | 16 ++ .../r/windows_virtual_machine.html.markdown | 16 ++ 9 files changed, 856 insertions(+), 57 deletions(-) diff --git a/internal/services/compute/linux_virtual_machine_resource.go b/internal/services/compute/linux_virtual_machine_resource.go index b455324b7b829..b79956b57d9c4 100644 --- a/internal/services/compute/linux_virtual_machine_resource.go +++ b/internal/services/compute/linux_virtual_machine_resource.go @@ -191,6 +191,16 @@ func resourceLinuxVirtualMachine() *pluginsdk.Resource { Default: true, }, + "disk_controller_type": { + Type: pluginsdk.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringInSlice([]string{ + string(compute.DiskControllerTypesNVMe), + string(compute.DiskControllerTypesSCSI), + }, false), + }, + "edge_zone": commonschema.EdgeZoneOptionalForceNew(), "encryption_at_host_enabled": { @@ -336,6 +346,12 @@ func resourceLinuxVirtualMachine() *pluginsdk.Resource { ValidateFunc: commonids.ValidateVirtualMachineScaleSetID, }, + "vm_agent_platform_updates_enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: false, + }, + "vtpm_enabled": { Type: pluginsdk.TypeBool, Optional: true, @@ -353,6 +369,8 @@ func resourceLinuxVirtualMachine() *pluginsdk.Resource { "tags": tags.Schema(), + "os_image_notification": virtualMachineOsImageNotificationSchema(), + "termination_notification": virtualMachineTerminationNotificationSchema(), "user_data": { @@ -436,6 +454,7 @@ func resourceLinuxVirtualMachineCreate(d *pluginsdk.ResourceData, meta interface computerName = id.VirtualMachineName } disablePasswordAuthentication := d.Get("disable_password_authentication").(bool) + vmAgentPlatformUpdatesEnabled := d.Get("vm_agent_platform_updates_enabled").(bool) location := azure.NormalizeLocation(d.Get("location").(string)) identityRaw := d.Get("identity").([]interface{}) identity, err := expandVirtualMachineIdentity(identityRaw) @@ -488,6 +507,7 @@ func resourceLinuxVirtualMachineCreate(d *pluginsdk.ResourceData, meta interface AllowExtensionOperations: utils.Bool(allowExtensionOperations), LinuxConfiguration: &compute.LinuxConfiguration{ DisablePasswordAuthentication: utils.Bool(disablePasswordAuthentication), + EnableVMAgentPlatformUpdates: utils.Bool(vmAgentPlatformUpdatesEnabled), ProvisionVMAgent: utils.Bool(provisionVMAgent), SSH: &compute.SSHConfiguration{ PublicKeys: &sshKeys, @@ -516,6 +536,10 @@ func resourceLinuxVirtualMachineCreate(d *pluginsdk.ResourceData, meta interface Tags: tags.Expand(t), } + if diskControllerType, ok := d.GetOk("disk_controller_type"); ok { + params.StorageProfile.DiskControllerType = compute.DiskControllerTypes(diskControllerType.(string)) + } + if encryptionAtHostEnabled, ok := d.GetOk("encryption_at_host_enabled"); ok { if encryptionAtHostEnabled.(bool) { if compute.SecurityEncryptionTypesDiskWithVMGuestState == compute.SecurityEncryptionTypes(securityEncryptionType) { @@ -630,8 +654,22 @@ func resourceLinuxVirtualMachineCreate(d *pluginsdk.ResourceData, meta interface } } + var osImageNotificationProfile *compute.OSImageNotificationProfile + var terminateNotificationProfile *compute.TerminateNotificationProfile + + if v, ok := d.GetOk("os_image_notification"); ok { + osImageNotificationProfile = expandOsImageNotificationProfile(v.([]interface{})) + } + if v, ok := d.GetOk("termination_notification"); ok { - params.VirtualMachineProperties.ScheduledEventsProfile = expandVirtualMachineScheduledEventsProfile(v.([]interface{})) + terminateNotificationProfile = expandTerminateNotificationProfile(v.([]interface{})) + } + + if terminateNotificationProfile != nil || osImageNotificationProfile != nil { + params.VirtualMachineProperties.ScheduledEventsProfile = &compute.ScheduledEventsProfile{ + OsImageNotificationProfile: osImageNotificationProfile, + TerminateNotificationProfile: terminateNotificationProfile, + } } if !provisionVMAgent && allowExtensionOperations { @@ -871,6 +909,7 @@ func resourceLinuxVirtualMachineRead(d *pluginsdk.ResourceData, meta interface{} if config := profile.LinuxConfiguration; config != nil { d.Set("disable_password_authentication", config.DisablePasswordAuthentication) d.Set("provision_vm_agent", config.ProvisionVMAgent) + d.Set("vm_agent_platform_updates_enabled", config.EnableVMAgentPlatformUpdates) flattenedSSHKeys, err := FlattenSSHKeys(config.SSH) if err != nil { @@ -919,6 +958,8 @@ func resourceLinuxVirtualMachineRead(d *pluginsdk.ResourceData, meta interface{} d.Set("proximity_placement_group_id", proximityPlacementGroupId) if profile := props.StorageProfile; profile != nil { + d.Set("disk_controller_type", string(props.StorageProfile.DiskControllerType)) + // the storage_account_type isn't returned so we need to look it up flattenedOSDisk, err := flattenVirtualMachineOSDisk(ctx, disksClient, profile.OsDisk) if err != nil { @@ -947,7 +988,11 @@ func resourceLinuxVirtualMachineRead(d *pluginsdk.ResourceData, meta interface{} } if scheduleProfile := props.ScheduledEventsProfile; scheduleProfile != nil { - if err := d.Set("termination_notification", flattenVirtualMachineScheduledEventsProfile(scheduleProfile)); err != nil { + if err := d.Set("os_image_notification", flattenOsImageNotificationProfile(scheduleProfile.OsImageNotificationProfile)); err != nil { + return fmt.Errorf("setting `termination_notification`: %+v", err) + } + + if err := d.Set("termination_notification", flattenTerminateNotificationProfile(scheduleProfile.TerminateNotificationProfile)); err != nil { return fmt.Errorf("setting `termination_notification`: %+v", err) } } @@ -1175,6 +1220,17 @@ func resourceLinuxVirtualMachineUpdate(d *pluginsdk.ResourceData, meta interface } } + if d.HasChange("disk_controller_type") { + shouldUpdate = true + shouldDeallocate = true + + if update.VirtualMachineProperties.StorageProfile == nil { + update.VirtualMachineProperties.StorageProfile = &compute.StorageProfile{} + } + + update.VirtualMachineProperties.StorageProfile.DiskControllerType = compute.DiskControllerTypes(d.Get("disk_controller_type").(string)) + } + if d.HasChange("os_disk") { shouldUpdate = true @@ -1188,9 +1244,11 @@ func resourceLinuxVirtualMachineUpdate(d *pluginsdk.ResourceData, meta interface return fmt.Errorf("expanding `os_disk`: %+v", err) } - update.VirtualMachineProperties.StorageProfile = &compute.StorageProfile{ - OsDisk: osDisk, + if update.VirtualMachineProperties.StorageProfile == nil { + update.VirtualMachineProperties.StorageProfile = &compute.StorageProfile{} } + + update.VirtualMachineProperties.StorageProfile.OsDisk = osDisk } if d.HasChange("virtual_machine_scale_set_id") { @@ -1264,6 +1322,19 @@ func resourceLinuxVirtualMachineUpdate(d *pluginsdk.ResourceData, meta interface } } + if d.HasChange("vm_agent_platform_updates_enabled") { + shouldUpdate = true + if update.VirtualMachineProperties.OsProfile == nil { + update.VirtualMachineProperties.OsProfile = &compute.OSProfile{} + } + + if update.VirtualMachineProperties.OsProfile.LinuxConfiguration == nil { + update.VirtualMachineProperties.OsProfile.LinuxConfiguration = &compute.LinuxConfiguration{} + } + + update.VirtualMachineProperties.OsProfile.LinuxConfiguration.EnableVMAgentPlatformUpdates = utils.Bool(d.Get("vm_agent_platform_updates_enabled").(bool)) + } + if d.HasChange("patch_mode") { shouldUpdate = true patchSettings := &compute.LinuxPatchSettings{} @@ -1377,11 +1448,24 @@ func resourceLinuxVirtualMachineUpdate(d *pluginsdk.ResourceData, meta interface update.OsProfile.AllowExtensionOperations = utils.Bool(allowExtensionOperations) } + var osImageNotificationProfile *compute.OSImageNotificationProfile + var terminateNotificationProfile *compute.TerminateNotificationProfile + + if d.HasChange("os_image_notification") { + shouldUpdate = true + osImageNotificationProfile = expandOsImageNotificationProfile(d.Get("os_image_notification").([]interface{})) + } + if d.HasChange("termination_notification") { shouldUpdate = true + terminateNotificationProfile = expandTerminateNotificationProfile(d.Get("termination_notification").([]interface{})) + } - notificationRaw := d.Get("termination_notification").([]interface{}) - update.ScheduledEventsProfile = expandVirtualMachineScheduledEventsProfile(notificationRaw) + if osImageNotificationProfile != nil || terminateNotificationProfile != nil { + update.ScheduledEventsProfile = &compute.ScheduledEventsProfile{ + OsImageNotificationProfile: osImageNotificationProfile, + TerminateNotificationProfile: terminateNotificationProfile, + } } if d.HasChange("tags") { diff --git a/internal/services/compute/linux_virtual_machine_resource_disk_os_test.go b/internal/services/compute/linux_virtual_machine_resource_disk_os_test.go index 21d86b6961cbd..afdb65fd3b9f6 100644 --- a/internal/services/compute/linux_virtual_machine_resource_disk_os_test.go +++ b/internal/services/compute/linux_virtual_machine_resource_disk_os_test.go @@ -300,6 +300,35 @@ func TestAccLinuxVirtualMachine_diskOSStorageTypeUpdate(t *testing.T) { }) } +func TestAccLinuxVirtualMachine_diskOSControllerType(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_linux_virtual_machine", "test") + r := LinuxVirtualMachineResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.diskOSControllerTypeNVMe(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.diskOSControllerTypeSCSI(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.diskOSControllerTypeNVMe(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + func TestAccLinuxVirtualMachine_diskOSWriteAcceleratorEnabled(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_linux_virtual_machine", "test") r := LinuxVirtualMachineResource{} @@ -892,6 +921,78 @@ func (r LinuxVirtualMachineResource) diskOSStorageAccountTypeWithRestrictedLocat return r.diskOSStorageAccountType(data, accountType) } +func (r LinuxVirtualMachineResource) diskOSControllerTypeSCSI(data acceptance.TestData) string { + 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_B1s" + admin_username = "adminuser" + disk_controller_type = "SCSI" + + 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 = "0001-com-ubuntu-server-jammy" + sku = "22_04-lts-gen2" + version = "latest" + } +} +`, r.template(data), data.RandomInteger) +} + +func (r LinuxVirtualMachineResource) diskOSControllerTypeNVMe(data acceptance.TestData) string { + 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_E2bds_v5" + admin_username = "adminuser" + disk_controller_type = "NVMe" + + 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 = "0001-com-ubuntu-server-jammy" + sku = "22_04-lts-gen2" + version = "latest" + } +} +`, r.template(data), data.RandomInteger) +} + func (r LinuxVirtualMachineResource) diskOSWriteAcceleratorEnabled(data acceptance.TestData, enabled bool) string { return fmt.Sprintf(` %s 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 0839a898538de..67b8a5bc785ba 100644 --- a/internal/services/compute/linux_virtual_machine_resource_other_test.go +++ b/internal/services/compute/linux_virtual_machine_resource_other_test.go @@ -93,6 +93,30 @@ func TestAccLinuxVirtualMachine_otherAllowExtensionOperationsUpdatedWithoutVmAge }) } +func TestAccLinuxVirtualMachine_otherVmAgentPlatformUpdates(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_linux_virtual_machine", "test") + r := LinuxVirtualMachineResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.otherVmAgentPlatformUpdatesEnabled(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("vm_agent_platform_updates_enabled").HasValue("true"), + ), + }, + data.ImportStep(), + { + Config: r.otherVmAgentPlatformUpdatesDisabled(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("vm_agent_platform_updates_enabled").HasValue("false"), + ), + }, + data.ImportStep(), + }) +} + func TestAccLinuxVirtualMachine_otherExtensionsTimeBudget(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_linux_virtual_machine", "test") r := LinuxVirtualMachineResource{} @@ -508,6 +532,37 @@ func TestAccLinuxVirtualMachine_otherTags(t *testing.T) { }) } +func TestAccLinuxVirtualMachine_otherOsImageNotification(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_linux_virtual_machine", "test") + r := LinuxVirtualMachineResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.otherOsImageNotification(data, true), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("os_image_notification.#").HasValue("1"), + ), + }, + data.ImportStep(), + { + Config: r.otherOsImageNotification(data, false), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.otherOsImageNotification(data, true), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("os_image_notification.#").HasValue("1"), + ), + }, + data.ImportStep(), + }) +} + func TestAccLinuxVirtualMachine_otherTerminationNotification(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_linux_virtual_machine", "test") r := LinuxVirtualMachineResource{} @@ -1168,6 +1223,76 @@ resource "azurerm_linux_virtual_machine" "test" { `, r.template(data), data.RandomInteger) } +func (r LinuxVirtualMachineResource) otherVmAgentPlatformUpdatesEnabled(data acceptance.TestData) string { + 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" + vm_agent_platform_updates_enabled = true + + 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 = "0001-com-ubuntu-server-jammy" + sku = "22_04-lts" + version = "latest" + } +} +`, r.template(data), data.RandomInteger) +} + +func (r LinuxVirtualMachineResource) otherVmAgentPlatformUpdatesDisabled(data acceptance.TestData) string { + 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 = "0001-com-ubuntu-server-jammy" + sku = "22_04-lts" + version = "latest" + } +} +`, r.template(data), data.RandomInteger) +} + func (r LinuxVirtualMachineResource) otherExtensionsTimeBudget(data acceptance.TestData, duration string) string { return fmt.Sprintf(` %s @@ -1615,10 +1740,12 @@ resource "azurerm_linux_virtual_machine" "test" { } gallery_application { - version_id = azurerm_gallery_application_version.test2.id - order = 2 - configuration_blob_uri = azurerm_storage_blob.test2.id - tag = "app2" + version_id = azurerm_gallery_application_version.test2.id + automatic_upgrade_enabled = true + order = 2 + configuration_blob_uri = azurerm_storage_blob.test2.id + tag = "app2" + treat_failure_as_deployment_failure_enabled = true } } `, r.otherGalleryApplicationTemplate(data), data.RandomInteger) @@ -1716,8 +1843,8 @@ resource "azurerm_gallery_application_version" "test" { } manage_action { - install = "[install command]" - remove = "[remove command]" + install = "echo install" + remove = "echo remove" } target_region { @@ -1746,8 +1873,8 @@ resource "azurerm_gallery_application_version" "test2" { } manage_action { - install = "[install command]" - remove = "[remove command]" + install = "echo install" + remove = "echo remove" } target_region { @@ -2392,6 +2519,47 @@ resource "azurerm_linux_virtual_machine" "test" { `, r.template(data), data.RandomInteger) } +func (r LinuxVirtualMachineResource) otherOsImageNotification(data acceptance.TestData, enabled bool) string { + osImageNotificationConfig := "" + if enabled { + osImageNotificationConfig = "os_image_notification {}" + } + + 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 = "0001-com-ubuntu-server-jammy" + sku = "22_04-lts" + version = "latest" + } + + %s +} +`, r.template(data), data.RandomInteger, osImageNotificationConfig) +} + func (r LinuxVirtualMachineResource) otherTerminationNotification(data acceptance.TestData, enabled bool) string { return fmt.Sprintf(` %s diff --git a/internal/services/compute/virtual_machine.go b/internal/services/compute/virtual_machine.go index cec8f2fe70f9b..525fc9d148991 100644 --- a/internal/services/compute/virtual_machine.go +++ b/internal/services/compute/virtual_machine.go @@ -7,6 +7,7 @@ import ( "context" "fmt" + "github.com/hashicorp/go-azure-helpers/lang/pointer" "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonids" "github.com/hashicorp/go-azure-helpers/resourcemanager/identity" @@ -426,6 +427,26 @@ func flattenVirtualMachineOSDisk(ctx context.Context, disksClient *disks.DisksCl }, nil } +func virtualMachineOsImageNotificationSchema() *pluginsdk.Schema { + return &pluginsdk.Schema{ + Type: pluginsdk.TypeList, + Optional: true, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "timeout": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + "PT15M", + }, false), + Default: "PT15M", + }, + }, + }, + } +} + func virtualMachineTerminationNotificationSchema() *pluginsdk.Schema { return &pluginsdk.Schema{ Type: pluginsdk.TypeList, @@ -449,12 +470,26 @@ func virtualMachineTerminationNotificationSchema() *pluginsdk.Schema { } } -func expandVirtualMachineScheduledEventsProfile(input []interface{}) *compute.ScheduledEventsProfile { +func expandOsImageNotificationProfile(input []interface{}) *compute.OSImageNotificationProfile { if len(input) == 0 { - return &compute.ScheduledEventsProfile{ - TerminateNotificationProfile: &compute.TerminateNotificationProfile{ - Enable: utils.Bool(false), - }, + return &compute.OSImageNotificationProfile{ + Enable: utils.Bool(false), + } + } + + raw := input[0].(map[string]interface{}) + timeout := raw["timeout"].(string) + + return &compute.OSImageNotificationProfile{ + Enable: utils.Bool(true), + NotBeforeTimeout: &timeout, + } +} + +func expandTerminateNotificationProfile(input []interface{}) *compute.TerminateNotificationProfile { + if len(input) == 0 { + return &compute.TerminateNotificationProfile{ + Enable: utils.Bool(false), } } @@ -462,26 +497,41 @@ func expandVirtualMachineScheduledEventsProfile(input []interface{}) *compute.Sc enabled := raw["enabled"].(bool) timeout := raw["timeout"].(string) - return &compute.ScheduledEventsProfile{ - TerminateNotificationProfile: &compute.TerminateNotificationProfile{ - Enable: &enabled, - NotBeforeTimeout: &timeout, + return &compute.TerminateNotificationProfile{ + Enable: &enabled, + NotBeforeTimeout: &timeout, + } +} + +func flattenOsImageNotificationProfile(input *compute.OSImageNotificationProfile) []interface{} { + if input == nil || !pointer.From(input.Enable) { + return nil + } + + timeout := "PT15M" + if input.NotBeforeTimeout != nil { + timeout = *input.NotBeforeTimeout + } + + return []interface{}{ + map[string]interface{}{ + "timeout": timeout, }, } } -func flattenVirtualMachineScheduledEventsProfile(input *compute.ScheduledEventsProfile) []interface{} { +func flattenTerminateNotificationProfile(input *compute.TerminateNotificationProfile) []interface{} { // if enabled is set to false, there will be no ScheduledEventsProfile in response, to avoid plan non empty when // a user explicitly set enabled to false, we need to assign a default block to this field enabled := false - if input != nil && input.TerminateNotificationProfile != nil && input.TerminateNotificationProfile.Enable != nil { - enabled = *input.TerminateNotificationProfile.Enable + if input != nil && input.Enable != nil { + enabled = *input.Enable } timeout := "PT5M" - if input != nil && input.TerminateNotificationProfile != nil && input.TerminateNotificationProfile.NotBeforeTimeout != nil { - timeout = *input.TerminateNotificationProfile.NotBeforeTimeout + if input != nil && input.NotBeforeTimeout != nil { + timeout = *input.NotBeforeTimeout } return []interface{}{ @@ -505,6 +555,12 @@ func VirtualMachineGalleryApplicationSchema() *pluginsdk.Schema { ValidateFunc: galleryapplicationversions.ValidateApplicationVersionID, }, + "automatic_upgrade_enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: false, + }, + // Example: https://mystorageaccount.blob.core.windows.net/configurations/settings.config "configuration_blob_uri": { Type: pluginsdk.TypeString, @@ -525,6 +581,12 @@ func VirtualMachineGalleryApplicationSchema() *pluginsdk.Schema { Optional: true, ValidateFunc: validation.StringIsNotEmpty, }, + + "treat_failure_as_deployment_failure_enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: false, + }, }, }, } @@ -538,15 +600,19 @@ func expandVirtualMachineGalleryApplication(input []interface{}) *[]compute.VMGa for _, v := range input { packageReferenceId := v.(map[string]interface{})["version_id"].(string) + automaticUpgradeEnabled := v.(map[string]interface{})["automatic_upgrade_enabled"].(bool) configurationReference := v.(map[string]interface{})["configuration_blob_uri"].(string) order := v.(map[string]interface{})["order"].(int) tag := v.(map[string]interface{})["tag"].(string) + treatFailureAsDeploymentFailureEnabled := v.(map[string]interface{})["treat_failure_as_deployment_failure_enabled"].(bool) app := &compute.VMGalleryApplication{ - PackageReferenceID: utils.String(packageReferenceId), - ConfigurationReference: utils.String(configurationReference), - Order: utils.Int32(int32(order)), - Tags: utils.String(tag), + PackageReferenceID: utils.String(packageReferenceId), + ConfigurationReference: utils.String(configurationReference), + Order: utils.Int32(int32(order)), + Tags: utils.String(tag), + EnableAutomaticUpgrade: utils.Bool(automaticUpgradeEnabled), + TreatFailureAsDeploymentFailure: utils.Bool(treatFailureAsDeploymentFailureEnabled), } out = append(out, *app) @@ -565,6 +631,7 @@ func flattenVirtualMachineGalleryApplication(input *[]compute.VMGalleryApplicati for _, v := range *input { var packageReferenceId, configurationReference, tag string var order int + var automaticUpgradeEnabled, treatFailureAsDeploymentFailureEnabled bool if v.PackageReferenceID != nil { packageReferenceId = *v.PackageReferenceID @@ -574,6 +641,10 @@ func flattenVirtualMachineGalleryApplication(input *[]compute.VMGalleryApplicati configurationReference = *v.ConfigurationReference } + if v.EnableAutomaticUpgrade != nil { + automaticUpgradeEnabled = *v.EnableAutomaticUpgrade + } + if v.Order != nil { order = int(*v.Order) } @@ -582,11 +653,17 @@ func flattenVirtualMachineGalleryApplication(input *[]compute.VMGalleryApplicati tag = *v.Tags } + if v.TreatFailureAsDeploymentFailure != nil { + treatFailureAsDeploymentFailureEnabled = *v.TreatFailureAsDeploymentFailure + } + app := map[string]interface{}{ - "version_id": packageReferenceId, - "configuration_blob_uri": configurationReference, - "order": order, - "tag": tag, + "version_id": packageReferenceId, + "automatic_upgrade_enabled": automaticUpgradeEnabled, + "configuration_blob_uri": configurationReference, + "order": order, + "tag": tag, + "treat_failure_as_deployment_failure_enabled": treatFailureAsDeploymentFailureEnabled, } out = append(out, app) diff --git a/internal/services/compute/windows_virtual_machine_resource.go b/internal/services/compute/windows_virtual_machine_resource.go index 4ca9b55b3caed..9d8cafbd145b0 100644 --- a/internal/services/compute/windows_virtual_machine_resource.go +++ b/internal/services/compute/windows_virtual_machine_resource.go @@ -186,6 +186,16 @@ func resourceWindowsVirtualMachine() *pluginsdk.Resource { }, }, + "disk_controller_type": { + Type: pluginsdk.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringInSlice([]string{ + string(compute.DiskControllerTypesNVMe), + string(compute.DiskControllerTypesSCSI), + }, false), + }, + "edge_zone": commonschema.EdgeZoneOptionalForceNew(), // TODO 4.0: change this from enable_* to *_enabled @@ -347,6 +357,8 @@ func resourceWindowsVirtualMachine() *pluginsdk.Resource { "tags": tags.Schema(), + "os_image_notification": virtualMachineOsImageNotificationSchema(), + "termination_notification": virtualMachineTerminationNotificationSchema(), "timezone": { @@ -365,6 +377,12 @@ func resourceWindowsVirtualMachine() *pluginsdk.Resource { ValidateFunc: commonids.ValidateVirtualMachineScaleSetID, }, + "vm_agent_platform_updates_enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: false, + }, + "platform_fault_domain": { Type: pluginsdk.TypeInt, Optional: true, @@ -502,6 +520,8 @@ func resourceWindowsVirtualMachineCreate(d *pluginsdk.ResourceData, meta interfa sourceImageId := d.Get("source_image_id").(string) sourceImageReference := expandSourceImageReference(sourceImageReferenceRaw, sourceImageId) + vmAgentPlatformUpdatesEnabled := d.Get("vm_agent_platform_updates_enabled").(bool) + winRmListenersRaw := d.Get("winrm_listener").(*pluginsdk.Set).List() winRmListeners := expandWinRMListener(winRmListenersRaw) @@ -524,9 +544,10 @@ func resourceWindowsVirtualMachineCreate(d *pluginsdk.ResourceData, meta interfa ComputerName: utils.String(computerName), AllowExtensionOperations: utils.Bool(allowExtensionOperations), WindowsConfiguration: &compute.WindowsConfiguration{ - ProvisionVMAgent: utils.Bool(provisionVMAgent), - EnableAutomaticUpdates: utils.Bool(enableAutomaticUpdates), - WinRM: winRmListeners, + ProvisionVMAgent: utils.Bool(provisionVMAgent), + EnableAutomaticUpdates: utils.Bool(enableAutomaticUpdates), + EnableVMAgentPlatformUpdates: utils.Bool(vmAgentPlatformUpdatesEnabled), + WinRM: winRmListeners, }, Secrets: secrets, }, @@ -551,6 +572,10 @@ func resourceWindowsVirtualMachineCreate(d *pluginsdk.ResourceData, meta interfa Tags: tags.Expand(t), } + if diskControllerType, ok := d.GetOk("disk_controller_type"); ok { + params.StorageProfile.DiskControllerType = compute.DiskControllerTypes(diskControllerType.(string)) + } + if !provisionVMAgent && allowExtensionOperations { return fmt.Errorf("`allow_extension_operations` cannot be set to `true` when `provision_vm_agent` is set to `false`") } @@ -753,8 +778,22 @@ func resourceWindowsVirtualMachineCreate(d *pluginsdk.ResourceData, meta interfa params.PlatformFaultDomain = utils.Int32(int32(platformFaultDomain)) } + var osImageNotificationProfile *compute.OSImageNotificationProfile + var terminateNotificationProfile *compute.TerminateNotificationProfile + + if v, ok := d.GetOk("os_image_notification"); ok { + osImageNotificationProfile = expandOsImageNotificationProfile(v.([]interface{})) + } + if v, ok := d.GetOk("termination_notification"); ok { - params.VirtualMachineProperties.ScheduledEventsProfile = expandVirtualMachineScheduledEventsProfile(v.([]interface{})) + terminateNotificationProfile = expandTerminateNotificationProfile(v.([]interface{})) + } + + if terminateNotificationProfile != nil || osImageNotificationProfile != nil { + params.VirtualMachineProperties.ScheduledEventsProfile = &compute.ScheduledEventsProfile{ + OsImageNotificationProfile: osImageNotificationProfile, + TerminateNotificationProfile: terminateNotificationProfile, + } } if v, ok := d.GetOk("timezone"); ok { @@ -913,8 +952,8 @@ func resourceWindowsVirtualMachineRead(d *pluginsdk.ResourceData, meta interface } d.Set("enable_automatic_updates", config.EnableAutomaticUpdates) - d.Set("provision_vm_agent", config.ProvisionVMAgent) + d.Set("vm_agent_platform_updates_enabled", config.EnableVMAgentPlatformUpdates) assessmentMode := string(compute.WindowsPatchAssessmentModeImageDefault) bypassPlatformSafetyChecksOnUserScheduleEnabled := false @@ -961,6 +1000,8 @@ func resourceWindowsVirtualMachineRead(d *pluginsdk.ResourceData, meta interface d.Set("proximity_placement_group_id", proximityPlacementGroupId) if profile := props.StorageProfile; profile != nil { + d.Set("disk_controller_type", string(props.StorageProfile.DiskControllerType)) + // the storage_account_type isn't returned so we need to look it up flattenedOSDisk, err := flattenVirtualMachineOSDisk(ctx, disksClient, profile.OsDisk) if err != nil { @@ -988,7 +1029,11 @@ func resourceWindowsVirtualMachineRead(d *pluginsdk.ResourceData, meta interface } if scheduleProfile := props.ScheduledEventsProfile; scheduleProfile != nil { - if err := d.Set("termination_notification", flattenVirtualMachineScheduledEventsProfile(scheduleProfile)); err != nil { + if err := d.Set("os_image_notification", flattenOsImageNotificationProfile(scheduleProfile.OsImageNotificationProfile)); err != nil { + return fmt.Errorf("setting `termination_notification`: %+v", err) + } + + if err := d.Set("termination_notification", flattenTerminateNotificationProfile(scheduleProfile.TerminateNotificationProfile)); err != nil { return fmt.Errorf("setting `termination_notification`: %+v", err) } } @@ -1115,6 +1160,19 @@ func resourceWindowsVirtualMachineUpdate(d *pluginsdk.ResourceData, meta interfa update.OsProfile.AllowExtensionOperations = utils.Bool(allowExtensionOperations) } + if d.HasChange("vm_agent_platform_updates_enabled") { + shouldUpdate = true + if update.OsProfile == nil { + update.OsProfile = &compute.OSProfile{} + } + + if update.OsProfile.WindowsConfiguration == nil { + update.OsProfile.WindowsConfiguration = &compute.WindowsConfiguration{} + } + + update.OsProfile.WindowsConfiguration.EnableVMAgentPlatformUpdates = utils.Bool(d.Get("vm_agent_platform_updates_enabled").(bool)) + } + if d.HasChange("patch_mode") { shouldUpdate = true @@ -1336,6 +1394,17 @@ func resourceWindowsVirtualMachineUpdate(d *pluginsdk.ResourceData, meta interfa } } + if d.HasChange("disk_controller_type") { + shouldUpdate = true + shouldDeallocate = true + + if update.VirtualMachineProperties.StorageProfile == nil { + update.VirtualMachineProperties.StorageProfile = &compute.StorageProfile{} + } + + update.VirtualMachineProperties.StorageProfile.DiskControllerType = compute.DiskControllerTypes(d.Get("disk_controller_type").(string)) + } + if d.HasChange("os_disk") { shouldUpdate = true @@ -1349,9 +1418,11 @@ func resourceWindowsVirtualMachineUpdate(d *pluginsdk.ResourceData, meta interfa return fmt.Errorf("expanding `os_disk`: %+v", err) } - update.VirtualMachineProperties.StorageProfile = &compute.StorageProfile{ - OsDisk: osDisk, + if update.VirtualMachineProperties.StorageProfile == nil { + update.VirtualMachineProperties.StorageProfile = &compute.StorageProfile{} } + + update.VirtualMachineProperties.StorageProfile.OsDisk = osDisk } if d.HasChange("virtual_machine_scale_set_id") { @@ -1432,11 +1503,24 @@ func resourceWindowsVirtualMachineUpdate(d *pluginsdk.ResourceData, meta interfa update.Tags = tags.Expand(tagsRaw) } + var osImageNotificationProfile *compute.OSImageNotificationProfile + var terminateNotificationProfile *compute.TerminateNotificationProfile + + if d.HasChange("os_image_notification") { + shouldUpdate = true + osImageNotificationProfile = expandOsImageNotificationProfile(d.Get("os_image_notification").([]interface{})) + } + if d.HasChange("termination_notification") { shouldUpdate = true + terminateNotificationProfile = expandTerminateNotificationProfile(d.Get("termination_notification").([]interface{})) + } - notificationRaw := d.Get("termination_notification").([]interface{}) - update.ScheduledEventsProfile = expandVirtualMachineScheduledEventsProfile(notificationRaw) + if osImageNotificationProfile != nil || terminateNotificationProfile != nil { + update.ScheduledEventsProfile = &compute.ScheduledEventsProfile{ + OsImageNotificationProfile: osImageNotificationProfile, + TerminateNotificationProfile: terminateNotificationProfile, + } } if d.HasChange("additional_capabilities") { diff --git a/internal/services/compute/windows_virtual_machine_resource_disk_os_test.go b/internal/services/compute/windows_virtual_machine_resource_disk_os_test.go index 3313a410a927f..939c0d7f6a4d3 100644 --- a/internal/services/compute/windows_virtual_machine_resource_disk_os_test.go +++ b/internal/services/compute/windows_virtual_machine_resource_disk_os_test.go @@ -300,6 +300,35 @@ func TestAccWindowsVirtualMachine_diskOSStorageTypeUpdate(t *testing.T) { }) } +func TestAccWindowsVirtualMachine_diskOSControllerType(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_windows_virtual_machine", "test") + r := WindowsVirtualMachineResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.diskOSControllerTypeNVMe(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("admin_password"), + { + Config: r.diskOSControllerTypeSCSI(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("admin_password"), + { + Config: r.diskOSControllerTypeNVMe(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("admin_password"), + }) +} + func TestAccWindowsVirtualMachine_diskOSWriteAcceleratorEnabled(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_windows_virtual_machine", "test") r := WindowsVirtualMachineResource{} @@ -853,6 +882,70 @@ func (r WindowsVirtualMachineResource) diskOSStorageAccountTypeWithRestrictedLoc return r.diskOSStorageAccountType(data, accountType) } +func (r WindowsVirtualMachineResource) diskOSControllerTypeSCSI(data acceptance.TestData) string { + 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_E2bds_v5" + admin_username = "adminuser" + admin_password = "P@$$w0rd1234!" + disk_controller_type = "SCSI" + + 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 = "2022-datacenter-azure-edition" + version = "latest" + } +} +`, r.template(data)) +} + +func (r WindowsVirtualMachineResource) diskOSControllerTypeNVMe(data acceptance.TestData) string { + 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_E2bds_v5" + admin_username = "adminuser" + admin_password = "P@$$w0rd1234!" + disk_controller_type = "NVMe" + + 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 = "2022-datacenter-azure-edition" + version = "latest" + } +} +`, r.template(data)) +} + func (r WindowsVirtualMachineResource) diskOSWriteAcceleratorEnabled(data acceptance.TestData, enabled bool) string { return fmt.Sprintf(` %s 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 ac3b12fe5526d..3affe71faee84 100644 --- a/internal/services/compute/windows_virtual_machine_resource_other_test.go +++ b/internal/services/compute/windows_virtual_machine_resource_other_test.go @@ -86,6 +86,30 @@ func TestAccWindowsVirtualMachine_otherPatchModeUpdate(t *testing.T) { }) } +func TestAccWindowsVirtualMachine_otherVmAgentPlatformUpdates(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_windows_virtual_machine", "test") + r := WindowsVirtualMachineResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.otherVmAgentPlatformUpdatesEnabled(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("vm_agent_platform_updates_enabled").HasValue("true"), + ), + }, + data.ImportStep("admin_password"), + { + Config: r.otherVmAgentPlatformUpdatesDisabled(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("vm_agent_platform_updates_enabled").HasValue("false"), + ), + }, + data.ImportStep("admin_password"), + }) +} + func TestAccWindowsVirtualMachine_otherPatchAssessmentModeDefault(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_windows_virtual_machine", "test") r := WindowsVirtualMachineResource{} @@ -714,6 +738,37 @@ func TestAccWindowsVirtualMachine_otherTags(t *testing.T) { }) } +func TestAccWindowsVirtualMachine_otherOsImageNotification(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_windows_virtual_machine", "test") + r := WindowsVirtualMachineResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.otherOsImageNotification(data, true), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("os_image_notification.#").HasValue("1"), + ), + }, + data.ImportStep("admin_password"), + { + Config: r.otherOsImageNotification(data, false), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("admin_password"), + { + Config: r.otherOsImageNotification(data, true), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("os_image_notification.#").HasValue("1"), + ), + }, + data.ImportStep("admin_password"), + }) +} + func TestAccWindowsVirtualMachine_otherTerminationNotification(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_windows_virtual_machine", "test") r := WindowsVirtualMachineResource{} @@ -1243,7 +1298,7 @@ resource "azurerm_windows_virtual_machine" "test" { `, r.template(data), patchMode) } -func (r WindowsVirtualMachineResource) otherPatchModeManual(data acceptance.TestData) string { +func (r WindowsVirtualMachineResource) otherVmAgentPlatformUpdatesEnabled(data acceptance.TestData) string { return fmt.Sprintf(` %s @@ -1271,8 +1326,40 @@ resource "azurerm_windows_virtual_machine" "test" { version = "latest" } - enable_automatic_updates = false - patch_mode = "Manual" + vm_agent_platform_updates_enabled = true +} +`, r.template(data)) +} + +func (r WindowsVirtualMachineResource) otherVmAgentPlatformUpdatesDisabled(data acceptance.TestData) string { + 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" + } + + vm_agent_platform_updates_enabled = false } `, r.template(data)) } @@ -1343,6 +1430,40 @@ resource "azurerm_windows_virtual_machine" "test" { `, r.template(data)) } +func (r WindowsVirtualMachineResource) otherPatchModeManual(data acceptance.TestData) string { + 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" + } + + enable_automatic_updates = false + patch_mode = "Manual" +} +`, r.template(data)) +} + func (r WindowsVirtualMachineResource) otherPatchAssessmentModeDefault(data acceptance.TestData) string { return fmt.Sprintf(` %s @@ -1968,10 +2089,12 @@ resource "azurerm_windows_virtual_machine" "test" { } gallery_application { - version_id = azurerm_gallery_application_version.test2.id - order = 2 - configuration_blob_uri = azurerm_storage_blob.test2.id - tag = "app2" + version_id = azurerm_gallery_application_version.test2.id + automatic_upgrade_enabled = true + order = 2 + configuration_blob_uri = azurerm_storage_blob.test2.id + tag = "app2" + treat_failure_as_deployment_failure_enabled = true } } `, r.otherGalleryApplicationTemplate(data)) @@ -2065,8 +2188,8 @@ resource "azurerm_gallery_application_version" "test" { } manage_action { - install = "[install command]" - remove = "[remove command]" + install = "echo install" + remove = "echo remove" } target_region { @@ -2094,8 +2217,8 @@ resource "azurerm_gallery_application_version" "test2" { } manage_action { - install = "[install command]" - remove = "[remove command]" + install = "echo install" + remove = "echo remove" } target_region { @@ -2773,6 +2896,43 @@ resource "azurerm_windows_virtual_machine" "test" { `, r.template(data)) } +func (r WindowsVirtualMachineResource) otherOsImageNotification(data acceptance.TestData, enabled bool) string { + osImageNotificationConfig := "" + if enabled { + osImageNotificationConfig = "os_image_notification {}" + } + + 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" + } + + %s +} +`, r.template(data), osImageNotificationConfig) +} + func (r WindowsVirtualMachineResource) otherTerminationNotification(data acceptance.TestData, enabled bool) 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 8a99b4eb07989..6f49ac6c7cce2 100644 --- a/website/docs/r/linux_virtual_machine.html.markdown +++ b/website/docs/r/linux_virtual_machine.html.markdown @@ -148,6 +148,8 @@ The following arguments are supported: -> **NOTE:** When an `admin_password` is specified `disable_password_authentication` must be set to `false`. +* `disk_controller_type` - (Optional) Specifies the Disk Controller Type used for this Virtual Machine. Possible values are `SCSI` and `NVMe`. + * `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? @@ -204,10 +206,14 @@ The following arguments are supported: * `tags` - (Optional) A mapping of tags which should be assigned to this Virtual Machine. +* `os_image_notification` - (Optional) A `os_image_notification` block as defined below. + * `termination_notification` - (Optional) A `termination_notification` block as defined below. * `user_data` - (Optional) The Base64-Encoded User Data which should be used for this Virtual Machine. +* `vm_agent_platform_updates_enabled` - (Optional) Specifies whether VMAgent Platform Updates is enabled. Defaults to `false`. + * `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. @@ -264,12 +270,16 @@ A `gallery_application` block supports the following: * `version_id` - (Required) Specifies the Gallery Application Version resource ID. +* `automatic_upgrade_enabled` - (Optional) Specifies whether the version will be automatically updated for the VM when a new Gallery Application version is available in PIR/SIG. Defaults to `false`. + * `configuration_blob_uri` - (Optional) Specifies the URI to an Azure Blob that will replace the default configuration for the package if provided. * `order` - (Optional) Specifies the order in which the packages have to be installed. Possible values are between `0` and `2,147,483,647`. * `tag` - (Optional) Specifies a passthrough value for more generic context. This field can be any valid `string` value. +* `treat_failure_as_deployment_failure_enabled` - (Optional) Specifies whether any failure for any operation in the VmApplication will fail the deployment of the VM. Defaults to `false`. + --- An `identity` block supports the following: @@ -348,6 +358,12 @@ The `source_image_reference` block supports the following: --- +A `os_image_notification` block supports the following: + +* `timeout` - (Optional) Length of time a notification to be sent to the VM on the instance metadata server till the VM gets OS upgraded. The only possible value is `PT15M`. Defaults to `PT15M`. + +--- + A `termination_notification` block supports the following: * `enabled` - (Required) Should the termination notification be enabled on this Virtual Machine? diff --git a/website/docs/r/windows_virtual_machine.html.markdown b/website/docs/r/windows_virtual_machine.html.markdown index e859c5f0aa24c..1aa2daca460af 100644 --- a/website/docs/r/windows_virtual_machine.html.markdown +++ b/website/docs/r/windows_virtual_machine.html.markdown @@ -137,6 +137,8 @@ The following arguments are supported: * `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. +* `disk_controller_type` - (Optional) Specifies the Disk Controller Type used for this Virtual Machine. Possible values are `SCSI` and `NVMe`. + * `enable_automatic_updates` - (Optional) Specifies if Automatic Updates are Enabled for the Windows Virtual Machine. Changing this forces a new resource to be created. 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? @@ -199,6 +201,8 @@ The following arguments are supported: * `tags` - (Optional) A mapping of tags which should be assigned to this Virtual Machine. +* `os_image_notification` - (Optional) A `os_image_notification` block as defined below. + * `termination_notification` - (Optional) A `termination_notification` block as defined below. * `timezone` - (Optional) Specifies the Time Zone which should be used by the Virtual Machine, [the possible values are defined here](https://jackstromberg.com/2017/01/list-of-time-zones-consumed-by-azure/). Changing this forces a new resource to be created. @@ -211,6 +215,8 @@ The following arguments are supported: ~> **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). +* `vm_agent_platform_updates_enabled` - (Optional) Specifies whether VMAgent Platform Updates is enabled. Defaults to `false`. + * `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. * `winrm_listener` - (Optional) One or more `winrm_listener` blocks as defined below. Changing this forces a new resource to be created. @@ -263,12 +269,16 @@ A `gallery_application` block supports the following: * `version_id` - (Required) Specifies the Gallery Application Version resource ID. +* `automatic_upgrade_enabled` - (Optional) Specifies whether the version will be automatically updated for the VM when a new Gallery Application version is available in PIR/SIG. Defaults to `false`. + * `configuration_blob_uri` - (Optional) Specifies the URI to an Azure Blob that will replace the default configuration for the package if provided. * `order` - (Optional) Specifies the order in which the packages have to be installed. Possible values are between `0` and `2,147,483,647`. * `tag` - (Optional) Specifies a passthrough value for more generic context. This field can be any valid `string` value. +* `treat_failure_as_deployment_failure_enabled` - (Optional) Specifies whether any failure for any operation in the VmApplication will fail the deployment of the VM. Defaults to `false`. + --- An `identity` block supports the following: @@ -349,6 +359,12 @@ The `source_image_reference` block supports the following: --- +A `os_image_notification` block supports the following: + +* `timeout` - (Optional) Length of time a notification to be sent to the VM on the instance metadata server till the VM gets OS upgraded. The only possible value is `PT15M`. Defaults to `PT15M`. + +--- + A `termination_notification` block supports the following: * `enabled` - (Required) Should the termination notification be enabled on this Virtual Machine?