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