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

New resource: azurerm_orchestrated_virtual_machine_scale_set #6626

Merged
merged 29 commits into from May 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
b48bd4b
Refine VM ID parse functions
ArcturusZhang Apr 8, 2020
4f30719
Some follow ups on VM ID refactor
ArcturusZhang Apr 8, 2020
5658d03
VMSS and extension refactor
ArcturusZhang Apr 8, 2020
6facd42
VM extension refactor
ArcturusZhang Apr 8, 2020
94236b9
Managed disk ID
ArcturusZhang Apr 8, 2020
865f825
Fix CI
ArcturusZhang Apr 8, 2020
988a70c
Fix another missed one
ArcturusZhang Apr 8, 2020
48a2e32
go imports
ArcturusZhang Apr 9, 2020
d54f13f
Goimports again...
ArcturusZhang Apr 9, 2020
b873afe
Add new resource of VMSS in VMO mode
ArcturusZhang Apr 8, 2020
5a4cf2c
Modify VM to support create VM in VMSS VMO mode
ArcturusZhang Apr 8, 2020
79ddbbe
Fix some problems
ArcturusZhang Apr 9, 2020
b69881f
Initial commit of acc test
ArcturusZhang Apr 10, 2020
9d33259
Merge remote-tracking branch 'origin/master' into Orchestration-mode
ArcturusZhang Apr 10, 2020
0cb68ac
Finalize tests and doc
ArcturusZhang Apr 10, 2020
85d2761
Merge remote-tracking branch 'origin/master' into Orchestration-mode
ArcturusZhang Apr 10, 2020
86ea743
Merge remote-tracking branch 'origin/master' into Orchestration-mode
ArcturusZhang Apr 15, 2020
cec54f6
Finalize orchestration mode
ArcturusZhang Apr 22, 2020
8397ec4
Merge remote-tracking branch 'origin/master' into Orchestration-mode
ArcturusZhang Apr 22, 2020
aa5bb58
terrafmt
ArcturusZhang Apr 22, 2020
bd796fc
Resolve comments
ArcturusZhang Apr 26, 2020
cdcfa20
gofmt
ArcturusZhang Apr 26, 2020
b5bd514
terrafmt
ArcturusZhang Apr 26, 2020
4c43f60
Merge remote-tracking branch 'origin/master' into Orchestration-mode
ArcturusZhang May 8, 2020
23f8129
Rename virtual_machine_scale_set_orchestrator_vm to orchestrated_virt…
ArcturusZhang May 8, 2020
a7abdc5
Resolve comments
ArcturusZhang May 15, 2020
8351c72
Fix the bad link
ArcturusZhang May 15, 2020
8e7a2bd
Merge remote-tracking branch 'origin/master' into Orchestration-mode
ArcturusZhang May 18, 2020
563322f
Fix bad test cases
ArcturusZhang May 21, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -114,7 +114,7 @@ func resourceLinuxVirtualMachine() *schema.Resource {
// TODO: raise a GH issue for the broken API
// availability_set_id: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/acctestRG-200122113424880096/providers/Microsoft.Compute/availabilitySets/ACCTESTAVSET-200122113424880096" => "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/acctestRG-200122113424880096/providers/Microsoft.Compute/availabilitySets/acctestavset-200122113424880096" (forces new resource)
ConflictsWith: []string{
// TODO: "virtual_machine_scale_set_id"
"virtual_machine_scale_set_id",
"zone",
},
},
Expand Down Expand Up @@ -216,15 +216,27 @@ func resourceLinuxVirtualMachine() *schema.Resource {

"source_image_reference": sourceImageReferenceSchema(true),

"virtual_machine_scale_set_id": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
ConflictsWith: []string{
"availability_set_id",
},
ValidateFunc: computeValidate.VirtualMachineScaleSetID,
},

"tags": tags.Schema(),

"zone": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
// this has to be computed because when you are trying to assign this VM to a VMSS in VMO mode,
// the VMO mode VMSS will assign a zone for each of its instance
Computed: true,
katbyte marked this conversation as resolved.
Show resolved Hide resolved
ConflictsWith: []string{
"availability_set_id",
// TODO: "virtual_machine_scale_set_id"
},
},

Expand Down Expand Up @@ -371,11 +383,6 @@ func resourceLinuxVirtualMachineCreate(d *schema.ResourceData, meta interface{})
// Optional
AdditionalCapabilities: additionalCapabilities,
DiagnosticsProfile: bootDiagnostics,

// @tombuildsstuff: passing in a VMSS ID returns:
// > Code="InvalidParameter" Message="The value of parameter virtualMachineScaleSet is invalid." Target="virtualMachineScaleSet"
// presuming this isn't finished yet; note: this'll conflict with availability set id
VirtualMachineScaleSet: nil,
},
Tags: tags.Expand(t),
}
Expand Down Expand Up @@ -426,6 +433,16 @@ func resourceLinuxVirtualMachineCreate(d *schema.ResourceData, meta interface{})
}
}

if v, ok := d.GetOk("virtual_machine_scale_set_id"); ok {
// you must also specify a zone in order to assign this vm to a orchestrated vmss
if _, ok := d.GetOk("zone"); !ok {
return fmt.Errorf("`zone` must be specified when `virtual_machine_scale_set_id` is set")
}
params.VirtualMachineScaleSet = &compute.SubResource{
ID: utils.String(v.(string)),
}
}

if v, ok := d.GetOk("zone"); ok {
params.Zones = &[]string{
v.(string),
Expand Down Expand Up @@ -547,6 +564,12 @@ func resourceLinuxVirtualMachineRead(d *schema.ResourceData, meta interface{}) e
}
d.Set("dedicated_host_id", dedicatedHostId)

virtualMachineScaleSetId := ""
if props.VirtualMachineScaleSet != nil && props.VirtualMachineScaleSet.ID != nil {
virtualMachineScaleSetId = *props.VirtualMachineScaleSet.ID
}
d.Set("virtual_machine_scale_set_id", virtualMachineScaleSetId)

if profile := props.OsProfile; profile != nil {
d.Set("admin_username", profile.AdminUsername)
d.Set("allow_extension_operations", profile.AllowExtensionOperations)
Expand Down
@@ -0,0 +1,191 @@
package compute

import (
"fmt"
"log"
"time"

"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/location"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/compute/parse"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags"
azSchema "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tf/schema"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils"
)

func resourceArmOrchestratedVirtualMachineScaleSet() *schema.Resource {
return &schema.Resource{
Create: resourceArmOrchestratedVirtualMachineScaleSetCreateUpdate,
Read: resourceArmOrchestratedVirtualMachineScaleSetRead,
Update: resourceArmOrchestratedVirtualMachineScaleSetCreateUpdate,
Delete: resourceArmOrchestratedVirtualMachineScaleSetDelete,

Importer: azSchema.ValidateResourceIDPriorToImportThen(func(id string) error {
_, err := parse.VirtualMachineScaleSetID(id)
return err
}, importOrchestratedVirtualMachineScaleSet),

Timeouts: &schema.ResourceTimeout{
Create: schema.DefaultTimeout(30 * time.Minute),
Read: schema.DefaultTimeout(5 * time.Minute),
Update: schema.DefaultTimeout(30 * time.Minute),
Delete: schema.DefaultTimeout(30 * time.Minute),
},

Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: ValidateOrchestratedVMSSName,
},

"resource_group_name": azure.SchemaResourceGroupName(),

"location": azure.SchemaLocation(),

"platform_fault_domain_count": {
Type: schema.TypeInt,
Required: true,
ForceNew: true,
// The range of this value varies in different locations
ValidateFunc: validation.IntBetween(0, 5),
},

"single_placement_group": {
Type: schema.TypeBool,
Required: true,
ForceNew: true,
},

// the VMO mode can only be deployed into one zone for now, and its zone will also be assigned to all its VM instances
"zones": azure.SchemaSingleZone(),

"unique_id": {
Type: schema.TypeString,
Computed: true,
},

"tags": tags.Schema(),
},
}
}

func resourceArmOrchestratedVirtualMachineScaleSetCreateUpdate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*clients.Client).Compute.VMScaleSetClient
ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d)
defer cancel()

resourceGroup := d.Get("resource_group_name").(string)
name := d.Get("name").(string)

if d.IsNewResource() {
existing, err := client.Get(ctx, resourceGroup, name)
if err != nil {
if !utils.ResponseWasNotFound(existing.Response) {
return fmt.Errorf("checking for existing Orchestrated Virtual Machine Scale Set %q (Resource Group %q): %+v", name, resourceGroup, err)
}
}

if existing.ID != nil && *existing.ID != "" {
return tf.ImportAsExistsError("azurerm_orchestrated_virtual_machine_scale_set", *existing.ID)
}
}

props := compute.VirtualMachineScaleSet{
Location: utils.String(location.Normalize(d.Get("location").(string))),
Tags: tags.Expand(d.Get("tags").(map[string]interface{})),
VirtualMachineScaleSetProperties: &compute.VirtualMachineScaleSetProperties{
PlatformFaultDomainCount: utils.Int32(int32(d.Get("platform_fault_domain_count").(int))),
SinglePlacementGroup: utils.Bool(d.Get("single_placement_group").(bool)),
katbyte marked this conversation as resolved.
Show resolved Hide resolved
},
Zones: azure.ExpandZones(d.Get("zones").([]interface{})),
}

future, err := client.CreateOrUpdate(ctx, resourceGroup, name, props)
if err != nil {
return fmt.Errorf("creating Orchestrated Virtual Machine Scale Set %q (Resource Group %q): %+v", name, resourceGroup, err)
}

if err := future.WaitForCompletionRef(ctx, client.Client); err != nil {
return fmt.Errorf("waiting for creation of Orchestrated Virtual Machine Scale Set %q (Resource Group %q): %+v", name, resourceGroup, err)
}

resp, err := client.Get(ctx, resourceGroup, name)
if err != nil {
return fmt.Errorf("retrieving Orchestrated Virtual Machine Scale Set %q (Resource Group %q): %+v", name, resourceGroup, err)
}

if resp.ID == nil || *resp.ID == "" {
return fmt.Errorf("retrieving Orchestrated Virtual Machine Scale Set %q (Resource Group %q): ID was empty", name, resourceGroup)
}
d.SetId(*resp.ID)

return resourceArmOrchestratedVirtualMachineScaleSetRead(d, meta)
}

func resourceArmOrchestratedVirtualMachineScaleSetRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*clients.Client).Compute.VMScaleSetClient
ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d)
defer cancel()

id, err := parse.VirtualMachineScaleSetID(d.Id())
if err != nil {
return err
}

resp, err := client.Get(ctx, id.ResourceGroup, id.Name)
if err != nil {
if utils.ResponseWasNotFound(resp.Response) {
log.Printf("[DEBUG] Orchestrated Virtual Machine Scale Set %q was not found in Resource Group %q - removing from state!", id.Name, id.ResourceGroup)
d.SetId("")
return nil
}

return fmt.Errorf("retrieving Orchestrated Virtual Machine Scale Set %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err)
}

d.Set("name", id.Name)
d.Set("resource_group_name", id.ResourceGroup)
d.Set("location", location.NormalizeNilable(resp.Location))

if props := resp.VirtualMachineScaleSetProperties; props != nil {
d.Set("platform_fault_domain_count", props.PlatformFaultDomainCount)
d.Set("single_placement_group", props.SinglePlacementGroup)
d.Set("unique_id", props.UniqueID)
}

if err := d.Set("zones", resp.Zones); err != nil {
return fmt.Errorf("setting `zones`: %+v", err)
}

return tags.FlattenAndSet(d, resp.Tags)
}

func resourceArmOrchestratedVirtualMachineScaleSetDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*clients.Client).Compute.VMScaleSetClient
ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d)
defer cancel()

id, err := parse.VirtualMachineScaleSetID(d.Id())
if err != nil {
return err
}

future, err := client.Delete(ctx, id.ResourceGroup, id.Name)
if err != nil {
return fmt.Errorf("deleting Orchestrated Virtual Machine Scale Set %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err)
}

if err := future.WaitForCompletionRef(ctx, client.Client); err != nil {
return fmt.Errorf("waiting for deletion of Orchestrated Virtual Machine Scale Set %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err)
}

return nil
}
43 changes: 22 additions & 21 deletions azurerm/internal/services/compute/registration.go
Expand Up @@ -41,27 +41,28 @@ func (r Registration) SupportedDataSources() map[string]*schema.Resource {
// SupportedResources returns the supported Resources supported by this Service
func (r Registration) SupportedResources() map[string]*schema.Resource {
resources := map[string]*schema.Resource{
"azurerm_availability_set": resourceArmAvailabilitySet(),
"azurerm_dedicated_host": resourceArmDedicatedHost(),
"azurerm_dedicated_host_group": resourceArmDedicatedHostGroup(),
"azurerm_disk_encryption_set": resourceArmDiskEncryptionSet(),
"azurerm_image": resourceArmImage(),
"azurerm_managed_disk": resourceArmManagedDisk(),
"azurerm_marketplace_agreement": resourceArmMarketplaceAgreement(),
"azurerm_proximity_placement_group": resourceArmProximityPlacementGroup(),
"azurerm_shared_image_gallery": resourceArmSharedImageGallery(),
"azurerm_shared_image_version": resourceArmSharedImageVersion(),
"azurerm_shared_image": resourceArmSharedImage(),
"azurerm_snapshot": resourceArmSnapshot(),
"azurerm_virtual_machine_data_disk_attachment": resourceArmVirtualMachineDataDiskAttachment(),
"azurerm_virtual_machine_extension": resourceArmVirtualMachineExtension(),
"azurerm_virtual_machine_scale_set": resourceArmVirtualMachineScaleSet(),
"azurerm_virtual_machine": resourceArmVirtualMachine(),
"azurerm_linux_virtual_machine": resourceLinuxVirtualMachine(),
"azurerm_linux_virtual_machine_scale_set": resourceArmLinuxVirtualMachineScaleSet(),
"azurerm_virtual_machine_scale_set_extension": resourceArmVirtualMachineScaleSetExtension(),
"azurerm_windows_virtual_machine": resourceWindowsVirtualMachine(),
"azurerm_windows_virtual_machine_scale_set": resourceArmWindowsVirtualMachineScaleSet(),
"azurerm_availability_set": resourceArmAvailabilitySet(),
"azurerm_dedicated_host": resourceArmDedicatedHost(),
"azurerm_dedicated_host_group": resourceArmDedicatedHostGroup(),
"azurerm_disk_encryption_set": resourceArmDiskEncryptionSet(),
"azurerm_image": resourceArmImage(),
"azurerm_managed_disk": resourceArmManagedDisk(),
"azurerm_marketplace_agreement": resourceArmMarketplaceAgreement(),
"azurerm_proximity_placement_group": resourceArmProximityPlacementGroup(),
"azurerm_shared_image_gallery": resourceArmSharedImageGallery(),
"azurerm_shared_image_version": resourceArmSharedImageVersion(),
"azurerm_shared_image": resourceArmSharedImage(),
"azurerm_snapshot": resourceArmSnapshot(),
"azurerm_virtual_machine_data_disk_attachment": resourceArmVirtualMachineDataDiskAttachment(),
"azurerm_virtual_machine_extension": resourceArmVirtualMachineExtension(),
"azurerm_virtual_machine_scale_set": resourceArmVirtualMachineScaleSet(),
"azurerm_orchestrated_virtual_machine_scale_set": resourceArmOrchestratedVirtualMachineScaleSet(),
"azurerm_virtual_machine": resourceArmVirtualMachine(),
"azurerm_linux_virtual_machine": resourceLinuxVirtualMachine(),
"azurerm_linux_virtual_machine_scale_set": resourceArmLinuxVirtualMachineScaleSet(),
"azurerm_virtual_machine_scale_set_extension": resourceArmVirtualMachineScaleSetExtension(),
"azurerm_windows_virtual_machine": resourceWindowsVirtualMachine(),
"azurerm_windows_virtual_machine_scale_set": resourceArmWindowsVirtualMachineScaleSet(),
}

return resources
Expand Down