Skip to content

fix(operator): exclude conflicting backup, restore, wipe, sleep, and rollout operations #718

Closed

Description

@Baylem

Backup ownership currently coordinates quiesced backups with other quiesced backups. It does not provide shared exclusion against restart, idle sleep, template rollout, or newly created restore/wipe work. Extend lifecycle ownership to cover the source data and workload throughout a copy, including backups with quiesce=false.

Evidence comes from static inspection of master 04e41075cafc4c1a99bcb3723b0a8745ee810957; the interleavings below are source-derived scenarios, not runtime reproductions.

Triggers and impact

During a long quiesced backup, idle sleep or a restart can stop the source game. Its final save may modify files while Restic reads them. A template update can replace the pod with a fresh process that never received the original quiesce request. The backup may fail or lose the application-consistency guarantee.

Restore already checks existing pods and Jobs using the PVC. However, an unquiesced Backup can create a new reader after that check because it acquires no backup guard and does not honor restore ownership. That copy can capture a partially restored or wiped filesystem. Scanning current users cannot prevent another reconciler from creating work after the scan.

Pinned evidence

Recommended implementation

Create one durable lifecycle ownership record bound to the GameServer UID, operation UID, and operation generation. Use an uncached read plus resourceVersion compare-and-swap for acquisition. Start with exclusive ownership for backup/restore/wipe to keep the compatibility rules reviewable; add compatible reader modes only with explicit invariants.

Require all Backup variants to claim ownership before creating a Job or VolumeSnapshot. Restore and wipe must acquire the same record. Make idle transitions, restart commands, and pod-template rollout defer while a protected copy owns the target. Fence the StatefulSet mutation path so a reconcile computed before acquisition cannot scale or roll a writer afterward.

Persist completion/abort state before releasing ownership. Recover orphan owners by UID, cancel and drain their workers, and finish any quiesce cleanup before admitting another operation. A force-delete must not turn into permission to ignore live workers. Keep per-server serialization so independent servers remain concurrent.

Acceptance criteria

  • CI exercises backup versus restore, wipe, idle sleep, restart, and template rollout, with both quiesce settings.
  • A new Backup created after restore's initial user scan cannot start until restore releases ownership.
  • Stale reconciles, simultaneous claims, operator restarts, pod replacements, and deleted owners preserve exclusion.
  • Failure/cancellation leaves the correct suspend intent and never releases a target with authorized writers still running.
  • Existing duplicate-backup and restore/wipe serialization cases remain valid.

This extends #590, whose description separates its backup work from #585's restore/wipe guards. Preserve those protections and #454's cleanup retries.

Activity

  1. ValgulNecron commented on Oct 20, 2026

    @ValgulNecron
    Collaborator

    Thanks, confirmed on master, and it's a bit broader than described: backups with quiesce: false take no guard at all (operator/internal/controller/backup_guard.go:63-66), the backup code never checks the restore or wipe guards, and none of the GameServer paths (idle sleep, restart, template rollout) look at an in-flight backup (the idle busy check at gameserver_idle.go:300-301 only covers restart and wipe tokens). So a backup can silently capture a half-restored or mid-stop filesystem.

    Go ahead with a PR using exclusive ownership: one durable, UID-bound owner record, acquired with compare-and-swap, that every Backup variant (including quiesce: false and CSI snapshots) must hold before creating a Job or VolumeSnapshot. Restore and wipe acquire the same record, and idle sleep, restart and rollout defer while it is held. Please keep it exclusive for now; compatible reader modes can be a follow-up with explicit invariants.

    #716, #717, #719 and #731 depend on this, so it's the one to land first.

  2. Baylem commented on Oct 25, 2026

    @Baylem
    MemberAuthor

    Implemented in #760. Every Backup variant, including quiesce:false and CSI, now acquires the same durable owner as Restore and wipe. Admission binds the operation UID, target UID and generation through an uncached read and resourceVersion-checked write. Idle transitions, restart and template changes wait while it is held; workers and cleanup obligations must drain before release. Ownership remains exclusive.

    The dependent PRs are #766 for #716, #767 for capture metadata, #769 for #731, and #772 for #717/#719. They include the ownership prerequisite, so #760 remains the first change to land. Regression sources cover concurrent claims, stale workload writes, owner replacement and deferred lifecycle actions; runtime tests remain in CI.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions