Skip to content
DocsAll docs
Console

Lineage

Show the chain of snapshots of a volume, find its tip, and delete a snapshot or a version from the chain.

Last updated

On this page

Description and operation

General

The lineage of a volume is the chain of its snapshots. Each snapshot names its parent, the snapshot that it was taken after. The history shows the lineage newest first. A snapshot stays in the lineage until it expires or you delete it.

text
backend-base@3 ← backend-base@2 ← backend-base@1      tip (main) = backend-base@3"before the refactor"  "add tests"    "first push"

Sync points are not part of the lineage. The platform keeps them between snapshots. They are never listed, are not a restore target and cannot be deleted by hand.

PartDescription
idThe name of the snapshot. It starts with the volume id. Restore, clone and delete take it.
versionThe number of the push under the name of its volume, or null. See Names and versions.
parentThe snapshot that came before this one. null for the first snapshot.
parent_versionThe version of the parent. Only the versions list shows it. null when the parent has no number or is deleted.
messageAn optional note from the push.
createdAtThe time the snapshot was taken.
phaseThe progress of the snapshot. See States.
stateWhat the source was made of at the time. See Snapshot types.
saved_byThe pipeline, run and job that made the version, or null for a push by hand. Only the versions list shows it.

The history lists every snapshot of the volume that you own, in every phase, also error. The versions list shows only snapshots that have a number.

Order and tip

The history puts the snapshot with the longest chain of parents first. Snapshots with an equal chain length come newest first. The first row is main, the tip of the lineage. main can be in any phase.

A name reference works on version numbers, not on this order. go-base is the ready version with the highest number. After a branch, main and go-base can name different snapshots.

Deleting a snapshot does not change the parent of the snapshots after it. Their parent still names the deleted id.

Restore and clone

A restore does not change the lineage. It makes a new working copy of the volume at a past snapshot. The first push of that working copy takes the restored snapshot as its parent. The lineage then branches.

text
backend-base@5 ← backend-base@3 ← backend-base@2 ← backend-base@1                                                          ↑                                       backend-base@4 ────┘

Here the workspace backend pushed versions 1, 2, 3 and then 5. A second workspace was restored at version 1 and pushed version 4. The history order is 5, 3, 4, 2, 1. A version number counts pushes of the volume, not depth.

A push takes as its parent the newest ready snapshot that the same workspace or environment pushed. When it pushed none, the parent is the snapshot it started from. These rules follow from the push:

  • A workspace made by a restore starts from the snapshot that you named.
  • A workspace made by a clone starts from a sync point of its source. The first push names that sync point as parent. No row of the history has that id.
  • An environment that you restore in place keeps its own pushes. Its next push chains on its newest ready snapshot, not on the restored one.
  • An environment made from a snapshot starts from that snapshot. A clone of the live state of an environment starts a new volume and a new lineage.
  • A pipeline job with saveTo adds a version to the volume. saved_by names the pipeline, the run and the job.

Restore and clone from a ready snapshot move its expiry to a full default lifetime from now. See Expiry.

Delete from the lineage

You delete one snapshot at a time. A delete is immediate. It is refused with 409 for a sync point and for a snapshot that a running workspace or environment stands on.

A pipeline can read a snapshot. A pipeline reads a version when its latest version pins it, as go-base@2, or names its snapshot id. A pipeline that names go-base with no number reads the last ready snapshot of the volume. A queued or running run reads what it started from. The refusal names the readers.

When you delete the last snapshot of a detached volume, the volume is deleted too.

To do these tasks with an AI agent, see Agentic workflows – Volumes.

Tasks

Show the lineage

Reason for the task: Find the snapshots of a volume in order, with their ids and parents.

Job set-up

  • Access: you, or a member of the team that owns the volume.
  • Conditions: you know the volume id. Read it from the volume field of the workspace or the environment, or see Show the volumes.
  • References: GET /v1/volumes/{key}/history.

Procedure

  1. Show the snapshots, newest first.

    Python
    for row in kl.volumes.history(volume="ws-0a1b2c3d4e5f6a7b"):    print(row["id"], row["version"], row["parent"], row["createdAt"], row["phase"], row["message"])
    TypeScript
    const rows = (await kl.volumes.history({ volume: "ws-0a1b2c3d4e5f6a7b" })) as Record<string, unknown>[];for (const row of rows) {  console.log(row.id, row.version, row.parent, row.createdAt, row.phase, row.message);}
    Go
    rows, err := kl.Volumes.History("ws-0a1b2c3d4e5f6a7b")if err != nil {    log.Fatal(err)}for _, row := range rows {    fmt.Println(row["id"], row["version"], row["parent"], row["createdAt"], row["phase"], row["message"])}
    Ruby
    kl.volumes.history(volume: "ws-0a1b2c3d4e5f6a7b").each do |row|  puts row.values_at("id", "version", "parent", "createdAt", "phase", "message").join(" ")end
    Java
    // The SDK returns the answer as raw JSON. Read the fields with your own JSON library.System.out.println(kl.volumes().history("ws-0a1b2c3d4e5f6a7b"));
    CLI
    kloudlite snapshots list ws-0a1b2c3d4e5f6a7b

Close-out

  1. Write down the id of the snapshot for a restore, a clone or a delete.

Show the versions of a volume

Reason for the task: Find the version numbers of a named volume, their parents and which of them a pipeline saved.

Job set-up

Procedure

  1. Show the versions, newest first.

    Python
    for v in kl.volumes.versions(owner="acme", name="go-base"):    print(v["version"], v["snapshot"], v["phase"], v["parent_version"], v["expires_at"], v["saved_by"])
    TypeScript
    const versions = (await kl.volumes.versions({ owner: "acme", name: "go-base" })) as Record<string, unknown>[];for (const v of versions) {  console.log(v.version, v.snapshot, v.phase, v.parent_version, v.expires_at, v.saved_by);}
    Go
    versions, err := kl.Volumes.Versions("acme", "go-base")if err != nil {    log.Fatal(err)}for _, v := range versions {    fmt.Println(v["version"], v["snapshot"], v["phase"], v["parent_version"], v["expires_at"], v["saved_by"])}
    Ruby
    kl.volumes.versions(owner: "acme", name: "go-base").each do |v|  puts v.values_at("version", "snapshot", "phase", "parent_version", "expires_at").join(" ")end
    Java
    // The SDK returns the answer as raw JSON. Read the fields with your own JSON library.System.out.println(kl.volumes().versions("acme", "go-base"));
    CLI
    kloudlite volumes versions acme/go-base

Close-out

  1. Make sure that the newest ready version has the number that you expect. A gap in the numbers is normal.

Show the tip

Reason for the task: Find the snapshot at the head of the lineage.

Job set-up

Procedure

  1. Show the snapshot in main. The value is null for a volume with no snapshot.

    Python
    print(kl.volumes.refs(volume="ws-0a1b2c3d4e5f6a7b")["main"])
    TypeScript
    const refs = (await kl.volumes.refs({ volume: "ws-0a1b2c3d4e5f6a7b" })) as Record<string, unknown>;console.log(refs.main);
    Go
    refs, err := kl.Volumes.Refs("ws-0a1b2c3d4e5f6a7b")if err != nil {    log.Fatal(err)}fmt.Println(refs["main"])
    Ruby
    puts kl.volumes.refs(volume: "ws-0a1b2c3d4e5f6a7b")["main"]
    Java
    // The SDK returns the answer as raw JSON. Read the fields with your own JSON library.System.out.println(kl.volumes().refs("ws-0a1b2c3d4e5f6a7b"));
    CLI
    kloudlite snapshots refs ws-0a1b2c3d4e5f6a7b

Close-out

  1. Make sure that the id is the first row of the history, as in task 001.

Delete a snapshot from the lineage

Reason for the task: Remove a snapshot that you do not need, and release its quota.

Job set-up

WARNING

The deletion is immediate and final. If it is the last snapshot of a detached volume, the volume and its data are deleted too.

Procedure

  1. Delete the snapshot. Use the id from the history for snapshot.

    Python
    kl.volumes.delete_snapshot(volume="ws-0a1b2c3d4e5f6a7b", snapshot="ws-0a1b2c3d4e5f6a7b-8a7b6c5d")
    TypeScript
    await kl.volumes.deleteSnapshot({ volume: "ws-0a1b2c3d4e5f6a7b", snapshot: "ws-0a1b2c3d4e5f6a7b-8a7b6c5d" });
    Go
    if err := kl.Volumes.DeleteSnapshot(kloudlite.DeleteSnapshot{Volume: "ws-0a1b2c3d4e5f6a7b", Snapshot: "ws-0a1b2c3d4e5f6a7b-8a7b6c5d"}); err != nil {    log.Fatal(err)}
    Ruby
    kl.volumes.delete_snapshot(volume: "ws-0a1b2c3d4e5f6a7b", snapshot: "ws-0a1b2c3d4e5f6a7b-8a7b6c5d")
    Java
    kl.volumes().deleteSnapshot(new Kloudlite.DeleteSnapshot().volume("ws-0a1b2c3d4e5f6a7b").snapshot("ws-0a1b2c3d4e5f6a7b-8a7b6c5d"));
    CLI
    kloudlite snapshots delete ws-0a1b2c3d4e5f6a7b ws-0a1b2c3d4e5f6a7b-8a7b6c5d

Close-out

  1. Show the lineage, as in task 001. Make sure that the id is gone, or that the call returns 404 because the volume went with it.

Delete a version from the lineage

Reason for the task: Remove one version of a named volume to free disk, and keep the others.

Job set-up

WARNING

The platform deletes the version at once. A job that pins go-base@2 then fails at start.

Procedure

  1. Delete the version.

    Python
    kl.volumes.delete_version(owner="acme", name="go-base", n=2)
    TypeScript
    await kl.volumes.deleteVersion({ owner: "acme", name: "go-base", n: 2 });
    Go
    if err := kl.Volumes.DeleteVersion("acme", "go-base", 2); err != nil {    log.Fatal(err)}
    Ruby
    kl.volumes.delete_version(owner: "acme", name: "go-base", n: 2)
    Java
    kl.volumes().deleteVersion("acme", "go-base", 2);
    CLI
    kloudlite volumes delete-version acme/go-base 2

Close-out

  1. Show the versions as in task 002. Make sure that the number is gone.

Troubleshooting

SymptomPossible causeCorrective action
404 with not foundThe volume or the snapshot does not exist, is not yours, or expired.Show the lineage and use an id from the list.
404 with volume go-base has no version 9The version does not exist or is deleted.Use a number from the versions.
The history does not show a snapshot that you expectThe snapshot is a sync point, or another owner pushed it.Use an id of a snapshot that you own.
main is not the snapshot with the highest versionThe lineage branched after a restore.Use the version number to select a version. See Order and tip.
409 with a sync point cannot be deleted by handThe id is a sync point, not a snapshot.Use an id from the history.
409 with version 2 of go-base is used by pipeline buildA pipeline or a run reads the version.Change the pipeline, or wait for the run. See Readers.
409 with this snapshot is the base of a running worktreeA running workspace or environment uses this snapshot.Stop or delete it, or delete a different snapshot.
503 with the cluster could not be reachedThe platform cannot check what uses the snapshot. Nothing is deleted.Wait, then delete again.