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