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