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