podman-standalone.sh: - Add HF_CACHE_DIR=/opt/turnstone/hf-cache with mkdir guard - Mount HF_HOME=/hf-cache so model weights persist across restarts - Forward all multi-agent env vars (TURNSTONE_MULTI_AGENT_DIAGNOSE, GPU_SERVER_URL, TURNSTONE_CLASSIFIER_MODEL, TURNSTONE_EMBED_*) - Add documentation comments for Contributor/Contributor2 remote instance setup requirements.txt: - Add torch (CPU-only), transformers, sentence-transformers for the 5-stage multi-agent diagnose pipeline (classifier + suppressor stages) - Use --extra-index-url for cpu wheel to keep image ~2GB lighter - Both modules keep ImportError guards so server starts without them, but container images should ship fully capable
180 lines
8.4 KiB
Bash
Executable file
180 lines
8.4 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# podman-standalone.sh — Turnstone rootful Podman setup (no Compose)
|
|
#
|
|
# For hosts running system Podman (non-rootless) with systemd.
|
|
# Turnstone is a diagnostic log intelligence layer — glean service logs,
|
|
# search by symptom, and view incidents in a lightweight web UI.
|
|
#
|
|
# ── Prerequisites ────────────────────────────────────────────────────────────
|
|
# 1. Clone the repo:
|
|
# sudo git clone https://git.opensourcesolarpunk.com/Circuit-Forge/turnstone.git /opt/turnstone
|
|
# sudo chown -R x:x /opt/turnstone
|
|
#
|
|
# 2. Build the image (requires Docker or Podman with BuildKit/multi-stage support):
|
|
# cd /opt/turnstone && podman build -t localhost/turnstone:latest .
|
|
#
|
|
# 3. Create data and patterns directories, then copy config files:
|
|
# mkdir -p /opt/turnstone/{data,patterns}
|
|
# cp /opt/turnstone/patterns/default.yaml /opt/turnstone/patterns/
|
|
# cp /opt/turnstone/patterns/sources.yaml /opt/turnstone/patterns/
|
|
# # Edit sources.yaml if any paths differ on this host.
|
|
#
|
|
# 4. Run this script:
|
|
# bash /opt/turnstone/podman-standalone.sh
|
|
#
|
|
# ── After setup — generate systemd unit file ─────────────────────────────────
|
|
# sudo podman generate systemd --new --name turnstone \
|
|
# | sudo tee /etc/systemd/system/turnstone.service
|
|
# sudo systemctl daemon-reload
|
|
# sudo systemctl enable --now turnstone
|
|
#
|
|
# ── Gleaning logs ─────────────────────────────────────────────────────────────
|
|
# All service logs under /opt are accessible inside the container.
|
|
# Sources are configured in patterns/sources.yaml (bind-mounted at /patterns/).
|
|
#
|
|
# To glean all sources (run manually or via cron):
|
|
#
|
|
# sudo podman exec turnstone python scripts/glean_corpus.py \
|
|
# --sources /patterns/sources.yaml --db /data/turnstone.db
|
|
#
|
|
# Example cron (every 15 minutes, add to root's crontab with: sudo crontab -e):
|
|
# */15 * * * * podman exec turnstone python scripts/glean_corpus.py \
|
|
# --sources /patterns/sources.yaml --db /data/turnstone.db >> /var/log/turnstone-glean.log 2>&1
|
|
#
|
|
# To add a new log source: edit /opt/turnstone/patterns/sources.yaml — no restart needed.
|
|
#
|
|
# ── Adding Caddy reverse proxy ────────────────────────────────────────────────
|
|
# Add to /etc/caddy/Caddyfile:
|
|
#
|
|
# turnstone.example-node.tv {
|
|
# import protected
|
|
# reverse_proxy 10.0.0.10:8534
|
|
# import cloudflare
|
|
# }
|
|
#
|
|
# Then: sudo systemctl reload caddy
|
|
#
|
|
# ── Ports ────────────────────────────────────────────────────────────────────
|
|
# Turnstone UI → http://localhost:8534/turnstone/
|
|
#
|
|
set -euo pipefail
|
|
|
|
REPO_DIR=/opt/turnstone
|
|
DATA_DIR=/opt/turnstone/data
|
|
PATTERNS_DIR=/opt/turnstone/patterns
|
|
HF_CACHE_DIR=/opt/turnstone/hf-cache # persists downloaded ML models across restarts
|
|
TZ=America/Los_Angeles
|
|
|
|
# ── Bundle push configuration ────────────────────────────────────────────────
|
|
# Set TURNSTONE_BUNDLE_ENDPOINT before running this script to enable the
|
|
# "Send Bundle" button in the Incidents UI:
|
|
#
|
|
# export TURNSTONE_BUNDLE_ENDPOINT=https://turnstone.circuitforge.tech/turnstone/api/bundles
|
|
# bash /opt/turnstone/podman-standalone.sh
|
|
#
|
|
# ── Orchard submission (opt-in telemetry) ────────────────────────────────────
|
|
# Set TURNSTONE_SUBMIT_ENDPOINT to push pattern-matched log entries to a CF
|
|
# receiving instance after each glean run. Only matched entries are sent —
|
|
# no raw log content. Used to build Avocet training data.
|
|
#
|
|
# export TURNSTONE_SUBMIT_ENDPOINT=https://harvest.circuitforge.tech/contrib2
|
|
# bash /opt/turnstone/podman-standalone.sh
|
|
#
|
|
# TURNSTONE_SOURCE_HOST is auto-detected from `hostname` — override if needed.
|
|
#
|
|
# ── Multi-agent diagnose pipeline ────────────────────────────────────────────
|
|
# The 5-stage ML pipeline requires three env vars and a writable HF cache dir:
|
|
#
|
|
# TURNSTONE_MULTI_AGENT_DIAGNOSE=true — enable the pipeline
|
|
# GPU_SERVER_URL=http://<orch-host>:7700 — cf-orch coordinator or Ollama base URL
|
|
#
|
|
# ML models are downloaded on first diagnose run and cached in HF_CACHE_DIR.
|
|
# On a CPU-only host (no GPU) set TURNSTONE_EMBED_DEVICE=cpu (default).
|
|
#
|
|
# For Contributor2's instance (example-node.tv) — Heimdall's cf-orch via WireGuard:
|
|
# export GPU_SERVER_URL=http://<YOUR_HOST_IP>:7700
|
|
# export TURNSTONE_MULTI_AGENT_DIAGNOSE=true
|
|
# sudo bash /opt/turnstone/podman-standalone.sh
|
|
#
|
|
# For Contributor's instance (Huginn) — same cf-orch via WireGuard:
|
|
# export GPU_SERVER_URL=http://<YOUR_HOST_IP>:7700
|
|
# export TURNSTONE_MULTI_AGENT_DIAGNOSE=true
|
|
# bash /opt/turnstone/podman-standalone.sh (or rebuild Docker container)
|
|
|
|
# ── Turnstone container ───────────────────────────────────────────────────────
|
|
# Image is built locally — no registry auto-update label.
|
|
# Run this script after every `git pull` to rebuild and redeploy.
|
|
#
|
|
# /opt is mounted read-only so all service logs under /opt/*/config/logs/ are
|
|
# accessible without per-service mounts. Add new sources to patterns/sources.yaml
|
|
# — no container restart needed.
|
|
#
|
|
# Must be run as root (sudo bash podman-standalone.sh) — rootful Podman only.
|
|
#
|
|
|
|
# Build image from current source (bakes app/ code into the image)
|
|
echo "Building Turnstone image..."
|
|
podman build -t localhost/turnstone:latest "${REPO_DIR}"
|
|
|
|
# Create HF model cache dir if not present (persists across container rebuilds)
|
|
mkdir -p "${HF_CACHE_DIR}"
|
|
|
|
# Remove existing container if present (safe re-run)
|
|
podman rm -f turnstone 2>/dev/null || true
|
|
|
|
podman run -d \
|
|
--name=turnstone \
|
|
--restart=unless-stopped \
|
|
--net=host \
|
|
-v "${DATA_DIR}:/data:Z" \
|
|
-v "${PATTERNS_DIR}:/patterns:Z" \
|
|
-v "${HF_CACHE_DIR}:/hf-cache:Z" \
|
|
-v /opt:/opt:ro \
|
|
-v /var/log:/var/log:ro \
|
|
-e TURNSTONE_DB=/data/turnstone.db \
|
|
-e TURNSTONE_SOURCE_HOST="$(hostname)" \
|
|
-e TURNSTONE_BUNDLE_ENDPOINT="${TURNSTONE_BUNDLE_ENDPOINT:-}" \
|
|
-e TURNSTONE_SUBMIT_ENDPOINT="${TURNSTONE_SUBMIT_ENDPOINT:-}" \
|
|
-e PYTHONUNBUFFERED=1 \
|
|
-e TZ="${TZ}" \
|
|
-e TURNSTONE_MULTI_AGENT_DIAGNOSE="${TURNSTONE_MULTI_AGENT_DIAGNOSE:-false}" \
|
|
-e GPU_SERVER_URL="${GPU_SERVER_URL:-}" \
|
|
-e HF_HOME=/hf-cache \
|
|
-e TURNSTONE_CLASSIFIER_MODEL="${TURNSTONE_CLASSIFIER_MODEL:-byviz/bylastic_classification_logs}" \
|
|
-e TURNSTONE_EMBED_BACKEND="${TURNSTONE_EMBED_BACKEND:-sentence_transformers}" \
|
|
-e TURNSTONE_EMBED_MODEL="${TURNSTONE_EMBED_MODEL:-sentence-transformers/all-MiniLM-L6-v2}" \
|
|
-e TURNSTONE_EMBED_DEVICE="${TURNSTONE_EMBED_DEVICE:-cpu}" \
|
|
--health-cmd="curl -f http://localhost:8534/turnstone/health || exit 1" \
|
|
--health-interval=30s \
|
|
--health-timeout=10s \
|
|
--health-start-period=20s \
|
|
--health-retries=3 \
|
|
localhost/turnstone:latest
|
|
|
|
echo ""
|
|
echo "Turnstone is starting up."
|
|
echo " UI: http://localhost:8534/turnstone/"
|
|
echo ""
|
|
|
|
# Regenerate systemd unit so it references the freshly-built image.
|
|
# The --new flag means systemd re-creates the container on each start
|
|
# rather than binding to a specific container ID.
|
|
if [ -d /etc/systemd/system ]; then
|
|
echo "Regenerating systemd unit..."
|
|
podman generate systemd --new --name turnstone \
|
|
| tee /etc/systemd/system/turnstone.service > /dev/null
|
|
systemctl daemon-reload
|
|
systemctl enable turnstone.service 2>/dev/null || true
|
|
echo " systemd unit updated — run: sudo systemctl restart turnstone.service"
|
|
echo ""
|
|
fi
|
|
|
|
echo "Check container health with:"
|
|
echo " sudo podman ps"
|
|
echo " sudo podman logs turnstone"
|
|
echo ""
|
|
echo "To glean all sources now:"
|
|
echo " sudo podman exec turnstone python scripts/glean_corpus.py \\"
|
|
echo " --sources /patterns/sources.yaml --db /data/turnstone.db"
|
|
echo ""
|
|
echo "To add a new source: edit /opt/turnstone/patterns/sources.yaml — no restart needed."
|