@@ -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