github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/cloudstack/resource_cloudstack_loadbalancer_rule.go (about)

     1  package cloudstack
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"strings"
     7  
     8  	"github.com/hashicorp/terraform/helper/schema"
     9  	"github.com/xanzy/go-cloudstack/cloudstack"
    10  )
    11  
    12  func resourceCloudStackLoadBalancerRule() *schema.Resource {
    13  	return &schema.Resource{
    14  		Create: resourceCloudStackLoadBalancerRuleCreate,
    15  		Read:   resourceCloudStackLoadBalancerRuleRead,
    16  		Update: resourceCloudStackLoadBalancerRuleUpdate,
    17  		Delete: resourceCloudStackLoadBalancerRuleDelete,
    18  
    19  		Schema: map[string]*schema.Schema{
    20  			"name": &schema.Schema{
    21  				Type:     schema.TypeString,
    22  				Required: true,
    23  			},
    24  
    25  			"description": &schema.Schema{
    26  				Type:     schema.TypeString,
    27  				Optional: true,
    28  				Computed: true,
    29  			},
    30  
    31  			"ip_address_id": &schema.Schema{
    32  				Type:     schema.TypeString,
    33  				Required: true,
    34  				ForceNew: true,
    35  			},
    36  
    37  			"network_id": &schema.Schema{
    38  				Type:     schema.TypeString,
    39  				Optional: true,
    40  				ForceNew: true,
    41  			},
    42  
    43  			"algorithm": &schema.Schema{
    44  				Type:     schema.TypeString,
    45  				Required: true,
    46  			},
    47  
    48  			"private_port": &schema.Schema{
    49  				Type:     schema.TypeInt,
    50  				Required: true,
    51  				ForceNew: true,
    52  			},
    53  
    54  			"public_port": &schema.Schema{
    55  				Type:     schema.TypeInt,
    56  				Required: true,
    57  				ForceNew: true,
    58  			},
    59  
    60  			"member_ids": &schema.Schema{
    61  				Type:     schema.TypeSet,
    62  				Required: true,
    63  				ForceNew: false,
    64  				Elem:     &schema.Schema{Type: schema.TypeString},
    65  				Set:      schema.HashString,
    66  			},
    67  
    68  			"project": &schema.Schema{
    69  				Type:     schema.TypeString,
    70  				Optional: true,
    71  				Computed: true,
    72  				ForceNew: true,
    73  			},
    74  		},
    75  	}
    76  }
    77  
    78  func resourceCloudStackLoadBalancerRuleCreate(d *schema.ResourceData, meta interface{}) error {
    79  	cs := meta.(*cloudstack.CloudStackClient)
    80  	d.Partial(true)
    81  
    82  	// Create a new parameter struct
    83  	p := cs.LoadBalancer.NewCreateLoadBalancerRuleParams(
    84  		d.Get("algorithm").(string),
    85  		d.Get("name").(string),
    86  		d.Get("private_port").(int),
    87  		d.Get("public_port").(int),
    88  	)
    89  
    90  	// Don't autocreate a firewall rule, use a resource if needed
    91  	p.SetOpenfirewall(false)
    92  
    93  	// Set the description
    94  	if description, ok := d.GetOk("description"); ok {
    95  		p.SetDescription(description.(string))
    96  	} else {
    97  		p.SetDescription(d.Get("name").(string))
    98  	}
    99  
   100  	if networkid, ok := d.GetOk("network_id"); ok {
   101  		// Set the network id
   102  		p.SetNetworkid(networkid.(string))
   103  	}
   104  
   105  	// Set the ipaddress id
   106  	p.SetPublicipid(d.Get("ip_address_id").(string))
   107  
   108  	// Create the load balancer rule
   109  	r, err := cs.LoadBalancer.CreateLoadBalancerRule(p)
   110  	if err != nil {
   111  		return err
   112  	}
   113  
   114  	// Set the load balancer rule ID and set partials
   115  	d.SetId(r.Id)
   116  	d.SetPartial("name")
   117  	d.SetPartial("description")
   118  	d.SetPartial("ip_address_id")
   119  	d.SetPartial("network_id")
   120  	d.SetPartial("algorithm")
   121  	d.SetPartial("private_port")
   122  	d.SetPartial("public_port")
   123  
   124  	// Create a new parameter struct
   125  	ap := cs.LoadBalancer.NewAssignToLoadBalancerRuleParams(r.Id)
   126  
   127  	var mbs []string
   128  	for _, id := range d.Get("member_ids").(*schema.Set).List() {
   129  		mbs = append(mbs, id.(string))
   130  	}
   131  
   132  	ap.SetVirtualmachineids(mbs)
   133  
   134  	_, err = cs.LoadBalancer.AssignToLoadBalancerRule(ap)
   135  	if err != nil {
   136  		return err
   137  	}
   138  
   139  	d.SetPartial("member_ids")
   140  	d.Partial(false)
   141  
   142  	return resourceCloudStackLoadBalancerRuleRead(d, meta)
   143  }
   144  
   145  func resourceCloudStackLoadBalancerRuleRead(d *schema.ResourceData, meta interface{}) error {
   146  	cs := meta.(*cloudstack.CloudStackClient)
   147  
   148  	// Get the load balancer details
   149  	lb, count, err := cs.LoadBalancer.GetLoadBalancerRuleByID(
   150  		d.Id(),
   151  		cloudstack.WithProject(d.Get("project").(string)),
   152  	)
   153  	if err != nil {
   154  		if count == 0 {
   155  			log.Printf("[DEBUG] Load balancer rule %s does no longer exist", d.Get("name").(string))
   156  			d.SetId("")
   157  			return nil
   158  		}
   159  
   160  		return err
   161  	}
   162  
   163  	d.Set("algorithm", lb.Algorithm)
   164  	d.Set("public_port", lb.Publicport)
   165  	d.Set("private_port", lb.Privateport)
   166  	d.Set("ip_address_id", lb.Publicipid)
   167  
   168  	// Only set network if user specified it to avoid spurious diffs
   169  	if _, ok := d.GetOk("network_id"); ok {
   170  		d.Set("network_id", lb.Networkid)
   171  	}
   172  
   173  	setValueOrID(d, "project", lb.Project, lb.Projectid)
   174  
   175  	p := cs.LoadBalancer.NewListLoadBalancerRuleInstancesParams(d.Id())
   176  	l, err := cs.LoadBalancer.ListLoadBalancerRuleInstances(p)
   177  	if err != nil {
   178  		return err
   179  	}
   180  
   181  	var mbs []string
   182  	for _, i := range l.LoadBalancerRuleInstances {
   183  		mbs = append(mbs, i.Id)
   184  	}
   185  	d.Set("member_ids", mbs)
   186  
   187  	return nil
   188  }
   189  
   190  func resourceCloudStackLoadBalancerRuleUpdate(d *schema.ResourceData, meta interface{}) error {
   191  	cs := meta.(*cloudstack.CloudStackClient)
   192  
   193  	if d.HasChange("name") || d.HasChange("description") || d.HasChange("algorithm") {
   194  		name := d.Get("name").(string)
   195  
   196  		// Create new parameter struct
   197  		p := cs.LoadBalancer.NewUpdateLoadBalancerRuleParams(d.Id())
   198  
   199  		if d.HasChange("name") {
   200  			log.Printf("[DEBUG] Name has changed for load balancer rule %s, starting update", name)
   201  
   202  			p.SetName(name)
   203  		}
   204  
   205  		if d.HasChange("description") {
   206  			log.Printf(
   207  				"[DEBUG] Description has changed for load balancer rule %s, starting update", name)
   208  
   209  			p.SetDescription(d.Get("description").(string))
   210  		}
   211  
   212  		if d.HasChange("algorithm") {
   213  			algorithm := d.Get("algorithm").(string)
   214  
   215  			log.Printf(
   216  				"[DEBUG] Algorithm has changed to %s for load balancer rule %s, starting update",
   217  				algorithm,
   218  				name,
   219  			)
   220  
   221  			// Set the new Algorithm
   222  			p.SetAlgorithm(algorithm)
   223  		}
   224  
   225  		_, err := cs.LoadBalancer.UpdateLoadBalancerRule(p)
   226  		if err != nil {
   227  			return fmt.Errorf(
   228  				"Error updating load balancer rule %s", name)
   229  		}
   230  	}
   231  
   232  	if d.HasChange("member_ids") {
   233  		o, n := d.GetChange("member_ids")
   234  		ombs, nmbs := o.(*schema.Set), n.(*schema.Set)
   235  
   236  		setToStringList := func(s *schema.Set) []string {
   237  			l := make([]string, s.Len())
   238  			for i, v := range s.List() {
   239  				l[i] = v.(string)
   240  			}
   241  			return l
   242  		}
   243  
   244  		membersToAdd := setToStringList(nmbs.Difference(ombs))
   245  		membersToRemove := setToStringList(ombs.Difference(nmbs))
   246  
   247  		log.Printf("[DEBUG] Members to add: %v, remove: %v", membersToAdd, membersToRemove)
   248  
   249  		if len(membersToAdd) > 0 {
   250  			p := cs.LoadBalancer.NewAssignToLoadBalancerRuleParams(d.Id())
   251  			p.SetVirtualmachineids(membersToAdd)
   252  			if _, err := cs.LoadBalancer.AssignToLoadBalancerRule(p); err != nil {
   253  				return err
   254  			}
   255  		}
   256  
   257  		if len(membersToRemove) > 0 {
   258  			p := cs.LoadBalancer.NewRemoveFromLoadBalancerRuleParams(d.Id())
   259  			p.SetVirtualmachineids(membersToRemove)
   260  			if _, err := cs.LoadBalancer.RemoveFromLoadBalancerRule(p); err != nil {
   261  				return err
   262  			}
   263  		}
   264  	}
   265  
   266  	return resourceCloudStackLoadBalancerRuleRead(d, meta)
   267  }
   268  
   269  func resourceCloudStackLoadBalancerRuleDelete(d *schema.ResourceData, meta interface{}) error {
   270  	cs := meta.(*cloudstack.CloudStackClient)
   271  
   272  	// Create a new parameter struct
   273  	p := cs.LoadBalancer.NewDeleteLoadBalancerRuleParams(d.Id())
   274  
   275  	log.Printf("[INFO] Deleting load balancer rule: %s", d.Get("name").(string))
   276  	if _, err := cs.LoadBalancer.DeleteLoadBalancerRule(p); err != nil {
   277  		// This is a very poor way to be told the ID does no longer exist :(
   278  		if !strings.Contains(err.Error(), fmt.Sprintf(
   279  			"Invalid parameter id value=%s due to incorrect long value format, "+
   280  				"or entity does not exist", d.Id())) {
   281  			return err
   282  		}
   283  	}
   284  
   285  	return nil
   286  }