katalon-cli 0.2.1__tar.gz → 0.3.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {katalon_cli-0.2.1 → katalon_cli-0.3.1}/PKG-INFO +26 -1
- {katalon_cli-0.2.1 → katalon_cli-0.3.1}/README.md +25 -0
- {katalon_cli-0.2.1 → katalon_cli-0.3.1}/pyproject.toml +1 -1
- {katalon_cli-0.2.1 → katalon_cli-0.3.1}/pyproject.toml.orig +1 -1
- {katalon_cli-0.2.1 → katalon_cli-0.3.1}/src/katalon_cli/core/checks.py +2 -0
- {katalon_cli-0.2.1 → katalon_cli-0.3.1}/src/katalon_cli/main.py +45 -0
- {katalon_cli-0.2.1 → katalon_cli-0.3.1}/src/katalon_cli/templates/compose.yaml.j2 +28 -3
- {katalon_cli-0.2.1 → katalon_cli-0.3.1}/src/katalon_cli/templates/nginx.conf.j2 +18 -0
- {katalon_cli-0.2.1 → katalon_cli-0.3.1}/src/katalon_cli/__init__.py +0 -0
- {katalon_cli-0.2.1 → katalon_cli-0.3.1}/src/katalon_cli/core/__init__.py +0 -0
- {katalon_cli-0.2.1 → katalon_cli-0.3.1}/src/katalon_cli/core/backup.py +0 -0
- {katalon_cli-0.2.1 → katalon_cli-0.3.1}/src/katalon_cli/core/compose_gen.py +0 -0
- {katalon_cli-0.2.1 → katalon_cli-0.3.1}/src/katalon_cli/core/docker.py +0 -0
- {katalon_cli-0.2.1 → katalon_cli-0.3.1}/src/katalon_cli/core/paths.py +0 -0
- {katalon_cli-0.2.1 → katalon_cli-0.3.1}/src/katalon_cli/core/permissions.py +0 -0
- {katalon_cli-0.2.1 → katalon_cli-0.3.1}/src/katalon_cli/core/reindex.py +0 -0
- {katalon_cli-0.2.1 → katalon_cli-0.3.1}/src/katalon_cli/core/release.py +0 -0
- {katalon_cli-0.2.1 → katalon_cli-0.3.1}/src/katalon_cli/core/selfupdate.py +0 -0
- {katalon_cli-0.2.1 → katalon_cli-0.3.1}/src/katalon_cli/core/state.py +0 -0
- {katalon_cli-0.2.1 → katalon_cli-0.3.1}/src/katalon_cli/py.typed +0 -0
- {katalon_cli-0.2.1 → katalon_cli-0.3.1}/src/katalon_cli/templates/Caddyfile.j2 +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: katalon-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: Installer & Updater CLI für Katalon Production-Instanzen
|
|
5
5
|
Author: Karl Krägelin
|
|
6
6
|
Author-email: Karl Krägelin <karlkraegelin@gmail.com>
|
|
@@ -83,6 +83,31 @@ unter `MEDIA_ROOT`, die noch einem anderen Eigentümer gehören. Dateiinhalte we
|
|
|
83
83
|
verändert; ein erneuter Lauf ändert nichts. `katalon doctor` meldet ein nicht beschreibbares
|
|
84
84
|
`MEDIA_ROOT`, bevor Uploads mit HTTP 500 scheitern.
|
|
85
85
|
|
|
86
|
+
## Bild-Cache (Cantaloupe)
|
|
87
|
+
|
|
88
|
+
Vorschaubilder und Viewer-Kacheln rechnet Cantaloupe aus den Originalen und legt sie im
|
|
89
|
+
Instanzverzeichnis unter `cantaloupe-cache/` ab (abweichend: `CANTALOUPE_CACHE_DIR` in `.env`).
|
|
90
|
+
Der Cache übersteht Neustarts und Updates; ein kurzlebiger Init-Container übergibt das
|
|
91
|
+
Verzeichnis vor jedem Start dem Cantaloupe-User. Abgelaufene Derivate
|
|
92
|
+
(`CANTALOUPE_CACHE_SERVER_DERIVATIVE_TTL_SECONDS`, Standard 30 Tage) löscht Cantaloupe selbst.
|
|
93
|
+
|
|
94
|
+
Eine Größenbegrenzung kennt Cantaloupe nicht. Als Richtwert ~25 KB pro Vorschaubild plus
|
|
95
|
+
Kacheln der aufgerufenen Detailansichten einplanen; wer den Platz hart begrenzen muss, legt
|
|
96
|
+
`CANTALOUPE_CACHE_DIR` auf ein eigenes Dateisystem bzw. Quota-Verzeichnis. Hosts ohne
|
|
97
|
+
Plattenplatz nutzen mit `CANTALOUPE_FILESYSTEMCACHE_PATHNAME=/tmpfs/cache` einen RAM-Cache
|
|
98
|
+
(`CANTALOUPE_CACHE_TMPFS_SIZE`, Standard `512m`), der nach jedem Neustart leer ist.
|
|
99
|
+
|
|
100
|
+
Vorschaubilder lassen sich vorab berechnen, damit schon der erste Aufruf der Trefferliste
|
|
101
|
+
schnell ist: `katalon media warm-thumbnails` (Hauptbilder zuerst, dann die übrigen; mit
|
|
102
|
+
`--primary-only` nur Hauptbilder, `--status` zeigt den Fortschritt). Der Lauf arbeitet im
|
|
103
|
+
Worker in kleinen Paketen, belegt höchstens `THUMBNAIL_WARM_CONCURRENCY` (Standard 3)
|
|
104
|
+
Cantaloupe-Kerne und setzt nach einer Unterbrechung beim letzten Stand fort. Neu hochgeladene
|
|
105
|
+
Bilder werden automatisch vorberechnet.
|
|
106
|
+
|
|
107
|
+
Bestehende Instanzen stellt `katalon update` automatisch um (neue `compose.yaml`); der bisherige
|
|
108
|
+
RAM-Cache entfällt dabei. Releases, die eine neuere CLI voraussetzen, bricht `katalon update`
|
|
109
|
+
mit einem Hinweis auf `uv tool upgrade katalon-cli` ab.
|
|
110
|
+
|
|
86
111
|
## Domain und HTTPS
|
|
87
112
|
|
|
88
113
|
Für eine lokale Installation bleibt `http://localhost` mit TLS-Modus `none` der Standard.
|
|
@@ -69,6 +69,31 @@ unter `MEDIA_ROOT`, die noch einem anderen Eigentümer gehören. Dateiinhalte we
|
|
|
69
69
|
verändert; ein erneuter Lauf ändert nichts. `katalon doctor` meldet ein nicht beschreibbares
|
|
70
70
|
`MEDIA_ROOT`, bevor Uploads mit HTTP 500 scheitern.
|
|
71
71
|
|
|
72
|
+
## Bild-Cache (Cantaloupe)
|
|
73
|
+
|
|
74
|
+
Vorschaubilder und Viewer-Kacheln rechnet Cantaloupe aus den Originalen und legt sie im
|
|
75
|
+
Instanzverzeichnis unter `cantaloupe-cache/` ab (abweichend: `CANTALOUPE_CACHE_DIR` in `.env`).
|
|
76
|
+
Der Cache übersteht Neustarts und Updates; ein kurzlebiger Init-Container übergibt das
|
|
77
|
+
Verzeichnis vor jedem Start dem Cantaloupe-User. Abgelaufene Derivate
|
|
78
|
+
(`CANTALOUPE_CACHE_SERVER_DERIVATIVE_TTL_SECONDS`, Standard 30 Tage) löscht Cantaloupe selbst.
|
|
79
|
+
|
|
80
|
+
Eine Größenbegrenzung kennt Cantaloupe nicht. Als Richtwert ~25 KB pro Vorschaubild plus
|
|
81
|
+
Kacheln der aufgerufenen Detailansichten einplanen; wer den Platz hart begrenzen muss, legt
|
|
82
|
+
`CANTALOUPE_CACHE_DIR` auf ein eigenes Dateisystem bzw. Quota-Verzeichnis. Hosts ohne
|
|
83
|
+
Plattenplatz nutzen mit `CANTALOUPE_FILESYSTEMCACHE_PATHNAME=/tmpfs/cache` einen RAM-Cache
|
|
84
|
+
(`CANTALOUPE_CACHE_TMPFS_SIZE`, Standard `512m`), der nach jedem Neustart leer ist.
|
|
85
|
+
|
|
86
|
+
Vorschaubilder lassen sich vorab berechnen, damit schon der erste Aufruf der Trefferliste
|
|
87
|
+
schnell ist: `katalon media warm-thumbnails` (Hauptbilder zuerst, dann die übrigen; mit
|
|
88
|
+
`--primary-only` nur Hauptbilder, `--status` zeigt den Fortschritt). Der Lauf arbeitet im
|
|
89
|
+
Worker in kleinen Paketen, belegt höchstens `THUMBNAIL_WARM_CONCURRENCY` (Standard 3)
|
|
90
|
+
Cantaloupe-Kerne und setzt nach einer Unterbrechung beim letzten Stand fort. Neu hochgeladene
|
|
91
|
+
Bilder werden automatisch vorberechnet.
|
|
92
|
+
|
|
93
|
+
Bestehende Instanzen stellt `katalon update` automatisch um (neue `compose.yaml`); der bisherige
|
|
94
|
+
RAM-Cache entfällt dabei. Releases, die eine neuere CLI voraussetzen, bricht `katalon update`
|
|
95
|
+
mit einem Hinweis auf `uv tool upgrade katalon-cli` ab.
|
|
96
|
+
|
|
72
97
|
## Domain und HTTPS
|
|
73
98
|
|
|
74
99
|
Für eine lokale Installation bleibt `http://localhost` mit TLS-Modus `none` der Standard.
|
|
@@ -26,6 +26,8 @@ def check_docker() -> CheckResult:
|
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
def check_compose() -> CheckResult:
|
|
29
|
+
if not shutil.which("docker"):
|
|
30
|
+
return CheckResult("Docker Compose", False, "Docker fehlt")
|
|
29
31
|
probe = subprocess.run(["docker", "compose", "version"], capture_output=True, text=True)
|
|
30
32
|
if probe.returncode == 0:
|
|
31
33
|
return CheckResult("Docker Compose", True, probe.stdout.strip())
|
|
@@ -456,6 +456,21 @@ def _media_root(dir: Path) -> str:
|
|
|
456
456
|
return str(path if path.is_absolute() else dir / path)
|
|
457
457
|
|
|
458
458
|
|
|
459
|
+
def _require_installer_version(minimum: str) -> None:
|
|
460
|
+
"""Bricht ab, wenn das Release eine neuere CLI braucht (z. B. neues Compose-Template).
|
|
461
|
+
|
|
462
|
+
Sonst würde eine alte CLI ihr altes compose.yaml-Template schreiben und das Release
|
|
463
|
+
liefe ohne die Topologie, für die es gebaut ist."""
|
|
464
|
+
current = version("katalon-cli")
|
|
465
|
+
if selfupdate.is_newer(minimum, current):
|
|
466
|
+
console.print(
|
|
467
|
+
f"[red]✖ Dieses Release braucht katalon-cli ≥ {minimum} (installiert: {current}).[/]\n"
|
|
468
|
+
" Zuerst aktualisieren: [bold]uv tool upgrade katalon-cli[/], dann erneut "
|
|
469
|
+
"[bold]katalon update[/]."
|
|
470
|
+
)
|
|
471
|
+
raise typer.Exit(1)
|
|
472
|
+
|
|
473
|
+
|
|
459
474
|
def _ensure_media_permissions(dir: Path) -> bool:
|
|
460
475
|
"""Macht MEDIA_ROOT für den Container-User von API/Worker beschreibbar (idempotent).
|
|
461
476
|
|
|
@@ -475,6 +490,9 @@ def _ensure_media_permissions(dir: Path) -> bool:
|
|
|
475
490
|
|
|
476
491
|
|
|
477
492
|
def _start(dir: Path, show_credentials: bool = False) -> None:
|
|
493
|
+
# Ohne capture: Fortschritt sichtbar, sonst wirkt der erste Image-Pull wie ein Hänger.
|
|
494
|
+
console.print("Lade Images (beim ersten Start einige Minuten) …")
|
|
495
|
+
docker.compose(dir, "pull")
|
|
478
496
|
_ensure_media_permissions(dir)
|
|
479
497
|
docker.compose(dir, "up", "-d")
|
|
480
498
|
console.print("[green]✔[/] Stack gestartet.")
|
|
@@ -559,6 +577,32 @@ def manage(
|
|
|
559
577
|
raise typer.Exit(result.returncode)
|
|
560
578
|
|
|
561
579
|
|
|
580
|
+
media_app = typer.Typer(no_args_is_help=True, help="Medien: Vorschaubilder vorberechnen.")
|
|
581
|
+
app.add_typer(media_app, name="media")
|
|
582
|
+
|
|
583
|
+
|
|
584
|
+
@media_app.command("warm-thumbnails")
|
|
585
|
+
def media_warm_thumbnails(
|
|
586
|
+
dir: Path | None = typer.Option(None, "--dir"),
|
|
587
|
+
primary_only: bool = typer.Option(False, "--primary-only", help="Nur das Hauptbild jedes Objekts."),
|
|
588
|
+
restart: bool = typer.Option(False, "--restart", help="Von vorn beginnen statt fortsetzen."),
|
|
589
|
+
status: bool = typer.Option(False, "--status", help="Nur den Fortschritt anzeigen."),
|
|
590
|
+
):
|
|
591
|
+
"""Vorschaubilder im Cantaloupe-Cache vorberechnen (läuft im Worker, fortsetzbar).
|
|
592
|
+
|
|
593
|
+
Sinnvoll nach Installation, Massenimport oder Umstellung des Bild-Caches."""
|
|
594
|
+
dir = instance_dir_or_raise(dir)
|
|
595
|
+
args = ["warm-thumbnails"]
|
|
596
|
+
if primary_only:
|
|
597
|
+
args.append("--primary-only")
|
|
598
|
+
if restart:
|
|
599
|
+
args.append("--restart")
|
|
600
|
+
if status:
|
|
601
|
+
args.append("--status")
|
|
602
|
+
result = docker.compose(dir, "exec", "api", "katalon-manage", *args, check=False)
|
|
603
|
+
raise typer.Exit(result.returncode)
|
|
604
|
+
|
|
605
|
+
|
|
562
606
|
def _ensure_db_running(dir: Path, yes: bool = False) -> None:
|
|
563
607
|
if docker.is_running(dir, "db"):
|
|
564
608
|
return
|
|
@@ -630,6 +674,7 @@ def check_updates(dir: Path | None = typer.Option(None, "--dir")):
|
|
|
630
674
|
if meta.version == state.version:
|
|
631
675
|
console.print(f"[green]✔[/] Bereits auf aktueller Version {meta.version}.")
|
|
632
676
|
return
|
|
677
|
+
_require_installer_version(meta.minimum_installer_version)
|
|
633
678
|
console.print(f"Update verfügbar: [bold]{state.version}[/] → [bold]{meta.version}[/]")
|
|
634
679
|
|
|
635
680
|
|
|
@@ -39,15 +39,31 @@ services:
|
|
|
39
39
|
timeout: 10s
|
|
40
40
|
retries: 20
|
|
41
41
|
|
|
42
|
+
# Legt den Derivat-Cache an und übergibt ihn dem Cantaloupe-User des Images.
|
|
43
|
+
# Ändert nur Einträge mit falschem Eigentümer (idempotent, schnell bei vollem Cache).
|
|
44
|
+
cantaloupe-cache-init:
|
|
45
|
+
image: islandora/cantaloupe:main
|
|
46
|
+
user: "0:0"
|
|
47
|
+
entrypoint: ["sh", "-c", "mkdir -p /data/cache && find /data ! -user cantaloupe -exec chown cantaloupe:cantaloupe {} +"]
|
|
48
|
+
volumes:
|
|
49
|
+
- ${CANTALOUPE_CACHE_DIR:-./cantaloupe-cache}:/data
|
|
50
|
+
restart: "no"
|
|
51
|
+
|
|
42
52
|
cantaloupe:
|
|
43
53
|
image: islandora/cantaloupe:main
|
|
44
54
|
restart: unless-stopped
|
|
45
55
|
volumes:
|
|
46
56
|
- ${MEDIA_ROOT:-./media}:/var/lib/cantaloupe/images:ro
|
|
57
|
+
# Derivat-Cache auf Platte, übersteht Neustarts. Ohne Plattenplatz:
|
|
58
|
+
# CANTALOUPE_FILESYSTEMCACHE_PATHNAME=/tmpfs/cache in .env (RAM, leer nach Neustart).
|
|
59
|
+
- ${CANTALOUPE_CACHE_DIR:-./cantaloupe-cache}:/data
|
|
47
60
|
- type: tmpfs
|
|
48
|
-
target: /
|
|
61
|
+
target: /tmpfs
|
|
49
62
|
tmpfs:
|
|
50
63
|
size: ${CANTALOUPE_CACHE_TMPFS_SIZE:-512m}
|
|
64
|
+
mode: 1023 # = 0o1777 (Compose liest den Wert dezimal)
|
|
65
|
+
depends_on:
|
|
66
|
+
cantaloupe-cache-init: { condition: service_completed_successfully }
|
|
51
67
|
environment:
|
|
52
68
|
CANTALOUPE_SOURCE_STATIC: FilesystemSource
|
|
53
69
|
CANTALOUPE_FILESYSTEMSOURCE_LOOKUP_STRATEGY: BasicLookupStrategy
|
|
@@ -55,10 +71,19 @@ services:
|
|
|
55
71
|
CANTALOUPE_BASE_URI: ${CANTALOUPE_PUBLIC_URL:-http://localhost}
|
|
56
72
|
CANTALOUPE_CACHE_SERVER_DERIVATIVE: FilesystemCache
|
|
57
73
|
CANTALOUPE_CACHE_SERVER_DERIVATIVE_ENABLED: "true"
|
|
58
|
-
CANTALOUPE_FILESYSTEMCACHE_PATHNAME: /
|
|
74
|
+
CANTALOUPE_FILESYSTEMCACHE_PATHNAME: ${CANTALOUPE_FILESYSTEMCACHE_PATHNAME:-/data/cache}
|
|
75
|
+
# Der Cache-Worker löscht Derivate älter als die TTL; ohne ihn wächst der Cache unbegrenzt.
|
|
76
|
+
CANTALOUPE_CACHE_SERVER_WORKER_ENABLED: "true"
|
|
77
|
+
CANTALOUPE_CACHE_SERVER_DERIVATIVE_TTL_SECONDS: ${CANTALOUPE_CACHE_SERVER_DERIVATIVE_TTL_SECONDS:-2592000}
|
|
59
78
|
CANTALOUPE_PROCESSOR_MANUALSELECTIONSTRATEGY_JPG: Java2dProcessor
|
|
79
|
+
# Fallback ohne nginx davor: nie "public". nginx setzt Cache-Control für /iiif/
|
|
80
|
+
# nach Sichtbarkeit (X-Media-Visibility aus /v1/media/_authorize).
|
|
81
|
+
CANTALOUPE_CACHE_CLIENT_PUBLIC: "false"
|
|
82
|
+
CANTALOUPE_CACHE_CLIENT_PRIVATE: "true"
|
|
60
83
|
healthcheck:
|
|
61
|
-
|
|
84
|
+
# Prüft neben der Erreichbarkeit, dass der Cantaloupe-Prozess in seinen Cache
|
|
85
|
+
# schreiben kann — sonst liefert er Bilder mit 0 Bytes bei HTTP 200.
|
|
86
|
+
test: ["CMD-SHELL", "curl -sf http://localhost:8182/iiif/3 && runuser -u cantaloupe -- sh -c 'd=$${CANTALOUPE_FILESYSTEMCACHE_PATHNAME:-/data/cache}; mkdir -p \"$$d\" && touch \"$$d/.healthcheck\" && rm -f \"$$d/.healthcheck\"'"]
|
|
62
87
|
interval: 10s
|
|
63
88
|
timeout: 5s
|
|
64
89
|
start_period: 300s
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
resolver 127.0.0.11 valid=10s ipv6=off;
|
|
2
2
|
|
|
3
|
+
# Cache-Control for /iiif/ from the media's visibility (set by /v1/media/_authorize via
|
|
4
|
+
# auth_request_set): shared caches (CDN, proxies) may keep only what anonymous
|
|
5
|
+
# visitors may see; derivatives of internal media stay in the requesting browser.
|
|
6
|
+
map $media_visibility $iiif_cache_control {
|
|
7
|
+
public "public, max-age=2592000";
|
|
8
|
+
default "private, max-age=86400";
|
|
9
|
+
}
|
|
10
|
+
|
|
3
11
|
server {
|
|
4
12
|
{% if tls_mode == "standalone" %}
|
|
5
13
|
listen 80;
|
|
@@ -73,12 +81,22 @@ server {
|
|
|
73
81
|
|
|
74
82
|
location /iiif/ {
|
|
75
83
|
auth_request /internal/media-authorize;
|
|
84
|
+
auth_request_set $media_visibility $upstream_http_x_media_visibility;
|
|
76
85
|
set $upstream_cantaloupe cantaloupe:8182;
|
|
77
86
|
proxy_pass http://$upstream_cantaloupe;
|
|
78
87
|
proxy_set_header Host $host;
|
|
79
88
|
proxy_set_header X-Real-IP $remote_addr;
|
|
80
89
|
proxy_read_timeout 300s;
|
|
81
90
|
proxy_buffering off;
|
|
91
|
+
# Cantaloupe marks every derivative public; decide by visibility instead.
|
|
92
|
+
proxy_hide_header Cache-Control;
|
|
93
|
+
add_header Cache-Control $iiif_cache_control;
|
|
94
|
+
# An add_header here drops the server-level ones: repeat them.
|
|
95
|
+
add_header Content-Security-Policy "default-src 'self'; base-uri 'self'; object-src 'none'; frame-ancestors 'self'; form-action 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; font-src 'self' data:; img-src 'self' data: blob: https:; media-src 'self' blob: https:; connect-src 'self' https:; frame-src 'self' https://www.openstreetmap.org; worker-src 'self' blob:" always;
|
|
96
|
+
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
|
97
|
+
add_header X-Content-Type-Options "nosniff" always;
|
|
98
|
+
add_header X-Frame-Options "SAMEORIGIN" always;
|
|
99
|
+
add_header Permissions-Policy "camera=(), geolocation=(), microphone=()" always;
|
|
82
100
|
}
|
|
83
101
|
|
|
84
102
|
location = /internal/media-authorize {
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|