Skip to content

Commit 94b238d

Browse files
authored
fix: redis support maz modified (#979)
* fix: redis support maz modified * fix: redis prepaid testcase
1 parent 93e4f16 commit 94b238d

File tree

7 files changed

+405
-48
lines changed

7 files changed

+405
-48
lines changed

tencentcloud/commom_test.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ package tencentcloud
22

33
import (
44
"testing"
5+
6+
sdkErrors "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
7+
8+
"github.com/stretchr/testify/assert"
59
)
610

711
func TestIsContains(t *testing.T) {
@@ -71,3 +75,53 @@ func TestIsContains(t *testing.T) {
7175
}
7276
}
7377
}
78+
79+
func TestGetListIncrement(t *testing.T) {
80+
var (
81+
old1 = []int{1, 2, 2, 3, 5}
82+
new1 = []int{1, 2, 3, 2, 4, 5, 6, 3}
83+
expected1 = []int{4, 6, 3}
84+
)
85+
actual1, _ := GetListIncrement(old1, new1)
86+
assert.Equalf(t, expected1, actual1, "incr1 should equal, got %v %v", expected1, actual1)
87+
88+
var (
89+
old2 = []int{1, 2, 4, 5}
90+
new2 = []int{1, 2, 3, 2, 4, 5, 6, 3}
91+
expected2 = []int{3, 2, 6, 3}
92+
)
93+
actual2, _ := GetListIncrement(old2, new2)
94+
assert.Equalf(t, expected2, actual2, "incr1 should equal, got %v %v", expected2, actual2)
95+
96+
var (
97+
old3 = []int{1, 2, 4, 5, 3, 6, 3, 2}
98+
new3 = []int{1, 2, 3, 2, 4, 5, 6, 3}
99+
expected3 = make([]int, 0)
100+
)
101+
actual3, _ := GetListIncrement(old3, new3)
102+
assert.Equalf(t, expected3, actual3, "incr1 should equal, got %v %v", expected3, actual3)
103+
104+
var (
105+
old4 = []int{1}
106+
new4 = []int{2}
107+
)
108+
109+
_, err := GetListIncrement(old4, new4)
110+
assert.EqualError(t, err, "elem 1 not exist")
111+
112+
}
113+
114+
func TestIsExpectError(t *testing.T) {
115+
116+
err := sdkErrors.NewTencentCloudSDKError("ClientError.NetworkError", "", "")
117+
118+
expectedFull := []string{"ClientError.NetworkError"}
119+
expectedShort := []string{"ClientError"}
120+
unExpectedMatchHead := []string{"ClientError.HttpStatusCodeError"}
121+
unExpectedShort := []string{"SystemError"}
122+
123+
assert.Equalf(t, isExpectError(err, expectedFull), true, "")
124+
assert.Equalf(t, isExpectError(err, expectedShort), true, "")
125+
assert.Equalf(t, isExpectError(err, unExpectedMatchHead), false, "")
126+
assert.Equalf(t, isExpectError(err, unExpectedShort), false, "")
127+
}

tencentcloud/common.go

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ func retryError(err error, additionRetryableError ...string) *resource.RetryErro
147147
return resource.NonRetryableError(err)
148148
}
149149

150-
// isExpectError returns whether error is expect error
150+
// isExpectError returns whether error is expected error
151151
func isExpectError(err error, expectError []string) bool {
152152
e, ok := err.(*sdkErrors.TencentCloudSDKError)
153153
if !ok {
@@ -276,3 +276,33 @@ func IsContains(array interface{}, value interface{}) bool {
276276
return reflect.DeepEqual(array, value)
277277
}
278278
}
279+
280+
func FindIntListIndex(list []int, elem int) int {
281+
for i, v := range list {
282+
if v == elem {
283+
return i
284+
}
285+
}
286+
return -1
287+
}
288+
289+
func GetListIncrement(o []int, n []int) (result []int, err error) {
290+
result = append(result, n...)
291+
if len(o) > len(n) {
292+
err = fmt.Errorf("new list elem count %d less than old: %d", len(n), len(o))
293+
return
294+
}
295+
for _, v := range o {
296+
index := FindIntListIndex(result, v)
297+
if index == -1 {
298+
err = fmt.Errorf("elem %d not exist", v)
299+
return
300+
}
301+
if index+1 >= len(result) {
302+
result = result[:index]
303+
} else {
304+
result = append(result[:index], result[index+1:]...)
305+
}
306+
}
307+
return
308+
}

tencentcloud/internal/helper/transform.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,14 @@ func InterfacesStringsPoint(configured []interface{}) []*string {
7777
return vs
7878
}
7979

80+
func InterfacesIntegers(configured []interface{}) []int {
81+
vs := make([]int, 0, len(configured))
82+
for _, v := range configured {
83+
vs = append(vs, v.(int))
84+
}
85+
return vs
86+
}
87+
8088
func InterfacesIntInt64Point(configured []interface{}) []*int64 {
8189
vs := make([]*int64, 0, len(configured))
8290
for _, v := range configured {

tencentcloud/resource_tc_redis_instance.go

Lines changed: 182 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -124,14 +124,12 @@ func resourceTencentCloudRedisInstance() *schema.Resource {
124124
"redis_replicas_num": {
125125
Type: schema.TypeInt,
126126
Optional: true,
127-
ForceNew: true,
128127
Default: 1,
129128
Description: "The number of instance copies. This is not required for standalone and master slave versions.",
130129
},
131130
"replica_zone_ids": {
132131
Type: schema.TypeList,
133132
Optional: true,
134-
ForceNew: true,
135133
Description: "ID of replica nodes available zone. This is not required for standalone and master slave versions.",
136134
Elem: &schema.Schema{Type: schema.TypeInt},
137135
},
@@ -578,17 +576,25 @@ func resourceTencentCloudRedisInstanceRead(d *schema.ResourceData, meta interfac
578576
}
579577

580578
if info.NodeSet != nil {
581-
var zoneIds []uint64
579+
var zoneIds []int
582580
for i := range info.NodeSet {
583581
nodeInfo := info.NodeSet[i]
584582
if *nodeInfo.NodeType == 0 {
585583
continue
586584
}
587-
zoneIds = append(zoneIds, *nodeInfo.ZoneId)
585+
zoneIds = append(zoneIds, int(*nodeInfo.ZoneId))
586+
}
587+
588+
var zoneIdsEqual = false
589+
590+
raw, ok := d.GetOk("replica_zone_ids")
591+
if ok {
592+
oldIds := helper.InterfacesIntegers(raw.([]interface{}))
593+
zoneIdsEqual = checkZoneIdsEqual(oldIds, zoneIds)
588594
}
589595

590-
if err := d.Set("replica_zone_ids", zoneIds); err != nil {
591-
log.Printf("[WARN] replica_zone_ids set error: %s", err.Error())
596+
if !zoneIdsEqual {
597+
_ = d.Set("replica_zone_ids", zoneIds)
592598
}
593599
}
594600

@@ -643,28 +649,29 @@ func resourceTencentCloudRedisInstanceUpdate(d *schema.ResourceData, meta interf
643649
d.SetPartial("name")
644650
}
645651

652+
// MemSize, ShardNum and ReplicaNum can only change one for each upgrade invoke
646653
if d.HasChange("mem_size") {
647654

648655
_, newInter := d.GetChange("mem_size")
649656
newMemSize := newInter.(int)
650-
//oldMemSize := oldInter.(int)
651-
652-
//if oldMemSize >= newMemSize {
653-
// return fmt.Errorf("redis mem_size can only increase")
654-
//}
657+
oShard, _ := d.GetChange("redis_shard_num")
658+
redisShardNum := oShard.(int)
659+
oReplica, _ := d.GetChange("redis_replicas_num")
660+
redisReplicasNum := oReplica.(int)
655661

656662
if newMemSize < 1 {
657663
return fmt.Errorf("redis mem_size value cannot be set to less than 1")
658664
}
659-
redisShardNum := d.Get("redis_shard_num").(int)
660-
redisReplicasNum := d.Get("redis_replicas_num").(int)
661-
_, err := redisService.UpgradeInstance(ctx, id, int64(newMemSize), int64(redisShardNum), int64(redisReplicasNum))
665+
666+
_, err := redisService.UpgradeInstance(ctx, id, newMemSize, redisShardNum, redisReplicasNum, nil)
662667

663668
if err != nil {
664-
log.Printf("[CRITAL]%s redis update mem size error, reason:%s\n", logId, err.Error())
669+
log.Printf("[CRITAL]%s redis upgrade instance error, reason:%s\n", logId, err.Error())
665670
return err
666671
}
667672

673+
startUpdate := false
674+
668675
err = resource.Retry(4*readRetryTimeout, func() *resource.RetryError {
669676
_, _, info, err := redisService.CheckRedisOnlineOk(ctx, id)
670677

@@ -673,12 +680,17 @@ func resourceTencentCloudRedisInstanceUpdate(d *schema.ResourceData, meta interf
673680
if status == "" {
674681
return resource.NonRetryableError(fmt.Errorf("after update redis mem size, redis status is unknown ,status=%d", *info.Status))
675682
}
676-
if *info.Status == REDIS_STATUS_PROCESSING || *info.Status == REDIS_STATUS_INIT {
677-
return resource.RetryableError(fmt.Errorf("redis update processing."))
683+
if *info.Status == REDIS_STATUS_ONLINE && !startUpdate {
684+
return resource.RetryableError(fmt.Errorf("waiting for status change to proccessing"))
678685
}
679-
if *info.Status == REDIS_STATUS_ONLINE {
686+
if *info.Status == REDIS_STATUS_ONLINE && startUpdate {
680687
return nil
681688
}
689+
startUpdate = true
690+
691+
if *info.Status == REDIS_STATUS_PROCESSING || *info.Status == REDIS_STATUS_INIT {
692+
return resource.RetryableError(fmt.Errorf("redis update processing."))
693+
}
682694
return resource.NonRetryableError(fmt.Errorf("after update redis mem size, redis status is %s", status))
683695
}
684696

@@ -696,8 +708,143 @@ func resourceTencentCloudRedisInstanceUpdate(d *schema.ResourceData, meta interf
696708
log.Printf("[CRITAL]%s redis update mem size fail , reason:%s\n", logId, err.Error())
697709
return err
698710
}
711+
}
712+
713+
// MemSize, ShardNum and ReplicaNum can only change one for each upgrade invoke
714+
if d.HasChange("redis_shard_num") {
715+
redisShardNum := d.Get("redis_shard_num").(int)
716+
oReplica, _ := d.GetChange("redis_replicas_num")
717+
redisReplicasNum := oReplica.(int)
718+
memSize := d.Get("mem_size").(int)
719+
err := resource.Retry(writeRetryTimeout, func() *resource.RetryError {
720+
_, err := redisService.UpgradeInstance(ctx, id, memSize, redisShardNum, redisReplicasNum, nil)
721+
if err != nil {
722+
// Upgrade memory will cause instance lock and cannot acknowledge by polling status, wait until lock release
723+
return retryError(err, redis.FAILEDOPERATION_UNKNOWN, redis.FAILEDOPERATION_SYSTEMERROR)
724+
}
725+
return nil
726+
})
727+
728+
if err != nil {
729+
log.Printf("[CRITAL]%s redis upgrade instance error, reason:%s\n", logId, err.Error())
730+
return err
731+
}
732+
733+
startUpdate := false
734+
735+
err = resource.Retry(4*readRetryTimeout, func() *resource.RetryError {
736+
_, _, info, err := redisService.CheckRedisOnlineOk(ctx, id)
737+
738+
if info != nil {
739+
status := REDIS_STATUS[*info.Status]
740+
if status == "" {
741+
return resource.NonRetryableError(fmt.Errorf("after update redis shard num, redis status is unknown ,status=%d", *info.Status))
742+
}
743+
if *info.Status == REDIS_STATUS_ONLINE && !startUpdate {
744+
return resource.RetryableError(fmt.Errorf("waiting for status change to proccessing"))
745+
}
746+
if *info.Status == REDIS_STATUS_ONLINE && startUpdate {
747+
return nil
748+
}
749+
startUpdate = true
750+
751+
if *info.Status == REDIS_STATUS_PROCESSING || *info.Status == REDIS_STATUS_INIT {
752+
return resource.RetryableError(fmt.Errorf("redis update processing."))
753+
}
754+
return resource.NonRetryableError(fmt.Errorf("after update redis shard num, redis status is %s", status))
755+
}
756+
757+
if err != nil {
758+
if _, ok := err.(*sdkErrors.TencentCloudSDKError); !ok {
759+
return resource.RetryableError(err)
760+
} else {
761+
return resource.NonRetryableError(err)
762+
}
763+
}
764+
return resource.NonRetryableError(fmt.Errorf("after update redis shard num, redis disappear"))
765+
})
766+
767+
if err != nil {
768+
log.Printf("[CRITAL]%s redis update shard num fail , reason:%s\n", logId, err.Error())
769+
return err
770+
}
771+
}
772+
773+
// MemSize, ShardNum and ReplicaNum can only change one for each upgrade invoke
774+
if d.HasChange("redis_replicas_num") || d.HasChange("replica_zone_ids") {
775+
//availabilityZone := d.Get("availability_zone").(string)
776+
o, n := d.GetChange("replica_zone_ids") // Only pass zone id increments
777+
ov := helper.InterfacesIntegers(o.([]interface{}))
778+
nv := helper.InterfacesIntegers(n.([]interface{}))
779+
zoneIds, err := GetListIncrement(ov, nv)
780+
781+
if err != nil {
782+
return fmt.Errorf("get diff replica error: %s", err.Error())
783+
}
784+
785+
var nodeInfo []*redis.RedisNodeInfo
786+
787+
for _, id := range zoneIds {
788+
nodeInfo = append(nodeInfo, &redis.RedisNodeInfo{
789+
NodeType: helper.Int64(1),
790+
ZoneId: helper.IntUint64(id),
791+
})
792+
}
793+
redisReplicasNum := d.Get("redis_replicas_num").(int)
794+
memSize := d.Get("mem_size").(int)
795+
redisShardNum := d.Get("redis_shard_num").(int)
796+
err = resource.Retry(writeRetryTimeout, func() *resource.RetryError {
797+
_, err = redisService.UpgradeInstance(ctx, id, memSize, redisShardNum, redisReplicasNum, nodeInfo)
798+
if err != nil {
799+
// Upgrade memory will cause instance lock and cannot acknowledge by polling status, wait until lock release
800+
return retryError(err, redis.FAILEDOPERATION_UNKNOWN, redis.FAILEDOPERATION_SYSTEMERROR)
801+
}
802+
return nil
803+
})
804+
805+
if err != nil {
806+
return err
807+
}
808+
809+
err = resource.Retry(4*readRetryTimeout, func() *resource.RetryError {
810+
_, _, info, err := redisService.CheckRedisOnlineOk(ctx, id)
811+
812+
if info != nil {
813+
status := REDIS_STATUS[*info.Status]
814+
if status == "" {
815+
return resource.NonRetryableError(fmt.Errorf("after update redis replicas, redis status is unknown ,status=%d", *info.Status))
816+
}
817+
actualNodeCount := len(info.NodeSet)
818+
expectedNodeCount := len(nv) + 1
819+
// wait until node set as expected or will cause status inconsistent
820+
if *info.Status == REDIS_STATUS_ONLINE && actualNodeCount != expectedNodeCount {
821+
return resource.RetryableError(fmt.Errorf("waiting for status change to proccessing"))
822+
}
823+
if *info.Status == REDIS_STATUS_ONLINE && actualNodeCount == expectedNodeCount {
824+
return nil
825+
}
826+
if *info.Status == REDIS_STATUS_PROCESSING || *info.Status == REDIS_STATUS_INIT {
827+
return resource.RetryableError(fmt.Errorf("redis update processing."))
828+
}
829+
830+
return resource.NonRetryableError(fmt.Errorf("after update redis replicas, redis status is %s", status))
831+
}
832+
833+
if err != nil {
834+
if _, ok := err.(*sdkErrors.TencentCloudSDKError); !ok {
835+
return resource.RetryableError(err)
836+
} else {
837+
return resource.NonRetryableError(err)
838+
}
839+
}
840+
return resource.NonRetryableError(fmt.Errorf("after update redis replicas, redis disappear"))
841+
})
842+
843+
if err != nil {
844+
log.Printf("[CRITAL]%s redis update replicas fail , reason:%s\n", logId, err.Error())
845+
return err
846+
}
699847

700-
d.SetPartial("mem_size")
701848
}
702849

703850
if d.HasChange("password") {
@@ -880,3 +1027,19 @@ func resourceTencentCloudRedisInstanceDelete(d *schema.ResourceData, meta interf
8801027
return nil
8811028
}
8821029
}
1030+
1031+
func checkZoneIdsEqual(o []int, n []int) bool {
1032+
if len(o) != len(n) {
1033+
return false
1034+
}
1035+
1036+
sort.Ints(o)
1037+
sort.Ints(n)
1038+
1039+
for i, v := range o {
1040+
if v != n[i] {
1041+
return false
1042+
}
1043+
}
1044+
return true
1045+
}

0 commit comments

Comments
 (0)