Add distro/ubuntuCore for UC26 snap and image builds.
Centralize salmanoff snapcraft, dangerous-model image scripts, and QEMU workflow so UC26 can be reproduced from the SMO repo without ubuntu-core-practice. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,30 @@
|
|||||||
|
# Image build outputs (large)
|
||||||
|
artifacts/images/
|
||||||
|
artifacts/images-dev/
|
||||||
|
artifacts/logs/
|
||||||
|
|
||||||
|
# ubuntu-image scratch
|
||||||
|
work/ubuntu-image-snap/
|
||||||
|
work/ubuntu-image-dev/
|
||||||
|
|
||||||
|
# Dev signing outputs (account-specific)
|
||||||
|
models/salmanoff-dev-amd64.model
|
||||||
|
models/ubuntu-core-26-amd64.model
|
||||||
|
assertions/
|
||||||
|
config/dev-image.env
|
||||||
|
config/ssh/smo-dev
|
||||||
|
config/ssh/smo-dev.pub
|
||||||
|
|
||||||
|
# QEMU writable UEFI vars
|
||||||
|
artifacts/firmware/OVMF_VARS_4M.ms.fd
|
||||||
|
|
||||||
|
# snapcraft working tree
|
||||||
|
snaps/salmanoff/parts/
|
||||||
|
snaps/salmanoff/stage/
|
||||||
|
snaps/salmanoff/prime/
|
||||||
|
snaps/salmanoff/.snapcraft/
|
||||||
|
snaps/salmanoff/*.snap
|
||||||
|
|
||||||
|
# Editor / OS noise
|
||||||
|
*~
|
||||||
|
.DS_Store
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
# Copy to config/dev-image.env and adjust after setup-dev-signing.sh.
|
||||||
|
#
|
||||||
|
# ACCOUNT_ID comes from: snapcraft whoami (or snap whoami when logged in)
|
||||||
|
# SIGN_KEY_NAME comes from: snap keys (after snapcraft create-key + register-key)
|
||||||
|
|
||||||
|
ACCOUNT_ID=
|
||||||
|
SIGN_KEY_NAME=salmanoff-dev
|
||||||
|
|
||||||
|
# System user created on first boot (no Ubuntu One / console-conf SSO).
|
||||||
|
SYSTEM_USER_NAME=smo
|
||||||
|
SYSTEM_USER_EMAIL=smo-dev@salmanoff
|
||||||
|
# Public key used in the system-user assertion (private key stays local).
|
||||||
|
SSH_PUBKEY_FILE=config/ssh/smo-dev.pub
|
||||||
|
|
||||||
|
# Dangerous-grade dev model (UC26 amd64). salmanoff is optional until --snap is passed.
|
||||||
|
MODEL_NAME=salmanoff-dev-amd64
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
# Defaults for scripts/run-qemu.sh (source manually if you want overrides)
|
||||||
|
RAM_MB=2048
|
||||||
|
SMP=2
|
||||||
|
SSH_PORT=8022
|
||||||
|
OVMF_CODE=/usr/share/OVMF/OVMF_CODE_4M.secboot.fd
|
||||||
|
OVMF_VARS_TEMPLATE=/usr/share/OVMF/OVMF_VARS_4M.ms.fd
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# Optional: remote git source if snapcraft.yaml is switched from local tree to git.
|
||||||
|
SMO_GIT_URL=git@zbz-gitea-as-hayodea:hayodea/salmanoff.git
|
||||||
|
SMO_GIT_BRANCH=clast
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
{
|
||||||
|
"type": "model",
|
||||||
|
"authority-id": "@ACCOUNT_ID@",
|
||||||
|
"brand-id": "@ACCOUNT_ID@",
|
||||||
|
"series": "16",
|
||||||
|
"model": "salmanoff-dev-amd64",
|
||||||
|
"architecture": "amd64",
|
||||||
|
"base": "core26",
|
||||||
|
"grade": "dangerous",
|
||||||
|
"system-user-authority": "*",
|
||||||
|
"timestamp": "@TIMESTAMP@",
|
||||||
|
"snaps": [
|
||||||
|
{
|
||||||
|
"name": "pc",
|
||||||
|
"type": "gadget",
|
||||||
|
"default-channel": "26/stable",
|
||||||
|
"id": "UqFziVZDHLSyO3TqSWgNBoAdHbLI4dAH"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "pc-kernel",
|
||||||
|
"type": "kernel",
|
||||||
|
"default-channel": "26/stable",
|
||||||
|
"id": "pYVQrBcKmBa0mZ4CCN7ExT6jH8rY1hza"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "core26",
|
||||||
|
"type": "base",
|
||||||
|
"default-channel": "cloud-init/stable",
|
||||||
|
"id": "cUqM61hRuZAJYmIS898Ux66VY61gBbZf"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "snapd",
|
||||||
|
"type": "snapd",
|
||||||
|
"default-channel": "latest/stable",
|
||||||
|
"id": "PMrrV4ml8uWuEUDBT8dSGnKUYbevVhc4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "salmanoff",
|
||||||
|
"type": "app",
|
||||||
|
"presence": "optional"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Executable
+133
@@ -0,0 +1,133 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Build dangerous-grade UC26 image with seeded system-user (no Ubuntu One at first boot).
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
UC_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
ENV_FILE="${UC_ROOT}/config/dev-image.env"
|
||||||
|
|
||||||
|
MODEL="${UC_ROOT}/models/salmanoff-dev-amd64.model"
|
||||||
|
SYSTEM_USER_ASSERT="${UC_ROOT}/assertions/smo-system-user.assert"
|
||||||
|
WORKDIR="${UC_ROOT}/work/ubuntu-image-dev"
|
||||||
|
OUTPUT_DIR="${UC_ROOT}/artifacts/images-dev"
|
||||||
|
LOG_DIR="${UC_ROOT}/artifacts/logs"
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<'EOF'
|
||||||
|
Usage: build-dev-image.sh [OPTIONS]
|
||||||
|
|
||||||
|
Build a dangerous-grade ubuntu-core dev image with:
|
||||||
|
- custom model (salmanoff-dev-amd64)
|
||||||
|
- system-user assertion seeded (SSH login as smo, no Ubuntu One)
|
||||||
|
|
||||||
|
Prerequisites:
|
||||||
|
scripts/setup-dev-signing.sh (once: Snap Store login + signing key)
|
||||||
|
scripts/sign-dev-assertions.sh (sign model + system-user)
|
||||||
|
|
||||||
|
Options:
|
||||||
|
--snap PATH Extra snap to preinstall (repeatable). Requires grade dangerous.
|
||||||
|
--fresh-workdir Remove work/ubuntu-image-dev before building
|
||||||
|
--resume Pass --resume to ubuntu-image
|
||||||
|
--no-sign Skip sign-dev-assertions.sh (use existing assertions)
|
||||||
|
-h, --help Show this help
|
||||||
|
|
||||||
|
Outputs:
|
||||||
|
artifacts/images-dev/pc.img
|
||||||
|
artifacts/logs/build-dev-<timestamp>.log
|
||||||
|
|
||||||
|
After first boot in QEMU:
|
||||||
|
ssh -i config/ssh/smo-dev smo@localhost -p 8022
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
fresh_workdir=false
|
||||||
|
resume=false
|
||||||
|
no_sign=false
|
||||||
|
extra_snaps=()
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--snap) extra_snaps+=("$2"); shift 2 ;;
|
||||||
|
--fresh-workdir) fresh_workdir=true; shift ;;
|
||||||
|
--resume) resume=true; shift ;;
|
||||||
|
--no-sign) no_sign=true; shift ;;
|
||||||
|
-h|--help) usage; exit 0 ;;
|
||||||
|
*) echo "Unknown option: $1" >&2; usage >&2; exit 1 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ "$no_sign" == false ]]; then
|
||||||
|
"${UC_ROOT}/scripts/sign-dev-assertions.sh"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -f "$MODEL" ]]; then
|
||||||
|
echo "Missing signed model: $MODEL" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [[ ! -f "$SYSTEM_USER_ASSERT" ]]; then
|
||||||
|
echo "Missing system-user assertion: $SYSTEM_USER_ASSERT" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! command -v ubuntu-image >/dev/null 2>&1; then
|
||||||
|
echo "ubuntu-image not found. Install with: sudo snap install ubuntu-image --classic" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$OUTPUT_DIR" "$LOG_DIR"
|
||||||
|
|
||||||
|
if [[ "$fresh_workdir" == true ]] || [[ "$resume" == false ]]; then
|
||||||
|
if [[ -d "$WORKDIR" ]]; then
|
||||||
|
echo "Removing workdir: $WORKDIR"
|
||||||
|
rm -rf "$WORKDIR"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
mkdir -p "$WORKDIR"
|
||||||
|
|
||||||
|
timestamp="$(date +%Y%m%d-%H%M%S)"
|
||||||
|
log_file="${LOG_DIR}/build-dev-${timestamp}.log"
|
||||||
|
|
||||||
|
cmd=(ubuntu-image snap
|
||||||
|
--workdir "$WORKDIR"
|
||||||
|
--output-dir "$OUTPUT_DIR"
|
||||||
|
--image-size 4G
|
||||||
|
--assertion "$SYSTEM_USER_ASSERT"
|
||||||
|
"$MODEL")
|
||||||
|
|
||||||
|
for snap_path in "${extra_snaps[@]}"; do
|
||||||
|
if [[ ! -f "$snap_path" ]]; then
|
||||||
|
echo "Snap not found: $snap_path" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
cmd+=(--snap "$snap_path")
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ "$resume" == true ]]; then
|
||||||
|
cmd+=(--resume)
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Model: $MODEL"
|
||||||
|
echo "System user: $SYSTEM_USER_ASSERT"
|
||||||
|
echo "Workdir: $WORKDIR"
|
||||||
|
echo "Output dir: $OUTPUT_DIR"
|
||||||
|
echo "Log: $log_file"
|
||||||
|
if [[ ${#extra_snaps[@]} -gt 0 ]]; then
|
||||||
|
echo "Extra snaps: ${extra_snaps[*]}"
|
||||||
|
fi
|
||||||
|
echo "Running: ${cmd[*]}"
|
||||||
|
|
||||||
|
"${cmd[@]}" 2>&1 | tee "$log_file"
|
||||||
|
|
||||||
|
img="${OUTPUT_DIR}/pc.img"
|
||||||
|
if [[ ! -f "$img" ]]; then
|
||||||
|
echo "Build finished but $img not found" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Done. Image: $img"
|
||||||
|
if [[ -f "$ENV_FILE" ]]; then
|
||||||
|
# shellcheck source=/dev/null
|
||||||
|
source "$ENV_FILE"
|
||||||
|
echo "SSH: ssh -i ${UC_ROOT}/config/ssh/smo-dev ${SYSTEM_USER_NAME:-smo}@localhost -p 8022"
|
||||||
|
fi
|
||||||
|
ls -lh "$img" "${img}.seed.manifest" 2>/dev/null || ls -lh "$img"
|
||||||
Executable
+78
@@ -0,0 +1,78 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Build the salmanoff snap from the enclosing SMO repo tree.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
UC_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
SNAP_DIR="${UC_ROOT}/snaps/salmanoff"
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<'EOF'
|
||||||
|
Usage: build-snap.sh [OPTIONS]
|
||||||
|
|
||||||
|
Build salmanoff snap with snapcraft (source: SMO repo root via local snapcraft.yaml).
|
||||||
|
|
||||||
|
Options:
|
||||||
|
--refetch-source Clean salmanoff part before pack (re-copy tree + submodules)
|
||||||
|
--clean Remove all snapcraft parts/prime/stage before building
|
||||||
|
--lxd Use LXD cleanroom instead of --destructive-mode
|
||||||
|
-h, --help Show this help
|
||||||
|
|
||||||
|
Prerequisites:
|
||||||
|
snap install snapcraft --classic
|
||||||
|
For --lxd on core26: LXD outbound internet (run: sudo scripts/fix-lxd-network.sh)
|
||||||
|
For --destructive-mode: run on Ubuntu 26.04 or use --lxd
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
clean=false
|
||||||
|
refetch_source=false
|
||||||
|
use_lxd=false
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--clean) clean=true; shift ;;
|
||||||
|
--refetch-source) refetch_source=true; shift ;;
|
||||||
|
--lxd) use_lxd=true; shift ;;
|
||||||
|
-h|--help) usage; exit 0 ;;
|
||||||
|
*) echo "Unknown option: $1" >&2; usage >&2; exit 1 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if ! command -v snapcraft >/dev/null 2>&1; then
|
||||||
|
echo "snapcraft not found. Install with: sudo snap install snapcraft --classic" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$clean" == true ]]; then
|
||||||
|
rm -rf "${SNAP_DIR}/parts" "${SNAP_DIR}/stage" "${SNAP_DIR}/prime" \
|
||||||
|
"${SNAP_DIR}/.snapcraft" "${SNAP_DIR}"/*.snap 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd "$SNAP_DIR"
|
||||||
|
|
||||||
|
pack_flags=()
|
||||||
|
if [[ "$use_lxd" != true ]]; then
|
||||||
|
pack_flags+=(--destructive-mode)
|
||||||
|
else
|
||||||
|
pack_flags+=(--use-lxd)
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$refetch_source" == true && "$clean" != true ]]; then
|
||||||
|
echo "Refetching salmanoff source (clean part + pull)..."
|
||||||
|
snapcraft clean salmanoff "${pack_flags[@]}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
cmd=(snapcraft pack "${pack_flags[@]}")
|
||||||
|
|
||||||
|
echo "UC root: $UC_ROOT"
|
||||||
|
echo "Snap dir: $SNAP_DIR"
|
||||||
|
echo "Running: ${cmd[*]}"
|
||||||
|
|
||||||
|
"${cmd[@]}"
|
||||||
|
|
||||||
|
snap_file="$(ls -1t "${SNAP_DIR}"/*.snap 2>/dev/null | head -1)"
|
||||||
|
if [[ -n "$snap_file" ]]; then
|
||||||
|
echo ""
|
||||||
|
echo "Built: $snap_file"
|
||||||
|
ls -lh "$snap_file"
|
||||||
|
fi
|
||||||
+96
@@ -0,0 +1,96 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Build stock Ubuntu Core 26 amd64 image from Canonical's signed model assertion.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
UC_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
|
||||||
|
MODEL="${UC_ROOT}/models/ubuntu-core-26-amd64.model"
|
||||||
|
WORKDIR="${UC_ROOT}/work/ubuntu-image-snap"
|
||||||
|
OUTPUT_DIR="${UC_ROOT}/artifacts/images"
|
||||||
|
LOG_DIR="${UC_ROOT}/artifacts/logs"
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<'EOF'
|
||||||
|
Usage: build-stock-image.sh [OPTIONS]
|
||||||
|
|
||||||
|
Build a stock ubuntu-core-26-amd64 disk image with ubuntu-image snap.
|
||||||
|
|
||||||
|
Options:
|
||||||
|
--fresh-workdir Remove work/ubuntu-image-snap before building (full re-download)
|
||||||
|
--resume Pass --resume to ubuntu-image (continue partial build)
|
||||||
|
-h, --help Show this help
|
||||||
|
|
||||||
|
Outputs:
|
||||||
|
artifacts/images/pc.img
|
||||||
|
artifacts/images/pc.img.seed.manifest
|
||||||
|
artifacts/logs/build-<timestamp>.log
|
||||||
|
|
||||||
|
Host prerequisites:
|
||||||
|
snap install ubuntu-image --classic
|
||||||
|
scripts/fetch-model.sh (download signed model if missing)
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
fresh_workdir=false
|
||||||
|
resume=false
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--fresh-workdir) fresh_workdir=true; shift ;;
|
||||||
|
--resume) resume=true; shift ;;
|
||||||
|
-h|--help) usage; exit 0 ;;
|
||||||
|
*) echo "Unknown option: $1" >&2; usage >&2; exit 1 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ ! -f "$MODEL" ]]; then
|
||||||
|
echo "Missing model assertion: $MODEL" >&2
|
||||||
|
echo "Run: scripts/fetch-model.sh" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! command -v ubuntu-image >/dev/null 2>&1; then
|
||||||
|
echo "ubuntu-image not found. Install with: sudo snap install ubuntu-image --classic" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$OUTPUT_DIR" "$LOG_DIR"
|
||||||
|
|
||||||
|
if [[ "$fresh_workdir" == true ]] || [[ "$resume" == false ]]; then
|
||||||
|
if [[ -d "$WORKDIR" ]]; then
|
||||||
|
echo "Removing workdir: $WORKDIR"
|
||||||
|
rm -rf "$WORKDIR"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
mkdir -p "$WORKDIR"
|
||||||
|
|
||||||
|
timestamp="$(date +%Y%m%d-%H%M%S)"
|
||||||
|
log_file="${LOG_DIR}/build-${timestamp}.log"
|
||||||
|
|
||||||
|
cmd=(ubuntu-image snap
|
||||||
|
--workdir "$WORKDIR"
|
||||||
|
--output-dir "$OUTPUT_DIR"
|
||||||
|
--image-size 4G
|
||||||
|
"$MODEL")
|
||||||
|
|
||||||
|
if [[ "$resume" == true ]]; then
|
||||||
|
cmd+=(--resume)
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Model: $MODEL"
|
||||||
|
echo "Workdir: $WORKDIR"
|
||||||
|
echo "Output dir: $OUTPUT_DIR"
|
||||||
|
echo "Log: $log_file"
|
||||||
|
echo "Running: ${cmd[*]}"
|
||||||
|
|
||||||
|
"${cmd[@]}" 2>&1 | tee "$log_file"
|
||||||
|
|
||||||
|
img="${OUTPUT_DIR}/pc.img"
|
||||||
|
if [[ ! -f "$img" ]]; then
|
||||||
|
echo "Build finished but $img not found" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Done. Image: $img"
|
||||||
|
ls -lh "$img" "${img}.seed.manifest" 2>/dev/null || ls -lh "$img"
|
||||||
Executable
+12
@@ -0,0 +1,12 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Refresh the signed reference model from snapcore/models on GitHub.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
UC_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
MODEL="${UC_ROOT}/models/ubuntu-core-26-amd64.model"
|
||||||
|
URL="https://raw.githubusercontent.com/snapcore/models/master/ubuntu-core-26-amd64.model"
|
||||||
|
|
||||||
|
mkdir -p "$(dirname "$MODEL")"
|
||||||
|
curl -fsSL -o "$MODEL" "$URL"
|
||||||
|
echo "Updated: $MODEL"
|
||||||
|
head -15 "$MODEL"
|
||||||
Executable
+68
@@ -0,0 +1,68 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Restore outbound internet for LXD containers (common Docker + LXD conflict on Ubuntu).
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
if [[ "${EUID}" -ne 0 ]]; then
|
||||||
|
echo "Run with sudo: sudo $0" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
LXD_BRIDGE="${LXD_BRIDGE:-lxdbr0}"
|
||||||
|
LXD_SUBNET="$(lxc network get "${LXD_BRIDGE}" ipv4.address 2>/dev/null | cut -d/ -f1 | awk -F. '{print $1"."$2"."$3".0/24"}')"
|
||||||
|
if [[ -z "${LXD_SUBNET}" || "${LXD_SUBNET}" == ".0/24" ]]; then
|
||||||
|
LXD_SUBNET="10.239.141.0/24"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "LXD bridge: ${LXD_BRIDGE}"
|
||||||
|
echo "LXD subnet: ${LXD_SUBNET}"
|
||||||
|
|
||||||
|
echo "==> Allow LXD traffic through Docker's DOCKER-USER chain (if present)"
|
||||||
|
if iptables -L DOCKER-USER -n &>/dev/null; then
|
||||||
|
iptables -C DOCKER-USER -i "${LXD_BRIDGE}" -j ACCEPT 2>/dev/null \
|
||||||
|
|| iptables -I DOCKER-USER 1 -i "${LXD_BRIDGE}" -j ACCEPT
|
||||||
|
iptables -C DOCKER-USER -o "${LXD_BRIDGE}" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT 2>/dev/null \
|
||||||
|
|| iptables -I DOCKER-USER 2 -o "${LXD_BRIDGE}" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
|
||||||
|
echo " DOCKER-USER rules added"
|
||||||
|
else
|
||||||
|
echo " No DOCKER-USER chain (Docker may not be managing iptables)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "==> Ensure FORWARD accepts ${LXD_BRIDGE}"
|
||||||
|
iptables -C FORWARD -i "${LXD_BRIDGE}" -j ACCEPT 2>/dev/null \
|
||||||
|
|| iptables -I FORWARD 1 -i "${LXD_BRIDGE}" -j ACCEPT
|
||||||
|
iptables -C FORWARD -o "${LXD_BRIDGE}" -j ACCEPT 2>/dev/null \
|
||||||
|
|| iptables -I FORWARD 1 -o "${LXD_BRIDGE}" -j ACCEPT
|
||||||
|
|
||||||
|
echo "==> Ensure MASQUERADE for ${LXD_SUBNET}"
|
||||||
|
if ! iptables -t nat -C POSTROUTING -s "${LXD_SUBNET}" ! -d "${LXD_SUBNET}" -j MASQUERADE 2>/dev/null; then
|
||||||
|
iptables -t nat -A POSTROUTING -s "${LXD_SUBNET}" ! -d "${LXD_SUBNET}" -j MASQUERADE
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "==> LXD network: disable per-network firewall, refresh NAT"
|
||||||
|
lxc network set "${LXD_BRIDGE}" ipv4.firewall false
|
||||||
|
lxc network set "${LXD_BRIDGE}" ipv6.firewall false
|
||||||
|
lxc network set "${LXD_BRIDGE}" ipv4.nat false
|
||||||
|
lxc network set "${LXD_BRIDGE}" ipv4.nat true
|
||||||
|
|
||||||
|
echo "==> Restart LXD daemon"
|
||||||
|
if command -v snap >/dev/null 2>&1 && snap list lxd &>/dev/null; then
|
||||||
|
snap restart lxd
|
||||||
|
else
|
||||||
|
systemctl restart lxd || systemctl restart snap.lxd.daemon
|
||||||
|
fi
|
||||||
|
sleep 2
|
||||||
|
|
||||||
|
echo "==> Smoke test (ephemeral container in project snapcraft)"
|
||||||
|
TEST_NAME="lxd-net-test-$$"
|
||||||
|
lxc launch ubuntu:26.04 "${TEST_NAME}" --project snapcraft
|
||||||
|
trap 'lxc delete -f --project snapcraft "${TEST_NAME}" 2>/dev/null || true' EXIT
|
||||||
|
if lxc exec --project snapcraft "${TEST_NAME}" -- curl -fsSI --max-time 15 https://github.com | head -1; then
|
||||||
|
echo "OK: container outbound HTTPS works"
|
||||||
|
else
|
||||||
|
echo "FAIL: container still cannot reach github.com" >&2
|
||||||
|
echo "Consider permanent Docker fix: add \"iptables\": false to /etc/docker/daemon.json and restart docker" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Done. LXD containers should have outbound internet now."
|
||||||
Executable
+105
@@ -0,0 +1,105 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Boot Ubuntu Core 26 amd64 image in QEMU (UEFI, user networking, SSH on localhost:8022).
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
UC_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
|
||||||
|
IMG="${UC_ROOT}/artifacts/images-dev/pc.img"
|
||||||
|
FIRMWARE_DIR="${UC_ROOT}/artifacts/firmware"
|
||||||
|
|
||||||
|
OVMF_CODE="${OVMF_CODE:-/usr/share/OVMF/OVMF_CODE_4M.secboot.fd}"
|
||||||
|
OVMF_VARS_TEMPLATE="${OVMF_VARS_TEMPLATE:-/usr/share/OVMF/OVMF_VARS_4M.ms.fd}"
|
||||||
|
OVMF_VARS="${FIRMWARE_DIR}/OVMF_VARS_4M.ms.fd"
|
||||||
|
|
||||||
|
RAM_MB="${RAM_MB:-2048}"
|
||||||
|
SMP="${SMP:-2}"
|
||||||
|
SSH_PORT="${SSH_PORT:-8022}"
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<'EOF'
|
||||||
|
Usage: run-qemu.sh [OPTIONS]
|
||||||
|
|
||||||
|
Boot a UC26 pc.img in QEMU.
|
||||||
|
|
||||||
|
Options:
|
||||||
|
--img PATH Disk image (default: artifacts/images-dev/pc.img)
|
||||||
|
--stock Use stock image artifacts/images/pc.img (console-conf / Ubuntu SSO)
|
||||||
|
--ram MB RAM in MiB (default: 2048)
|
||||||
|
--smp N vCPU count (default: 2)
|
||||||
|
--ssh-port PORT Host port forwarded to guest :22 (default: 8022)
|
||||||
|
--reset-uefi-vars Recopy writable OVMF vars from host template
|
||||||
|
-h, --help Show this help
|
||||||
|
|
||||||
|
Dev image (default): SSH after first boot without Ubuntu One:
|
||||||
|
ssh -i config/ssh/smo-dev smo@localhost -p 8022
|
||||||
|
|
||||||
|
Stock image (--stock): complete console-conf in the serial console first.
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
reset_vars=false
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--stock) IMG="${UC_ROOT}/artifacts/images/pc.img"; shift ;;
|
||||||
|
--img) IMG="$2"; shift 2 ;;
|
||||||
|
--ram) RAM_MB="$2"; shift 2 ;;
|
||||||
|
--smp) SMP="$2"; shift 2 ;;
|
||||||
|
--ssh-port) SSH_PORT="$2"; shift 2 ;;
|
||||||
|
--reset-uefi-vars) reset_vars=true; shift ;;
|
||||||
|
-h|--help) usage; exit 0 ;;
|
||||||
|
*) echo "Unknown option: $1" >&2; usage >&2; exit 1 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ ! -f "$IMG" ]]; then
|
||||||
|
echo "Image not found: $IMG" >&2
|
||||||
|
echo "Build dev image: scripts/build-dev-image.sh" >&2
|
||||||
|
echo "Or stock image: scripts/build-stock-image.sh (then run-qemu.sh --stock)" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
for f in "$OVMF_CODE" "$OVMF_VARS_TEMPLATE"; do
|
||||||
|
if [[ ! -f "$f" ]]; then
|
||||||
|
echo "Missing firmware file: $f" >&2
|
||||||
|
echo "Install with: sudo apt install ovmf qemu-kvm" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if ! command -v qemu-system-x86_64 >/dev/null 2>&1; then
|
||||||
|
echo "qemu-system-x86_64 not found. Install with: sudo apt install qemu-kvm" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$FIRMWARE_DIR"
|
||||||
|
|
||||||
|
if [[ "$reset_vars" == true || ! -f "$OVMF_VARS" ]]; then
|
||||||
|
cp "$OVMF_VARS_TEMPLATE" "$OVMF_VARS"
|
||||||
|
echo "UEFI vars: $OVMF_VARS (fresh copy from template)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
kvm_args=()
|
||||||
|
if [[ -r /dev/kvm ]]; then
|
||||||
|
kvm_args=(-enable-kvm -cpu host)
|
||||||
|
else
|
||||||
|
echo "Warning: /dev/kvm not available; running without KVM" >&2
|
||||||
|
kvm_args=(-cpu max)
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Image: $IMG"
|
||||||
|
echo "RAM: ${RAM_MB}M SMP: $SMP SSH: localhost:${SSH_PORT}"
|
||||||
|
|
||||||
|
exec qemu-system-x86_64 \
|
||||||
|
"${kvm_args[@]}" \
|
||||||
|
-smp "$SMP" \
|
||||||
|
-m "$RAM_MB" \
|
||||||
|
-machine q35 \
|
||||||
|
-global ICH9-LPC.disable_s3=1 \
|
||||||
|
-netdev "user,id=net0,hostfwd=tcp::${SSH_PORT}-:22" \
|
||||||
|
-device virtio-net-pci,netdev=net0 \
|
||||||
|
-drive "file=${OVMF_CODE},if=pflash,format=raw,unit=0,readonly=on" \
|
||||||
|
-drive "file=${OVMF_VARS},if=pflash,format=raw,unit=1" \
|
||||||
|
-drive "file=${IMG},if=none,format=raw,id=disk1" \
|
||||||
|
-device virtio-blk-pci,drive=disk1,bootindex=1 \
|
||||||
|
-serial mon:stdio
|
||||||
+120
@@ -0,0 +1,120 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# One-time setup: Ubuntu One login + GPG signing key for custom UC26 dev models.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
UC_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
ENV_FILE="${UC_ROOT}/config/dev-image.env"
|
||||||
|
EXAMPLE="${UC_ROOT}/config/dev-image.env.example"
|
||||||
|
KEY_NAME="${SIGN_KEY_NAME:-salmanoff-dev}"
|
||||||
|
SSH_DIR="${UC_ROOT}/config/ssh"
|
||||||
|
SSH_PRIV="${SSH_DIR}/smo-dev"
|
||||||
|
SSH_PUB="${SSH_DIR}/smo-dev.pub"
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<'EOF'
|
||||||
|
Usage: setup-dev-signing.sh [OPTIONS]
|
||||||
|
|
||||||
|
Prepare signing credentials for dangerous-grade salmanoff-dev-amd64 images.
|
||||||
|
|
||||||
|
This script:
|
||||||
|
1. Ensures an SSH keypair exists for the seeded system user (smo).
|
||||||
|
2. Guides snapcraft login + create-key + register-key (interactive).
|
||||||
|
3. Writes config/dev-image.env with your Snap Store account id.
|
||||||
|
|
||||||
|
Options:
|
||||||
|
--key-name NAME Signing key name (default: salmanoff-dev)
|
||||||
|
-h, --help Show this help
|
||||||
|
|
||||||
|
After setup, run:
|
||||||
|
scripts/sign-dev-assertions.sh
|
||||||
|
scripts/build-dev-image.sh
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--key-name) KEY_NAME="$2"; shift 2 ;;
|
||||||
|
-h|--help) usage; exit 0 ;;
|
||||||
|
*) echo "Unknown option: $1" >&2; usage >&2; exit 1 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
mkdir -p "$SSH_DIR"
|
||||||
|
|
||||||
|
if [[ ! -f "$SSH_PUB" ]]; then
|
||||||
|
echo "Generating SSH keypair for system user: $SSH_PRIV"
|
||||||
|
ssh-keygen -t ed25519 -N "" -f "$SSH_PRIV" -C "smo-dev@salmanoff"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! command -v snapcraft >/dev/null 2>&1; then
|
||||||
|
echo "snapcraft not found. Install with: sudo snap install snapcraft --classic" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Step 1: log in to the Snap Store (Ubuntu One) ==="
|
||||||
|
echo "Run: snapcraft login"
|
||||||
|
echo ""
|
||||||
|
if ! snapcraft whoami >/dev/null 2>&1; then
|
||||||
|
echo "Not logged in yet. Complete 'snapcraft login' in this terminal, then re-run this script." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
ACCOUNT_ID="$(snapcraft whoami 2>/dev/null | awk '/^id:/ {print $2}')"
|
||||||
|
if [[ -z "$ACCOUNT_ID" ]]; then
|
||||||
|
echo "Could not read account id from 'snapcraft whoami'" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "Account id: $ACCOUNT_ID"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Step 2: create and register a signing key ==="
|
||||||
|
if ! snap keys 2>/dev/null | awk 'NR>1 {print $1}' | grep -qx "$KEY_NAME"; then
|
||||||
|
echo "No local key named '$KEY_NAME'."
|
||||||
|
echo "Run interactively (you will choose a passphrase):"
|
||||||
|
echo " snapcraft create-key $KEY_NAME"
|
||||||
|
echo " snapcraft register-key $KEY_NAME"
|
||||||
|
echo ""
|
||||||
|
echo "Re-run this script after both commands succeed." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
KEY_FP="$(snap keys 2>/dev/null | awk -v k="$KEY_NAME" '$1 == k {print $2}')"
|
||||||
|
if [[ -z "$KEY_FP" ]]; then
|
||||||
|
echo "Could not read SHA3-384 fingerprint for key '$KEY_NAME'" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! snap known --remote account-key "public-key-sha3-384=${KEY_FP}" >/dev/null 2>&1; then
|
||||||
|
echo "Key '$KEY_NAME' exists locally but is not registered in the store."
|
||||||
|
echo "Run: snapcraft register-key $KEY_NAME"
|
||||||
|
echo "Then re-run this script." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Signing key: $KEY_NAME ($KEY_FP)"
|
||||||
|
|
||||||
|
if [[ ! -f "$ENV_FILE" ]]; then
|
||||||
|
cp "$EXAMPLE" "$ENV_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
tmp="$(mktemp)"
|
||||||
|
while IFS= read -r line || [[ -n "$line" ]]; do
|
||||||
|
case "$line" in
|
||||||
|
ACCOUNT_ID=*) echo "ACCOUNT_ID=${ACCOUNT_ID}" ;;
|
||||||
|
SIGN_KEY_NAME=*) echo "SIGN_KEY_NAME=${KEY_NAME}" ;;
|
||||||
|
SSH_PUBKEY_FILE=*) echo "SSH_PUBKEY_FILE=config/ssh/smo-dev.pub" ;;
|
||||||
|
*) echo "$line" ;;
|
||||||
|
esac
|
||||||
|
done < "$ENV_FILE" > "$tmp"
|
||||||
|
mv "$tmp" "$ENV_FILE"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Wrote $ENV_FILE"
|
||||||
|
echo ""
|
||||||
|
echo "Next:"
|
||||||
|
echo " scripts/sign-dev-assertions.sh"
|
||||||
|
echo " scripts/build-dev-image.sh"
|
||||||
|
echo ""
|
||||||
|
echo "SSH to the VM after first boot:"
|
||||||
|
echo " ssh -i ${SSH_PRIV} smo@localhost -p 8022"
|
||||||
+106
@@ -0,0 +1,106 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Sign dangerous-grade model + system-user assertions for salmanoff-dev-amd64.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
UC_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
ENV_FILE="${UC_ROOT}/config/dev-image.env"
|
||||||
|
MODEL_TEMPLATE="${UC_ROOT}/models/salmanoff-dev-amd64.model.json"
|
||||||
|
ASSERT_DIR="${UC_ROOT}/assertions"
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<'EOF'
|
||||||
|
Usage: sign-dev-assertions.sh [OPTIONS]
|
||||||
|
|
||||||
|
Sign the dev model assertion and a system-user assertion (SSH key, no Ubuntu One).
|
||||||
|
|
||||||
|
Requires config/dev-image.env (see scripts/setup-dev-signing.sh).
|
||||||
|
|
||||||
|
Outputs:
|
||||||
|
models/salmanoff-dev-amd64.model
|
||||||
|
assertions/smo-system-user.assert (account + account-key + system-user chain)
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
-h|--help) usage; exit 0 ;;
|
||||||
|
*) echo "Unknown option: $1" >&2; usage >&2; exit 1 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ ! -f "$ENV_FILE" ]]; then
|
||||||
|
echo "Missing $ENV_FILE — run scripts/setup-dev-signing.sh first" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
# shellcheck source=/dev/null
|
||||||
|
source "$ENV_FILE"
|
||||||
|
|
||||||
|
: "${ACCOUNT_ID:?ACCOUNT_ID not set in $ENV_FILE}"
|
||||||
|
: "${SIGN_KEY_NAME:?SIGN_KEY_NAME not set in $ENV_FILE}"
|
||||||
|
: "${SYSTEM_USER_NAME:=smo}"
|
||||||
|
: "${SYSTEM_USER_EMAIL:=smo-dev@salmanoff}"
|
||||||
|
: "${SSH_PUBKEY_FILE:=config/ssh/smo-dev.pub}"
|
||||||
|
: "${MODEL_NAME:=salmanoff-dev-amd64}"
|
||||||
|
|
||||||
|
SSH_PUBKEY_PATH="${UC_ROOT}/${SSH_PUBKEY_FILE}"
|
||||||
|
if [[ ! -f "$SSH_PUBKEY_PATH" ]]; then
|
||||||
|
echo "SSH public key not found: $SSH_PUBKEY_PATH" >&2
|
||||||
|
echo "Run scripts/setup-dev-signing.sh" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
KEY_FP="$(snap keys 2>/dev/null | awk -v k="$SIGN_KEY_NAME" '$1 == k {print $2}')"
|
||||||
|
if [[ -z "$KEY_FP" ]]; then
|
||||||
|
echo "Signing key '$SIGN_KEY_NAME' not found. Run scripts/setup-dev-signing.sh" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! snap known --remote account-key "public-key-sha3-384=${KEY_FP}" >/dev/null 2>&1; then
|
||||||
|
echo "Key '$SIGN_KEY_NAME' is not registered in the Snap Store." >&2
|
||||||
|
echo "Run: snapcraft register-key $SIGN_KEY_NAME" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
export GPG_TTY="${GPG_TTY:-$(tty)}"
|
||||||
|
|
||||||
|
mkdir -p "$ASSERT_DIR" "${UC_ROOT}/models"
|
||||||
|
|
||||||
|
TIMESTAMP="$(date -Iseconds --utc)"
|
||||||
|
MODEL_JSON="$(mktemp)"
|
||||||
|
MODEL_OUT="${UC_ROOT}/models/${MODEL_NAME}.model"
|
||||||
|
SYSTEM_USER_JSON="$(mktemp)"
|
||||||
|
SYSTEM_USER_OUT="${ASSERT_DIR}/smo-system-user.assert"
|
||||||
|
|
||||||
|
sed -e "s/@ACCOUNT_ID@/${ACCOUNT_ID}/g" \
|
||||||
|
-e "s/@TIMESTAMP@/${TIMESTAMP}/g" \
|
||||||
|
"$MODEL_TEMPLATE" > "$MODEL_JSON"
|
||||||
|
|
||||||
|
echo "Signing model → $MODEL_OUT"
|
||||||
|
snap sign -k "$SIGN_KEY_NAME" "$MODEL_JSON" > "$MODEL_OUT"
|
||||||
|
|
||||||
|
SSH_PUB="$(tr -d '\n' < "$SSH_PUBKEY_PATH")"
|
||||||
|
cat > "$SYSTEM_USER_JSON" <<EOF
|
||||||
|
{
|
||||||
|
"type": "system-user",
|
||||||
|
"authority-id": "${ACCOUNT_ID}",
|
||||||
|
"brand-id": "${ACCOUNT_ID}",
|
||||||
|
"series": ["16"],
|
||||||
|
"models": ["${MODEL_NAME}"],
|
||||||
|
"name": "Salmanoff Dev",
|
||||||
|
"username": "${SYSTEM_USER_NAME}",
|
||||||
|
"email": "${SYSTEM_USER_EMAIL}",
|
||||||
|
"ssh-keys": ["${SSH_PUB}"],
|
||||||
|
"since": "2026-06-21T00:00:00+00:00",
|
||||||
|
"until": "2064-06-21T00:00:00+00:00"
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo "Signing system-user chain → $SYSTEM_USER_OUT"
|
||||||
|
snap sign -k "$SIGN_KEY_NAME" "$SYSTEM_USER_JSON" --chain > "$SYSTEM_USER_OUT"
|
||||||
|
|
||||||
|
rm -f "$MODEL_JSON" "$SYSTEM_USER_JSON"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Model authority/brand: $ACCOUNT_ID"
|
||||||
|
echo "System user: ${SYSTEM_USER_NAME} (SSH pubkey from ${SSH_PUBKEY_FILE})"
|
||||||
|
echo "Signing key: ${SIGN_KEY_NAME} (${KEY_FP})"
|
||||||
Executable
+74
@@ -0,0 +1,74 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Install and smoke-test the salmanoff snap (strict by default).
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
UC_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
SNAP_DIR="${UC_ROOT}/snaps/salmanoff"
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<'EOF'
|
||||||
|
Usage: test-snap.sh [OPTIONS] [-- ARGS_FOR_SALMANOFF...]
|
||||||
|
|
||||||
|
Install the newest salmanoff_*.snap and run a smoke test.
|
||||||
|
|
||||||
|
Options:
|
||||||
|
--snap PATH Specific .snap file (default: newest in snaps/salmanoff/)
|
||||||
|
--no-install Skip install; only run snap run (snap already installed)
|
||||||
|
--devmode Install with --devmode (overrides strict snap metadata)
|
||||||
|
-- ARGS Passed to salmanoff (default: --help)
|
||||||
|
-h, --help Show this help
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
snap_file=""
|
||||||
|
do_install=true
|
||||||
|
use_devmode=false
|
||||||
|
extra_args=(--help)
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--snap) snap_file="$2"; shift 2 ;;
|
||||||
|
--no-install) do_install=false; shift ;;
|
||||||
|
--devmode) use_devmode=true; shift ;;
|
||||||
|
--) shift; extra_args=("$@"); break ;;
|
||||||
|
-h|--help) usage; exit 0 ;;
|
||||||
|
*) extra_args=("$@"); break ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ -z "$snap_file" ]]; then
|
||||||
|
snap_file="$(ls -1t "${SNAP_DIR}"/*.snap 2>/dev/null | head -1 || true)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$snap_file" || ! -f "$snap_file" ]]; then
|
||||||
|
if [[ "$do_install" == true ]]; then
|
||||||
|
echo "No .snap found. Build first: ./scripts/build-snap.sh" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Newest .snap: $snap_file"
|
||||||
|
fi
|
||||||
|
|
||||||
|
connect_plugs() {
|
||||||
|
local plug
|
||||||
|
for plug in network network-bind hardware-observe camera media-control; do
|
||||||
|
if snap interfaces 2>/dev/null | grep -q "salmanoff:${plug}"; then
|
||||||
|
if ! snap interfaces 2>/dev/null | grep -q "salmanoff:${plug}.*-"; then
|
||||||
|
echo "Connecting plug: ${plug}"
|
||||||
|
sudo snap connect "salmanoff:${plug}" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ "$do_install" == true ]]; then
|
||||||
|
install_flags=(--dangerous)
|
||||||
|
if [[ "$use_devmode" == true ]]; then
|
||||||
|
install_flags+=(--devmode)
|
||||||
|
fi
|
||||||
|
sudo snap install "${install_flags[@]}" "$snap_file"
|
||||||
|
connect_plugs
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Running: snap run salmanoff ${extra_args[*]}"
|
||||||
|
snap run salmanoff "${extra_args[@]}"
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Wrapper: plugin search path, OpenCL ICD, Rusticl llvmpipe, Gallium DRI, libcamera IPA.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
shopt -s nullglob
|
||||||
|
lib_dirs=("$SNAP/usr/lib/"*-linux-gnu)
|
||||||
|
if ((${#lib_dirs[@]} > 0)); then
|
||||||
|
lib_dir="${lib_dirs[0]}"
|
||||||
|
else
|
||||||
|
lib_dir="$SNAP/usr/lib"
|
||||||
|
fi
|
||||||
|
|
||||||
|
export RUSTICL_ENABLE="${RUSTICL_ENABLE:-llvmpipe}"
|
||||||
|
export OCL_ICD_VENDORS="${OCL_ICD_VENDORS:-$SNAP/etc/OpenCL/vendors}"
|
||||||
|
export LIBGL_DRIVERS_PATH="${LIBGL_DRIVERS_PATH:-${lib_dir}/dri}"
|
||||||
|
export LIBCAMERA_IPA_MODULE_PATH="${LIBCAMERA_IPA_MODULE_PATH:-${lib_dir}/libcamera}"
|
||||||
|
export LIBCAMERA_IPA_CONFIG_PATH="${LIBCAMERA_IPA_CONFIG_PATH:-$SNAP/usr/share/libcamera/ipa}"
|
||||||
|
export LD_LIBRARY_PATH="${lib_dir}:${SNAP}/usr/lib:${LD_LIBRARY_PATH:-}"
|
||||||
|
|
||||||
|
exec "${SNAP}/usr/bin/salmanoff" -p "${lib_dir}" "$@"
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
# Salmanoff snap for Ubuntu Core 26 (salmanoff-dev-amd64 dangerous model).
|
||||||
|
# Build from distro/ubuntuCore: ../../scripts/build-snap.sh
|
||||||
|
name: salmanoff
|
||||||
|
version: "0.01.001"
|
||||||
|
summary: Salmanoff cognitive robotics runtime
|
||||||
|
description: |
|
||||||
|
Sensor management runtime (SMO) with Livox LiDAR, libcamera, and OpenCL
|
||||||
|
stimulus paths. Packaged for iterative snap-first development before seeding
|
||||||
|
into an Ubuntu Core image.
|
||||||
|
|
||||||
|
grade: devel
|
||||||
|
confinement: strict
|
||||||
|
base: core26
|
||||||
|
|
||||||
|
lint:
|
||||||
|
ignore:
|
||||||
|
- unused-library:
|
||||||
|
- usr/lib/*/libcoreComp.so*
|
||||||
|
- usr/lib/*/liblcameraBuff.so*
|
||||||
|
- usr/lib/*/liblcameraDev.so*
|
||||||
|
- usr/lib/*/liblivoxGen1.so*
|
||||||
|
- usr/lib/*/liblivoxProto1.so*
|
||||||
|
- usr/lib/*/libattachmentSupport.so*
|
||||||
|
- usr/lib/*/libspinscale.so*
|
||||||
|
- usr/lib/*/libRusticlOpenCL.so*
|
||||||
|
- usr/lib/*/libboost_log_setup.so*
|
||||||
|
- usr/lib/*/libunwind*.so*
|
||||||
|
- usr/lib/*/liburing-ffi.so*
|
||||||
|
- usr/lib/*/libicu*.so*
|
||||||
|
- usr/lib/*/liblttng*.so*
|
||||||
|
|
||||||
|
apps:
|
||||||
|
salmanoff:
|
||||||
|
command: bin/salmanoff-launch
|
||||||
|
plugs:
|
||||||
|
- network
|
||||||
|
- network-bind
|
||||||
|
- hardware-observe
|
||||||
|
- camera
|
||||||
|
- media-control
|
||||||
|
environment:
|
||||||
|
RUSTICL_ENABLE: llvmpipe
|
||||||
|
OCL_ICD_VENDORS: $SNAP/etc/OpenCL/vendors
|
||||||
|
|
||||||
|
layout:
|
||||||
|
/etc/OpenCL:
|
||||||
|
bind: $SNAP/etc/OpenCL
|
||||||
|
/usr/lib/clc:
|
||||||
|
bind: $SNAP/usr/lib/clc
|
||||||
|
/usr/lib/x86_64-linux-gnu/libcamera:
|
||||||
|
bind: $SNAP/usr/lib/x86_64-linux-gnu/libcamera
|
||||||
|
/usr/share/libcamera:
|
||||||
|
bind: $SNAP/usr/share/libcamera
|
||||||
|
|
||||||
|
parts:
|
||||||
|
launch:
|
||||||
|
plugin: nil
|
||||||
|
override-build: |
|
||||||
|
install -Dm755 "$CRAFT_PROJECT_DIR/bin/salmanoff-launch" \
|
||||||
|
"$CRAFT_PART_INSTALL/bin/salmanoff-launch"
|
||||||
|
|
||||||
|
salmanoff:
|
||||||
|
after: [launch]
|
||||||
|
plugin: cmake
|
||||||
|
# SMO repo root (distro/ubuntuCore/snaps/salmanoff -> ../../../..)
|
||||||
|
source: ../../..
|
||||||
|
source-type: local
|
||||||
|
source-submodules:
|
||||||
|
- libspinscale
|
||||||
|
build-packages:
|
||||||
|
- build-essential
|
||||||
|
- cmake
|
||||||
|
- ninja-build
|
||||||
|
- pkg-config
|
||||||
|
- flex
|
||||||
|
- bison
|
||||||
|
- git
|
||||||
|
- libboost1.88-dev
|
||||||
|
- libboost-system1.88-dev
|
||||||
|
- libboost-log1.88-dev
|
||||||
|
- liburing-dev
|
||||||
|
- libcamera-dev
|
||||||
|
- ocl-icd-opencl-dev
|
||||||
|
stage-packages:
|
||||||
|
- libboost-system1.88.0
|
||||||
|
- libboost-log1.88.0
|
||||||
|
- liburing2
|
||||||
|
- libcamera0.7
|
||||||
|
- libcamera-ipa
|
||||||
|
- ocl-icd-libopencl1
|
||||||
|
- mesa-opencl-icd
|
||||||
|
- libclc-20
|
||||||
|
- mesa-libgallium
|
||||||
|
- libgl1-mesa-dri
|
||||||
|
cmake-parameters:
|
||||||
|
- -DCMAKE_INSTALL_PREFIX=/usr
|
||||||
|
- -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||||
|
- -DBoost_DIR=/usr/lib/x86_64-linux-gnu/cmake/Boost-1.88.0
|
||||||
|
- -DENABLE_TESTS=OFF
|
||||||
|
- -DENABLE_LIB_xcbXorg=OFF
|
||||||
|
- -DENABLE_LIB_lcameraDev=ON
|
||||||
|
- -DENABLE_STIMBUFFAPI_lcameraBuff=ON
|
||||||
|
- -DENABLE_LCAMERADEV_TOOLS=OFF
|
||||||
|
- -DCOMPILE_PCL_TOOLS=OFF
|
||||||
|
override-pull: |
|
||||||
|
craftctl default
|
||||||
|
git -C "$CRAFT_PART_SRC" submodule update --init libspinscale
|
||||||
|
prime:
|
||||||
|
- -usr/lib/x86_64-linux-gnu/liburing-ffi.so*
|
||||||
@@ -0,0 +1,276 @@
|
|||||||
|
# Salmanoff on Ubuntu Core — Plan (derived from Yocto work)
|
||||||
|
|
||||||
|
## Purpose of this document
|
||||||
|
|
||||||
|
This plan is **not** a translation of an original Yocto design doc. It reflects **what we actually built and validated** in the Yocto path, reframed as goals for Ubuntu Core. Use it as primary context when scaffolding snaps, gadget/model, and dev VM workflow.
|
||||||
|
|
||||||
|
When done, snap definitions and support files land in the SMO repo under:
|
||||||
|
|
||||||
|
```
|
||||||
|
smo/distro/ubuntuCore/
|
||||||
|
```
|
||||||
|
|
||||||
|
(parallel to the existing `smo/distro/yocto/meta-salmanoff/`).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## What we proved in Yocto (facts, not aspirations)
|
||||||
|
|
||||||
|
We shipped a **minimal headless image** that runs the Salmanoff (SMO) cognitive robotics runtime on **QEMU x86-64**, bridged onto a lab LAN, talking to a **Livox LiDAR** on a fixed IP.
|
||||||
|
|
||||||
|
### Lab network (canonical — carry forward unchanged)
|
||||||
|
|
||||||
|
| Host | IP | Role |
|
||||||
|
|---|---|---|
|
||||||
|
| Laptop / gateway | `10.42.0.1` | Gateway + DNS |
|
||||||
|
| RPi5 (production target) | `10.42.0.2` | Future production node |
|
||||||
|
| **Dev guest (QEMU / UC VM)** | **`10.42.0.16`** | SMO dev runtime |
|
||||||
|
| Livox Avia | `10.42.0.139` | LiDAR sensor |
|
||||||
|
|
||||||
|
### Runtime configuration we validated
|
||||||
|
|
||||||
|
- **Body file**: `yocto-qemu-x86-headless.dapss` — Livox-only, headless (no win0/camera), `smo-ip=10.42.0.16`, includes `avia0.dapss`.
|
||||||
|
- **SMO build profile** (CMake):
|
||||||
|
- `RelWithDebInfo`
|
||||||
|
- `ENABLE_LIB_lcameraDev=ON`, `ENABLE_STIMBUFFAPI_lcameraBuff=ON` (libcamera + OpenCL YUV path compiled in; no camera passthrough needed in QEMU)
|
||||||
|
- `ENABLE_LIB_xcbXorg=OFF`, `COMPILE_PCL_TOOLS=OFF`, `ENABLE_TESTS=OFF`, `ENABLE_LCAMERADEV_TOOLS=OFF`
|
||||||
|
- Git submodules required (`libspinscale`, etc.)
|
||||||
|
- **Runtime command shape** (approximate):
|
||||||
|
```bash
|
||||||
|
salmanoff -d /usr/share/salmanoff/devices/bodies/body_yocto_qemu_x86_headless.daps -p /usr/lib -v
|
||||||
|
```
|
||||||
|
(exact installed `.daps` filename follows DAPSS build output naming)
|
||||||
|
|
||||||
|
### Platform services / packages we pulled into the image
|
||||||
|
|
||||||
|
| Need | What we used in Yocto |
|
||||||
|
|---|---|
|
||||||
|
| SMO runtime + libs | `salmanoff` recipe (`libspinscale`, `liblcameraDev`, `liblcameraBuff`, `liblivoxGen1`, …) |
|
||||||
|
| Boost | Pinned **1.86** (shared `boost-system`; must stay **< 1.89**) |
|
||||||
|
| liburing | Runtime dep |
|
||||||
|
| libcamera + v4l-utils | Present on image; camera optional at runtime |
|
||||||
|
| OpenCL | Mesa Rusticl via `opencl` distro feature; **needs `RUSTICL_ENABLE=llvmpipe`** or platform shows 0 devices |
|
||||||
|
| OpenCL verify | `clinfo` (also discovered **256M RAM OOMs** OpenCL probe — use **≥ 2G** for dev VM) |
|
||||||
|
| Network | Static `eth0`: `10.42.0.16/24`, gw `10.42.0.1` |
|
||||||
|
| Dev access | SSH (openssh on Yocto image) |
|
||||||
|
| Kernel probe | `rseqsliceprobe` + kernel config append for rseq slice extension |
|
||||||
|
| QEMU dev | Host bridge `br-smo`, `runqemu` with `bridge=br-smo`, `nographic`, `-m 2048` |
|
||||||
|
|
||||||
|
### Repo / packaging decisions already made in SMO
|
||||||
|
|
||||||
|
- Yocto layer vendored at `smo/distro/yocto/meta-salmanoff/` (committed on `clast`).
|
||||||
|
- SMO source changes on `clast`: headless body, flex/bison repo-relative `#line` paths, etc.
|
||||||
|
- Fetch uses private Gitea (`hayodea/salmanoff`, branch `clast`, submodules via `libspinscale` on separate SSH host alias).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Conceptual goals (portable to Ubuntu Core)
|
||||||
|
|
||||||
|
These are the **intent** items — independent of BitBake:
|
||||||
|
|
||||||
|
1. **Repeatable dev environment** — headless guest on `10.42.0.16`, reachable from laptop, Livox at `10.42.0.139`.
|
||||||
|
2. **SMO as first-class payload** — not “install deps manually”; runtime + `.daps` bodies + plugin `.so`s packaged and startable.
|
||||||
|
3. **Same CMake feature profile** as Yocto (lcamera + OpenCL enabled; xcb/PCL tools off).
|
||||||
|
4. **OpenCL that actually works headless** — Rusticl/llvmpipe with env var set before SMO starts.
|
||||||
|
5. **libcamera stack present** — libraries available even when no camera device is passed through (QEMU/UC dev).
|
||||||
|
6. **Boost version constraint honored** — do not silently pick Boost ≥ 1.89.
|
||||||
|
7. **Production path to RPi5** — same snap(s), different body/IP (`10.42.0.2`), gadget/kernel for Pi hardware.
|
||||||
|
8. **Distro metadata lives in SMO** — `distro/ubuntuCore/` committed back into SMO when stable (mirrors Yocto layout).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Yocto → Ubuntu Core mapping
|
||||||
|
|
||||||
|
| Yocto (what we did) | Ubuntu Core (target) |
|
||||||
|
|---|---|
|
||||||
|
| `meta-salmanoff/` layer | `distro/ubuntuCore/` — snaps, gadget, model, helper scripts |
|
||||||
|
| `salmanoff-image.bb` | **Model assertion** + `core` + gadget snap + app snaps on seeded image |
|
||||||
|
| `salmanoff.bb` recipe | **`salmanoff` snap** (`snapcraft.yaml`: cmake build, submodules, organize libs + daps) |
|
||||||
|
| `IMAGE_INSTALL` | Snap `stage-packages` / parts / content snaps (`mesa`, libcamera deps) |
|
||||||
|
| `salmanoff-rusticl-env` recipe | Snap `environment:` block or wrapper script: `RUSTICL_ENABLE=llvmpipe` |
|
||||||
|
| `init-ifupdown` static IP | **Netplan** via gadget default config, `network-setup` snap, or `system-connections` on UC |
|
||||||
|
| `runqemu-salmanoff-bridge` | **Dev VM script**: UC image in QEMU/LXD/multipass on `br-smo`, static `10.42.0.16`, 2G RAM |
|
||||||
|
| `DISTRO_FEATURES += opencl` | Ensure Mesa/OpenCL ICD available to snap (layout + plugs or bundled libs) |
|
||||||
|
| `DEPENDS` / `RDEPENDS` | Snapcraft `build-packages`, `stage-packages`, `slots`/`plugs`, `layout:` for `/usr/lib` ICD paths |
|
||||||
|
| `gitsm://` + `SRCREV` | Snapcraft `source` + `source-submodules` or `override-pull` git submodule update |
|
||||||
|
| `yocto-qemu-x86-headless.dapss` | Installed by salmanoff snap; UC-specific body can be `ubuntu-core-x86-headless.dapss` later |
|
||||||
|
| `rseqsliceprobe` | Validate UC kernel/base; custom kernel snap only if probe fails on stock UC kernel |
|
||||||
|
| SSH on image | UC: serial console, `ssh-keys` in model, or dedicated snap — **don’t assume openssh like Yocto** |
|
||||||
|
| Boost 1.86 pin | Pin in snapcraft (`stage-packages` version) or build Boost part from source |
|
||||||
|
| `RelWithDebInfo` + debug maps | Snapcraft `override-build` cmake flags; consider `debug` snap or stripped separate artifact |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Proposed Ubuntu Core architecture
|
||||||
|
|
||||||
|
```
|
||||||
|
Host (10.42.0.1)
|
||||||
|
└── bridge br-smo (10.42.0.0/24)
|
||||||
|
└── UC dev VM / RPi5 (10.42.0.16 or .2)
|
||||||
|
├── snap: core (or core24)
|
||||||
|
├── snap: gadget-<platform> (boot, partitions, default netplan)
|
||||||
|
├── snap: salmanoff (daemon — main payload)
|
||||||
|
└── optional: mesa-support / libcamera-support content snaps if not bundled
|
||||||
|
```
|
||||||
|
|
||||||
|
### `salmanoff` snap (primary deliverable)
|
||||||
|
|
||||||
|
**Type**: likely `daemon` (simple) or `daemon` (notify) once startup semantics are known.
|
||||||
|
|
||||||
|
**Build** (mirror Yocto recipe intent):
|
||||||
|
|
||||||
|
- Source: SMO repo `clast` (submodules!)
|
||||||
|
- CMake options: same as Yocto `EXTRA_OECMAKE` block
|
||||||
|
- Install: `salmanoff` binary, `lib*.so*`, `/usr/share/salmanoff/devices/**`
|
||||||
|
- Apps: main daemon + optional `salmanoff.probe` for debugging
|
||||||
|
|
||||||
|
**Runtime environment**:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
environment:
|
||||||
|
RUSTICL_ENABLE: llvmpipe
|
||||||
|
```
|
||||||
|
|
||||||
|
**Interfaces to evaluate early** (exact set TBD by confinement testing):
|
||||||
|
|
||||||
|
- `network` / `network-bind` — Livox UDP/TCP to `10.42.0.139`
|
||||||
|
- `hardware-observe` — may be needed for camera discovery on Pi
|
||||||
|
- `camera` — for libcamera on production Pi
|
||||||
|
- `opengl` — if Mesa GL stack needed beyond OpenCL ICD
|
||||||
|
- `raw-usb` / `serial-port` — only if Livox path requires it on some platforms
|
||||||
|
- `home` — usually **avoid**; use `$SNAP_DATA` for state
|
||||||
|
|
||||||
|
**Layouts** (likely needed):
|
||||||
|
|
||||||
|
- OpenCL ICD loader expects `/etc/OpenCL/vendors` or known `LD_LIBRARY_PATH`
|
||||||
|
- May need `layout:` bind mounts for Mesa `libRusticlOpenCL.so` / gallium stack
|
||||||
|
|
||||||
|
### Platform snaps
|
||||||
|
|
||||||
|
| Platform | Gadget | Notes |
|
||||||
|
|---|---|---|
|
||||||
|
| **QEMU x86 dev** | `pc` or custom gadget | Static IP `10.42.0.16`, 2G RAM, bridged NIC |
|
||||||
|
| **RPi5 production** | `pi` gadget (22+ arm64) | Static IP `10.42.0.2`, libcamera, Livox |
|
||||||
|
|
||||||
|
### Bodies / config
|
||||||
|
|
||||||
|
- **Dev (UC VM)**: start from Yocto body or add `ubuntu-core-x86-headless.dapss` with same Livox-only intent and `smo-ip=10.42.0.16`.
|
||||||
|
- **Production (RPi5)**: reuse/adapt existing `rpi5-persys-headless.dapss` pattern with `smo-ip=10.42.0.2`.
|
||||||
|
|
||||||
|
Body files stay in SMO `devices/bodies/`; snap selects default via config or snap config hook.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phased plan (recommended order)
|
||||||
|
|
||||||
|
### Phase 0 — Repo scaffold
|
||||||
|
|
||||||
|
- [ ] New repo (or `distro/ubuntuCore/` in SMO) with `snapcraft.yaml` skeleton
|
||||||
|
- [ ] Document lab IP table and bridge prerequisites (port `runqemu-salmanoff-bridge` concepts)
|
||||||
|
- [ ] Link to SMO `clast` branch + submodule SSH host requirements
|
||||||
|
|
||||||
|
### Phase 1 — Build snap on host (no hardware)
|
||||||
|
|
||||||
|
- [ ] `snapcraft` / `craft` builds SMO with same CMake profile as Yocto
|
||||||
|
- [ ] Confirm submodule pull (`libspinscale`) in clean CI/local environment
|
||||||
|
- [ ] Resolve Boost < 1.89 (stage-package pin or source part)
|
||||||
|
- [ ] Package `.daps` + shared libs; verify `salmanoff -v` / dry-run in snap run environment
|
||||||
|
|
||||||
|
### Phase 2 — OpenCL + libcamera in confinement
|
||||||
|
|
||||||
|
- [ ] Replicate Yocto OpenCL stack inside snap (bundled vs system Mesa)
|
||||||
|
- [ ] Confirm `RUSTICL_ENABLE=llvmpipe` → `clinfo` shows ≥1 device **inside snap**
|
||||||
|
- [ ] Confirm `liblcameraDev` / `liblcameraBuff` load; no crash without camera device
|
||||||
|
- [ ] Document RAM requirement (≥ 2G for dev VM)
|
||||||
|
|
||||||
|
### Phase 3 — UC dev VM on lab LAN
|
||||||
|
|
||||||
|
- [ ] Boot Ubuntu Core x86 VM bridged to `br-smo`
|
||||||
|
- [ ] Static IP **10.42.0.16** (netplan/gadget)
|
||||||
|
- [ ] Install seeded `salmanoff` snap (devmode first, then strict)
|
||||||
|
- [ ] Ping gateway; reach Livox at `10.42.0.139`
|
||||||
|
- [ ] Run headless body; validate Livox traffic / SMO logs
|
||||||
|
|
||||||
|
### Phase 4 — Production path (RPi5)
|
||||||
|
|
||||||
|
- [ ] Model assertion for Pi5 + arm64 core
|
||||||
|
- [ ] Gadget with `10.42.0.2` netplan
|
||||||
|
- [ ] libcamera plug + Pi body file
|
||||||
|
- [ ] OTA refresh via snap channels
|
||||||
|
|
||||||
|
### Phase 5 — Commit back to SMO
|
||||||
|
|
||||||
|
- [ ] Move stable `distro/ubuntuCore/` into SMO repo
|
||||||
|
- [ ] Commit on `clast` (or dedicated branch); do **not** block on unfinished WIP snaps
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Known constraints & pitfalls (from Yocto — expect repeats)
|
||||||
|
|
||||||
|
1. **OpenCL**: platform visible but **0 devices** until `RUSTICL_ENABLE=llvmpipe`.
|
||||||
|
2. **Memory**: 256M insufficient for Rusticl/`clinfo`; use **2G** for dev VM.
|
||||||
|
3. **Boost**: must stay **< 1.89** (shared `boost-system` linkage).
|
||||||
|
4. **Submodules**: `libspinscale` is mandatory; fetch must be recursive; separate SSH host alias on Gitea.
|
||||||
|
5. **lcamera without hardware**: compile and ship libs; no QEMU camera passthrough required for basic bring-up.
|
||||||
|
6. **PCL / xcb**: keep off unless explicitly needed (MPI/cmake pain in Yocto).
|
||||||
|
7. **Private git**: snapcraft build needs SSH keys / credentials for Gitea fetch (or vendored source tarball part).
|
||||||
|
8. **Strict confinement**: biggest unknown vs Yocto — plan devmode → strict iteration; interfaces will take multiple passes.
|
||||||
|
9. **rseq kernel feature**: validate on UC base; custom kernel snap is expensive — only if probe fails.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Success criteria (match Yocto milestone)
|
||||||
|
|
||||||
|
Minimum “we’re at parity” for UC dev:
|
||||||
|
|
||||||
|
- [ ] UC VM at `10.42.0.16` on `10.42.0.0/24` via host bridge
|
||||||
|
- [ ] `salmanoff` snap installed and daemon running (or manual `snap run` equivalent)
|
||||||
|
- [ ] Headless Livox body loaded; SMO stable with Livox on `10.42.0.139`
|
||||||
|
- [ ] OpenCL initialized (llvmpipe); lcamera libs present
|
||||||
|
- [ ] Snap definitions committed under `smo/distro/ubuntuCore/`
|
||||||
|
|
||||||
|
Stretch (production):
|
||||||
|
|
||||||
|
- [ ] Same snap on RPi5 at `10.42.0.2` with Pi-appropriate body
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Explicit non-goals (for now)
|
||||||
|
|
||||||
|
- Re-implement Yocto layer / BitBake in UC repo
|
||||||
|
- Camera passthrough in QEMU/UC x86 dev
|
||||||
|
- PCL tools / xcb window stack
|
||||||
|
- lcameraDev probe tools (need test support libs — off in Yocto too)
|
||||||
|
- Full OTA/signing production pipeline (Phase 4+)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Reference: Yocto artifacts in SMO repo
|
||||||
|
|
||||||
|
When unsure, read the working Yocto implementation:
|
||||||
|
|
||||||
|
```
|
||||||
|
smo/distro/yocto/meta-salmanoff/
|
||||||
|
conf/layer.conf
|
||||||
|
conf/salmanoff-local.inc # opencl distro feature
|
||||||
|
recipes-salmanoff/salmanoff/salmanoff.bb
|
||||||
|
recipes-core/images/salmanoff-image.bb
|
||||||
|
recipes-core/init-ifupdown/... # 10.42.0.16 static IP
|
||||||
|
recipes-support/salmanoff-rusticl-env/
|
||||||
|
scripts/runqemu-salmanoff-bridge
|
||||||
|
|
||||||
|
smo/devices/bodies/yocto-qemu-x86-headless.dapss
|
||||||
|
```
|
||||||
|
|
||||||
|
SMO branch: **`clast`** on `hayodea/salmanoff` (Gitea).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Instructions for the LLM in the Ubuntu Core repo
|
||||||
|
|
||||||
|
1. **Treat Yocto work as validated reference**, not something to re-derive from scratch.
|
||||||
|
2. **Preserve lab IP plan and CMake profile** unless user says otherwise.
|
||||||
|
3. **Start with snapcraft build on host**, then UC VM, then strict confinement — same order we used (build → package QA → runtime).
|
||||||
|
4. **Plan for `distro/ubuntuCore/` in SMO** as the final home of snaps/gadget/model/scripts.
|
||||||
|
5. **Ask before** committing snaps into SMO; user will commit when done.
|
||||||
|
6. **Do not** assume UC has openssh or classic Ubuntu package management — everything is snaps + interfaces.
|
||||||
Reference in New Issue
Block a user