Skip to content

Commit df8e230

Browse files
authored
fix: cvm - charge validate (#956)
1 parent d8dab1d commit df8e230

File tree

1 file changed

+73
-125
lines changed

1 file changed

+73
-125
lines changed

tencentcloud/resource_tc_instance.go

Lines changed: 73 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -541,9 +541,6 @@ func resourceTencentCloudInstanceCreate(d *schema.ResourceData, meta interface{}
541541
if period, ok := d.GetOk("instance_charge_type_prepaid_period"); ok {
542542
periodInt64 := int64(period.(int))
543543
request.InstanceChargePrepaid.Period = &periodInt64
544-
} else {
545-
return fmt.Errorf("instance charge type prepaid period can not be empty when charge type is %s",
546-
instanceChargeType)
547544
}
548545
if renewFlag, ok := d.GetOk("instance_charge_type_prepaid_renew_flag"); ok {
549546
request.InstanceChargePrepaid.RenewFlag = helper.String(renewFlag.(string))
@@ -1006,12 +1003,19 @@ func resourceTencentCloudInstanceUpdate(d *schema.ResourceData, meta interface{}
10061003

10071004
d.Partial(true)
10081005

1006+
// Get the latest instance info from actual resource.
1007+
instanceInfo, err := cvmService.DescribeInstanceById(ctx, instanceId)
1008+
if err != nil {
1009+
return err
1010+
}
1011+
10091012
var (
1010-
periodSet = false
1011-
renewFlagSet = false
1013+
periodSet = false
1014+
renewFlagSet = false
1015+
alreadyPrepaid = *instanceInfo.InstanceChargeType == CVM_CHARGE_TYPE_PREPAID
10121016
)
10131017

1014-
if d.HasChange("instance_charge_type") {
1018+
if d.HasChange("instance_charge_type") && !alreadyPrepaid {
10151019
old, chargeType := d.GetChange("instance_charge_type")
10161020
if old.(string) != CVM_CHARGE_TYPE_POSTPAID || chargeType.(string) != CVM_CHARGE_TYPE_PREPAID {
10171021
return fmt.Errorf("Only support change chargeType from POSTPAID_BY_HOUR to PREPAID.")
@@ -1022,9 +1026,6 @@ func resourceTencentCloudInstanceUpdate(d *schema.ResourceData, meta interface{}
10221026
)
10231027
if v, ok := d.GetOk("instance_charge_type_prepaid_period"); ok {
10241028
period = v.(int)
1025-
} else {
1026-
return fmt.Errorf("instance charge type prepaid period can not"+
1027-
" be empty when charge type is %s", chargeType)
10281029
}
10291030
if v, ok := d.GetOk("instance_charge_type_prepaid_renew_flag"); ok {
10301031
renewFlag = v.(string)
@@ -1035,70 +1036,48 @@ func resourceTencentCloudInstanceUpdate(d *schema.ResourceData, meta interface{}
10351036
return err
10361037
}
10371038
// query cvm status
1038-
err = resource.Retry(5*readRetryTimeout, func() *resource.RetryError {
1039-
instance, errRet := cvmService.DescribeInstanceById(ctx, instanceId)
1040-
if errRet != nil {
1041-
return retryError(errRet, InternalError)
1042-
}
1043-
if instance != nil && instance.LatestOperationState != nil {
1044-
if *instance.LatestOperationState == CVM_LATEST_OPERATION_STATE_OPERATING {
1045-
return resource.RetryableError(fmt.Errorf("cvm instance status is %s, retry...", *instance.LatestOperationState))
1046-
}
1047-
if *instance.LatestOperationState == CVM_LATEST_OPERATION_STATE_FAILED {
1048-
return resource.NonRetryableError(fmt.Errorf("failed operation when modify instance charge type"))
1049-
}
1050-
}
1051-
return nil
1052-
})
1039+
err = waitForOperationFinished(d, meta, 5*readRetryTimeout, CVM_LATEST_OPERATION_STATE_OPERATING, false)
10531040
if err != nil {
10541041
return err
10551042
}
10561043
periodSet = true
10571044
renewFlagSet = true
10581045
}
10591046

1047+
// When instance is prepaid but period was empty and set to 1, skip this case.
1048+
op, np := d.GetChange("instance_charge_type_prepaid_period")
1049+
if _, ok := op.(int); !ok && np.(int) == 1 {
1050+
periodSet = true
1051+
}
10601052
if d.HasChange("instance_charge_type_prepaid_period") && !periodSet {
10611053
chargeType := d.Get("instance_charge_type").(string)
1062-
if chargeType != CVM_CHARGE_TYPE_PREPAID {
1063-
return fmt.Errorf("tencentcloud_cvm_instance update on instance_charge_type_prepaid_period or instance_charge_type_prepaid_renew_flag is only supported with charge type PREPAID")
1054+
period := d.Get("instance_charge_type_prepaid_period").(int)
1055+
renewFlag := ""
1056+
1057+
if v, ok := d.GetOk("instance_charge_type_prepaid_renew_flag"); ok {
1058+
renewFlag = v.(string)
10641059
}
1065-
if !d.HasChange("instance_charge_type") {
1066-
return fmt.Errorf("tencentcloud_cvm_instance update on instance_charge_type_prepaid_period is only with charge type change to PREPAID")
1060+
err := cvmService.ModifyInstanceChargeType(ctx, instanceId, chargeType, period, renewFlag)
1061+
if err != nil {
1062+
return err
10671063
}
1064+
// query cvm status
1065+
err = waitForOperationFinished(d, meta, 5*readRetryTimeout, CVM_LATEST_OPERATION_STATE_OPERATING, false)
1066+
if err != nil {
1067+
return err
1068+
}
1069+
renewFlagSet = true
10681070
}
10691071

10701072
if d.HasChange("instance_charge_type_prepaid_renew_flag") && !renewFlagSet {
1071-
//check
1072-
chargeType := d.Get("instance_charge_type").(string)
1073-
if chargeType != CVM_CHARGE_TYPE_PREPAID {
1074-
return fmt.Errorf("tencentcloud_cvm_instance update on instance_charge_type_prepaid_period or instance_charge_type_prepaid_renew_flag is only supported with charge type PREPAID")
1075-
}
1076-
10771073
//renew api
10781074
err := cvmService.ModifyRenewParam(ctx, instanceId, d.Get("instance_charge_type_prepaid_renew_flag").(string))
10791075
if err != nil {
10801076
return err
10811077
}
10821078

10831079
//check success
1084-
err = resource.Retry(2*readRetryTimeout, func() *resource.RetryError {
1085-
instance, errRet := cvmService.DescribeInstanceById(ctx, instanceId)
1086-
if errRet != nil {
1087-
return retryError(errRet, InternalError)
1088-
}
1089-
if instance != nil && instance.LatestOperationState != nil {
1090-
if *instance.LatestOperationState == CVM_LATEST_OPERATION_STATE_SUCCESS {
1091-
return nil
1092-
} else if *instance.LatestOperationState == CVM_LATEST_OPERATION_STATE_FAILED {
1093-
return resource.NonRetryableError(fmt.Errorf("update instance %s prepaid charge type failed", instanceId))
1094-
} else {
1095-
return resource.RetryableError(fmt.Errorf("cvm instance status is %s, retry...", *instance.InstanceState))
1096-
}
1097-
} else {
1098-
return resource.RetryableError(fmt.Errorf("cvm instance %s returns nil status", instanceId))
1099-
}
1100-
1101-
})
1080+
err = waitForOperationFinished(d, meta, 2*readRetryTimeout, CVM_LATEST_OPERATION_STATE_OPERATING, false)
11021081
if err != nil {
11031082
return err
11041083
}
@@ -1217,18 +1196,7 @@ func resourceTencentCloudInstanceUpdate(d *schema.ResourceData, meta interface{}
12171196
if err != nil {
12181197
return err
12191198
}
1220-
d.SetPartial("password")
1221-
time.Sleep(10 * time.Second)
1222-
err = resource.Retry(2*readRetryTimeout, func() *resource.RetryError {
1223-
instance, errRet := cvmService.DescribeInstanceById(ctx, instanceId)
1224-
if errRet != nil {
1225-
return retryError(errRet, InternalError)
1226-
}
1227-
if instance != nil && instance.LatestOperationState != nil && *instance.LatestOperationState == CVM_LATEST_OPERATION_STATE_OPERATING {
1228-
return resource.RetryableError(fmt.Errorf("cvm instance latest operetion status is %s, retry...", *instance.LatestOperationState))
1229-
}
1230-
return nil
1231-
})
1199+
err = waitForOperationFinished(d, meta, 2*readRetryTimeout, CVM_LATEST_OPERATION_STATE_OPERATING, false)
12321200
if err != nil {
12331201
return err
12341202
}
@@ -1243,17 +1211,7 @@ func resourceTencentCloudInstanceUpdate(d *schema.ResourceData, meta interface{}
12431211
if err != nil {
12441212
return err
12451213
}
1246-
time.Sleep(10 * time.Second)
1247-
err = resource.Retry(2*readRetryTimeout, func() *resource.RetryError {
1248-
instance, errRet := cvmService.DescribeInstanceById(ctx, instanceId)
1249-
if errRet != nil {
1250-
return retryError(errRet, InternalError)
1251-
}
1252-
if instance != nil && instance.LatestOperationState != nil && *instance.LatestOperationState == CVM_LATEST_OPERATION_STATE_OPERATING {
1253-
return resource.RetryableError(fmt.Errorf("cvm instance latest operetion status is %s, retry...", *instance.LatestOperationState))
1254-
}
1255-
return nil
1256-
})
1214+
err = waitForOperationFinished(d, meta, 2*readRetryTimeout, CVM_LATEST_OPERATION_STATE_OPERATING, false)
12571215
if err != nil {
12581216
return err
12591217
}
@@ -1264,17 +1222,7 @@ func resourceTencentCloudInstanceUpdate(d *schema.ResourceData, meta interface{}
12641222
if err != nil {
12651223
return err
12661224
}
1267-
time.Sleep(10 * time.Second)
1268-
err = resource.Retry(2*readRetryTimeout, func() *resource.RetryError {
1269-
instance, errRet := cvmService.DescribeInstanceById(ctx, instanceId)
1270-
if errRet != nil {
1271-
return retryError(errRet, InternalError)
1272-
}
1273-
if instance != nil && instance.LatestOperationState != nil && *instance.LatestOperationState == CVM_LATEST_OPERATION_STATE_OPERATING {
1274-
return resource.RetryableError(fmt.Errorf("cvm instance latest operetion status is %s, retry...", *instance.LatestOperationState))
1275-
}
1276-
return nil
1277-
})
1225+
err = waitForOperationFinished(d, meta, 2*readRetryTimeout, CVM_LATEST_OPERATION_STATE_OPERATING, false)
12781226
if err != nil {
12791227
return err
12801228
}
@@ -1379,20 +1327,7 @@ func resourceTencentCloudInstanceUpdate(d *schema.ResourceData, meta interface{}
13791327
}
13801328
d.SetPartial("instance_type")
13811329

1382-
// wait for status
1383-
err = resource.Retry(2*readRetryTimeout, func() *resource.RetryError {
1384-
instance, errRet := cvmService.DescribeInstanceById(ctx, instanceId)
1385-
if errRet != nil {
1386-
return retryError(errRet, InternalError)
1387-
}
1388-
// Modifying instance type need restart the instance
1389-
// so status of CVM must be running when running flag is true
1390-
if instance != nil && instance.LatestOperationState != nil && (*instance.LatestOperationState == CVM_LATEST_OPERATION_STATE_OPERATING ||
1391-
(flag && *instance.InstanceState != CVM_STATUS_RUNNING)) {
1392-
return resource.RetryableError(fmt.Errorf("cvm instance latest operetion status is %s, retry...", *instance.LatestOperationState))
1393-
}
1394-
return nil
1395-
})
1330+
err = waitForOperationFinished(d, meta, 2*readRetryTimeout, CVM_LATEST_OPERATION_STATE_OPERATING, false)
13961331
if err != nil {
13971332
return err
13981333
}
@@ -1405,20 +1340,7 @@ func resourceTencentCloudInstanceUpdate(d *schema.ResourceData, meta interface{}
14051340
}
14061341
d.SetPartial("cdh_instance_type")
14071342

1408-
// wait for status
1409-
err = resource.Retry(2*readRetryTimeout, func() *resource.RetryError {
1410-
instance, errRet := cvmService.DescribeInstanceById(ctx, instanceId)
1411-
if errRet != nil {
1412-
return retryError(errRet, InternalError)
1413-
}
1414-
// Modifying instance type need restart the instance
1415-
// so status of CVM must be running when running flag is true
1416-
if instance != nil && (instance.LatestOperationState != nil && *instance.LatestOperationState == CVM_LATEST_OPERATION_STATE_OPERATING ||
1417-
(flag && instance.LatestOperationState != nil && *instance.InstanceState != CVM_STATUS_RUNNING)) {
1418-
return resource.RetryableError(fmt.Errorf("cvm instance latest operetion status is %s, retry...", *instance.LatestOperationState))
1419-
}
1420-
return nil
1421-
})
1343+
err = waitForOperationFinished(d, meta, 2*readRetryTimeout, CVM_LATEST_OPERATION_STATE_OPERATING, false)
14221344
if err != nil {
14231345
return err
14241346
}
@@ -1491,17 +1413,7 @@ func resourceTencentCloudInstanceUpdate(d *schema.ResourceData, meta interface{}
14911413
return err
14921414
}
14931415
d.SetPartial("internet_max_bandwidth_out")
1494-
time.Sleep(1 * time.Second)
1495-
err = resource.Retry(2*readRetryTimeout, func() *resource.RetryError {
1496-
instance, errRet := cvmService.DescribeInstanceById(ctx, instanceId)
1497-
if errRet != nil {
1498-
return retryError(errRet, InternalError)
1499-
}
1500-
if instance != nil && *instance.LatestOperationState == CVM_LATEST_OPERATION_STATE_OPERATING {
1501-
return resource.RetryableError(fmt.Errorf("cvm instance latest operetion status is %s, retry...", *instance.LatestOperationState))
1502-
}
1503-
return nil
1504-
})
1416+
err = waitForOperationFinished(d, meta, 2*readRetryTimeout, CVM_LATEST_OPERATION_STATE_OPERATING, false)
15051417
if err != nil {
15061418
return err
15071419
}
@@ -1749,3 +1661,39 @@ func switchInstance(cvmService *CvmService, ctx context.Context, d *schema.Resou
17491661
}
17501662
return nil
17511663
}
1664+
1665+
func waitForOperationFinished(d *schema.ResourceData, meta interface{}, timeout time.Duration, state string, immediately bool) error {
1666+
logId := getLogId(contextNil)
1667+
ctx := context.WithValue(context.TODO(), logIdKey, logId)
1668+
client := meta.(*TencentCloudClient).apiV3Conn
1669+
cvmService := CvmService{client}
1670+
instanceId := d.Id()
1671+
// We cannot catch LatestOperationState change immediately after modification returns, we must wait for LatestOperationState update to expected.
1672+
if !immediately {
1673+
time.Sleep(time.Second * 10)
1674+
}
1675+
1676+
err := resource.Retry(timeout, func() *resource.RetryError {
1677+
instance, errRet := cvmService.DescribeInstanceById(ctx, instanceId)
1678+
if errRet != nil {
1679+
return retryError(errRet, InternalError)
1680+
}
1681+
if instance == nil {
1682+
return resource.NonRetryableError(fmt.Errorf("%s not exists", instanceId))
1683+
}
1684+
if instance.LatestOperationState == nil {
1685+
return resource.RetryableError(fmt.Errorf("wait for operation update"))
1686+
}
1687+
if *instance.LatestOperationState == state {
1688+
return resource.RetryableError(fmt.Errorf("waiting for instance %s operation", instanceId))
1689+
}
1690+
if *instance.LatestOperationState == CVM_LATEST_OPERATION_STATE_FAILED {
1691+
return resource.NonRetryableError(fmt.Errorf("failed operation"))
1692+
}
1693+
return nil
1694+
})
1695+
if err != nil {
1696+
return err
1697+
}
1698+
return nil
1699+
}

0 commit comments

Comments
 (0)