feat: install logging, error trapping, PXE/ISO integration tests
Kickstart installs on real hardware failed silently — no error reporting,
only 3 progress callbacks, zero log streaming. This overhaul makes every
install fully observable.
Kickstart improvements:
- Error trapping in %pre and %post (trap ERR sends failure details to bastion)
- 12+ granular progress stages (was 3): SSH, hostname, k3s prep, EFI boot, metadata
- Background log streamer: tails %post output and batch-sends to /api/log
- bastion_log() function for explicit log lines from kickstart scripts
Bastion API:
- POST /api/log — receives raw log lines from kickstart (single or batch)
- InstallLogBuffer — per-MAC ring buffer (2000 lines) + file persistence
- GET /api/logs/:mac — now returns log_lines + log_total alongside stages
- SSE /api/logs/:mac/follow — uses named events (event: stage vs event: log)
- Progress events forwarded to labd via bastion-progress WebSocket message
- Post-provision k3s logs routed through progressBus (was console-only)
dnsmasq fixes found during VM testing:
- HTTP Boot filename: ipxe-real.efi → ipxe.efi (leftover from old 2-stage approach)
- pxe-service directives: only in proxy mode (breaks OVMF PXE in full mode)
- PXEClient vendor class echo for UEFI firmware compatibility
Integration tests:
- PXE boot test: blank UEFI VM → dnsmasq → HTTP Boot → iPXE → bastion → install
- ISO boot test: blank VM boots from bastion-generated ISO → same flow
- Shared helpers: pxe-network (no DHCP, nftables fix), pxe-vm (UEFI + ISO boot)
- test-provision.sh: runs both PXE + ISO tests with prerequisite checks
- 250GB sparse QCOW2 disk (LVM layout needs ~204GB)
201 unit tests passing (11 new).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 22:26:33 +00:00
|
|
|
#!/bin/bash
|
|
|
|
|
# Build labd container image (multi-arch) and push to Gitea container registry
|
|
|
|
|
set -e
|
|
|
|
|
|
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
|
|
|
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
|
|
|
|
cd "$PROJECT_ROOT"
|
|
|
|
|
|
|
|
|
|
# Load .env for GITEA_TOKEN
|
|
|
|
|
if [ -f .env ]; then
|
|
|
|
|
set -a; source .env; set +a
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
# ── Argument parsing ───────────────────────────────────────────────
|
|
|
|
|
PUSH=false
|
|
|
|
|
PLATFORMS="linux/amd64,linux/arm64"
|
|
|
|
|
|
|
|
|
|
usage() {
|
|
|
|
|
cat <<EOF
|
|
|
|
|
Usage: $(basename "$0") [OPTIONS] [TAG]
|
|
|
|
|
|
|
|
|
|
Build labd container image (multi-arch) and optionally push to registry.
|
|
|
|
|
|
|
|
|
|
Options:
|
|
|
|
|
--push Push to registry after building
|
|
|
|
|
--platforms LIST Comma-separated platforms (default: linux/amd64,linux/arm64)
|
|
|
|
|
-h, --help Show this help message
|
|
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
|
TAG Image tag (default: version from package.json)
|
|
|
|
|
EOF
|
|
|
|
|
exit 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
POSITIONAL_ARGS=()
|
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
|
|
|
case "$1" in
|
|
|
|
|
--push)
|
|
|
|
|
PUSH=true
|
|
|
|
|
shift
|
|
|
|
|
;;
|
|
|
|
|
--platforms)
|
|
|
|
|
PLATFORMS="$2"
|
|
|
|
|
shift 2
|
|
|
|
|
;;
|
|
|
|
|
-h|--help)
|
|
|
|
|
usage
|
|
|
|
|
;;
|
|
|
|
|
*)
|
|
|
|
|
POSITIONAL_ARGS+=("$1")
|
|
|
|
|
shift
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
REGISTRY="${GITEA_REGISTRY:-mysources.co.uk}"
|
|
|
|
|
REPO="michal/lab/labd"
|
|
|
|
|
FULL_IMAGE="$REGISTRY/$REPO"
|
|
|
|
|
VERSION=$(node -p "require('./package.json').version")
|
|
|
|
|
TAG="${POSITIONAL_ARGS[0]:-$VERSION}"
|
|
|
|
|
|
|
|
|
|
echo "==> Building labd image"
|
|
|
|
|
echo " Tag: $TAG"
|
|
|
|
|
echo " Platforms: $PLATFORMS"
|
|
|
|
|
echo " Registry: $FULL_IMAGE"
|
|
|
|
|
|
|
|
|
|
# ── Build multi-arch manifest ────────────────────────────────────
|
|
|
|
|
MANIFEST="lab-labd:$TAG"
|
|
|
|
|
|
|
|
|
|
# Remove existing manifest/image with the same tag
|
|
|
|
|
podman manifest rm "$MANIFEST" 2>/dev/null || true
|
|
|
|
|
podman rmi "$MANIFEST" 2>/dev/null || true
|
|
|
|
|
|
|
|
|
|
echo "==> Building for platforms: $PLATFORMS..."
|
|
|
|
|
podman build \
|
|
|
|
|
--platform "$PLATFORMS" \
|
|
|
|
|
--manifest "$MANIFEST" \
|
|
|
|
|
-f Dockerfile.labd \
|
|
|
|
|
.
|
|
|
|
|
|
|
|
|
|
echo "==> Build complete. Manifest:"
|
|
|
|
|
podman manifest inspect "$MANIFEST" | grep -E '"(architecture|os)"'
|
|
|
|
|
|
|
|
|
|
# ── Push ─────────────────────────────────────────────────────────
|
|
|
|
|
if [ "$PUSH" = true ]; then
|
|
|
|
|
if [ -z "$GITEA_TOKEN" ]; then
|
|
|
|
|
if [ -f "$HOME/.gitea-token" ]; then
|
|
|
|
|
GITEA_TOKEN="$(cat "$HOME/.gitea-token")"
|
|
|
|
|
else
|
|
|
|
|
echo "ERROR: GITEA_TOKEN not set and ~/.gitea-token not found"
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
fi
|
|
|
|
|
|
2026-04-01 17:59:39 +01:00
|
|
|
# Use --tls-verify=false for plain HTTP registries (e.g. 10.0.0.194:3012)
|
|
|
|
|
TLS_FLAG=""
|
|
|
|
|
if [[ "$REGISTRY" =~ ^[0-9] ]] || [[ "$REGISTRY" =~ ^localhost ]]; then
|
|
|
|
|
TLS_FLAG="--tls-verify=false"
|
|
|
|
|
fi
|
|
|
|
|
|
feat: install logging, error trapping, PXE/ISO integration tests
Kickstart installs on real hardware failed silently — no error reporting,
only 3 progress callbacks, zero log streaming. This overhaul makes every
install fully observable.
Kickstart improvements:
- Error trapping in %pre and %post (trap ERR sends failure details to bastion)
- 12+ granular progress stages (was 3): SSH, hostname, k3s prep, EFI boot, metadata
- Background log streamer: tails %post output and batch-sends to /api/log
- bastion_log() function for explicit log lines from kickstart scripts
Bastion API:
- POST /api/log — receives raw log lines from kickstart (single or batch)
- InstallLogBuffer — per-MAC ring buffer (2000 lines) + file persistence
- GET /api/logs/:mac — now returns log_lines + log_total alongside stages
- SSE /api/logs/:mac/follow — uses named events (event: stage vs event: log)
- Progress events forwarded to labd via bastion-progress WebSocket message
- Post-provision k3s logs routed through progressBus (was console-only)
dnsmasq fixes found during VM testing:
- HTTP Boot filename: ipxe-real.efi → ipxe.efi (leftover from old 2-stage approach)
- pxe-service directives: only in proxy mode (breaks OVMF PXE in full mode)
- PXEClient vendor class echo for UEFI firmware compatibility
Integration tests:
- PXE boot test: blank UEFI VM → dnsmasq → HTTP Boot → iPXE → bastion → install
- ISO boot test: blank VM boots from bastion-generated ISO → same flow
- Shared helpers: pxe-network (no DHCP, nftables fix), pxe-vm (UEFI + ISO boot)
- test-provision.sh: runs both PXE + ISO tests with prerequisite checks
- 250GB sparse QCOW2 disk (LVM layout needs ~204GB)
201 unit tests passing (11 new).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 22:26:33 +00:00
|
|
|
echo "==> Logging in to $REGISTRY..."
|
2026-04-01 17:59:39 +01:00
|
|
|
podman login $TLS_FLAG -u michal -p "$GITEA_TOKEN" "$REGISTRY"
|
feat: install logging, error trapping, PXE/ISO integration tests
Kickstart installs on real hardware failed silently — no error reporting,
only 3 progress callbacks, zero log streaming. This overhaul makes every
install fully observable.
Kickstart improvements:
- Error trapping in %pre and %post (trap ERR sends failure details to bastion)
- 12+ granular progress stages (was 3): SSH, hostname, k3s prep, EFI boot, metadata
- Background log streamer: tails %post output and batch-sends to /api/log
- bastion_log() function for explicit log lines from kickstart scripts
Bastion API:
- POST /api/log — receives raw log lines from kickstart (single or batch)
- InstallLogBuffer — per-MAC ring buffer (2000 lines) + file persistence
- GET /api/logs/:mac — now returns log_lines + log_total alongside stages
- SSE /api/logs/:mac/follow — uses named events (event: stage vs event: log)
- Progress events forwarded to labd via bastion-progress WebSocket message
- Post-provision k3s logs routed through progressBus (was console-only)
dnsmasq fixes found during VM testing:
- HTTP Boot filename: ipxe-real.efi → ipxe.efi (leftover from old 2-stage approach)
- pxe-service directives: only in proxy mode (breaks OVMF PXE in full mode)
- PXEClient vendor class echo for UEFI firmware compatibility
Integration tests:
- PXE boot test: blank UEFI VM → dnsmasq → HTTP Boot → iPXE → bastion → install
- ISO boot test: blank VM boots from bastion-generated ISO → same flow
- Shared helpers: pxe-network (no DHCP, nftables fix), pxe-vm (UEFI + ISO boot)
- test-provision.sh: runs both PXE + ISO tests with prerequisite checks
- 250GB sparse QCOW2 disk (LVM layout needs ~204GB)
201 unit tests passing (11 new).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 22:26:33 +00:00
|
|
|
|
|
|
|
|
echo "==> Pushing $FULL_IMAGE:$TAG..."
|
2026-04-01 17:59:39 +01:00
|
|
|
podman manifest push --all $TLS_FLAG "$MANIFEST" "docker://$FULL_IMAGE:$TAG"
|
feat: install logging, error trapping, PXE/ISO integration tests
Kickstart installs on real hardware failed silently — no error reporting,
only 3 progress callbacks, zero log streaming. This overhaul makes every
install fully observable.
Kickstart improvements:
- Error trapping in %pre and %post (trap ERR sends failure details to bastion)
- 12+ granular progress stages (was 3): SSH, hostname, k3s prep, EFI boot, metadata
- Background log streamer: tails %post output and batch-sends to /api/log
- bastion_log() function for explicit log lines from kickstart scripts
Bastion API:
- POST /api/log — receives raw log lines from kickstart (single or batch)
- InstallLogBuffer — per-MAC ring buffer (2000 lines) + file persistence
- GET /api/logs/:mac — now returns log_lines + log_total alongside stages
- SSE /api/logs/:mac/follow — uses named events (event: stage vs event: log)
- Progress events forwarded to labd via bastion-progress WebSocket message
- Post-provision k3s logs routed through progressBus (was console-only)
dnsmasq fixes found during VM testing:
- HTTP Boot filename: ipxe-real.efi → ipxe.efi (leftover from old 2-stage approach)
- pxe-service directives: only in proxy mode (breaks OVMF PXE in full mode)
- PXEClient vendor class echo for UEFI firmware compatibility
Integration tests:
- PXE boot test: blank UEFI VM → dnsmasq → HTTP Boot → iPXE → bastion → install
- ISO boot test: blank VM boots from bastion-generated ISO → same flow
- Shared helpers: pxe-network (no DHCP, nftables fix), pxe-vm (UEFI + ISO boot)
- test-provision.sh: runs both PXE + ISO tests with prerequisite checks
- 250GB sparse QCOW2 disk (LVM layout needs ~204GB)
201 unit tests passing (11 new).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 22:26:33 +00:00
|
|
|
|
|
|
|
|
if [ "$TAG" != "latest" ]; then
|
|
|
|
|
echo "==> Also pushing as :latest..."
|
2026-04-01 17:59:39 +01:00
|
|
|
podman manifest push --all $TLS_FLAG "$MANIFEST" "docker://$FULL_IMAGE:latest"
|
feat: install logging, error trapping, PXE/ISO integration tests
Kickstart installs on real hardware failed silently — no error reporting,
only 3 progress callbacks, zero log streaming. This overhaul makes every
install fully observable.
Kickstart improvements:
- Error trapping in %pre and %post (trap ERR sends failure details to bastion)
- 12+ granular progress stages (was 3): SSH, hostname, k3s prep, EFI boot, metadata
- Background log streamer: tails %post output and batch-sends to /api/log
- bastion_log() function for explicit log lines from kickstart scripts
Bastion API:
- POST /api/log — receives raw log lines from kickstart (single or batch)
- InstallLogBuffer — per-MAC ring buffer (2000 lines) + file persistence
- GET /api/logs/:mac — now returns log_lines + log_total alongside stages
- SSE /api/logs/:mac/follow — uses named events (event: stage vs event: log)
- Progress events forwarded to labd via bastion-progress WebSocket message
- Post-provision k3s logs routed through progressBus (was console-only)
dnsmasq fixes found during VM testing:
- HTTP Boot filename: ipxe-real.efi → ipxe.efi (leftover from old 2-stage approach)
- pxe-service directives: only in proxy mode (breaks OVMF PXE in full mode)
- PXEClient vendor class echo for UEFI firmware compatibility
Integration tests:
- PXE boot test: blank UEFI VM → dnsmasq → HTTP Boot → iPXE → bastion → install
- ISO boot test: blank VM boots from bastion-generated ISO → same flow
- Shared helpers: pxe-network (no DHCP, nftables fix), pxe-vm (UEFI + ISO boot)
- test-provision.sh: runs both PXE + ISO tests with prerequisite checks
- 250GB sparse QCOW2 disk (LVM layout needs ~204GB)
201 unit tests passing (11 new).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 22:26:33 +00:00
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if [ -f "$SCRIPT_DIR/link-package.sh" ]; then
|
|
|
|
|
source "$SCRIPT_DIR/link-package.sh"
|
|
|
|
|
link_package "container" "labd"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
echo "==> Pushed successfully!"
|
|
|
|
|
else
|
|
|
|
|
echo "==> Skipping push (use --push to push to registry)"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
echo "==> Done!"
|
|
|
|
|
echo " Image: $FULL_IMAGE:$TAG"
|
|
|
|
|
echo " Platforms: $PLATFORMS"
|