Dateien nach "docker/syncer" hochladen

This commit is contained in:
2026-08-26 15:18:52 +02:00
parent de45ca2260
commit 27ecf5d4ba
5 changed files with 961 additions and 0 deletions
+191
View File
@@ -0,0 +1,191 @@
#!/bin/bash
# Synct die Paket-Whitelist aus Git (oder aus einer lokal gemounteten Datei)
# und laedt die selektierten Pakete aus den jeweils angegebenen Fremd-Repos.
# Erzeugt anschliessend RPM- und - sofern der Generator vorhanden ist -
# AppStream-Metadaten.
set -euo pipefail
# createrepo_c uebernimmt die umask des Aufrufers. Ohne "umask 022" kann
# repodata/ mit 0700 landen; der nginx-Worker (User nginx) kommt dann nicht
# hinein und liefert 403 - bzw. 404, falls die nginx-Config try_files nutzt.
umask 022
# --- Pfade ----------------------------------------------------------------
# Muessen zu den Volumes in docker-compose.yml passen:
# repo-data -> /srv/repo (im nginx-Container: /usr/share/nginx/html/repo)
# sync-cache -> /var/cache/rpm-mirror-sync
# Daraus ergibt sich die oeffentliche URL: <host>/repo/pkgs/repodata/repomd.xml
WORK_DIR="${WORK_DIR:-/var/cache/rpm-mirror-sync}"
REPO_ROOT="${REPO_ROOT:-/srv/repo}"
DEST="$REPO_ROOT/pkgs"
CONFIG_DIR="$WORK_DIR/config"
LOCAL_PACKAGES_FILE=/config/packages.yaml
TMP_REPO_DIR=/etc/yum.repos.d
LOCKFILE="$WORK_DIR/sync.lock"
APPSTREAM_GEN="${APPSTREAM_GEN:-/usr/local/bin/appstream-gen.py}"
mkdir -p "$WORK_DIR" "$DEST"
exec 200>"$LOCKFILE"
if ! flock -n 200; then
echo "[sync] Ein anderer Sync-Lauf ist bereits aktiv, breche ab."
exit 0
fi
echo "[sync] $(date -Iseconds) Starte Sync-Lauf"
# --- 1. Whitelist besorgen ------------------------------------------------
# Eine gemountete /config/packages.yaml hat Vorrang. Nur wenn sie fehlt,
# wird SOURCES_GIT_REPO gebraucht.
if [ -f "$LOCAL_PACKAGES_FILE" ]; then
PACKAGES_FILE="$LOCAL_PACKAGES_FILE"
echo "[sync] Nutze lokal gemountete $PACKAGES_FILE"
else
: "${SOURCES_GIT_REPO:?weder SOURCES_GIT_REPO gesetzt noch /config/packages.yaml gemountet}"
CONFIG_REPO_BRANCH="${CONFIG_REPO_BRANCH:-main}"
PACKAGES_FILE="$CONFIG_DIR/packages.yaml"
if [ -n "${GIT_SSH_KEY_PATH:-}" ] && [ -f "$GIT_SSH_KEY_PATH" ]; then
export GIT_SSH_COMMAND="ssh -i ${GIT_SSH_KEY_PATH} -o StrictHostKeyChecking=accept-new"
fi
if [ -d "$CONFIG_DIR/.git" ]; then
git -C "$CONFIG_DIR" fetch --depth=1 origin "$CONFIG_REPO_BRANCH"
git -C "$CONFIG_DIR" reset --hard "origin/$CONFIG_REPO_BRANCH"
else
# Reste eines abgebrochenen Clones wegraeumen, sonst scheitert git clone.
rm -rf "$CONFIG_DIR"
git clone --depth=1 --branch "$CONFIG_REPO_BRANCH" "$SOURCES_GIT_REPO" "$CONFIG_DIR"
fi
fi
if [ ! -f "$PACKAGES_FILE" ]; then
echo "[sync] FEHLER: $PACKAGES_FILE nicht gefunden."
exit 1
fi
# --- 2. Pro Quelle: temporaeres Repo aktivieren, Pakete gezielt ziehen -----
source_count=$(yq -o=json '.sources | length' "$PACKAGES_FILE")
download_failed=0
for i in $(seq 0 $((source_count - 1))); do
src=$(yq -o=json ".sources[$i]" "$PACKAGES_FILE")
name=$(echo "$src" | jq -r '.name')
baseurl=$(echo "$src" | jq -r '.baseurl')
gpgkey=$(echo "$src" | jq -r '.gpgkey // empty')
# Standard: false. Nur bei echten Fremd-Repos aktivieren, deren
# Abhaengigkeiten die Clients nicht ueber ihre Basis-Repos bekommen.
resolve_deps=$(echo "$src" | jq -r '.resolve_deps // false')
# Paketeintraege koennen Strings ODER Mappings mit Metadaten sein.
mapfile -t packages < <(
echo "$src" | jq -r '.packages[] | if type == "string" then . else .name end'
)
if [ "${#packages[@]}" -eq 0 ]; then
echo "[sync] Quelle '$name': keine Pakete gelistet, ueberspringe."
continue
fi
echo "[sync] Quelle '$name': ${#packages[@]} Paket(e) -> $baseurl"
repofile="$TMP_REPO_DIR/tmp-${name}.repo"
{
echo "[tmp-${name}]"
echo "name=${name}"
echo "baseurl=${baseurl}"
echo "enabled=0"
if [ -n "$gpgkey" ]; then
echo "gpgcheck=1"
echo "gpgkey=${gpgkey}"
else
echo "gpgcheck=0"
fi
} > "$repofile"
# Die Basis-Repos des Containers bleiben aktiviert, damit dnf
# Abhaengigkeiten wie glibc oder libstdc++ ueberhaupt aufloesen kann.
# Ohne sie scheitert bereits die Aufloesung, nicht erst der Download.
dl_args=(--destdir="$DEST" --enablerepo="tmp-${name}")
if [ "$resolve_deps" = "true" ]; then
echo "[sync] Quelle '$name': Abhaengigkeiten werden mitgespiegelt"
# Bewusst OHNE --alldeps: bereits im Container installierte Pakete
# (glibc & Co.) haben die Clients ohnehin und muessen nicht ins Repo.
dl_args+=(--resolve)
fi
if ! dnf download "${dl_args[@]}" "${packages[@]}"; then
echo "[sync] WARNUNG: Download fuer Quelle '$name' fehlgeschlagen."
download_failed=1
fi
rm -f "$repofile"
done
# --- 3. Alte Paketversionen aufraeumen ------------------------------------
# repomanage braucht bereits vorhandene Metadaten. Beim allerersten Lauf
# gibt es noch keine, deshalb der Existenztest.
if [ -f "$DEST/repodata/repomd.xml" ]; then
echo "[sync] Raeume veraltete Paketversionen auf"
if ! dnf repomanage --old "$DEST" | xargs -r rm -f; then
echo "[sync] WARNUNG: repomanage fehlgeschlagen, ueberspringe Aufraeumen."
fi
else
echo "[sync] Erster Lauf, kein Aufraeumen noetig."
fi
# --- 4. RPM-Metadaten neu erzeugen ----------------------------------------
echo "[sync] Aktualisiere Repo-Metadaten"
createrepo_c --update "$DEST"
# --- 5. AppStream-Katalog erzeugen und einhaengen --------------------------
# Ohne diesen Schritt sind die Pakete zwar per dnf installierbar, tauchen
# aber weder in Discover noch in GNOME Software auf. Der Generator ist
# optional: fehlt er, laeuft der Sync trotzdem sauber durch.
if [ -x "$APPSTREAM_GEN" ]; then
echo "[sync] Erzeuge AppStream-Katalog"
ASWORK=$(mktemp -d)
trap 'rm -rf "$ASWORK"' EXIT
# Welche Pakete liegen tatsaechlich im Repo? Verhindert, dass Discover
# Eintraege anzeigt, deren RPM gar nicht da ist.
if compgen -G "$DEST"/*.rpm > /dev/null; then
rpm -qp --qf '%{NAME}\n' "$DEST"/*.rpm 2>/dev/null \
| sort -u > "$ASWORK/vorhanden.txt"
else
echo "[sync] WARNUNG: Keine RPMs in $DEST gefunden."
: > "$ASWORK/vorhanden.txt"
fi
python3 "$APPSTREAM_GEN" "$PACKAGES_FILE" \
--output "$ASWORK/appstream.xml.gz" \
--available-packages "$ASWORK/vorhanden.txt"
# Optionale Validierung, falls appstreamcli im Image vorhanden ist.
if command -v appstreamcli > /dev/null 2>&1; then
if ! appstreamcli validate --no-net "$ASWORK/appstream.xml.gz"; then
echo "[sync] WARNUNG: AppStream-Katalog hat Validierungshinweise."
fi
fi
# modifyrepo_c MUSS nach createrepo_c laufen, da createrepo_c die
# repomd.xml komplett neu schreibt.
modifyrepo_c --mdtype=appstream "$ASWORK/appstream.xml.gz" "$DEST/repodata/"
else
echo "[sync] HINWEIS: $APPSTREAM_GEN nicht vorhanden - AppStream wird uebersprungen."
fi
# --- 6. Leserechte fuer den Webserver sicherstellen ------------------------
# a+rX = Leserecht auf alles, Betretungsrecht nur auf Verzeichnisse.
chmod -R a+rX "$REPO_ROOT"
if [ "$download_failed" -ne 0 ]; then
echo "[sync] $(date -Iseconds) Sync-Lauf mit Fehlern abgeschlossen"
exit 1
fi
echo "[sync] $(date -Iseconds) Sync-Lauf abgeschlossen"