From e03e68e5e2b73c58e1bfb613fc7c7d375d00d453 Mon Sep 17 00:00:00 2001 From: Kagashino Date: Fri, 15 Apr 2022 11:35:35 +0800 Subject: [PATCH 1/2] fix: redis support maz modified --- tencentcloud/commom_test.go | 54 +++++ tencentcloud/common.go | 32 ++- tencentcloud/internal/helper/transform.go | 8 + tencentcloud/resource_tc_redis_instance.go | 201 ++++++++++++++++-- .../resource_tc_redis_instance_test.go | 134 ++++++++++-- tencentcloud/service_tencentcloud_redis.go | 20 +- website/docs/r/redis_instance.html.markdown | 4 +- 7 files changed, 405 insertions(+), 48 deletions(-) diff --git a/tencentcloud/commom_test.go b/tencentcloud/commom_test.go index ae5e0cd4ea..0fc8854395 100644 --- a/tencentcloud/commom_test.go +++ b/tencentcloud/commom_test.go @@ -2,6 +2,10 @@ package tencentcloud import ( "testing" + + sdkErrors "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors" + + "github.com/stretchr/testify/assert" ) func TestIsContains(t *testing.T) { @@ -71,3 +75,53 @@ func TestIsContains(t *testing.T) { } } } + +func TestGetListIncrement(t *testing.T) { + var ( + old1 = []int{1, 2, 2, 3, 5} + new1 = []int{1, 2, 3, 2, 4, 5, 6, 3} + expected1 = []int{4, 6, 3} + ) + actual1, _ := GetListIncrement(old1, new1) + assert.Equalf(t, expected1, actual1, "incr1 should equal, got %v %v", expected1, actual1) + + var ( + old2 = []int{1, 2, 4, 5} + new2 = []int{1, 2, 3, 2, 4, 5, 6, 3} + expected2 = []int{3, 2, 6, 3} + ) + actual2, _ := GetListIncrement(old2, new2) + assert.Equalf(t, expected2, actual2, "incr1 should equal, got %v %v", expected2, actual2) + + var ( + old3 = []int{1, 2, 4, 5, 3, 6, 3, 2} + new3 = []int{1, 2, 3, 2, 4, 5, 6, 3} + expected3 = make([]int, 0) + ) + actual3, _ := GetListIncrement(old3, new3) + assert.Equalf(t, expected3, actual3, "incr1 should equal, got %v %v", expected3, actual3) + + var ( + old4 = []int{1} + new4 = []int{2} + ) + + _, err := GetListIncrement(old4, new4) + assert.EqualError(t, err, "elem 1 not exist") + +} + +func TestIsExpectError(t *testing.T) { + + err := sdkErrors.NewTencentCloudSDKError("ClientError.NetworkError", "", "") + + expectedFull := []string{"ClientError.NetworkError"} + expectedShort := []string{"ClientError"} + unExpectedMatchHead := []string{"ClientError.HttpStatusCodeError"} + unExpectedShort := []string{"SystemError"} + + assert.Equalf(t, isExpectError(err, expectedFull), true, "") + assert.Equalf(t, isExpectError(err, expectedShort), true, "") + assert.Equalf(t, isExpectError(err, unExpectedMatchHead), false, "") + assert.Equalf(t, isExpectError(err, unExpectedShort), false, "") +} diff --git a/tencentcloud/common.go b/tencentcloud/common.go index 0de189abed..c68d0bb345 100644 --- a/tencentcloud/common.go +++ b/tencentcloud/common.go @@ -147,7 +147,7 @@ func retryError(err error, additionRetryableError ...string) *resource.RetryErro return resource.NonRetryableError(err) } -// isExpectError returns whether error is expect error +// isExpectError returns whether error is expected error func isExpectError(err error, expectError []string) bool { e, ok := err.(*sdkErrors.TencentCloudSDKError) if !ok { @@ -276,3 +276,33 @@ func IsContains(array interface{}, value interface{}) bool { return reflect.DeepEqual(array, value) } } + +func FindIntListIndex(list []int, elem int) int { + for i, v := range list { + if v == elem { + return i + } + } + return -1 +} + +func GetListIncrement(o []int, n []int) (result []int, err error) { + result = append(result, n...) + if len(o) > len(n) { + err = fmt.Errorf("new list elem count %d less than old: %d", len(n), len(o)) + return + } + for _, v := range o { + index := FindIntListIndex(result, v) + if index == -1 { + err = fmt.Errorf("elem %d not exist", v) + return + } + if index+1 >= len(result) { + result = result[:index] + } else { + result = append(result[:index], result[index+1:]...) + } + } + return +} diff --git a/tencentcloud/internal/helper/transform.go b/tencentcloud/internal/helper/transform.go index 8a30f39230..f9e1df66fe 100644 --- a/tencentcloud/internal/helper/transform.go +++ b/tencentcloud/internal/helper/transform.go @@ -77,6 +77,14 @@ func InterfacesStringsPoint(configured []interface{}) []*string { return vs } +func InterfacesIntegers(configured []interface{}) []int { + vs := make([]int, 0, len(configured)) + for _, v := range configured { + vs = append(vs, v.(int)) + } + return vs +} + func InterfacesIntInt64Point(configured []interface{}) []*int64 { vs := make([]*int64, 0, len(configured)) for _, v := range configured { diff --git a/tencentcloud/resource_tc_redis_instance.go b/tencentcloud/resource_tc_redis_instance.go index 62f86c37ac..4370291a92 100644 --- a/tencentcloud/resource_tc_redis_instance.go +++ b/tencentcloud/resource_tc_redis_instance.go @@ -124,14 +124,12 @@ func resourceTencentCloudRedisInstance() *schema.Resource { "redis_replicas_num": { Type: schema.TypeInt, Optional: true, - ForceNew: true, Default: 1, Description: "The number of instance copies. This is not required for standalone and master slave versions.", }, "replica_zone_ids": { Type: schema.TypeList, Optional: true, - ForceNew: true, Description: "ID of replica nodes available zone. This is not required for standalone and master slave versions.", Elem: &schema.Schema{Type: schema.TypeInt}, }, @@ -578,17 +576,25 @@ func resourceTencentCloudRedisInstanceRead(d *schema.ResourceData, meta interfac } if info.NodeSet != nil { - var zoneIds []uint64 + var zoneIds []int for i := range info.NodeSet { nodeInfo := info.NodeSet[i] if *nodeInfo.NodeType == 0 { continue } - zoneIds = append(zoneIds, *nodeInfo.ZoneId) + zoneIds = append(zoneIds, int(*nodeInfo.ZoneId)) + } + + var zoneIdsEqual = false + + raw, ok := d.GetOk("replica_zone_ids") + if ok { + oldIds := helper.InterfacesIntegers(raw.([]interface{})) + zoneIdsEqual = checkZoneIdsEqual(oldIds, zoneIds) } - if err := d.Set("replica_zone_ids", zoneIds); err != nil { - log.Printf("[WARN] replica_zone_ids set error: %s", err.Error()) + if !zoneIdsEqual { + _ = d.Set("replica_zone_ids", zoneIds) } } @@ -643,28 +649,29 @@ func resourceTencentCloudRedisInstanceUpdate(d *schema.ResourceData, meta interf d.SetPartial("name") } + // MemSize, ShardNum and ReplicaNum can only change one for each upgrade invoke if d.HasChange("mem_size") { _, newInter := d.GetChange("mem_size") newMemSize := newInter.(int) - //oldMemSize := oldInter.(int) - - //if oldMemSize >= newMemSize { - // return fmt.Errorf("redis mem_size can only increase") - //} + oShard, _ := d.GetChange("redis_shard_num") + redisShardNum := oShard.(int) + oReplica, _ := d.GetChange("redis_replicas_num") + redisReplicasNum := oReplica.(int) if newMemSize < 1 { return fmt.Errorf("redis mem_size value cannot be set to less than 1") } - redisShardNum := d.Get("redis_shard_num").(int) - redisReplicasNum := d.Get("redis_replicas_num").(int) - _, err := redisService.UpgradeInstance(ctx, id, int64(newMemSize), int64(redisShardNum), int64(redisReplicasNum)) + + _, err := redisService.UpgradeInstance(ctx, id, newMemSize, redisShardNum, redisReplicasNum, nil) if err != nil { - log.Printf("[CRITAL]%s redis update mem size error, reason:%s\n", logId, err.Error()) + log.Printf("[CRITAL]%s redis upgrade instance error, reason:%s\n", logId, err.Error()) return err } + startUpdate := false + err = resource.Retry(4*readRetryTimeout, func() *resource.RetryError { _, _, info, err := redisService.CheckRedisOnlineOk(ctx, id) @@ -673,12 +680,17 @@ func resourceTencentCloudRedisInstanceUpdate(d *schema.ResourceData, meta interf if status == "" { return resource.NonRetryableError(fmt.Errorf("after update redis mem size, redis status is unknown ,status=%d", *info.Status)) } - if *info.Status == REDIS_STATUS_PROCESSING || *info.Status == REDIS_STATUS_INIT { - return resource.RetryableError(fmt.Errorf("redis update processing.")) + if *info.Status == REDIS_STATUS_ONLINE && !startUpdate { + return resource.RetryableError(fmt.Errorf("waiting for status change to proccessing")) } - if *info.Status == REDIS_STATUS_ONLINE { + if *info.Status == REDIS_STATUS_ONLINE && startUpdate { return nil } + startUpdate = true + + if *info.Status == REDIS_STATUS_PROCESSING || *info.Status == REDIS_STATUS_INIT { + return resource.RetryableError(fmt.Errorf("redis update processing.")) + } return resource.NonRetryableError(fmt.Errorf("after update redis mem size, redis status is %s", status)) } @@ -696,8 +708,143 @@ func resourceTencentCloudRedisInstanceUpdate(d *schema.ResourceData, meta interf log.Printf("[CRITAL]%s redis update mem size fail , reason:%s\n", logId, err.Error()) return err } + } + + // MemSize, ShardNum and ReplicaNum can only change one for each upgrade invoke + if d.HasChange("redis_shard_num") { + redisShardNum := d.Get("redis_shard_num").(int) + oReplica, _ := d.GetChange("redis_replicas_num") + redisReplicasNum := oReplica.(int) + memSize := d.Get("mem_size").(int) + err := resource.Retry(writeRetryTimeout, func() *resource.RetryError { + _, err := redisService.UpgradeInstance(ctx, id, memSize, redisShardNum, redisReplicasNum, nil) + if err != nil { + // Upgrade memory will cause instance lock and cannot acknowledge by polling status, wait until lock release + return retryError(err, redis.FAILEDOPERATION_UNKNOWN, redis.FAILEDOPERATION_SYSTEMERROR) + } + return nil + }) + + if err != nil { + log.Printf("[CRITAL]%s redis upgrade instance error, reason:%s\n", logId, err.Error()) + return err + } + + startUpdate := false + + err = resource.Retry(4*readRetryTimeout, func() *resource.RetryError { + _, _, info, err := redisService.CheckRedisOnlineOk(ctx, id) + + if info != nil { + status := REDIS_STATUS[*info.Status] + if status == "" { + return resource.NonRetryableError(fmt.Errorf("after update redis shard num, redis status is unknown ,status=%d", *info.Status)) + } + if *info.Status == REDIS_STATUS_ONLINE && !startUpdate { + return resource.RetryableError(fmt.Errorf("waiting for status change to proccessing")) + } + if *info.Status == REDIS_STATUS_ONLINE && startUpdate { + return nil + } + startUpdate = true + + if *info.Status == REDIS_STATUS_PROCESSING || *info.Status == REDIS_STATUS_INIT { + return resource.RetryableError(fmt.Errorf("redis update processing.")) + } + return resource.NonRetryableError(fmt.Errorf("after update redis shard num, redis status is %s", status)) + } + + if err != nil { + if _, ok := err.(*sdkErrors.TencentCloudSDKError); !ok { + return resource.RetryableError(err) + } else { + return resource.NonRetryableError(err) + } + } + return resource.NonRetryableError(fmt.Errorf("after update redis shard num, redis disappear")) + }) + + if err != nil { + log.Printf("[CRITAL]%s redis update shard num fail , reason:%s\n", logId, err.Error()) + return err + } + } + + // MemSize, ShardNum and ReplicaNum can only change one for each upgrade invoke + if d.HasChange("redis_replicas_num") || d.HasChange("replica_zone_ids") { + //availabilityZone := d.Get("availability_zone").(string) + o, n := d.GetChange("replica_zone_ids") // Only pass zone id increments + ov := helper.InterfacesIntegers(o.([]interface{})) + nv := helper.InterfacesIntegers(n.([]interface{})) + zoneIds, err := GetListIncrement(ov, nv) + + if err != nil { + return fmt.Errorf("get diff replica error: %s", err.Error()) + } + + var nodeInfo []*redis.RedisNodeInfo + + for _, id := range zoneIds { + nodeInfo = append(nodeInfo, &redis.RedisNodeInfo{ + NodeType: helper.Int64(1), + ZoneId: helper.IntUint64(id), + }) + } + redisReplicasNum := d.Get("redis_replicas_num").(int) + memSize := d.Get("mem_size").(int) + redisShardNum := d.Get("redis_shard_num").(int) + err = resource.Retry(writeRetryTimeout, func() *resource.RetryError { + _, err = redisService.UpgradeInstance(ctx, id, memSize, redisShardNum, redisReplicasNum, nodeInfo) + if err != nil { + // Upgrade memory will cause instance lock and cannot acknowledge by polling status, wait until lock release + return retryError(err, redis.FAILEDOPERATION_UNKNOWN, redis.FAILEDOPERATION_SYSTEMERROR) + } + return nil + }) + + if err != nil { + return err + } + + err = resource.Retry(4*readRetryTimeout, func() *resource.RetryError { + _, _, info, err := redisService.CheckRedisOnlineOk(ctx, id) + + if info != nil { + status := REDIS_STATUS[*info.Status] + if status == "" { + return resource.NonRetryableError(fmt.Errorf("after update redis replicas, redis status is unknown ,status=%d", *info.Status)) + } + actualNodeCount := len(info.NodeSet) + expectedNodeCount := len(nv) + 1 + // wait until node set as expected or will cause status inconsistent + if *info.Status == REDIS_STATUS_ONLINE && actualNodeCount != expectedNodeCount { + return resource.RetryableError(fmt.Errorf("waiting for status change to proccessing")) + } + if *info.Status == REDIS_STATUS_ONLINE && actualNodeCount == expectedNodeCount { + return nil + } + if *info.Status == REDIS_STATUS_PROCESSING || *info.Status == REDIS_STATUS_INIT { + return resource.RetryableError(fmt.Errorf("redis update processing.")) + } + + return resource.NonRetryableError(fmt.Errorf("after update redis replicas, redis status is %s", status)) + } + + if err != nil { + if _, ok := err.(*sdkErrors.TencentCloudSDKError); !ok { + return resource.RetryableError(err) + } else { + return resource.NonRetryableError(err) + } + } + return resource.NonRetryableError(fmt.Errorf("after update redis replicas, redis disappear")) + }) + + if err != nil { + log.Printf("[CRITAL]%s redis update replicas fail , reason:%s\n", logId, err.Error()) + return err + } - d.SetPartial("mem_size") } if d.HasChange("password") { @@ -880,3 +1027,19 @@ func resourceTencentCloudRedisInstanceDelete(d *schema.ResourceData, meta interf return nil } } + +func checkZoneIdsEqual(o []int, n []int) bool { + if len(o) != len(n) { + return false + } + + sort.Ints(o) + sort.Ints(n) + + for i, v := range o { + if v != n[i] { + return false + } + } + return true +} diff --git a/tencentcloud/resource_tc_redis_instance_test.go b/tencentcloud/resource_tc_redis_instance_test.go index e159caf8e9..9d4ce997b0 100644 --- a/tencentcloud/resource_tc_redis_instance_test.go +++ b/tencentcloud/resource_tc_redis_instance_test.go @@ -138,7 +138,6 @@ func init() { } func TestAccTencentCloudRedisInstance(t *testing.T) { - t.Parallel() resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, @@ -155,7 +154,7 @@ func TestAccTencentCloudRedisInstance(t *testing.T) { resource.TestCheckResourceAttr("tencentcloud_redis_instance.redis_instance_test", "redis_shard_num", "1"), resource.TestCheckResourceAttr("tencentcloud_redis_instance.redis_instance_test", "redis_replicas_num", "1"), resource.TestCheckResourceAttr("tencentcloud_redis_instance.redis_instance_test", "mem_size", "8192"), - resource.TestCheckResourceAttr("tencentcloud_redis_instance.redis_instance_test", "name", "terrform_test"), + resource.TestCheckResourceAttr("tencentcloud_redis_instance.redis_instance_test", "name", "terraform_test"), resource.TestCheckResourceAttr("tencentcloud_redis_instance.redis_instance_test", "project_id", "0"), resource.TestCheckResourceAttr("tencentcloud_redis_instance.redis_instance_test", "status", "online"), ), @@ -186,7 +185,7 @@ func TestAccTencentCloudRedisInstance(t *testing.T) { resource.TestCheckResourceAttr("tencentcloud_redis_instance.redis_instance_test", "redis_shard_num", "1"), resource.TestCheckResourceAttr("tencentcloud_redis_instance.redis_instance_test", "redis_replicas_num", "1"), resource.TestCheckResourceAttr("tencentcloud_redis_instance.redis_instance_test", "mem_size", "8192"), - resource.TestCheckResourceAttr("tencentcloud_redis_instance.redis_instance_test", "name", "terrform_test_update"), + resource.TestCheckResourceAttr("tencentcloud_redis_instance.redis_instance_test", "name", "terraform_test_update"), resource.TestCheckResourceAttr("tencentcloud_redis_instance.redis_instance_test", "project_id", "0"), resource.TestCheckResourceAttr("tencentcloud_redis_instance.redis_instance_test", "status", "online"), ), @@ -203,7 +202,7 @@ func TestAccTencentCloudRedisInstance(t *testing.T) { resource.TestCheckResourceAttr("tencentcloud_redis_instance.redis_instance_test", "redis_replicas_num", "1"), resource.TestCheckResourceAttr("tencentcloud_redis_instance.redis_instance_test", "type_id", "2"), resource.TestCheckResourceAttr("tencentcloud_redis_instance.redis_instance_test", "mem_size", "12288"), - resource.TestCheckResourceAttr("tencentcloud_redis_instance.redis_instance_test", "name", "terrform_test_update"), + resource.TestCheckResourceAttr("tencentcloud_redis_instance.redis_instance_test", "name", "terraform_test_update"), resource.TestCheckResourceAttr("tencentcloud_redis_instance.redis_instance_test", "project_id", "0"), resource.TestCheckResourceAttr("tencentcloud_redis_instance.redis_instance_test", "status", "online"), ), @@ -218,20 +217,61 @@ func TestAccTencentCloudRedisInstance(t *testing.T) { }) } -/* -func TestAccTencentCloudRedisInstance_Prepaid(t *testing.T) { - t.Parallel() +func TestAccTencentCloudRedisInstance_Maz(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testAccTencentCloudRedisInstanceDestroy, Steps: []resource.TestStep{ { - ResourceName: "tencentcloud_redis_instance.redis_instance_test", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"password", "type", "redis_shard_num", "redis_replicas_num", "force_delete"}, + Config: testAccRedisInstanceMaz(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccTencentCloudRedisInstanceExists("tencentcloud_redis_instance.redis_maz"), + resource.TestCheckResourceAttr("tencentcloud_redis_instance.redis_maz", "redis_replicas_num", "2"), + resource.TestCheckResourceAttr("tencentcloud_redis_instance.redis_maz", "replica_zone_ids.#", "2"), + ), + }, + { + Config: testAccRedisInstanceMazUpdate(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccTencentCloudRedisInstanceExists("tencentcloud_redis_instance.redis_maz"), + resource.TestCheckResourceAttr("tencentcloud_redis_instance.redis_maz", "mem_size", "8192"), + resource.TestCheckResourceAttr("tencentcloud_redis_instance.redis_maz", "redis_replicas_num", "3"), + resource.TestCheckResourceAttr("tencentcloud_redis_instance.redis_maz", "replica_zone_ids.#", "3"), + ), + }, + { + Config: testAccRedisInstanceMazUpdate2(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccTencentCloudRedisInstanceExists("tencentcloud_redis_instance.redis_maz"), + resource.TestCheckResourceAttr("tencentcloud_redis_instance.redis_maz", "redis_replicas_num", "4"), + resource.TestCheckResourceAttr("tencentcloud_redis_instance.redis_maz", "replica_zone_ids.#", "4"), + ), + }, + { + Destroy: false, + ResourceName: "tencentcloud_redis_instance.redis_maz", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "password", + "type", + "redis_shard_num", + "force_delete", + "replica_zone_ids.2", // sequence of ids proceeded + "replica_zone_ids.3", // sequence of ids proceeded + }, }, + }, + }) +} + +func TestAccTencentCloudRedisInstance_Prepaid(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheckCommon(t, ACCOUNT_TYPE_PREPAY) }, + Providers: testAccProviders, + CheckDestroy: testAccTencentCloudRedisInstanceDestroy, + Steps: []resource.TestStep{ { Config: testAccRedisInstancePrepaidBasic(), Check: resource.ComposeAggregateTestCheckFunc( @@ -243,16 +283,21 @@ func TestAccTencentCloudRedisInstance_Prepaid(t *testing.T) { resource.TestCheckResourceAttr("tencentcloud_redis_instance.redis_prepaid_instance_test", "redis_shard_num", "1"), resource.TestCheckResourceAttr("tencentcloud_redis_instance.redis_prepaid_instance_test", "redis_replicas_num", "1"), resource.TestCheckResourceAttr("tencentcloud_redis_instance.redis_prepaid_instance_test", "mem_size", "8192"), - resource.TestCheckResourceAttr("tencentcloud_redis_instance.redis_prepaid_instance_test", "name", "terrform_prepaid_test"), + resource.TestCheckResourceAttr("tencentcloud_redis_instance.redis_prepaid_instance_test", "name", "terraform_prepaid_test"), resource.TestCheckResourceAttr("tencentcloud_redis_instance.redis_prepaid_instance_test", "project_id", "0"), resource.TestCheckResourceAttr("tencentcloud_redis_instance.redis_prepaid_instance_test", "status", "online"), resource.TestCheckResourceAttr("tencentcloud_redis_instance.redis_prepaid_instance_test", "charge_type", "PREPAID"), ), }, + { + ResourceName: "tencentcloud_redis_instance.redis_instance_test", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"password", "type", "redis_shard_num", "redis_replicas_num", "force_delete"}, + }, }, }) } -*/ func testAccTencentCloudRedisInstanceExists(r string) resource.TestCheckFunc { return func(s *terraform.State) error { @@ -313,7 +358,7 @@ resource "tencentcloud_redis_instance" "redis_instance_test" { type_id = 2 password = "test12345789" mem_size = 8192 - name = "terrform_test" + name = "terraform_test" port = 6379 redis_shard_num = 1 redis_replicas_num = 1 @@ -327,7 +372,7 @@ resource "tencentcloud_redis_instance" "redis_instance_test" { type_id = 2 password = "test12345789" mem_size = 8192 - name = "terrform_test" + name = "terraform_test" port = 6379 redis_shard_num = 1 redis_replicas_num = 1 @@ -345,7 +390,7 @@ resource "tencentcloud_redis_instance" "redis_instance_test" { type_id = 2 password = "test12345789" mem_size = 8192 - name = "terrform_test" + name = "terraform_test" port = 6379 redis_shard_num = 1 redis_replicas_num = 1 @@ -363,7 +408,7 @@ resource "tencentcloud_redis_instance" "redis_instance_test" { type_id = 2 password = "test12345789" mem_size = 8192 - name = "terrform_test_update" + name = "terraform_test_update" port = 6379 redis_shard_num = 1 redis_replicas_num = 1 @@ -381,7 +426,7 @@ resource "tencentcloud_redis_instance" "redis_instance_test" { type_id = 2 password = "AAA123456BBB" mem_size = 12288 - name = "terrform_test_update" + name = "terraform_test_update" port = 6379 redis_shard_num = 1 redis_replicas_num = 1 @@ -392,6 +437,57 @@ resource "tencentcloud_redis_instance" "redis_instance_test" { }` } +func testAccRedisInstanceMaz() string { + return defaultVpcVariable + ` +resource "tencentcloud_redis_instance" "redis_maz" { + availability_zone = "ap-guangzhou-3" + type_id = 6 #7 + password = "AAA123456BBB" + mem_size = 4096 + name = "terraform_maz" + port = 6379 + redis_shard_num = 1 + redis_replicas_num = 2 + replica_zone_ids = [100003, 100004] + vpc_id = var.vpc_id + subnet_id = var.subnet_id +}` +} + +func testAccRedisInstanceMazUpdate() string { + return defaultVpcVariable + ` +resource "tencentcloud_redis_instance" "redis_maz" { + availability_zone = "ap-guangzhou-3" + type_id = 6 #7 + password = "AAA123456BBB" + mem_size = 8192 + name = "terraform_maz" + port = 6379 + redis_shard_num = 1 + redis_replicas_num = 3 + replica_zone_ids = [100003, 100004, 100003] + vpc_id = var.vpc_id + subnet_id = var.subnet_id +}` +} + +func testAccRedisInstanceMazUpdate2() string { + return defaultVpcVariable + ` +resource "tencentcloud_redis_instance" "redis_maz" { + availability_zone = "ap-guangzhou-3" + type_id = 6 #7 + password = "AAA123456BBB" + mem_size = 8192 + name = "terraform_maz" + port = 6379 + redis_shard_num = 1 + redis_replicas_num = 4 + replica_zone_ids = [100003, 100004, 100006, 100003] + vpc_id = var.vpc_id + subnet_id = var.subnet_id +}` +} + func testAccRedisInstancePrepaidBasic() string { return ` resource "tencentcloud_redis_instance" "redis_prepaid_instance_test" { @@ -399,7 +495,7 @@ resource "tencentcloud_redis_instance" "redis_prepaid_instance_test" { type_id = 2 password = "test12345789" mem_size = 8192 - name = "terrform_prepaid_test" + name = "terraform_prepaid_test" port = 6379 redis_shard_num = 1 redis_replicas_num = 1 diff --git a/tencentcloud/service_tencentcloud_redis.go b/tencentcloud/service_tencentcloud_redis.go index e67dea366f..69716023f5 100644 --- a/tencentcloud/service_tencentcloud_redis.go +++ b/tencentcloud/service_tencentcloud_redis.go @@ -743,17 +743,23 @@ func (me *RedisService) CleanUpInstance(ctx context.Context, redisId string) (ta return } -func (me *RedisService) UpgradeInstance(ctx context.Context, redisId string, newMemSize int64, redisShardNum int64, redisReplicasNum int64) (dealId string, errRet error) { +func (me *RedisService) UpgradeInstance(ctx context.Context, redisId string, newMemSize, redisShardNum, redisReplicasNum int, nodeSet []*redis.RedisNodeInfo) (dealId string, errRet error) { logId := getLogId(ctx) - var uintNewMemSize = uint64(newMemSize) - var uintRedisReplicas = uint64(redisReplicasNum) - var uintRedisShardNum = uint64(redisShardNum) request := redis.NewUpgradeInstanceRequest() request.InstanceId = &redisId - request.MemSize = &uintNewMemSize - request.RedisReplicasNum = &uintRedisReplicas - request.RedisShardNum = &uintRedisShardNum + if newMemSize > 0 { + request.MemSize = helper.IntUint64(newMemSize) + } + if redisShardNum > 0 { + request.RedisShardNum = helper.IntUint64(redisShardNum) + } + if redisReplicasNum != 0 { + request.RedisReplicasNum = helper.IntUint64(redisReplicasNum) + } + if len(nodeSet) > 0 { + request.NodeSet = nodeSet + } defer func() { if errRet != nil { diff --git a/website/docs/r/redis_instance.html.markdown b/website/docs/r/redis_instance.html.markdown index d9a3713df0..1814ebee34 100644 --- a/website/docs/r/redis_instance.html.markdown +++ b/website/docs/r/redis_instance.html.markdown @@ -78,9 +78,9 @@ The following arguments are supported: * `port` - (Optional, ForceNew) The port used to access a redis instance. The default value is 6379. And this value can't be changed after creation, or the Redis instance will be recreated. * `prepaid_period` - (Optional) The tenancy (time unit is month) of the prepaid instance, NOTE: it only works when charge_type is set to `PREPAID`. Valid values are `1`, `2`, `3`, `4`, `5`, `6`, `7`, `8`, `9`, `10`, `11`, `12`, `24`, `36`. * `project_id` - (Optional) Specifies which project the instance should belong to. -* `redis_replicas_num` - (Optional, ForceNew) The number of instance copies. This is not required for standalone and master slave versions. +* `redis_replicas_num` - (Optional) The number of instance copies. This is not required for standalone and master slave versions. * `redis_shard_num` - (Optional, ForceNew) The number of instance shard. This is not required for standalone and master slave versions. -* `replica_zone_ids` - (Optional, ForceNew) ID of replica nodes available zone. This is not required for standalone and master slave versions. +* `replica_zone_ids` - (Optional) ID of replica nodes available zone. This is not required for standalone and master slave versions. * `replicas_read_only` - (Optional, ForceNew) Whether copy read-only is supported, Redis 2.8 Standard Edition and CKV Standard Edition do not support replica read-only, turn on replica read-only, the instance will automatically read and write separate, write requests are routed to the primary node, read requests are routed to the replica node, if you need to open replica read-only, the recommended number of replicas >=2. * `security_groups` - (Optional, ForceNew) ID of security group. If both vpc_id and subnet_id are not set, this argument should not be set either. * `subnet_id` - (Optional, ForceNew) Specifies which subnet the instance should belong to. From d81f22435f2880fd9fc8324970085da00d448ead Mon Sep 17 00:00:00 2001 From: Kagashino Date: Sun, 24 Apr 2022 19:35:50 +0800 Subject: [PATCH 2/2] fix: redis prepaid testcase --- tencentcloud/resource_tc_redis_instance_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tencentcloud/resource_tc_redis_instance_test.go b/tencentcloud/resource_tc_redis_instance_test.go index 9d4ce997b0..b654cb45bf 100644 --- a/tencentcloud/resource_tc_redis_instance_test.go +++ b/tencentcloud/resource_tc_redis_instance_test.go @@ -290,10 +290,10 @@ func TestAccTencentCloudRedisInstance_Prepaid(t *testing.T) { ), }, { - ResourceName: "tencentcloud_redis_instance.redis_instance_test", + ResourceName: "tencentcloud_redis_instance.redis_prepaid_instance_test", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"password", "type", "redis_shard_num", "redis_replicas_num", "force_delete"}, + ImportStateVerifyIgnore: []string{"password", "type", "redis_shard_num", "redis_replicas_num", "force_delete", "prepaid_period"}, }, }, })