@microck/raft 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -10
- package/deploy/deploy.py +112 -19
- package/deploy/install-incus.sh +10 -0
- package/deploy/verify-controls.py +34 -48
- package/deploy/verify-features.py +350 -4
- package/deploy/verify-fresh-host.py +64 -1
- package/deploy/verify-limits.py +325 -71
- package/deploy/verify-live.py +38 -29
- package/deploy/verify-self-update.py +372 -0
- package/docs/boat-capabilities.md +8 -7
- package/docs/boot-performance.mdx +1 -1
- package/docs/contract.md +28 -17
- package/docs/guides/backup-recovery.mdx +1 -1
- package/docs/guides/config-policy.mdx +179 -0
- package/docs/guides/docker.mdx +9 -1
- package/docs/guides/long-running-services.mdx +2 -2
- package/docs/guides/meta.json +1 -0
- package/docs/guides/project-setup.mdx +4 -3
- package/docs/guides/scripting-ci.mdx +25 -10
- package/docs/guides/snapshots-forks.mdx +9 -3
- package/docs/guides/troubleshooting.mdx +18 -6
- package/docs/guides/upgrades.mdx +13 -3
- package/docs/index.mdx +1 -0
- package/docs/operations.mdx +16 -14
- package/docs/reference/capacity.mdx +198 -0
- package/docs/reference/cli.md +166 -29
- package/docs/reference/configuration.mdx +36 -2
- package/docs/reference/meta.json +1 -1
- package/docs/releases/0.4.0.md +15 -0
- package/docs/releases/0.5.0.md +19 -0
- package/docs/requirements.mdx +2 -2
- package/docs/verification.mdx +14 -8
- package/package.json +1 -1
- package/raft.py +1105 -125
- package/skills/raft-cli/SKILL.md +76 -12
- package/docs/reference/capacity-limits.mdx +0 -92
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Box sizing and capacity
|
|
3
|
+
description: Size boxes for the task, give them their own disks, and read the advisory host capacity estimate.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Box sizing and capacity
|
|
7
|
+
|
|
8
|
+
<Callout type="info" title="Advisory estimate only">
|
|
9
|
+
Raft enforces no box count or size budget. Create the boxes your task needs, sized for the work. `raft capacity` is planning advice, never a reason to skip a box.
|
|
10
|
+
</Callout>
|
|
11
|
+
|
|
12
|
+
## Sizing a box
|
|
13
|
+
|
|
14
|
+
Choose CPU, RAM and disk when you run `raft new`:
|
|
15
|
+
|
|
16
|
+
- `--cpu N`: any whole number of CPUs, from `1` up to the host's CPU count (default: `1`). Boxes share host CPUs, so a limit is a ceiling, not a reservation.
|
|
17
|
+
- `--memory SIZE`: any whole number of GiB, such as `3GiB` or `32GiB`, up to the host's RAM (default: `2GiB`). This is the box's cgroup memory limit.
|
|
18
|
+
- `--disk SIZE`: give the box its own disk instead of the shared pool, on hosts that enable own box disks. See [Own box disks](#own-box-disks).
|
|
19
|
+
|
|
20
|
+
A box from the image starts from these defaults, or from the controller's
|
|
21
|
+
[`config.json` defaults](../guides/config-policy.mdx#defaults-for-new) when set.
|
|
22
|
+
A box from a snapshot (`new --from`) or a fork keeps the source's CPU, RAM and
|
|
23
|
+
disk instead of any default, and each flag you pass overrides only its own value.
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
box=$(raft new --cpu 4 --memory 16GiB --disk 40GiB --ttl 3600 --purpose "Large build")
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
A CPU or RAM request larger than the whole host fails before anything is
|
|
30
|
+
created, because Incus would accept it and quietly give the box less:
|
|
31
|
+
|
|
32
|
+
```text
|
|
33
|
+
Requested 64 CPUs, but this host has 8
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Change CPU and RAM when you resume a stopped box or fork one:
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
raft resume "$box" --ttl 1800 --cpu 2 --memory 4GiB
|
|
40
|
+
copy=$(raft fork "$box" --ttl 1800 --memory 2GiB)
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Resume requires a stopped box; fork requires a stopped source. Omitted values
|
|
44
|
+
stay unchanged on resume and inherit the source limits on fork. Live resizing is
|
|
45
|
+
not exposed by the CLI. See [Snapshots and forks](../guides/snapshots-forks.mdx).
|
|
46
|
+
|
|
47
|
+
## Own box disks
|
|
48
|
+
|
|
49
|
+
By default every box stores its files in the shared 60 GiB Btrfs pool
|
|
50
|
+
`raft-data`. Boxes there grow until the pool is full, and Btrfs quotas cannot
|
|
51
|
+
hold them back: Docker and other tools create nested subvolumes that escape
|
|
52
|
+
Btrfs quotas.
|
|
53
|
+
|
|
54
|
+
`raft new --disk SIZE` gives the box its own disk instead: an LVM thin volume
|
|
55
|
+
of SIZE with an ext4 filesystem in the `raft-disks` pool. Everything the box
|
|
56
|
+
writes, including Docker images, layers and container files, lands in that
|
|
57
|
+
filesystem, so the box gets "No space left on device" at SIZE and cannot touch
|
|
58
|
+
other boxes' space. Raft reserves the whole SIZE in the pool when the box is
|
|
59
|
+
created, so other boxes cannot take it either.
|
|
60
|
+
|
|
61
|
+
Own box disks are opt-in per host. A host deployed without `--disk-pool` has no
|
|
62
|
+
`raft-disks` pool, which is a normal, healthy state: `raft doctor` and
|
|
63
|
+
`raft capacity` say own box disks are not enabled, and `new --disk` fails before
|
|
64
|
+
creating anything with the command that enables them.
|
|
65
|
+
|
|
66
|
+
- **Size**: whole GiB, such as `20GiB`. The development image holds about 5 GiB of files, so give boxes at least `8GiB`; a disk too small for the image fails at creation and leaves nothing behind. Disks of 10 GiB or more start fastest: smaller ones are shrunk after the copy. ext4 keeps a little of the volume for itself, so `df` shows slightly less than SIZE.
|
|
67
|
+
- **Copy-on-write**: a new own-disk box starts as a thin snapshot of the image, and forks, templates (`new --from`) and snapshots of own-disk boxes are thin snapshots of their source. They are created in seconds and share the source's blocks until they write their own.
|
|
68
|
+
- **Reservations**: each own disk, and each snapshot of one, reserves its full size in the pool, even though it shares blocks. A request that would reserve more than the pool holds fails before anything is created. See [Reservation accounting](#reservation-accounting).
|
|
69
|
+
- **Forks, templates and backups**: `fork` and `new --from` keep the source disk, shared or own, with the same size. `new --from BOX/SNAPSHOT --disk SIZE` copies a snapshot onto an own disk of a new size. `recover` puts an own-disk backup back onto an own disk of the same size, and needs the pool on the destination. Resume never changes the disk.
|
|
70
|
+
- **Inspection**: `raft list` reports `disk` as `"shared"` or the size; `raft info` shows it in `expanded_devices.root`; `raft usage` reports the filesystem's space with a `filesystemScope` of `own SIZE box disk`.
|
|
71
|
+
|
|
72
|
+
### Enabling the `raft-disks` pool
|
|
73
|
+
|
|
74
|
+
Pass `--disk-pool SIZE` to `raft host add`, or to
|
|
75
|
+
`python3 deploy/deploy.py --location LOCATION` on a host that is already
|
|
76
|
+
deployed. The deployer creates `raft-disks` beside `raft-data`: a loop-backed
|
|
77
|
+
LVM thin pool (`lvm.use_thinpool=true`) of SIZE. It allocates the pool's file on
|
|
78
|
+
the host disk in full, so every reservation is backed by real host space, and
|
|
79
|
+
it sets the thin pool to `--discards nopassdown`, so freed blocks return to the
|
|
80
|
+
pool without punching holes back into that file. A fresh host then needs 80 GiB
|
|
81
|
+
plus SIZE free; adding the pool later needs SIZE plus 20 GiB free.
|
|
82
|
+
|
|
83
|
+
Redeploying never resizes the pool: an explicit `--disk-pool` that differs from
|
|
84
|
+
the existing size is refused, and omitting it keeps the pool as it is. To change
|
|
85
|
+
the size, back up the own-disk boxes, delete them, remove the pool explicitly
|
|
86
|
+
with Incus and redeploy.
|
|
87
|
+
|
|
88
|
+
### Reservation accounting
|
|
89
|
+
|
|
90
|
+
A thin pool can promise its volumes more space than it holds, and when it fills
|
|
91
|
+
up every volume in it fails at once. Raft never lets that happen. A thin volume
|
|
92
|
+
can never hold more data than its own size, so as long as the sizes of all thin
|
|
93
|
+
volumes in the pool add up to no more than the pool's data space, the pool
|
|
94
|
+
cannot fill, however much the boxes write.
|
|
95
|
+
|
|
96
|
+
Under the host lock, before Incus adds a thin volume to `raft-disks`, Raft adds
|
|
97
|
+
up the size of every thin volume already there, as `lvs` reports it, and refuses
|
|
98
|
+
the request if the new volumes would not fit. The sum covers everything in the
|
|
99
|
+
pool: own-disk boxes, their snapshots, the cached image and anything an
|
|
100
|
+
operator created. Each operation adds:
|
|
101
|
+
|
|
102
|
+
| Operation | Adds |
|
|
103
|
+
| --- | --- |
|
|
104
|
+
| `new --disk SIZE` | The larger of SIZE and the cached image volume, plus the image volume itself the first time a box on this host needs it |
|
|
105
|
+
| `new --from BOX/SNAPSHOT` of an own-disk snapshot | The larger of the snapshot's size and `--disk` |
|
|
106
|
+
| `new --from BOX/SNAPSHOT --disk SIZE` of a shared-pool snapshot | SIZE |
|
|
107
|
+
| `fork` of an own-disk box | The box's size |
|
|
108
|
+
| `snapshot` of an own-disk box | The box's size |
|
|
109
|
+
| `recover` of an own-disk backup | The box's size once for the box and once per snapshot in the backup |
|
|
110
|
+
|
|
111
|
+
`restore` adds nothing: it swaps in a thin snapshot of the snapshot and removes
|
|
112
|
+
the old volume. Destroying a box or deleting a snapshot frees its reservation.
|
|
113
|
+
Incus caches the image in a 10 GiB volume (the pool's `volume.size` when set),
|
|
114
|
+
which stays reserved while the image is in use; plan the pool size as 10 GiB
|
|
115
|
+
plus the own disks and snapshots you want at once. The pool's data space is a
|
|
116
|
+
little below SIZE, because LVM keeps part of the file for thin pool metadata.
|
|
117
|
+
|
|
118
|
+
LVM sizes that metadata at 64 bytes per data block, above the 48 bytes per
|
|
119
|
+
block the kernel documentation recommends for a fully mapped pool, and
|
|
120
|
+
reservations keep the number of mapped blocks below the pool's block count. If
|
|
121
|
+
metadata ever filled, every own-disk box would stop and the pool would need
|
|
122
|
+
offline repair, so `raft capacity` warns when it passes 80%.
|
|
123
|
+
|
|
124
|
+
## Inspecting capacity with `raft capacity`
|
|
125
|
+
|
|
126
|
+
```sh title="CONTROLLER: View the advisory capacity estimate"
|
|
127
|
+
raft capacity
|
|
128
|
+
|
|
129
|
+
# Output JSON for programmatic inspection
|
|
130
|
+
raft capacity --location lab --json
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
```text
|
|
134
|
+
Advisory estimate only. Raft enforces no box count or size budget; create the boxes your task needs.
|
|
135
|
+
lab: 8 CPUs, 31.3 GiB RAM (27.9 GiB available)
|
|
136
|
+
Boxes: 3 saved, 2 active
|
|
137
|
+
Allocated to active boxes: 3 CPUs, 6.0 GiB; host reserve: 1 CPU, 3.1 GiB; headroom: 4 CPUs, 22.2 GiB
|
|
138
|
+
Disk free: 41.5 of 60.0 GiB shared pool, 48.2 GiB host
|
|
139
|
+
Own box disks: 19.9 of 39.9 GiB unreserved
|
|
140
|
+
CPU RAM GiB Fit on empty host Fit now
|
|
141
|
+
1 2 7 4
|
|
142
|
+
2 4 3 2
|
|
143
|
+
4 8 1 1
|
|
144
|
+
Counts assume every box uses its full CPU and RAM at once. Boxes share host CPUs, so more can run when they are not all busy. Any whole CPU count and GiB size works.
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
The table lists example shapes that double from the 1 CPU / 2 GiB default at
|
|
148
|
+
2 GiB per CPU, up to the largest that fits the host. For any other size, divide
|
|
149
|
+
`headroom` by the box's CPU and RAM.
|
|
150
|
+
|
|
151
|
+
### JSON fields
|
|
152
|
+
|
|
153
|
+
| Field | Meaning |
|
|
154
|
+
| --- | --- |
|
|
155
|
+
| `notice` | The advisory sentence above |
|
|
156
|
+
| `host` | CPUs, total and available RAM, free host disk, `sharedPool` space, and `boxDiskPool` |
|
|
157
|
+
| `host.boxDiskPool` | `null` when own box disks are not enabled. Otherwise `totalBytes` (thin pool data space), `reservedBytes` (sizes of all its thin volumes), `usedBytes` (data written) and `metadataUsedPercent`; the last two are `null` while no own-disk volume is active. New own disks fit in `totalBytes - reservedBytes` |
|
|
158
|
+
| `boxes`, `activeBoxes` | Saved boxes, and those not `Stopped` |
|
|
159
|
+
| `allocated` | CPU and RAM limits of active boxes |
|
|
160
|
+
| `reserve` | Host share left out of the estimates |
|
|
161
|
+
| `headroom` | CPU and RAM left for more active boxes after the reserve |
|
|
162
|
+
| `estimates` | Example shapes with `fitEmptyHost` and `fitNow` counts |
|
|
163
|
+
| `warnings` | Low RAM or disk, overcommitted boxes, or thin pool metadata above 80% |
|
|
164
|
+
|
|
165
|
+
### Calculations
|
|
166
|
+
|
|
167
|
+
| Value | Calculation |
|
|
168
|
+
| --- | --- |
|
|
169
|
+
| CPU reserve | 1 CPU for the host OS |
|
|
170
|
+
| Memory reserve | The larger of 2 GiB or 10% of host RAM |
|
|
171
|
+
| Fit on empty host | `min(floor((CPUs - 1) / box CPUs), floor((RAM - reserve) / box RAM))` |
|
|
172
|
+
| Fit now | The same with `headroom`, which also subtracts active allocations and keeps `MemAvailable - reserve` |
|
|
173
|
+
|
|
174
|
+
All non-`Stopped` states, such as `Running` or `Frozen`, count as active.
|
|
175
|
+
Stopped boxes use no CPU or RAM and keep their disk. Reserves are planning
|
|
176
|
+
margins, not cgroup locks.
|
|
177
|
+
|
|
178
|
+
### Illustrative hosts
|
|
179
|
+
|
|
180
|
+
Fit on empty host for 1 CPU / 2 GiB boxes, using exact usable RAM values:
|
|
181
|
+
|
|
182
|
+
| Host CPUs | Host RAM | Fit on empty host |
|
|
183
|
+
| ---: | ---: | ---: |
|
|
184
|
+
| 2 | 8 GiB | 1 |
|
|
185
|
+
| 4 | 8 GiB | 3 |
|
|
186
|
+
| 4 | 16 GiB | 3 |
|
|
187
|
+
| 8 | 32 GiB | 7 |
|
|
188
|
+
|
|
189
|
+
Operating systems report less usable RAM than the hardware size, so near
|
|
190
|
+
boundaries the estimate can be one lower. Available RAM and host processes can
|
|
191
|
+
lower it further. These are point-in-time estimates, not reservations.
|
|
192
|
+
|
|
193
|
+
## Disk warnings
|
|
194
|
+
|
|
195
|
+
`raft capacity` warns when free host disk or the shared pool falls below 5 GiB,
|
|
196
|
+
and when `raft-disks` thin pool metadata passes 80%. Warnings do not block
|
|
197
|
+
anything. `raft doctor` reports the shared pool and, when own box disks are
|
|
198
|
+
enabled, `raft-disks`; a host without `raft-disks` is healthy.
|
package/docs/reference/cli.md
CHANGED
|
@@ -14,6 +14,12 @@ Syntax:
|
|
|
14
14
|
and `raft --version` prints the installed version without loading configuration.
|
|
15
15
|
Output is command-specific; see [Scripting and CI](../guides/scripting-ci.mdx).
|
|
16
16
|
|
|
17
|
+
At most once a day, after a command finishes, Raft checks GitHub for a newer
|
|
18
|
+
release and prints one line on stderr, such as
|
|
19
|
+
`raft 0.6.0 is available (you have 0.5.0). Run: raft self-update`. It never
|
|
20
|
+
installs anything or changes stdout, and network failures stay silent. See
|
|
21
|
+
[`self-update`](#self-update) to turn it off.
|
|
22
|
+
|
|
17
23
|
Workspaces are referenced by location-qualified handles formatted as `<location>:<instance-name>` (for example `lab:rf-a1b2c3d4e5f60718`).
|
|
18
24
|
|
|
19
25
|
## Command index
|
|
@@ -28,7 +34,9 @@ Workspaces are referenced by location-qualified handles formatted as `<location>
|
|
|
28
34
|
| Port forwarding and desktop | [`forward`](#forward), [`desktop`](#desktop) |
|
|
29
35
|
| Backup and recovery | [`backup`](#backup), [`recover`](#recover) |
|
|
30
36
|
| Locations | [`host add`](#host-add), [`locations`](#locations), [`note`](#note) |
|
|
31
|
-
|
|
|
37
|
+
| Defaults and policies | [`config`](#config), [`policy`](#policy) |
|
|
38
|
+
| Host inspection and maintenance | [`capacity`](#capacity), [`doctor`](#doctor), [`list`](#list), [`gc`](#gc), [`prune`](#prune) |
|
|
39
|
+
| CLI maintenance | [`self-update`](#self-update) |
|
|
32
40
|
|
|
33
41
|
## Workspace lifecycle commands
|
|
34
42
|
|
|
@@ -36,18 +44,28 @@ Workspaces are referenced by location-qualified handles formatted as `<location>
|
|
|
36
44
|
|
|
37
45
|
Create and launch a new workspace container.
|
|
38
46
|
|
|
39
|
-
`raft new [--location LOCATION] [--ttl TTL] [--cpu
|
|
47
|
+
`raft new [--location LOCATION] [--ttl TTL] [--cpu N] [--memory SIZE] [--disk SIZE] [--disposable] [--from LOCATION:BOX/SNAPSHOT] [--purpose TEXT [--owner TEXT] [--next TEXT]]`
|
|
48
|
+
|
|
49
|
+
- `--location LOCATION`: Target host location in `~/.config/raft/incus.json`. Built-in default: first configured location.
|
|
50
|
+
- `--ttl TTL`: Lifetime in seconds before automatic stop (`60` to `2592000`). Built-in default: `600`.
|
|
51
|
+
- `--cpu N`: CPU limit, any whole number from `1` up to the host's CPU count. Built-in default: `1`, or the snapshot's with `--from`.
|
|
52
|
+
- `--memory SIZE`: Memory limit in whole GiB, for example `16GiB`, up to the host's RAM. Built-in default: `2GiB`, or the snapshot's with `--from`.
|
|
53
|
+
- `--disk SIZE`: Give the box its own disk of SIZE in whole GiB, for example `20GiB`, instead of the shared pool. Needs a host deployed with `--disk-pool`. The box, and Docker inside it, cannot write past SIZE, and the pool reserves SIZE when the box is created. `--disk shared` asks for the shared pool, overriding a configured `disk`. Built-in default: the shared pool, or with `--from` the snapshot's disk. See [Box sizing and own disks](./capacity.mdx#own-box-disks).
|
|
40
54
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
55
|
+
An omitted option takes the controller default set with [`config`](#config),
|
|
56
|
+
then the built-in default. With `--from`, configured `cpu`, `memory` and `disk`
|
|
57
|
+
defaults do not apply: the box keeps the snapshot's size unless a flag overrides
|
|
58
|
+
it, and `--disk shared` is refused.
|
|
45
59
|
|
|
46
60
|
- `--disposable`: Delete the box and snapshots on stop or expiry. Off by default.
|
|
47
|
-
- `--from LOCATION:BOX/SNAPSHOT`: Copy a named snapshot on its source host instead of the configured image.
|
|
61
|
+
- `--from LOCATION:BOX/SNAPSHOT`: Copy a named snapshot on its source host instead of the configured image. The box keeps the snapshot's CPU, RAM and disk unless `--cpu`, `--memory` or `--disk` overrides them; the source can be running. Cannot target a different location.
|
|
62
|
+
- `--purpose TEXT`, `--owner TEXT`, `--next TEXT`: Record a [box note](#note). `--owner` and `--next` need `--purpose`. Without them the box starts with no note, including boxes created `--from` a noted snapshot. A host [policy](#policy) can require fields.
|
|
48
63
|
|
|
49
64
|
Returns the qualified workspace handle. If the location has a note, `new` prints
|
|
50
|
-
it to stderr; stdout still contains only the handle.
|
|
65
|
+
it to stderr; stdout still contains only the handle. Raft limits neither the
|
|
66
|
+
number of boxes nor their size; requests larger than the whole host, own disks
|
|
67
|
+
on a host without `raft-disks`, or own disks larger than the unreserved
|
|
68
|
+
`raft-disks` space, fail with the reason before anything is created.
|
|
51
69
|
|
|
52
70
|
### `stop`
|
|
53
71
|
|
|
@@ -61,12 +79,13 @@ Terminates guest processes and stops the container. Persistent boxes retain file
|
|
|
61
79
|
|
|
62
80
|
Start a stopped workspace with a renewed lifetime deadline.
|
|
63
81
|
|
|
64
|
-
`raft resume <box> --ttl TTL [--cpu
|
|
82
|
+
`raft resume <box> --ttl TTL [--cpu N] [--memory SIZE]`
|
|
65
83
|
|
|
66
84
|
- `--ttl TTL`: Lifetime in seconds from resumption (`60` to `2592000`). Required.
|
|
67
85
|
|
|
68
86
|
CPU/RAM overrides on resume apply before startup. Omitted values stay unchanged.
|
|
69
|
-
A running box is rejected before changing its limits.
|
|
87
|
+
A running box is rejected before changing its limits. Resume never changes the
|
|
88
|
+
box's disk.
|
|
70
89
|
|
|
71
90
|
### `extend`
|
|
72
91
|
|
|
@@ -82,7 +101,7 @@ Permanently delete a workspace container and its snapshots.
|
|
|
82
101
|
|
|
83
102
|
`raft destroy <box>`
|
|
84
103
|
|
|
85
|
-
Stops the container if running, removes all associated
|
|
104
|
+
Stops the container if running, removes all associated snapshots, and releases its storage, including an own disk.
|
|
86
105
|
|
|
87
106
|
## Execution and inspection commands
|
|
88
107
|
|
|
@@ -108,13 +127,13 @@ Open an interactive root terminal session inside the workspace over host SSH and
|
|
|
108
127
|
|
|
109
128
|
### `info`
|
|
110
129
|
|
|
111
|
-
Display container metadata from Incus in JSON format, including status, IP addresses, resource limits, and timestamps.
|
|
130
|
+
Display container metadata from Incus in JSON format, including status, IP addresses, resource limits, and timestamps. `expanded_devices.root` shows the disk: `pool: raft-data` for the shared pool, or `pool: raft-disks` with the own disk's `size`.
|
|
112
131
|
|
|
113
132
|
`raft info <box>`
|
|
114
133
|
|
|
115
134
|
### `usage`
|
|
116
135
|
|
|
117
|
-
Display active resource consumption for a running workspace: cgroup memory, CPU microseconds, CPU affinity, and shared
|
|
136
|
+
Display active resource consumption for a running workspace: cgroup memory, CPU microseconds, CPU affinity, and filesystem space. `filesystemScope` says whether the space is the shared pool or the box's own disk.
|
|
118
137
|
|
|
119
138
|
`raft usage <box>`
|
|
120
139
|
|
|
@@ -174,6 +193,8 @@ Create a named point-in-time snapshot of a stopped workspace. Names use alphanum
|
|
|
174
193
|
|
|
175
194
|
`raft snapshot <box> <name>`
|
|
176
195
|
|
|
196
|
+
A snapshot of a box with its own disk is a thin snapshot that reserves the box's disk size in `raft-disks`; it fails before anything is created when the pool lacks unreserved space.
|
|
197
|
+
|
|
177
198
|
### `snapshots`
|
|
178
199
|
|
|
179
200
|
List existing snapshots and creation timestamps for a workspace.
|
|
@@ -196,11 +217,13 @@ Roll back a stopped workspace filesystem to a named snapshot using `--diskonly`,
|
|
|
196
217
|
|
|
197
218
|
Clone a stopped workspace into an independent container on the same host and start it.
|
|
198
219
|
|
|
199
|
-
`raft fork <box> --ttl TTL [--cpu
|
|
220
|
+
`raft fork <box> --ttl TTL [--cpu N] [--memory SIZE] [--disposable] [--purpose TEXT [--owner TEXT] [--next TEXT]]`
|
|
200
221
|
|
|
201
222
|
- `--ttl TTL`: Lifetime in seconds for the clone. Required.
|
|
223
|
+
- `--purpose TEXT`, `--owner TEXT`, `--next TEXT`: Replace the clone's whole note. Without them the clone keeps the source note.
|
|
202
224
|
|
|
203
|
-
Omitted CPU/RAM values inherit the source limits. The clone is persistent unless `--disposable` is supplied, regardless of the source policy.
|
|
225
|
+
Omitted CPU/RAM values inherit the source limits; controller defaults never apply to forks. The clone keeps the source's disk: the shared pool, or an own disk of the same size as a thin snapshot, which reserves that size in `raft-disks`. To copy a box onto a disk of another size, snapshot it and use `new --from BOX/SNAPSHOT --disk SIZE`. The clone is persistent unless `--disposable` is supplied, regardless of the source policy.
|
|
226
|
+
The note the clone ends up with must satisfy the host [policy](#policy).
|
|
204
227
|
|
|
205
228
|
Returns the qualified handle of the clone.
|
|
206
229
|
|
|
@@ -239,12 +262,17 @@ Export a stopped workspace and its snapshots to a compressed archive on the cont
|
|
|
239
262
|
|
|
240
263
|
Import a portable backup archive onto a host as a fresh stopped workspace.
|
|
241
264
|
|
|
242
|
-
`raft recover <source> --location LOCATION`
|
|
265
|
+
`raft recover <source> --location LOCATION [--purpose TEXT [--owner TEXT] [--next TEXT]]`
|
|
243
266
|
|
|
244
267
|
- `<source>`: Path to archive file on controller.
|
|
245
268
|
- `--location LOCATION`: Target host location. Required.
|
|
269
|
+
- `--purpose TEXT`, `--owner TEXT`, `--next TEXT`: Replace the recovered box's whole note. Without them it keeps the archived note.
|
|
270
|
+
|
|
271
|
+
Under a host [policy](#policy), a given note is checked before the upload. An
|
|
272
|
+
archived note is checked after import; if it fails, the imported box is deleted
|
|
273
|
+
in the same locked step.
|
|
246
274
|
|
|
247
|
-
Returns the qualified handle of the imported stopped workspace.
|
|
275
|
+
Returns the qualified handle of the imported stopped workspace. A backup of a box with its own disk is recovered onto an own disk of the same size in `raft-disks`, which must exist on the destination and have room to reserve that size for the box and each of its snapshots; any other backup lands in the shared pool.
|
|
248
276
|
|
|
249
277
|
## Location commands
|
|
250
278
|
|
|
@@ -252,19 +280,20 @@ Returns the qualified handle of the imported stopped workspace.
|
|
|
252
280
|
|
|
253
281
|
Check, provision and register a new workspace host, then prove it works.
|
|
254
282
|
|
|
255
|
-
`raft host add LOCATION --ssh TARGET [--image-release TAG | --image-archive PATH | --build] [--dry-run] [--yes]`
|
|
283
|
+
`raft host add LOCATION --ssh TARGET [--image-release TAG | --image-archive PATH | --build] [--disk-pool SIZE] [--dry-run] [--yes]`
|
|
256
284
|
|
|
257
285
|
- `LOCATION`: New location name. Existing locations are rejected.
|
|
258
286
|
- `--ssh TARGET`: Key-based SSH target, such as `ubuntu@192.0.2.10` or an `~/.ssh/config` alias. Accept the host key interactively first.
|
|
259
287
|
- `--image-release TAG`: Download `raft-dev-<arch>.tar.gz` from this release on the host and verify it against the release `SHA256SUMS`. Default: the CLI's own version.
|
|
260
288
|
- `--image-archive PATH`: Upload and import a local image archive instead.
|
|
261
289
|
- `--build`: Build the image on the host from Debian 13 instead.
|
|
290
|
+
- `--disk-pool SIZE`: Enable [own box disks](./capacity.mdx#own-box-disks) with a `raft-disks` thin pool of SIZE, in whole GiB. Default: not enabled. The pool's file takes its full size on the host disk when created. To enable them on a host that is already deployed, run `python3 deploy/deploy.py --location LOCATION --disk-pool SIZE`. An existing pool keeps its size; a different explicit value is refused.
|
|
262
291
|
- `--dry-run`: Probe the host and print the plan without changing anything.
|
|
263
292
|
- `--yes`: Apply the plan without the interactive prompt. Without a terminal, `--yes` is required.
|
|
264
293
|
|
|
265
294
|
Before any change, a read-only probe checks SSH, passwordless sudo, Ubuntu 22.04 or
|
|
266
295
|
24.04, ARM64 or AMD64, python3, at least 2 CPUs, 8 GiB RAM and, for a fresh host,
|
|
267
|
-
80 GiB free disk. Unsupported targets, including macOS, fail with the reasons and
|
|
296
|
+
80 GiB of free disk, plus the `--disk-pool` size when given. Unsupported targets, including macOS, fail with the reasons and
|
|
268
297
|
no changes. The command then runs the deployer, imports the image only if its
|
|
269
298
|
checksum and architecture match, adds the location with the pinned fingerprint,
|
|
270
299
|
and runs `doctor` plus a disposable create/exec/destroy smoke test. If the final
|
|
@@ -291,31 +320,101 @@ Prints one JSON object per location (JSONL) in configuration order, with
|
|
|
291
320
|
|
|
292
321
|
### `note`
|
|
293
322
|
|
|
294
|
-
Set or clear
|
|
323
|
+
Set or clear the note of a location or a box.
|
|
295
324
|
|
|
296
325
|
`raft note LOCATION TEXT`
|
|
297
326
|
`raft note LOCATION --clear`
|
|
327
|
+
`raft note BOX --purpose TEXT [--owner TEXT] [--next TEXT]`
|
|
328
|
+
`raft note BOX --clear`
|
|
329
|
+
|
|
330
|
+
Location notes are operator guidance stored in `~/.config/raft/incus.json`. Use
|
|
331
|
+
them to record which host is preferred or what a host should not run. Raft shows
|
|
332
|
+
them in `locations`, `capacity` and `new`.
|
|
333
|
+
|
|
334
|
+
Box notes tell other agents and people why a box exists. They follow one
|
|
335
|
+
template, stored on the box as JSON in the Incus key `user.raft.note`:
|
|
336
|
+
|
|
337
|
+
| Field | Meaning | Example |
|
|
338
|
+
| --- | --- | --- |
|
|
339
|
+
| `purpose` (required) | What the box is for | `Integration tests for PR 42` |
|
|
340
|
+
| `owner` | Who uses it | `codex session in ~/work/app` |
|
|
341
|
+
| `next` | What happens to it next | `Destroy after the tests pass` |
|
|
342
|
+
|
|
343
|
+
Each call replaces the whole note, on running or stopped boxes. `raft list`
|
|
344
|
+
shows it as `note`. Forks and recovered backups keep the source box's note
|
|
345
|
+
unless `fork` or `recover` gets note flags; update it if the copy has a
|
|
346
|
+
different job.
|
|
347
|
+
|
|
348
|
+
Empty values are rejected; use `--clear` to remove a note. A host
|
|
349
|
+
[policy](#policy) can require fields, and then rejects notes and `--clear` that
|
|
350
|
+
would leave them out. Otherwise Raft does not interpret notes.
|
|
351
|
+
|
|
352
|
+
### `config`
|
|
353
|
+
|
|
354
|
+
Show or change the controller defaults for `new`.
|
|
355
|
+
|
|
356
|
+
`raft config`
|
|
357
|
+
`raft config set KEY VALUE`
|
|
358
|
+
`raft config unset KEY`
|
|
359
|
+
|
|
360
|
+
- `KEY`: One of `location`, `ttl`, `cpu`, `memory`, `disk`.
|
|
361
|
+
- `VALUE`: Accepted exactly when the same text is accepted by the matching `new` flag. A `location` must be configured.
|
|
362
|
+
|
|
363
|
+
`cpu`, `memory` and `disk` size only boxes created from the image. `new --from`
|
|
364
|
+
and `fork` keep the source's CPU, RAM and disk; only explicit flags change them.
|
|
365
|
+
A `disk` default on a location without `raft-disks`, or larger than its
|
|
366
|
+
unreserved space, fails `new` with the same error as `--disk`, plus a sentence
|
|
367
|
+
naming `defaults.disk` as the source. `--disk shared` overrides it for one box.
|
|
368
|
+
|
|
369
|
+
Defaults live in `~/.config/raft/config.json` as `{"defaults": {"KEY": VALUE}}`.
|
|
370
|
+
`set` and `unset` print the old and new value, write atomically under a
|
|
371
|
+
controller lock and keep mode `0600`. An unknown key, bad value or malformed
|
|
372
|
+
file makes `new` fail with the file path and key; `set` or `unset` that key to
|
|
373
|
+
repair it.
|
|
374
|
+
|
|
375
|
+
`raft config` prints one JSON object: `file`, `defaults` (each key's `value` and
|
|
376
|
+
`source`, `config` or `built-in`) and `policy` (each location's `require` list
|
|
377
|
+
and `changed` record). It contacts every configured host to read policies.
|
|
378
|
+
See [Defaults and note policies](../guides/config-policy.mdx).
|
|
298
379
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
380
|
+
### `policy`
|
|
381
|
+
|
|
382
|
+
Set or clear the box note fields a location's host requires.
|
|
383
|
+
|
|
384
|
+
`raft policy LOCATION --require FIELDS`
|
|
385
|
+
`raft policy LOCATION --clear`
|
|
386
|
+
|
|
387
|
+
- `--require FIELDS`: Comma-separated fields from `purpose`, `owner`, `next`. Must include `purpose`.
|
|
388
|
+
- `--clear`: Stop requiring fields.
|
|
389
|
+
|
|
390
|
+
The policy is stored on the host in the Incus project key `user.raft.require`,
|
|
391
|
+
so it applies to every controller. `new`, `fork`, `recover` and `note` check it
|
|
392
|
+
on the controller for an actionable error, then again in the host transaction
|
|
393
|
+
that writes the note. The command prints the change and the host records the
|
|
394
|
+
time, SSH account and controller in `user.raft.require.changed` and the host
|
|
395
|
+
journal (`journalctl -t raft`).
|
|
396
|
+
|
|
397
|
+
This is a guardrail for agents, not a security boundary: SSH and sudo on the
|
|
398
|
+
host can change the policy or bypass it, and older controllers do not check it.
|
|
302
399
|
|
|
303
400
|
## Host inspection and maintenance commands
|
|
304
401
|
|
|
305
|
-
### `
|
|
402
|
+
### `capacity`
|
|
306
403
|
|
|
307
|
-
|
|
404
|
+
Estimate how many more boxes a host can run well. The report is advice: Raft
|
|
405
|
+
enforces no box count or size budget, so create the boxes your task needs.
|
|
308
406
|
|
|
309
|
-
`raft
|
|
407
|
+
`raft capacity [--location LOCATION] [--json]`
|
|
310
408
|
|
|
311
409
|
- `--location LOCATION`: Filter report to a specific host.
|
|
312
410
|
- `--json`: Output report as JSON.
|
|
313
411
|
|
|
314
|
-
Each report includes the location's `note`,
|
|
412
|
+
Each report leads with that advisory notice and includes the location's `note`,
|
|
413
|
+
if any. See [Box sizing and capacity](./capacity.mdx) for the fields.
|
|
315
414
|
|
|
316
415
|
### `doctor`
|
|
317
416
|
|
|
318
|
-
Inspect host connectivity, Incus version, expiry-worker compatibility, active systemd units (`incus`, `raft-expire.timer`, `raft-network.service`), root filesystem usage,
|
|
417
|
+
Inspect host connectivity, Incus version, expiry-worker compatibility, active systemd units (`incus`, `raft-expire.timer`, `raft-network.service`), root filesystem usage, status of the shared `raft-data` pool and, when own box disks are enabled, the `raft-disks` pool, and saved box count across configured hosts. Without `raft-disks` it prints `own box disks: not enabled (redeploy with --disk-pool SIZE)` and does not fail. An incompatible worker returns a nonzero exit status and names the failing location without running expiry or modifying boxes.
|
|
319
418
|
|
|
320
419
|
`raft doctor`
|
|
321
420
|
|
|
@@ -325,7 +424,9 @@ List existing workspace containers across configured hosts.
|
|
|
325
424
|
|
|
326
425
|
`raft list [--location LOCATION]`
|
|
327
426
|
|
|
328
|
-
Prints one JSON object per box (JSONL), with `box`, `state`, and `
|
|
427
|
+
Prints one JSON object per box (JSONL), with `box`, `state`, `stopAt`, `disk` and `note` fields.
|
|
428
|
+
`disk` is `"shared"` for the shared pool or the own disk's size, such as `"20GiB"`.
|
|
429
|
+
`note` is the box note object, or `null` when the box has none.
|
|
329
430
|
An empty inventory prints no records. See [Scripting and CI](../guides/scripting-ci.mdx)
|
|
330
431
|
for output formats, exit codes, readiness, and failure handling.
|
|
331
432
|
|
|
@@ -344,3 +445,39 @@ Preview deletion of persistent stopped boxes older than the selected number of d
|
|
|
344
445
|
Days must be at least one. Without `--yes`, this only prints JSONL candidates. With `--yes`, it deletes matching boxes and their snapshots under the host lock. Running boxes and boxes without a recorded stop time are excluded. Stop timestamps come from Raft stop/expiry, not box creation. No automatic retention policy is enabled.
|
|
345
446
|
|
|
346
447
|
Disposable creation/fork and prune require the current expiry worker installed through the deployer. A mismatch fails with deployment guidance; the CLI does not install or adapt an older worker.
|
|
448
|
+
|
|
449
|
+
## CLI maintenance commands
|
|
450
|
+
|
|
451
|
+
### `self-update`
|
|
452
|
+
|
|
453
|
+
Upgrade the installed CLI to the latest GitHub release, or to a chosen one.
|
|
454
|
+
|
|
455
|
+
`raft self-update [--check | --version X.Y.Z]`
|
|
456
|
+
|
|
457
|
+
- `--check`: Report whether a newer release exists without installing it. Exits `0` when the CLI is current and `100` when an update is available.
|
|
458
|
+
- `--version X.Y.Z`: Install this release instead of the latest, for example to roll back. Without it, `self-update` never downgrades.
|
|
459
|
+
|
|
460
|
+
The latest release on GitHub decides what is current. `self-update` installs
|
|
461
|
+
through the channel that installed the running copy and never switches channel:
|
|
462
|
+
|
|
463
|
+
| Installed with | Detected by | Upgrade | Integrity |
|
|
464
|
+
| --- | --- | --- | --- |
|
|
465
|
+
| `npm install -g @microck/raft` | `PREFIX/lib/node_modules/@microck/raft`, linked from `PREFIX/bin/raft` | `npm install --global --prefix PREFIX @microck/raft@X.Y.Z` | npm checks the registry integrity hash; Raft publishes with npm provenance |
|
|
466
|
+
| `uv tool install` of a release wheel | A uv tool environment named `raft` | Downloads the wheel and `SHA256SUMS` from the release, then `uv tool install --force` | Refuses a wheel whose SHA-256 differs from the release `SHA256SUMS` |
|
|
467
|
+
|
|
468
|
+
Source checkouts, editable installs, pip and other layouts are refused with
|
|
469
|
+
instructions. For a uv tool, `uv tool dir` must still name the original tool
|
|
470
|
+
directory; set `UV_TOOL_DIR` if it moved.
|
|
471
|
+
|
|
472
|
+
`self-update` prints `raft OLD -> NEW` and the release notes link. A current CLI
|
|
473
|
+
is a no-op. Hosts are not changed: run [`doctor`](#doctor) next. If a host's
|
|
474
|
+
worker differs from the new CLI, redeploy that host from the same release; see
|
|
475
|
+
[Upgrades and image changes](../guides/upgrades.mdx). After an update,
|
|
476
|
+
[`host add`](#host-add) downloads the new release's image by default. Existing
|
|
477
|
+
image pins stay unchanged.
|
|
478
|
+
|
|
479
|
+
Set `RAFT_NO_UPDATE_CHECK=1` to turn off the daily release notice, for example in
|
|
480
|
+
pinned or scripted runs. The notice caches its last result in
|
|
481
|
+
`$XDG_CACHE_HOME/raft/update.json` (default `~/.cache/raft/update.json`). It
|
|
482
|
+
waits at most 2 seconds for GitHub and is skipped for `self-update` and
|
|
483
|
+
`--version`.
|
|
@@ -40,7 +40,7 @@ The configuration file maps location names to host definition objects:
|
|
|
40
40
|
### Location keys
|
|
41
41
|
|
|
42
42
|
- **Naming format**: Matches `^[a-zA-Z0-9][a-zA-Z0-9_-]*$`. Starts with an alphanumeric character and contains ASCII letters, digits, underscores, or hyphens.
|
|
43
|
-
- **Default location**: The first location listed is the default for `raft new`. `raft list`, `raft
|
|
43
|
+
- **Default location**: The first location listed is the default for `raft new`. `raft list`, `raft capacity`, `raft gc`, and `raft prune` accept `--location` filters. Without a filter they check all configured hosts; `raft doctor` always checks all configured hosts.
|
|
44
44
|
|
|
45
45
|
### Host entry fields
|
|
46
46
|
|
|
@@ -60,7 +60,7 @@ raft note spare --clear
|
|
|
60
60
|
```
|
|
61
61
|
|
|
62
62
|
`raft note` rewrites the file with two-space indentation, keeps location order and
|
|
63
|
-
mode `0600`. `raft locations`, `raft
|
|
63
|
+
mode `0600`. `raft locations`, `raft capacity` and `raft new` show the note.
|
|
64
64
|
|
|
65
65
|
<Callout type="warn" title="Replace placeholder image fingerprint">
|
|
66
66
|
The `image` field requires the full 64-character hash for `raft new`; aliases such as `raft-dev` are rejected. Replace the example hash with the actual imported image fingerprint for that host.
|
|
@@ -68,6 +68,40 @@ The `image` field requires the full 64-character hash for `raft new`; aliases su
|
|
|
68
68
|
ARM64 and AMD64 images produce different fingerprints; do not reuse an ARM64 hash on an AMD64 host.
|
|
69
69
|
</Callout>
|
|
70
70
|
|
|
71
|
+
## Defaults for new
|
|
72
|
+
|
|
73
|
+
`~/.config/raft/config.json` is optional. It sets defaults for `raft new` on this
|
|
74
|
+
controller and is separate from the location inventory:
|
|
75
|
+
|
|
76
|
+
```json title="Example ~/.config/raft/config.json"
|
|
77
|
+
{
|
|
78
|
+
"defaults": {
|
|
79
|
+
"location": "lab",
|
|
80
|
+
"ttl": 3600,
|
|
81
|
+
"cpu": 2,
|
|
82
|
+
"memory": "4GiB",
|
|
83
|
+
"disk": "20GiB"
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
| Key | Accepted values | Built-in default |
|
|
89
|
+
| :--- | :--- | :--- |
|
|
90
|
+
| `location` | A configured location name | First configured location |
|
|
91
|
+
| `ttl` | `60` to `2592000` seconds | `600` |
|
|
92
|
+
| `cpu` | A positive whole number | `1` |
|
|
93
|
+
| `memory` | Whole GiB, e.g. `16GiB` | `2GiB` |
|
|
94
|
+
| `disk` | Whole GiB for an own box disk, or `shared` | `shared` |
|
|
95
|
+
|
|
96
|
+
Explicit flags win over these values. `cpu`, `memory` and `disk` size only boxes
|
|
97
|
+
created from the image: `new --from` and `fork` keep the source's size unless a
|
|
98
|
+
flag overrides it. A `disk` default needs the `raft-disks` pool on the target
|
|
99
|
+
host, like `--disk`. Unknown keys and invalid values make
|
|
100
|
+
`raft new` fail with the file path and key. Edit the file with
|
|
101
|
+
`raft config set KEY VALUE` and `raft config unset KEY`, and inspect it with
|
|
102
|
+
`raft config`. Required box note fields are a host policy, not part of this
|
|
103
|
+
file; see [Defaults and note policies](../guides/config-policy.mdx).
|
|
104
|
+
|
|
71
105
|
## SSH configuration and connection behavior
|
|
72
106
|
|
|
73
107
|
Primary remote commands (`raft ssh`, `upload`, `download`, and control commands) run OpenSSH with `BatchMode=yes` and `-o ConnectTimeout=10` to fail fast on unreachable hosts. The timeout applies to initial connection establishment, not session or transfer duration.
|
package/docs/reference/meta.json
CHANGED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Raft 0.4.0
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Raft 0.4.0
|
|
6
|
+
|
|
7
|
+
- Boxes accept a note that says why they exist, so agents and people can tell which boxes are in use. The note follows one template: `purpose` (required), `owner` and `next`.
|
|
8
|
+
- `raft new --purpose TEXT [--owner TEXT] [--next TEXT]` notes a box when it is created. `raft note BOX --purpose ...` replaces a box's note and `raft note BOX --clear` removes it. `raft note LOCATION ...` still edits location notes.
|
|
9
|
+
- `raft list` adds a `note` field to each box: the note object, or `null`.
|
|
10
|
+
- Forks and recovered backups keep the source box's note. `new --from` starts without one.
|
|
11
|
+
- The `raft-cli` agent skill asks agents to note every box they create and to read notes before resuming, stopping, forking or destroying a box.
|
|
12
|
+
|
|
13
|
+
Install on Linux with Python 3.11.8+ using `npm install -g @microck/raft@0.4.0`, or install the attached Python wheel. Box notes live in each box's Incus configuration; host workers are unchanged and need no redeployment.
|
|
14
|
+
|
|
15
|
+
ARM64 and AMD64 development images accompany this release. Verify `SHA256SUMS` before importing an image for your host architecture.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Raft 0.5.0
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Raft 0.5.0
|
|
6
|
+
|
|
7
|
+
- **No box cap.** A location no longer stops at four saved boxes. Agents create the boxes their task needs; creation only fails for real reasons such as a full pool.
|
|
8
|
+
- **Any size.** `--cpu N` and `--memory NGiB` accept any positive size up to the host's CPUs and RAM. A box from the image gets 1 CPU, 2 GiB and the shared disk; `new --from` and `fork` keep the source's CPU, RAM and disk, and each flag overrides only its own value.
|
|
9
|
+
- **Own box disks.** `raft new --disk SIZE` gives a box its own ext4 disk with a hard cap that also holds for Docker inside the box. Own disks are opt-in per host: redeploy with `--disk-pool SIZE` to create the thin LVM pool `raft-disks`. New boxes, forks, template copies and snapshots are copy-on-write, and a reservation check refuses any request that would overcommit the pool. `raft list` shows each box's `disk`.
|
|
10
|
+
- **`raft capacity` replaces `raft limits`.** It is advisory only: it reports host CPUs, RAM, allocations, both pools and how many more boxes of example sizes fit, and never limits creation. JSON fields changed (`boxes`, `estimates`, `sharedPool`, `boxDiskPool`, `headroom`, `notice`).
|
|
11
|
+
- **`raft self-update`.** Updates the CLI through the channel that installed it: npm, or a uv tool from the release wheel verified against `SHA256SUMS`. `--check` reports without installing (exit 100 when an update exists) and `--version X.Y.Z` installs a specific release. A notice on stderr at most once a day says when a newer release exists; `RAFT_NO_UPDATE_CHECK=1` turns it off. It never installs on its own and never changes hosts.
|
|
12
|
+
- **Controller defaults.** `raft config`, `raft config set KEY VALUE` and `raft config unset KEY` manage `~/.config/raft/config.json` with defaults for `location`, `ttl`, `cpu`, `memory` and `disk`. A flag beats the config, which beats the built-in default. `--disk shared` overrides a configured disk default for one box.
|
|
13
|
+
- **Note policies.** `raft policy LOCATION --require purpose,owner` makes a host require those box note fields. `new`, `fork`, `recover` and `note` refuse a box without them, with an error naming the missing flag, and the host checks again under its lock. Policy changes are recorded on the host and in its journal. This is a guardrail for agents, not a security boundary.
|
|
14
|
+
|
|
15
|
+
Install on Linux with Python 3.11.8+ using `npm install -g @microck/raft@0.5.0`, or install the attached Python wheel; existing installs can run `raft self-update`.
|
|
16
|
+
|
|
17
|
+
Redeploy each host with this release's `deploy/deploy.py`. It installs `lvm2` and `python3-yaml`, which `raft recover` now needs to read backups, and changes nothing else unless you add `--disk-pool SIZE` to enable own box disks. That needs SIZE plus 20 GiB free on the host; existing storage is never resized.
|
|
18
|
+
|
|
19
|
+
ARM64 and AMD64 development images accompany this release. Verify `SHA256SUMS` before importing an image for your host architecture.
|
package/docs/requirements.mdx
CHANGED
|
@@ -17,11 +17,11 @@ Each workspace host must be a dedicated physical machine or virtual instance:
|
|
|
17
17
|
| **Operating system** | Ubuntu 22.04 LTS or 24.04 LTS | The deployer installs Incus 6.0 LTS and nftables bridge isolation rules. |
|
|
18
18
|
| **CPU** | At least 2 CPU cores | Capacity calculations reserve 1 CPU core for the host OS and services (an advisory estimate, not an enforced host reservation). |
|
|
19
19
|
| **RAM** | At least 8 GiB | Sizing calculations reserve the larger of 2 GiB or 10% of host RAM (an advisory estimate, not an enforced host reservation). |
|
|
20
|
-
| **Free disk** | At least 80 GiB on host disk |
|
|
20
|
+
| **Free disk** | At least 80 GiB on host disk | For the 60 GiB shared Btrfs pool (`raft-data`), images and the host. [Own box disks](./reference/capacity.mdx#own-box-disks) are optional: `--disk-pool SIZE` adds a `raft-disks` pool of SIZE, so a fresh host then needs 80 GiB plus SIZE, and an existing host SIZE plus 20 GiB. |
|
|
21
21
|
|
|
22
22
|
`raft host add` checks these requirements read-only before it changes a host.
|
|
23
23
|
|
|
24
|
-
Host CPU and RAM reserves are advisory estimates for `raft
|
|
24
|
+
Host CPU and RAM reserves are advisory estimates for `raft capacity`, not enforced cgroup locks. Raft limits neither how many boxes a host runs nor their size.
|
|
25
25
|
|
|
26
26
|
<Callout type="warn" title="Dedicated host requirement">
|
|
27
27
|
Do not deploy Raft on hosts with existing Incus storage pools or shared virtualization workloads. Deployment configures dedicated nftables rules, storage pools, and system services.
|