clawdie-ai/scripts/inspect-system.sh
Operator & Claude Code 75009dcb7f refactor(identity): remove PLATFORM_ID/SERVICE_NAME/RUNTIME_USER env vars
Step 5 of system-namespace cutover: complete the env-var removal that
step 4 set up. All consumers now import SERVICE_NAME from
src/platform-identity.ts directly; the deprecated PLATFORM_*
re-exports in src/config.ts are gone.

src/config.ts:
- PLATFORM_ID, PLATFORM_SERVICE_NAME, PLATFORM_RUNTIME_USER exports
  removed.
- PLATFORM_RUNTIME_HOME stays (derived from SERVICE_NAME, used by
  ~10 consumers for path construction).
- Env-var allowlist drops PLATFORM_ID / PLATFORM_SERVICE_NAME /
  PLATFORM_RUNTIME_USER / PLATFORM_RUNTIME_HOME entries.
- CONTROLPLANE_AIDER_TMUX_SESSION uses SERVICE_NAME directly.

setup/onboarding.ts:
- writeIdentity() simplified to write only ASSISTANT_NAME (display).
  PLATFORM_ID / PLATFORM_SERVICE_NAME / PLATFORM_RUNTIME_USER are no
  longer written to .env. Fresh installs have no PLATFORM_* keys.
- Status emission switched from PLATFORM_ID to SERVICE_NAME.

setup/env-audit.ts:
- Audit lists SERVICE_NAME instead of PLATFORM_ID; the env-file
  PLATFORM_ID read is gone.

24 source files (src/*.ts, setup/*.ts, scripts/dashboard.ts):
- Bare PLATFORM_ID / PLATFORM_SERVICE_NAME / PLATFORM_RUNTIME_USER
  references replaced with SERVICE_NAME.
- Imports rewired: SERVICE_NAME comes from
  ../{src/}platform-identity.js, not from config.js.
- Imports deduped where the sed sweep produced collisions.

Shell scripts (scripts/bhyve-evidence.sh, glass.sh, inspect-system.sh):
- Hardcoded SERVICE_NAME='clawdie' and SERVICE_USER='clawdie'.
  No more grep-the-.env fallbacks; the constants are the source.

Tests (middle path):
- Mechanical fixes (import path, renamed assertion text):
  src/hostd/privileged-commands.test.ts, src/startup-report.test.ts,
  setup/env-audit.test.ts, setup/install-mode.test.ts.
- Skipped with `// system-namespace:` markers (pinned removed
  env-driven override behavior; Codex rewrites once the bootstrap-
  config service-user override path lands):
    setup/verify.test.ts > 'uses the platform service name for PID candidates'
    setup/service.test.ts > 'resolves a platform runtime separately from the tenant'

Test files still containing PLATFORM_* strings in vi.mock contents,
ENV_KEYS arrays, or comments are left untouched — they are test
artifacts that don't affect runtime; mock contents resolve to
'clawdie' which still equals SERVICE_NAME.

tsc clean. 2095 tests pass, 4 skipped, 0 fail.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---
Build: pass | Tests: pass — Tests  2095 passed | 4 skipped (2099)
2026-05-02 14:49:19 +02:00

508 lines
17 KiB
Bash
Executable file

#!/usr/bin/env bash
set -euo pipefail
repo_root() {
cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd
}
ROOT_DIR="$(repo_root)"
DEFAULT_OUTPUT_DIR="$ROOT_DIR/tmp/inspect"
SETUP_SCHEMA_VERSION=1
SYSTEM_SCHEMA_VERSION=1
read_env_value() {
local key="$1"
local env_file="$ROOT_DIR/.env"
if [ ! -f "$env_file" ]; then
return 1
fi
awk -F= -v key="$key" '
$1 == key {
value = substr($0, index($0, "=") + 1)
gsub(/^["'"'"']|["'"'"']$/, "", value)
print value
exit
}
' "$env_file"
}
read_setup_value() {
local file="$1"
local key="$2"
if [ ! -f "$file" ]; then
return 1
fi
awk -F= -v key="$key" '
$1 == key {
value = substr($0, index($0, "=") + 1)
gsub(/^[[:space:]]+|[[:space:]]+$/, "", value)
print value
exit
}
' "$file"
}
OUTPUT_DIR="$DEFAULT_OUTPUT_DIR"
APPLY_SETUP_FILE=""
APPLY_SYSTEM_ENV_FILE=""
while [ $# -gt 0 ]; do
case "$1" in
--output)
if [ $# -lt 2 ]; then
echo "--output requires a path" >&2
exit 1
fi
OUTPUT_DIR="$2"
shift 2
;;
--apply-setup)
if [ $# -lt 2 ]; then
echo "--apply-setup requires a setup.txt path" >&2
exit 1
fi
APPLY_SETUP_FILE="$2"
shift 2
;;
--apply-system-env)
if [ $# -lt 2 ]; then
echo "--apply-system-env requires a system.env path" >&2
exit 1
fi
APPLY_SYSTEM_ENV_FILE="$2"
shift 2
;;
*)
echo "Usage: $0 [--output <dir>] [--apply-setup <setup.txt>] [--apply-system-env <system.env>]" >&2
exit 1
;;
esac
done
mkdir -p "$OUTPUT_DIR"
ISO_RELEASE="$(sed -n 's/.*"version":[[:space:]]*"\([^"]*\)".*/v\1/p' "$ROOT_DIR/package.json" | head -n 1 || true)"
if [ -z "$ISO_RELEASE" ]; then
ISO_RELEASE="v0.0.0"
fi
ISO_GIT_COMMIT=""
if command -v git >/dev/null 2>&1; then
ISO_GIT_COMMIT="$(git -C "$ROOT_DIR" rev-parse --short=8 HEAD 2>/dev/null || true)"
fi
capture() {
local filename="$1"
shift
if command -v "$1" >/dev/null 2>&1; then
"$@" >"$OUTPUT_DIR/$filename" 2>&1 || true
else
printf 'Command not found: %s\n' "$1" >"$OUTPUT_DIR/$filename"
fi
}
capture "uname.txt" uname -a
capture "freebsd-version.txt" freebsd-version
capture "dmesg.txt" dmesg
capture "pciconf.txt" pciconf -lv
capture "geom-disk-list.txt" geom disk list
capture "ifconfig.txt" ifconfig -a
capture "pf-status.txt" service pf status
capture "pf-interfaces.txt" pfctl -s Interfaces
capture "zpool-list.txt" zpool list -H -o name,size,alloc,free,cap,frag,health
capture "zpool-status.txt" zpool status
capture "zfs-list.txt" zfs list -H -o name,used,avail,refer,mountpoint
if [ -r /dev/sndstat ]; then
cat /dev/sndstat >"$OUTPUT_DIR/sndstat.txt" 2>&1 || true
else
printf 'sndstat unavailable\n' >"$OUTPUT_DIR/sndstat.txt"
fi
apply_if_blank() {
local file="$1"
local key="$2"
local value="$3"
local tmp_file="${file}.tmp.$$"
if [ ! -f "$file" ]; then
printf '%s=%s\n' "$key" "$value" >"$file"
return
fi
awk -F= -v key="$key" -v value="$value" '
BEGIN { updated = 0 }
$1 == key {
current = substr($0, index($0, "=") + 1)
gsub(/^[[:space:]]+|[[:space:]]+$/, "", current)
if (current == "") {
print key "=" value
} else {
print $0
}
updated = 1
next
}
{ print $0 }
END {
if (!updated) {
print key "=" value
}
}
' "$file" >"$tmp_file"
mv "$tmp_file" "$file"
}
OBSERVED_AT="$(bash "$ROOT_DIR/scripts/date-format.sh" display-ts)"
HOSTNAME_VALUE="$(hostname 2>/dev/null || echo unknown)"
FREEBSD_VERSION="$(tr -d '\r' <"$OUTPUT_DIR/freebsd-version.txt" | head -n 1 || true)"
UNAME_VALUE="$(tr -d '\r' <"$OUTPUT_DIR/uname.txt" | head -n 1 || true)"
# Service name and service-account user are the constant 'clawdie'
# baked into code (see src/platform-identity.ts). PLATFORM_* env vars
# are removed.
SERVICE_NAME="clawdie"
SERVICE_USER="clawdie"
ZFS_PREFIX_VALUE="${ZFS_PREFIX:-$(read_env_value ZFS_PREFIX 2>/dev/null || true)}"
if [ -z "$ZFS_PREFIX_VALUE" ]; then
ZFS_PREFIX_VALUE="clawdie-runtime"
fi
ENV_SIGNAL="no"
if [ -f "$ROOT_DIR/.env" ] && grep -q '^[^#[:space:]].*=.*' "$ROOT_DIR/.env"; then
ENV_SIGNAL="yes"
fi
GROUPS_SIGNAL="no"
if [ -d "$ROOT_DIR/groups" ] && find "$ROOT_DIR/groups" -mindepth 1 -maxdepth 1 ! -name '.*' | grep -q .; then
GROUPS_SIGNAL="yes"
fi
SERVICE_SIGNAL="no"
if [ -f "/usr/local/etc/rc.d/$SERVICE_NAME" ]; then
SERVICE_SIGNAL="yes"
fi
RUNTIME_USER_SIGNAL="no"
if id -u "$SERVICE_USER" >/dev/null 2>&1; then
RUNTIME_USER_SIGNAL="yes"
fi
ZFS_SIGNAL="no"
if command -v zfs >/dev/null 2>&1; then
if zfs list -H -o name 2>/dev/null | grep -Eq "(^|/)$ZFS_PREFIX_VALUE($|/|@)"; then
ZFS_SIGNAL="yes"
fi
fi
STRONG_SIGNALS=()
SOFT_SIGNALS=()
[ "$SERVICE_SIGNAL" = "yes" ] && STRONG_SIGNALS+=("service")
[ "$ZFS_SIGNAL" = "yes" ] && STRONG_SIGNALS+=("zfs")
[ "$RUNTIME_USER_SIGNAL" = "yes" ] && STRONG_SIGNALS+=("runtime-user")
[ "$ENV_SIGNAL" = "yes" ] && SOFT_SIGNALS+=("env")
[ "$GROUPS_SIGNAL" = "yes" ] && SOFT_SIGNALS+=("groups")
EXISTING_INSTALL="no"
if [ "${#STRONG_SIGNALS[@]}" -gt 0 ] || [ "${#SOFT_SIGNALS[@]}" -ge 2 ]; then
EXISTING_INSTALL="yes"
fi
SUGGESTED_INSTALL_MODE="fresh"
if [ "$EXISTING_INSTALL" = "yes" ]; then
SUGGESTED_INSTALL_MODE="upgrade"
fi
DISK_DEVICES="$(awk -F': ' '/^[[:space:]]*Geom name: /{print $2}' "$OUTPUT_DIR/geom-disk-list.txt" | paste -sd',' -)"
DISK_COUNT=0
if [ -n "$DISK_DEVICES" ]; then
DISK_COUNT="$(printf '%s\n' "$DISK_DEVICES" | tr ',' '\n' | awk 'NF {count += 1} END {print count + 0}')"
fi
POOL_NAME="$(awk -F'\t' 'NF {print $1; exit}' "$OUTPUT_DIR/zpool-list.txt")"
[ -z "$POOL_NAME" ] && POOL_NAME="zroot"
POOL_ROWS="$(awk -F'\t' 'NF {printf "%s (%s, %s used)", $1, $7, $5; exit}' "$OUTPUT_DIR/zpool-list.txt")"
[ -z "$POOL_ROWS" ] && POOL_ROWS="none detected"
OBSERVED_LAYOUTS=""
grep -q 'mirror-[0-9]' "$OUTPUT_DIR/zpool-status.txt" && OBSERVED_LAYOUTS="mirror"
grep -q 'raidz1-[0-9]' "$OUTPUT_DIR/zpool-status.txt" && OBSERVED_LAYOUTS="raidz1"
grep -q 'raidz2-[0-9]' "$OUTPUT_DIR/zpool-status.txt" && OBSERVED_LAYOUTS="raidz2"
if [ -z "$OBSERVED_LAYOUTS" ] && [ -s "$OUTPUT_DIR/zpool-list.txt" ]; then
OBSERVED_LAYOUTS="single"
fi
[ -z "$OBSERVED_LAYOUTS" ] && OBSERVED_LAYOUTS="none detected"
SUGGESTED_ZFS_LAYOUT="single"
SUGGESTED_ZFS_DATA_DISKS=1
SUGGESTED_ZFS_HOT_SPARES=0
SUGGESTED_ZFS_REASON="Single-disk default. Fine for bootstrap, not the recommended long-running durable layout."
case "$OBSERVED_LAYOUTS" in
raidz2)
SUGGESTED_ZFS_LAYOUT="raidz2"
if [ "$DISK_COUNT" -ge 4 ]; then
SUGGESTED_ZFS_DATA_DISKS="$DISK_COUNT"
else
SUGGESTED_ZFS_DATA_DISKS=4
fi
SUGGESTED_ZFS_REASON="Observed pool topology already includes raidz2. Preserve it for upgrade or rescue."
;;
raidz1)
SUGGESTED_ZFS_LAYOUT="raidz1"
if [ "$DISK_COUNT" -ge 3 ]; then
SUGGESTED_ZFS_DATA_DISKS="$DISK_COUNT"
else
SUGGESTED_ZFS_DATA_DISKS=3
fi
SUGGESTED_ZFS_REASON="Observed pool topology already includes raidz1. Preserve it for upgrade or rescue."
;;
mirror)
SUGGESTED_ZFS_LAYOUT="mirror"
if [ "$DISK_COUNT" -ge 2 ]; then
SUGGESTED_ZFS_DATA_DISKS="$DISK_COUNT"
else
SUGGESTED_ZFS_DATA_DISKS=2
fi
SUGGESTED_ZFS_REASON="Observed pool topology already includes a mirror. Preserve it for upgrade or rescue."
;;
single)
SUGGESTED_ZFS_LAYOUT="single"
SUGGESTED_ZFS_DATA_DISKS=1
SUGGESTED_ZFS_HOT_SPARES=0
SUGGESTED_ZFS_REASON="Single-disk default. Fine for bootstrap, not the recommended long-running durable layout."
;;
*)
if [ "$DISK_COUNT" -le 1 ]; then
SUGGESTED_ZFS_LAYOUT="single"
SUGGESTED_ZFS_DATA_DISKS=1
SUGGESTED_ZFS_HOT_SPARES=0
SUGGESTED_ZFS_REASON="Single-disk default. Fine for bootstrap, not the recommended long-running durable layout."
elif [ "$DISK_COUNT" -eq 2 ]; then
SUGGESTED_ZFS_LAYOUT="mirror"
SUGGESTED_ZFS_DATA_DISKS=2
SUGGESTED_ZFS_HOT_SPARES=0
SUGGESTED_ZFS_REASON="Two disks detected. Mirror is the cleanest durable layout."
elif [ "$DISK_COUNT" -eq 3 ]; then
SUGGESTED_ZFS_LAYOUT="raidz1"
SUGGESTED_ZFS_DATA_DISKS=3
SUGGESTED_ZFS_HOT_SPARES=0
SUGGESTED_ZFS_REASON="Three disks detected. raidz1 is the recommended durable layout."
else
SUGGESTED_ZFS_LAYOUT="raidz1"
SUGGESTED_ZFS_DATA_DISKS=$((DISK_COUNT - 1))
SUGGESTED_ZFS_HOT_SPARES=1
SUGGESTED_ZFS_REASON="Four or more disks detected. Suggested default is raidz1 plus one hot spare."
fi
;;
esac
INTERFACES="$(awk -F: '/: flags=/{print $1}' "$OUTPUT_DIR/ifconfig.txt" | paste -sd',' -)"
PF_VISIBLE_INTERFACES="$(awk '
NF &&
$0 !~ /^pfctl:/ &&
$0 !~ /^(Status|Enabled|Disabled|No)$/ &&
$0 ~ /^[A-Za-z0-9_.:-]+$/ {print $0}
' "$OUTPUT_DIR/pf-interfaces.txt" | paste -sd',' -)"
[ -z "$PF_VISIBLE_INTERFACES" ] && PF_VISIBLE_INTERFACES="none detected"
EXTERNAL_IFACES=""
INTERNAL_IFACES=""
if [ -n "$INTERFACES" ]; then
while IFS= read -r iface; do
[ -z "$iface" ] && continue
if printf '%s' "$iface" | grep -Eq '^warden[0-9]+$|^bridge[0-9]+$|^[A-Za-z][0-9][ab]_[A-Za-z0-9_-]+$'; then
INTERNAL_IFACES="${INTERNAL_IFACES:+$INTERNAL_IFACES,}$iface"
continue
fi
if printf '%s' "$iface" | grep -Eq '^(lo|pflog|pfsync|epair|bridge|tap|tun|wg|vlan)'; then
continue
fi
EXTERNAL_IFACES="${EXTERNAL_IFACES:+$EXTERNAL_IFACES,}$iface"
done <<EOF
$(printf '%s\n' "$INTERFACES" | tr ',' '\n')
EOF
fi
[ -z "$EXTERNAL_IFACES" ] && EXTERNAL_IFACES="none detected"
[ -z "$INTERNAL_IFACES" ] && INTERNAL_IFACES="none detected"
DATASET_PREVIEW="$(awk -F'\t' 'NF {print $1}' "$OUTPUT_DIR/zfs-list.txt" | head -n 8 | paste -sd',' -)"
[ -z "$DATASET_PREVIEW" ] && DATASET_PREVIEW="none detected"
PRIMARY_EXTERNAL_IF="$(printf '%s' "$EXTERNAL_IFACES" | awk -F',' 'NF {print $1}')"
PRIMARY_INTERNAL_IF="$(printf '%s' "$INTERNAL_IFACES" | awk -F',' 'NF {print $1}')"
[ "$PRIMARY_EXTERNAL_IF" = "none detected" ] && PRIMARY_EXTERNAL_IF=""
[ "$PRIMARY_INTERNAL_IF" = "none detected" ] && PRIMARY_INTERNAL_IF=""
TAILSCALE_IF=""
printf '%s\n' "$INTERFACES" | tr ',' '\n' | grep -qx 'tailscale0' && TAILSCALE_IF='tailscale0'
GPU_DEVICE=""
if [ -e /dev/drm0 ] || [ -e /dev/dri/card0 ]; then
GPU_DEVICE="drm0"
elif grep -Eiq '(VGA|display)' "$OUTPUT_DIR/pciconf.txt"; then
GPU_DEVICE="auto-gpu"
fi
SND_DEVICE="$(grep -Eo 'pcm[0-9]+' "$OUTPUT_DIR/sndstat.txt" | head -n 1 || true)"
ZFS_DATA_DEVICE_LIST=""
ZFS_SPARE_DEVICE_LIST=""
if [ "$DISK_COUNT" -gt 0 ] && [ -n "$DISK_DEVICES" ]; then
if [ "$SUGGESTED_ZFS_HOT_SPARES" -gt 0 ]; then
ZFS_DATA_DEVICE_LIST="$(printf '%s\n' "$DISK_DEVICES" | tr ',' '\n' | head -n "$SUGGESTED_ZFS_DATA_DISKS" | paste -sd',' -)"
ZFS_SPARE_DEVICE_LIST="$(printf '%s\n' "$DISK_DEVICES" | tr ',' '\n' | tail -n "$SUGGESTED_ZFS_HOT_SPARES" | paste -sd',' -)"
else
ZFS_DATA_DEVICE_LIST="$DISK_DEVICES"
fi
fi
cat >"$OUTPUT_DIR/suggested-setup.txt" <<EOF
SETUP_SCHEMA_VERSION=$SETUP_SCHEMA_VERSION
ISO_RELEASE=$ISO_RELEASE
ISO_GIT_COMMIT=$ISO_GIT_COMMIT
INSTALL_MODE=$SUGGESTED_INSTALL_MODE
ZFS_POOL=$POOL_NAME
ZFS_LAYOUT=$SUGGESTED_ZFS_LAYOUT
ZFS_DATA_DISKS=$SUGGESTED_ZFS_DATA_DISKS
ZFS_HOT_SPARES=$SUGGESTED_ZFS_HOT_SPARES
EOF
cat >"$OUTPUT_DIR/system.env" <<EOF
SYSTEM_SCHEMA_VERSION=$SYSTEM_SCHEMA_VERSION
NETWORK_EXTERNAL_IF=$PRIMARY_EXTERNAL_IF
NETWORK_INTERNAL_IF=$PRIMARY_INTERNAL_IF
TAILSCALE_IF=$TAILSCALE_IF
ZFS_POOL=$POOL_NAME
ZFS_LAYOUT=$SUGGESTED_ZFS_LAYOUT
ZFS_DATA_DISKS=$SUGGESTED_ZFS_DATA_DISKS
ZFS_HOT_SPARES=$SUGGESTED_ZFS_HOT_SPARES
ZFS_DISKS=$ZFS_DATA_DEVICE_LIST
ZFS_SPARE_DISKS=$ZFS_SPARE_DEVICE_LIST
ZFS_PREFIX=$ZFS_PREFIX_VALUE
GPU_DEVICE=$GPU_DEVICE
SND_DEVICE=$SND_DEVICE
EOF
if [ -n "$APPLY_SETUP_FILE" ]; then
mkdir -p "$(dirname "$APPLY_SETUP_FILE")"
if [ ! -f "$APPLY_SETUP_FILE" ]; then
: >"$APPLY_SETUP_FILE"
fi
apply_if_blank "$APPLY_SETUP_FILE" "SETUP_SCHEMA_VERSION" "$SETUP_SCHEMA_VERSION"
apply_if_blank "$APPLY_SETUP_FILE" "ISO_RELEASE" "$ISO_RELEASE"
apply_if_blank "$APPLY_SETUP_FILE" "ISO_GIT_COMMIT" "$ISO_GIT_COMMIT"
apply_if_blank "$APPLY_SETUP_FILE" "INSTALL_MODE" "$SUGGESTED_INSTALL_MODE"
apply_if_blank "$APPLY_SETUP_FILE" "ZFS_POOL" "$POOL_NAME"
CURRENT_ZFS_LAYOUT="$(read_setup_value "$APPLY_SETUP_FILE" "ZFS_LAYOUT" 2>/dev/null || true)"
apply_if_blank "$APPLY_SETUP_FILE" "ZFS_LAYOUT" "$SUGGESTED_ZFS_LAYOUT"
if [ -z "$CURRENT_ZFS_LAYOUT" ] || [ "$CURRENT_ZFS_LAYOUT" = "$SUGGESTED_ZFS_LAYOUT" ]; then
apply_if_blank "$APPLY_SETUP_FILE" "ZFS_DATA_DISKS" "$SUGGESTED_ZFS_DATA_DISKS"
apply_if_blank "$APPLY_SETUP_FILE" "ZFS_HOT_SPARES" "$SUGGESTED_ZFS_HOT_SPARES"
fi
fi
if [ -n "$APPLY_SYSTEM_ENV_FILE" ]; then
mkdir -p "$(dirname "$APPLY_SYSTEM_ENV_FILE")"
if [ ! -f "$APPLY_SYSTEM_ENV_FILE" ]; then
: >"$APPLY_SYSTEM_ENV_FILE"
fi
apply_if_blank "$APPLY_SYSTEM_ENV_FILE" "SYSTEM_SCHEMA_VERSION" "$SYSTEM_SCHEMA_VERSION"
apply_if_blank "$APPLY_SYSTEM_ENV_FILE" "NETWORK_EXTERNAL_IF" "$PRIMARY_EXTERNAL_IF"
apply_if_blank "$APPLY_SYSTEM_ENV_FILE" "NETWORK_INTERNAL_IF" "$PRIMARY_INTERNAL_IF"
apply_if_blank "$APPLY_SYSTEM_ENV_FILE" "TAILSCALE_IF" "$TAILSCALE_IF"
apply_if_blank "$APPLY_SYSTEM_ENV_FILE" "ZFS_POOL" "$POOL_NAME"
CURRENT_SYSTEM_ZFS_LAYOUT="$(read_setup_value "$APPLY_SYSTEM_ENV_FILE" "ZFS_LAYOUT" 2>/dev/null || true)"
apply_if_blank "$APPLY_SYSTEM_ENV_FILE" "ZFS_LAYOUT" "$SUGGESTED_ZFS_LAYOUT"
if [ -z "$CURRENT_SYSTEM_ZFS_LAYOUT" ] || [ "$CURRENT_SYSTEM_ZFS_LAYOUT" = "$SUGGESTED_ZFS_LAYOUT" ]; then
apply_if_blank "$APPLY_SYSTEM_ENV_FILE" "ZFS_DATA_DISKS" "$SUGGESTED_ZFS_DATA_DISKS"
apply_if_blank "$APPLY_SYSTEM_ENV_FILE" "ZFS_HOT_SPARES" "$SUGGESTED_ZFS_HOT_SPARES"
apply_if_blank "$APPLY_SYSTEM_ENV_FILE" "ZFS_DISKS" "$ZFS_DATA_DEVICE_LIST"
apply_if_blank "$APPLY_SYSTEM_ENV_FILE" "ZFS_SPARE_DISKS" "$ZFS_SPARE_DEVICE_LIST"
fi
apply_if_blank "$APPLY_SYSTEM_ENV_FILE" "ZFS_PREFIX" "$ZFS_PREFIX_VALUE"
apply_if_blank "$APPLY_SYSTEM_ENV_FILE" "GPU_DEVICE" "$GPU_DEVICE"
apply_if_blank "$APPLY_SYSTEM_ENV_FILE" "SND_DEVICE" "$SND_DEVICE"
fi
cat >"$OUTPUT_DIR/inspect-facts.env" <<EOF
INSPECT_HOSTNAME=$HOSTNAME_VALUE
INSPECT_EXISTING_INSTALL=$EXISTING_INSTALL
INSPECT_STRONG_SIGNALS=$(IFS=,; echo "${STRONG_SIGNALS[*]-}")
INSPECT_SOFT_SIGNALS=$(IFS=,; echo "${SOFT_SIGNALS[*]-}")
INSPECT_SUGGESTED_INSTALL_MODE=$SUGGESTED_INSTALL_MODE
INSPECT_DISK_COUNT=$DISK_COUNT
INSPECT_DISK_DEVICES=$DISK_DEVICES
INSPECT_ZFS_POOL=$POOL_NAME
INSPECT_OBSERVED_LAYOUTS=$OBSERVED_LAYOUTS
INSPECT_SUGGESTED_ZFS_LAYOUT=$SUGGESTED_ZFS_LAYOUT
INSPECT_SUGGESTED_ZFS_DATA_DISKS=$SUGGESTED_ZFS_DATA_DISKS
INSPECT_SUGGESTED_ZFS_HOT_SPARES=$SUGGESTED_ZFS_HOT_SPARES
INSPECT_EXTERNAL_INTERFACES=$EXTERNAL_IFACES
INSPECT_INTERNAL_INTERFACES=$INTERNAL_IFACES
INSPECT_PF_VISIBLE_INTERFACES=$PF_VISIBLE_INTERFACES
EOF
cat >"$OUTPUT_DIR/system.txt" <<EOF
Clawdie Inspect Report
Observed: $OBSERVED_AT
Host
- Hostname: $HOSTNAME_VALUE
- OS: ${FREEBSD_VERSION:-unknown} · ${UNAME_VALUE:-unknown}
Install Detection
- Existing install: $EXISTING_INSTALL
- Strong signals: $(IFS=,; echo "${STRONG_SIGNALS[*]-none}")
- Soft signals: $(IFS=,; echo "${SOFT_SIGNALS[*]-none}")
- Suggested install mode: $SUGGESTED_INSTALL_MODE
Storage
- Disk devices ($DISK_COUNT): ${DISK_DEVICES:-none detected}
- Pools: $POOL_ROWS
- Pool layouts: $OBSERVED_LAYOUTS
- Example datasets: $DATASET_PREVIEW
- Suggested ZFS shape: $SUGGESTED_ZFS_LAYOUT · data disks $SUGGESTED_ZFS_DATA_DISKS · hot spares $SUGGESTED_ZFS_HOT_SPARES
- Reason: $SUGGESTED_ZFS_REASON
Network
- Interfaces: ${INTERFACES:-none detected}
- PF-visible interfaces: $PF_VISIBLE_INTERFACES
- Suggested external PF interfaces: $EXTERNAL_IFACES
- Suggested internal/jail interfaces: $INTERNAL_IFACES
Suggested setup.txt lines
- INSTALL_MODE=$SUGGESTED_INSTALL_MODE
- ZFS_POOL=$POOL_NAME
- ZFS_LAYOUT=$SUGGESTED_ZFS_LAYOUT
- ZFS_DATA_DISKS=$SUGGESTED_ZFS_DATA_DISKS
- ZFS_HOT_SPARES=$SUGGESTED_ZFS_HOT_SPARES
Artifacts
- system.txt
- system.env
- inspect-facts.env
- suggested-setup.txt
- dmesg.txt
- pciconf.txt
- sndstat.txt
- geom-disk-list.txt
- ifconfig.txt
- pf-status.txt
- pf-interfaces.txt
- zpool-list.txt
- zpool-status.txt
- zfs-list.txt
EOF
echo "Inspect artifacts written to $OUTPUT_DIR"
echo "Suggested install mode: $SUGGESTED_INSTALL_MODE"
echo "Suggested ZFS shape: $SUGGESTED_ZFS_LAYOUT ($SUGGESTED_ZFS_DATA_DISKS data disk(s), $SUGGESTED_ZFS_HOT_SPARES hot spare(s))"
if [ -n "$APPLY_SETUP_FILE" ]; then
echo "Applied missing setup.txt values to $APPLY_SETUP_FILE"
if [ -n "${CURRENT_ZFS_LAYOUT:-}" ] && [ "$CURRENT_ZFS_LAYOUT" != "$SUGGESTED_ZFS_LAYOUT" ]; then
echo "Skipped ZFS_DATA_DISKS/ZFS_HOT_SPARES backfill because setup.txt already declares ZFS_LAYOUT=$CURRENT_ZFS_LAYOUT"
fi
fi
if [ -n "$APPLY_SYSTEM_ENV_FILE" ]; then
echo "Applied missing system.env values to $APPLY_SYSTEM_ENV_FILE"
if [ -n "${CURRENT_SYSTEM_ZFS_LAYOUT:-}" ] && [ "$CURRENT_SYSTEM_ZFS_LAYOUT" != "$SUGGESTED_ZFS_LAYOUT" ]; then
echo "Skipped ZFS_DATA_DISKS/ZFS_HOT_SPARES/ZFS_DISKS/ZFS_SPARE_DISKS backfill because system.env already declares ZFS_LAYOUT=$CURRENT_SYSTEM_ZFS_LAYOUT"
fi
fi