github.com/anfernee/terraform@v0.6.16-0.20160430000239-06e5085a92f2/builtin/providers/clc/resource_clc_server.go (about) 1 package clc 2 3 import ( 4 "fmt" 5 "log" 6 "strings" 7 8 clc "github.com/CenturyLinkCloud/clc-sdk" 9 "github.com/CenturyLinkCloud/clc-sdk/api" 10 "github.com/CenturyLinkCloud/clc-sdk/server" 11 "github.com/CenturyLinkCloud/clc-sdk/status" 12 13 "github.com/hashicorp/terraform/helper/schema" 14 ) 15 16 func resourceCLCServer() *schema.Resource { 17 return &schema.Resource{ 18 Create: resourceCLCServerCreate, 19 Read: resourceCLCServerRead, 20 Update: resourceCLCServerUpdate, 21 Delete: resourceCLCServerDelete, 22 Schema: map[string]*schema.Schema{ 23 "name_template": &schema.Schema{ 24 Type: schema.TypeString, 25 Required: true, 26 }, 27 "name": &schema.Schema{ 28 Type: schema.TypeString, 29 Computed: true, 30 }, 31 "group_id": &schema.Schema{ 32 Type: schema.TypeString, 33 Required: true, 34 }, 35 "source_server_id": &schema.Schema{ 36 Type: schema.TypeString, 37 Required: true, 38 }, 39 "cpu": &schema.Schema{ 40 Type: schema.TypeInt, 41 Required: true, 42 }, 43 "memory_mb": &schema.Schema{ 44 Type: schema.TypeInt, 45 Required: true, 46 }, 47 "password": &schema.Schema{ 48 Type: schema.TypeString, 49 Required: true, 50 }, 51 // optional 52 "description": &schema.Schema{ 53 Type: schema.TypeString, 54 Optional: true, 55 Default: "", 56 }, 57 "type": &schema.Schema{ 58 Type: schema.TypeString, 59 Optional: true, 60 Default: "standard", 61 }, 62 "network_id": &schema.Schema{ 63 Type: schema.TypeString, 64 Optional: true, 65 }, 66 "custom_fields": &schema.Schema{ 67 Type: schema.TypeList, 68 Optional: true, 69 Elem: &schema.Schema{Type: schema.TypeMap}, 70 }, 71 "additional_disks": &schema.Schema{ 72 Type: schema.TypeList, 73 Optional: true, 74 Elem: &schema.Schema{Type: schema.TypeMap}, 75 }, 76 77 // optional: misc state storage. non-CLC field 78 "metadata": &schema.Schema{ 79 Type: schema.TypeMap, 80 Optional: true, 81 }, 82 83 // optional 84 "storage_type": &schema.Schema{ 85 Type: schema.TypeString, 86 Optional: true, 87 Default: "standard", 88 }, 89 90 // sorta computed 91 "private_ip_address": &schema.Schema{ 92 Type: schema.TypeString, 93 Optional: true, 94 Computed: true, 95 Default: nil, 96 }, 97 "power_state": &schema.Schema{ 98 Type: schema.TypeString, 99 Optional: true, 100 Computed: true, 101 Default: nil, 102 }, 103 104 // computed 105 "created_date": &schema.Schema{ 106 Type: schema.TypeString, 107 Computed: true, 108 }, 109 "modified_date": &schema.Schema{ 110 Type: schema.TypeString, 111 Computed: true, 112 }, 113 "public_ip_address": &schema.Schema{ 114 // RO: if a public_ip is on this server, populate it 115 Type: schema.TypeString, 116 Computed: true, 117 }, 118 }, 119 } 120 } 121 122 func resourceCLCServerCreate(d *schema.ResourceData, meta interface{}) error { 123 client := meta.(*clc.Client) 124 spec := server.Server{ 125 Name: d.Get("name_template").(string), 126 Password: d.Get("password").(string), 127 Description: d.Get("description").(string), 128 GroupID: d.Get("group_id").(string), 129 CPU: d.Get("cpu").(int), 130 MemoryGB: d.Get("memory_mb").(int) / 1024, 131 SourceServerID: d.Get("source_server_id").(string), 132 Type: d.Get("type").(string), 133 IPaddress: d.Get("private_ip_address").(string), 134 NetworkID: d.Get("network_id").(string), 135 Storagetype: d.Get("storage_type").(string), 136 } 137 138 var err error 139 disks, err := parseAdditionalDisks(d) 140 if err != nil { 141 return fmt.Errorf("Failed parsing disks: %v", err) 142 } 143 spec.Additionaldisks = disks 144 fields, err := parseCustomFields(d) 145 if err != nil { 146 return fmt.Errorf("Failed setting customfields: %v", err) 147 } 148 spec.Customfields = fields 149 150 resp, err := client.Server.Create(spec) 151 if err != nil || !resp.IsQueued { 152 return fmt.Errorf("Failed creating server: %v", err) 153 } 154 // server's UUID returned under rel=self link 155 _, uuid := resp.Links.GetID("self") 156 157 ok, st := resp.GetStatusID() 158 if !ok { 159 return fmt.Errorf("Failed extracting status to poll on %v: %v", resp, err) 160 } 161 err = waitStatus(client, st) 162 if err != nil { 163 return err 164 } 165 166 s, err := client.Server.Get(uuid) 167 d.SetId(strings.ToUpper(s.Name)) 168 log.Printf("[INFO] Server created. id: %v", s.Name) 169 return resourceCLCServerRead(d, meta) 170 } 171 172 func resourceCLCServerRead(d *schema.ResourceData, meta interface{}) error { 173 client := meta.(*clc.Client) 174 s, err := client.Server.Get(d.Id()) 175 if err != nil { 176 log.Printf("[INFO] Failed finding server: %v. Marking destroyed", d.Id()) 177 d.SetId("") 178 return nil 179 } 180 if len(s.Details.IPaddresses) > 0 { 181 d.Set("private_ip_address", s.Details.IPaddresses[0].Internal) 182 if "" != s.Details.IPaddresses[0].Public { 183 d.Set("public_ip_address", s.Details.IPaddresses[0].Public) 184 } 185 } 186 187 d.Set("name", s.Name) 188 d.Set("groupId", s.GroupID) 189 d.Set("status", s.Status) 190 d.Set("power_state", s.Details.Powerstate) 191 d.Set("cpu", s.Details.CPU) 192 d.Set("memory_mb", s.Details.MemoryMB) 193 d.Set("disk_gb", s.Details.Storagegb) 194 d.Set("status", s.Status) 195 d.Set("storage_type", s.Storagetype) 196 d.Set("created_date", s.ChangeInfo.CreatedDate) 197 d.Set("modified_date", s.ChangeInfo.ModifiedDate) 198 return nil 199 } 200 201 func resourceCLCServerUpdate(d *schema.ResourceData, meta interface{}) error { 202 client := meta.(*clc.Client) 203 id := d.Id() 204 205 var err error 206 var edits []api.Update 207 var updates []api.Update 208 var i int 209 210 poll := make(chan *status.Response, 1) 211 d.Partial(true) 212 s, err := client.Server.Get(id) 213 if err != nil { 214 return fmt.Errorf("Failed fetching server: %v - %v", d.Id(), err) 215 } 216 // edits happen synchronously 217 if delta, orig := d.Get("description").(string), s.Description; delta != orig { 218 d.SetPartial("description") 219 edits = append(edits, server.UpdateDescription(delta)) 220 } 221 if delta, orig := d.Get("group_id").(string), s.GroupID; delta != orig { 222 d.SetPartial("group_id") 223 edits = append(edits, server.UpdateGroup(delta)) 224 } 225 if len(edits) > 0 { 226 err = client.Server.Edit(id, edits...) 227 if err != nil { 228 return fmt.Errorf("Failed saving edits: %v", err) 229 } 230 } 231 // updates are queue processed 232 if d.HasChange("password") { 233 d.SetPartial("password") 234 o, _ := d.GetChange("password") 235 old := o.(string) 236 pass := d.Get("password").(string) 237 updates = append(updates, server.UpdateCredentials(old, pass)) 238 } 239 if i = d.Get("cpu").(int); i != s.Details.CPU { 240 d.SetPartial("cpu") 241 updates = append(updates, server.UpdateCPU(i)) 242 } 243 if i = d.Get("memory_mb").(int); i != s.Details.MemoryMB { 244 d.SetPartial("memory_mb") 245 updates = append(updates, server.UpdateMemory(i/1024)) // takes GB 246 } 247 248 if d.HasChange("custom_fields") { 249 d.SetPartial("custom_fields") 250 fields, err := parseCustomFields(d) 251 if err != nil { 252 return fmt.Errorf("Failed setting customfields: %v", err) 253 } 254 updates = append(updates, server.UpdateCustomfields(fields)) 255 } 256 if d.HasChange("additional_disks") { 257 d.SetPartial("additional_disks") 258 disks, err := parseAdditionalDisks(d) 259 if err != nil { 260 return fmt.Errorf("Failed parsing disks: %v", err) 261 } 262 updates = append(updates, server.UpdateAdditionaldisks(disks)) 263 } 264 265 if len(updates) > 0 { 266 resp, err := client.Server.Update(id, updates...) 267 if err != nil { 268 return fmt.Errorf("Failed saving updates: %v", err) 269 } 270 271 err = client.Status.Poll(resp.ID, poll) 272 if err != nil { 273 return err 274 } 275 status := <-poll 276 if status.Failed() { 277 return fmt.Errorf("Update failed") 278 } 279 log.Printf("[INFO] Server updated! status: %v", status.Status) 280 } 281 282 if d.HasChange("power_state") { 283 st := d.Get("power_state").(string) 284 log.Printf("[DEBUG] POWER: %v => %v", s.Details.Powerstate, st) 285 newst := stateFromString(st) 286 servers, err := client.Server.PowerState(newst, s.Name) 287 if err != nil { 288 return fmt.Errorf("Failed setting power state to: %v", newst) 289 } 290 ok, id := servers[0].GetStatusID() 291 if !ok { 292 return fmt.Errorf("Failed extracting power state queue status from: %v", servers[0]) 293 } 294 err = client.Status.Poll(id, poll) 295 if err != nil { 296 return err 297 } 298 status := <-poll 299 if status.Failed() { 300 return fmt.Errorf("Update failed") 301 } 302 log.Printf("[INFO] state updated: %v", status) 303 } 304 305 d.Partial(false) 306 return nil 307 } 308 309 func resourceCLCServerDelete(d *schema.ResourceData, meta interface{}) error { 310 client := meta.(*clc.Client) 311 id := d.Id() 312 resp, err := client.Server.Delete(id) 313 if err != nil || !resp.IsQueued { 314 return fmt.Errorf("Failed queueing delete of %v - %v", id, err) 315 } 316 317 ok, st := resp.GetStatusID() 318 if !ok { 319 return fmt.Errorf("Failed extracting status to poll on %v: %v", resp, err) 320 } 321 err = waitStatus(client, st) 322 if err != nil { 323 return err 324 } 325 log.Printf("[INFO] Server sucessfully deleted: %v", st) 326 return nil 327 }