Skip to content

Commit c4776d8

Browse files
authored
feat: tke nodepool instance charge type (#858)
* fix: node_pool testcase - delete also remove instance * fix: data.sec_group name * feat: node pool charge type
1 parent 0b82607 commit c4776d8

File tree

4 files changed

+239
-22
lines changed

4 files changed

+239
-22
lines changed

tencentcloud/extension_as.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ var INTERNET_CHARGE_ALLOW_TYPE = []string{
3737
const (
3838
INSTANCE_CHARGE_TYPE_POSTPAID = "POSTPAID_BY_HOUR"
3939
INSTANCE_CHARGE_TYPE_SPOTPAID = "SPOTPAID"
40+
INSTANCE_CHARGE_TYPE_PREPAID = "PREPAID"
4041
)
4142

4243
const (

tencentcloud/resource_tc_kubernetes_node_pool.go

Lines changed: 173 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,51 @@ resource "tencentcloud_kubernetes_node_pool" "mynodepool" {
9292
]
9393
}
9494
}
95+
```
96+
97+
Using Spot CVM Instance
98+
```hcl
99+
resource "tencentcloud_kubernetes_node_pool" "mynodepool" {
100+
name = "mynodepool"
101+
cluster_id = tencentcloud_kubernetes_cluster.managed_cluster.id
102+
max_size = 6
103+
min_size = 1
104+
vpc_id = data.tencentcloud_vpc_subnets.vpc.instance_list.0.vpc_id
105+
subnet_ids = [data.tencentcloud_vpc_subnets.vpc.instance_list.0.subnet_id]
106+
retry_policy = "INCREMENTAL_INTERVALS"
107+
desired_capacity = 4
108+
enable_auto_scale = true
109+
multi_zone_subnet_policy = "EQUALITY"
110+
111+
auto_scaling_config {
112+
instance_type = var.default_instance_type
113+
system_disk_type = "CLOUD_PREMIUM"
114+
system_disk_size = "50"
115+
security_group_ids = ["sg-24vswocp"]
116+
instance_charge_type = "SPOTPAID"
117+
spot_instance_type = "one-time"
118+
spot_max_price = "1000"
119+
120+
data_disk {
121+
disk_type = "CLOUD_PREMIUM"
122+
disk_size = 50
123+
}
124+
125+
internet_charge_type = "TRAFFIC_POSTPAID_BY_HOUR"
126+
internet_max_bandwidth_out = 10
127+
public_ip_assigned = true
128+
password = "test123#"
129+
enhanced_security_service = false
130+
enhanced_monitor_service = false
131+
}
132+
133+
labels = {
134+
"test1" = "test1",
135+
"test2" = "test2",
136+
}
137+
138+
}
139+
95140
```
96141
*/
97142
package tencentcloud
@@ -193,6 +238,38 @@ func composedKubernetesAsScalingConfigPara() map[string]*schema.Schema {
193238
},
194239
},
195240
},
241+
// payment
242+
"instance_charge_type": {
243+
Type: schema.TypeString,
244+
Optional: true,
245+
Computed: true,
246+
Description: "Charge type of instance. Valid values are `PREPAID`, `POSTPAID_BY_HOUR`, `SPOTPAID`. The default is `POSTPAID_BY_HOUR`. NOTE: `SPOTPAID` instance must set `spot_instance_type` and `spot_max_price` at the same time.",
247+
},
248+
"instance_charge_type_prepaid_period": {
249+
Type: schema.TypeInt,
250+
Optional: true,
251+
ValidateFunc: validateAllowedIntValue(CVM_PREPAID_PERIOD),
252+
Description: "The tenancy (in month) of the prepaid instance, NOTE: it only works when instance_charge_type is set to `PREPAID`. Valid values are `1`, `2`, `3`, `4`, `5`, `6`, `7`, `8`, `9`, `10`, `11`, `12`, `24`, `36`.",
253+
},
254+
"instance_charge_type_prepaid_renew_flag": {
255+
Type: schema.TypeString,
256+
Optional: true,
257+
Computed: true,
258+
ValidateFunc: validateAllowedStringValue(CVM_PREPAID_RENEW_FLAG),
259+
Description: "Auto renewal flag. Valid values: `NOTIFY_AND_AUTO_RENEW`: notify upon expiration and renew automatically, `NOTIFY_AND_MANUAL_RENEW`: notify upon expiration but do not renew automatically, `DISABLE_NOTIFY_AND_MANUAL_RENEW`: neither notify upon expiration nor renew automatically. Default value: `NOTIFY_AND_MANUAL_RENEW`. If this parameter is specified as `NOTIFY_AND_AUTO_RENEW`, the instance will be automatically renewed on a monthly basis if the account balance is sufficient. NOTE: it only works when instance_charge_type is set to `PREPAID`.",
260+
},
261+
"spot_instance_type": {
262+
Type: schema.TypeString,
263+
Optional: true,
264+
ValidateFunc: validateAllowedStringValue([]string{"one-time"}),
265+
Description: "Type of spot instance, only support `one-time` now. Note: it only works when instance_charge_type is set to `SPOTPAID`.",
266+
},
267+
"spot_max_price": {
268+
Type: schema.TypeString,
269+
Optional: true,
270+
ValidateFunc: validateStringNumber,
271+
Description: "Max price of a spot instance, is the format of decimal string, for example \"0.50\". Note: it only works when instance_charge_type is set to `SPOTPAID`.",
272+
},
196273
"internet_charge_type": {
197274
Type: schema.TypeString,
198275
Optional: true,
@@ -634,7 +711,32 @@ func composedKubernetesAsScalingConfigParaSerial(dMap map[string]interface{}, me
634711
}
635712
}
636713

637-
chargeType := INSTANCE_CHARGE_TYPE_POSTPAID
714+
chargeType, ok := dMap["instance_charge_type"].(string)
715+
if !ok || chargeType == "" {
716+
chargeType = INSTANCE_CHARGE_TYPE_POSTPAID
717+
}
718+
719+
if chargeType == INSTANCE_CHARGE_TYPE_SPOTPAID {
720+
spotMaxPrice := dMap["spot_max_price"].(string)
721+
spotInstanceType := dMap["spot_instance_type"].(string)
722+
request.InstanceMarketOptions = &as.InstanceMarketOptionsRequest{
723+
MarketType: helper.String("spot"),
724+
SpotOptions: &as.SpotMarketOptions{
725+
MaxPrice: &spotMaxPrice,
726+
SpotInstanceType: &spotInstanceType,
727+
},
728+
}
729+
}
730+
731+
if chargeType == INSTANCE_CHARGE_TYPE_PREPAID {
732+
period := dMap["instance_charge_type_prepaid_period"].(int)
733+
renewFlag := dMap["instance_charge_type_prepaid_renew_flag"].(string)
734+
request.InstanceChargePrepaid = &as.InstanceChargePrepaid{
735+
Period: helper.IntInt64(period),
736+
RenewFlag: &renewFlag,
737+
}
738+
}
739+
638740
request.InstanceChargeType = &chargeType
639741

640742
result = request.ToJsonString()
@@ -703,6 +805,35 @@ func composeAsLaunchConfigModifyRequest(d *schema.ResourceData, launchConfigId s
703805
}
704806
}
705807

808+
chargeType, ok := dMap["instance_charge_type"].(string)
809+
810+
if !ok || chargeType == "" {
811+
chargeType = INSTANCE_CHARGE_TYPE_POSTPAID
812+
}
813+
814+
if chargeType == INSTANCE_CHARGE_TYPE_SPOTPAID {
815+
spotMaxPrice := dMap["spot_max_price"].(string)
816+
spotInstanceType := dMap["spot_instance_type"].(string)
817+
request.InstanceMarketOptions = &as.InstanceMarketOptionsRequest{
818+
MarketType: helper.String("spot"),
819+
SpotOptions: &as.SpotMarketOptions{
820+
MaxPrice: &spotMaxPrice,
821+
SpotInstanceType: &spotInstanceType,
822+
},
823+
}
824+
}
825+
826+
if chargeType == INSTANCE_CHARGE_TYPE_PREPAID {
827+
period := dMap["instance_charge_type_prepaid_period"].(int)
828+
renewFlag := dMap["instance_charge_type_prepaid_renew_flag"].(string)
829+
request.InstanceChargePrepaid = &as.InstanceChargePrepaid{
830+
Period: helper.IntInt64(period),
831+
RenewFlag: &renewFlag,
832+
}
833+
}
834+
835+
request.InstanceChargeType = &chargeType
836+
706837
return request
707838
}
708839

@@ -745,19 +876,27 @@ func resourceKubernetesNodePoolRead(d *schema.ResourceData, meta interface{}) er
745876
_ = d.Set("cluster_id", clusterId)
746877

747878
//Describe Node Pool
748-
nodePool, has, err := service.DescribeNodePool(ctx, clusterId, nodePoolId)
749-
if err != nil {
750-
err = resource.Retry(readRetryTimeout, func() *resource.RetryError {
751-
_, has, err = service.DescribeNodePool(ctx, clusterId, nodePoolId)
752-
if err != nil {
753-
return retryError(err)
754-
}
755-
return nil
756-
})
757-
}
879+
var (
880+
nodePool *tke.NodePool
881+
)
882+
883+
err = resource.Retry(readRetryTimeout, func() *resource.RetryError {
884+
nodePool, has, err = service.DescribeNodePool(ctx, clusterId, nodePoolId)
885+
if err != nil {
886+
return resource.NonRetryableError(err)
887+
}
888+
889+
status := *nodePool.AutoscalingGroupStatus
890+
891+
if status == "enabling" || status == "disabling" {
892+
return resource.RetryableError(fmt.Errorf("node pool status is %s, retrying", status))
893+
}
758894

759-
if err != nil {
760895
return nil
896+
})
897+
898+
if err != nil {
899+
return err
761900
}
762901

763902
if !has {
@@ -803,9 +942,12 @@ func resourceKubernetesNodePoolRead(d *schema.ResourceData, meta interface{}) er
803942
if hasLC > 0 {
804943
launchConfig := make(map[string]interface{})
805944
if launchCfg.InstanceTypes != nil {
806-
backupInsTypes := launchCfg.InstanceTypes
807-
launchConfig["instance_type"] = backupInsTypes[0]
808-
launchConfig["backup_instance_types"] = helper.StringsInterfaces(backupInsTypes[1:])
945+
insTypes := launchCfg.InstanceTypes
946+
launchConfig["instance_type"] = insTypes[0]
947+
backupInsTypes := insTypes[1:]
948+
if len(backupInsTypes) > 0 {
949+
launchConfig["backup_instance_types"] = helper.StringsInterfaces(backupInsTypes)
950+
}
809951
} else {
810952
launchConfig["instance_type"] = launchCfg.InstanceType
811953
}
@@ -827,6 +969,17 @@ func resourceKubernetesNodePoolRead(d *schema.ResourceData, meta interface{}) er
827969
if launchCfg.InternetAccessible.PublicIpAssigned != nil {
828970
launchConfig["public_ip_assigned"] = launchCfg.InternetAccessible.PublicIpAssigned
829971
}
972+
if launchCfg.InstanceChargeType != nil {
973+
launchConfig["instance_charge_type"] = launchCfg.InstanceChargeType
974+
if *launchCfg.InstanceChargeType == INSTANCE_CHARGE_TYPE_SPOTPAID && launchCfg.InstanceMarketOptions != nil {
975+
launchConfig["spot_instance_type"] = launchCfg.InstanceMarketOptions.SpotOptions.SpotInstanceType
976+
launchConfig["spot_max_price"] = launchCfg.InstanceMarketOptions.SpotOptions.MaxPrice
977+
}
978+
if *launchCfg.InstanceChargeType == INSTANCE_CHARGE_TYPE_PREPAID && launchCfg.InstanceChargePrepaid != nil {
979+
launchConfig["instance_charge_type_prepaid_period"] = launchCfg.InstanceChargePrepaid.Period
980+
launchConfig["instance_charge_type_prepaid_renew_flag"] = launchCfg.InstanceChargePrepaid.RenewFlag
981+
}
982+
}
830983
if len(launchCfg.DataDisks) > 0 {
831984
dataDisks := make([]map[string]interface{}, 0, len(launchCfg.DataDisks))
832985
for i := range launchCfg.DataDisks {
@@ -906,7 +1059,11 @@ func resourceKubernetesNodePoolRead(d *schema.ResourceData, meta interface{}) er
9061059
_ = d.Set("vpc_id", asg.VpcId)
9071060
_ = d.Set("retry_policy", asg.RetryPolicy)
9081061
_ = d.Set("subnet_ids", helper.StringsInterfaces(asg.SubnetIdSet))
909-
_ = d.Set("multi_zone_subnet_policy", asg.MultiZoneSubnetPolicy)
1062+
1063+
// If not check, the diff between computed and default empty value leads to force replacement
1064+
if _, ok := d.GetOk("multi_zone_subnet_policy"); ok {
1065+
_ = d.Set("multi_zone_subnet_policy", asg.MultiZoneSubnetPolicy)
1066+
}
9101067
}
9111068

9121069
taints := make([]map[string]interface{}, len(nodePool.Taints))

tencentcloud/resource_tc_kubernetes_node_pool_test.go

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,16 @@ func TestAccTencentCloudTkeNodePoolResource(t *testing.T) {
5454
resource.TestCheckResourceAttr(testTkeClusterNodePoolResourceKey, "auto_scaling_config.0.system_disk_size", "100"),
5555
resource.TestCheckResourceAttr(testTkeClusterNodePoolResourceKey, "auto_scaling_config.0.data_disk.#", "2"),
5656
resource.TestCheckResourceAttr(testTkeClusterNodePoolResourceKey, "auto_scaling_config.0.internet_max_bandwidth_out", "20"),
57+
resource.TestCheckResourceAttr(testTkeClusterNodePoolResourceKey, "auto_scaling_config.0.instance_charge_type", "SPOTPAID"),
58+
resource.TestCheckResourceAttr(testTkeClusterNodePoolResourceKey, "auto_scaling_config.0.spot_instance_type", "one-time"),
59+
resource.TestCheckResourceAttr(testTkeClusterNodePoolResourceKey, "auto_scaling_config.0.spot_max_price", "1000"),
5760
resource.TestCheckResourceAttr(testTkeClusterNodePoolResourceKey, "max_size", "5"),
5861
resource.TestCheckResourceAttr(testTkeClusterNodePoolResourceKey, "min_size", "2"),
5962
resource.TestCheckResourceAttr(testTkeClusterNodePoolResourceKey, "labels.test3", "test3"),
6063
resource.TestCheckResourceAttr(testTkeClusterNodePoolResourceKey, "desired_capacity", "2"),
6164
resource.TestCheckResourceAttr(testTkeClusterNodePoolResourceKey, "name", "mynodepoolupdate"),
6265
resource.TestCheckResourceAttr(testTkeClusterNodePoolResourceKey, "node_os", "ubuntu18.04.1x86_64"),
63-
resource.TestCheckResourceAttr(testTkeClusterNodePoolResourceKey, "unschedulable", "1"),
66+
resource.TestCheckResourceAttr(testTkeClusterNodePoolResourceKey, "unschedulable", "0"),
6467
resource.TestCheckResourceAttr(testTkeClusterNodePoolResourceKey, "scaling_group_name", "basic_group_test"),
6568
resource.TestCheckResourceAttr(testTkeClusterNodePoolResourceKey, "default_cooldown", "350"),
6669
resource.TestCheckResourceAttr(testTkeClusterNodePoolResourceKey, "termination_policies.#", "1"),
@@ -155,7 +158,9 @@ data "tencentcloud_vpc_subnets" "vpc" {
155158
availability_zone = var.availability_zone
156159
}
157160
158-
data "tencentcloud_security_groups" "sg" {}
161+
data "tencentcloud_security_groups" "sg" {
162+
name = "test_preset_sg"
163+
}
159164
160165
variable "default_instance_type" {
161166
default = "S1.SMALL1"
@@ -169,6 +174,7 @@ resource "tencentcloud_kubernetes_cluster" "managed_cluster" {
169174
cluster_desc = "test cluster desc"
170175
cluster_max_service_num = 32
171176
cluster_version = "1.18.4"
177+
cluster_os = "tlinux2.2(tkernel3)x86_64"
172178
173179
worker_config {
174180
count = 1
@@ -214,7 +220,7 @@ resource "tencentcloud_kubernetes_node_pool" "np_test" {
214220
instance_type = var.default_instance_type
215221
system_disk_type = "CLOUD_PREMIUM"
216222
system_disk_size = "50"
217-
security_group_ids = [data.tencentcloud_security_groups.group.security_groups[0].security_group_id]
223+
security_group_ids = [data.tencentcloud_security_groups.sg.security_groups[0].security_group_id]
218224
219225
data_disk {
220226
disk_type = "CLOUD_PREMIUM"
@@ -261,7 +267,7 @@ resource "tencentcloud_kubernetes_node_pool" "np_test" {
261267
desired_capacity = 2
262268
enable_auto_scale = false
263269
node_os = "ubuntu18.04.1x86_64"
264-
delete_keep_instance = true
270+
delete_keep_instance = false
265271
scaling_group_name = "basic_group_test"
266272
default_cooldown = 350
267273
termination_policies = ["NEWEST_INSTANCE"]
@@ -270,7 +276,10 @@ resource "tencentcloud_kubernetes_node_pool" "np_test" {
270276
instance_type = var.default_instance_type
271277
system_disk_type = "CLOUD_PREMIUM"
272278
system_disk_size = "100"
273-
security_group_ids = [data.tencentcloud_security_groups.group.security_groups[0].security_group_id]
279+
security_group_ids = [data.tencentcloud_security_groups.sg.security_groups[0].security_group_id]
280+
instance_charge_type = "SPOTPAID"
281+
spot_instance_type = "one-time"
282+
spot_max_price = "1000"
274283
275284
data_disk {
276285
disk_type = "CLOUD_PREMIUM"
@@ -289,7 +298,7 @@ resource "tencentcloud_kubernetes_node_pool" "np_test" {
289298
enhanced_monitor_service = false
290299
291300
}
292-
unschedulable = 1
301+
unschedulable = 0
293302
labels = {
294303
"test3" = "test3",
295304
"test2" = "test2",

0 commit comments

Comments
 (0)