alicloud/resource_alicloud_ess_scaling_group.go (1,032 lines of code) (raw):

package alicloud import ( "encoding/json" "fmt" "math" "strconv" "time" "github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests" "github.com/aliyun/alibaba-cloud-sdk-go/services/ess" "github.com/aliyun/terraform-provider-alicloud/alicloud/connectivity" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" ) func resourceAlicloudEssScalingGroup() *schema.Resource { return &schema.Resource{ Create: resourceAliyunEssScalingGroupCreate, Read: resourceAliyunEssScalingGroupRead, Update: resourceAliyunEssScalingGroupUpdate, Delete: resourceAliyunEssScalingGroupDelete, Importer: &schema.ResourceImporter{ State: schema.ImportStatePassthrough, }, Schema: map[string]*schema.Schema{ "min_size": { Type: schema.TypeInt, Required: true, ValidateFunc: IntBetween(0, 2000), }, "max_size": { Type: schema.TypeInt, Required: true, ValidateFunc: IntBetween(0, 2000), }, "stop_instance_timeout": { Type: schema.TypeInt, Optional: true, ValidateFunc: IntBetween(30, 240), }, "desired_capacity": { Type: schema.TypeInt, Optional: true, ValidateFunc: IntBetween(0, 2000), }, "scaling_group_name": { Type: schema.TypeString, Optional: true, }, "health_check_type": { Type: schema.TypeString, Computed: true, ValidateFunc: StringInSlice([]string{"ECS", "NONE", "LOAD_BALANCER"}, false), Optional: true, ConflictsWith: []string{"health_check_types"}, }, "scaling_policy": { Type: schema.TypeString, Computed: true, ValidateFunc: StringInSlice([]string{"recycle", "release", "forceRecycle", "forceRelease"}, false), Optional: true, }, "max_instance_lifetime": { Type: schema.TypeInt, Optional: true, ValidateFunc: IntAtLeast(86400), }, "default_cooldown": { Type: schema.TypeInt, Default: 300, Optional: true, ValidateFunc: IntBetween(0, 86400), }, "vswitch_id": { Type: schema.TypeString, Optional: true, Deprecated: "Field 'vswitch_id' has been deprecated from provider version 1.7.1, and new field 'vswitch_ids' can replace it.", }, "instance_id": { Type: schema.TypeString, Optional: true, ForceNew: true, }, "container_group_id": { Type: schema.TypeString, Optional: true, ForceNew: true, }, "health_check_types": { Type: schema.TypeList, Optional: true, Elem: &schema.Schema{Type: schema.TypeString}, ConflictsWith: []string{"health_check_type"}, }, "vswitch_ids": { Type: schema.TypeSet, Optional: true, Elem: &schema.Schema{Type: schema.TypeString}, MinItems: 1, }, "removal_policies": { Type: schema.TypeList, Elem: &schema.Schema{Type: schema.TypeString}, Optional: true, Computed: true, MaxItems: 2, MinItems: 1, }, "alb_server_group": { Optional: true, Type: schema.TypeSet, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "alb_server_group_id": { Type: schema.TypeString, Optional: true, }, "weight": { Type: schema.TypeInt, Optional: true, }, "port": { Type: schema.TypeInt, Optional: true, }, }, }, }, "db_instance_ids": { Type: schema.TypeSet, Elem: &schema.Schema{Type: schema.TypeString}, Optional: true, MinItems: 0, }, "loadbalancer_ids": { Type: schema.TypeSet, Elem: &schema.Schema{Type: schema.TypeString}, Optional: true, MinItems: 0, }, "multi_az_policy": { Type: schema.TypeString, Optional: true, Default: "PRIORITY", ValidateFunc: StringInSlice([]string{"PRIORITY", "BALANCE", "COST_OPTIMIZED", "COMPOSABLE"}, false), ForceNew: true, }, "az_balance": { Type: schema.TypeBool, Optional: true, }, "allocation_strategy": { Type: schema.TypeString, Optional: true, ValidateFunc: StringInSlice([]string{"priority", "lowestPrice"}, false), Computed: true, }, "spot_allocation_strategy": { Type: schema.TypeString, Optional: true, ValidateFunc: StringInSlice([]string{"priority", "lowestPrice"}, false), Computed: true, }, "on_demand_base_capacity": { Type: schema.TypeInt, Optional: true, Computed: true, ValidateFunc: IntBetween(0, 1000), }, "on_demand_percentage_above_base_capacity": { Type: schema.TypeInt, Optional: true, Computed: true, ValidateFunc: IntBetween(0, 100), }, "spot_instance_pools": { Type: schema.TypeInt, Optional: true, Computed: true, ValidateFunc: IntBetween(1, 10), }, "spot_instance_remedy": { Type: schema.TypeBool, Optional: true, Computed: true, }, "compensate_with_on_demand": { Type: schema.TypeBool, Optional: true, Computed: true, }, "capacity_options_on_demand_base_capacity": { Type: schema.TypeInt, Optional: true, Computed: true, ValidateFunc: IntBetween(0, 1000), }, "capacity_options_on_demand_percentage_above_base_capacity": { Type: schema.TypeInt, Optional: true, Computed: true, ValidateFunc: IntBetween(0, 100), }, "capacity_options_compensate_with_on_demand": { Type: schema.TypeBool, Optional: true, Computed: true, }, "capacity_options_spot_auto_replace_on_demand": { Type: schema.TypeBool, Optional: true, Computed: true, }, "capacity_options_price_comparison_mode": { Type: schema.TypeString, Optional: true, Computed: true, }, "resource_group_id": { Type: schema.TypeString, Optional: true, Computed: true, }, "group_deletion_protection": { Type: schema.TypeBool, Optional: true, Default: false, }, "launch_template_id": { Type: schema.TypeString, Optional: true, }, "launch_template_version": { Type: schema.TypeString, Optional: true, }, "tags": tagsSchema(), "group_type": { Type: schema.TypeString, Optional: true, Computed: true, ForceNew: true, ValidateFunc: StringInSlice([]string{"ECS", "ECI"}, false), }, "protected_instances": { Type: schema.TypeSet, Elem: &schema.Schema{Type: schema.TypeString}, Optional: true, }, "launch_template_override": { Optional: true, Type: schema.TypeSet, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "instance_type": { Type: schema.TypeString, Optional: true, }, "weighted_capacity": { Type: schema.TypeInt, Optional: true, }, "spot_price_limit": { Type: schema.TypeFloat, Optional: true, }, }, }, }, }, } } func resourceAliyunEssScalingGroupCreate(d *schema.ResourceData, meta interface{}) error { client := meta.(*connectivity.AliyunClient) essService := EssService{client} var response map[string]interface{} request, err := buildAlicloudEssScalingGroupArgs(d, meta) if err != nil { return WrapError(err) } err = resource.Retry(5*time.Minute, func() *resource.RetryError { response, err = client.RpcPost("Ess", "2014-08-28", "CreateScalingGroup", nil, request, true) if err != nil { if NeedRetry(err) || IsExpectedErrors(err, []string{Throttling, "IncorrectLoadBalancerHealthCheck", "IncorrectLoadBalancerStatus"}) { return resource.RetryableError(err) } return resource.NonRetryableError(err) } return nil }) if err != nil { return WrapErrorf(err, DefaultErrorMsg, "alicloud_ess_scaling_group", "CreateScalingGroup", AlibabaCloudSdkGoERROR) } d.SetId(fmt.Sprint(response["ScalingGroupId"])) d.Set("alb_server_group", request["AlbServerGroup"]) if err := essService.WaitForEssScalingGroup(d.Id(), Inactive, DefaultTimeout); err != nil { return WrapError(err) } // enable group if use launchTemplate if request["LaunchTemplateId"] != "" && request["LaunchTemplateId"] != nil { enableGroupRequest := ess.CreateEnableScalingGroupRequest() enableGroupRequest.ScalingGroupId = d.Id() err := resource.Retry(client.GetRetryTimeout(d.Timeout(schema.TimeoutUpdate)), func() *resource.RetryError { raw, err := client.WithEssClient(func(essClient *ess.Client) (interface{}, error) { return essClient.EnableScalingGroup(enableGroupRequest) }) if err != nil { if IsExpectedErrors(err, []string{"IncorrectScalingGroupStatus"}) { return resource.RetryableError(err) } return resource.NonRetryableError(err) } addDebug(enableGroupRequest.GetActionName(), raw, enableGroupRequest.RpcRequest, enableGroupRequest) return nil }) if err != nil { return WrapErrorf(err, DefaultErrorMsg, "alicloud_ess_scaling_group", enableGroupRequest.GetActionName(), AlibabaCloudSdkGoERROR) } } return resourceAliyunEssScalingGroupUpdate(d, meta) } func resourceAliyunEssScalingGroupRead(d *schema.ResourceData, meta interface{}) error { client := meta.(*connectivity.AliyunClient) essService := EssService{client} object, err := essService.DescribeEssScalingGroupById(d.Id()) if err != nil { if NotFoundError(err) { d.SetId("") return nil } return WrapError(err) } d.Set("min_size", object["MinSize"]) d.Set("max_size", object["MaxSize"]) if object["StopInstanceTimeout"] != nil { d.Set("stop_instance_timeout", object["StopInstanceTimeout"]) } d.Set("resource_group_id", object["ResourceGroupId"]) d.Set("desired_capacity", object["DesiredCapacity"]) d.Set("scaling_group_name", object["ScalingGroupName"]) d.Set("default_cooldown", object["DefaultCooldown"]) if object["MaxInstanceLifetime"] != nil { d.Set("max_instance_lifetime", object["MaxInstanceLifetime"]) } d.Set("multi_az_policy", object["MultiAZPolicy"]) d.Set("az_balance", object["AzBalance"]) d.Set("allocation_strategy", object["AllocationStrategy"]) d.Set("spot_allocation_strategy", object["SpotAllocationStrategy"]) d.Set("on_demand_base_capacity", object["OnDemandBaseCapacity"]) d.Set("on_demand_percentage_above_base_capacity", object["OnDemandPercentageAboveBaseCapacity"]) if object["SpotInstancePools"] != nil { d.Set("spot_instance_pools", object["SpotInstancePools"]) } d.Set("spot_instance_remedy", object["SpotInstanceRemedy"]) d.Set("compensate_with_on_demand", object["CompensateWithOnDemand"]) d.Set("group_deletion_protection", object["GroupDeletionProtection"]) var polices []string if len(object["RemovalPolicies"].(map[string]interface{})["RemovalPolicy"].([]interface{})) > 0 { for _, v := range object["RemovalPolicies"].(map[string]interface{})["RemovalPolicy"].([]interface{}) { polices = append(polices, v.(string)) } } d.Set("removal_policies", polices) var dbIds []string if len(object["DBInstanceIds"].(map[string]interface{})["DBInstanceId"].([]interface{})) > 0 { for _, v := range object["DBInstanceIds"].(map[string]interface{})["DBInstanceId"].([]interface{}) { dbIds = append(dbIds, v.(string)) } } d.Set("db_instance_ids", dbIds) var slbIds []string if len(object["LoadBalancerIds"].(map[string]interface{})["LoadBalancerId"].([]interface{})) > 0 { for _, v := range object["LoadBalancerIds"].(map[string]interface{})["LoadBalancerId"].([]interface{}) { slbIds = append(slbIds, v.(string)) } } d.Set("loadbalancer_ids", slbIds) var vswitchIds []string if object["VSwitchIds"] != nil && len(object["VSwitchIds"].(map[string]interface{})["VSwitchId"].([]interface{})) > 0 { for _, v := range object["VSwitchIds"].(map[string]interface{})["VSwitchId"].([]interface{}) { vswitchIds = append(vswitchIds, v.(string)) } } var healthCheckTypes []string if object["HealthCheckTypes"] != nil && len(object["HealthCheckTypes"].(map[string]interface{})["HealthCheckType"].([]interface{})) > 0 { for _, v := range object["HealthCheckTypes"].(map[string]interface{})["HealthCheckType"].([]interface{}) { healthCheckTypes = append(healthCheckTypes, v.(string)) } } if v := object["LaunchTemplateOverrides"]; v != nil { result := make([]map[string]interface{}, 0) for _, i := range v.(map[string]interface{})["LaunchTemplateOverride"].([]interface{}) { launchTemplateOverride := i.(map[string]interface{}) l := map[string]interface{}{ "instance_type": launchTemplateOverride["InstanceType"], } if launchTemplateOverride["SpotPriceLimit"] != nil { spotPriceLimitFloatformat, _ := launchTemplateOverride["SpotPriceLimit"].(json.Number).Float64() spotPriceLimit, _ := strconv.ParseFloat(strconv.FormatFloat(spotPriceLimitFloatformat, 'f', 2, 64), 64) l["spot_price_limit"] = spotPriceLimit } if launchTemplateOverride["WeightedCapacity"] != nil { l["weighted_capacity"] = launchTemplateOverride["WeightedCapacity"] } result = append(result, l) } err := d.Set("launch_template_override", result) if err != nil { return WrapError(err) } } if v := object["CapacityOptions"]; v != nil { m := v.(map[string]interface{}) if m["OnDemandBaseCapacity"] != nil { d.Set("capacity_options_on_demand_base_capacity", m["OnDemandBaseCapacity"]) } if m["OnDemandPercentageAboveBaseCapacity"] != nil { d.Set("capacity_options_on_demand_percentage_above_base_capacity", m["OnDemandPercentageAboveBaseCapacity"]) } if m["CompensateWithOnDemand"] != nil { d.Set("capacity_options_compensate_with_on_demand", m["CompensateWithOnDemand"]) } if m["SpotAutoReplaceOnDemand"] != nil { d.Set("capacity_options_spot_auto_replace_on_demand", m["SpotAutoReplaceOnDemand"]) } if m["PriceComparisonMode"] != nil { d.Set("capacity_options_price_comparison_mode", m["PriceComparisonMode"]) } } if v := object["AlbServerGroups"]; v != nil { result := make([]map[string]interface{}, 0) if w, ok := d.GetOk("alb_server_group"); ok { albServerGroups := w.(*schema.Set).List() for _, rew := range albServerGroups { item := rew.(map[string]interface{}) for _, i := range v.(map[string]interface{})["AlbServerGroup"].([]interface{}) { r := i.(map[string]interface{}) uu, _ := r["Port"].(json.Number).Int64() if albServerGroupId, ok := item["alb_server_group_id"].(string); ok && albServerGroupId != "" { if r["AlbServerGroupId"].(string) == albServerGroupId && int64(item["port"].(int)) == uu { l := map[string]interface{}{ "alb_server_group_id": r["AlbServerGroupId"], "weight": r["Weight"], "port": r["Port"], } result = append(result, l) } } } err := d.Set("alb_server_group", result) if err != nil { return WrapError(err) } } } } d.Set("vswitch_ids", vswitchIds) d.Set("launch_template_id", object["LaunchTemplateId"]) d.Set("launch_template_version", object["LaunchTemplateVersion"]) d.Set("group_type", object["GroupType"]) d.Set("health_check_type", object["HealthCheckType"]) if object["HealthCheckType"] == nil { d.Set("health_check_types", healthCheckTypes) } d.Set("scaling_policy", object["ScalingPolicy"]) listTagResourcesObject, err := essService.ListTagResources(d.Id(), client) if err != nil { return WrapError(err) } d.Set("tags", tagsToMap(listTagResourcesObject)) instances, _ := essService.DescribeInstances(d.Id(), "Protected") var protectedInstances []string for _, v := range instances { protectedInstances = append(protectedInstances, v.InstanceId) } d.Set("protected_instances", protectedInstances) return nil } func resourceAliyunEssScalingGroupUpdate(d *schema.ResourceData, meta interface{}) error { client := meta.(*connectivity.AliyunClient) var err error action := "ModifyScalingGroup" request := map[string]interface{}{ "ScalingGroupId": d.Id(), } essService := EssService{client} //开启 允许部分属性修改 d.Partial(true) if d.HasChange("tags") { if err := essService.SetResourceTags(d, d.Id(), client); err != nil { return WrapError(err) } } if d.HasChange("resource_group_id") { if err := essService.ChangeResourceGroup(d, d.Id(), client); err != nil { return WrapError(err) } } if d.HasChange("scaling_group_name") { request["ScalingGroupName"] = d.Get("scaling_group_name").(string) } if d.HasChange("health_check_type") { request["HealthCheckType"] = d.Get("health_check_type").(string) } if d.HasChange("scaling_policy") { request["ScalingPolicy"] = d.Get("scaling_policy").(string) } if d.HasChange("min_size") { request["MinSize"] = requests.NewInteger(d.Get("min_size").(int)) } if d.HasChange("max_size") { request["MaxSize"] = requests.NewInteger(d.Get("max_size").(int)) } if d.HasChange("stop_instance_timeout") { if v, ok := d.GetOkExists("stop_instance_timeout"); ok { request["StopInstanceTimeout"] = requests.NewInteger(v.(int)) } } if d.HasChange("desired_capacity") { if v, ok := d.GetOkExists("desired_capacity"); ok { request["DesiredCapacity"] = requests.NewInteger(v.(int)) } } if d.HasChange("max_instance_lifetime") { if v, ok := d.GetOkExists("max_instance_lifetime"); ok { request["MaxInstanceLifetime"] = requests.NewInteger(v.(int)) } } if d.HasChange("default_cooldown") { request["DefaultCooldown"] = requests.NewInteger(d.Get("default_cooldown").(int)) } if d.HasChange("vswitch_ids") { vSwitchIds := expandStringList(d.Get("vswitch_ids").(*schema.Set).List()) request["VSwitchIds"] = &vSwitchIds } if d.HasChange("health_check_types") { healthCheckTypes := expandStringList(d.Get("health_check_types").([]interface{})) request["HealthCheckTypes"] = &healthCheckTypes } if d.HasChange("removal_policies") { policyies := expandStringList(d.Get("removal_policies").([]interface{})) for i, p := range policyies { request[fmt.Sprintf("RemovalPolicy.%d", i+1)] = p } } if d.HasChange("on_demand_base_capacity") { request["OnDemandBaseCapacity"] = requests.NewInteger(d.Get("on_demand_base_capacity").(int)) } if d.HasChange("on_demand_percentage_above_base_capacity") { request["OnDemandPercentageAboveBaseCapacity"] = requests.NewInteger(d.Get("on_demand_percentage_above_base_capacity").(int)) } if d.HasChange("spot_instance_pools") { request["SpotInstancePools"] = requests.NewInteger(d.Get("spot_instance_pools").(int)) } if d.HasChange("capacity_options_on_demand_base_capacity") { if v, ok := d.GetOkExists("capacity_options_on_demand_base_capacity"); ok { request["CapacityOptions.OnDemandBaseCapacity"] = requests.NewInteger(v.(int)) } } if d.HasChange("capacity_options_on_demand_percentage_above_base_capacity") { if v, ok := d.GetOkExists("capacity_options_on_demand_percentage_above_base_capacity"); ok { request["CapacityOptions.OnDemandPercentageAboveBaseCapacity"] = requests.NewInteger(v.(int)) } } if d.HasChange("capacity_options_compensate_with_on_demand") { if v, ok := d.GetOkExists("capacity_options_compensate_with_on_demand"); ok { request["CapacityOptions.CompensateWithOnDemand"] = requests.NewBoolean(v.(bool)) } } if d.HasChange("capacity_options_spot_auto_replace_on_demand") { if v, ok := d.GetOkExists("capacity_options_spot_auto_replace_on_demand"); ok { request["CapacityOptions.SpotAutoReplaceOnDemand"] = requests.NewBoolean(v.(bool)) } } if d.HasChange("capacity_options_price_comparison_mode") { if v, ok := d.GetOk("capacity_options_price_comparison_mode"); ok && v.(string) != "" { request["CapacityOptions.PriceComparisonMode"] = d.Get("capacity_options_price_comparison_mode").(string) } } if d.HasChange("spot_instance_remedy") { request["SpotInstanceRemedy"] = requests.NewBoolean(d.Get("spot_instance_remedy").(bool)) } if d.HasChange("compensate_with_on_demand") { if v, ok := d.GetOkExists("compensate_with_on_demand"); ok { request["CompensateWithOnDemand"] = requests.NewBoolean(v.(bool)) } } if d.HasChange("az_balance") { request["AzBalance"] = requests.NewBoolean(d.Get("az_balance").(bool)) } if d.HasChange("allocation_strategy") { request["AllocationStrategy"] = d.Get("allocation_strategy").(string) } if d.HasChange("spot_allocation_strategy") { request["SpotAllocationStrategy"] = d.Get("spot_allocation_strategy").(string) } if d.HasChange("group_deletion_protection") { request["GroupDeletionProtection"] = requests.NewBoolean(d.Get("group_deletion_protection").(bool)) } if d.HasChange("launch_template_id") || d.HasChange("launch_template_version") { request["LaunchTemplateId"] = d.Get("launch_template_id").(string) request["LaunchTemplateVersion"] = d.Get("launch_template_version").(string) } if d.HasChange("launch_template_override") { v, ok := d.GetOk("launch_template_override") if ok { launchTemplateOverrides := make([]map[string]interface{}, 0) for _, rew := range v.(*schema.Set).List() { item := rew.(map[string]interface{}) l := map[string]interface{}{ "InstanceType": item["instance_type"].(string), } if item["spot_price_limit"].(float64) != 0 { l["SpotPriceLimit"] = strconv.FormatFloat(item["spot_price_limit"].(float64), 'f', 2, 64) } if item["weighted_capacity"].(int) != 0 { l["WeightedCapacity"] = strconv.Itoa(item["weighted_capacity"].(int)) } launchTemplateOverrides = append(launchTemplateOverrides, l) } request["LaunchTemplateVersion"] = d.Get("launch_template_version").(string) request["LaunchTemplateId"] = d.Get("launch_template_id").(string) request["LaunchTemplateOverride"] = &launchTemplateOverrides } } _, err = client.RpcPost("Ess", "2014-08-28", action, nil, request, false) if err != nil { return WrapErrorf(err, DefaultErrorMsg, "alicloud_ess_scaling_group", "ModifyScalingGroup", AlibabaCloudSdkGoERROR) } if d.HasChange("loadbalancer_ids") { oldLoadbalancers, newLoadbalancers := d.GetChange("loadbalancer_ids") err = attachOrDetachLoadbalancers(d, client, oldLoadbalancers.(*schema.Set), newLoadbalancers.(*schema.Set)) if err != nil { return WrapError(err) } } if d.HasChange("alb_server_group") { oldAlbServerGroups, newAlbServerGroups := d.GetChange("alb_server_group") err = attachOrDetachAlbServerGroups(d, client, oldAlbServerGroups.(*schema.Set), newAlbServerGroups.(*schema.Set)) if err != nil { return WrapError(err) } } if d.HasChange("db_instance_ids") { oldDbInstanceIds, newDbInstanceIds := d.GetChange("db_instance_ids") err = attachOrDetachDbInstances(d, client, oldDbInstanceIds.(*schema.Set), newDbInstanceIds.(*schema.Set)) if err != nil { return WrapError(err) } } if d.HasChange("protected_instances") { oldProtectedInstances, newProtectedInstances := d.GetChange("protected_instances") err = setProtectedInstances(d, client, oldProtectedInstances.(*schema.Set), newProtectedInstances.(*schema.Set)) if err != nil { return WrapError(err) } } d.Partial(false) return resourceAliyunEssScalingGroupRead(d, meta) } func resourceAliyunEssScalingGroupDelete(d *schema.ResourceData, meta interface{}) error { client := meta.(*connectivity.AliyunClient) essService := EssService{client} request := ess.CreateDeleteScalingGroupRequest() request.RegionId = client.RegionId request.ScalingGroupId = d.Id() request.ForceDelete = requests.NewBoolean(true) err := resource.Retry(client.GetRetryTimeout(d.Timeout(schema.TimeoutDelete)), func() *resource.RetryError { raw, err := client.WithEssClient(func(essClient *ess.Client) (interface{}, error) { return essClient.DeleteScalingGroup(request) }) if err != nil { if IsExpectedErrors(err, []string{"InvalidScalingGroupId.NotFound"}) { return nil } if IsExpectedErrors(err, []string{"InternalError"}) { return resource.RetryableError(err) } return resource.NonRetryableError(err) } addDebug(request.GetActionName(), raw, request.RpcRequest, request) return nil }) if err != nil { return WrapErrorf(err, DefaultErrorMsg, d.Id(), request.GetActionName(), AlibabaCloudSdkGoERROR) } return WrapError(essService.WaitForEssScalingGroup(d.Id(), Deleted, DefaultLongTimeout)) } func buildAlicloudEssScalingGroupArgs(d *schema.ResourceData, meta interface{}) (map[string]interface{}, error) { client := meta.(*connectivity.AliyunClient) request := map[string]interface{}{ "RegionId": client.RegionId, "MinSize": d.Get("min_size"), "MaxSize": d.Get("max_size"), "DefaultCooldown": d.Get("default_cooldown"), "MultiAZPolicy": d.Get("multi_az_policy"), "GroupType": d.Get("group_type"), } slbService := SlbService{client} if v, ok := d.GetOk("scaling_group_name"); ok && v.(string) != "" { request["ScalingGroupName"] = v } if v, ok := d.GetOk("allocation_strategy"); ok && v.(string) != "" { request["AllocationStrategy"] = v } if v, ok := d.GetOk("spot_allocation_strategy"); ok && v.(string) != "" { request["SpotAllocationStrategy"] = v } if v, ok := d.GetOk("az_balance"); ok { request["AzBalance"] = v } if v, ok := d.GetOk("resource_group_id"); ok { request["ResourceGroupId"] = v } if v, ok := d.GetOk("instance_id"); ok { request["InstanceId"] = v } if v, ok := d.GetOk("container_group_id"); ok { request["ContainerGroupId"] = v } if v, ok := d.GetOk("vswitch_ids"); ok { count := 1 for _, value := range v.(*schema.Set).List() { request[fmt.Sprintf("VSwitchIds.%d", count)] = value count++ } } if v, ok := d.GetOk("health_check_types"); ok { count := 1 for _, value := range v.(*schema.Set).List() { request[fmt.Sprintf("HealthCheckTypes.%d", count)] = value count++ } } if v, ok := d.GetOk("alb_server_group"); ok { albServerGroupsMaps := make([]map[string]interface{}, 0) albServerGroups := v.(*schema.Set).List() for _, rew := range albServerGroups { albServerGroupsMap := make(map[string]interface{}) item := rew.(map[string]interface{}) if albServerGroupId, ok := item["alb_server_group_id"].(string); ok && albServerGroupId != "" { albServerGroupsMap["AlbServerGroupId"] = albServerGroupId } albServerGroupsMap["Weight"] = item["weight"] albServerGroupsMap["Port"] = item["port"] albServerGroupsMaps = append(albServerGroupsMaps, albServerGroupsMap) } request["AlbServerGroup"] = albServerGroupsMaps } if dbs, ok := d.GetOk("db_instance_ids"); ok { request["DBInstanceIds"] = convertListToJsonString(dbs.(*schema.Set).List()) } if lbs, ok := d.GetOk("loadbalancer_ids"); ok { for _, lb := range lbs.(*schema.Set).List() { if err := slbService.WaitForSlb(lb.(string), Active, DefaultTimeout); err != nil { return nil, WrapError(err) } } request["LoadBalancerIds"] = convertListToJsonString(lbs.(*schema.Set).List()) } if v, ok := d.GetOk("desired_capacity"); ok { request["DesiredCapacity"] = v } if v, ok := d.GetOk("stop_instance_timeout"); ok { request["StopInstanceTimeout"] = v } if v, ok := d.GetOk("max_instance_lifetime"); ok { request["MaxInstanceLifetime"] = v } request["OnDemandBaseCapacity"] = d.Get("on_demand_base_capacity") request["OnDemandPercentageAboveBaseCapacity"] = d.Get("on_demand_percentage_above_base_capacity") if v, ok := d.GetOk("spot_instance_pools"); ok { request["SpotInstancePools"] = v } if v, ok := d.GetOkExists("capacity_options_on_demand_base_capacity"); ok { request["CapacityOptions.OnDemandBaseCapacity"] = v } if v, ok := d.GetOkExists("capacity_options_on_demand_percentage_above_base_capacity"); ok { request["CapacityOptions.OnDemandPercentageAboveBaseCapacity"] = v } if v, ok := d.GetOkExists("capacity_options_compensate_with_on_demand"); ok { request["CapacityOptions.CompensateWithOnDemand"] = v } if v, ok := d.GetOkExists("capacity_options_spot_auto_replace_on_demand"); ok { request["CapacityOptions.SpotAutoReplaceOnDemand"] = v } if v, ok := d.GetOk("capacity_options_price_comparison_mode"); ok && v.(string) != "" { request["CapacityOptions.PriceComparisonMode"] = v } if v, ok := d.GetOk("spot_instance_remedy"); ok { request["SpotInstanceRemedy"] = v } if v, ok := d.GetOkExists("compensate_with_on_demand"); ok { request["CompensateWithOnDemand"] = v } if v, ok := d.GetOk("health_check_type"); ok { request["HealthCheckType"] = v } if v, ok := d.GetOk("scaling_policy"); ok { request["ScalingPolicy"] = v } if v, ok := d.GetOk("group_deletion_protection"); ok { request["GroupDeletionProtection"] = v } if v, ok := d.GetOk("launch_template_id"); ok { request["LaunchTemplateId"] = v } if v, ok := d.GetOk("launch_template_override"); ok { launchTemplateOverridesMaps := make([]map[string]interface{}, 0) launchTemplateOverrides := v.(*schema.Set).List() for _, rew := range launchTemplateOverrides { launchTemplateOverridesMap := make(map[string]interface{}) item := rew.(map[string]interface{}) if instanceType, ok := item["instance_type"].(string); ok && instanceType != "" { launchTemplateOverridesMap["InstanceType"] = instanceType } if item["spot_price_limit"].(float64) != 0 { launchTemplateOverridesMap["SpotPriceLimit"] = strconv.FormatFloat(item["spot_price_limit"].(float64), 'f', 2, 64) } if item["weighted_capacity"].(int) != 0 { launchTemplateOverridesMap["WeightedCapacity"] = item["weighted_capacity"].(int) } launchTemplateOverridesMaps = append(launchTemplateOverridesMaps, launchTemplateOverridesMap) } request["LaunchTemplateOverride"] = launchTemplateOverridesMaps } if v, ok := d.GetOk("launch_template_version"); ok { request["LaunchTemplateVersion"] = v } return request, nil } func attachOrDetachLoadbalancers(d *schema.ResourceData, client *connectivity.AliyunClient, oldLoadbalancerSet *schema.Set, newLoadbalancerSet *schema.Set) error { detachLoadbalancerSet := oldLoadbalancerSet.Difference(newLoadbalancerSet) attachLoadbalancerSet := newLoadbalancerSet.Difference(oldLoadbalancerSet) if attachLoadbalancerSet.Len() > 0 { var subLists = partition(attachLoadbalancerSet, int(AttachDetachLoadbalancersBatchsize)) for _, subList := range subLists { attachLoadbalancersRequest := ess.CreateAttachLoadBalancersRequest() attachLoadbalancersRequest.RegionId = client.RegionId attachLoadbalancersRequest.ScalingGroupId = d.Id() attachLoadbalancersRequest.ForceAttach = requests.NewBoolean(true) attachLoadbalancersRequest.LoadBalancer = &subList raw, err := client.WithEssClient(func(essClient *ess.Client) (interface{}, error) { return essClient.AttachLoadBalancers(attachLoadbalancersRequest) }) if err != nil { return WrapErrorf(err, DefaultErrorMsg, d.Id(), attachLoadbalancersRequest.GetActionName(), AlibabaCloudSdkGoERROR) } addDebug(attachLoadbalancersRequest.GetActionName(), raw, attachLoadbalancersRequest.RpcRequest, attachLoadbalancersRequest) } } if detachLoadbalancerSet.Len() > 0 { var subLists = partition(detachLoadbalancerSet, int(AttachDetachLoadbalancersBatchsize)) for _, subList := range subLists { detachLoadbalancersRequest := ess.CreateDetachLoadBalancersRequest() detachLoadbalancersRequest.RegionId = client.RegionId detachLoadbalancersRequest.ScalingGroupId = d.Id() detachLoadbalancersRequest.ForceDetach = requests.NewBoolean(false) detachLoadbalancersRequest.LoadBalancer = &subList raw, err := client.WithEssClient(func(essClient *ess.Client) (interface{}, error) { return essClient.DetachLoadBalancers(detachLoadbalancersRequest) }) if err != nil { return WrapErrorf(err, DefaultErrorMsg, d.Id(), detachLoadbalancersRequest.GetActionName(), AlibabaCloudSdkGoERROR) } addDebug(detachLoadbalancersRequest.GetActionName(), raw, detachLoadbalancersRequest.RpcRequest, detachLoadbalancersRequest) } } return nil } func setProtectedInstances(d *schema.ResourceData, client *connectivity.AliyunClient, oldInstances *schema.Set, newInstances *schema.Set) error { unprotected := oldInstances.Difference(newInstances) protected := newInstances.Difference(oldInstances) request := ess.CreateSetInstancesProtectionRequest() request.RegionId = client.RegionId request.ScalingGroupId = d.Id() if protected.Len() > 0 { var subLists = partition(protected, 20) for _, subList := range subLists { request.InstanceId = &subList request.ProtectedFromScaleIn = requests.Boolean(strconv.FormatBool(true)) _, err := client.WithEssClient(func(essClient *ess.Client) (interface{}, error) { return essClient.SetInstancesProtection(request) }) if err != nil { return WrapErrorf(err, DefaultErrorMsg, d.Id(), request.GetActionName(), AlibabaCloudSdkGoERROR) } } } if unprotected.Len() > 0 { var subLists = partition(unprotected, 20) for _, subList := range subLists { request.InstanceId = &subList request.ProtectedFromScaleIn = requests.Boolean(strconv.FormatBool(false)) _, err := client.WithEssClient(func(essClient *ess.Client) (interface{}, error) { return essClient.SetInstancesProtection(request) }) if err != nil { return WrapErrorf(err, DefaultErrorMsg, d.Id(), request.GetActionName(), AlibabaCloudSdkGoERROR) } } } return nil } func attachOrDetachAlbServerGroups(d *schema.ResourceData, client *connectivity.AliyunClient, oldAlbServerGroupSet *schema.Set, newAlbServerGroupSet *schema.Set) error { detachAlbServerGroupSet := oldAlbServerGroupSet.Difference(newAlbServerGroupSet).List() attachAlbServerGroupSet := newAlbServerGroupSet.Difference(oldAlbServerGroupSet).List() var response map[string]interface{} var err error if len(detachAlbServerGroupSet) > 0 { var subLists = SplitSlice(detachAlbServerGroupSet, int(AttachDetachAlbServerGroupBatchsize)) for _, subList := range subLists { action := "DetachAlbServerGroups" albRequest := map[string]interface{}{ "ScalingGroupId": d.Id(), "ForceDetach": true, "RegionId": client.RegionId, } albServerGroupsMaps := make([]map[string]interface{}, 0) for _, rew := range subList { albServerGroupsMap := make(map[string]interface{}) item := rew.(map[string]interface{}) if albServerGroupId, ok := item["alb_server_group_id"].(string); ok && albServerGroupId != "" { albServerGroupsMap["AlbServerGroupId"] = albServerGroupId } albServerGroupsMap["Port"] = item["port"] albServerGroupsMaps = append(albServerGroupsMaps, albServerGroupsMap) } albRequest["AlbServerGroup"] = albServerGroupsMaps err = resource.Retry(d.Timeout(schema.TimeoutUpdate), func() *resource.RetryError { response, err = client.RpcPost("Ess", "2014-08-28", action, nil, albRequest, true) if err != nil { if IsExpectedErrors(err, []string{"IncorrectScalingGroupStatus"}) || NeedRetry(err) { return resource.RetryableError(err) } return resource.NonRetryableError(err) } return nil }) if err != nil { return WrapErrorf(err, DefaultErrorMsg, d.Id(), action, AlibabaCloudSdkGoERROR) } addDebug(action, response, albRequest) } } if len(attachAlbServerGroupSet) > 0 { var subLists = SplitSlice(attachAlbServerGroupSet, int(AttachDetachAlbServerGroupBatchsize)) for _, subList := range subLists { action := "AttachAlbServerGroups" albRequest := map[string]interface{}{ "ScalingGroupId": d.Id(), "ForceAttach": true, "RegionId": client.RegionId, } albServerGroupsMaps := make([]map[string]interface{}, 0) for _, rew := range subList { albServerGroupsMap := make(map[string]interface{}) item := rew.(map[string]interface{}) if albServerGroupId, ok := item["alb_server_group_id"].(string); ok && albServerGroupId != "" { albServerGroupsMap["AlbServerGroupId"] = albServerGroupId } albServerGroupsMap["Port"] = item["port"] albServerGroupsMap["Weight"] = item["weight"] albServerGroupsMaps = append(albServerGroupsMaps, albServerGroupsMap) } albRequest["AlbServerGroup"] = albServerGroupsMaps err = resource.Retry(d.Timeout(schema.TimeoutUpdate), func() *resource.RetryError { response, err = client.RpcPost("Ess", "2014-08-28", action, nil, albRequest, true) if err != nil { if IsExpectedErrors(err, []string{"IncorrectScalingGroupStatus"}) || NeedRetry(err) { return resource.RetryableError(err) } return resource.NonRetryableError(err) } return nil }) if err != nil { return WrapErrorf(err, DefaultErrorMsg, d.Id(), action, AlibabaCloudSdkGoERROR) } addDebug(action, response, albRequest) } } return nil } func attachOrDetachDbInstances(d *schema.ResourceData, client *connectivity.AliyunClient, oldDbInstanceIdSet *schema.Set, newDbInstanceIdSet *schema.Set) error { detachDbInstanceSet := oldDbInstanceIdSet.Difference(newDbInstanceIdSet) attachDbInstanceSet := newDbInstanceIdSet.Difference(oldDbInstanceIdSet) if attachDbInstanceSet.Len() > 0 { var subLists = partition(attachDbInstanceSet, int(AttachDetachDbinstancesBatchsize)) for _, subList := range subLists { attachDbInstancesRequest := ess.CreateAttachDBInstancesRequest() attachDbInstancesRequest.RegionId = client.RegionId attachDbInstancesRequest.ScalingGroupId = d.Id() attachDbInstancesRequest.ForceAttach = requests.NewBoolean(true) attachDbInstancesRequest.DBInstance = &subList raw, err := client.WithEssClient(func(essClient *ess.Client) (interface{}, error) { return essClient.AttachDBInstances(attachDbInstancesRequest) }) if err != nil { return WrapErrorf(err, DefaultErrorMsg, d.Id(), attachDbInstancesRequest.GetActionName(), AlibabaCloudSdkGoERROR) } addDebug(attachDbInstancesRequest.GetActionName(), raw, attachDbInstancesRequest.RpcRequest, attachDbInstancesRequest) } } if detachDbInstanceSet.Len() > 0 { var subLists = partition(detachDbInstanceSet, int(AttachDetachDbinstancesBatchsize)) for _, subList := range subLists { detachDbInstancesRequest := ess.CreateDetachDBInstancesRequest() detachDbInstancesRequest.RegionId = client.RegionId detachDbInstancesRequest.ScalingGroupId = d.Id() detachDbInstancesRequest.ForceDetach = requests.NewBoolean(true) detachDbInstancesRequest.DBInstance = &subList raw, err := client.WithEssClient(func(essClient *ess.Client) (interface{}, error) { return essClient.DetachDBInstances(detachDbInstancesRequest) }) if err != nil { return WrapErrorf(err, DefaultErrorMsg, d.Id(), detachDbInstancesRequest.GetActionName(), AlibabaCloudSdkGoERROR) } addDebug(detachDbInstancesRequest.GetActionName(), raw, detachDbInstancesRequest.RpcRequest, detachDbInstancesRequest) } } return nil } func partition(instanceIds *schema.Set, batchSize int) [][]string { var res [][]string size := instanceIds.Len() batchCount := int(math.Ceil(float64(size) / float64(batchSize))) idList := expandStringList(instanceIds.List()) for i := 1; i <= batchCount; i++ { fromIndex := batchSize * (i - 1) toIndex := int(math.Min(float64(batchSize*i), float64(size))) subList := idList[fromIndex:toIndex] res = append(res, subList) } return res }