From df87f224169886407861f0fd1347d3b7817735ee Mon Sep 17 00:00:00 2001 From: pyr0ball Date: Mon, 11 May 2026 05:13:58 -0700 Subject: [PATCH] feat: Podman container deployment for Contributor2's system MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Dockerfile: multi-stage build (node:22-alpine builds Vue SPA, python:3.12-slim runs uvicorn) — no Node.js required on the host - requirements.txt: minimal runtime deps (fastapi, uvicorn, pyyaml, aiofiles, pydantic, python-multipart) - podman-standalone.sh: mirrors Peregrine's deployment pattern; binds /opt/turnstone/data + /opt/turnstone/patterns + /opt/qbittorrent/config/data/logs (ro); includes cron and Caddy config instructions in comments - .gitignore: add log/, .turnstone-api.pid (generated by manage.sh dev mode) --- .gitignore | 2 + Dockerfile | 36 ++++++++++++++ podman-standalone.sh | 109 +++++++++++++++++++++++++++++++++++++++++++ requirements.txt | 6 +++ 4 files changed, 153 insertions(+) create mode 100644 Dockerfile create mode 100755 podman-standalone.sh create mode 100644 requirements.txt diff --git a/.gitignore b/.gitignore index 07aecfc..3613d6b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ data/ corpus/raw/ +log/ __pycache__/ *.pyc *.pyo @@ -8,5 +9,6 @@ __pycache__/ *.db *.db-wal *.db-shm +.turnstone-api.pid web/node_modules/ web/dist/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..8ea52d1 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,36 @@ +# ── Stage 1: Build Vue SPA ──────────────────────────────────────────────────── +FROM node:22-alpine AS web-builder +WORKDIR /web +COPY web/package.json web/package-lock.json ./ +RUN npm ci +COPY web/ ./ +RUN npm run build + +# ── Stage 2: Python runtime ─────────────────────────────────────────────────── +FROM python:3.12-slim +WORKDIR /app + +RUN apt-get update && apt-get install -y --no-install-recommends \ + curl \ + && rm -rf /var/lib/apt/lists/* + +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt + +COPY app/ ./app/ +COPY patterns/ ./patterns/ +COPY scripts/ ./scripts/ +COPY --from=web-builder /web/dist ./web/dist + +# Volume mount points — override at runtime: +# /data/ → TURNSTONE_DB=/data/turnstone.db (read-write) +# /patterns/ → custom pattern YAML files (read-write) +# /logs/ → host log directories (read-only) +ENV TURNSTONE_DB=/data/turnstone.db + +EXPOSE 8534 + +HEALTHCHECK --interval=30s --timeout=10s --start-period=20s --retries=3 \ + CMD curl -f http://localhost:8534/turnstone/health || exit 1 + +CMD ["uvicorn", "app.rest:app", "--host", "0.0.0.0", "--port", "8534"] diff --git a/podman-standalone.sh b/podman-standalone.sh new file mode 100755 index 0000000..e4e83cb --- /dev/null +++ b/podman-standalone.sh @@ -0,0 +1,109 @@ +#!/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 — ingest 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 custom patterns directories: +# mkdir -p /opt/turnstone/{data,patterns} +# # Optionally copy default patterns as a starting point: +# cp /opt/turnstone/patterns/default.yaml /opt/turnstone/patterns/ +# +# 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 +# +# ── Ingesting logs ──────────────────────────────────────────────────────────── +# Log files on the host are bind-mounted read-only under /logs/ in the +# container. To ingest (run manually or via cron): +# +# podman exec turnstone python scripts/ingest_corpus.py \ +# /logs/qbittorrent/qbittorrent.log /data/turnstone.db +# +# Example cron (every 15 minutes): +# */15 * * * * podman exec turnstone python scripts/ingest_corpus.py \ +# /logs/qbittorrent/qbittorrent.log /data/turnstone.db >> /var/log/turnstone-ingest.log 2>&1 +# +# ── 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 +TZ=America/Los_Angeles + +# ── Log source bind mounts ──────────────────────────────────────────────────── +# Add or remove mount flags below for each service whose logs you want to ingest. +# Inside the container, paths appear under /logs// +# +QBIT_LOGS=/opt/qbittorrent/config/data/logs + +# ── Turnstone container ─────────────────────────────────────────────────────── +# Image is built locally — no registry auto-update label. +# To update: podman build -t localhost/turnstone:latest /opt/turnstone +# podman restart turnstone +# +# 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 "${QBIT_LOGS}:/logs/qbittorrent:ro" \ + -e TURNSTONE_DB=/data/turnstone.db \ + -e PYTHONUNBUFFERED=1 \ + -e TZ="${TZ}" \ + --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 "" +echo "Check container health with:" +echo " podman ps" +echo " podman logs turnstone" +echo "" +echo "To register as a systemd service:" +echo " sudo podman generate systemd --new --name turnstone \\" +echo " | sudo tee /etc/systemd/system/turnstone.service" +echo " sudo systemctl daemon-reload" +echo " sudo systemctl enable --now turnstone" +echo "" +echo "To ingest qBittorrent logs now:" +echo " podman exec turnstone python scripts/ingest_corpus.py \\" +echo " /logs/qbittorrent/qbittorrent.log /data/turnstone.db" diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..9408a53 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,6 @@ +fastapi>=0.110.0 +uvicorn[standard]>=0.27.0 +pydantic>=2.0.0 +pyyaml>=6.0 +aiofiles>=23.0.0 +python-multipart>=0.0.9