Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions .github/actions/check-quality/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,7 @@ runs:
guest/common/nvx-container-launch-azurelinux \
guest/common/nvx-sandbox-smoke guest/common/nvx-snapshot \
guest/common/nvx-virtio-restore-probe \
scripts/setup/setup-linux-mshv.sh \
scripts/setup/setup-linux-runner.sh
scripts/setup/setup-linux.sh
${SHELLCHECK} --shell=bash \
.github/actions/run-benchmark/forward-signals.sh \
.github/specula/setup-runner.sh guest/ubuntu/nvx-bashrc \
Expand All @@ -70,8 +69,7 @@ runs:
guest/common/nvx-container-launch-azurelinux \
guest/common/nvx-sandbox-smoke guest/common/nvx-snapshot \
guest/common/nvx-virtio-restore-probe \
scripts/setup/setup-linux-mshv.sh \
scripts/setup/setup-linux-runner.sh
scripts/setup/setup-linux.sh
${SHFMT} -d -ln bash -i 4 -ci \
.github/actions/run-benchmark/forward-signals.sh \
.github/specula/setup-runner.sh guest/ubuntu/nvx-bashrc \
Expand Down
2 changes: 1 addition & 1 deletion .github/actions/validate-runner/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ runs:
test -n "${toolchain}"
if ! rustup toolchain list | awk -v name="${toolchain}" \
'index($1, name "-") == 1 { found = 1 } END { exit !found }'; then
echo "::error::Rust ${toolchain}, which rust-toolchain.toml pins, is not installed; rerun scripts/setup/setup-linux-runner.sh" >&2
echo "::error::Rust ${toolchain}, which rust-toolchain.toml pins, is not installed; rerun scripts/setup/setup-linux.sh --runner-only" >&2
exit 1
fi
rust_version=$(rustc --version)
Expand Down
3 changes: 1 addition & 2 deletions doc/project-structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,7 @@ nvx/
| | |-- time_abi.py Time ABI harness checks and CPU profile guidance
| | `-- ubuntu.py Verified Ubuntu rootfs and EROFS preparation
| |-- setup/ Host and Actions runner bootstrap scripts
| | |-- setup-linux-mshv.sh Linux/MSHV development-host bootstrap
| | |-- setup-linux-runner.sh Linux/KVM or Linux/MSHV Actions runner bootstrap
| | |-- setup-linux.sh Linux/KVM or Linux/MSHV development-host and Actions runner bootstrap
| | |-- setup-windows-whp.ps1 Windows/WHP development-host and Actions runner bootstrap
| | `-- tool-versions.conf Shared tool release and checksum pins
| |-- check_markdown_links.py Markdown link, anchor, and doc/ path check run by CI
Expand Down
17 changes: 10 additions & 7 deletions doc/setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ rustup toolchain install "$toolchain" --profile minimal
rustup target add --toolchain "$toolchain" x86_64-unknown-linux-musl
```

The Linux runner setup scripts and Copilot setup install this target
Both modes of the Linux setup script, and Copilot setup, install this target
automatically. `build-essential` remains necessary for the kernel and as
Rust's linker driver; no separate guest libc compiler is required.

Expand Down Expand Up @@ -140,9 +140,12 @@ SDK, and Docker Desktop using Linux containers.
## Automated environment bootstrap

The scripts in [`scripts/setup`](../scripts/setup/README.md) prepare Linux/KVM, Linux/MSHV, and
Windows/WHP development or GitHub Actions hosts. They install the platform build prerequisites,
configure hypervisor access, and provide non-mutating validation modes. Runner registration
tokens are read from standard input so they do not appear in command history.
Windows/WHP development or GitHub Actions hosts. On Linux, `setup-linux.sh` configures a
development host for the selected backend by default and an Actions runner with
`--runner-only`, as `setup-windows-whp.ps1` does on Windows with `-RunnerOnly`. They install the
platform build prerequisites, configure hypervisor access, and provide non-mutating validation
modes. Runner registration tokens are read from standard input so they do not appear in command
history.

Linux can also emit a revision-bound, checksummed guest artifact bundle for Windows. The Windows
script verifies that bundle before copying it into the checkout and building OpenVMM natively.
Expand Down Expand Up @@ -221,7 +224,7 @@ shellcheck --shell=sh \
guest/common/nvx-container-launch-azurelinux \
guest/common/nvx-sandbox-smoke \
guest/common/nvx-snapshot guest/common/nvx-virtio-restore-probe \
scripts/setup/setup-linux-mshv.sh scripts/setup/setup-linux-runner.sh
scripts/setup/setup-linux.sh
shellcheck --shell=bash \
.github/specula/setup-runner.sh guest/ubuntu/nvx-bashrc
python3 -m pyright --pythonplatform Linux
Expand All @@ -236,7 +239,7 @@ shfmt -d -ln posix -i 4 -ci \
guest/common/nvx-container-launch-azurelinux \
guest/common/nvx-sandbox-smoke \
guest/common/nvx-snapshot guest/common/nvx-virtio-restore-probe \
scripts/setup/setup-linux-mshv.sh scripts/setup/setup-linux-runner.sh
scripts/setup/setup-linux.sh
shfmt -d -ln bash -i 4 -ci \
.github/specula/setup-runner.sh guest/ubuntu/nvx-bashrc
python3 scripts/check_markdown_links.py
Expand Down Expand Up @@ -282,7 +285,7 @@ shfmt -w -ln posix -i 4 -ci \
guest/common/nvx-container-launch-azurelinux \
guest/common/nvx-sandbox-smoke \
guest/common/nvx-snapshot guest/common/nvx-virtio-restore-probe \
scripts/setup/setup-linux-mshv.sh scripts/setup/setup-linux-runner.sh
scripts/setup/setup-linux.sh
shfmt -w -ln bash -i 4 -ci \
.github/specula/setup-runner.sh guest/ubuntu/nvx-bashrc
```
110 changes: 82 additions & 28 deletions scripts/setup/README.md
Original file line number Diff line number Diff line change
@@ -1,34 +1,81 @@
# Environment bootstrap

These scripts prepare an existing NVX checkout on a supported host:
These scripts prepare a supported host for NVX:

- `setup-linux-mshv.sh` configures Linux/MSHV build and device prerequisites.
- `setup-windows-whp.ps1` configures Windows/WHP build prerequisites.
- `setup-linux-runner.sh` configures a Linux/KVM or Linux/MSHV Actions runner.
- `setup-linux.sh` configures a Linux/KVM or Linux/MSHV host.
- `setup-windows-whp.ps1` configures a Windows/WHP host.

Each script has two modes. By default, it prepares a development host: an
existing NVX checkout from which a developer builds, tests, and runs NVX.
Runner-only mode, which `--runner-only` on Linux and `-RunnerOnly` on Windows
select, prepares a persistent GitHub Actions runner for NVX's CI jobs instead,
and needs no checkout.

For Azure VMSS bootstrapping, see [Azure provisioning](azure/README.md). The
scripts in this directory remain usable on supported hosts outside Azure.

They do not create machines or initialize a checkout. The runner modes consume
a short-lived registration token from standard input and do not store repository
credentials in the scripts. Initialize the OpenVMM submodule before using the
development-host modes.
They do not create machines or initialize a checkout. Runner-only mode
consumes a short-lived registration token from standard input and does not
store repository credentials in the scripts. Initialize the OpenVMM submodule
before using development-host mode.

Each script reads the versions, release artifacts, and checksums of the tools
that it installs from [`tool-versions.conf`](tool-versions.conf) in its own
directory, so stage the manifest next to a script that runs outside a
checkout; see [Tool versions](#tool-versions).

## Linux modes

`setup-linux.sh` requires `--backend kvm` or `--backend mshv` in both modes. It
supports distributions with `apt-get`, `dnf`, or `tdnf`, such as Ubuntu and
Azure Linux. Both modes install the same native build dependencies, the
pinned rustup, Rust release, and cargo-nextest, and a udev rule that lets only
the backend's group open its device, `/dev/kvm` or `/dev/mshv`; on MSHV, they
load `mshv_root` when the device is missing. They differ in everything else:

| | Development host (default) | Runner (`--runner-only`) |
| --- | --- | --- |
| Runs as | Root, or a user whose `sudo` may prompt | The SSH administrator with passwordless `sudo`, never root |
| NVX checkout | Required: the one that contains the script, or `--workspace PATH` | Not used |
| Rust tools | The current user's, with the musl target of the guest binaries | Root-owned and read-only to jobs under `/opt/nvx`, with OpenVMM's test targets and the pinned sccache |
| Docker | Installs Docker with Buildx unless the host has a Docker CLI, and adds the user to `docker` | Keeps `nvx-runner` out of `docker` |
| Backend device | Adds the user to the backend's group | Makes the backend's group the only supplementary group of `nvx-runner` |
| Completes with | A build of NVX and its guests, unless `--skip-build`, and `NVX_SETUP_COMPLETE=1` | With `--runner-name`, a registered runner service, and `NVX_RUNNER_SETUP_COMPLETE=1` |
| `--check-only` prints | `NVX_SETUP_CHECK=ok` | `NVX_RUNNER_SETUP_COMPLETE=1` |

Each mode rejects the other's options, so a misplaced option fails before the
script inspects or changes the host. [Linux development
hosts](#linux-development-hosts) and [GitHub Actions
runners](#github-actions-runners) describe the modes.

### Migrating from the former Linux scripts

`setup-linux.sh` replaces `setup-linux-mshv.sh` and `setup-linux-runner.sh`.
Stage it with `tool-versions.conf` instead of them, and translate their
invocations:

| Former invocation | Replacement |
| --- | --- |
| `setup-linux-mshv.sh [OPTIONS]` | `setup-linux.sh --backend mshv [OPTIONS]` |
| `setup-linux-runner.sh --backend BACKEND [OPTIONS]` | `setup-linux.sh --runner-only --backend BACKEND [OPTIONS]` |

Their options, output markers, and exit statuses are otherwise unchanged.
Development-host mode also accepts `--backend kvm` now, keeps a Docker
installation that the host already has, and its check mode also requires the
musl target that it installs. A runner that the former script configured needs
no migration: runner-only mode manages the same account, toolchain,
installation, and service.

## GitHub Actions runners

Generate a repository runner registration token on an authenticated workstation,
then stream it to the target without placing it in shell history. On Linux:

```bash
scp scripts/setup/setup-linux-runner.sh scripts/setup/tool-versions.conf HOST:/tmp/
scp scripts/setup/setup-linux.sh scripts/setup/tool-versions.conf HOST:/tmp/
gh api --method POST repos/microsoft/nvx/actions/runners/registration-token \
--jq .token |
ssh HOST '/tmp/setup-linux-runner.sh --backend kvm --runner-name azure-kvm-1 --runner-token-stdin'
ssh HOST 'sh /tmp/setup-linux.sh --runner-only --backend kvm --runner-name azure-kvm-1 --runner-token-stdin'
```

For Windows/WHP, stage `setup-windows-whp.ps1` and `tool-versions.conf` in one
Expand Down Expand Up @@ -105,7 +152,8 @@ registration; a subsequent named pass accepts that directory but refuses
unrelated partial runner installations.
Rustup bootstrap binaries are versioned and SHA-256 verified before execution;
Linux provisioning also installs `zstd` for native Actions cache archives.
Both runner setup scripts install a pinned, SHA-256-verified `sccache` binary.
Both scripts' runner-only modes install a pinned, SHA-256-verified `sccache`
binary.
Runner services use a persistent `_work/_sccache` directory with a 10-GiB
limit, disable Cargo incremental compilation, and expose `sccache` through
`RUSTC_WRAPPER`. CI uses clean Cargo target directories and reports per-job
Expand Down Expand Up @@ -153,8 +201,8 @@ branch.
Validate an installed runner without changing the host:

```bash
sh scripts/setup/setup-linux-runner.sh \
--backend kvm --runner-name azure-kvm-1 --check-only
sh scripts/setup/setup-linux.sh \
--runner-only --backend kvm --runner-name azure-kvm-1 --check-only
```

```powershell
Expand All @@ -164,7 +212,7 @@ sh scripts/setup/setup-linux-runner.sh \

### Rust toolchain

The runner scripts install the Rust release that `rust.toolchain` in the
Runner-only mode installs the Rust release that `rust.toolchain` in the
manifest pins, which equals the release in the repository's
[`rust-toolchain.toml`](../../rust-toolchain.toml), with its OpenVMM
targets, into the read-only trusted toolchain, and check mode requires exactly
Expand All @@ -176,9 +224,9 @@ through `rust-toolchain.toml`. Stage the updated script and manifest, then run
that pass and validate the runner:

```bash
scp scripts/setup/setup-linux-runner.sh scripts/setup/tool-versions.conf HOST:/tmp/
ssh HOST 'sh /tmp/setup-linux-runner.sh --backend kvm'
ssh HOST 'sh /tmp/setup-linux-runner.sh --backend kvm --runner-name azure-kvm-1 --check-only'
scp scripts/setup/setup-linux.sh scripts/setup/tool-versions.conf HOST:/tmp/
ssh HOST 'sh /tmp/setup-linux.sh --runner-only --backend kvm'
ssh HOST 'sh /tmp/setup-linux.sh --runner-only --backend kvm --runner-name azure-kvm-1 --check-only'
```

```powershell
Expand All @@ -189,17 +237,22 @@ ssh HOST powershell.exe -NoProfile -ExecutionPolicy Bypass `
-File C:\setup-windows-whp.ps1 -RunnerOnly -RunnerName nvx-windows-3 -CheckOnly
```

## Linux / MSHV
## Linux development hosts

The Linux script supports distributions with `apt-get`, `dnf`, or `tdnf`. It
installs native build dependencies and the Rust and cargo-nextest releases
that the manifest pins. It installs Docker with Buildx and configures
group-based access to Docker and `/dev/mshv`.
Development-host mode prepares a Linux/KVM or Linux/MSHV checkout for the user
who runs the script. It installs native build dependencies, Docker with Buildx,
and the Rust and cargo-nextest releases that the manifest pins, and configures
group-based access to Docker and to the backend's device. A host that already
has a Docker CLI keeps its Docker, such as Docker's own `docker-ce`, which the
distribution's packages would replace; install Buildx for it if it lacks the
plugin. The udev rule lets only the backend's group open the device, so
another user of the host needs that group too, even where the device was open
to everyone before.

Run the complete bootstrap from the checkout:
Run the complete bootstrap from the checkout, naming the host's backend:

```bash
sh scripts/setup/setup-linux-mshv.sh
sh scripts/setup/setup-linux.sh --backend mshv
```

Changing group membership exits with status 20. Reconnect and run the script
Expand All @@ -208,16 +261,17 @@ again so the new membership applies.
Validate dependencies without changing the host or requiring build artifacts:

```bash
sh scripts/setup/setup-linux-mshv.sh --check-only --skip-build
sh scripts/setup/setup-linux.sh --backend kvm --check-only --skip-build
```

Omit `--skip-build` to also validate the built artifacts and generated MSHV
command. Use `--workspace PATH` when the script is outside the checkout.
Omit `--skip-build` to also validate the built artifacts and the command that
NVX generates for the backend. Use `--workspace PATH` when the script is
outside the checkout.

To produce a revision-bound guest bundle for a Windows build:

```bash
sh scripts/setup/setup-linux-mshv.sh \
sh scripts/setup/setup-linux.sh --backend mshv \
--guest-bundle /path/to/nvx-guest-artifacts
```

Expand Down
7 changes: 4 additions & 3 deletions scripts/setup/azure/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

These Azure-specific adapters configure **existing** NVX CI virtual machine
scale sets. They package the provider-neutral
[`setup-linux-runner.sh`](../setup-linux-runner.sh) or
[`setup-windows-whp.ps1`](../setup-windows-whp.ps1) together with the adjacent
[`setup-linux.sh`](../setup-linux.sh), which the Linux bootstrap runs in
runner-only mode, or [`setup-windows-whp.ps1`](../setup-windows-whp.ps1)
together with the adjacent
[`tool-versions.conf`](../tool-versions.conf). That manifest and
[`rust-toolchain.toml`](../../../rust-toolchain.toml) must pin the same release.
Do not maintain a second copy of the runner setup or its tool versions here.
Expand All @@ -13,7 +14,7 @@ Do not maintain a second copy of the runner setup or its tool versions here.
| `linux/bootstrap-runner.sh` | Validate Azure instance identity, prepare the attached disk and backend, derive a runner name, and register using managed identity and Key Vault. |
| `linux/block-runner-metadata.sh` | Block the dedicated runner account from Azure instance metadata with a verified, reboot-persistent IPv4 owner rule. |
| `linux/setup-data-disk.sh` | Find an Azure managed disk by LUN, preserve recognized ext4 data, and initialize only a blank or owned incomplete disk. |
| `linux/setup-mshv.sh`, `linux/verify-mshv.sh` | Optional Azure Linux 3 Dom0 boot preparation and post-boot verification. This differs from the checkout/build helper `../setup-linux-mshv.sh`. |
| `linux/setup-mshv.sh`, `linux/verify-mshv.sh` | Optional Azure Linux 3 Dom0 boot preparation and post-boot verification. This differs from `../setup-linux.sh`, which requires an MSHV kernel that is already running. |
| `windows/bootstrap-runner.ps1` | Validate instance identity; set up disk, WHP/Hyper-V features, reboot continuation, and the Network Service runner. |
| `windows/setup-data-disk.ps1` | Safely prepare an Azure managed NTFS data disk and handle temporary-drive/pagefile conflicts. |
| `windows/vmss-bootstrap.ps1`, `windows/install-package.ps1` | Run through Custom Script, configure OpenSSH, verify and unpack the source bundle, and start Windows bootstrap. |
Expand Down
4 changes: 2 additions & 2 deletions scripts/setup/azure/build_package.py
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,7 @@ def load_config(path: str | Path) -> LinuxConfig | WindowsConfig:


def source(path: str) -> bytes:
if path in {"setup-linux-runner.sh", "setup-windows-whp.ps1", "tool-versions.conf"}:
if path in {"setup-linux.sh", "setup-windows-whp.ps1", "tool-versions.conf"}:
location = SETUP / path
elif path == "rust-toolchain.toml":
location = REPO / path
Expand Down Expand Up @@ -466,7 +466,7 @@ def linux_payload(
) -> tuple[bytes, dict[str, bytes], dict[str, bytes]]:
files = {
"config.json": configuration_bytes(config),
"setup-linux-runner.sh": source("setup-linux-runner.sh"),
"setup-linux.sh": source("setup-linux.sh"),
"tool-versions.conf": source("tool-versions.conf"),
"setup-data-disk.sh": source("linux/setup-data-disk.sh"),
"bootstrap-runner.sh": source("linux/bootstrap-runner.sh"),
Expand Down
5 changes: 3 additions & 2 deletions scripts/setup/azure/linux/bootstrap-runner.sh
Original file line number Diff line number Diff line change
Expand Up @@ -186,14 +186,15 @@ fi
}

setup_arguments=(
--runner-only
--backend "$backend"
--repository-url "https://github.com/$repository"
--runner-directory "$runner_directory"
)
if [ -n "$extra_runner_labels" ]; then
setup_arguments+=(--extra-runner-labels "$extra_runner_labels")
fi
sudo -u "$admin_username" -H sh "$setup_root/setup-linux-runner.sh" "${setup_arguments[@]}"
sudo -u "$admin_username" -H sh "$setup_root/setup-linux.sh" "${setup_arguments[@]}"

metadata_service=nvx-runner-metadata-block.service
systemctl enable "$metadata_service"
Expand Down Expand Up @@ -246,7 +247,7 @@ if [ "$benchmark_runner" = true ]; then
registration_arguments+=(--benchmark-runner)
fi
printf '%s\n' "$runner_token" |
sudo -u "$admin_username" -H sh "$setup_root/setup-linux-runner.sh" \
sudo -u "$admin_username" -H sh "$setup_root/setup-linux.sh" \
"${registration_arguments[@]}" --runner-token-stdin
runner_token=

Expand Down
Loading
Loading