github.com/vtorhonen/terraform@v0.9.0-beta2.0.20170307220345-5d894e4ffda7/builtin/providers/alicloud/resource_alicloud_slb.go (about) 1 package alicloud 2 3 import ( 4 "bytes" 5 "fmt" 6 "strings" 7 8 "github.com/denverdino/aliyungo/common" 9 "github.com/denverdino/aliyungo/slb" 10 "github.com/hashicorp/terraform/helper/hashcode" 11 "github.com/hashicorp/terraform/helper/resource" 12 "github.com/hashicorp/terraform/helper/schema" 13 "time" 14 ) 15 16 func resourceAliyunSlb() *schema.Resource { 17 return &schema.Resource{ 18 Create: resourceAliyunSlbCreate, 19 Read: resourceAliyunSlbRead, 20 Update: resourceAliyunSlbUpdate, 21 Delete: resourceAliyunSlbDelete, 22 23 Schema: map[string]*schema.Schema{ 24 "name": &schema.Schema{ 25 Type: schema.TypeString, 26 Optional: true, 27 ValidateFunc: validateSlbName, 28 Computed: true, 29 }, 30 31 "internet": &schema.Schema{ 32 Type: schema.TypeBool, 33 Optional: true, 34 ForceNew: true, 35 }, 36 37 "vswitch_id": &schema.Schema{ 38 Type: schema.TypeString, 39 Optional: true, 40 ForceNew: true, 41 }, 42 43 "internet_charge_type": &schema.Schema{ 44 Type: schema.TypeString, 45 Optional: true, 46 ForceNew: true, 47 Default: "paybytraffic", 48 ValidateFunc: validateSlbInternetChargeType, 49 }, 50 51 "bandwidth": &schema.Schema{ 52 Type: schema.TypeInt, 53 Optional: true, 54 ValidateFunc: validateSlbBandwidth, 55 Computed: true, 56 }, 57 58 "listener": &schema.Schema{ 59 Type: schema.TypeSet, 60 Optional: true, 61 Elem: &schema.Resource{ 62 Schema: map[string]*schema.Schema{ 63 "instance_port": &schema.Schema{ 64 Type: schema.TypeInt, 65 ValidateFunc: validateInstancePort, 66 Required: true, 67 }, 68 69 "lb_port": &schema.Schema{ 70 Type: schema.TypeInt, 71 ValidateFunc: validateInstancePort, 72 Required: true, 73 }, 74 75 "lb_protocol": &schema.Schema{ 76 Type: schema.TypeString, 77 ValidateFunc: validateInstanceProtocol, 78 Required: true, 79 }, 80 81 "bandwidth": &schema.Schema{ 82 Type: schema.TypeInt, 83 ValidateFunc: validateSlbListenerBandwidth, 84 Required: true, 85 }, 86 //http 87 "scheduler": &schema.Schema{ 88 Type: schema.TypeString, 89 ValidateFunc: validateSlbListenerScheduler, 90 Optional: true, 91 Default: "wrr", 92 }, 93 94 "sticky_session": &schema.Schema{ 95 Type: schema.TypeString, 96 ValidateFunc: validateSlbListenerStickySession, 97 Optional: true, 98 }, 99 "sticky_session_type": &schema.Schema{ 100 Type: schema.TypeString, 101 ValidateFunc: validateSlbListenerStickySessionType, 102 Optional: true, 103 }, 104 "cookie": &schema.Schema{ 105 Type: schema.TypeString, 106 ValidateFunc: validateSlbListenerCookie, 107 Optional: true, 108 }, 109 "PersistenceTimeout": &schema.Schema{ 110 Type: schema.TypeInt, 111 ValidateFunc: validateSlbListenerPersistenceTimeout, 112 Optional: true, 113 Default: 0, 114 }, 115 //https 116 "ssl_certificate_id": &schema.Schema{ 117 Type: schema.TypeString, 118 Optional: true, 119 }, 120 }, 121 }, 122 Set: resourceAliyunSlbListenerHash, 123 }, 124 125 //deprecated 126 "instances": &schema.Schema{ 127 Type: schema.TypeSet, 128 Elem: &schema.Schema{Type: schema.TypeString}, 129 Optional: true, 130 Set: schema.HashString, 131 }, 132 133 "address": &schema.Schema{ 134 Type: schema.TypeString, 135 Computed: true, 136 }, 137 }, 138 } 139 } 140 141 func resourceAliyunSlbCreate(d *schema.ResourceData, meta interface{}) error { 142 143 slbconn := meta.(*AliyunClient).slbconn 144 145 var slbName string 146 if v, ok := d.GetOk("name"); ok { 147 slbName = v.(string) 148 } else { 149 slbName = resource.PrefixedUniqueId("tf-lb-") 150 d.Set("name", slbName) 151 } 152 153 slbArgs := &slb.CreateLoadBalancerArgs{ 154 RegionId: getRegion(d, meta), 155 LoadBalancerName: slbName, 156 } 157 158 if internet, ok := d.GetOk("internet"); ok && internet.(bool) { 159 slbArgs.AddressType = slb.InternetAddressType 160 d.Set("internet", true) 161 } else { 162 slbArgs.AddressType = slb.IntranetAddressType 163 d.Set("internet", false) 164 } 165 166 if v, ok := d.GetOk("internet_charge_type"); ok && v.(string) != "" { 167 slbArgs.InternetChargeType = slb.InternetChargeType(v.(string)) 168 } 169 170 if v, ok := d.GetOk("bandwidth"); ok && v.(int) != 0 { 171 slbArgs.Bandwidth = v.(int) 172 } 173 174 if v, ok := d.GetOk("vswitch_id"); ok && v.(string) != "" { 175 slbArgs.VSwitchId = v.(string) 176 } 177 slb, err := slbconn.CreateLoadBalancer(slbArgs) 178 if err != nil { 179 return err 180 } 181 182 d.SetId(slb.LoadBalancerId) 183 184 return resourceAliyunSlbUpdate(d, meta) 185 } 186 187 func resourceAliyunSlbRead(d *schema.ResourceData, meta interface{}) error { 188 slbconn := meta.(*AliyunClient).slbconn 189 loadBalancer, err := slbconn.DescribeLoadBalancerAttribute(d.Id()) 190 if err != nil { 191 if notFoundError(err) { 192 d.SetId("") 193 return nil 194 } 195 196 return err 197 } 198 199 d.Set("name", loadBalancer.LoadBalancerName) 200 201 if loadBalancer.AddressType == slb.InternetAddressType { 202 d.Set("internal", true) 203 } else { 204 d.Set("internal", false) 205 } 206 d.Set("internet_charge_type", loadBalancer.InternetChargeType) 207 d.Set("bandwidth", loadBalancer.Bandwidth) 208 d.Set("vswitch_id", loadBalancer.VSwitchId) 209 d.Set("address", loadBalancer.Address) 210 211 return nil 212 } 213 214 func resourceAliyunSlbUpdate(d *schema.ResourceData, meta interface{}) error { 215 216 slbconn := meta.(*AliyunClient).slbconn 217 218 d.Partial(true) 219 220 if d.HasChange("name") { 221 err := slbconn.SetLoadBalancerName(d.Id(), d.Get("name").(string)) 222 if err != nil { 223 return err 224 } 225 226 d.SetPartial("name") 227 } 228 229 if d.Get("internet") == true && d.Get("internet_charge_type") == "paybybandwidth" { 230 //don't intranet web and paybybandwidth, then can modify bandwidth 231 if d.HasChange("bandwidth") { 232 args := &slb.ModifyLoadBalancerInternetSpecArgs{ 233 LoadBalancerId: d.Id(), 234 Bandwidth: d.Get("bandwidth").(int), 235 } 236 err := slbconn.ModifyLoadBalancerInternetSpec(args) 237 if err != nil { 238 return err 239 } 240 241 d.SetPartial("bandwidth") 242 } 243 } 244 245 if d.HasChange("listener") { 246 o, n := d.GetChange("listener") 247 os := o.(*schema.Set) 248 ns := n.(*schema.Set) 249 250 remove, _ := expandListeners(os.Difference(ns).List()) 251 add, _ := expandListeners(ns.Difference(os).List()) 252 253 if len(remove) > 0 { 254 for _, listener := range remove { 255 err := slbconn.DeleteLoadBalancerListener(d.Id(), listener.LoadBalancerPort) 256 if err != nil { 257 return fmt.Errorf("Failure removing outdated SLB listeners: %#v", err) 258 } 259 } 260 } 261 262 if len(add) > 0 { 263 for _, listener := range add { 264 err := createListener(slbconn, d.Id(), listener) 265 if err != nil { 266 return fmt.Errorf("Failure add SLB listeners: %#v", err) 267 } 268 } 269 } 270 271 d.SetPartial("listener") 272 } 273 274 // If we currently have instances, or did have instances, 275 // we want to figure out what to add and remove from the load 276 // balancer 277 if d.HasChange("instances") { 278 o, n := d.GetChange("instances") 279 os := o.(*schema.Set) 280 ns := n.(*schema.Set) 281 remove := expandBackendServers(os.Difference(ns).List()) 282 add := expandBackendServers(ns.Difference(os).List()) 283 284 if len(add) > 0 { 285 _, err := slbconn.AddBackendServers(d.Id(), add) 286 if err != nil { 287 return err 288 } 289 } 290 if len(remove) > 0 { 291 removeBackendServers := make([]string, 0, len(remove)) 292 for _, e := range remove { 293 removeBackendServers = append(removeBackendServers, e.ServerId) 294 } 295 _, err := slbconn.RemoveBackendServers(d.Id(), removeBackendServers) 296 if err != nil { 297 return err 298 } 299 } 300 301 d.SetPartial("instances") 302 } 303 304 d.Partial(false) 305 306 return resourceAliyunSlbRead(d, meta) 307 } 308 309 func resourceAliyunSlbDelete(d *schema.ResourceData, meta interface{}) error { 310 conn := meta.(*AliyunClient).slbconn 311 312 return resource.Retry(5*time.Minute, func() *resource.RetryError { 313 err := conn.DeleteLoadBalancer(d.Id()) 314 315 if err != nil { 316 return resource.NonRetryableError(err) 317 } 318 319 loadBalancer, err := conn.DescribeLoadBalancerAttribute(d.Id()) 320 if err != nil { 321 e, _ := err.(*common.Error) 322 if e.ErrorResponse.Code == LoadBalancerNotFound { 323 return nil 324 } 325 return resource.NonRetryableError(err) 326 } 327 if loadBalancer != nil { 328 return resource.RetryableError(fmt.Errorf("LoadBalancer in use - trying again while it deleted.")) 329 } 330 return nil 331 }) 332 } 333 334 func resourceAliyunSlbListenerHash(v interface{}) int { 335 var buf bytes.Buffer 336 m := v.(map[string]interface{}) 337 buf.WriteString(fmt.Sprintf("%d-", m["instance_port"].(int))) 338 buf.WriteString(fmt.Sprintf("%d-", m["lb_port"].(int))) 339 buf.WriteString(fmt.Sprintf("%s-", 340 strings.ToLower(m["lb_protocol"].(string)))) 341 342 buf.WriteString(fmt.Sprintf("%d-", m["bandwidth"].(int))) 343 344 if v, ok := m["ssl_certificate_id"]; ok { 345 buf.WriteString(fmt.Sprintf("%s-", v.(string))) 346 } 347 348 return hashcode.String(buf.String()) 349 } 350 351 func createListener(conn *slb.Client, loadBalancerId string, listener *Listener) error { 352 if listener.Protocol == strings.ToLower("tcp") { 353 args := &slb.CreateLoadBalancerTCPListenerArgs{ 354 LoadBalancerId: loadBalancerId, 355 ListenerPort: listener.LoadBalancerPort, 356 BackendServerPort: listener.InstancePort, 357 Bandwidth: listener.Bandwidth, 358 } 359 if err := conn.CreateLoadBalancerTCPListener(args); err != nil { 360 return err 361 } 362 } 363 364 if listener.Protocol == strings.ToLower("http") { 365 args := &slb.CreateLoadBalancerHTTPListenerArgs{ 366 LoadBalancerId: loadBalancerId, 367 ListenerPort: listener.LoadBalancerPort, 368 BackendServerPort: listener.InstancePort, 369 Bandwidth: listener.Bandwidth, 370 StickySession: slb.OffFlag, 371 HealthCheck: slb.OffFlag, 372 } 373 374 if err := conn.CreateLoadBalancerHTTPListener(args); err != nil { 375 return err 376 } 377 } 378 379 if listener.Protocol == strings.ToLower("https") { 380 args := &slb.CreateLoadBalancerHTTPSListenerArgs{ 381 382 HTTPListenerType: slb.HTTPListenerType{ 383 LoadBalancerId: loadBalancerId, 384 ListenerPort: listener.LoadBalancerPort, 385 BackendServerPort: listener.InstancePort, 386 Bandwidth: listener.Bandwidth, 387 StickySession: slb.OffFlag, 388 HealthCheck: slb.OffFlag, 389 }, 390 } 391 if listener.SSLCertificateId == "" { 392 return fmt.Errorf("Server Certificated Id cann't be null") 393 } 394 395 args.ServerCertificateId = listener.SSLCertificateId 396 397 if err := conn.CreateLoadBalancerHTTPSListener(args); err != nil { 398 return err 399 } 400 } 401 402 if listener.Protocol == strings.ToLower("udp") { 403 args := &slb.CreateLoadBalancerUDPListenerArgs{ 404 LoadBalancerId: loadBalancerId, 405 ListenerPort: listener.LoadBalancerPort, 406 BackendServerPort: listener.InstancePort, 407 Bandwidth: listener.Bandwidth, 408 } 409 410 if err := conn.CreateLoadBalancerUDPListener(args); err != nil { 411 return err 412 } 413 } 414 415 if err := conn.StartLoadBalancerListener(loadBalancerId, listener.LoadBalancerPort); err != nil { 416 return err 417 } 418 419 return nil 420 }