From 4f28791d002896518559124ea3b2cdfce98fd48d Mon Sep 17 00:00:00 2001 From: Kagashino Date: Fri, 22 Apr 2022 16:37:17 +0800 Subject: [PATCH 1/4] fix: postgresql - support backup plans and xlog datasource --- tencentcloud/basic_test.go | 15 ++ .../data_source_tc_postgresql_xlogs.go | 163 ++++++++++++++++++ .../data_source_tc_postgresql_xlogs_test.go | 52 ++++++ tencentcloud/provider.go | 2 + .../resource_tc_postgresql_instance.go | 110 ++++++++++++ .../resource_tc_postgresql_instance_test.go | 83 +++++---- .../service_tencentcloud_postgresql.go | 81 +++++++++ website/docs/d/postgresql_xlogs.html.markdown | 45 +++++ .../docs/r/postgresql_instance.html.markdown | 8 + website/tencentcloud.erb | 3 + 10 files changed, 531 insertions(+), 31 deletions(-) create mode 100644 tencentcloud/data_source_tc_postgresql_xlogs.go create mode 100644 tencentcloud/data_source_tc_postgresql_xlogs_test.go create mode 100644 website/docs/d/postgresql_xlogs.html.markdown diff --git a/tencentcloud/basic_test.go b/tencentcloud/basic_test.go index 26079f5e40..3d54e3c0e9 100644 --- a/tencentcloud/basic_test.go +++ b/tencentcloud/basic_test.go @@ -277,6 +277,21 @@ resource "tencentcloud_instance" "default" { // End of SQLServer +// PostgreSQL + +const defaultPGSQLName = "keep-postgresql" +const CommonPresetPGSQL = ` +data "tencentcloud_postgresql_instances" "foo" { + name = "` + defaultPGSQLName + `" +} + +locals { + pgsql_id = data.tencentcloud_postgresql_instances.foo.instance_list.0.id +} +` + +// End of PostgreSQL + const defaultCVMName = "keep-cvm" const presetCVM = ` data "tencentcloud_instances" "instance" { diff --git a/tencentcloud/data_source_tc_postgresql_xlogs.go b/tencentcloud/data_source_tc_postgresql_xlogs.go new file mode 100644 index 0000000000..2fa300b660 --- /dev/null +++ b/tencentcloud/data_source_tc_postgresql_xlogs.go @@ -0,0 +1,163 @@ +/* +Provide a datasource to query PostgreSQL Xlogs. + +Example Usage + +```hcl +data "tencentcloud_postgresql_xlogs" "foo" { + instance_id = "postgres-xxxxxxxx" + start_time = "2022-01-01 00:00:00" + end_time = "2022-01-07 01:02:03" +} +``` + + +*/ +package tencentcloud + +import ( + "context" + "time" + + postgresql "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/postgres/v20170312" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/internal/helper" +) + +func datasourceTencentCloudPostgresqlXlogs() *schema.Resource { + return &schema.Resource{ + Read: datasourceTencentCloudPostgresqlXlogsRead, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Schema: map[string]*schema.Schema{ + "instance_id": { + Type: schema.TypeString, + Required: true, + Description: "PostgreSQL instance id.", + }, + "start_time": { + Type: schema.TypeString, + Optional: true, + Description: "Xlog start time, format `yyyy-MM-dd hh:mm:ss`, start time cannot before 7 days ago.", + }, + "end_time": { + Type: schema.TypeString, + Optional: true, + Description: "Xlog end time, format `yyyy-MM-dd hh:mm:ss`.", + }, + "result_output_file": { + Type: schema.TypeString, + Optional: true, + Description: "Used for save results.", + }, + "list": { + Type: schema.TypeList, + Computed: true, + Description: "List of Xlog query result.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeInt, + Computed: true, + Description: "Xlog id.", + }, + "start_time": { + Type: schema.TypeString, + Computed: true, + Description: "Xlog file created start time.", + }, + "end_time": { + Type: schema.TypeString, + Computed: true, + Description: "Xlog file created end time.", + }, + "internal_addr": { + Type: schema.TypeString, + Computed: true, + Description: "Xlog internal download address.", + }, + "external_addr": { + Type: schema.TypeString, + Computed: true, + Description: "Xlog external download address.", + }, + "size": { + Type: schema.TypeInt, + Computed: true, + Description: "Xlog file size.", + }, + }, + }, + }, + }, + } +} + +func datasourceTencentCloudPostgresqlXlogsRead(d *schema.ResourceData, meta interface{}) error { + defer logElapsed("datasource.tencentcloud_postgresql_xlogs.read")() + defer inconsistentCheck(d, meta)() + + logId := getLogId(contextNil) + ctx := context.WithValue(context.TODO(), logIdKey, logId) + client := meta.(*TencentCloudClient).apiV3Conn + service := PostgresqlService{client} + + request := postgresql.NewDescribeDBXlogsRequest() + + id := d.Get("instance_id").(string) + defaultEndTime := time.Now() + + if endTime, ok := d.GetOk("end_time"); ok && endTime != "" { + request.EndTime = helper.String(endTime.(string)) + } else { + endTime := defaultEndTime.Format("2006-01-02 15:04:05") + request.EndTime = &endTime + } + + if startTime, ok := d.GetOk("start_time"); ok && startTime != "" { + request.StartTime = helper.String(startTime.(string)) + } else { + defaultStartTime := defaultEndTime.AddDate(0, 0, -7) + startTime := defaultStartTime.Format("2006-01-02 15:04:05") + request.StartTime = &startTime + } + + request.DBInstanceId = &id + + result, err := service.DescribeDBXlogs(ctx, request) + + if err != nil { + d.SetId("") + return err + } + + list := make([]interface{}, 0, len(result)) + + for i := range result { + item := result[i] + xlog := map[string]interface{}{ + "id": item.Id, + "start_time": item.StartTime, + "end_time": item.EndTime, + "internal_addr": item.InternalAddr, + "external_addr": item.ExternalAddr, + "size": item.Size, + } + + list = append(list, xlog) + } + + d.SetId("postgres-xlog-" + id) + + if err := d.Set("list", list); err != nil { + return err + } + + if output, ok := d.GetOk("result_output_file"); ok { + return writeToFile(output.(string), list) + } + + return nil +} diff --git a/tencentcloud/data_source_tc_postgresql_xlogs_test.go b/tencentcloud/data_source_tc_postgresql_xlogs_test.go new file mode 100644 index 0000000000..db25b6a560 --- /dev/null +++ b/tencentcloud/data_source_tc_postgresql_xlogs_test.go @@ -0,0 +1,52 @@ +package tencentcloud + +import ( + "fmt" + "testing" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" +) + +func TestAccTencentCloudDataSourcePostgresqlXlogs(t *testing.T) { + t.Parallel() + + startTime := time.Now().AddDate(0, 0, -7).Format("2006-01-02 15:04:05") + endTime := time.Now().Format("2006-01-02 15:04:05") + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourcePostgresqlXlogsBasic(startTime, endTime), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("data.tencentcloud_postgresql_xlogs.foo", "start_time", startTime), + resource.TestCheckResourceAttr("data.tencentcloud_postgresql_xlogs.foo", "end_time", endTime), + resource.TestCheckResourceAttrSet("data.tencentcloud_postgresql_xlogs.foo", "list.#"), + resource.TestCheckResourceAttrSet("data.tencentcloud_postgresql_xlogs.foo", "list.0.id"), + resource.TestCheckResourceAttrSet("data.tencentcloud_postgresql_xlogs.foo", "list.0.start_time"), + resource.TestCheckResourceAttrSet("data.tencentcloud_postgresql_xlogs.foo", "list.0.end_time"), + resource.TestCheckResourceAttrSet("data.tencentcloud_postgresql_xlogs.foo", "list.0.internal_addr"), + resource.TestCheckResourceAttrSet("data.tencentcloud_postgresql_xlogs.foo", "list.0.external_addr"), + resource.TestCheckResourceAttrSet("data.tencentcloud_postgresql_xlogs.foo", "list.0.size"), + resource.TestCheckResourceAttrSet("data.tencentcloud_postgresql_xlogs.bar", "list.#"), + ), + }, + }, + }) +} + +func testAccDataSourcePostgresqlXlogsBasic(startTime, endTime string) string { + return fmt.Sprintf(` +%s +data "tencentcloud_postgresql_xlogs" "foo" { + instance_id = local.pgsql_id + start_time = "%s" + end_time = "%s" +} + +data "tencentcloud_postgresql_xlogs" "bar" { + instance_id = local.pgsql_id +} +`, CommonPresetPGSQL, startTime, endTime) +} diff --git a/tencentcloud/provider.go b/tencentcloud/provider.go index 68c9408cc4..3752620496 100644 --- a/tencentcloud/provider.go +++ b/tencentcloud/provider.go @@ -412,6 +412,7 @@ PostgreSQL Data Source tencentcloud_postgresql_instances tencentcloud_postgresql_specinfos + tencentcloud_postgresql_xlogs Resource tencentcloud_postgresql_instance @@ -844,6 +845,7 @@ func Provider() terraform.ResourceProvider { "tencentcloud_elasticsearch_instances": dataSourceTencentCloudElasticsearchInstances(), "tencentcloud_postgresql_instances": dataSourceTencentCloudPostgresqlInstances(), "tencentcloud_postgresql_specinfos": dataSourceTencentCloudPostgresqlSpecinfos(), + "tencentcloud_postgresql_xlogs": datasourceTencentCloudPostgresqlXlogs(), "tencentcloud_sqlserver_zone_config": dataSourceTencentSqlserverZoneConfig(), "tencentcloud_sqlserver_instances": dataSourceTencentCloudSqlserverInstances(), "tencentcloud_sqlserver_backups": dataSourceTencentCloudSqlserverBackups(), diff --git a/tencentcloud/resource_tc_postgresql_instance.go b/tencentcloud/resource_tc_postgresql_instance.go index 85b4781f88..f8ccda4417 100644 --- a/tencentcloud/resource_tc_postgresql_instance.go +++ b/tencentcloud/resource_tc_postgresql_instance.go @@ -264,6 +264,37 @@ func resourceTencentCloudPostgresqlInstance() *schema.Resource { Computed: true, Description: "max_standby_streaming_delay applies when WAL data is being received via streaming replication. Units are milliseconds if not specified.", }, + "backup_plan": { + Type: schema.TypeList, + Optional: true, + Description: "Specify DB backup plan.", + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "min_backup_start_time": { + Type: schema.TypeString, + Optional: true, + Description: "Specify earliest backup start time, format `hh:mm:ss`.", + }, + "max_backup_start_time": { + Type: schema.TypeString, + Optional: true, + Description: "Specify latest backup start time, format `hh:mm:ss`.", + }, + "base_backup_retention_period": { + Type: schema.TypeInt, + Optional: true, + Description: "Specify days of the retention.", + }, + "backup_period": { + Type: schema.TypeList, + Optional: true, + Description: "List of backup period per week, available values: `monday`, `tuesday`, `wednesday`, `thursday`, `friday`, `saturday`, `sunday`. NOTE: At least specify two days.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, "db_node_set": { Type: schema.TypeSet, Optional: true, @@ -543,6 +574,29 @@ func resourceTencentCloudPostgresqlInstanceCreate(d *schema.ResourceData, meta i time.Sleep(10 * time.Second) } + // set backup plan + + if plan, ok := helper.InterfacesHeadMap(d, "backup_plan"); ok { + request := postgresql.NewModifyBackupPlanRequest() + request.DBInstanceId = &instanceId + if v, ok := plan["min_backup_start_time"].(string); ok { + request.MinBackupStartTime = &v + } + if v, ok := plan["max_backup_start_time"].(string); ok { + request.MaxBackupStartTime = &v + } + if v, ok := plan["base_backup_retention_period"].(int); ok { + request.BaseBackupRetentionPeriod = helper.IntUint64(v) + } + if v, ok := plan["backup_period"].([]interface{}); ok { + request.BackupPeriod = helper.InterfacesStringsPoint(v) + } + err := postgresqlService.ModifyBackupPlan(ctx, request) + if err != nil { + return err + } + } + return resourceTencentCloudPostgresqlInstanceRead(d, meta) } @@ -684,6 +738,29 @@ func resourceTencentCloudPostgresqlInstanceUpdate(d *schema.ResourceData, meta i d.SetPartial("security_groups") } + if d.HasChange("backup_plan") { + if plan, ok := helper.InterfacesHeadMap(d, "backup_plan"); ok { + request := postgresql.NewModifyBackupPlanRequest() + request.DBInstanceId = &instanceId + if v, ok := plan["min_backup_start_time"].(string); ok { + request.MinBackupStartTime = &v + } + if v, ok := plan["max_backup_start_time"].(string); ok { + request.MaxBackupStartTime = &v + } + if v, ok := plan["base_backup_retention_period"].(int); ok { + request.BaseBackupRetentionPeriod = helper.IntUint64(v) + } + if v, ok := plan["backup_period"].([]interface{}); ok { + request.BackupPeriod = helper.InterfacesStringsPoint(v) + } + err := postgresqlService.ModifyBackupPlan(ctx, request) + if err != nil { + return err + } + } + } + if d.HasChange("db_node_set") { if include, z, nzs := checkZoneSetInclude(d); !include { @@ -952,6 +1029,39 @@ func resourceTencentCloudPostgresqlInstanceRead(d *schema.ResourceData, meta int } _ = d.Set("tags", tags) + // backup plans (only specified will rewrite) + if _, ok := d.GetOk("backup_plan"); ok { + request := postgresql.NewDescribeBackupPlansRequest() + request.DBInstanceId = helper.String(d.Id()) + response, err := postgresqlService.DescribeBackupPlans(ctx, request) + + if err != nil { + return err + } + + var backupPlan *postgresql.BackupPlan + + if len(response) > 0 { + backupPlan = response[0] + } + + if backupPlan != nil { + if _, ok := d.GetOk("backup_plan.0.min_backup_start_time"); ok { + _ = d.Set("backup_plan.0.min_backup_start_time", backupPlan.MinBackupStartTime) + } + if _, ok := d.GetOk("backup_plan.0.max_backup_start_time"); ok { + _ = d.Set("backup_plan.0.max_backup_start_time", backupPlan.MaxBackupStartTime) + } + if _, ok := d.GetOk("backup_plan.0.base_backup_retention_period"); ok { + _ = d.Set("backup_plan.0.base_backup_retention_period", backupPlan.BaseBackupRetentionPeriod) + } + if _, ok := d.GetOk("backup_plan.0.backup_period"); ok { + _ = d.Set("backup_plan.0.backup_period", backupPlan.BackupPeriod) + } + } + + } + // pg params var parmas map[string]string err = resource.Retry(readRetryTimeout, func() *resource.RetryError { diff --git a/tencentcloud/resource_tc_postgresql_instance_test.go b/tencentcloud/resource_tc_postgresql_instance_test.go index b0d9a2a59f..6b73bb9ed3 100644 --- a/tencentcloud/resource_tc_postgresql_instance_test.go +++ b/tencentcloud/resource_tc_postgresql_instance_test.go @@ -112,6 +112,11 @@ func TestAccTencentCloudPostgresqlInstanceResource(t *testing.T) { resource.TestCheckResourceAttrSet(testPostgresqlInstanceResourceKey, "availability_zone"), resource.TestCheckResourceAttrSet(testPostgresqlInstanceResourceKey, "private_access_ip"), resource.TestCheckResourceAttrSet(testPostgresqlInstanceResourceKey, "private_access_port"), + resource.TestCheckResourceAttr(testPostgresqlInstanceResourceKey, "backup_plan.#", "1"), + resource.TestCheckResourceAttr(testPostgresqlInstanceResourceKey, "backup_plan.0.min_backup_start_time", "00:10:11"), + resource.TestCheckResourceAttr(testPostgresqlInstanceResourceKey, "backup_plan.0.max_backup_start_time", "01:10:11"), + resource.TestCheckResourceAttr(testPostgresqlInstanceResourceKey, "backup_plan.0.backup_period.#", "2"), + resource.TestCheckResourceAttr(testPostgresqlInstanceResourceKey, "backup_plan.0.base_backup_retention_period", "7"), //resource.TestCheckResourceAttr(testPostgresqlInstanceResourceKey, "tags.tf", "test"), ), }, @@ -119,7 +124,7 @@ func TestAccTencentCloudPostgresqlInstanceResource(t *testing.T) { ResourceName: testPostgresqlInstanceResourceKey, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"root_password", "spec_code", "public_access_switch", "charset"}, + ImportStateVerifyIgnore: []string{"root_password", "spec_code", "public_access_switch", "charset", "backup_plan"}, }, { @@ -134,7 +139,6 @@ func TestAccTencentCloudPostgresqlInstanceResource(t *testing.T) { resource.TestCheckResourceAttr(testPostgresqlInstanceResourceKey, "memory", "4"), resource.TestCheckResourceAttr(testPostgresqlInstanceResourceKey, "storage", "250"), resource.TestCheckResourceAttrSet(testPostgresqlInstanceResourceKey, "create_time"), - // FIXME After PGSQL fixed can reopen case resource.TestCheckResourceAttr(testPostgresqlInstanceResourceKey, "project_id", "0"), resource.TestCheckResourceAttr(testPostgresqlInstanceResourceKey, "public_access_switch", "true"), resource.TestCheckResourceAttr(testPostgresqlInstanceResourceKey, "root_password", "t1qaA2k1wgvfa3?ZZZ"), @@ -143,6 +147,10 @@ func TestAccTencentCloudPostgresqlInstanceResource(t *testing.T) { resource.TestCheckResourceAttrSet(testPostgresqlInstanceResourceKey, "private_access_port"), resource.TestCheckResourceAttrSet(testPostgresqlInstanceResourceKey, "public_access_host"), resource.TestCheckResourceAttrSet(testPostgresqlInstanceResourceKey, "public_access_port"), + resource.TestCheckResourceAttr(testPostgresqlInstanceResourceKey, "backup_plan.0.min_backup_start_time", "01:10:11"), + resource.TestCheckResourceAttr(testPostgresqlInstanceResourceKey, "backup_plan.0.max_backup_start_time", "02:10:11"), + resource.TestCheckResourceAttr(testPostgresqlInstanceResourceKey, "backup_plan.0.backup_period.#", "3"), + resource.TestCheckResourceAttr(testPostgresqlInstanceResourceKey, "backup_plan.0.base_backup_retention_period", "5"), //resource.TestCheckResourceAttr(testPostgresqlInstanceResourceKey, "tags.tf", "teest"), ), }, @@ -243,44 +251,57 @@ data "tencentcloud_availability_zones_by_product" "zone" { } ` -const testAccPostgresqlInstance string = testAccPostgresqlInstanceBasic + ` +const testAccPostgresqlInstance string = testAccPostgresqlInstanceBasic + defaultVpcSubnets + ` resource "tencentcloud_postgresql_instance" "test" { - name = "tf_postsql_instance" - availability_zone = data.tencentcloud_availability_zones_by_product.zone.zones[0].name - charge_type = "POSTPAID_BY_HOUR" - vpc_id = "` + defaultVpcId + `" - subnet_id = "` + defaultSubnetId + `" - engine_version = "10.4" - root_password = "t1qaA2k1wgvfa3?ZZZ" - charset = "LATIN1" - project_id = 0 - memory = 4 - storage = 100 + name = "tf_postsql_instance" + availability_zone = data.tencentcloud_availability_zones_by_product.zone.zones[5].name + charge_type = "POSTPAID_BY_HOUR" + vpc_id = local.vpc_id + subnet_id = local.subnet_id + engine_version = "10.4" + root_password = "t1qaA2k1wgvfa3?ZZZ" + charset = "LATIN1" + project_id = 0 + memory = 4 + storage = 100 + + backup_plan { + min_backup_start_time = "00:10:11" + max_backup_start_time = "01:10:11" + base_backup_retention_period = 7 + backup_period = ["tuesday", "wednesday"] + } - tags = { - tf = "test" - } + tags = { + tf = "test" + } } ` -const testAccPostgresqlInstanceUpdate string = testAccPostgresqlInstanceBasic + ` +const testAccPostgresqlInstanceUpdate string = testAccPostgresqlInstanceBasic + defaultVpcSubnets + ` resource "tencentcloud_postgresql_instance" "test" { name = "tf_postsql_instance_update" - availability_zone = data.tencentcloud_availability_zones_by_product.zone.zones[0].name - charge_type = "POSTPAID_BY_HOUR" - vpc_id = "` + defaultVpcId + `" - subnet_id = "` + defaultSubnetId + `" - engine_version = "10.4" - root_password = "t1qaA2k1wgvfa3?ZZZ" - charset = "LATIN1" - project_id = 0 + availability_zone = data.tencentcloud_availability_zones_by_product.zone.zones[5].name + charge_type = "POSTPAID_BY_HOUR" + vpc_id = local.vpc_id + subnet_id = local.subnet_id + engine_version = "10.4" + root_password = "t1qaA2k1wgvfa3?ZZZ" + charset = "LATIN1" + project_id = 0 public_access_switch = true - memory = 4 - storage = 250 + memory = 4 + storage = 250 + backup_plan { + min_backup_start_time = "01:10:11" + max_backup_start_time = "02:10:11" + base_backup_retention_period = 5 + backup_period = ["monday", "thursday", "sunday"] + } - tags = { - tf = "teest" - } + tags = { + tf = "teest" + } } ` diff --git a/tencentcloud/service_tencentcloud_postgresql.go b/tencentcloud/service_tencentcloud_postgresql.go index e69a6bc408..f7f83e2513 100644 --- a/tencentcloud/service_tencentcloud_postgresql.go +++ b/tencentcloud/service_tencentcloud_postgresql.go @@ -131,6 +131,87 @@ func (me *PostgresqlService) DescribeSpecinfos(ctx context.Context, zone string) return } +func (me *PostgresqlService) ModifyBackupPlan(ctx context.Context, request *postgresql.ModifyBackupPlanRequest) (errRet error) { + logId := getLogId(ctx) + defer func() { + if errRet != nil { + log.Printf("[CRITAL]%s api[%s] fail, request body [%s], reason[%s]\n", + logId, request.GetAction(), request.ToJsonString(), errRet.Error()) + } + }() + + ratelimit.Check(request.GetAction()) + response, err := me.client.UsePostgresqlClient().ModifyBackupPlan(request) + + if err != nil { + errRet = err + return + } + + log.Printf("[DEBUG]%s api[%s] success, request body [%s], response body [%s]\n", + logId, request.GetAction(), request.ToJsonString(), response.ToJsonString()) + + return +} + +func (me *PostgresqlService) DescribeBackupPlans(ctx context.Context, request *postgresql.DescribeBackupPlansRequest) (result []*postgresql.BackupPlan, errRet error) { + logId := getLogId(ctx) + defer func() { + if errRet != nil { + log.Printf("[CRITAL]%s api[%s] fail, request body [%s], reason[%s]\n", + logId, request.GetAction(), request.ToJsonString(), errRet.Error()) + } + }() + + ratelimit.Check(request.GetAction()) + response, err := me.client.UsePostgresqlClient().DescribeBackupPlans(request) + + if err != nil { + errRet = err + return + } + + if len(response.Response.Plans) > 0 { + result = response.Response.Plans + } + + log.Printf("[DEBUG]%s api[%s] success, request body [%s], response body [%s]\n", + logId, request.GetAction(), request.ToJsonString(), response.ToJsonString()) + + return +} + +func (me *PostgresqlService) DescribeDBXlogs(ctx context.Context, request *postgresql.DescribeDBXlogsRequest) (xlogs []*postgresql.Xlog, errRet error) { + logId := getLogId(ctx) + defer func() { + if errRet != nil { + log.Printf("[CRITAL]%s api[%s] fail, request body [%s], reason[%s]\n", + logId, request.GetAction(), request.ToJsonString(), errRet.Error()) + } + }() + + offset := 0 + request.Limit = helper.IntInt64(100) + request.Offset = helper.IntInt64(offset) + ratelimit.Check(request.GetAction()) + + response, err := me.client.UsePostgresqlClient().DescribeDBXlogs(request) + + if err != nil { + errRet = err + return + } + + if len(response.Response.XlogList) > 0 { + xlogs = append(xlogs, response.Response.XlogList...) + } + + log.Printf("[DEBUG]%s api[%s] success, request body [%s], response body [%s]\n", + logId, request.GetAction(), request.ToJsonString(), response.ToJsonString()) + + return +} + func (me *PostgresqlService) ModifyPublicService(ctx context.Context, openInternet bool, instanceId string) (errRet error) { logId := getLogId(ctx) defer func() { diff --git a/website/docs/d/postgresql_xlogs.html.markdown b/website/docs/d/postgresql_xlogs.html.markdown new file mode 100644 index 0000000000..d7be14e13c --- /dev/null +++ b/website/docs/d/postgresql_xlogs.html.markdown @@ -0,0 +1,45 @@ +--- +subcategory: "PostgreSQL" +layout: "tencentcloud" +page_title: "TencentCloud: tencentcloud_postgresql_xlogs" +sidebar_current: "docs-tencentcloud-datasource-postgresql_xlogs" +description: |- + Provide a datasource to query PostgreSQL Xlogs. +--- + +# tencentcloud_postgresql_xlogs + +Provide a datasource to query PostgreSQL Xlogs. + +## Example Usage + +```hcl +data "tencentcloud_postgresql_xlogs" "foo" { + instance_id = "postgres-xxxxxxxx" + start_time = "2022-01-01 00:00:00" + end_time = "2022-01-07 01:02:03" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `instance_id` - (Required) PostgreSQL instance id. +* `end_time` - (Optional) Xlog end time, format `yyyy-MM-dd hh:mm:ss`. +* `result_output_file` - (Optional) Used for save results. +* `start_time` - (Optional) Xlog start time, format `yyyy-MM-dd hh:mm:ss`, start time cannot before 7 days ago. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `list` - List of Xlog query result. + * `end_time` - Xlog file created end time. + * `external_addr` - Xlog external download address. + * `id` - Xlog id. + * `internal_addr` - Xlog internal download address. + * `size` - Xlog file size. + * `start_time` - Xlog file created start time. + + diff --git a/website/docs/r/postgresql_instance.html.markdown b/website/docs/r/postgresql_instance.html.markdown index 4b96fbdfe8..a21d8fc3f9 100644 --- a/website/docs/r/postgresql_instance.html.markdown +++ b/website/docs/r/postgresql_instance.html.markdown @@ -118,6 +118,7 @@ The following arguments are supported: * `name` - (Required) Name of the postgresql instance. * `root_password` - (Required) Password of root account. This parameter can be specified when you purchase master instances, but it should be ignored when you purchase read-only instances or disaster recovery instances. * `storage` - (Required) Volume 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_postgresql_specinfos` provides. +* `backup_plan` - (Optional) Specify DB backup plan. * `charge_type` - (Optional, ForceNew) Pay type of the postgresql instance. For now, only `POSTPAID_BY_HOUR` is valid. * `charset` - (Optional, ForceNew) Charset of the root account. Valid values are `UTF8`,`LATIN1`. * `db_node_set` - (Optional) Specify instance node info for disaster migration. @@ -132,6 +133,13 @@ The following arguments are supported: * `tags` - (Optional) The available tags within this postgresql. * `vpc_id` - (Optional, ForceNew) ID of VPC. +The `backup_plan` object supports the following: + +* `backup_period` - (Optional) List of backup period per week, available values: `monday`, `tuesday`, `wednesday`, `thursday`, `friday`, `saturday`, `sunday`. NOTE: At least specify two days. +* `base_backup_retention_period` - (Optional) Specify days of the retention. +* `max_backup_start_time` - (Optional) Specify latest backup start time, format `hh:mm:ss`. +* `min_backup_start_time` - (Optional) Specify earliest backup start time, format `hh:mm:ss`. + The `db_node_set` object supports the following: * `zone` - (Required) Indicates the node available zone. diff --git a/website/tencentcloud.erb b/website/tencentcloud.erb index 804c319fa0..1935abc6eb 100644 --- a/website/tencentcloud.erb +++ b/website/tencentcloud.erb @@ -1120,6 +1120,9 @@
  • tencentcloud_postgresql_specinfos
  • +
  • + tencentcloud_postgresql_xlogs +
  • From 3e4a58dc5e0f641446e0f05ad8d9c861f7a38c80 Mon Sep 17 00:00:00 2001 From: Kagashino Date: Fri, 22 Apr 2022 17:49:02 +0800 Subject: [PATCH 2/4] fix: pgsql backup plan assignment --- ...ata_source_tc_postgresql_instances_test.go | 44 +------------------ .../resource_tc_postgresql_instance.go | 16 +++---- 2 files changed, 10 insertions(+), 50 deletions(-) diff --git a/tencentcloud/data_source_tc_postgresql_instances_test.go b/tencentcloud/data_source_tc_postgresql_instances_test.go index 84443aeaaa..2cca6b0f86 100644 --- a/tencentcloud/data_source_tc_postgresql_instances_test.go +++ b/tencentcloud/data_source_tc_postgresql_instances_test.go @@ -38,49 +38,9 @@ func TestAccTencentCloudDataPostgresqlInstances(t *testing.T) { }) } -const testAccTencentCloudDataPostgresqlInstanceBasic = ` -data "tencentcloud_availability_zones_by_product" "pg" { - product = "postgres" -} - -resource "tencentcloud_vpc" "vpc" { - cidr_block = "10.0.0.0/24" - name = "test-pg-vpc" -} - -resource "tencentcloud_subnet" "subnet" { - availability_zone = local.az - cidr_block = "10.0.0.0/24" - name = "sub1" - vpc_id = tencentcloud_vpc.vpc.id -} - -locals { - az = data.tencentcloud_availability_zones_by_product.pg.zones.0.name - vpc_id = tencentcloud_vpc.vpc.id - subnet_id = tencentcloud_subnet.subnet.id -} - - -resource "tencentcloud_postgresql_instance" "test" { - name = "tf_postsql_instance" - availability_zone = local.az - charge_type = "POSTPAID_BY_HOUR" - engine_version = "10.4" - root_password = "1qaA2k1wgvfa!_3ZZZ" - charset = "UTF8" - project_id = 0 - memory = 2 - storage = 10 - vpc_id = local.vpc_id - subnet_id = local.subnet_id - - tags = { - tf = "test" - } -} +const testAccTencentCloudDataPostgresqlInstanceBasic = CommonPresetPGSQL + ` data "tencentcloud_postgresql_instances" "id_test"{ - id = tencentcloud_postgresql_instance.test.id + id = local.pgsql_id } ` diff --git a/tencentcloud/resource_tc_postgresql_instance.go b/tencentcloud/resource_tc_postgresql_instance.go index f8ccda4417..6ac709deef 100644 --- a/tencentcloud/resource_tc_postgresql_instance.go +++ b/tencentcloud/resource_tc_postgresql_instance.go @@ -579,16 +579,16 @@ func resourceTencentCloudPostgresqlInstanceCreate(d *schema.ResourceData, meta i if plan, ok := helper.InterfacesHeadMap(d, "backup_plan"); ok { request := postgresql.NewModifyBackupPlanRequest() request.DBInstanceId = &instanceId - if v, ok := plan["min_backup_start_time"].(string); ok { + if v, ok := plan["min_backup_start_time"].(string); ok && v != "" { request.MinBackupStartTime = &v } - if v, ok := plan["max_backup_start_time"].(string); ok { + if v, ok := plan["max_backup_start_time"].(string); ok && v != "" { request.MaxBackupStartTime = &v } - if v, ok := plan["base_backup_retention_period"].(int); ok { + if v, ok := plan["base_backup_retention_period"].(int); ok && v != 0 { request.BaseBackupRetentionPeriod = helper.IntUint64(v) } - if v, ok := plan["backup_period"].([]interface{}); ok { + if v, ok := plan["backup_period"].([]interface{}); ok && len(v) > 0 { request.BackupPeriod = helper.InterfacesStringsPoint(v) } err := postgresqlService.ModifyBackupPlan(ctx, request) @@ -742,16 +742,16 @@ func resourceTencentCloudPostgresqlInstanceUpdate(d *schema.ResourceData, meta i if plan, ok := helper.InterfacesHeadMap(d, "backup_plan"); ok { request := postgresql.NewModifyBackupPlanRequest() request.DBInstanceId = &instanceId - if v, ok := plan["min_backup_start_time"].(string); ok { + if v, ok := plan["min_backup_start_time"].(string); ok && v != "" { request.MinBackupStartTime = &v } - if v, ok := plan["max_backup_start_time"].(string); ok { + if v, ok := plan["max_backup_start_time"].(string); ok && v != "" { request.MaxBackupStartTime = &v } - if v, ok := plan["base_backup_retention_period"].(int); ok { + if v, ok := plan["base_backup_retention_period"].(int); ok && v != 0 { request.BaseBackupRetentionPeriod = helper.IntUint64(v) } - if v, ok := plan["backup_period"].([]interface{}); ok { + if v, ok := plan["backup_period"].([]interface{}); ok && len(v) > 0 { request.BackupPeriod = helper.InterfacesStringsPoint(v) } err := postgresqlService.ModifyBackupPlan(ctx, request) From bca070ac25b20bce758de045a8ad43a5b582a4e4 Mon Sep 17 00:00:00 2001 From: Kagashino Date: Fri, 22 Apr 2022 19:33:40 +0800 Subject: [PATCH 3/4] fix: add open/close extranet retry --- .../service_tencentcloud_postgresql.go | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/tencentcloud/service_tencentcloud_postgresql.go b/tencentcloud/service_tencentcloud_postgresql.go index f7f83e2513..2ea7252003 100644 --- a/tencentcloud/service_tencentcloud_postgresql.go +++ b/tencentcloud/service_tencentcloud_postgresql.go @@ -225,7 +225,16 @@ func (me *PostgresqlService) ModifyPublicService(ctx context.Context, openIntern request.DBInstanceId = &instanceId ratelimit.Check(request.GetAction()) - response, err := me.client.UsePostgresqlClient().OpenDBExtranetAccess(request) + var response *postgresql.OpenDBExtranetAccessResponse + err := resource.Retry(writeRetryTimeout, func() *resource.RetryError { + resp, err := me.client.UsePostgresqlClient().OpenDBExtranetAccess(request) + if err != nil { + return retryError(err, postgresql.OPERATIONDENIED_INSTANCESTATUSLIMITOPERROR) + } + response = resp + return nil + }) + if err != nil { errRet = err return @@ -270,7 +279,16 @@ func (me *PostgresqlService) ModifyPublicService(ctx context.Context, openIntern request.DBInstanceId = &instanceId ratelimit.Check(request.GetAction()) - response, err := me.client.UsePostgresqlClient().CloseDBExtranetAccess(request) + var response *postgresql.CloseDBExtranetAccessResponse + err := resource.Retry(writeRetryTimeout, func() *resource.RetryError { + resp, err := me.client.UsePostgresqlClient().CloseDBExtranetAccess(request) + if err != nil { + return retryError(err, postgresql.OPERATIONDENIED_INSTANCESTATUSLIMITOPERROR) + } + response = resp + return nil + }) + if err != nil { return err } From 81766ea9eb72a25445dabf35d4fa2e921f1faf55 Mon Sep 17 00:00:00 2001 From: Kagashino Date: Fri, 22 Apr 2022 20:43:59 +0800 Subject: [PATCH 4/4] fix: isolate retry and datasource testcase --- .../data_source_tc_postgresql_instances_test.go | 12 +++++------- tencentcloud/resource_tc_postgresql_instance.go | 2 +- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/tencentcloud/data_source_tc_postgresql_instances_test.go b/tencentcloud/data_source_tc_postgresql_instances_test.go index 2cca6b0f86..18fd7e7044 100644 --- a/tencentcloud/data_source_tc_postgresql_instances_test.go +++ b/tencentcloud/data_source_tc_postgresql_instances_test.go @@ -18,20 +18,18 @@ func TestAccTencentCloudDataPostgresqlInstances(t *testing.T) { { Config: testAccTencentCloudDataPostgresqlInstanceBasic, Check: resource.ComposeTestCheckFunc( - testAccCheckPostgresqlInstanceExists("tencentcloud_postgresql_instance.test"), resource.TestCheckResourceAttr(testDataPostgresqlInstancesName, "instance_list.#", "1"), resource.TestCheckResourceAttrSet(testDataPostgresqlInstancesName, "instance_list.0.id"), resource.TestCheckResourceAttrSet(testDataPostgresqlInstancesName, "instance_list.0.create_time"), - resource.TestCheckResourceAttr(testDataPostgresqlInstancesName, "instance_list.0.charge_type", "POSTPAID_BY_HOUR"), - resource.TestCheckResourceAttr(testDataPostgresqlInstancesName, "instance_list.0.engine_version", "10.4"), - resource.TestCheckResourceAttr(testDataPostgresqlInstancesName, "instance_list.0.project_id", "0"), - resource.TestCheckResourceAttr(testDataPostgresqlInstancesName, "instance_list.0.memory", "2"), - resource.TestCheckResourceAttr(testDataPostgresqlInstancesName, "instance_list.0.storage", "10"), + resource.TestCheckResourceAttrSet(testDataPostgresqlInstancesName, "instance_list.0.charge_type"), + resource.TestCheckResourceAttrSet(testDataPostgresqlInstancesName, "instance_list.0.engine_version"), + resource.TestCheckResourceAttrSet(testDataPostgresqlInstancesName, "instance_list.0.project_id"), + resource.TestCheckResourceAttrSet(testDataPostgresqlInstancesName, "instance_list.0.memory"), + resource.TestCheckResourceAttrSet(testDataPostgresqlInstancesName, "instance_list.0.storage"), resource.TestCheckResourceAttrSet(testDataPostgresqlInstancesName, "instance_list.0.private_access_ip"), resource.TestCheckResourceAttrSet(testDataPostgresqlInstancesName, "instance_list.0.private_access_port"), resource.TestCheckResourceAttrSet(testDataPostgresqlInstancesName, "instance_list.0.public_access_switch"), resource.TestCheckResourceAttrSet(testDataPostgresqlInstancesName, "instance_list.0.charset"), - resource.TestCheckResourceAttr(testDataPostgresqlInstancesName, "instance_list.0.tags.tf", "test"), ), }, }, diff --git a/tencentcloud/resource_tc_postgresql_instance.go b/tencentcloud/resource_tc_postgresql_instance.go index 6ac709deef..446f96f83b 100644 --- a/tencentcloud/resource_tc_postgresql_instance.go +++ b/tencentcloud/resource_tc_postgresql_instance.go @@ -1112,7 +1112,7 @@ func resourceTencentCLoudPostgresqlInstanceDelete(d *schema.ResourceData, meta i if ok && ee.GetCode() == "ResourceNotFound.InstanceNotFoundError" { return nil } - return retryError(inErr) + return retryError(inErr, postgresql.OPERATIONDENIED_INSTANCESTATUSLIMITOPERROR) } return nil })