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