Local mirror for CentOS Stream & EPEL in a container image
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

79 lines
3.3 KiB

#!/bin/bash
set -Eeuo pipefail
# The version of CentOS Stream to mirror.
declare CENTOS_VERSION="10"
declare EPEL_VERSION="${EPEL_VERSION:-${CENTOS_VERSION}}"
# Sync process configuration
declare IMAGE_BASE="localhost/mirrors/centos-stream-${CENTOS_VERSION}"
declare IMAGE_TAG="$(date -I)"
declare RSYNC_MIRROR="${RSYNC_MIRROR:-rsync://mirror.in2p3.fr}"
declare CENTOS_PATH="${CENTOS_PATH:-/pub/linux/centos-stream}"
declare EPEL_PATH="${EPEL_PATH:-/pub/epel}"
declare RSYNC_OPTS="-azH --progress --delete --exclude-from=${BASH_SOURCE[0]%/*}/rsync-excludes.txt"
# Pre-requisites
if ! rsync -V &>/dev/null; then
echo "rsync is required on the host to synchronize the repositories. Please install it and try again." >&2
exit 1
fi
##
## First stage: build the base image with the necessary tools to synchronize the repositories.
##
if ! podman image inspect "${IMAGE_BASE}:base" &>/dev/null; then
# Compute podman command line arguments
declare -a PODMAN_ARGS=()
PODMAN_ARGS+=( --file Containerfile.base )
PODMAN_ARGS+=( -t "${IMAGE_BASE}:base" )
podman build "${PODMAN_ARGS[@]}" .
fi
##
## Second stage: build the image with the synchronized repositories using buildah.
##
if ! podman image inspect "${IMAGE_BASE}:latest" &>/dev/null; then
podman tag "${IMAGE_BASE}:base" "${IMAGE_BASE}:latest"
fi
# TODO: Maybe let the user specify the Buildah container name to be able have different sessions running in parallel?
# Currently, the container name is deterministic to be able to resume a build if it fails or is interrupted.
# In that case, the synchronization will be resumed from the last successful step instead of starting from scratch.
# But, it is assumed that only one build per version of CentOS Stream is running at the same time to avoid conflicts on the container name.
BUILDAH_CONTAINER_NAME="buildah-sync-centos-${CENTOS_VERSION}"
if buildah inspect "$BUILDAH_CONTAINER_NAME" &>/dev/null; then
echo "Resuming build with existing Buildah container: ${BUILDAH_CONTAINER_NAME}"
else
# Create Buildah container from the base image.
echo "Creating Buildah container from ${IMAGE_BASE}:latest..."
BUILDAH_CONTAINER_NAME=$(buildah from --name="${BUILDAH_CONTAINER_NAME}" "${IMAGE_BASE}:latest")
fi
# Expect unprivileged buildah, so it is mandatory to run the sync script from an dedicated user namespace.
echo "Starting synchronization in a modified user namespace..."
export CENTOS_VERSION EPEL_VERSION RSYNC_MIRROR CENTOS_PATH EPEL_PATH RSYNC_OPTS
if [ $UID -eq 0 ]; then
function cleanup {
if [ -n "$container_to_umount" ]; then
buildah umount "$container_to_umount" || true
fi
}
trap cleanup EXIT
export BUILDAH_ROOT=$(buildah mount "$BUILDAH_CONTAINER_NAME")
container_to_umount="$BUILDAH_CONTAINER_NAME"
"${BASH_SOURCE[0]%/*}/sync.sh"
else
buildah unshare --mount=BUILDAH_ROOT="$BUILDAH_CONTAINER_NAME" "${BASH_SOURCE[0]%/*}/sync.sh"
fi
# Finalize the image
echo "Creating final image ${IMAGE_BASE} with tag ${IMAGE_TAG} + latest..."
buildah umount "$BUILDAH_CONTAINER_NAME"
container_to_umount="" # Unset the variable so that the cleanup function does not try to unmount it again.
buildah commit --quiet "$BUILDAH_CONTAINER_NAME" "${IMAGE_BASE}:${IMAGE_TAG}"
buildah tag "${IMAGE_BASE}:${IMAGE_TAG}" "${IMAGE_BASE}:latest"
buildah rm "$BUILDAH_CONTAINER_NAME"
echo "Build complete."