From 971b500228fc7d106a86d643adc283bf7c0300f7 Mon Sep 17 00:00:00 2001 From: He Guimin Date: Thu, 16 Nov 2017 10:06:02 +0800 Subject: [PATCH 01/14] modify listener max health_timeout and health_interval --- CHANGELOG.md | 5 +++++ alicloud/resource_alicloud_slb.go | 6 ++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a056eb6c..2f2f5e39c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ ## 1.3.0 (unreleased) +## 1.2.10 (November 16, 2017) +IMPROVMENTS: + * fix slb listener max healthy check timeout and interval: ([#276](https://github.com/alibaba/terraform-provider/pull/276)) + + ## 1.2.9 (November 16, 2017) IMPROVMENTS: * fix retriving instance types bug: ([#270](https://github.com/alibaba/terraform-provider/pull/270)) diff --git a/alicloud/resource_alicloud_slb.go b/alicloud/resource_alicloud_slb.go index 973e4af38..90be38746 100644 --- a/alicloud/resource_alicloud_slb.go +++ b/alicloud/resource_alicloud_slb.go @@ -178,13 +178,15 @@ func resourceAliyunSlb() *schema.Resource { "health_check_timeout": &schema.Schema{ Type: schema.TypeInt, - ValidateFunc: validateIntegerInRange(1, 50), + ValidateFunc: validateIntegerInRange(1, 300), Optional: true, + Default: 5, }, "health_check_interval": &schema.Schema{ Type: schema.TypeInt, - ValidateFunc: validateIntegerInRange(1, 5), + ValidateFunc: validateIntegerInRange(1, 50), Optional: true, + Default: 2, }, //http & https & tcp "health_check_http_code": &schema.Schema{ From a6dd6d3e6536f72498b4bc85d85a772111dba97a Mon Sep 17 00:00:00 2001 From: He Guimin Date: Fri, 17 Nov 2017 17:54:24 +0800 Subject: [PATCH 02/14] fix slb listener diff can be run when change listener health parameters --- CHANGELOG.md | 5 + alicloud/resource_alicloud_slb.go | 124 +++++++++++++++++++--- alicloud/resource_alicloud_slb_test.go | 3 +- alicloud/validators.go | 12 +-- terraform/examples/alicloud-slb/README.md | 16 +-- terraform/examples/alicloud-slb/main.tf | 1 - 6 files changed, 126 insertions(+), 35 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f2f5e39c..3c3f7c283 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ ## 1.3.0 (unreleased) +## 1.2.11 (November 17, 2017) +IMPROVMENTS: + * fix slb listener diff can be run when change listener health parameters: ([#278](https://github.com/alibaba/terraform-provider/pull/278)) + + ## 1.2.10 (November 16, 2017) IMPROVMENTS: * fix slb listener max healthy check timeout and interval: ([#276](https://github.com/alibaba/terraform-provider/pull/276)) diff --git a/alicloud/resource_alicloud_slb.go b/alicloud/resource_alicloud_slb.go index 90be38746..91cc75486 100644 --- a/alicloud/resource_alicloud_slb.go +++ b/alicloud/resource_alicloud_slb.go @@ -11,6 +11,7 @@ import ( "github.com/hashicorp/terraform/helper/hashcode" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" + "log" "reflect" "time" ) @@ -116,6 +117,7 @@ func resourceAliyunSlb() *schema.Resource { Type: schema.TypeInt, ValidateFunc: validateSlbListenerCookieTimeout, Optional: true, + Default: 3600, }, //http & https "cookie": &schema.Schema{ @@ -164,16 +166,19 @@ func resourceAliyunSlb() *schema.Resource { Type: schema.TypeInt, ValidateFunc: validateSlbListenerHealthCheckConnectPort, Optional: true, + Computed: true, }, "healthy_threshold": &schema.Schema{ Type: schema.TypeInt, ValidateFunc: validateIntegerInRange(1, 10), Optional: true, + Default: 3, }, "unhealthy_threshold": &schema.Schema{ Type: schema.TypeInt, ValidateFunc: validateIntegerInRange(1, 10), Optional: true, + Default: 3, }, "health_check_timeout": &schema.Schema{ @@ -197,6 +202,7 @@ func resourceAliyunSlb() *schema.Resource { string(slb.HTTP_4XX), string(slb.HTTP_5XX)}, ","), Optional: true, + Default: slb.HTTP_2XX, }, //https "ssl_certificate_id": &schema.Schema{ @@ -251,7 +257,7 @@ func resourceAliyunSlbCreate(d *schema.ResourceData, meta interface{}) error { slbArgs.AddressType = slb.InternetAddressType } - if v, ok := d.GetOk("internet_charge_type"); ok && v.(string) != "" { + if v, ok := d.GetOk("internet_charge_type"); ok { slbArgs.InternetChargeType = slb.InternetChargeType(v.(string)) } @@ -259,7 +265,7 @@ func resourceAliyunSlbCreate(d *schema.ResourceData, meta interface{}) error { slbArgs.Bandwidth = v.(int) } - if v, ok := d.GetOk("vswitch_id"); ok && v.(string) != "" { + if v, ok := d.GetOk("vswitch_id"); ok { slbArgs.VSwitchId = v.(string) } slb, err := slbconn.CreateLoadBalancer(slbArgs) @@ -441,10 +447,94 @@ func resourceAliyunSlbListenerHash(v interface{}) int { buf.WriteString(fmt.Sprintf("%d-", m["bandwidth"].(int))) - if v, ok := m["ssl_certificate_id"]; ok { + http := Protocol(m["lb_protocol"].(string)) == Http + https := Protocol(m["lb_protocol"].(string)) == Https + tcp := Protocol(m["lb_protocol"].(string)) == Tcp + udp := Protocol(m["lb_protocol"].(string)) == Udp + health_check := false + + if v, ok := m["scheduler"]; ok { buf.WriteString(fmt.Sprintf("%s-", v.(string))) } + if http || https { + if v, ok := m["sticky_session"]; ok { + buf.WriteString(fmt.Sprintf("%s-", v.(string))) + if slb.FlagType(v.(string)) == slb.OnFlag { + if v, ok := m["sticky_session_type"]; ok { + buf.WriteString(fmt.Sprintf("%s-", v.(string))) + if slb.StickySessionType(v.(string)) == slb.InsertStickySessionType { + if v, ok := m["cookie_timeout"]; ok { + buf.WriteString(fmt.Sprintf("%d-", v.(int))) + } + } else { + if v, ok := m["cookie"]; ok { + buf.WriteString(fmt.Sprintf("%s-", v.(string))) + } + } + } + } + } + + if v, ok := m["health_check"]; ok { + buf.WriteString(fmt.Sprintf("%s-", v.(string))) + if slb.FlagType(v.(string)) == slb.OnFlag { + health_check = true + } + } + } + + if health_check || tcp { + if v, ok := m["health_check_domain"]; ok { + buf.WriteString(fmt.Sprintf("%s-", v.(string))) + } + if v, ok := m["health_check_uri"]; ok { + buf.WriteString(fmt.Sprintf("%s-", v.(string))) + } + if v, ok := m["health_check_http_code"]; ok { + buf.WriteString(fmt.Sprintf("%s-", v.(string))) + } + } + + if tcp || udp { + if v, ok := m["persistence_timeout"]; ok { + buf.WriteString(fmt.Sprintf("%d-", v.(int))) + } + } + + if tcp { + if v, ok := m["health_check_type"]; ok { + buf.WriteString(fmt.Sprintf("%s-", v.(string))) + } + } + + if https { + if v, ok := m["ssl_certificate_id"]; ok { + buf.WriteString(fmt.Sprintf("%s-", v.(string))) + } + } + + if health_check || tcp || udp { + if v, ok := m["healthy_threshold"]; ok { + buf.WriteString(fmt.Sprintf("%d-", v.(int))) + } + + if v, ok := m["unhealthy_threshold"]; ok { + buf.WriteString(fmt.Sprintf("%d-", v.(int))) + } + + if v, ok := m["health_check_timeout"]; ok { + buf.WriteString(fmt.Sprintf("%d-", v.(int))) + } + + if v, ok := m["health_check_interval"]; ok { + buf.WriteString(fmt.Sprintf("%d-", v.(int))) + } + if v, ok := m["health_check_connect_port"]; ok { + buf.WriteString(fmt.Sprintf("%d-", v.(int))) + } + } + return hashcode.String(buf.String()) } @@ -454,17 +544,15 @@ func createListener(conn *slb.Client, loadBalancerId string, listener *Listener) if err != nil { if listenerType, ok := err.(*ListenerErr); ok { if listenerType.ErrType == HealthCheckErrType { - return fmt.Errorf("When the HealthCheck is %s, then related HealthCheck parameter "+ - "must have.", slb.OnFlag) + return fmt.Errorf("'health_check_uri': required field is not set when the HealthCheck is %s.", slb.OnFlag) } else if listenerType.ErrType == StickySessionErrType { - return fmt.Errorf("When the StickySession is %s, then StickySessionType parameter "+ - "must have.", slb.OnFlag) + return fmt.Errorf("'sticky_session_type': required field is not set when the StickySession is %s.", slb.OnFlag) } else if listenerType.ErrType == CookieTimeOutErrType { - return fmt.Errorf("When the StickySession is %s and StickySessionType is %s, "+ - "then CookieTimeout parameter must have.", slb.OnFlag, slb.InsertStickySessionType) + return fmt.Errorf("'cookie_timeout': required field is not set when the StickySession is %s "+ + "and StickySessionType is %s.", slb.OnFlag, slb.InsertStickySessionType) } else if listenerType.ErrType == CookieErrType { - return fmt.Errorf("When the StickySession is %s and StickySessionType is %s, "+ - "then Cookie parameter must have.", slb.OnFlag, slb.ServerStickySessionType) + return fmt.Errorf("'cookie': required field is not set when the StickySession is %s "+ + "and StickySessionType is %s.", slb.OnFlag, slb.ServerStickySessionType) } return fmt.Errorf("slb listener check errtype not found.") } @@ -555,6 +643,10 @@ func getUdpListenerArgs(loadBalancerId string, listener *Listener) slb.CreateLoa PersistenceTimeout: listener.PersistenceTimeout, HealthCheckConnectTimeout: listener.HealthCheckTimeout, HealthCheckInterval: listener.HealthCheckInterval, + Scheduler: listener.Scheduler, + HealthCheckConnectPort: listener.HealthCheckConnectPort, + HealthyThreshold: listener.HealthyThreshold, + UnhealthyThreshold: listener.UnhealthyThreshold, } return args } @@ -562,10 +654,7 @@ func getUdpListenerArgs(loadBalancerId string, listener *Listener) slb.CreateLoa func getHttpListenerType(loadBalancerId string, listener *Listener) (listenType slb.HTTPListenerType, err error) { if listener.HealthCheck == slb.OnFlag { - if listener.HealthCheckURI == "" || listener.HealthCheckDomain == "" || listener.HealthCheckConnectPort == 0 || - listener.HealthyThreshold == 0 || listener.UnhealthyThreshold == 0 || listener.HealthCheckTimeout == 0 || - listener.HealthCheckHttpCode == "" || listener.HealthCheckInterval == 0 { - + if listener.HealthCheckURI == "" { errMsg := errors.New("err: HealthCheck empty.") return listenType, &ListenerErr{HealthCheckErrType, errMsg} } @@ -659,7 +748,7 @@ func readListerners(conn *slb.Client, loadBalancer *slb.LoadBalancerType) ([]map listeners = append(listeners, setListenerAttribute(udp_ls, Udp)) } } - + log.Printf("Listeners set: %#v", listeners) return listeners, nil } @@ -721,6 +810,9 @@ func setListenerAttribute(listen interface{}, protocol Protocol) map[string]inte if val := v.FieldByName("HealthCheckTimeout"); val.IsValid() { listener["health_check_timeout"] = val.Interface().(int) } + if val := v.FieldByName("HealthCheckConnectTimeout"); val.IsValid() { + listener["health_check_timeout"] = val.Interface().(int) + } if val := v.FieldByName("HealthCheckInterval"); val.IsValid() { listener["health_check_interval"] = val.Interface().(int) } diff --git a/alicloud/resource_alicloud_slb_test.go b/alicloud/resource_alicloud_slb_test.go index c2ceeb6d3..c5d134a96 100644 --- a/alicloud/resource_alicloud_slb_test.go +++ b/alicloud/resource_alicloud_slb_test.go @@ -85,7 +85,7 @@ func TestAccAlicloudSlb_listener(t *testing.T) { testListener := func() resource.TestCheckFunc { return func(*terraform.State) error { listenerPorts := slb.ListenerPorts.ListenerPort[0] - if listenerPorts != 2001 { + if listenerPorts != 80 { return fmt.Errorf("bad loadbalancer listener: %#v", listenerPorts) } @@ -279,7 +279,6 @@ resource "alicloud_slb" "listener" { "cookie" = "testslblistenercookie" "cookie_timeout" = 1800 "health_check" = "on" - "health_check_domain" = "$_ip" "health_check_uri" = "/console" "health_check_connect_port" = 20 "healthy_threshold" = 8 diff --git a/alicloud/validators.go b/alicloud/validators.go index d17029ed0..4b41469cf 100644 --- a/alicloud/validators.go +++ b/alicloud/validators.go @@ -17,7 +17,6 @@ import ( "github.com/denverdino/aliyungo/ram" "github.com/denverdino/aliyungo/slb" "github.com/hashicorp/terraform/helper/schema" - "log" ) // common @@ -378,9 +377,9 @@ func validateSlbListenerCookie(v interface{}, k string) (ws []string, errors []e func validateSlbListenerCookieTimeout(v interface{}, k string) (ws []string, errors []error) { value := v.(int) - if value < 0 || value > 86400 { + if value < 1 || value > 86400 { errors = append(errors, fmt.Errorf( - "%q must be a valid load balancer cookie timeout between 0 and 86400", + "%q must be a valid load balancer cookie timeout between 1 and 86400", k)) return } @@ -400,9 +399,8 @@ func validateSlbListenerPersistenceTimeout(v interface{}, k string) (ws []string func validateSlbListenerHealthCheckDomain(v interface{}, k string) (ws []string, errors []error) { if value := v.(string); value != "" { - //the len add "$_ip",so to max is 84 - if len(value) < 1 || len(value) > 84 { - errors = append(errors, fmt.Errorf("%q cannot be longer than 84 characters", k)) + if reg := regexp.MustCompile(`^[\w\-.]{1,80}$`); !reg.MatchString(value) { + errors = append(errors, fmt.Errorf("%q length is limited to 1-80 and only characters such as letters, digits, '-' and '.' are allowed", k)) } } return @@ -1039,9 +1037,7 @@ func validateRouterInterfaceDescription(v interface{}, k string) (ws []string, e func validateInstanceType(v interface{}, k string) (ws []string, errors []error) { value := v.(string) - log.Printf("*********value:%#v", v) if !strings.HasPrefix(value, "ecs.") { - log.Printf("*********value2:%#v", value) errors = append(errors, fmt.Errorf("Invalid %q: %s. It must be 'ecs.' as prefix.", k, value)) } return diff --git a/terraform/examples/alicloud-slb/README.md b/terraform/examples/alicloud-slb/README.md index 50289d1d6..086205b2d 100644 --- a/terraform/examples/alicloud-slb/README.md +++ b/terraform/examples/alicloud-slb/README.md @@ -15,16 +15,16 @@ sticky_session_type | http & https | insert or server | if sticky_session is on, cookie_timeout | http & https | 1-86400 | if sticky_session is on and sticky_session_type is insert, the value must have| cookie | http & https | | if sticky_session is on and sticky_session_type is server, the value must have| persistence_timeout | tcp & udp | 0-3600 | | -health_check | http & https | on or off | | +health_check | http & https | on or off | | TCP and UDP listener's HealthCheck is always on health_check_type | tcp | tcp or http | if health_check is on, the value must have | -health_check_domain | http & https & tcp | | example: $_ip/some string/.if health_check is on, the value must have | +health_check_domain | http & https & tcp | | one string which length is 1-80 and only allow letters, digits, '-' and '.' characters. When it is not set or empty, Server Load Balancer uses the private network IP address of each backend server as Domain used for health check | health_check_uri | http & https & tcp | | example: /aliyun. if health_check is on, the value must have | -health_check_connect_port | http & https & tcp & udp | 1-65535 or -520 | if health_check is on, the value must have | -healthy_threshold | http & https & tcp & udp | 1-10 | if health_check is on, the value must have | -unhealthy_threshold | http & https & tcp & udp | 1-10 | if health_check is on, the value must have | -health_check_timeout | http & https & tcp & udp | 1-50 | if health_check is on, the value must have | -health_check_interval | http & https & tcp & udp | 1-5 | if health_check is on, the value must have | -health_check_http_code | http & https & tcp | http_2xx,http_3xx,http_4xx,http_5xx | if health_check is on, the value must have | +health_check_connect_port | http & https & tcp & udp | 1-65535 | If the parameter is not set, the backend server port (BackendServerPort) will be used. | +healthy_threshold | http & https & tcp & udp | 1-10 | default to 3 when the health_check is on | +unhealthy_threshold | http & https & tcp & udp | 1-10 | default to 3 when the health_check is on | +health_check_timeout | http & https & tcp & udp | 1-300 | default to 5 when the health_check is on | +health_check_interval | http & https & tcp & udp | 1-50 | default to 2 when the health_check is on | +health_check_http_code | http & https & tcp | http_2xx,http_3xx,http_4xx,http_5xx | default to http_2xx when the health_check is on | ssl_certificate_id | https | | | ### Get up and running diff --git a/terraform/examples/alicloud-slb/main.tf b/terraform/examples/alicloud-slb/main.tf index a4c179f69..8e5d95f2b 100644 --- a/terraform/examples/alicloud-slb/main.tf +++ b/terraform/examples/alicloud-slb/main.tf @@ -41,7 +41,6 @@ resource "alicloud_slb" "instance" { "cookie" = "testslblistenercookie" "cookie_timeout" = 86400 "health_check" = "on" - "health_check_domain" = "$_ip" "health_check_uri" = "/console" "health_check_connect_port" = 20 "healthy_threshold" = 8 From a6bc4beb4feac343b1b52e15843217db459346e3 Mon Sep 17 00:00:00 2001 From: He Guimin Date: Thu, 30 Nov 2017 12:52:50 +0800 Subject: [PATCH 03/14] fix creating multiple route entry bug --- CHANGELOG.md | 6 ++ alicloud/errors.go | 4 ++ .../resource_alicloud_ess_scalinggroup.go | 21 ++++--- .../resource_alicloud_router_interface.go | 9 ++- alicloud/resource_alicloud_vpc.go | 13 ++-- alicloud/resource_alicloud_vpc_test.go | 43 ++++++++++++++ alicloud/resource_alicloud_vroute_entry.go | 44 ++++++++++---- .../resource_alicloud_vroute_entry_test.go | 4 +- alicloud/resource_alicloud_vswitch.go | 16 ++--- alicloud/resource_alicloud_vswitch_test.go | 59 +++++++++++++++++++ .../alicloud-container-cluster/main.tf | 1 - 11 files changed, 183 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f2f5e39c..c41b27e30 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ ## 1.3.0 (unreleased) +## 1.2.11 (November 30, 2017) +IMPROVMENTS: + * fix creating multiple route entries bug: ([#286](https://github.com/alibaba/terraform-provider/pull/286)) + * add creating multiple vpcs and vswitches test case: ([#286](https://github.com/alibaba/terraform-provider/pull/286)) + * modify ess scaling group maxsize/minsize/default_cooldown type to int pointer: ([#286](https://github.com/alibaba/terraform-provider/pull/286)) + ## 1.2.10 (November 16, 2017) IMPROVMENTS: * fix slb listener max healthy check timeout and interval: ([#276](https://github.com/alibaba/terraform-provider/pull/276)) diff --git a/alicloud/errors.go b/alicloud/errors.go index 641f4e662..e3319b0fc 100644 --- a/alicloud/errors.go +++ b/alicloud/errors.go @@ -40,6 +40,10 @@ const ( VpcQuotaExceeded = "QuotaExceeded.Vpc" // vswitch VswitcInvalidRegionId = "InvalidRegionId.NotFound" + //vroute entry + IncorrectRouteEntryStatus = "IncorrectRouteEntryStatus" + TaskConflict = "TaskConflict" + RouterEntryForbbiden = "Forbbiden" // ess InvalidScalingGroupIdNotFound = "InvalidScalingGroupId.NotFound" diff --git a/alicloud/resource_alicloud_ess_scalinggroup.go b/alicloud/resource_alicloud_ess_scalinggroup.go index 2faf40e9e..006f7242c 100644 --- a/alicloud/resource_alicloud_ess_scalinggroup.go +++ b/alicloud/resource_alicloud_ess_scalinggroup.go @@ -120,17 +120,20 @@ func resourceAliyunEssScalingGroupUpdate(d *schema.ResourceData, meta interface{ } if d.HasChange("min_size") { - args.MinSize = d.Get("min_size").(int) + minsize := d.Get("min_size").(int) + args.MinSize = &minsize d.SetPartial("min_size") } if d.HasChange("max_size") { - args.MaxSize = d.Get("max_size").(int) + maxsize := d.Get("max_size").(int) + args.MaxSize = &maxsize d.SetPartial("max_size") } if d.HasChange("default_cooldown") { - args.DefaultCooldown = d.Get("default_cooldown").(int) + cooldown := d.Get("default_cooldown").(int) + args.DefaultCooldown = &cooldown d.SetPartial("default_cooldown") } @@ -157,12 +160,16 @@ func resourceAliyunEssScalingGroupDelete(d *schema.ResourceData, meta interface{ func buildAlicloudEssScalingGroupArgs(d *schema.ResourceData, meta interface{}) (*ess.CreateScalingGroupArgs, error) { client := meta.(*AliyunClient) args := &ess.CreateScalingGroupArgs{ - RegionId: getRegion(d, meta), - MinSize: d.Get("min_size").(int), - MaxSize: d.Get("max_size").(int), - DefaultCooldown: d.Get("default_cooldown").(int), + RegionId: getRegion(d, meta), } + minsize := d.Get("min_size").(int) + maxsize := d.Get("max_size").(int) + cooldown := d.Get("default_cooldown").(int) + args.MinSize = &minsize + args.MaxSize = &maxsize + args.DefaultCooldown = &cooldown + if v := d.Get("scaling_group_name").(string); v != "" { args.ScalingGroupName = v } diff --git a/alicloud/resource_alicloud_router_interface.go b/alicloud/resource_alicloud_router_interface.go index 2db0d4808..d1295ce8e 100644 --- a/alicloud/resource_alicloud_router_interface.go +++ b/alicloud/resource_alicloud_router_interface.go @@ -112,6 +112,11 @@ func resourceAlicloudRouterInterfaceCreate(d *schema.ResourceData, meta interfac } d.SetId(response.RouterInterfaceId) + + if err := conn.WaitForRouterInterfaceAsyn(getRegion(d, meta), d.Id(), ecs.Idle, 300); err != nil { + return fmt.Errorf("WaitForRouterInterface %s got error: %#v", ecs.Idle, err) + } + return resourceAlicloudRouterInterfaceUpdate(d, meta) } @@ -199,7 +204,9 @@ func resourceAlicloudRouterInterfaceDelete(d *schema.ResourceData, meta interfac return resource.Retry(5*time.Minute, func() *resource.RetryError { if _, err := conn.DeleteRouterInterface(args); err != nil { if IsExceptedError(err, RouterInterfaceIncorrectStatus) || IsExceptedError(err, DependencyViolationRouterInterfaceReferedByRouteEntry) { - return resource.RetryableError(fmt.Errorf("Router interface in use - trying again while it is deleted.")) + time.Sleep(5 * time.Second) + //e, _ := err.(*common.Error) + return resource.RetryableError(fmt.Errorf("Router interface in use: %#v. Trying again while it is deleted.", err)) } return resource.NonRetryableError(fmt.Errorf("Error deleting interface %s: %#v", d.Id(), err)) } diff --git a/alicloud/resource_alicloud_vpc.go b/alicloud/resource_alicloud_vpc.go index 82ba13dfe..136dee228 100644 --- a/alicloud/resource_alicloud_vpc.go +++ b/alicloud/resource_alicloud_vpc.go @@ -73,15 +73,14 @@ func resourceAliyunVpc() *schema.Resource { func resourceAliyunVpcCreate(d *schema.ResourceData, meta interface{}) error { - args, err := buildAliyunVpcArgs(d, meta) - if err != nil { - return err - } - ecsconn := meta.(*AliyunClient).ecsconn var vpc *ecs.CreateVpcResponse - err = resource.Retry(3*time.Minute, func() *resource.RetryError { + err := resource.Retry(3*time.Minute, func() *resource.RetryError { + args, err := buildAliyunVpcArgs(d, meta) + if err != nil { + return resource.NonRetryableError(fmt.Errorf("Building CreateVpcArgs got an error: %#v", err)) + } resp, err := ecsconn.CreateVpc(args) if err != nil { if IsExceptedError(err, VpcQuotaExceeded) { @@ -101,7 +100,7 @@ func resourceAliyunVpcCreate(d *schema.ResourceData, meta interface{}) error { d.SetId(vpc.VpcId) - err = ecsconn.WaitForVpcAvailable(args.RegionId, vpc.VpcId, 60) + err = ecsconn.WaitForVpcAvailable(getRegion(d, meta), d.Id(), 60) if err != nil { return fmt.Errorf("Timeout when WaitForVpcAvailable") } diff --git a/alicloud/resource_alicloud_vpc_test.go b/alicloud/resource_alicloud_vpc_test.go index f9fcf8807..9dde47ca5 100644 --- a/alicloud/resource_alicloud_vpc_test.go +++ b/alicloud/resource_alicloud_vpc_test.go @@ -70,6 +70,34 @@ func TestAccAlicloudVpc_update(t *testing.T) { }) } +func TestAccAlicloudVpc_multi(t *testing.T) { + var vpc ecs.VpcSetType + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + }, + Providers: testAccProviders, + CheckDestroy: testAccCheckVpcDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccVpcConfigMulti, + Check: resource.ComposeTestCheckFunc( + testAccCheckVpcExists("alicloud_vpc.bar_1", &vpc), + resource.TestCheckResourceAttr( + "alicloud_vpc.bar_1", "cidr_block", "172.16.0.0/12"), + testAccCheckVpcExists("alicloud_vpc.bar_2", &vpc), + resource.TestCheckResourceAttr( + "alicloud_vpc.bar_2", "cidr_block", "192.168.0.0/16"), + testAccCheckVpcExists("alicloud_vpc.bar_3", &vpc), + resource.TestCheckResourceAttr( + "alicloud_vpc.bar_3", "cidr_block", "10.1.0.0/21"), + ), + }, + }, + }) +} + func testAccCheckVpcExists(n string, vpc *ecs.VpcSetType) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] @@ -138,3 +166,18 @@ resource "alicloud_vpc" "foo" { name = "tf_test_bar" } ` + +const testAccVpcConfigMulti = ` +resource "alicloud_vpc" "bar_1" { + cidr_block = "172.16.0.0/12" + name = "tf_test_bar_1" +} +resource "alicloud_vpc" "bar_2" { + cidr_block = "192.168.0.0/16" + name = "tf_test_bar_2" +} +resource "alicloud_vpc" "bar_3" { + cidr_block = "10.1.0.0/21" + name = "tf_test_bar_3" +} +` diff --git a/alicloud/resource_alicloud_vroute_entry.go b/alicloud/resource_alicloud_vroute_entry.go index 5ba728cbb..bbc003537 100644 --- a/alicloud/resource_alicloud_vroute_entry.go +++ b/alicloud/resource_alicloud_vroute_entry.go @@ -68,17 +68,32 @@ func resourceAliyunRouteEntryCreate(d *schema.ResourceData, meta interface{}) er return fmt.Errorf("Error query route table: %#v", err) } - if err := conn.WaitForAllRouteEntriesAvailable(table.VRouterId, rtId, defaultTimeout); err != nil { - return fmt.Errorf("WaitFor route entry got error: %#v", err) - } + err = resource.Retry(3*time.Minute, func() *resource.RetryError { - args, err := buildAliyunRouteEntryArgs(d, meta) - if err != nil { - return err - } - err = conn.CreateRouteEntry(args) + if err := conn.WaitForAllRouteEntriesAvailable(table.VRouterId, rtId, defaultTimeout); err != nil { + return resource.NonRetryableError(fmt.Errorf("WaitFor route entry got error: %#v", err)) + } + + args, err := buildAliyunRouteEntryArgs(d, meta) + if err != nil { + return resource.NonRetryableError(fmt.Errorf("Building CreateRouteEntryArgs got an error: %#v", err)) + } + //args.ClientToken = fmt.Sprintf("%s-%d", args.ClientToken, timeNow) + + if err := conn.CreateRouteEntry(args); err != nil { + // Route Entry does not support concurrence when creating or deleting it; + // Route Entry does not support creating or deleting within 5 seconds frequently + // It must ensure all the route entries and vswitches' status must be available before creating or deleting route entry. + if IsExceptedError(err, TaskConflict) || IsExceptedError(err, IncorrectRouteEntryStatus) { + time.Sleep(5 * time.Second) + return resource.RetryableError(fmt.Errorf("Vroute entry is still creating -- try again, err:%#v", err)) + } + return resource.NonRetryableError(fmt.Errorf("Creating Route entry got an error: %#v", err)) + } + return nil + }) if err != nil { - return err + return fmt.Errorf("Create Vroute Entry got an error :%#v", err) } // route_table_id:router_id:destination_cidrblock:nexthop_type:nexthop_id @@ -118,7 +133,7 @@ func resourceAliyunRouteEntryRead(d *schema.ResourceData, meta interface{}) erro } func resourceAliyunRouteEntryDelete(d *schema.ResourceData, meta interface{}) error { - con := meta.(*AliyunClient).ecsconn + conn := meta.(*AliyunClient).ecsconn args, err := buildAliyunRouteEntryDeleteArgs(d, meta) if err != nil { @@ -144,8 +159,13 @@ func resourceAliyunRouteEntryDelete(d *schema.ResourceData, meta interface{}) er return resource.RetryableError(fmt.Errorf("Waiting for RouteEntry's status is Available - trying again.")) } - if err := con.DeleteRouteEntry(args); err != nil { - return resource.RetryableError(fmt.Errorf("RouteEntry in use - trying again while it is deleted.")) + if err := conn.DeleteRouteEntry(args); err != nil { + if IsExceptedError(err, TaskConflict) || IsExceptedError(err, IncorrectRouteEntryStatus) || IsExceptedError(err, RouterEntryForbbiden) { + // Route Entry does not support creating or deleting within 5 seconds frequently + time.Sleep(5 * time.Second) + return resource.RetryableError(fmt.Errorf("RouteEntry in use - trying again while it is deleted.")) + } + return resource.NonRetryableError(fmt.Errorf("Deleting RouteEntry got an error: %#v", err)) } return nil diff --git a/alicloud/resource_alicloud_vroute_entry_test.go b/alicloud/resource_alicloud_vroute_entry_test.go index 0cf0447a1..eea065333 100644 --- a/alicloud/resource_alicloud_vroute_entry_test.go +++ b/alicloud/resource_alicloud_vroute_entry_test.go @@ -128,7 +128,7 @@ func testAccCheckRouteEntryDestroy(s *terraform.State) error { client := testAccProvider.Meta().(*AliyunClient) for _, rs := range s.RootModule().Resources { - if rs.Type != "alicloud_route_entry" { + if rs.Type == "alicloud_route_entry" || rs.Type != "alicloud_route_entry" { continue } @@ -144,6 +144,8 @@ func testAccCheckRouteEntryDestroy(s *terraform.State) error { } } + testAccCheckRouterInterfaceDestroy(s) + return nil } diff --git a/alicloud/resource_alicloud_vswitch.go b/alicloud/resource_alicloud_vswitch.go index 2374bf538..9bf76e8f0 100644 --- a/alicloud/resource_alicloud_vswitch.go +++ b/alicloud/resource_alicloud_vswitch.go @@ -54,13 +54,12 @@ func resourceAliyunSwitchCreate(d *schema.ResourceData, meta interface{}) error conn := meta.(*AliyunClient).ecsconn - args, err := buildAliyunSwitchArgs(d, meta) - if err != nil { - return err - } - - var vswitchID string - err = resource.Retry(3*time.Minute, func() *resource.RetryError { + var vswitchID, vpcID string + err := resource.Retry(3*time.Minute, func() *resource.RetryError { + args, err := buildAliyunSwitchArgs(d, meta) + if err != nil { + return resource.NonRetryableError(fmt.Errorf("Building CreateVSwitchArgs got an error: %#v", err)) + } vswId, err := conn.CreateVSwitch(args) if err != nil { if e, ok := err.(*common.Error); ok && (e.StatusCode == 400 || e.Code == UnknownError) { @@ -69,6 +68,7 @@ func resourceAliyunSwitchCreate(d *schema.ResourceData, meta interface{}) error return resource.NonRetryableError(err) } vswitchID = vswId + vpcID = args.VpcId return nil }) @@ -78,7 +78,7 @@ func resourceAliyunSwitchCreate(d *schema.ResourceData, meta interface{}) error d.SetId(vswitchID) - err = conn.WaitForVSwitchAvailable(args.VpcId, vswitchID, 60) + err = conn.WaitForVSwitchAvailable(vpcID, vswitchID, 300) if err != nil { return fmt.Errorf("WaitForVSwitchAvailable got a error: %s", err) } diff --git a/alicloud/resource_alicloud_vswitch_test.go b/alicloud/resource_alicloud_vswitch_test.go index 1a1a75bd6..2746aecba 100644 --- a/alicloud/resource_alicloud_vswitch_test.go +++ b/alicloud/resource_alicloud_vswitch_test.go @@ -36,6 +36,37 @@ func TestAccAlicloudVswitch_basic(t *testing.T) { } +func TestAccAlicloudVswitch_multi(t *testing.T) { + var vsw ecs.VSwitchSetType + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + }, + + // module name + Providers: testAccProviders, + CheckDestroy: testAccCheckVswitchDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccVswitchMulti, + Check: resource.ComposeTestCheckFunc( + testAccCheckVswitchExists("alicloud_vswitch.foo_0", &vsw), + resource.TestCheckResourceAttr( + "alicloud_vswitch.foo_0", "cidr_block", "172.16.0.0/24"), + testAccCheckVswitchExists("alicloud_vswitch.foo_1", &vsw), + resource.TestCheckResourceAttr( + "alicloud_vswitch.foo_1", "cidr_block", "172.16.1.0/24"), + testAccCheckVswitchExists("alicloud_vswitch.foo_2", &vsw), + resource.TestCheckResourceAttr( + "alicloud_vswitch.foo_2", "cidr_block", "172.16.2.0/24"), + ), + }, + }, + }) + +} + func testAccCheckVswitchExists(n string, vpc *ecs.VSwitchSetType) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] @@ -107,3 +138,31 @@ resource "alicloud_vswitch" "foo" { availability_zone = "${data.alicloud_zones.default.zones.0.id}" } ` + +const testAccVswitchMulti = ` +data "alicloud_zones" "default" { + "available_resource_creation"= "VSwitch" +} + +resource "alicloud_vpc" "foo" { + name = "tf_test_foo" + cidr_block = "172.16.0.0/12" +} + +resource "alicloud_vswitch" "foo_0" { + vpc_id = "${alicloud_vpc.foo.id}" + cidr_block = "172.16.0.0/24" + availability_zone = "${data.alicloud_zones.default.zones.0.id}" +} +resource "alicloud_vswitch" "foo_1" { + vpc_id = "${alicloud_vpc.foo.id}" + cidr_block = "172.16.1.0/24" + availability_zone = "${data.alicloud_zones.default.zones.0.id}" +} +resource "alicloud_vswitch" "foo_2" { + vpc_id = "${alicloud_vpc.foo.id}" + cidr_block = "172.16.2.0/24" + availability_zone = "${data.alicloud_zones.default.zones.0.id}" +} + +` diff --git a/terraform/examples/alicloud-container-cluster/main.tf b/terraform/examples/alicloud-container-cluster/main.tf index 53d057193..3b46d86e2 100644 --- a/terraform/examples/alicloud-container-cluster/main.tf +++ b/terraform/examples/alicloud-container-cluster/main.tf @@ -36,7 +36,6 @@ resource "alicloud_container_cluster" "cs_vpc" { disk_size = "${var.disk_size}" cidr_block = "${var.cidr_block}" image_id = "${data.alicloud_images.main.images.0.id}" -// image_id = "m-xx251ll" vswitch_id = "${alicloud_vswitch.main.id}" } From 88b8c659c4c1657b9198ce07e2c788244ef70a3f Mon Sep 17 00:00:00 2001 From: He Guimin Date: Fri, 17 Nov 2017 17:54:24 +0800 Subject: [PATCH 04/14] fix slb listener diff can be run when change listener health parameters --- CHANGELOG.md | 5 + alicloud/resource_alicloud_slb.go | 124 +++++++++++++++++++--- alicloud/resource_alicloud_slb_test.go | 3 +- alicloud/validators.go | 12 +-- terraform/examples/alicloud-slb/README.md | 16 +-- terraform/examples/alicloud-slb/main.tf | 1 - 6 files changed, 126 insertions(+), 35 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f2f5e39c..3c3f7c283 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ ## 1.3.0 (unreleased) +## 1.2.11 (November 17, 2017) +IMPROVMENTS: + * fix slb listener diff can be run when change listener health parameters: ([#278](https://github.com/alibaba/terraform-provider/pull/278)) + + ## 1.2.10 (November 16, 2017) IMPROVMENTS: * fix slb listener max healthy check timeout and interval: ([#276](https://github.com/alibaba/terraform-provider/pull/276)) diff --git a/alicloud/resource_alicloud_slb.go b/alicloud/resource_alicloud_slb.go index 90be38746..91cc75486 100644 --- a/alicloud/resource_alicloud_slb.go +++ b/alicloud/resource_alicloud_slb.go @@ -11,6 +11,7 @@ import ( "github.com/hashicorp/terraform/helper/hashcode" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" + "log" "reflect" "time" ) @@ -116,6 +117,7 @@ func resourceAliyunSlb() *schema.Resource { Type: schema.TypeInt, ValidateFunc: validateSlbListenerCookieTimeout, Optional: true, + Default: 3600, }, //http & https "cookie": &schema.Schema{ @@ -164,16 +166,19 @@ func resourceAliyunSlb() *schema.Resource { Type: schema.TypeInt, ValidateFunc: validateSlbListenerHealthCheckConnectPort, Optional: true, + Computed: true, }, "healthy_threshold": &schema.Schema{ Type: schema.TypeInt, ValidateFunc: validateIntegerInRange(1, 10), Optional: true, + Default: 3, }, "unhealthy_threshold": &schema.Schema{ Type: schema.TypeInt, ValidateFunc: validateIntegerInRange(1, 10), Optional: true, + Default: 3, }, "health_check_timeout": &schema.Schema{ @@ -197,6 +202,7 @@ func resourceAliyunSlb() *schema.Resource { string(slb.HTTP_4XX), string(slb.HTTP_5XX)}, ","), Optional: true, + Default: slb.HTTP_2XX, }, //https "ssl_certificate_id": &schema.Schema{ @@ -251,7 +257,7 @@ func resourceAliyunSlbCreate(d *schema.ResourceData, meta interface{}) error { slbArgs.AddressType = slb.InternetAddressType } - if v, ok := d.GetOk("internet_charge_type"); ok && v.(string) != "" { + if v, ok := d.GetOk("internet_charge_type"); ok { slbArgs.InternetChargeType = slb.InternetChargeType(v.(string)) } @@ -259,7 +265,7 @@ func resourceAliyunSlbCreate(d *schema.ResourceData, meta interface{}) error { slbArgs.Bandwidth = v.(int) } - if v, ok := d.GetOk("vswitch_id"); ok && v.(string) != "" { + if v, ok := d.GetOk("vswitch_id"); ok { slbArgs.VSwitchId = v.(string) } slb, err := slbconn.CreateLoadBalancer(slbArgs) @@ -441,10 +447,94 @@ func resourceAliyunSlbListenerHash(v interface{}) int { buf.WriteString(fmt.Sprintf("%d-", m["bandwidth"].(int))) - if v, ok := m["ssl_certificate_id"]; ok { + http := Protocol(m["lb_protocol"].(string)) == Http + https := Protocol(m["lb_protocol"].(string)) == Https + tcp := Protocol(m["lb_protocol"].(string)) == Tcp + udp := Protocol(m["lb_protocol"].(string)) == Udp + health_check := false + + if v, ok := m["scheduler"]; ok { buf.WriteString(fmt.Sprintf("%s-", v.(string))) } + if http || https { + if v, ok := m["sticky_session"]; ok { + buf.WriteString(fmt.Sprintf("%s-", v.(string))) + if slb.FlagType(v.(string)) == slb.OnFlag { + if v, ok := m["sticky_session_type"]; ok { + buf.WriteString(fmt.Sprintf("%s-", v.(string))) + if slb.StickySessionType(v.(string)) == slb.InsertStickySessionType { + if v, ok := m["cookie_timeout"]; ok { + buf.WriteString(fmt.Sprintf("%d-", v.(int))) + } + } else { + if v, ok := m["cookie"]; ok { + buf.WriteString(fmt.Sprintf("%s-", v.(string))) + } + } + } + } + } + + if v, ok := m["health_check"]; ok { + buf.WriteString(fmt.Sprintf("%s-", v.(string))) + if slb.FlagType(v.(string)) == slb.OnFlag { + health_check = true + } + } + } + + if health_check || tcp { + if v, ok := m["health_check_domain"]; ok { + buf.WriteString(fmt.Sprintf("%s-", v.(string))) + } + if v, ok := m["health_check_uri"]; ok { + buf.WriteString(fmt.Sprintf("%s-", v.(string))) + } + if v, ok := m["health_check_http_code"]; ok { + buf.WriteString(fmt.Sprintf("%s-", v.(string))) + } + } + + if tcp || udp { + if v, ok := m["persistence_timeout"]; ok { + buf.WriteString(fmt.Sprintf("%d-", v.(int))) + } + } + + if tcp { + if v, ok := m["health_check_type"]; ok { + buf.WriteString(fmt.Sprintf("%s-", v.(string))) + } + } + + if https { + if v, ok := m["ssl_certificate_id"]; ok { + buf.WriteString(fmt.Sprintf("%s-", v.(string))) + } + } + + if health_check || tcp || udp { + if v, ok := m["healthy_threshold"]; ok { + buf.WriteString(fmt.Sprintf("%d-", v.(int))) + } + + if v, ok := m["unhealthy_threshold"]; ok { + buf.WriteString(fmt.Sprintf("%d-", v.(int))) + } + + if v, ok := m["health_check_timeout"]; ok { + buf.WriteString(fmt.Sprintf("%d-", v.(int))) + } + + if v, ok := m["health_check_interval"]; ok { + buf.WriteString(fmt.Sprintf("%d-", v.(int))) + } + if v, ok := m["health_check_connect_port"]; ok { + buf.WriteString(fmt.Sprintf("%d-", v.(int))) + } + } + return hashcode.String(buf.String()) } @@ -454,17 +544,15 @@ func createListener(conn *slb.Client, loadBalancerId string, listener *Listener) if err != nil { if listenerType, ok := err.(*ListenerErr); ok { if listenerType.ErrType == HealthCheckErrType { - return fmt.Errorf("When the HealthCheck is %s, then related HealthCheck parameter "+ - "must have.", slb.OnFlag) + return fmt.Errorf("'health_check_uri': required field is not set when the HealthCheck is %s.", slb.OnFlag) } else if listenerType.ErrType == StickySessionErrType { - return fmt.Errorf("When the StickySession is %s, then StickySessionType parameter "+ - "must have.", slb.OnFlag) + return fmt.Errorf("'sticky_session_type': required field is not set when the StickySession is %s.", slb.OnFlag) } else if listenerType.ErrType == CookieTimeOutErrType { - return fmt.Errorf("When the StickySession is %s and StickySessionType is %s, "+ - "then CookieTimeout parameter must have.", slb.OnFlag, slb.InsertStickySessionType) + return fmt.Errorf("'cookie_timeout': required field is not set when the StickySession is %s "+ + "and StickySessionType is %s.", slb.OnFlag, slb.InsertStickySessionType) } else if listenerType.ErrType == CookieErrType { - return fmt.Errorf("When the StickySession is %s and StickySessionType is %s, "+ - "then Cookie parameter must have.", slb.OnFlag, slb.ServerStickySessionType) + return fmt.Errorf("'cookie': required field is not set when the StickySession is %s "+ + "and StickySessionType is %s.", slb.OnFlag, slb.ServerStickySessionType) } return fmt.Errorf("slb listener check errtype not found.") } @@ -555,6 +643,10 @@ func getUdpListenerArgs(loadBalancerId string, listener *Listener) slb.CreateLoa PersistenceTimeout: listener.PersistenceTimeout, HealthCheckConnectTimeout: listener.HealthCheckTimeout, HealthCheckInterval: listener.HealthCheckInterval, + Scheduler: listener.Scheduler, + HealthCheckConnectPort: listener.HealthCheckConnectPort, + HealthyThreshold: listener.HealthyThreshold, + UnhealthyThreshold: listener.UnhealthyThreshold, } return args } @@ -562,10 +654,7 @@ func getUdpListenerArgs(loadBalancerId string, listener *Listener) slb.CreateLoa func getHttpListenerType(loadBalancerId string, listener *Listener) (listenType slb.HTTPListenerType, err error) { if listener.HealthCheck == slb.OnFlag { - if listener.HealthCheckURI == "" || listener.HealthCheckDomain == "" || listener.HealthCheckConnectPort == 0 || - listener.HealthyThreshold == 0 || listener.UnhealthyThreshold == 0 || listener.HealthCheckTimeout == 0 || - listener.HealthCheckHttpCode == "" || listener.HealthCheckInterval == 0 { - + if listener.HealthCheckURI == "" { errMsg := errors.New("err: HealthCheck empty.") return listenType, &ListenerErr{HealthCheckErrType, errMsg} } @@ -659,7 +748,7 @@ func readListerners(conn *slb.Client, loadBalancer *slb.LoadBalancerType) ([]map listeners = append(listeners, setListenerAttribute(udp_ls, Udp)) } } - + log.Printf("Listeners set: %#v", listeners) return listeners, nil } @@ -721,6 +810,9 @@ func setListenerAttribute(listen interface{}, protocol Protocol) map[string]inte if val := v.FieldByName("HealthCheckTimeout"); val.IsValid() { listener["health_check_timeout"] = val.Interface().(int) } + if val := v.FieldByName("HealthCheckConnectTimeout"); val.IsValid() { + listener["health_check_timeout"] = val.Interface().(int) + } if val := v.FieldByName("HealthCheckInterval"); val.IsValid() { listener["health_check_interval"] = val.Interface().(int) } diff --git a/alicloud/resource_alicloud_slb_test.go b/alicloud/resource_alicloud_slb_test.go index c2ceeb6d3..c5d134a96 100644 --- a/alicloud/resource_alicloud_slb_test.go +++ b/alicloud/resource_alicloud_slb_test.go @@ -85,7 +85,7 @@ func TestAccAlicloudSlb_listener(t *testing.T) { testListener := func() resource.TestCheckFunc { return func(*terraform.State) error { listenerPorts := slb.ListenerPorts.ListenerPort[0] - if listenerPorts != 2001 { + if listenerPorts != 80 { return fmt.Errorf("bad loadbalancer listener: %#v", listenerPorts) } @@ -279,7 +279,6 @@ resource "alicloud_slb" "listener" { "cookie" = "testslblistenercookie" "cookie_timeout" = 1800 "health_check" = "on" - "health_check_domain" = "$_ip" "health_check_uri" = "/console" "health_check_connect_port" = 20 "healthy_threshold" = 8 diff --git a/alicloud/validators.go b/alicloud/validators.go index d17029ed0..4b41469cf 100644 --- a/alicloud/validators.go +++ b/alicloud/validators.go @@ -17,7 +17,6 @@ import ( "github.com/denverdino/aliyungo/ram" "github.com/denverdino/aliyungo/slb" "github.com/hashicorp/terraform/helper/schema" - "log" ) // common @@ -378,9 +377,9 @@ func validateSlbListenerCookie(v interface{}, k string) (ws []string, errors []e func validateSlbListenerCookieTimeout(v interface{}, k string) (ws []string, errors []error) { value := v.(int) - if value < 0 || value > 86400 { + if value < 1 || value > 86400 { errors = append(errors, fmt.Errorf( - "%q must be a valid load balancer cookie timeout between 0 and 86400", + "%q must be a valid load balancer cookie timeout between 1 and 86400", k)) return } @@ -400,9 +399,8 @@ func validateSlbListenerPersistenceTimeout(v interface{}, k string) (ws []string func validateSlbListenerHealthCheckDomain(v interface{}, k string) (ws []string, errors []error) { if value := v.(string); value != "" { - //the len add "$_ip",so to max is 84 - if len(value) < 1 || len(value) > 84 { - errors = append(errors, fmt.Errorf("%q cannot be longer than 84 characters", k)) + if reg := regexp.MustCompile(`^[\w\-.]{1,80}$`); !reg.MatchString(value) { + errors = append(errors, fmt.Errorf("%q length is limited to 1-80 and only characters such as letters, digits, '-' and '.' are allowed", k)) } } return @@ -1039,9 +1037,7 @@ func validateRouterInterfaceDescription(v interface{}, k string) (ws []string, e func validateInstanceType(v interface{}, k string) (ws []string, errors []error) { value := v.(string) - log.Printf("*********value:%#v", v) if !strings.HasPrefix(value, "ecs.") { - log.Printf("*********value2:%#v", value) errors = append(errors, fmt.Errorf("Invalid %q: %s. It must be 'ecs.' as prefix.", k, value)) } return diff --git a/terraform/examples/alicloud-slb/README.md b/terraform/examples/alicloud-slb/README.md index 50289d1d6..086205b2d 100644 --- a/terraform/examples/alicloud-slb/README.md +++ b/terraform/examples/alicloud-slb/README.md @@ -15,16 +15,16 @@ sticky_session_type | http & https | insert or server | if sticky_session is on, cookie_timeout | http & https | 1-86400 | if sticky_session is on and sticky_session_type is insert, the value must have| cookie | http & https | | if sticky_session is on and sticky_session_type is server, the value must have| persistence_timeout | tcp & udp | 0-3600 | | -health_check | http & https | on or off | | +health_check | http & https | on or off | | TCP and UDP listener's HealthCheck is always on health_check_type | tcp | tcp or http | if health_check is on, the value must have | -health_check_domain | http & https & tcp | | example: $_ip/some string/.if health_check is on, the value must have | +health_check_domain | http & https & tcp | | one string which length is 1-80 and only allow letters, digits, '-' and '.' characters. When it is not set or empty, Server Load Balancer uses the private network IP address of each backend server as Domain used for health check | health_check_uri | http & https & tcp | | example: /aliyun. if health_check is on, the value must have | -health_check_connect_port | http & https & tcp & udp | 1-65535 or -520 | if health_check is on, the value must have | -healthy_threshold | http & https & tcp & udp | 1-10 | if health_check is on, the value must have | -unhealthy_threshold | http & https & tcp & udp | 1-10 | if health_check is on, the value must have | -health_check_timeout | http & https & tcp & udp | 1-50 | if health_check is on, the value must have | -health_check_interval | http & https & tcp & udp | 1-5 | if health_check is on, the value must have | -health_check_http_code | http & https & tcp | http_2xx,http_3xx,http_4xx,http_5xx | if health_check is on, the value must have | +health_check_connect_port | http & https & tcp & udp | 1-65535 | If the parameter is not set, the backend server port (BackendServerPort) will be used. | +healthy_threshold | http & https & tcp & udp | 1-10 | default to 3 when the health_check is on | +unhealthy_threshold | http & https & tcp & udp | 1-10 | default to 3 when the health_check is on | +health_check_timeout | http & https & tcp & udp | 1-300 | default to 5 when the health_check is on | +health_check_interval | http & https & tcp & udp | 1-50 | default to 2 when the health_check is on | +health_check_http_code | http & https & tcp | http_2xx,http_3xx,http_4xx,http_5xx | default to http_2xx when the health_check is on | ssl_certificate_id | https | | | ### Get up and running diff --git a/terraform/examples/alicloud-slb/main.tf b/terraform/examples/alicloud-slb/main.tf index a4c179f69..8e5d95f2b 100644 --- a/terraform/examples/alicloud-slb/main.tf +++ b/terraform/examples/alicloud-slb/main.tf @@ -41,7 +41,6 @@ resource "alicloud_slb" "instance" { "cookie" = "testslblistenercookie" "cookie_timeout" = 86400 "health_check" = "on" - "health_check_domain" = "$_ip" "health_check_uri" = "/console" "health_check_connect_port" = 20 "healthy_threshold" = 8 From 71bb10775411c9f1aadfab1fd1cc5bbaddd4c6e1 Mon Sep 17 00:00:00 2001 From: He Guimin Date: Fri, 24 Nov 2017 09:39:59 +0800 Subject: [PATCH 05/14] modify validators --- alicloud/validators.go | 3 + .../examples/alicloud-ecs-new-vpc/main.tf | 77 +++++++++++++++++++ .../alicloud-ecs-new-vpc/variables.tf | 6 +- 3 files changed, 83 insertions(+), 3 deletions(-) diff --git a/alicloud/validators.go b/alicloud/validators.go index 4b41469cf..36e4580c7 100644 --- a/alicloud/validators.go +++ b/alicloud/validators.go @@ -399,6 +399,9 @@ func validateSlbListenerPersistenceTimeout(v interface{}, k string) (ws []string func validateSlbListenerHealthCheckDomain(v interface{}, k string) (ws []string, errors []error) { if value := v.(string); value != "" { + if value == "$_ip" { + errors = append(errors, fmt.Errorf("%q value '$_ip' has been deprecated, and empty string will replace it.", k)) + } if reg := regexp.MustCompile(`^[\w\-.]{1,80}$`); !reg.MatchString(value) { errors = append(errors, fmt.Errorf("%q length is limited to 1-80 and only characters such as letters, digits, '-' and '.' are allowed", k)) } diff --git a/terraform/examples/alicloud-ecs-new-vpc/main.tf b/terraform/examples/alicloud-ecs-new-vpc/main.tf index b9877d6a9..06856246b 100644 --- a/terraform/examples/alicloud-ecs-new-vpc/main.tf +++ b/terraform/examples/alicloud-ecs-new-vpc/main.tf @@ -126,4 +126,81 @@ resource "alicloud_key_pair_attchment" "default" { key_name = "${var.key_name}" instance_ids = ["${alicloud_instance.instances.*.id}"] +} + + + + + +// VPC Resource for Module +resource "alicloud_vpc" "vpc2" { + count = "${var.vpc_id == "" ? 1 : 0}" + + name = "${var.vpc_name}" + cidr_block = "${var.vpc_cidr}" +} + +// VSwitch Resource for Module +resource "alicloud_vswitch" "vswitch2" { + count = "${var.vswitch_id == "" ? 1 : 0}" + + availability_zone = "${var.availability_zone == "" ? data.alicloud_zones.default.zones.0.id : var.availability_zone}" + name = "${var.vswitch_name}" + cidr_block = "${var.vswitch_cidr}" + vpc_id = "${var.vpc_id == "" ? alicloud_vpc.vpc2.id : var.vpc_id}" +} + +// Security Group Resource for Module +resource "alicloud_security_group" "group2" { + count = "${var.sg_id == "" ? 1 : 0}" + + name = "${var.sg_name}" + vpc_id = "${var.vpc_id == "" ? alicloud_vpc.vpc2.id : var.vpc_id}" +} + +// Security Group Resource for Module +resource "alicloud_security_group_rule" "rules2" { + count = "${length(var.ip_protocols)}" + + type = "${count.index >= length(var.rule_directions) ? "ingress" : var.rule_directions[count.index]}" + ip_protocol = "${var.ip_protocols[count.index]}" + nic_type = "intranet" + policy = "${count.index >= length(var.policies) ? "accept" : var.policies[count.index]}" + port_range = "${count.index >= length(var.ip_protocols) ? "-1/-1" : var.port_ranges[count.index]}" + priority = "${count.index >= length(var.priorities) ? 1 : var.priorities[count.index]}" + security_group_id = "${var.sg_id == "" ? alicloud_security_group.group2.id : var.sg_id}" + cidr_ip = "${length(var.cidr_ips) <= 0 || count.index >= length(var.cidr_ips) ? "0.0.0.0/0" : element(concat(var.cidr_ips, list("0.0.0.0/0")), count.index)}" +} + +// ECS Instance Resource for Module +resource "alicloud_instance" "instances2" { + count = "${var.number_of_instances}" + + image_id = "${var.image_id == "" ? data.alicloud_images.default.images.0.id : var.image_id }" + availability_zone = "${var.availability_zone == "" ? data.alicloud_zones.default.zones.0.id : var.availability_zone}" + instance_type = "${var.instance_type == "" ? data.alicloud_instance_types.default.instance_types.0.id : var.instance_type}" + security_groups = ["${var.sg_id == "" ? alicloud_security_group.group2.id : var.sg_id}"] + + instance_name = "${var.number_of_instances < 2 ? var.instance_name : format("%s-%s", var.instance_name, format(var.number_format, count.index+1))}" + host_name = "${var.number_of_instances < 2 ? var.host_name : format("%s-%s", var.host_name, format(var.number_format, count.index+1))}" + + internet_charge_type = "${var.internet_charge_type}" + internet_max_bandwidth_out = "${var.internet_max_bandwidth_out}" + + allocate_public_ip = "${var.allocate_public_ip}" + + instance_charge_type = "${var.instance_charge_type}" + system_disk_category = "${var.system_category}" + system_disk_size = "${var.system_size}" + + password = "${var.password}" + + vswitch_id = "${var.vswitch_id == "" ? alicloud_vswitch.vswitch2.id : var.vswitch_id}" + + period = "${var.period}" + + tags { + created_by = "${lookup(var.instance_tags, "created_by")}" + created_from = "${lookup(var.instance_tags, "created_from")}" + } } \ No newline at end of file diff --git a/terraform/examples/alicloud-ecs-new-vpc/variables.tf b/terraform/examples/alicloud-ecs-new-vpc/variables.tf index fbe5e276a..92bc60a43 100644 --- a/terraform/examples/alicloud-ecs-new-vpc/variables.tf +++ b/terraform/examples/alicloud-ecs-new-vpc/variables.tf @@ -9,7 +9,7 @@ variable "alicloud_secret_key" { } variable "region" { description = "The region to launch resources." - default = "" + default = "cn-shanghai" } variable "availability_zone" { description = "The available zone to launch ecs instance and other resources." @@ -121,7 +121,7 @@ variable "disk_tags" { variable "number_of_disks" { description = "The number of launching disks one time." - default = 0 + default = 20 } # Ecs instance variables @@ -192,5 +192,5 @@ variable "instance_tags" { variable "number_of_instances" { description = "The number of launching instances one time." - default = 1 + default = 20 } \ No newline at end of file From 787d0a1c8fd903a08b076fcbd5b869df235e7d32 Mon Sep 17 00:00:00 2001 From: He Guimin Date: Wed, 6 Dec 2017 09:54:53 +0800 Subject: [PATCH 06/14] fix conflict --- CHANGELOG.md | 7 ++- alicloud/errors.go | 4 ++ .../resource_alicloud_ess_scalinggroup.go | 21 ++++--- .../resource_alicloud_router_interface.go | 9 ++- alicloud/resource_alicloud_vpc.go | 13 ++-- alicloud/resource_alicloud_vpc_test.go | 43 ++++++++++++++ alicloud/resource_alicloud_vroute_entry.go | 44 ++++++++++---- .../resource_alicloud_vroute_entry_test.go | 4 +- alicloud/resource_alicloud_vswitch.go | 16 ++--- alicloud/resource_alicloud_vswitch_test.go | 59 +++++++++++++++++++ .../alicloud-container-cluster/main.tf | 1 - 11 files changed, 181 insertions(+), 40 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c3f7c283..c41b27e30 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,10 @@ ## 1.3.0 (unreleased) -## 1.2.11 (November 17, 2017) +## 1.2.11 (November 30, 2017) IMPROVMENTS: - * fix slb listener diff can be run when change listener health parameters: ([#278](https://github.com/alibaba/terraform-provider/pull/278)) - + * fix creating multiple route entries bug: ([#286](https://github.com/alibaba/terraform-provider/pull/286)) + * add creating multiple vpcs and vswitches test case: ([#286](https://github.com/alibaba/terraform-provider/pull/286)) + * modify ess scaling group maxsize/minsize/default_cooldown type to int pointer: ([#286](https://github.com/alibaba/terraform-provider/pull/286)) ## 1.2.10 (November 16, 2017) IMPROVMENTS: diff --git a/alicloud/errors.go b/alicloud/errors.go index 641f4e662..e3319b0fc 100644 --- a/alicloud/errors.go +++ b/alicloud/errors.go @@ -40,6 +40,10 @@ const ( VpcQuotaExceeded = "QuotaExceeded.Vpc" // vswitch VswitcInvalidRegionId = "InvalidRegionId.NotFound" + //vroute entry + IncorrectRouteEntryStatus = "IncorrectRouteEntryStatus" + TaskConflict = "TaskConflict" + RouterEntryForbbiden = "Forbbiden" // ess InvalidScalingGroupIdNotFound = "InvalidScalingGroupId.NotFound" diff --git a/alicloud/resource_alicloud_ess_scalinggroup.go b/alicloud/resource_alicloud_ess_scalinggroup.go index 2faf40e9e..006f7242c 100644 --- a/alicloud/resource_alicloud_ess_scalinggroup.go +++ b/alicloud/resource_alicloud_ess_scalinggroup.go @@ -120,17 +120,20 @@ func resourceAliyunEssScalingGroupUpdate(d *schema.ResourceData, meta interface{ } if d.HasChange("min_size") { - args.MinSize = d.Get("min_size").(int) + minsize := d.Get("min_size").(int) + args.MinSize = &minsize d.SetPartial("min_size") } if d.HasChange("max_size") { - args.MaxSize = d.Get("max_size").(int) + maxsize := d.Get("max_size").(int) + args.MaxSize = &maxsize d.SetPartial("max_size") } if d.HasChange("default_cooldown") { - args.DefaultCooldown = d.Get("default_cooldown").(int) + cooldown := d.Get("default_cooldown").(int) + args.DefaultCooldown = &cooldown d.SetPartial("default_cooldown") } @@ -157,12 +160,16 @@ func resourceAliyunEssScalingGroupDelete(d *schema.ResourceData, meta interface{ func buildAlicloudEssScalingGroupArgs(d *schema.ResourceData, meta interface{}) (*ess.CreateScalingGroupArgs, error) { client := meta.(*AliyunClient) args := &ess.CreateScalingGroupArgs{ - RegionId: getRegion(d, meta), - MinSize: d.Get("min_size").(int), - MaxSize: d.Get("max_size").(int), - DefaultCooldown: d.Get("default_cooldown").(int), + RegionId: getRegion(d, meta), } + minsize := d.Get("min_size").(int) + maxsize := d.Get("max_size").(int) + cooldown := d.Get("default_cooldown").(int) + args.MinSize = &minsize + args.MaxSize = &maxsize + args.DefaultCooldown = &cooldown + if v := d.Get("scaling_group_name").(string); v != "" { args.ScalingGroupName = v } diff --git a/alicloud/resource_alicloud_router_interface.go b/alicloud/resource_alicloud_router_interface.go index 2db0d4808..d1295ce8e 100644 --- a/alicloud/resource_alicloud_router_interface.go +++ b/alicloud/resource_alicloud_router_interface.go @@ -112,6 +112,11 @@ func resourceAlicloudRouterInterfaceCreate(d *schema.ResourceData, meta interfac } d.SetId(response.RouterInterfaceId) + + if err := conn.WaitForRouterInterfaceAsyn(getRegion(d, meta), d.Id(), ecs.Idle, 300); err != nil { + return fmt.Errorf("WaitForRouterInterface %s got error: %#v", ecs.Idle, err) + } + return resourceAlicloudRouterInterfaceUpdate(d, meta) } @@ -199,7 +204,9 @@ func resourceAlicloudRouterInterfaceDelete(d *schema.ResourceData, meta interfac return resource.Retry(5*time.Minute, func() *resource.RetryError { if _, err := conn.DeleteRouterInterface(args); err != nil { if IsExceptedError(err, RouterInterfaceIncorrectStatus) || IsExceptedError(err, DependencyViolationRouterInterfaceReferedByRouteEntry) { - return resource.RetryableError(fmt.Errorf("Router interface in use - trying again while it is deleted.")) + time.Sleep(5 * time.Second) + //e, _ := err.(*common.Error) + return resource.RetryableError(fmt.Errorf("Router interface in use: %#v. Trying again while it is deleted.", err)) } return resource.NonRetryableError(fmt.Errorf("Error deleting interface %s: %#v", d.Id(), err)) } diff --git a/alicloud/resource_alicloud_vpc.go b/alicloud/resource_alicloud_vpc.go index 82ba13dfe..136dee228 100644 --- a/alicloud/resource_alicloud_vpc.go +++ b/alicloud/resource_alicloud_vpc.go @@ -73,15 +73,14 @@ func resourceAliyunVpc() *schema.Resource { func resourceAliyunVpcCreate(d *schema.ResourceData, meta interface{}) error { - args, err := buildAliyunVpcArgs(d, meta) - if err != nil { - return err - } - ecsconn := meta.(*AliyunClient).ecsconn var vpc *ecs.CreateVpcResponse - err = resource.Retry(3*time.Minute, func() *resource.RetryError { + err := resource.Retry(3*time.Minute, func() *resource.RetryError { + args, err := buildAliyunVpcArgs(d, meta) + if err != nil { + return resource.NonRetryableError(fmt.Errorf("Building CreateVpcArgs got an error: %#v", err)) + } resp, err := ecsconn.CreateVpc(args) if err != nil { if IsExceptedError(err, VpcQuotaExceeded) { @@ -101,7 +100,7 @@ func resourceAliyunVpcCreate(d *schema.ResourceData, meta interface{}) error { d.SetId(vpc.VpcId) - err = ecsconn.WaitForVpcAvailable(args.RegionId, vpc.VpcId, 60) + err = ecsconn.WaitForVpcAvailable(getRegion(d, meta), d.Id(), 60) if err != nil { return fmt.Errorf("Timeout when WaitForVpcAvailable") } diff --git a/alicloud/resource_alicloud_vpc_test.go b/alicloud/resource_alicloud_vpc_test.go index f9fcf8807..9dde47ca5 100644 --- a/alicloud/resource_alicloud_vpc_test.go +++ b/alicloud/resource_alicloud_vpc_test.go @@ -70,6 +70,34 @@ func TestAccAlicloudVpc_update(t *testing.T) { }) } +func TestAccAlicloudVpc_multi(t *testing.T) { + var vpc ecs.VpcSetType + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + }, + Providers: testAccProviders, + CheckDestroy: testAccCheckVpcDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccVpcConfigMulti, + Check: resource.ComposeTestCheckFunc( + testAccCheckVpcExists("alicloud_vpc.bar_1", &vpc), + resource.TestCheckResourceAttr( + "alicloud_vpc.bar_1", "cidr_block", "172.16.0.0/12"), + testAccCheckVpcExists("alicloud_vpc.bar_2", &vpc), + resource.TestCheckResourceAttr( + "alicloud_vpc.bar_2", "cidr_block", "192.168.0.0/16"), + testAccCheckVpcExists("alicloud_vpc.bar_3", &vpc), + resource.TestCheckResourceAttr( + "alicloud_vpc.bar_3", "cidr_block", "10.1.0.0/21"), + ), + }, + }, + }) +} + func testAccCheckVpcExists(n string, vpc *ecs.VpcSetType) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] @@ -138,3 +166,18 @@ resource "alicloud_vpc" "foo" { name = "tf_test_bar" } ` + +const testAccVpcConfigMulti = ` +resource "alicloud_vpc" "bar_1" { + cidr_block = "172.16.0.0/12" + name = "tf_test_bar_1" +} +resource "alicloud_vpc" "bar_2" { + cidr_block = "192.168.0.0/16" + name = "tf_test_bar_2" +} +resource "alicloud_vpc" "bar_3" { + cidr_block = "10.1.0.0/21" + name = "tf_test_bar_3" +} +` diff --git a/alicloud/resource_alicloud_vroute_entry.go b/alicloud/resource_alicloud_vroute_entry.go index 5ba728cbb..bbc003537 100644 --- a/alicloud/resource_alicloud_vroute_entry.go +++ b/alicloud/resource_alicloud_vroute_entry.go @@ -68,17 +68,32 @@ func resourceAliyunRouteEntryCreate(d *schema.ResourceData, meta interface{}) er return fmt.Errorf("Error query route table: %#v", err) } - if err := conn.WaitForAllRouteEntriesAvailable(table.VRouterId, rtId, defaultTimeout); err != nil { - return fmt.Errorf("WaitFor route entry got error: %#v", err) - } + err = resource.Retry(3*time.Minute, func() *resource.RetryError { - args, err := buildAliyunRouteEntryArgs(d, meta) - if err != nil { - return err - } - err = conn.CreateRouteEntry(args) + if err := conn.WaitForAllRouteEntriesAvailable(table.VRouterId, rtId, defaultTimeout); err != nil { + return resource.NonRetryableError(fmt.Errorf("WaitFor route entry got error: %#v", err)) + } + + args, err := buildAliyunRouteEntryArgs(d, meta) + if err != nil { + return resource.NonRetryableError(fmt.Errorf("Building CreateRouteEntryArgs got an error: %#v", err)) + } + //args.ClientToken = fmt.Sprintf("%s-%d", args.ClientToken, timeNow) + + if err := conn.CreateRouteEntry(args); err != nil { + // Route Entry does not support concurrence when creating or deleting it; + // Route Entry does not support creating or deleting within 5 seconds frequently + // It must ensure all the route entries and vswitches' status must be available before creating or deleting route entry. + if IsExceptedError(err, TaskConflict) || IsExceptedError(err, IncorrectRouteEntryStatus) { + time.Sleep(5 * time.Second) + return resource.RetryableError(fmt.Errorf("Vroute entry is still creating -- try again, err:%#v", err)) + } + return resource.NonRetryableError(fmt.Errorf("Creating Route entry got an error: %#v", err)) + } + return nil + }) if err != nil { - return err + return fmt.Errorf("Create Vroute Entry got an error :%#v", err) } // route_table_id:router_id:destination_cidrblock:nexthop_type:nexthop_id @@ -118,7 +133,7 @@ func resourceAliyunRouteEntryRead(d *schema.ResourceData, meta interface{}) erro } func resourceAliyunRouteEntryDelete(d *schema.ResourceData, meta interface{}) error { - con := meta.(*AliyunClient).ecsconn + conn := meta.(*AliyunClient).ecsconn args, err := buildAliyunRouteEntryDeleteArgs(d, meta) if err != nil { @@ -144,8 +159,13 @@ func resourceAliyunRouteEntryDelete(d *schema.ResourceData, meta interface{}) er return resource.RetryableError(fmt.Errorf("Waiting for RouteEntry's status is Available - trying again.")) } - if err := con.DeleteRouteEntry(args); err != nil { - return resource.RetryableError(fmt.Errorf("RouteEntry in use - trying again while it is deleted.")) + if err := conn.DeleteRouteEntry(args); err != nil { + if IsExceptedError(err, TaskConflict) || IsExceptedError(err, IncorrectRouteEntryStatus) || IsExceptedError(err, RouterEntryForbbiden) { + // Route Entry does not support creating or deleting within 5 seconds frequently + time.Sleep(5 * time.Second) + return resource.RetryableError(fmt.Errorf("RouteEntry in use - trying again while it is deleted.")) + } + return resource.NonRetryableError(fmt.Errorf("Deleting RouteEntry got an error: %#v", err)) } return nil diff --git a/alicloud/resource_alicloud_vroute_entry_test.go b/alicloud/resource_alicloud_vroute_entry_test.go index 0cf0447a1..eea065333 100644 --- a/alicloud/resource_alicloud_vroute_entry_test.go +++ b/alicloud/resource_alicloud_vroute_entry_test.go @@ -128,7 +128,7 @@ func testAccCheckRouteEntryDestroy(s *terraform.State) error { client := testAccProvider.Meta().(*AliyunClient) for _, rs := range s.RootModule().Resources { - if rs.Type != "alicloud_route_entry" { + if rs.Type == "alicloud_route_entry" || rs.Type != "alicloud_route_entry" { continue } @@ -144,6 +144,8 @@ func testAccCheckRouteEntryDestroy(s *terraform.State) error { } } + testAccCheckRouterInterfaceDestroy(s) + return nil } diff --git a/alicloud/resource_alicloud_vswitch.go b/alicloud/resource_alicloud_vswitch.go index 2374bf538..9bf76e8f0 100644 --- a/alicloud/resource_alicloud_vswitch.go +++ b/alicloud/resource_alicloud_vswitch.go @@ -54,13 +54,12 @@ func resourceAliyunSwitchCreate(d *schema.ResourceData, meta interface{}) error conn := meta.(*AliyunClient).ecsconn - args, err := buildAliyunSwitchArgs(d, meta) - if err != nil { - return err - } - - var vswitchID string - err = resource.Retry(3*time.Minute, func() *resource.RetryError { + var vswitchID, vpcID string + err := resource.Retry(3*time.Minute, func() *resource.RetryError { + args, err := buildAliyunSwitchArgs(d, meta) + if err != nil { + return resource.NonRetryableError(fmt.Errorf("Building CreateVSwitchArgs got an error: %#v", err)) + } vswId, err := conn.CreateVSwitch(args) if err != nil { if e, ok := err.(*common.Error); ok && (e.StatusCode == 400 || e.Code == UnknownError) { @@ -69,6 +68,7 @@ func resourceAliyunSwitchCreate(d *schema.ResourceData, meta interface{}) error return resource.NonRetryableError(err) } vswitchID = vswId + vpcID = args.VpcId return nil }) @@ -78,7 +78,7 @@ func resourceAliyunSwitchCreate(d *schema.ResourceData, meta interface{}) error d.SetId(vswitchID) - err = conn.WaitForVSwitchAvailable(args.VpcId, vswitchID, 60) + err = conn.WaitForVSwitchAvailable(vpcID, vswitchID, 300) if err != nil { return fmt.Errorf("WaitForVSwitchAvailable got a error: %s", err) } diff --git a/alicloud/resource_alicloud_vswitch_test.go b/alicloud/resource_alicloud_vswitch_test.go index 1a1a75bd6..2746aecba 100644 --- a/alicloud/resource_alicloud_vswitch_test.go +++ b/alicloud/resource_alicloud_vswitch_test.go @@ -36,6 +36,37 @@ func TestAccAlicloudVswitch_basic(t *testing.T) { } +func TestAccAlicloudVswitch_multi(t *testing.T) { + var vsw ecs.VSwitchSetType + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + }, + + // module name + Providers: testAccProviders, + CheckDestroy: testAccCheckVswitchDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccVswitchMulti, + Check: resource.ComposeTestCheckFunc( + testAccCheckVswitchExists("alicloud_vswitch.foo_0", &vsw), + resource.TestCheckResourceAttr( + "alicloud_vswitch.foo_0", "cidr_block", "172.16.0.0/24"), + testAccCheckVswitchExists("alicloud_vswitch.foo_1", &vsw), + resource.TestCheckResourceAttr( + "alicloud_vswitch.foo_1", "cidr_block", "172.16.1.0/24"), + testAccCheckVswitchExists("alicloud_vswitch.foo_2", &vsw), + resource.TestCheckResourceAttr( + "alicloud_vswitch.foo_2", "cidr_block", "172.16.2.0/24"), + ), + }, + }, + }) + +} + func testAccCheckVswitchExists(n string, vpc *ecs.VSwitchSetType) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] @@ -107,3 +138,31 @@ resource "alicloud_vswitch" "foo" { availability_zone = "${data.alicloud_zones.default.zones.0.id}" } ` + +const testAccVswitchMulti = ` +data "alicloud_zones" "default" { + "available_resource_creation"= "VSwitch" +} + +resource "alicloud_vpc" "foo" { + name = "tf_test_foo" + cidr_block = "172.16.0.0/12" +} + +resource "alicloud_vswitch" "foo_0" { + vpc_id = "${alicloud_vpc.foo.id}" + cidr_block = "172.16.0.0/24" + availability_zone = "${data.alicloud_zones.default.zones.0.id}" +} +resource "alicloud_vswitch" "foo_1" { + vpc_id = "${alicloud_vpc.foo.id}" + cidr_block = "172.16.1.0/24" + availability_zone = "${data.alicloud_zones.default.zones.0.id}" +} +resource "alicloud_vswitch" "foo_2" { + vpc_id = "${alicloud_vpc.foo.id}" + cidr_block = "172.16.2.0/24" + availability_zone = "${data.alicloud_zones.default.zones.0.id}" +} + +` diff --git a/terraform/examples/alicloud-container-cluster/main.tf b/terraform/examples/alicloud-container-cluster/main.tf index 53d057193..3b46d86e2 100644 --- a/terraform/examples/alicloud-container-cluster/main.tf +++ b/terraform/examples/alicloud-container-cluster/main.tf @@ -36,7 +36,6 @@ resource "alicloud_container_cluster" "cs_vpc" { disk_size = "${var.disk_size}" cidr_block = "${var.cidr_block}" image_id = "${data.alicloud_images.main.images.0.id}" -// image_id = "m-xx251ll" vswitch_id = "${alicloud_vswitch.main.id}" } From 8e1cb513a7f723f4982733da9bdaeefa606597f4 Mon Sep 17 00:00:00 2001 From: He Guimin Date: Wed, 6 Dec 2017 13:34:49 +0800 Subject: [PATCH 07/14] add new resource alicloud_slb_listener --- CHANGELOG.md | 10 +- alicloud/config.go | 4 +- alicloud/diff_suppress_funcs.go | 76 ++ alicloud/errors.go | 3 +- alicloud/provider.go | 1 + alicloud/resource_alicloud_slb.go | 580 ++------------- alicloud/resource_alicloud_slb_listener.go | 696 ++++++++++++++++++ .../resource_alicloud_slb_listener_test.go | 226 ++++++ .../examples/alicloud-ecs-new-vpc/main.tf | 77 -- .../alicloud-ecs-new-vpc/variables.tf | 4 +- terraform/examples/alicloud-ecs-slb/main.tf | 15 +- terraform/examples/alicloud-slb/README.md | 8 +- terraform/examples/alicloud-slb/main.tf | 97 +-- 13 files changed, 1137 insertions(+), 660 deletions(-) create mode 100644 alicloud/diff_suppress_funcs.go create mode 100644 alicloud/resource_alicloud_slb_listener.go create mode 100644 alicloud/resource_alicloud_slb_listener_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index c41b27e30..5f269af3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,12 @@ -## 1.3.0 (unreleased) +## 1.4.0 (unreleased) + +## 1.3.0 (December 6, 2017) +FEATURES: + + * **New Resource:** `alicloud_slb_listener` ([#290](https://github.com/alibaba/terraform-provider/pull/290)) + +IMPROVMENTS: + * modify client and support endpoint: ([#290](https://github.com/alibaba/terraform-provider/pull/290)) ## 1.2.11 (November 30, 2017) IMPROVMENTS: diff --git a/alicloud/config.go b/alicloud/config.go index d8be2a592..5f14c34d3 100644 --- a/alicloud/config.go +++ b/alicloud/config.go @@ -145,9 +145,7 @@ func (c *Config) ecsConn() (*ecs.Client, error) { client.SetBusinessInfo(BusinessInfoKey) client.SetUserAgent(getUserAgent()) - _, err := client.DescribeRegions() - - if err != nil { + if _, err := client.DescribeRegions(); err != nil { return nil, err } diff --git a/alicloud/diff_suppress_funcs.go b/alicloud/diff_suppress_funcs.go new file mode 100644 index 000000000..9dd0b6b9e --- /dev/null +++ b/alicloud/diff_suppress_funcs.go @@ -0,0 +1,76 @@ +package alicloud + +import ( + "github.com/denverdino/aliyungo/slb" + "github.com/hashicorp/terraform/helper/schema" +) + +func httpHttpsDiffSuppressFunc(k, old, new string, d *schema.ResourceData) bool { + if protocol, ok := d.GetOk("protocol"); ok && (Protocol(protocol.(string)) == Http || Protocol(protocol.(string)) == Https) { + return false + } + return true +} + +func stickySessionTypeDiffSuppressFunc(k, old, new string, d *schema.ResourceData) bool { + httpDiff := httpHttpsDiffSuppressFunc(k, old, new, d) + if session, ok := d.GetOk("sticky_session"); !httpDiff && ok && slb.FlagType(session.(string)) == slb.OnFlag { + return false + } + return true +} + +func cookieTimeoutDiffSuppressFunc(k, old, new string, d *schema.ResourceData) bool { + stickSessionTypeDiff := stickySessionTypeDiffSuppressFunc(k, old, new, d) + if session_type, ok := d.GetOk("sticky_session_type"); !stickSessionTypeDiff && ok && slb.StickySessionType(session_type.(string)) == slb.InsertStickySessionType { + return false + } + return true +} + +func cookieDiffSuppressFunc(k, old, new string, d *schema.ResourceData) bool { + stickSessionTypeDiff := stickySessionTypeDiffSuppressFunc(k, old, new, d) + if session_type, ok := d.GetOk("sticky_session_type"); !stickSessionTypeDiff && ok && slb.StickySessionType(session_type.(string)) == slb.ServerStickySessionType { + return false + } + return true +} + +func tcpUdpDiffSuppressFunc(k, old, new string, d *schema.ResourceData) bool { + if protocol, ok := d.GetOk("protocol"); ok && (Protocol(protocol.(string)) == Tcp || Protocol(protocol.(string)) == Udp) { + return false + } + return true +} + +func healthCheckDiffSuppressFunc(k, old, new string, d *schema.ResourceData) bool { + httpDiff := httpHttpsDiffSuppressFunc(k, old, new, d) + if health, ok := d.GetOk("health_check"); httpDiff || (ok && slb.FlagType(health.(string)) == slb.OnFlag) { + return false + } + return true +} + +func healthCheckTypeDiffSuppressFunc(k, old, new string, d *schema.ResourceData) bool { + if protocol, ok := d.GetOk("protocol"); ok && Protocol(protocol.(string)) == Tcp { + return false + } + return true +} +func httpHttpsTcpDiffSuppressFunc(k, old, new string, d *schema.ResourceData) bool { + httpDiff := httpHttpsDiffSuppressFunc(k, old, new, d) + health, okHc := d.GetOk("health_check") + protocol, okPro := d.GetOk("protocol") + checkType, okType := d.GetOk("health_check_type") + if (!httpDiff && okHc && slb.FlagType(health.(string)) == slb.OnFlag) || + (okPro && Protocol(protocol.(string)) == Tcp && okType && slb.HealthCheckType(checkType.(string)) == slb.HTTPHealthCheckType) { + return false + } + return true +} +func sslCertificateIdDiffSuppressFunc(k, old, new string, d *schema.ResourceData) bool { + if protocol, ok := d.GetOk("protocol"); ok && Protocol(protocol.(string)) == Https { + return false + } + return true +} diff --git a/alicloud/errors.go b/alicloud/errors.go index e3319b0fc..d9a73859f 100644 --- a/alicloud/errors.go +++ b/alicloud/errors.go @@ -24,7 +24,8 @@ const ( // slb LoadBalancerNotFound = "InvalidLoadBalancerId.NotFound" UnsupportedProtocalPort = "UnsupportedOperationonfixedprotocalport" - + ListenerNotFound = "The specified resource does not exist" + ListenerAlreadyExists = "ListenerAlreadyExists" // security_group InvalidInstanceIdAlreadyExists = "InvalidInstanceId.AlreadyExists" InvalidSecurityGroupIdNotFound = "InvalidSecurityGroupId.NotFound" diff --git a/alicloud/provider.go b/alicloud/provider.go index f047edac4..b43a20f19 100644 --- a/alicloud/provider.go +++ b/alicloud/provider.go @@ -71,6 +71,7 @@ func Provider() terraform.ResourceProvider { "alicloud_eip": resourceAliyunEip(), "alicloud_eip_association": resourceAliyunEipAssociation(), "alicloud_slb": resourceAliyunSlb(), + "alicloud_slb_listener": resourceAliyunSlbListener(), "alicloud_slb_attachment": resourceAliyunSlbAttachment(), "alicloud_oss_bucket": resourceAlicloudOssBucket(), "alicloud_oss_bucket_object": resourceAlicloudOssBucketObject(), diff --git a/alicloud/resource_alicloud_slb.go b/alicloud/resource_alicloud_slb.go index 91cc75486..efab7e467 100644 --- a/alicloud/resource_alicloud_slb.go +++ b/alicloud/resource_alicloud_slb.go @@ -1,18 +1,12 @@ package alicloud import ( - "bytes" "fmt" - "strings" - "errors" "github.com/denverdino/aliyungo/common" "github.com/denverdino/aliyungo/slb" - "github.com/hashicorp/terraform/helper/hashcode" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" - "log" - "reflect" "time" ) @@ -62,161 +56,136 @@ func resourceAliyunSlb() *schema.Resource { }, "listener": &schema.Schema{ - Type: schema.TypeSet, - Optional: true, + Type: schema.TypeSet, + Optional: true, + Computed: true, + Deprecated: "Field 'listener' has been deprecated, and using new resource 'alicloud_slb_listener' to replace.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "instance_port": &schema.Schema{ - Type: schema.TypeInt, - ValidateFunc: validateInstancePort, - Required: true, + Type: schema.TypeInt, + Optional: true, + Computed: true, }, "lb_port": &schema.Schema{ - Type: schema.TypeInt, - ValidateFunc: validateInstancePort, - Required: true, + Type: schema.TypeInt, + Optional: true, Computed: true, }, "lb_protocol": &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: validateInstanceProtocol, - Required: true, + Type: schema.TypeString, + Optional: true, + Computed: true, }, "bandwidth": &schema.Schema{ - Type: schema.TypeInt, - ValidateFunc: validateSlbListenerBandwidth, - Required: true, + Type: schema.TypeInt, + Optional: true, + Computed: true, }, "scheduler": &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: validateSlbListenerScheduler, - Optional: true, - Default: slb.WRRScheduler, + Type: schema.TypeString, + Optional: true, + Computed: true, }, //http & https "sticky_session": &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: validateAllowedStringValue([]string{ - string(slb.OnFlag), - string(slb.OffFlag)}), + Type: schema.TypeString, Optional: true, - Default: slb.OffFlag, + Computed: true, }, //http & https "sticky_session_type": &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: validateAllowedStringValue([]string{ - string(slb.InsertStickySessionType), - string(slb.ServerStickySessionType)}), + Type: schema.TypeString, Optional: true, + Computed: true, }, //http & https "cookie_timeout": &schema.Schema{ - Type: schema.TypeInt, - ValidateFunc: validateSlbListenerCookieTimeout, - Optional: true, - Default: 3600, + Type: schema.TypeInt, + Optional: true, + Computed: true, }, //http & https "cookie": &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: validateSlbListenerCookie, - Optional: true, + Type: schema.TypeString, + Optional: true, + Computed: true, }, //tcp & udp "persistence_timeout": &schema.Schema{ - Type: schema.TypeInt, - ValidateFunc: validateSlbListenerPersistenceTimeout, - Optional: true, - Default: 0, + Type: schema.TypeInt, + Optional: true, + Computed: true, }, //http & https "health_check": &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: validateAllowedStringValue([]string{ - string(slb.OnFlag), - string(slb.OffFlag)}), + Type: schema.TypeString, Optional: true, - Default: slb.OffFlag, + Computed: true, }, //tcp "health_check_type": &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: validateAllowedStringValue([]string{ - string(slb.TCPHealthCheckType), - string(slb.HTTPHealthCheckType)}), + Type: schema.TypeString, Optional: true, - Default: slb.TCPHealthCheckType, + Computed: true, }, //http & https & tcp "health_check_domain": &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: validateSlbListenerHealthCheckDomain, - Optional: true, + Type: schema.TypeString, + Optional: true, + Computed: true, }, //http & https & tcp "health_check_uri": &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: validateSlbListenerHealthCheckUri, - Optional: true, + Type: schema.TypeString, + Optional: true, + Computed: true, }, "health_check_connect_port": &schema.Schema{ - Type: schema.TypeInt, - ValidateFunc: validateSlbListenerHealthCheckConnectPort, - Optional: true, - Computed: true, + Type: schema.TypeInt, + Optional: true, + Computed: true, }, "healthy_threshold": &schema.Schema{ - Type: schema.TypeInt, - ValidateFunc: validateIntegerInRange(1, 10), - Optional: true, - Default: 3, + Type: schema.TypeInt, + Optional: true, + Computed: true, }, "unhealthy_threshold": &schema.Schema{ - Type: schema.TypeInt, - ValidateFunc: validateIntegerInRange(1, 10), - Optional: true, - Default: 3, + Type: schema.TypeInt, + Optional: true, + Computed: true, }, "health_check_timeout": &schema.Schema{ - Type: schema.TypeInt, - ValidateFunc: validateIntegerInRange(1, 300), - Optional: true, - Default: 5, + Type: schema.TypeInt, + Optional: true, + Computed: true, }, "health_check_interval": &schema.Schema{ - Type: schema.TypeInt, - ValidateFunc: validateIntegerInRange(1, 50), - Optional: true, - Default: 2, + Type: schema.TypeInt, + Optional: true, + Computed: true, }, //http & https & tcp "health_check_http_code": &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: validateAllowedSplitStringValue([]string{ - string(slb.HTTP_2XX), - string(slb.HTTP_3XX), - string(slb.HTTP_4XX), - string(slb.HTTP_5XX)}, ","), + Type: schema.TypeString, Optional: true, - Default: slb.HTTP_2XX, + Computed: true, }, //https "ssl_certificate_id": &schema.Schema{ Type: schema.TypeString, Optional: true, + Computed: true, }, - //https - //"ca_certificate_id": &schema.Schema{ - // Type: schema.TypeString, - // Optional: true, - //}, }, }, - Set: resourceAliyunSlbListenerHash, + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + return true + }, }, //deprecated @@ -307,13 +276,6 @@ func resourceAliyunSlbRead(d *schema.ResourceData, meta interface{}) error { d.Set("vswitch_id", loadBalancer.VSwitchId) d.Set("address", loadBalancer.Address) - // Read Load Balancer - if listeners, err := readListerners(slbconn, loadBalancer); err != nil { - return fmt.Errorf("Error reading listeners: %#v", err) - } else { - d.Set("listener", listeners) - } - return nil } @@ -348,35 +310,6 @@ func resourceAliyunSlbUpdate(d *schema.ResourceData, meta interface{}) error { } } - if d.HasChange("listener") { - o, n := d.GetChange("listener") - os := o.(*schema.Set) - ns := n.(*schema.Set) - - remove, _ := expandListeners(os.Difference(ns).List()) - add, _ := expandListeners(ns.Difference(os).List()) - - if len(remove) > 0 { - for _, listener := range remove { - err := slbconn.DeleteLoadBalancerListener(d.Id(), listener.LoadBalancerPort) - if err != nil { - return fmt.Errorf("Failure removing outdated SLB listeners: %#v", err) - } - } - } - - if len(add) > 0 { - for _, listener := range add { - err := createListener(slbconn, d.Id(), listener) - if err != nil { - return fmt.Errorf("Failure add SLB listeners: %#v", err) - } - } - } - - d.SetPartial("listener") - } - // If we currently have instances, or did have instances, // we want to figure out what to add and remove from the load // balancer @@ -436,392 +369,3 @@ func resourceAliyunSlbDelete(d *schema.ResourceData, meta interface{}) error { return nil }) } - -func resourceAliyunSlbListenerHash(v interface{}) int { - var buf bytes.Buffer - m := v.(map[string]interface{}) - buf.WriteString(fmt.Sprintf("%d-", m["instance_port"].(int))) - buf.WriteString(fmt.Sprintf("%d-", m["lb_port"].(int))) - buf.WriteString(fmt.Sprintf("%s-", - strings.ToLower(m["lb_protocol"].(string)))) - - buf.WriteString(fmt.Sprintf("%d-", m["bandwidth"].(int))) - - http := Protocol(m["lb_protocol"].(string)) == Http - https := Protocol(m["lb_protocol"].(string)) == Https - tcp := Protocol(m["lb_protocol"].(string)) == Tcp - udp := Protocol(m["lb_protocol"].(string)) == Udp - health_check := false - - if v, ok := m["scheduler"]; ok { - buf.WriteString(fmt.Sprintf("%s-", v.(string))) - } - - if http || https { - if v, ok := m["sticky_session"]; ok { - buf.WriteString(fmt.Sprintf("%s-", v.(string))) - if slb.FlagType(v.(string)) == slb.OnFlag { - if v, ok := m["sticky_session_type"]; ok { - buf.WriteString(fmt.Sprintf("%s-", v.(string))) - if slb.StickySessionType(v.(string)) == slb.InsertStickySessionType { - if v, ok := m["cookie_timeout"]; ok { - buf.WriteString(fmt.Sprintf("%d-", v.(int))) - } - } else { - if v, ok := m["cookie"]; ok { - buf.WriteString(fmt.Sprintf("%s-", v.(string))) - } - } - } - } - } - - if v, ok := m["health_check"]; ok { - buf.WriteString(fmt.Sprintf("%s-", v.(string))) - if slb.FlagType(v.(string)) == slb.OnFlag { - health_check = true - } - } - } - - if health_check || tcp { - if v, ok := m["health_check_domain"]; ok { - buf.WriteString(fmt.Sprintf("%s-", v.(string))) - } - if v, ok := m["health_check_uri"]; ok { - buf.WriteString(fmt.Sprintf("%s-", v.(string))) - } - if v, ok := m["health_check_http_code"]; ok { - buf.WriteString(fmt.Sprintf("%s-", v.(string))) - } - } - - if tcp || udp { - if v, ok := m["persistence_timeout"]; ok { - buf.WriteString(fmt.Sprintf("%d-", v.(int))) - } - } - - if tcp { - if v, ok := m["health_check_type"]; ok { - buf.WriteString(fmt.Sprintf("%s-", v.(string))) - } - } - - if https { - if v, ok := m["ssl_certificate_id"]; ok { - buf.WriteString(fmt.Sprintf("%s-", v.(string))) - } - } - - if health_check || tcp || udp { - if v, ok := m["healthy_threshold"]; ok { - buf.WriteString(fmt.Sprintf("%d-", v.(int))) - } - - if v, ok := m["unhealthy_threshold"]; ok { - buf.WriteString(fmt.Sprintf("%d-", v.(int))) - } - - if v, ok := m["health_check_timeout"]; ok { - buf.WriteString(fmt.Sprintf("%d-", v.(int))) - } - - if v, ok := m["health_check_interval"]; ok { - buf.WriteString(fmt.Sprintf("%d-", v.(int))) - } - if v, ok := m["health_check_connect_port"]; ok { - buf.WriteString(fmt.Sprintf("%d-", v.(int))) - } - } - - return hashcode.String(buf.String()) -} - -func createListener(conn *slb.Client, loadBalancerId string, listener *Listener) error { - - errTypeJudge := func(err error) error { - if err != nil { - if listenerType, ok := err.(*ListenerErr); ok { - if listenerType.ErrType == HealthCheckErrType { - return fmt.Errorf("'health_check_uri': required field is not set when the HealthCheck is %s.", slb.OnFlag) - } else if listenerType.ErrType == StickySessionErrType { - return fmt.Errorf("'sticky_session_type': required field is not set when the StickySession is %s.", slb.OnFlag) - } else if listenerType.ErrType == CookieTimeOutErrType { - return fmt.Errorf("'cookie_timeout': required field is not set when the StickySession is %s "+ - "and StickySessionType is %s.", slb.OnFlag, slb.InsertStickySessionType) - } else if listenerType.ErrType == CookieErrType { - return fmt.Errorf("'cookie': required field is not set when the StickySession is %s "+ - "and StickySessionType is %s.", slb.OnFlag, slb.ServerStickySessionType) - } - return fmt.Errorf("slb listener check errtype not found.") - } - } - return nil - } - - if listener.Protocol == strings.ToLower("tcp") { - - args := getTcpListenerArgs(loadBalancerId, listener) - - if err := conn.CreateLoadBalancerTCPListener(&args); err != nil { - return err - } - } else if listener.Protocol == strings.ToLower("http") { - args, argsErr := getHttpListenerArgs(loadBalancerId, listener) - if paramErr := errTypeJudge(argsErr); paramErr != nil { - return paramErr - } - - if err := conn.CreateLoadBalancerHTTPListener(&args); err != nil { - return err - } - } else if listener.Protocol == strings.ToLower("https") { - listenerType, err := getHttpListenerType(loadBalancerId, listener) - if paramErr := errTypeJudge(err); paramErr != nil { - return paramErr - } - - args := &slb.CreateLoadBalancerHTTPSListenerArgs{ - HTTPListenerType: listenerType, - } - if listener.SSLCertificateId == "" { - return fmt.Errorf("Server Certificated Id cann't be null") - } - - args.ServerCertificateId = listener.SSLCertificateId - - if err := conn.CreateLoadBalancerHTTPSListener(args); err != nil { - return err - } - } else if listener.Protocol == strings.ToLower("udp") { - args := getUdpListenerArgs(loadBalancerId, listener) - - if err := conn.CreateLoadBalancerUDPListener(&args); err != nil { - return err - } - } - - if err := conn.WaitForListenerAsyn(loadBalancerId, listener.LoadBalancerPort, slb.ListenerType(strings.ToUpper(listener.Protocol)), slb.Stopped, defaultTimeout); err != nil { - return fmt.Errorf("WaitForListener %s got error: %#v", slb.Stopped, err) - } - - if err := conn.StartLoadBalancerListener(loadBalancerId, listener.LoadBalancerPort); err != nil { - return err - } - - return nil -} - -func getTcpListenerArgs(loadBalancerId string, listener *Listener) slb.CreateLoadBalancerTCPListenerArgs { - args := slb.CreateLoadBalancerTCPListenerArgs{ - LoadBalancerId: loadBalancerId, - ListenerPort: listener.LoadBalancerPort, - BackendServerPort: listener.InstancePort, - Bandwidth: listener.Bandwidth, - Scheduler: listener.Scheduler, - PersistenceTimeout: listener.PersistenceTimeout, - HealthCheckType: listener.HealthCheckType, - HealthCheckDomain: listener.HealthCheckDomain, - HealthCheckURI: listener.HealthCheckURI, - HealthCheckConnectPort: listener.HealthCheckConnectPort, - HealthyThreshold: listener.HealthyThreshold, - UnhealthyThreshold: listener.UnhealthyThreshold, - HealthCheckConnectTimeout: listener.HealthCheckTimeout, - HealthCheckInterval: listener.HealthCheckInterval, - HealthCheckHttpCode: listener.HealthCheckHttpCode, - } - return args -} - -func getUdpListenerArgs(loadBalancerId string, listener *Listener) slb.CreateLoadBalancerUDPListenerArgs { - args := slb.CreateLoadBalancerUDPListenerArgs{ - LoadBalancerId: loadBalancerId, - ListenerPort: listener.LoadBalancerPort, - BackendServerPort: listener.InstancePort, - Bandwidth: listener.Bandwidth, - PersistenceTimeout: listener.PersistenceTimeout, - HealthCheckConnectTimeout: listener.HealthCheckTimeout, - HealthCheckInterval: listener.HealthCheckInterval, - Scheduler: listener.Scheduler, - HealthCheckConnectPort: listener.HealthCheckConnectPort, - HealthyThreshold: listener.HealthyThreshold, - UnhealthyThreshold: listener.UnhealthyThreshold, - } - return args -} - -func getHttpListenerType(loadBalancerId string, listener *Listener) (listenType slb.HTTPListenerType, err error) { - - if listener.HealthCheck == slb.OnFlag { - if listener.HealthCheckURI == "" { - errMsg := errors.New("err: HealthCheck empty.") - return listenType, &ListenerErr{HealthCheckErrType, errMsg} - } - } - - if listener.StickySession == slb.OnFlag { - if listener.StickySessionType == "" { - errMsg := errors.New("err: stickySession empty.") - return listenType, &ListenerErr{StickySessionErrType, errMsg} - } - - if listener.StickySessionType == slb.InsertStickySessionType { - if listener.CookieTimeout == 0 { - errMsg := errors.New("err: cookieTimeout empty.") - return listenType, &ListenerErr{CookieTimeOutErrType, errMsg} - } - } else if listener.StickySessionType == slb.ServerStickySessionType { - if listener.Cookie == "" { - errMsg := errors.New("err: cookie empty.") - return listenType, &ListenerErr{CookieErrType, errMsg} - } - } - } - - httpListenertType := slb.HTTPListenerType{ - LoadBalancerId: loadBalancerId, - ListenerPort: listener.LoadBalancerPort, - BackendServerPort: listener.InstancePort, - Bandwidth: listener.Bandwidth, - Scheduler: listener.Scheduler, - HealthCheck: listener.HealthCheck, - StickySession: listener.StickySession, - StickySessionType: listener.StickySessionType, - CookieTimeout: listener.CookieTimeout, - Cookie: listener.Cookie, - HealthCheckDomain: listener.HealthCheckDomain, - HealthCheckURI: listener.HealthCheckURI, - HealthCheckConnectPort: listener.HealthCheckConnectPort, - HealthyThreshold: listener.HealthyThreshold, - UnhealthyThreshold: listener.UnhealthyThreshold, - HealthCheckTimeout: listener.HealthCheckTimeout, - HealthCheckInterval: listener.HealthCheckInterval, - HealthCheckHttpCode: listener.HealthCheckHttpCode, - } - - return httpListenertType, err -} - -func getHttpListenerArgs(loadBalancerId string, listener *Listener) (listenType slb.CreateLoadBalancerHTTPListenerArgs, err error) { - httpListenerType, err := getHttpListenerType(loadBalancerId, listener) - if err != nil { - return listenType, err - } - - httpArgs := slb.CreateLoadBalancerHTTPListenerArgs(httpListenerType) - return httpArgs, err -} - -func readListerners(conn *slb.Client, loadBalancer *slb.LoadBalancerType) ([]map[string]interface{}, error) { - listeners := make([]map[string]interface{}, 0, len(loadBalancer.ListenerPortsAndProtocol.ListenerPortAndProtocol)) - for _, port := range loadBalancer.ListenerPorts.ListenerPort { - http_ls, err := conn.DescribeLoadBalancerHTTPListenerAttribute(loadBalancer.LoadBalancerId, port) - if err != nil && !IsExceptedError(err, UnsupportedProtocalPort) { - return nil, fmt.Errorf("Error DescribeLoadBalancerHTTPListenerAttribute: %#v", err) - } - if http_ls != nil { - listeners = append(listeners, setListenerAttribute(http_ls, Http)) - } - - https_ls, err := conn.DescribeLoadBalancerHTTPSListenerAttribute(loadBalancer.LoadBalancerId, port) - if err != nil && !IsExceptedError(err, UnsupportedProtocalPort) { - return nil, fmt.Errorf("Error DescribeLoadBalancerHTTPSListenerAttribute: %#v", err) - } - if https_ls != nil { - listeners = append(listeners, setListenerAttribute(https_ls, Https)) - } - - tcp_ls, err := conn.DescribeLoadBalancerTCPListenerAttribute(loadBalancer.LoadBalancerId, port) - if err != nil && !IsExceptedError(err, UnsupportedProtocalPort) { - return nil, fmt.Errorf("Error DescribeLoadBalancerTCPListenerAttribute: %#v", err) - } - if tcp_ls != nil { - listeners = append(listeners, setListenerAttribute(tcp_ls, Tcp)) - } - - udp_ls, err := conn.DescribeLoadBalancerUDPListenerAttribute(loadBalancer.LoadBalancerId, port) - if err != nil && !IsExceptedError(err, UnsupportedProtocalPort) { - return nil, fmt.Errorf("Error DescribeLoadBalancerUDPListenerAttribute: %#v", err) - } - if udp_ls != nil { - listeners = append(listeners, setListenerAttribute(udp_ls, Udp)) - } - } - log.Printf("Listeners set: %#v", listeners) - return listeners, nil -} - -func setListenerAttribute(listen interface{}, protocol Protocol) map[string]interface{} { - listener := make(map[string]interface{}) - v := reflect.ValueOf(listen).Elem() - - if val := v.FieldByName("BackendServerPort"); val.IsValid() { - listener["instance_port"] = val.Interface().(int) - } - if val := v.FieldByName("ListenerPort"); val.IsValid() { - listener["lb_port"] = val.Interface().(int) - } - if val := v.FieldByName("Bandwidth"); val.IsValid() { - listener["bandwidth"] = val.Interface().(int) - } - if val := v.FieldByName("Scheduler"); val.IsValid() { - listener["scheduler"] = string(val.Interface().(slb.SchedulerType)) - } - - listener["lb_protocol"] = string(protocol) - - if val := v.FieldByName("HealthCheck"); val.IsValid() { - listener["health_check"] = string(val.Interface().(slb.FlagType)) - } - if val := v.FieldByName("StickySession"); val.IsValid() { - listener["sticky_session"] = string(val.Interface().(slb.FlagType)) - } - if val := v.FieldByName("StickySessionType"); val.IsValid() { - listener["sticky_session_type"] = string(val.Interface().(slb.StickySessionType)) - } - if val := v.FieldByName("CookieTimeout"); val.IsValid() { - listener["cookie_timeout"] = val.Interface().(int) - } - if val := v.FieldByName("Cookie"); val.IsValid() { - listener["cookie"] = val.Interface().(string) - } - if val := v.FieldByName("PersistenceTimeout"); val.IsValid() { - listener["persistence_timeout"] = val.Interface().(int) - } - if val := v.FieldByName("HealthCheckType"); val.IsValid() { - listener["health_check_type"] = string(val.Interface().(slb.HealthCheckType)) - } - if val := v.FieldByName("HealthCheckDomain"); val.IsValid() { - listener["health_check_domain"] = val.Interface().(string) - } - if val := v.FieldByName("HealthCheckConnectPort"); val.IsValid() { - listener["health_check_connect_port"] = val.Interface().(int) - } - if val := v.FieldByName("HealthCheckURI"); val.IsValid() { - listener["health_check_uri"] = val.Interface().(string) - } - if val := v.FieldByName("HealthyThreshold"); val.IsValid() { - listener["healthy_threshold"] = val.Interface().(int) - } - if val := v.FieldByName("UnhealthyThreshold"); val.IsValid() { - listener["unhealthy_threshold"] = val.Interface().(int) - } - if val := v.FieldByName("HealthCheckTimeout"); val.IsValid() { - listener["health_check_timeout"] = val.Interface().(int) - } - if val := v.FieldByName("HealthCheckConnectTimeout"); val.IsValid() { - listener["health_check_timeout"] = val.Interface().(int) - } - if val := v.FieldByName("HealthCheckInterval"); val.IsValid() { - listener["health_check_interval"] = val.Interface().(int) - } - if val := v.FieldByName("HealthCheckHttpCode"); val.IsValid() { - listener["health_check_http_code"] = string(val.Interface().(slb.HealthCheckHttpCodeType)) - } - if val := v.FieldByName("ServerCertificateId"); val.IsValid() { - listener["ssl_certificate_id"] = val.Interface().(string) - } - - return listener -} diff --git a/alicloud/resource_alicloud_slb_listener.go b/alicloud/resource_alicloud_slb_listener.go new file mode 100644 index 000000000..441c36726 --- /dev/null +++ b/alicloud/resource_alicloud_slb_listener.go @@ -0,0 +1,696 @@ +package alicloud + +import ( + "fmt" + "github.com/denverdino/aliyungo/slb" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/helper/schema" + "reflect" + "strconv" + "strings" + "time" +) + +func resourceAliyunSlbListener() *schema.Resource { + return &schema.Resource{ + Create: resourceAliyunSlbListenerCreate, + Read: resourceAliyunSlbListenerRead, + Update: resourceAliyunSlbListenerUpdate, + Delete: resourceAliyunSlbListenerDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "load_balancer_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "frontend_port": &schema.Schema{ + Type: schema.TypeInt, + ValidateFunc: validateInstancePort, + Required: true, + ForceNew: true, + }, + "lb_port": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Deprecated: "Field 'lb_port' has been deprecated, and using 'frontend_port' to replace.", + }, + + "backend_port": &schema.Schema{ + Type: schema.TypeInt, + ValidateFunc: validateInstancePort, + Required: true, + ForceNew: true, + }, + + "instance_port": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Deprecated: "Field 'instance_port' has been deprecated, and using 'backend_port' to replace.", + }, + + "lb_protocol": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Deprecated: "Field 'lb_protocol' has been deprecated, and using 'protocol' to replace.", + }, + + "protocol": &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validateInstanceProtocol, + Required: true, + ForceNew: true, + }, + + "bandwidth": &schema.Schema{ + Type: schema.TypeInt, + ValidateFunc: validateSlbListenerBandwidth, + Required: true, + }, + "scheduler": &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validateSlbListenerScheduler, + Optional: true, + Default: slb.WRRScheduler, + }, + //http & https + "sticky_session": &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validateAllowedStringValue([]string{ + string(slb.OnFlag), + string(slb.OffFlag)}), + Optional: true, + Default: slb.OffFlag, + DiffSuppressFunc: httpHttpsDiffSuppressFunc, + }, + //http & https + "sticky_session_type": &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validateAllowedStringValue([]string{ + string(slb.InsertStickySessionType), + string(slb.ServerStickySessionType)}), + Optional: true, + DiffSuppressFunc: stickySessionTypeDiffSuppressFunc, + }, + //http & https + "cookie_timeout": &schema.Schema{ + Type: schema.TypeInt, + ValidateFunc: validateSlbListenerCookieTimeout, + Optional: true, + DiffSuppressFunc: cookieTimeoutDiffSuppressFunc, + }, + //http & https + "cookie": &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validateSlbListenerCookie, + Optional: true, + DiffSuppressFunc: cookieDiffSuppressFunc, + }, + //tcp & udp + "persistence_timeout": &schema.Schema{ + Type: schema.TypeInt, + ValidateFunc: validateSlbListenerPersistenceTimeout, + Optional: true, + Default: 0, + DiffSuppressFunc: tcpUdpDiffSuppressFunc, + }, + //http & https + "health_check": &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validateAllowedStringValue([]string{ + string(slb.OnFlag), + string(slb.OffFlag)}), + Optional: true, + Default: slb.OnFlag, + DiffSuppressFunc: httpHttpsDiffSuppressFunc, + }, + //tcp + "health_check_type": &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validateAllowedStringValue([]string{ + string(slb.TCPHealthCheckType), + string(slb.HTTPHealthCheckType)}), + Optional: true, + Default: slb.TCPHealthCheckType, + DiffSuppressFunc: healthCheckTypeDiffSuppressFunc, + }, + //http & https & tcp + "health_check_domain": &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validateSlbListenerHealthCheckDomain, + Optional: true, + DiffSuppressFunc: httpHttpsTcpDiffSuppressFunc, + }, + //http & https & tcp + "health_check_uri": &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validateSlbListenerHealthCheckUri, + Optional: true, + Default: "/", + DiffSuppressFunc: httpHttpsTcpDiffSuppressFunc, + }, + "health_check_connect_port": &schema.Schema{ + Type: schema.TypeInt, + ValidateFunc: validateSlbListenerHealthCheckConnectPort, + Optional: true, + Computed: true, + DiffSuppressFunc: healthCheckDiffSuppressFunc, + }, + "healthy_threshold": &schema.Schema{ + Type: schema.TypeInt, + ValidateFunc: validateIntegerInRange(1, 10), + Optional: true, + Default: 3, + DiffSuppressFunc: healthCheckDiffSuppressFunc, + }, + "unhealthy_threshold": &schema.Schema{ + Type: schema.TypeInt, + ValidateFunc: validateIntegerInRange(1, 10), + Optional: true, + Default: 3, + DiffSuppressFunc: healthCheckDiffSuppressFunc, + }, + + "health_check_timeout": &schema.Schema{ + Type: schema.TypeInt, + ValidateFunc: validateIntegerInRange(1, 300), + Optional: true, + Default: 5, + DiffSuppressFunc: healthCheckDiffSuppressFunc, + }, + "health_check_interval": &schema.Schema{ + Type: schema.TypeInt, + ValidateFunc: validateIntegerInRange(1, 50), + Optional: true, + Default: 2, + DiffSuppressFunc: healthCheckDiffSuppressFunc, + }, + //http & https & tcp + "health_check_http_code": &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validateAllowedSplitStringValue([]string{ + string(slb.HTTP_2XX), + string(slb.HTTP_3XX), + string(slb.HTTP_4XX), + string(slb.HTTP_5XX)}, ","), + Optional: true, + Default: slb.HTTP_2XX, + DiffSuppressFunc: httpHttpsTcpDiffSuppressFunc, + }, + //https + "ssl_certificate_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + DiffSuppressFunc: sslCertificateIdDiffSuppressFunc, + }, + }, + } +} + +func resourceAliyunSlbListenerCreate(d *schema.ResourceData, meta interface{}) error { + + slbconn := meta.(*AliyunClient).slbconn + + protocol := d.Get("protocol").(string) + lb_id := d.Get("load_balancer_id").(string) + frontend := d.Get("frontend_port").(int) + var err error + + switch Protocol(protocol) { + case Https: + ssl_id, ok := d.GetOk("ssl_certificate_id") + if !ok || ssl_id == "" { + return fmt.Errorf("'ssl_certificate_id': required field is not set when the protocol is 'https'.") + } + httpType, buildErr := buildHttpListenerType(d) + if buildErr != nil { + return buildErr + } + args := slb.CreateLoadBalancerHTTPSListenerArgs(slb.HTTPSListenerType{ + HTTPListenerType: httpType, + ServerCertificateId: ssl_id.(string), + }) + err = slbconn.CreateLoadBalancerHTTPSListener(&args) + case Tcp: + args := buildTcpListenerArgs(d) + err = slbconn.CreateLoadBalancerTCPListener(&args) + case Udp: + args := buildUdpListenerArgs(d) + err = slbconn.CreateLoadBalancerUDPListener(&args) + default: + httpType, buildErr := buildHttpListenerType(d) + if buildErr != nil { + return buildErr + } + args := slb.CreateLoadBalancerHTTPListenerArgs(httpType) + err = slbconn.CreateLoadBalancerHTTPListener(&args) + } + + if err != nil { + if IsExceptedError(err, ListenerAlreadyExists) { + return fmt.Errorf("The listener with the frontend port %d already exists. Please define a new 'alicloud_slb_listener' resource and "+ + "use ID '%s:%d' to import it or modify its frontend port and then try again.", frontend, lb_id, frontend) + } + return fmt.Errorf("Create %s Listener got an error: %#v", protocol, err) + } + + d.SetId(lb_id + ":" + strconv.Itoa(frontend)) + + if err := slbconn.WaitForListenerAsyn(lb_id, frontend, slb.ListenerType(protocol), slb.Stopped, defaultTimeout); err != nil { + return fmt.Errorf("WaitForListener %s got error: %#v", slb.Stopped, err) + } + + if err := slbconn.StartLoadBalancerListener(lb_id, frontend); err != nil { + return err + } + + if err := slbconn.WaitForListenerAsyn(lb_id, frontend, slb.ListenerType(protocol), slb.Running, defaultTimeout); err != nil { + return fmt.Errorf("WaitForListener %s got error: %#v", slb.Running, err) + } + + return resourceAliyunSlbListenerUpdate(d, meta) +} + +func resourceAliyunSlbListenerRead(d *schema.ResourceData, meta interface{}) error { + slbconn := meta.(*AliyunClient).slbconn + lb_id, protocol, port, err := parseListenerId(d, meta) + if err != nil { + return fmt.Errorf("Get slb listener got an error: %#v", err) + } + + if protocol == "" { + d.SetId("") + return nil + } + d.Set("protocol", protocol) + d.Set("load_balancer_id", lb_id) + + switch Protocol(protocol) { + case Https: + https_ls, err := slbconn.DescribeLoadBalancerHTTPSListenerAttribute(lb_id, port) + return readListenerAttribute(d, protocol, https_ls, err) + case Tcp: + tcp_ls, err := slbconn.DescribeLoadBalancerTCPListenerAttribute(lb_id, port) + return readListenerAttribute(d, protocol, tcp_ls, err) + case Udp: + udp_ls, err := slbconn.DescribeLoadBalancerUDPListenerAttribute(lb_id, port) + return readListenerAttribute(d, protocol, udp_ls, err) + default: + http_ls, err := slbconn.DescribeLoadBalancerHTTPListenerAttribute(lb_id, port) + return readListenerAttribute(d, protocol, http_ls, err) + } +} + +func resourceAliyunSlbListenerUpdate(d *schema.ResourceData, meta interface{}) error { + + slbconn := meta.(*AliyunClient).slbconn + protocol := Protocol(d.Get("protocol").(string)) + + d.Partial(true) + + httpType, err := buildHttpListenerType(d) + if (protocol == Https || protocol == Http) && err != nil { + return err + } + tcpArgs := slb.SetLoadBalancerTCPListenerAttributeArgs(buildTcpListenerArgs(d)) + udpArgs := slb.SetLoadBalancerUDPListenerAttributeArgs(buildUdpListenerArgs(d)) + httpsArgs := slb.SetLoadBalancerHTTPSListenerAttributeArgs(slb.CreateLoadBalancerHTTPSListenerArgs(slb.HTTPSListenerType{})) + + update := false + if d.HasChange("scheduler") { + scheduler := slb.SchedulerType(d.Get("scheduler").(string)) + httpType.Scheduler = scheduler + tcpArgs.Scheduler = scheduler + udpArgs.Scheduler = scheduler + d.SetPartial("scheduler") + update = true + } + // http https + if d.HasChange("sticky_session") { + d.SetPartial("sticky_session") + update = true + } + if d.HasChange("sticky_session_type") { + d.SetPartial("sticky_session_type") + update = true + } + if d.HasChange("cookie_timeout") { + d.SetPartial("cookie_timeout") + update = true + } + if d.HasChange("cookie") { + d.SetPartial("cookie") + update = true + } + + // http https + if d.HasChange("health_check") { + d.SetPartial("health_check") + update = true + } + + // http https tcp + if d.HasChange("health_check_domain") { + if domain, ok := d.GetOk("health_check_domain"); ok { + tcpArgs.HealthCheckDomain = domain.(string) + d.SetPartial("health_check_domain") + update = true + } + } + if d.HasChange("health_check_uri") { + tcpArgs.HealthCheckURI = d.Get("health_check_uri").(string) + d.SetPartial("health_check_uri") + update = true + } + if d.HasChange("health_check_http_code") { + tcpArgs.HealthCheckHttpCode = slb.HealthCheckHttpCodeType(d.Get("health_check_http_code").(string)) + d.SetPartial("health_check_http_code") + update = true + } + + // http https tcp udp and health_check=on + if d.HasChange("unhealthy_threshold") { + tcpArgs.UnhealthyThreshold = d.Get("unhealthy_threshold").(int) + udpArgs.UnhealthyThreshold = d.Get("unhealthy_threshold").(int) + d.SetPartial("unhealthy_threshold") + update = true + //} + } + if d.HasChange("healthy_threshold") { + tcpArgs.HealthyThreshold = d.Get("healthy_threshold").(int) + udpArgs.HealthyThreshold = d.Get("healthy_threshold").(int) + d.SetPartial("healthy_threshold") + update = true + } + if d.HasChange("health_check_timeout") { + tcpArgs.HealthCheckConnectTimeout = d.Get("health_check_timeout").(int) + udpArgs.HealthCheckConnectTimeout = d.Get("health_check_timeout").(int) + d.SetPartial("health_check_timeout") + update = true + } + if d.HasChange("health_check_interval") { + tcpArgs.HealthCheckInterval = d.Get("health_check_interval").(int) + udpArgs.HealthCheckInterval = d.Get("health_check_interval").(int) + d.SetPartial("health_check_interval") + update = true + } + if d.HasChange("health_check_connect_port") { + if port, ok := d.GetOk("health_check_connect_port"); ok { + httpType.HealthCheckConnectPort = port.(int) + tcpArgs.HealthCheckConnectPort = port.(int) + udpArgs.HealthCheckConnectPort = port.(int) + d.SetPartial("health_check_connect_port") + update = true + } + } + + // tcp and udp + if d.HasChange("persistence_timeout") { + tcpArgs.PersistenceTimeout = d.Get("persistence_timeout").(int) + udpArgs.PersistenceTimeout = d.Get("persistence_timeout").(int) + d.SetPartial("persistence_timeout") + update = true + } + + // tcp + if d.HasChange("health_check_type") { + tcpArgs.HealthCheckType = slb.HealthCheckType(d.Get("health_check_type").(string)) + d.SetPartial("health_check_type") + update = true + } + + // https + if protocol == Https { + ssl_id, ok := d.GetOk("ssl_certificate_id") + if !ok && ssl_id == "" { + return fmt.Errorf("'ssl_certificate_id': required field is not set when the protocol is 'https'.") + } + + httpsArgs.ServerCertificateId = ssl_id.(string) + if d.HasChange("ssl_certificate_id") { + d.SetPartial("ssl_certificate_id") + update = true + } + } + + if update { + switch protocol { + case Https: + httpsArgs.HTTPListenerType = httpType + if err := slbconn.SetLoadBalancerHTTPSListenerAttribute(&httpsArgs); err != nil { + return fmt.Errorf("SetHTTPSListenerAttribute got an error: %#v", err) + } + case Tcp: + if err := slbconn.SetLoadBalancerTCPListenerAttribute(&tcpArgs); err != nil { + return fmt.Errorf("SetTCPListenerAttribute got an error: %#v", err) + } + case Udp: + if err := slbconn.SetLoadBalancerUDPListenerAttribute(&udpArgs); err != nil { + return fmt.Errorf("SetTCPListenerAttribute got an error: %#v", err) + } + default: + httpArgs := slb.SetLoadBalancerHTTPListenerAttributeArgs(slb.CreateLoadBalancerHTTPListenerArgs(httpType)) + if err := slbconn.SetLoadBalancerHTTPListenerAttribute(&httpArgs); err != nil { + return fmt.Errorf("SetHTTPListenerAttribute got an error: %#v", err) + } + } + } + + d.Partial(false) + + return resourceAliyunSlbListenerRead(d, meta) +} + +func resourceAliyunSlbListenerDelete(d *schema.ResourceData, meta interface{}) error { + slbconn := meta.(*AliyunClient).slbconn + lb_id, protocol, port, err := parseListenerId(d, meta) + if err != nil { + return fmt.Errorf("Get slb listener got an error: %#v", err) + } + + if protocol == "" { + d.SetId("") + return nil + } + return resource.Retry(5*time.Minute, func() *resource.RetryError { + err := slbconn.DeleteLoadBalancerListener(lb_id, port) + + if err != nil { + return resource.NonRetryableError(err) + } + + switch Protocol(protocol) { + case Https: + https_ls, err := slbconn.DescribeLoadBalancerHTTPSListenerAttribute(lb_id, port) + return ensureListenerAbsent(d, protocol, https_ls, err) + case Tcp: + tcp_ls, err := slbconn.DescribeLoadBalancerTCPListenerAttribute(lb_id, port) + return ensureListenerAbsent(d, protocol, tcp_ls, err) + case Udp: + udp_ls, err := slbconn.DescribeLoadBalancerUDPListenerAttribute(lb_id, port) + return ensureListenerAbsent(d, protocol, udp_ls, err) + default: + http_ls, err := slbconn.DescribeLoadBalancerHTTPListenerAttribute(lb_id, port) + return ensureListenerAbsent(d, protocol, http_ls, err) + } + }) +} + +func buildHttpListenerType(d *schema.ResourceData) (slb.HTTPListenerType, error) { + + httpType := slb.HTTPListenerType{ + LoadBalancerId: d.Get("load_balancer_id").(string), + ListenerPort: d.Get("frontend_port").(int), + BackendServerPort: d.Get("backend_port").(int), + Bandwidth: d.Get("bandwidth").(int), + StickySession: slb.FlagType(d.Get("sticky_session").(string)), + HealthCheck: slb.FlagType(d.Get("health_check").(string)), + } + if httpType.StickySession == slb.OnFlag { + if sessionType, ok := d.GetOk("sticky_session_type"); !ok || sessionType.(string) == "" { + return httpType, fmt.Errorf("'sticky_session_type': required field is not set when the StickySession is %s.", slb.OnFlag) + } else { + httpType.StickySessionType = slb.StickySessionType(sessionType.(string)) + + } + if httpType.StickySessionType == slb.InsertStickySessionType { + if timeout, ok := d.GetOk("cookie_timeout"); !ok || timeout == 0 { + return httpType, fmt.Errorf("'cookie_timeout': required field is not set when the StickySession is %s "+ + "and StickySessionType is %s.", slb.OnFlag, slb.InsertStickySessionType) + } else { + httpType.CookieTimeout = timeout.(int) + } + } else { + if cookie, ok := d.GetOk("cookie"); !ok || cookie.(string) == "" { + return httpType, fmt.Errorf("'cookie': required field is not set when the StickySession is %s "+ + "and StickySessionType is %s.", slb.OnFlag, slb.ServerStickySessionType) + } else { + httpType.Cookie = cookie.(string) + } + } + } + if httpType.HealthCheck == slb.OnFlag { + httpType.HealthCheckURI = d.Get("health_check_uri").(string) + if port, ok := d.GetOk("health_check_connect_port"); !ok || port.(int) == 0 { + return httpType, fmt.Errorf("'health_check_connect_port': required field is not set when the HealthCheck is %s.", slb.OnFlag) + } else { + httpType.HealthCheckConnectPort = port.(int) + } + httpType.HealthyThreshold = d.Get("healthy_threshold").(int) + httpType.UnhealthyThreshold = d.Get("unhealthy_threshold").(int) + httpType.HealthCheckTimeout = d.Get("health_check_timeout").(int) + httpType.HealthCheckInterval = d.Get("health_check_interval").(int) + httpType.HealthCheckHttpCode = slb.HealthCheckHttpCodeType(d.Get("health_check_http_code").(string)) + } + return httpType, nil +} + +func buildTcpListenerArgs(d *schema.ResourceData) slb.CreateLoadBalancerTCPListenerArgs { + + return slb.CreateLoadBalancerTCPListenerArgs(slb.TCPListenerType{ + LoadBalancerId: d.Get("load_balancer_id").(string), + ListenerPort: d.Get("frontend_port").(int), + BackendServerPort: d.Get("backend_port").(int), + Bandwidth: d.Get("bandwidth").(int), + }) +} +func buildUdpListenerArgs(d *schema.ResourceData) slb.CreateLoadBalancerUDPListenerArgs { + + return slb.CreateLoadBalancerUDPListenerArgs(slb.UDPListenerType{ + LoadBalancerId: d.Get("load_balancer_id").(string), + ListenerPort: d.Get("frontend_port").(int), + BackendServerPort: d.Get("backend_port").(int), + Bandwidth: d.Get("bandwidth").(int), + }) +} + +func parseListenerId(d *schema.ResourceData, meta interface{}) (string, string, int, error) { + slbconn := meta.(*AliyunClient).slbconn + parts := strings.Split(d.Id(), ":") + port, err := strconv.Atoi(parts[1]) + if err != nil { + return "", "", 0, fmt.Errorf("Parsing SlbListener's id got an error: %#v", err) + } + loadBalancer, err := slbconn.DescribeLoadBalancerAttribute(parts[0]) + if err != nil { + if IsExceptedError(err, LoadBalancerNotFound) { + return "", "", 0, nil + } + return "", "", 0, fmt.Errorf("DescribeLoadBalancerAttribute got an error: %#v", parts[0]) + } + for _, portAndProtocol := range loadBalancer.ListenerPortsAndProtocol.ListenerPortAndProtocol { + if portAndProtocol.ListenerPort == port { + return loadBalancer.LoadBalancerId, portAndProtocol.ListenerProtocol, port, nil + } + } + return "", "", 0, nil +} + +func readListenerAttribute(d *schema.ResourceData, protocol string, listen interface{}, err error) error { + v := reflect.ValueOf(listen).Elem() + + if err != nil { + if IsExceptedError(err, ListenerNotFound) { + d.SetId("") + return nil + } + return fmt.Errorf("DescribeLoadBalancer%sListenerAttribute got an error: %#v", strings.ToUpper(protocol), err) + } + if port := v.FieldByName("ListenerPort"); port.IsValid() && port.Interface().(int) > 0 { + readListener(d, listen) + } else { + d.SetId("") + } + return nil +} + +func readListener(d *schema.ResourceData, listen interface{}) { + v := reflect.ValueOf(listen).Elem() + + if val := v.FieldByName("BackendServerPort"); val.IsValid() { + d.Set("backend_port", val.Interface().(int)) + } + if val := v.FieldByName("ListenerPort"); val.IsValid() { + d.Set("frontend_port", val.Interface().(int)) + } + if val := v.FieldByName("Bandwidth"); val.IsValid() { + d.Set("bandwidth", val.Interface().(int)) + } + if val := v.FieldByName("Scheduler"); val.IsValid() { + d.Set("scheduler", string(val.Interface().(slb.SchedulerType))) + } + if val := v.FieldByName("HealthCheck"); val.IsValid() { + d.Set("health_check", string(val.Interface().(slb.FlagType))) + } + if val := v.FieldByName("StickySession"); val.IsValid() { + d.Set("sticky_session", string(val.Interface().(slb.FlagType))) + } + if val := v.FieldByName("StickySessionType"); val.IsValid() { + d.Set("sticky_session_type", string(val.Interface().(slb.StickySessionType))) + } + if val := v.FieldByName("CookieTimeout"); val.IsValid() { + d.Set("cookie_timeout", val.Interface().(int)) + } + if val := v.FieldByName("Cookie"); val.IsValid() { + d.Set("cookie", val.Interface().(string)) + } + if val := v.FieldByName("PersistenceTimeout"); val.IsValid() { + d.Set("persistence_timeout", val.Interface().(int)) + } + if val := v.FieldByName("HealthCheckType"); val.IsValid() { + d.Set("health_check_type", string(val.Interface().(slb.HealthCheckType))) + } + if val := v.FieldByName("HealthCheckDomain"); val.IsValid() { + d.Set("health_check_domain", val.Interface().(string)) + } + if val := v.FieldByName("HealthCheckConnectPort"); val.IsValid() { + d.Set("health_check_connect_port", val.Interface().(int)) + } + if val := v.FieldByName("HealthCheckURI"); val.IsValid() { + d.Set("health_check_uri", val.Interface().(string)) + } + if val := v.FieldByName("HealthyThreshold"); val.IsValid() { + d.Set("healthy_threshold", val.Interface().(int)) + } + if val := v.FieldByName("UnhealthyThreshold"); val.IsValid() { + d.Set("unhealthy_threshold", val.Interface().(int)) + } + if val := v.FieldByName("HealthCheckTimeout"); val.IsValid() { + d.Set("health_check_timeout", val.Interface().(int)) + } + if val := v.FieldByName("HealthCheckConnectTimeout"); val.IsValid() { + d.Set("health_check_timeout", val.Interface().(int)) + } + if val := v.FieldByName("HealthCheckInterval"); val.IsValid() { + d.Set("health_check_interval", val.Interface().(int)) + } + if val := v.FieldByName("HealthCheckHttpCode"); val.IsValid() { + d.Set("health_check_http_code", string(val.Interface().(slb.HealthCheckHttpCodeType))) + } + if val := v.FieldByName("ServerCertificateId"); val.IsValid() { + d.Set("ssl_certificate_id", val.Interface().(string)) + } + + return +} + +func ensureListenerAbsent(d *schema.ResourceData, protocol string, listen interface{}, err error) *resource.RetryError { + v := reflect.ValueOf(listen).Elem() + + if err != nil { + if IsExceptedError(err, ListenerNotFound) { + d.SetId("") + return nil + } + return resource.NonRetryableError(fmt.Errorf("While deleting listener, DescribeLoadBalancer%sListenerAttribute got an error: %#v", protocol, err)) + } + if port := v.FieldByName("ListenerPort"); port.IsValid() && port.Interface().(int) > 0 { + return resource.RetryableError(fmt.Errorf("Listener in use - trying again while it deleted.")) + } + d.SetId("") + return nil +} diff --git a/alicloud/resource_alicloud_slb_listener_test.go b/alicloud/resource_alicloud_slb_listener_test.go new file mode 100644 index 000000000..486d58041 --- /dev/null +++ b/alicloud/resource_alicloud_slb_listener_test.go @@ -0,0 +1,226 @@ +package alicloud + +import ( + "fmt" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + "strconv" + "strings" + "testing" +) + +func TestAccAlicloudSlbListener_http(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + }, + + // module name + IDRefreshName: "alicloud_slb_listener.http", + Providers: testAccProviders, + CheckDestroy: testAccCheckSlbListenerDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccSlbListenerHttp, + Check: resource.ComposeTestCheckFunc( + testAccCheckSlbListenerExists("alicloud_slb_listener.http", 80), + resource.TestCheckResourceAttr( + "alicloud_slb_listener.http", "protocol", "http"), + resource.TestCheckResourceAttr( + "alicloud_slb_listener.http", "backend_port", "80"), + resource.TestCheckResourceAttr( + "alicloud_slb_listener.http", "health_check", "on"), + ), + }, + }, + }) +} + +func TestAccAlicloudSlbListener_tcp(t *testing.T) { + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + }, + + // module name + IDRefreshName: "alicloud_slb_listener.tcp", + Providers: testAccProviders, + CheckDestroy: testAccCheckSlbListenerDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccSlbListenerTcp, + Check: resource.ComposeTestCheckFunc( + testAccCheckSlbListenerExists("alicloud_slb_listener.tcp", 22), + resource.TestCheckResourceAttr( + "alicloud_slb_listener.tcp", "protocol", "tcp"), + resource.TestCheckResourceAttr( + "alicloud_slb_listener.tcp", "backend_port", "22"), + resource.TestCheckResourceAttr( + "alicloud_slb_listener.tcp", "healthy_threshold", "8"), + ), + }, + }, + }) +} + +func TestAccAlicloudSlbListener_udp(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + }, + + // module name + IDRefreshName: "alicloud_slb_listener.udp", + Providers: testAccProviders, + CheckDestroy: testAccCheckSlbListenerDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccSlbListenerUdp, + Check: resource.ComposeTestCheckFunc( + testAccCheckSlbListenerExists("alicloud_slb_listener.udp", 2001), + resource.TestCheckResourceAttr( + "alicloud_slb_listener.udp", "protocol", "udp"), + resource.TestCheckResourceAttr( + "alicloud_slb_listener.udp", "persistence_timeout", "3600"), + resource.TestCheckResourceAttr( + "alicloud_slb_listener.udp", "healthy_threshold", "8"), + ), + }, + }, + }) +} + +func testAccCheckSlbListenerExists(n string, port int) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No SLB listener ID is set") + } + + client := testAccProvider.Meta().(*AliyunClient) + parts := strings.Split(rs.Primary.ID, ":") + loadBalancer, err := client.DescribeLoadBalancerAttribute(parts[0]) + if err != nil { + return fmt.Errorf("DescribeLoadBalancerAttribute got an error: %#v", parts[0]) + } + for _, portAndProtocol := range loadBalancer.ListenerPortsAndProtocol.ListenerPortAndProtocol { + if portAndProtocol.ListenerPort == port { + return nil + } + } + + return fmt.Errorf("The Listener %d not found.", port) + } +} + +func testAccCheckSlbListenerDestroy(s *terraform.State) error { + client := testAccProvider.Meta().(*AliyunClient) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "alicloud_slb_listener" { + continue + } + + // Try to find the Slb + parts := strings.Split(rs.Primary.ID, ":") + port, err := strconv.Atoi(parts[1]) + if err != nil { + return fmt.Errorf("Parsing SlbListener's id got an error: %#v", err) + } + loadBalancer, err := client.DescribeLoadBalancerAttribute(parts[0]) + if err != nil { + if IsExceptedError(err, LoadBalancerNotFound) { + return nil + } + return fmt.Errorf("DescribeLoadBalancerAttribute got an error: %#v", err) + } + for _, portAndProtocol := range loadBalancer.ListenerPortsAndProtocol.ListenerPortAndProtocol { + if portAndProtocol.ListenerPort == port { + return fmt.Errorf("SLB listener still exist") + } + } + + } + + return nil +} + +const testAccSlbListenerHttp = ` +resource "alicloud_slb" "instance" { + name = "tf_test_slb_http" + internet_charge_type = "paybytraffic" + internet = true +} +resource "alicloud_slb_listener" "http" { + load_balancer_id = "${alicloud_slb.instance.id}" + backend_port = 80 + frontend_port = 80 + protocol = "http" + sticky_session = "on" + sticky_session_type = "insert" + cookie = "testslblistenercookie" + cookie_timeout = 86400 + health_check = "on" + health_check_uri = "/cons" + health_check_connect_port = 20 + healthy_threshold = 8 + unhealthy_threshold = 8 + health_check_timeout = 8 + health_check_interval = 5 + health_check_http_code = "http_2xx,http_3xx" + bandwidth = 10 +} +` + +const testAccSlbListenerTcp = ` +resource "alicloud_slb" "instance" { + name = "tf_test_slb_tcp" + internet_charge_type = "paybytraffic" + internet = true +} +resource "alicloud_slb_listener" "tcp" { + load_balancer_id = "${alicloud_slb.instance.id}" + backend_port = "22" + frontend_port = "22" + protocol = "tcp" + bandwidth = "10" + health_check_type = "tcp" + persistence_timeout = 3600 + healthy_threshold = 8 + unhealthy_threshold = 8 + health_check_timeout = 8 + health_check_interval = 5 + health_check_http_code = "http_2xx" + health_check_timeout = 8 + health_check_connect_port = 20 + health_check_uri = "/console" +} +` + +const testAccSlbListenerUdp = ` +resource "alicloud_slb" "instance" { + name = "tf_test_slb_udp" + internet_charge_type = "paybybandwidth" + internet = true + bandwidth = 20 +} +resource "alicloud_slb_listener" "udp" { + load_balancer_id = "${alicloud_slb.instance.id}" + backend_port = 2001 + frontend_port = 2001 + protocol = "udp" + bandwidth = 10 + persistence_timeout = 3600 + healthy_threshold = 8 + unhealthy_threshold = 8 + health_check_timeout = 8 + health_check_interval = 4 + health_check_timeout = 8 + health_check_connect_port = 20 +} +` diff --git a/terraform/examples/alicloud-ecs-new-vpc/main.tf b/terraform/examples/alicloud-ecs-new-vpc/main.tf index 06856246b..b9877d6a9 100644 --- a/terraform/examples/alicloud-ecs-new-vpc/main.tf +++ b/terraform/examples/alicloud-ecs-new-vpc/main.tf @@ -126,81 +126,4 @@ resource "alicloud_key_pair_attchment" "default" { key_name = "${var.key_name}" instance_ids = ["${alicloud_instance.instances.*.id}"] -} - - - - - -// VPC Resource for Module -resource "alicloud_vpc" "vpc2" { - count = "${var.vpc_id == "" ? 1 : 0}" - - name = "${var.vpc_name}" - cidr_block = "${var.vpc_cidr}" -} - -// VSwitch Resource for Module -resource "alicloud_vswitch" "vswitch2" { - count = "${var.vswitch_id == "" ? 1 : 0}" - - availability_zone = "${var.availability_zone == "" ? data.alicloud_zones.default.zones.0.id : var.availability_zone}" - name = "${var.vswitch_name}" - cidr_block = "${var.vswitch_cidr}" - vpc_id = "${var.vpc_id == "" ? alicloud_vpc.vpc2.id : var.vpc_id}" -} - -// Security Group Resource for Module -resource "alicloud_security_group" "group2" { - count = "${var.sg_id == "" ? 1 : 0}" - - name = "${var.sg_name}" - vpc_id = "${var.vpc_id == "" ? alicloud_vpc.vpc2.id : var.vpc_id}" -} - -// Security Group Resource for Module -resource "alicloud_security_group_rule" "rules2" { - count = "${length(var.ip_protocols)}" - - type = "${count.index >= length(var.rule_directions) ? "ingress" : var.rule_directions[count.index]}" - ip_protocol = "${var.ip_protocols[count.index]}" - nic_type = "intranet" - policy = "${count.index >= length(var.policies) ? "accept" : var.policies[count.index]}" - port_range = "${count.index >= length(var.ip_protocols) ? "-1/-1" : var.port_ranges[count.index]}" - priority = "${count.index >= length(var.priorities) ? 1 : var.priorities[count.index]}" - security_group_id = "${var.sg_id == "" ? alicloud_security_group.group2.id : var.sg_id}" - cidr_ip = "${length(var.cidr_ips) <= 0 || count.index >= length(var.cidr_ips) ? "0.0.0.0/0" : element(concat(var.cidr_ips, list("0.0.0.0/0")), count.index)}" -} - -// ECS Instance Resource for Module -resource "alicloud_instance" "instances2" { - count = "${var.number_of_instances}" - - image_id = "${var.image_id == "" ? data.alicloud_images.default.images.0.id : var.image_id }" - availability_zone = "${var.availability_zone == "" ? data.alicloud_zones.default.zones.0.id : var.availability_zone}" - instance_type = "${var.instance_type == "" ? data.alicloud_instance_types.default.instance_types.0.id : var.instance_type}" - security_groups = ["${var.sg_id == "" ? alicloud_security_group.group2.id : var.sg_id}"] - - instance_name = "${var.number_of_instances < 2 ? var.instance_name : format("%s-%s", var.instance_name, format(var.number_format, count.index+1))}" - host_name = "${var.number_of_instances < 2 ? var.host_name : format("%s-%s", var.host_name, format(var.number_format, count.index+1))}" - - internet_charge_type = "${var.internet_charge_type}" - internet_max_bandwidth_out = "${var.internet_max_bandwidth_out}" - - allocate_public_ip = "${var.allocate_public_ip}" - - instance_charge_type = "${var.instance_charge_type}" - system_disk_category = "${var.system_category}" - system_disk_size = "${var.system_size}" - - password = "${var.password}" - - vswitch_id = "${var.vswitch_id == "" ? alicloud_vswitch.vswitch2.id : var.vswitch_id}" - - period = "${var.period}" - - tags { - created_by = "${lookup(var.instance_tags, "created_by")}" - created_from = "${lookup(var.instance_tags, "created_from")}" - } } \ No newline at end of file diff --git a/terraform/examples/alicloud-ecs-new-vpc/variables.tf b/terraform/examples/alicloud-ecs-new-vpc/variables.tf index 92bc60a43..8364079fa 100644 --- a/terraform/examples/alicloud-ecs-new-vpc/variables.tf +++ b/terraform/examples/alicloud-ecs-new-vpc/variables.tf @@ -121,7 +121,7 @@ variable "disk_tags" { variable "number_of_disks" { description = "The number of launching disks one time." - default = 20 + default = 2 } # Ecs instance variables @@ -192,5 +192,5 @@ variable "instance_tags" { variable "number_of_instances" { description = "The number of launching instances one time." - default = 20 + default = 2 } \ No newline at end of file diff --git a/terraform/examples/alicloud-ecs-slb/main.tf b/terraform/examples/alicloud-ecs-slb/main.tf index 6f5b14d0f..7f477f6cf 100644 --- a/terraform/examples/alicloud-ecs-slb/main.tf +++ b/terraform/examples/alicloud-ecs-slb/main.tf @@ -61,16 +61,15 @@ resource "alicloud_slb" "instance" { name = "${var.slb_name}" internet_charge_type = "${var.slb_internet_charge_type}" internet = "${var.internet}" - - listener = [ - { - "instance_port" = "2111" - "lb_port" = "21" - "lb_protocol" = "tcp" - "bandwidth" = "5" - }] } +resource "alicloud_slb_listener" "listener" { + load_balancer_id = "${alicloud_slb.instance.id}" + backend_port = 2111 + frontend_port = 21 + protocol = "tcp" + bandwidth = 5 +} resource "alicloud_slb_attachment" "default" { slb_id = "${alicloud_slb.instance.id}" diff --git a/terraform/examples/alicloud-slb/README.md b/terraform/examples/alicloud-slb/README.md index 086205b2d..4c40fa1f0 100644 --- a/terraform/examples/alicloud-slb/README.md +++ b/terraform/examples/alicloud-slb/README.md @@ -5,9 +5,9 @@ The example create SLB and additional listener, the listener parameter following ### SLB Listener parameter describe listener parameter | support protocol | value range | remark | ------------- | ------------- | ------------- | ------------- | -instance_port | http & https & tcp & udp | 1-65535 | the ecs instance port | -lb_port | http & https & tcp & udp | 1-65535 | the slb linstener port | -lb_protocol | http & https & tcp & udp | http or https or tcp or udp | | +backend_port | http & https & tcp & udp | 1-65535 | the ecs instance port | +frontend_port | http & https & tcp & udp | 1-65535 | the slb linstener port | +protocol | http & https & tcp & udp | http or https or tcp or udp | | bandwidth | http & https & tcp & udp | -1 / 1-1000 | | scheduler | http & https & tcp & udp | wrr or wlc | | sticky_session | http & https | on or off | | @@ -18,7 +18,7 @@ persistence_timeout | tcp & udp | 0-3600 | | health_check | http & https | on or off | | TCP and UDP listener's HealthCheck is always on health_check_type | tcp | tcp or http | if health_check is on, the value must have | health_check_domain | http & https & tcp | | one string which length is 1-80 and only allow letters, digits, '-' and '.' characters. When it is not set or empty, Server Load Balancer uses the private network IP address of each backend server as Domain used for health check | -health_check_uri | http & https & tcp | | example: /aliyun. if health_check is on, the value must have | +health_check_uri | http & https & tcp | | example: /aliyun. if health_check is on, the value must have . Default to "/"| health_check_connect_port | http & https & tcp & udp | 1-65535 | If the parameter is not set, the backend server port (BackendServerPort) will be used. | healthy_threshold | http & https & tcp & udp | 1-10 | default to 3 when the health_check is on | unhealthy_threshold | http & https & tcp & udp | 1-10 | default to 3 when the health_check is on | diff --git a/terraform/examples/alicloud-slb/main.tf b/terraform/examples/alicloud-slb/main.tf index 8e5d95f2b..c17692827 100644 --- a/terraform/examples/alicloud-slb/main.tf +++ b/terraform/examples/alicloud-slb/main.tf @@ -2,52 +2,57 @@ resource "alicloud_slb" "instance" { name = "${var.slb_name}" internet_charge_type = "${var.internet_charge_type}" internet = "${var.internet}" +} - listener = [ - { - "instance_port" = "22" - "lb_port" = "22" - "lb_protocol" = "tcp" - "bandwidth" = "10" - "health_check_type" = "http" - "persistence_timeout" = 3600 - "healthy_threshold" = 8 - "unhealthy_threshold" = 8 - "health_check_timeout" = 8 - "health_check_interval" = 5 - "health_check_http_code" = "http_2xx,http_3xx" - "health_check_timeout" = 8 - }, - - { - "instance_port" = "2001" - "lb_port" = "2001" - "lb_protocol" = "udp" - "bandwidth" = "10" - "persistence_timeout" = 3600 - "healthy_threshold" = 8 - "unhealthy_threshold" = 8 - "health_check_timeout" = 8 - "health_check_interval" = 4 - "health_check_timeout" = 8 - }, +resource "alicloud_slb_listener" "tcp" { + load_balancer_id = "${alicloud_slb.instance.id}" + backend_port = "22" + frontend_port = "22" + protocol = "tcp" + bandwidth = "10" + health_check_type = "tcp" + persistence_timeout = 3600 + healthy_threshold = 8 + unhealthy_threshold = 8 + health_check_timeout = 8 + health_check_interval = 5 + health_check_http_code = "http_2xx" + health_check_timeout = 8 + health_check_connect_port = 20 + health_check_uri = "/console" +} - { - "instance_port" = "80" - "lb_port" = "80" - "lb_protocol" = "http" - "sticky_session" = "on" - "sticky_session_type" = "server" - "cookie" = "testslblistenercookie" - "cookie_timeout" = 86400 - "health_check" = "on" - "health_check_uri" = "/console" - "health_check_connect_port" = 20 - "healthy_threshold" = 8 - "unhealthy_threshold" = 8 - "health_check_timeout" = 8 - "health_check_interval" = 5 - "health_check_http_code" = "http_2xx,http_3xx" - "bandwidth" = 10 - }] +resource "alicloud_slb_listener" "udp" { + load_balancer_id = "${alicloud_slb.instance.id}" + backend_port = 2001 + frontend_port = 2001 + protocol = "udp" + bandwidth = 10 + persistence_timeout = 3600 + healthy_threshold = 8 + unhealthy_threshold = 8 + health_check_timeout = 8 + health_check_interval = 4 + health_check_timeout = 8 + health_check_connect_port = 20 } + +resource "alicloud_slb_listener" "http" { + load_balancer_id = "${alicloud_slb.instance.id}" + backend_port = 80 + frontend_port = 80 + protocol = "http" + sticky_session = "on" + sticky_session_type = "insert" + cookie = "testslblistenercookie" + cookie_timeout = 86400 + health_check = "on" + health_check_uri = "/cons" + health_check_connect_port = 20 + healthy_threshold = 8 + unhealthy_threshold = 8 + health_check_timeout = 8 + health_check_interval = 5 + health_check_http_code = "http_2xx,http_3xx" + bandwidth = 10 +} \ No newline at end of file From 3d4c2ed525105336cc93a364260529138f8f5803 Mon Sep 17 00:00:00 2001 From: He Guimin Date: Thu, 30 Nov 2017 12:52:50 +0800 Subject: [PATCH 08/14] fix creating multiple route entry bug --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bf64bb51b..dddf842d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,12 @@ IMPROVMENTS: * modify ess scaling group maxsize/minsize/default_cooldown type to int pointer: ([#286](https://github.com/alibaba/terraform-provider/pull/286)) +## 1.2.11 (November 30, 2017) +IMPROVMENTS: + * fix creating multiple route entries bug: ([#286](https://github.com/alibaba/terraform-provider/pull/286)) + * add creating multiple vpcs and vswitches test case: ([#286](https://github.com/alibaba/terraform-provider/pull/286)) + * modify ess scaling group maxsize/minsize/default_cooldown type to int pointer: ([#286](https://github.com/alibaba/terraform-provider/pull/286)) + ## 1.2.10 (November 16, 2017) IMPROVMENTS: * fix slb listener max healthy check timeout and interval: ([#276](https://github.com/alibaba/terraform-provider/pull/276)) From 30d78e0a0256a959b8b85378ff61904d27bd9dbf Mon Sep 17 00:00:00 2001 From: He Guimin Date: Thu, 7 Dec 2017 20:47:33 +0800 Subject: [PATCH 09/14] fix slb attachment bug --- CHANGELOG.md | 5 ++ alicloud/errors.go | 10 ++-- alicloud/resource_alicloud_ram_user_test.go | 2 +- alicloud/resource_alicloud_slb_attachment.go | 55 ++++++++++++-------- alicloud/resource_alicloud_slb_listener.go | 1 + terraform/examples/alicloud-ecs-slb/main.tf | 6 ++- terraform/examples/alicloud-slb-vpc/main.tf | 15 +++--- 7 files changed, 60 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dddf842d7..5a8509149 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ ## 1.4.0 (unreleased) +## 1.3.1 (December 7, 2017) + +IMPROVMENTS: + * fix slb attachment failed and heath_check_domain diff ignore: ([#296](https://github.com/alibaba/terraform-provider/pull/296)) + ## 1.3.0 (December 6, 2017) FEATURES: diff --git a/alicloud/errors.go b/alicloud/errors.go index d9a73859f..ddb04b08c 100644 --- a/alicloud/errors.go +++ b/alicloud/errors.go @@ -22,10 +22,12 @@ const ( InstanceIncorrectStatus = "IncorrectInstanceStatus" HaVipIncorrectStatus = "IncorrectHaVipStatus" // slb - LoadBalancerNotFound = "InvalidLoadBalancerId.NotFound" - UnsupportedProtocalPort = "UnsupportedOperationonfixedprotocalport" - ListenerNotFound = "The specified resource does not exist" - ListenerAlreadyExists = "ListenerAlreadyExists" + LoadBalancerNotFound = "InvalidLoadBalancerId.NotFound" + UnsupportedProtocalPort = "UnsupportedOperationonfixedprotocalport" + ListenerNotFound = "The specified resource does not exist" + ListenerAlreadyExists = "ListenerAlreadyExists" + ServiceIsConfiguring = "ServiceIsConfiguring" + BackendServerconfiguring = "BackendServer.configuring" // security_group InvalidInstanceIdAlreadyExists = "InvalidInstanceId.AlreadyExists" InvalidSecurityGroupIdNotFound = "InvalidSecurityGroupId.NotFound" diff --git a/alicloud/resource_alicloud_ram_user_test.go b/alicloud/resource_alicloud_ram_user_test.go index 839ebdd4c..50de98f26 100644 --- a/alicloud/resource_alicloud_ram_user_test.go +++ b/alicloud/resource_alicloud_ram_user_test.go @@ -31,7 +31,7 @@ func TestAccAlicloudRamUser_basic(t *testing.T) { "alicloud_ram_user.user", &v), resource.TestCheckResourceAttr( "alicloud_ram_user.user", - "user_name", + "name", "username"), resource.TestCheckResourceAttr( "alicloud_ram_user.user", diff --git a/alicloud/resource_alicloud_slb_attachment.go b/alicloud/resource_alicloud_slb_attachment.go index 4d5c9b58c..fe9d7b3fa 100644 --- a/alicloud/resource_alicloud_slb_attachment.go +++ b/alicloud/resource_alicloud_slb_attachment.go @@ -2,8 +2,12 @@ package alicloud import ( "fmt" + "github.com/denverdino/aliyungo/slb" + "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" "strings" + "time" + //"bytes" ) func resourceAliyunSlbAttachment() *schema.Resource { @@ -104,22 +108,22 @@ func resourceAliyunSlbAttachmentUpdate(d *schema.ResourceData, meta interface{}) add := expandBackendServers(ns.Difference(os).List()) if len(add) > 0 { - _, err := slbconn.AddBackendServers(d.Id(), add) - if err != nil { + if err := resource.Retry(2*time.Minute, func() *resource.RetryError { + _, err := slbconn.AddBackendServers(d.Id(), add) + if err != nil { + if IsExceptedError(err, ServiceIsConfiguring) { + return resource.RetryableError(fmt.Errorf("Load banalcer is configuring - trying again while it is adding backend servers.")) + } + return resource.NonRetryableError(fmt.Errorf("Add backend servers got an error: %#v", err)) + } + return nil + }); err != nil { return err } } - if len(remove) > 0 { - removeBackendServers := make([]string, 0, len(remove)) - for _, e := range remove { - removeBackendServers = append(removeBackendServers, e.ServerId) - } - _, err := slbconn.RemoveBackendServers(d.Id(), removeBackendServers) - if err != nil { - return err - } + if err := removeBackendServers(d, meta, remove); err != nil { + return err } - } return resourceAliyunSlbAttachmentRead(d, meta) @@ -128,21 +132,30 @@ func resourceAliyunSlbAttachmentUpdate(d *schema.ResourceData, meta interface{}) func resourceAliyunSlbAttachmentDelete(d *schema.ResourceData, meta interface{}) error { - slbconn := meta.(*AliyunClient).slbconn o := d.Get("instances") os := o.(*schema.Set) remove := expandBackendServers(os.List()) - if len(remove) > 0 { - removeBackendServers := make([]string, 0, len(remove)) - for _, e := range remove { + return removeBackendServers(d, meta, remove) +} + +func removeBackendServers(d *schema.ResourceData, meta interface{}, servers []slb.BackendServerType) error { + slbconn := meta.(*AliyunClient).slbconn + if len(servers) > 0 { + removeBackendServers := make([]string, 0, len(servers)) + for _, e := range servers { removeBackendServers = append(removeBackendServers, e.ServerId) } - _, err := slbconn.RemoveBackendServers(d.Id(), removeBackendServers) - if err != nil { - return err - } + return resource.Retry(3*time.Minute, func() *resource.RetryError { + _, err := slbconn.RemoveBackendServers(d.Id(), removeBackendServers) + if err != nil { + if IsExceptedError(err, BackendServerconfiguring) { + return resource.RetryableError(fmt.Errorf("Backend server is in use - trying again while it is detached.")) + } + return resource.NonRetryableError(fmt.Errorf("Remove backend servers got an error: %#v", err)) + } + return nil + }) } - return nil } diff --git a/alicloud/resource_alicloud_slb_listener.go b/alicloud/resource_alicloud_slb_listener.go index 441c36726..e60d01019 100644 --- a/alicloud/resource_alicloud_slb_listener.go +++ b/alicloud/resource_alicloud_slb_listener.go @@ -356,6 +356,7 @@ func resourceAliyunSlbListenerUpdate(d *schema.ResourceData, meta interface{}) e // http https tcp if d.HasChange("health_check_domain") { if domain, ok := d.GetOk("health_check_domain"); ok { + httpType.HealthCheckDomain = domain.(string) tcpArgs.HealthCheckDomain = domain.(string) d.SetPartial("health_check_domain") update = true diff --git a/terraform/examples/alicloud-ecs-slb/main.tf b/terraform/examples/alicloud-ecs-slb/main.tf index 7f477f6cf..3c0717272 100644 --- a/terraform/examples/alicloud-ecs-slb/main.tf +++ b/terraform/examples/alicloud-ecs-slb/main.tf @@ -1,3 +1,7 @@ +data "alicloud_zones" "zone" { + available_instance_type = "${var.ecs_type}" +} + resource "alicloud_security_group" "group" { name = "${var.short_name}" description = "New security group" @@ -47,7 +51,7 @@ resource "alicloud_instance" "instance" { internet_max_bandwidth_out = "${var.internet_max_bandwidth_out}" password = "${var.ecs_password}" allocate_public_ip = "${var.allocate_public_ip}" - availability_zone = "" + availability_zone = "${data.alicloud_zones.zone.zones.0.id}" instance_charge_type = "PostPaid" system_disk_category = "cloud_efficiency" diff --git a/terraform/examples/alicloud-slb-vpc/main.tf b/terraform/examples/alicloud-slb-vpc/main.tf index 49a44abe1..7531e1ce0 100644 --- a/terraform/examples/alicloud-slb-vpc/main.tf +++ b/terraform/examples/alicloud-slb-vpc/main.tf @@ -16,13 +16,14 @@ resource "alicloud_slb" "instance" { name = "${var.name}" vswitch_id = "${alicloud_vswitch.main.id}" internet_charge_type = "${var.internet_charge_type}" - listener = [ - { - "instance_port" = "2111" - "lb_port" = "21" - "lb_protocol" = "tcp" - "bandwidth" = "5" - }] +} + +resource "alicloud_slb_listener" "listener" { + load_balancer_id = "${alicloud_slb.instance.id}" + backend_port = "2111" + frontend_port = "21" + protocol = "tcp" + bandwidth = "5" } resource "alicloud_router_interface" "interface" { From 5130694cb7033cb9823a8714b57c29476d1bd421 Mon Sep 17 00:00:00 2001 From: He Guimin Date: Fri, 8 Dec 2017 10:07:57 +0800 Subject: [PATCH 10/14] match sdk changes --- CHANGELOG.md | 1 + alicloud/extension_ecs.go | 7 ------- alicloud/resource_alicloud_security_group_rule.go | 8 ++++---- alicloud/service_alicloud_ecs.go | 6 +++--- alicloud/service_alicloud_rds.go | 8 ++------ alicloud/validators.go | 4 ++-- 6 files changed, 12 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a8509149..0cff30c7c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ IMPROVMENTS: * fix slb attachment failed and heath_check_domain diff ignore: ([#296](https://github.com/alibaba/terraform-provider/pull/296)) + * match sdk changes: ([#300](https://github.com/alibaba/terraform-provider/pull/300)) ## 1.3.0 (December 6, 2017) FEATURES: diff --git a/alicloud/extension_ecs.go b/alicloud/extension_ecs.go index 245624afe..94c8f9069 100644 --- a/alicloud/extension_ecs.go +++ b/alicloud/extension_ecs.go @@ -2,13 +2,6 @@ package alicloud import "github.com/denverdino/aliyungo/ecs" -type GroupRuleDirection string - -const ( - GroupRuleIngress = GroupRuleDirection("ingress") - GroupRuleEgress = GroupRuleDirection("egress") -) - type GroupRuleIpProtocol string const ( diff --git a/alicloud/resource_alicloud_security_group_rule.go b/alicloud/resource_alicloud_security_group_rule.go index 00ba787e0..2b07625ff 100644 --- a/alicloud/resource_alicloud_security_group_rule.go +++ b/alicloud/resource_alicloud_security_group_rule.go @@ -110,13 +110,13 @@ func resourceAliyunSecurityGroupRuleCreate(d *schema.ResourceData, meta interfac var autherr error switch GroupRuleDirection(direction) { - case GroupRuleIngress: + case ecs.DirectionIngress: args, err := buildAliyunSecurityIngressArgs(d, meta) if err != nil { return err } autherr = conn.AuthorizeSecurityGroup(args) - case GroupRuleEgress: + case ecs.DirectionEgress: args, err := buildAliyunSecurityEgressArgs(d, meta) if err != nil { return err @@ -180,7 +180,7 @@ func resourceAliyunSecurityGroupRuleRead(d *schema.ResourceData, meta interface{ d.Set("priority", rule.Priority) d.Set("security_group_id", sgId) //support source and desc by type - if GroupRuleDirection(direction) == GroupRuleIngress { + if GroupRuleDirection(direction) == ecs.DirectionIngress { d.Set("cidr_ip", rule.SourceCidrIp) d.Set("source_security_group_id", rule.SourceGroupId) d.Set("source_group_owner_account", rule.SourceGroupOwnerAccount) @@ -196,7 +196,7 @@ func deleteSecurityGroupRule(d *schema.ResourceData, meta interface{}) error { client := meta.(*AliyunClient) ruleType := d.Get("type").(string) - if GroupRuleDirection(ruleType) == GroupRuleIngress { + if GroupRuleDirection(ruleType) == ecs.DirectionIngress { args, err := buildAliyunSecurityIngressArgs(d, meta) if err != nil { return err diff --git a/alicloud/service_alicloud_ecs.go b/alicloud/service_alicloud_ecs.go index 80f474d4d..212db62e5 100644 --- a/alicloud/service_alicloud_ecs.go +++ b/alicloud/service_alicloud_ecs.go @@ -227,7 +227,7 @@ func (client *AliyunClient) DescribeSecurityGroupRule(groupId, direction, ipProt rules, err := client.ecsconn.DescribeSecurityGroupAttribute(&ecs.DescribeSecurityGroupAttributeArgs{ RegionId: client.Region, SecurityGroupId: groupId, - Direction: direction, + Direction: ecs.Direction(direction), NicType: ecs.NicType(nicType), }) @@ -238,10 +238,10 @@ func (client *AliyunClient) DescribeSecurityGroupRule(groupId, direction, ipProt for _, ru := range rules.Permissions.Permission { if strings.ToLower(string(ru.IpProtocol)) == ipProtocol && ru.PortRange == portRange { cidr := ru.SourceCidrIp - if GroupRuleDirection(direction) == GroupRuleIngress && cidr == "" { + if GroupRuleDirection(direction) == ecs.DirectionIngress && cidr == "" { cidr = ru.SourceGroupId } - if GroupRuleDirection(direction) == GroupRuleEgress { + if GroupRuleDirection(direction) == ecs.DirectionEgress { if cidr = ru.DestCidrIp; cidr == "" { cidr = ru.DestGroupId } diff --git a/alicloud/service_alicloud_rds.go b/alicloud/service_alicloud_rds.go index 931f1cb45..b7b7d4120 100644 --- a/alicloud/service_alicloud_rds.go +++ b/alicloud/service_alicloud_rds.go @@ -141,13 +141,9 @@ func (client *AliyunClient) ConfigDBBackup(instanceId, backupTime, backupPeriod } func (client *AliyunClient) ModifyDBSecurityIps(instanceId, ips string) error { - sargs := rds.DBInstanceIPArray{ - SecurityIps: ips, - } - args := rds.ModifySecurityIpsArgs{ - DBInstanceId: instanceId, - DBInstanceIPArray: sargs, + DBInstanceId: instanceId, + SecurityIps: ips, } if _, err := client.rdsconn.ModifySecurityIps(&args); err != nil { diff --git a/alicloud/validators.go b/alicloud/validators.go index 36e4580c7..1d37d6d14 100644 --- a/alicloud/validators.go +++ b/alicloud/validators.go @@ -130,8 +130,8 @@ func validateSecurityGroupDescription(v interface{}, k string) (ws []string, err func validateSecurityRuleType(v interface{}, k string) (ws []string, errors []error) { rt := GroupRuleDirection(v.(string)) - if rt != GroupRuleIngress && rt != GroupRuleEgress { - errors = append(errors, fmt.Errorf("%s must be one of %s %s", k, GroupRuleIngress, GroupRuleEgress)) + if rt != ecs.DirectionIngress && rt != ecs.DirectionEgress{ + errors = append(errors, fmt.Errorf("%s must be one of %s %s", k, ecs.DirectionIngress, ecs.DirectionEgress)) } return From 290e8523f2f4688b84b1f3b057a2b6a265d6fd20 Mon Sep 17 00:00:00 2001 From: He Guimin Date: Fri, 8 Dec 2017 11:00:15 +0800 Subject: [PATCH 11/14] fix compilation error (#302) * fix compilation error --- alicloud/resource_alicloud_security_group_rule.go | 6 +++--- alicloud/service_alicloud_ecs.go | 4 ++-- alicloud/validators.go | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/alicloud/resource_alicloud_security_group_rule.go b/alicloud/resource_alicloud_security_group_rule.go index 2b07625ff..a8b2f32af 100644 --- a/alicloud/resource_alicloud_security_group_rule.go +++ b/alicloud/resource_alicloud_security_group_rule.go @@ -109,7 +109,7 @@ func resourceAliyunSecurityGroupRuleCreate(d *schema.ResourceData, meta interfac } var autherr error - switch GroupRuleDirection(direction) { + switch ecs.Direction(direction) { case ecs.DirectionIngress: args, err := buildAliyunSecurityIngressArgs(d, meta) if err != nil { @@ -180,7 +180,7 @@ func resourceAliyunSecurityGroupRuleRead(d *schema.ResourceData, meta interface{ d.Set("priority", rule.Priority) d.Set("security_group_id", sgId) //support source and desc by type - if GroupRuleDirection(direction) == ecs.DirectionIngress { + if ecs.Direction(direction) == ecs.DirectionIngress { d.Set("cidr_ip", rule.SourceCidrIp) d.Set("source_security_group_id", rule.SourceGroupId) d.Set("source_group_owner_account", rule.SourceGroupOwnerAccount) @@ -196,7 +196,7 @@ func deleteSecurityGroupRule(d *schema.ResourceData, meta interface{}) error { client := meta.(*AliyunClient) ruleType := d.Get("type").(string) - if GroupRuleDirection(ruleType) == ecs.DirectionIngress { + if ecs.Direction(ruleType) == ecs.DirectionIngress { args, err := buildAliyunSecurityIngressArgs(d, meta) if err != nil { return err diff --git a/alicloud/service_alicloud_ecs.go b/alicloud/service_alicloud_ecs.go index 212db62e5..850bf3a6b 100644 --- a/alicloud/service_alicloud_ecs.go +++ b/alicloud/service_alicloud_ecs.go @@ -238,10 +238,10 @@ func (client *AliyunClient) DescribeSecurityGroupRule(groupId, direction, ipProt for _, ru := range rules.Permissions.Permission { if strings.ToLower(string(ru.IpProtocol)) == ipProtocol && ru.PortRange == portRange { cidr := ru.SourceCidrIp - if GroupRuleDirection(direction) == ecs.DirectionIngress && cidr == "" { + if ecs.Direction(direction) == ecs.DirectionIngress && cidr == "" { cidr = ru.SourceGroupId } - if GroupRuleDirection(direction) == ecs.DirectionEgress { + if ecs.Direction(direction) == ecs.DirectionEgress { if cidr = ru.DestCidrIp; cidr == "" { cidr = ru.DestGroupId } diff --git a/alicloud/validators.go b/alicloud/validators.go index 1d37d6d14..913459ee8 100644 --- a/alicloud/validators.go +++ b/alicloud/validators.go @@ -129,8 +129,8 @@ func validateSecurityGroupDescription(v interface{}, k string) (ws []string, err } func validateSecurityRuleType(v interface{}, k string) (ws []string, errors []error) { - rt := GroupRuleDirection(v.(string)) - if rt != ecs.DirectionIngress && rt != ecs.DirectionEgress{ + rt := ecs.Direction(v.(string)) + if rt != ecs.DirectionIngress && rt != ecs.DirectionEgress { errors = append(errors, fmt.Errorf("%s must be one of %s %s", k, ecs.DirectionIngress, ecs.DirectionEgress)) } From ab320b7227ec5f913ff938be920380dc6b507df4 Mon Sep 17 00:00:00 2001 From: He Guimin Date: Wed, 13 Dec 2017 20:43:29 +0800 Subject: [PATCH 12/14] fix ess attaching slb bug --- CHANGELOG.md | 4 +- .../resource_alicloud_ess_scalinggroup.go | 5 +- ...resource_alicloud_ess_scalinggroup_test.go | 178 ++++++++++++------ alicloud/resource_alicloud_security_group.go | 11 +- .../resource_alicloud_security_group_rule.go | 6 +- alicloud/resource_alicloud_slb.go | 15 +- 6 files changed, 143 insertions(+), 76 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f0d09fbe..46a89599a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ ## 1.6.0 (unreleased) -## 1.5.0 (December 12, 2017) +## 1.3.2 (December 13, 2017) IMPROVMENTS: * deprecated ram_alias and add ram_account_alias ([#305](https://github.com/alibaba/terraform-provider/pull/305)) @@ -8,6 +8,8 @@ IMPROVMENTS: * deprecated dns_domain_records and add dns_records ([#305](https://github.com/alibaba/terraform-provider/pull/305)) * add slb listener importing test ([#305](https://github.com/alibaba/terraform-provider/pull/305)) * fix dns records bug ([#305](https://github.com/alibaba/terraform-provider/pull/305)) + * fix ESS bind SLB failed bug ([#306](https://github.com/alibaba/terraform-provider/pull/306)) + * fix security group not found bug ([#306](https://github.com/alibaba/terraform-provider/pull/306)) ## 1.3.1 (December 7, 2017) diff --git a/alicloud/resource_alicloud_ess_scalinggroup.go b/alicloud/resource_alicloud_ess_scalinggroup.go index 006f7242c..fc5d71887 100644 --- a/alicloud/resource_alicloud_ess_scalinggroup.go +++ b/alicloud/resource_alicloud_ess_scalinggroup.go @@ -4,7 +4,6 @@ import ( "fmt" "github.com/denverdino/aliyungo/ess" "github.com/hashicorp/terraform/helper/schema" - "strings" ) func resourceAlicloudEssScalingGroup() *schema.Resource { @@ -196,8 +195,8 @@ func buildAlicloudEssScalingGroupArgs(d *schema.ResourceData, meta interface{}) lbs, ok := d.GetOk("loadbalancer_ids") if ok { - lbsStrings := lbs.([]interface{}) - args.LoadBalancerId = strings.Join(expandStringList(lbsStrings), COMMA_SEPARATED) + //lbsStrings := lbs.([]interface{}) + args.LoadBalancerIds = convertListToJsonString(lbs.([]interface{})) } return args, nil diff --git a/alicloud/resource_alicloud_ess_scalinggroup_test.go b/alicloud/resource_alicloud_ess_scalinggroup_test.go index b973c60a7..85fc409f9 100644 --- a/alicloud/resource_alicloud_ess_scalinggroup_test.go +++ b/alicloud/resource_alicloud_ess_scalinggroup_test.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/denverdino/aliyungo/common" "github.com/denverdino/aliyungo/ess" + "github.com/denverdino/aliyungo/slb" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/terraform" "log" @@ -30,27 +31,17 @@ func TestAccAlicloudEssScalingGroup_basic(t *testing.T) { testAccCheckEssScalingGroupExists( "alicloud_ess_scaling_group.foo", &sg), resource.TestCheckResourceAttr( - "alicloud_ess_scaling_group.foo", - "min_size", - "1"), + "alicloud_ess_scaling_group.foo", "min_size", "1"), resource.TestCheckResourceAttr( - "alicloud_ess_scaling_group.foo", - "max_size", - "1"), + "alicloud_ess_scaling_group.foo", "max_size", "1"), resource.TestCheckResourceAttr( - "alicloud_ess_scaling_group.foo", - "scaling_group_name", - "foo"), + "alicloud_ess_scaling_group.foo", "scaling_group_name", "sg-for-test-config"), resource.TestCheckResourceAttr( - "alicloud_ess_scaling_group.foo", - "removal_policies.#", - "2", - ), + "alicloud_ess_scaling_group.foo", "removal_policies.#", "2" ), ), }, }, }) - } func TestAccAlicloudEssScalingGroup_update(t *testing.T) { @@ -73,22 +64,13 @@ func TestAccAlicloudEssScalingGroup_update(t *testing.T) { testAccCheckEssScalingGroupExists( "alicloud_ess_scaling_group.foo", &sg), resource.TestCheckResourceAttr( - "alicloud_ess_scaling_group.foo", - "min_size", - "1"), + "alicloud_ess_scaling_group.foo", "min_size", "1"), resource.TestCheckResourceAttr( - "alicloud_ess_scaling_group.foo", - "max_size", - "1"), + "alicloud_ess_scaling_group.foo", "max_size", "1"), resource.TestCheckResourceAttr( - "alicloud_ess_scaling_group.foo", - "scaling_group_name", - "foo"), + "alicloud_ess_scaling_group.foo", "scaling_group_name", "sg-for-test"), resource.TestCheckResourceAttr( - "alicloud_ess_scaling_group.foo", - "removal_policies.#", - "2", - ), + "alicloud_ess_scaling_group.foo", "removal_policies.#", "2"), ), }, @@ -98,22 +80,13 @@ func TestAccAlicloudEssScalingGroup_update(t *testing.T) { testAccCheckEssScalingGroupExists( "alicloud_ess_scaling_group.foo", &sg), resource.TestCheckResourceAttr( - "alicloud_ess_scaling_group.foo", - "min_size", - "2"), + "alicloud_ess_scaling_group.foo", "min_size", "2"), resource.TestCheckResourceAttr( - "alicloud_ess_scaling_group.foo", - "max_size", - "2"), + "alicloud_ess_scaling_group.foo", "max_size", "2"), resource.TestCheckResourceAttr( - "alicloud_ess_scaling_group.foo", - "scaling_group_name", - "update"), + "alicloud_ess_scaling_group.foo", "scaling_group_name", "update"), resource.TestCheckResourceAttr( - "alicloud_ess_scaling_group.foo", - "removal_policies.#", - "1", - ), + "alicloud_ess_scaling_group.foo", "removal_policies.#", "1"), ), }, }, @@ -121,7 +94,7 @@ func TestAccAlicloudEssScalingGroup_update(t *testing.T) { } -func SkipTestAccAlicloudEssScalingGroup_vpc(t *testing.T) { +func TestAccAlicloudEssScalingGroup_vpc(t *testing.T) { var sg ess.ScalingGroupItemType resource.Test(t, resource.TestCase{ @@ -141,22 +114,48 @@ func SkipTestAccAlicloudEssScalingGroup_vpc(t *testing.T) { testAccCheckEssScalingGroupExists( "alicloud_ess_scaling_group.foo", &sg), resource.TestCheckResourceAttr( - "alicloud_ess_scaling_group.foo", - "min_size", - "1"), + "alicloud_ess_scaling_group.foo", "min_size", "1"), + resource.TestCheckResourceAttr( + "alicloud_ess_scaling_group.foo", "max_size", "1"), + resource.TestCheckResourceAttr( + "alicloud_ess_scaling_group.foo", "scaling_group_name", "sg-for-test-vpc"), resource.TestCheckResourceAttr( - "alicloud_ess_scaling_group.foo", - "max_size", - "1"), + "alicloud_ess_scaling_group.foo", "removal_policies.#", "2"), + ), + }, + }, + }) + +} + +func TestAccAlicloudEssScalingGroup_slb(t *testing.T) { + var sg ess.ScalingGroupItemType + var slb slb.LoadBalancerType + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + }, + + // module name + IDRefreshName: "alicloud_ess_scaling_group.scaling", + + Providers: testAccProviders, + CheckDestroy: testAccCheckEssScalingGroupDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccEssScalingGroup_slb, + Check: resource.ComposeTestCheckFunc( + testAccCheckEssScalingGroupExists( + "alicloud_ess_scaling_group.scaling", &sg), + testAccCheckSlbExists( + "alicloud_slb.instance.0", &slb), + testAccCheckSlbExists( + "alicloud_slb.instance.1", &slb), resource.TestCheckResourceAttr( - "alicloud_ess_scaling_group.foo", - "scaling_group_name", - "foo"), + "alicloud_ess_scaling_group.scaling", "min_size", "1"), resource.TestCheckResourceAttr( - "alicloud_ess_scaling_group.foo", - "removal_policies.#", - "2", - ), + "alicloud_ess_scaling_group.scaling", "max_size", "1"), ), }, }, @@ -224,7 +223,7 @@ const testAccEssScalingGroupConfig = ` resource "alicloud_ess_scaling_group" "foo" { min_size = 1 max_size = 1 - scaling_group_name = "foo" + scaling_group_name = "sg-for-test-config" removal_policies = ["OldestInstance", "NewestInstance"] } ` @@ -233,7 +232,7 @@ const testAccEssScalingGroup = ` resource "alicloud_ess_scaling_group" "foo" { min_size = 1 max_size = 1 - scaling_group_name = "foo" + scaling_group_name = "sg-for-test" removal_policies = ["OldestInstance", "NewestInstance"] } ` @@ -276,7 +275,7 @@ resource "alicloud_security_group" "tf_test_foo" { resource "alicloud_ess_scaling_group" "foo" { min_size = 1 max_size = 1 - scaling_group_name = "foo" + scaling_group_name = "sg-for-test-vpc" default_cooldown = 20 vswitch_id = "${alicloud_vswitch.foo.id}" removal_policies = ["OldestInstance", "NewestInstance"] @@ -285,12 +284,75 @@ resource "alicloud_ess_scaling_group" "foo" { resource "alicloud_ess_scaling_configuration" "foo" { scaling_group_id = "${alicloud_ess_scaling_group.foo.id}" enable = true - + active = true image_id = "${data.alicloud_images.ecs_image.images.0.id}" instance_type = "ecs.n4.large" system_disk_category = "cloud_efficiency" internet_charge_type = "PayByTraffic" internet_max_bandwidth_out = 10 security_group_id = "${alicloud_security_group.tf_test_foo.id}" + force_delete = "true" } ` + +const testAccEssScalingGroup_slb = ` +data "alicloud_images" "ecs_image" { + most_recent = true + name_regex = "^centos_6\\w{1,5}[64].*" +} +// Zones data source for availability_zone +data "alicloud_zones" "default" { + available_resource_creation = "VSwitch" +} + +// If there is not specifying vpc_id, the module will launch a new vpc +resource "alicloud_vpc" "vpc" { + cidr_block = "172.16.0.0/12" +} + +// According to the vswitch cidr blocks to launch several vswitches +resource "alicloud_vswitch" "vswitch" { + vpc_id = "${alicloud_vpc.vpc.id}" + cidr_block = "172.16.0.0/16" + availability_zone = "${data.alicloud_zones.default.zones.0.id}" +} + +resource "alicloud_security_group" "sg" { + vpc_id = "${alicloud_vpc.vpc.id}" +} + +resource "alicloud_ess_scaling_group" "scaling" { + min_size = "1" + max_size = "1" + scaling_group_name = "sg-for-test-slb" + removal_policies = ["OldestInstance", "NewestInstance"] + vswitch_id = "${alicloud_vswitch.vswitch.id}" + loadbalancer_ids = ["${alicloud_slb.instance.0.id}","${alicloud_slb.instance.1.id}"] +} + +resource "alicloud_ess_scaling_configuration" "config" { + scaling_group_id = "${alicloud_ess_scaling_group.scaling.id}" + active = true + enable = true + image_id = "${data.alicloud_images.ecs_image.images.0.id}" + instance_type = "ecs.n4.small" + security_group_id = "${alicloud_security_group.sg.id}" + force_delete = "true" +} + +resource "alicloud_slb" "instance" { + count=2 + name = "slb-for-ess" + internet_charge_type = "paybytraffic" + internet = false +} +resource "alicloud_slb_listener" "tcp" { + count = 2 + load_balancer_id = "${element(alicloud_slb.instance.*.id, count.index)}" + backend_port = "22" + frontend_port = "22" + protocol = "tcp" + bandwidth = "10" + health_check_type = "tcp" +} +` \ No newline at end of file diff --git a/alicloud/resource_alicloud_security_group.go b/alicloud/resource_alicloud_security_group.go index c5c4f046b..424309fe9 100644 --- a/alicloud/resource_alicloud_security_group.go +++ b/alicloud/resource_alicloud_security_group.go @@ -68,9 +68,13 @@ func resourceAliyunSecurityGroupRead(d *schema.ResourceData, meta interface{}) e } //err := resource.Retry(3*time.Minute, func() *resource.RetryError { var sg *ecs.DescribeSecurityGroupAttributeResponse - err := resource.Retry(3*time.Minute, func() *resource.RetryError { + err := resource.Retry(1*time.Minute, func() *resource.RetryError { group, e := conn.DescribeSecurityGroupAttribute(args) - if e != nil && !NotFoundError(e) { + if e != nil { + if IsExceptedError(e, InvalidSecurityGroupIdNotFound) { + sg = nil + return nil + } return resource.NonRetryableError(fmt.Errorf("Error DescribeSecurityGroupAttribute: %#v", e)) } if group != nil { @@ -150,8 +154,7 @@ func resourceAliyunSecurityGroupDelete(d *schema.ResourceData, meta interface{}) }) if err != nil { - e, _ := err.(*common.Error) - if e.ErrorResponse.Code == InvalidSecurityGroupIdNotFound { + if IsExceptedError(err, InvalidSecurityGroupIdNotFound) { return nil } return resource.NonRetryableError(err) diff --git a/alicloud/resource_alicloud_security_group_rule.go b/alicloud/resource_alicloud_security_group_rule.go index a8b2f32af..ee96b54d5 100644 --- a/alicloud/resource_alicloud_security_group_rule.go +++ b/alicloud/resource_alicloud_security_group_rule.go @@ -165,11 +165,11 @@ func resourceAliyunSecurityGroupRuleRead(d *schema.ResourceData, meta interface{ rule, err := client.DescribeSecurityGroupRule(sgId, direction, parts[2], parts[3], parts[4], parts[5], policy, priority) if err != nil { - if NotFoundError(err) { + if IsExceptedError(err, InvalidSecurityGroupIdNotFound) { d.SetId("") return nil } - return fmt.Errorf("Error SecurityGroup rule: %#v", err) + return fmt.Errorf("Error describing security group rule: %#v", err) } d.Set("type", rule.Direction) @@ -245,7 +245,7 @@ func resourceAliyunSecurityGroupRuleDelete(d *schema.ResourceData, meta interfac _, err = client.DescribeSecurityGroupRule(parts[0], parts[1], parts[2], parts[3], parts[4], parts[5], policy, priority) if err != nil { - if NotFoundError(err) { + if IsExceptedError(err, InvalidSecurityGroupIdNotFound) { return nil } return resource.NonRetryableError(err) diff --git a/alicloud/resource_alicloud_slb.go b/alicloud/resource_alicloud_slb.go index efab7e467..5c110d859 100644 --- a/alicloud/resource_alicloud_slb.go +++ b/alicloud/resource_alicloud_slb.go @@ -3,7 +3,6 @@ package alicloud import ( "fmt" - "github.com/denverdino/aliyungo/common" "github.com/denverdino/aliyungo/slb" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" @@ -251,12 +250,12 @@ func resourceAliyunSlbRead(d *schema.ResourceData, meta interface{}) error { slbconn := meta.(*AliyunClient).slbconn loadBalancer, err := slbconn.DescribeLoadBalancerAttribute(d.Id()) if err != nil { - if NotFoundError(err) { + if IsExceptedError(err, LoadBalancerNotFound) { d.SetId("") return nil } - return err + return fmt.Errorf("Error describing load balancer failed: %#v", err) } if loadBalancer == nil { @@ -352,16 +351,18 @@ func resourceAliyunSlbDelete(d *schema.ResourceData, meta interface{}) error { err := conn.DeleteLoadBalancer(d.Id()) if err != nil { - return resource.NonRetryableError(err) + if IsExceptedError(err, LoadBalancerNotFound) { + return nil + } + return resource.NonRetryableError(fmt.Errorf("Error deleting slb failed: %#v", err)) } loadBalancer, err := conn.DescribeLoadBalancerAttribute(d.Id()) if err != nil { - e, _ := err.(*common.Error) - if e.ErrorResponse.Code == LoadBalancerNotFound { + if IsExceptedError(err, LoadBalancerNotFound) { return nil } - return resource.NonRetryableError(err) + return resource.NonRetryableError(fmt.Errorf("Error describing slb failed when deleting SLB: %#v", err)) } if loadBalancer != nil { return resource.RetryableError(fmt.Errorf("LoadBalancer in use - trying again while it deleted.")) From 8dc51fc7ddff1832fd240170f1824c2e1a8d9dbc Mon Sep 17 00:00:00 2001 From: He Guimin Date: Wed, 13 Dec 2017 20:47:27 +0800 Subject: [PATCH 13/14] fix ess attaching slb bug --- CHANGELOG.md | 4 +- .../resource_alicloud_ess_scalinggroup.go | 5 +- ...resource_alicloud_ess_scalinggroup_test.go | 178 ++++++++++++------ alicloud/resource_alicloud_security_group.go | 11 +- .../resource_alicloud_security_group_rule.go | 6 +- alicloud/resource_alicloud_slb.go | 15 +- 6 files changed, 143 insertions(+), 76 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f0d09fbe..fa1b8810c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ ## 1.6.0 (unreleased) -## 1.5.0 (December 12, 2017) +## 1.3.2 (December 13, 2017) IMPROVMENTS: * deprecated ram_alias and add ram_account_alias ([#305](https://github.com/alibaba/terraform-provider/pull/305)) @@ -8,6 +8,8 @@ IMPROVMENTS: * deprecated dns_domain_records and add dns_records ([#305](https://github.com/alibaba/terraform-provider/pull/305)) * add slb listener importing test ([#305](https://github.com/alibaba/terraform-provider/pull/305)) * fix dns records bug ([#305](https://github.com/alibaba/terraform-provider/pull/305)) + * fix ESS bind SLB failed bug ([#308](https://github.com/alibaba/terraform-provider/pull/308)) + * fix security group not found bug ([#308](https://github.com/alibaba/terraform-provider/pull/308)) ## 1.3.1 (December 7, 2017) diff --git a/alicloud/resource_alicloud_ess_scalinggroup.go b/alicloud/resource_alicloud_ess_scalinggroup.go index 006f7242c..fc5d71887 100644 --- a/alicloud/resource_alicloud_ess_scalinggroup.go +++ b/alicloud/resource_alicloud_ess_scalinggroup.go @@ -4,7 +4,6 @@ import ( "fmt" "github.com/denverdino/aliyungo/ess" "github.com/hashicorp/terraform/helper/schema" - "strings" ) func resourceAlicloudEssScalingGroup() *schema.Resource { @@ -196,8 +195,8 @@ func buildAlicloudEssScalingGroupArgs(d *schema.ResourceData, meta interface{}) lbs, ok := d.GetOk("loadbalancer_ids") if ok { - lbsStrings := lbs.([]interface{}) - args.LoadBalancerId = strings.Join(expandStringList(lbsStrings), COMMA_SEPARATED) + //lbsStrings := lbs.([]interface{}) + args.LoadBalancerIds = convertListToJsonString(lbs.([]interface{})) } return args, nil diff --git a/alicloud/resource_alicloud_ess_scalinggroup_test.go b/alicloud/resource_alicloud_ess_scalinggroup_test.go index b973c60a7..85fc409f9 100644 --- a/alicloud/resource_alicloud_ess_scalinggroup_test.go +++ b/alicloud/resource_alicloud_ess_scalinggroup_test.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/denverdino/aliyungo/common" "github.com/denverdino/aliyungo/ess" + "github.com/denverdino/aliyungo/slb" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/terraform" "log" @@ -30,27 +31,17 @@ func TestAccAlicloudEssScalingGroup_basic(t *testing.T) { testAccCheckEssScalingGroupExists( "alicloud_ess_scaling_group.foo", &sg), resource.TestCheckResourceAttr( - "alicloud_ess_scaling_group.foo", - "min_size", - "1"), + "alicloud_ess_scaling_group.foo", "min_size", "1"), resource.TestCheckResourceAttr( - "alicloud_ess_scaling_group.foo", - "max_size", - "1"), + "alicloud_ess_scaling_group.foo", "max_size", "1"), resource.TestCheckResourceAttr( - "alicloud_ess_scaling_group.foo", - "scaling_group_name", - "foo"), + "alicloud_ess_scaling_group.foo", "scaling_group_name", "sg-for-test-config"), resource.TestCheckResourceAttr( - "alicloud_ess_scaling_group.foo", - "removal_policies.#", - "2", - ), + "alicloud_ess_scaling_group.foo", "removal_policies.#", "2" ), ), }, }, }) - } func TestAccAlicloudEssScalingGroup_update(t *testing.T) { @@ -73,22 +64,13 @@ func TestAccAlicloudEssScalingGroup_update(t *testing.T) { testAccCheckEssScalingGroupExists( "alicloud_ess_scaling_group.foo", &sg), resource.TestCheckResourceAttr( - "alicloud_ess_scaling_group.foo", - "min_size", - "1"), + "alicloud_ess_scaling_group.foo", "min_size", "1"), resource.TestCheckResourceAttr( - "alicloud_ess_scaling_group.foo", - "max_size", - "1"), + "alicloud_ess_scaling_group.foo", "max_size", "1"), resource.TestCheckResourceAttr( - "alicloud_ess_scaling_group.foo", - "scaling_group_name", - "foo"), + "alicloud_ess_scaling_group.foo", "scaling_group_name", "sg-for-test"), resource.TestCheckResourceAttr( - "alicloud_ess_scaling_group.foo", - "removal_policies.#", - "2", - ), + "alicloud_ess_scaling_group.foo", "removal_policies.#", "2"), ), }, @@ -98,22 +80,13 @@ func TestAccAlicloudEssScalingGroup_update(t *testing.T) { testAccCheckEssScalingGroupExists( "alicloud_ess_scaling_group.foo", &sg), resource.TestCheckResourceAttr( - "alicloud_ess_scaling_group.foo", - "min_size", - "2"), + "alicloud_ess_scaling_group.foo", "min_size", "2"), resource.TestCheckResourceAttr( - "alicloud_ess_scaling_group.foo", - "max_size", - "2"), + "alicloud_ess_scaling_group.foo", "max_size", "2"), resource.TestCheckResourceAttr( - "alicloud_ess_scaling_group.foo", - "scaling_group_name", - "update"), + "alicloud_ess_scaling_group.foo", "scaling_group_name", "update"), resource.TestCheckResourceAttr( - "alicloud_ess_scaling_group.foo", - "removal_policies.#", - "1", - ), + "alicloud_ess_scaling_group.foo", "removal_policies.#", "1"), ), }, }, @@ -121,7 +94,7 @@ func TestAccAlicloudEssScalingGroup_update(t *testing.T) { } -func SkipTestAccAlicloudEssScalingGroup_vpc(t *testing.T) { +func TestAccAlicloudEssScalingGroup_vpc(t *testing.T) { var sg ess.ScalingGroupItemType resource.Test(t, resource.TestCase{ @@ -141,22 +114,48 @@ func SkipTestAccAlicloudEssScalingGroup_vpc(t *testing.T) { testAccCheckEssScalingGroupExists( "alicloud_ess_scaling_group.foo", &sg), resource.TestCheckResourceAttr( - "alicloud_ess_scaling_group.foo", - "min_size", - "1"), + "alicloud_ess_scaling_group.foo", "min_size", "1"), + resource.TestCheckResourceAttr( + "alicloud_ess_scaling_group.foo", "max_size", "1"), + resource.TestCheckResourceAttr( + "alicloud_ess_scaling_group.foo", "scaling_group_name", "sg-for-test-vpc"), resource.TestCheckResourceAttr( - "alicloud_ess_scaling_group.foo", - "max_size", - "1"), + "alicloud_ess_scaling_group.foo", "removal_policies.#", "2"), + ), + }, + }, + }) + +} + +func TestAccAlicloudEssScalingGroup_slb(t *testing.T) { + var sg ess.ScalingGroupItemType + var slb slb.LoadBalancerType + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + }, + + // module name + IDRefreshName: "alicloud_ess_scaling_group.scaling", + + Providers: testAccProviders, + CheckDestroy: testAccCheckEssScalingGroupDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccEssScalingGroup_slb, + Check: resource.ComposeTestCheckFunc( + testAccCheckEssScalingGroupExists( + "alicloud_ess_scaling_group.scaling", &sg), + testAccCheckSlbExists( + "alicloud_slb.instance.0", &slb), + testAccCheckSlbExists( + "alicloud_slb.instance.1", &slb), resource.TestCheckResourceAttr( - "alicloud_ess_scaling_group.foo", - "scaling_group_name", - "foo"), + "alicloud_ess_scaling_group.scaling", "min_size", "1"), resource.TestCheckResourceAttr( - "alicloud_ess_scaling_group.foo", - "removal_policies.#", - "2", - ), + "alicloud_ess_scaling_group.scaling", "max_size", "1"), ), }, }, @@ -224,7 +223,7 @@ const testAccEssScalingGroupConfig = ` resource "alicloud_ess_scaling_group" "foo" { min_size = 1 max_size = 1 - scaling_group_name = "foo" + scaling_group_name = "sg-for-test-config" removal_policies = ["OldestInstance", "NewestInstance"] } ` @@ -233,7 +232,7 @@ const testAccEssScalingGroup = ` resource "alicloud_ess_scaling_group" "foo" { min_size = 1 max_size = 1 - scaling_group_name = "foo" + scaling_group_name = "sg-for-test" removal_policies = ["OldestInstance", "NewestInstance"] } ` @@ -276,7 +275,7 @@ resource "alicloud_security_group" "tf_test_foo" { resource "alicloud_ess_scaling_group" "foo" { min_size = 1 max_size = 1 - scaling_group_name = "foo" + scaling_group_name = "sg-for-test-vpc" default_cooldown = 20 vswitch_id = "${alicloud_vswitch.foo.id}" removal_policies = ["OldestInstance", "NewestInstance"] @@ -285,12 +284,75 @@ resource "alicloud_ess_scaling_group" "foo" { resource "alicloud_ess_scaling_configuration" "foo" { scaling_group_id = "${alicloud_ess_scaling_group.foo.id}" enable = true - + active = true image_id = "${data.alicloud_images.ecs_image.images.0.id}" instance_type = "ecs.n4.large" system_disk_category = "cloud_efficiency" internet_charge_type = "PayByTraffic" internet_max_bandwidth_out = 10 security_group_id = "${alicloud_security_group.tf_test_foo.id}" + force_delete = "true" } ` + +const testAccEssScalingGroup_slb = ` +data "alicloud_images" "ecs_image" { + most_recent = true + name_regex = "^centos_6\\w{1,5}[64].*" +} +// Zones data source for availability_zone +data "alicloud_zones" "default" { + available_resource_creation = "VSwitch" +} + +// If there is not specifying vpc_id, the module will launch a new vpc +resource "alicloud_vpc" "vpc" { + cidr_block = "172.16.0.0/12" +} + +// According to the vswitch cidr blocks to launch several vswitches +resource "alicloud_vswitch" "vswitch" { + vpc_id = "${alicloud_vpc.vpc.id}" + cidr_block = "172.16.0.0/16" + availability_zone = "${data.alicloud_zones.default.zones.0.id}" +} + +resource "alicloud_security_group" "sg" { + vpc_id = "${alicloud_vpc.vpc.id}" +} + +resource "alicloud_ess_scaling_group" "scaling" { + min_size = "1" + max_size = "1" + scaling_group_name = "sg-for-test-slb" + removal_policies = ["OldestInstance", "NewestInstance"] + vswitch_id = "${alicloud_vswitch.vswitch.id}" + loadbalancer_ids = ["${alicloud_slb.instance.0.id}","${alicloud_slb.instance.1.id}"] +} + +resource "alicloud_ess_scaling_configuration" "config" { + scaling_group_id = "${alicloud_ess_scaling_group.scaling.id}" + active = true + enable = true + image_id = "${data.alicloud_images.ecs_image.images.0.id}" + instance_type = "ecs.n4.small" + security_group_id = "${alicloud_security_group.sg.id}" + force_delete = "true" +} + +resource "alicloud_slb" "instance" { + count=2 + name = "slb-for-ess" + internet_charge_type = "paybytraffic" + internet = false +} +resource "alicloud_slb_listener" "tcp" { + count = 2 + load_balancer_id = "${element(alicloud_slb.instance.*.id, count.index)}" + backend_port = "22" + frontend_port = "22" + protocol = "tcp" + bandwidth = "10" + health_check_type = "tcp" +} +` \ No newline at end of file diff --git a/alicloud/resource_alicloud_security_group.go b/alicloud/resource_alicloud_security_group.go index c5c4f046b..424309fe9 100644 --- a/alicloud/resource_alicloud_security_group.go +++ b/alicloud/resource_alicloud_security_group.go @@ -68,9 +68,13 @@ func resourceAliyunSecurityGroupRead(d *schema.ResourceData, meta interface{}) e } //err := resource.Retry(3*time.Minute, func() *resource.RetryError { var sg *ecs.DescribeSecurityGroupAttributeResponse - err := resource.Retry(3*time.Minute, func() *resource.RetryError { + err := resource.Retry(1*time.Minute, func() *resource.RetryError { group, e := conn.DescribeSecurityGroupAttribute(args) - if e != nil && !NotFoundError(e) { + if e != nil { + if IsExceptedError(e, InvalidSecurityGroupIdNotFound) { + sg = nil + return nil + } return resource.NonRetryableError(fmt.Errorf("Error DescribeSecurityGroupAttribute: %#v", e)) } if group != nil { @@ -150,8 +154,7 @@ func resourceAliyunSecurityGroupDelete(d *schema.ResourceData, meta interface{}) }) if err != nil { - e, _ := err.(*common.Error) - if e.ErrorResponse.Code == InvalidSecurityGroupIdNotFound { + if IsExceptedError(err, InvalidSecurityGroupIdNotFound) { return nil } return resource.NonRetryableError(err) diff --git a/alicloud/resource_alicloud_security_group_rule.go b/alicloud/resource_alicloud_security_group_rule.go index a8b2f32af..ee96b54d5 100644 --- a/alicloud/resource_alicloud_security_group_rule.go +++ b/alicloud/resource_alicloud_security_group_rule.go @@ -165,11 +165,11 @@ func resourceAliyunSecurityGroupRuleRead(d *schema.ResourceData, meta interface{ rule, err := client.DescribeSecurityGroupRule(sgId, direction, parts[2], parts[3], parts[4], parts[5], policy, priority) if err != nil { - if NotFoundError(err) { + if IsExceptedError(err, InvalidSecurityGroupIdNotFound) { d.SetId("") return nil } - return fmt.Errorf("Error SecurityGroup rule: %#v", err) + return fmt.Errorf("Error describing security group rule: %#v", err) } d.Set("type", rule.Direction) @@ -245,7 +245,7 @@ func resourceAliyunSecurityGroupRuleDelete(d *schema.ResourceData, meta interfac _, err = client.DescribeSecurityGroupRule(parts[0], parts[1], parts[2], parts[3], parts[4], parts[5], policy, priority) if err != nil { - if NotFoundError(err) { + if IsExceptedError(err, InvalidSecurityGroupIdNotFound) { return nil } return resource.NonRetryableError(err) diff --git a/alicloud/resource_alicloud_slb.go b/alicloud/resource_alicloud_slb.go index efab7e467..5c110d859 100644 --- a/alicloud/resource_alicloud_slb.go +++ b/alicloud/resource_alicloud_slb.go @@ -3,7 +3,6 @@ package alicloud import ( "fmt" - "github.com/denverdino/aliyungo/common" "github.com/denverdino/aliyungo/slb" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" @@ -251,12 +250,12 @@ func resourceAliyunSlbRead(d *schema.ResourceData, meta interface{}) error { slbconn := meta.(*AliyunClient).slbconn loadBalancer, err := slbconn.DescribeLoadBalancerAttribute(d.Id()) if err != nil { - if NotFoundError(err) { + if IsExceptedError(err, LoadBalancerNotFound) { d.SetId("") return nil } - return err + return fmt.Errorf("Error describing load balancer failed: %#v", err) } if loadBalancer == nil { @@ -352,16 +351,18 @@ func resourceAliyunSlbDelete(d *schema.ResourceData, meta interface{}) error { err := conn.DeleteLoadBalancer(d.Id()) if err != nil { - return resource.NonRetryableError(err) + if IsExceptedError(err, LoadBalancerNotFound) { + return nil + } + return resource.NonRetryableError(fmt.Errorf("Error deleting slb failed: %#v", err)) } loadBalancer, err := conn.DescribeLoadBalancerAttribute(d.Id()) if err != nil { - e, _ := err.(*common.Error) - if e.ErrorResponse.Code == LoadBalancerNotFound { + if IsExceptedError(err, LoadBalancerNotFound) { return nil } - return resource.NonRetryableError(err) + return resource.NonRetryableError(fmt.Errorf("Error describing slb failed when deleting SLB: %#v", err)) } if loadBalancer != nil { return resource.RetryableError(fmt.Errorf("LoadBalancer in use - trying again while it deleted.")) From 0639a0df548714c3191fba7dc51823ad77b1d136 Mon Sep 17 00:00:00 2001 From: He Guimin Date: Thu, 14 Dec 2017 07:13:57 +0800 Subject: [PATCH 14/14] wait for SLB active before return back --- CHANGELOG.md | 7 ++++ README.md | 1 + .../resource_alicloud_security_group_rule.go | 7 ++-- alicloud/resource_alicloud_slb.go | 8 +++-- alicloud/resource_alicloud_slb_test.go | 36 ------------------- 5 files changed, 19 insertions(+), 40 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa1b8810c..effbc883e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ ## 1.6.0 (unreleased) +## 1.3.3 (December 14, 2017) + +IMPROVMENTS: + * wait for SLB active before return back ([#310](https://github.com/alibaba/terraform-provider/pull/310)) + ## 1.3.2 (December 13, 2017) IMPROVMENTS: @@ -7,6 +12,8 @@ IMPROVMENTS: * deprecated dns_domain_groups and add dns_groups ([#305](https://github.com/alibaba/terraform-provider/pull/305)) * deprecated dns_domain_records and add dns_records ([#305](https://github.com/alibaba/terraform-provider/pull/305)) * add slb listener importing test ([#305](https://github.com/alibaba/terraform-provider/pull/305)) + +BUG FIXES: * fix dns records bug ([#305](https://github.com/alibaba/terraform-provider/pull/305)) * fix ESS bind SLB failed bug ([#308](https://github.com/alibaba/terraform-provider/pull/308)) * fix security group not found bug ([#308](https://github.com/alibaba/terraform-provider/pull/308)) diff --git a/README.md b/README.md index 337b2e47d..d17619e44 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,7 @@ terraform get # set the creds export ALICLOUD_ACCESS_KEY="***" export ALICLOUD_SECRET_KEY="***" +export ALICLOUD_REGION="***" # you're good to start rocking # alicloud.tf contains the default example diff --git a/alicloud/resource_alicloud_security_group_rule.go b/alicloud/resource_alicloud_security_group_rule.go index ee96b54d5..01ac60cbd 100644 --- a/alicloud/resource_alicloud_security_group_rule.go +++ b/alicloud/resource_alicloud_security_group_rule.go @@ -165,7 +165,7 @@ func resourceAliyunSecurityGroupRuleRead(d *schema.ResourceData, meta interface{ rule, err := client.DescribeSecurityGroupRule(sgId, direction, parts[2], parts[3], parts[4], parts[5], policy, priority) if err != nil { - if IsExceptedError(err, InvalidSecurityGroupIdNotFound) { + if NotFoundError(err) || IsExceptedError(err, InvalidSecurityGroupIdNotFound) { d.SetId("") return nil } @@ -240,12 +240,15 @@ func resourceAliyunSecurityGroupRuleDelete(d *schema.ResourceData, meta interfac err := deleteSecurityGroupRule(d, meta) if err != nil { + if NotFoundError(err) || IsExceptedError(err, InvalidSecurityGroupIdNotFound) { + return nil + } resource.RetryableError(fmt.Errorf("Security group rule in use - trying again while it is deleted.")) } _, err = client.DescribeSecurityGroupRule(parts[0], parts[1], parts[2], parts[3], parts[4], parts[5], policy, priority) if err != nil { - if IsExceptedError(err, InvalidSecurityGroupIdNotFound) { + if NotFoundError(err) || IsExceptedError(err, InvalidSecurityGroupIdNotFound) { return nil } return resource.NonRetryableError(err) diff --git a/alicloud/resource_alicloud_slb.go b/alicloud/resource_alicloud_slb.go index 5c110d859..7947093ca 100644 --- a/alicloud/resource_alicloud_slb.go +++ b/alicloud/resource_alicloud_slb.go @@ -236,12 +236,16 @@ func resourceAliyunSlbCreate(d *schema.ResourceData, meta interface{}) error { if v, ok := d.GetOk("vswitch_id"); ok { slbArgs.VSwitchId = v.(string) } - slb, err := slbconn.CreateLoadBalancer(slbArgs) + lb, err := slbconn.CreateLoadBalancer(slbArgs) if err != nil { return err } - d.SetId(slb.LoadBalancerId) + d.SetId(lb.LoadBalancerId) + + if err := slbconn.WaitForLoadBalancerAsyn(lb.LoadBalancerId, slb.ActiveStatus, defaultTimeout); err != nil { + return fmt.Errorf("WaitForListener %s got error: %#v", slb.ActiveStatus, err) + } return resourceAliyunSlbUpdate(d, meta) } diff --git a/alicloud/resource_alicloud_slb_test.go b/alicloud/resource_alicloud_slb_test.go index 7298bf7fd..4b24de020 100644 --- a/alicloud/resource_alicloud_slb_test.go +++ b/alicloud/resource_alicloud_slb_test.go @@ -130,42 +130,6 @@ func testAccCheckSlbExists(n string, slb *slb.LoadBalancerType) resource.TestChe } } -func testAccCheckListenersExists(n string, slb *slb.LoadBalancerType, p string) resource.TestCheckFunc { - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - if rs.Primary.ID == "" { - return fmt.Errorf("No SLB ID is set") - } - - client := testAccProvider.Meta().(*AliyunClient) - instance, err := client.DescribeLoadBalancerAttribute(rs.Primary.ID) - - if err != nil { - return err - } - if instance == nil { - return fmt.Errorf("SLB not found") - } - - exist := false - for _, listener := range instance.ListenerPortsAndProtocol.ListenerPortAndProtocol { - if listener.ListenerProtocol == p { - exist = true - break - } - } - - if !exist { - return fmt.Errorf("The %s protocol Listener not found.", p) - } - return nil - } -} - func testAccCheckSlbDestroy(s *terraform.State) error { client := testAccProvider.Meta().(*AliyunClient)