@@ -54,6 +54,19 @@ func filterDelta(
5454 delta .Add ("Spec.LogDeliveryConfigurations" , desired .ko .Spec .LogDeliveryConfigurations ,
5555 unmarshalLastRequestedLDCs (desired ))
5656 }
57+
58+ if multiAZRequiresUpdate (desired , latest ) {
59+ delta .Add ("Spec.MultiAZEnabled" , desired .ko .Spec .MultiAZEnabled , latest .ko .Status .MultiAZ )
60+ }
61+
62+ if autoFailoverRequiresUpdate (desired , latest ) {
63+ delta .Add ("Spec.AutomaticFailoverEnabled" , desired .ko .Spec .AutomaticFailoverEnabled ,
64+ latest .ko .Status .AutomaticFailover )
65+ }
66+
67+ if updateRequired , current := primaryClusterIDRequiresUpdate (desired , latest ); updateRequired {
68+ delta .Add ("Spec.PrimaryClusterID" , desired .ko .Spec .PrimaryClusterID , * current )
69+ }
5770}
5871
5972// returns true if desired and latest engine versions match and false otherwise
@@ -100,3 +113,76 @@ func unmarshalLastRequestedLDCs(desired *resource) []*svcapitypes.LogDeliveryCon
100113
101114 return lastRequestedConfigs
102115}
116+
117+ // multiAZRequiresUpdate returns true if the latest multi AZ status does not yet match the
118+ // desired state, and false otherwise
119+ func multiAZRequiresUpdate (desired * resource , latest * resource ) bool {
120+ // no preference for multi AZ specified; no update required
121+ if desired .ko .Spec .MultiAZEnabled == nil {
122+ return false
123+ }
124+
125+ // API should return a non-nil value, but if it doesn't then attempt to update
126+ if latest .ko .Status .MultiAZ == nil {
127+ return true
128+ }
129+
130+ // true maps to "enabled"; false maps to "disabled"
131+ // this accounts for values such as "enabling" and "disabling"
132+ if * desired .ko .Spec .MultiAZEnabled {
133+ return * latest .ko .Status .MultiAZ != "enabled"
134+ } else {
135+ return * latest .ko .Status .MultiAZ != "disabled"
136+ }
137+ }
138+
139+ // autoFailoverRequiresUpdate returns true if the latest auto failover status does not yet match the
140+ // desired state, and false otherwise
141+ func autoFailoverRequiresUpdate (desired * resource , latest * resource ) bool {
142+ // the logic is exactly analogous to multiAZRequiresUpdate above
143+ if desired .ko .Spec .AutomaticFailoverEnabled == nil {
144+ return false
145+ }
146+
147+ if latest .ko .Status .AutomaticFailover == nil {
148+ return true
149+ }
150+
151+ if * desired .ko .Spec .AutomaticFailoverEnabled {
152+ return * latest .ko .Status .AutomaticFailover != "enabled"
153+ } else {
154+ return * latest .ko .Status .AutomaticFailover != "disabled"
155+ }
156+ }
157+
158+ // primaryClusterIDRequiresUpdate retrieves the current primary cluster ID and determines whether
159+ // an update is required. If no desired state is specified or there is an issue retrieving the
160+ // latest state, return false, nil. Otherwise, return false or true depending on equality of
161+ // the latest and desired states, and a non-nil pointer to the latest value
162+ func primaryClusterIDRequiresUpdate (desired * resource , latest * resource ) (bool , * string ) {
163+ if desired .ko .Spec .PrimaryClusterID == nil {
164+ return false , nil
165+ }
166+
167+ // primary cluster ID applies to cluster mode disabled only; if API returns multiple
168+ // or no node groups, or the provided node group is nil, there is nothing that can be done
169+ if len (latest .ko .Status .NodeGroups ) != 1 || latest .ko .Status .NodeGroups [0 ] == nil {
170+ return false , nil
171+ }
172+
173+ // attempt to find primary cluster in node group. If for some reason it is not present, we
174+ // don't have a reliable latest state, so do nothing
175+ ng := * latest .ko .Status .NodeGroups [0 ]
176+ for _ , member := range ng .NodeGroupMembers {
177+ if member == nil {
178+ continue
179+ }
180+
181+ if member .CurrentRole != nil && * member .CurrentRole == "primary" && member .CacheClusterID != nil {
182+ val := * member .CacheClusterID
183+ return val != * desired .ko .Spec .PrimaryClusterID , & val
184+ }
185+ }
186+
187+ return false , nil
188+ }
0 commit comments