> ## Documentation Index
> Fetch the complete documentation index at: https://docs.celum.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Add a disk to a VM

> Hot-plug storage onto a running VM — an existing claim, a blank disk, or one cloned from a snapshot — and mount it in the guest.

By the end of this page a running VM has more storage than it started with, the guest can find the new device deterministically, and you know which of the three ways to remove it destroys data.

This page starts where [Run a VM](https://docs.celum.io/get-started/run-a-vm.md) ended: a VM running in your project namespace.

> [!WARNING]
>
> **Celum does not grow a disk — it adds one.** There is no expand or resize operation anywhere in the API, so a VM that is running out of space gets another disk, not a bigger one. Plan for that: a filesystem that must grow in place is a decision to make at create time, through `rootPartitions` and `diskSize`, not afterwards.

## What this changes on your cluster

One of three things, depending on where the disk comes from:

| Source | What is created |
| - | - |
| `pvc` | nothing — an existing PersistentVolumeClaim is referenced |
| `blank` | a CDI `DataVolume`, which provisions an empty PVC |
| `snapshot` | a CDI `DataVolume` that clones a `VolumeSnapshot` into a new PVC |

Then, in all three cases, the volume is hot-plugged onto the VM through KubeVirt's `addvolume` subresource. **The same call works whether the VM is running or stopped** — running means a live hot-plug, stopped means it persists into the VM spec — so there is one path and no state to check first.

## Before you start

* **A running VM**, if you want the disk to appear without a restart.
* **A snapshot class and the snapshot controller**, if the source is a snapshot. Both come from the Storage step of onboarding.
* **The guest agent**, if you want Celum to mount the disk for you. In-guest mounting is Linux only.
* **Permission** `vm:AttachVolume`, scoped `supervisor:<name>:vm:<vm>`.

## The shape of it

**Choose the source → attach → mount → verify the guest sees it.** The mount is optional and can fail on its own, which is the part worth watching.

## Step 1 — Choose where the disk comes from

> [tab] Dashboard
>
> The VM detail page → **Disks** → **Attach volume**. The dialog offers all three sources and browses existing claims and snapshots for you.

> [tab] API
>
> `POST /api/supervisors/{name}/vms/{vm}/attach-volume?namespace=…` with `source` set to `pvc`, `blank` or `snapshot`. Browse candidates with `GET .../pvcs?namespace=` and `GET .../volume-snapshots?namespace=`.

> [tab] MCP
>
> `attach_vm_disk`, with `list_pvcs` and `list_volume_snapshots` to find a source.

![The Attach volume dialog for a VM, with source cards Existing PVC, Blank disk and From snapshot, a table of the project's PVCs with capacity, storage class, access mode and status, the disk bus set to scsi, and a Mount inside guest section](https://mintcdn.com/celum-e0119be0/sA7S2Ajgv1l2CH1V/images/get-started/vm-attach-volume.png?fit=max\&auto=format\&n=sA7S2Ajgv1l2CH1V\&q=85\&s=f3054921af268aecd2dc2bc0fe363a06)

Attach volume: the three sources, the claims already in the project, the bus, and the optional mount

Each source has its own required fields, and the call tells you which one is missing rather than failing generically:

* **`pvc`** needs `claimName`. The disk takes that name unless you give it one.
* **`blank`** needs `name` and `size`. `volumeMode` picks Filesystem or Block; `accessMode` defaults to **ReadWriteOnce**.
* **`snapshot`** needs `name`, `size` and `snapshotName`.

`bus` defaults to `scsi`, which is what hot-plug requires — leave it alone unless you know why you are changing it.

**Result:** `200` with the volume and the backing PVC named.

## Step 2 — Let it mount, or mount it yourself

Pass **`mountPath`** and Celum formats the disk (`fsType`, default `ext4`) and mounts it inside the guest. Add **`persist: true`** and it also writes a UUID entry to `/etc/fstab`, so the mount survives a reboot — without it, the mount is for this boot only.

> [!NOTE]
>
> The response carries `mounted` and `mountMessage` separately from the attach status. **The attach can succeed while the mount does not** — a guest agent that is down, or a Windows guest, which the in-guest path does not support at all. Read both fields rather than the status alone.

If you mount it yourself, the disk carries a **stable serial** derived from its name, so the guest can find it deterministically:

```bash theme={null}
lsblk -o NAME,SERIAL,SIZE
```

That is the reliable way to identify a freshly attached disk. Device order is not.

## Verify

The disk appears on the VM's Disks tab, with its backing claim named. Inside the guest, `lsblk` shows the new device by its serial; if you asked for a mount, it is at `mountPath` and, with `persist`, in `/etc/fstab`.

## Removing it — three verbs, and only one destroys data

This is the part to read before pressing anything. The three operations look adjacent in the UI and are not equivalent.

| Operation | What happens | Data |
| - | - | - |
| **Unmount** | unmounts the filesystem in the guest and removes its `/etc/fstab` entry. The volume stays attached | kept |
| **Detach** | best-effort guest unmount, then hot-unplug from the VM. The backing DataVolume / PVC is **left intact** | kept |
| **Delete volume** | unmount, detach, then **delete the backing DataVolume / PVC** | **destroyed** |

Detach is the exact inverse of attach. Delete is not — it is detach plus destruction, and there is no undo.

> [!WARNING]
>
> **Detach and delete share one permission.** Both are `vm:Eject`, so IAM does not distinguish "stop using this disk" from "destroy it". An operator you trusted to unplug a disk can also erase it. If that distinction matters in your estate, it has to be enforced by who gets `vm:Eject` at all.

Over MCP, `detach_vm_disk` exists and there is **no tool that deletes the volume** — consistent with the catalog's standing policy that no tool destroys data. Deleting requires a person.

## What commonly goes wrong

| Symptom | Cause |
| - | - |
| You are looking for a way to grow an existing disk | there isn't one. Add a disk instead |
| `400` naming a field you did not send | each source has different required fields — `claimName` for pvc, `name` + `size` for blank, plus `snapshotName` for snapshot |
| The attach succeeded but nothing is mounted | read `mounted` and `mountMessage`. A stopped guest agent, or a Windows guest, which is not supported for in-guest mounting |
| The mount is gone after a reboot | `persist` was not set, so no `/etc/fstab` entry was written |
| The guest sees the disk at an unexpected device name | do not rely on device order. Match on the disk's serial |
| The disk vanished and so did the data | that was **delete volume**, not detach. They are one permission apart |

## Next

> [card] [VM storage & disks](https://docs.celum.io/vms/storage.md)
>
> The full disk surface on a VM, including block versus filesystem volumes.

> [card] [PVCs & snapshots](https://docs.celum.io/storage/pvcs-and-snapshots.md)
>
> Where snapshots come from, and the checklist for a claim stuck Pending.

> [card] [Classes & profiles](https://docs.celum.io/storage/classes-and-profiles.md)
>
> Which StorageClass to give a disk, and what its clone strategy costs.

> [card] [VM lifecycle](https://docs.celum.io/vms/lifecycle.md)
>
> Snapshots, restores and live migration for the VM as a whole.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.