Initial commit: llamacppctl – llama.cpp Docker server control CLI
Steuert einen llama.cpp-Server als Docker-Container: --start/--check/--stop/
--change/--chat, INI-Konfiguration (builtin defaults -> [default] ->
[model.<profile>] -> CLI), SSRF-gehärtete Prompt-Eingabe (Datei/HTTPS-URL),
File-Locking für --start/--change und ein OpenAI-kompatibler HTTP-Layer.
Enthält u. a.:
- Env-Var-Expansion in hf_home (hf_home = ${HF_HOME})
- konfigurierbares Chat-Antwortbudget (max_tokens/chat_temperature,
CLI: --max-tokens/--chat-temp); temperature defer an Server-Default
- DNS-Pinning gegen DNS-Rebinding bei URL-Quellen
- dry-run als nebenwirkungsfreie Vorschau (kein Lock/Removal/Modell-Check)
- 98 Tests (pytest)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
commit
3158d16f9b
32 changed files with 3912 additions and 0 deletions
152
README.md
Normal file
152
README.md
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
# llamacppctl
|
||||
|
||||
Ein einziges, sicherheitsgehärtetes CLI-Werkzeug zum Starten, Prüfen, Stoppen und
|
||||
Wechseln von `llama.cpp`-Server-Instanzen, die als Docker-Container laufen —
|
||||
inklusive einer SSRF-gehärteten Eingabeschicht für System- und User-Prompts aus
|
||||
Text, Datei oder Remote-URL.
|
||||
|
||||
`llamacppctl` ersetzt eine Sammlung einzelner Shell-Skripte
|
||||
(`start-llm-server.sh`, `status-llm-server.sh`, `switch-llm.sh`, …) durch ein
|
||||
einziges Python-Paket mit konsistenter Konfiguration, Locking und
|
||||
Fehlerbehandlung.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
tar xzf llamacppctl-installable.tar.gz
|
||||
cd llamacppctl
|
||||
python3 -m venv .venv
|
||||
source .venv/bin/activate
|
||||
pip install .
|
||||
```
|
||||
|
||||
Danach steht der Befehl `llamacppctl` innerhalb der aktivierten virtuellen
|
||||
Umgebung zur Verfügung. Für eine systemweite Installation (ohne venv):
|
||||
|
||||
```bash
|
||||
pip install --user .
|
||||
```
|
||||
|
||||
Voraussetzungen auf dem Zielsystem:
|
||||
|
||||
- Python >= 3.10
|
||||
- Docker (CLI + laufender Daemon), für `--start`/--check`/--stop`/--change`
|
||||
- Netzwerkzugriff auf den Container-Host-Port für `--chat`/--check`
|
||||
|
||||
`--print-effective-config` und `--dry-run` benötigen keinen laufenden Docker-Daemon
|
||||
für die reine Konfigurationsprüfung; `--start`/--check`/--stop`/--change` erfordern
|
||||
einen erreichbaren Docker-Daemon.
|
||||
|
||||
## Konfiguration
|
||||
|
||||
Kopiere `llama.cpp.config.example` nach `llama.cpp.config` und passe es an:
|
||||
|
||||
```bash
|
||||
cp llama.cpp.config.example llama.cpp.config
|
||||
```
|
||||
|
||||
Abschnittstypen:
|
||||
|
||||
- `[default]` — globale Defaults, überschreiben die eingebauten Fallback-Werte
|
||||
- `[model.<name>]` — ein Modell-Profil, ausgewählt über `--profile <name>`
|
||||
- `[prompt.<name>]` — ein System-Prompt-Profil, ausgewählt über
|
||||
`--system-prompt-profile <name>` (liefert nur einen *Fallback*-Systemprompt;
|
||||
ein explizites `-s/--system-file/--system-url` gewinnt immer)
|
||||
|
||||
**`container_name` ist Pflicht** und muss für jedes Profil, das parallel
|
||||
laufen soll, eindeutig sein — er ist der einzige Identitätsanker für
|
||||
Docker-Namensgebung, Locking (`--start`/`--change`) sowie
|
||||
`--stop`/`--check`-Ziel.
|
||||
|
||||
`hf_home` unterstützt Environment-Variablen und `~`, z. B. `hf_home = ${HF_HOME}`.
|
||||
|
||||
Das Chat-Antwortbudget ist ebenfalls konfigurierbar (wirkt auf `--chat` und die
|
||||
Antwort nach `--start`, nicht auf den Container): `max_tokens` (Default 2048 —
|
||||
für Reasoning-Modelle / lange Texte hochsetzen, sonst bricht die Antwort mitten
|
||||
im „Denken" ab und `content` bleibt leer) und `chat_temperature` (leer =
|
||||
Server-`temp` gilt). CLI-Overrides: `--max-tokens`, `--chat-temp`.
|
||||
|
||||
Auflösungsreihenfolge (niedrigste zu höchster Priorität):
|
||||
|
||||
1. Eingebaute Defaults
|
||||
2. `[default]`-Sektion
|
||||
3. `[model.<profile>]`-Sektion (falls `--profile` gesetzt)
|
||||
4. CLI-Overrides (`--image`, `--host-port`, …)
|
||||
|
||||
## Verwendung
|
||||
|
||||
```bash
|
||||
# Server starten
|
||||
llamacppctl --start --config llama.cpp.config --profile qwen35
|
||||
|
||||
# Nur den geplanten docker-run-Befehl anzeigen, nichts ausführen
|
||||
llamacppctl --start --config llama.cpp.config --profile qwen35 --dry-run
|
||||
|
||||
# Effektive Konfiguration als JSON ausgeben
|
||||
llamacppctl --print-effective-config --config llama.cpp.config --profile qwen35 --start
|
||||
|
||||
# Status prüfen
|
||||
llamacppctl --check --config llama.cpp.config --profile qwen35
|
||||
|
||||
# Server stoppen und Container entfernen
|
||||
llamacppctl --stop --config llama.cpp.config --profile qwen35
|
||||
|
||||
# Modell wechseln (stop, neu konfigurieren, restart) unter Lock-Schutz
|
||||
llamacppctl --change --config llama.cpp.config --profile deepseek
|
||||
|
||||
# Direkten Chat-Request an einen laufenden Server senden
|
||||
llamacppctl --chat --config llama.cpp.config --profile qwen35 \
|
||||
-s "Du antwortest kurz." -p "Was ist 2+2?"
|
||||
|
||||
# System-Prompt aus einer lokalen Datei, User-Prompt als Literal
|
||||
llamacppctl --start --config llama.cpp.config --profile qwen35 \
|
||||
--system-file ./prompts/coding.md -p "Refaktoriere diese Funktion."
|
||||
|
||||
# System-Prompt von einer HTTPS-URL (öffentliches, nicht-privates Ziel)
|
||||
llamacppctl --chat --config llama.cpp.config --profile qwen35 \
|
||||
--system-url https://example.com/prompts/system.txt -p "Hallo"
|
||||
```
|
||||
|
||||
Vollständige Optionsliste: `llamacppctl --help` oder die Manpage
|
||||
(`man/llamacppctl.1`, siehe unten).
|
||||
|
||||
## Sicherheitsmodell (Kurzfassung)
|
||||
|
||||
Für Details siehe [`docs/SECURITY_AND_OPERATIONS.md`](docs/SECURITY_AND_OPERATIONS.md).
|
||||
|
||||
- Alle Docker-Aufrufe laufen über `subprocess.run()` mit Argumentlisten —
|
||||
niemals über Shell-Strings, somit keine Shell-Injection-Fläche.
|
||||
- `--system-file`/--prompt-file` lesen ausschließlich reguläre Dateien,
|
||||
Größenlimit (`--max-input-bytes`, Default 1 MiB), UTF-8-Text erzwungen,
|
||||
Symlinks standardmäßig abgelehnt, per `--allow-symlinks` freischaltbar.
|
||||
- `--system-url`/--prompt-url` sind standardmäßig HTTPS-only, blockieren
|
||||
IP-Literale, private/loopback/link-local/reserved Adressbereiche sowie die
|
||||
Cloud-Metadata-IP `169.254.169.254`, verbieten eingebettete Zugangsdaten in
|
||||
der URL, erlauben standardmäßig keine Redirects (jeder Hop wird bei
|
||||
Aktivierung erneut validiert), erzwingen eine Content-Type-Allowlist und ein
|
||||
hartes Größenlimit sowohl über `Content-Length` als auch beim Streaming.
|
||||
- `container_name` ist verpflichtend und muss pro parallel betriebenem
|
||||
Profil eindeutig sein, um Docker-Namenskollisionen und ungewollte
|
||||
Container-Übernahmen zu verhindern.
|
||||
- `--start`/--change` nutzen echte Chat-Completions zum Readiness-Check
|
||||
(nicht nur einen offenen Port), um sicherzustellen, dass das Modell
|
||||
tatsächlich geladen und inferenzfähig ist.
|
||||
- `--change` verwendet eine exklusive, nicht-blockierende Dateisperre
|
||||
(`/tmp/llamacppctl.<container_name>.lock`), um parallele Änderungen am
|
||||
selben Container zu verhindern.
|
||||
|
||||
## Entwicklung / Tests
|
||||
|
||||
```bash
|
||||
pip install -e ".[dev]"
|
||||
pytest -q
|
||||
```
|
||||
|
||||
Die Test-Suite deckt die Prompt-Eingabeschicht (Datei- und URL-Quellen inkl.
|
||||
SSRF-Abwehr mit gemockter DNS-Auflösung), die Konfigurationsauflösung, die
|
||||
CLI-Validierung sowie Docker-/HTTP-Operationen (mit gemocktem `subprocess`
|
||||
bzw. `requests`) ab.
|
||||
|
||||
## Lizenz
|
||||
|
||||
MIT
|
||||
Loading…
Add table
Add a link
Reference in a new issue