github.com/koding/terraform@v0.6.4-0.20170608090606-5d7e0339779d/builtin/providers/digitalocean/resource_digitalocean_floating_ip.go (about)

     1  package digitalocean
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"log"
     7  	"time"
     8  
     9  	"github.com/digitalocean/godo"
    10  	"github.com/hashicorp/terraform/helper/resource"
    11  	"github.com/hashicorp/terraform/helper/schema"
    12  )
    13  
    14  func resourceDigitalOceanFloatingIp() *schema.Resource {
    15  	return &schema.Resource{
    16  		Create: resourceDigitalOceanFloatingIpCreate,
    17  		Update: resourceDigitalOceanFloatingIpUpdate,
    18  		Read:   resourceDigitalOceanFloatingIpRead,
    19  		Delete: resourceDigitalOceanFloatingIpDelete,
    20  		Importer: &schema.ResourceImporter{
    21  			State: schema.ImportStatePassthrough,
    22  		},
    23  
    24  		Schema: map[string]*schema.Schema{
    25  			"ip_address": {
    26  				Type:     schema.TypeString,
    27  				Optional: true,
    28  				Computed: true,
    29  			},
    30  
    31  			"region": {
    32  				Type:     schema.TypeString,
    33  				Required: true,
    34  				ForceNew: true,
    35  			},
    36  
    37  			"droplet_id": {
    38  				Type:     schema.TypeInt,
    39  				Optional: true,
    40  			},
    41  		},
    42  	}
    43  }
    44  
    45  func resourceDigitalOceanFloatingIpCreate(d *schema.ResourceData, meta interface{}) error {
    46  	client := meta.(*godo.Client)
    47  
    48  	log.Printf("[INFO] Create a FloatingIP In a Region")
    49  	regionOpts := &godo.FloatingIPCreateRequest{
    50  		Region: d.Get("region").(string),
    51  	}
    52  
    53  	log.Printf("[DEBUG] FloatingIP Create: %#v", regionOpts)
    54  	floatingIp, _, err := client.FloatingIPs.Create(context.Background(), regionOpts)
    55  	if err != nil {
    56  		return fmt.Errorf("Error creating FloatingIP: %s", err)
    57  	}
    58  
    59  	d.SetId(floatingIp.IP)
    60  
    61  	if v, ok := d.GetOk("droplet_id"); ok {
    62  
    63  		log.Printf("[INFO] Assigning the Floating IP to the Droplet %d", v.(int))
    64  		action, _, err := client.FloatingIPActions.Assign(context.Background(), d.Id(), v.(int))
    65  		if err != nil {
    66  			return fmt.Errorf(
    67  				"Error Assigning FloatingIP (%s) to the droplet: %s", d.Id(), err)
    68  		}
    69  
    70  		_, unassignedErr := waitForFloatingIPReady(d, "completed", []string{"new", "in-progress"}, "status", meta, action.ID)
    71  		if unassignedErr != nil {
    72  			return fmt.Errorf(
    73  				"Error waiting for FloatingIP (%s) to be Assigned: %s", d.Id(), unassignedErr)
    74  		}
    75  	}
    76  
    77  	return resourceDigitalOceanFloatingIpRead(d, meta)
    78  }
    79  
    80  func resourceDigitalOceanFloatingIpUpdate(d *schema.ResourceData, meta interface{}) error {
    81  	client := meta.(*godo.Client)
    82  
    83  	if d.HasChange("droplet_id") {
    84  		if v, ok := d.GetOk("droplet_id"); ok {
    85  			log.Printf("[INFO] Assigning the Floating IP %s to the Droplet %d", d.Id(), v.(int))
    86  			action, _, err := client.FloatingIPActions.Assign(context.Background(), d.Id(), v.(int))
    87  			if err != nil {
    88  				return fmt.Errorf(
    89  					"Error Assigning FloatingIP (%s) to the droplet: %s", d.Id(), err)
    90  			}
    91  
    92  			_, unassignedErr := waitForFloatingIPReady(d, "completed", []string{"new", "in-progress"}, "status", meta, action.ID)
    93  			if unassignedErr != nil {
    94  				return fmt.Errorf(
    95  					"Error waiting for FloatingIP (%s) to be Assigned: %s", d.Id(), unassignedErr)
    96  			}
    97  		} else {
    98  			log.Printf("[INFO] Unassigning the Floating IP %s", d.Id())
    99  			action, _, err := client.FloatingIPActions.Unassign(context.Background(), d.Id())
   100  			if err != nil {
   101  				return fmt.Errorf(
   102  					"Error Unassigning FloatingIP (%s): %s", d.Id(), err)
   103  			}
   104  
   105  			_, unassignedErr := waitForFloatingIPReady(d, "completed", []string{"new", "in-progress"}, "status", meta, action.ID)
   106  			if unassignedErr != nil {
   107  				return fmt.Errorf(
   108  					"Error waiting for FloatingIP (%s) to be Unassigned: %s", d.Id(), unassignedErr)
   109  			}
   110  		}
   111  	}
   112  
   113  	return resourceDigitalOceanFloatingIpRead(d, meta)
   114  }
   115  
   116  func resourceDigitalOceanFloatingIpRead(d *schema.ResourceData, meta interface{}) error {
   117  	client := meta.(*godo.Client)
   118  
   119  	log.Printf("[INFO] Reading the details of the FloatingIP %s", d.Id())
   120  	floatingIp, _, err := client.FloatingIPs.Get(context.Background(), d.Id())
   121  	if err != nil {
   122  		return fmt.Errorf("Error retrieving FloatingIP: %s", err)
   123  	}
   124  
   125  	if floatingIp.Droplet != nil {
   126  		log.Printf("[INFO] A droplet was detected on the FloatingIP so setting the Region based on the Droplet")
   127  		log.Printf("[INFO] The region of the Droplet is %s", floatingIp.Droplet.Region.Slug)
   128  		d.Set("region", floatingIp.Droplet.Region.Slug)
   129  		d.Set("droplet_id", floatingIp.Droplet.ID)
   130  	} else {
   131  		d.Set("region", floatingIp.Region.Slug)
   132  	}
   133  
   134  	d.Set("ip_address", floatingIp.IP)
   135  
   136  	return nil
   137  }
   138  
   139  func resourceDigitalOceanFloatingIpDelete(d *schema.ResourceData, meta interface{}) error {
   140  	client := meta.(*godo.Client)
   141  
   142  	if _, ok := d.GetOk("droplet_id"); ok {
   143  		log.Printf("[INFO] Unassigning the Floating IP from the Droplet")
   144  		action, _, err := client.FloatingIPActions.Unassign(context.Background(), d.Id())
   145  		if err != nil {
   146  			return fmt.Errorf(
   147  				"Error Unassigning FloatingIP (%s) from the droplet: %s", d.Id(), err)
   148  		}
   149  
   150  		_, unassignedErr := waitForFloatingIPReady(d, "completed", []string{"new", "in-progress"}, "status", meta, action.ID)
   151  		if unassignedErr != nil {
   152  			return fmt.Errorf(
   153  				"Error waiting for FloatingIP (%s) to be unassigned: %s", d.Id(), unassignedErr)
   154  		}
   155  	}
   156  
   157  	log.Printf("[INFO] Deleting FloatingIP: %s", d.Id())
   158  	_, err := client.FloatingIPs.Delete(context.Background(), d.Id())
   159  	if err != nil {
   160  		return fmt.Errorf("Error deleting FloatingIP: %s", err)
   161  	}
   162  
   163  	d.SetId("")
   164  	return nil
   165  }
   166  
   167  func waitForFloatingIPReady(
   168  	d *schema.ResourceData, target string, pending []string, attribute string, meta interface{}, actionId int) (interface{}, error) {
   169  	log.Printf(
   170  		"[INFO] Waiting for FloatingIP (%s) to have %s of %s",
   171  		d.Id(), attribute, target)
   172  
   173  	stateConf := &resource.StateChangeConf{
   174  		Pending:    pending,
   175  		Target:     []string{target},
   176  		Refresh:    newFloatingIPStateRefreshFunc(d, attribute, meta, actionId),
   177  		Timeout:    60 * time.Minute,
   178  		Delay:      10 * time.Second,
   179  		MinTimeout: 3 * time.Second,
   180  
   181  		NotFoundChecks: 60,
   182  	}
   183  
   184  	return stateConf.WaitForState()
   185  }
   186  
   187  func newFloatingIPStateRefreshFunc(
   188  	d *schema.ResourceData, attribute string, meta interface{}, actionId int) resource.StateRefreshFunc {
   189  	client := meta.(*godo.Client)
   190  	return func() (interface{}, string, error) {
   191  
   192  		log.Printf("[INFO] Assigning the Floating IP to the Droplet")
   193  		action, _, err := client.FloatingIPActions.Get(context.Background(), d.Id(), actionId)
   194  		if err != nil {
   195  			return nil, "", fmt.Errorf("Error retrieving FloatingIP (%s) ActionId (%d): %s", d.Id(), actionId, err)
   196  		}
   197  
   198  		log.Printf("[INFO] The FloatingIP Action Status is %s", action.Status)
   199  		return &action, action.Status, nil
   200  	}
   201  }