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