Refactor bee CLI and LiveCD integration
This commit is contained in:
44
iso/builder/Dockerfile
Normal file
44
iso/builder/Dockerfile
Normal file
@@ -0,0 +1,44 @@
|
||||
FROM debian:12
|
||||
|
||||
ARG GO_VERSION=1.23.6
|
||||
ARG DEBIAN_KERNEL_ABI=6.1.0-43
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
RUN apt-get update -qq && apt-get install -y \
|
||||
ca-certificates \
|
||||
live-build \
|
||||
debootstrap \
|
||||
squashfs-tools \
|
||||
xorriso \
|
||||
grub-pc-bin \
|
||||
grub-efi-amd64-bin \
|
||||
mtools \
|
||||
git \
|
||||
wget \
|
||||
curl \
|
||||
tar \
|
||||
xz-utils \
|
||||
rsync \
|
||||
build-essential \
|
||||
gcc \
|
||||
make \
|
||||
perl \
|
||||
"linux-headers-${DEBIAN_KERNEL_ABI}-amd64" \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN arch="$(dpkg --print-architecture)" \
|
||||
&& case "$arch" in \
|
||||
amd64) goarch=amd64 ;; \
|
||||
arm64) goarch=arm64 ;; \
|
||||
*) echo "unsupported architecture: $arch" >&2; exit 1 ;; \
|
||||
esac \
|
||||
&& wget -q -O /tmp/go.tar.gz "https://go.dev/dl/go${GO_VERSION}.linux-${goarch}.tar.gz" \
|
||||
&& rm -rf /usr/local/go \
|
||||
&& tar -C /usr/local -xzf /tmp/go.tar.gz \
|
||||
&& rm -f /tmp/go.tar.gz
|
||||
|
||||
ENV PATH=/usr/local/go/bin:${PATH}
|
||||
WORKDIR /work
|
||||
|
||||
CMD ["/bin/bash"]
|
||||
61
iso/builder/build-in-container.sh
Executable file
61
iso/builder/build-in-container.sh
Executable file
@@ -0,0 +1,61 @@
|
||||
#!/bin/sh
|
||||
# build-in-container.sh — build the bee ISO inside a Debian container.
|
||||
|
||||
set -e
|
||||
|
||||
REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
|
||||
BUILDER_DIR="${REPO_ROOT}/iso/builder"
|
||||
CONTAINER_TOOL="${CONTAINER_TOOL:-docker}"
|
||||
IMAGE_TAG="${BEE_BUILDER_IMAGE:-bee-iso-builder}"
|
||||
AUTH_KEYS=""
|
||||
|
||||
. "${BUILDER_DIR}/VERSIONS"
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--authorized-keys)
|
||||
AUTH_KEYS="$2"
|
||||
shift 2
|
||||
;;
|
||||
*)
|
||||
echo "unknown arg: $1" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if ! command -v "$CONTAINER_TOOL" >/dev/null 2>&1; then
|
||||
echo "container tool not found: $CONTAINER_TOOL" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -n "$AUTH_KEYS" ]; then
|
||||
[ -f "$AUTH_KEYS" ] || { echo "authorized_keys not found: $AUTH_KEYS" >&2; exit 1; }
|
||||
AUTH_KEYS_ABS="$(cd "$(dirname "$AUTH_KEYS")" && pwd)/$(basename "$AUTH_KEYS")"
|
||||
AUTH_KEYS_DIR="$(dirname "$AUTH_KEYS_ABS")"
|
||||
AUTH_KEYS_BASE="$(basename "$AUTH_KEYS_ABS")"
|
||||
fi
|
||||
|
||||
"$CONTAINER_TOOL" build \
|
||||
--build-arg GO_VERSION="${GO_VERSION}" \
|
||||
--build-arg DEBIAN_KERNEL_ABI="${DEBIAN_KERNEL_ABI}" \
|
||||
-t "${IMAGE_TAG}:debian${DEBIAN_VERSION}" \
|
||||
"${BUILDER_DIR}"
|
||||
|
||||
set -- \
|
||||
run --rm --privileged \
|
||||
-v "${REPO_ROOT}:/work" \
|
||||
-w /work \
|
||||
"${IMAGE_TAG}:debian${DEBIAN_VERSION}" \
|
||||
sh /work/iso/builder/build.sh
|
||||
|
||||
if [ -n "$AUTH_KEYS" ]; then
|
||||
set -- run --rm --privileged \
|
||||
-v "${REPO_ROOT}:/work" \
|
||||
-v "${AUTH_KEYS_DIR}:/tmp/bee-authkeys:ro" \
|
||||
-w /work \
|
||||
"${IMAGE_TAG}:debian${DEBIAN_VERSION}" \
|
||||
sh /work/iso/builder/build.sh --authorized-keys "/tmp/bee-authkeys/${AUTH_KEYS_BASE}"
|
||||
fi
|
||||
|
||||
"$CONTAINER_TOOL" "$@"
|
||||
@@ -14,6 +14,8 @@ BUILDER_DIR="${REPO_ROOT}/iso/builder"
|
||||
OVERLAY_DIR="${REPO_ROOT}/iso/overlay"
|
||||
DIST_DIR="${REPO_ROOT}/dist"
|
||||
VENDOR_DIR="${REPO_ROOT}/iso/vendor"
|
||||
BUILD_WORK_DIR="${DIST_DIR}/live-build-work"
|
||||
OVERLAY_STAGE_DIR="${DIST_DIR}/overlay-stage"
|
||||
AUTH_KEYS=""
|
||||
|
||||
# parse args
|
||||
@@ -26,36 +28,49 @@ done
|
||||
|
||||
. "${BUILDER_DIR}/VERSIONS"
|
||||
export PATH="$PATH:/usr/local/go/bin"
|
||||
mkdir -p "${DIST_DIR}"
|
||||
|
||||
echo "=== bee ISO build ==="
|
||||
echo "Debian: ${DEBIAN_VERSION}, Kernel ABI: ${DEBIAN_KERNEL_ABI}, Go: ${GO_VERSION}"
|
||||
echo ""
|
||||
|
||||
# --- compile audit binary (static, Linux amd64) ---
|
||||
AUDIT_BIN="${DIST_DIR}/bee-audit-linux-amd64"
|
||||
# --- compile bee binary (static, Linux amd64) ---
|
||||
BEE_BIN="${DIST_DIR}/bee-linux-amd64"
|
||||
NEED_BUILD=1
|
||||
if [ -f "$AUDIT_BIN" ]; then
|
||||
NEWEST_SRC=$(find "${REPO_ROOT}/audit" -name '*.go' -newer "$AUDIT_BIN" | head -1)
|
||||
if [ -f "$BEE_BIN" ]; then
|
||||
NEWEST_SRC=$(find "${REPO_ROOT}/audit" -name '*.go' -newer "$BEE_BIN" | head -1)
|
||||
[ -z "$NEWEST_SRC" ] && NEED_BUILD=0
|
||||
fi
|
||||
|
||||
if [ "$NEED_BUILD" = "1" ]; then
|
||||
echo "=== building audit binary ==="
|
||||
echo "=== building bee binary ==="
|
||||
cd "${REPO_ROOT}/audit"
|
||||
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 \
|
||||
go build \
|
||||
-ldflags "-s -w -X main.Version=${AUDIT_VERSION:-$(date +%Y%m%d)}" \
|
||||
-o "$AUDIT_BIN" \
|
||||
./cmd/audit
|
||||
echo "binary: $AUDIT_BIN"
|
||||
echo "size: $(du -sh "$AUDIT_BIN" | cut -f1)"
|
||||
-o "$BEE_BIN" \
|
||||
./cmd/bee
|
||||
echo "binary: $BEE_BIN"
|
||||
echo "size: $(du -sh "$BEE_BIN" | cut -f1)"
|
||||
else
|
||||
echo "=== audit binary up to date, skipping build ==="
|
||||
echo "=== bee binary up to date, skipping build ==="
|
||||
fi
|
||||
|
||||
echo "=== preparing staged overlay ==="
|
||||
rm -rf "${BUILD_WORK_DIR}" "${OVERLAY_STAGE_DIR}"
|
||||
mkdir -p "${BUILD_WORK_DIR}" "${OVERLAY_STAGE_DIR}"
|
||||
rsync -a "${BUILDER_DIR}/" "${BUILD_WORK_DIR}/"
|
||||
rsync -a "${OVERLAY_DIR}/" "${OVERLAY_STAGE_DIR}/"
|
||||
rm -f \
|
||||
"${OVERLAY_STAGE_DIR}/etc/bee-ssh-password-fallback" \
|
||||
"${OVERLAY_STAGE_DIR}/etc/bee-release" \
|
||||
"${OVERLAY_STAGE_DIR}/root/.ssh/authorized_keys" \
|
||||
"${OVERLAY_STAGE_DIR}/usr/local/bin/bee" \
|
||||
"${OVERLAY_STAGE_DIR}/usr/local/bin/bee-smoketest"
|
||||
|
||||
# --- inject authorized_keys for SSH access ---
|
||||
AUTHORIZED_KEYS_FILE="${OVERLAY_DIR}/root/.ssh/authorized_keys"
|
||||
mkdir -p "${OVERLAY_DIR}/root/.ssh"
|
||||
AUTHORIZED_KEYS_FILE="${OVERLAY_STAGE_DIR}/root/.ssh/authorized_keys"
|
||||
mkdir -p "${OVERLAY_STAGE_DIR}/root/.ssh"
|
||||
|
||||
if [ -n "$AUTH_KEYS" ]; then
|
||||
cp "$AUTH_KEYS" "$AUTHORIZED_KEYS_FILE"
|
||||
@@ -81,25 +96,25 @@ else
|
||||
fi
|
||||
|
||||
if [ "${USE_PASSWORD_FALLBACK:-0}" = "1" ]; then
|
||||
touch "${OVERLAY_DIR}/etc/bee-ssh-password-fallback"
|
||||
touch "${OVERLAY_STAGE_DIR}/etc/bee-ssh-password-fallback"
|
||||
else
|
||||
rm -f "${OVERLAY_DIR}/etc/bee-ssh-password-fallback"
|
||||
rm -f "${OVERLAY_STAGE_DIR}/etc/bee-ssh-password-fallback"
|
||||
fi
|
||||
|
||||
# --- copy audit binary into overlay ---
|
||||
mkdir -p "${OVERLAY_DIR}/usr/local/bin"
|
||||
cp "${DIST_DIR}/bee-audit-linux-amd64" "${OVERLAY_DIR}/usr/local/bin/audit"
|
||||
chmod +x "${OVERLAY_DIR}/usr/local/bin/audit"
|
||||
# --- copy bee binary into overlay ---
|
||||
mkdir -p "${OVERLAY_STAGE_DIR}/usr/local/bin"
|
||||
cp "${DIST_DIR}/bee-linux-amd64" "${OVERLAY_STAGE_DIR}/usr/local/bin/bee"
|
||||
chmod +x "${OVERLAY_STAGE_DIR}/usr/local/bin/bee"
|
||||
|
||||
# --- inject smoketest into overlay so it runs directly on the live CD ---
|
||||
cp "${BUILDER_DIR}/smoketest.sh" "${OVERLAY_DIR}/usr/local/bin/bee-smoketest"
|
||||
chmod +x "${OVERLAY_DIR}/usr/local/bin/bee-smoketest"
|
||||
cp "${BUILDER_DIR}/smoketest.sh" "${OVERLAY_STAGE_DIR}/usr/local/bin/bee-smoketest"
|
||||
chmod +x "${OVERLAY_STAGE_DIR}/usr/local/bin/bee-smoketest"
|
||||
|
||||
# --- vendor utilities (optional pre-fetched binaries) ---
|
||||
for tool in storcli64 sas2ircu sas3ircu mstflint; do
|
||||
if [ -f "${VENDOR_DIR}/${tool}" ]; then
|
||||
cp "${VENDOR_DIR}/${tool}" "${OVERLAY_DIR}/usr/local/bin/${tool}"
|
||||
chmod +x "${OVERLAY_DIR}/usr/local/bin/${tool}" || true
|
||||
cp "${VENDOR_DIR}/${tool}" "${OVERLAY_STAGE_DIR}/usr/local/bin/${tool}"
|
||||
chmod +x "${OVERLAY_STAGE_DIR}/usr/local/bin/${tool}" || true
|
||||
echo "vendor tool: ${tool} (included)"
|
||||
else
|
||||
echo "vendor tool: ${tool} (not found, skipped)"
|
||||
@@ -116,29 +131,30 @@ NVIDIA_CACHE="${DIST_DIR}/nvidia-${NVIDIA_DRIVER_VERSION}-${KVER}"
|
||||
|
||||
# Inject .ko files into overlay at /usr/local/lib/nvidia/
|
||||
OVERLAY_KMOD_DIR="${OVERLAY_DIR}/usr/local/lib/nvidia"
|
||||
OVERLAY_KMOD_DIR="${OVERLAY_STAGE_DIR}/usr/local/lib/nvidia"
|
||||
mkdir -p "${OVERLAY_KMOD_DIR}"
|
||||
cp "${NVIDIA_CACHE}/modules/"*.ko "${OVERLAY_KMOD_DIR}/"
|
||||
|
||||
# Inject nvidia-smi and libnvidia-ml
|
||||
mkdir -p "${OVERLAY_DIR}/usr/local/bin" "${OVERLAY_DIR}/usr/lib"
|
||||
cp "${NVIDIA_CACHE}/bin/nvidia-smi" "${OVERLAY_DIR}/usr/local/bin/"
|
||||
chmod +x "${OVERLAY_DIR}/usr/local/bin/nvidia-smi"
|
||||
cp "${NVIDIA_CACHE}/bin/nvidia-bug-report.sh" "${OVERLAY_DIR}/usr/local/bin/" 2>/dev/null || true
|
||||
chmod +x "${OVERLAY_DIR}/usr/local/bin/nvidia-bug-report.sh" 2>/dev/null || true
|
||||
cp "${NVIDIA_CACHE}/lib/"* "${OVERLAY_DIR}/usr/lib/" 2>/dev/null || true
|
||||
mkdir -p "${OVERLAY_STAGE_DIR}/usr/local/bin" "${OVERLAY_STAGE_DIR}/usr/lib"
|
||||
cp "${NVIDIA_CACHE}/bin/nvidia-smi" "${OVERLAY_STAGE_DIR}/usr/local/bin/"
|
||||
chmod +x "${OVERLAY_STAGE_DIR}/usr/local/bin/nvidia-smi"
|
||||
cp "${NVIDIA_CACHE}/bin/nvidia-bug-report.sh" "${OVERLAY_STAGE_DIR}/usr/local/bin/" 2>/dev/null || true
|
||||
chmod +x "${OVERLAY_STAGE_DIR}/usr/local/bin/nvidia-bug-report.sh" 2>/dev/null || true
|
||||
cp "${NVIDIA_CACHE}/lib/"* "${OVERLAY_STAGE_DIR}/usr/lib/" 2>/dev/null || true
|
||||
|
||||
# Inject GSP firmware into /lib/firmware/nvidia/<version>/
|
||||
if [ -d "${NVIDIA_CACHE}/firmware" ] && [ "$(ls -A "${NVIDIA_CACHE}/firmware" 2>/dev/null)" ]; then
|
||||
mkdir -p "${OVERLAY_DIR}/lib/firmware/nvidia/${NVIDIA_DRIVER_VERSION}"
|
||||
cp "${NVIDIA_CACHE}/firmware/"* "${OVERLAY_DIR}/lib/firmware/nvidia/${NVIDIA_DRIVER_VERSION}/"
|
||||
echo "=== firmware: $(ls "${OVERLAY_DIR}/lib/firmware/nvidia/${NVIDIA_DRIVER_VERSION}/" | wc -l) files injected ==="
|
||||
mkdir -p "${OVERLAY_STAGE_DIR}/lib/firmware/nvidia/${NVIDIA_DRIVER_VERSION}"
|
||||
cp "${NVIDIA_CACHE}/firmware/"* "${OVERLAY_STAGE_DIR}/lib/firmware/nvidia/${NVIDIA_DRIVER_VERSION}/"
|
||||
echo "=== firmware: $(ls "${OVERLAY_STAGE_DIR}/lib/firmware/nvidia/${NVIDIA_DRIVER_VERSION}/" | wc -l) files injected ==="
|
||||
fi
|
||||
|
||||
# --- embed build metadata ---
|
||||
mkdir -p "${OVERLAY_DIR}/etc"
|
||||
mkdir -p "${OVERLAY_STAGE_DIR}/etc"
|
||||
BUILD_DATE="$(date +%Y-%m-%d)"
|
||||
GIT_COMMIT="$(git -C "${REPO_ROOT}" rev-parse --short HEAD 2>/dev/null || echo unknown)"
|
||||
cat > "${OVERLAY_DIR}/etc/bee-release" <<EOF
|
||||
cat > "${OVERLAY_STAGE_DIR}/etc/bee-release" <<EOF
|
||||
BEE_ISO_VERSION=${AUDIT_VERSION}
|
||||
BEE_AUDIT_VERSION=${AUDIT_VERSION}
|
||||
BUILD_DATE=${BUILD_DATE}
|
||||
@@ -150,17 +166,17 @@ EOF
|
||||
|
||||
# Patch motd with build info
|
||||
BEE_BUILD_INFO="${BUILD_DATE} git:${GIT_COMMIT} debian:${DEBIAN_VERSION} nvidia:${NVIDIA_DRIVER_VERSION}"
|
||||
if [ -f "${OVERLAY_DIR}/etc/motd" ]; then
|
||||
sed "s/%%BUILD_INFO%%/${BEE_BUILD_INFO}/" "${OVERLAY_DIR}/etc/motd" \
|
||||
> "${OVERLAY_DIR}/etc/motd.patched"
|
||||
mv "${OVERLAY_DIR}/etc/motd.patched" "${OVERLAY_DIR}/etc/motd"
|
||||
if [ -f "${OVERLAY_STAGE_DIR}/etc/motd" ]; then
|
||||
sed "s/%%BUILD_INFO%%/${BEE_BUILD_INFO}/" "${OVERLAY_STAGE_DIR}/etc/motd" \
|
||||
> "${OVERLAY_STAGE_DIR}/etc/motd.patched"
|
||||
mv "${OVERLAY_STAGE_DIR}/etc/motd.patched" "${OVERLAY_STAGE_DIR}/etc/motd"
|
||||
fi
|
||||
|
||||
# --- sync overlay into live-build includes.chroot ---
|
||||
LB_DIR="${BUILDER_DIR}"
|
||||
LB_DIR="${BUILD_WORK_DIR}"
|
||||
LB_INCLUDES="${LB_DIR}/config/includes.chroot"
|
||||
mkdir -p "${LB_INCLUDES}"
|
||||
rsync -a "${OVERLAY_DIR}/" "${LB_INCLUDES}/"
|
||||
rsync -a "${OVERLAY_STAGE_DIR}/" "${LB_INCLUDES}/"
|
||||
|
||||
# Ensure SSH authorized_keys perms are correct (rsync may alter)
|
||||
if [ -f "${LB_INCLUDES}/root/.ssh/authorized_keys" ]; then
|
||||
@@ -169,7 +185,6 @@ if [ -f "${LB_INCLUDES}/root/.ssh/authorized_keys" ]; then
|
||||
fi
|
||||
|
||||
# --- build ISO using live-build ---
|
||||
mkdir -p "${DIST_DIR}"
|
||||
echo ""
|
||||
echo "=== building ISO (live-build) ==="
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ chmod +x /usr/local/bin/bee-nvidia-load 2>/dev/null || true
|
||||
chmod +x /usr/local/bin/bee-sshsetup 2>/dev/null || true
|
||||
chmod +x /usr/local/bin/bee-smoketest 2>/dev/null || true
|
||||
chmod +x /usr/local/bin/bee-tui 2>/dev/null || true
|
||||
chmod +x /usr/local/bin/audit 2>/dev/null || true
|
||||
chmod +x /usr/local/bin/bee 2>/dev/null || true
|
||||
|
||||
# Reload udev rules
|
||||
udevadm control --reload-rules 2>/dev/null || true
|
||||
|
||||
@@ -21,7 +21,6 @@ lsof
|
||||
file
|
||||
less
|
||||
vim-tiny
|
||||
dialog
|
||||
|
||||
# QR codes (for displaying audit results)
|
||||
qrencode
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
#!/bin/sh
|
||||
# setup-builder.sh — prepare Debian 12 VM as bee ISO builder
|
||||
# setup-builder.sh — prepare Debian 12 host/VM as bee ISO builder
|
||||
#
|
||||
# Run once on a fresh Debian 12 (Bookworm) VM as root.
|
||||
# After this script completes, the VM can build bee ISO images.
|
||||
# Run once on a fresh Debian 12 (Bookworm) host/VM as root.
|
||||
# After this script completes, the machine can build bee ISO images directly.
|
||||
# Container alternative: use `iso/builder/build-in-container.sh`.
|
||||
#
|
||||
# Usage (on Debian VM):
|
||||
# wget -O- https://git.mchus.pro/mchus/bee/raw/branch/main/iso/builder/setup-builder.sh | sh
|
||||
|
||||
@@ -29,7 +29,7 @@ info "kernel: $KVER"
|
||||
|
||||
# --- PATH & binaries ---
|
||||
echo "-- PATH & binaries --"
|
||||
for tool in dmidecode smartctl nvme ipmitool lspci audit; do
|
||||
for tool in dmidecode smartctl nvme ipmitool lspci bee; do
|
||||
if p=$(PATH="/usr/local/bin:$PATH" command -v "$tool" 2>/dev/null); then
|
||||
ok "$tool found: $p"
|
||||
else
|
||||
@@ -114,14 +114,14 @@ for svc in ssh bee-sshsetup; do
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "-- audit binary --"
|
||||
AUDIT=/usr/local/bin/audit
|
||||
if [ -x "$AUDIT" ]; then
|
||||
ok "audit binary: present"
|
||||
ver=$("$AUDIT" --version 2>/dev/null || "$AUDIT" version 2>/dev/null || echo "unknown")
|
||||
info "audit version: $ver"
|
||||
echo "-- bee binary --"
|
||||
BEE=/usr/local/bin/bee
|
||||
if [ -x "$BEE" ]; then
|
||||
ok "bee binary: present"
|
||||
ver=$("$BEE" version 2>/dev/null || echo "unknown")
|
||||
info "bee version: $ver"
|
||||
else
|
||||
fail "audit binary: NOT FOUND at $AUDIT"
|
||||
fail "bee binary: NOT FOUND at $BEE"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
[Unit]
|
||||
Description=Bee: run hardware audit
|
||||
After=bee-network.service bee-nvidia.service network-online.target
|
||||
Wants=network-online.target
|
||||
After=bee-network.service bee-nvidia.service
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/local/bin/audit --output file:/var/log/bee-audit.json
|
||||
ExecStart=/bin/sh -c '/usr/local/bin/bee audit --runtime livecd --output file:/var/log/bee-audit.json; rc=$?; if [ "$rc" -ne 0 ]; then echo "[bee-audit] WARN: audit exited with rc=$rc"; fi; exit 0'
|
||||
StandardOutput=append:/var/log/bee-audit.log
|
||||
StandardError=append:/var/log/bee-audit.log
|
||||
RemainAfterExit=yes
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
for iface in $(ip -o link show | awk -F': ' '{print $2}' | grep -v '^lo$' | grep -vE '^(docker|virbr|veth|tun|tap|br-|bond|dummy)'); do
|
||||
echo "[$iface] bringing up..."
|
||||
ip link set "$iface" up 2>/dev/null
|
||||
udhcpc -i "$iface" -t 5 -T 3
|
||||
ip link set "$iface" up 2>/dev/null || true
|
||||
dhclient -r "$iface" >/dev/null 2>&1 || true
|
||||
dhclient -4 -v "$iface"
|
||||
done
|
||||
|
||||
@@ -4,15 +4,35 @@
|
||||
|
||||
log() { echo "[bee-sshsetup] $*"; }
|
||||
|
||||
# Always create dedicated 'bee' user for password fallback.
|
||||
if ! id bee > /dev/null 2>&1; then
|
||||
useradd -m -s /bin/sh bee > /dev/null 2>&1
|
||||
fi
|
||||
echo "bee:eeb" | chpasswd > /dev/null 2>&1
|
||||
SSHD_DIR="/etc/ssh/sshd_config.d"
|
||||
AUTH_CONF="${SSHD_DIR}/99-bee-auth.conf"
|
||||
|
||||
mkdir -p "$SSHD_DIR"
|
||||
|
||||
if [ -f /etc/bee-ssh-password-fallback ]; then
|
||||
if ! id bee > /dev/null 2>&1; then
|
||||
useradd -m -s /bin/sh bee > /dev/null 2>&1
|
||||
fi
|
||||
echo "bee:eeb" | chpasswd > /dev/null 2>&1
|
||||
cat > "$AUTH_CONF" <<'EOF'
|
||||
PermitRootLogin prohibit-password
|
||||
PasswordAuthentication yes
|
||||
KbdInteractiveAuthentication yes
|
||||
ChallengeResponseAuthentication yes
|
||||
UsePAM yes
|
||||
EOF
|
||||
log "SSH key auth unavailable — password fallback active"
|
||||
log "Login: bee / eeb"
|
||||
else
|
||||
if id bee > /dev/null 2>&1; then
|
||||
passwd -l bee > /dev/null 2>&1 || true
|
||||
fi
|
||||
cat > "$AUTH_CONF" <<'EOF'
|
||||
PermitRootLogin prohibit-password
|
||||
PasswordAuthentication no
|
||||
KbdInteractiveAuthentication no
|
||||
ChallengeResponseAuthentication no
|
||||
UsePAM yes
|
||||
EOF
|
||||
log "SSH key auth configured"
|
||||
fi
|
||||
|
||||
577
iso/overlay/usr/local/bin/bee-tui
Executable file → Normal file
577
iso/overlay/usr/local/bin/bee-tui
Executable file → Normal file
@@ -1,577 +1,2 @@
|
||||
#!/bin/sh
|
||||
# bee-tui: interactive text menu for debug LiveCD operations.
|
||||
|
||||
set -u
|
||||
|
||||
if ! command -v dialog >/dev/null 2>&1; then
|
||||
echo "ERROR: dialog is required but not installed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
pause() {
|
||||
echo
|
||||
printf 'Press Enter to continue... '
|
||||
read -r _
|
||||
}
|
||||
|
||||
header() {
|
||||
clear
|
||||
echo "=============================================="
|
||||
echo " bee TUI (debug)"
|
||||
echo "=============================================="
|
||||
echo
|
||||
}
|
||||
|
||||
menu_choice() {
|
||||
title="$1"
|
||||
prompt="$2"
|
||||
shift 2
|
||||
dialog --clear --stdout --title "$title" --menu "$prompt" 20 90 12 "$@"
|
||||
}
|
||||
|
||||
list_ifaces() {
|
||||
ip -o link show \
|
||||
| awk -F': ' '{print $2}' \
|
||||
| grep -v '^lo$' \
|
||||
| grep -vE '^(docker|virbr|veth|tun|tap|br-|bond|dummy)' \
|
||||
| sort
|
||||
}
|
||||
|
||||
show_network_status() {
|
||||
header
|
||||
echo "Network interfaces"
|
||||
echo
|
||||
for iface in $(list_ifaces); do
|
||||
state=$(ip -o link show "$iface" | awk '{print $9}')
|
||||
ipv4=$(ip -o -4 addr show dev "$iface" | awk '{print $4}' | paste -sd ',')
|
||||
[ -n "$ipv4" ] || ipv4="(no IPv4)"
|
||||
echo "- $iface: state=$state ip=$ipv4"
|
||||
done
|
||||
echo
|
||||
ip route | sed 's/^/ route: /'
|
||||
pause
|
||||
}
|
||||
|
||||
choose_interface() {
|
||||
ifaces="$(list_ifaces)"
|
||||
if [ -z "$ifaces" ]; then
|
||||
echo "No physical interfaces found"
|
||||
return 1
|
||||
fi
|
||||
|
||||
set --
|
||||
for iface in $ifaces; do
|
||||
set -- "$@" "$iface" "$iface"
|
||||
done
|
||||
iface=$(menu_choice "Network" "Select interface" "$@") || return 1
|
||||
|
||||
CHOSEN_IFACE="$iface"
|
||||
return 0
|
||||
}
|
||||
|
||||
network_dhcp_one() {
|
||||
header
|
||||
echo "DHCP on one interface"
|
||||
echo
|
||||
choose_interface || { pause; return; }
|
||||
|
||||
iface="$CHOSEN_IFACE"
|
||||
echo
|
||||
echo "Starting DHCP on $iface..."
|
||||
ip link set "$iface" up 2>/dev/null || true
|
||||
udhcpc -i "$iface" -t 5 -T 3
|
||||
pause
|
||||
}
|
||||
|
||||
network_dhcp_all() {
|
||||
header
|
||||
echo "Restarting DHCP on all physical interfaces..."
|
||||
echo
|
||||
/usr/local/bin/bee-net-restart
|
||||
pause
|
||||
}
|
||||
|
||||
network_static_one() {
|
||||
header
|
||||
echo "Static IPv4 setup"
|
||||
echo
|
||||
choose_interface || { pause; return; }
|
||||
|
||||
iface="$CHOSEN_IFACE"
|
||||
echo
|
||||
printf 'IPv4 address (example 192.168.1.10): '
|
||||
read -r ip
|
||||
if [ -z "$ip" ]; then
|
||||
echo "IP address is required"
|
||||
pause
|
||||
return
|
||||
fi
|
||||
|
||||
# derive default gateway: first three octets of IP + .1
|
||||
ip_base="$(echo "$ip" | cut -d. -f1-3)"
|
||||
default_gw="${ip_base}.1"
|
||||
|
||||
printf 'Netmask [24]: '
|
||||
read -r mask
|
||||
[ -z "$mask" ] && mask="24"
|
||||
prefix=$(mask_to_prefix "$mask")
|
||||
if [ -z "$prefix" ]; then
|
||||
echo "Invalid netmask: $mask"
|
||||
pause
|
||||
return
|
||||
fi
|
||||
cidr="$ip/$prefix"
|
||||
|
||||
printf 'Default gateway [%s]: ' "$default_gw"
|
||||
read -r gw
|
||||
[ -z "$gw" ] && gw="$default_gw"
|
||||
|
||||
printf 'DNS servers [77.88.8.8 77.88.8.1 1.1.1.1 8.8.8.8]: '
|
||||
read -r dns
|
||||
|
||||
ip link set "$iface" up 2>/dev/null || true
|
||||
ip addr flush dev "$iface"
|
||||
if ! ip addr add "$cidr" dev "$iface"; then
|
||||
echo "Failed to set IP"
|
||||
pause
|
||||
return
|
||||
fi
|
||||
|
||||
if [ -n "$gw" ]; then
|
||||
ip route del default >/dev/null 2>&1 || true
|
||||
ip route add default via "$gw" dev "$iface"
|
||||
fi
|
||||
|
||||
if [ -z "$dns" ]; then
|
||||
dns="77.88.8.8 77.88.8.1 1.1.1.1 8.8.8.8"
|
||||
fi
|
||||
: > /etc/resolv.conf
|
||||
for d in $dns; do
|
||||
printf 'nameserver %s\n' "$d" >> /etc/resolv.conf
|
||||
done
|
||||
|
||||
echo
|
||||
echo "Static config applied to $iface"
|
||||
pause
|
||||
}
|
||||
|
||||
mask_to_prefix() {
|
||||
mask="$(echo "$1" | tr -d '[:space:]')"
|
||||
case "$mask" in
|
||||
0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32)
|
||||
echo "$mask"
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
case "$mask" in
|
||||
255.0.0.0) echo 8 ;;
|
||||
255.128.0.0) echo 9 ;;
|
||||
255.192.0.0) echo 10 ;;
|
||||
255.224.0.0) echo 11 ;;
|
||||
255.240.0.0) echo 12 ;;
|
||||
255.248.0.0) echo 13 ;;
|
||||
255.252.0.0) echo 14 ;;
|
||||
255.254.0.0) echo 15 ;;
|
||||
255.255.0.0) echo 16 ;;
|
||||
255.255.128.0) echo 17 ;;
|
||||
255.255.192.0) echo 18 ;;
|
||||
255.255.224.0) echo 19 ;;
|
||||
255.255.240.0) echo 20 ;;
|
||||
255.255.248.0) echo 21 ;;
|
||||
255.255.252.0) echo 22 ;;
|
||||
255.255.254.0) echo 23 ;;
|
||||
255.255.255.0) echo 24 ;;
|
||||
255.255.255.128) echo 25 ;;
|
||||
255.255.255.192) echo 26 ;;
|
||||
255.255.255.224) echo 27 ;;
|
||||
255.255.255.240) echo 28 ;;
|
||||
255.255.255.248) echo 29 ;;
|
||||
255.255.255.252) echo 30 ;;
|
||||
255.255.255.254) echo 31 ;;
|
||||
255.255.255.255) echo 32 ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
network_menu() {
|
||||
while true; do
|
||||
choice=$(menu_choice "Network" "Select action" \
|
||||
"1" "Show network status" \
|
||||
"2" "DHCP on all interfaces" \
|
||||
"3" "DHCP on one interface" \
|
||||
"4" "Set static IPv4 on one interface" \
|
||||
"5" "Back") || return
|
||||
|
||||
case "$choice" in
|
||||
1) show_network_status ;;
|
||||
2) network_dhcp_all ;;
|
||||
3) network_dhcp_one ;;
|
||||
4) network_static_one ;;
|
||||
5) return ;;
|
||||
*) echo "Invalid choice"; pause ;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
bee_services_list() {
|
||||
for path in /etc/init.d/bee-*; do
|
||||
[ -e "$path" ] || continue
|
||||
basename "$path"
|
||||
done
|
||||
}
|
||||
|
||||
services_status_all() {
|
||||
header
|
||||
echo "bee service status"
|
||||
echo
|
||||
for svc in $(bee_services_list); do
|
||||
if rc-service "$svc" status >/dev/null 2>&1; then
|
||||
echo "- $svc: running"
|
||||
else
|
||||
echo "- $svc: stopped"
|
||||
fi
|
||||
done
|
||||
pause
|
||||
}
|
||||
|
||||
choose_service() {
|
||||
svcs="$(bee_services_list)"
|
||||
if [ -z "$svcs" ]; then
|
||||
echo "No bee-* services found"
|
||||
return 1
|
||||
fi
|
||||
|
||||
set --
|
||||
for svc in $svcs; do
|
||||
set -- "$@" "$svc" "$svc"
|
||||
done
|
||||
svc=$(menu_choice "bee Services" "Select service" "$@") || return 1
|
||||
|
||||
CHOSEN_SERVICE="$svc"
|
||||
return 0
|
||||
}
|
||||
|
||||
service_action_menu() {
|
||||
header
|
||||
echo "Service action"
|
||||
echo
|
||||
choose_service || { pause; return; }
|
||||
svc="$CHOSEN_SERVICE"
|
||||
|
||||
act=$(menu_choice "Service: $svc" "Select action" \
|
||||
"1" "status" \
|
||||
"2" "restart" \
|
||||
"3" "start" \
|
||||
"4" "stop" \
|
||||
"5" "toggle start/stop" \
|
||||
"6" "Back") || return
|
||||
|
||||
case "$act" in
|
||||
1) rc-service "$svc" status || true ;;
|
||||
2) rc-service "$svc" restart || true ;;
|
||||
3) rc-service "$svc" start || true ;;
|
||||
4) rc-service "$svc" stop || true ;;
|
||||
5)
|
||||
if rc-service "$svc" status >/dev/null 2>&1; then
|
||||
rc-service "$svc" stop || true
|
||||
else
|
||||
rc-service "$svc" start || true
|
||||
fi
|
||||
;;
|
||||
6) return ;;
|
||||
*) echo "Invalid action" ;;
|
||||
esac
|
||||
pause
|
||||
}
|
||||
|
||||
services_menu() {
|
||||
while true; do
|
||||
choice=$(menu_choice "bee Services" "Select action" \
|
||||
"1" "Status of all bee-* services" \
|
||||
"2" "Manage one service (status/restart/start/stop/toggle)" \
|
||||
"3" "Back") || return
|
||||
|
||||
case "$choice" in
|
||||
1) services_status_all ;;
|
||||
2) service_action_menu ;;
|
||||
3) return ;;
|
||||
*) echo "Invalid choice"; pause ;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
confirm_phrase() {
|
||||
phrase="$1"
|
||||
prompt="$2"
|
||||
echo
|
||||
printf '%s (%s): ' "$prompt" "$phrase"
|
||||
read -r value
|
||||
[ "$value" = "$phrase" ]
|
||||
}
|
||||
|
||||
shutdown_menu() {
|
||||
while true; do
|
||||
choice=$(menu_choice "Shutdown/Reboot Tests" "Select action" \
|
||||
"1" "Reboot now" \
|
||||
"2" "Power off now" \
|
||||
"3" "Schedule poweroff in 60s" \
|
||||
"4" "Cancel scheduled shutdown" \
|
||||
"5" "IPMI chassis power status" \
|
||||
"6" "IPMI chassis power soft" \
|
||||
"7" "IPMI chassis power cycle" \
|
||||
"8" "Back") || return
|
||||
|
||||
case "$choice" in
|
||||
1)
|
||||
confirm_phrase "REBOOT" "Type confirmation" || { echo "Canceled"; pause; continue; }
|
||||
reboot
|
||||
;;
|
||||
2)
|
||||
confirm_phrase "POWEROFF" "Type confirmation" || { echo "Canceled"; pause; continue; }
|
||||
poweroff
|
||||
;;
|
||||
3)
|
||||
confirm_phrase "SCHEDULE" "Type confirmation" || { echo "Canceled"; pause; continue; }
|
||||
shutdown -P +1 "bee test: scheduled poweroff in 60 seconds"
|
||||
echo "Scheduled"
|
||||
pause
|
||||
;;
|
||||
4)
|
||||
shutdown -c || true
|
||||
echo "Canceled (if any schedule existed)"
|
||||
pause
|
||||
;;
|
||||
5)
|
||||
ipmitool chassis power status || echo "ipmitool power status failed"
|
||||
pause
|
||||
;;
|
||||
6)
|
||||
confirm_phrase "IPMI-SOFT" "Type confirmation" || { echo "Canceled"; pause; continue; }
|
||||
ipmitool chassis power soft || echo "ipmitool soft power failed"
|
||||
pause
|
||||
;;
|
||||
7)
|
||||
confirm_phrase "IPMI-CYCLE" "Type confirmation" || { echo "Canceled"; pause; continue; }
|
||||
ipmitool chassis power cycle || echo "ipmitool power cycle failed"
|
||||
pause
|
||||
;;
|
||||
8)
|
||||
return
|
||||
;;
|
||||
*)
|
||||
echo "Invalid choice"
|
||||
pause
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
gpu_burn_10m() {
|
||||
header
|
||||
echo "GPU Burn (10 minutes)"
|
||||
echo
|
||||
if ! command -v gpu_burn >/dev/null 2>&1; then
|
||||
echo "gpu_burn binary not found in PATH"
|
||||
echo "Expected command: gpu_burn"
|
||||
pause
|
||||
return
|
||||
fi
|
||||
if ! command -v nvidia-smi >/dev/null 2>&1 || ! nvidia-smi -L >/dev/null 2>&1; then
|
||||
echo "NVIDIA driver/GPU not ready (nvidia-smi failed)"
|
||||
pause
|
||||
return
|
||||
fi
|
||||
|
||||
confirm_phrase "GPU-BURN" "Type confirmation to start benchmark" || { echo "Canceled"; pause; return; }
|
||||
echo "Running: gpu_burn 600"
|
||||
echo "Log: /var/log/bee-gpuburn.log"
|
||||
gpu_burn 600 2>&1 | tee /var/log/bee-gpuburn.log
|
||||
echo
|
||||
echo "GPU Burn finished"
|
||||
pause
|
||||
}
|
||||
|
||||
gpu_benchmarks_menu() {
|
||||
while true; do
|
||||
choice=$(menu_choice "Benchmarks -> GPU" "Select action" \
|
||||
"1" "GPU Burn (10 minutes)" \
|
||||
"2" "Back") || return
|
||||
|
||||
case "$choice" in
|
||||
1) gpu_burn_10m ;;
|
||||
2) return ;;
|
||||
*) echo "Invalid choice"; pause ;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
benchmarks_menu() {
|
||||
while true; do
|
||||
choice=$(menu_choice "Benchmarks" "Select category" \
|
||||
"1" "GPU" \
|
||||
"2" "Back") || return
|
||||
|
||||
case "$choice" in
|
||||
1) gpu_benchmarks_menu ;;
|
||||
2) return ;;
|
||||
*) echo "Invalid choice"; pause ;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
run_cmd_log() {
|
||||
label="$1"
|
||||
cmd="$2"
|
||||
log_file="$3"
|
||||
|
||||
{
|
||||
echo "=== $label ==="
|
||||
echo "time: $(date -u '+%Y-%m-%dT%H:%M:%SZ')"
|
||||
echo "cmd: $cmd"
|
||||
echo
|
||||
sh -c "$cmd"
|
||||
} >"$log_file" 2>&1
|
||||
return $?
|
||||
}
|
||||
|
||||
run_gpu_nvidia_acceptance_test() {
|
||||
header
|
||||
echo "System acceptance tests -> GPU NVIDIA"
|
||||
echo
|
||||
confirm_phrase "SAT-GPU" "Type confirmation to start tests" || { echo "Canceled"; pause; return; }
|
||||
|
||||
ts="$(date -u '+%Y%m%d-%H%M%S')"
|
||||
base_dir="/var/log/bee-sat"
|
||||
run_dir="$base_dir/gpu-nvidia-$ts"
|
||||
archive="$base_dir/gpu-nvidia-$ts.tar.gz"
|
||||
mkdir -p "$run_dir"
|
||||
|
||||
summary="$run_dir/summary.txt"
|
||||
: >"$summary"
|
||||
|
||||
echo "Running acceptance commands..."
|
||||
echo "Logs directory: $run_dir"
|
||||
echo "Archive target: $archive"
|
||||
echo
|
||||
|
||||
c1="nvidia-smi -q"
|
||||
c2="dmidecode -t baseboard"
|
||||
c3="dmidecode -t system"
|
||||
c4="nvidia-bug-report.sh --output $run_dir/nvidia-bug-report.log"
|
||||
|
||||
run_cmd_log "nvidia_smi_q" "$c1" "$run_dir/01-nvidia-smi-q.log"; rc1=$?
|
||||
run_cmd_log "dmidecode_baseboard" "$c2" "$run_dir/02-dmidecode-baseboard.log"; rc2=$?
|
||||
run_cmd_log "dmidecode_system" "$c3" "$run_dir/03-dmidecode-system.log"; rc3=$?
|
||||
run_cmd_log "nvidia_bug_report" "$c4" "$run_dir/04-nvidia-bug-report.log"; rc4=$?
|
||||
|
||||
{
|
||||
echo "run_at_utc=$(date -u '+%Y-%m-%dT%H:%M:%SZ')"
|
||||
echo "cmd_nvidia_smi_q_rc=$rc1"
|
||||
echo "cmd_dmidecode_baseboard_rc=$rc2"
|
||||
echo "cmd_dmidecode_system_rc=$rc3"
|
||||
echo "cmd_nvidia_bug_report_rc=$rc4"
|
||||
} >>"$summary"
|
||||
|
||||
tar -czf "$archive" -C "$base_dir" "gpu-nvidia-$ts"
|
||||
tar_rc=$?
|
||||
echo "archive_rc=$tar_rc" >>"$summary"
|
||||
|
||||
echo
|
||||
echo "Done."
|
||||
echo "- Logs: $run_dir"
|
||||
echo "- Archive: $archive (rc=$tar_rc)"
|
||||
pause
|
||||
}
|
||||
|
||||
gpu_nvidia_sat_menu() {
|
||||
while true; do
|
||||
choice=$(menu_choice "System acceptance tests -> GPU NVIDIA" "Select action" \
|
||||
"1" "Run command pack" \
|
||||
"2" "Back") || return
|
||||
|
||||
case "$choice" in
|
||||
1) run_gpu_nvidia_acceptance_test ;;
|
||||
2) return ;;
|
||||
*) echo "Invalid choice"; pause ;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
system_acceptance_tests_menu() {
|
||||
while true; do
|
||||
choice=$(menu_choice "System acceptance tests" "Select category" \
|
||||
"1" "GPU NVIDIA" \
|
||||
"2" "Back") || return
|
||||
|
||||
case "$choice" in
|
||||
1) gpu_nvidia_sat_menu ;;
|
||||
2) return ;;
|
||||
*) echo "Invalid choice"; pause ;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
run_audit_now() {
|
||||
header
|
||||
echo "Run audit now"
|
||||
echo
|
||||
/usr/local/bin/audit --output stdout > /var/log/bee-audit.json 2>/var/log/bee-audit.log
|
||||
rc=$?
|
||||
if [ "$rc" -eq 0 ]; then
|
||||
echo "Audit completed successfully"
|
||||
else
|
||||
echo "Audit finished with errors (rc=$rc)"
|
||||
fi
|
||||
echo "Logs: /var/log/bee-audit.log, /var/log/bee-audit.json"
|
||||
pause
|
||||
}
|
||||
|
||||
check_required_tools() {
|
||||
header
|
||||
echo "Required tools check"
|
||||
echo
|
||||
for tool in dmidecode smartctl nvme ipmitool lspci audit nvidia-smi gpu_burn dialog; do
|
||||
if command -v "$tool" >/dev/null 2>&1; then
|
||||
echo "- $tool: OK ($(command -v "$tool"))"
|
||||
else
|
||||
echo "- $tool: MISSING"
|
||||
fi
|
||||
done
|
||||
pause
|
||||
}
|
||||
|
||||
main_menu() {
|
||||
while true; do
|
||||
choice=$(menu_choice "Bee TUI (debug)" "Select action" \
|
||||
"1" "Network setup" \
|
||||
"2" "bee service management" \
|
||||
"3" "Shutdown/reboot tests" \
|
||||
"4" "Benchmarks" \
|
||||
"5" "System acceptance tests" \
|
||||
"6" "Run audit now" \
|
||||
"7" "Check required tools" \
|
||||
"8" "Show last audit log tail" \
|
||||
"9" "Exit to console") || exit 0
|
||||
|
||||
case "$choice" in
|
||||
1) network_menu ;;
|
||||
2) services_menu ;;
|
||||
3) shutdown_menu ;;
|
||||
4) benchmarks_menu ;;
|
||||
5) system_acceptance_tests_menu ;;
|
||||
6) run_audit_now ;;
|
||||
7) check_required_tools ;;
|
||||
8)
|
||||
header
|
||||
tail -n 40 /var/log/bee-audit.log 2>/dev/null || echo "No /var/log/bee-audit.log"
|
||||
echo
|
||||
tail -n 20 /var/log/bee-audit.json 2>/dev/null || true
|
||||
pause
|
||||
;;
|
||||
9) exit 0 ;;
|
||||
*) echo "Invalid choice"; pause ;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
main_menu
|
||||
exec /usr/local/bin/bee tui --runtime livecd "$@"
|
||||
|
||||
Reference in New Issue
Block a user