From 829d2a8df06a50b7e93dd0cdaab4b4d8cad82e8b Mon Sep 17 00:00:00 2001 From: mikatong Date: Tue, 29 Oct 2024 20:29:06 +0800 Subject: [PATCH 1/2] emr support multi_disks --- tencentcloud/services/emr/extension_emr.go | 186 ++++++++++++++++-- .../services/emr/resource_tc_emr_cluster.go | 80 +++++--- .../emr/resource_tc_emr_cluster_test.go | 22 +++ .../services/emr/service_tencentcloud_emr.go | 28 ++- website/docs/r/emr_cluster.html.markdown | 26 +-- 5 files changed, 280 insertions(+), 62 deletions(-) diff --git a/tencentcloud/services/emr/extension_emr.go b/tencentcloud/services/emr/extension_emr.go index 9c33e03090..9f5b903061 100644 --- a/tencentcloud/services/emr/extension_emr.go +++ b/tencentcloud/services/emr/extension_emr.go @@ -1,9 +1,12 @@ package emr import ( + "fmt" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" emr "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/emr/v20190103" + "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/internal/helper" ) const ( @@ -35,38 +38,122 @@ func buildResourceSpecSchema() *schema.Schema { MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "spec": {Type: schema.TypeString, Optional: true}, - "storage_type": {Type: schema.TypeInt, Optional: true}, - "disk_type": {Type: schema.TypeString, Optional: true}, - "mem_size": {Type: schema.TypeInt, Optional: true}, - "cpu": {Type: schema.TypeInt, Optional: true}, - "disk_size": {Type: schema.TypeInt, Optional: true}, - "root_size": {Type: schema.TypeInt, Optional: true}, + "spec": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "Node specification description, such as CVM.SA2.", + }, + "storage_type": { + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + Description: "Storage type. Value range:\n" + + " - 4: Represents cloud SSD;\n" + + " - 5: Represents efficient cloud disk;\n" + + " - 6: Represents enhanced SSD Cloud Block Storage;\n" + + " - 11: Represents throughput Cloud Block Storage;\n" + + " - 12: Represents extremely fast SSD Cloud Block Storage.", + }, + "disk_type": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "disk types. Value range:\n" + + " - CLOUD_SSD: Represents cloud SSD;\n" + + " - CLOUD_PREMIUM: Represents efficient cloud disk;\n" + + " - CLOUD_BASIC: Represents Cloud Block Storage.", + }, + "mem_size": { + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + Description: "Memory size in M.", + }, + "cpu": { + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + Description: "Number of CPU cores.", + }, + "disk_size": { + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + Description: "Data disk capacity.", + }, + "root_size": { + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + Description: "Root disk capacity.", + }, + "multi_disks": { + Type: schema.TypeSet, + Optional: true, + Computed: true, + ForceNew: true, + Description: "Cloud disk list. When the data disk is a cloud disk, use disk_type and disk_size parameters directly, and use multi_disks for excess parts.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "disk_type": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Description: "Cloud disk type\n" + + " - CLOUD_SSD: Represents cloud SSD;\n" + + " - CLOUD_PREMIUM: Represents efficient cloud disk;\n" + + " - CLOUD_HSSD: Represents enhanced SSD Cloud Block Storage.", + }, + "volume": { + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + Description: "Cloud disk size.", + }, + "count": { + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + Description: "Number of cloud disks of this type.", + }, + }, + }, + Set: func(v interface{}) int { + m := v.(map[string]interface{}) + return helper.HashString(fmt.Sprintf("%s-%d-%d", m["disk_type"].(string), m["volume"].(int), m["count"].(int))) + + }, + }, }, }, } } -func ParseMultiDisks(_multiDisks []map[string]interface{}) []*emr.MultiDisk { - multiDisks := make([]*emr.MultiDisk, len(_multiDisks)) - for _, item := range _multiDisks { +func ParseMultiDisks(_multiDisks []interface{}) []*emr.MultiDisk { + multiDisks := make([]*emr.MultiDisk, 0, len(_multiDisks)) + for _, multiDisk := range _multiDisks { + item := multiDisk.(map[string]interface{}) var diskType string - var volume int64 - var count int64 + var volume int + var count int for subK, subV := range item { if subK == "disk_type" { diskType = subV.(string) } else if subK == "volume" { - volume = subV.(int64) + volume = subV.(int) } else if subK == "count" { - count = subV.(int64) + count = subV.(int) } } multiDisks = append(multiDisks, &emr.MultiDisk{ - DiskType: common.StringPtr(diskType), - Volume: common.Int64Ptr(volume), - Count: common.Int64Ptr(count), + DiskType: helper.String(diskType), + Volume: helper.IntInt64(volume), + Count: helper.IntInt64(count), }) } @@ -101,7 +188,7 @@ func ParseResource(_resource map[string]interface{}) *emr.Resource { } else if k == "root_size" { resultResource.RootSize = common.Int64Ptr((int64)(v.(int))) } else if k == "multi_disks" { - multiDisks := v.([]map[string]interface{}) + multiDisks := v.(*schema.Set).List() resultResource.MultiDisks = ParseMultiDisks(multiDisks) } else if k == "tags" { tags := v.([]map[string]string) @@ -116,3 +203,66 @@ func ParseResource(_resource map[string]interface{}) *emr.Resource { } return resultResource } + +func validateMultiDisks(r map[string]interface{}) error { + if _, ok := r["multi_disks"]; !ok { + return nil + } + multiDiskList := r["multi_disks"].(*schema.Set).List() + visited := make(map[string]struct{}) + + for _, multiDisk := range multiDiskList { + multiDiskMap := multiDisk.(map[string]interface{}) + key := fmt.Sprintf("%s-%d", multiDiskMap["disk_type"].(string), multiDiskMap["volume"].(int)) + if _, ok := visited[key]; ok { + return fmt.Errorf("Merge disks of the same specifications") + } else { + visited[key] = struct{}{} + } + } + + return nil +} + +func fetchMultiDisks(v *emr.NodeHardwareInfo, r *emr.OutterResource) (multiDisks []interface{}) { + var inputDataDiskTag string + if r.DiskType != nil && r.DiskSize != nil { + inputDataDiskTag = fmt.Sprintf("%s-%d", *r.DiskType, *r.DiskSize) + } + for _, item := range v.MCMultiDisk { + outputDataDiskTag := "" + multiDisk := make(map[string]interface{}) + if item.Type != nil { + var diskType string + if *item.Type == 4 { + diskType = "CLOUD_SSD" + } + if *item.Type == 5 { + diskType = "CLOUD_PREMIUM" + } + if *item.Type == 6 { + diskType = "CLOUD_HSSD" + } + multiDisk["disk_type"] = diskType + outputDataDiskTag = diskType + } + if item.Volume != nil { + volume := int(*item.Volume / 1024 / 1024 / 1024) + multiDisk["volume"] = volume + outputDataDiskTag = fmt.Sprintf("%s-%d", outputDataDiskTag, volume) + } + var count int + if item.Count != nil { + count = int(*item.Count) + if count > 0 && inputDataDiskTag == outputDataDiskTag { + count -= 1 + } + multiDisk["count"] = count + } + + if count != 0 { + multiDisks = append(multiDisks, multiDisk) + } + } + return +} diff --git a/tencentcloud/services/emr/resource_tc_emr_cluster.go b/tencentcloud/services/emr/resource_tc_emr_cluster.go index 8d0a010074..1d4d29277f 100644 --- a/tencentcloud/services/emr/resource_tc_emr_cluster.go +++ b/tencentcloud/services/emr/resource_tc_emr_cluster.go @@ -40,18 +40,20 @@ func ResourceTencentCloudEmrCluster() *schema.Resource { Required: true, ForceNew: true, Description: "Product ID. Different products ID represents different EMR product versions. Value range:\n" + - "- 16: represents EMR-V2.3.0\n" + - "- 20: indicates EMR-V2.5.0\n" + - "- 25: represents EMR-V3.1.0\n" + - "- 27: represents KAFKA-V1.0.0\n" + - "- 30: indicates EMR-V2.6.0\n" + - "- 33: represents EMR-V3.2.1\n" + - "- 34: stands for EMR-V3.3.0\n" + - "- 36: represents STARROCKS-V1.0.0\n" + - "- 37: indicates EMR-V3.4.0\n" + - "- 38: represents EMR-V2.7.0\n" + - "- 39: stands for STARROCKS-V1.1.0\n" + - "- 41: represents DRUID-V1.1.0.", + " - 16: represents EMR-V2.3.0\n" + + " - 20: represents EMR-V2.5.0\n" + + " - 25: represents EMR-V3.1.0\n" + + " - 27: represents KAFKA-V1.0.0\n" + + " - 30: represents EMR-V2.6.0\n" + + " - 33: represents EMR-V3.2.1\n" + + " - 34: represents EMR-V3.3.0\n" + + " - 37: represents EMR-V3.4.0\n" + + " - 38: represents EMR-V2.7.0\n" + + " - 44: represents EMR-V3.5.0\n" + + " - 50: represents KAFKA-V2.0.0\n" + + " - 51: represents STARROCKS-V1.4.0\n" + + " - 53: represents EMR-V3.6.0\n" + + " - 54: represents STARROCKS-V2.0.0.", }, "vpc_settings": { Type: schema.TypeMap, @@ -534,6 +536,31 @@ func resourceTencentCloudEmrClusterRead(d *schema.ResourceData, meta interface{} } _ = d.Set("instance_id", instanceId) + clusterNodeMap := make(map[string]*emr.NodeHardwareInfo) + err = resource.Retry(tccommon.ReadRetryTimeout, func() *resource.RetryError { + result, err := emrService.DescribeClusterNodes(ctx, instanceId, "all", "all", 0, 10) + + if err != nil { + return resource.RetryableError(err) + } + + if len(result) > 0 { + _ = d.Set("auto_renew", result[0].IsAutoRenew) + for _, item := range result { + node := item + // 节点类型 0:common节点;1:master节点;2:core节点;3:task节点 + if node.Flag != nil { + clusterNodeMap[strconv.FormatInt(*node.Flag, 10)] = node + } + } + } + + return nil + }) + + if err != nil { + return err + } if instance != nil { _ = d.Set("product_id", instance.ProductId) _ = d.Set("vpc_settings", map[string]interface{}{ @@ -587,6 +614,9 @@ func resourceTencentCloudEmrClusterRead(d *schema.ResourceData, meta interface{} if masterResource.RootSize != nil { masterResourceSpec["root_size"] = *masterResource.RootSize } + if v, ok := clusterNodeMap["1"]; ok { + masterResourceSpec["multi_disks"] = fetchMultiDisks(v, masterResource) + } resourceSpec["master_resource_spec"] = []interface{}{masterResourceSpec} } @@ -619,6 +649,10 @@ func resourceTencentCloudEmrClusterRead(d *schema.ResourceData, meta interface{} if coreResource.RootSize != nil { coreResourceSpec["root_size"] = *coreResource.RootSize } + if v, ok := clusterNodeMap["2"]; ok { + coreResourceSpec["multi_disks"] = fetchMultiDisks(v, coreResource) + } + resourceSpec["core_resource_spec"] = []interface{}{coreResourceSpec} } @@ -651,6 +685,9 @@ func resourceTencentCloudEmrClusterRead(d *schema.ResourceData, meta interface{} if taskResource.RootSize != nil { taskResourceSpec["root_size"] = *taskResource.RootSize } + if v, ok := clusterNodeMap["3"]; ok { + taskResourceSpec["multi_disks"] = fetchMultiDisks(v, taskResource) + } resourceSpec["task_resource_spec"] = []interface{}{taskResourceSpec} } @@ -683,6 +720,9 @@ func resourceTencentCloudEmrClusterRead(d *schema.ResourceData, meta interface{} if comResource.RootSize != nil { comResourceSpec["root_size"] = *comResource.RootSize } + if v, ok := clusterNodeMap["0"]; ok { + comResourceSpec["multi_disks"] = fetchMultiDisks(v, comResource) + } resourceSpec["common_resource_spec"] = []interface{}{comResourceSpec} } @@ -713,22 +753,6 @@ func resourceTencentCloudEmrClusterRead(d *schema.ResourceData, meta interface{} return err } _ = d.Set("tags", tags) - err = resource.Retry(tccommon.ReadRetryTimeout, func() *resource.RetryError { - result, err := emrService.DescribeClusterNodes(ctx, instanceId, "all", "all", 0, 10) - - if err != nil { - return resource.RetryableError(err) - } - if len(result) > 0 { - _ = d.Set("auto_renew", result[0].IsAutoRenew) - } - - return nil - }) - - if err != nil { - return err - } return nil } diff --git a/tencentcloud/services/emr/resource_tc_emr_cluster_test.go b/tencentcloud/services/emr/resource_tc_emr_cluster_test.go index 30b1922dc4..3a3eeb7ab2 100644 --- a/tencentcloud/services/emr/resource_tc_emr_cluster_test.go +++ b/tencentcloud/services/emr/resource_tc_emr_cluster_test.go @@ -157,6 +157,8 @@ func TestAccTencentCloudEmrClusterResource_Basic(t *testing.T) { resource.TestCheckResourceAttr(testEmrClusterResourceKey, "sg_id", tcacctest.DefaultEMRSgId), resource.TestCheckResourceAttr(testEmrClusterResourceKey, "tags.emr-key", "emr-value"), resource.TestCheckResourceAttr(testEmrClusterResourceKey, "resource_spec.0.core_count", "2"), + resource.TestCheckResourceAttr(testEmrClusterResourceKey, "resource_spec.0.master_resource_spec.0.multi_disks.#", "1"), + resource.TestCheckResourceAttr(testEmrClusterResourceKey, "resource_spec.0.core_resource_spec.0.multi_disks.#", "1"), ), }, { @@ -305,6 +307,11 @@ resource "tencentcloud_emr_cluster" "emrrrr" { spec="CVM.${data.tencentcloud_instance_types.cvm4c8m.instance_types.0.family}" storage_type=5 root_size=50 + multi_disks { + disk_type = "CLOUD_PREMIUM" + volume = 200 + count = 1 + } } core_resource_spec { mem_size=8192 @@ -314,6 +321,11 @@ resource "tencentcloud_emr_cluster" "emrrrr" { spec="CVM.${data.tencentcloud_instance_types.cvm4c8m.instance_types.0.family}" storage_type=5 root_size=50 + multi_disks { + disk_type = "CLOUD_PREMIUM" + volume = 100 + count = 2 + } } master_count=1 core_count=2 @@ -374,6 +386,11 @@ resource "tencentcloud_emr_cluster" "emrrrr" { spec="CVM.${data.tencentcloud_instance_types.cvm4c8m.instance_types.0.family}" storage_type=5 root_size=50 + multi_disks { + disk_type = "CLOUD_PREMIUM" + volume = 200 + count = 1 + } } core_resource_spec { mem_size=8192 @@ -383,6 +400,11 @@ resource "tencentcloud_emr_cluster" "emrrrr" { spec="CVM.${data.tencentcloud_instance_types.cvm4c8m.instance_types.0.family}" storage_type=5 root_size=50 + multi_disks { + disk_type = "CLOUD_PREMIUM" + volume = 100 + count = 2 + } } master_count=1 core_count=3 diff --git a/tencentcloud/services/emr/service_tencentcloud_emr.go b/tencentcloud/services/emr/service_tencentcloud_emr.go index 6aa572ebb4..cfff6c9231 100644 --- a/tencentcloud/services/emr/service_tencentcloud_emr.go +++ b/tencentcloud/services/emr/service_tencentcloud_emr.go @@ -101,15 +101,30 @@ func (me *EMRService) CreateInstance(ctx context.Context, d *schema.ResourceData for k, v := range resourceSpec { if k == "master_resource_spec" { if len(v.([]interface{})) > 0 { - request.ResourceSpec.MasterResourceSpec = ParseResource(v.([]interface{})[0].(map[string]interface{})) + spec := v.([]interface{})[0].(map[string]interface{}) + err = validateMultiDisks(spec) + if err != nil { + return + } + request.ResourceSpec.MasterResourceSpec = ParseResource(spec) } } else if k == "core_resource_spec" { if len(v.([]interface{})) > 0 { - request.ResourceSpec.CoreResourceSpec = ParseResource(v.([]interface{})[0].(map[string]interface{})) + spec := v.([]interface{})[0].(map[string]interface{}) + err = validateMultiDisks(spec) + if err != nil { + return + } + request.ResourceSpec.CoreResourceSpec = ParseResource(spec) } } else if k == "task_resource_spec" { if len(v.([]interface{})) > 0 { - request.ResourceSpec.TaskResourceSpec = ParseResource(v.([]interface{})[0].(map[string]interface{})) + spec := v.([]interface{})[0].(map[string]interface{}) + err = validateMultiDisks(spec) + if err != nil { + return + } + request.ResourceSpec.TaskResourceSpec = ParseResource(spec) } } else if k == "master_count" { request.ResourceSpec.MasterCount = common.Int64Ptr((int64)(v.(int))) @@ -119,7 +134,12 @@ func (me *EMRService) CreateInstance(ctx context.Context, d *schema.ResourceData request.ResourceSpec.TaskCount = common.Int64Ptr((int64)(v.(int))) } else if k == "common_resource_spec" { if len(v.([]interface{})) > 0 { - request.ResourceSpec.CommonResourceSpec = ParseResource(v.([]interface{})[0].(map[string]interface{})) + spec := v.([]interface{})[0].(map[string]interface{}) + err = validateMultiDisks(spec) + if err != nil { + return + } + request.ResourceSpec.CommonResourceSpec = ParseResource(spec) } } else if k == "common_count" { request.ResourceSpec.CommonCount = common.Int64Ptr((int64)(v.(int))) diff --git a/website/docs/r/emr_cluster.html.markdown b/website/docs/r/emr_cluster.html.markdown index 6f52d8a523..821c8d07b2 100644 --- a/website/docs/r/emr_cluster.html.markdown +++ b/website/docs/r/emr_cluster.html.markdown @@ -109,18 +109,20 @@ The following arguments are supported: * `instance_name` - (Required, String, ForceNew) Name of the instance, which can contain 6 to 36 English letters, Chinese characters, digits, dashes(-), or underscores(_). * `pay_mode` - (Required, Int) The pay mode of instance. 0 represent POSTPAID_BY_HOUR, 1 represent PREPAID. * `product_id` - (Required, Int, ForceNew) Product ID. Different products ID represents different EMR product versions. Value range: -- 16: represents EMR-V2.3.0 -- 20: indicates EMR-V2.5.0 -- 25: represents EMR-V3.1.0 -- 27: represents KAFKA-V1.0.0 -- 30: indicates EMR-V2.6.0 -- 33: represents EMR-V3.2.1 -- 34: stands for EMR-V3.3.0 -- 36: represents STARROCKS-V1.0.0 -- 37: indicates EMR-V3.4.0 -- 38: represents EMR-V2.7.0 -- 39: stands for STARROCKS-V1.1.0 -- 41: represents DRUID-V1.1.0. + - 16: represents EMR-V2.3.0 + - 20: represents EMR-V2.5.0 + - 25: represents EMR-V3.1.0 + - 27: represents KAFKA-V1.0.0 + - 30: represents EMR-V2.6.0 + - 33: represents EMR-V3.2.1 + - 34: represents EMR-V3.3.0 + - 37: represents EMR-V3.4.0 + - 38: represents EMR-V2.7.0 + - 44: represents EMR-V3.5.0 + - 50: represents KAFKA-V2.0.0 + - 51: represents STARROCKS-V1.4.0 + - 53: represents EMR-V3.6.0 + - 54: represents STARROCKS-V2.0.0. * `softwares` - (Required, Set: [`String`], ForceNew) The softwares of a EMR instance. * `support_ha` - (Required, Int, ForceNew) The flag whether the instance support high availability.(0=>not support, 1=>support). * `vpc_settings` - (Required, Map, ForceNew) The private net config of EMR instance. From c65822b22e378683a62a8fe01ef293900ec2299c Mon Sep 17 00:00:00 2001 From: mikatong Date: Wed, 30 Oct 2024 14:26:42 +0800 Subject: [PATCH 2/2] update --- .changelog/2919.txt | 3 + tencentcloud/services/emr/extension_emr.go | 1 + website/docs/r/emr_cluster.html.markdown | 120 ++++++++++++++++++++- 3 files changed, 120 insertions(+), 4 deletions(-) create mode 100644 .changelog/2919.txt diff --git a/.changelog/2919.txt b/.changelog/2919.txt new file mode 100644 index 0000000000..9f574d743f --- /dev/null +++ b/.changelog/2919.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/tencentcloud_emr_cluster: Support multi_disks. +``` \ No newline at end of file diff --git a/tencentcloud/services/emr/extension_emr.go b/tencentcloud/services/emr/extension_emr.go index 9f5b903061..29059db8d4 100644 --- a/tencentcloud/services/emr/extension_emr.go +++ b/tencentcloud/services/emr/extension_emr.go @@ -130,6 +130,7 @@ func buildResourceSpecSchema() *schema.Schema { }, }, }, + Description: "Resource details.", } } diff --git a/website/docs/r/emr_cluster.html.markdown b/website/docs/r/emr_cluster.html.markdown index 821c8d07b2..1bd35736dd 100644 --- a/website/docs/r/emr_cluster.html.markdown +++ b/website/docs/r/emr_cluster.html.markdown @@ -144,6 +144,99 @@ The following arguments are supported: When TimeUnit is m, the number filled in by this parameter indicates the length of purchase of the monthly instance of the package year, such as 1 for one month of purchase. * `time_unit` - (Optional, String) The unit of time in which the instance was purchased. When PayMode is 0, TimeUnit can only take values of s(second). When PayMode is 1, TimeUnit can only take the value m(month). +The `common_resource_spec` object of `resource_spec` supports the following: + +* `cpu` - (Optional, Int, ForceNew) Number of CPU cores. +* `disk_size` - (Optional, Int, ForceNew) Data disk capacity. +* `disk_type` - (Optional, String, ForceNew) disk types. Value range: + - CLOUD_SSD: Represents cloud SSD; + - CLOUD_PREMIUM: Represents efficient cloud disk; + - CLOUD_BASIC: Represents Cloud Block Storage. +* `mem_size` - (Optional, Int, ForceNew) Memory size in M. +* `multi_disks` - (Optional, Set, ForceNew) Cloud disk list. When the data disk is a cloud disk, use disk_type and disk_size parameters directly, and use multi_disks for excess parts. +* `root_size` - (Optional, Int, ForceNew) Root disk capacity. +* `spec` - (Optional, String, ForceNew) Node specification description, such as CVM.SA2. +* `storage_type` - (Optional, Int, ForceNew) Storage type. Value range: + - 4: Represents cloud SSD; + - 5: Represents efficient cloud disk; + - 6: Represents enhanced SSD Cloud Block Storage; + - 11: Represents throughput Cloud Block Storage; + - 12: Represents extremely fast SSD Cloud Block Storage. + +The `core_resource_spec` object of `resource_spec` supports the following: + +* `cpu` - (Optional, Int, ForceNew) Number of CPU cores. +* `disk_size` - (Optional, Int, ForceNew) Data disk capacity. +* `disk_type` - (Optional, String, ForceNew) disk types. Value range: + - CLOUD_SSD: Represents cloud SSD; + - CLOUD_PREMIUM: Represents efficient cloud disk; + - CLOUD_BASIC: Represents Cloud Block Storage. +* `mem_size` - (Optional, Int, ForceNew) Memory size in M. +* `multi_disks` - (Optional, Set, ForceNew) Cloud disk list. When the data disk is a cloud disk, use disk_type and disk_size parameters directly, and use multi_disks for excess parts. +* `root_size` - (Optional, Int, ForceNew) Root disk capacity. +* `spec` - (Optional, String, ForceNew) Node specification description, such as CVM.SA2. +* `storage_type` - (Optional, Int, ForceNew) Storage type. Value range: + - 4: Represents cloud SSD; + - 5: Represents efficient cloud disk; + - 6: Represents enhanced SSD Cloud Block Storage; + - 11: Represents throughput Cloud Block Storage; + - 12: Represents extremely fast SSD Cloud Block Storage. + +The `master_resource_spec` object of `resource_spec` supports the following: + +* `cpu` - (Optional, Int, ForceNew) Number of CPU cores. +* `disk_size` - (Optional, Int, ForceNew) Data disk capacity. +* `disk_type` - (Optional, String, ForceNew) disk types. Value range: + - CLOUD_SSD: Represents cloud SSD; + - CLOUD_PREMIUM: Represents efficient cloud disk; + - CLOUD_BASIC: Represents Cloud Block Storage. +* `mem_size` - (Optional, Int, ForceNew) Memory size in M. +* `multi_disks` - (Optional, Set, ForceNew) Cloud disk list. When the data disk is a cloud disk, use disk_type and disk_size parameters directly, and use multi_disks for excess parts. +* `root_size` - (Optional, Int, ForceNew) Root disk capacity. +* `spec` - (Optional, String, ForceNew) Node specification description, such as CVM.SA2. +* `storage_type` - (Optional, Int, ForceNew) Storage type. Value range: + - 4: Represents cloud SSD; + - 5: Represents efficient cloud disk; + - 6: Represents enhanced SSD Cloud Block Storage; + - 11: Represents throughput Cloud Block Storage; + - 12: Represents extremely fast SSD Cloud Block Storage. + +The `multi_disks` object of `common_resource_spec` supports the following: + +* `count` - (Optional, Int, ForceNew) Number of cloud disks of this type. +* `disk_type` - (Optional, String, ForceNew) Cloud disk type + - CLOUD_SSD: Represents cloud SSD; + - CLOUD_PREMIUM: Represents efficient cloud disk; + - CLOUD_HSSD: Represents enhanced SSD Cloud Block Storage. +* `volume` - (Optional, Int, ForceNew) Cloud disk size. + +The `multi_disks` object of `core_resource_spec` supports the following: + +* `count` - (Optional, Int, ForceNew) Number of cloud disks of this type. +* `disk_type` - (Optional, String, ForceNew) Cloud disk type + - CLOUD_SSD: Represents cloud SSD; + - CLOUD_PREMIUM: Represents efficient cloud disk; + - CLOUD_HSSD: Represents enhanced SSD Cloud Block Storage. +* `volume` - (Optional, Int, ForceNew) Cloud disk size. + +The `multi_disks` object of `master_resource_spec` supports the following: + +* `count` - (Optional, Int, ForceNew) Number of cloud disks of this type. +* `disk_type` - (Optional, String, ForceNew) Cloud disk type + - CLOUD_SSD: Represents cloud SSD; + - CLOUD_PREMIUM: Represents efficient cloud disk; + - CLOUD_HSSD: Represents enhanced SSD Cloud Block Storage. +* `volume` - (Optional, Int, ForceNew) Cloud disk size. + +The `multi_disks` object of `task_resource_spec` supports the following: + +* `count` - (Optional, Int, ForceNew) Number of cloud disks of this type. +* `disk_type` - (Optional, String, ForceNew) Cloud disk type + - CLOUD_SSD: Represents cloud SSD; + - CLOUD_PREMIUM: Represents efficient cloud disk; + - CLOUD_HSSD: Represents enhanced SSD Cloud Block Storage. +* `volume` - (Optional, Int, ForceNew) Cloud disk size. + The `placement_info` object supports the following: * `zone` - (Required, String) Zone. @@ -152,13 +245,32 @@ The `placement_info` object supports the following: The `resource_spec` object supports the following: * `common_count` - (Optional, Int, ForceNew) The number of common node. -* `common_resource_spec` - (Optional, List, ForceNew) +* `common_resource_spec` - (Optional, List, ForceNew) Resource details. * `core_count` - (Optional, Int) The number of core node. -* `core_resource_spec` - (Optional, List, ForceNew) +* `core_resource_spec` - (Optional, List, ForceNew) Resource details. * `master_count` - (Optional, Int) The number of master node. -* `master_resource_spec` - (Optional, List, ForceNew) +* `master_resource_spec` - (Optional, List, ForceNew) Resource details. * `task_count` - (Optional, Int) The number of core node. -* `task_resource_spec` - (Optional, List, ForceNew) +* `task_resource_spec` - (Optional, List, ForceNew) Resource details. + +The `task_resource_spec` object of `resource_spec` supports the following: + +* `cpu` - (Optional, Int, ForceNew) Number of CPU cores. +* `disk_size` - (Optional, Int, ForceNew) Data disk capacity. +* `disk_type` - (Optional, String, ForceNew) disk types. Value range: + - CLOUD_SSD: Represents cloud SSD; + - CLOUD_PREMIUM: Represents efficient cloud disk; + - CLOUD_BASIC: Represents Cloud Block Storage. +* `mem_size` - (Optional, Int, ForceNew) Memory size in M. +* `multi_disks` - (Optional, Set, ForceNew) Cloud disk list. When the data disk is a cloud disk, use disk_type and disk_size parameters directly, and use multi_disks for excess parts. +* `root_size` - (Optional, Int, ForceNew) Root disk capacity. +* `spec` - (Optional, String, ForceNew) Node specification description, such as CVM.SA2. +* `storage_type` - (Optional, Int, ForceNew) Storage type. Value range: + - 4: Represents cloud SSD; + - 5: Represents efficient cloud disk; + - 6: Represents enhanced SSD Cloud Block Storage; + - 11: Represents throughput Cloud Block Storage; + - 12: Represents extremely fast SSD Cloud Block Storage. The `terminate_node_info` object supports the following: