Files

353 lines
13 KiB
Markdown

# Algorithm Diagrams
---
## 1. Installation Flow
```
User runs: ./install.sh [--skip <phase>] [--steps <spec>] [--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/<name>/ │
│ .env │
│ │
│ SERVICE=xxx │
│ IMAGE_URL= │
│ SERVICEPORT= │
└────────┬───────────┘
│ merged on first "up"
┌────────────────────┐
│ Layer 3: Per-svc │
│ /srv/<service>/ │
│ .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 docker 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
```