diff --git a/algorithm.md b/algorithm.md new file mode 100644 index 0000000..ad21760 --- /dev/null +++ b/algorithm.md @@ -0,0 +1,352 @@ +# Algorithm Diagrams + +--- + +## 1. Installation Flow + +``` +User runs: ./install.sh [--skip ] [--steps ] [--dry-run] + │ + ▼ + ┌─────────────────────┐ + │ Parse CLI flags │ + │ --skip, --steps, │ + │ --dry-run, --apps │ + └─────────┬───────────┘ + │ + ▼ + ┌─ should_run(1, preinstall) ? + │ YES NO + ▼ ▼ + ┌────────────────┐ ┌──────────────┐ + │ preinstall.sh │ │ skip │ + │ apt update │ │ │ + │ 25+ packages │ │ │ + │ yt-dlp │ │ │ + │ fail2ban │ │ │ + └───────┬────────┘ └──────────────┘ + │ + ▼ + ┌─ should_run(2, scripts) ? + │ YES NO + ▼ ▼ + ┌────────────────┐ ──────── + │ Copy bin/* │ + │ → /usr/local │ + │ Copy lib/ │ + │ → common.sh │ + └───────┬────────┘ + │ + ▼ + ┌─ should_run(3, postinstall) ? + │ YES NO + ▼ ▼ + ┌──────────────────────────┐ + │ postinstall.sh │ + │ • fail2ban config │ + │ • ~/.bashrc PATH │ + │ • bash completion │ + │ • systemd services │ + │ • SSH authorized_keys │ + └──────────┬───────────────┘ + │ + ▼ + ┌─ should_run(4, scalepoint) ? + │ YES NO + ▼ ▼ + ┌──────────────────────────┐ + │ Clone ScaleTail │ + │ → /usr/local/share/ │ + │ linux_post_install/ │ + └──────────┬───────────────┘ + │ + ▼ + ┌─ RUN_APPS ? + │ ┌── 1 (--apps) ─── interactive picker + │ ├── 2 (--full) ─── install all + │ └── else ─── skip + ▼ + ┌──────────────────────┐ + │ Bootstrap complete │ + └──────────────────────┘ +``` + +--- + +## 2. `pos` CLI Dispatch + +``` +User: pos docker compose up jellyfin + │ + ▼ + ┌──────────────────────┐ + │ args = [docker, │ + │ compose, │ + │ up, │ + │ jellyfin] │ + │ n = 4 │ + └──────────┬───────────┘ + │ + ▼ + ┌──────────────────────┐ + │ Loop i from n-1 to 0 │ + │ Build candidate: │ + │ pos-args[0..i] │ + └──────────┬───────────┘ + │ + ┌──────────┴──────────┐ + │ i=3: pos-up-jellyfin│ ✗ not found + │ i=2: pos-up │ ✗ not found + │ i=1: pos-compose-up │ ✗ not found + │ i=0: pos-docker │ ✗ not found + │ │ + │ Fallback to │ + │ pos-docker-compose │ ✓ found! + │ Remaining args: │ + │ [up, jellyfin] │ + └──────────┬──────────┘ + │ + ▼ + ┌───────────────┐ + │ Is this an │ + │ interactive │ + │ command? │ + │ (system- │ + │ firewall, │ + │ media-mp4) │ + └──┬────────┬───┘ + │ YES │ NO + ▼ ▼ + ┌────────┐ ┌──────────────┐ + │ Log │ │ Run cmd │ + │ invoc. │ │ + tee to │ + │ only │ │ log file │ + │ exec │ │ + log rc │ + │ direct │ │ exit rc │ + └────────┘ └──────────────┘ +``` + +--- + +## 3. Docker Compose `up` Algorithm + +``` +pos docker compose up qbittorrent + │ + ▼ + ┌──────────────────────┐ + │ check_deps: docker │ ──✗──→ ERROR + │ installed? │ + └──────────┬───────────┘ + │ ✓ + ▼ + ┌──────────────────────┐ + │ check_templates: │ ──✗──→ ERROR + │ ScaleTail dir exist? │ + └──────────┬───────────┘ + │ ✓ + ▼ + ┌──────────────────────┐ + │ check_service: │ ──✗──→ ERROR + │ template for │ + │ qbittorrent exists? │ + └──────────┬───────────┘ + │ ✓ + ▼ + ┌──────────────────────┐ + │ load_global_config │ + │ SERVICES_BASE=/srv │ + │ target=/srv/ │ + │ qbittorrent │ + └──────────┬───────────┘ + │ + ▼ + ┌──────────────┐ + │ /srv/ │ + │ qbittorrent/ │ + │ exists? │ + └──┬───────┬───┘ + NO YES + │ │ + ▼ ▼ + ┌────────┐ ┌──────────┐ + │ Create │ │ mkdir -p │ + │ dirs │ │ config/ │ + │ copy │ │ data/ │ + │ compose│ │ │ + │ .yaml │ │ │ + └───┬────┘ └──────────┘ + │ │ + └─────┬─────┘ + │ + ▼ + ┌──────────────┐ + │ .env file │ + │ exists? │ + └──┬───────┬───┘ + NO YES + │ │ + │ ▼ + │ (skip to + │ startup) + ▼ + ┌──────────────────────────┐ + │ Copy template .env or │ + │ create from defaults │ + │ │ + │ Fill in global values: │ + │ • TS_AUTHKEY ← global │ + │ • TZ ← global │ + │ • DNS_SERVER ← global │ + │ │ + │ If TS_AUTHKEY empty: │ + │ prompt user │ + └──────────┬───────────────┘ + │ + ▼ + ┌──────────────┐ + │ Prompt: │ + │ "Edit .env │ + │ before │ + │ starting?" │ + └──┬───────┬───┘ + YES NO + │ │ + ▼ ▼ + ┌────────┐ ┌──────────┐ + │ Open │ │ Continue │ + │ $EDITOR│ │ │ + │ (nano) │ │ │ + └───┬────┘ └──────────┘ + │ │ + └─────┬─────┘ + │ + ▼ + ┌──────────────────────┐ + │ docker compose up -d │ + │ (in /srv/qbittorrent)│ + └──────────┬───────────┘ + │ + ▼ + ┌──────────────────────┐ + │ "qbittorrent is │ + │ running" │ + └──────────────────────┘ +``` + +--- + +## 4. Config Cascade (Three Layers) + +``` + USER + │ + ┌──────────────┴──────────────┐ + │ sets via │ + │ pos docker compose config │ + │ set TS_AUTHKEY=... │ + ▼ │ + ┌────────────────────┐ │ + │ Layer 2: Global │◄────────────────┘ + │ ~/.config/ │ + │ linux_post_install│ + │ /compose.env │ + │ │ + │ TS_AUTHKEY=... │ + │ TZ=Europe/... │ + │ DNS_SERVER=9.9... │ + │ SERVICES_BASE=/srv│ + └────────┬───────────┘ + │ + │ values propagate to new deployments + ▼ + ┌────────────────────┐ + │ Layer 1: Template │ + │ /usr/local/share/ │ + │ linux_post_install│ + │ /scale-tail/ │ + │ services// │ + │ .env │ + │ │ + │ SERVICE=xxx │ + │ IMAGE_URL= │ + │ SERVICEPORT= │ + └────────┬───────────┘ + │ + │ merged on first "up" + ▼ + ┌────────────────────┐ + │ Layer 3: Per-svc │ + │ /srv// │ + │ .env │ + │ │ + │ ─── NEVER ─── │ + │ ─── TOUCHED ─── │ + │ ─── AFTER ───── │ + └────────────────────┘ + │ + ▼ + ┌────────────────────┐ + │ docker compose │ + │ up -d │ + │ │ + │ update only │ + │ refreshes │ + │ compose.yaml, │ + │ NOT .env │ + └────────────────────┘ +``` + +--- + +## 5. Logging System + +``` +pos docker compose up jellyfin + │ + ├── Is it an interactive command? + │ (system-firewall, media-mp4) + │ + ├── YES ──→ log: "pos system firewall → exit 0" + │ exec: run directly (no tee) + │ + └── NO ───→ LOG_DIR=~/.local/share/linux_post_install/logs/ + │ + ├── CMD_SAFE = docker_compose_up_jellyfin + │ + ├── LOG_FILE = 20260728_120000_pos_docker_compose_up_jellyfin.log + │ (full stdout+stderr via tee) + │ + ├── MAIN_LOG = pos.log + │ (appended: timestamp + command + logfile + exit code) + │ + └── exit with command's exit code +``` + +--- + +## 6. `pos-vbox` Lifecycle + +``` +create lab1 + │ + ├── docker run -d --name lab1 + │ --label linux_post_install.vbox=true + │ [--volume $PWD:/workspace] ← --dir . + │ image: ubuntu:latest sleep infinity + │ + ├── "Enter now? [Y/n]" + │ ├── Y → docker exec -it lab1 bash + │ └── n → exit + │ + └── Container is labeled → ls filters by label + +enter lab1 + │ + ├── docker start lab1 ← auto-starts if stopped + ├── Detect bind mount from labels + └── docker exec -it lab1 bash + +ls + └── docker ps -a --filter label=linux_post_install.vbox=true +```