SCF-830: Added state management for cluster hibernation - #17
Conversation
Coverage Report for CI Build 29651611343Warning No base build found for commit Coverage: 44.986%Details
Uncovered Changes
Coverage RegressionsRequires a base build to compare against. How to fix this → Coverage Stats
💛 - Coveralls |
serdardalgic
left a comment
There was a problem hiding this comment.
Some minor issues @adshin21. After that, I would like to review it again.
| if c.Statefulset == nil || c.Statefulset.Spec.Replicas == nil { | ||
| return nil | ||
| } | ||
| return c.Statefulset.Spec.Replicas |
There was a problem hiding this comment.
| return c.Statefulset.Spec.Replicas | |
| return c.Statefulset.Status.Replicas |
Shouldn't this be Status as you want to get the current replica count of the StatefulSet?
There was a problem hiding this comment.
Yes, but to get the current status, we need to make an API call to k8s.
| const ( | ||
| LifecycleActionNone LifecycleAction = iota | ||
| LifecycleActionHibernate // Running -> Stopping (initiate hibernate) | ||
| LifecycleActionStoppingCompleted // Stopping -> Stopped (pods fully terminated) |
There was a problem hiding this comment.
Are you using LifecycleActionStoppingCompleted ? If not, please remove it.
…sist lifecycle spec changes in Sync
serdardalgic
left a comment
There was a problem hiding this comment.
So, some stuff that caught my attention, here it is.
|
|
||
|
|
There was a problem hiding this comment.
This is also a mistake, I guess.
Replace the four-line flag-juggling (isWakingUpSimple / hasPreviousInstances / needsRestore) with a wantsStopped flag plus three self-documenting guards. This removes the latent bug where the inner isWakingUp check was being dropped (Stopped + phase=stopped incorrectly returned WakeUp).
…enum Introduce LifecyclePhase string type with LifecyclePhaseStopped constant and Phase.Stopped() helper; the CRD enum accepts "" or "stopped" via +kubebuilder:validation:Enum="";stopped. Tighten blockLifecycleUpdate error message and cluster_manifest.md wake-up text to mention setting lifecycle.phase to an empty string. Generate DeepCopy for PostgresStatus.PreviousPoolerInstances and use it in Postgresql.DeepCopyInto so the operator's in-memory cache does not share map state with the cluster object.
Tighten the second wake-up guard in detectLifecycleTransition to require PreviousNumberOfInstances > 0. Without a stored replica count, transitioning to Updating with 0 replicas leaves the cluster stuck indefinitely: the sync defer skips Running when oldSpec had 0 instances, and the next periodic Sync sees the same dead-end state. The "Stopped + cleared + no previous instances" test case is renamed and updated to expect LifecycleActionNone, since the previous behavior was a recovery attempt on a corrupted state that produced a worse outcome than the cluster staying in Stopped. Update initiateWakeUp's doc comment to note that the PreviousNumberOfInstances == 0 branch is now unreachable in practice (detect refuses the transition upstream).
* Rewrite the misleading comment in syncStateLocked's defer. The old
wording claimed oldSpec.Spec.NumberOfInstances == 0 during wake-up
because initiateWakeUp hadn't run yet; the real reason is that
c.Postgresql was already hibernated when the reconcile started.
* Skip 0-replica entries in scalePoolerDown's stored map. A pooler
already at 0 has nothing to restore on wake-up; storing it produced
a spurious no-op patch on the way up. Update the corresponding test
case to expect nil instead of {"master": 0}.
* Document the PreviousNumberOfInstances == 0 limitation in
cluster_manifest.md: the operator will not transition out of
Stopped if the field is missing (e.g. due to a partial write or a
manual edit); the user must edit spec.numberOfInstances to wake
the cluster up manually.
…dates Fix bug encountered in e2e tests: user annotations (e.g. last-major-upgrade-failure) were silently dropped when a watch event arrived mid-lifecycle, causing the v16->v18 major version upgrade to proceed despite the failure annotation.
7f48801 to
c378463
Compare
| // - (true, nil) if update is blocked and caller should return early | ||
| // - (false, nil) if update can proceed | ||
| // - (false, error) on error | ||
| func (c *Cluster) blockLifecycleUpdate(newSpec *acidv1.Postgresql) (bool, error) { |
There was a problem hiding this comment.
This function basically doesn't block anything, the name is a bit misleading.
Shouldn't it be better to name it something like shouldBlockLifecycleUpdate or isLifecycleUpdateBlocked ?
|
|
||
|
|
No description provided.