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

azurerm_windows_virtual_machine_scale_set/azurerm_linux_virtual_machine_scale_set - define Hash function for extension block to ignore protected_setting #13440

Merged
merged 8 commits into from
Sep 24, 2021
Original file line number Diff line number Diff line change
Expand Up @@ -523,7 +523,7 @@ func TestAccLinuxVirtualMachineScaleSet_otherEncryptionAtHost(t *testing.T) {
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep("admin_password", "extension.0.protected_settings"),
data.ImportStep("admin_password"),
})
}

Expand All @@ -538,21 +538,21 @@ func TestAccLinuxVirtualMachineScaleSet_otherEncryptionAtHostUpdate(t *testing.T
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep("admin_password", "extension.0.protected_settings"),
data.ImportStep("admin_password"),
{
Config: r.otherEncryptionAtHost(data, false),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep("admin_password", "extension.0.protected_settings"),
data.ImportStep("admin_password"),
{
Config: r.otherEncryptionAtHost(data, true),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep("admin_password", "extension.0.protected_settings"),
data.ImportStep("admin_password"),
})
}

Expand All @@ -567,7 +567,7 @@ func TestAccLinuxVirtualMachineScaleSet_otherEncryptionAtHostWithCMK(t *testing.
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep("admin_password", "extension.0.protected_settings"),
data.ImportStep("admin_password"),
})
}

Expand All @@ -582,7 +582,7 @@ func TestAccLinuxVirtualMachineScaleSet_otherPlatformFaultDomainCount(t *testing
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep("admin_password", "extension.0.protected_settings"),
data.ImportStep("admin_password"),
})
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func (r LinuxVirtualMachineScaleSetResource) Exists(ctx context.Context, clients

resp, err := clients.Compute.VMScaleSetClient.Get(ctx, id.ResourceGroup, id.Name)
if err != nil {
return nil, fmt.Errorf("retrieving Compute Linux Virtual Machine Scale Set %q", id)
return nil, fmt.Errorf("retrieving Compute Linux Virtual Machine Scale Set %q: %+v", id, err)
}

return utils.Bool(resp.ID != nil), nil
Expand Down
77 changes: 71 additions & 6 deletions internal/services/compute/virtual_machine_scale_set.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package compute

import (
"bytes"
"fmt"

"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2020-12-01/compute"
Expand Down Expand Up @@ -1553,13 +1554,61 @@ func VirtualMachineScaleSetExtensionsSchema() *pluginsdk.Schema {
},
},
},
Set: virtualMachineScaleSetExtensionHash,
}
}

func virtualMachineScaleSetExtensionHash(v interface{}) int {
var buf bytes.Buffer

if m, ok := v.(map[string]interface{}); ok {
buf.WriteString(fmt.Sprintf("%s-", m["name"].(string)))
buf.WriteString(fmt.Sprintf("%s-", m["publisher"].(string)))
buf.WriteString(fmt.Sprintf("%s-", m["type"].(string)))
buf.WriteString(fmt.Sprintf("%s-", m["type_handler_version"].(string)))
buf.WriteString(fmt.Sprintf("%t-", m["auto_upgrade_minor_version"].(bool)))

if v, ok = m["force_update_tag"]; ok {
buf.WriteString(fmt.Sprintf("%s-", v))
}

if v, ok := m["provision_after_extensions"]; ok {
buf.WriteString(fmt.Sprintf("%s-", v))
}

// we need to ensure the whitespace is consistent
settings := m["settings"].(string)
if settings != "" {
expandedSettings, err := pluginsdk.ExpandJsonFromString(settings)
if err == nil {
serializedSettings, err := pluginsdk.FlattenJsonToString(expandedSettings)
if err == nil {
buf.WriteString(fmt.Sprintf("%s-", serializedSettings))
}
}
}

if v, ok := m["protected_settings"]; ok {
settings := v.(string)
if settings != "" {
expandedSettings, err := pluginsdk.ExpandJsonFromString(settings)
if err == nil {
serializedSettings, err := pluginsdk.FlattenJsonToString(expandedSettings)
if err == nil {
buf.WriteString(fmt.Sprintf("%s-", serializedSettings))
}
}
}
}
}

return pluginsdk.HashString(buf.String())
}

func expandVirtualMachineScaleSetExtensions(input []interface{}) (extensionProfile *compute.VirtualMachineScaleSetExtensionProfile, hasHealthExtension bool, err error) {
extensionProfile = &compute.VirtualMachineScaleSetExtensionProfile{}
if len(input) == 0 {
return nil, false, nil
return extensionProfile, false, nil
}

extensions := make([]compute.VirtualMachineScaleSetExtension, 0)
Expand Down Expand Up @@ -1616,7 +1665,21 @@ func flattenVirtualMachineScaleSetExtensions(input *compute.VirtualMachineScaleS
return result, nil
}

for k, v := range *input.Extensions {
// extensionsFromState holds the "extension" block, which is used to retrieve the "protected_settings" to fill it back the state,
// since it is not returned from the API.
extensionsFromState := map[string]map[string]interface{}{}
if extSet, ok := d.GetOk("extension"); ok && extSet != nil {
extensions := extSet.(*pluginsdk.Set).List()
for _, ext := range extensions {
if ext == nil {
continue
}
ext := ext.(map[string]interface{})
extensionsFromState[ext["name"].(string)] = ext
}
}

for _, v := range *input.Extensions {
name := ""
if v.Name != nil {
name = *v.Name
Expand Down Expand Up @@ -1664,10 +1727,12 @@ func flattenVirtualMachineScaleSetExtensions(input *compute.VirtualMachineScaleS
extSettings = extSettingsRaw
}
}
// protected_settings isn't returned, so we attempt to get it from config otherwise set to empty string
if protectedSettingsFromConfig, ok := d.GetOk(fmt.Sprintf("extension.%d.protected_settings", k)); ok {
if protectedSettingsFromConfig.(string) != "" && protectedSettingsFromConfig.(string) != "{}" {
protectedSettings = protectedSettingsFromConfig.(string)
// protected_settings isn't returned, so we attempt to get it from state otherwise set to empty string
if ext, ok := extensionsFromState[name]; ok {
if protectedSettingsFromState, ok := ext["protected_settings"]; ok {
if protectedSettingsFromState.(string) != "" && protectedSettingsFromState.(string) != "{}" {
protectedSettings = protectedSettingsFromState.(string)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ func TestAccWindowsVirtualMachineScaleSet_extensionMultiple(t *testing.T) {
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep("admin_password", "extension.0.protected_settings"),
data.ImportStep("admin_password", "extension.0.protected_settings", "extension.1.protected_settings"),
})
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -629,7 +629,7 @@ func TestAccWindowsVirtualMachineScaleSet_otherEncryptionAtHostEnabled(t *testin
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep("admin_password", "extension.0.protected_settings"),
data.ImportStep("admin_password"),
})
}

Expand All @@ -644,21 +644,21 @@ func TestAccWindowsVirtualMachineScaleSet_otherEncryptionAtHostEnabledUpdate(t *
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep("admin_password", "extension.0.protected_settings"),
data.ImportStep("admin_password"),
{
Config: r.otherEncryptionAtHostEnabled(data, false),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep("admin_password", "extension.0.protected_settings"),
data.ImportStep("admin_password"),
{
Config: r.otherEncryptionAtHostEnabled(data, true),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep("admin_password", "extension.0.protected_settings"),
data.ImportStep("admin_password"),
})
}

Expand All @@ -673,7 +673,7 @@ func TestAccWindowsVirtualMachineScaleSet_otherEncryptionAtHostEnabledWithCMK(t
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep("admin_password", "extension.0.protected_settings"),
data.ImportStep("admin_password"),
})
}

Expand All @@ -688,7 +688,7 @@ func TestAccWindowsVirtualMachineScaleSet_otherPlatformFaultDomainCount(t *testi
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep("admin_password", "extension.0.protected_settings"),
data.ImportStep("admin_password"),
})
}

Expand Down