HibernatePlan¶
The HibernatePlan is the primary Custom Resource Definition (CRD) in Hibernator. It declares the complete hibernation intent: what to hibernate, when, and how.
Lifecycle Phases¶
A HibernatePlan transitions through these phases:
Pending → Active → Hibernating → Hibernated → WakingUp → Active → ...
↕
Suspended
↘ Error (from any active phase)
| Phase | Description |
|---|---|
Pending |
Plan is created but not yet evaluated |
Active |
Plan is active, waiting for the next schedule window |
Hibernating |
Shutdown operation is in progress |
Hibernated |
All targets successfully hibernated |
WakingUp |
Wakeup operation is in progress |
Suspended |
Plan is manually suspended via spec.suspend: true |
Error |
An error occurred; may auto-retry based on configuration |
Schedule¶
Schedules use a human-friendly format with timezone awareness:
schedule:
timezone: "Asia/Jakarta"
offHours:
- start: "20:00" # HH:MM format (24-hour)
end: "06:00" # Next eligible day when end < start
daysOfWeek: ["MON", "TUE", "WED", "THU", "FRI"]
All executions — both hibernation and wakeup — are bounded to daysOfWeek. Wakeup only triggers on days listed in the schedule. For example, Friday 20:00 hibernation does not wake up Saturday 06:00; resources stay hibernated until Monday 06:00.
The controller applies a schedule buffer (default: 1 minute) and safety buffer (10 seconds) to every execution, so actual actions occur up to 1m 10s after the nominal schedule time. See Execution Timing for details.
Multiple Windows¶
You can define multiple off-hour windows that are evaluated with OR-logic:
schedule:
timezone: "US/Eastern"
offHours:
# Weeknight window
- start: "20:00"
end: "06:00"
daysOfWeek: ["MON", "TUE", "WED", "THU", "FRI"]
# Full weekend
- start: "00:00"
end: "23:59"
daysOfWeek: ["SAT", "SUN"]
Hibernation triggers when any window condition is met. The next event time is computed as the earliest across all windows.
Execution Strategies¶
The execution strategy determines the order in which targets are processed:
All targets execute simultaneously, bounded by maxConcurrency.
execution:
strategy:
type: DAG
maxConcurrency: 3
dependencies:
- from: karpenter-nodes
to: eks-nodegroups
- from: app-servers
to: database
Topological order based on explicit dependency edges. Cycles are detected and rejected at admission time.
execution:
strategy:
type: Staged
stages:
- name: frontend
parallel: true
targets: [web, api-gateway]
- name: backend
parallel: true
targets: [app-server, worker]
- name: data
parallel: false
targets: [cache, database]
Stages execute in order. Within each stage, targets can run in parallel or sequentially.
Behavior¶
Control how failures are handled:
behavior:
mode: Strict # Strict or BestEffort
failFast: true # Stop on first failure
retries: 3 # Max retry attempts (0-10)
| Mode | Description |
|---|---|
Strict |
Fail the entire plan if any target fails |
BestEffort |
Continue with remaining targets even if some fail |
Targets¶
Each target defines a resource to hibernate:
targets:
- name: my-database # Unique name within the plan
type: rds # Executor type
connectorRef:
kind: CloudProvider # CloudProvider or K8SCluster
name: aws-prod
parameters: # Executor-specific config
snapshotBeforeStop: true
Supported Target Types¶
| Type | Description | Connector Kind |
|---|---|---|
eks |
EKS managed node groups | CloudProvider |
karpenter |
Karpenter NodePools | K8SCluster |
rds |
RDS database instances | CloudProvider |
ec2 |
EC2 instances | CloudProvider |
workloadscaler |
Kubernetes workloads | K8SCluster |
Notifications¶
Hibernator can deliver real-time notifications when lifecycle events occur — execution starting, success, failure, recovery, and individual target progress.
Notifications are not configured inside a HibernatePlan. Instead, they are declared in a separate HibernateNotification custom resource and matched to plans using label selectors, the same pattern used by ScheduleException. A single HibernateNotification can target multiple plans, and a plan can match multiple notification resources simultaneously.
apiVersion: hibernator.ardikabs.com/v1alpha1
kind: HibernateNotification
metadata:
name: prod-alerts
namespace: hibernator-system
spec:
selector:
matchLabels:
env: production # matches any HibernatePlan with this label
onEvents:
- Start
- Success
- Failure
sinks:
- name: slack-team
type: slack
secretRef:
name: slack-webhook
The notification dispatcher runs asynchronously and never blocks or slows down the hibernation reconciliation loop.
Supported sink types: slack, telegram, webhook.
See User Guide: Notifications for full configuration, custom templates, and advanced options.
Control Intent Priority¶
When multiple control signals are applied simultaneously, the controller resolves them using a strict priority model. This prevents conflicting intents (e.g., hibernate vs. wakeup) from fighting each other.
Priority Hierarchy¶
Tier 1: Deletion (highest priority — always wins)
Tier 2: Suspension
Tier 3: Revert
Tier 4: Override
Tier 5: Restart (lowest priority among user intents)
Base: Schedule (default when no user intent is active)
| Tier | Trigger | Description |
|---|---|---|
| Deletion | kubectl delete or deletionTimestamp |
Immediate cleanup; no other intent can override |
| Suspension | spec.suspend=true |
Pauses all operations; auto-clears conflicting annotations |
| Revert | hibernator/revert=true |
Recovers from partial failure; only valid in PhaseError |
| Override | override-action=true + override-phase-target |
Manual phase control; suppresses schedule |
| Restart | restart=true |
One-shot re-execution of last operation |
| Schedule | Time-based evaluation | Default behavior when no user intent is active |
Coexistence Matrix¶
| Combination | Winner | Behavior |
|---|---|---|
| Deletion + anything | Deletion | Finalizer cleanup, plan removed |
| Suspension + user intent | Suspension | Auto-clear lower-priority annotations |
| Revert + Override/Restart | Revert | Revert proceeds; others ignored in Error |
| Override + Restart | Override | Override captures tick; may handle restart internally |
| Schedule + user intent | User intent | Schedule suppressed for that reconciliation |
OperationTrigger Field¶
The status.operationTrigger field tracks the origin of the current operation:
| Value | Meaning | Set By |
|---|---|---|
Schedule |
Time-based evaluation | Schedule evaluator |
Revert |
Revert annotation | revertState handler |
Retry |
Retry annotation or backoff | recoveryState handler |
Override |
Override annotation | overrideActionState handler |
Restart |
Restart annotation | restartState handler |
| (empty) | Stable state, no pending operation | After successful completion |
Preserved in stable states: Unlike operation state fields that clear immediately, OperationTrigger is preserved in PhaseActive and PhaseHibernated so you can always see what brought the plan to its current state. It is cleared when entering PhaseSuspended.
See User Guide: Override Actions and User Guide: Plan Suspension for operational details.
Cycle Intent Locking¶
Once a hibernation or wakeup cycle begins, the controller resolves the complete execution intent and stores it in .status.planSnapshot. This snapshot locks the effective targets, execution strategy, failure behavior, and any overrides for the lifetime of the cycle.
Intent locking guarantees that:
- A cycle runs with a consistent configuration from start to finish.
- Automatic retry, manual retry, resume-from-suspension, and restart all use the same locked intent.
- Changes made after a cycle starts do not affect that cycle.
Relevance to ScheduleException¶
ScheduleException resources are a primary source of variability in the execution intent. When a cycle starts while one or more exceptions are active, the controller composes the base plan and all active exceptions, applies any targetOverrides or executionOverride, and records the result in the snapshot. From that point onward, the cycle is decoupled from the exceptions that produced it. Editing or deleting an active ScheduleException does not change the behavior of an in-flight cycle.
To force the controller to re-evaluate exceptions and start a new cycle, use the restart or override-action annotations together with fresh=true. By default, those actions preserve the locked snapshot and re-run the same intent; adding fresh=true discards the locked snapshot and begins a fresh cycle against the current live plan and exception state. The fresh modifier is only relevant for hibernating intent — wakeup operations always continue with the existing locked snapshot because they depend on restore data captured during the original shutdown.
See the Override Actions user guide for the operational details of restart, override, and the fresh annotation.
Suspension¶
Temporarily disable a plan without deleting it:
Set back to false to resume.
See Also¶
- API Reference: HibernatePlan — Full field documentation
- User Guide: Hibernation Lifecycle — Step-by-step operations
- User Guide: Execution Strategies — Strategy deep dive
- User Guide: Notifications — Sink configuration, events, and custom templates