Skip to content

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:

execution:
  strategy:
    type: Sequential

Targets execute one at a time, in declaration order.

execution:
  strategy:
    type: Parallel
    maxConcurrency: 3

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:

spec:
  suspend: true   # Stops all operations; running jobs complete naturally

Set back to false to resume.

See Also