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