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