From 8e8a521151ec1a1727c32ab06fb22f75b84bb3dd Mon Sep 17 00:00:00 2001 From: chenhanzhang Date: Fri, 28 Nov 2025 00:24:33 +0800 Subject: [PATCH] resource/alicloud_eflo_node: Added the field cluster_id, hostname, ip_allocation_policy, machine_type_policy, bonds, subnet, name, machine_type, bond_policy, bond_default_subnet, node_policy, node_id, login_password, node_group_id, node_type, user_data, vswitch_id, vpc_id, Code, Value. --- alicloud/resource_alicloud_eflo_node.go | 900 +++++++++++++++---- alicloud/resource_alicloud_eflo_node_test.go | 27 +- alicloud/service_alicloud_eflo_v2.go | 52 +- website/docs/r/eflo_node.html.markdown | 95 +- 4 files changed, 889 insertions(+), 185 deletions(-) diff --git a/alicloud/resource_alicloud_eflo_node.go b/alicloud/resource_alicloud_eflo_node.go index 552d06c03942..8b309b419931 100644 --- a/alicloud/resource_alicloud_eflo_node.go +++ b/alicloud/resource_alicloud_eflo_node.go @@ -2,6 +2,7 @@ package alicloud import ( + "encoding/json" "fmt" "log" "time" @@ -10,6 +11,7 @@ import ( "github.com/aliyun/terraform-provider-alicloud/alicloud/connectivity" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/tidwall/sjson" ) func resourceAliCloudEfloNode() *schema.Resource { @@ -23,7 +25,7 @@ func resourceAliCloudEfloNode() *schema.Resource { }, Timeouts: &schema.ResourceTimeout{ Create: schema.DefaultTimeout(10 * time.Minute), - Update: schema.DefaultTimeout(5 * time.Minute), + Update: schema.DefaultTimeout(6 * time.Minute), Delete: schema.DefaultTimeout(5 * time.Minute), }, Schema: map[string]*schema.Schema{ @@ -35,6 +37,10 @@ func resourceAliCloudEfloNode() *schema.Resource { Type: schema.TypeString, Optional: true, }, + "cluster_id": { + Type: schema.TypeString, + Optional: true, + }, "computing_server": { Type: schema.TypeString, Optional: true, @@ -50,17 +56,151 @@ func resourceAliCloudEfloNode() *schema.Resource { Type: schema.TypeString, Optional: true, }, + "hostname": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, "hpn_zone": { Type: schema.TypeString, Optional: true, ForceNew: true, }, + "ip_allocation_policy": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "machine_type_policy": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "bonds": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "subnet": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "name": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + }, + }, + }, + "machine_type": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + }, + }, + }, + "bond_policy": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "bonds": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "subnet": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "name": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + }, + }, + }, + "bond_default_subnet": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + }, + }, + }, + "node_policy": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "bonds": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "subnet": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "name": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + }, + }, + }, + "node_id": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "hostname": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + }, + }, + }, + }, + }, + }, + "login_password": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Sensitive: true, + }, "machine_type": { Type: schema.TypeString, Optional: true, Computed: true, ForceNew: true, }, + "node_group_id": { + Type: schema.TypeString, + Optional: true, + }, + "node_type": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, "payment_ratio": { Type: schema.TypeString, Optional: true, @@ -112,6 +252,21 @@ func resourceAliCloudEfloNode() *schema.Resource { Computed: true, }, "tags": tagsSchema(), + "user_data": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "vswitch_id": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "vpc_id": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, "zone": { Type: schema.TypeString, Optional: true, @@ -133,184 +288,349 @@ func resourceAliCloudEfloNodeCreate(d *schema.ResourceData, meta interface{}) er } client := meta.(*connectivity.AliyunClient) + if v, ok := d.GetOk("payment_type"); ok && InArray(fmt.Sprint(v), []string{"Subscription"}) { + action := "CreateInstance" + var request map[string]interface{} + var response map[string]interface{} + query := make(map[string]interface{}) + var err error + request = make(map[string]interface{}) - action := "CreateInstance" - var request map[string]interface{} - var response map[string]interface{} - query := make(map[string]interface{}) - var err error - request = make(map[string]interface{}) - - request["ClientToken"] = buildClientToken(action) + request["ClientToken"] = buildClientToken(action) - request["SubscriptionType"] = d.Get("payment_type") - parameterMapList := make([]map[string]interface{}, 0) - if v, ok := d.GetOk("server_arch"); ok { - parameterMapList = append(parameterMapList, map[string]interface{}{ - "Code": "ServerArch", - "Value": v, - }) - } - if v, ok := d.GetOk("hpn_zone"); ok { - parameterMapList = append(parameterMapList, map[string]interface{}{ - "Code": "HpnZone", - "Value": v, - }) - } - if v, ok := d.GetOk("stage_num"); ok { - parameterMapList = append(parameterMapList, map[string]interface{}{ - "Code": "StageNum", - "Value": v, - }) - } - if v, ok := d.GetOk("payment_ratio"); ok { - parameterMapList = append(parameterMapList, map[string]interface{}{ - "Code": "PaymentRatio", - "Value": v, - }) - } - parameterMapList = append(parameterMapList, map[string]interface{}{ - "Code": "RegionId", - "Value": client.RegionId, - }) - if v, ok := d.GetOk("classify"); ok { - parameterMapList = append(parameterMapList, map[string]interface{}{ - "Code": "Classify", - "Value": v, - }) - } - discountlevelCode := "discountlevel" - if installPai { - discountlevelCode = "DiscountLevel" - } - if v, ok := d.GetOk("discount_level"); ok { - parameterMapList = append(parameterMapList, map[string]interface{}{ - "Code": discountlevelCode, - "Value": v, - }) - } - if v, ok := d.GetOk("billing_cycle"); ok { - if v.(string) == "1month" && installPai { - v = "1m" + request["SubscriptionType"] = d.Get("payment_type") + parameterMapList := make([]map[string]interface{}, 0) + if v, ok := d.GetOk("server_arch"); ok { + parameterMapList = append(parameterMapList, map[string]interface{}{ + "Code": "ServerArch", + "Value": v, + }) + } + if v, ok := d.GetOk("hpn_zone"); ok { + parameterMapList = append(parameterMapList, map[string]interface{}{ + "Code": "HpnZone", + "Value": v, + }) + } + if v, ok := d.GetOk("stage_num"); ok { + parameterMapList = append(parameterMapList, map[string]interface{}{ + "Code": "StageNum", + "Value": v, + }) + } + if v, ok := d.GetOk("payment_ratio"); ok { + parameterMapList = append(parameterMapList, map[string]interface{}{ + "Code": "PaymentRatio", + "Value": v, + }) } parameterMapList = append(parameterMapList, map[string]interface{}{ - "Code": "BillingCycle", - "Value": v, - }) - } - computingServerCode := "computingserver" - if installPai { - computingServerCode = "ComputingServer" - } - if v, ok := d.GetOk("machine_type"); ok { - parameterMapList = append(parameterMapList, map[string]interface{}{ - "Code": computingServerCode, - "Value": v, - }) - } - if v, ok := d.GetOk("computing_server"); ok { - parameterMapList = append(parameterMapList, map[string]interface{}{ - "Code": computingServerCode, - "Value": v, - }) - } - if v, ok := d.GetOk("zone"); ok { - parameterMapList = append(parameterMapList, map[string]interface{}{ - "Code": "Zone", - "Value": v, - }) - } - if v, ok := d.GetOk("product_form"); ok { - parameterMapList = append(parameterMapList, map[string]interface{}{ - "Code": "ProductForm", - "Value": v, + "Code": "RegionId", + "Value": client.RegionId, }) - } - request["Parameter"] = parameterMapList - - if v, ok := d.GetOk("renewal_status"); ok { - request["RenewalStatus"] = v - } - if v, ok := d.GetOkExists("period"); ok { - request["Period"] = v - } - if v, ok := d.GetOkExists("renew_period"); ok { - request["RenewPeriod"] = v - } - var endpoint string - request["ProductCode"] = "bccluster" - request["ProductType"] = "bccluster_eflocomputing_public_cn" - if installPai { - request["ProductCode"] = "learn" - request["ProductType"] = "learn_eflocomputing_public_cn" - } - if v, ok := d.GetOk("payment_type"); ok && v == "PayAsYouGo" { - request["ProductCode"] = "bccluster" - request["ProductType"] = "bccluster_computinginstance_public_cn" + if v, ok := d.GetOk("classify"); ok { + parameterMapList = append(parameterMapList, map[string]interface{}{ + "Code": "Classify", + "Value": v, + }) + } + discountlevelCode := "discountlevel" if installPai { - return WrapError(Error("InstallPai currently does not support pay-as-you-go products.")) + discountlevelCode = "DiscountLevel" } - } - if client.IsInternationalAccount() { + if v, ok := d.GetOk("discount_level"); ok { + parameterMapList = append(parameterMapList, map[string]interface{}{ + "Code": discountlevelCode, + "Value": v, + }) + } + if v, ok := d.GetOk("billing_cycle"); ok { + if v.(string) == "1month" && installPai { + v = "1m" + } + parameterMapList = append(parameterMapList, map[string]interface{}{ + "Code": "BillingCycle", + "Value": v, + }) + } + computingServerCode := "computingserver" + if installPai { + computingServerCode = "ComputingServer" + } + if v, ok := d.GetOk("machine_type"); ok { + parameterMapList = append(parameterMapList, map[string]interface{}{ + "Code": computingServerCode, + "Value": v, + }) + } + if v, ok := d.GetOk("computing_server"); ok { + parameterMapList = append(parameterMapList, map[string]interface{}{ + "Code": computingServerCode, + "Value": v, + }) + } + if v, ok := d.GetOk("zone"); ok { + parameterMapList = append(parameterMapList, map[string]interface{}{ + "Code": "Zone", + "Value": v, + }) + } + if v, ok := d.GetOk("product_form"); ok { + parameterMapList = append(parameterMapList, map[string]interface{}{ + "Code": "ProductForm", + "Value": v, + }) + } + request["Parameter"] = parameterMapList + + if v, ok := d.GetOk("renewal_status"); ok { + request["RenewalStatus"] = v + } + if v, ok := d.GetOkExists("period"); ok { + request["Period"] = v + } + if v, ok := d.GetOkExists("renew_period"); ok { + request["RenewPeriod"] = v + } + var endpoint string request["ProductCode"] = "bccluster" - request["ProductType"] = "bccluster_eflocomputing_public_intl" + request["ProductType"] = "bccluster_eflocomputing_public_cn" if installPai { request["ProductCode"] = "learn" - request["ProductType"] = "learn_eflocomputing_public_intl" + request["ProductType"] = "learn_eflocomputing_public_cn" } if v, ok := d.GetOk("payment_type"); ok && v == "PayAsYouGo" { request["ProductCode"] = "bccluster" - request["ProductType"] = "bccluster_computinginstance_public_intl" + request["ProductType"] = "bccluster_computinginstance_public_cn" if installPai { return WrapError(Error("InstallPai currently does not support pay-as-you-go products.")) } } - } - if request["SubscriptionType"] == "" { - request["SubscriptionType"] = "Subscription" - } - wait := incrementalWait(3*time.Second, 5*time.Second) - err = resource.Retry(d.Timeout(schema.TimeoutCreate), func() *resource.RetryError { - response, err = client.RpcPostWithEndpoint("BssOpenApi", "2017-12-14", action, query, request, true, endpoint) - if err != nil { - if IsExpectedErrors(err, []string{"CSS_CHECK_ORDER_ERROR", "InternalError", "SYSTEM.CONCURRENT_OPERATE"}) || NeedRetry(err) { - wait() - return resource.RetryableError(err) + if client.IsInternationalAccount() { + request["ProductCode"] = "bccluster" + request["ProductType"] = "bccluster_eflocomputing_public_intl" + if installPai { + request["ProductCode"] = "learn" + request["ProductType"] = "learn_eflocomputing_public_intl" } - if !client.IsInternationalAccount() && IsExpectedErrors(err, []string{"NotApplicable"}) { + if v, ok := d.GetOk("payment_type"); ok && v == "PayAsYouGo" { request["ProductCode"] = "bccluster" - request["ProductType"] = "bccluster_eflocomputing_public_intl" + request["ProductType"] = "bccluster_computinginstance_public_intl" if installPai { - request["ProductCode"] = "learn" - request["ProductType"] = "learn_eflocomputing_public_intl" + return WrapError(Error("InstallPai currently does not support pay-as-you-go products.")) } - if v, ok := d.GetOk("payment_type"); ok && v == "PayAsYouGo" { + } + } + if request["SubscriptionType"] == "" { + request["SubscriptionType"] = "Subscription" + } + wait := incrementalWait(3*time.Second, 5*time.Second) + err = resource.Retry(d.Timeout(schema.TimeoutCreate), func() *resource.RetryError { + response, err = client.RpcPostWithEndpoint("BssOpenApi", "2017-12-14", action, query, request, true, endpoint) + if err != nil { + if IsExpectedErrors(err, []string{"CSS_CHECK_ORDER_ERROR", "InternalError", "SYSTEM.CONCURRENT_OPERATE"}) || NeedRetry(err) { + wait() + return resource.RetryableError(err) + } + if !client.IsInternationalAccount() && IsExpectedErrors(err, []string{"NotApplicable"}) { request["ProductCode"] = "bccluster" - request["ProductType"] = "bccluster_computinginstance_public_intl" + request["ProductType"] = "bccluster_eflocomputing_public_intl" if installPai { - return resource.RetryableError(err) + request["ProductCode"] = "learn" + request["ProductType"] = "learn_eflocomputing_public_intl" } + if v, ok := d.GetOk("payment_type"); ok && v == "PayAsYouGo" { + request["ProductCode"] = "bccluster" + request["ProductType"] = "bccluster_computinginstance_public_intl" + if installPai { + return resource.RetryableError(err) + } + } + endpoint = connectivity.BssOpenAPIEndpointInternational + return resource.RetryableError(err) } - endpoint = connectivity.BssOpenAPIEndpointInternational - return resource.RetryableError(err) + return resource.NonRetryableError(err) } - return resource.NonRetryableError(err) + return nil + }) + addDebug(action, response, request) + + if err != nil { + return WrapErrorf(err, DefaultErrorMsg, "alicloud_eflo_node", action, AlibabaCloudSdkGoERROR) + } + + id, _ := jsonpath.Get("$.Data.InstanceId", response) + d.SetId(fmt.Sprint(id)) + + efloServiceV2 := EfloServiceV2{client} + stateConf := BuildStateConf([]string{}, []string{"Unused"}, d.Timeout(schema.TimeoutCreate), 5*time.Second, efloServiceV2.EfloNodeStateRefreshFunc(d.Id(), "OperatingState", []string{})) + if _, err := stateConf.WaitForState(); err != nil { + return WrapErrorf(err, IdMsg, d.Id()) } - return nil - }) - addDebug(action, response, request) - if err != nil { - return WrapErrorf(err, DefaultErrorMsg, "alicloud_eflo_node", action, AlibabaCloudSdkGoERROR) } - id, _ := jsonpath.Get("$.Data.InstanceId", response) - d.SetId(fmt.Sprint(id)) + if v, ok := d.GetOk("payment_type"); ok && InArray(fmt.Sprint(v), []string{"PayAsYouGo"}) { + action := "ExtendCluster" + var request map[string]interface{} + var response map[string]interface{} + query := make(map[string]interface{}) + var err error + request = make(map[string]interface{}) + request["RegionId"] = client.RegionId + + if v, ok := d.GetOk("ip_allocation_policy"); ok { + ipAllocationPolicyMapsArray := make([]interface{}, 0) + for _, dataLoop := range convertToInterfaceArray(v) { + dataLoopTmp := dataLoop.(map[string]interface{}) + dataLoopMap := make(map[string]interface{}) + localData1 := make(map[string]interface{}) + if v, ok := dataLoopTmp["bond_policy"]; ok { + localData2, err := jsonpath.Get("$[0].bonds", v) + if err != nil { + localData2 = make([]interface{}, 0) + } + localMaps1 := make([]interface{}, 0) + for _, dataLoop2 := range convertToInterfaceArray(localData2) { + dataLoop2Tmp := make(map[string]interface{}) + if dataLoop2 != nil { + dataLoop2Tmp = dataLoop2.(map[string]interface{}) + } + dataLoop2Map := make(map[string]interface{}) + dataLoop2Map["Subnet"] = dataLoop2Tmp["subnet"] + dataLoop2Map["Name"] = dataLoop2Tmp["name"] + localMaps1 = append(localMaps1, dataLoop2Map) + } + localData1["Bonds"] = localMaps1 + } + + bondDefaultSubnet1, _ := jsonpath.Get("$[0].bond_default_subnet", dataLoopTmp["bond_policy"]) + if bondDefaultSubnet1 != nil && bondDefaultSubnet1 != "" { + localData1["BondDefaultSubnet"] = bondDefaultSubnet1 + } + if len(localData1) > 0 { + dataLoopMap["BondPolicy"] = localData1 + } + localMaps2 := make([]interface{}, 0) + localData3 := dataLoopTmp["node_policy"] + for _, dataLoop3 := range convertToInterfaceArray(localData3) { + dataLoop3Tmp := dataLoop3.(map[string]interface{}) + dataLoop3Map := make(map[string]interface{}) + localMaps3 := make([]interface{}, 0) + localData4 := dataLoop3Tmp["bonds"] + for _, dataLoop4 := range convertToInterfaceArray(localData4) { + dataLoop4Tmp := dataLoop4.(map[string]interface{}) + dataLoop4Map := make(map[string]interface{}) + dataLoop4Map["Name"] = dataLoop4Tmp["name"] + dataLoop4Map["Subnet"] = dataLoop4Tmp["subnet"] + localMaps3 = append(localMaps3, dataLoop4Map) + } + dataLoop3Map["Bonds"] = localMaps3 + dataLoop3Map["Hostname"] = dataLoop3Tmp["hostname"] + dataLoop3Map["NodeId"] = dataLoop3Tmp["node_id"] + localMaps2 = append(localMaps2, dataLoop3Map) + } + dataLoopMap["NodePolicy"] = localMaps2 + localMaps4 := make([]interface{}, 0) + localData5 := dataLoopTmp["machine_type_policy"] + for _, dataLoop5 := range convertToInterfaceArray(localData5) { + dataLoop5Tmp := dataLoop5.(map[string]interface{}) + dataLoop5Map := make(map[string]interface{}) + localMaps5 := make([]interface{}, 0) + localData6 := dataLoop5Tmp["bonds"] + for _, dataLoop6 := range convertToInterfaceArray(localData6) { + dataLoop6Tmp := dataLoop6.(map[string]interface{}) + dataLoop6Map := make(map[string]interface{}) + dataLoop6Map["Subnet"] = dataLoop6Tmp["subnet"] + dataLoop6Map["Name"] = dataLoop6Tmp["name"] + localMaps5 = append(localMaps5, dataLoop6Map) + } + dataLoop5Map["Bonds"] = localMaps5 + dataLoop5Map["MachineType"] = dataLoop5Tmp["machine_type"] + localMaps4 = append(localMaps4, dataLoop5Map) + } + dataLoopMap["MachineTypePolicy"] = localMaps4 + ipAllocationPolicyMapsArray = append(ipAllocationPolicyMapsArray, dataLoopMap) + } + ipAllocationPolicyMapsJson, err := json.Marshal(ipAllocationPolicyMapsArray) + if err != nil { + return WrapError(err) + } + request["IpAllocationPolicy"] = string(ipAllocationPolicyMapsJson) + } + + nodeGroupsDataList := make(map[string]interface{}) + + if v, ok := d.GetOk("payment_type"); ok { + nodeGroupsDataList["ChargeType"] = v + } + + if v, ok := d.GetOk("hostname"); ok { + nodeGroupsDataList["Hostnames"] = v + } + + if v, ok := d.GetOk("vswitch_id"); ok { + nodeGroupsDataList["VSwitchId"] = v + } + + if v, ok := d.GetOk("node_group_id"); ok { + nodeGroupsDataList["NodeGroupId"] = v + } + + nodeGroupsDataList["Amount"] = "1" + + if v, ok := d.GetOk("login_password"); ok { + nodeGroupsDataList["LoginPassword"] = v + } + + if v, ok := d.GetOk("user_data"); ok { + nodeGroupsDataList["UserData"] = v + } + + if v, ok := d.GetOk("vpc_id"); ok { + nodeGroupsDataList["VpcId"] = v + } + + if v, ok := d.GetOk("zone"); ok { + nodeGroupsDataList["ZoneId"] = v + } + + NodeGroupsMap := make([]interface{}, 0) + NodeGroupsMap = append(NodeGroupsMap, nodeGroupsDataList) + nodeGroupsDataListJson, err := json.Marshal(NodeGroupsMap) + if err != nil { + return WrapError(err) + } + request["NodeGroups"] = string(nodeGroupsDataListJson) + + if v, ok := d.GetOk("cluster_id"); ok { + request["ClusterId"] = v + } + + wait := incrementalWait(3*time.Second, 5*time.Second) + err = resource.Retry(d.Timeout(schema.TimeoutCreate), func() *resource.RetryError { + response, err = client.RpcPost("eflo-controller", "2022-12-15", action, query, request, true) + if err != nil { + if NeedRetry(err) { + wait() + return resource.RetryableError(err) + } + return resource.NonRetryableError(err) + } + return nil + }) + addDebug(action, response, request) + + if err != nil { + return WrapErrorf(err, DefaultErrorMsg, "alicloud_eflo_node", action, AlibabaCloudSdkGoERROR) + } + + efloServiceV2 := EfloServiceV2{client} + stateConf := BuildStateConf([]string{}, []string{"Using"}, d.Timeout(schema.TimeoutCreate), 5*time.Minute, efloServiceV2.EfloNodeStateRefreshFunc(d.Id(), "OperatingState", []string{})) + if _, err := stateConf.WaitForState(); err != nil { + return WrapErrorf(err, IdMsg, d.Id()) + } - efloServiceV2 := EfloServiceV2{client} - stateConf := BuildStateConf([]string{}, []string{"Unused"}, d.Timeout(schema.TimeoutCreate), 5*time.Second, efloServiceV2.EfloNodeStateRefreshFunc(d.Id(), "OperatingState", []string{})) - if _, err := stateConf.WaitForState(); err != nil { - return WrapErrorf(err, IdMsg, d.Id()) } return resourceAliCloudEfloNodeUpdate(d, meta) @@ -330,12 +650,17 @@ func resourceAliCloudEfloNodeRead(d *schema.ResourceData, meta interface{}) erro return WrapError(err) } + d.Set("cluster_id", objectRaw["ClusterId"]) d.Set("computing_server", objectRaw["MachineType"]) d.Set("create_time", objectRaw["CreateTime"]) + d.Set("hostname", objectRaw["Hostname"]) d.Set("hpn_zone", objectRaw["HpnZone"]) d.Set("machine_type", objectRaw["MachineType"]) + d.Set("node_group_id", objectRaw["NodeGroupId"]) + d.Set("node_type", objectRaw["NodeType"]) d.Set("resource_group_id", objectRaw["ResourceGroupId"]) d.Set("status", objectRaw["OperatingState"]) + d.Set("user_data", objectRaw["UserData"]) d.Set("zone", objectRaw["ZoneId"]) objectRaw, err = efloServiceV2.DescribeNodeListTagResources(d.Id()) @@ -360,6 +685,14 @@ func resourceAliCloudEfloNodeRead(d *schema.ResourceData, meta interface{}) erro } d.Set("renewal_status", objectRaw["RenewStatus"]) + objectRaw, err = efloServiceV2.DescribeNodeListClusterNodes(d.Id()) + if err != nil && !NotFoundError(err) { + return WrapError(err) + } + + d.Set("vswitch_id", objectRaw["VSwitchId"]) + d.Set("vpc_id", objectRaw["VpcId"]) + return nil } @@ -382,6 +715,7 @@ func resourceAliCloudEfloNodeUpdate(d *schema.ResourceData, meta interface{}) er } request["ResourceGroupId"] = d.Get("resource_group_id") request["ResourceType"] = "Node" + if update { wait := incrementalWait(3*time.Second, 5*time.Second) err = resource.Retry(d.Timeout(schema.TimeoutUpdate), func() *resource.RetryError { @@ -509,6 +843,43 @@ func resourceAliCloudEfloNodeUpdate(d *schema.ResourceData, meta interface{}) er return WrapErrorf(err, DefaultErrorMsg, d.Id(), action, AlibabaCloudSdkGoERROR) } } + update = false + action = "ChangeNodeTypes" + request = make(map[string]interface{}) + query = make(map[string]interface{}) + request["RegionId"] = client.RegionId + if d.HasChange("node_type") { + update = true + request["NodeType"] = d.Get("node_type") + } + + jsonString := convertObjectToJsonString(request) + jsonString, _ = sjson.Set(jsonString, "NodeIds.0", d.Id()) + _ = json.Unmarshal([]byte(jsonString), &request) + + if update { + wait := incrementalWait(3*time.Second, 5*time.Second) + err = resource.Retry(d.Timeout(schema.TimeoutUpdate), func() *resource.RetryError { + response, err = client.RpcPost("eflo-controller", "2022-12-15", action, query, request, true) + if err != nil { + if NeedRetry(err) { + wait() + return resource.RetryableError(err) + } + return resource.NonRetryableError(err) + } + return nil + }) + addDebug(action, response, request) + if err != nil { + return WrapErrorf(err, DefaultErrorMsg, d.Id(), action, AlibabaCloudSdkGoERROR) + } + efloServiceV2 := EfloServiceV2{client} + stateConf := BuildStateConf([]string{}, []string{"Using"}, d.Timeout(schema.TimeoutUpdate), 5*time.Minute, efloServiceV2.EfloNodeStateRefreshFunc(d.Id(), "OperatingState", []string{})) + if _, err := stateConf.WaitForState(); err != nil { + return WrapErrorf(err, IdMsg, d.Id()) + } + } if d.HasChange("tags") { efloServiceV2 := EfloServiceV2{client} @@ -516,23 +887,228 @@ func resourceAliCloudEfloNodeUpdate(d *schema.ResourceData, meta interface{}) er return WrapError(err) } } + if !d.IsNewResource() && d.HasChange("node_group_id") { + oldEntry, newEntry := d.GetChange("node_group_id") + oldValue := oldEntry.(string) + newValue := newEntry.(string) + + if oldValue != "" { + action := "ShrinkCluster" + request = make(map[string]interface{}) + query = make(map[string]interface{}) + request["RegionId"] = client.RegionId + if v, ok := d.GetOk("cluster_id"); ok { + request["ClusterId"] = v + } + nodeGroupsDataList := make(map[string]interface{}) + + if v, ok := d.GetOk("node_group_id"); ok { + nodeGroupsDataList["NodeGroupId"] = v + } + + NodeGroupsMap := make([]interface{}, 0) + NodeGroupsMap = append(NodeGroupsMap, nodeGroupsDataList) + nodeGroupsDataListJson, err := json.Marshal(NodeGroupsMap) + if err != nil { + return WrapError(err) + } + request["NodeGroups"] = string(nodeGroupsDataListJson) + + jsonString := convertObjectToJsonString(request) + jsonString, _ = sjson.Set(jsonString, "NodeGroups.0.Nodes.0.NodeId", d.Id()) + _ = json.Unmarshal([]byte(jsonString), &request) + + wait := incrementalWait(3*time.Second, 5*time.Second) + err = resource.Retry(d.Timeout(schema.TimeoutUpdate), func() *resource.RetryError { + response, err = client.RpcPost("eflo-controller", "2022-12-15", action, query, request, true) + if err != nil { + if NeedRetry(err) { + wait() + return resource.RetryableError(err) + } + return resource.NonRetryableError(err) + } + return nil + }) + addDebug(action, response, request) + if err != nil { + return WrapErrorf(err, DefaultErrorMsg, d.Id(), action, AlibabaCloudSdkGoERROR) + } + efloServiceV2 := EfloServiceV2{client} + stateConf := BuildStateConf([]string{}, []string{"Unused"}, d.Timeout(schema.TimeoutUpdate), 5*time.Minute, efloServiceV2.EfloNodeStateRefreshFunc(d.Id(), "OperatingState", []string{})) + if _, err := stateConf.WaitForState(); err != nil { + return WrapErrorf(err, IdMsg, d.Id()) + } + + } + + if newValue != "" { + action := "ExtendCluster" + request = make(map[string]interface{}) + query = make(map[string]interface{}) + request["RegionId"] = client.RegionId + if v, ok := d.GetOk("cluster_id"); ok { + request["ClusterId"] = v + } + nodeGroupsDataList := make(map[string]interface{}) + + if v, ok := d.GetOk("node_group_id"); ok { + nodeGroupsDataList["NodeGroupId"] = v + } + + NodeGroupsMap := make([]interface{}, 0) + NodeGroupsMap = append(NodeGroupsMap, nodeGroupsDataList) + nodeGroupsDataListJson, err := json.Marshal(NodeGroupsMap) + if err != nil { + return WrapError(err) + } + request["NodeGroups"] = string(nodeGroupsDataListJson) + + jsonString := convertObjectToJsonString(request) + jsonString, _ = sjson.Set(jsonString, "NodeGroups.0.Nodes.0.NodeId", d.Id()) + _ = json.Unmarshal([]byte(jsonString), &request) + + wait := incrementalWait(3*time.Second, 5*time.Second) + err = resource.Retry(d.Timeout(schema.TimeoutUpdate), func() *resource.RetryError { + response, err = client.RpcPost("eflo-controller", "2022-12-15", action, query, request, true) + if err != nil { + if NeedRetry(err) { + wait() + return resource.RetryableError(err) + } + return resource.NonRetryableError(err) + } + return nil + }) + addDebug(action, response, request) + if err != nil { + return WrapErrorf(err, DefaultErrorMsg, d.Id(), action, AlibabaCloudSdkGoERROR) + } + efloServiceV2 := EfloServiceV2{client} + stateConf := BuildStateConf([]string{}, []string{"Using"}, d.Timeout(schema.TimeoutUpdate), 5*time.Minute, efloServiceV2.EfloNodeStateRefreshFunc(d.Id(), "OperatingState", []string{})) + if _, err := stateConf.WaitForState(); err != nil { + return WrapErrorf(err, IdMsg, d.Id()) + } + + } + } + if !d.IsNewResource() && d.HasChange("cluster_id") { + oldEntry, newEntry := d.GetChange("cluster_id") + oldValue := oldEntry.(string) + newValue := newEntry.(string) + + if oldValue != "" { + action := "ShrinkCluster" + request = make(map[string]interface{}) + query = make(map[string]interface{}) + request["RegionId"] = client.RegionId + request["ClusterId"] = oldValue + + nodeGroupsDataList := make(map[string]interface{}) + + if v, ok := d.GetOk("node_group_id"); ok { + nodeGroupsDataList["NodeGroupId"] = v + } + + NodeGroupsMap := make([]interface{}, 0) + NodeGroupsMap = append(NodeGroupsMap, nodeGroupsDataList) + nodeGroupsDataListJson, err := json.Marshal(NodeGroupsMap) + if err != nil { + return WrapError(err) + } + request["NodeGroups"] = string(nodeGroupsDataListJson) + + jsonString := convertObjectToJsonString(request) + jsonString, _ = sjson.Set(jsonString, "NodeGroups.0.Nodes.0.NodeId", d.Id()) + _ = json.Unmarshal([]byte(jsonString), &request) + + wait := incrementalWait(3*time.Second, 5*time.Second) + err = resource.Retry(d.Timeout(schema.TimeoutUpdate), func() *resource.RetryError { + response, err = client.RpcPost("eflo-controller", "2022-12-15", action, query, request, true) + if err != nil { + if NeedRetry(err) { + wait() + return resource.RetryableError(err) + } + return resource.NonRetryableError(err) + } + return nil + }) + addDebug(action, response, request) + if err != nil { + return WrapErrorf(err, DefaultErrorMsg, d.Id(), action, AlibabaCloudSdkGoERROR) + } + efloServiceV2 := EfloServiceV2{client} + stateConf := BuildStateConf([]string{}, []string{"Unused"}, d.Timeout(schema.TimeoutUpdate), 5*time.Minute, efloServiceV2.EfloNodeStateRefreshFunc(d.Id(), "OperatingState", []string{})) + if _, err := stateConf.WaitForState(); err != nil { + return WrapErrorf(err, IdMsg, d.Id()) + } + + } + + if newValue != "" { + action := "ExtendCluster" + request = make(map[string]interface{}) + query = make(map[string]interface{}) + request["RegionId"] = client.RegionId + request["ClusterId"] = newValue + + nodeGroupsDataList := make(map[string]interface{}) + + if v, ok := d.GetOk("node_group_id"); ok { + nodeGroupsDataList["NodeGroupId"] = v + } + + NodeGroupsMap := make([]interface{}, 0) + NodeGroupsMap = append(NodeGroupsMap, nodeGroupsDataList) + nodeGroupsDataListJson, err := json.Marshal(NodeGroupsMap) + if err != nil { + return WrapError(err) + } + request["NodeGroups"] = string(nodeGroupsDataListJson) + + jsonString := convertObjectToJsonString(request) + jsonString, _ = sjson.Set(jsonString, "NodeGroups.0.Nodes.0.NodeId", d.Id()) + _ = json.Unmarshal([]byte(jsonString), &request) + + wait := incrementalWait(3*time.Second, 5*time.Second) + err = resource.Retry(d.Timeout(schema.TimeoutUpdate), func() *resource.RetryError { + response, err = client.RpcPost("eflo-controller", "2022-12-15", action, query, request, true) + if err != nil { + if NeedRetry(err) { + wait() + return resource.RetryableError(err) + } + return resource.NonRetryableError(err) + } + return nil + }) + addDebug(action, response, request) + if err != nil { + return WrapErrorf(err, DefaultErrorMsg, d.Id(), action, AlibabaCloudSdkGoERROR) + } + efloServiceV2 := EfloServiceV2{client} + stateConf := BuildStateConf([]string{}, []string{"Using"}, d.Timeout(schema.TimeoutUpdate), 5*time.Minute, efloServiceV2.EfloNodeStateRefreshFunc(d.Id(), "OperatingState", []string{})) + if _, err := stateConf.WaitForState(); err != nil { + return WrapErrorf(err, IdMsg, d.Id()) + } + + } + } d.Partial(false) return resourceAliCloudEfloNodeRead(d, meta) } func resourceAliCloudEfloNodeDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*connectivity.AliyunClient) enableDelete := false - if _, ok := d.GetOk("payment_type"); !ok { - enableDelete = true - } - if v, ok := d.GetOk("payment_type"); ok { + if v, ok := d.GetOkExists("payment_type"); ok { if InArray(fmt.Sprint(v), []string{"Subscription"}) { enableDelete = true } } if enableDelete { - client := meta.(*connectivity.AliyunClient) action := "RefundInstance" var request map[string]interface{} var response map[string]interface{} @@ -626,7 +1202,7 @@ func resourceAliCloudEfloNodeDelete(d *schema.ResourceData, meta interface{}) er } efloServiceV2 := EfloServiceV2{client} - stateConf := BuildStateConf([]string{}, []string{}, d.Timeout(schema.TimeoutDelete), 5*time.Second, efloServiceV2.EfloNodeStateRefreshFunc(d.Id(), "$.NodeId", []string{})) + stateConf := BuildStateConf([]string{}, []string{""}, d.Timeout(schema.TimeoutDelete), 5*time.Second, efloServiceV2.EfloNodeStateRefreshFunc(d.Id(), "$.NodeId", []string{})) if _, err := stateConf.WaitForState(); err != nil { return WrapErrorf(err, IdMsg, d.Id()) } @@ -634,13 +1210,12 @@ func resourceAliCloudEfloNodeDelete(d *schema.ResourceData, meta interface{}) er } enableDelete = false - if v, ok := d.GetOk("payment_type"); ok { + if v, ok := d.GetOkExists("payment_type"); ok { if InArray(fmt.Sprint(v), []string{"PayAsYouGo"}) { enableDelete = true } } if enableDelete { - client := meta.(*connectivity.AliyunClient) action := "DeleteNode" var request map[string]interface{} var response map[string]interface{} @@ -672,7 +1247,7 @@ func resourceAliCloudEfloNodeDelete(d *schema.ResourceData, meta interface{}) er } efloServiceV2 := EfloServiceV2{client} - stateConf := BuildStateConf([]string{}, []string{}, d.Timeout(schema.TimeoutDelete), 5*time.Second, efloServiceV2.EfloNodeStateRefreshFunc(d.Id(), "$.NodeId", []string{})) + stateConf := BuildStateConf([]string{}, []string{""}, d.Timeout(schema.TimeoutDelete), 5*time.Second, efloServiceV2.EfloNodeStateRefreshFunc(d.Id(), "$.NodeId", []string{})) if _, err := stateConf.WaitForState(); err != nil { return WrapErrorf(err, IdMsg, d.Id()) } @@ -735,3 +1310,14 @@ func isInstallPai(instanceId string, timeout time.Duration, client *connectivity } return productCode == "learn", nil } + +func convertEfloNodeNodeGroupsArrayChargeTypeRequest(source interface{}) interface{} { + source = fmt.Sprint(source) + switch source { + case "Subscription": + return "PREPAY" + case "PayAsYouGo": + return "POSTPAY" + } + return source +} diff --git a/alicloud/resource_alicloud_eflo_node_test.go b/alicloud/resource_alicloud_eflo_node_test.go index 4f31290f70c7..3888aed9090f 100644 --- a/alicloud/resource_alicloud_eflo_node_test.go +++ b/alicloud/resource_alicloud_eflo_node_test.go @@ -149,7 +149,7 @@ func TestAccAliCloudEfloNode_basic11276(t *testing.T) { testAccConfig := resourceTestAccConfigFunc(resourceId, name, AlicloudEfloNodeBasicDependence11276) resource.Test(t, resource.TestCase{ PreCheck: func() { - testAccPreCheckWithRegions(t, true, []connectivity.Region{"cn-wulanchabu"}) + testAccPreCheckWithRegions(t, true, []connectivity.Region{"cn-hangzhou"}) testAccPreCheck(t) }, IDRefreshName: resourceId, @@ -173,13 +173,11 @@ func TestAccAliCloudEfloNode_basic11276(t *testing.T) { "renewal_status": "AutoRenewal", "renew_period": "36", "status": "Unused", - "install_pai": "true", }), Check: resource.ComposeTestCheckFunc( testAccCheck(map[string]string{ "resource_group_id": CHECKSET, "period": "36", - "product_type": "learn_eflocomputing_public_intl", "discount_level": CHECKSET, "billing_cycle": "1month", "classify": "gpuserver", @@ -252,7 +250,7 @@ func TestAccAliCloudEfloNode_basic11276(t *testing.T) { ResourceName: resourceId, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"billing_cycle", "classify", "computing_server", "discount_level", "hpn_zone", "payment_ratio", "period", "product_form", "renew_period", "renewal_status", "server_arch", "stage_num", "zone", "install_pai"}, + ImportStateVerifyIgnore: []string{"billing_cycle", "classify", "discount_level", "login_password", "payment_ratio", "period", "product_form", "server_arch", "stage_num"}, }, }, }) @@ -260,6 +258,7 @@ func TestAccAliCloudEfloNode_basic11276(t *testing.T) { var AlicloudEfloNodeMap11276 = map[string]string{ "create_time": CHECKSET, + "region_id": CHECKSET, } func AlicloudEfloNodeBasicDependence11276(name string) string { @@ -289,7 +288,7 @@ func TestAccAliCloudEfloNode_basic11280(t *testing.T) { testAccConfig := resourceTestAccConfigFunc(resourceId, name, AlicloudEfloNodeBasicDependence11280) resource.Test(t, resource.TestCase{ PreCheck: func() { - testAccPreCheckWithRegions(t, true, []connectivity.Region{"cn-wulanchabu"}) + testAccPreCheckWithRegions(t, true, []connectivity.Region{"cn-hangzhou"}) testAccPreCheck(t) }, IDRefreshName: resourceId, @@ -390,7 +389,7 @@ func TestAccAliCloudEfloNode_basic11280(t *testing.T) { ResourceName: resourceId, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"billing_cycle", "classify", "computing_server", "discount_level", "hpn_zone", "payment_ratio", "period", "product_form", "renew_period", "renewal_status", "server_arch", "stage_num", "zone", "install_pai"}, + ImportStateVerifyIgnore: []string{"billing_cycle", "classify", "discount_level", "login_password", "payment_ratio", "period", "product_form", "server_arch", "stage_num"}, }, }, }) @@ -398,6 +397,7 @@ func TestAccAliCloudEfloNode_basic11280(t *testing.T) { var AlicloudEfloNodeMap11280 = map[string]string{ "create_time": CHECKSET, + "region_id": CHECKSET, } func AlicloudEfloNodeBasicDependence11280(name string) string { @@ -427,7 +427,7 @@ func TestAccAliCloudEfloNode_basic11275(t *testing.T) { testAccConfig := resourceTestAccConfigFunc(resourceId, name, AlicloudEfloNodeBasicDependence11275) resource.Test(t, resource.TestCase{ PreCheck: func() { - testAccPreCheckWithRegions(t, true, []connectivity.Region{"cn-wulanchabu"}) + testAccPreCheckWithRegions(t, true, []connectivity.Region{"cn-hangzhou"}) testAccPreCheck(t) }, IDRefreshName: resourceId, @@ -439,7 +439,7 @@ func TestAccAliCloudEfloNode_basic11275(t *testing.T) { "resource_group_id": "${data.alicloud_resource_manager_resource_groups.default.ids.0}", "period": "36", "discount_level": "36", - "billing_cycle": "1month", + "billing_cycle": "1m", "classify": "gpuserver", "zone": "cn-wulanchabu-a", "product_form": "instance", @@ -451,14 +451,13 @@ func TestAccAliCloudEfloNode_basic11275(t *testing.T) { "renewal_status": "AutoRenewal", "renew_period": "36", "status": "Unused", - "install_pai": "true", }), Check: resource.ComposeTestCheckFunc( testAccCheck(map[string]string{ "resource_group_id": CHECKSET, "period": "36", "discount_level": CHECKSET, - "billing_cycle": "1month", + "billing_cycle": "1m", "classify": "gpuserver", "zone": "cn-wulanchabu-a", "product_form": "instance", @@ -529,7 +528,7 @@ func TestAccAliCloudEfloNode_basic11275(t *testing.T) { ResourceName: resourceId, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"billing_cycle", "classify", "computing_server", "discount_level", "hpn_zone", "payment_ratio", "period", "product_form", "renew_period", "renewal_status", "server_arch", "stage_num", "zone", "install_pai"}, + ImportStateVerifyIgnore: []string{"billing_cycle", "classify", "discount_level", "login_password", "payment_ratio", "period", "product_form", "server_arch", "stage_num"}, }, }, }) @@ -537,6 +536,7 @@ func TestAccAliCloudEfloNode_basic11275(t *testing.T) { var AlicloudEfloNodeMap11275 = map[string]string{ "create_time": CHECKSET, + "region_id": CHECKSET, } func AlicloudEfloNodeBasicDependence11275(name string) string { @@ -566,7 +566,7 @@ func TestAccAliCloudEfloNode_basic11278(t *testing.T) { testAccConfig := resourceTestAccConfigFunc(resourceId, name, AlicloudEfloNodeBasicDependence11278) resource.Test(t, resource.TestCase{ PreCheck: func() { - testAccPreCheckWithRegions(t, true, []connectivity.Region{"cn-wulanchabu"}) + testAccPreCheckWithRegions(t, true, []connectivity.Region{"cn-hangzhou"}) testAccPreCheck(t) }, IDRefreshName: resourceId, @@ -667,7 +667,7 @@ func TestAccAliCloudEfloNode_basic11278(t *testing.T) { ResourceName: resourceId, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"billing_cycle", "classify", "computing_server", "discount_level", "hpn_zone", "payment_ratio", "period", "product_form", "renew_period", "renewal_status", "server_arch", "stage_num", "zone", "install_pai"}, + ImportStateVerifyIgnore: []string{"billing_cycle", "classify", "discount_level", "login_password", "payment_ratio", "period", "product_form", "server_arch", "stage_num"}, }, }, }) @@ -675,6 +675,7 @@ func TestAccAliCloudEfloNode_basic11278(t *testing.T) { var AlicloudEfloNodeMap11278 = map[string]string{ "create_time": CHECKSET, + "region_id": CHECKSET, } func AlicloudEfloNodeBasicDependence11278(name string) string { diff --git a/alicloud/service_alicloud_eflo_v2.go b/alicloud/service_alicloud_eflo_v2.go index 8267fe2afc22..3283b0230484 100644 --- a/alicloud/service_alicloud_eflo_v2.go +++ b/alicloud/service_alicloud_eflo_v2.go @@ -84,17 +84,18 @@ func (s *EfloServiceV2) DescribeNodeListTagResources(id string) (object map[stri return response, nil } func (s *EfloServiceV2) DescribeNodeQueryAvailableInstances(d *schema.ResourceData) (object map[string]interface{}, err error) { + + installPai := false + if v, ok := d.GetOk("install_pai"); ok && v.(bool) { + installPai = true + } client := s.client + id := d.Id() var request map[string]interface{} var response map[string]interface{} var query map[string]interface{} request = make(map[string]interface{}) query = make(map[string]interface{}) - id := d.Id() - installPai := false - if v, ok := d.GetOk("install_pai"); ok && v.(bool) { - installPai = true - } request["InstanceIDs"] = id request["Region"] = client.RegionId var endpoint string @@ -174,6 +175,45 @@ func (s *EfloServiceV2) DescribeNodeQueryAvailableInstances(d *schema.ResourceDa return v.([]interface{})[0].(map[string]interface{}), nil } +func (s *EfloServiceV2) DescribeNodeListClusterNodes(id string) (object map[string]interface{}, err error) { + client := s.client + var request map[string]interface{} + var response map[string]interface{} + var query map[string]interface{} + request = make(map[string]interface{}) + query = make(map[string]interface{}) + request["RegionId"] = client.RegionId + action := "ListClusterNodes" + + wait := incrementalWait(3*time.Second, 5*time.Second) + err = resource.Retry(1*time.Minute, func() *resource.RetryError { + response, err = client.RpcPost("eflo-controller", "2022-12-15", action, query, request, true) + + if err != nil { + if NeedRetry(err) { + wait() + return resource.RetryableError(err) + } + return resource.NonRetryableError(err) + } + return nil + }) + addDebug(action, response, request) + if err != nil { + return object, WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR) + } + + v, err := jsonpath.Get("$.Nodes[*]", response) + if err != nil { + return object, WrapErrorf(err, FailedGetAttributeMsg, id, "$.Nodes[*]", response) + } + + if len(v.([]interface{})) == 0 { + return object, WrapErrorf(NotFoundErr("Node", id), NotFoundMsg, response) + } + + return v.([]interface{})[0].(map[string]interface{}), nil +} func (s *EfloServiceV2) EfloNodeStateRefreshFunc(id string, field string, failStates []string) resource.StateRefreshFunc { return s.EfloNodeStateRefreshFuncWithApi(id, field, failStates, s.DescribeEfloNode) @@ -184,7 +224,7 @@ func (s *EfloServiceV2) EfloNodeStateRefreshFuncWithApi(id string, field string, object, err := call(id) if err != nil { if NotFoundError(err) { - return nil, "", nil + return object, "", nil } return nil, "", WrapError(err) } diff --git a/website/docs/r/eflo_node.html.markdown b/website/docs/r/eflo_node.html.markdown index 71eff0194297..6b6d051bd848 100644 --- a/website/docs/r/eflo_node.html.markdown +++ b/website/docs/r/eflo_node.html.markdown @@ -20,12 +20,6 @@ For information about Eflo Node and how to use it, see [What is Node](https://ne Basic Usage -
- ```terraform # Before executing this example, you need to confirm with the product team whether the resources are sufficient or you will get an error message with "Failure to check order before create instance" variable "name" { @@ -56,22 +50,52 @@ resource "alicloud_eflo_node" "default" { } ``` +### Deleting `alicloud_eflo_node` or removing it from your configuration + +The `alicloud_eflo_node` resource allows you to manage `payment_type = "Subscription"` instance, but Terraform cannot destroy it. +Deleting the subscription resource or removing it from your configuration will remove it from your state file and management, but will not destroy the Instance. +You can resume managing the subscription instance via the AlibabaCloud Console. + ## Argument Reference The following arguments are supported: * `install_pai` - (Optional) Whether to buy PAI. default value `false`. * `billing_cycle` - (Optional) Billing cycle + +-> **NOTE:** The parameter is immutable after resource creation. It only applies during resource creation and has no effect when modified post-creation. + * `classify` - (Optional) Classification -* `computing_server` - (Optional, Deprecated since v1.261.0) Node Model. Field 'computing_server' has been deprecated from provider version 1.261.0. New field 'machine_type' instead. + +-> **NOTE:** The parameter is immutable after resource creation. It only applies during resource creation and has no effect when modified post-creation. + +* `cluster_id` - (Optional, Available since v1.264.0) Cluster id +* `computing_server` - (Optional, ForceNew, Computed, Deprecated since v1.264.0) Node Model * `discount_level` - (Optional) Offer Information + +-> **NOTE:** The parameter is immutable after resource creation. It only applies during resource creation and has no effect when modified post-creation. + +* `hostname` - (Optional, ForceNew, Available since v1.264.0) Host name * `hpn_zone` - (Optional, ForceNew) Cluster Number -* `machine_type` - (Optional, ForceNew, Available since v1.261.0) Model +* `ip_allocation_policy` - (Optional, ForceNew, List, Available since v1.264.0) IP address combination policy: only one policy type can be selected for each policy, and multiple policies can be combined. See [`ip_allocation_policy`](#ip_allocation_policy) below. +* `login_password` - (Optional, ForceNew, Available since v1.264.0) Login Password +* `machine_type` - (Optional, ForceNew, Computed, Available since v1.261.0) Model +* `node_group_id` - (Optional, Available since v1.264.0) node group id +* `node_type` - (Optional, Computed, Available since v1.264.0) node type * `payment_ratio` - (Optional) Down payment ratio + +-> **NOTE:** The parameter is immutable after resource creation. It only applies during resource creation and has no effect when modified post-creation. + * `payment_type` - (Optional, ForceNew, Computed, Available since v1.261.0) The payment method of the node. Value range: Subscription: fixed fee installment; PayAsYouGo: pay by volume. The default is Subscription. * `period` - (Optional, Int) Prepaid cycle. The unit is Month, please enter an integer multiple of 12 for the annual payment product. + +-> **NOTE:** The parameter is immutable after resource creation. It only applies during resource creation and has no effect when modified post-creation. + * `product_form` - (Optional) Form + +-> **NOTE:** The parameter is immutable after resource creation. It only applies during resource creation and has no effect when modified post-creation. + * `renew_period` - (Optional, Int) Automatic renewal period, in months. -> **NOTE:** When setting `RenewalStatus` to `AutoRenewal`, it must be set. @@ -83,11 +107,64 @@ The default is Subscription. The default ManualRenewal. * `resource_group_id` - (Optional, Computed) The ID of the resource group * `server_arch` - (Optional) Architecture + +-> **NOTE:** The parameter is immutable after resource creation. It only applies during resource creation and has no effect when modified post-creation. + * `stage_num` - (Optional) Number of stages + +-> **NOTE:** The parameter is immutable after resource creation. It only applies during resource creation and has no effect when modified post-creation. + * `status` - (Optional, Computed) The status of the resource * `tags` - (Optional, Map) The tag of the resource +* `user_data` - (Optional, ForceNew, Available since v1.264.0) Custom Data +* `vswitch_id` - (Optional, ForceNew, Available since v1.264.0) Switch ID +* `vpc_id` - (Optional, ForceNew, Available since v1.264.0) VPC ID * `zone` - (Optional, ForceNew) Availability Zone +### `ip_allocation_policy` + +The ip_allocation_policy supports the following: +* `bond_policy` - (Optional, ForceNew, List, Available since v1.264.0) Specify the cluster subnet ID based on the bond name See [`bond_policy`](#ip_allocation_policy-bond_policy) below. +* `machine_type_policy` - (Optional, ForceNew, List, Available since v1.264.0) Model Assignment Policy See [`machine_type_policy`](#ip_allocation_policy-machine_type_policy) below. +* `node_policy` - (Optional, ForceNew, List, Available since v1.264.0) Node allocation policy See [`node_policy`](#ip_allocation_policy-node_policy) below. + +### `ip_allocation_policy-bond_policy` + +The ip_allocation_policy-bond_policy supports the following: +* `bond_default_subnet` - (Optional, ForceNew, Available since v1.264.0) Default bond cluster subnet +* `bonds` - (Optional, ForceNew, List, Available since v1.264.0) Bond information See [`bonds`](#ip_allocation_policy-bond_policy-bonds) below. + +### `ip_allocation_policy-machine_type_policy` + +The ip_allocation_policy-machine_type_policy supports the following: +* `bonds` - (Optional, ForceNew, List, Available since v1.264.0) Bond information See [`bonds`](#ip_allocation_policy-machine_type_policy-bonds) below. +* `machine_type` - (Optional, ForceNew, Available since v1.264.0) Model + +### `ip_allocation_policy-node_policy` + +The ip_allocation_policy-node_policy supports the following: +* `bonds` - (Optional, ForceNew, List, Available since v1.264.0) Bond information See [`bonds`](#ip_allocation_policy-node_policy-bonds) below. +* `hostname` - (Optional, ForceNew, Available since v1.264.0) Host name +* `node_id` - (Optional, ForceNew, Available since v1.264.0) Node ID + +### `ip_allocation_policy-node_policy-bonds` + +The ip_allocation_policy-node_policy-bonds supports the following: +* `name` - (Optional, ForceNew, Available since v1.264.0) Bond Name +* `subnet` - (Optional, ForceNew, Available since v1.264.0) IP source cluster subnet + +### `ip_allocation_policy-machine_type_policy-bonds` + +The ip_allocation_policy-machine_type_policy-bonds supports the following: +* `name` - (Optional, ForceNew, Available since v1.264.0) Bond Name +* `subnet` - (Optional, ForceNew, Available since v1.264.0) IP source cluster subnet + +### `ip_allocation_policy-bond_policy-bonds` + +The ip_allocation_policy-bond_policy-bonds supports the following: +* `name` - (Optional, ForceNew, Available since v1.264.0) Bond Name +* `subnet` - (Optional, ForceNew, Available since v1.264.0) IP source cluster subnet + ## Attributes Reference The following attributes are exported: @@ -100,7 +177,7 @@ The following attributes are exported: The `timeouts` block allows you to specify [timeouts](https://developer.hashicorp.com/terraform/language/resources/syntax#operation-timeouts) for certain actions: * `create` - (Defaults to 10 mins) Used when create the Node. * `delete` - (Defaults to 5 mins) Used when delete the Node. -* `update` - (Defaults to 5 mins) Used when update the Node. +* `update` - (Defaults to 6 mins) Used when update the Node. ## Import