From f271e66c282b4a4f805cf6f78de303f4470397fe Mon Sep 17 00:00:00 2001 From: Kagashino Date: Mon, 21 Mar 2022 02:37:49 +0800 Subject: [PATCH 1/2] fix: sqlserver - add prepaid charge type and fix testcases --- tencentcloud/basic_test.go | 10 ++ ...c_sqlserver_account_db_attachments_test.go | 2 +- .../data_source_tc_sqlserver_accounts_test.go | 2 +- .../data_source_tc_sqlserver_backups_test.go | 2 +- ...ource_tc_sqlserver_basic_instances_test.go | 2 +- ...data_source_tc_sqlserver_instances_test.go | 15 +- ...ource_tc_sqlserver_readonly_groups_test.go | 2 +- tencentcloud/extension_sqlserver.go | 2 + tencentcloud/resource_tc_sqlserver_db_test.go | 8 +- .../resource_tc_sqlserver_instance.go | 124 ++++++++++++++-- .../resource_tc_sqlserver_instance_test.go | 138 +++++++++++++++++- ...resource_tc_sqlserver_readonly_instance.go | 55 ++++++- .../service_tencentcloud_sqlserver.go | 71 ++------- .../docs/r/sqlserver_instance.html.markdown | 6 +- .../sqlserver_readonly_instance.html.markdown | 5 +- 15 files changed, 337 insertions(+), 107 deletions(-) diff --git a/tencentcloud/basic_test.go b/tencentcloud/basic_test.go index cae1ba341a..05ef713c20 100644 --- a/tencentcloud/basic_test.go +++ b/tencentcloud/basic_test.go @@ -163,6 +163,16 @@ locals { } ` +const CommonPresetSQLServer = ` +data "tencentcloud_sqlserver_instances" "sqlserver" { + project_id = "` + defaultProjectId + `" +} + +locals { + sqlserver_id = data.tencentcloud_sqlserver_instances.sqlserver.instance_list.0.id +} +` + const instanceCommonTestCase = defaultInstanceVariable + ` resource "tencentcloud_instance" "default" { instance_name = var.instance_name diff --git a/tencentcloud/data_source_tc_sqlserver_account_db_attachments_test.go b/tencentcloud/data_source_tc_sqlserver_account_db_attachments_test.go index f45a87cf4f..07485f1da3 100644 --- a/tencentcloud/data_source_tc_sqlserver_account_db_attachments_test.go +++ b/tencentcloud/data_source_tc_sqlserver_account_db_attachments_test.go @@ -8,7 +8,7 @@ import ( var testDataSqlserverAccountDBAttachmentsName = "data.tencentcloud_sqlserver_account_db_attachments.test" -func TestAccTencentCloudDataSqlserverAccountDBAttachments(t *testing.T) { +func TestAccDataSourceTencentCloudSqlserverAccountDBAttachments(t *testing.T) { t.Parallel() resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, diff --git a/tencentcloud/data_source_tc_sqlserver_accounts_test.go b/tencentcloud/data_source_tc_sqlserver_accounts_test.go index 9144d01e9e..f749e2e526 100644 --- a/tencentcloud/data_source_tc_sqlserver_accounts_test.go +++ b/tencentcloud/data_source_tc_sqlserver_accounts_test.go @@ -8,7 +8,7 @@ import ( var testDataSqlserverAccountsName = "data.tencentcloud_sqlserver_accounts.test" -func TestAccTencentCloudDataSqlserverAccounts(t *testing.T) { +func TestAccDataSourceTencentCloudSqlserverAccounts(t *testing.T) { t.Parallel() resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, diff --git a/tencentcloud/data_source_tc_sqlserver_backups_test.go b/tencentcloud/data_source_tc_sqlserver_backups_test.go index f10d539cca..b10db7f65a 100644 --- a/tencentcloud/data_source_tc_sqlserver_backups_test.go +++ b/tencentcloud/data_source_tc_sqlserver_backups_test.go @@ -8,7 +8,7 @@ import ( var testDataSqlserverBackupsName = "data.tencentcloud_sqlserver_backups.test" -func TestAccTencentCloudDataSqlserverBackups(t *testing.T) { +func TestAccDataSourceTencentCloudSqlserverBackups(t *testing.T) { t.Parallel() resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, diff --git a/tencentcloud/data_source_tc_sqlserver_basic_instances_test.go b/tencentcloud/data_source_tc_sqlserver_basic_instances_test.go index 18ee6f24bc..622de0f173 100644 --- a/tencentcloud/data_source_tc_sqlserver_basic_instances_test.go +++ b/tencentcloud/data_source_tc_sqlserver_basic_instances_test.go @@ -8,7 +8,7 @@ import ( var testDataSqlserverBasicInstancesName = "data.tencentcloud_sqlserver_basic_instances.id_test" -func TestAccTencentCloudDataSqlserverBasicInstances(t *testing.T) { +func TestAccDataSourceTencentCloudSqlserverBasicInstances(t *testing.T) { t.Parallel() resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, diff --git a/tencentcloud/data_source_tc_sqlserver_instances_test.go b/tencentcloud/data_source_tc_sqlserver_instances_test.go index ab25e0dd1b..9ad6a89538 100644 --- a/tencentcloud/data_source_tc_sqlserver_instances_test.go +++ b/tencentcloud/data_source_tc_sqlserver_instances_test.go @@ -8,7 +8,7 @@ import ( var testDataSqlserverInstancesName = "data.tencentcloud_sqlserver_instances.id_test" -func TestAccTencentCloudDataSqlserverInstances(t *testing.T) { +func TestAccDataSourceTencentCloudSqlserverInstances(t *testing.T) { t.Parallel() resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -32,28 +32,21 @@ func TestAccTencentCloudDataSqlserverInstances(t *testing.T) { resource.TestCheckResourceAttrSet(testDataSqlserverInstancesName, "instance_list.0.vport"), resource.TestCheckResourceAttrSet(testDataSqlserverInstancesName, "instance_list.0.status"), resource.TestCheckResourceAttrSet(testDataSqlserverInstancesName, "instance_list.0.used_storage"), - resource.TestCheckResourceAttr(testDataPostgresqlInstancesName, "instance_list.0.tags.tf", "test"), ), }, }, }) } -const testAccTencentCloudDataSqlserverInstancesBasic = ` -variable "availability_zone"{ - default = "ap-guangzhou-2" -} +var testAccTencentCloudDataSqlserverInstancesBasic = testAccSqlserverInstanceBasic + ` resource "tencentcloud_sqlserver_instance" "test" { - name = "tf_postsql_instance" - availability_zone = var.availability_zone + name = "tf_sqlserver_instance" + availability_zone = local.az charge_type = "POSTPAID_BY_HOUR" project_id = 0 memory = 2 storage = 10 - tags = { - tf = "test" - } } data "tencentcloud_sqlserver_instances" "id_test"{ diff --git a/tencentcloud/data_source_tc_sqlserver_readonly_groups_test.go b/tencentcloud/data_source_tc_sqlserver_readonly_groups_test.go index 5afeaf769f..f0a44c07ce 100644 --- a/tencentcloud/data_source_tc_sqlserver_readonly_groups_test.go +++ b/tencentcloud/data_source_tc_sqlserver_readonly_groups_test.go @@ -8,7 +8,7 @@ import ( var testDataSqlserverReadonlyGroupsName = "data.tencentcloud_sqlserver_readonly_groups.test" -func TestAccTencentCloudDataSqlserverReadonlyGroups(t *testing.T) { +func TestAccDataSourceTencentCloudSqlserverReadonlyGroups(t *testing.T) { t.Parallel() resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, diff --git a/tencentcloud/extension_sqlserver.go b/tencentcloud/extension_sqlserver.go index c7b1e54a59..60bdeba5f4 100644 --- a/tencentcloud/extension_sqlserver.go +++ b/tencentcloud/extension_sqlserver.go @@ -46,6 +46,7 @@ const ( SQLSERVER_DB_RUNNING = 2 SQLSERVER_DB_MODIFYING = 3 SQLSERVER_DB_DELETING = -1 + SQLSERVER_DB_UPGRADING = 9 ) var SQLSERVER_DB_STATUS = map[int64]string{ @@ -53,6 +54,7 @@ var SQLSERVER_DB_STATUS = map[int64]string{ SQLSERVER_DB_RUNNING: "running", SQLSERVER_DB_MODIFYING: "modifying", SQLSERVER_DB_DELETING: "deleting", + SQLSERVER_DB_UPGRADING: "upgrading", } const ( diff --git a/tencentcloud/resource_tc_sqlserver_db_test.go b/tencentcloud/resource_tc_sqlserver_db_test.go index 5d7211b7f1..e7d055c2fc 100644 --- a/tencentcloud/resource_tc_sqlserver_db_test.go +++ b/tencentcloud/resource_tc_sqlserver_db_test.go @@ -89,17 +89,17 @@ func testAccCheckSqlserverDBExists(n string) resource.TestCheckFunc { } } -const testAccSqlserverDB_basic = testAccSqlserverInstance + ` +const testAccSqlserverDB_basic = CommonPresetSQLServer + ` resource "tencentcloud_sqlserver_db" "mysqlserver_db" { - instance_id = tencentcloud_sqlserver_instance.test.id + instance_id = local.sqlserver_id name = "testAccSqlserverDB" charset = "Chinese_PRC_BIN" remark = "testACC-remark" }` -const testAccSqlserverDB_basic_update_remark = testAccSqlserverInstance + ` +const testAccSqlserverDB_basic_update_remark = CommonPresetSQLServer + ` resource "tencentcloud_sqlserver_db" "mysqlserver_db" { - instance_id = tencentcloud_sqlserver_instance.test.id + instance_id = local.sqlserver_id name = "testAccSqlserverDB" charset = "Chinese_PRC_BIN" remark = "testACC-remark_update" diff --git a/tencentcloud/resource_tc_sqlserver_instance.go b/tencentcloud/resource_tc_sqlserver_instance.go index fa3a67013c..e83700700a 100644 --- a/tencentcloud/resource_tc_sqlserver_instance.go +++ b/tencentcloud/resource_tc_sqlserver_instance.go @@ -36,8 +36,8 @@ import ( "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/internal/helper" ) -func TencentSqlServerBasicInfo() map[string]*schema.Schema { - return map[string]*schema.Schema{ +func TencentSqlServerBasicInfo(isROInstance bool) map[string]*schema.Schema { + basicSchema := map[string]*schema.Schema{ "name": { Type: schema.TypeString, Required: true, @@ -49,8 +49,28 @@ func TencentSqlServerBasicInfo() map[string]*schema.Schema { Optional: true, Default: COMMON_PAYTYPE_POSTPAID, ForceNew: true, - ValidateFunc: validateAllowedStringValue(POSTGRESQL_PAYTYPE), - Description: "Pay type of the SQL Server instance. For now, only `POSTPAID_BY_HOUR` is valid.", + ValidateFunc: validateAllowedStringValue([]string{COMMON_PAYTYPE_PREPAID, COMMON_PAYTYPE_POSTPAID}), + Description: "Pay type of the SQL Server instance. Available values `PREPAID`, `POSTPAID_BY_HOUR`.", + }, + "period": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validateIntegerInRange(1, 48), + Description: "Purchase instance period in month. The value does not exceed 48.", + }, + "auto_voucher": { + Type: schema.TypeInt, + Optional: true, + Default: 0, + Description: "Whether to use the voucher automatically; 1 for yes, 0 for no, the default is 0.", + }, + "voucher_ids": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Description: "An array of voucher IDs, currently only one can be used for a single order.", }, "vpc_id": { Type: schema.TypeString, @@ -121,6 +141,16 @@ func TencentSqlServerBasicInfo() map[string]*schema.Schema { Description: "The tags of the SQL Server.", }, } + + if !isROInstance { + basicSchema["auto_renew"] = &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "Automatic renewal sign. 0 for normal renewal, 1 for automatic renewal, the default is 1 automatic renewal. Only valid when purchasing a prepaid instance.", + } + } + + return basicSchema } func resourceTencentCloudSqlserverInstance() *schema.Resource { @@ -173,7 +203,7 @@ func resourceTencentCloudSqlserverInstance() *schema.Resource { Description: "Project ID, default value is 0.", }, } - basic := TencentSqlServerBasicInfo() + basic := TencentSqlServerBasicInfo(false) for k, v := range basic { specialInfo[k] = v } @@ -223,9 +253,7 @@ func resourceTencentCloudSqlserverInstanceCreate(d *schema.ResourceData, meta in weekSet = append(weekSet, vv.(int)) } } - if payType == COMMON_PAYTYPE_POSTPAID { - payType = "POSTPAID" - } + var instanceId string var outErr, inErr error @@ -235,8 +263,65 @@ func resourceTencentCloudSqlserverInstanceCreate(d *schema.ResourceData, meta in securityGroups = append(securityGroups, sg.(string)) } } + + request := sqlserver.NewCreateDBInstancesRequest() + request.DBVersion = &dbVersion + request.Memory = helper.IntInt64(memory) + request.Storage = helper.IntInt64(storage) + request.SubnetId = &subnetId + request.VpcId = &vpcId + request.HAType = &haType + request.MultiZones = &multiZones + + if payType == COMMON_PAYTYPE_POSTPAID { + request.InstanceChargeType = helper.String("POSTPAID") + } + if payType == COMMON_PAYTYPE_PREPAID { + request.InstanceChargeType = helper.String("PREPAID") + if v, ok := d.Get("auto_renew").(int); ok { + request.AutoRenewFlag = helper.IntInt64(v) + } + + if v, ok := d.Get("period").(int); ok { + request.Period = helper.IntInt64(v) + } + } + + if v, ok := d.Get("auto_voucher").(int); ok { + request.AutoVoucher = helper.IntInt64(v) + } + + if v, ok := d.Get("voucher_ids").([]interface{}); ok { + request.VoucherIds = helper.InterfacesStringsPoint(v) + } + + if projectId != 0 { + request.ProjectId = helper.IntInt64(projectId) + } + + if len(weekSet) > 0 { + request.Weekly = make([]*int64, 0) + for _, i := range weekSet { + request.Weekly = append(request.Weekly, helper.IntInt64(i)) + } + } + if startTime != "" { + request.StartTime = &startTime + } + if timeSpan != 0 { + request.Span = helper.IntInt64(timeSpan) + } + + request.SecurityGroupList = make([]*string, 0, len(securityGroups)) + for _, v := range securityGroups { + request.SecurityGroupList = append(request.SecurityGroupList, &v) + } + + request.GoodsNum = helper.IntInt64(1) + request.Zone = &zone + outErr = resource.Retry(writeRetryTimeout, func() *resource.RetryError { - instanceId, inErr = sqlserverService.CreateSqlserverInstance(ctx, dbVersion, payType, memory, 0, projectId, subnetId, vpcId, zone, storage, weekSet, startTime, timeSpan, multiZones, haType, securityGroups) + instanceId, inErr = sqlserverService.CreateSqlserverInstance(ctx, request) if inErr != nil { return retryError(inErr) } @@ -294,20 +379,37 @@ func sqlServerAllInstanceRoleUpdate(ctx context.Context, d *schema.ResourceData, } //upgrade storage and memory size - if d.HasChange("memory") || d.HasChange("storage") { + if d.HasChange("memory") || d.HasChange("storage") || d.HasChange("auto_voucher") || d.HasChange("voucher_ids") { memory := d.Get("memory").(int) storage := d.Get("storage").(int) + autoVoucher := d.Get("auto_voucher").(int) + voucherIds := d.Get("voucher_ids").([]interface{}) outErr = resource.Retry(writeRetryTimeout, func() *resource.RetryError { - inErr = sqlserverService.UpgradeSqlserverInstance(ctx, instanceId, memory, storage) + inErr = sqlserverService.UpgradeSqlserverInstance(ctx, instanceId, memory, storage, autoVoucher, helper.InterfacesStringsPoint(voucherIds)) if inErr != nil { return retryError(inErr) } return nil }) + if outErr != nil { return outErr } + outErr = resource.Retry(writeRetryTimeout, func() *resource.RetryError { + instance, _, inErr := sqlserverService.DescribeSqlserverInstanceById(ctx, instanceId) + + if inErr != nil { + return retryError(inErr) + } + //specAsExpected := int(*instance.Memory) != memory && int(*instance.Storage) != storage + + if *instance.Status == SQLSERVER_DB_UPGRADING { + return resource.RetryableError(fmt.Errorf("instance status code is: %d, waiting for upgrade complete", *instance.Status)) + } + return nil + }) + d.SetPartial("memory") d.SetPartial("storage") } diff --git a/tencentcloud/resource_tc_sqlserver_instance_test.go b/tencentcloud/resource_tc_sqlserver_instance_test.go index 9b1ea68416..10d4cd21c4 100644 --- a/tencentcloud/resource_tc_sqlserver_instance_test.go +++ b/tencentcloud/resource_tc_sqlserver_instance_test.go @@ -3,8 +3,12 @@ package tencentcloud import ( "context" "fmt" + "strings" + "sync" "testing" + sqlserver "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/sqlserver/v20180328" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/terraform" ) @@ -12,6 +16,124 @@ import ( var testSqlserverInstanceResourceName = "tencentcloud_sqlserver_instance" var testSqlserverInstanceResourceKey = testSqlserverInstanceResourceName + ".test" +func init() { + resource.AddTestSweepers("tencentcloud_sqlserver_instance", &resource.Sweeper{ + Name: "tencentcloud_sqlserver_instance", + F: func(r string) error { + logId := getLogId(contextNil) + ctx := context.WithValue(context.TODO(), logIdKey, logId) + cli, _ := sharedClientForRegion(r) + client := cli.(*TencentCloudClient).apiV3Conn + service := SqlserverService{client: client} + instances, err := service.DescribeSqlserverInstances(ctx, "", -1, defaultVpcId, defaultSubnetId, 1) + + if err != nil { + return err + } + + err = batchDeleteSQLServerInstances(ctx, service, instances) + + if err != nil { + return err + } + + return nil + }, + }) +} + +func batchDeleteSQLServerInstances(ctx context.Context, service SqlserverService, instances []*sqlserver.DBInstance) error { + wg := sync.WaitGroup{} + + wg.Add(len(instances)) + for i := range instances { + go func(i int) { + defer wg.Done() + id := *instances[i].InstanceId + name := *instances[i].Name + if strings.HasPrefix(name, "preset_sqlserver") { + return + } + + var outErr, inErr error + var has bool + + outErr = resource.Retry(readRetryTimeout, func() *resource.RetryError { + _, has, inErr = service.DescribeSqlserverInstanceById(ctx, id) + if inErr != nil { + return retryError(inErr) + } + return nil + }) + + if outErr != nil { + return + } + + if !has { + return + } + + //terminate sql instance + outErr = service.TerminateSqlserverInstance(ctx, id) + + if outErr != nil { + outErr = resource.Retry(writeRetryTimeout, func() *resource.RetryError { + inErr = service.TerminateSqlserverInstance(ctx, id) + if inErr != nil { + return retryError(inErr) + } + return nil + }) + } + + if outErr != nil { + return + } + + outErr = service.DeleteSqlserverInstance(ctx, id) + + if outErr != nil { + outErr = resource.Retry(writeRetryTimeout, func() *resource.RetryError { + inErr = service.DeleteSqlserverInstance(ctx, id) + if inErr != nil { + return retryError(inErr) + } + return nil + }) + } + + if outErr != nil { + return + } + + outErr = service.RecycleDBInstance(ctx, id) + if outErr != nil { + return + } + + outErr = resource.Retry(readRetryTimeout, func() *resource.RetryError { + _, has, inErr := service.DescribeSqlserverInstanceById(ctx, id) + if inErr != nil { + return retryError(inErr) + } + if has { + inErr = fmt.Errorf("delete SQL Server instance %s fail, instance still exists from SDK DescribeSqlserverInstanceById", id) + return resource.RetryableError(inErr) + } + return nil + }) + + if outErr != nil { + return + } + }(i) + } + + wg.Wait() + return nil +} + func TestAccTencentCloudSqlserverInstanceResource(t *testing.T) { t.Parallel() resource.Test(t, resource.TestCase{ @@ -67,8 +189,8 @@ func TestAccTencentCloudSqlserverInstanceResource(t *testing.T) { resource.TestCheckResourceAttrSet(testSqlserverInstanceResourceKey, "vport"), resource.TestCheckResourceAttrSet(testSqlserverInstanceResourceKey, "status"), resource.TestCheckResourceAttr(testSqlserverInstanceResourceKey, "security_groups.#", "0"), - resource.TestCheckNoResourceAttr(testSqlserverInstanceResourceKey, "tags.test"), - resource.TestCheckResourceAttr(testSqlserverInstanceResourceKey, "tags.abc", "abc"), + //resource.TestCheckNoResourceAttr(testSqlserverInstanceResourceKey, "tags.test"), + //resource.TestCheckResourceAttr(testSqlserverInstanceResourceKey, "tags.abc", "abc"), ), }, }, @@ -113,6 +235,7 @@ func TestAccTencentCloudSqlserverInstanceMultiClusterResource(t *testing.T) { }, }) } + func testAccCheckSqlserverInstanceDestroy(s *terraform.State) error { for _, rs := range s.RootModule().Resources { if rs.Type != testSqlserverInstanceResourceName { @@ -166,12 +289,17 @@ const testAccSqlserverInstanceBasic = ` data "tencentcloud_availability_zones_by_product" "zone" { product = "sqlserver" } + +locals { + az = data.tencentcloud_availability_zones_by_product.zone.zones[0].name + az1 = data.tencentcloud_availability_zones_by_product.zone.zones[1].name +} ` const testAccSqlserverInstance string = testAccSqlserverInstanceBasic + ` resource "tencentcloud_sqlserver_instance" "test" { name = "tf_sqlserver_instance" - availability_zone = data.tencentcloud_availability_zones_by_product.zone.zones[1].name + availability_zone = local.az1 charge_type = "POSTPAID_BY_HOUR" vpc_id = "` + defaultVpcId + `" subnet_id = "` + defaultSubnetId + `" @@ -192,7 +320,7 @@ resource "tencentcloud_sqlserver_instance" "test" { const testAccSqlserverInstanceUpdate string = testAccSqlserverInstanceBasic + ` resource "tencentcloud_sqlserver_instance" "test" { name = "tf_sqlserver_instance_update" - availability_zone = data.tencentcloud_availability_zones_by_product.zone.zones[0].name + availability_zone = local.az1 charge_type = "POSTPAID_BY_HOUR" vpc_id = "` + defaultVpcId + `" subnet_id = "` + defaultSubnetId + `" @@ -212,7 +340,7 @@ resource "tencentcloud_sqlserver_instance" "test" { const testAccSqlserverInstanceMultiCluster string = testAccSqlserverInstanceBasic + ` resource "tencentcloud_sqlserver_instance" "test" { name = "tf_sqlserver_instance_multi" - availability_zone = data.tencentcloud_availability_zones_by_product.zone.zones[0].name + availability_zone = local.az1 charge_type = "POSTPAID_BY_HOUR" engine_version = "2017" vpc_id = "` + defaultVpcId + `" diff --git a/tencentcloud/resource_tc_sqlserver_readonly_instance.go b/tencentcloud/resource_tc_sqlserver_readonly_instance.go index 64e544b9cd..1b79582029 100644 --- a/tencentcloud/resource_tc_sqlserver_readonly_instance.go +++ b/tencentcloud/resource_tc_sqlserver_readonly_instance.go @@ -32,6 +32,8 @@ import ( "context" "fmt" + sqlserver "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/sqlserver/v20180328" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/internal/helper" @@ -67,7 +69,7 @@ func resourceTencentCloudSqlserverReadonlyInstance() *schema.Resource { }, } - basic := TencentSqlServerBasicInfo() + basic := TencentSqlServerBasicInfo(true) for k, v := range basic { readonlyInstanceInfo[k] = v } @@ -108,26 +110,65 @@ func resourceTencentCloudSqlserverReadonlyInstanceCreate(d *schema.ResourceData, securityGroups = make([]string, 0) ) - if payType == COMMON_PAYTYPE_POSTPAID { - payType = "POSTPAID" - } - if v, ok := d.GetOk("readonly_group_id"); ok && readonlyGroupType == 3 { readonlyGroupId = v.(string) } - if temp, ok := d.GetOkExists("security_groups"); ok { + if temp, ok := d.GetOk("security_groups"); ok { sgGroup := temp.(*schema.Set).List() for _, sg := range sgGroup { securityGroups = append(securityGroups, sg.(string)) } } + request := sqlserver.NewCreateReadOnlyDBInstancesRequest() + + request.InstanceId = &masterInstanceId + request.InstanceChargeType = &payType + request.Memory = helper.IntInt64(memory) + request.Storage = helper.IntInt64(storage) + request.SubnetId = &subnetId + request.VpcId = &vpcId + request.GoodsNum = helper.IntInt64(1) + + request.ReadOnlyGroupType = helper.IntInt64(readonlyGroupType) + if readonlyGroupId != "" { + request.ReadOnlyGroupId = &readonlyGroupId + } + + if forceUpgrade { + request.ReadOnlyGroupForcedUpgrade = helper.BoolToInt64Ptr(forceUpgrade) + } + request.Zone = &zone + request.SecurityGroupList = make([]*string, 0, len(securityGroups)) + for _, v := range securityGroups { + request.SecurityGroupList = append(request.SecurityGroupList, &v) + } + + if payType == COMMON_PAYTYPE_POSTPAID { + request.InstanceChargeType = helper.String("POSTPAID") + } + if payType == COMMON_PAYTYPE_PREPAID { + request.InstanceChargeType = helper.String("PREPAID") + + if v, ok := d.Get("period").(int); ok { + request.Period = helper.IntInt64(v) + } + } + + if v, ok := d.Get("auto_voucher").(int); ok { + request.AutoVoucher = helper.IntInt64(v) + } + + if v, ok := d.Get("voucher_ids").([]interface{}); ok { + request.VoucherIds = helper.InterfacesStringsPoint(v) + } + var instanceId string var outErr, inErr error outErr = resource.Retry(5*writeRetryTimeout, func() *resource.RetryError { - instanceId, inErr = sqlserverService.CreateSqlserverReadonlyInstance(ctx, masterInstanceId, subnetId, vpcId, payType, memory, zone, storage, readonlyGroupType, readonlyGroupId, forceUpgrade, securityGroups) + instanceId, inErr = sqlserverService.CreateSqlserverReadonlyInstance(ctx, request) if inErr != nil { return retryError(inErr) } diff --git a/tencentcloud/service_tencentcloud_sqlserver.go b/tencentcloud/service_tencentcloud_sqlserver.go index 76086cb10f..9d4422791d 100644 --- a/tencentcloud/service_tencentcloud_sqlserver.go +++ b/tencentcloud/service_tencentcloud_sqlserver.go @@ -85,49 +85,14 @@ func (me *SqlserverService) DescribeProductConfig(ctx context.Context, zone stri return } -func (me *SqlserverService) CreateSqlserverInstance(ctx context.Context, dbVersion string, chargeType string, memory int, autoRenewFlag int, projectId int, subnetId string, vpcId string, zone string, storage int, weekSet []int, startTime string, timeSpan int, multiZones bool, haType string, securityGroups []string) (instanceId string, errRet error) { +func (me *SqlserverService) CreateSqlserverInstance(ctx context.Context, request *sqlserver.CreateDBInstancesRequest) (instanceId string, errRet error) { logId := getLogId(ctx) - request := sqlserver.NewCreateDBInstancesRequest() defer func() { if errRet != nil { log.Printf("[CRITAL]%s api[%s] fail, reason[%s]", logId, request.GetAction(), errRet.Error()) } }() - request.DBVersion = &dbVersion - request.InstanceChargeType = &chargeType - request.Memory = helper.IntInt64(memory) - request.Storage = helper.IntInt64(storage) - request.SubnetId = &subnetId - request.VpcId = &vpcId - request.HAType = &haType - request.MultiZones = &multiZones - request.AutoRenewFlag = helper.IntInt64(autoRenewFlag) - if projectId != 0 { - request.ProjectId = helper.IntInt64(projectId) - } - - if len(weekSet) > 0 { - request.Weekly = make([]*int64, 0) - for _, i := range weekSet { - request.Weekly = append(request.Weekly, helper.IntInt64(i)) - } - } - if startTime != "" { - request.StartTime = &startTime - } - if timeSpan != 0 { - request.Span = helper.IntInt64(timeSpan) - } - - request.SecurityGroupList = make([]*string, 0, len(securityGroups)) - for _, v := range securityGroups { - request.SecurityGroupList = append(request.SecurityGroupList, &v) - } - - request.GoodsNum = helper.IntInt64(1) - request.Zone = &zone - ratelimit.Check(request.GetAction()) response, err := me.client.UseSqlserverClient().CreateDBInstances(request) if err != nil { @@ -186,12 +151,18 @@ func (me *SqlserverService) ModifySqlserverInstanceProjectId(ctx context.Context return err } -func (me *SqlserverService) UpgradeSqlserverInstance(ctx context.Context, instanceId string, memory int, storage int) (errRet error) { +func (me *SqlserverService) UpgradeSqlserverInstance(ctx context.Context, instanceId string, memory, storage, autoVoucher int, voucherIds []*string) (errRet error) { logId := getLogId(ctx) request := sqlserver.NewUpgradeDBInstanceRequest() request.InstanceId = &instanceId request.Memory = helper.IntInt64(memory) request.Storage = helper.IntInt64(storage) + if autoVoucher != 0 { + request.AutoVoucher = helper.IntInt64(autoVoucher) + } + if len(voucherIds) > 0 { + request.VoucherIds = voucherIds + } defer func() { if errRet != nil { log.Printf("[CRITAL]%s api[%s] fail, reason[%s]", logId, request.GetAction(), errRet.Error()) @@ -505,38 +476,14 @@ func (me *SqlserverService) DescribeReadonlyGroupList(ctx context.Context, insta return } -func (me *SqlserverService) CreateSqlserverReadonlyInstance(ctx context.Context, masterInstanceId string, subnetId string, vpcId string, chargeType string, memory int, zone string, storage int, readonlyGroupType int, readonlyGroupId string, forceUpgrade bool, securityGroups []string) (instanceId string, errRet error) { +func (me *SqlserverService) CreateSqlserverReadonlyInstance(ctx context.Context, request *sqlserver.CreateReadOnlyDBInstancesRequest) (instanceId string, errRet error) { logId := getLogId(ctx) - request := sqlserver.NewCreateReadOnlyDBInstancesRequest() defer func() { if errRet != nil { log.Printf("[CRITAL]%s api[%s] fail, reason[%s]", logId, request.GetAction(), errRet.Error()) } }() - request.InstanceId = &masterInstanceId - request.InstanceChargeType = &chargeType - request.Memory = helper.IntInt64(memory) - request.Storage = helper.IntInt64(storage) - request.SubnetId = &subnetId - request.VpcId = &vpcId - request.GoodsNum = helper.IntInt64(1) - - request.ReadOnlyGroupType = helper.IntInt64(readonlyGroupType) - if readonlyGroupId != "" { - request.ReadOnlyGroupId = &readonlyGroupId - } - - if forceUpgrade { - request.ReadOnlyGroupForcedUpgrade = helper.BoolToInt64Ptr(forceUpgrade) - } - request.GoodsNum = helper.IntInt64(1) - request.Zone = &zone - request.SecurityGroupList = make([]*string, 0, len(securityGroups)) - for _, v := range securityGroups { - request.SecurityGroupList = append(request.SecurityGroupList, &v) - } - ratelimit.Check(request.GetAction()) response, err := me.client.UseSqlserverClient().CreateReadOnlyDBInstances(request) if err != nil { diff --git a/website/docs/r/sqlserver_instance.html.markdown b/website/docs/r/sqlserver_instance.html.markdown index 0c6fab7160..facc259a8d 100644 --- a/website/docs/r/sqlserver_instance.html.markdown +++ b/website/docs/r/sqlserver_instance.html.markdown @@ -33,18 +33,22 @@ The following arguments are supported: * `memory` - (Required) Memory size (in GB). Allowed value must be larger than `memory` that data source `tencentcloud_sqlserver_specinfos` provides. * `name` - (Required) Name of the SQL Server instance. * `storage` - (Required) Disk size (in GB). Allowed value must be a multiple of 10. The storage must be set with the limit of `storage_min` and `storage_max` which data source `tencentcloud_sqlserver_specinfos` provides. +* `auto_renew` - (Optional) Automatic renewal sign. 0 for normal renewal, 1 for automatic renewal, the default is 1 automatic renewal. Only valid when purchasing a prepaid instance. +* `auto_voucher` - (Optional) Whether to use the voucher automatically; 1 for yes, 0 for no, the default is 0. * `availability_zone` - (Optional, ForceNew) Availability zone. -* `charge_type` - (Optional, ForceNew) Pay type of the SQL Server instance. For now, only `POSTPAID_BY_HOUR` is valid. +* `charge_type` - (Optional, ForceNew) Pay type of the SQL Server instance. Available values `PREPAID`, `POSTPAID_BY_HOUR`. * `engine_version` - (Optional, ForceNew) Version of the SQL Server database engine. Allowed values are `2008R2`(SQL Server 2008 Enterprise), `2012SP3`(SQL Server 2012 Enterprise), `2016SP1` (SQL Server 2016 Enterprise), `201602`(SQL Server 2016 Standard) and `2017`(SQL Server 2017 Enterprise). Default is `2008R2`. * `ha_type` - (Optional, ForceNew) Instance type. `DUAL` (dual-server high availability), `CLUSTER` (cluster). Default is `DUAL`. * `maintenance_start_time` - (Optional) Start time of the maintenance in one day, format like `HH:mm`. * `maintenance_time_span` - (Optional) The timespan of maintenance in one day, unit is hour. * `maintenance_week_set` - (Optional) A list of integer indicates weekly maintenance. For example, [2,7] presents do weekly maintenance on every Tuesday and Sunday. * `multi_zones` - (Optional, ForceNew) Indicate whether to deploy across availability zones. +* `period` - (Optional) Purchase instance period in month. The value does not exceed 48. * `project_id` - (Optional) Project ID, default value is 0. * `security_groups` - (Optional) Security group bound to the instance. * `subnet_id` - (Optional, ForceNew) ID of subnet. * `tags` - (Optional) The tags of the SQL Server. +* `voucher_ids` - (Optional) An array of voucher IDs, currently only one can be used for a single order. * `vpc_id` - (Optional, ForceNew) ID of VPC. ## Attributes Reference diff --git a/website/docs/r/sqlserver_readonly_instance.html.markdown b/website/docs/r/sqlserver_readonly_instance.html.markdown index 17db3f4d9e..8d6339ac34 100644 --- a/website/docs/r/sqlserver_readonly_instance.html.markdown +++ b/website/docs/r/sqlserver_readonly_instance.html.markdown @@ -37,13 +37,16 @@ The following arguments are supported: * `name` - (Required) Name of the SQL Server instance. * `readonly_group_type` - (Required, ForceNew) Type of readonly group. Valid values: `1`, `3`. `1` for one auto-assigned readonly instance per one readonly group, `2` for creating new readonly group, `3` for all exist readonly instances stay in the exist readonly group. For now, only `1` and `3` are supported. * `storage` - (Required) Disk size (in GB). Allowed value must be a multiple of 10. The storage must be set with the limit of `storage_min` and `storage_max` which data source `tencentcloud_sqlserver_specinfos` provides. +* `auto_voucher` - (Optional) Whether to use the voucher automatically; 1 for yes, 0 for no, the default is 0. * `availability_zone` - (Optional, ForceNew) Availability zone. -* `charge_type` - (Optional, ForceNew) Pay type of the SQL Server instance. For now, only `POSTPAID_BY_HOUR` is valid. +* `charge_type` - (Optional, ForceNew) Pay type of the SQL Server instance. Available values `PREPAID`, `POSTPAID_BY_HOUR`. * `force_upgrade` - (Optional, ForceNew) Indicate that the master instance upgrade or not. `true` for upgrading the master SQL Server instance to cluster type by force. Default is false. Note: this is not supported with `DUAL`(ha_type), `2017`(engine_version) master SQL Server instance, for it will cause ha_type of the master SQL Server instance change. +* `period` - (Optional) Purchase instance period in month. The value does not exceed 48. * `readonly_group_id` - (Optional) ID of the readonly group that this instance belongs to. When `readonly_group_type` set value `3`, it must be set with valid value. * `security_groups` - (Optional) Security group bound to the instance. * `subnet_id` - (Optional, ForceNew) ID of subnet. * `tags` - (Optional) The tags of the SQL Server. +* `voucher_ids` - (Optional) An array of voucher IDs, currently only one can be used for a single order. * `vpc_id` - (Optional, ForceNew) ID of VPC. ## Attributes Reference From e60c5e0cacd35d0aaf58a56cd2d5723a8e8fb0f0 Mon Sep 17 00:00:00 2001 From: Kagashino Date: Mon, 28 Mar 2022 19:56:16 +0800 Subject: [PATCH 2/2] fix: sqlserver - prepaid charge and testcase --- .../resource_tc_sqlserver_instance.go | 5 +- .../resource_tc_sqlserver_instance_test.go | 85 +++++++++++++++++++ .../docs/r/sqlserver_instance.html.markdown | 2 +- 3 files changed, 90 insertions(+), 2 deletions(-) diff --git a/tencentcloud/resource_tc_sqlserver_instance.go b/tencentcloud/resource_tc_sqlserver_instance.go index e83700700a..384d437bfa 100644 --- a/tencentcloud/resource_tc_sqlserver_instance.go +++ b/tencentcloud/resource_tc_sqlserver_instance.go @@ -146,7 +146,7 @@ func TencentSqlServerBasicInfo(isROInstance bool) map[string]*schema.Schema { basicSchema["auto_renew"] = &schema.Schema{ Type: schema.TypeInt, Optional: true, - Description: "Automatic renewal sign. 0 for normal renewal, 1 for automatic renewal, the default is 1 automatic renewal. Only valid when purchasing a prepaid instance.", + Description: "Automatic renewal sign. 0 for normal renewal, 1 for automatic renewal (Default). Only valid when purchasing a prepaid instance.", } } @@ -581,6 +581,9 @@ func tencentSqlServerBasicInfoRead(ctx context.Context, d *schema.ResourceData, if int(*instance.PayMode) == 1 { _ = d.Set("charge_type", COMMON_PAYTYPE_PREPAID) + if _, ok := d.GetOk("auto_renew"); ok { + _ = d.Set("auto_renew", instance.RenewFlag) + } } else { _ = d.Set("charge_type", COMMON_PAYTYPE_POSTPAID) } diff --git a/tencentcloud/resource_tc_sqlserver_instance_test.go b/tencentcloud/resource_tc_sqlserver_instance_test.go index 10d4cd21c4..75cbcb8327 100644 --- a/tencentcloud/resource_tc_sqlserver_instance_test.go +++ b/tencentcloud/resource_tc_sqlserver_instance_test.go @@ -197,6 +197,35 @@ func TestAccTencentCloudSqlserverInstanceResource(t *testing.T) { }) } +func TestAccTencentCloudSqlserverInstanceResource_Prepaid(t *testing.T) { + t.Parallel() + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheckCommon(t, ACCOUNT_TYPE_PREPAY) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckSqlserverInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccSqlserverInstancePrepaid, + Check: resource.ComposeTestCheckFunc( + testAccCheckSqlserverInstanceExists(testSqlserverInstanceResourceKey), + resource.TestCheckResourceAttrSet(testSqlserverInstanceResourceKey, "id"), + resource.TestCheckResourceAttr(testSqlserverInstanceResourceKey, "name", "tf_sqlserver_instance"), + resource.TestCheckResourceAttr(testSqlserverInstanceResourceKey, "charge_type", "POSTPAID_BY_HOUR"), + ), + }, + { + Config: testAccSqlserverInstancePrepaidUpdate, + Check: resource.ComposeTestCheckFunc( + testAccCheckSqlserverInstanceExists(testSqlserverInstanceResourceKey), + resource.TestCheckResourceAttrSet(testSqlserverInstanceResourceKey, "id"), + resource.TestCheckResourceAttr(testSqlserverInstanceResourceKey, "name", "tf_sqlserver_instance_update"), + resource.TestCheckResourceAttr(testSqlserverInstanceResourceKey, "charge_type", "PREPAID"), + ), + }, + }, + }) +} + func TestAccTencentCloudSqlserverInstanceMultiClusterResource(t *testing.T) { t.Parallel() resource.Test(t, resource.TestCase{ @@ -296,6 +325,27 @@ locals { } ` +const testAccSqlserverInstanceBasicPrepaid = ` +locals { + vpc_id = data.tencentcloud_vpc_instances.vpc.instance_list.0.vpc_id + vpc_subnet_id = data.tencentcloud_vpc_instances.vpc.instance_list.0.subnet_ids.0 + az = data.tencentcloud_subnet.sub.availability_zone + sg = data.tencentcloud_security_group.group.security_group_id +} + +data "tencentcloud_vpc_instances" "vpc" { + name = "keep" +} + +data "tencentcloud_security_group" "group" {} + + +data "tencentcloud_subnet" "sub" { + vpc_id = local.vpc_id + subnet_id = local.vpc_subnet_id +} +` + const testAccSqlserverInstance string = testAccSqlserverInstanceBasic + ` resource "tencentcloud_sqlserver_instance" "test" { name = "tf_sqlserver_instance" @@ -337,6 +387,41 @@ resource "tencentcloud_sqlserver_instance" "test" { } ` +const testAccSqlserverInstancePrepaid string = testAccSqlserverInstanceBasicPrepaid + ` +resource "tencentcloud_sqlserver_instance" "test" { + name = "tf_sqlserver_instance" + availability_zone = local.az + charge_type = "POSTPAID_BY_HOUR" + vpc_id = local.vpc_id + subnet_id = local.vpc_subnet_id + project_id = 0 + memory = 2 + storage = 10 + maintenance_week_set = [1,2,3] + maintenance_start_time = "09:00" + maintenance_time_span = 3 + security_groups = [local.sg] +} +` + +const testAccSqlserverInstancePrepaidUpdate string = testAccSqlserverInstanceBasicPrepaid + ` +resource "tencentcloud_sqlserver_instance" "test" { + name = "tf_sqlserver_instance_update" + availability_zone = local.az + charge_type = "PREPAID" + period = 1 + vpc_id = local.vpc_id + subnet_id = local.vpc_subnet_id + project_id = 0 + memory = 2 + storage = 10 + maintenance_week_set = [1,2,3] + maintenance_start_time = "09:00" + maintenance_time_span = 3 + security_groups = [local.sg] +} +` + const testAccSqlserverInstanceMultiCluster string = testAccSqlserverInstanceBasic + ` resource "tencentcloud_sqlserver_instance" "test" { name = "tf_sqlserver_instance_multi" diff --git a/website/docs/r/sqlserver_instance.html.markdown b/website/docs/r/sqlserver_instance.html.markdown index facc259a8d..f82f34ec08 100644 --- a/website/docs/r/sqlserver_instance.html.markdown +++ b/website/docs/r/sqlserver_instance.html.markdown @@ -33,7 +33,7 @@ The following arguments are supported: * `memory` - (Required) Memory size (in GB). Allowed value must be larger than `memory` that data source `tencentcloud_sqlserver_specinfos` provides. * `name` - (Required) Name of the SQL Server instance. * `storage` - (Required) Disk size (in GB). Allowed value must be a multiple of 10. The storage must be set with the limit of `storage_min` and `storage_max` which data source `tencentcloud_sqlserver_specinfos` provides. -* `auto_renew` - (Optional) Automatic renewal sign. 0 for normal renewal, 1 for automatic renewal, the default is 1 automatic renewal. Only valid when purchasing a prepaid instance. +* `auto_renew` - (Optional) Automatic renewal sign. 0 for normal renewal, 1 for automatic renewal (Default). Only valid when purchasing a prepaid instance. * `auto_voucher` - (Optional) Whether to use the voucher automatically; 1 for yes, 0 for no, the default is 0. * `availability_zone` - (Optional, ForceNew) Availability zone. * `charge_type` - (Optional, ForceNew) Pay type of the SQL Server instance. Available values `PREPAID`, `POSTPAID_BY_HOUR`.