github.com/minamijoyo/terraform@v0.7.8-0.20161029001309-18b3736ba44b/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(d.Get("region").(string)) 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(d.Get("region").(string)) 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 return nil 139 } 140 141 func resourceNetworkFloatingIPV2Update(d *schema.ResourceData, meta interface{}) error { 142 config := meta.(*Config) 143 networkingClient, err := config.networkingV2Client(d.Get("region").(string)) 144 if err != nil { 145 return fmt.Errorf("Error creating OpenStack network client: %s", err) 146 } 147 148 var updateOpts floatingips.UpdateOpts 149 150 if d.HasChange("port_id") { 151 portID := d.Get("port_id").(string) 152 updateOpts.PortID = &portID 153 } 154 155 log.Printf("[DEBUG] Update Options: %#v", updateOpts) 156 157 _, err = floatingips.Update(networkingClient, d.Id(), updateOpts).Extract() 158 if err != nil { 159 return fmt.Errorf("Error updating floating IP: %s", err) 160 } 161 162 return resourceNetworkFloatingIPV2Read(d, meta) 163 } 164 165 func resourceNetworkFloatingIPV2Delete(d *schema.ResourceData, meta interface{}) error { 166 config := meta.(*Config) 167 networkingClient, err := config.networkingV2Client(d.Get("region").(string)) 168 if err != nil { 169 return fmt.Errorf("Error creating OpenStack network client: %s", err) 170 } 171 172 stateConf := &resource.StateChangeConf{ 173 Pending: []string{"ACTIVE"}, 174 Target: []string{"DELETED"}, 175 Refresh: waitForFloatingIPDelete(networkingClient, d.Id()), 176 Timeout: 2 * time.Minute, 177 Delay: 5 * time.Second, 178 MinTimeout: 3 * time.Second, 179 } 180 181 _, err = stateConf.WaitForState() 182 if err != nil { 183 return fmt.Errorf("Error deleting OpenStack Neutron Floating IP: %s", err) 184 } 185 186 d.SetId("") 187 return nil 188 } 189 190 func getNetworkID(d *schema.ResourceData, meta interface{}, networkName string) (string, error) { 191 config := meta.(*Config) 192 networkingClient, err := config.networkingV2Client(d.Get("region").(string)) 193 if err != nil { 194 return "", fmt.Errorf("Error creating OpenStack network client: %s", err) 195 } 196 197 opts := networks.ListOpts{Name: networkName} 198 pager := networks.List(networkingClient, opts) 199 networkID := "" 200 201 err = pager.EachPage(func(page pagination.Page) (bool, error) { 202 networkList, err := networks.ExtractNetworks(page) 203 if err != nil { 204 return false, err 205 } 206 207 for _, n := range networkList { 208 if n.Name == networkName { 209 networkID = n.ID 210 return false, nil 211 } 212 } 213 214 return true, nil 215 }) 216 217 return networkID, err 218 } 219 220 func getNetworkName(d *schema.ResourceData, meta interface{}, networkID string) (string, error) { 221 config := meta.(*Config) 222 networkingClient, err := config.networkingV2Client(d.Get("region").(string)) 223 if err != nil { 224 return "", fmt.Errorf("Error creating OpenStack network client: %s", err) 225 } 226 227 opts := networks.ListOpts{ID: networkID} 228 pager := networks.List(networkingClient, opts) 229 networkName := "" 230 231 err = pager.EachPage(func(page pagination.Page) (bool, error) { 232 networkList, err := networks.ExtractNetworks(page) 233 if err != nil { 234 return false, err 235 } 236 237 for _, n := range networkList { 238 if n.ID == networkID { 239 networkName = n.Name 240 return false, nil 241 } 242 } 243 244 return true, nil 245 }) 246 247 return networkName, err 248 } 249 250 func waitForFloatingIPActive(networkingClient *gophercloud.ServiceClient, fId string) resource.StateRefreshFunc { 251 return func() (interface{}, string, error) { 252 f, err := floatingips.Get(networkingClient, fId).Extract() 253 if err != nil { 254 return nil, "", err 255 } 256 257 log.Printf("[DEBUG] OpenStack Neutron Floating IP: %+v", f) 258 if f.Status == "DOWN" || f.Status == "ACTIVE" { 259 return f, "ACTIVE", nil 260 } 261 262 return f, "", nil 263 } 264 } 265 266 func waitForFloatingIPDelete(networkingClient *gophercloud.ServiceClient, fId string) resource.StateRefreshFunc { 267 return func() (interface{}, string, error) { 268 log.Printf("[DEBUG] Attempting to delete OpenStack Floating IP %s.\n", fId) 269 270 f, err := floatingips.Get(networkingClient, fId).Extract() 271 if err != nil { 272 if _, ok := err.(gophercloud.ErrDefault404); ok { 273 log.Printf("[DEBUG] Successfully deleted OpenStack Floating IP %s", fId) 274 return f, "DELETED", nil 275 } 276 return f, "ACTIVE", err 277 } 278 279 err = floatingips.Delete(networkingClient, fId).ExtractErr() 280 if err != nil { 281 if _, ok := err.(gophercloud.ErrDefault404); ok { 282 log.Printf("[DEBUG] Successfully deleted OpenStack Floating IP %s", fId) 283 return f, "DELETED", nil 284 } 285 return f, "ACTIVE", err 286 } 287 288 log.Printf("[DEBUG] OpenStack Floating IP %s still active.\n", fId) 289 return f, "ACTIVE", nil 290 } 291 }