mirror of
https://github.com/nestriness/nestri.git
synced 2026-09-24 03:28:18 +03:00
feat: resident guest init (#333)
Get this thing going..
<!-- greptile_comment -->
<!-- greptile_summary -->
<h2><a
href="https://app.greptile.com/api/retrigger?id=63134761"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/RetriggerDark.svg?v=1"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/Retrigger.svg?v=1"><img
alt="Retrigger"
src="https://greptile-static-assets.s3.amazonaws.com/badges/Retrigger.svg?v=1"
align="right"></picture></a>Confidence Score: 5/5</h2>
The PR appears safe to merge; all previous findings are resolved and the
latest readiness change introduces no established actionable regression.
<h3>Summary</h3>
- Establishes required guest filesystems, runtime directories, device
permissions, and service processes.
- Reports initialization and service deaths over the lifecycle channel.
- Supports launch, restart, and shutdown commands for a resident guest.
- Separates service and workload identities and configures per-launch
runtime environments.
- Removes the currently inactive nescope screenshot option and makes
capture-chain verification fail explicitly when compositor readback is
unavailable.
- Reworks the guest image around `nesinit` as PID 1 without a
distribution service manager.
<h3>Diagram</h3>
```mermaid
sequenceDiagram
participant Host
participant Init as nesinit
participant FS as Guest filesystems
participant Services as Service stack
participant Workload
Init->>Host: Ready(protocol version)
Host->>Init: Boot(mount descriptors)
Init->>FS: Establish and mount shares
Init->>Services: Spawn services in order
Services-->>Init: Required sockets ready
Init->>Host: Initialized(service names)
Host->>Init: Launch(id, exec, on_exit)
Init->>Workload: Spawn with isolated UID/runtime
Init->>Host: Started(id)
Workload-->>Init: Exit status
Init->>Host: WorkloadExited(id, status)
Host->>Init: Launch / Restart / Shutdown
```
<sub>Reviews (4) · Last reviewed commit: ["fix(nesinit): readiness is a
socket
that..."](731d34df9d)</sub>
<!-- /greptile_comment -->
---------
Co-authored-by: DatCaptainHorse <DatCaptainHorse@users.noreply.github.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
committed by
GitHub
parent
ec8b13d0c9
commit
8246aa5538
@@ -2,8 +2,9 @@
|
||||
|
||||
PID 1 inside a box.
|
||||
|
||||
A microVM has no init unless something is it. Three of the jobs are nobody
|
||||
else's, and this is all of them:
|
||||
A microVM has no init unless something is it, and in a box nothing else is:
|
||||
there is no service manager in the image and no init scripts. Four jobs, and
|
||||
this is all of them:
|
||||
|
||||
- **Reaping.** A process whose parent dies is reparented to PID 1. Without a
|
||||
reaper, every orphan the workload leaves behind holds a pid and a slot in the
|
||||
@@ -11,25 +12,46 @@ else's, and this is all of them:
|
||||
- **Ordered shutdown.** The workload stops first and alone, then everything
|
||||
else, then the disks are flushed and the machine is powered off. An init that
|
||||
returns leaves a guest running with nothing in it.
|
||||
- **The box's own services.** The bus, audio, and the transport that carries a
|
||||
session out, started in order from a table compiled into this binary. There
|
||||
is no unit format and no directory of files to read: the services in a box
|
||||
are fixed, and running on any distribution comes from depending on none of
|
||||
their init scripts rather than from being configurable.
|
||||
- **The guest end of the control channel.** One vsock connection out, carrying
|
||||
what to run in and what happened back.
|
||||
|
||||
It does not know what it is running. It is handed a command line, a set of
|
||||
shares and what an exit means; there is no code path here that branches on
|
||||
which workload it started, and there is not meant to be.
|
||||
It does not know what it is running. It is handed a set of shares, and then
|
||||
commands naming what to run and what an exit means; there is no code path here
|
||||
that branches on which workload it started, and there is not meant to be.
|
||||
|
||||
**A box outlives what runs in it.** Init mounts, brings the services up, says
|
||||
it is ready, and then takes commands for as long as the box lives — so this
|
||||
image on its own runs nothing at all, and a box may be launched into more than
|
||||
once.
|
||||
|
||||
### The channel
|
||||
|
||||
The guest dials out on a fixed vsock port and speaks first:
|
||||
|
||||
```
|
||||
guest → { "type": "ready", "protocol_version": 2 }
|
||||
guest ← { "type": "boot", "exec": {...}, "mounts": [...], "geometry": {...}, "on_exit": {...} }
|
||||
guest → { "type": "ready", "protocol_version": 3 }
|
||||
guest ← { "type": "boot", "mounts": [...] }
|
||||
guest → { "type": "mounted" }
|
||||
guest → { "type": "started" }
|
||||
guest → { "type": "workload_exited", "exit_code": 0 }
|
||||
guest → { "type": "initialized", "services": ["dbus-system", ...] }
|
||||
guest ← { "type": "launch", "id": "…", "exec": {...}, "on_exit": {...} }
|
||||
guest → { "type": "started", "id": "…" }
|
||||
guest → { "type": "workload_exited", "id": "…", "exit_code": 0 }
|
||||
```
|
||||
|
||||
`ready` is the handshake and `initialized` is the box working. They are two
|
||||
facts and must not be treated as one: a caller that waits on the first has a
|
||||
wait that succeeds before anything in the guest has started.
|
||||
|
||||
Every launch carries an id and every message about a launch carries it back.
|
||||
Without one, a second launch's exit is indistinguishable from the first's —
|
||||
which reads at the far end as a finished session still running, or a running
|
||||
one reported as stopped.
|
||||
|
||||
Newline-delimited JSON. Dialling out rather than being connected to is worth
|
||||
keeping for two reasons: the listener is up before the VM starts, so nothing
|
||||
races a booting kernel and nothing has to retry, and the connection
|
||||
@@ -109,19 +131,40 @@ later for no visible reason.
|
||||
|
||||
### It reports; it does not supervise
|
||||
|
||||
When the workload ends, the exit goes up the channel and the session is over.
|
||||
`on_exit` says what that exit *means* — whether it ends the session — and
|
||||
nothing here restarts anything. Starting something again is a decision for the
|
||||
end that can see whether restarting is repair or a loop.
|
||||
When a launch ends, the exit goes up the channel. `on_exit` says what that exit
|
||||
*means* — whether it ends the session or leaves the box up to be launched into
|
||||
again — and nothing here restarts anything of its own accord. Starting
|
||||
something again is a decision for the end that can see whether restarting is
|
||||
repair or a loop.
|
||||
|
||||
`restart` exists as one message and is defined as exactly that: a kill followed
|
||||
by a launch of the same command, keeping the id, with no retry and no backoff.
|
||||
It is one message rather than two only because a caller sending two has the
|
||||
same effect with a worse race in it.
|
||||
|
||||
The same rule covers the box's own services. One that dies is **reported and
|
||||
left dead** — nothing else in the guest is watching them, so a death that is
|
||||
not said here is a box that looks healthy and cannot work.
|
||||
|
||||
**One launch at a time.** A launch arriving while one is running is refused,
|
||||
carrying the id it was asked for, rather than queued or silently replacing it:
|
||||
a box has one screen, so a second concurrent launch has nowhere to draw.
|
||||
|
||||
A signalled workload is reported as signalled, with no exit code. Reporting
|
||||
`0` for a killed process would make a kill look like a clean run.
|
||||
|
||||
### What is not here yet
|
||||
|
||||
`geometry` is carried and parsed but nothing consumes it: nesinit does not
|
||||
start the guest's own services yet. `ticket` exists as a message with no
|
||||
producer wired to it.
|
||||
**It has never been PID 1 of anything.** Every line of this is written for a
|
||||
box and all of it has been tested outside one. It runs perfectly well as an
|
||||
ordinary process — it warns rather than fails when it is not PID 1 — which is
|
||||
how most of it is exercised, and is also how a guest that will not boot gets
|
||||
debugged: `init=/bin/bash` on the kernel command line, then run this by hand
|
||||
and watch it fail.
|
||||
|
||||
Output geometry is deliberately absent from this layer. The compositor is
|
||||
started by a launch, with that launch's geometry in its own arguments, so the
|
||||
numbers appear in one place rather than two that can disagree.
|
||||
|
||||
### Testing
|
||||
|
||||
|
||||
Reference in New Issue
Block a user