From 5892bc2849f64f736efa2e761dbbab9a96b4d8b8 Mon Sep 17 00:00:00 2001 From: Imanol Date: Fri, 22 Feb 2019 12:58:58 +0100 Subject: [PATCH 1/3] [ADD]: provisionAfterExtension field for chaining multiple extensions execution --- .../resource_arm_virtual_machine_scale_set.go | 34 +++++++++++++++++++ .../r/virtual_machine_scale_set.html.markdown | 1 + 2 files changed, 35 insertions(+) diff --git a/azurerm/resource_arm_virtual_machine_scale_set.go b/azurerm/resource_arm_virtual_machine_scale_set.go index f0f27b3b1ab0..bdfdd17d5729 100644 --- a/azurerm/resource_arm_virtual_machine_scale_set.go +++ b/azurerm/resource_arm_virtual_machine_scale_set.go @@ -714,6 +714,16 @@ func resourceArmVirtualMachineScaleSet() *schema.Resource { Optional: true, }, + "provision_after_extensions": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validate.NoEmptyStrings, + }, + Set: schema.HashString, + }, + "settings": { Type: schema.TypeString, Optional: true, @@ -1464,6 +1474,14 @@ func flattenAzureRmVirtualMachineScaleSetExtensionProfile(profile *compute.Virtu e["auto_upgrade_minor_version"] = *properties.AutoUpgradeMinorVersion } + provisionAfterExtensions := make([]interface{}, 0) + if properties.ProvisionAfterExtensions != nil { + for _, provisionAfterExtension := range *properties.ProvisionAfterExtensions { + provisionAfterExtensions = append(provisionAfterExtensions, provisionAfterExtension) + } + } + e["provision_after_extensions"] = schema.NewSet(schema.HashString, provisionAfterExtensions) + if settings := properties.Settings; settings != nil { settingsVal := settings.(map[string]interface{}) settingsJson, err := structure.FlattenJsonToString(settingsVal) @@ -1567,6 +1585,10 @@ func resourceArmVirtualMachineScaleSetExtensionHash(v interface{}) int { buf.WriteString(fmt.Sprintf("%t-", v.(bool))) } + if v, ok := m["provision_after_extensions"]; ok { + buf.WriteString(fmt.Sprintf("%s-", v.(*schema.Set).List())) + } + // we need to ensure the whitespace is consistent settings := m["settings"].(string) if settings != "" { @@ -2151,6 +2173,18 @@ func expandAzureRMVirtualMachineScaleSetExtensions(d *schema.ResourceData) (*com extension.VirtualMachineScaleSetExtensionProperties.AutoUpgradeMinorVersion = &upgrade } + if a := config["provision_after_extensions"]; a != nil { + provision_after_extensions := config["provision_after_extensions"].(*schema.Set).List() + if len(provision_after_extensions) > 0 { + var provisionAfterExtensions []string + for _, a := range provision_after_extensions { + str := a.(string) + provisionAfterExtensions = append(provisionAfterExtensions, str) + } + extension.VirtualMachineScaleSetExtensionProperties.ProvisionAfterExtensions = &provisionAfterExtensions + } + } + if s := config["settings"].(string); s != "" { settings, err := structure.ExpandJsonFromString(s) if err != nil { diff --git a/website/docs/r/virtual_machine_scale_set.html.markdown b/website/docs/r/virtual_machine_scale_set.html.markdown index 0486ac5c7478..72630dfadf91 100644 --- a/website/docs/r/virtual_machine_scale_set.html.markdown +++ b/website/docs/r/virtual_machine_scale_set.html.markdown @@ -489,6 +489,7 @@ machine scale set, as in the [example below](#example-of-storage_profile_image_r * `type` - (Required) The type of extension, available types for a publisher can be found using the Azure CLI. * `type_handler_version` - (Required) Specifies the version of the extension to use, available versions can be found using the Azure CLI. * `auto_upgrade_minor_version` - (Optional) Specifies whether or not to use the latest minor version available. +* `provision_after_extensions` - (Optional) Specifies a dependency array of extensions required to be executed before, the array stores the name of each extension. * `settings` - (Required) The settings passed to the extension, these are specified as a JSON object in a string. * `protected_settings` - (Optional) The protected_settings passed to the extension, like settings, these are specified as a JSON object in a string. From 83f09b1c60cd50591c0c2e605cd2d80f47aac582 Mon Sep 17 00:00:00 2001 From: Imanol Date: Fri, 22 Feb 2019 14:21:21 +0100 Subject: [PATCH 2/3] [FIX]: code format --- azurerm/resource_arm_virtual_machine_scale_set.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azurerm/resource_arm_virtual_machine_scale_set.go b/azurerm/resource_arm_virtual_machine_scale_set.go index bdfdd17d5729..255846058b37 100644 --- a/azurerm/resource_arm_virtual_machine_scale_set.go +++ b/azurerm/resource_arm_virtual_machine_scale_set.go @@ -718,10 +718,10 @@ func resourceArmVirtualMachineScaleSet() *schema.Resource { Type: schema.TypeSet, Optional: true, Elem: &schema.Schema{ - Type: schema.TypeString, + Type: schema.TypeString, ValidateFunc: validate.NoEmptyStrings, }, - Set: schema.HashString, + Set: schema.HashString, }, "settings": { From b9057a8cd271f2617eb0126883e0fa7b6d929bf1 Mon Sep 17 00:00:00 2001 From: Imanol Date: Sat, 23 Mar 2019 15:52:35 +0100 Subject: [PATCH 3/3] [ADD]: provision_after_extension tests & vmss migration --- .../resource_arm_virtual_machine_scale_set.go | 10 +- ...arm_virtual_machine_scale_set_migration.go | 44 ++++++ ...urce_arm_virtual_machine_scale_set_test.go | 139 ++++++++++++++++++ 3 files changed, 189 insertions(+), 4 deletions(-) create mode 100644 azurerm/resource_arm_virtual_machine_scale_set_migration.go diff --git a/azurerm/resource_arm_virtual_machine_scale_set.go b/azurerm/resource_arm_virtual_machine_scale_set.go index 255846058b37..0bbcbc9beb06 100644 --- a/azurerm/resource_arm_virtual_machine_scale_set.go +++ b/azurerm/resource_arm_virtual_machine_scale_set.go @@ -21,10 +21,12 @@ import ( func resourceArmVirtualMachineScaleSet() *schema.Resource { return &schema.Resource{ - Create: resourceArmVirtualMachineScaleSetCreateUpdate, - Read: resourceArmVirtualMachineScaleSetRead, - Update: resourceArmVirtualMachineScaleSetCreateUpdate, - Delete: resourceArmVirtualMachineScaleSetDelete, + Create: resourceArmVirtualMachineScaleSetCreateUpdate, + Read: resourceArmVirtualMachineScaleSetRead, + Update: resourceArmVirtualMachineScaleSetCreateUpdate, + Delete: resourceArmVirtualMachineScaleSetDelete, + MigrateState: resourceVirtualMachineScaleSetMigrateState, + SchemaVersion: 1, Importer: &schema.ResourceImporter{ State: schema.ImportStatePassthrough, diff --git a/azurerm/resource_arm_virtual_machine_scale_set_migration.go b/azurerm/resource_arm_virtual_machine_scale_set_migration.go new file mode 100644 index 000000000000..2d4578eb26bd --- /dev/null +++ b/azurerm/resource_arm_virtual_machine_scale_set_migration.go @@ -0,0 +1,44 @@ +package azurerm + +import ( + "fmt" + "log" + + "github.com/hashicorp/terraform/terraform" +) + +func resourceVirtualMachineScaleSetMigrateState(v int, is *terraform.InstanceState, meta interface{}) (*terraform.InstanceState, error) { + switch v { + case 0: + log.Println("[INFO] Found AzureRM Scale Set State v0; migrating to v1") + return resourceVirtualMachineScaleSetStateV0toV1(is, meta) + default: + return is, fmt.Errorf("Unexpected schema version: %d", v) + } +} + +func resourceVirtualMachineScaleSetStateV0toV1(is *terraform.InstanceState, meta interface{}) (*terraform.InstanceState, error) { + if is.Empty() { + log.Println("[DEBUG] Empty InstanceState; nothing to migrate.") + return is, nil + } + + log.Printf("[DEBUG] ARM Virtual Machine Scale Set Attributes before Migration: %#v", is.Attributes) + + client := meta.(*ArmClient).vmScaleSetClient + ctx := meta.(*ArmClient).StopContext + + resGroup := is.Attributes["resource_group_name"] + name := is.Attributes["name"] + + read, err := client.Get(ctx, resGroup, name) + if err != nil { + return is, err + } + + is.ID = *read.ID + + log.Printf("[DEBUG] ARM Virtual Machine Scale Set Attributes after State Migration: %#v", is.Attributes) + + return is, nil +} diff --git a/azurerm/resource_arm_virtual_machine_scale_set_test.go b/azurerm/resource_arm_virtual_machine_scale_set_test.go index ff12d56be92f..fea4e6b70fc9 100644 --- a/azurerm/resource_arm_virtual_machine_scale_set_test.go +++ b/azurerm/resource_arm_virtual_machine_scale_set_test.go @@ -796,6 +796,32 @@ func TestAccAzureRMVirtualMachineScaleSet_multipleExtensions(t *testing.T) { }) } +func TestAccAzureRMVirtualMachineScaleSet_multipleExtensions_provision_after_extension(t *testing.T) { + resourceName := "azurerm_virtual_machine_scale_set.test" + ri := tf.AccRandTimeInt() + config := testAccAzureRMVirtualMachineScaleSetMultipleExtensionsTemplate_provision_after_extension(ri, testLocation()) + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMVirtualMachineScaleSetDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMVirtualMachineScaleSetExists(resourceName), + testCheckAzureRMVirtualMachineScaleSetExtension(resourceName), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"os_profile.0.admin_password"}, + }, + }, + }) +} + func TestAccAzureRMVirtualMachineScaleSet_osDiskTypeConflict(t *testing.T) { ri := tf.AccRandTimeInt() config := testAccAzureRMVirtualMachineScaleSet_osDiskTypeConflict(ri, testLocation()) @@ -4076,6 +4102,119 @@ SETTINGS `, rInt, location) } +func testAccAzureRMVirtualMachineScaleSetMultipleExtensionsTemplate_provision_after_extension(rInt int, location string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%[1]d" + location = "%[2]s" +} + +resource "azurerm_virtual_network" "test" { + name = "acctvn-%[1]d" + address_space = ["10.0.0.0/16"] + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" +} + +resource "azurerm_subnet" "test" { + name = "acctsub-%[1]d" + resource_group_name = "${azurerm_resource_group.test.name}" + virtual_network_name = "${azurerm_virtual_network.test.name}" + address_prefix = "10.0.2.0/24" +} + +resource "azurerm_storage_account" "test" { + name = "accsa%[1]d" + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + account_tier = "Standard" + account_replication_type = "LRS" +} + +resource "azurerm_storage_container" "test" { + name = "vhds" + resource_group_name = "${azurerm_resource_group.test.name}" + storage_account_name = "${azurerm_storage_account.test.name}" + container_access_type = "private" +} + +resource "azurerm_virtual_machine_scale_set" "test" { + name = "acctvmss-%[1]d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + upgrade_policy_mode = "Manual" + overprovision = false + + sku { + name = "Standard_D1_v2" + tier = "Standard" + capacity = 1 + } + + os_profile { + computer_name_prefix = "testvm-%[1]d" + admin_username = "myadmin" + admin_password = "Passwword1234" + } + + network_profile { + name = "TestNetworkProfile" + primary = true + + ip_configuration { + name = "TestIPConfiguration" + primary = true + subnet_id = "${azurerm_subnet.test.id}" + } + } + + storage_profile_os_disk { + name = "os-disk" + caching = "ReadWrite" + create_option = "FromImage" + vhd_containers = ["${azurerm_storage_account.test.primary_blob_endpoint}${azurerm_storage_container.test.name}"] + } + + storage_profile_image_reference { + publisher = "Canonical" + offer = "UbuntuServer" + sku = "16.04-LTS" + version = "latest" + } + + extension { + name = "CustomScript" + publisher = "Microsoft.Azure.Extensions" + type = "CustomScript" + type_handler_version = "2.0" + auto_upgrade_minor_version = true + + settings = <