353 lines
13 KiB
Markdown
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
|
|
```
|