diff --git a/site/profiles/templates/reposync/autopromoter.erb b/site/profiles/templates/reposync/autopromoter.erb index 0bf995f..ea000b6 100644 --- a/site/profiles/templates/reposync/autopromoter.erb +++ b/site/profiles/templates/reposync/autopromoter.erb @@ -1,33 +1,72 @@ #!/usr/bin/env bash +set -euo pipefail + +: "${DRY_RUN:=}" # set DRY_RUN=1 to preview deletions + +log() { printf '[%(%F %T)T] %s\n' -1 "$*" >&2; } # Function to create symlink for snapshots create_symlink() { - local osname="$1" - local release="$2" - local repository="$3" - local basepath="$4" - local label="$5" # 'monthly', 'weekly', or 'daily' - local date_format="$6" # Date format for finding the snapshot + local osname="$1" # e.g. almalinux + local release="$2" # e.g. 9.6 + local repository="$3" # e.g. appstream + local basepath="$4" # e.g. /shared/apps/packagerepo + local label="$5" # monthly|weekly|daily + local date_value="$6" # YYYYMMDD for the snapshot to promote - # The path where snapshots are stored - local snap_path="${basepath}/snap/${osname}/${release}/${repository}-${date_format}" - - # The target path for the symlink + local snap_path="${basepath}/snap/${osname}/${release}/${repository}-${date_value}" local symlink_target="${basepath}/snap/${osname}/${release}/${repository}-${label}" - # Check if the source directory exists if [[ -d "$snap_path" ]]; then - # Create the symlink, overwrite if it already exists ln -sfn "$snap_path" "$symlink_target" - echo "Symlink created for $snap_path -> $symlink_target" + log "Symlink set: ${symlink_target} -> ${snap_path}" + return 0 else - echo "Snapshot path does not exist: $snap_path" + log "Snapshot path does not exist: $snap_path" return 1 fi } +# Cleanup snapshot directories older than a cutoff date (YYYYMMDD) +cleanup_older_than_monthly() { + local osname="$1" + local release="$2" + local repository="$3" + local basepath="$4" + local cutoff_date="$5" # newly promoted monthly date, YYYYMMDD + + local root="${basepath}/snap/${osname}/${release}" + local pattern="${repository}-"[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9] + + shopt -s nullglob + for dir in "${root}"/${pattern}; do + # Skip symlinks and non-directories + [[ -L "$dir" ]] && continue + [[ -d "$dir" ]] || continue + + # Extract the date suffix + local name base datepart + name="$(basename -- "$dir")" + base="${name%-????????}" # remove last 8 chars + datepart="${name#${base}-}" # after "-" + + # Only act on valid YYYYMMDD dates + if [[ "$datepart" =~ ^[0-9]{8}$ ]]; then + if [[ "$datepart" -lt "$cutoff_date" ]]; then + if [[ -n "${DRY_RUN}" ]]; then + log "[DRY_RUN] Would remove: $dir" + else + log "Removing: $dir" + rm -rf --one-file-system -- "$dir" + fi + fi + fi + done + shopt -u nullglob +} + # Determine which snapshot to promote based on the passed argument -case "$1" in +case "${1:-}" in monthly) promote_date=$(date --date="$(date +%Y%m01) -1 month" +%Y%m%d) ;; @@ -43,11 +82,26 @@ case "$1" in ;; esac -# Call the function with appropriate arguments -# Iterate over the repositories to create symlinks for each +label="$1" + +# Process each repo conf for conf in /etc/reposync/conf.d/*.conf; do + # shellcheck disable=SC1090 source "$conf" - # Create symlink based on the provided argument - create_symlink "$OSNAME" "$RELEASE" "$REPOSITORY" "$BASEPATH" "$1" "$promote_date" + # Expecting these vars in the conf: OSNAME, RELEASE, REPOSITORY, BASEPATH + : "${OSNAME:?missing OSNAME in $conf}" + : "${RELEASE:?missing RELEASE in $conf}" + : "${REPOSITORY:?missing REPOSITORY in $conf}" + : "${BASEPATH:?missing BASEPATH in $conf}" + + # 1) Promote the symlink for this label + if create_symlink "$OSNAME" "$RELEASE" "$REPOSITORY" "$BASEPATH" "$label" "$promote_date"; then + # 2) If monthly, clean up older snapshot dirs for this repo + if [[ "$label" == "monthly" ]]; then + cleanup_older_than_monthly "$OSNAME" "$RELEASE" "$REPOSITORY" "$BASEPATH" "$promote_date" + fi + else + log "Skipping cleanup for ${OSNAME}/${RELEASE}/${REPOSITORY} due to missing ${REPOSITORY}-${promote_date}" + fi done