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