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