github.com/vtorhonen/terraform@v0.9.0-beta2.0.20170307220345-5d894e4ffda7/builtin/providers/digitalocean/resource_digitalocean_loadbalancer.go (about)

     1  package digitalocean
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"strconv"
     7  	"time"
     8  
     9  	"github.com/digitalocean/godo"
    10  	"github.com/hashicorp/terraform/helper/resource"
    11  	"github.com/hashicorp/terraform/helper/schema"
    12  )
    13  
    14  func resourceDigitalOceanLoadbalancer() *schema.Resource {
    15  	return &schema.Resource{
    16  		Create: resourceDigitalOceanLoadbalancerCreate,
    17  		Read:   resourceDigitalOceanLoadbalancerRead,
    18  		Update: resourceDigitalOceanLoadbalancerUpdate,
    19  		Delete: resourceDigitalOceanLoadbalancerDelete,
    20  
    21  		Schema: map[string]*schema.Schema{
    22  			"name": {
    23  				Type:     schema.TypeString,
    24  				Required: true,
    25  			},
    26  
    27  			"region": {
    28  				Type:     schema.TypeString,
    29  				Required: true,
    30  				ForceNew: true,
    31  			},
    32  
    33  			"algorithm": {
    34  				Type:     schema.TypeString,
    35  				Optional: true,
    36  				Default:  "round_robin",
    37  			},
    38  
    39  			"forwarding_rule": {
    40  				Type:     schema.TypeList,
    41  				Required: true,
    42  				MinItems: 1,
    43  				Elem: &schema.Resource{
    44  					Schema: map[string]*schema.Schema{
    45  						"entry_protocol": {
    46  							Type:     schema.TypeString,
    47  							Required: true,
    48  						},
    49  						"entry_port": {
    50  							Type:     schema.TypeInt,
    51  							Required: true,
    52  						},
    53  						"target_protocol": {
    54  							Type:     schema.TypeString,
    55  							Required: true,
    56  						},
    57  						"target_port": {
    58  							Type:     schema.TypeInt,
    59  							Required: true,
    60  						},
    61  						"certificate_id": {
    62  							Type:     schema.TypeString,
    63  							Optional: true,
    64  						},
    65  						"tls_passthrough": {
    66  							Type:     schema.TypeBool,
    67  							Optional: true,
    68  							Default:  false,
    69  						},
    70  					},
    71  				},
    72  			},
    73  
    74  			"healthcheck": {
    75  				Type:     schema.TypeList,
    76  				Optional: true,
    77  				MaxItems: 1,
    78  				Elem: &schema.Resource{
    79  					Schema: map[string]*schema.Schema{
    80  						"protocol": {
    81  							Type:     schema.TypeString,
    82  							Required: true,
    83  						},
    84  						"port": {
    85  							Type:     schema.TypeInt,
    86  							Required: true,
    87  						},
    88  						"path": {
    89  							Type:     schema.TypeString,
    90  							Optional: true,
    91  						},
    92  						"check_interval_seconds": {
    93  							Type:     schema.TypeInt,
    94  							Optional: true,
    95  							Default:  10,
    96  						},
    97  						"response_timeout_seconds": {
    98  							Type:     schema.TypeInt,
    99  							Optional: true,
   100  							Default:  5,
   101  						},
   102  						"unhealthy_threshold": {
   103  							Type:     schema.TypeInt,
   104  							Optional: true,
   105  							Default:  3,
   106  						},
   107  						"healthy_threshold": {
   108  							Type:     schema.TypeInt,
   109  							Optional: true,
   110  							Default:  5,
   111  						},
   112  					},
   113  				},
   114  			},
   115  
   116  			"sticky_sessions": {
   117  				Type:     schema.TypeList,
   118  				Optional: true,
   119  				Computed: true, //this needs to be computed as the API returns a struct with none as the type
   120  				MaxItems: 1,
   121  				Elem: &schema.Resource{
   122  					Schema: map[string]*schema.Schema{
   123  						"type": {
   124  							Type:     schema.TypeString,
   125  							Optional: true,
   126  							Default:  "none",
   127  						},
   128  						"cookie_name": {
   129  							Type:     schema.TypeString,
   130  							Optional: true,
   131  						},
   132  						"cookie_ttl_seconds": {
   133  							Type:     schema.TypeInt,
   134  							Optional: true,
   135  						},
   136  					},
   137  				},
   138  			},
   139  
   140  			"droplet_ids": {
   141  				Type:     schema.TypeList,
   142  				Elem:     &schema.Schema{Type: schema.TypeString},
   143  				Optional: true,
   144  			},
   145  
   146  			"droplet_tag": {
   147  				Type:     schema.TypeString,
   148  				Optional: true,
   149  			},
   150  
   151  			"redirect_http_to_https": {
   152  				Type:     schema.TypeBool,
   153  				Optional: true,
   154  				Default:  false,
   155  			},
   156  
   157  			"ip": {
   158  				Type:     schema.TypeString,
   159  				Computed: true,
   160  			},
   161  		},
   162  	}
   163  }
   164  
   165  func buildLoadBalancerRequest(d *schema.ResourceData) (*godo.LoadBalancerRequest, error) {
   166  	opts := &godo.LoadBalancerRequest{
   167  		Name:                d.Get("name").(string),
   168  		Region:              d.Get("region").(string),
   169  		Algorithm:           d.Get("algorithm").(string),
   170  		RedirectHttpToHttps: d.Get("redirect_http_to_https").(bool),
   171  		ForwardingRules:     expandForwardingRules(d.Get("forwarding_rule").([]interface{})),
   172  	}
   173  
   174  	if v, ok := d.GetOk("droplet_ids"); ok {
   175  		var droplets []int
   176  		for _, id := range v.([]interface{}) {
   177  			i, err := strconv.Atoi(id.(string))
   178  			if err != nil {
   179  				return nil, err
   180  			}
   181  			droplets = append(droplets, i)
   182  		}
   183  
   184  		opts.DropletIDs = droplets
   185  	}
   186  
   187  	if v, ok := d.GetOk("droplet_tag"); ok {
   188  		opts.Tag = v.(string)
   189  	}
   190  
   191  	if v, ok := d.GetOk("healthcheck"); ok {
   192  		opts.HealthCheck = expandHealthCheck(v.([]interface{}))
   193  	}
   194  
   195  	if v, ok := d.GetOk("sticky_sessions"); ok {
   196  		opts.StickySessions = expandStickySessions(v.([]interface{}))
   197  	}
   198  
   199  	return opts, nil
   200  }
   201  
   202  func resourceDigitalOceanLoadbalancerCreate(d *schema.ResourceData, meta interface{}) error {
   203  	client := meta.(*godo.Client)
   204  
   205  	log.Printf("[INFO] Create a Loadbalancer Request")
   206  
   207  	lbOpts, err := buildLoadBalancerRequest(d)
   208  	if err != nil {
   209  		return err
   210  	}
   211  
   212  	log.Printf("[DEBUG] Loadbalancer Create: %#v", lbOpts)
   213  	loadbalancer, _, err := client.LoadBalancers.Create(lbOpts)
   214  	if err != nil {
   215  		return fmt.Errorf("Error creating Load Balancer: %s", err)
   216  	}
   217  
   218  	d.SetId(loadbalancer.ID)
   219  
   220  	log.Printf("[DEBUG] Waiting for Load Balancer (%s) to become active", d.Get("name"))
   221  	stateConf := &resource.StateChangeConf{
   222  		Pending:    []string{"new"},
   223  		Target:     []string{"active"},
   224  		Refresh:    loadbalancerStateRefreshFunc(client, d.Id()),
   225  		Timeout:    10 * time.Minute,
   226  		MinTimeout: 15 * time.Second,
   227  	}
   228  	if _, err := stateConf.WaitForState(); err != nil {
   229  		return fmt.Errorf("Error waiting for Load Balancer (%s) to become active: %s", d.Get("name"), err)
   230  	}
   231  
   232  	return resourceDigitalOceanLoadbalancerRead(d, meta)
   233  }
   234  
   235  func resourceDigitalOceanLoadbalancerRead(d *schema.ResourceData, meta interface{}) error {
   236  	client := meta.(*godo.Client)
   237  
   238  	log.Printf("[INFO] Reading the details of the Loadbalancer %s", d.Id())
   239  	loadbalancer, _, err := client.LoadBalancers.Get(d.Id())
   240  	if err != nil {
   241  		return fmt.Errorf("Error retrieving Loadbalancer: %s", err)
   242  	}
   243  
   244  	d.Set("name", loadbalancer.Name)
   245  	d.Set("ip", loadbalancer.IP)
   246  	d.Set("algorithm", loadbalancer.Algorithm)
   247  	d.Set("region", loadbalancer.Region.Slug)
   248  	d.Set("redirect_http_to_https", loadbalancer.RedirectHttpToHttps)
   249  	d.Set("droplet_ids", flattenDropletIds(loadbalancer.DropletIDs))
   250  	d.Set("droplet_tag", loadbalancer.Tag)
   251  
   252  	if err := d.Set("sticky_sessions", flattenStickySessions(loadbalancer.StickySessions)); err != nil {
   253  		return fmt.Errorf("[DEBUG] Error setting Load Balancer sticky_sessions - error: %#v", err)
   254  	}
   255  
   256  	if err := d.Set("healthcheck", flattenHealthChecks(loadbalancer.HealthCheck)); err != nil {
   257  		return fmt.Errorf("[DEBUG] Error setting Load Balancer healthcheck - error: %#v", err)
   258  	}
   259  
   260  	if err := d.Set("forwarding_rule", flattenForwardingRules(loadbalancer.ForwardingRules)); err != nil {
   261  		return fmt.Errorf("[DEBUG] Error setting Load Balancer forwarding_rule - error: %#v", err)
   262  	}
   263  
   264  	return nil
   265  
   266  }
   267  
   268  func resourceDigitalOceanLoadbalancerUpdate(d *schema.ResourceData, meta interface{}) error {
   269  	client := meta.(*godo.Client)
   270  
   271  	lbOpts, err := buildLoadBalancerRequest(d)
   272  	if err != nil {
   273  		return err
   274  	}
   275  
   276  	log.Printf("[DEBUG] Load Balancer Update: %#v", lbOpts)
   277  	_, _, err = client.LoadBalancers.Update(d.Id(), lbOpts)
   278  	if err != nil {
   279  		return fmt.Errorf("Error updating Load Balancer: %s", err)
   280  	}
   281  
   282  	return resourceDigitalOceanLoadbalancerRead(d, meta)
   283  }
   284  
   285  func resourceDigitalOceanLoadbalancerDelete(d *schema.ResourceData, meta interface{}) error {
   286  	client := meta.(*godo.Client)
   287  
   288  	log.Printf("[INFO] Deleting Load Balancer: %s", d.Id())
   289  	_, err := client.LoadBalancers.Delete(d.Id())
   290  	if err != nil {
   291  		return fmt.Errorf("Error deleting Load Balancer: %s", err)
   292  	}
   293  
   294  	d.SetId("")
   295  	return nil
   296  
   297  }