github.com/jdextraze/terraform@v0.6.17-0.20160511153921-e33847c8a8af/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 // optional 48 "description": &schema.Schema{ 49 Type: schema.TypeString, 50 Optional: true, 51 Default: "", 52 }, 53 "type": &schema.Schema{ 54 Type: schema.TypeString, 55 Optional: true, 56 Default: "standard", 57 }, 58 "network_id": &schema.Schema{ 59 Type: schema.TypeString, 60 Optional: true, 61 }, 62 "custom_fields": &schema.Schema{ 63 Type: schema.TypeList, 64 Optional: true, 65 Elem: &schema.Schema{Type: schema.TypeMap}, 66 }, 67 "additional_disks": &schema.Schema{ 68 Type: schema.TypeList, 69 Optional: true, 70 Elem: &schema.Schema{Type: schema.TypeMap}, 71 }, 72 "packages": &schema.Schema{ 73 Type: schema.TypeList, 74 Optional: true, 75 Elem: &schema.Schema{Type: schema.TypeMap}, 76 }, 77 78 // optional: misc state storage. non-CLC field 79 "metadata": &schema.Schema{ 80 Type: schema.TypeMap, 81 Optional: true, 82 }, 83 84 // optional 85 "storage_type": &schema.Schema{ 86 Type: schema.TypeString, 87 Optional: true, 88 Default: "standard", 89 }, 90 "aa_policy_id": &schema.Schema{ 91 Type: schema.TypeString, 92 Optional: true, 93 }, 94 95 // optional fields for bareMetal 96 "configuration_id": &schema.Schema{ 97 Type: schema.TypeString, 98 Optional: true, 99 }, 100 "os_type": &schema.Schema{ 101 Type: schema.TypeString, 102 Optional: true, 103 }, 104 105 // sorta computed 106 "password": &schema.Schema{ 107 Type: schema.TypeString, 108 Optional: true, 109 Computed: true, 110 Default: nil, 111 }, 112 "private_ip_address": &schema.Schema{ 113 Type: schema.TypeString, 114 Optional: true, 115 Computed: true, 116 Default: nil, 117 }, 118 "power_state": &schema.Schema{ 119 Type: schema.TypeString, 120 Optional: true, 121 Computed: true, 122 Default: nil, 123 }, 124 125 // computed 126 "created_date": &schema.Schema{ 127 Type: schema.TypeString, 128 Computed: true, 129 }, 130 "modified_date": &schema.Schema{ 131 Type: schema.TypeString, 132 Computed: true, 133 }, 134 "public_ip_address": &schema.Schema{ 135 // RO: if a public_ip is on this server, populate it 136 Type: schema.TypeString, 137 Computed: true, 138 }, 139 }, 140 } 141 } 142 143 func resourceCLCServerCreate(d *schema.ResourceData, meta interface{}) error { 144 client := meta.(*clc.Client) 145 spec := server.Server{ 146 Name: d.Get("name_template").(string), 147 Password: d.Get("password").(string), 148 Description: d.Get("description").(string), 149 GroupID: d.Get("group_id").(string), 150 CPU: d.Get("cpu").(int), 151 MemoryGB: d.Get("memory_mb").(int) / 1024, 152 SourceServerID: d.Get("source_server_id").(string), 153 Type: d.Get("type").(string), 154 IPaddress: d.Get("private_ip_address").(string), 155 NetworkID: d.Get("network_id").(string), 156 Storagetype: d.Get("storage_type").(string), 157 AntiAffinityPolicyID: d.Get("aa_policy_id").(string), 158 } 159 160 var err error 161 disks, err := parseAdditionalDisks(d) 162 if err != nil { 163 return fmt.Errorf("Failed parsing disks: %v", err) 164 } 165 spec.Additionaldisks = disks 166 fields, err := parseCustomFields(d) 167 if err != nil { 168 return fmt.Errorf("Failed setting customfields: %v", err) 169 } 170 spec.Customfields = fields 171 172 pkgs, err := parsePackages(d) 173 if err != nil { 174 return fmt.Errorf("Failed setting packages: %v", err) 175 } 176 spec.Packages = pkgs 177 178 if spec.Type == "bareMetal" { 179 // additional bareMetal fields 180 if conf_id := d.Get("configuration_id").(string); conf_id != "" { 181 spec.ConfigurationID = conf_id 182 } 183 if os_type := d.Get("os_type").(string); os_type != "" { 184 spec.OSType = os_type 185 } 186 } 187 188 resp, err := client.Server.Create(spec) 189 if err != nil || !resp.IsQueued { 190 return fmt.Errorf("Failed creating server: %v", err) 191 } 192 // server's UUID returned under rel=self link 193 _, uuid := resp.Links.GetID("self") 194 195 ok, st := resp.GetStatusID() 196 if !ok { 197 return fmt.Errorf("Failed extracting status to poll on %v: %v", resp, err) 198 } 199 err = waitStatus(client, st) 200 if err != nil { 201 return err 202 } 203 204 s, err := client.Server.Get(uuid) 205 d.SetId(strings.ToUpper(s.Name)) 206 log.Printf("[INFO] Server created. id: %v", s.Name) 207 return resourceCLCServerRead(d, meta) 208 } 209 210 func resourceCLCServerRead(d *schema.ResourceData, meta interface{}) error { 211 client := meta.(*clc.Client) 212 s, err := client.Server.Get(d.Id()) 213 if err != nil { 214 log.Printf("[INFO] Failed finding server: %v. Marking destroyed", d.Id()) 215 d.SetId("") 216 return nil 217 } 218 if len(s.Details.IPaddresses) > 0 { 219 d.Set("private_ip_address", s.Details.IPaddresses[0].Internal) 220 if "" != s.Details.IPaddresses[0].Public { 221 d.Set("public_ip_address", s.Details.IPaddresses[0].Public) 222 } 223 } 224 225 d.Set("name", s.Name) 226 d.Set("groupId", s.GroupID) 227 d.Set("status", s.Status) 228 d.Set("power_state", s.Details.Powerstate) 229 d.Set("cpu", s.Details.CPU) 230 d.Set("memory_mb", s.Details.MemoryMB) 231 d.Set("disk_gb", s.Details.Storagegb) 232 d.Set("status", s.Status) 233 d.Set("storage_type", s.Storagetype) 234 d.Set("created_date", s.ChangeInfo.CreatedDate) 235 d.Set("modified_date", s.ChangeInfo.ModifiedDate) 236 237 creds, err := client.Server.GetCredentials(d.Id()) 238 if err != nil { 239 return err 240 } 241 d.Set("password", creds.Password) 242 return nil 243 } 244 245 func resourceCLCServerUpdate(d *schema.ResourceData, meta interface{}) error { 246 client := meta.(*clc.Client) 247 id := d.Id() 248 249 var err error 250 var edits []api.Update 251 var updates []api.Update 252 var i int 253 254 poll := make(chan *status.Response, 1) 255 d.Partial(true) 256 s, err := client.Server.Get(id) 257 if err != nil { 258 return fmt.Errorf("Failed fetching server: %v - %v", d.Id(), err) 259 } 260 // edits happen synchronously 261 if delta, orig := d.Get("description").(string), s.Description; delta != orig { 262 d.SetPartial("description") 263 edits = append(edits, server.UpdateDescription(delta)) 264 } 265 if delta, orig := d.Get("group_id").(string), s.GroupID; delta != orig { 266 d.SetPartial("group_id") 267 edits = append(edits, server.UpdateGroup(delta)) 268 } 269 if len(edits) > 0 { 270 err = client.Server.Edit(id, edits...) 271 if err != nil { 272 return fmt.Errorf("Failed saving edits: %v", err) 273 } 274 } 275 // updates are queue processed 276 if d.HasChange("password") { 277 d.SetPartial("password") 278 creds, _ := client.Server.GetCredentials(id) 279 old := creds.Password 280 pass := d.Get("password").(string) 281 updates = append(updates, server.UpdateCredentials(old, pass)) 282 } 283 if i = d.Get("cpu").(int); i != s.Details.CPU { 284 d.SetPartial("cpu") 285 updates = append(updates, server.UpdateCPU(i)) 286 } 287 if i = d.Get("memory_mb").(int); i != s.Details.MemoryMB { 288 d.SetPartial("memory_mb") 289 updates = append(updates, server.UpdateMemory(i/1024)) // takes GB 290 } 291 292 if d.HasChange("custom_fields") { 293 d.SetPartial("custom_fields") 294 fields, err := parseCustomFields(d) 295 if err != nil { 296 return fmt.Errorf("Failed setting customfields: %v", err) 297 } 298 updates = append(updates, server.UpdateCustomfields(fields)) 299 } 300 if d.HasChange("additional_disks") { 301 d.SetPartial("additional_disks") 302 disks, err := parseAdditionalDisks(d) 303 if err != nil { 304 return fmt.Errorf("Failed parsing disks: %v", err) 305 } 306 updates = append(updates, server.UpdateAdditionaldisks(disks)) 307 } 308 309 if len(updates) > 0 { 310 resp, err := client.Server.Update(id, updates...) 311 if err != nil { 312 return fmt.Errorf("Failed saving updates: %v", err) 313 } 314 315 err = client.Status.Poll(resp.ID, poll) 316 if err != nil { 317 return err 318 } 319 status := <-poll 320 if status.Failed() { 321 return fmt.Errorf("Update failed") 322 } 323 log.Printf("[INFO] Server updated! status: %v", status.Status) 324 } 325 326 if d.HasChange("power_state") { 327 st := d.Get("power_state").(string) 328 log.Printf("[DEBUG] POWER: %v => %v", s.Details.Powerstate, st) 329 newst := stateFromString(st) 330 servers, err := client.Server.PowerState(newst, s.Name) 331 if err != nil { 332 return fmt.Errorf("Failed setting power state to: %v", newst) 333 } 334 ok, id := servers[0].GetStatusID() 335 if !ok { 336 return fmt.Errorf("Failed extracting power state queue status from: %v", servers[0]) 337 } 338 err = client.Status.Poll(id, poll) 339 if err != nil { 340 return err 341 } 342 status := <-poll 343 if status.Failed() { 344 return fmt.Errorf("Update failed") 345 } 346 log.Printf("[INFO] state updated: %v", status) 347 } 348 349 d.Partial(false) 350 return resourceCLCServerRead(d, meta) 351 } 352 353 func resourceCLCServerDelete(d *schema.ResourceData, meta interface{}) error { 354 client := meta.(*clc.Client) 355 id := d.Id() 356 resp, err := client.Server.Delete(id) 357 if err != nil || !resp.IsQueued { 358 return fmt.Errorf("Failed queueing delete of %v - %v", id, err) 359 } 360 361 ok, st := resp.GetStatusID() 362 if !ok { 363 return fmt.Errorf("Failed extracting status to poll on %v: %v", resp, err) 364 } 365 err = waitStatus(client, st) 366 if err != nil { 367 return err 368 } 369 log.Printf("[INFO] Server sucessfully deleted: %v", st) 370 return nil 371 }