feat: implement resource resizing for VMs with storage management
- Added KnownHostsManager to handle cleanup of SSH known_hosts entries upon VM deletion. - Introduced disk_size_bytes method in ImageStore to read logical disk capacity. - Enhanced LifecycleService to manage VM resource resizing, including CPU, RAM, and storage. - Updated application configuration to support known_hosts_files for SSH management. - Modified dashboard to include resource resizing options in the UI. - Improved error handling and validation for resource inputs in the dashboard. - Removed obsolete .pyc files from the repository.
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
`uvm` is a small, local Firecracker microVM command-line manager for Ubuntu.
|
||||
It creates one Firecracker process per VM, attaches it to a host TAP device,
|
||||
and keeps a private disk and local registry for named VMs. The CLI supports
|
||||
create, start, stop, restart, delete, inspection, SSH, logs, diagnostics, and
|
||||
create, start, stop, restart, resize, delete, inspection, SSH, logs, diagnostics, and
|
||||
enforced private-IPv4 TCP port allowlists.
|
||||
|
||||
This directory is a self-contained project. All UVM code, tests, packaging
|
||||
@@ -40,7 +40,7 @@ The project is an application, not a reusable Python SDK.
|
||||
- Linux 5.3 or newer with native bridge conntrack and safe pidfd support
|
||||
- An x86_64 or ARM64 (`aarch64`) host, including NVIDIA DGX Spark
|
||||
- Working host networking, `iproute2`, `iptables`, `nftables`, `conntrack`,
|
||||
`e2fsprogs`, `util-linux`, `openssl`, and `openssh-client`
|
||||
`coreutils`, `e2fsprogs`, `util-linux`, `openssl`, and `openssh-client`
|
||||
- An STP-disabled software bridge; no offload path that bypasses bridge hooks
|
||||
|
||||
`uvm install` installs the required host packages. It validates `/dev/kvm`
|
||||
@@ -89,7 +89,7 @@ sudo env UVM_ALLOW_UNVERIFIED_DOWNLOADS=1 ./uvm.py install
|
||||
An unverified manifest is not accepted as publisher trust in a later strict
|
||||
run. Reinstall with trusted digests to establish a verified local manifest.
|
||||
To boot VMs from an unverified local-development install, retain
|
||||
`UVM_ALLOW_UNVERIFIED_DOWNLOADS=1` on later `create`, `start`, and `restart`
|
||||
`UVM_ALLOW_UNVERIFIED_DOWNLOADS=1` on later `create`, `start`, `restart`, and `resize`
|
||||
commands and on the API server process.
|
||||
|
||||
## Commands
|
||||
@@ -100,12 +100,12 @@ These are separate operation examples, not a script to run from top to bottom.
|
||||
# Install after supplying the trusted checksum variables shown above.
|
||||
# A bare `install` command fails under the default strict integrity policy.
|
||||
|
||||
# Create a named VM: 1 CPU, 512 MiB RAM, root/root, and private TCP/22.
|
||||
# Create a named VM: 1 CPU, 512 MiB RAM, 30 GiB storage, root/root, and private TCP/22.
|
||||
# Use a unique non-default password for anything beyond a throwaway VM.
|
||||
sudo ./uvm.py create --name web
|
||||
|
||||
# Choose resources, a private guest IP, and additional service ports.
|
||||
sudo ./uvm.py create --name app --cpu 1 --ram 1G \
|
||||
sudo ./uvm.py create --name app --cpu 1 --ram 1G --storage 50G \
|
||||
--guest-ip 10.42.0.10 --ports 80:HTTP,443:HTTPS
|
||||
|
||||
# Read a password from one line of stdin, rather than a --password argument.
|
||||
@@ -133,6 +133,10 @@ sudo ./uvm.py stop web --timeout 5
|
||||
sudo ./uvm.py start web
|
||||
sudo ./uvm.py restart web app --timeout 10
|
||||
|
||||
# Stop, change resources, and boot the same VM with its existing identity/data.
|
||||
sudo ./uvm.py resize app --cpu 2 --ram 4G --storage 80G
|
||||
sudo ./uvm.py resize app --ram 2G
|
||||
|
||||
# Preview bulk operations before confirming them.
|
||||
sudo ./uvm.py stop --all --dry-run --json
|
||||
sudo ./uvm.py stop --all -y
|
||||
@@ -150,6 +154,28 @@ sudo ./uvm.py delete web -y
|
||||
start. It is a finite non-negative SIGTERM wait in seconds, default `5`, not
|
||||
a total command deadline or a guest shutdown timeout.
|
||||
|
||||
### Storage and Resizing
|
||||
|
||||
New VMs default to a **30 GiB private disk**, which is also the minimum.
|
||||
`--storage` accepts values such as `30G`, `50G`, or `1T`; bare numbers use GiB.
|
||||
As with RAM, `G`/`GB`/`GiB` are binary units. Capacities round up to whole MiB
|
||||
and are returned as `storage_mib`. Disks are sparse: the configured capacity
|
||||
does not immediately reserve that much physical host space.
|
||||
|
||||
`resize VM` accepts any combination of `--cpu`, `--ram`, and `--storage`, plus
|
||||
`--timeout` and `--json`. It stops the VM, resizes the ext4 disk when needed,
|
||||
updates the resource settings, and boots it. A previously stopped VM also boots
|
||||
at the end. VM ID, IP/MAC, username/password, port rules, guest files, and SSH
|
||||
host keys are retained. The dashboard exposes the same operation under
|
||||
**Resize resources**; the API uses `POST /vms/{identifier}/resize`.
|
||||
|
||||
Storage can grow or shrink, provided ext4 can fit its existing data into the
|
||||
requested capacity. Disk changes are prepared on a temporary sparse copy and
|
||||
published after verification. Failed resizes retain a `pending_resize` target
|
||||
for retry; `start` on the stopped VM completes that target before booting.
|
||||
Older VMs report `storage_mib: null` until their first resize, which retains
|
||||
their current capacity or grows it to the 30 GiB minimum when storage is omitted.
|
||||
|
||||
Stop sends SIGTERM and, if needed, SIGKILL to the Firecracker VMM. It is **not
|
||||
a guest-coordinated shutdown**. Start boots the retained disk without resetting
|
||||
guest data, SSH host keys, or credentials; it does not restore guest memory.
|
||||
@@ -248,11 +274,12 @@ The server exposes these routes:
|
||||
| `GET` | `/diagnostics` | Run host readiness checks for the dashboard/system view |
|
||||
| `POST` | `/install` | Install or refresh host assets; body: `{ "force": false }` |
|
||||
| `GET` | `/vms` | List VM records and observed status |
|
||||
| `POST` | `/vms` | Create; supports `cpu`, `ram`, `guest_ip`, `username`, `password`, `name`, `ports`, `no_default_ports` |
|
||||
| `POST` | `/vms` | Create; supports `cpu`, `ram`, `storage`, `guest_ip`, `username`, `password`, `name`, `ports`, `no_default_ports` |
|
||||
| `POST` | `/vms/actions` | Run a fixed snapshot of selected or all VM lifecycle actions |
|
||||
| `GET` | `/vms/{identifier}` | Inspect by exact ID, name, or guest IP |
|
||||
| `POST` | `/vms/{identifier}/start` | Boot a retained private disk |
|
||||
| `POST` | `/vms/{identifier}/restart` | Stop then boot a VM; optional `timeout` query parameter |
|
||||
| `POST` | `/vms/{identifier}/resize` | Stop, resize CPU/RAM/storage, and boot; optional `timeout` query parameter |
|
||||
| `POST` | `/vms/{identifier}/stop` | Stop a VM while retaining its private disk; optional `timeout` query parameter |
|
||||
| `DELETE` | `/vms/{identifier}` | Delete a VM and release its resources; optional `timeout` query parameter |
|
||||
| `POST` | `/vms/{vm_id}/ports` | Set, open, or close private port rules for an exact VM ID |
|
||||
@@ -260,7 +287,9 @@ The server exposes these routes:
|
||||
| `GET` | `/vms/{identifier}/logs` | Read a bounded, non-following tail of a VM log |
|
||||
|
||||
API port rules are objects such as `{"port": 80, "protocol": "HTTP"}`;
|
||||
`no_default_ports` is a boolean, default `false`. Port changes use
|
||||
`no_default_ports` is a boolean, default `false`. Create also accepts `storage`,
|
||||
defaulting to `"30G"`; resize accepts optional `cpu`, `ram`, and `storage` fields.
|
||||
Port changes use
|
||||
`{"mode":"set"|"open"|"close", "ports":[...]}`. A legacy VM must be
|
||||
stopped and use `set` to establish a managed policy. Responses include `name`,
|
||||
`ports`, `policy_status`, and `operation`, but never passwords. See
|
||||
@@ -379,7 +408,7 @@ The default data directory is `/var/lib/uvm`:
|
||||
└── state.json # Root-only VM inventory and guest credentials
|
||||
```
|
||||
|
||||
The default registry is `/var/lib/uvm/state.json`, schema version `2`. Writes
|
||||
The default registry is `/var/lib/uvm/state.json`, schema version `3`. Writes
|
||||
are locked and atomic. Lifecycle, port-policy, and installation mutations
|
||||
share an operation lock; bulk operations use a fixed snapshot of VM IDs.
|
||||
|
||||
@@ -404,6 +433,11 @@ time, running binary, exact API-socket command line, and protected paths all
|
||||
match. Missing or ambiguous evidence fails closed: UVM will not guess which
|
||||
process to signal or release a disk while process exit is unconfirmed.
|
||||
|
||||
Schema 3 adds disk capacity and durable resize targets. Older registries migrate
|
||||
on the next write; a recorded pending resize is completed before a stopped VM
|
||||
can boot. A boot failure after a successful resize retains the new allocation
|
||||
for a later start.
|
||||
|
||||
## Configuration
|
||||
|
||||
Host and API settings can be overridden through environment variables:
|
||||
@@ -467,6 +501,8 @@ dependencies are installed.
|
||||
|
||||
When `nft` and `conntrack` are installed, the suite also checks their command
|
||||
parsers using deliberately invalid final commands/options that prevent mutations.
|
||||
With e2fsprogs installed, offline disk tests grow and shrink temporary sparse ext4
|
||||
images and check that data and credential/key fixtures survive; no VM is booted.
|
||||
|
||||
Opt-in packet checks run **only in disposable isolated user/network
|
||||
namespaces**, which may require privileges and the installed network tools:
|
||||
|
||||
Reference in New Issue
Block a user