Skip to content

Commit e962664

Browse files
authored
feat: pg - support prepaid arguments (#1502)
* feat: pg - support prepaid arguments * fix: add readonly voucher arguments * changelog 1502 * fix: cancel prepaid parallel test
1 parent 6143f93 commit e962664

File tree

8 files changed

+251
-16
lines changed

8 files changed

+251
-16
lines changed

.changelog/1502.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:enhancement
2+
resource/tencentcloud_postgresql_instance: feat: pg - support prepaid arguments
3+
```

tencentcloud/internal/helper/helper.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,17 @@ func ImportWithDefaultValue(defaultValues map[string]interface{}) schema.StateFu
202202
}
203203
}
204204

205+
func ImmutableArgsChek(d *schema.ResourceData, arguments ...string) error {
206+
for _, v := range arguments {
207+
if d.HasChange(v) {
208+
o, _ := d.GetChange(v)
209+
_ = d.Set(v, o)
210+
return fmt.Errorf("argument `%s` cannot be changed", v)
211+
}
212+
}
213+
return nil
214+
}
215+
205216
func IsEmptyStr(s *string) bool {
206217
if s == nil {
207218
return true

tencentcloud/resource_tc_postgresql_instance.go

Lines changed: 60 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -178,12 +178,33 @@ func resourceTencentCloudPostgresqlInstance() *schema.Resource {
178178
Description: "Name of the postgresql instance.",
179179
},
180180
"charge_type": {
181-
Type: schema.TypeString,
181+
Type: schema.TypeString,
182+
Optional: true,
183+
Default: COMMON_PAYTYPE_POSTPAID,
184+
ForceNew: true,
185+
Description: "Pay type of the postgresql instance. Values `POSTPAID_BY_HOUR` (Default), `PREPAID`.",
186+
},
187+
"period": {
188+
Type: schema.TypeInt,
189+
Optional: true,
190+
Description: "Specify Prepaid period in month. Default `1`. Values: `1`, `2`, `3`, `4`, `5`, `6`, `7`, `8`, `9`, `10`, `11`, `12`, `24`, `36`.",
191+
},
192+
"auto_renew_flag": {
193+
Type: schema.TypeInt,
194+
Optional: true,
195+
Description: "Auto renew flag, `1` for enabled. NOTES: Only support prepaid instance.",
196+
},
197+
"auto_voucher": {
198+
Type: schema.TypeInt,
199+
Optional: true,
200+
Description: "Whether to use voucher, `1` for enabled.",
201+
},
202+
"voucher_ids": {
203+
Type: schema.TypeList,
182204
Optional: true,
183-
Default: COMMON_PAYTYPE_POSTPAID,
184-
ForceNew: true,
185-
ValidateFunc: validateAllowedStringValue(POSTGRESQL_PAYTYPE),
186-
Description: "Pay type of the postgresql instance. For now, only `POSTPAID_BY_HOUR` is valid.",
205+
RequiredWith: []string{"auto_voucher"},
206+
Description: "Specify Voucher Ids if `auto_voucher` was `1`, only support using 1 vouchers for now.",
207+
Elem: &schema.Schema{Type: schema.TypeString},
187208
},
188209
"engine_version": {
189210
Type: schema.TypeString,
@@ -449,7 +470,6 @@ func resourceTencentCloudPostgresqlInstanceCreate(d *schema.ResourceData, meta i
449470
nodeSet = d.Get("db_node_set").(*schema.Set).List()
450471
)
451472

452-
var period = 1
453473
// the sdk asks to set value with 1 when paytype is postpaid
454474

455475
var instanceId, specVersion, specCode string
@@ -462,8 +482,18 @@ func resourceTencentCloudPostgresqlInstanceCreate(d *schema.ResourceData, meta i
462482
needSupportTde = 0
463483
kmsKeyId = ""
464484
kmsRegion = ""
485+
period = 1
486+
autoRenewFlag = 0
487+
autoVoucher = 0
488+
voucherIds []*string
465489
)
466490

491+
if v, ok := d.GetOk("period"); ok {
492+
log.Printf("period set")
493+
period = v.(int)
494+
} else {
495+
log.Printf("period not set")
496+
}
467497
if v, ok := d.GetOk("db_major_vesion"); ok {
468498
dbMajorVersion = v.(string)
469499
}
@@ -482,6 +512,15 @@ func resourceTencentCloudPostgresqlInstanceCreate(d *schema.ResourceData, meta i
482512
if v, ok := d.GetOk("kms_region"); ok {
483513
kmsRegion = v.(string)
484514
}
515+
if v, ok := d.Get("auto_renew_flag").(int); ok {
516+
autoRenewFlag = v
517+
}
518+
if v, ok := d.Get("auto_voucher").(int); ok {
519+
autoVoucher = v
520+
}
521+
if v, ok := d.GetOk("voucher_ids"); ok {
522+
voucherIds = helper.InterfacesStringsPoint(v.([]interface{}))
523+
}
485524
requestSecurityGroup := make([]string, 0, len(securityGroups))
486525

487526
for _, v := range securityGroups {
@@ -552,8 +591,9 @@ func resourceTencentCloudPostgresqlInstanceCreate(d *schema.ResourceData, meta i
552591
dbVersion,
553592
dbMajorVersion,
554593
dbKernelVersion,
555-
payType, specCode,
556-
0,
594+
payType,
595+
specCode,
596+
autoRenewFlag,
557597
projectId,
558598
period,
559599
subnetId,
@@ -568,6 +608,8 @@ func resourceTencentCloudPostgresqlInstanceCreate(d *schema.ResourceData, meta i
568608
needSupportTde,
569609
kmsKeyId,
570610
kmsRegion,
611+
autoVoucher,
612+
voucherIds,
571613
)
572614
if inErr != nil {
573615
return retryError(inErr)
@@ -724,6 +766,16 @@ func resourceTencentCloudPostgresqlInstanceUpdate(d *schema.ResourceData, meta i
724766
instanceId := d.Id()
725767
d.Partial(true)
726768

769+
if err := helper.ImmutableArgsChek(d,
770+
"charge_type",
771+
"period",
772+
"auto_renew_flag",
773+
"auto_voucher",
774+
"voucher_ids",
775+
); err != nil {
776+
return err
777+
}
778+
727779
var outErr, inErr, checkErr error
728780
// update name
729781
if d.HasChange("name") {

tencentcloud/resource_tc_postgresql_instance_test.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,42 @@ func TestAccTencentCloudPostgresqlInstanceResource(t *testing.T) {
168168
})
169169
}
170170

171+
func TestAccTencentCloudPostgresqlInstanceResource_prepaid(t *testing.T) {
172+
resource.Test(t, resource.TestCase{
173+
PreCheck: func() { testAccPreCheckCommon(t, ACCOUNT_TYPE_PREPAY) },
174+
Providers: testAccProviders,
175+
CheckDestroy: testAccCheckPostgresqlInstanceDestroy,
176+
Steps: []resource.TestStep{
177+
{
178+
Config: testAccPostgresqlInstancePrepaid,
179+
Check: resource.ComposeTestCheckFunc(
180+
testAccCheckPostgresqlInstanceExists(testPostgresqlInstanceResourceKey),
181+
resource.TestCheckResourceAttrSet(testPostgresqlInstanceResourceKey, "id"),
182+
resource.TestCheckResourceAttr(testPostgresqlInstanceResourceKey, "name", "tf_postsql_pre"),
183+
resource.TestCheckResourceAttr(testPostgresqlInstanceResourceKey, "charge_type", "PREPAID"),
184+
resource.TestCheckResourceAttrSet(testPostgresqlInstanceResourceKey, "vpc_id"),
185+
resource.TestCheckResourceAttrSet(testPostgresqlInstanceResourceKey, "subnet_id"),
186+
resource.TestCheckResourceAttr(testPostgresqlInstanceResourceKey, "memory", "2"),
187+
resource.TestCheckResourceAttr(testPostgresqlInstanceResourceKey, "storage", "50"),
188+
resource.TestCheckResourceAttrSet(testPostgresqlInstanceResourceKey, "create_time"),
189+
resource.TestCheckResourceAttr(testPostgresqlInstanceResourceKey, "public_access_switch", "false"),
190+
resource.TestCheckResourceAttrSet(testPostgresqlInstanceResourceKey, "availability_zone"),
191+
resource.TestCheckResourceAttrSet(testPostgresqlInstanceResourceKey, "private_access_ip"),
192+
resource.TestCheckResourceAttrSet(testPostgresqlInstanceResourceKey, "private_access_port"),
193+
resource.TestCheckResourceAttrSet(testPostgresqlInstanceResourceKey, "db_major_vesion"),
194+
resource.TestCheckResourceAttrSet(testPostgresqlInstanceResourceKey, "db_major_version"),
195+
),
196+
},
197+
{
198+
ResourceName: testPostgresqlInstanceResourceKey,
199+
ImportState: true,
200+
ImportStateVerify: true,
201+
ImportStateVerifyIgnore: []string{"root_password", "spec_code", "public_access_switch", "charset", "backup_plan"},
202+
},
203+
},
204+
})
205+
}
206+
171207
func TestAccTencentCloudPostgresqlInstanceResource_MAZ(t *testing.T) {
172208
t.Parallel()
173209
resource.Test(t, resource.TestCase{
@@ -289,6 +325,34 @@ resource "tencentcloud_postgresql_instance" "test" {
289325
}
290326
`
291327

328+
const testAccPostgresqlInstancePrepaid = defaultVpcSubnets + `
329+
data "tencentcloud_availability_zones_by_product" "zone" {
330+
product = "postgres"
331+
}
332+
333+
data "tencentcloud_security_groups" "internal" {
334+
name = "default"
335+
}
336+
337+
locals {
338+
sg_id = data.tencentcloud_security_groups.internal.security_groups.0.security_group_id
339+
}
340+
341+
resource "tencentcloud_postgresql_instance" "test" {
342+
name = "tf_postsql_pre"
343+
availability_zone = data.tencentcloud_availability_zones_by_product.zone.zones[5].name
344+
charge_type = "PREPAID"
345+
vpc_id = local.vpc_id
346+
subnet_id = local.subnet_id
347+
engine_version = "10.4"
348+
root_password = "t1qaA2k1wgvfa3?ZZZ"
349+
security_groups = [local.sg_id]
350+
charset = "LATIN1"
351+
project_id = 0
352+
memory = 2
353+
storage = 50
354+
}`
355+
292356
const testAccPostgresqlInstanceOpenPublic string = testAccPostgresqlInstanceBasic + defaultVpcSubnets + `
293357
resource "tencentcloud_postgresql_instance" "test" {
294358
name = "tf_postsql_instance_update"

tencentcloud/resource_tc_postgresql_readonly_instance.go

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,12 +120,28 @@ func resourceTencentCloudPostgresqlReadonlyInstance() *schema.Resource {
120120
ValidateFunc: validateAllowedStringValue(POSTGRESQL_PAYTYPE),
121121
Description: "instance billing mode. Valid values: PREPAID (monthly subscription), POSTPAID_BY_HOUR (pay-as-you-go).",
122122
},
123+
"period": {
124+
Type: schema.TypeInt,
125+
Optional: true,
126+
Description: "Specify Prepaid period in month. Default `1`. Values: `1`, `2`, `3`, `4`, `5`, `6`, `7`, `8`, `9`, `10`, `11`, `12`, `24`, `36`.",
127+
},
123128
"auto_renew_flag": {
124129
Type: schema.TypeInt,
125130
Optional: true,
126131
Default: 0,
127-
ForceNew: true,
128-
Description: "Renewal flag. Valid values: 0 (manual renewal), 1 (auto-renewal). Default value: 0.",
132+
Description: "Auto renew flag, `1` for enabled. NOTES: Only support prepaid instance.",
133+
},
134+
"auto_voucher": {
135+
Type: schema.TypeInt,
136+
Optional: true,
137+
Description: "Whether to use voucher, `1` for enabled.",
138+
},
139+
"voucher_ids": {
140+
Type: schema.TypeList,
141+
Optional: true,
142+
RequiredWith: []string{"auto_voucher"},
143+
Description: "Specify Voucher Ids if `auto_voucher` was `1`, only support using 1 vouchers for now.",
144+
Elem: &schema.Schema{Type: schema.TypeString},
129145
},
130146
"need_support_ipv6": {
131147
Type: schema.TypeInt,
@@ -194,6 +210,15 @@ func resourceTencentCloudPostgresqlReadOnlyInstanceCreate(d *schema.ResourceData
194210
if v, ok := d.GetOk("auto_renew_flag"); ok {
195211
request.AutoRenewFlag = helper.IntInt64(v.(int))
196212
}
213+
if v, ok := d.Get("period").(int); ok && v > 0 {
214+
request.Period = helper.IntUint64(v)
215+
}
216+
if v, ok := d.Get("auto_voucher").(int); ok && v > 0 {
217+
request.AutoVoucher = helper.IntUint64(v)
218+
}
219+
if v, ok := d.GetOk("voucher_ids"); ok {
220+
request.VoucherIds = helper.InterfacesStringsPoint(v.([]interface{}))
221+
}
197222
if v, ok := d.GetOk("vpc_id"); ok {
198223
request.VpcId = helper.String(v.(string))
199224
}
@@ -373,6 +398,16 @@ func resourceTencentCloudPostgresqlReadOnlyInstanceUpdate(d *schema.ResourceData
373398
instanceId := d.Id()
374399
d.Partial(true)
375400

401+
if err := helper.ImmutableArgsChek(d,
402+
"charge_type",
403+
"period",
404+
"auto_renew_flag",
405+
"auto_voucher",
406+
"voucher_ids",
407+
); err != nil {
408+
return err
409+
}
410+
376411
var outErr, inErr, checkErr error
377412
// update name
378413
if d.HasChange("name") {

tencentcloud/service_tencentcloud_postgresql.go

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ func (me *PostgresqlService) CreatePostgresqlInstance(
2727
storage int,
2828
username, password, charset string,
2929
dbNodeSet []*postgresql.DBNode,
30-
needSupportTde int, kmsKeyId, kmsRegion string,
30+
needSupportTde int, kmsKeyId, kmsRegion string, autoVoucher int, voucherIds []*string,
3131
) (instanceId string, errRet error) {
3232
logId := getLogId(ctx)
3333
request := postgresql.NewCreateInstancesRequest()
@@ -79,6 +79,14 @@ func (me *PostgresqlService) CreatePostgresqlInstance(
7979
request.DBNodeSet = dbNodeSet
8080
}
8181

82+
if autoVoucher > 0 {
83+
request.AutoVoucher = helper.IntUint64(autoVoucher)
84+
}
85+
86+
if len(voucherIds) > 0 {
87+
request.VoucherIds = voucherIds
88+
}
89+
8290
ratelimit.Check(request.GetAction())
8391
response, err := me.client.UsePostgresqlClient().CreateInstances(request)
8492
if err != nil {
@@ -89,13 +97,68 @@ func (me *PostgresqlService) CreatePostgresqlInstance(
8997
errRet = fmt.Errorf("TencentCloud SDK return nil response, %s", request.GetAction())
9098
}
9199
if len(response.Response.DBInstanceIdSet) == 0 {
92-
errRet = errors.New("TencentCloud SDK returns empty postgresql ID")
93-
return
100+
if len(response.Response.DealNames) == 0 {
101+
errRet = errors.New("TencentCloud SDK returns empty postgresql ID and Deals")
102+
return
103+
}
104+
log.Printf("[WARN] No postgresql ID returns, requesting Deal Id")
105+
dealId := response.Response.DealNames[0]
106+
deals, err := me.DescribeOrders(ctx, []*string{dealId})
107+
if err != nil {
108+
errRet = err
109+
return
110+
}
111+
if len(deals) > 0 && len(deals[0].DBInstanceIdSet) > 0 {
112+
instanceId = *deals[0].DBInstanceIdSet[0]
113+
}
94114
} else if len(response.Response.DBInstanceIdSet) > 1 {
95115
errRet = errors.New("TencentCloud SDK returns more than one postgresql ID")
96116
return
117+
} else {
118+
instanceId = *response.Response.DBInstanceIdSet[0]
119+
}
120+
return
121+
}
122+
123+
func (me *PostgresqlService) DescribeOrders(ctx context.Context, dealIds []*string) (deals []*postgresql.PgDeal, errRet error) {
124+
logId := getLogId(ctx)
125+
request := postgresql.NewDescribeOrdersRequest()
126+
defer func() {
127+
if errRet != nil {
128+
log.Printf("[CRITAL]%s api[%s] fail, request body [%s], reason[%s]\n",
129+
logId, request.GetAction(), request.ToJsonString(), errRet.Error())
130+
}
131+
}()
132+
133+
request.DealNames = dealIds
134+
135+
ratelimit.Check(request.GetAction())
136+
137+
var response *postgresql.DescribeOrdersResponse
138+
err := resource.Retry(readRetryTimeout*5, func() *resource.RetryError {
139+
res, err := me.client.UsePostgresqlClient().DescribeOrders(request)
140+
if err != nil {
141+
return retryError(err)
142+
}
143+
if len(res.Response.Deals) == 0 {
144+
return resource.RetryableError(fmt.Errorf("waiting for deal return instance id"))
145+
}
146+
response = res
147+
return nil
148+
})
149+
150+
if err != nil {
151+
errRet = err
152+
return
97153
}
98-
instanceId = *response.Response.DBInstanceIdSet[0]
154+
155+
if response != nil {
156+
deals = response.Response.Deals
157+
}
158+
159+
log.Printf("[DEBUG]%s api[%s] success, request body [%s], response body [%s]\n",
160+
logId, request.GetAction(), request.ToJsonString(), response.ToJsonString())
161+
99162
return
100163
}
101164

0 commit comments

Comments
 (0)