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