@@ -15,11 +15,14 @@ package replication_group
1515
1616import (
1717 "context"
18+ "encoding/json"
1819 "fmt"
1920 "github.com/aws-controllers-k8s/runtime/pkg/requeue"
2021 "github.com/aws/aws-sdk-go/aws/awserr"
2122 "github.com/pkg/errors"
23+ "reflect"
2224 "sort"
25+ "strconv"
2326
2427 svcapitypes "github.com/aws-controllers-k8s/elasticache-controller/apis/v1alpha1"
2528 ackcompare "github.com/aws-controllers-k8s/runtime/pkg/compare"
@@ -70,6 +73,28 @@ func (rm *resourceManager) CustomModifyReplicationGroup(
7073 requeue .DefaultRequeueAfterDuration )
7174 }
7275
76+ // Handle the asynchronous rollback case for while Scaling down.
77+ // This means that we have already attempted to apply the CacheNodeType once and
78+ // were not successful hence we will set a terminal condition.
79+ if ! cacheNodeTypeRequiresUpdate (desired ) && delta .DifferentAt ("Spec.CacheNodeType" ) {
80+ return nil , awserr .New ("InvalidParameterCombination" , "Cannot update CacheNodeType, " +
81+ "Please refer to Events for more details" , nil )
82+
83+ }
84+
85+ // Handle the asynchronous rollback for Resharding.
86+ if ! nodeGroupRequiresUpdate (desired ) && rm .shardConfigurationsDiffer (desired , latest ) {
87+
88+ return nil , awserr .New ("InvalidParameterCombination" , "Cannot update NodeGroups, " +
89+ "Please refer to Events for more details" , nil )
90+ }
91+
92+ // Handle NodeGroupConfiguration asynchronous rollback situations other than Resharding.
93+ if ! nodeGroupRequiresUpdate (desired ) && (rm .replicaCountDifference (desired , latest ) != 0 && ! delta .DifferentAt ("Spec.ReplicasPerNodeGroup" )) {
94+ return nil , awserr .New ("InvalidParameterCombination" , "Cannot update NodeGroupConfiguration, " +
95+ "Please refer to Events for more details" , nil )
96+ }
97+
7398 // Order of operations when diffs map to multiple updates APIs:
7499 // 1. When automaticFailoverEnabled differs:
75100 // if automaticFailoverEnabled == false; do nothing in this custom logic, let the modify execute first.
@@ -316,7 +341,18 @@ func (rm *resourceManager) updateShardConfiguration(
316341 rm .log .V (1 ).Info ("Error during ModifyReplicationGroupShardConfiguration" , "error" , respErr )
317342 return nil , respErr
318343 }
319- return rm .setReplicationGroupOutput (desired , resp .ReplicationGroup )
344+
345+ r , err := rm .setReplicationGroupOutput (desired , resp .ReplicationGroup )
346+
347+ if err != nil {
348+ return r , err
349+ }
350+
351+ ko := r .ko .DeepCopy ()
352+ // Update the annotations since API call was successful
353+ rm .setLastRequestedNodeGroupConfiguration (desired , ko )
354+ rm .setLastRequestedNumNodeGroups (desired , ko )
355+ return & resource {ko }, nil
320356}
321357
322358// newIncreaseReplicaCountRequestPayload returns an SDK-specific struct for the HTTP request
@@ -691,3 +727,45 @@ func (rm *resourceManager) newModifyReplicationGroupRequestPayload(
691727
692728 return input
693729}
730+
731+ // cacheNodeTypeRequiresUpdate retrieves the last requested cacheNodeType saved in annotations and compares them
732+ // to the current desired cacheNodeType
733+ func cacheNodeTypeRequiresUpdate (desired * resource ) bool {
734+ annotations := desired .ko .ObjectMeta .GetAnnotations ()
735+ if val , ok := annotations [AnnotationLastRequestedCNT ]; ok && desired .ko .Spec .CacheNodeType != nil {
736+ return val != * desired .ko .Spec .CacheNodeType
737+ }
738+
739+ // This means there is delta and no value in annotation or in Spec
740+ return true
741+ }
742+
743+ // nodeGroupRequiresUpdate retrieves the last applied NumNodeGroups and NodeGroupConfiguration and compares them
744+ // to the current desired NumNodeGroups and NodeGroupConfiguration
745+ func nodeGroupRequiresUpdate (desired * resource ) bool {
746+ annotations := desired .ko .ObjectMeta .GetAnnotations ()
747+
748+ if val , ok := annotations [AnnotationLastRequestedNNG ]; ok && val != "null" {
749+ numNodes , err := strconv .ParseInt (val , 10 , 64 )
750+
751+ if err != nil {
752+ return false
753+ }
754+
755+ if numNodes != * desired .ko .Spec .NumNodeGroups {
756+ return true
757+ }
758+
759+ return false
760+ }
761+
762+ desiredNodeGroupConfig := desired .ko .Spec .NodeGroupConfiguration
763+ if val , ok := annotations [AnnotationLastRequestedNGC ]; ok && val != "null" {
764+ var lastRequestedNodeGroupConfig []* svcapitypes.NodeGroupConfiguration
765+ _ = json .Unmarshal ([]byte (val ), & lastRequestedNodeGroupConfig )
766+ return ! reflect .DeepEqual (desiredNodeGroupConfig , lastRequestedNodeGroupConfig )
767+ }
768+
769+ // This means there is delta and no value in annotation or in Spec
770+ return true
771+ }
0 commit comments