github.com/jsoriano/terraform@v0.6.7-0.20151026070445-8b70867fdd95/builtin/providers/openstack/resource_openstack_lb_vip_v1.go (about)

     1  package openstack
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"strconv"
     7  
     8  	"github.com/hashicorp/terraform/helper/schema"
     9  	"github.com/rackspace/gophercloud"
    10  	"github.com/rackspace/gophercloud/openstack/networking/v2/extensions/layer3/floatingips"
    11  	"github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/vips"
    12  )
    13  
    14  func resourceLBVipV1() *schema.Resource {
    15  	return &schema.Resource{
    16  		Create: resourceLBVipV1Create,
    17  		Read:   resourceLBVipV1Read,
    18  		Update: resourceLBVipV1Update,
    19  		Delete: resourceLBVipV1Delete,
    20  
    21  		Schema: map[string]*schema.Schema{
    22  			"region": &schema.Schema{
    23  				Type:        schema.TypeString,
    24  				Required:    true,
    25  				ForceNew:    true,
    26  				DefaultFunc: envDefaultFuncAllowMissing("OS_REGION_NAME"),
    27  			},
    28  			"name": &schema.Schema{
    29  				Type:     schema.TypeString,
    30  				Required: true,
    31  				ForceNew: false,
    32  			},
    33  			"subnet_id": &schema.Schema{
    34  				Type:     schema.TypeString,
    35  				Required: true,
    36  				ForceNew: true,
    37  			},
    38  			"protocol": &schema.Schema{
    39  				Type:     schema.TypeString,
    40  				Required: true,
    41  				ForceNew: true,
    42  			},
    43  			"port": &schema.Schema{
    44  				Type:     schema.TypeInt,
    45  				Required: true,
    46  				ForceNew: true,
    47  			},
    48  			"pool_id": &schema.Schema{
    49  				Type:     schema.TypeString,
    50  				Required: true,
    51  				ForceNew: false,
    52  			},
    53  			"tenant_id": &schema.Schema{
    54  				Type:     schema.TypeString,
    55  				Optional: true,
    56  				ForceNew: true,
    57  			},
    58  			"address": &schema.Schema{
    59  				Type:     schema.TypeString,
    60  				Optional: true,
    61  				ForceNew: true,
    62  			},
    63  			"description": &schema.Schema{
    64  				Type:     schema.TypeString,
    65  				Optional: true,
    66  				ForceNew: false,
    67  			},
    68  			"persistence": &schema.Schema{
    69  				Type:     schema.TypeMap,
    70  				Optional: true,
    71  				ForceNew: false,
    72  			},
    73  			"conn_limit": &schema.Schema{
    74  				Type:     schema.TypeInt,
    75  				Optional: true,
    76  				ForceNew: false,
    77  			},
    78  			"port_id": &schema.Schema{
    79  				Type:     schema.TypeString,
    80  				Computed: true,
    81  				ForceNew: false,
    82  			},
    83  			"floating_ip": &schema.Schema{
    84  				Type:     schema.TypeString,
    85  				Optional: true,
    86  				ForceNew: false,
    87  			},
    88  			"admin_state_up": &schema.Schema{
    89  				Type:     schema.TypeString,
    90  				Optional: true,
    91  				ForceNew: false,
    92  			},
    93  		},
    94  	}
    95  }
    96  
    97  func resourceLBVipV1Create(d *schema.ResourceData, meta interface{}) error {
    98  	config := meta.(*Config)
    99  	networkingClient, err := config.networkingV2Client(d.Get("region").(string))
   100  	if err != nil {
   101  		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
   102  	}
   103  
   104  	createOpts := vips.CreateOpts{
   105  		Name:         d.Get("name").(string),
   106  		SubnetID:     d.Get("subnet_id").(string),
   107  		Protocol:     d.Get("protocol").(string),
   108  		ProtocolPort: d.Get("port").(int),
   109  		PoolID:       d.Get("pool_id").(string),
   110  		TenantID:     d.Get("tenant_id").(string),
   111  		Address:      d.Get("address").(string),
   112  		Description:  d.Get("description").(string),
   113  		Persistence:  resourceVipPersistenceV1(d),
   114  		ConnLimit:    gophercloud.MaybeInt(d.Get("conn_limit").(int)),
   115  	}
   116  
   117  	asuRaw := d.Get("admin_state_up").(string)
   118  	if asuRaw != "" {
   119  		asu, err := strconv.ParseBool(asuRaw)
   120  		if err != nil {
   121  			return fmt.Errorf("admin_state_up, if provided, must be either 'true' or 'false'")
   122  		}
   123  		createOpts.AdminStateUp = &asu
   124  	}
   125  
   126  	log.Printf("[DEBUG] Create Options: %#v", createOpts)
   127  	p, err := vips.Create(networkingClient, createOpts).Extract()
   128  	if err != nil {
   129  		return fmt.Errorf("Error creating OpenStack LB VIP: %s", err)
   130  	}
   131  	log.Printf("[INFO] LB VIP ID: %s", p.ID)
   132  
   133  	floatingIP := d.Get("floating_ip").(string)
   134  	if floatingIP != "" {
   135  		lbVipV1AssignFloatingIP(floatingIP, p.PortID, networkingClient)
   136  	}
   137  
   138  	d.SetId(p.ID)
   139  
   140  	return resourceLBVipV1Read(d, meta)
   141  }
   142  
   143  func resourceLBVipV1Read(d *schema.ResourceData, meta interface{}) error {
   144  	config := meta.(*Config)
   145  	networkingClient, err := config.networkingV2Client(d.Get("region").(string))
   146  	if err != nil {
   147  		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
   148  	}
   149  
   150  	p, err := vips.Get(networkingClient, d.Id()).Extract()
   151  	if err != nil {
   152  		return CheckDeleted(d, err, "LB VIP")
   153  	}
   154  
   155  	log.Printf("[DEBUG] Retreived OpenStack LB VIP %s: %+v", d.Id(), p)
   156  
   157  	d.Set("name", p.Name)
   158  	d.Set("subnet_id", p.SubnetID)
   159  	d.Set("protocol", p.Protocol)
   160  	d.Set("port", p.ProtocolPort)
   161  	d.Set("pool_id", p.PoolID)
   162  	d.Set("port_id", p.PortID)
   163  
   164  	if t, exists := d.GetOk("tenant_id"); exists && t != "" {
   165  		d.Set("tenant_id", p.TenantID)
   166  	} else {
   167  		d.Set("tenant_id", "")
   168  	}
   169  
   170  	if t, exists := d.GetOk("address"); exists && t != "" {
   171  		d.Set("address", p.Address)
   172  	} else {
   173  		d.Set("address", "")
   174  	}
   175  
   176  	if t, exists := d.GetOk("description"); exists && t != "" {
   177  		d.Set("description", p.Description)
   178  	} else {
   179  		d.Set("description", "")
   180  	}
   181  
   182  	if t, exists := d.GetOk("persistence"); exists && t != "" {
   183  		d.Set("persistence", p.Description)
   184  	}
   185  
   186  	if t, exists := d.GetOk("conn_limit"); exists && t != "" {
   187  		d.Set("conn_limit", p.ConnLimit)
   188  	} else {
   189  		d.Set("conn_limit", "")
   190  	}
   191  
   192  	if t, exists := d.GetOk("admin_state_up"); exists && t != "" {
   193  		d.Set("admin_state_up", strconv.FormatBool(p.AdminStateUp))
   194  	} else {
   195  		d.Set("admin_state_up", "")
   196  	}
   197  
   198  	return nil
   199  }
   200  
   201  func resourceLBVipV1Update(d *schema.ResourceData, meta interface{}) error {
   202  	config := meta.(*Config)
   203  	networkingClient, err := config.networkingV2Client(d.Get("region").(string))
   204  	if err != nil {
   205  		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
   206  	}
   207  
   208  	var updateOpts vips.UpdateOpts
   209  	if d.HasChange("name") {
   210  		updateOpts.Name = d.Get("name").(string)
   211  	}
   212  	if d.HasChange("pool_id") {
   213  		updateOpts.PoolID = d.Get("pool_id").(string)
   214  	}
   215  	if d.HasChange("description") {
   216  		updateOpts.Description = d.Get("description").(string)
   217  	}
   218  	if d.HasChange("persistence") {
   219  		updateOpts.Persistence = resourceVipPersistenceV1(d)
   220  	}
   221  	if d.HasChange("conn_limit") {
   222  		updateOpts.ConnLimit = gophercloud.MaybeInt(d.Get("conn_limit").(int))
   223  	}
   224  	if d.HasChange("floating_ip") {
   225  		portID := d.Get("port_id").(string)
   226  
   227  		// Searching for a floating IP assigned to the VIP
   228  		listOpts := floatingips.ListOpts{
   229  			PortID: portID,
   230  		}
   231  		page, err := floatingips.List(networkingClient, listOpts).AllPages()
   232  		if err != nil {
   233  			return err
   234  		}
   235  
   236  		fips, err := floatingips.ExtractFloatingIPs(page)
   237  		if err != nil {
   238  			return err
   239  		}
   240  
   241  		// If a floating IP is found we unassign it
   242  		if len(fips) == 1 {
   243  			updateOpts := floatingips.UpdateOpts{
   244  				PortID: "",
   245  			}
   246  			if err = floatingips.Update(networkingClient, fips[0].ID, updateOpts).Err; err != nil {
   247  				return err
   248  			}
   249  		}
   250  
   251  		// Assign the updated floating IP
   252  		floatingIP := d.Get("floating_ip").(string)
   253  		if floatingIP != "" {
   254  			lbVipV1AssignFloatingIP(floatingIP, portID, networkingClient)
   255  		}
   256  	}
   257  	if d.HasChange("admin_state_up") {
   258  		asuRaw := d.Get("admin_state_up").(string)
   259  		if asuRaw != "" {
   260  			asu, err := strconv.ParseBool(asuRaw)
   261  			if err != nil {
   262  				return fmt.Errorf("admin_state_up, if provided, must be either 'true' or 'false'")
   263  			}
   264  			updateOpts.AdminStateUp = &asu
   265  		}
   266  	}
   267  
   268  	log.Printf("[DEBUG] Updating OpenStack LB VIP %s with options: %+v", d.Id(), updateOpts)
   269  
   270  	_, err = vips.Update(networkingClient, d.Id(), updateOpts).Extract()
   271  	if err != nil {
   272  		return fmt.Errorf("Error updating OpenStack LB VIP: %s", err)
   273  	}
   274  
   275  	return resourceLBVipV1Read(d, meta)
   276  }
   277  
   278  func resourceLBVipV1Delete(d *schema.ResourceData, meta interface{}) error {
   279  	config := meta.(*Config)
   280  	networkingClient, err := config.networkingV2Client(d.Get("region").(string))
   281  	if err != nil {
   282  		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
   283  	}
   284  
   285  	err = vips.Delete(networkingClient, d.Id()).ExtractErr()
   286  	if err != nil {
   287  		return fmt.Errorf("Error deleting OpenStack LB VIP: %s", err)
   288  	}
   289  
   290  	d.SetId("")
   291  	return nil
   292  }
   293  
   294  func resourceVipPersistenceV1(d *schema.ResourceData) *vips.SessionPersistence {
   295  	rawP := d.Get("persistence").(interface{})
   296  	rawMap := rawP.(map[string]interface{})
   297  	if len(rawMap) != 0 {
   298  		p := vips.SessionPersistence{}
   299  		if t, ok := rawMap["type"]; ok {
   300  			p.Type = t.(string)
   301  		}
   302  		if c, ok := rawMap["cookie_name"]; ok {
   303  			p.CookieName = c.(string)
   304  		}
   305  		return &p
   306  	}
   307  	return nil
   308  }
   309  
   310  func lbVipV1AssignFloatingIP(floatingIP, portID string, networkingClient *gophercloud.ServiceClient) error {
   311  	log.Printf("[DEBUG] Assigning floating IP %s to VIP %s", floatingIP, portID)
   312  
   313  	listOpts := floatingips.ListOpts{
   314  		FloatingIP: floatingIP,
   315  	}
   316  	page, err := floatingips.List(networkingClient, listOpts).AllPages()
   317  	if err != nil {
   318  		return err
   319  	}
   320  
   321  	fips, err := floatingips.ExtractFloatingIPs(page)
   322  	if err != nil {
   323  		return err
   324  	}
   325  	if len(fips) != 1 {
   326  		return fmt.Errorf("Unable to retrieve floating IP '%s'", floatingIP)
   327  	}
   328  
   329  	updateOpts := floatingips.UpdateOpts{
   330  		PortID: portID,
   331  	}
   332  	if err = floatingips.Update(networkingClient, fips[0].ID, updateOpts).Err; err != nil {
   333  		return err
   334  	}
   335  
   336  	return nil
   337  }