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 }