github.com/memsql/terraform@v0.7.0-rc2.0.20160706152241-21e2173e0a32/builtin/providers/openstack/resource_openstack_networking_floatingip_v2.go (about) 1 package openstack 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 11 "github.com/rackspace/gophercloud" 12 "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/layer3/floatingips" 13 "github.com/rackspace/gophercloud/openstack/networking/v2/networks" 14 "github.com/rackspace/gophercloud/pagination" 15 ) 16 17 func resourceNetworkingFloatingIPV2() *schema.Resource { 18 return &schema.Resource{ 19 Create: resourceNetworkFloatingIPV2Create, 20 Read: resourceNetworkFloatingIPV2Read, 21 Update: resourceNetworkFloatingIPV2Update, 22 Delete: resourceNetworkFloatingIPV2Delete, 23 24 Schema: map[string]*schema.Schema{ 25 "region": &schema.Schema{ 26 Type: schema.TypeString, 27 Required: true, 28 ForceNew: true, 29 DefaultFunc: schema.EnvDefaultFunc("OS_REGION_NAME", ""), 30 }, 31 "address": &schema.Schema{ 32 Type: schema.TypeString, 33 Computed: true, 34 }, 35 "pool": &schema.Schema{ 36 Type: schema.TypeString, 37 Required: true, 38 ForceNew: true, 39 DefaultFunc: schema.EnvDefaultFunc("OS_POOL_NAME", nil), 40 }, 41 "port_id": &schema.Schema{ 42 Type: schema.TypeString, 43 Optional: true, 44 Computed: true, 45 }, 46 "tenant_id": &schema.Schema{ 47 Type: schema.TypeString, 48 Optional: true, 49 Computed: true, 50 ForceNew: true, 51 }, 52 "fixed_ip": &schema.Schema{ 53 Type: schema.TypeString, 54 Optional: true, 55 Computed: true, 56 }, 57 }, 58 } 59 } 60 61 func resourceNetworkFloatingIPV2Create(d *schema.ResourceData, meta interface{}) error { 62 config := meta.(*Config) 63 networkingClient, err := config.networkingV2Client(d.Get("region").(string)) 64 if err != nil { 65 return fmt.Errorf("Error creating OpenStack network client: %s", err) 66 } 67 68 poolID, err := getNetworkID(d, meta, d.Get("pool").(string)) 69 if err != nil { 70 return fmt.Errorf("Error retrieving floating IP pool name: %s", err) 71 } 72 if len(poolID) == 0 { 73 return fmt.Errorf("No network found with name: %s", d.Get("pool").(string)) 74 } 75 createOpts := floatingips.CreateOpts{ 76 FloatingNetworkID: poolID, 77 PortID: d.Get("port_id").(string), 78 TenantID: d.Get("tenant_id").(string), 79 FixedIP: d.Get("fixed_ip").(string), 80 } 81 log.Printf("[DEBUG] Create Options: %#v", createOpts) 82 floatingIP, err := floatingips.Create(networkingClient, createOpts).Extract() 83 if err != nil { 84 return fmt.Errorf("Error allocating floating IP: %s", err) 85 } 86 87 log.Printf("[DEBUG] Waiting for OpenStack Neutron Floating IP (%s) to become available.", floatingIP.ID) 88 89 stateConf := &resource.StateChangeConf{ 90 Target: []string{"ACTIVE"}, 91 Refresh: waitForFloatingIPActive(networkingClient, floatingIP.ID), 92 Timeout: 2 * time.Minute, 93 Delay: 5 * time.Second, 94 MinTimeout: 3 * time.Second, 95 } 96 97 _, err = stateConf.WaitForState() 98 99 d.SetId(floatingIP.ID) 100 101 return resourceNetworkFloatingIPV2Read(d, meta) 102 } 103 104 func resourceNetworkFloatingIPV2Read(d *schema.ResourceData, meta interface{}) error { 105 config := meta.(*Config) 106 networkingClient, err := config.networkingV2Client(d.Get("region").(string)) 107 if err != nil { 108 return fmt.Errorf("Error creating OpenStack network client: %s", err) 109 } 110 111 floatingIP, err := floatingips.Get(networkingClient, d.Id()).Extract() 112 if err != nil { 113 return CheckDeleted(d, err, "floating IP") 114 } 115 116 d.Set("address", floatingIP.FloatingIP) 117 d.Set("port_id", floatingIP.PortID) 118 d.Set("fixed_ip", floatingIP.FixedIP) 119 poolName, err := getNetworkName(d, meta, floatingIP.FloatingNetworkID) 120 if err != nil { 121 return fmt.Errorf("Error retrieving floating IP pool name: %s", err) 122 } 123 d.Set("pool", poolName) 124 d.Set("tenant_id", floatingIP.TenantID) 125 126 return nil 127 } 128 129 func resourceNetworkFloatingIPV2Update(d *schema.ResourceData, meta interface{}) error { 130 config := meta.(*Config) 131 networkingClient, err := config.networkingV2Client(d.Get("region").(string)) 132 if err != nil { 133 return fmt.Errorf("Error creating OpenStack network client: %s", err) 134 } 135 136 var updateOpts floatingips.UpdateOpts 137 138 if d.HasChange("port_id") { 139 updateOpts.PortID = d.Get("port_id").(string) 140 } 141 142 log.Printf("[DEBUG] Update Options: %#v", updateOpts) 143 144 _, err = floatingips.Update(networkingClient, d.Id(), updateOpts).Extract() 145 if err != nil { 146 return fmt.Errorf("Error updating floating IP: %s", err) 147 } 148 149 return resourceNetworkFloatingIPV2Read(d, meta) 150 } 151 152 func resourceNetworkFloatingIPV2Delete(d *schema.ResourceData, meta interface{}) error { 153 config := meta.(*Config) 154 networkingClient, err := config.networkingV2Client(d.Get("region").(string)) 155 if err != nil { 156 return fmt.Errorf("Error creating OpenStack network client: %s", err) 157 } 158 159 stateConf := &resource.StateChangeConf{ 160 Pending: []string{"ACTIVE"}, 161 Target: []string{"DELETED"}, 162 Refresh: waitForFloatingIPDelete(networkingClient, d.Id()), 163 Timeout: 2 * time.Minute, 164 Delay: 5 * time.Second, 165 MinTimeout: 3 * time.Second, 166 } 167 168 _, err = stateConf.WaitForState() 169 if err != nil { 170 return fmt.Errorf("Error deleting OpenStack Neutron Floating IP: %s", err) 171 } 172 173 d.SetId("") 174 return nil 175 } 176 177 func getNetworkID(d *schema.ResourceData, meta interface{}, networkName string) (string, error) { 178 config := meta.(*Config) 179 networkingClient, err := config.networkingV2Client(d.Get("region").(string)) 180 if err != nil { 181 return "", fmt.Errorf("Error creating OpenStack network client: %s", err) 182 } 183 184 opts := networks.ListOpts{Name: networkName} 185 pager := networks.List(networkingClient, opts) 186 networkID := "" 187 188 err = pager.EachPage(func(page pagination.Page) (bool, error) { 189 networkList, err := networks.ExtractNetworks(page) 190 if err != nil { 191 return false, err 192 } 193 194 for _, n := range networkList { 195 if n.Name == networkName { 196 networkID = n.ID 197 return false, nil 198 } 199 } 200 201 return true, nil 202 }) 203 204 return networkID, err 205 } 206 207 func getNetworkName(d *schema.ResourceData, meta interface{}, networkID string) (string, error) { 208 config := meta.(*Config) 209 networkingClient, err := config.networkingV2Client(d.Get("region").(string)) 210 if err != nil { 211 return "", fmt.Errorf("Error creating OpenStack network client: %s", err) 212 } 213 214 opts := networks.ListOpts{ID: networkID} 215 pager := networks.List(networkingClient, opts) 216 networkName := "" 217 218 err = pager.EachPage(func(page pagination.Page) (bool, error) { 219 networkList, err := networks.ExtractNetworks(page) 220 if err != nil { 221 return false, err 222 } 223 224 for _, n := range networkList { 225 if n.ID == networkID { 226 networkName = n.Name 227 return false, nil 228 } 229 } 230 231 return true, nil 232 }) 233 234 return networkName, err 235 } 236 237 func waitForFloatingIPActive(networkingClient *gophercloud.ServiceClient, fId string) resource.StateRefreshFunc { 238 return func() (interface{}, string, error) { 239 f, err := floatingips.Get(networkingClient, fId).Extract() 240 if err != nil { 241 return nil, "", err 242 } 243 244 log.Printf("[DEBUG] OpenStack Neutron Floating IP: %+v", f) 245 if f.Status == "DOWN" || f.Status == "ACTIVE" { 246 return f, "ACTIVE", nil 247 } 248 249 return f, "", nil 250 } 251 } 252 253 func waitForFloatingIPDelete(networkingClient *gophercloud.ServiceClient, fId string) resource.StateRefreshFunc { 254 return func() (interface{}, string, error) { 255 log.Printf("[DEBUG] Attempting to delete OpenStack Floating IP %s.\n", fId) 256 257 f, err := floatingips.Get(networkingClient, fId).Extract() 258 if err != nil { 259 errCode, ok := err.(*gophercloud.UnexpectedResponseCodeError) 260 if !ok { 261 return f, "ACTIVE", err 262 } 263 if errCode.Actual == 404 { 264 log.Printf("[DEBUG] Successfully deleted OpenStack Floating IP %s", fId) 265 return f, "DELETED", nil 266 } 267 } 268 269 err = floatingips.Delete(networkingClient, fId).ExtractErr() 270 if err != nil { 271 errCode, ok := err.(*gophercloud.UnexpectedResponseCodeError) 272 if !ok { 273 return f, "ACTIVE", err 274 } 275 if errCode.Actual == 404 { 276 log.Printf("[DEBUG] Successfully deleted OpenStack Floating IP %s", fId) 277 return f, "DELETED", nil 278 } 279 } 280 281 log.Printf("[DEBUG] OpenStack Floating IP %s still active.\n", fId) 282 return f, "ACTIVE", nil 283 } 284 }