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