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.
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.
| Part | Description |
|---|---|
id | The name of the snapshot. It starts with the volume id. Restore, clone and delete take it. |
version | The number of the push under the name of its volume, or null. See Names and versions. |
parent | The snapshot that came before this one. null for the first snapshot. |
parent_version | The version of the parent. Only the versions list shows it. null when the parent has no number or is deleted. |
message | An optional note from the push. |
createdAt | The time the snapshot was taken. |
phase | The progress of the snapshot. See States. |
state | What the source was made of at the time. See Snapshot types. |
saved_by | The 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.
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 thatid. - An environment that you restore in place keeps its own pushes. Its next push chains on its newest
readysnapshot, 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
saveToadds a version to the volume.saved_bynames 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
volumefield of the workspace or the environment, or see Show the volumes. - References:
GET /v1/volumes/{key}/history.
Procedure
Show the snapshots, newest first.
for row in kl.volumes.history(volume="ws-0a1b2c3d4e5f6a7b"): print(row["id"], row["version"], row["parent"], row["createdAt"], row["phase"], row["message"])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);}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"])}kl.volumes.history(volume: "ws-0a1b2c3d4e5f6a7b").each do |row| puts row.values_at("id", "version", "parent", "createdAt", "phase", "message").join(" ")end// The SDK returns the answer as raw JSON. Read the fields with your own JSON library.System.out.println(kl.volumes().history("ws-0a1b2c3d4e5f6a7b"));kloudlite snapshots list ws-0a1b2c3d4e5f6a7b
Close-out
- Write down the
idof 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
- Access: you, or a member of the team that owns the volume.
- Conditions: the volume has a name. See Show the volumes.
- References:
GET /v1/volumes/{key}/{name}/versions.
Procedure
Show the versions, newest first.
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"])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);}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"])}kl.volumes.versions(owner: "acme", name: "go-base").each do |v| puts v.values_at("version", "snapshot", "phase", "parent_version", "expires_at").join(" ")end// 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"));kloudlite volumes versions acme/go-base
Close-out
- Make sure that the newest
readyversion 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
- Access: you, or a member of the team that owns the volume.
- Conditions: you know the volume id. See Show the lineage.
- References:
GET /v1/volumes/{key}/refs.
Procedure
Show the snapshot in
main. The value isnullfor a volume with no snapshot.print(kl.volumes.refs(volume="ws-0a1b2c3d4e5f6a7b")["main"])const refs = (await kl.volumes.refs({ volume: "ws-0a1b2c3d4e5f6a7b" })) as Record<string, unknown>;console.log(refs.main);refs, err := kl.Volumes.Refs("ws-0a1b2c3d4e5f6a7b")if err != nil { log.Fatal(err)}fmt.Println(refs["main"])puts kl.volumes.refs(volume: "ws-0a1b2c3d4e5f6a7b")["main"]// The SDK returns the answer as raw JSON. Read the fields with your own JSON library.System.out.println(kl.volumes().refs("ws-0a1b2c3d4e5f6a7b"));kloudlite snapshots refs ws-0a1b2c3d4e5f6a7b
Close-out
- Make sure that the
idis 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
- Access: you, or a member of the team that owns the volume.
- Conditions: no running workspace or environment uses the snapshot. No pipeline reads it.
- References:
DELETE /v1/volumes/{key}/snapshots/{snapshot}.
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
Delete the snapshot. Use the
idfrom the history forsnapshot.kl.volumes.delete_snapshot(volume="ws-0a1b2c3d4e5f6a7b", snapshot="ws-0a1b2c3d4e5f6a7b-8a7b6c5d")await kl.volumes.deleteSnapshot({ volume: "ws-0a1b2c3d4e5f6a7b", snapshot: "ws-0a1b2c3d4e5f6a7b-8a7b6c5d" });if err := kl.Volumes.DeleteSnapshot(kloudlite.DeleteSnapshot{Volume: "ws-0a1b2c3d4e5f6a7b", Snapshot: "ws-0a1b2c3d4e5f6a7b-8a7b6c5d"}); err != nil { log.Fatal(err)}kl.volumes.delete_snapshot(volume: "ws-0a1b2c3d4e5f6a7b", snapshot: "ws-0a1b2c3d4e5f6a7b-8a7b6c5d")kl.volumes().deleteSnapshot(new Kloudlite.DeleteSnapshot().volume("ws-0a1b2c3d4e5f6a7b").snapshot("ws-0a1b2c3d4e5f6a7b-8a7b6c5d"));kloudlite snapshots delete ws-0a1b2c3d4e5f6a7b ws-0a1b2c3d4e5f6a7b-8a7b6c5d
Close-out
- Show the lineage, as in task 001. Make sure that the
idis gone, or that the call returns404because 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
- Access: you, or a member of the team that owns the volume.
- Conditions: no pipeline pins the version, and no run started from it.
- References:
DELETE /v1/volumes/{key}/{name}/versions/{n}.
The platform deletes the version at once. A job that pins go-base@2 then fails at start.
Procedure
Delete the version.
kl.volumes.delete_version(owner="acme", name="go-base", n=2)await kl.volumes.deleteVersion({ owner: "acme", name: "go-base", n: 2 });if err := kl.Volumes.DeleteVersion("acme", "go-base", 2); err != nil { log.Fatal(err)}kl.volumes.delete_version(owner: "acme", name: "go-base", n: 2)kl.volumes().deleteVersion("acme", "go-base", 2);kloudlite volumes delete-version acme/go-base 2
Close-out
- Show the versions as in task 002. Make sure that the number is gone.
Troubleshooting
| Symptom | Possible cause | Corrective action |
|---|---|---|
404 with not found | The 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 9 | The version does not exist or is deleted. | Use a number from the versions. |
| The history does not show a snapshot that you expect | The 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 version | The 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 hand | The 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 build | A 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 worktree | A running workspace or environment uses this snapshot. | Stop or delete it, or delete a different snapshot. |
503 with the cluster could not be reached | The platform cannot check what uses the snapshot. Nothing is deleted. | Wait, then delete again. |