Reorganize the source checkout layout
Separate tracked source from generated artifacts so the repo root stops accumulating helper scripts, manifests, and local runtime outputs. Move manual shell entrypoints under scripts/, manifests under config/, and the Firecracker API reference under docs/reference/. Make build and runtimebundle now target build/bin, build/runtime, and build/dist as the canonical source-checkout paths. Update runtime discovery, helper scripts, tests, and docs to follow the new layout while keeping legacy source-checkout runtime fallbacks for existing local bundles during migration. Validated with bash -n on the moved scripts, make build, and GOCACHE=/tmp/banger-gocache go test ./....
This commit is contained in:
parent
2362d0ae39
commit
01c7cb5e65
23 changed files with 296 additions and 186 deletions
|
|
@ -1,619 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
log() {
|
||||
printf '[make-rootfs-void] %s\n' "$*"
|
||||
}
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage: ./make-rootfs-void.sh [--out <path>] [--size <size>] [--mirror <url>] [--arch <arch>] [--packages <path>]
|
||||
|
||||
Build an experimental Void Linux rootfs image plus a matching /root work-seed.
|
||||
|
||||
Defaults:
|
||||
--out ./runtime/rootfs-void.ext4
|
||||
--size 2G
|
||||
--mirror https://repo-default.voidlinux.org
|
||||
--arch x86_64
|
||||
--packages ./packages.void
|
||||
|
||||
This path is experimental and local-only. If ./runtime/void-kernel exists it
|
||||
uses the staged Void kernel modules from that directory; otherwise it falls back
|
||||
to the current runtime bundle modules. It does not change the default Debian
|
||||
image flow.
|
||||
EOF
|
||||
}
|
||||
|
||||
parse_size() {
|
||||
local raw="$1"
|
||||
if [[ "$raw" =~ ^([0-9]+)([KMG])?$ ]]; then
|
||||
local num="${BASH_REMATCH[1]}"
|
||||
local unit="${BASH_REMATCH[2]}"
|
||||
case "$unit" in
|
||||
K) printf '%s\n' $((num * 1024)) ;;
|
||||
M|"") printf '%s\n' $((num * 1024 * 1024)) ;;
|
||||
G) printf '%s\n' $((num * 1024 * 1024 * 1024)) ;;
|
||||
esac
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
require_command() {
|
||||
local name="$1"
|
||||
command -v "$name" >/dev/null 2>&1 || {
|
||||
log "required command not found: $name"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
resolve_banger_bin() {
|
||||
if [[ -n "${BANGER_BIN:-}" ]]; then
|
||||
printf '%s\n' "$BANGER_BIN"
|
||||
return
|
||||
fi
|
||||
if [[ -x "$SCRIPT_DIR/banger" ]]; then
|
||||
printf '%s\n' "$SCRIPT_DIR/banger"
|
||||
return
|
||||
fi
|
||||
if command -v banger >/dev/null 2>&1; then
|
||||
command -v banger
|
||||
return
|
||||
fi
|
||||
log "banger binary not found; build it first with 'make build' or set BANGER_BIN"
|
||||
exit 1
|
||||
}
|
||||
|
||||
normalize_mirror() {
|
||||
local mirror="${1%/}"
|
||||
mirror="${mirror%/current}"
|
||||
mirror="${mirror%/static}"
|
||||
printf '%s\n' "$mirror"
|
||||
}
|
||||
|
||||
bundle_path() {
|
||||
local key="$1"
|
||||
local fallback="$2"
|
||||
local rel=""
|
||||
|
||||
if [[ -f "$BUNDLE_METADATA" ]] && command -v jq >/dev/null 2>&1; then
|
||||
rel="$(jq -r --arg key "$key" '.[$key] // empty' "$BUNDLE_METADATA" 2>/dev/null || true)"
|
||||
fi
|
||||
if [[ -n "$rel" && "$rel" != "null" ]]; then
|
||||
printf '%s\n' "$RUNTIME_DIR/$rel"
|
||||
return
|
||||
fi
|
||||
printf '%s\n' "$fallback"
|
||||
}
|
||||
|
||||
find_latest_module_dir() {
|
||||
local root="$1"
|
||||
if [[ ! -d "$root" ]]; then
|
||||
return 1
|
||||
fi
|
||||
find "$root" -mindepth 1 -maxdepth 1 -type d | sort | tail -n 1
|
||||
}
|
||||
|
||||
find_static_binary() {
|
||||
local name="$1"
|
||||
find "$STATIC_DIR" -type f \( -name "$name" -o -name "$name.static" \) -perm -u+x | sort | head -n 1
|
||||
}
|
||||
|
||||
find_static_keys_dir() {
|
||||
find "$STATIC_DIR" -type d -path '*/var/db/xbps/keys' | sort | head -n 1
|
||||
}
|
||||
|
||||
install_root_authorized_key() {
|
||||
local public_key
|
||||
public_key="$(ssh-keygen -y -f "$SSH_KEY")"
|
||||
sudo mkdir -p "$ROOT_MOUNT/root/.ssh"
|
||||
printf '%s\n' "$public_key" | sudo tee "$ROOT_MOUNT/root/.ssh/authorized_keys" >/dev/null
|
||||
sudo chmod 700 "$ROOT_MOUNT/root/.ssh"
|
||||
sudo chmod 600 "$ROOT_MOUNT/root/.ssh/authorized_keys"
|
||||
}
|
||||
|
||||
ensure_sshd_include() {
|
||||
local cfg="$ROOT_MOUNT/etc/ssh/sshd_config"
|
||||
local tmp_cfg="$TMP_DIR/sshd_config"
|
||||
local include_line="Include /etc/ssh/sshd_config.d/*.conf"
|
||||
|
||||
sudo mkdir -p "$ROOT_MOUNT/etc/ssh/sshd_config.d"
|
||||
if sudo test -f "$cfg"; then
|
||||
sudo cat "$cfg" > "$tmp_cfg"
|
||||
else
|
||||
: > "$tmp_cfg"
|
||||
fi
|
||||
|
||||
if ! grep -Eq '^[[:space:]]*Include[[:space:]]+/etc/ssh/sshd_config\.d/\*\.conf([[:space:]]|$)' "$tmp_cfg"; then
|
||||
{
|
||||
printf '%s\n' "$include_line"
|
||||
cat "$tmp_cfg"
|
||||
} > "${tmp_cfg}.new"
|
||||
mv "${tmp_cfg}.new" "$tmp_cfg"
|
||||
sudo install -m 0644 "$tmp_cfg" "$cfg"
|
||||
fi
|
||||
}
|
||||
|
||||
install_vsock_service() {
|
||||
local service_dir="$ROOT_MOUNT/etc/sv/banger-vsock-agent"
|
||||
local run_path="$service_dir/run"
|
||||
local finish_path="$service_dir/finish"
|
||||
|
||||
sudo mkdir -p "$service_dir"
|
||||
cat <<'EOF' | sudo tee "$run_path" >/dev/null
|
||||
#!/bin/sh
|
||||
modprobe vsock 2>/dev/null || true
|
||||
modprobe vmw_vsock_virtio_transport 2>/dev/null || true
|
||||
exec /usr/local/bin/banger-vsock-agent
|
||||
EOF
|
||||
cat <<'EOF' | sudo tee "$finish_path" >/dev/null
|
||||
#!/bin/sh
|
||||
exit 0
|
||||
EOF
|
||||
sudo chmod 0755 "$run_path" "$finish_path"
|
||||
sudo mkdir -p "$ROOT_MOUNT/etc/runit/runsvdir/default"
|
||||
sudo ln -snf /etc/sv/banger-vsock-agent "$ROOT_MOUNT/etc/runit/runsvdir/default/banger-vsock-agent"
|
||||
}
|
||||
|
||||
install_opencode_service() {
|
||||
local service_dir="$ROOT_MOUNT/etc/sv/banger-opencode"
|
||||
local run_path="$service_dir/run"
|
||||
local finish_path="$service_dir/finish"
|
||||
|
||||
sudo mkdir -p "$service_dir"
|
||||
cat <<'EOF' | sudo tee "$run_path" >/dev/null
|
||||
#!/bin/sh
|
||||
set -e
|
||||
export HOME=/root
|
||||
cd /root
|
||||
exec /usr/local/bin/opencode serve --hostname 0.0.0.0 --port 4096
|
||||
EOF
|
||||
cat <<'EOF' | sudo tee "$finish_path" >/dev/null
|
||||
#!/bin/sh
|
||||
exit 0
|
||||
EOF
|
||||
sudo chmod 0755 "$run_path" "$finish_path"
|
||||
sudo mkdir -p "$ROOT_MOUNT/etc/runit/runsvdir/default"
|
||||
sudo ln -snf /etc/sv/banger-opencode "$ROOT_MOUNT/etc/runit/runsvdir/default/banger-opencode"
|
||||
}
|
||||
|
||||
install_guest_network_bootstrap() {
|
||||
sudo mkdir -p "$ROOT_MOUNT/usr/local/libexec" "$ROOT_MOUNT/etc/runit/core-services"
|
||||
sudo install -m 0755 "$GUESTNET_BOOTSTRAP_SCRIPT" "$ROOT_MOUNT/usr/local/libexec/banger-network-bootstrap"
|
||||
sudo install -m 0644 "$GUESTNET_VOID_CORE_SERVICE" "$ROOT_MOUNT/etc/runit/core-services/20-banger-network.sh"
|
||||
}
|
||||
|
||||
configure_docker_bootstrap() {
|
||||
local modules_conf="$ROOT_MOUNT/etc/modules-load.d/docker-netfilter.conf"
|
||||
local sysctl_conf="$ROOT_MOUNT/etc/sysctl.d/99-docker.conf"
|
||||
local service_dir="$ROOT_MOUNT/etc/sv/docker"
|
||||
local run_path="$service_dir/run"
|
||||
local orig_run_path="$service_dir/run.orig"
|
||||
local preflight_path="$ROOT_MOUNT/usr/local/bin/banger-docker-preflight"
|
||||
|
||||
sudo mkdir -p "$ROOT_MOUNT/etc/modules-load.d" "$ROOT_MOUNT/etc/sysctl.d" "$ROOT_MOUNT/usr/local/bin"
|
||||
cat <<'EOF' | sudo tee "$modules_conf" >/dev/null
|
||||
nf_tables
|
||||
nft_chain_nat
|
||||
veth
|
||||
br_netfilter
|
||||
overlay
|
||||
EOF
|
||||
cat <<'EOF' | sudo tee "$sysctl_conf" >/dev/null
|
||||
net.bridge.bridge-nf-call-iptables = 1
|
||||
net.bridge.bridge-nf-call-ip6tables = 1
|
||||
net.ipv4.ip_forward = 1
|
||||
EOF
|
||||
cat <<'EOF' | sudo tee "$preflight_path" >/dev/null
|
||||
#!/bin/sh
|
||||
for module in nf_tables nft_chain_nat veth br_netfilter overlay; do
|
||||
modprobe "$module" 2>/dev/null || true
|
||||
done
|
||||
if command -v sysctl >/dev/null 2>&1; then
|
||||
sysctl --load /etc/sysctl.d/99-docker.conf >/dev/null 2>&1 || true
|
||||
fi
|
||||
EOF
|
||||
|
||||
if [[ ! -f "$run_path" ]]; then
|
||||
log "Void rootfs is missing /etc/sv/docker/run after docker install"
|
||||
exit 1
|
||||
fi
|
||||
sudo install -m 0755 "$run_path" "$orig_run_path"
|
||||
cat <<'EOF' | sudo tee "$run_path" >/dev/null
|
||||
#!/bin/sh
|
||||
set -e
|
||||
/usr/local/bin/banger-docker-preflight
|
||||
exec /etc/sv/docker/run.orig
|
||||
EOF
|
||||
sudo chmod 0644 "$modules_conf" "$sysctl_conf"
|
||||
sudo chmod 0755 "$preflight_path" "$run_path" "$orig_run_path"
|
||||
}
|
||||
|
||||
enable_sshd_service() {
|
||||
if [[ ! -d "$ROOT_MOUNT/etc/sv/sshd" ]]; then
|
||||
log "Void rootfs is missing /etc/sv/sshd after openssh install"
|
||||
exit 1
|
||||
fi
|
||||
sudo mkdir -p "$ROOT_MOUNT/etc/runit/runsvdir/default"
|
||||
sudo ln -snf /etc/sv/sshd "$ROOT_MOUNT/etc/runit/runsvdir/default/sshd"
|
||||
}
|
||||
|
||||
enable_docker_service() {
|
||||
if [[ ! -d "$ROOT_MOUNT/etc/sv/docker" ]]; then
|
||||
log "Void rootfs is missing /etc/sv/docker after docker install"
|
||||
exit 1
|
||||
fi
|
||||
sudo mkdir -p "$ROOT_MOUNT/etc/runit/runsvdir/default"
|
||||
sudo ln -snf /etc/sv/docker "$ROOT_MOUNT/etc/runit/runsvdir/default/docker"
|
||||
}
|
||||
|
||||
normalize_root_shell() {
|
||||
local passwd="$ROOT_MOUNT/etc/passwd"
|
||||
local shells="$ROOT_MOUNT/etc/shells"
|
||||
local wanted_shell="/bin/bash"
|
||||
local tmp_passwd="$TMP_DIR/passwd"
|
||||
local root_shell=""
|
||||
|
||||
if [[ ! -x "$ROOT_MOUNT$wanted_shell" ]]; then
|
||||
log "required root shell is missing from the Void image: $wanted_shell"
|
||||
exit 1
|
||||
fi
|
||||
if [[ ! -f "$shells" ]]; then
|
||||
log "Void image is missing /etc/shells"
|
||||
exit 1
|
||||
fi
|
||||
if ! sudo grep -Fxq "$wanted_shell" "$shells"; then
|
||||
log "Void image does not allow $wanted_shell in /etc/shells"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
sudo cat "$passwd" > "$tmp_passwd"
|
||||
awk -F: -v OFS=: -v shell="$wanted_shell" '
|
||||
$1 == "root" {
|
||||
$7 = shell
|
||||
found = 1
|
||||
}
|
||||
{ print }
|
||||
END {
|
||||
if (!found) {
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
' "$tmp_passwd" > "${tmp_passwd}.new" || {
|
||||
log "failed to rewrite root shell in /etc/passwd"
|
||||
exit 1
|
||||
}
|
||||
mv "${tmp_passwd}.new" "$tmp_passwd"
|
||||
sudo install -m 0644 "$tmp_passwd" "$passwd"
|
||||
|
||||
root_shell="$(sudo awk -F: '$1 == "root" { print $7 }' "$passwd")"
|
||||
if [[ "$root_shell" != "$wanted_shell" ]]; then
|
||||
log "root shell normalization failed: expected $wanted_shell, got ${root_shell:-<empty>}"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
configure_root_bash_prompt() {
|
||||
local bashrc="$ROOT_MOUNT/root/.bashrc"
|
||||
local bash_profile="$ROOT_MOUNT/root/.bash_profile"
|
||||
local profile_prompt="$ROOT_MOUNT/etc/profile.d/banger-bash-prompt.sh"
|
||||
|
||||
sudo mkdir -p "$ROOT_MOUNT/root" "$ROOT_MOUNT/etc/profile.d"
|
||||
cat <<'EOF' | sudo tee "$bashrc" >/dev/null
|
||||
# banger: default interactive prompt for experimental Void guests
|
||||
case "$-" in
|
||||
*i*) ;;
|
||||
*) return ;;
|
||||
esac
|
||||
|
||||
if [ -z "${BANGER_MISE_ACTIVATED:-}" ] && [ -x '/usr/local/bin/mise' ]; then
|
||||
export BANGER_MISE_ACTIVATED=1
|
||||
eval "$(/usr/local/bin/mise activate bash)"
|
||||
fi
|
||||
|
||||
PS1='\u@\h:\w\$ '
|
||||
EOF
|
||||
cat <<'EOF' | sudo tee "$bash_profile" >/dev/null
|
||||
if [ -f ~/.bashrc ]; then
|
||||
. ~/.bashrc
|
||||
fi
|
||||
EOF
|
||||
cat <<'EOF' | sudo tee "$profile_prompt" >/dev/null
|
||||
case "$-" in
|
||||
*i*) ;;
|
||||
*) return 0 2>/dev/null || exit 0 ;;
|
||||
esac
|
||||
|
||||
if [ -n "${BASH_VERSION:-}" ]; then
|
||||
PS1='\u@\h:\w\$ '
|
||||
fi
|
||||
EOF
|
||||
sudo chmod 0644 "$bashrc" "$bash_profile" "$profile_prompt"
|
||||
}
|
||||
|
||||
install_mise_and_opencode() {
|
||||
local profile_mise="$ROOT_MOUNT/etc/profile.d/mise.sh"
|
||||
|
||||
sudo mkdir -p "$ROOT_MOUNT/etc/profile.d"
|
||||
if [[ -r /etc/resolv.conf ]]; then
|
||||
sudo install -m 0644 /etc/resolv.conf "$ROOT_MOUNT/etc/resolv.conf"
|
||||
fi
|
||||
|
||||
sudo env \
|
||||
HOME=/root \
|
||||
PATH=/usr/local/bin:/usr/bin:/bin \
|
||||
chroot "$ROOT_MOUNT" /bin/bash -se <<EOF
|
||||
set -euo pipefail
|
||||
curl -fsSL https://mise.run | MISE_INSTALL_PATH="$MISE_INSTALL_PATH" MISE_VERSION="$MISE_VERSION" sh
|
||||
"$MISE_INSTALL_PATH" use -g "$OPENCODE_TOOL"
|
||||
"$MISE_INSTALL_PATH" reshim
|
||||
if [[ ! -e /root/.local/share/mise/shims/opencode ]]; then
|
||||
echo "opencode shim not found after mise install" >&2
|
||||
exit 1
|
||||
fi
|
||||
ln -snf /root/.local/share/mise/shims/opencode /usr/local/bin/opencode
|
||||
EOF
|
||||
|
||||
cat <<'EOF' | sudo tee "$profile_mise" >/dev/null
|
||||
if [ -n "${BASH_VERSION:-}" ] && [ -z "${BANGER_MISE_ACTIVATED:-}" ] && [ -x '/usr/local/bin/mise' ]; then
|
||||
export BANGER_MISE_ACTIVATED=1
|
||||
eval "$(/usr/local/bin/mise activate bash)"
|
||||
fi
|
||||
EOF
|
||||
sudo chmod 0644 "$profile_mise"
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
if [[ -n "${ROOT_MOUNT:-}" ]] && command -v mountpoint >/dev/null 2>&1 && mountpoint -q "$ROOT_MOUNT"; then
|
||||
sudo umount "$ROOT_MOUNT" || true
|
||||
fi
|
||||
if [[ "${BUILD_DONE:-0}" != "1" ]]; then
|
||||
rm -f "${OUT_ROOTFS:-}" "${WORK_SEED:-}" "${OUT_ROOTFS:-}.packages.sha256"
|
||||
fi
|
||||
if [[ -n "${TMP_DIR:-}" && -d "${TMP_DIR:-}" ]]; then
|
||||
rm -rf "$TMP_DIR"
|
||||
fi
|
||||
}
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PACKAGES_FILE="$SCRIPT_DIR/packages.void"
|
||||
export BANGER_APT_PACKAGES_FILE="$PACKAGES_FILE"
|
||||
source "$SCRIPT_DIR/packages.sh"
|
||||
|
||||
DEFAULT_RUNTIME_DIR="$SCRIPT_DIR"
|
||||
if [[ -d "$SCRIPT_DIR/runtime" ]]; then
|
||||
DEFAULT_RUNTIME_DIR="$SCRIPT_DIR/runtime"
|
||||
fi
|
||||
RUNTIME_DIR="${BANGER_RUNTIME_DIR:-$DEFAULT_RUNTIME_DIR}"
|
||||
if [[ ! -d "$RUNTIME_DIR" ]]; then
|
||||
log "runtime bundle not found: $RUNTIME_DIR"
|
||||
log "run 'make runtime-bundle' or set BANGER_RUNTIME_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BUNDLE_METADATA="$RUNTIME_DIR/bundle.json"
|
||||
SSH_KEY="$(bundle_path ssh_key_path "$RUNTIME_DIR/id_ed25519")"
|
||||
OUT_ROOTFS="$RUNTIME_DIR/rootfs-void.ext4"
|
||||
SIZE_SPEC="2G"
|
||||
MIRROR="https://repo-default.voidlinux.org"
|
||||
ARCH="x86_64"
|
||||
MISE_VERSION="v2025.12.0"
|
||||
MISE_INSTALL_PATH="/usr/local/bin/mise"
|
||||
OPENCODE_TOOL="github:anomalyco/opencode"
|
||||
GUESTNET_BOOTSTRAP_SCRIPT="$SCRIPT_DIR/internal/guestnet/assets/bootstrap.sh"
|
||||
GUESTNET_VOID_CORE_SERVICE="$SCRIPT_DIR/internal/guestnet/assets/void-core-service.sh"
|
||||
MODULES_DIR="$(bundle_path default_modules_dir "$RUNTIME_DIR/wtf/root/lib/modules/6.8.0-94-generic")"
|
||||
VOID_KERNEL_MODULES_DIR="$(find_latest_module_dir "$RUNTIME_DIR/void-kernel/lib/modules" || true)"
|
||||
VSOCK_AGENT="$(bundle_path vsock_agent_path "$RUNTIME_DIR/banger-vsock-agent")"
|
||||
if [[ "$VSOCK_AGENT" == "$RUNTIME_DIR/banger-vsock-agent" && ! -x "$VSOCK_AGENT" ]]; then
|
||||
VSOCK_AGENT="$(bundle_path vsock_ping_helper_path "$RUNTIME_DIR/banger-vsock-pingd")"
|
||||
fi
|
||||
if [[ -n "$VOID_KERNEL_MODULES_DIR" ]]; then
|
||||
MODULES_DIR="$VOID_KERNEL_MODULES_DIR"
|
||||
fi
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--out)
|
||||
OUT_ROOTFS="${2:-}"
|
||||
shift 2
|
||||
;;
|
||||
--size)
|
||||
SIZE_SPEC="${2:-}"
|
||||
shift 2
|
||||
;;
|
||||
--mirror)
|
||||
MIRROR="${2:-}"
|
||||
shift 2
|
||||
;;
|
||||
--arch)
|
||||
ARCH="${2:-}"
|
||||
shift 2
|
||||
;;
|
||||
--packages)
|
||||
PACKAGES_FILE="${2:-}"
|
||||
export BANGER_APT_PACKAGES_FILE="$PACKAGES_FILE"
|
||||
shift 2
|
||||
;;
|
||||
-h|--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
log "unknown option: $1"
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
MIRROR="$(normalize_mirror "$MIRROR")"
|
||||
REPO_URL="$MIRROR/current"
|
||||
STATIC_ARCHIVE_URL="$MIRROR/static/xbps-static-latest.x86_64-musl.tar.xz"
|
||||
|
||||
if [[ "$ARCH" != "x86_64" ]]; then
|
||||
log "unsupported arch: $ARCH"
|
||||
log "this experimental builder currently supports only x86_64-glibc"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "$PACKAGES_FILE" ]]; then
|
||||
log "package manifest not found: $PACKAGES_FILE"
|
||||
exit 1
|
||||
fi
|
||||
if [[ ! -d "$MODULES_DIR" ]]; then
|
||||
log "modules dir not found: $MODULES_DIR"
|
||||
exit 1
|
||||
fi
|
||||
if [[ ! -x "$VSOCK_AGENT" ]]; then
|
||||
log "vsock agent not found or not executable: $VSOCK_AGENT"
|
||||
log "run 'make build' or refresh the runtime bundle"
|
||||
exit 1
|
||||
fi
|
||||
if [[ ! -f "$GUESTNET_BOOTSTRAP_SCRIPT" ]]; then
|
||||
log "guest network bootstrap script not found: $GUESTNET_BOOTSTRAP_SCRIPT"
|
||||
exit 1
|
||||
fi
|
||||
if [[ ! -f "$GUESTNET_VOID_CORE_SERVICE" ]]; then
|
||||
log "guest network core-service shim not found: $GUESTNET_VOID_CORE_SERVICE"
|
||||
exit 1
|
||||
fi
|
||||
if [[ -e "$OUT_ROOTFS" ]]; then
|
||||
log "output rootfs already exists: $OUT_ROOTFS"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
require_command curl
|
||||
require_command tar
|
||||
require_command sudo
|
||||
require_command mkfs.ext4
|
||||
require_command ssh-keygen
|
||||
require_command mount
|
||||
require_command umount
|
||||
require_command install
|
||||
require_command find
|
||||
require_command awk
|
||||
require_command sed
|
||||
require_command sha256sum
|
||||
require_command truncate
|
||||
require_command mountpoint
|
||||
|
||||
VOID_PACKAGES=()
|
||||
if ! banger_packages_read_array VOID_PACKAGES "$PACKAGES_FILE"; then
|
||||
log "package manifest is empty: $PACKAGES_FILE"
|
||||
exit 1
|
||||
fi
|
||||
if ! PACKAGES_HASH="$(banger_packages_manifest_hash "$PACKAGES_FILE")"; then
|
||||
log "failed to hash package manifest: $PACKAGES_FILE"
|
||||
exit 1
|
||||
fi
|
||||
if ! SIZE_BYTES="$(parse_size "$SIZE_SPEC")"; then
|
||||
log "invalid size: $SIZE_SPEC"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BANGER_BIN="$(resolve_banger_bin)"
|
||||
if [[ "$OUT_ROOTFS" == *.ext4 ]]; then
|
||||
WORK_SEED="${OUT_ROOTFS%.ext4}.work-seed.ext4"
|
||||
else
|
||||
WORK_SEED="${OUT_ROOTFS}.work-seed"
|
||||
fi
|
||||
|
||||
TMP_DIR="$(mktemp -d -t banger-void-rootfs-XXXXXX)"
|
||||
STATIC_DIR="$TMP_DIR/static"
|
||||
ROOT_MOUNT="$TMP_DIR/rootfs"
|
||||
STATIC_ARCHIVE="$TMP_DIR/xbps-static.tar.xz"
|
||||
BUILD_DONE=0
|
||||
trap cleanup EXIT
|
||||
|
||||
mkdir -p "$STATIC_DIR" "$ROOT_MOUNT"
|
||||
|
||||
log "downloading static XBPS from $STATIC_ARCHIVE_URL"
|
||||
curl -fsSL "$STATIC_ARCHIVE_URL" -o "$STATIC_ARCHIVE"
|
||||
tar -xf "$STATIC_ARCHIVE" -C "$STATIC_DIR"
|
||||
|
||||
XBPS_INSTALL="$(find_static_binary xbps-install)"
|
||||
XBPS_QUERY="$(find_static_binary xbps-query)"
|
||||
STATIC_KEYS_DIR="$(find_static_keys_dir)"
|
||||
|
||||
if [[ -z "$XBPS_INSTALL" || ! -x "$XBPS_INSTALL" ]]; then
|
||||
log "failed to locate xbps-install in the static archive"
|
||||
exit 1
|
||||
fi
|
||||
if [[ -z "$STATIC_KEYS_DIR" || ! -d "$STATIC_KEYS_DIR" ]]; then
|
||||
log "failed to locate Void repository keys in the static archive"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log "creating $OUT_ROOTFS ($SIZE_SPEC)"
|
||||
truncate -s "$SIZE_BYTES" "$OUT_ROOTFS"
|
||||
mkfs.ext4 -F -m 0 -L banger-void-root "$OUT_ROOTFS" >/dev/null
|
||||
sudo mount -o loop "$OUT_ROOTFS" "$ROOT_MOUNT"
|
||||
sudo mkdir -p "$ROOT_MOUNT/var/db/xbps/keys"
|
||||
sudo cp -a "$STATIC_KEYS_DIR/." "$ROOT_MOUNT/var/db/xbps/keys/"
|
||||
|
||||
log "installing Void packages into the rootfs"
|
||||
sudo env XBPS_ARCH="$ARCH" "$XBPS_INSTALL" -S -y -r "$ROOT_MOUNT" -R "$REPO_URL" "${VOID_PACKAGES[@]}"
|
||||
|
||||
if [[ -n "$XBPS_QUERY" && -x "$XBPS_QUERY" ]]; then
|
||||
log "installed package set:"
|
||||
sudo env XBPS_ARCH="$ARCH" "$XBPS_QUERY" -r "$ROOT_MOUNT" -l | awk '/^ii/ {print " " $2}' || true
|
||||
fi
|
||||
|
||||
if [[ -n "$VOID_KERNEL_MODULES_DIR" ]]; then
|
||||
log "copying staged Void kernel modules into the guest"
|
||||
else
|
||||
log "copying bundled kernel modules into the guest"
|
||||
fi
|
||||
sudo mkdir -p "$ROOT_MOUNT/lib/modules"
|
||||
sudo cp -a "$MODULES_DIR" "$ROOT_MOUNT/lib/modules/"
|
||||
|
||||
log "installing the guest-side vsock agent"
|
||||
sudo mkdir -p "$ROOT_MOUNT/usr/local/bin"
|
||||
sudo install -m 0755 "$VSOCK_AGENT" "$ROOT_MOUNT/usr/local/bin/banger-vsock-agent"
|
||||
|
||||
log "preparing SSH and runit services"
|
||||
install_guest_network_bootstrap
|
||||
ensure_sshd_include
|
||||
enable_sshd_service
|
||||
install_vsock_service
|
||||
configure_docker_bootstrap
|
||||
enable_docker_service
|
||||
normalize_root_shell
|
||||
configure_root_bash_prompt
|
||||
log "installing mise and opencode"
|
||||
install_mise_and_opencode
|
||||
install_opencode_service
|
||||
install_root_authorized_key
|
||||
sudo touch "$ROOT_MOUNT/etc/fstab" "$ROOT_MOUNT/etc/hostname"
|
||||
sudo chroot "$ROOT_MOUNT" /usr/bin/ssh-keygen -A
|
||||
|
||||
log "removing bulky caches, docs, and stale installer artifacts from the experimental image"
|
||||
sudo rm -rf \
|
||||
"$ROOT_MOUNT/var/cache/xbps" \
|
||||
"$ROOT_MOUNT/usr/share/doc" \
|
||||
"$ROOT_MOUNT/usr/share/info" \
|
||||
"$ROOT_MOUNT/usr/share/man"
|
||||
sudo rm -f \
|
||||
"$ROOT_MOUNT/root/get-docker" \
|
||||
"$ROOT_MOUNT/root/get-docker.sh" \
|
||||
"$ROOT_MOUNT/root/.cache/opencode" \
|
||||
"$ROOT_MOUNT/tmp/get-docker" \
|
||||
"$ROOT_MOUNT/tmp/get-docker.sh"
|
||||
sudo rm -rf \
|
||||
"$ROOT_MOUNT/root/.cache/mise" \
|
||||
"$ROOT_MOUNT/root/.local/share/mise/downloads" \
|
||||
"$ROOT_MOUNT/root/.local/share/mise/tmp"
|
||||
|
||||
sudo umount "$ROOT_MOUNT"
|
||||
|
||||
banger_write_rootfs_manifest_metadata "$OUT_ROOTFS" "$PACKAGES_HASH"
|
||||
|
||||
log "building work-seed $WORK_SEED"
|
||||
"$BANGER_BIN" internal work-seed --rootfs "$OUT_ROOTFS" --out "$WORK_SEED"
|
||||
|
||||
BUILD_DONE=1
|
||||
log "built experimental Void rootfs: $OUT_ROOTFS"
|
||||
log "built experimental Void work-seed: $WORK_SEED"
|
||||
log "use examples/void-exp.config.toml as the local config override template"
|
||||
Loading…
Add table
Add a link
Reference in a new issue