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  }