Skip to content

Commit

Permalink
#24282: Support additional_unattend_content part of azurerm_orchestra… (
Browse files Browse the repository at this point in the history
#24292)

* #24282: Support additional_unattend_content part of azurerm_orchestrated_virtual_machine_scale_set

* #24282: Changes as per review

* #24282: Fix errors and tests

* #24282: terrafmt
  • Loading branch information
harshavmb committed Feb 15, 2024
1 parent 0f6bf3d commit 38a7350
Show file tree
Hide file tree
Showing 3 changed files with 157 additions and 41 deletions.
94 changes: 53 additions & 41 deletions internal/services/compute/orchestrated_virtual_machine_scale_set.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,7 @@ func OrchestratedVirtualMachineScaleSetWindowsConfigurationSchema() *pluginsdk.S

"computer_name_prefix": computerPrefixWindowsSchema(),

// I am only commenting this out as this is going to be supported in the next release of the API in October 2021
// "additional_unattend_content": additionalUnattendContentSchema(),
"additional_unattend_content": additionalUnattendContentSchema(),

// TODO 4.0: change this from enable_* to *_enabled
"enable_automatic_updates": {
Expand Down Expand Up @@ -930,8 +929,9 @@ func expandOrchestratedVirtualMachineScaleSetOsProfileWithWindowsConfiguration(i
osProfile.Secrets = expandWindowsSecrets(secrets)
}

// I am only commenting this out as this is going to be supported in the next release of the API in October 2021
// winConfig.AdditionalUnattendContent = expandWindowsConfigurationAdditionalUnattendContent(input["additional_unattend_content"].([]interface{}))
if additionalUnattendContents := input["additional_unattend_content"].([]interface{}); len(additionalUnattendContents) > 0 {
winConfig.AdditionalUnattendContent = expandWindowsConfigurationAdditionalUnattendContent(input["additional_unattend_content"].([]interface{}))
}
winConfig.EnableAutomaticUpdates = utils.Bool(input["enable_automatic_updates"].(bool))
winConfig.ProvisionVMAgent = utils.Bool(input["provision_vm_agent"].(bool))
winRmListenersRaw := input["winrm_listener"].(*pluginsdk.Set).List()
Expand Down Expand Up @@ -998,25 +998,24 @@ func expandOrchestratedVirtualMachineScaleSetOsProfileWithLinuxConfiguration(inp
return &osProfile
}

// I am only commenting this out as this is going to be supported in the next release of the API version 2021-10-01
// func expandWindowsConfigurationAdditionalUnattendContent(input []interface{}) *[]compute.AdditionalUnattendContent {
// output := make([]compute.AdditionalUnattendContent, 0)
func expandWindowsConfigurationAdditionalUnattendContent(input []interface{}) *[]compute.AdditionalUnattendContent {
output := make([]compute.AdditionalUnattendContent, 0)

// for _, v := range input {
// raw := v.(map[string]interface{})
for _, v := range input {
raw := v.(map[string]interface{})

// output = append(output, compute.AdditionalUnattendContent{
// SettingName: compute.SettingNames(raw["setting"].(string)),
// Content: utils.String(raw["content"].(string)),
output = append(output, compute.AdditionalUnattendContent{
SettingName: compute.SettingNames(raw["setting"].(string)),
Content: utils.String(raw["content"].(string)),

// // no other possible values
// PassName: compute.PassNamesOobeSystem,
// ComponentName: compute.ComponentNamesMicrosoftWindowsShellSetup,
// })
// }
// no other possible values
PassName: compute.PassNamesOobeSystem,
ComponentName: compute.ComponentNamesMicrosoftWindowsShellSetup,
})
}

// return &output
// }
return &output
}

func ExpandOrchestratedVirtualMachineScaleSetNetworkInterface(input []interface{}) (*[]compute.VirtualMachineScaleSetNetworkConfiguration, error) {
output := make([]compute.VirtualMachineScaleSetNetworkConfiguration, 0)
Expand Down Expand Up @@ -1703,10 +1702,9 @@ func flattenOrchestratedVirtualMachineScaleSetWindowsConfiguration(input *comput
output["computer_name_prefix"] = *v
}

// I am only commenting this out as this is going to be supported in the next release of the API in October 2021
// if v := winConfig.AdditionalUnattendContent; v != nil {
// output["additional_unattend_content"] = flattenWindowsConfigurationAdditionalUnattendContent(winConfig)
// }
if v := winConfig.AdditionalUnattendContent; v != nil {
output["additional_unattend_content"] = flattenWindowsConfigurationAdditionalUnattendContent(winConfig, d)
}

if v := winConfig.EnableAutomaticUpdates; v != nil {
output["enable_automatic_updates"] = *v
Expand Down Expand Up @@ -1909,24 +1907,38 @@ func FlattenOrchestratedVirtualMachineScaleSetDataDisk(input *[]compute.VirtualM
return output
}

// I am only commenting this out as this is going to be supported in the next release of the API in October 2021
// func flattenWindowsConfigurationAdditionalUnattendContent(input *compute.WindowsConfiguration) []interface{} {
// if input == nil {
// return []interface{}{}
// }

// output := make([]interface{}, 0)
// for _, v := range *input.AdditionalUnattendContent {
// // content isn't returned by the API since it's sensitive data so we need to look it up later
// // where we can pull it out of the state file.
// output = append(output, map[string]interface{}{
// "content": "",
// "setting": string(v.SettingName),
// })
// }

// return output
// }
func flattenWindowsConfigurationAdditionalUnattendContent(input *compute.WindowsConfiguration, d *pluginsdk.ResourceData) []interface{} {
if input == nil {
return []interface{}{}
}

existing := make([]interface{}, 0)
if v, ok := d.GetOk("os_profile.0.windows_configuration.0.additional_unattend_content"); ok {
existing = v.([]interface{})
}

output := make([]interface{}, 0)
for i, v := range *input.AdditionalUnattendContent {
// content isn't returned by the API since it's sensitive data so we need to pull from the state file.
content := ""
if len(existing) > i {
existingVal := existing[i]
existingRaw, ok := existingVal.(map[string]interface{})
if ok {
contentRaw, ok := existingRaw["content"]
if ok {
content = contentRaw.(string)
}
}
}
output = append(output, map[string]interface{}{
"content": content,
"setting": string(v.SettingName),
})
}

return output
}

func FlattenOrchestratedVirtualMachineScaleSetOSDisk(input *compute.VirtualMachineScaleSetOSDisk) []interface{} {
if input == nil {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,21 @@ func TestAccOrchestratedVirtualMachineScaleSet_basicWindows(t *testing.T) {
})
}

func TestAccOrchestratedVirtualMachineScaleSet_otherAdditionalUnattendContent(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_orchestrated_virtual_machine_scale_set", "test")
r := OrchestratedVirtualMachineScaleSetResource{}

data.ResourceTest(t, r, []acceptance.TestStep{
{
Config: r.otherAdditionalUnattendContent(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
check.That(data.ResourceName).Key("os_profile.0.windows_configuration.0.additional_unattend_content.0.setting").HasValue("FirstLogonCommands"),
),
},
})
}

func TestAccOrchestratedVirtualMachineScaleSet_basicWindowsNoTimezone(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_orchestrated_virtual_machine_scale_set", "test")
r := OrchestratedVirtualMachineScaleSetResource{}
Expand Down Expand Up @@ -1000,6 +1015,85 @@ resource "azurerm_orchestrated_virtual_machine_scale_set" "test" {
winrm_listener {
protocol = "Http"
}
}
}
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 = "MicrosoftWindowsServer"
offer = "WindowsServer"
sku = "2016-Datacenter-Server-Core"
version = "latest"
}
}
`, data.RandomInteger, data.Locations.Primary, r.natgateway_template(data))
}

func (OrchestratedVirtualMachineScaleSetResource) otherAdditionalUnattendContent(data acceptance.TestData) 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_orchestrated_virtual_machine_scale_set" "test" {
name = "acctestOVMSS-%[1]d"
location = azurerm_resource_group.test.location
resource_group_name = azurerm_resource_group.test.name
sku_name = "Standard_D1_v2"
instances = 2
platform_fault_domain_count = 2
os_profile {
windows_configuration {
computer_name_prefix = "testvm"
admin_username = "myadmin"
admin_password = "Passwword1234"
enable_automatic_updates = true
provision_vm_agent = true
timezone = "W. Europe Standard Time"
winrm_listener {
protocol = "Http"
}
additional_unattend_content {
setting = "FirstLogonCommands"
content = "<FirstLogonCommands><SynchronousCommand><CommandLine>shutdown /r /t 0 /c \"initial reboot\"</CommandLine><Description>reboot</Description><Order>1</Order></SynchronousCommand></FirstLogonCommands>"
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,8 @@ A `windows_configuration` block supports the following:

* `winrm_listener` - (Optional) One or more `winrm_listener` blocks as defined below. Changing this forces a new resource to be created.

* `additional_unattend_content` - (Optional) One or more `additional_unattend_content` blocks as defined below. Changing this forces a new resource to be created.

---

A `linux_configuration` block supports the following:
Expand Down Expand Up @@ -211,6 +213,14 @@ A `secret` block supports the following:

---

An `additional_unattend_content` block supports the following:

* `content` - (Required) The XML formatted content that is added to the unattend.xml file for the specified path and component. Changing this forces a new resource to be created.

* `setting` - (Required) The name of the setting to which the content applies. Possible values are `AutoLogon` and `FirstLogonCommands`. Changing this forces a new resource to be created.

---

A (Windows) `certificate` block supports the following:

* `store` - (Required) The certificate store on the Virtual Machine where the certificate should be added.
Expand Down

0 comments on commit 38a7350

Please sign in to comment.