Skip to content

Commit 35b0e2b

Browse files
committed
Add AutoScaleVmProfile resource
1 parent 992d253 commit 35b0e2b

File tree

6 files changed

+594
-0
lines changed

6 files changed

+594
-0
lines changed

cloudstack/metadata.go

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package cloudstack
2+
3+
import (
4+
"log"
5+
6+
"github.com/hashicorp/terraform/helper/schema"
7+
"github.com/xanzy/go-cloudstack/cloudstack"
8+
)
9+
10+
// metadataSchema returns the schema to use for metadata
11+
func metadataSchema() *schema.Schema {
12+
return &schema.Schema{
13+
Type: schema.TypeMap,
14+
Optional: true,
15+
Computed: true,
16+
}
17+
}
18+
19+
// setMetadata is a helper to set the metadata for a resource. It expects the
20+
// metadata field to be named "metadata"
21+
func setMetadata(cs *cloudstack.CloudStackClient, d *schema.ResourceData, resourceType string) error {
22+
if metadata, ok := d.GetOk("metadata"); ok {
23+
p := cs.Resourcemetadata.NewAddResourceDetailParams(
24+
tagsFromSchema(metadata.(map[string]interface{})),
25+
d.Id(), resourceType,
26+
)
27+
_, err := cs.Resourcemetadata.AddResourceDetail(p)
28+
if err != nil {
29+
return err
30+
}
31+
}
32+
33+
return nil
34+
}
35+
36+
func getMetadata(cs *cloudstack.CloudStackClient, d *schema.ResourceData, resourceType string) (map[string]interface{}, error) {
37+
p := cs.Resourcemetadata.NewListResourceDetailsParams(resourceType)
38+
p.SetResourceid(d.Id())
39+
response, err := cs.Resourcemetadata.ListResourceDetails(p)
40+
if err != nil {
41+
return nil, err
42+
}
43+
// Only return metadata values that were explicitely set
44+
var existingFilter map[string]interface{}
45+
if metadata, ok := d.GetOk("metadata"); ok {
46+
existingFilter = metadata.(map[string]interface{})
47+
}
48+
metadata := make(map[string]interface{}, response.Count)
49+
for _, detail := range response.ResourceDetails {
50+
if _, ok := existingFilter[detail.Key]; ok {
51+
metadata[detail.Key] = detail.Value
52+
}
53+
}
54+
return metadata, nil
55+
}
56+
57+
// updateMetadata is a helper to update only when metadata field change metadata
58+
// field to be named "metadata"
59+
func updateMetadata(cs *cloudstack.CloudStackClient, d *schema.ResourceData, resourceType string) error {
60+
oraw, nraw := d.GetChange("metadata")
61+
o := oraw.(map[string]interface{})
62+
n := nraw.(map[string]interface{})
63+
64+
remove, create := diffTags(tagsFromSchema(o), tagsFromSchema(n))
65+
log.Printf("[DEBUG] metadata to remove: %v", remove)
66+
log.Printf("[DEBUG] metadata to create: %v", create)
67+
68+
// First remove any obsolete metadata
69+
if len(remove) > 0 {
70+
log.Printf("[DEBUG] Removing metadata: %v from %s", remove, d.Id())
71+
p := cs.Resourcemetadata.NewRemoveResourceDetailParams(d.Id(), resourceType)
72+
for key := range remove {
73+
p.SetKey(key)
74+
_, err := cs.Resourcemetadata.RemoveResourceDetail(p)
75+
if err != nil {
76+
return err
77+
}
78+
}
79+
}
80+
81+
// Then add any new metadata
82+
if len(create) > 0 {
83+
log.Printf("[DEBUG] Creating metadata: %v for %s", create, d.Id())
84+
p := cs.Resourcemetadata.NewAddResourceDetailParams(create, d.Id(), resourceType)
85+
_, err := cs.Resourcemetadata.AddResourceDetail(p)
86+
if err != nil {
87+
return err
88+
}
89+
}
90+
91+
return nil
92+
}

cloudstack/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ func Provider() terraform.ResourceProvider {
6464

6565
ResourcesMap: map[string]*schema.Resource{
6666
"cloudstack_affinity_group": resourceCloudStackAffinityGroup(),
67+
"cloudstack_autoscale_vm_profile": resourceCloudStackAutoScaleVMProfile(),
6768
"cloudstack_disk": resourceCloudStackDisk(),
6869
"cloudstack_egress_firewall": resourceCloudStackEgressFirewall(),
6970
"cloudstack_firewall": resourceCloudStackFirewall(),
Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
package cloudstack
2+
3+
import (
4+
"fmt"
5+
"log"
6+
"net/url"
7+
"strings"
8+
"time"
9+
10+
"github.com/hashicorp/terraform/helper/schema"
11+
"github.com/xanzy/go-cloudstack/cloudstack"
12+
)
13+
14+
func resourceCloudStackAutoScaleVMProfile() *schema.Resource {
15+
return &schema.Resource{
16+
Create: resourceCloudStackAutoScaleVMProfileCreate,
17+
Read: resourceCloudStackAutoScaleVMProfileRead,
18+
Update: resourceCloudStackAutoScaleVMProfileUpdate,
19+
Delete: resourceCloudStackAutoScaleVMProfileDelete,
20+
21+
Schema: map[string]*schema.Schema{
22+
"zone": {
23+
Type: schema.TypeString,
24+
Required: true,
25+
ForceNew: true,
26+
},
27+
28+
"service_offering": {
29+
Type: schema.TypeString,
30+
Required: true,
31+
ForceNew: true,
32+
},
33+
34+
"template": {
35+
Type: schema.TypeString,
36+
Required: true,
37+
},
38+
39+
"other_deploy_params": {
40+
Type: schema.TypeMap,
41+
Optional: true,
42+
Computed: true,
43+
ForceNew: true,
44+
},
45+
46+
"destroy_vm_grace_period": {
47+
Type: schema.TypeString,
48+
Optional: true,
49+
Computed: true,
50+
},
51+
52+
"metadata": metadataSchema(),
53+
},
54+
}
55+
}
56+
57+
func resourceCloudStackAutoScaleVMProfileCreate(d *schema.ResourceData, meta interface{}) error {
58+
cs := meta.(*cloudstack.CloudStackClient)
59+
60+
// Retrieve the service_offering ID
61+
serviceofferingid, e := retrieveID(cs, "service_offering", d.Get("service_offering").(string))
62+
if e != nil {
63+
return e.Error()
64+
}
65+
66+
// Retrieve the zone ID
67+
zoneid, e := retrieveID(cs, "zone", d.Get("zone").(string))
68+
if e != nil {
69+
return e.Error()
70+
}
71+
72+
// Retrieve the template ID
73+
templateid, e := retrieveTemplateID(cs, zoneid, d.Get("template").(string))
74+
if e != nil {
75+
return e.Error()
76+
}
77+
78+
p := cs.AutoScale.NewCreateAutoScaleVmProfileParams(serviceofferingid, templateid, zoneid)
79+
80+
if v, ok := d.GetOk("other_deploy_params"); ok {
81+
otherMap := v.(map[string]interface{})
82+
result := url.Values{}
83+
for k, v := range otherMap {
84+
result.Set(k, fmt.Sprint(v))
85+
}
86+
p.SetOtherdeployparams(result.Encode())
87+
}
88+
89+
if v, ok := d.GetOk("destroy_vm_grace_period"); ok {
90+
duration, err := time.ParseDuration(v.(string))
91+
if err != nil {
92+
return err
93+
}
94+
p.SetDestroyvmgraceperiod(int(duration.Seconds()))
95+
}
96+
97+
// Create the new vm profile
98+
r, err := cs.AutoScale.CreateAutoScaleVmProfile(p)
99+
if err != nil {
100+
return fmt.Errorf("Error creating AutoScaleVmProfile %s: %s", d.Id(), err)
101+
}
102+
103+
d.SetId(r.Id)
104+
105+
// Set metadata if necessary
106+
if err = setMetadata(cs, d, "AutoScaleVmProfile"); err != nil {
107+
return fmt.Errorf("Error setting metadata on the AutoScaleVmProfile %s: %s", d.Id(), err)
108+
}
109+
110+
return nil
111+
}
112+
113+
func resourceCloudStackAutoScaleVMProfileRead(d *schema.ResourceData, meta interface{}) error {
114+
cs := meta.(*cloudstack.CloudStackClient)
115+
116+
p, count, err := cs.AutoScale.GetAutoScaleVmProfileByID(d.Id())
117+
118+
if err != nil {
119+
if count == 0 {
120+
log.Printf(
121+
"[DEBUG] AutoScaleVmProfile %s no longer exists", d.Id())
122+
d.SetId("")
123+
return nil
124+
}
125+
126+
return err
127+
}
128+
129+
zone, _, err := cs.Zone.GetZoneByID(p.Zoneid)
130+
if err != nil {
131+
return err
132+
}
133+
134+
offering, _, err := cs.ServiceOffering.GetServiceOfferingByID(p.Serviceofferingid)
135+
if err != nil {
136+
return err
137+
}
138+
139+
template, _, err := cs.Template.GetTemplateByID(p.Templateid, "executable")
140+
if err != nil {
141+
return err
142+
}
143+
144+
setValueOrID(d, "zone", zone.Name, p.Zoneid)
145+
setValueOrID(d, "service_offering", offering.Name, p.Serviceofferingid)
146+
setValueOrID(d, "template", template.Name, p.Templateid)
147+
148+
if p.Otherdeployparams != "" {
149+
var values url.Values
150+
values, err = url.ParseQuery(p.Otherdeployparams)
151+
if err != nil {
152+
return err
153+
}
154+
otherParams := make(map[string]interface{}, len(values))
155+
for key := range values {
156+
otherParams[key] = values.Get(key)
157+
}
158+
d.Set("other_deploy_params", otherParams)
159+
}
160+
161+
d.Set("destroy_vm_grace_period", (time.Duration(p.Destroyvmgraceperiod) * time.Second).String())
162+
163+
metadata, err := getMetadata(cs, d, "AutoScaleVmProfile")
164+
if err != nil {
165+
return err
166+
}
167+
d.Set("metadata", metadata)
168+
169+
return nil
170+
}
171+
172+
func resourceCloudStackAutoScaleVMProfileUpdate(d *schema.ResourceData, meta interface{}) error {
173+
cs := meta.(*cloudstack.CloudStackClient)
174+
175+
// Create a new parameter struct
176+
p := cs.AutoScale.NewUpdateAutoScaleVmProfileParams(d.Id())
177+
178+
if d.HasChange("template") {
179+
zoneid, e := retrieveID(cs, "zone", d.Get("zone").(string))
180+
if e != nil {
181+
return e.Error()
182+
}
183+
templateid, e := retrieveTemplateID(cs, zoneid, d.Get("template").(string))
184+
if e != nil {
185+
return e.Error()
186+
}
187+
p.SetTemplateid(templateid)
188+
}
189+
190+
if d.HasChange("destroy_vm_grace_period") {
191+
duration, err := time.ParseDuration(d.Get("destroy_vm_grace_period").(string))
192+
if err != nil {
193+
return err
194+
}
195+
p.SetDestroyvmgraceperiod(int(duration.Seconds()))
196+
}
197+
198+
_, err := cs.AutoScale.UpdateAutoScaleVmProfile(p)
199+
if err != nil {
200+
return fmt.Errorf("Error updating AutoScaleVmProfile %s: %s", d.Id(), err)
201+
}
202+
203+
if d.HasChange("metadata") {
204+
if err := updateMetadata(cs, d, "AutoScaleVmProfile"); err != nil {
205+
return fmt.Errorf("Error updating tags on AutoScaleVmProfile %s: %s", d.Id(), err)
206+
}
207+
}
208+
209+
return resourceCloudStackAutoScaleVMProfileRead(d, meta)
210+
}
211+
212+
func resourceCloudStackAutoScaleVMProfileDelete(d *schema.ResourceData, meta interface{}) error {
213+
cs := meta.(*cloudstack.CloudStackClient)
214+
215+
// Create a new parameter struct
216+
p := cs.AutoScale.NewDeleteAutoScaleVmProfileParams(d.Id())
217+
218+
// Delete the template
219+
log.Printf("[INFO] Deleting AutoScaleVmProfile: %s", d.Id())
220+
_, err := cs.AutoScale.DeleteAutoScaleVmProfile(p)
221+
if err != nil {
222+
// This is a very poor way to be told the ID does no longer exist :(
223+
if strings.Contains(err.Error(), fmt.Sprintf(
224+
"Invalid parameter id value=%s due to incorrect long value format, "+
225+
"or entity does not exist", d.Id())) {
226+
return nil
227+
}
228+
229+
return fmt.Errorf("Error deleting AutoScaleVmProfile %s: %s", d.Id(), err)
230+
}
231+
return nil
232+
}

0 commit comments

Comments
 (0)