#!/bin/bash -x # On container start, run an rsync to get a good copy of the tree. # Then execute rsyncd; we will start serving once the sync completes. # Then keep syncing in the background every 30m. # We keep the trees in a TMPFS, we need a million inodes and 1300MB of space. mount -t tmpfs -o size=1300m,nr_inodes=1000000 tmpfs "${DEST_DIR}" if [[ $? -ne 0 ]]; then logger -t rsync "Init: Failed to create tmpfs: ${DEST_DIR}" return 1 fi # Maintain 2 'partitions' of the tree. # "serving" - This copy is served to users and is not mutated. # "updating" - This copy is a shadow copy used for updates. # Create the two partitions on startup. PARTITION1=$(mktemp -d -p "${DEST_DIR}" XXXXXX) PARTITION2=$(mktemp -d -p "${DEST_DIR}" XXXXXX) # Function sync syncs dest ("${2}") from source ("${1}") function sync() { OPTS=( --quiet --recursive --links --perms --times --delete --timeout=300 --progress # NOTE(antarus): Checksum upsets some public mirror nodes; so don't use it for now. # --checksum ) SRC="${2}" DST="${1}" logger -t rsync "Started update at: $(date)" logger -t rsync "re-rsyncing the gentoo-portage tree" /usr/bin/rsync ${OPTS[@]} "${SRC}" "${DST}" >> $0.log 2>&1 err=$? if [[ $err -ne 0 ]]; then logger -t rsync "Failed to rsync tree: ${SRC}: $(date)" return 1 fi logger -t rsync "End: $(date)" return 0 } # Function init does a first sync, to populate the serving partition and # setup symlinks, and begin serving data. # "${1}" is the serving partition. "${2}" is the update partition function init() { sync "${1}" "${SOURCE_MIRROR}" # this is synchronous. # We serve out of ${DEST_DIR}/serving ln -s "${1}" "${DEST_DIR}/serving" # Setup the update partition ln -s "${2}" "${DEST_DIR}/update" # Then launch rsyncd; it will detach into the background and serve from serving. rsync --daemon --config="/opt/rsync/rsyncd.conf" return 0 } # Function update syncs the 'update' partition and, if successful, swaps the partitions. function update() { update=$(readlink "${DEST_DIR}/update") # If we fail to sync, just return false and avoid modifying the serving state. if ! sync "${update}" "${SOURCE_MIRROR}"; then return 1 fi # Save the previous serving partition old_serving=$(readlink "${DEST_DIR}/serving") # Point the serving symlink at the update partition; now freshly updated. mv -fT "${DEST_DIR}/update" "${DEST_DIR}/serving" # Point the update partition at the old serving partition. ln -sf "${old_serving}" "${DEST_DIR}/update" } function serve() { while true do # TODO(antarus): Add exponential backoff. sleep "${WAIT_TIME}" update done } # Partition1 starts as "serving", partition2 as "update" init "${PARTITION1}" "${PARTITION2}" if [[ $? -ne 0 ]]; then exit 1 fi # Serve forever serve