diff --git a/azurerm/resource_arm_virtual_machine_scale_set.go b/azurerm/resource_arm_virtual_machine_scale_set.go index 13e3fb25003e..f193de42ae1b 100644 --- a/azurerm/resource_arm_virtual_machine_scale_set.go +++ b/azurerm/resource_arm_virtual_machine_scale_set.go @@ -417,6 +417,31 @@ func resourceArmVirtualMachineScaleSet() *schema.Resource { Set: resourceArmVirtualMachineScaleSetStorageProfileImageReferenceHash, }, + "plan": { + Type: schema.TypeSet, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + + "publisher": { + Type: schema.TypeString, + Required: true, + }, + + "product": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + Set: resourceArmVirtualMachineScaleSetPlanHash, + }, + "extension": { Type: schema.TypeSet, Optional: true, @@ -545,6 +570,16 @@ func resourceArmVirtualMachineScaleSetCreate(d *schema.ResourceData, meta interf Sku: sku, VirtualMachineScaleSetProperties: &scaleSetProps, } + + if _, ok := d.GetOk("plan"); ok { + plan, err := expandAzureRmVirtualMachineScaleSetPlan(d) + if err != nil { + return err + } + + scaleSetParams.Plan = plan + } + _, vmError := vmScaleSetClient.CreateOrUpdate(resGroup, name, scaleSetParams, make(chan struct{})) vmErr := <-vmError if vmErr != nil { @@ -653,6 +688,10 @@ func resourceArmVirtualMachineScaleSetRead(d *schema.ResourceData, meta interfac d.Set("extension", extension) } + if resp.Plan != nil { + d.Set("plan", flattenAzureRmVirtualMachineScaleSetPlan(resp.Plan)) + } + flattenAndSetTags(d, resp.Tags) return nil @@ -1475,3 +1514,40 @@ func expandAzureRMVirtualMachineScaleSetExtensions(d *schema.ResourceData) (*com Extensions: &resources, }, nil } + +func expandAzureRmVirtualMachineScaleSetPlan(d *schema.ResourceData) (*compute.Plan, error) { + planConfigs := d.Get("plan").(*schema.Set).List() + + planConfig := planConfigs[0].(map[string]interface{}) + + publisher := planConfig["publisher"].(string) + name := planConfig["name"].(string) + product := planConfig["product"].(string) + + return &compute.Plan{ + Publisher: &publisher, + Name: &name, + Product: &product, + }, nil +} + +func resourceArmVirtualMachineScaleSetPlanHash(v interface{}) int { + var buf bytes.Buffer + m := v.(map[string]interface{}) + + buf.WriteString(fmt.Sprintf("%s-", m["name"].(string))) + buf.WriteString(fmt.Sprintf("%s-", m["publisher"].(string))) + buf.WriteString(fmt.Sprintf("%s-", m["product"].(string))) + + return hashcode.String(buf.String()) +} + +func flattenAzureRmVirtualMachineScaleSetPlan(plan *compute.Plan) []interface{} { + result := make(map[string]interface{}) + + result["name"] = *plan.Name + result["publisher"] = *plan.Publisher + result["product"] = *plan.Product + + return []interface{}{result} +} diff --git a/azurerm/resource_arm_virtual_machine_scale_set_test.go b/azurerm/resource_arm_virtual_machine_scale_set_test.go index 17a62edfbb96..be31907c9259 100644 --- a/azurerm/resource_arm_virtual_machine_scale_set_test.go +++ b/azurerm/resource_arm_virtual_machine_scale_set_test.go @@ -135,6 +135,24 @@ func TestAccAzureRMVirtualMachineScaleSet_basicLinux_disappears(t *testing.T) { }) } +func TestAccAzureRMVirtualMachineScaleSet_planManagedDisk(t *testing.T) { + ri := acctest.RandInt() + config := testAccAzureRMVirtualMachineScaleSet_planManagedDisk(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"), + ), + }, + }, + }) +} + func TestAccAzureRMVirtualMachineScaleSet_loadBalancer(t *testing.T) { ri := acctest.RandInt() config := fmt.Sprintf(testAccAzureRMVirtualMachineScaleSetLoadbalancerTemplate, ri, ri, ri, ri, ri, ri, ri) @@ -1607,3 +1625,73 @@ resource "azurerm_virtual_machine_scale_set" "test" { } `, ri, ri, ri, ri, ri, ri, ri, ri) } + +func testAccAzureRMVirtualMachineScaleSet_planManagedDisk(rInt int) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "West US 2" +} + +resource "azurerm_virtual_network" "test" { + name = "acctvn-%d" + address_space = ["10.0.0.0/16"] + location = "West US 2" + 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_virtual_machine_scale_set" "test" { + name = "acctvmss-%d" + location = "West US 2" + resource_group_name = "${azurerm_resource_group.test.name}" + upgrade_policy_mode = "Manual" + + sku { + name = "Standard_D1_v2" + tier = "Standard" + capacity = 2 + } + + os_profile { + computer_name_prefix = "testvm-%d" + admin_username = "myadmin" + admin_password = "Passwword1234" + } + + network_profile { + name = "TestNetworkProfile-%d" + primary = true + ip_configuration { + name = "TestIPConfiguration" + subnet_id = "${azurerm_subnet.test.id}" + } + } + + plan { + name = "os" + product = "rancheros" + publisher = "rancher" + } + + storage_profile_os_disk { + caching = "ReadWrite" + create_option = "FromImage" + managed_disk_type = "Standard_LRS" + } + + storage_profile_image_reference { + publisher = "rancher" + offer = "rancheros" + sku = "os" + version = "latest" + } +} +`, rInt, rInt, rInt, rInt, rInt, rInt) +} diff --git a/website/docs/r/virtual_machine_scale_set.html.markdown b/website/docs/r/virtual_machine_scale_set.html.markdown index 951376d8f375..b3c1204dd24b 100644 --- a/website/docs/r/virtual_machine_scale_set.html.markdown +++ b/website/docs/r/virtual_machine_scale_set.html.markdown @@ -199,7 +199,7 @@ resource "azurerm_virtual_machine_scale_set" "test" { lun = 0 caching = "ReadWrite" create_option = "Empty" - disk_size_gb = 10 + disk_size_gb = 10 } os_profile { @@ -256,6 +256,7 @@ The following arguments are supported: * `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. +* `plan` - (Optional) A plan block as documented below. * `tags` - (Optional) A mapping of tags to assign to the resource. @@ -360,6 +361,12 @@ The following arguments are supported: * `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. +`plan` supports the following: + +* `name` - (Required) Specifies the name of the image from the marketplace. +* `publisher` - (Required) Specifies the publisher of the image. +* `product` - (Required) Specifies the product of the image from the marketplace. + ## Attributes Reference The following attributes are exported: