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 }