From abca28b42f0e33052498b9806209d855869afcea Mon Sep 17 00:00:00 2001 From: chenhanzhang Date: Wed, 19 Mar 2025 14:45:20 +0800 Subject: [PATCH] New Resource: alicloud_eflo_cluster; New Resource: alicloud_eflo_node; New Resource: alicloud_eflo_node_group; New Resource: alicloud_eflo_invocation. --- alicloud/connectivity/endpoint.go | 1 + alicloud/provider.go | 13 + alicloud/resource_alicloud_eflo_cluster.go | 787 ++++++++++++++++++ .../resource_alicloud_eflo_cluster_test.go | 327 ++++++++ alicloud/resource_alicloud_eflo_invocation.go | 249 ++++++ .../resource_alicloud_eflo_invocation_test.go | 91 ++ alicloud/resource_alicloud_eflo_node.go | 348 ++++++++ alicloud/resource_alicloud_eflo_node_group.go | 687 +++++++++++++++ .../resource_alicloud_eflo_node_group_test.go | 162 ++++ alicloud/resource_alicloud_eflo_node_test.go | 100 +++ alicloud/service_alicloud_eflo_v2.go | 537 ++++++++++++ website/docs/r/eflo_cluster.html.markdown | 275 ++++++ website/docs/r/eflo_invocation.html.markdown | 290 +++++++ website/docs/r/eflo_node.html.markdown | 97 +++ website/docs/r/eflo_node_group.html.markdown | 280 +++++++ 15 files changed, 4244 insertions(+) create mode 100644 alicloud/resource_alicloud_eflo_cluster.go create mode 100644 alicloud/resource_alicloud_eflo_cluster_test.go create mode 100644 alicloud/resource_alicloud_eflo_invocation.go create mode 100644 alicloud/resource_alicloud_eflo_invocation_test.go create mode 100644 alicloud/resource_alicloud_eflo_node.go create mode 100644 alicloud/resource_alicloud_eflo_node_group.go create mode 100644 alicloud/resource_alicloud_eflo_node_group_test.go create mode 100644 alicloud/resource_alicloud_eflo_node_test.go create mode 100644 alicloud/service_alicloud_eflo_v2.go create mode 100644 website/docs/r/eflo_cluster.html.markdown create mode 100644 website/docs/r/eflo_invocation.html.markdown create mode 100644 website/docs/r/eflo_node.html.markdown create mode 100644 website/docs/r/eflo_node_group.html.markdown diff --git a/alicloud/connectivity/endpoint.go b/alicloud/connectivity/endpoint.go index beb230215cb7..76a24096be29 100644 --- a/alicloud/connectivity/endpoint.go +++ b/alicloud/connectivity/endpoint.go @@ -308,6 +308,7 @@ var productCodeToLocationCode = map[string]string{ "live": "live", // Live "eds_aic": "wycloudphone", // CloudPhone "cloudcontrol": "cloudcontrol", // CloudControl + "eflo_controller": "efloctrl", // Eflo } // irregularProductEndpoint specially records those product codes that diff --git a/alicloud/provider.go b/alicloud/provider.go index 39bdf5820419..9cb638f6fe88 100644 --- a/alicloud/provider.go +++ b/alicloud/provider.go @@ -896,6 +896,10 @@ func Provider() terraform.ResourceProvider { }, ResourcesMap: map[string]*schema.Resource{ "alicloud_resource_manager_auto_grouping_rule": resourceAliCloudResourceManagerAutoGroupingRule(), + "alicloud_eflo_invocation": resourceAliCloudEfloInvocation(), + "alicloud_eflo_cluster": resourceAliCloudEfloCluster(), + "alicloud_eflo_node_group": resourceAliCloudEfloNodeGroup(), + "alicloud_eflo_node": resourceAliCloudEfloNode(), "alicloud_oss_bucket_style": resourceAliCloudOssBucketStyle(), "alicloud_rocketmq_acl": resourceAliCloudRocketmqAcl(), "alicloud_rocketmq_account": resourceAliCloudRocketmqAccount(), @@ -2583,6 +2587,8 @@ func init() { "eflo_endpoint": "Use this to override the default endpoint URL constructed from the `region`. It's typically used to connect to custom eflo endpoints.", + "eflo_controller_endpoint": "Use this to override the default endpoint URL constructed from the `region`. It's typically used to connect to custom efloctrl endpoints.", + "oceanbase_endpoint": "Use this to override the default endpoint URL constructed from the `region`. It's typically used to connect to custom oceanbase endpoints.", "beebot_endpoint": "Use this to override the default endpoint URL constructed from the `region`. It's typically used to connect to custom beebot endpoints.", @@ -2738,6 +2744,13 @@ func endpointsSchema() *schema.Schema { Description: descriptions["eflo_endpoint"], }, + "eflo_controller": { + Type: schema.TypeString, + Optional: true, + Default: "", + Description: descriptions["eflo_controller_endpoint"], + }, + "srvcatalog": { Type: schema.TypeString, Optional: true, diff --git a/alicloud/resource_alicloud_eflo_cluster.go b/alicloud/resource_alicloud_eflo_cluster.go new file mode 100644 index 000000000000..cf98ac2bd9c0 --- /dev/null +++ b/alicloud/resource_alicloud_eflo_cluster.go @@ -0,0 +1,787 @@ +package alicloud + +import ( + "encoding/json" + "fmt" + "log" + "time" + + "github.com/PaesslerAG/jsonpath" + "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 resourceAliCloudEfloCluster() *schema.Resource { + return &schema.Resource{ + Create: resourceAliCloudEfloClusterCreate, + Read: resourceAliCloudEfloClusterRead, + Update: resourceAliCloudEfloClusterUpdate, + Delete: resourceAliCloudEfloClusterDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(5 * time.Minute), + Update: schema.DefaultTimeout(5 * time.Minute), + Delete: schema.DefaultTimeout(5 * time.Minute), + }, + Schema: map[string]*schema.Schema{ + "cluster_description": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "cluster_name": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "cluster_type": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "components": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "component_type": { + Type: schema.TypeString, + Optional: true, + }, + "component_config": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "basic_args": { + Type: schema.TypeString, + Optional: true, + }, + "node_units": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + }, + }, + }, + "create_time": { + Type: schema.TypeString, + Computed: true, + }, + "hpn_zone": { + Type: schema.TypeString, + Optional: true, + }, + "ignore_failed_node_tasks": { + Type: schema.TypeBool, + Optional: true, + }, + "networks": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "vpd_info": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "vpd_id": { + Type: schema.TypeString, + Optional: true, + }, + "vpd_subnets": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + "ip_allocation_policy": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "machine_type_policy": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "bonds": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "subnet": { + Type: schema.TypeString, + Optional: true, + }, + "name": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "machine_type": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "bond_policy": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "bonds": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "subnet": { + Type: schema.TypeString, + Optional: true, + }, + "name": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "bond_default_subnet": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "node_policy": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "bonds": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "subnet": { + Type: schema.TypeString, + Optional: true, + }, + "name": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "node_id": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + }, + }, + }, + "vpc_id": { + Type: schema.TypeString, + Optional: true, + }, + "security_group_id": { + Type: schema.TypeString, + Optional: true, + }, + "vswitch_id": { + Type: schema.TypeString, + Optional: true, + }, + "tail_ip_version": { + Type: schema.TypeString, + Optional: true, + }, + "vswitch_zone_id": { + Type: schema.TypeString, + Optional: true, + }, + "new_vpd_info": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cloud_link_cidr": { + Type: schema.TypeString, + Optional: true, + }, + "monitor_vpc_id": { + Type: schema.TypeString, + Optional: true, + }, + "cen_id": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: StringInSlice([]string{"11111"}, false), + }, + "vpd_cidr": { + Type: schema.TypeString, + Optional: true, + }, + "monitor_vswitch_id": { + Type: schema.TypeString, + Optional: true, + }, + "vpd_subnets": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "subnet_cidr": { + Type: schema.TypeString, + Optional: true, + }, + "zone_id": { + Type: schema.TypeString, + Optional: true, + }, + "subnet_type": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "cloud_link_id": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + }, + }, + }, + "nimiz_vswitches": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "node_groups": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "node_group_description": { + Type: schema.TypeString, + Optional: true, + }, + "node_group_name": { + Type: schema.TypeString, + Optional: true, + }, + "zone_id": { + Type: schema.TypeString, + Optional: true, + }, + "user_data": { + Type: schema.TypeString, + Optional: true, + }, + "machine_type": { + Type: schema.TypeString, + Optional: true, + }, + "image_id": { + Type: schema.TypeString, + Optional: true, + }, + "nodes": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "vpc_id": { + Type: schema.TypeString, + Optional: true, + }, + "vswitch_id": { + Type: schema.TypeString, + Optional: true, + }, + "node_id": { + Type: schema.TypeString, + Optional: true, + }, + "hostname": { + Type: schema.TypeString, + Optional: true, + }, + "login_password": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + }, + }, + }, + "open_eni_jumbo_frame": { + Type: schema.TypeBool, + Optional: true, + }, + "resource_group_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "status": { + Type: schema.TypeString, + Computed: true, + }, + "tags": tagsSchema(), + }, + } +} + +func resourceAliCloudEfloClusterCreate(d *schema.ResourceData, meta interface{}) error { + + client := meta.(*connectivity.AliyunClient) + + action := "CreateCluster" + 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 + + objectDataLocalMap := make(map[string]interface{}) + + if v := d.Get("networks"); !IsNil(v) { + vSwitchId1, _ := jsonpath.Get("$[0].vswitch_id", v) + if vSwitchId1 != nil && vSwitchId1 != "" { + objectDataLocalMap["VSwitchId"] = vSwitchId1 + } + if v, ok := d.GetOk("networks"); ok { + localData, err := jsonpath.Get("$[0].ip_allocation_policy", v) + if err != nil { + localData = make([]interface{}, 0) + } + localMaps := make([]interface{}, 0) + for _, dataLoop := range localData.([]interface{}) { + dataLoopTmp := make(map[string]interface{}) + if dataLoop != nil { + dataLoopTmp = dataLoop.(map[string]interface{}) + } + dataLoopMap := make(map[string]interface{}) + localData1 := make(map[string]interface{}) + bondDefaultSubnet1, _ := jsonpath.Get("$[0].bond_default_subnet", dataLoopTmp["bond_policy"]) + if bondDefaultSubnet1 != nil && bondDefaultSubnet1 != "" { + localData1["BondDefaultSubnet"] = bondDefaultSubnet1 + } + if v, ok := dataLoopTmp["bond_policy"]; ok { + localData2, err := jsonpath.Get("$[0].bonds", v) + if err != nil { + localData2 = make([]interface{}, 0) + } + localMaps2 := make([]interface{}, 0) + for _, dataLoop2 := range localData2.([]interface{}) { + 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"] + localMaps2 = append(localMaps2, dataLoop2Map) + } + localData1["Bonds"] = localMaps2 + } + + dataLoopMap["BondPolicy"] = localData1 + localMaps3 := make([]interface{}, 0) + localData3 := dataLoopTmp["node_policy"] + for _, dataLoop3 := range localData3.([]interface{}) { + dataLoop3Tmp := dataLoop3.(map[string]interface{}) + dataLoop3Map := make(map[string]interface{}) + dataLoop3Map["NodeId"] = dataLoop3Tmp["node_id"] + localData2, err := jsonpath.Get("$.bonds", dataLoop3Tmp) + if err != nil { + localData2 = make([]interface{}, 0) + } + localMaps2 := make([]interface{}, 0) + for _, dataLoop2 := range localData2.([]interface{}) { + 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"] + localMaps2 = append(localMaps2, dataLoop2Map) + } + dataLoop3Map["Bonds"] = localMaps2 + localMaps3 = append(localMaps3, dataLoop3Map) + } + dataLoopMap["NodePolicy"] = localMaps3 + localMaps5 := make([]interface{}, 0) + localData5 := dataLoopTmp["machine_type_policy"] + for _, dataLoop5 := range localData5.([]interface{}) { + dataLoop5Tmp := dataLoop5.(map[string]interface{}) + dataLoop5Map := make(map[string]interface{}) + dataLoop5Map["MachineType"] = dataLoop5Tmp["machine_type"] + localData2, err := jsonpath.Get("$.bonds", dataLoop5Tmp) + if err != nil { + localData2 = make([]interface{}, 0) + } + localMaps2 := make([]interface{}, 0) + for _, dataLoop2 := range localData2.([]interface{}) { + 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"] + localMaps2 = append(localMaps2, dataLoop2Map) + } + dataLoop5Map["Bonds"] = localMaps2 + localMaps5 = append(localMaps5, dataLoop5Map) + } + dataLoopMap["MachineTypePolicy"] = localMaps5 + localMaps = append(localMaps, dataLoopMap) + } + objectDataLocalMap["IpAllocationPolicy"] = localMaps + } + + vpcId1, _ := jsonpath.Get("$[0].vpc_id", v) + if vpcId1 != nil && vpcId1 != "" { + objectDataLocalMap["VpcId"] = vpcId1 + } + newVpdInfo := make(map[string]interface{}) + if v, ok := d.GetOk("networks"); ok { + localData7, err := jsonpath.Get("$[0].new_vpd_info[0].vpd_subnets", v) + if err != nil { + localData7 = make([]interface{}, 0) + } + localMaps7 := make([]interface{}, 0) + for _, dataLoop7 := range localData7.([]interface{}) { + dataLoop7Tmp := make(map[string]interface{}) + if dataLoop7 != nil { + dataLoop7Tmp = dataLoop7.(map[string]interface{}) + } + dataLoop7Map := make(map[string]interface{}) + dataLoop7Map["SubnetCidr"] = dataLoop7Tmp["subnet_cidr"] + dataLoop7Map["ZoneId"] = dataLoop7Tmp["zone_id"] + dataLoop7Map["SubnetType"] = dataLoop7Tmp["subnet_type"] + localMaps7 = append(localMaps7, dataLoop7Map) + } + newVpdInfo["VpdSubnets"] = localMaps7 + } + + cloudLinkId1, _ := jsonpath.Get("$[0].new_vpd_info[0].cloud_link_id", v) + if cloudLinkId1 != nil && cloudLinkId1 != "" { + newVpdInfo["CloudLinkId"] = cloudLinkId1 + } + cloudLinkCidr1, _ := jsonpath.Get("$[0].new_vpd_info[0].cloud_link_cidr", v) + if cloudLinkCidr1 != nil && cloudLinkCidr1 != "" { + newVpdInfo["CloudLinkCidr"] = cloudLinkCidr1 + } + monitorVswitchId1, _ := jsonpath.Get("$[0].new_vpd_info[0].monitor_vswitch_id", v) + if monitorVswitchId1 != nil && monitorVswitchId1 != "" { + newVpdInfo["MonitorVswitchId"] = monitorVswitchId1 + } + vpdCidr1, _ := jsonpath.Get("$[0].new_vpd_info[0].vpd_cidr", v) + if vpdCidr1 != nil && vpdCidr1 != "" { + newVpdInfo["VpdCidr"] = vpdCidr1 + } + cenId1, _ := jsonpath.Get("$[0].new_vpd_info[0].cen_id", v) + if cenId1 != nil && cenId1 != "" { + newVpdInfo["CenId"] = cenId1 + } + monitorVpcId1, _ := jsonpath.Get("$[0].new_vpd_info[0].monitor_vpc_id", v) + if monitorVpcId1 != nil && monitorVpcId1 != "" { + newVpdInfo["MonitorVpcId"] = monitorVpcId1 + } + + objectDataLocalMap["NewVpdInfo"] = newVpdInfo + securityGroupId1, _ := jsonpath.Get("$[0].security_group_id", v) + if securityGroupId1 != nil && securityGroupId1 != "" { + objectDataLocalMap["SecurityGroupId"] = securityGroupId1 + } + vpdInfo := make(map[string]interface{}) + vpdSubnets2, _ := jsonpath.Get("$[0].vpd_info[0].vpd_subnets", v) + if vpdSubnets2 != nil && vpdSubnets2 != "" { + vpdInfo["VpdSubnets"] = vpdSubnets2 + } + vpdId1, _ := jsonpath.Get("$[0].vpd_info[0].vpd_id", v) + if vpdId1 != nil && vpdId1 != "" { + vpdInfo["VpdId"] = vpdId1 + } + + objectDataLocalMap["VpdInfo"] = vpdInfo + vSwitchZoneId1, _ := jsonpath.Get("$[0].vswitch_zone_id", v) + if vSwitchZoneId1 != nil && vSwitchZoneId1 != "" { + objectDataLocalMap["VSwitchZoneId"] = vSwitchZoneId1 + } + tailIpVersion1, _ := jsonpath.Get("$[0].tail_ip_version", v) + if tailIpVersion1 != nil && tailIpVersion1 != "" { + objectDataLocalMap["TailIpVersion"] = tailIpVersion1 + } + + objectDataLocalMapJson, err := json.Marshal(objectDataLocalMap) + if err != nil { + return WrapError(err) + } + request["Networks"] = string(objectDataLocalMapJson) + } + + if v, ok := d.GetOk("node_groups"); ok { + nodeGroupsMapsArray := make([]interface{}, 0) + for _, dataLoop8 := range v.([]interface{}) { + dataLoop8Tmp := dataLoop8.(map[string]interface{}) + dataLoop8Map := make(map[string]interface{}) + dataLoop8Map["UserData"] = dataLoop8Tmp["user_data"] + dataLoop8Map["ZoneId"] = dataLoop8Tmp["zone_id"] + dataLoop8Map["NodeGroupDescription"] = dataLoop8Tmp["node_group_description"] + localMaps8 := make([]interface{}, 0) + localData9 := dataLoop8Tmp["nodes"] + for _, dataLoop9 := range localData9.([]interface{}) { + dataLoop9Tmp := dataLoop9.(map[string]interface{}) + dataLoop9Map := make(map[string]interface{}) + dataLoop9Map["Hostname"] = dataLoop9Tmp["hostname"] + dataLoop9Map["VSwitchId"] = dataLoop9Tmp["vswitch_id"] + dataLoop9Map["VpcId"] = dataLoop9Tmp["vpc_id"] + dataLoop9Map["NodeId"] = dataLoop9Tmp["node_id"] + dataLoop9Map["LoginPassword"] = dataLoop9Tmp["login_password"] + localMaps8 = append(localMaps8, dataLoop9Map) + } + dataLoop8Map["Nodes"] = localMaps8 + dataLoop8Map["NodeGroupName"] = dataLoop8Tmp["node_group_name"] + dataLoop8Map["MachineType"] = dataLoop8Tmp["machine_type"] + dataLoop8Map["ImageId"] = dataLoop8Tmp["image_id"] + nodeGroupsMapsArray = append(nodeGroupsMapsArray, dataLoop8Map) + } + nodeGroupsMapsJson, err := json.Marshal(nodeGroupsMapsArray) + if err != nil { + return WrapError(err) + } + request["NodeGroups"] = string(nodeGroupsMapsJson) + } + + if v, ok := d.GetOk("cluster_name"); ok { + request["ClusterName"] = v + } + if v, ok := d.GetOk("cluster_description"); ok { + request["ClusterDescription"] = v + } + if v, ok := d.GetOk("tags"); ok { + tagsMap := ConvertTags(v.(map[string]interface{})) + request = expandTagsToMap(request, tagsMap) + } + + if v, ok := d.GetOk("resource_group_id"); ok { + request["ResourceGroupId"] = v + } + if v, ok := d.GetOk("components"); ok { + componentsMapsArray := make([]interface{}, 0) + for _, dataLoop11 := range v.([]interface{}) { + dataLoop11Tmp := dataLoop11.(map[string]interface{}) + dataLoop11Map := make(map[string]interface{}) + localData12 := make(map[string]interface{}) + basicArgs1, _ := jsonpath.Get("$[0].basic_args", dataLoop11Tmp["component_config"]) + if basicArgs1 != nil && basicArgs1 != "" { + localData12["BasicArgs"] = basicArgs1 + } + nodeUnits1, _ := jsonpath.Get("$[0].node_units", dataLoop11Tmp["component_config"]) + if nodeUnits1 != nil && nodeUnits1 != "" { + localData12["NodeUnits"] = nodeUnits1 + } + dataLoop11Map["ComponentConfig"] = localData12 + dataLoop11Map["ComponentType"] = dataLoop11Tmp["component_type"] + componentsMapsArray = append(componentsMapsArray, dataLoop11Map) + } + componentsMapsJson, err := json.Marshal(componentsMapsArray) + if err != nil { + return WrapError(err) + } + request["Components"] = string(componentsMapsJson) + } + + if v, ok := d.GetOkExists("ignore_failed_node_tasks"); ok { + request["IgnoreFailedNodeTasks"] = v + } + if v, ok := d.GetOk("cluster_type"); ok { + request["ClusterType"] = v + } + if v, ok := d.GetOk("nimiz_vswitches"); ok { + nimizVSwitchesMapsArray := v.([]interface{}) + nimizVSwitchesMapsJson, err := json.Marshal(nimizVSwitchesMapsArray) + if err != nil { + return WrapError(err) + } + request["NimizVSwitches"] = string(nimizVSwitchesMapsJson) + } + + if v, ok := d.GetOk("hpn_zone"); ok { + request["HpnZone"] = v + } + if v, ok := d.GetOkExists("open_eni_jumbo_frame"); ok { + request["OpenEniJumboFrame"] = v + } + wait := incrementalWait(10*time.Second, 60*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 { + addDebug(action, err, request) + 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_cluster", action, AlibabaCloudSdkGoERROR) + } + + d.SetId(fmt.Sprint(response["ClusterId"])) + + return resourceAliCloudEfloClusterUpdate(d, meta) +} + +func resourceAliCloudEfloClusterRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*connectivity.AliyunClient) + efloServiceV2 := EfloServiceV2{client} + + objectRaw, err := efloServiceV2.DescribeEfloCluster(d.Id()) + if err != nil { + if !d.IsNewResource() && NotFoundError(err) { + log.Printf("[DEBUG] Resource alicloud_eflo_cluster DescribeEfloCluster Failed!!! %s", err) + d.SetId("") + return nil + } + return WrapError(err) + } + + d.Set("cluster_description", objectRaw["ClusterDescription"]) + d.Set("cluster_name", objectRaw["ClusterName"]) + d.Set("cluster_type", objectRaw["ClusterType"]) + d.Set("create_time", objectRaw["CreateTime"]) + d.Set("resource_group_id", objectRaw["ResourceGroupId"]) + d.Set("status", objectRaw["OperatingState"]) + + objectRaw, err = efloServiceV2.DescribeClusterListTagResources(d.Id()) + if err != nil && !NotFoundError(err) { + return WrapError(err) + } + + tagsMaps, _ := jsonpath.Get("$.TagResources.TagResource", objectRaw) + d.Set("tags", tagsToMap(tagsMaps)) + + return nil +} + +func resourceAliCloudEfloClusterUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*connectivity.AliyunClient) + var request map[string]interface{} + var response map[string]interface{} + var query map[string]interface{} + update := false + + var err error + action := "ChangeResourceGroup" + request = make(map[string]interface{}) + query = make(map[string]interface{}) + request["ResourceId"] = d.Id() + request["ResourceRegionId"] = client.RegionId + if _, ok := d.GetOk("resource_group_id"); ok && !d.IsNewResource() && d.HasChange("resource_group_id") { + update = true + } + request["ResourceGroupId"] = d.Get("resource_group_id") + request["ResourceType"] = "Cluster" + 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) + } + } + + if d.HasChange("tags") { + efloServiceV2 := EfloServiceV2{client} + if err := efloServiceV2.SetResourceTags(d, "Cluster"); err != nil { + return WrapError(err) + } + } + return resourceAliCloudEfloClusterRead(d, meta) +} + +func resourceAliCloudEfloClusterDelete(d *schema.ResourceData, meta interface{}) error { + + client := meta.(*connectivity.AliyunClient) + action := "DeleteCluster" + var request map[string]interface{} + var response map[string]interface{} + query := make(map[string]interface{}) + var err error + request = make(map[string]interface{}) + request["ClusterId"] = d.Id() + request["RegionId"] = client.RegionId + + wait := incrementalWait(3*time.Second, 5*time.Second) + err = resource.Retry(d.Timeout(schema.TimeoutDelete), 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 { + if NotFoundError(err) { + return nil + } + return WrapErrorf(err, DefaultErrorMsg, d.Id(), action, AlibabaCloudSdkGoERROR) + } + + return nil +} diff --git a/alicloud/resource_alicloud_eflo_cluster_test.go b/alicloud/resource_alicloud_eflo_cluster_test.go new file mode 100644 index 000000000000..2b560d7efab7 --- /dev/null +++ b/alicloud/resource_alicloud_eflo_cluster_test.go @@ -0,0 +1,327 @@ +package alicloud + +import ( + "fmt" + "testing" + + "github.com/aliyun/terraform-provider-alicloud/alicloud/connectivity" + "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" +) + +func TestAccAliCloudEfloCluster_basic10311(t *testing.T) { + var v map[string]interface{} + resourceId := "alicloud_eflo_cluster.default" + ra := resourceAttrInit(resourceId, AlicloudEfloClusterMap10311) + rc := resourceCheckInitWithDescribeMethod(resourceId, &v, func() interface{} { + return &EfloServiceV2{testAccProvider.Meta().(*connectivity.AliyunClient)} + }, "DescribeEfloCluster") + rac := resourceAttrCheckInit(rc, ra) + testAccCheck := rac.resourceAttrMapUpdateSet() + rand := acctest.RandIntRange(10000, 99999) + name := fmt.Sprintf("tfacceflo%d", rand) + testAccConfig := resourceTestAccConfigFunc(resourceId, name, AlicloudEfloClusterBasicDependence10311) + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + }, + IDRefreshName: resourceId, + Providers: testAccProviders, + CheckDestroy: rac.checkResourceDestroy(), + Steps: []resource.TestStep{ + { + Config: testAccConfig(map[string]interface{}{ + "hpn_zone": "B1", + "networks": []map[string]interface{}{ + { + "new_vpd_info": []map[string]interface{}{ + { + "cloud_link_cidr": "169.254.128.0/23", + "monitor_vpc_id": "${alicloud_vpc.create_vpc.id}", + "monitor_vswitch_id": "${alicloud_vswitch.create_vswitch.id}", + "cen_id": "11111", + "cloud_link_id": "1111", + "vpd_cidr": "111", + "vpd_subnets": []map[string]interface{}{ + { + "subnet_cidr": "111", + "subnet_type": "111", + "zone_id": "1111", + }, + }, + }, + }, + "security_group_id": "${alicloud_security_group.create_security_group.id}", + "vswitch_zone_id": "cn-wulanchabu-b", + "vpc_id": "${alicloud_vpc.create_vpc.id}", + "vswitch_id": "${alicloud_vswitch.create_vswitch.id}", + "vpd_info": []map[string]interface{}{ + { + "vpd_id": "111", + "vpd_subnets": []string{ + "111"}, + }, + }, + "ip_allocation_policy": []map[string]interface{}{ + { + "bond_policy": []map[string]interface{}{ + { + "bond_default_subnet": "111", + "bonds": []map[string]interface{}{ + { + "name": "111", + "subnet": "111", + }, + }, + }, + }, + "machine_type_policy": []map[string]interface{}{ + { + "bonds": []map[string]interface{}{ + { + "name": "111", + "subnet": "111", + }, + }, + "machine_type": "111", + }, + }, + "node_policy": []map[string]interface{}{ + { + "bonds": []map[string]interface{}{ + { + "name": "111", + "subnet": "111", + }, + }, + "node_id": "111", + }, + }, + }, + }, + "tail_ip_version": "ipv4", + }, + }, + "ignore_failed_node_tasks": "true", + "cluster_type": "Lite", + "cluster_name": name, + "cluster_description": "cluster-resource-test", + "resource_group_id": "${data.alicloud_resource_manager_resource_groups.default.ids.0}", + "node_groups": []map[string]interface{}{ + { + "node_group_name": "cluster-resource-test", + "node_group_description": "cluster-resource-test", + "machine_type": "efg1.nvga1n", + "image_id": "i190982651690986913088", + "zone_id": "cn-wulanchabu-b", + }, + }, + "nimiz_vswitches": []string{ + "1111"}, + "open_eni_jumbo_frame": "false", + }), + Check: resource.ComposeTestCheckFunc( + testAccCheck(map[string]string{ + "hpn_zone": "B1", + "ignore_failed_node_tasks": "true", + "cluster_type": "Lite", + "cluster_name": name, + "cluster_description": "cluster-resource-test", + "resource_group_id": CHECKSET, + "node_groups.#": "1", + "nimiz_vswitches.#": "1", + "open_eni_jumbo_frame": "false", + }), + ), + }, + { + Config: testAccConfig(map[string]interface{}{ + "resource_group_id": "${data.alicloud_resource_manager_resource_groups.default.ids.1}", + }), + Check: resource.ComposeTestCheckFunc( + testAccCheck(map[string]string{ + "resource_group_id": CHECKSET, + }), + ), + }, + { + Config: testAccConfig(map[string]interface{}{ + "tags": map[string]string{ + "Created": "TF", + "For": "Test", + }, + }), + Check: resource.ComposeTestCheckFunc( + testAccCheck(map[string]string{ + "tags.%": "2", + "tags.Created": "TF", + "tags.For": "Test", + }), + ), + }, + { + Config: testAccConfig(map[string]interface{}{ + "tags": map[string]string{ + "Created": "TF-update", + "For": "Test-update", + }, + }), + Check: resource.ComposeTestCheckFunc( + testAccCheck(map[string]string{ + "tags.%": "2", + "tags.Created": "TF-update", + "tags.For": "Test-update", + }), + ), + }, + { + Config: testAccConfig(map[string]interface{}{ + "tags": REMOVEKEY, + }), + Check: resource.ComposeTestCheckFunc( + testAccCheck(map[string]string{ + "tags.%": "0", + "tags.Created": REMOVEKEY, + "tags.For": REMOVEKEY, + }), + ), + }, + { + ResourceName: resourceId, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"components", "hpn_zone", "ignore_failed_node_tasks", "networks", "nimiz_vswitches", "node_groups", "open_eni_jumbo_frame"}, + }, + }, + }) +} + +var AlicloudEfloClusterMap10311 = map[string]string{ + "status": CHECKSET, + "create_time": CHECKSET, +} + +func AlicloudEfloClusterBasicDependence10311(name string) string { + return fmt.Sprintf(` +variable "name" { + default = "%s" +} + +data "alicloud_resource_manager_resource_groups" "default" {} + +resource "alicloud_vpc" "create_vpc" { + cidr_block = "192.168.0.0/16" + vpc_name = "cluster-resoure-test" +} + +resource "alicloud_vswitch" "create_vswitch" { + vpc_id = alicloud_vpc.create_vpc.id + zone_id = "cn-wulanchabu-b" + cidr_block = "192.168.0.0/24" + vswitch_name = "cluster-resoure-test" +} + +resource "alicloud_security_group" "create_security_group" { + description = "sg" + security_group_name = "cluster-resoure-test" + security_group_type = "normal" + vpc_id = alicloud_vpc.create_vpc.id +} + + +`, name) +} + +// Case 创建集群 1874 +func TestAccAliCloudEfloCluster_basic1874(t *testing.T) { + var v map[string]interface{} + resourceId := "alicloud_eflo_cluster.default" + ra := resourceAttrInit(resourceId, AlicloudEfloClusterMap1874) + rc := resourceCheckInitWithDescribeMethod(resourceId, &v, func() interface{} { + return &EfloServiceV2{testAccProvider.Meta().(*connectivity.AliyunClient)} + }, "DescribeEfloCluster") + rac := resourceAttrCheckInit(rc, ra) + testAccCheck := rac.resourceAttrMapUpdateSet() + rand := acctest.RandIntRange(10000, 99999) + name := fmt.Sprintf("tfacceflo%d", rand) + testAccConfig := resourceTestAccConfigFunc(resourceId, name, AlicloudEfloClusterBasicDependence1874) + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + }, + IDRefreshName: resourceId, + Providers: testAccProviders, + CheckDestroy: rac.checkResourceDestroy(), + Steps: []resource.TestStep{ + { + Config: testAccConfig(map[string]interface{}{}), + Check: resource.ComposeTestCheckFunc( + testAccCheck(map[string]string{}), + ), + }, + { + Config: testAccConfig(map[string]interface{}{ + "tags": map[string]string{ + "Created": "TF", + "For": "Test", + }, + }), + Check: resource.ComposeTestCheckFunc( + testAccCheck(map[string]string{ + "tags.%": "2", + "tags.Created": "TF", + "tags.For": "Test", + }), + ), + }, + { + Config: testAccConfig(map[string]interface{}{ + "tags": map[string]string{ + "Created": "TF-update", + "For": "Test-update", + }, + }), + Check: resource.ComposeTestCheckFunc( + testAccCheck(map[string]string{ + "tags.%": "2", + "tags.Created": "TF-update", + "tags.For": "Test-update", + }), + ), + }, + { + Config: testAccConfig(map[string]interface{}{ + "tags": REMOVEKEY, + }), + Check: resource.ComposeTestCheckFunc( + testAccCheck(map[string]string{ + "tags.%": "0", + "tags.Created": REMOVEKEY, + "tags.For": REMOVEKEY, + }), + ), + }, + { + ResourceName: resourceId, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"components", "hpn_zone", "ignore_failed_node_tasks", "networks", "nimiz_vswitches", "node_groups", "open_eni_jumbo_frame"}, + }, + }, + }) +} + +var AlicloudEfloClusterMap1874 = map[string]string{ + "status": CHECKSET, + "create_time": CHECKSET, +} + +func AlicloudEfloClusterBasicDependence1874(name string) string { + return fmt.Sprintf(` +variable "name" { + default = "%s" +} + + +`, name) +} diff --git a/alicloud/resource_alicloud_eflo_invocation.go b/alicloud/resource_alicloud_eflo_invocation.go new file mode 100644 index 000000000000..bd5c575f3971 --- /dev/null +++ b/alicloud/resource_alicloud_eflo_invocation.go @@ -0,0 +1,249 @@ +package alicloud + +import ( + "encoding/json" + "fmt" + "log" + "time" + + "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 resourceAliCloudEfloInvocation() *schema.Resource { + return &schema.Resource{ + Create: resourceAliCloudEfloInvocationCreate, + Read: resourceAliCloudEfloInvocationRead, + Update: resourceAliCloudEfloInvocationUpdate, + Delete: resourceAliCloudEfloInvocationDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(5 * time.Minute), + Update: schema.DefaultTimeout(5 * time.Minute), + Delete: schema.DefaultTimeout(5 * time.Minute), + }, + Schema: map[string]*schema.Schema{ + "command_content": { + Type: schema.TypeString, + Optional: true, + }, + "command_id": { + Type: schema.TypeString, + Optional: true, + }, + "content_encoding": { + Type: schema.TypeString, + Optional: true, + }, + "description": { + Type: schema.TypeString, + Optional: true, + }, + "enable_parameter": { + Type: schema.TypeBool, + Optional: true, + }, + "frequency": { + Type: schema.TypeString, + Optional: true, + }, + "launcher": { + Type: schema.TypeString, + Optional: true, + }, + "name": { + Type: schema.TypeString, + Optional: true, + }, + "node_id_list": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "parameters": { + Type: schema.TypeMap, + Optional: true, + }, + "repeat_mode": { + Type: schema.TypeString, + Optional: true, + }, + "termination_mode": { + Type: schema.TypeString, + Optional: true, + }, + "timeout": { + Type: schema.TypeInt, + Optional: true, + }, + "username": { + Type: schema.TypeString, + Optional: true, + }, + "working_dir": { + Type: schema.TypeString, + Optional: true, + }, + }, + } +} + +func resourceAliCloudEfloInvocationCreate(d *schema.ResourceData, meta interface{}) error { + + client := meta.(*connectivity.AliyunClient) + + action := "RunCommand" + 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 + request["ClientToken"] = buildClientToken(action) + + if v, ok := d.GetOk("content_encoding"); ok { + request["ContentEncoding"] = v + } + if v, ok := d.GetOk("username"); ok { + request["Username"] = v + } + if v, ok := d.GetOk("command_id"); ok { + request["CommandId"] = v + } + if v, ok := d.GetOk("description"); ok { + request["Description"] = v + } + if v, ok := d.GetOk("working_dir"); ok { + request["WorkingDir"] = v + } + if v, ok := d.GetOk("command_content"); ok { + request["CommandContent"] = v + } + if v, ok := d.GetOk("parameters"); ok { + request["Parameters"] = v + } + if v, ok := d.GetOk("node_id_list"); ok { + nodeIdListMapsArray := v.([]interface{}) + nodeIdListMapsJson, err := json.Marshal(nodeIdListMapsArray) + if err != nil { + return WrapError(err) + } + request["NodeIdList"] = string(nodeIdListMapsJson) + } + + if v, ok := d.GetOkExists("enable_parameter"); ok { + request["EnableParameter"] = v + } + if v, ok := d.GetOkExists("timeout"); ok { + request["Timeout"] = v + } + if v, ok := d.GetOk("name"); ok { + request["Name"] = v + } + if v, ok := d.GetOk("termination_mode"); ok { + request["TerminationMode"] = v + } + if v, ok := d.GetOk("frequency"); ok { + request["Frequency"] = v + } + if v, ok := d.GetOk("launcher"); ok { + request["Launcher"] = v + } + if v, ok := d.GetOk("repeat_mode"); ok { + request["RepeatMode"] = 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_invocation", action, AlibabaCloudSdkGoERROR) + } + + d.SetId(fmt.Sprint(response["InvokeId"])) + + return resourceAliCloudEfloInvocationUpdate(d, meta) +} + +func resourceAliCloudEfloInvocationRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*connectivity.AliyunClient) + efloServiceV2 := EfloServiceV2{client} + + _, err := efloServiceV2.DescribeEfloInvocation(d.Id()) + if err != nil { + if !d.IsNewResource() && NotFoundError(err) { + log.Printf("[DEBUG] Resource alicloud_eflo_invocation DescribeEfloInvocation Failed!!! %s", err) + d.SetId("") + return nil + } + return WrapError(err) + } + + return nil +} + +func resourceAliCloudEfloInvocationUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*connectivity.AliyunClient) + var request map[string]interface{} + var response map[string]interface{} + var query map[string]interface{} + update := false + + var err error + action := "StopInvocation" + request = make(map[string]interface{}) + query = make(map[string]interface{}) + request["InvokeId"] = d.Id() + request["RegionId"] = client.RegionId + if !d.IsNewResource() && d.HasChange("node_id_list") { + update = true + if v, ok := d.GetOk("node_id_list"); ok || d.HasChange("node_id_list") { + nodeIdListMapsArray := v.([]interface{}) + nodeIdListMapsJson, err := json.Marshal(nodeIdListMapsArray) + if err != nil { + return WrapError(err) + } + request["NodeIdList"] = string(nodeIdListMapsJson) + } + } + + 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) + } + } + + return resourceAliCloudEfloInvocationRead(d, meta) +} + +func resourceAliCloudEfloInvocationDelete(d *schema.ResourceData, meta interface{}) error { + log.Printf("[WARN] Cannot destroy resource AliCloud Resource Invocation. Terraform will remove this resource from the state file, however resources may remain.") + return nil +} diff --git a/alicloud/resource_alicloud_eflo_invocation_test.go b/alicloud/resource_alicloud_eflo_invocation_test.go new file mode 100644 index 000000000000..90eb2c55a383 --- /dev/null +++ b/alicloud/resource_alicloud_eflo_invocation_test.go @@ -0,0 +1,91 @@ +package alicloud + +import ( + "fmt" + "testing" + + "github.com/aliyun/terraform-provider-alicloud/alicloud/connectivity" + "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" +) + +func TestAccAliCloudEfloInvocation_basic10348(t *testing.T) { + var v map[string]interface{} + resourceId := "alicloud_eflo_invocation.default" + ra := resourceAttrInit(resourceId, AlicloudEfloInvocationMap10348) + rc := resourceCheckInitWithDescribeMethod(resourceId, &v, func() interface{} { + return &EfloServiceV2{testAccProvider.Meta().(*connectivity.AliyunClient)} + }, "DescribeEfloInvocation") + rac := resourceAttrCheckInit(rc, ra) + testAccCheck := rac.resourceAttrMapUpdateSet() + rand := acctest.RandIntRange(10000, 99999) + name := fmt.Sprintf("tfacceflo%d", rand) + testAccConfig := resourceTestAccConfigFunc(resourceId, name, AlicloudEfloInvocationBasicDependence10348) + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + testAccPreCheckWithRegions(t, true, []connectivity.Region{"cn-hangzhou"}) + }, + IDRefreshName: resourceId, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccConfig(map[string]interface{}{ + "description": "test", + "content_encoding": "Base64", + "name": name, + "repeat_mode": "Once", + "parameters": map[string]interface{}{ + "\"name\"": "Jack", + }, + "node_id_list": []string{ + "e01-cn-rno46i6rdfn"}, + "timeout": "68", + "command_content": "ZWNobyAxMjM=", + "working_dir": "/home/", + "username": "root", + "enable_parameter": "false", + "termination_mode": "ProcessTree", + }), + Check: resource.ComposeTestCheckFunc( + testAccCheck(map[string]string{ + "description": "test", + "content_encoding": "Base64", + "name": name, + "repeat_mode": "Once", + "timeout": "68", + "command_content": "ZWNobyAxMjM=", + "working_dir": "/home/", + "username": "root", + "enable_parameter": "false", + "termination_mode": "ProcessTree", + }), + ), + }, + { + Config: testAccConfig(map[string]interface{}{}), + Check: resource.ComposeTestCheckFunc( + testAccCheck(map[string]string{}), + ), + }, + { + ResourceName: resourceId, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"command_content", "command_id", "content_encoding", "description", "enable_parameter", "frequency", "launcher", "name", "parameters", "repeat_mode", "termination_mode", "timeout", "username", "working_dir", "node_id_list"}, + }, + }, + }) +} + +var AlicloudEfloInvocationMap10348 = map[string]string{} + +func AlicloudEfloInvocationBasicDependence10348(name string) string { + return fmt.Sprintf(` +variable "name" { + default = "%s" +} + + +`, name) +} diff --git a/alicloud/resource_alicloud_eflo_node.go b/alicloud/resource_alicloud_eflo_node.go new file mode 100644 index 000000000000..dabc2a0b6824 --- /dev/null +++ b/alicloud/resource_alicloud_eflo_node.go @@ -0,0 +1,348 @@ +package alicloud + +import ( + "fmt" + "log" + "time" + + "github.com/PaesslerAG/jsonpath" + "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 resourceAliCloudEfloNode() *schema.Resource { + return &schema.Resource{ + Create: resourceAliCloudEfloNodeCreate, + Read: resourceAliCloudEfloNodeRead, + Update: resourceAliCloudEfloNodeUpdate, + Delete: resourceAliCloudEfloNodeDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(5 * time.Minute), + Update: schema.DefaultTimeout(5 * time.Minute), + Delete: schema.DefaultTimeout(5 * time.Minute), + }, + Schema: map[string]*schema.Schema{ + "billing_cycle": { + Type: schema.TypeString, + Optional: true, + }, + "classify": { + Type: schema.TypeString, + Optional: true, + }, + "computing_server": { + Type: schema.TypeString, + Optional: true, + }, + "create_time": { + Type: schema.TypeString, + Computed: true, + }, + "discount_level": { + Type: schema.TypeString, + Optional: true, + }, + "hpn_zone": { + Type: schema.TypeString, + Optional: true, + }, + "payment_ratio": { + Type: schema.TypeString, + Optional: true, + }, + "period": { + Type: schema.TypeInt, + Optional: true, + }, + "product_form": { + Type: schema.TypeString, + Optional: true, + }, + "renew_period": { + Type: schema.TypeInt, + Optional: true, + }, + "renewal_status": { + Type: schema.TypeString, + Optional: true, + }, + "resource_group_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "server_arch": { + Type: schema.TypeString, + Optional: true, + }, + "stage_num": { + Type: schema.TypeString, + Optional: true, + }, + "status": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "zone": { + Type: schema.TypeString, + Optional: true, + }, + }, + } +} + +func resourceAliCloudEfloNodeCreate(d *schema.ResourceData, meta interface{}) error { + + client := meta.(*connectivity.AliyunClient) + + 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) + + 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, + }) + } + if v, ok := d.GetOk("discount_level"); ok { + parameterMapList = append(parameterMapList, map[string]interface{}{ + "Code": "discountlevel", + "Value": v, + }) + } + if v, ok := d.GetOk("billing_cycle"); ok { + parameterMapList = append(parameterMapList, map[string]interface{}{ + "Code": "BillingCycle", + "Value": v, + }) + } + if v, ok := d.GetOk("computing_server"); ok { + parameterMapList = append(parameterMapList, map[string]interface{}{ + "Code": "computingserver", + "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 + + request["SubscriptionType"] = "Subscription" + 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 client.IsInternationalAccount() { + request["ProductType"] = "bccluster_eflocomputing_public_intl" + } + 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 NeedRetry(err) { + wait() + return resource.RetryableError(err) + } + if !client.IsInternationalAccount() && IsExpectedErrors(err, []string{"NotApplicable"}) { + request["ProductCode"] = "bccluster" + request["ProductType"] = "bccluster_eflocomputing_public_intl" + endpoint = connectivity.BssOpenAPIEndpointInternational + 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) + } + + id, _ := jsonpath.Get("$.Data.InstanceId", response) + d.SetId(fmt.Sprint(id)) + + efloServiceV2 := EfloServiceV2{client} + stateConf := BuildStateConf([]string{}, []string{"#CHECKSET"}, d.Timeout(schema.TimeoutCreate), 5*time.Second, efloServiceV2.EfloNodeStateRefreshFunc(d.Id(), "#$.NodeId", []string{})) + if _, err := stateConf.WaitForState(); err != nil { + return WrapErrorf(err, IdMsg, d.Id()) + } + + return resourceAliCloudEfloNodeUpdate(d, meta) +} + +func resourceAliCloudEfloNodeRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*connectivity.AliyunClient) + efloServiceV2 := EfloServiceV2{client} + + objectRaw, err := efloServiceV2.DescribeEfloNode(d.Id()) + if err != nil { + if !d.IsNewResource() && NotFoundError(err) { + log.Printf("[DEBUG] Resource alicloud_eflo_node DescribeEfloNode Failed!!! %s", err) + d.SetId("") + return nil + } + return WrapError(err) + } + + d.Set("create_time", objectRaw["CreateTime"]) + d.Set("resource_group_id", objectRaw["ResourceGroupId"]) + d.Set("status", objectRaw["OperatingState"]) + + return nil +} + +func resourceAliCloudEfloNodeUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*connectivity.AliyunClient) + var request map[string]interface{} + var response map[string]interface{} + var query map[string]interface{} + update := false + + var err error + action := "ChangeResourceGroup" + request = make(map[string]interface{}) + query = make(map[string]interface{}) + request["ResourceId"] = d.Id() + request["ResourceRegionId"] = client.RegionId + if _, ok := d.GetOk("resource_group_id"); ok && d.HasChange("resource_group_id") { + update = true + } + 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 { + response, err = client.RpcPost("eflo-controller", "2022-12-15", action, query, request, true) + if err != nil { + if IsExpectedErrors(err, []string{"ResourceNotFound"}) || 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) + } + } + + return resourceAliCloudEfloNodeRead(d, meta) +} + +func resourceAliCloudEfloNodeDelete(d *schema.ResourceData, meta interface{}) error { + + client := meta.(*connectivity.AliyunClient) + action := "RefundInstance" + var request map[string]interface{} + var response map[string]interface{} + query := make(map[string]interface{}) + var err error + request = make(map[string]interface{}) + request["InstanceId"] = d.Id() + + request["ClientToken"] = buildClientToken(action) + + request["ImmediatelyRelease"] = "1" + var endpoint string + request["ProductCode"] = "bccluster" + request["ProductType"] = "bccluster_eflocomputing_public_cn" + if client.IsInternationalAccount() { + request["ProductType"] = "bccluster_eflocomputing_public_intl" + } + wait := incrementalWait(3*time.Second, 5*time.Second) + err = resource.Retry(d.Timeout(schema.TimeoutDelete), func() *resource.RetryError { + response, err = client.RpcPostWithEndpoint("BssOpenApi", "2017-12-14", action, query, request, true, endpoint) + request["ClientToken"] = buildClientToken(action) + + if err != nil { + if NeedRetry(err) { + wait() + return resource.RetryableError(err) + } + if !client.IsInternationalAccount() && IsExpectedErrors(err, []string{"NotApplicable"}) { + request["ProductCode"] = "bccluster" + request["ProductType"] = "bccluster_eflocomputing_public_intl" + endpoint = connectivity.BssOpenAPIEndpointInternational + return resource.RetryableError(err) + } + return resource.NonRetryableError(err) + } + return nil + }) + addDebug(action, response, request) + + if err != nil { + if IsExpectedErrors(err, []string{"RESOURCE_NOT_FOUND"}) || NotFoundError(err) { + return nil + } + return WrapErrorf(err, DefaultErrorMsg, d.Id(), action, AlibabaCloudSdkGoERROR) + } + + efloServiceV2 := EfloServiceV2{client} + 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()) + } + + return nil +} diff --git a/alicloud/resource_alicloud_eflo_node_group.go b/alicloud/resource_alicloud_eflo_node_group.go new file mode 100644 index 000000000000..03aaf097ca48 --- /dev/null +++ b/alicloud/resource_alicloud_eflo_node_group.go @@ -0,0 +1,687 @@ +package alicloud + +import ( + "bytes" + "encoding/json" + "fmt" + "github.com/hashicorp/terraform-plugin-sdk/helper/hashcode" + "log" + "strings" + "time" + + "github.com/PaesslerAG/jsonpath" + "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 resourceAliCloudEfloNodeGroup() *schema.Resource { + return &schema.Resource{ + Create: resourceAliCloudEfloNodeGroupCreate, + Read: resourceAliCloudEfloNodeGroupRead, + Update: resourceAliCloudEfloNodeGroupUpdate, + Delete: resourceAliCloudEfloNodeGroupDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(5 * time.Minute), + Update: schema.DefaultTimeout(120 * time.Minute), + Delete: schema.DefaultTimeout(5 * time.Minute), + }, + Schema: map[string]*schema.Schema{ + "az": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "cluster_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "create_time": { + Type: schema.TypeString, + Computed: true, + }, + "ignore_failed_node_tasks": { + Type: schema.TypeBool, + Optional: true, + }, + "image_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "ip_allocation_policy": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "machine_type_policy": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "bonds": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "subnet": { + Type: schema.TypeString, + Optional: true, + }, + "name": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "machine_type": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "bond_policy": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "bonds": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "subnet": { + Type: schema.TypeString, + Optional: true, + }, + "name": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "bond_default_subnet": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "node_policy": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "bonds": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "subnet": { + Type: schema.TypeString, + Optional: true, + }, + "name": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "node_id": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + }, + }, + }, + "machine_type": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "node_group_description": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "node_group_id": { + Type: schema.TypeString, + Computed: true, + }, + "node_group_name": { + Type: schema.TypeString, + Required: true, + }, + "nodes": { + Type: schema.TypeSet, + Optional: true, + Set: func(v interface{}) int { + var buf bytes.Buffer + m := v.(map[string]interface{}) + if v, ok := m["node_id"]; ok { + buf.WriteString(fmt.Sprint(v)) + } + return hashcode.String(buf.String()) + }, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "vpc_id": { + Type: schema.TypeString, + Optional: true, + }, + "vswitch_id": { + Type: schema.TypeString, + Optional: true, + }, + "hostname": { + Type: schema.TypeString, + Optional: true, + }, + "node_id": { + Type: schema.TypeString, + Optional: true, + }, + "login_password": { + Type: schema.TypeString, + Optional: true, + Sensitive: true, + }, + }, + }, + }, + "user_data": { + Type: schema.TypeString, + Optional: true, + }, + "vswitch_zone_id": { + Type: schema.TypeString, + Optional: true, + }, + "vpd_subnets": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "zone_id": { + Type: schema.TypeString, + Optional: true, + }, + }, + } +} + +func resourceAliCloudEfloNodeGroupCreate(d *schema.ResourceData, meta interface{}) error { + + client := meta.(*connectivity.AliyunClient) + + action := "CreateNodeGroup" + var request map[string]interface{} + var response map[string]interface{} + query := make(map[string]interface{}) + var err error + request = make(map[string]interface{}) + if v, ok := d.GetOk("cluster_id"); ok { + request["ClusterId"] = v + } + request["RegionId"] = client.RegionId + + objectDataLocalMap := make(map[string]interface{}) + + if v, ok := d.GetOk("node_group_description"); ok { + objectDataLocalMap["NodeGroupDescription"] = v + } + + if v, ok := d.GetOk("az"); ok { + objectDataLocalMap["Az"] = v + } + + if v, ok := d.GetOk("machine_type"); ok { + objectDataLocalMap["MachineType"] = v + } + + if v, ok := d.GetOk("image_id"); ok { + objectDataLocalMap["ImageId"] = v + } + + if v, ok := d.GetOk("node_group_name"); ok { + objectDataLocalMap["NodeGroupName"] = v + } + + objectDataLocalMapJson, err := json.Marshal(objectDataLocalMap) + if err != nil { + return WrapError(err) + } + request["NodeGroup"] = string(objectDataLocalMapJson) + + 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_group", action, AlibabaCloudSdkGoERROR) + } + + d.SetId(fmt.Sprintf("%v:%v", request["ClusterId"], response["NodeGroupId"])) + + return resourceAliCloudEfloNodeGroupUpdate(d, meta) +} + +func resourceAliCloudEfloNodeGroupRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*connectivity.AliyunClient) + efloServiceV2 := EfloServiceV2{client} + + objectRaw, err := efloServiceV2.DescribeEfloNodeGroup(d.Id()) + if err != nil { + if !d.IsNewResource() && NotFoundError(err) { + log.Printf("[DEBUG] Resource alicloud_eflo_node_group DescribeEfloNodeGroup Failed!!! %s", err) + d.SetId("") + return nil + } + return WrapError(err) + } + + d.Set("az", objectRaw["ZoneId"]) + d.Set("create_time", objectRaw["CreateTime"]) + d.Set("image_id", objectRaw["ImageId"]) + d.Set("machine_type", objectRaw["MachineType"]) + d.Set("node_group_description", objectRaw["Description"]) + d.Set("node_group_name", objectRaw["GroupName"]) + d.Set("cluster_id", objectRaw["ClusterId"]) + d.Set("node_group_id", objectRaw["GroupId"]) + + objectRaw, err = efloServiceV2.DescribeNodeGroupListClusterNodes(d.Id()) + if err != nil && !NotFoundError(err) { + return WrapError(err) + } + + loginPasswordMap := make(map[string]interface{}) + if v := d.Get("nodes"); !IsNil(v) { + if v, ok := d.GetOk("nodes"); ok { + localData, err := jsonpath.Get("$", v) + if err != nil { + localData = make([]interface{}, 0) + } + for _, dataLoop := range localData.(*schema.Set).List() { + dataLoopTmp := make(map[string]interface{}) + if dataLoop != nil { + dataLoopTmp = dataLoop.(map[string]interface{}) + } + loginPasswordMap[dataLoopTmp["node_id"].(string)] = dataLoopTmp["login_password"] + } + } + } + + nodesRaw, _ := jsonpath.Get("$.Nodes", objectRaw) + + nodesMaps := make([]map[string]interface{}, 0) + if nodesRaw != nil { + for _, nodesChildRaw := range nodesRaw.([]interface{}) { + nodesMap := make(map[string]interface{}) + nodesChildRaw := nodesChildRaw.(map[string]interface{}) + nodesMap["hostname"] = nodesChildRaw["Hostname"] + nodesMap["node_id"] = nodesChildRaw["NodeId"] + nodesMap["vswitch_id"] = nodesChildRaw["VSwitchId"] + nodesMap["vpc_id"] = nodesChildRaw["VpcId"] + if password, ok := loginPasswordMap[fmt.Sprint(nodesMap["node_id"])]; ok { + nodesMap["login_password"] = password + } + + nodesMaps = append(nodesMaps, nodesMap) + } + } + if err := d.Set("nodes", nodesMaps); err != nil { + return err + } + + return nil +} + +func resourceAliCloudEfloNodeGroupUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*connectivity.AliyunClient) + var request map[string]interface{} + var response map[string]interface{} + var query map[string]interface{} + update := false + + var err error + parts := strings.Split(d.Id(), ":") + action := "UpdateNodeGroup" + request = make(map[string]interface{}) + query = make(map[string]interface{}) + request["NodeGroupId"] = parts[1] + request["RegionId"] = client.RegionId + if !d.IsNewResource() && d.HasChange("node_group_name") { + update = true + } + request["NewNodeGroupName"] = d.Get("node_group_name") + 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) + } + } + + if d.HasChange("nodes") { + oldEntry, newEntry := d.GetChange("nodes") + oldEntrySet := oldEntry.(*schema.Set) + newEntrySet := newEntry.(*schema.Set) + removed := oldEntrySet.Difference(newEntrySet) + added := newEntrySet.Difference(oldEntrySet) + + if removed.Len() > 0 { + parts := strings.Split(d.Id(), ":") + action := "ShrinkCluster" + request = make(map[string]interface{}) + query = make(map[string]interface{}) + request["ClusterId"] = parts[0] + request["RegionId"] = client.RegionId + objectDataLocalMap := make(map[string]interface{}) + + localMaps := make([]interface{}, 0) + for _, dataLoop := range removed.List() { + dataLoopTmp := make(map[string]interface{}) + if dataLoop != nil { + dataLoopTmp = dataLoop.(map[string]interface{}) + } + dataLoopMap := make(map[string]interface{}) + dataLoopMap["NodeId"] = dataLoopTmp["node_id"] + localMaps = append(localMaps, dataLoopMap) + } + objectDataLocalMap["Nodes"] = localMaps + + if v, ok := d.GetOk("node_group_id"); ok { + objectDataLocalMap["NodeGroupId"] = v + } + + NodeGroupsMap := make([]interface{}, 0) + NodeGroupsMap = append(NodeGroupsMap, objectDataLocalMap) + objectDataLocalMapJson, err := json.Marshal(NodeGroupsMap) + if err != nil { + return WrapError(err) + } + request["NodeGroups"] = string(objectDataLocalMapJson) + + if v, ok := d.GetOkExists("ignore_failed_node_tasks"); ok { + request["IgnoreFailedNodeTasks"] = v + } + jsonString := convertObjectToJsonString(request) + jsonString, _ = sjson.Set(jsonString, "NodeGroups.0.NodeGroupId", parts[1]) + _ = 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{"execution_success"}, d.Timeout(schema.TimeoutUpdate), 10*time.Second, efloServiceV2.DescribeAsyncEfloNodeGroupStateRefreshFunc(d, response, "$.TaskState", []string{})) + if jobDetail, err := stateConf.WaitForState(); err != nil { + return WrapErrorf(err, IdMsg, d.Id(), jobDetail) + } + + } + + if added.Len() > 0 { + parts := strings.Split(d.Id(), ":") + action := "ExtendCluster" + request = make(map[string]interface{}) + query = make(map[string]interface{}) + request["ClusterId"] = parts[0] + request["RegionId"] = client.RegionId + objectDataLocalMap := make(map[string]interface{}) + + localMaps := make([]interface{}, 0) + for _, dataLoop := range added.List() { + dataLoopTmp := make(map[string]interface{}) + if dataLoop != nil { + dataLoopTmp = dataLoop.(map[string]interface{}) + } + dataLoopMap := make(map[string]interface{}) + dataLoopMap["NodeId"] = dataLoopTmp["node_id"] + dataLoopMap["Hostname"] = dataLoopTmp["hostname"] + dataLoopMap["LoginPassword"] = dataLoopTmp["login_password"] + dataLoopMap["VpcId"] = dataLoopTmp["vpc_id"] + dataLoopMap["VSwitchId"] = dataLoopTmp["vswitch_id"] + localMaps = append(localMaps, dataLoopMap) + } + objectDataLocalMap["Nodes"] = localMaps + + if v, ok := d.GetOk("node_group_id"); ok { + objectDataLocalMap["NodeGroupId"] = v + } + + if v, ok := d.GetOk("user_data"); ok { + objectDataLocalMap["UserData"] = v + } + + if v, ok := d.GetOk("zone_id"); ok { + objectDataLocalMap["ZoneId"] = v + } + + NodeGroupsMap := make([]interface{}, 0) + NodeGroupsMap = append(NodeGroupsMap, objectDataLocalMap) + objectDataLocalMapJson, err := json.Marshal(NodeGroupsMap) + if err != nil { + return WrapError(err) + } + request["NodeGroups"] = string(objectDataLocalMapJson) + + localData1 := d.Get("ip_allocation_policy").([]interface{}) + ipAllocationPolicyMapsArray := make([]interface{}, 0) + for _, dataLoop1 := range localData1 { + dataLoop1Tmp := dataLoop1.(map[string]interface{}) + dataLoop1Map := make(map[string]interface{}) + + localData3 := make(map[string]interface{}) + bondDefaultSubnet1, _ := jsonpath.Get("$[0].bond_default_subnet", dataLoop1Tmp["bond_policy"]) + if bondDefaultSubnet1 != nil && bondDefaultSubnet1 != "" { + localData3["BondDefaultSubnet"] = bondDefaultSubnet1 + } + if v, ok := dataLoop1Tmp["bond_policy"]; ok { + localData2, err := jsonpath.Get("$[0].bonds", v) + if err != nil { + localData2 = make([]interface{}, 0) + } + localMaps2 := make([]interface{}, 0) + for _, dataLoop2 := range localData2.([]interface{}) { + 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"] + localMaps2 = append(localMaps2, dataLoop2Map) + } + localData3["Bonds"] = localMaps2 + } + dataLoop1Map["BondPolicy"] = localData3 + + localMaps3 := make([]interface{}, 0) + localData4 := dataLoop1Tmp["node_policy"] + for _, dataLoop4 := range localData4.([]interface{}) { + dataLoop4Tmp := dataLoop4.(map[string]interface{}) + dataLoop4Map := make(map[string]interface{}) + dataLoop4Map["NodeId"] = dataLoop4Tmp["node_id"] + localData2, err := jsonpath.Get("$.bonds", dataLoop4Tmp) + if err != nil { + localData2 = make([]interface{}, 0) + } + localMaps2 := make([]interface{}, 0) + for _, dataLoop2 := range localData2.([]interface{}) { + 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"] + localMaps2 = append(localMaps2, dataLoop2Map) + } + dataLoop4Map["Bonds"] = localMaps2 + localMaps3 = append(localMaps3, dataLoop4Map) + } + dataLoop1Map["NodePolicy"] = localMaps3 + localMaps5 := make([]interface{}, 0) + localData6 := dataLoop1Tmp["machine_type_policy"] + for _, dataLoop6 := range localData6.([]interface{}) { + dataLoop6Tmp := dataLoop6.(map[string]interface{}) + dataLoop6Map := make(map[string]interface{}) + dataLoop6Map["MachineType"] = dataLoop6Tmp["machine_type"] + localData2, err := jsonpath.Get("$.bonds", dataLoop6Tmp) + if err != nil { + localData2 = make([]interface{}, 0) + } + localMaps2 := make([]interface{}, 0) + for _, dataLoop2 := range localData2.([]interface{}) { + 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"] + localMaps2 = append(localMaps2, dataLoop2Map) + } + dataLoop6Map["Bonds"] = localMaps2 + localMaps5 = append(localMaps5, dataLoop6Map) + } + dataLoop1Map["MachineTypePolicy"] = localMaps5 + ipAllocationPolicyMapsArray = append(ipAllocationPolicyMapsArray, dataLoop1Map) + } + ipAllocationPolicyMapsJson, err := json.Marshal(ipAllocationPolicyMapsArray) + if err != nil { + return WrapError(err) + } + request["IpAllocationPolicy"] = string(ipAllocationPolicyMapsJson) + + localData8 := d.Get("vpd_subnets").([]interface{}) + vpdSubnetsMapsArray := localData8 + vpdSubnetsMapsJson, err := json.Marshal(vpdSubnetsMapsArray) + if err != nil { + return WrapError(err) + } + request["VpdSubnets"] = string(vpdSubnetsMapsJson) + + if v, ok := d.GetOkExists("ignore_failed_node_tasks"); ok { + request["IgnoreFailedNodeTasks"] = v + } + if v, ok := d.GetOk("vswitch_zone_id"); ok { + request["VSwitchZoneId"] = v + } + jsonString := convertObjectToJsonString(request) + jsonString, _ = sjson.Set(jsonString, "NodeGroups.0.NodeGroupId", parts[1]) + _ = 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{"execution_success"}, d.Timeout(schema.TimeoutUpdate), 10*time.Second, efloServiceV2.DescribeAsyncEfloNodeGroupStateRefreshFunc(d, response, "$.TaskState", []string{})) + if jobDetail, err := stateConf.WaitForState(); err != nil { + return WrapErrorf(err, IdMsg, d.Id(), jobDetail) + } + + } + + } + return resourceAliCloudEfloNodeGroupRead(d, meta) +} + +func resourceAliCloudEfloNodeGroupDelete(d *schema.ResourceData, meta interface{}) error { + + client := meta.(*connectivity.AliyunClient) + parts := strings.Split(d.Id(), ":") + action := "DeleteNodeGroup" + var request map[string]interface{} + var response map[string]interface{} + query := make(map[string]interface{}) + var err error + request = make(map[string]interface{}) + request["ClusterId"] = parts[0] + request["NodeGroupId"] = parts[1] + request["RegionId"] = client.RegionId + + wait := incrementalWait(3*time.Second, 5*time.Second) + err = resource.Retry(d.Timeout(schema.TimeoutDelete), 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 { + if NotFoundError(err) { + return nil + } + return WrapErrorf(err, DefaultErrorMsg, d.Id(), action, AlibabaCloudSdkGoERROR) + } + + return nil +} diff --git a/alicloud/resource_alicloud_eflo_node_group_test.go b/alicloud/resource_alicloud_eflo_node_group_test.go new file mode 100644 index 000000000000..bf76b0020fde --- /dev/null +++ b/alicloud/resource_alicloud_eflo_node_group_test.go @@ -0,0 +1,162 @@ +package alicloud + +import ( + "fmt" + "testing" + + "github.com/aliyun/terraform-provider-alicloud/alicloud/connectivity" + "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" +) + +func TestAccAliCloudEfloNodeGroup_basic10344(t *testing.T) { + var v map[string]interface{} + resourceId := "alicloud_eflo_node_group.default" + ra := resourceAttrInit(resourceId, AlicloudEfloNodeGroupMap10344) + rc := resourceCheckInitWithDescribeMethod(resourceId, &v, func() interface{} { + return &EfloServiceV2{testAccProvider.Meta().(*connectivity.AliyunClient)} + }, "DescribeEfloNodeGroup") + rac := resourceAttrCheckInit(rc, ra) + testAccCheck := rac.resourceAttrMapUpdateSet() + rand := acctest.RandIntRange(10000, 99999) + name := fmt.Sprintf("tfacceflo%d", rand) + testAccConfig := resourceTestAccConfigFunc(resourceId, name, AlicloudEfloNodeGroupBasicDependence10344) + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + testAccPreCheckWithRegions(t, true, []connectivity.Region{"cn-hangzhou"}) + }, + IDRefreshName: resourceId, + Providers: testAccProviders, + CheckDestroy: rac.checkResourceDestroy(), + Steps: []resource.TestStep{ + { + Config: testAccConfig(map[string]interface{}{ + "node_group_description": "resource-test1", + "node_group_name": name, + "cluster_id": "i118078301742281630607", + "machine_type": "efg2.C48cA3sen", + "az": "cn-hangzhou-b", + "image_id": "i198448731735114628708", + }), + Check: resource.ComposeTestCheckFunc( + testAccCheck(map[string]string{ + "node_group_description": "resource-test1", + "node_group_name": name, + "cluster_id": "i118078301742281630607", + "machine_type": "efg2.C48cA3sen", + "az": "cn-hangzhou-b", + "image_id": "i198448731735114628708", + }), + ), + }, + { + Config: testAccConfig(map[string]interface{}{ + "node_group_name": name + "_update", + "nodes": []map[string]interface{}{ + { + "login_password": "Alibaba@2025", + "node_id": "e01-cn-rno46i6rdfn", + "vpc_id": "vpc-bp15z92ev9jflxq14c2l0", + "vswitch_id": "vsw-bp1lii10s3tl99bpx20mo", + "hostname": "jxyhostname", + }, + //{ + // "login_password": "Alibaba@2025", + // "node_id": "e01-cn-rno46i6rdfn-mock", + // "vpc_id": "vpc-bp15z92ev9jflxq14c2l0", + // "vswitch_id": "vsw-bp1lii10s3tl99bpx20mo", + // "hostname": "jxyhostname", + //}, + }, + "ignore_failed_node_tasks": "true", + "zone_id": "cn-hangzhou-b", + "user_data": "YWxpLGFsaSxhbGliYWJh", + "vpd_subnets": []string{ + "test"}, + "vswitch_zone_id": "cn-hangzhou-b", + "ip_allocation_policy": []map[string]interface{}{ + { + "bond_policy": []map[string]interface{}{ + { + "bond_default_subnet": "test", + "bonds": []map[string]interface{}{ + { + "name": "test", + "subnet": "test", + }, + }, + }, + }, + "machine_type_policy": []map[string]interface{}{ + { + "bonds": []map[string]interface{}{ + { + "name": "test", + "subnet": "test", + }, + }, + "machine_type": "test", + }, + }, + "node_policy": []map[string]interface{}{ + { + "bonds": []map[string]interface{}{ + { + "name": "test", + "subnet": "test", + }, + }, + "node_id": "e01-cn-rno46i6rdfn", + }, + }, + }, + }, + }), + Check: resource.ComposeTestCheckFunc( + testAccCheck(map[string]string{ + "node_group_name": name + "_update", + "nodes.#": "1", + "ignore_failed_node_tasks": "true", + "zone_id": "cn-hangzhou-b", + "user_data": "YWxpLGFsaSxhbGliYWJh", + "vpd_subnets.#": "1", + "vswitch_zone_id": "cn-hangzhou-b", + "ip_allocation_policy.#": "1", + }), + ), + }, + { + Config: testAccConfig(map[string]interface{}{ + "nodes": REMOVEKEY, + }), + Check: resource.ComposeTestCheckFunc( + testAccCheck(map[string]string{ + "nodes.#": "0", + }), + ), + }, + { + ResourceName: resourceId, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"ignore_failed_node_tasks", "ip_allocation_policy", "user_data", "vswitch_zone_id", "vpd_subnets", "zone_id"}, + }, + }, + }) +} + +var AlicloudEfloNodeGroupMap10344 = map[string]string{ + "create_time": CHECKSET, + "node_group_id": CHECKSET, +} + +func AlicloudEfloNodeGroupBasicDependence10344(name string) string { + return fmt.Sprintf(` +variable "name" { + default = "%s" +} + + +`, name) +} diff --git a/alicloud/resource_alicloud_eflo_node_test.go b/alicloud/resource_alicloud_eflo_node_test.go new file mode 100644 index 000000000000..5d5061405f92 --- /dev/null +++ b/alicloud/resource_alicloud_eflo_node_test.go @@ -0,0 +1,100 @@ +package alicloud + +import ( + "fmt" + "testing" + + "github.com/aliyun/terraform-provider-alicloud/alicloud/connectivity" + "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" +) + +func TestAccAliCloudEfloNode_basic10171(t *testing.T) { + var v map[string]interface{} + resourceId := "alicloud_eflo_node.default" + ra := resourceAttrInit(resourceId, AlicloudEfloNodeMap10171) + rc := resourceCheckInitWithDescribeMethod(resourceId, &v, func() interface{} { + return &EfloServiceV2{testAccProvider.Meta().(*connectivity.AliyunClient)} + }, "DescribeEfloNode") + rac := resourceAttrCheckInit(rc, ra) + testAccCheck := rac.resourceAttrMapUpdateSet() + rand := acctest.RandIntRange(10000, 99999) + name := fmt.Sprintf("tfacceflo%d", rand) + testAccConfig := resourceTestAccConfigFunc(resourceId, name, AlicloudEfloNodeBasicDependence10171) + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + testAccPreCheckWithRegions(t, true, []connectivity.Region{"cn-hangzhou"}) + }, + IDRefreshName: resourceId, + Providers: testAccProviders, + CheckDestroy: rac.checkResourceDestroy(), + Steps: []resource.TestStep{ + { + Config: testAccConfig(map[string]interface{}{ + "resource_group_id": "${data.alicloud_resource_manager_resource_groups.default.ids.0}", + "period": "36", + "discount_level": "36", + "billing_cycle": "1month", + "classify": "gpuserver", + "zone": "cn-hangzhou-b", + "product_form": "instance", + "payment_ratio": "0", + "hpn_zone": "B1", + "server_arch": "bmserver", + "computing_server": "efg2.C48cA3sen", + "stage_num": "36", + }), + Check: resource.ComposeTestCheckFunc( + testAccCheck(map[string]string{ + "resource_group_id": CHECKSET, + "period": "36", + "discount_level": CHECKSET, + "billing_cycle": "1month", + "classify": "gpuserver", + "zone": "cn-hangzhou-b", + "product_form": "instance", + "payment_ratio": CHECKSET, + "hpn_zone": "B1", + "server_arch": "bmserver", + "computing_server": "efg2.C48cA3sen", + "stage_num": CHECKSET, + }), + ), + }, + { + Config: testAccConfig(map[string]interface{}{ + "resource_group_id": "${data.alicloud_resource_manager_resource_groups.default.ids.1}", + }), + Check: resource.ComposeTestCheckFunc( + testAccCheck(map[string]string{ + "resource_group_id": CHECKSET, + }), + ), + }, + { + ResourceName: resourceId, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"billing_cycle", "classify", "computing_server", "discount_level", "hpn_zone", "payment_ratio", "period", "pricing_cycle", "product_code", "product_form", "product_type", "renew_period", "renewal_status", "server_arch", "stage_num", "subscription_type", "zone"}, + }, + }, + }) +} + +var AlicloudEfloNodeMap10171 = map[string]string{ + "status": CHECKSET, + "create_time": CHECKSET, +} + +func AlicloudEfloNodeBasicDependence10171(name string) string { + return fmt.Sprintf(` +variable "name" { + default = "%s" +} + +data "alicloud_resource_manager_resource_groups" "default" {} + + +`, name) +} diff --git a/alicloud/service_alicloud_eflo_v2.go b/alicloud/service_alicloud_eflo_v2.go new file mode 100644 index 000000000000..7a1d7d2d4f17 --- /dev/null +++ b/alicloud/service_alicloud_eflo_v2.go @@ -0,0 +1,537 @@ +package alicloud + +import ( + "fmt" + "strings" + "time" + + "github.com/PaesslerAG/jsonpath" + "github.com/aliyun/terraform-provider-alicloud/alicloud/connectivity" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +type EfloServiceV2 struct { + client *connectivity.AliyunClient +} + +// DescribeEfloNode <<< Encapsulated get interface for Eflo Node. + +func (s *EfloServiceV2) DescribeEfloNode(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["NodeId"] = id + request["RegionId"] = client.RegionId + action := "DescribeNode" + + 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 { + if IsExpectedErrors(err, []string{"RESOURCE_NOT_FOUND"}) || NotFoundError(err) { + return object, WrapErrorf(Error(GetNotFoundMessage("EfloNode", id)), NotFoundMsg, response) + } + return object, WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR) + } + + return response, nil +} + +func (s *EfloServiceV2) EfloNodeStateRefreshFunc(id string, field string, failStates []string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + object, err := s.DescribeEfloNode(id) + if err != nil { + if NotFoundError(err) { + return nil, "", nil + } + return nil, "", WrapError(err) + } + + v, err := jsonpath.Get(field, object) + currentStatus := fmt.Sprint(v) + + if strings.HasPrefix(field, "#") { + v, _ := jsonpath.Get(strings.TrimPrefix(field, "#"), object) + if v != nil { + currentStatus = "#CHECKSET" + } + } + + for _, failState := range failStates { + if currentStatus == failState { + return object, currentStatus, WrapError(Error(FailedToReachTargetStatus, currentStatus)) + } + } + return object, currentStatus, nil + } +} + +// DescribeEfloNode >>> Encapsulated. + +// DescribeEfloCluster <<< Encapsulated get interface for Eflo Cluster. + +func (s *EfloServiceV2) DescribeEfloCluster(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["ClusterId"] = id + request["RegionId"] = client.RegionId + action := "DescribeCluster" + + 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) + } + + currentStatus := response["ClusterId"] + if currentStatus == nil { + return object, WrapErrorf(Error(GetNotFoundMessage("Cluster", id)), NotFoundMsg, response) + } + + return response, nil +} +func (s *EfloServiceV2) DescribeClusterListTagResources(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["ResourceId.1"] = id + request["RegionId"] = client.RegionId + request["ResourceType"] = "Cluster" + action := "ListTagResources" + + 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) + } + + return response, nil +} + +func (s *EfloServiceV2) EfloClusterStateRefreshFunc(id string, field string, failStates []string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + object, err := s.DescribeEfloCluster(id) + if err != nil { + if NotFoundError(err) { + return object, "", nil + } + return nil, "", WrapError(err) + } + + v, err := jsonpath.Get(field, object) + currentStatus := fmt.Sprint(v) + + if strings.HasPrefix(field, "#") { + v, _ := jsonpath.Get(strings.TrimPrefix(field, "#"), object) + if v != nil { + currentStatus = "#CHECKSET" + } + } + + for _, failState := range failStates { + if currentStatus == failState { + return object, currentStatus, WrapError(Error(FailedToReachTargetStatus, currentStatus)) + } + } + return object, currentStatus, nil + } +} + +// DescribeEfloCluster >>> Encapsulated. + +// SetResourceTags <<< Encapsulated tag function for Eflo. +func (s *EfloServiceV2) SetResourceTags(d *schema.ResourceData, resourceType string) error { + if d.HasChange("tags") { + var action string + var err error + client := s.client + var request map[string]interface{} + var response map[string]interface{} + query := make(map[string]interface{}) + + added, removed := parsingTags(d) + removedTagKeys := make([]string, 0) + for _, v := range removed { + if !ignoredTags(v, "") { + removedTagKeys = append(removedTagKeys, v) + } + } + if len(removedTagKeys) > 0 { + action = "UntagResources" + request = make(map[string]interface{}) + query = make(map[string]interface{}) + request["ResourceId.1"] = d.Id() + request["RegionId"] = client.RegionId + for i, key := range removedTagKeys { + request[fmt.Sprintf("TagKey.%d", i+1)] = key + } + + request["ResourceType"] = resourceType + 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) + } + + } + + if len(added) > 0 { + action = "TagResources" + request = make(map[string]interface{}) + query = make(map[string]interface{}) + request["ResourceId.1"] = d.Id() + request["RegionId"] = client.RegionId + count := 1 + for key, value := range added { + request[fmt.Sprintf("Tag.%d.Key", count)] = key + request[fmt.Sprintf("Tag.%d.Value", count)] = value + count++ + } + + request["ResourceType"] = resourceType + 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) + } + + } + } + + return nil +} + +// SetResourceTags >>> tag function encapsulated. + +// DescribeEfloNodeGroup <<< Encapsulated get interface for Eflo NodeGroup. + +func (s *EfloServiceV2) DescribeEfloNodeGroup(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{} + parts := strings.Split(id, ":") + if len(parts) != 2 { + err = WrapError(fmt.Errorf("invalid Resource Id %s. Expected parts' length %d, got %d", id, 2, len(parts))) + } + request = make(map[string]interface{}) + query = make(map[string]interface{}) + request["ClusterId"] = parts[0] + request["NodeGroupId"] = parts[1] + request["RegionId"] = client.RegionId + action := "ListNodeGroups" + + 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("$.Groups[*]", response) + if err != nil { + return object, WrapErrorf(Error(GetNotFoundMessage("NodeGroup", id)), NotFoundMsg, response) + } + + if len(v.([]interface{})) == 0 { + return object, WrapErrorf(Error(GetNotFoundMessage("NodeGroup", id)), NotFoundMsg, response) + } + + currentStatus := v.([]interface{})[0].(map[string]interface{})["GroupId"] + if currentStatus == nil { + return object, WrapErrorf(Error(GetNotFoundMessage("NodeGroup", id)), NotFoundMsg, response) + } + + return v.([]interface{})[0].(map[string]interface{}), nil +} +func (s *EfloServiceV2) DescribeNodeGroupListClusterNodes(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{} + parts := strings.Split(id, ":") + if len(parts) != 2 { + err = WrapError(fmt.Errorf("invalid Resource Id %s. Expected parts' length %d, got %d", id, 2, len(parts))) + } + request = make(map[string]interface{}) + query = make(map[string]interface{}) + request["ClusterId"] = parts[0] + request["NodeGroupId"] = parts[1] + 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) + } + + return response, nil +} + +func (s *EfloServiceV2) EfloNodeGroupStateRefreshFunc(id string, field string, failStates []string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + object, err := s.DescribeEfloNodeGroup(id) + if err != nil { + if NotFoundError(err) { + return object, "", nil + } + return nil, "", WrapError(err) + } + + v, err := jsonpath.Get(field, object) + currentStatus := fmt.Sprint(v) + + if strings.HasPrefix(field, "#") { + v, _ := jsonpath.Get(strings.TrimPrefix(field, "#"), object) + if v != nil { + currentStatus = "#CHECKSET" + } + } + + for _, failState := range failStates { + if currentStatus == failState { + return object, currentStatus, WrapError(Error(FailedToReachTargetStatus, currentStatus)) + } + } + return object, currentStatus, nil + } +} + +func (s *EfloServiceV2) DescribeAsyncEfloNodeGroupStateRefreshFunc(d *schema.ResourceData, res map[string]interface{}, field string, failStates []string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + object, err := s.DescribeAsyncDescribeTask(d, res) + if err != nil { + if NotFoundError(err) { + return object, "", nil + } + } + + v, err := jsonpath.Get(field, object) + currentStatus := fmt.Sprint(v) + + if strings.HasPrefix(field, "#") { + v, _ := jsonpath.Get(strings.TrimPrefix(field, "#"), object) + if v != nil { + currentStatus = "#CHECKSET" + } + } + + for _, failState := range failStates { + if currentStatus == failState { + if _err, ok := object["error"]; ok { + return _err, currentStatus, WrapError(Error(FailedToReachTargetStatus, currentStatus)) + } + return object, currentStatus, WrapError(Error(FailedToReachTargetStatus, currentStatus)) + } + } + return object, currentStatus, nil + } +} + +// DescribeEfloNodeGroup >>> Encapsulated. + +// DescribeAsyncDescribeTask <<< Encapsulated for Eflo. +func (s *EfloServiceV2) DescribeAsyncDescribeTask(d *schema.ResourceData, res map[string]interface{}) (object map[string]interface{}, err error) { + client := s.client + id := d.Id() + var request map[string]interface{} + var response map[string]interface{} + var query map[string]interface{} + parts := strings.Split(id, ":") + if len(parts) != 2 { + err = WrapError(fmt.Errorf("invalid Resource Id %s. Expected parts' length %d, got %d", id, 2, len(parts))) + } + request = make(map[string]interface{}) + query = make(map[string]interface{}) + query["TaskId"], err = jsonpath.Get("$.TaskId", res) + request["RegionId"] = client.RegionId + action := "DescribeTask" + + 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 response, WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR) + } + + return response, nil +} + +// DescribeAsyncDescribeTask >>> Encapsulated. + +// DescribeEfloInvocation <<< Encapsulated get interface for Eflo Invocation. + +func (s *EfloServiceV2) DescribeEfloInvocation(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["InvokeId"] = id + request["RegionId"] = client.RegionId + action := "DescribeInvocations" + + 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("$.Invocations.Invocation[*]", response) + if err != nil { + return object, WrapErrorf(err, FailedGetAttributeMsg, id, "$.Invocations.Invocation[*]", response) + } + + if len(v.([]interface{})) == 0 { + return object, WrapErrorf(Error(GetNotFoundMessage("Invocation", id)), NotFoundMsg, response) + } + + return v.([]interface{})[0].(map[string]interface{}), nil +} + +func (s *EfloServiceV2) EfloInvocationStateRefreshFunc(id string, field string, failStates []string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + object, err := s.DescribeEfloInvocation(id) + if err != nil { + if NotFoundError(err) { + return object, "", nil + } + return nil, "", WrapError(err) + } + + v, err := jsonpath.Get(field, object) + currentStatus := fmt.Sprint(v) + + if strings.HasPrefix(field, "#") { + v, _ := jsonpath.Get(strings.TrimPrefix(field, "#"), object) + if v != nil { + currentStatus = "#CHECKSET" + } + } + + for _, failState := range failStates { + if currentStatus == failState { + return object, currentStatus, WrapError(Error(FailedToReachTargetStatus, currentStatus)) + } + } + return object, currentStatus, nil + } +} + +// DescribeEfloInvocation >>> Encapsulated. diff --git a/website/docs/r/eflo_cluster.html.markdown b/website/docs/r/eflo_cluster.html.markdown new file mode 100644 index 000000000000..436e6ae43fd6 --- /dev/null +++ b/website/docs/r/eflo_cluster.html.markdown @@ -0,0 +1,275 @@ +--- +subcategory: "Eflo" +layout: "alicloud" +page_title: "Alicloud: alicloud_eflo_cluster" +description: |- + Provides a Alicloud Eflo Cluster resource. +--- + +# alicloud_eflo_cluster + +Provides a Eflo Cluster resource. + +Large computing cluster. + +For information about Eflo Cluster and how to use it, see [What is Cluster](https://next.api.alibabacloud.com/document/eflo-controller/2022-12-15/CreateCluster). + +-> **NOTE:** Available since v1.246.0. + +## Example Usage + +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" { + default = "terraform-example" +} + +provider "alicloud" { + region = "cn-hangzhou" +} + +data "alicloud_resource_manager_resource_groups" "default" {} + +resource "alicloud_vpc" "create_vpc" { + cidr_block = "192.168.0.0/16" + vpc_name = "cluster-resoure-example" +} + +resource "alicloud_vswitch" "create_vswitch" { + vpc_id = alicloud_vpc.create_vpc.id + zone_id = "cn-hangzhou-b" + cidr_block = "192.168.0.0/24" + vswitch_name = "cluster-resoure-example" +} + +resource "alicloud_security_group" "create_security_group" { + description = "sg" + security_group_name = "cluster-resoure-example" + security_group_type = "normal" + vpc_id = alicloud_vpc.create_vpc.id +} + +resource "alicloud_eflo_cluster" "default" { + cluster_description = "cluster-resource-example" + open_eni_jumbo_frame = "false" + hpn_zone = "B1" + nimiz_vswitches = [ + "1111" + ] + ignore_failed_node_tasks = "true" + resource_group_id = data.alicloud_resource_manager_resource_groups.default.ids.1 + node_groups { + image_id = "i198448731735114628708" + zone_id = "cn-hangzhou-b" + node_group_name = "cluster-resource-example" + node_group_description = "cluster-resource-example" + machine_type = "efg2.C48cA3sen" + } + + networks { + tail_ip_version = "ipv4" + new_vpd_info { + monitor_vpc_id = alicloud_vpc.create_vpc.id + monitor_vswitch_id = alicloud_vswitch.create_vswitch.id + cen_id = "11111" + cloud_link_id = "1111" + vpd_cidr = "111" + vpd_subnets { + zone_id = "1111" + subnet_cidr = "111" + subnet_type = "111" + } + cloud_link_cidr = "169.254.128.0/23" + } + + security_group_id = alicloud_security_group.create_security_group.id + vswitch_zone_id = "cn-hangzhou-b" + vpc_id = alicloud_vpc.create_vpc.id + vswitch_id = alicloud_vswitch.create_vswitch.id + vpd_info { + vpd_id = "111" + vpd_subnets = [ + "111" + ] + } + ip_allocation_policy { + bond_policy { + bond_default_subnet = "111" + bonds { + name = "111" + subnet = "111" + } + } + machine_type_policy { + bonds { + name = "111" + subnet = "111" + } + machine_type = "111" + } + node_policy { + bonds { + name = "111" + subnet = "111" + } + node_id = "111" + } + } + } + + cluster_name = "tfacceflo7165" + cluster_type = "Lite" +} +``` + +## Argument Reference + +The following arguments are supported: +* `cluster_description` - (Optional, ForceNew) cluster description +* `cluster_name` - (Optional, ForceNew) ClusterName +* `cluster_type` - (Optional, ForceNew) cluster type +* `components` - (Optional, List) Component (software instance) See [`components`](#components) below. +* `hpn_zone` - (Optional) Cluster Number +* `ignore_failed_node_tasks` - (Optional) Whether to allow skipping failed nodes. Default value: False +* `networks` - (Optional, List) Network Information See [`networks`](#networks) below. +* `nimiz_vswitches` - (Optional, List) Node virtual switch +* `node_groups` - (Optional, List) Node Group List See [`node_groups`](#node_groups) below. +* `open_eni_jumbo_frame` - (Optional) Whether the network interface supports jumbo frames +* `resource_group_id` - (Optional, Computed) The ID of the resource group +* `tags` - (Optional, Map) tag + +### `components` + +The components supports the following: +* `component_config` - (Optional, List) Component Configuration See [`component_config`](#components-component_config) below. +* `component_type` - (Optional) Component Type + +### `components-component_config` + +The components-component_config supports the following: +* `basic_args` - (Optional) Component Basic Parameters +* `node_units` - (Optional, List) Node pool configuration, and is used to establish the corresponding relationship between node groups and node pools. When +ComponentType = "ACKEdge" is required. Other values are empty. + +### `networks` + +The networks supports the following: +* `ip_allocation_policy` - (Optional, List) IP allocation policy See [`ip_allocation_policy`](#networks-ip_allocation_policy) below. +* `new_vpd_info` - (Optional, List) Vpd configuration information See [`new_vpd_info`](#networks-new_vpd_info) below. +* `security_group_id` - (Optional) Security group ID +* `tail_ip_version` - (Optional) IP version +* `vswitch_id` - (Optional) Switch ID +* `vswitch_zone_id` - (Optional) Switch ZoneID +* `vpc_id` - (Optional) VPC ID +* `vpd_info` - (Optional, List) Multiplexing VPD information See [`vpd_info`](#networks-vpd_info) below. + +### `networks-ip_allocation_policy` + +The networks-ip_allocation_policy supports the following: +* `bond_policy` - (Optional, List) Bond policy See [`bond_policy`](#networks-ip_allocation_policy-bond_policy) below. +* `machine_type_policy` - (Optional, List) Model Assignment Policy See [`machine_type_policy`](#networks-ip_allocation_policy-machine_type_policy) below. +* `node_policy` - (Optional, List) Node allocation policy See [`node_policy`](#networks-ip_allocation_policy-node_policy) below. + +### `networks-new_vpd_info` + +The networks-new_vpd_info supports the following: +* `cen_id` - (Optional) Cloud Enterprise Network ID +* `cloud_link_cidr` - (Optional) Cloud chain cidr +* `cloud_link_id` - (Optional) Cloud chain ID +* `monitor_vpc_id` - (Optional) Proprietary Network +* `monitor_vswitch_id` - (Optional) Proprietary network switch +* `vpd_cidr` - (Optional) Cluster network segment +* `vpd_subnets` - (Optional, List) Cluster Subnet See [`vpd_subnets`](#networks-new_vpd_info-vpd_subnets) below. + +### `networks-vpd_info` + +The networks-vpd_info supports the following: +* `vpd_id` - (Optional) VPC ID +* `vpd_subnets` - (Optional, List) List of cluster subnet ID + +### `networks-new_vpd_info-vpd_subnets` + +The networks-new_vpd_info-vpd_subnets supports the following: +* `subnet_cidr` - (Optional) Subnet cidr +* `subnet_type` - (Optional) Subnet Type +* `zone_id` - (Optional) Zone ID + +### `networks-ip_allocation_policy-bond_policy` + +The networks-ip_allocation_policy-bond_policy supports the following: +* `bond_default_subnet` - (Optional) Default bond cluster subnet +* `bonds` - (Optional, List) Bond information See [`bonds`](#networks-ip_allocation_policy-bond_policy-bonds) below. + +### `networks-ip_allocation_policy-machine_type_policy` + +The networks-ip_allocation_policy-machine_type_policy supports the following: +* `bonds` - (Optional, List) Bond information See [`bonds`](#networks-ip_allocation_policy-machine_type_policy-bonds) below. +* `machine_type` - (Optional) Model + +### `networks-ip_allocation_policy-node_policy` + +The networks-ip_allocation_policy-node_policy supports the following: +* `bonds` - (Optional, List) Bond information See [`bonds`](#networks-ip_allocation_policy-node_policy-bonds) below. +* `node_id` - (Optional) Node ID + +### `networks-ip_allocation_policy-node_policy-bonds` + +The networks-ip_allocation_policy-node_policy-bonds supports the following: +* `name` - (Optional) The bond name +* `subnet` - (Optional) IP source cluster subnet + +### `networks-ip_allocation_policy-machine_type_policy-bonds` + +The networks-ip_allocation_policy-machine_type_policy-bonds supports the following: +* `name` - (Optional) The bond name +* `subnet` - (Optional) IP source cluster subnet + +### `networks-ip_allocation_policy-bond_policy-bonds` + +The networks-ip_allocation_policy-bond_policy-bonds supports the following: +* `name` - (Optional) The bond name +* `subnet` - (Optional) IP source cluster subnet + +### `node_groups` + +The node_groups supports the following: +* `image_id` - (Optional) System Image ID +* `machine_type` - (Optional) Model +* `node_group_description` - (Optional) Node Group Description +* `node_group_name` - (Optional) Node Group Name +* `nodes` - (Optional, List) Node List See [`nodes`](#node_groups-nodes) below. +* `user_data` - (Optional) Instance custom data. It needs to be encoded in Base64 mode, and the original data is at most 16KB. +* `zone_id` - (Optional) Zone ID + +### `node_groups-nodes` + +The node_groups-nodes supports the following: +* `hostname` - (Optional) Host name +* `login_password` - (Optional) Login Password +* `node_id` - (Optional) Node ID +* `vswitch_id` - (Optional) Virtual Switch ID +* `vpc_id` - (Optional) VPC ID + +## Attributes Reference + +The following attributes are exported: +* `id` - The ID of the resource supplied above. +* `create_time` - The creation time of the resource +* `status` - The status of the resource + +## Timeouts + +The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration-0-11/resources.html#timeouts) for certain actions: +* `create` - (Defaults to 5 mins) Used when create the Cluster. +* `delete` - (Defaults to 5 mins) Used when delete the Cluster. +* `update` - (Defaults to 5 mins) Used when update the Cluster. + +## Import + +Eflo Cluster can be imported using the id, e.g. + +```shell +$ terraform import alicloud_eflo_cluster.example +``` \ No newline at end of file diff --git a/website/docs/r/eflo_invocation.html.markdown b/website/docs/r/eflo_invocation.html.markdown new file mode 100644 index 000000000000..0baacce39e9a --- /dev/null +++ b/website/docs/r/eflo_invocation.html.markdown @@ -0,0 +1,290 @@ +--- +subcategory: "Eflo" +layout: "alicloud" +page_title: "Alicloud: alicloud_eflo_invocation" +description: |- + Provides a Alicloud Eflo Invocation resource. +--- + +# alicloud_eflo_invocation + +Provides a Eflo Invocation resource. + +Cloud assistant command execution on the node. + +For information about Eflo Invocation and how to use it, see [What is Invocation](https://next.api.alibabacloud.com/document/eflo-controller/2022-12-15/RunCommand). + +-> **NOTE:** Available since v1.246.0. + +## Example Usage + +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" { + default = "terraform-example" +} + +provider "alicloud" { + region = "cn-hangzhou" +} + +data "alicloud_resource_manager_resource_groups" "default" {} + +resource "alicloud_vpc" "create_vpc" { + cidr_block = "192.168.0.0/16" + vpc_name = "cluster-resoure-example" +} + +resource "alicloud_vswitch" "create_vswitch" { + vpc_id = alicloud_vpc.create_vpc.id + zone_id = "cn-hangzhou-b" + cidr_block = "192.168.0.0/24" + vswitch_name = "cluster-resoure-example" +} + +resource "alicloud_security_group" "create_security_group" { + description = "sg" + security_group_name = "cluster-resoure-example" + security_group_type = "normal" + vpc_id = alicloud_vpc.create_vpc.id +} + +resource "alicloud_eflo_cluster" "default" { + cluster_description = "cluster-resource-example" + open_eni_jumbo_frame = "false" + hpn_zone = "B1" + nimiz_vswitches = [ + "1111" + ] + ignore_failed_node_tasks = "true" + resource_group_id = data.alicloud_resource_manager_resource_groups.default.ids.1 + node_groups { + image_id = "i198448731735114628708" + zone_id = "cn-hangzhou-b" + node_group_name = "cluster-resource-example" + node_group_description = "cluster-resource-example" + machine_type = "efg2.C48cA3sen" + } + + networks { + tail_ip_version = "ipv4" + new_vpd_info { + monitor_vpc_id = alicloud_vpc.create_vpc.id + monitor_vswitch_id = alicloud_vswitch.create_vswitch.id + cen_id = "11111" + cloud_link_id = "1111" + vpd_cidr = "111" + vpd_subnets { + zone_id = "1111" + subnet_cidr = "111" + subnet_type = "111" + } + cloud_link_cidr = "169.254.128.0/23" + } + + security_group_id = alicloud_security_group.create_security_group.id + vswitch_zone_id = "cn-hangzhou-b" + vpc_id = alicloud_vpc.create_vpc.id + vswitch_id = alicloud_vswitch.create_vswitch.id + vpd_info { + vpd_id = "111" + vpd_subnets = [ + "111" + ] + } + ip_allocation_policy { + bond_policy { + bond_default_subnet = "111" + bonds { + name = "111" + subnet = "111" + } + } + machine_type_policy { + bonds { + name = "111" + subnet = "111" + } + machine_type = "111" + } + node_policy { + bonds { + name = "111" + subnet = "111" + } + node_id = "111" + } + } + } + + cluster_name = "tfacceflo7165" + cluster_type = "Lite" +} + +resource "alicloud_eflo_node" "default" { + period = "36" + discount_level = "36" + billing_cycle = "1month" + classify = "gpuserver" + zone = "cn-hangzhou-b" + product_form = "instance" + payment_ratio = "0" + hpn_zone = "B1" + server_arch = "bmserver" + computing_server = "efg1.nvga1n" + stage_num = "36" + renewal_status = "AutoRenewal" + renew_period = "36" + status = "Unused" +} + +resource "alicloud_eflo_node_group" "default" { + nodes { + node_id = alicloud_eflo_node.default.id + vpc_id = alicloud_vpc.create_vpc.id + vswitch_id = alicloud_vswitch.create_vswitch.id + hostname = "jxyhostname" + login_password = "Alibaba@2025" + } + + ignore_failed_node_tasks = "true" + cluster_id = alicloud_eflo_cluster.default.id + image_id = "i195048661660874208657" + zone_id = "cn-hangzhou-b" + vpd_subnets = [ + "example" + ] + user_data = "YWxpLGFsaSxhbGliYWJh" + vswitch_zone_id = "cn-hangzhou-b" + ip_allocation_policy { + bond_policy { + bond_default_subnet = "example" + bonds { + name = "example" + subnet = "example" + } + } + machine_type_policy { + bonds { + name = "example" + subnet = "example" + } + machine_type = "example" + } + node_policy { + node_id = alicloud_eflo_node.default.id + bonds { + name = "example" + subnet = "example" + } + } + } + machine_type = "efg1.nvga1" + az = "cn-hangzhou-b" + node_group_description = "resource-example1" + node_group_name = "tfacceflo63657_update" +} + +resource "alicloud_eflo_invocation" "default" { + description = "example" + content_encoding = "Base64" + name = "resource-example" + repeat_mode = "Once" + parameters { + name = "example" + } + node_id_list = [alicloud_eflo_node.default.id] + timeout = "68" + command_content = "ZWNobyAxMjM=" + working_dir = "/home/" + username = "root" + enable_parameter = false + termination_mode = "ProcessTree" +} +``` + +### Deleting `alicloud_eflo_invocation` or removing it from your configuration + +Terraform cannot destroy resource `alicloud_eflo_invocation`. Terraform will remove this resource from the state file, however resources may remain. + +## Argument Reference + +The following arguments are supported: +* `command_content` - (Optional) The command content. You need to pay attention: + - Specify the parameter 'EnableParameter = true' to enable the custom parameter feature in the command content. + - Define custom parameters in the form of {{}} inclusion, and spaces and line breaks before and after the parameter name in '{{}}' are ignored. + - The number of custom parameters cannot exceed 20. + - Custom parameter names can a-zA-Z0-9 a combination of-_. Other characters are not supported. Parameter names are not case-sensitive. + - A single custom parameter name cannot exceed 64 bytes. +* `command_id` - (Optional) Command ID +* `content_encoding` - (Optional) The encoding of the script content. Value range: + - PlainText: no encoding, using PlainText transmission. + - Base64:Base64 encoding. + +Default value: PlainText. If you fill it randomly or wrongly, the value will be treated as a PlainText. +* `description` - (Optional) The command description. +* `enable_parameter` - (Optional) Whether custom parameters are included in the command. +Default value: false. +* `frequency` - (Optional) The execution time of the scheduled execution command. Currently, three scheduled execution methods are supported: fixed interval execution (based on Rate expression), only once at a specified time, and timed execution based on clock (based on Cron expression). + - Fixed time interval execution: Based on the Rate expression, the command is executed at the set time interval. Time intervals can be selected by seconds (s), minutes (m), hours (h), and days (d), which is suitable for scenarios where tasks are executed at fixed time intervals. The format is rate( ). If the execution is performed every 5 minutes, the format is rate(5m). Executing with a fixed time interval has the following limitations: + - The set time interval is no more than 7 days and no less than 60 seconds, and must be greater than the timeout period of the scheduled task. + - The execution interval is based only on a fixed frequency, independent of the time the task actually takes to execute. For example, if the command is executed every 5 minutes and the task takes 2 minutes to complete, the next round will be executed 3 minutes after the task is completed. + - The task is not executed immediately when it is created. For example, if a command is executed every 5 minutes, the command is not executed immediately when a task is created, but is executed 5 minutes after the task is created. + - Execute only once at the specified time: Execute the command once according to the set time zone and execution time point. The format is at(yyyy-MM-dd HH:mm:ss ), that is, at (year-month-day time: minute: Second ). If you do not specify a time zone, the default is the UTC time zone. Time zones can be in the following three formats: the full name of the time zone, such as Asia/Shanghai (China/Shanghai time), America/los_angles (United States/Los Angeles time), and so on. The offset of the time zone relative to Greenwich Mean Time: E.G. GMT +8:00 (East Zone 8), GMT-7 (West Zone 7), etc. When using the GMT format, the hour bit does not support adding leading zeros. Time zone abbreviation: Only UTC (Coordinated Universal Time) is supported. +If it is specified to be executed once 13:15:30 June 06, 2022, China/Shanghai time, the format is at (Asia/Shanghai, 2022-06-06 13:15:30); If it is specified to be executed once 13:15:30 June 06, 2022, the format is at(2022-06-06 13:15:30 GMT-7:00). + - Timing based on clock (based on Cron expression): Based on Cron expression, commands are executed according to the set timing task. The format is , that is, . In the specified time zone, calculate the execution time of the scheduled task based on the Cron expression and execute it. If no time zone is specified, the default time zone is the internal time zone of the scheduled task instance. For more information about Cron expressions, see Cron Expressions. Time zones support the following three forms: + - Full time zone name: such as Asia/Shanghai (China/Shanghai time), America/los_angles (US/Los Angeles time), etc. + - The offset of the time zone relative to Greenwich Mean Time: E.G. GMT +8:00 (East Zone 8), GMT-7 (West Zone 7), etc. When using the GMT format, the hour bit does not support adding leading zeros. + - Time zone abbreviation: Only UTC (Coordinated Universal Time) is supported. + +For example, in China/Shanghai time, the command will be executed once every day at 10:15 am in 2022 in the format 0 15 10? * * 2022 Asia/Shanghai; In the eastern 8th District time, it will be executed every half hour from 10:00 a.m. to 11:30 a.m. every day in 2022, in the format of 0 0/30 10-11 * *? 2022 GMT +8:00; In UTC time, starting from 2022, it will be executed every 5 minutes from 14:00 P.M. to 14:55 p. M. Every two years in October, in the format of 0 0/5 14*10? 2022/2 UTC. +* `launcher` - (Optional) The bootstrapper for script execution. The length cannot exceed 1KB. +* `name` - (Optional) The command name. +* `node_id_list` - (Optional, ForceNew, List) A list of nodes. +* `parameters` - (Optional, Map) When the command contains custom parameters, the key-value pair of the custom parameters passed in when the command is executed. For example, if the command content is 'echo {{name}}', the key-value pair'{"name":"Jack"}'can be passed through the 'Parameter' parameter'. The custom parameter will automatically replace the variable value 'name' to get a new command that actually executes 'echo Jack '. + +The number of custom parameters ranges from 0 to 10, and you need to pay attention: + - The key is not allowed to be an empty string and supports a maximum of 64 characters. + - The value is allowed to be an empty string. + - After the custom parameters and the original command content are encoded in Base64, if the command is saved, the size of the command content after Base64 encoding cannot exceed 18KB. If the command is not saved, the size of the command content after Base64 encoding cannot exceed 24KB. You can set whether to keep the command through 'KeepCommand. + - The set of custom parameter names must be a subset of the parameter set defined when the command is created. For parameters that are not passed in, you can use an empty string instead. + +The default value is empty, which means that the parameter is unset and the custom parameter is disabled. +* `repeat_mode` - (Optional) Sets the way the command is executed. Value range: + - Once: Execute the command immediately. + - Period: executes the command regularly. When the value of this parameter is 'Period', the 'Frequency' parameter must also be specified. + - NextRebootOnly: Automatically execute the command when the instance is next started. + - EveryReboot: The command is automatically executed every time the instance is started. + +Default: + - When the'frequency' parameter is not specified, the default value is'once '. + - When the'frequency' parameter is specified, regardless of whether the parameter value has been set or not, it will be processed according to'period. +* `termination_mode` - (Optional) The mode when the task is stopped (manually stopped or execution time-out interrupted). Possible values: +Process: Stops the current script Process. +ProcessTree: Stops the current process tree (the script process and the collection of all child processes it created) +* `timeout` - (Optional, Int) The timeout period for command execution. Unit: seconds. A timeout occurs when a command cannot be run due to a process, a missing module, or a missing cloud assistant Agent. After the timeout, the command process is forcibly terminated. Default value: 60. +* `username` - (Optional) The name of the user who executed the command in the instance. The length must not exceed 255 characters. +The instance of the Linux system. By default, the root user runs commands. +* `working_dir` - (Optional) You can customize the command execution path. The default path is as follows: +Linux instance: the execution path is in the/home directory of the root user by default. + +## Attributes Reference + +The following attributes are exported: +* `id` - The ID of the resource supplied above. + +## Timeouts + +The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration-0-11/resources.html#timeouts) for certain actions: +* `create` - (Defaults to 5 mins) Used when create the Invocation. +* `update` - (Defaults to 5 mins) Used when update the Invocation. + +## Import + +Eflo Invocation can be imported using the id, e.g. + +```shell +$ terraform import alicloud_eflo_invocation.example +``` \ No newline at end of file diff --git a/website/docs/r/eflo_node.html.markdown b/website/docs/r/eflo_node.html.markdown new file mode 100644 index 000000000000..ceed58b248ba --- /dev/null +++ b/website/docs/r/eflo_node.html.markdown @@ -0,0 +1,97 @@ +--- +subcategory: "Eflo" +layout: "alicloud" +page_title: "Alicloud: alicloud_eflo_node" +description: |- + Provides a Alicloud Eflo Node resource. +--- + +# alicloud_eflo_node + +Provides a Eflo Node resource. + +Large computing node. + +For information about Eflo Node and how to use it, see [What is Node](https://next.api.alibabacloud.com/document/BssOpenApi/2017-12-14/CreateInstance). + +-> **NOTE:** Available since v1.246.0. + +## Example Usage + +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" { + default = "terraform-example" +} + +provider "alicloud" { + region = "cn-hangzhou" +} + +data "alicloud_resource_manager_resource_groups" "default" {} + +resource "alicloud_eflo_node" "default" { + period = "36" + discount_level = "36" + billing_cycle = "1month" + classify = "gpuserver" + zone = "cn-hangzhou-b" + product_form = "instance" + payment_ratio = "0" + hpn_zone = "B1" + server_arch = "bmserver" + computing_server = "efg1.nvga1n" + stage_num = "36" + renewal_status = "AutoRenewal" + renew_period = "36" + status = "Unused" +} +``` + +## Argument Reference + +The following arguments are supported: +* `billing_cycle` - (Optional) Billing cycle +* `classify` - (Optional) Classification +* `computing_server` - (Optional) Node Model +* `discount_level` - (Optional) Offer Information +* `hpn_zone` - (Optional) Cluster Number +* `payment_ratio` - (Optional) Down payment ratio +* `period` - (Optional, Int) Prepaid cycle. The unit is Month, please enter an integer multiple of 12 for the annual payment product. +* `product_form` - (Optional) Form +* `renew_period` - (Optional, Int) Automatic renewal period, in months. + +-> **NOTE:** When setting `RenewalStatus` to `AutoRenewal`, it must be set. + +* `renewal_status` - (Optional) Automatic renewal status, value: + - AutoRenewal: automatic renewal. + - ManualRenewal: manual renewal. + +The default ManualRenewal. +* `resource_group_id` - (Optional, Computed) The ID of the resource group +* `server_arch` - (Optional) Architecture +* `stage_num` - (Optional) Number of stages +* `status` - (Optional, Computed) The status of the resource +* `zone` - (Optional) Availability Zone + +## Attributes Reference + +The following attributes are exported: +* `id` - The ID of the resource supplied above. +* `create_time` - The creation time of the resource + +## Timeouts + +The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration-0-11/resources.html#timeouts) for certain actions: +* `create` - (Defaults to 5 mins) Used when create the Node. +* `delete` - (Defaults to 5 mins) Used when delete the Node. + +## Import + +Eflo Node can be imported using the id, e.g. + +```shell +$ terraform import alicloud_eflo_node.example +``` \ No newline at end of file diff --git a/website/docs/r/eflo_node_group.html.markdown b/website/docs/r/eflo_node_group.html.markdown new file mode 100644 index 000000000000..40f05c5d7710 --- /dev/null +++ b/website/docs/r/eflo_node_group.html.markdown @@ -0,0 +1,280 @@ +--- +subcategory: "Eflo" +layout: "alicloud" +page_title: "Alicloud: alicloud_eflo_node_group" +description: |- + Provides a Alicloud Eflo Node Group resource. +--- + +# alicloud_eflo_node_group + +Provides a Eflo Node Group resource. + +Node group. Divide a cluster into multiple node groups, each containing multiple nodes. + +For information about Eflo Node Group and how to use it, see [What is Node Group](https://next.api.alibabacloud.com/document/eflo-controller/2022-12-15/CreateNodeGroup). + +-> **NOTE:** Available since v1.246.0. + +## Example Usage + +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" { + default = "terraform-example" +} + +provider "alicloud" { + region = "cn-hangzhou" +} + +data "alicloud_resource_manager_resource_groups" "default" {} + +resource "alicloud_vpc" "create_vpc" { + cidr_block = "192.168.0.0/16" + vpc_name = "cluster-resoure-example" +} + +resource "alicloud_vswitch" "create_vswitch" { + vpc_id = alicloud_vpc.create_vpc.id + zone_id = "cn-hangzhou-b" + cidr_block = "192.168.0.0/24" + vswitch_name = "cluster-resoure-example" +} + +resource "alicloud_security_group" "create_security_group" { + description = "sg" + security_group_name = "cluster-resoure-example" + security_group_type = "normal" + vpc_id = alicloud_vpc.create_vpc.id +} + +resource "alicloud_eflo_cluster" "default" { + cluster_description = "cluster-resource-example" + open_eni_jumbo_frame = "false" + hpn_zone = "B1" + nimiz_vswitches = [ + "1111" + ] + ignore_failed_node_tasks = "true" + resource_group_id = data.alicloud_resource_manager_resource_groups.default.ids.1 + node_groups { + image_id = "i198448731735114628708" + zone_id = "cn-hangzhou-b" + node_group_name = "cluster-resource-example" + node_group_description = "cluster-resource-example" + machine_type = "efg2.C48cA3sen" + } + + networks { + tail_ip_version = "ipv4" + new_vpd_info { + monitor_vpc_id = alicloud_vpc.create_vpc.id + monitor_vswitch_id = alicloud_vswitch.create_vswitch.id + cen_id = "11111" + cloud_link_id = "1111" + vpd_cidr = "111" + vpd_subnets { + zone_id = "1111" + subnet_cidr = "111" + subnet_type = "111" + } + cloud_link_cidr = "169.254.128.0/23" + } + + security_group_id = alicloud_security_group.create_security_group.id + vswitch_zone_id = "cn-hangzhou-b" + vpc_id = alicloud_vpc.create_vpc.id + vswitch_id = alicloud_vswitch.create_vswitch.id + vpd_info { + vpd_id = "111" + vpd_subnets = [ + "111" + ] + } + ip_allocation_policy { + bond_policy { + bond_default_subnet = "111" + bonds { + name = "111" + subnet = "111" + } + } + machine_type_policy { + bonds { + name = "111" + subnet = "111" + } + machine_type = "111" + } + node_policy { + bonds { + name = "111" + subnet = "111" + } + node_id = "111" + } + } + } + + cluster_name = "tfacceflo7165" + cluster_type = "Lite" +} + +resource "alicloud_eflo_node" "default" { + period = "36" + discount_level = "36" + billing_cycle = "1month" + classify = "gpuserver" + zone = "cn-hangzhou-b" + product_form = "instance" + payment_ratio = "0" + hpn_zone = "B1" + server_arch = "bmserver" + computing_server = "efg1.nvga1n" + stage_num = "36" + renewal_status = "AutoRenewal" + renew_period = "36" + status = "Unused" +} + +resource "alicloud_eflo_node_group" "default" { + nodes { + node_id = alicloud_eflo_node.default.id + vpc_id = alicloud_vpc.create_vpc.id + vswitch_id = alicloud_vswitch.create_vswitch.id + hostname = "jxyhostname" + login_password = "Alibaba@2025" + } + + ignore_failed_node_tasks = "true" + cluster_id = alicloud_eflo_cluster.default.id + image_id = "i195048661660874208657" + zone_id = "cn-hangzhou-b" + vpd_subnets = [ + "example" + ] + user_data = "YWxpLGFsaSxhbGliYWJh" + vswitch_zone_id = "cn-hangzhou-b" + ip_allocation_policy { + bond_policy { + bond_default_subnet = "example" + bonds { + name = "example" + subnet = "example" + } + } + machine_type_policy { + bonds { + name = "example" + subnet = "example" + } + machine_type = "example" + } + node_policy { + node_id = alicloud_eflo_node.default.id + bonds { + name = "example" + subnet = "example" + } + } + } + machine_type = "efg1.nvga1" + az = "cn-hangzhou-b" + node_group_description = "resource-example1" + node_group_name = "tfacceflo63657_update" +} +``` + +## Argument Reference + +The following arguments are supported: +* `az` - (Required, ForceNew) Az +* `cluster_id` - (Required, ForceNew) Cluster ID +* `ignore_failed_node_tasks` - (Optional) Whether to allow skipping failed nodes. Default value: False +* `image_id` - (Required, ForceNew) Image ID +* `ip_allocation_policy` - (Optional, List) 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. +* `machine_type` - (Required, ForceNew) Machine type +* `node_group_description` - (Optional, ForceNew) NodeGroupDescription +* `node_group_name` - (Required) The name of the resource +* `nodes` - (Optional, Set) Node List See [`nodes`](#nodes) below. +* `user_data` - (Optional) Custom Data +* `vswitch_zone_id` - (Optional) Zone ID of the switch +* `vpd_subnets` - (Optional, List) Cluster subnet list +* `zone_id` - (Optional) Zone ID + +### `ip_allocation_policy` + +The ip_allocation_policy supports the following: +* `bond_policy` - (Optional, List) Specify the cluster subnet ID based on the bond name See [`bond_policy`](#ip_allocation_policy-bond_policy) below. +* `machine_type_policy` - (Optional, List) Model Assignment Policy See [`machine_type_policy`](#ip_allocation_policy-machine_type_policy) below. +* `node_policy` - (Optional, List) 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) Default bond cluster subnet +* `bonds` - (Optional, List) 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, List) Bond information See [`bonds`](#ip_allocation_policy-machine_type_policy-bonds) below. +* `machine_type` - (Optional) Model + +### `ip_allocation_policy-node_policy` + +The ip_allocation_policy-node_policy supports the following: +* `bonds` - (Optional, List) Bond information See [`bonds`](#ip_allocation_policy-node_policy-bonds) below. +* `node_id` - (Optional) Node ID + +### `ip_allocation_policy-node_policy-bonds` + +The ip_allocation_policy-node_policy-bonds supports the following: +* `name` - (Optional) The bond name +* `subnet` - (Optional) IP source cluster subnet + +### `ip_allocation_policy-machine_type_policy-bonds` + +The ip_allocation_policy-machine_type_policy-bonds supports the following: +* `name` - (Optional) The bond name +* `subnet` - (Optional) IP source cluster subnet + +### `ip_allocation_policy-bond_policy-bonds` + +The ip_allocation_policy-bond_policy-bonds supports the following: +* `name` - (Optional) The bond name +* `subnet` - (Optional) IP source cluster subnet + +### `nodes` + +The nodes supports the following: +* `hostname` - (Optional) Host name +* `login_password` - (Optional) Login Password +* `node_id` - (Optional) Node ID +* `vswitch_id` - (Optional) Switch ID +* `vpc_id` - (Optional) VPC ID + +## Attributes Reference + +The following attributes are exported: +* `id` - The ID of the resource supplied above.The value is formulated as `:`. +* `create_time` - Create time +* `node_group_id` - The first ID of the resource + +## Timeouts + +The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration-0-11/resources.html#timeouts) for certain actions: +* `create` - (Defaults to 5 mins) Used when create the Node Group. +* `delete` - (Defaults to 5 mins) Used when delete the Node Group. +* `update` - (Defaults to 120 mins) Used when update the Node Group. + +## Import + +Eflo Node Group can be imported using the id, e.g. + +```shell +$ terraform import alicloud_eflo_node_group.example : +``` \ No newline at end of file