From 6b8d37e93807087e197b8c3106af23e38124ff8a Mon Sep 17 00:00:00 2001 From: Sander van Harmelen Date: Fri, 21 Aug 2015 16:59:35 +0200 Subject: [PATCH] Fix issue #3033 and update tweak several cloudstack resources - Added a retry loop for attaching disks as this something was tried to fast when the VM was still booting - Fix issue #3033 - Update docs for latest updates and done some minor refactoring (styling) --- .../cloudstack/resource_cloudstack_disk.go | 95 +++++++++---------- .../resource_cloudstack_ipaddress.go | 32 +++---- .../cloudstack/resource_cloudstack_network.go | 36 +++---- .../resource_cloudstack_port_forward.go | 5 +- .../cloudstack/resource_cloudstack_vpc.go | 16 ++-- .../providers/cloudstack/r/disk.html.markdown | 3 + .../cloudstack/r/ipaddress.html.markdown | 3 + .../cloudstack/r/network.html.markdown | 3 + .../providers/cloudstack/r/vpc.html.markdown | 3 + 9 files changed, 102 insertions(+), 94 deletions(-) diff --git a/builtin/providers/cloudstack/resource_cloudstack_disk.go b/builtin/providers/cloudstack/resource_cloudstack_disk.go index c19cac8bc..a6731a0e9 100644 --- a/builtin/providers/cloudstack/resource_cloudstack_disk.go +++ b/builtin/providers/cloudstack/resource_cloudstack_disk.go @@ -56,17 +56,17 @@ func resourceCloudStackDisk() *schema.Resource { Optional: true, }, - "zone": &schema.Schema{ - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, - "project": &schema.Schema{ Type: schema.TypeString, Optional: true, ForceNew: true, }, + + "zone": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, }, } } @@ -80,17 +80,6 @@ func resourceCloudStackDiskCreate(d *schema.ResourceData, meta interface{}) erro // Create a new parameter struct p := cs.Volume.NewCreateVolumeParams(name) - // If there is a project supplied, we retreive and set the project id - if project, ok := d.GetOk("project"); ok { - // Retrieve the project UUID - projectid, e := retrieveUUID(cs, "project", project.(string)) - if e != nil { - return e.Error() - } - // Set the default project ID - p.SetProjectid(projectid) - } - // Retrieve the disk_offering UUID diskofferingid, e := retrieveUUID(cs, "disk_offering", d.Get("disk_offering").(string)) if e != nil { @@ -104,6 +93,17 @@ func resourceCloudStackDiskCreate(d *schema.ResourceData, meta interface{}) erro p.SetSize(int64(d.Get("size").(int))) } + // If there is a project supplied, we retreive and set the project id + if project, ok := d.GetOk("project"); ok { + // Retrieve the project UUID + projectid, e := retrieveUUID(cs, "project", project.(string)) + if e != nil { + return e.Error() + } + // Set the default project ID + p.SetProjectid(projectid) + } + // Retrieve the zone UUID zoneid, e := retrieveUUID(cs, "zone", d.Get("zone").(string)) if e != nil { @@ -125,6 +125,7 @@ func resourceCloudStackDiskCreate(d *schema.ResourceData, meta interface{}) erro d.SetPartial("disk_offering") d.SetPartial("size") d.SetPartial("virtual_machine") + d.SetPartial("project") d.SetPartial("zone") if d.Get("attach").(bool) { @@ -160,8 +161,8 @@ func resourceCloudStackDiskRead(d *schema.ResourceData, meta interface{}) error d.Set("size", int(v.Size/(1024*1024*1024))) // Needed to get GB's again setValueOrUUID(d, "disk_offering", v.Diskofferingname, v.Diskofferingid) - setValueOrUUID(d, "zone", v.Zonename, v.Zoneid) setValueOrUUID(d, "project", v.Project, v.Projectid) + setValueOrUUID(d, "zone", v.Zonename, v.Zoneid) if v.Attached != "" { // Get the virtual machine details @@ -319,12 +320,12 @@ func resourceCloudStackDiskAttach(d *schema.ResourceData, meta interface{}) erro } // Attach the new volume - r, err := cs.Volume.AttachVolume(p) + r, err := Retry(4, retryableAttachVolumeFunc(cs, p)) if err != nil { return err } - d.SetId(r.Id) + d.SetId(r.(*cloudstack.AttachVolumeResponse).Id) return nil } @@ -386,6 +387,18 @@ func isAttached(cs *cloudstack.CloudStackClient, id string) (bool, error) { return v.Attached != "", nil } +func retryableAttachVolumeFunc( + cs *cloudstack.CloudStackClient, + p *cloudstack.AttachVolumeParams) func() (interface{}, error) { + return func() (interface{}, error) { + r, err := cs.Volume.AttachVolume(p) + if err != nil { + return nil, err + } + return r, nil + } +} + func retrieveDeviceID(device string) int64 { switch device { case "/dev/xvdb", "D:": @@ -426,87 +439,73 @@ func retrieveDeviceName(device int64, os string) string { case 1: if os == "Windows" { return "D:" - } else { - return "/dev/xvdb" } + return "/dev/xvdb" case 2: if os == "Windows" { return "E:" - } else { - return "/dev/xvdc" } + return "/dev/xvdc" case 4: if os == "Windows" { return "F:" - } else { - return "/dev/xvde" } + return "/dev/xvde" case 5: if os == "Windows" { return "G:" - } else { - return "/dev/xvdf" } + return "/dev/xvdf" case 6: if os == "Windows" { return "H:" - } else { - return "/dev/xvdg" } + return "/dev/xvdg" case 7: if os == "Windows" { return "I:" - } else { - return "/dev/xvdh" } + return "/dev/xvdh" case 8: if os == "Windows" { return "J:" - } else { - return "/dev/xvdi" } + return "/dev/xvdi" case 9: if os == "Windows" { return "K:" - } else { - return "/dev/xvdj" } + return "/dev/xvdj" case 10: if os == "Windows" { return "L:" - } else { - return "/dev/xvdk" } + return "/dev/xvdk" case 11: if os == "Windows" { return "M:" - } else { - return "/dev/xvdl" } + return "/dev/xvdl" case 12: if os == "Windows" { return "N:" - } else { - return "/dev/xvdm" } + return "/dev/xvdm" case 13: if os == "Windows" { return "O:" - } else { - return "/dev/xvdn" } + return "/dev/xvdn" case 14: if os == "Windows" { return "P:" - } else { - return "/dev/xvdo" } + return "/dev/xvdo" case 15: if os == "Windows" { return "Q:" - } else { - return "/dev/xvdp" } + return "/dev/xvdp" default: return "unknown" } diff --git a/builtin/providers/cloudstack/resource_cloudstack_ipaddress.go b/builtin/providers/cloudstack/resource_cloudstack_ipaddress.go index 054c3bb74..608514676 100644 --- a/builtin/providers/cloudstack/resource_cloudstack_ipaddress.go +++ b/builtin/providers/cloudstack/resource_cloudstack_ipaddress.go @@ -28,16 +28,16 @@ func resourceCloudStackIPAddress() *schema.Resource { ForceNew: true, }, - "ipaddress": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - }, - "project": &schema.Schema{ Type: schema.TypeString, Optional: true, ForceNew: true, }, + + "ipaddress": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, }, } } @@ -52,17 +52,6 @@ func resourceCloudStackIPAddressCreate(d *schema.ResourceData, meta interface{}) // Create a new parameter struct p := cs.Address.NewAssociateIpAddressParams() - // If there is a project supplied, we retreive and set the project id - if project, ok := d.GetOk("project"); ok { - // Retrieve the project UUID - projectid, e := retrieveUUID(cs, "project", project.(string)) - if e != nil { - return e.Error() - } - // Set the default project ID - p.SetProjectid(projectid) - } - if network, ok := d.GetOk("network"); ok { // Retrieve the network UUID networkid, e := retrieveUUID(cs, "network", network.(string)) @@ -85,6 +74,17 @@ func resourceCloudStackIPAddressCreate(d *schema.ResourceData, meta interface{}) p.SetVpcid(vpcid) } + // If there is a project supplied, we retreive and set the project id + if project, ok := d.GetOk("project"); ok { + // Retrieve the project UUID + projectid, e := retrieveUUID(cs, "project", project.(string)) + if e != nil { + return e.Error() + } + // Set the default project ID + p.SetProjectid(projectid) + } + // Associate a new IP address r, err := cs.Address.AssociateIpAddress(p) if err != nil { diff --git a/builtin/providers/cloudstack/resource_cloudstack_network.go b/builtin/providers/cloudstack/resource_cloudstack_network.go index eebac4d73..e6a19dd24 100644 --- a/builtin/providers/cloudstack/resource_cloudstack_network.go +++ b/builtin/providers/cloudstack/resource_cloudstack_network.go @@ -52,17 +52,17 @@ func resourceCloudStackNetwork() *schema.Resource { ForceNew: true, }, - "zone": &schema.Schema{ - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, - "project": &schema.Schema{ Type: schema.TypeString, Optional: true, ForceNew: true, }, + + "zone": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, }, } } @@ -93,17 +93,6 @@ func resourceCloudStackNetworkCreate(d *schema.ResourceData, meta interface{}) e // Create a new parameter struct p := cs.Network.NewCreateNetworkParams(displaytext.(string), name, networkofferingid, zoneid) - // If there is a project supplied, we retreive and set the project id - if project, ok := d.GetOk("project"); ok { - // Retrieve the project UUID - projectid, e := retrieveUUID(cs, "project", project.(string)) - if e != nil { - return e.Error() - } - // Set the default project ID - p.SetProjectid(projectid) - } - // Get the network details from the CIDR m, err := parseCIDR(d.Get("cidr").(string)) if err != nil { @@ -136,6 +125,17 @@ func resourceCloudStackNetworkCreate(d *schema.ResourceData, meta interface{}) e } } + // If there is a project supplied, we retreive and set the project id + if project, ok := d.GetOk("project"); ok { + // Retrieve the project UUID + projectid, e := retrieveUUID(cs, "project", project.(string)) + if e != nil { + return e.Error() + } + // Set the default project ID + p.SetProjectid(projectid) + } + // Create the new network r, err := cs.Network.CreateNetwork(p) if err != nil { @@ -168,8 +168,8 @@ func resourceCloudStackNetworkRead(d *schema.ResourceData, meta interface{}) err d.Set("cidr", n.Cidr) setValueOrUUID(d, "network_offering", n.Networkofferingname, n.Networkofferingid) - setValueOrUUID(d, "zone", n.Zonename, n.Zoneid) setValueOrUUID(d, "project", n.Project, n.Projectid) + setValueOrUUID(d, "zone", n.Zonename, n.Zoneid) return nil } diff --git a/builtin/providers/cloudstack/resource_cloudstack_port_forward.go b/builtin/providers/cloudstack/resource_cloudstack_port_forward.go index 4982356d6..3781fc1ae 100644 --- a/builtin/providers/cloudstack/resource_cloudstack_port_forward.go +++ b/builtin/providers/cloudstack/resource_cloudstack_port_forward.go @@ -224,10 +224,7 @@ func resourceCloudStackPortForwardRead(d *schema.ResourceData, meta interface{}) // Delete all expected UUIDs from the uuids map for _, forward := range forwards.List() { forward := forward.(map[string]interface{}) - - for _, id := range forward["uuids"].(map[string]interface{}) { - delete(uuids, id.(string)) - } + delete(uuids, forward["uuid"].(string)) } for uuid := range uuids { diff --git a/builtin/providers/cloudstack/resource_cloudstack_vpc.go b/builtin/providers/cloudstack/resource_cloudstack_vpc.go index 8926b6e7f..80e88a48e 100644 --- a/builtin/providers/cloudstack/resource_cloudstack_vpc.go +++ b/builtin/providers/cloudstack/resource_cloudstack_vpc.go @@ -40,16 +40,17 @@ func resourceCloudStackVPC() *schema.Resource { ForceNew: true, }, - "zone": &schema.Schema{ - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, "project": &schema.Schema{ Type: schema.TypeString, Optional: true, ForceNew: true, }, + + "zone": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, }, } } @@ -80,7 +81,7 @@ func resourceCloudStackVPCCreate(d *schema.ResourceData, meta interface{}) error // Create a new parameter struct p := cs.VPC.NewCreateVPCParams(d.Get("cidr").(string), displaytext.(string), name, vpcofferingid, zoneid) - // If there is a project supplied, we retreive and set the project id + // If there is a project supplied, we retreive and set the project id if project, ok := d.GetOk("project"); ok { // Retrieve the project UUID projectid, e := retrieveUUID(cs, "project", project.(string)) @@ -122,8 +123,6 @@ func resourceCloudStackVPCRead(d *schema.ResourceData, meta interface{}) error { d.Set("display_text", v.Displaytext) d.Set("cidr", v.Cidr) - setValueOrUUID(d, "zone", v.Zonename, v.Zoneid) - // Get the VPC offering details o, _, err := cs.VPC.GetVPCOfferingByID(v.Vpcofferingid) if err != nil { @@ -132,6 +131,7 @@ func resourceCloudStackVPCRead(d *schema.ResourceData, meta interface{}) error { setValueOrUUID(d, "vpc_offering", o.Name, v.Vpcofferingid) setValueOrUUID(d, "project", v.Project, v.Projectid) + setValueOrUUID(d, "zone", v.Zonename, v.Zoneid) return nil } diff --git a/website/source/docs/providers/cloudstack/r/disk.html.markdown b/website/source/docs/providers/cloudstack/r/disk.html.markdown index 2dbd40ee6..208927738 100644 --- a/website/source/docs/providers/cloudstack/r/disk.html.markdown +++ b/website/source/docs/providers/cloudstack/r/disk.html.markdown @@ -47,6 +47,9 @@ The following arguments are supported: * `virtual_machine` - (Optional) The name or ID of the virtual machine to which you want to attach the disk volume. +* `project` - (Optional) The name or ID of the project to deploy this + instance to. Changing this forces a new resource to be created. + * `zone` - (Required) The name or ID of the zone where this disk volume will be available. Changing this forces a new resource to be created. diff --git a/website/source/docs/providers/cloudstack/r/ipaddress.html.markdown b/website/source/docs/providers/cloudstack/r/ipaddress.html.markdown index 6a1f0517c..5b542993c 100644 --- a/website/source/docs/providers/cloudstack/r/ipaddress.html.markdown +++ b/website/source/docs/providers/cloudstack/r/ipaddress.html.markdown @@ -28,6 +28,9 @@ The following arguments are supported: * `vpc` - (Optional) The name or ID of the VPC for which an IP address should be acquired and associated. Changing this forces a new resource to be created. +* `project` - (Optional) The name or ID of the project to deploy this + instance to. Changing this forces a new resource to be created. + *NOTE: Either `network` or `vpc` should have a value!* ## Attributes Reference diff --git a/website/source/docs/providers/cloudstack/r/network.html.markdown b/website/source/docs/providers/cloudstack/r/network.html.markdown index 596755434..4feb566b9 100644 --- a/website/source/docs/providers/cloudstack/r/network.html.markdown +++ b/website/source/docs/providers/cloudstack/r/network.html.markdown @@ -43,6 +43,9 @@ The following arguments are supported: * `aclid` - (Optional) The ID of a network ACL that should be attached to the network. Changing this forces a new resource to be created. +* `project` - (Optional) The name or ID of the project to deploy this + instance to. Changing this forces a new resource to be created. + * `zone` - (Required) The name or ID of the zone where this disk volume will be available. Changing this forces a new resource to be created. diff --git a/website/source/docs/providers/cloudstack/r/vpc.html.markdown b/website/source/docs/providers/cloudstack/r/vpc.html.markdown index 1e40c6466..d77357631 100644 --- a/website/source/docs/providers/cloudstack/r/vpc.html.markdown +++ b/website/source/docs/providers/cloudstack/r/vpc.html.markdown @@ -37,6 +37,9 @@ The following arguments are supported: * `vpc_offering` - (Required) The name or ID of the VPC offering to use for this VPC. Changing this forces a new resource to be created. +* `project` - (Optional) The name or ID of the project to deploy this + instance to. Changing this forces a new resource to be created. + * `zone` - (Required) The name or ID of the zone where this disk volume will be available. Changing this forces a new resource to be created.