diff --git a/.changelog/2959.txt b/.changelog/2959.txt new file mode 100644 index 0000000000..95a1792bcd --- /dev/null +++ b/.changelog/2959.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/tencentcloud_mysql_readonly_instance: Supports creating read-only instances across regions. +``` \ No newline at end of file diff --git a/tencentcloud/connectivity/client.go b/tencentcloud/connectivity/client.go index 1d0aa26146..b475b86f7a 100644 --- a/tencentcloud/connectivity/client.go +++ b/tencentcloud/connectivity/client.go @@ -393,10 +393,10 @@ func (me *TencentCloudClient) UseMysqlClient(iacExtInfo ...IacExtInfo) *cdb.Clie logRoundTripper.InstanceId = iacExtInfo[0].InstanceId } - if me.mysqlConn != nil { - me.mysqlConn.WithHttpTransport(&logRoundTripper) - return me.mysqlConn - } + // if me.mysqlConn != nil { + // me.mysqlConn.WithHttpTransport(&logRoundTripper) + // return me.mysqlConn + // } cpf := me.NewClientProfile(300) me.mysqlConn, _ = cdb.NewClient(me.Credential, me.Region, cpf) @@ -405,6 +405,23 @@ func (me *TencentCloudClient) UseMysqlClient(iacExtInfo ...IacExtInfo) *cdb.Clie return me.mysqlConn } +func (me *TencentCloudClient) UseMysqlClientRegion(region string, iacExtInfo ...IacExtInfo) *cdb.Client { + var logRoundTripper LogRoundTripper + if len(iacExtInfo) != 0 { + logRoundTripper.InstanceId = iacExtInfo[0].InstanceId + } + + cpf := me.NewClientProfile(300) + if region != "" { + me.mysqlConn, _ = cdb.NewClient(me.Credential, region, cpf) + } else { + me.mysqlConn, _ = cdb.NewClient(me.Credential, me.Region, cpf) + } + me.mysqlConn.WithHttpTransport(&logRoundTripper) + + return me.mysqlConn +} + // UseRedisClient returns redis client for service func (me *TencentCloudClient) UseRedisClient() *redis.Client { if me.redisConn != nil { diff --git a/tencentcloud/services/cdb/resource_tc_mysql_readonly_instance.go b/tencentcloud/services/cdb/resource_tc_mysql_readonly_instance.go index 7bd0887da9..7e46f5a9ef 100644 --- a/tencentcloud/services/cdb/resource_tc_mysql_readonly_instance.go +++ b/tencentcloud/services/cdb/resource_tc_mysql_readonly_instance.go @@ -46,7 +46,7 @@ func ResourceTencentCloudMysqlReadonlyInstance() *schema.Resource { Type: schema.TypeString, Optional: true, Computed: true, - Description: "Read only group id. If rogroupId is empty, a new ro group is created by default. If it is not empty, the existing ro group is used.", + Description: "Read only group id. If rogroupId is empty, a new ro group is created by default. If it is not empty, the existing ro group is used. Cross-region query requires master instance permission.", }, } @@ -216,13 +216,18 @@ func resourceTencentCloudMysqlReadonlyInstanceCreate(d *schema.ResourceData, met logId := tccommon.GetLogId(tccommon.ContextNil) ctx := context.WithValue(context.TODO(), tccommon.LogIdKey, logId) - mysqlService := MysqlService{client: meta.(tccommon.ProviderMeta).GetAPIV3Conn()} + client := meta.(tccommon.ProviderMeta).GetAPIV3Conn() + mysqlService := MysqlService{client: client} // the mysql master instance must have a backup before creating a read-only instance masterInstanceId := d.Get("master_instance_id").(string) + masterRegion := "" + if v, ok := d.GetOk("master_region"); ok { + masterRegion = v.(string) + } err := resource.Retry(2*tccommon.ReadRetryTimeout, func() *resource.RetryError { - backups, err := mysqlService.DescribeBackupsByMysqlId(ctx, masterInstanceId, 10) + backups, err := mysqlService.DescribeBackupsByMysqlIdRegion(ctx, masterInstanceId, 10, masterRegion) if err != nil { return resource.NonRetryableError(err) } @@ -297,6 +302,7 @@ func resourceTencentCloudMysqlReadonlyInstanceRead(d *schema.ResourceData, meta logId := tccommon.GetLogId(tccommon.ContextNil) ctx := context.WithValue(context.TODO(), tccommon.LogIdKey, logId) mysqlService := MysqlService{client: meta.(tccommon.ProviderMeta).GetAPIV3Conn()} + masterRegion := "" err := resource.Retry(tccommon.ReadRetryTimeout, func() *resource.RetryError { mysqlInfo, e := tencentMsyqlBasicInfoRead(ctx, d, meta, false) if e != nil { @@ -313,6 +319,7 @@ func resourceTencentCloudMysqlReadonlyInstanceRead(d *schema.ResourceData, meta _ = d.Set("master_instance_id", *mysqlInfo.MasterInfo.InstanceId) _ = d.Set("zone", *mysqlInfo.Zone) _ = d.Set("master_region", *mysqlInfo.MasterInfo.Region) + masterRegion = *mysqlInfo.MasterInfo.Region return nil }) @@ -394,7 +401,7 @@ func resourceTencentCloudMysqlReadonlyInstanceRead(d *schema.ResourceData, meta _ = d.Set("status", mysqlInfo.Status) _ = d.Set("task_status", mysqlInfo.TaskStatus) - roGroup, err := mysqlService.DescribeRoGroupByIdAndRoId(ctx, *mysqlInfo.MasterInfo.InstanceId, d.Id()) + roGroup, err := mysqlService.DescribeRoGroupByIdAndRoId(ctx, masterRegion, *mysqlInfo.MasterInfo.InstanceId, d.Id()) if err != nil { return err } diff --git a/tencentcloud/services/cdb/service_tencentcloud_mysql.go b/tencentcloud/services/cdb/service_tencentcloud_mysql.go index 419f1e8dc9..70fd4902f2 100644 --- a/tencentcloud/services/cdb/service_tencentcloud_mysql.go +++ b/tencentcloud/services/cdb/service_tencentcloud_mysql.go @@ -98,6 +98,61 @@ needMoreItems: } +func (me *MysqlService) DescribeBackupsByMysqlIdRegion(ctx context.Context, + mysqlId string, + leftNumber int64, region string) (backupInfos []*cdb.BackupInfo, errRet error) { + + logId := tccommon.GetLogId(ctx) + + listInitSize := leftNumber + if listInitSize > 500 { + listInitSize = 500 + } + backupInfos = make([]*cdb.BackupInfo, 0, listInitSize) + + request := cdb.NewDescribeBackupsRequest() + request.InstanceId = &mysqlId + + var offset, limit int64 = 0, 50 +needMoreItems: + if leftNumber <= 0 { + return + } + if leftNumber < limit { + limit = leftNumber + } + request.Limit = &limit + request.Offset = &offset + 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.UseMysqlClientRegion(region).DescribeBackups(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()) + + totalCount := *response.Response.TotalCount + leftNumber = leftNumber - limit + offset += limit + + backupInfos = append(backupInfos, response.Response.Items...) + if leftNumber > 0 && totalCount-offset > 0 { + goto needMoreItems + } + return backupInfos, nil + +} + func (me *MysqlService) CreateBackup(ctx context.Context, mysqlId string) (backupId int64, errRet error) { logId := tccommon.GetLogId(ctx) @@ -3154,7 +3209,7 @@ func (me *MysqlService) DescribeMysqlRoGroupById(ctx context.Context, instanceId return } -func (me *MysqlService) DescribeRoGroupByIdAndRoId(ctx context.Context, instanceId string, roInstanceId string) (roGroup *cdb.RoGroup, errRet error) { +func (me *MysqlService) DescribeRoGroupByIdAndRoId(ctx context.Context, region string, instanceId string, roInstanceId string) (roGroup *cdb.RoGroup, errRet error) { logId := tccommon.GetLogId(ctx) request := cdb.NewDescribeRoGroupsRequest() @@ -3168,7 +3223,7 @@ func (me *MysqlService) DescribeRoGroupByIdAndRoId(ctx context.Context, instance ratelimit.Check(request.GetAction()) - response, err := me.client.UseMysqlClient().DescribeRoGroups(request) + response, err := me.client.UseMysqlClientRegion(region).DescribeRoGroups(request) if err != nil { errRet = err return diff --git a/website/docs/r/mysql_readonly_instance.html.markdown b/website/docs/r/mysql_readonly_instance.html.markdown index 662895e8a4..0909201e52 100644 --- a/website/docs/r/mysql_readonly_instance.html.markdown +++ b/website/docs/r/mysql_readonly_instance.html.markdown @@ -101,7 +101,7 @@ The following arguments are supported: * `pay_type` - (Optional, Int, **Deprecated**) It has been deprecated from version 1.36.0. Please use `charge_type` instead. Pay type of instance. Valid values: `0`, `1`. `0`: prepaid, `1`: postpaid. * `period` - (Optional, Int, **Deprecated**) It has been deprecated from version 1.36.0. Please use `prepaid_period` instead. Period of instance. NOTES: Only supported prepaid instance. * `prepaid_period` - (Optional, Int) Period of instance. NOTES: Only supported prepaid instance. -* `ro_group_id` - (Optional, String) Read only group id. If rogroupId is empty, a new ro group is created by default. If it is not empty, the existing ro group is used. +* `ro_group_id` - (Optional, String) Read only group id. If rogroupId is empty, a new ro group is created by default. If it is not empty, the existing ro group is used. Cross-region query requires master instance permission. * `security_groups` - (Optional, Set: [`String`]) Security groups to use. * `slave_deploy_mode` - (Optional, Int) Availability zone deployment method. Available values: 0 - Single availability zone; 1 - Multiple availability zones. * `subnet_id` - (Optional, String) Private network ID. If `vpc_id` is set, this value is required.