SmartestHome/tools/build-core-pair.sh

110 lines
4.6 KiB
Bash
Executable File

#!/usr/bin/env bash
#
# Build the TWINNED core pair: the container host (Home Assistant + everything in
# hosts/container-host/) and the LLM host (Ollama, hosts/llm-host/), as two ISOs that
# already know about each other.
#
# WHAT "TWINNED" MEANS HERE, concretely: CoreSystemConfig.json states the subnet prefix
# once and one last octet per host. Everything else is computed. The container host's
# OLLAMA_HOST is the LLM host's address because both were derived from those numbers in
# the same build — not because someone typed the same IP into two files and remembered
# to keep them in sync. Move the LLM host from .13 to .21 and rebuild, and the
# container host's Ollama URL follows on its own. Neither ISO can be built pointing at
# an address the other one isn't using.
#
# Both images get a matching SMARTHOME_PAIR_ID in /etc/smarthome-build, so two ISOs on
# two USB sticks can be checked against each other months later.
#
# Everything each host needs is burnt in: static network config, hostname, admin user,
# SSH key, every service token, the generated env files, and this repo itself. The
# machines come up configured, with no post-install editing of env files by hand.
#
# sudo -E tools/build-core-pair.sh # both
# sudo -E tools/build-core-pair.sh container # just the container host
# sudo -E tools/build-core-pair.sh llm # just the LLM host
#
# READ THIS BEFORE YOU BUILD: the resulting ISOs contain every secret in
# CoreSystemConfig.json — Wi-Fi PSK, service tokens, MQTT and HA credentials, your
# SSH public key. They are credential-bearing artifacts. .gitignore keeps them out of
# the repo, but an ISO on a USB stick in a drawer is still every token in this
# household. Treat them accordingly, and wipe sticks you stop using.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=lib/coreconfig.sh
source "${SCRIPT_DIR}/lib/coreconfig.sh"
TARGET="${1:-both}"
case "$TARGET" in
both|container|llm) ;;
*) core_die "Usage: $0 [both|container|llm]" ;;
esac
core_load
core_require_root "$TARGET"
PAIR_ID="$(core_pair_id)"
cat <<EOF
============================================================================
SmartestHome — twinned core pair
============================================================================
Pair ID : ${PAIR_ID}
Subnet : ${CORE_SUBNET_PREFIX}.0/24 (gateway ${CORE_GATEWAY})
Container host : ${CORE_CONTAINER_HOST_NAME} ${CORE_CONTAINER_HOST_IP}
LLM host : ${CORE_LLM_HOST_NAME} ${CORE_LLM_HOST_IP}
Derived cross-references (nothing below was typed by hand):
container host -> Ollama : ${CORE_OLLAMA_HOST}
kiosks -> Home Assistant : ${CORE_HA_URL}
kiosks -> identity : ${CORE_IDENTITY_URL}
kiosks -> MQTT : ${CORE_MQTT_BROKER_HOST}:${CORE_MQTT_BROKER_PORT}
Building : ${TARGET}
============================================================================
EOF
OUTPUT_DIR="${CORE_REPO_ROOT}/${CORE_BUILD_OUTPUT_DIR}"
mkdir -p "$OUTPUT_DIR"
if [[ "$TARGET" == "both" || "$TARGET" == "container" ]]; then
core_log "Building the container host ISO"
"${SCRIPT_DIR}/build-container-host-iso.sh"
fi
if [[ "$TARGET" == "both" || "$TARGET" == "llm" ]]; then
core_log "Building the LLM host ISO"
"${SCRIPT_DIR}/build-llm-host-iso.sh"
fi
cat <<EOF
============================================================================
Done — pair ${PAIR_ID}
============================================================================
ISOs in: ${OUTPUT_DIR}
Install order matters slightly: bring up the CONTAINER host first, since the
LLM host is only ever a server and doesn't need to reach it, whereas the
container host's services will start looking for Ollama immediately (and
degrade quietly until it answers — which is by design, see
hosts/llm-host/README.md).
Two things still need a human afterwards, because neither can be known at
build time:
1. HA_TOKEN — a Long-Lived Access Token from Home Assistant's own UI, which
doesn't exist until HA has been started and an account created. Put it in
CoreSystemConfig.json and re-run this builder, or edit
/opt/smart-home/identity/identity.env on the container host directly.
2. TRUSTED_ENTITY_PREFIXES — the real entity_id prefixes your Private BLE
Device setup produces (Developer Tools -> States). The shipped default is
a guess, and it's the single highest-risk unknown in Phase 6.
Then do the thing the split exists for: power the LLM host OFF and confirm the
house still works. See hosts/llm-host/README.md.
============================================================================
EOF