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