CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
129 lines
5.9 KiB
Markdown
129 lines
5.9 KiB
Markdown
# The mirage host process
|
|
|
|
The host is the per-session worker that brings a session to life. There is
|
|
exactly one host per session (the orchestrator host on the real machine);
|
|
when it exits, the session is considered stopped. It is the same `mirage`
|
|
binary, invoked as `mirage host --session <id>`, and is normally spawned for
|
|
you by `mirage session start` and `mirage run`.
|
|
|
|
## Lifecycle
|
|
|
|
```text
|
|
┌──────────────────┐
|
|
CLI calls │ session create() │
|
|
session start │ writes def.json │
|
|
─────────▶ │
|
|
└────────┬─────────┘
|
|
│ spawn detached, new process group
|
|
▼
|
|
┌───────────────────────┐ ┌──────────────────────────┐
|
|
│ mirage host │───▶│ writes node/<rank>/pid │
|
|
│ --session <id> │ │ writes health.json │
|
|
│ │ │ { healthy: true, │
|
|
│ poll exec/ directory │ │ state: "ready" } │
|
|
└───────────┬───────────┘ └──────────────────────────┘
|
|
│ new exec/<id>/def.json appears
|
|
▼
|
|
┌───────────────────────┐
|
|
│ for each node n: │
|
|
│ mkfifo stdin │
|
|
│ open stdout │
|
|
│ spawn child (PTY) │
|
|
│ write node/<n>/pid │
|
|
└───────────┬───────────┘
|
|
▼
|
|
┌───────────────────────┐
|
|
│ wait(child) │
|
|
│ write exit_code │
|
|
│ update status.json │
|
|
│ if !keep, rm exec dir │
|
|
└───────────────────────┘
|
|
```
|
|
|
|
On `SIGTERM`/`SIGINT` the host:
|
|
|
|
1. Sets health `state="stopping", healthy=false`.
|
|
2. Signals every per-node child recorded under `exec/*/node/*/pid`.
|
|
3. Waits briefly, then escalates to `SIGKILL` for anything still alive.
|
|
4. Sets health `state="stopped"` and exits cleanly.
|
|
|
|
## Health states
|
|
|
|
`health.json` carries a `state` that is one of `starting`, `pulling`
|
|
(container image), `ready`, `degraded`, `stopping`, `stopped`, or `error`,
|
|
together with `healthy` and `terminal` booleans and an optional `message`.
|
|
|
|
`mirage session wait` and the `run`/`session start` ready-wait poll
|
|
`health.json` until `healthy=true` or the session becomes terminal — a
|
|
terminal-but-unhealthy session (a bad image, a node that won't start, a
|
|
missing emulator asset) is treated as a hard failure so the CLI never submits
|
|
an exec that no host will ever run.
|
|
|
|
## Polling cadence
|
|
|
|
The host polls `exec/` on a fixed, sub-second tick to discover new exec
|
|
definitions. Polling (rather than `inotify`) was chosen for portability and
|
|
simplicity; it is fast enough to feel interactive and cheap enough to be
|
|
invisible on idle systems.
|
|
|
|
## What the host watches
|
|
|
|
* `exec/<id>/def.json` — its appearance triggers a new exec launch.
|
|
* `exec/<id>/status.json` — the host (re)writes this; `ended=true` marks the
|
|
exec done.
|
|
|
|
It does not watch profiles: a profile is resolved by the CLI on session
|
|
create and inlined into the session's `def.json` as needed.
|
|
|
|
## Containerised sessions
|
|
|
|
When a profile (or `--image`/`--mount`/`--container-provider` override) requests
|
|
containerisation, the orchestrator host brings up one container per node
|
|
through the configured provider (podman or docker, autodetected), bind-mounts
|
|
the session directory in, and launches a per-node `mirage host` *inside* each
|
|
container. Those inner hosts run only their own node's execs and never manage
|
|
containers themselves. The provider, image, and per-node container ids are
|
|
recorded in the session state and surfaced by `mirage session list`.
|
|
|
|
The container provider can be selected with `--container-provider` or the
|
|
`MIRAGE_CONTAINER_PROVIDER` environment variable.
|
|
|
|
## Recovery
|
|
|
|
The session host is re-execable. Restarting `mirage host --session <id>` is
|
|
safe:
|
|
|
|
* The node's `pid` file is overwritten.
|
|
* Already-finished execs (`status.json: ended=true`) are skipped.
|
|
* In-progress execs whose child is still alive are not re-adopted (their stdio
|
|
FDs were owned by the previous host); they remain visible as
|
|
`started=true, ended=false` with a stale pid.
|
|
|
|
## Extending the host
|
|
|
|
The host is a thin orchestrator. Per-emulator behaviour lives behind the
|
|
`mirage_core::emulator::Emulator` trait:
|
|
|
|
* `injection_def()` returns env vars, files, and `LD_PRELOAD` entries added to
|
|
every child.
|
|
* `validate_profile()` checks a profile is runnable (reported at
|
|
`profile create` time).
|
|
* `health()` returns a snapshot the host periodically publishes.
|
|
|
|
To add a backend, implement `Emulator`, register it via `inventory`, and add
|
|
its Cargo feature (see [`architecture.md`](architecture.md)). No `match` arm in
|
|
the host needs editing.
|
|
|
|
## Environment
|
|
|
|
| Variable | Effect |
|
|
| ----------------- | ----------------------------------------------------- |
|
|
| `MIRAGE_LOG` | Tracing filter, e.g. `debug` or `mirage_host=debug`. |
|
|
| `MIRAGE_RUNTIME` | Override the runtime dir holding the session directory (else `$XDG_RUNTIME_DIR/mirage`). |
|
|
|
|
A `-v`/`-vv` passed to the CLI is propagated to the detached host via
|
|
`MIRAGE_LOG`, so host events land in `node/<rank>/host.log` at the requested
|
|
verbosity. Children inherit only a curated set of variables (`PATH`, `HOME`,
|
|
`USER`, `LANG`, `LC_ALL`, `TERM`, `TMPDIR`); to add more, set them in the
|
|
exec's `--env` or via the emulator's `injection_def()`.
|