diff --git a/internal/services/compute/orchestrated_virtual_machine_scale_set_other_resource_test.go b/internal/services/compute/orchestrated_virtual_machine_scale_set_other_resource_test.go index 84dc13cf5d33..fafee7917ae7 100644 --- a/internal/services/compute/orchestrated_virtual_machine_scale_set_other_resource_test.go +++ b/internal/services/compute/orchestrated_virtual_machine_scale_set_other_resource_test.go @@ -268,6 +268,28 @@ func TestAccOrchestratedVirtualMachineScaleSet_otherVMAgentDisabledWithExtension }) } +func TestAccOrchestratedVirtualMachineScaleSet_otherUserData(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_orchestrated_virtual_machine_scale_set", "test") + r := OrchestratedVirtualMachineScaleSetResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.otherUserData(data, "Hello World"), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("os_profile.0.linux_configuration.0.admin_password"), + { + Config: r.otherUserData(data, "Goodbye World"), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("os_profile.0.linux_configuration.0.admin_password"), + }) +} + func TestAccOrchestratedVirtualMachineScaleSet_otherSinglePlacementGroup(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_orchestrated_virtual_machine_scale_set", "test") r := OrchestratedVirtualMachineScaleSetResource{} @@ -1140,6 +1162,87 @@ resource "azurerm_orchestrated_virtual_machine_scale_set" "test" { `, data.RandomInteger, data.Locations.Primary, r.natgateway_template(data)) } +func (OrchestratedVirtualMachineScaleSetResource) otherUserData(data acceptance.TestData, userData string) string { + r := OrchestratedVirtualMachineScaleSetResource{} + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-OVMSS-%[1]d" + location = "%[2]s" +} + +%[3]s + +resource "azurerm_user_assigned_identity" "test" { + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + + name = "acctest%[4]s" +} + +resource "azurerm_orchestrated_virtual_machine_scale_set" "test" { + name = "acctestOVMSS-%[1]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + + zones = [] + + sku_name = "Standard_D1_v2" + instances = 1 + + platform_fault_domain_count = 2 + + os_profile { + linux_configuration { + computer_name_prefix = "testvm-%[1]d" + admin_username = "myadmin" + admin_password = "Passwword1234" + + disable_password_authentication = false + } + } + + network_interface { + name = "TestNetworkProfile-%[1]d" + primary = true + + ip_configuration { + name = "TestIPConfiguration" + primary = true + subnet_id = azurerm_subnet.test.id + + public_ip_address { + name = "TestPublicIPConfiguration" + domain_name_label = "test-domain-label" + idle_timeout_in_minutes = 4 + } + } + } + + os_disk { + storage_account_type = "Standard_LRS" + caching = "ReadWrite" + } + + source_image_reference { + publisher = "Canonical" + offer = "UbuntuServer" + sku = "16.04-LTS" + version = "latest" + } + + user_data_base64 = base64encode("%[5]s") + + tags = { + "platformsettings.host_environment.service.platform_optedin_for_rootcerts" = "true" + } +} +`, data.RandomInteger, data.Locations.Primary, r.natgateway_template(data), data.RandomString, userData) +} + func (OrchestratedVirtualMachineScaleSetResource) otherCapacityReservationGroupId(data acceptance.TestData) string { r := OrchestratedVirtualMachineScaleSetResource{} return fmt.Sprintf(` diff --git a/internal/services/compute/orchestrated_virtual_machine_scale_set_resource.go b/internal/services/compute/orchestrated_virtual_machine_scale_set_resource.go index e4b81f6ae97e..4f169fc695eb 100644 --- a/internal/services/compute/orchestrated_virtual_machine_scale_set_resource.go +++ b/internal/services/compute/orchestrated_virtual_machine_scale_set_resource.go @@ -248,6 +248,13 @@ func resourceOrchestratedVirtualMachineScaleSet() *pluginsdk.Resource { Type: pluginsdk.TypeString, Computed: true, }, + + "user_data_base64": { + Type: pluginsdk.TypeString, + Optional: true, + Sensitive: true, + ValidateFunc: validation.StringIsBase64, + }, }, } } @@ -377,6 +384,10 @@ func resourceOrchestratedVirtualMachineScaleSetCreate(d *pluginsdk.ResourceData, virtualMachineProfile.StorageProfile.ImageReference = sourceImageReference } + if userData, ok := d.GetOk("user_data_base64"); ok { + virtualMachineProfile.UserData = utils.String(userData.(string)) + } + osType := compute.OperatingSystemTypesWindows var winConfigRaw []interface{} var linConfigRaw []interface{} @@ -1062,6 +1073,11 @@ func resourceOrchestratedVirtualMachineScaleSetUpdate(d *pluginsdk.ResourceData, update.Tags = tags.Expand(d.Get("tags").(map[string]interface{})) } + if d.HasChange("user_data_base64") { + updateInstances = true + updateProps.VirtualMachineProfile.UserData = utils.String(d.Get("user_data_base64").(string)) + } + update.VirtualMachineScaleSetUpdateProperties = &updateProps if updateInstances { @@ -1266,6 +1282,7 @@ func resourceOrchestratedVirtualMachineScaleSetRead(d *pluginsdk.ResourceData, m encryptionAtHostEnabled = *profile.SecurityProfile.EncryptionAtHost } d.Set("encryption_at_host_enabled", encryptionAtHostEnabled) + d.Set("user_data_base64", profile.UserData) } d.Set("extension_operations_enabled", extensionOperationsEnabled) diff --git a/website/docs/r/orchestrated_virtual_machine_scale_set.html.markdown b/website/docs/r/orchestrated_virtual_machine_scale_set.html.markdown index a8c8a0177fff..ec1c38e02dca 100644 --- a/website/docs/r/orchestrated_virtual_machine_scale_set.html.markdown +++ b/website/docs/r/orchestrated_virtual_machine_scale_set.html.markdown @@ -101,6 +101,8 @@ resource "azurerm_orchestrated_virtual_machine_scale_set" "example" { * `termination_notification` - (Optional) A `termination_notification` block as defined below. +* `user_data_base64` - (Optional) The Base64-Encoded User Data which should be used for this Virtual Machine Scale Set. + * `proximity_placement_group_id` - (Optional) The ID of the Proximity Placement Group which the Orchestrated Virtual Machine should be assigned to. Changing this forces a new resource to be created. * `zones` - (Optional) Specifies a list of Availability Zones in which this Orchestrated Virtual Machine should be located. Changing this forces a new Orchestrated Virtual Machine to be created.