How the Rollback Feature Restores Sandbox State to Any Previous Checkpoint in CubeSandbox

The rollback feature recreates a sandbox exactly as it existed at a specific snapshot moment by cloning the checkpointed root‑FS into a new copy‑on‑write (COW) generation and atomically swapping the running VM to that restored state.

The rollback capability in TencentCloud/CubeSandbox enables instant restoration of sandbox state using the cubecow storage backend. This process operates entirely in‑process without external commands, leveraging COW volumes to preserve the original snapshot while creating a new writable root‑FS for the resumed workload.

Understanding the Rollback Architecture

The rollback mechanism relies on the cubecow copy‑on‑write (COW) storage backend to manage disk state efficiently. When a checkpoint is created, the system captures both the root‑FS volume (disk state) and memory volume (RAM contents). During rollback, the system derives a new root‑FS generation from the snapshot while reusing the memory volume, then instructs the containerd shim to destroy the current VM and resume a new one using the restored configuration.

Step‑by‑Step Rollback Execution Flow

API Entry and Request Validation

Clients initiate rollback via the RollbackSandbox endpoint, accessible through the Go SDK or cubecli command. The request requires sandbox_id, snapshot_id, and a new_gen value exceeding the current generation.

In Cubelet/services/cubebox/rollback.go, the validateRollbackSandboxRequest function verifies that the storage backend supports COW operations (storage.IsCowBackend). If validation fails, the service returns a structured error before any state changes occur.

Sandbox Locking and State Verification

Before proceeding, the system acquires a per‑sandbox lock via s.updateSandboxLocks.Lock to prevent concurrent modifications. The cubebox manager retrieves the live cubebox object and confirms the sandbox is running (not terminated), ensuring rollback only targets active instances.

Resolving Target Volumes

The resolveRollbackTargets function (lines 31‑55 in rollback.go) determines the sources for restoration:

  • Explicit overrides – Uses master‑supplied rootfs_vol, memory_vol, or meta_dir parameters if provided.
  • Catalog lookup – Calls storage.GetLocalSnapshot to retrieve the root‑FS and memory volume names associated with the requested snapshot ID.

Snapshot Object Resolution

storage.ResolveSnapshotForRollback (defined in Cubelet/storage/cubecow_snapshot_artifacts.go) obtains CowSnapshotObject handles for both root‑FS and memory volumes. This function supports the optional memory_kind parameter to distinguish between snapshot and volume types, enabling incremental memory snapshot restoration.

Creating the New Root‑FS Generation

RollbackDeriveNewGen (in cubecow_snapshot_artifacts.go) interacts with the CowVolumeManager to clone the snapshot’s root‑FS into a fresh COW volume. This new volume carries the requested generation number and optional size constraints, becoming the restored root‑FS without modifying the original snapshot data.

Configuring the Shim Restore

buildRollbackRestoreConfig constructs a JSON payload that guides the containerd shim through VM reconstruction:

  • SourceURL – File path to the snapshot’s meta directory.
  • MemoryVolURL – Device path of the memory volume.
  • Disks – Updated disk specifications where rollbackDisksFromSnapshotSpec replaces the old root‑FS entry with the new generation’s device path.

Executing the Atomic VM Swap

Before contacting the shim, setSandboxRollingBack sets an in‑memory flag on every container to signal that background scanners (such as DeadGC heartbeat monitors) should skip this sandbox, preventing race conditions during the swap.

updateShimForRollback transmits the restore configuration via containerd annotations:

task.Update(ctx, containerd.WithAnnotations(map[string]string{
    shimUpdateActionAnnotation:          shimUpdateRollbackAction,
    shimUpdateRollbackRestoreAnnotation: restoreConfig,
}))

The shim internally executes delete_vm to remove the old VM, then resume_vm_with_config to start a new VM from the supplied root‑FS and memory volumes.

Post‑Rollback Cleanup and Persistence

If the shim call succeeds, the temporary new root‑FS volume is retained (cleanupNewRootfs = false). Otherwise, deferred cleanup removes it. resetSandboxStatusAfterRollback clears any stale termination markers set by concurrent code paths during the swap, trusting the shim’s authoritative state transition.

PersistSandboxRootfsAfterRollback writes the new root‑FS volume name, kind, generation, and device path into the sandbox’s backend file, making the restored state permanent for subsequent operations.

The old root‑FS volume is then deleted via storage.DeleteCowObject on a best‑effort basis. If deletion fails, the rollback remains successful but notes the deferred cleanup in the response.

Implementing Rollback in Your Code

Go SDK Example

import "github.com/tencentcloud/CubeSandbox/sdk/go"

func rollbackExample() error {
    client, _ := sdk.NewClient(&sdk.Config{
        // endpoint & auth configuration
    })
    req := &sdk.RollbackSandboxRequest{
        SandboxID:  "sandbox-123",
        SnapshotID: "snap-2024-07-01",
        NewGen:     5, // must be > current generation
    }
    rsp, err := client.RollbackSandbox(req)
    if err != nil {
        return err
    }
    fmt.Printf("Rollback succeeded, new rootfs: %s (gen %d)\n",
        rsp.RootfsVol, rsp.NewGen)
    return nil
}

Source: sdk/go/snapshot.go

Command‑Line Interface


# Production rollback via cubecli

cubecli sandboxes rollback \
  --sandbox-id sb1 \
  --snapshot-id snapA \
  --new-gen 3

# Debug rollback with explicit volume overrides

cubecli cubebox debug-rollback \
  --sandbox-id sb1 \
  --snapshot-id snapA \
  --rootfs-vol tpl-snap-rootfs \
  --memory-vol tpl-snap-memory \
  --meta-dir /var/lib/cube/snapshots/snapA \
  --new-gen 3

Source: Cubelet/cmd/cubecli/commands/cubebox/debug_rollback.go

Python SDK Example

from cubesandbox import CubeSandboxClient

client = CubeSandboxClient(endpoint="http://localhost:8080")
resp = client.rollback_sandbox(
    sandbox_id="sandbox-01",
    snapshot_id="snap-2024-07-01",
    new_gen=4
)
print("New rootfs:", resp.rootfs_vol, "gen:", resp.new_gen)

Summary

  • CubeSandbox implements rollback through the cubecow storage backend, creating a new COW generation from the snapshot root‑FS while preserving the original checkpoint.
  • The process acquires per‑sandbox locks and sets rolling‑back flags to prevent race conditions with background processes like DeadGC.
  • RollbackDeriveNewGen clones the snapshot into a new writable volume, while updateShimForRollback atomically swaps the VM via containerd shim annotations.
  • Post‑rollback, PersistSandboxRootfsAfterRollback updates persistent metadata, and the old root‑FS is cleaned up on a best‑effort basis.
  • All operations occur in‑process without external command execution, ensuring consistent restoration to any previous checkpoint.

Frequently Asked Questions

What storage backend is required for rollback to function?

The rollback feature requires the cubecow copy‑on‑write storage backend. The validateRollbackSandboxRequest function in Cubelet/services/cubebox/rollback.go explicitly checks storage.IsCowBackend and rejects requests if the sandbox uses incompatible storage drivers.

How does CubeSandbox prevent race conditions during rollback?

The system uses a per‑sandbox mutex (s.updateSandboxLocks.Lock) to block concurrent modifications. Additionally, setSandboxRollingBack marks containers with an in‑memory flag that instructs background scanners like DeadGC to skip the sandbox while the shim destroys the old VM and resumes the new one.

What happens to the original root‑FS volume after a successful rollback?

The original root‑FS is deleted via storage.DeleteCowObject on a best‑effort basis after the new volume is persisted. If deletion fails due to locks or I/O errors, the rollback still succeeds but defers cleanup, exposing the old volume name in the response’s old_rootfs_vol field.

Can rollback target a sandbox that is not currently running?

No. The validateRollbackSandboxRequest function checks that the sandbox is in a running state. Rollback to a checkpoint requires an active cubebox instance because the operation involves swapping the running VM via the containerd shim rather than creating a fresh instance from scratch.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →