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