github.com/hobbeswalsh/terraform@v0.3.7-0.20150619183303-ad17cf55a0fa/builtin/providers/cloudstack/resource_cloudstack_template.go (about) 1 package cloudstack 2 3 import ( 4 "fmt" 5 "log" 6 "strings" 7 "time" 8 9 "github.com/hashicorp/terraform/helper/schema" 10 "github.com/xanzy/go-cloudstack/cloudstack" 11 ) 12 13 func resourceCloudStackTemplate() *schema.Resource { 14 return &schema.Resource{ 15 Create: resourceCloudStackTemplateCreate, 16 Read: resourceCloudStackTemplateRead, 17 Update: resourceCloudStackTemplateUpdate, 18 Delete: resourceCloudStackTemplateDelete, 19 20 Schema: map[string]*schema.Schema{ 21 "name": &schema.Schema{ 22 Type: schema.TypeString, 23 Required: true, 24 }, 25 26 "display_text": &schema.Schema{ 27 Type: schema.TypeString, 28 Optional: true, 29 Computed: true, 30 }, 31 32 "format": &schema.Schema{ 33 Type: schema.TypeString, 34 Required: true, 35 }, 36 37 "hypervisor": &schema.Schema{ 38 Type: schema.TypeString, 39 Required: true, 40 ForceNew: true, 41 }, 42 43 "os_type": &schema.Schema{ 44 Type: schema.TypeString, 45 Required: true, 46 }, 47 48 "url": &schema.Schema{ 49 Type: schema.TypeString, 50 Required: true, 51 ForceNew: true, 52 }, 53 54 "zone": &schema.Schema{ 55 Type: schema.TypeString, 56 Required: true, 57 ForceNew: true, 58 }, 59 60 "is_dynamically_scalable": &schema.Schema{ 61 Type: schema.TypeBool, 62 Optional: true, 63 Computed: true, 64 }, 65 66 "is_extractable": &schema.Schema{ 67 Type: schema.TypeBool, 68 Optional: true, 69 Computed: true, 70 ForceNew: true, 71 }, 72 73 "is_featured": &schema.Schema{ 74 Type: schema.TypeBool, 75 Optional: true, 76 Computed: true, 77 ForceNew: true, 78 }, 79 80 "is_public": &schema.Schema{ 81 Type: schema.TypeBool, 82 Optional: true, 83 Computed: true, 84 }, 85 86 "password_enabled": &schema.Schema{ 87 Type: schema.TypeBool, 88 Optional: true, 89 Computed: true, 90 }, 91 92 "is_ready": &schema.Schema{ 93 Type: schema.TypeBool, 94 Computed: true, 95 }, 96 97 "is_ready_timeout": &schema.Schema{ 98 Type: schema.TypeInt, 99 Optional: true, 100 Default: 300, 101 }, 102 }, 103 } 104 } 105 106 func resourceCloudStackTemplateCreate(d *schema.ResourceData, meta interface{}) error { 107 cs := meta.(*cloudstack.CloudStackClient) 108 109 if err := verifyTemplateParams(d); err != nil { 110 return err 111 } 112 113 name := d.Get("name").(string) 114 115 // Compute/set the display text 116 displaytext := d.Get("display_text").(string) 117 if displaytext == "" { 118 displaytext = name 119 } 120 121 // Retrieve the os_type UUID 122 ostypeid, e := retrieveUUID(cs, "os_type", d.Get("os_type").(string)) 123 if e != nil { 124 return e.Error() 125 } 126 127 // Retrieve the zone UUID 128 zoneid, e := retrieveUUID(cs, "zone", d.Get("zone").(string)) 129 if e != nil { 130 return e.Error() 131 } 132 133 // Create a new parameter struct 134 p := cs.Template.NewRegisterTemplateParams( 135 displaytext, 136 d.Get("format").(string), 137 d.Get("hypervisor").(string), 138 name, 139 ostypeid, 140 d.Get("url").(string), 141 zoneid) 142 143 // Set optional parameters 144 if v, ok := d.GetOk("is_dynamically_scalable"); ok { 145 p.SetIsdynamicallyscalable(v.(bool)) 146 } 147 148 if v, ok := d.GetOk("is_extractable"); ok { 149 p.SetIsextractable(v.(bool)) 150 } 151 152 if v, ok := d.GetOk("is_featured"); ok { 153 p.SetIsfeatured(v.(bool)) 154 } 155 156 if v, ok := d.GetOk("is_public"); ok { 157 p.SetIspublic(v.(bool)) 158 } 159 160 if v, ok := d.GetOk("password_enabled"); ok { 161 p.SetPasswordenabled(v.(bool)) 162 } 163 164 // Create the new template 165 r, err := cs.Template.RegisterTemplate(p) 166 if err != nil { 167 return fmt.Errorf("Error creating template %s: %s", name, err) 168 } 169 170 d.SetId(r.RegisterTemplate[0].Id) 171 172 // Wait until the template is ready to use, or timeout with an error... 173 currentTime := time.Now().Unix() 174 timeout := int64(d.Get("is_ready_timeout").(int)) 175 for { 176 // Start with the sleep so the register action has a few seconds 177 // to process the registration correctly. Without this wait 178 time.Sleep(10 * time.Second) 179 180 err := resourceCloudStackTemplateRead(d, meta) 181 if err != nil { 182 return err 183 } 184 185 if d.Get("is_ready").(bool) { 186 return nil 187 } 188 189 if time.Now().Unix()-currentTime > timeout { 190 return fmt.Errorf("Timeout while waiting for template to become ready") 191 } 192 } 193 } 194 195 func resourceCloudStackTemplateRead(d *schema.ResourceData, meta interface{}) error { 196 cs := meta.(*cloudstack.CloudStackClient) 197 198 // Get the template details 199 t, count, err := cs.Template.GetTemplateByID(d.Id(), "executable") 200 if err != nil { 201 if count == 0 { 202 log.Printf( 203 "[DEBUG] Template %s no longer exists", d.Get("name").(string)) 204 d.SetId("") 205 return nil 206 } 207 208 return err 209 } 210 211 d.Set("name", t.Name) 212 d.Set("display_text", t.Displaytext) 213 d.Set("format", t.Format) 214 d.Set("hypervisor", t.Hypervisor) 215 d.Set("is_dynamically_scalable", t.Isdynamicallyscalable) 216 d.Set("is_extractable", t.Isextractable) 217 d.Set("is_featured", t.Isfeatured) 218 d.Set("is_public", t.Ispublic) 219 d.Set("password_enabled", t.Passwordenabled) 220 d.Set("is_ready", t.Isready) 221 222 setValueOrUUID(d, "os_type", t.Ostypename, t.Ostypeid) 223 setValueOrUUID(d, "zone", t.Zonename, t.Zoneid) 224 225 return nil 226 } 227 228 func resourceCloudStackTemplateUpdate(d *schema.ResourceData, meta interface{}) error { 229 cs := meta.(*cloudstack.CloudStackClient) 230 name := d.Get("name").(string) 231 232 // Create a new parameter struct 233 p := cs.Template.NewUpdateTemplateParams(d.Id()) 234 235 if d.HasChange("name") { 236 p.SetName(name) 237 } 238 239 if d.HasChange("display_text") { 240 p.SetDisplaytext(d.Get("display_text").(string)) 241 } 242 243 if d.HasChange("format") { 244 p.SetFormat(d.Get("format").(string)) 245 } 246 247 if d.HasChange("is_dynamically_scalable") { 248 p.SetIsdynamicallyscalable(d.Get("is_dynamically_scalable").(bool)) 249 } 250 251 if d.HasChange("os_type") { 252 ostypeid, e := retrieveUUID(cs, "os_type", d.Get("os_type").(string)) 253 if e != nil { 254 return e.Error() 255 } 256 p.SetOstypeid(ostypeid) 257 } 258 259 if d.HasChange("password_enabled") { 260 p.SetPasswordenabled(d.Get("password_enabled").(bool)) 261 } 262 263 _, err := cs.Template.UpdateTemplate(p) 264 if err != nil { 265 return fmt.Errorf("Error updating template %s: %s", name, err) 266 } 267 268 return resourceCloudStackTemplateRead(d, meta) 269 } 270 271 func resourceCloudStackTemplateDelete(d *schema.ResourceData, meta interface{}) error { 272 cs := meta.(*cloudstack.CloudStackClient) 273 274 // Create a new parameter struct 275 p := cs.Template.NewDeleteTemplateParams(d.Id()) 276 277 // Delete the template 278 log.Printf("[INFO] Deleting template: %s", d.Get("name").(string)) 279 _, err := cs.Template.DeleteTemplate(p) 280 if err != nil { 281 // This is a very poor way to be told the UUID does no longer exist :( 282 if strings.Contains(err.Error(), fmt.Sprintf( 283 "Invalid parameter id value=%s due to incorrect long value format, "+ 284 "or entity does not exist", d.Id())) { 285 return nil 286 } 287 288 return fmt.Errorf("Error deleting template %s: %s", d.Get("name").(string), err) 289 } 290 return nil 291 } 292 293 func verifyTemplateParams(d *schema.ResourceData) error { 294 format := d.Get("format").(string) 295 if format != "OVA" && format != "QCOW2" && format != "RAW" && format != "VHD" && format != "VMDK" { 296 return fmt.Errorf( 297 "%s is not a valid format. Valid options are 'OVA','QCOW2', 'RAW', 'VHD' and 'VMDK'", format) 298 } 299 300 return nil 301 }