github.com/turtlemonvh/terraform@v0.6.9-0.20151204001754-8e40b6b855e8/builtin/providers/packet/resource_packet_device.go (about)

     1  package packet
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"time"
     7  
     8  	"github.com/hashicorp/terraform/helper/resource"
     9  	"github.com/hashicorp/terraform/helper/schema"
    10  	"github.com/packethost/packngo"
    11  )
    12  
    13  func resourcePacketDevice() *schema.Resource {
    14  	return &schema.Resource{
    15  		Create: resourcePacketDeviceCreate,
    16  		Read:   resourcePacketDeviceRead,
    17  		Update: resourcePacketDeviceUpdate,
    18  		Delete: resourcePacketDeviceDelete,
    19  
    20  		Schema: map[string]*schema.Schema{
    21  			"project_id": &schema.Schema{
    22  				Type:     schema.TypeString,
    23  				Required: true,
    24  				ForceNew: true,
    25  			},
    26  
    27  			"hostname": &schema.Schema{
    28  				Type:     schema.TypeString,
    29  				Required: true,
    30  				ForceNew: true,
    31  			},
    32  
    33  			"operating_system": &schema.Schema{
    34  				Type:     schema.TypeString,
    35  				Required: true,
    36  				ForceNew: true,
    37  			},
    38  
    39  			"facility": &schema.Schema{
    40  				Type:     schema.TypeString,
    41  				Required: true,
    42  				ForceNew: true,
    43  			},
    44  
    45  			"plan": &schema.Schema{
    46  				Type:     schema.TypeString,
    47  				Required: true,
    48  				ForceNew: true,
    49  			},
    50  
    51  			"billing_cycle": &schema.Schema{
    52  				Type:     schema.TypeString,
    53  				Required: true,
    54  				ForceNew: true,
    55  			},
    56  
    57  			"state": &schema.Schema{
    58  				Type:     schema.TypeString,
    59  				Computed: true,
    60  			},
    61  
    62  			"locked": &schema.Schema{
    63  				Type:     schema.TypeBool,
    64  				Computed: true,
    65  			},
    66  
    67  			"network": &schema.Schema{
    68  				Type:     schema.TypeList,
    69  				Computed: true,
    70  				Elem: &schema.Resource{
    71  					Schema: map[string]*schema.Schema{
    72  						"address": &schema.Schema{
    73  							Type:     schema.TypeString,
    74  							Computed: true,
    75  						},
    76  
    77  						"gateway": &schema.Schema{
    78  							Type:     schema.TypeString,
    79  							Computed: true,
    80  						},
    81  
    82  						"family": &schema.Schema{
    83  							Type:     schema.TypeInt,
    84  							Computed: true,
    85  						},
    86  
    87  						"cidr": &schema.Schema{
    88  							Type:     schema.TypeInt,
    89  							Computed: true,
    90  						},
    91  
    92  						"public": &schema.Schema{
    93  							Type:     schema.TypeBool,
    94  							Computed: true,
    95  						},
    96  					},
    97  				},
    98  			},
    99  
   100  			"created": &schema.Schema{
   101  				Type:     schema.TypeString,
   102  				Computed: true,
   103  			},
   104  
   105  			"updated": &schema.Schema{
   106  				Type:     schema.TypeString,
   107  				Computed: true,
   108  			},
   109  
   110  			"user_data": &schema.Schema{
   111  				Type:     schema.TypeString,
   112  				Optional: true,
   113  			},
   114  
   115  			"tags": &schema.Schema{
   116  				Type:     schema.TypeList,
   117  				Optional: true,
   118  				Elem:     &schema.Schema{Type: schema.TypeString},
   119  			},
   120  		},
   121  	}
   122  }
   123  
   124  func resourcePacketDeviceCreate(d *schema.ResourceData, meta interface{}) error {
   125  	client := meta.(*packngo.Client)
   126  
   127  	createRequest := &packngo.DeviceCreateRequest{
   128  		HostName:     d.Get("hostname").(string),
   129  		Plan:         d.Get("plan").(string),
   130  		Facility:     d.Get("facility").(string),
   131  		OS:           d.Get("operating_system").(string),
   132  		BillingCycle: d.Get("billing_cycle").(string),
   133  		ProjectID:    d.Get("project_id").(string),
   134  	}
   135  
   136  	if attr, ok := d.GetOk("user_data"); ok {
   137  		createRequest.UserData = attr.(string)
   138  	}
   139  
   140  	tags := d.Get("tags.#").(int)
   141  	if tags > 0 {
   142  		createRequest.Tags = make([]string, 0, tags)
   143  		for i := 0; i < tags; i++ {
   144  			key := fmt.Sprintf("tags.%d", i)
   145  			createRequest.Tags = append(createRequest.Tags, d.Get(key).(string))
   146  		}
   147  	}
   148  
   149  	log.Printf("[DEBUG] Device create configuration: %#v", createRequest)
   150  
   151  	newDevice, _, err := client.Devices.Create(createRequest)
   152  	if err != nil {
   153  		return fmt.Errorf("Error creating device: %s", err)
   154  	}
   155  
   156  	// Assign the device id
   157  	d.SetId(newDevice.ID)
   158  
   159  	log.Printf("[INFO] Device ID: %s", d.Id())
   160  
   161  	_, err = WaitForDeviceAttribute(d, "active", []string{"queued", "provisioning"}, "state", meta)
   162  	if err != nil {
   163  		return fmt.Errorf(
   164  			"Error waiting for device (%s) to become ready: %s", d.Id(), err)
   165  	}
   166  
   167  	return resourcePacketDeviceRead(d, meta)
   168  }
   169  
   170  func resourcePacketDeviceRead(d *schema.ResourceData, meta interface{}) error {
   171  	client := meta.(*packngo.Client)
   172  
   173  	// Retrieve the device properties for updating the state
   174  	device, _, err := client.Devices.Get(d.Id())
   175  	if err != nil {
   176  		return fmt.Errorf("Error retrieving device: %s", err)
   177  	}
   178  
   179  	d.Set("name", device.Hostname)
   180  	d.Set("plan", device.Plan.Slug)
   181  	d.Set("facility", device.Facility.Code)
   182  	d.Set("operating_system", device.OS.Slug)
   183  	d.Set("state", device.State)
   184  	d.Set("billing_cycle", device.BillingCycle)
   185  	d.Set("locked", device.Locked)
   186  	d.Set("created", device.Created)
   187  	d.Set("updated", device.Updated)
   188  
   189  	tags := make([]string, 0)
   190  	for _, tag := range device.Tags {
   191  		tags = append(tags, tag)
   192  	}
   193  	d.Set("tags", tags)
   194  
   195  	provisionerAddress := ""
   196  
   197  	networks := make([]map[string]interface{}, 0, 1)
   198  	for _, ip := range device.Network {
   199  		network := make(map[string]interface{})
   200  		network["address"] = ip.Address
   201  		network["gateway"] = ip.Gateway
   202  		network["family"] = ip.Family
   203  		network["cidr"] = ip.Cidr
   204  		network["public"] = ip.Public
   205  		networks = append(networks, network)
   206  		if ip.Family == 4 && ip.Public == true {
   207  			provisionerAddress = ip.Address
   208  		}
   209  	}
   210  	d.Set("network", networks)
   211  
   212  	log.Printf("[DEBUG] Provisioner Address set to %v", provisionerAddress)
   213  
   214  	if provisionerAddress != "" {
   215  		d.SetConnInfo(map[string]string{
   216  			"type": "ssh",
   217  			"host": provisionerAddress,
   218  		})
   219  	}
   220  
   221  	return nil
   222  }
   223  
   224  func resourcePacketDeviceUpdate(d *schema.ResourceData, meta interface{}) error {
   225  	client := meta.(*packngo.Client)
   226  
   227  	if d.HasChange("locked") && d.Get("locked").(bool) {
   228  		_, err := client.Devices.Lock(d.Id())
   229  
   230  		if err != nil {
   231  			return fmt.Errorf(
   232  				"Error locking device (%s): %s", d.Id(), err)
   233  		}
   234  	} else if d.HasChange("locked") {
   235  		_, err := client.Devices.Unlock(d.Id())
   236  
   237  		if err != nil {
   238  			return fmt.Errorf(
   239  				"Error unlocking device (%s): %s", d.Id(), err)
   240  		}
   241  	}
   242  
   243  	return resourcePacketDeviceRead(d, meta)
   244  }
   245  
   246  func resourcePacketDeviceDelete(d *schema.ResourceData, meta interface{}) error {
   247  	client := meta.(*packngo.Client)
   248  
   249  	log.Printf("[INFO] Deleting device: %s", d.Id())
   250  	if _, err := client.Devices.Delete(d.Id()); err != nil {
   251  		return fmt.Errorf("Error deleting device: %s", err)
   252  	}
   253  
   254  	return nil
   255  }
   256  
   257  func WaitForDeviceAttribute(
   258  	d *schema.ResourceData, target string, pending []string, attribute string, meta interface{}) (interface{}, error) {
   259  	// Wait for the device so we can get the networking attributes
   260  	// that show up after a while
   261  	log.Printf(
   262  		"[INFO] Waiting for device (%s) to have %s of %s",
   263  		d.Id(), attribute, target)
   264  
   265  	stateConf := &resource.StateChangeConf{
   266  		Pending:    pending,
   267  		Target:     target,
   268  		Refresh:    newDeviceStateRefreshFunc(d, attribute, meta),
   269  		Timeout:    60 * time.Minute,
   270  		Delay:      10 * time.Second,
   271  		MinTimeout: 3 * time.Second,
   272  	}
   273  
   274  	return stateConf.WaitForState()
   275  }
   276  
   277  func newDeviceStateRefreshFunc(
   278  	d *schema.ResourceData, attribute string, meta interface{}) resource.StateRefreshFunc {
   279  	client := meta.(*packngo.Client)
   280  	return func() (interface{}, string, error) {
   281  		err := resourcePacketDeviceRead(d, meta)
   282  		if err != nil {
   283  			return nil, "", err
   284  		}
   285  
   286  		// See if we can access our attribute
   287  		if attr, ok := d.GetOk(attribute); ok {
   288  			// Retrieve the device properties
   289  			device, _, err := client.Devices.Get(d.Id())
   290  			if err != nil {
   291  				return nil, "", fmt.Errorf("Error retrieving device: %s", err)
   292  			}
   293  
   294  			return &device, attr.(string), nil
   295  		}
   296  
   297  		return nil, "", nil
   298  	}
   299  }
   300  
   301  // Powers on the device and waits for it to be active
   302  func powerOnAndWait(d *schema.ResourceData, meta interface{}) error {
   303  	client := meta.(*packngo.Client)
   304  	_, err := client.Devices.PowerOn(d.Id())
   305  	if err != nil {
   306  		return err
   307  	}
   308  
   309  	// Wait for power on
   310  	_, err = WaitForDeviceAttribute(d, "active", []string{"off"}, "state", client)
   311  	if err != nil {
   312  		return err
   313  	}
   314  
   315  	return nil
   316  }