Add OmniOS builder VM definition and provisioning scripts

VMFile.kdl defines the omnios-builder VM with cloud-init, SSH config,
and a 3-stage provision pipeline (bootstrap packages + Rust, upload
forger source tarball, build and install forger). Makefile provides
convenience targets wrapping vmctl commands. pack-forger.sh creates a
minimal tarball of just the forger + spec-parser crates and image specs
from refraction-forger for upload to the VM.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Till Wegmueller 2026-02-14 21:56:43 +01:00
parent 38bc2fa6fb
commit eb78c24a8b
No known key found for this signature in database
6 changed files with 224 additions and 0 deletions

1
.gitignore vendored
View file

@ -1,2 +1,3 @@
/target /target
other-codes/ other-codes/
scripts/forger-src.tar.gz

16
Makefile Normal file
View file

@ -0,0 +1,16 @@
pack-forger:
./scripts/pack-forger.sh
up:
cargo run -p vmctl -- up
down:
cargo run -p vmctl -- down
provision:
cargo run -p vmctl -- provision
reload:
cargo run -p vmctl -- reload
.PHONY: pack-forger up down provision reload

32
VMFile.kdl Normal file
View file

@ -0,0 +1,32 @@
vm "omnios-builder" {
image-url "https://downloads.omnios.org/media/stable/omnios-r151056.cloud.qcow2"
vcpus 4
memory 4096
disk 20
cloud-init {
hostname "omnios-builder"
ssh-key "~/.ssh/id_ed25519.pub"
}
ssh {
user "smithy"
private-key "~/.ssh/id_ed25519"
}
// Stage 1: System packages and Rust toolchain
provision "shell" {
script "scripts/bootstrap-omnios.sh"
}
// Stage 2: Upload forger source
provision "file" {
source "scripts/forger-src.tar.gz"
destination "/tmp/forger-src.tar.gz"
}
// Stage 3: Extract and build forger
provision "shell" {
script "scripts/install-forger.sh"
}
}

75
scripts/bootstrap-omnios.sh Executable file
View file

@ -0,0 +1,75 @@
#!/usr/bin/env bash
set -euo pipefail
# OmniOS bootstrap: install system packages and Rust toolchain.
# Adapted from refraction-forger's bootstrap-illumos.sh.
# ---------------------------------------------------------------------------
# Prefer GNU userland (find, xargs, etc.) on OmniOS. Native /usr/bin tools
# lack options like -maxdepth and xargs -r.
# ---------------------------------------------------------------------------
for d in \
/usr/gnu/bin \
/usr/local/gnu/bin \
/opt/csw/gnu \
/opt/csw/bin \
/usr/sfw/bin
do
if [ -d "$d" ]; then
case ":$PATH:" in
*":$d:"*) ;;
*) PATH="$d:$PATH" ;;
esac
fi
done
export PATH
# ---------------------------------------------------------------------------
# System packages via IPS (pkg)
# ---------------------------------------------------------------------------
if ! command -v pkg >/dev/null 2>&1; then
echo "[bootstrap] pkg not found — expected OmniOS with IPS." >&2
exit 1
fi
echo "[bootstrap] Refreshing package catalog ..."
sudo pkg refresh --full
echo "[bootstrap] Installing system prerequisites ..."
sudo pkg install -v \
file/gnu-findutils \
developer/gcc14 \
developer/build/gnu-make \
developer/pkg-config \
library/security/openssl \
web/curl \
compress/unzip \
developer/versioning/git \
web/ca-bundle || true
# ---------------------------------------------------------------------------
# Rust toolchain via rustup
# ---------------------------------------------------------------------------
if ! command -v cargo >/dev/null 2>&1; then
echo "[bootstrap] Installing Rust toolchain via rustup ..."
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
| sh -s -- -y --profile minimal
# shellcheck disable=SC1091
source "$HOME/.cargo/env"
fi
export PATH="$HOME/.cargo/bin:$PATH"
# ---------------------------------------------------------------------------
# Verify critical tools
# ---------------------------------------------------------------------------
echo "[bootstrap] Verifying installed tools ..."
for tool in gcc cargo rustc pkg-config git curl; do
if ! command -v "$tool" >/dev/null 2>&1; then
echo "[bootstrap] ERROR: $tool not found after installation." >&2
exit 1
fi
echo " $tool: $(command -v "$tool")"
done
echo "[bootstrap] OmniOS bootstrap complete."

46
scripts/install-forger.sh Executable file
View file

@ -0,0 +1,46 @@
#!/usr/bin/env bash
set -euo pipefail
# Extract forger source, build, and install the binary.
# ---------------------------------------------------------------------------
# Cargo environment
# ---------------------------------------------------------------------------
if [ -f "$HOME/.cargo/env" ]; then
# shellcheck disable=SC1091
source "$HOME/.cargo/env"
fi
export PATH="$HOME/.cargo/bin:$PATH"
ARCHIVE="/tmp/forger-src.tar.gz"
DEST="$HOME/forger"
if [ ! -f "$ARCHIVE" ]; then
echo "[install-forger] Archive not found: $ARCHIVE" >&2
exit 1
fi
# ---------------------------------------------------------------------------
# Extract
# ---------------------------------------------------------------------------
echo "[install-forger] Extracting $ARCHIVE -> $DEST ..."
rm -rf "$DEST"
mkdir -p "$DEST"
tar xzf "$ARCHIVE" -C "$DEST"
# ---------------------------------------------------------------------------
# Build
# ---------------------------------------------------------------------------
echo "[install-forger] Building forger (release) ..."
cd "$DEST"
cargo build -p forger --release
# ---------------------------------------------------------------------------
# Install
# ---------------------------------------------------------------------------
echo "[install-forger] Installing /usr/local/bin/forger ..."
sudo install -m 755 -d /usr/local/bin
sudo install -m 755 "$DEST/target/release/forger" /usr/local/bin/forger
echo "[install-forger] Done."
forger --version || true

54
scripts/pack-forger.sh Executable file
View file

@ -0,0 +1,54 @@
#!/usr/bin/env bash
set -euo pipefail
# Pack the forger + spec-parser crates (and OmniOS image specs) into a tarball
# that can be uploaded to the OmniOS builder VM.
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
FORGER_ROOT="$PROJECT_ROOT/other-codes/refraction-forger"
OUTPUT="$SCRIPT_DIR/forger-src.tar.gz"
if [ ! -d "$FORGER_ROOT" ]; then
echo "refraction-forger not found at $FORGER_ROOT" >&2
exit 1
fi
STAGING="$(mktemp -d)"
trap 'rm -rf "$STAGING"' EXIT
echo "[pack-forger] Staging forger source ..."
# Copy crates
cp -a "$FORGER_ROOT/crates/forger" "$STAGING/crates/forger"
cp -a "$FORGER_ROOT/crates/spec-parser" "$STAGING/crates/spec-parser"
# Copy image specs
cp -a "$FORGER_ROOT/images" "$STAGING/images"
# Copy lockfile
cp "$FORGER_ROOT/Cargo.lock" "$STAGING/Cargo.lock"
# Generate a minimal workspace Cargo.toml (only forger + spec-parser)
cat > "$STAGING/Cargo.toml" <<'TOML'
[workspace]
resolver = "2"
members = [
"crates/forger",
"crates/spec-parser",
]
[workspace.dependencies]
clap = { version = "4.5", features = ["derive", "env"] }
miette = { version = "7", features = ["fancy"] }
thiserror = "2"
knuffel = "3.2"
tracing = "0.1"
tracing-subscriber = "0.3"
serde = { version = "1.0", features = ["derive"] }
TOML
echo "[pack-forger] Creating $OUTPUT ..."
tar czf "$OUTPUT" -C "$STAGING" .
echo "[pack-forger] Done ($(du -h "$OUTPUT" | cut -f1))."