Skip to content

snapshots: a snapshot request on the pod pushes a live snapshot of the running VM - #129

Merged
CMGS merged 3 commits into
mainfrom
tonic/snapshot-request
Oct 12, 2026
Merged

CMGS merged 3 commits into
mainfrom
tonic/snapshot-request

Conversation

@tonicmuroq

@tonicmuroq tonicmuroq commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor

What

  • UpdatePod reads a pending vm.cocoonstack.io/snapshot ref (a registry-relative repo[:tag] with no matching snapshot-status) before the pod is tracked, like the hibernate intent.
  • applyUpdate calls snapshot before the hibernate/wake switch when a VM is tracked, no hibernate is asked for, and a pusher is configured. A pod still Creating (fresh clone, or a wake that is still restoring) returns an error so the op retry serves the request once the VM is Ready; vk's own Ready patch updates the tracked copy and re-delivers no UpdatePod. A macOS pod answers failed. snapshot saves the VM as snap-<vm>, pushes it to the ref, removes the local copy, and patches vm.cocoonstack.io/snapshot-status with {ref, state: pushed|failed, message}.
  • A request still pending when vk-cocoon restarts is resumed at startup (owedOpFor returns resumeOpSnapshot), like an interrupted hibernate; UpdatePod is one-shot, so nothing else re-delivers it.
  • The save runs on context.WithoutCancel: vk-cocoon's shutdown cancels its context, and exec.CommandContext would then SIGKILL the cocoon CLI, possibly between CH's pause and resume, leaving a running VM paused. With KillMode=process the detached CLI outlives vk-cocoon and resumes the VM (cocoon writes no log between pause and resume, and its resume is itself detached). It may still die on its first stderr write afterwards (SIGPIPE on the closed CombinedOutput pipe), leaving a partial snapshot; the resumed request's SnapshotSave already removes a name holder by ID and retries.
  • The local name is never <vm>, so the request cannot overwrite the node-local snapshot that same-node wake uses.
  • The delete-time latest push and the requested push share saveAndPush; the delete path behaves as before.
  • Pusher.PushSnapshot exports its vmName argument as the local snapshot (PushOptions.LocalName) rather than the repo. Until now the two were always the same name (hibernate passes it for both, the delete push leaves repo empty), so those paths are unchanged; the requested push is the first to differ.

Why

The developer API needs "snapshot my machine" and "create / reset a machine from that snapshot". vk-cocoon only pushes on hibernate (CH+Windows drops the NIC first, so that snapshot cannot be a clone source) and on delete (the VM is gone afterwards). cocoon snapshot save pauses only for the save and resumes, and keeps the NICs, which clone hot-swaps for fresh ones, so a requested save is a clone source like the base snapshots. The request sits on the pod rather than the CocoonSet because it touches one VM and creates or deletes no pods.

Dependency

Needs cocoonstack/cocoon-common#38, merged as ba211c8; go.mod pins v0.3.8-0.20261012121517-ba211c820075.

Evidence

  • provider/cocoon/snapshot_test.go: a running VM saves snap-<vm>, exports snap-<vm> (not the repo), pushes to the requested repo:tag, removes the local copy and patches pushed; an answered ref does nothing; a save failure patches failed and pushes nothing; a pending request on a Ready pod is resumed by dispatchOwedWork and answered (fails without the owedOpFor branch).
  • Gates (GOWORK=off): make fmt-check clean, go test -race ./... green. make lint could not run locally (golangci-lint cannot read Go 1.27.2 export data); leaving it to CI.
  • Not yet run on hardware.

Known gaps

  • A request on a hibernated pod stays pending and is served after the wake reaches Ready.
  • If the pod is deleted while vk-cocoon is down mid-push, snap-<vm> stays on disk: the reclaimer skips names without the vk- prefix and pod delete does not remove it.
  • The push holds the pod lock and the node-wide push gate, so a hibernate or wake of the same pod, and other pushes on the node, wait behind it.

@tonicmuroq
tonicmuroq force-pushed the tonic/snapshot-request branch 5 times, most recently from 076e85e to b1024fb Compare October 12, 2026 01:52
…e running VM

vm.cocoonstack.io/snapshot names a registry-relative repo[:tag]. While the VM
runs and no hibernate is asked for, UpdatePod saves it as snap-<vm> (never the
VM-named warm-wake cache), pushes it there, drops the local copy, and answers in
vm.cocoonstack.io/snapshot-status with the ref echoed and pushed or failed. The
save pauses the VM only for its duration and keeps the NICs, so the result is a
clone source. The pending ref is read before the pod is tracked, like the
hibernate intent.

PushSnapshot now exports its vmName argument as the local snapshot
(PushOptions.LocalName) instead of the repo; the hibernate and latest pushes
pass the same name for both, so they are unchanged. The delete-time latest push
and the requested push share saveAndPush.

cocoon-common is pinned to cocoonstack/cocoon-common#38 until it merges.
@tonicmuroq
tonicmuroq force-pushed the tonic/snapshot-request branch from b1024fb to 40ff313 Compare October 12, 2026 02:03
CMGS added 2 commits October 12, 2026 15:36
A request on a Creating pod (fresh clone, or a wake from hibernate that
is still restoring) saved the guest mid post-clone setup. It now waits
for Ready through the op retry, which reads the tracked pod; vk's own
Ready patch updates that copy, so it re-delivers no UpdatePod. The update
path and the restart resume share one Creating predicate.

A macOS pod answers failed instead of never answering. A failure message
is truncated like other failures and logged; a superseded status patch is
not retried. Re-pins cocoon-common to the branch head 9b3ba3a, where
ReadSnapshotStatus returns the plain status.
@CMGS
CMGS merged commit 4f87a32 into main Oct 12, 2026
2 checks passed
@CMGS
CMGS deleted the tonic/snapshot-request branch October 12, 2026 12:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants