From 5884d518e71d89649661bea48369a7f392583a51 Mon Sep 17 00:00:00 2001 From: Eugene Chuvyrov Date: Thu, 18 May 2017 04:30:19 -0700 Subject: [PATCH] [MS] Adding support for VMSS Data Disks using Managed Disk feature (#14608) * Added support for data disks with managed disks feature * Updated docs with VMSS Data Disks changes --- .../resource_arm_virtual_machine_scale_set.go | 116 +++++++++++++++ ...urce_arm_virtual_machine_scale_set_test.go | 133 ++++++++++++++++++ .../virtual_machine_scale_sets.html.markdown | 17 +++ 3 files changed, 266 insertions(+) diff --git a/builtin/providers/azurerm/resource_arm_virtual_machine_scale_set.go b/builtin/providers/azurerm/resource_arm_virtual_machine_scale_set.go index f810bde97..12665b2c2 100644 --- a/builtin/providers/azurerm/resource_arm_virtual_machine_scale_set.go +++ b/builtin/providers/azurerm/resource_arm_virtual_machine_scale_set.go @@ -343,6 +343,47 @@ func resourceArmVirtualMachineScaleSet() *schema.Resource { Set: resourceArmVirtualMachineScaleSetStorageProfileOsDiskHash, }, + "storage_profile_data_disk": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "lun": { + Type: schema.TypeInt, + Required: true, + }, + + "create_option": { + Type: schema.TypeString, + Required: true, + }, + + "caching": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + + "disk_size_gb": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + ValidateFunc: validateDiskSizeGB, + }, + + "managed_disk_type": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringInSlice([]string{ + string(compute.PremiumLRS), + string(compute.StandardLRS), + }, true), + }, + }, + }, + }, + "storage_profile_image_reference": { Type: schema.TypeSet, Optional: true, @@ -450,6 +491,15 @@ func resourceArmVirtualMachineScaleSetCreate(d *schema.ResourceData, meta interf return err } storageProfile.OsDisk = osDisk + + if _, ok := d.GetOk("storage_profile_data_disk"); ok { + dataDisks, err := expandAzureRMVirtualMachineScaleSetsStorageProfileDataDisk(d) + if err != nil { + return err + } + storageProfile.DataDisks = &dataDisks + } + if _, ok := d.GetOk("storage_profile_image_reference"); ok { imageRef, err := expandAzureRmVirtualMachineScaleSetStorageProfileImageReference(d) if err != nil { @@ -586,6 +636,12 @@ func resourceArmVirtualMachineScaleSetRead(d *schema.ResourceData, meta interfac return fmt.Errorf("[DEBUG] Error setting Virtual Machine Scale Set Storage Profile OS Disk error: %#v", err) } + if resp.VirtualMachineProfile.StorageProfile.DataDisks != nil { + if err := d.Set("storage_profile_data_disk", flattenAzureRmVirtualMachineScaleSetStorageProfileDataDisk(properties.VirtualMachineProfile.StorageProfile.DataDisks)); err != nil { + return fmt.Errorf("[DEBUG] Error setting Virtual Machine Scale Set Storage Profile Data Disk error: %#v", err) + } + } + if properties.VirtualMachineProfile.ExtensionProfile != nil { extension, err := flattenAzureRmVirtualMachineScaleSetExtensionProfile(properties.VirtualMachineProfile.ExtensionProfile) if err != nil { @@ -802,6 +858,26 @@ func flattenAzureRmVirtualMachineScaleSetStorageProfileOSDisk(profile *compute.V return []interface{}{result} } +func flattenAzureRmVirtualMachineScaleSetStorageProfileDataDisk(disks *[]compute.VirtualMachineScaleSetDataDisk) interface{} { + result := make([]interface{}, len(*disks)) + for i, disk := range *disks { + l := make(map[string]interface{}) + if disk.ManagedDisk != nil { + l["managed_disk_type"] = string(disk.ManagedDisk.StorageAccountType) + } + + l["create_option"] = disk.CreateOption + l["caching"] = string(disk.Caching) + if disk.DiskSizeGB != nil { + l["disk_size_gb"] = *disk.DiskSizeGB + } + l["lun"] = *disk.Lun + + result[i] = l + } + return result +} + func flattenAzureRmVirtualMachineScaleSetStorageProfileImageReference(profile *compute.ImageReference) []interface{} { result := make(map[string]interface{}) result["publisher"] = *profile.Publisher @@ -1149,6 +1225,46 @@ func expandAzureRMVirtualMachineScaleSetsStorageProfileOsDisk(d *schema.Resource return osDisk, nil } +func expandAzureRMVirtualMachineScaleSetsStorageProfileDataDisk(d *schema.ResourceData) ([]compute.VirtualMachineScaleSetDataDisk, error) { + disks := d.Get("storage_profile_data_disk").([]interface{}) + dataDisks := make([]compute.VirtualMachineScaleSetDataDisk, 0, len(disks)) + for _, diskConfig := range disks { + config := diskConfig.(map[string]interface{}) + + createOption := config["create_option"].(string) + managedDiskType := config["managed_disk_type"].(string) + lun := int32(config["lun"].(int)) + + dataDisk := compute.VirtualMachineScaleSetDataDisk{ + Lun: &lun, + CreateOption: compute.DiskCreateOptionTypes(createOption), + } + + managedDiskVMSS := &compute.VirtualMachineScaleSetManagedDiskParameters{} + + if managedDiskType != "" { + managedDiskVMSS.StorageAccountType = compute.StorageAccountTypes(managedDiskType) + } else { + managedDiskVMSS.StorageAccountType = compute.StorageAccountTypes(compute.StandardLRS) + } + + //assume that data disks in VMSS can only be Managed Disks + dataDisk.ManagedDisk = managedDiskVMSS + if v := config["caching"].(string); v != "" { + dataDisk.Caching = compute.CachingTypes(v) + } + + if v := config["disk_size_gb"]; v != nil { + diskSize := int32(config["disk_size_gb"].(int)) + dataDisk.DiskSizeGB = &diskSize + } + + dataDisks = append(dataDisks, dataDisk) + } + + return dataDisks, nil +} + func expandAzureRmVirtualMachineScaleSetStorageProfileImageReference(d *schema.ResourceData) (*compute.ImageReference, error) { storageImageRefs := d.Get("storage_profile_image_reference").(*schema.Set).List() diff --git a/builtin/providers/azurerm/resource_arm_virtual_machine_scale_set_test.go b/builtin/providers/azurerm/resource_arm_virtual_machine_scale_set_test.go index 2873b9ba3..737f7969c 100644 --- a/builtin/providers/azurerm/resource_arm_virtual_machine_scale_set_test.go +++ b/builtin/providers/azurerm/resource_arm_virtual_machine_scale_set_test.go @@ -136,6 +136,25 @@ func TestAccAzureRMVirtualMachineScaleSet_loadBalancer(t *testing.T) { }) } +func TestAccAzureRMVirtualMachineScaleSet_loadBalancerManagedDataDisks(t *testing.T) { + ri := acctest.RandInt() + config := fmt.Sprintf(testAccAzureRMVirtualMachineScaleSetLoadbalancerTemplateManagedDataDisks, ri, ri, ri, ri, ri, ri) + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMVirtualMachineScaleSetDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMVirtualMachineScaleSetExists("azurerm_virtual_machine_scale_set.test"), + testCheckAzureRMVirtualMachineScaleSetHasDataDisks("azurerm_virtual_machine_scale_set.test"), + ), + }, + }, + }) +} + func TestAccAzureRMVirtualMachineScaleSet_overprovision(t *testing.T) { ri := acctest.RandInt() config := fmt.Sprintf(testAccAzureRMVirtualMachineScaleSetOverprovisionTemplate, ri, ri, ri, ri, ri, ri) @@ -369,6 +388,39 @@ func testCheckAzureRMVirtualMachineScaleSetExtension(name string) resource.TestC } } +func testCheckAzureRMVirtualMachineScaleSetHasDataDisks(name string) resource.TestCheckFunc { + return func(s *terraform.State) error { + // Ensure we have enough information in state to look up in API + rs, ok := s.RootModule().Resources[name] + if !ok { + return fmt.Errorf("Not found: %s", name) + } + + name := rs.Primary.Attributes["name"] + resourceGroup, hasResourceGroup := rs.Primary.Attributes["resource_group_name"] + if !hasResourceGroup { + return fmt.Errorf("Bad: no resource group found in state for virtual machine: scale set %s", name) + } + + conn := testAccProvider.Meta().(*ArmClient).vmScaleSetClient + resp, err := conn.Get(resourceGroup, name) + if err != nil { + return fmt.Errorf("Bad: Get on vmScaleSetClient: %s", err) + } + + if resp.StatusCode == http.StatusNotFound { + return fmt.Errorf("Bad: VirtualMachineScaleSet %q (resource group: %q) does not exist", name, resourceGroup) + } + + storageProfile := resp.VirtualMachineProfile.StorageProfile.DataDisks + if storageProfile == nil || len(*storageProfile) == 0 { + return fmt.Errorf("Bad: Could not get data disks configurations for scale set %v", name) + } + + return nil + } +} + var testAccAzureRMVirtualMachineScaleSet_basic = ` resource "azurerm_resource_group" "test" { name = "acctestRG-%d" @@ -1286,3 +1338,84 @@ resource "azurerm_virtual_machine_scale_set" "test" { } } ` + +var testAccAzureRMVirtualMachineScaleSetLoadbalancerTemplateManagedDataDisks = ` +resource "azurerm_resource_group" "test" { + name = "acctestrg-%d" + location = "southcentralus" +} +resource "azurerm_virtual_network" "test" { + name = "acctvn-%d" + address_space = ["10.0.0.0/16"] + location = "southcentralus" + resource_group_name = "${azurerm_resource_group.test.name}" +} +resource "azurerm_subnet" "test" { + name = "acctsub-%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_lb" "test" { + name = "acctestlb-%d" + location = "southcentralus" + resource_group_name = "${azurerm_resource_group.test.name}" + frontend_ip_configuration { + name = "default" + subnet_id = "${azurerm_subnet.test.id}" + private_ip_address_allocation = "Dynamic" + } +} +resource "azurerm_lb_backend_address_pool" "test" { + name = "test" + resource_group_name = "${azurerm_resource_group.test.name}" + loadbalancer_id = "${azurerm_lb.test.id}" +} +resource "azurerm_virtual_machine_scale_set" "test" { + name = "acctvmss-%d" + location = "southcentralus" + resource_group_name = "${azurerm_resource_group.test.name}" + upgrade_policy_mode = "Manual" + sku { + name = "Standard_A0" + tier = "Standard" + capacity = 1 + } + os_profile { + computer_name_prefix = "testvm-%d" + admin_username = "myadmin" + admin_password = "Passwword1234" + } + network_profile { + name = "TestNetworkProfile" + primary = true + ip_configuration { + name = "TestIPConfiguration" + subnet_id = "${azurerm_subnet.test.id}" + load_balancer_backend_address_pool_ids = [ "${azurerm_lb_backend_address_pool.test.id}" ] + } + } + + storage_profile_os_disk { + name = "" + caching = "ReadWrite" + create_option = "FromImage" + managed_disk_type = "Standard_LRS" + } + + storage_profile_data_disk { + lun = 0 + caching = "ReadWrite" + create_option = "Empty" + disk_size_gb = 10 + managed_disk_type = "Standard_LRS" + } + + storage_profile_image_reference { + publisher = "Canonical" + offer = "UbuntuServer" + sku = "16.04.0-LTS" + version = "latest" + } +} +` diff --git a/website/source/docs/providers/azurerm/r/virtual_machine_scale_sets.html.markdown b/website/source/docs/providers/azurerm/r/virtual_machine_scale_sets.html.markdown index 4ba6e88eb..90fccc2c3 100644 --- a/website/source/docs/providers/azurerm/r/virtual_machine_scale_sets.html.markdown +++ b/website/source/docs/providers/azurerm/r/virtual_machine_scale_sets.html.markdown @@ -195,6 +195,13 @@ resource "azurerm_virtual_machine_scale_set" "test" { managed_disk_type = "Standard_LRS" } + storage_profile_data_disk { + lun = 0 + caching = "ReadWrite" + create_option = "Empty" + disk_size_gb = 10 + } + os_profile { computer_name_prefix = "testvm" admin_username = "myadmin" @@ -248,6 +255,7 @@ The following arguments are supported: * `os_profile_linux_config` - (Required, when a linux machine) A Linux config block as documented below. * `network_profile` - (Required) A collection of network profile block as documented below. * `storage_profile_os_disk` - (Required) A storage profile os disk block as documented below +* `storage_profile_data_disk` - (Optional) A storage profile data disk block as documented below * `storage_profile_image_reference` - (Optional) A storage profile image reference block as documented below. * `extension` - (Optional) Can be specified multiple times to add extension profiles to the scale set. Each `extension` block supports the fields documented below. * `tags` - (Optional) A mapping of tags to assign to the resource. @@ -329,6 +337,15 @@ The following arguments are supported: When setting this field `os_type` needs to be specified. Cannot be used when `vhd_containers`, `managed_disk_type` or `storage_profile_image_reference ` are specified. * `os_type` - (Optional) Specifies the operating system Type, valid values are windows, linux. +`storage_profile_data_disk` supports the following: + +* `lun` - (Required) Specifies the Logical Unit Number of the disk in each virtual machine in the scale set. +`Premium_LRS`. +* `create_option` - (Optional) Specifies how the data disk should be created. The only possible options are `FromImage` and `Empty`. +* `caching` - (Optional) Specifies the caching requirements. Possible values include: `None` (default), `ReadOnly`, `ReadWrite`. +* `disk_size_gb` - (Optional) Specifies the size of the disk in GB. This element is required when creating an empty disk. +* `managed_disk_type` - (Optional) Specifies the type of managed disk to create. Value must be either `Standard_LRS` or + `storage_profile_image_reference` supports the following: * `publisher` - (Required) Specifies the publisher of the image used to create the virtual machines