diff options
author | Esteban Carnevale <alfplayer@mailoo.org> | 2014-11-05 11:34:31 -0300 |
---|---|---|
committer | Esteban Carnevale <alfplayer@mailoo.org> | 2014-11-05 11:34:31 -0300 |
commit | b22abc87dfd204f5667a418fd251863226a00655 (patch) | |
tree | 61d140f92c045819be87c421a04651bf431f3f97 | |
parent | 02cf9a83034daed51ee7df83b8973ea1cafee9eb (diff) |
parabola-mirror: Add script
-rwxr-xr-x | parabola-mirror | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/parabola-mirror b/parabola-mirror new file mode 100755 index 0000000..28b4c75 --- /dev/null +++ b/parabola-mirror @@ -0,0 +1,183 @@ +#!/bin/bash + +# alfplayer +# 2014-06-12 +# +# Mirror the whole Parabola repository using rsync and keep snapshots + +set -e + +script_filename="$(basename "$0")" + +# Create temporary log file +log_tmp="$(mktemp -p /var/tmp)" + +# Default configuration values. +# They can be overridden by setting the variables in the calling environment. +# 1 to set, 0 to unset +: ${repo:=rsync://repo.parabolagnulinux.org:875/repos} +: ${base_dir:=/srv/http} +: ${parabola_dir:=${base_dir}/parabola} +: ${oldest_version:=10} # snapshots older than this one will be deleted (see also no_delete above) +: ${log_file:=${script_filename}.log} +#: ${mail_to:=your@mail.com} # comment out to disable +#: ${date_exclude:=2014.06.19} # disable running this script this date (see next line) +: ${forcerun:=0} # force running on excluded date +: ${terminal:=1} # outputs to stdout using rsync --progress (and logs to a file) +: ${no_delete:=0} # disable deletion of oldest snapshots +#: ${TZ:=UTC} # set time zone + +export TZ + +# Lock with flock (provided by util-linux), save to log file and send email on exit +LOCKFILE="/var/lock/${script_filename}" +LOCKFD=99 + +_lock() { flock -$1 $LOCKFD; } + +# Wait until there is no process writing to ${log_tmp} +# Waiting can be necessary if command groups are not executed until the end +_wait_log_tmp() { + if [[ -e "${log_tmp}" ]] ; then + while fuser "${log_tmp}" > /dev/null ; do + sleep 0.2 + done + fi +} + +_no_more_locking() { + set +e + + # Save exit status + es=$? + + _wait_log_tmp + cat "${log_tmp}" >> "${log_file}" + + if [[ $? == 0 ]] ; then + log_written=1 + else + echo "=> ERROR: Failed to write to log file: ${log_file}" >&2 + fi + + if [[ -e ${parabola_dir}.tmp ]] ; then + echo "=> WARNING: Directory with partial transfer ${LOCAL}.tmp remains in file system" + fi + + if [[ ${mail_to} ]] ; then + echo "=> Sending output to ${mail_to}" + mail -s "[$(hostname)] ${script_filename}" "${mail_to}" < "${log_tmp}" + fi + + if [[ ${log_written} == 1 ]] ; then + rm -f "${log_tmp}" + fi + + if [[ $es != 0 ]] ; then + echo "=> WARNING: Unsuccessful script termination. Exit status: $es" + if [[ ${mail_to} ]] ; then + echo "=> Sending error notification to ${mail_to}" + mail -s "[$(hostname)] ${script_filename} failed. See logged output." "${mail_to}" < /dev/null + fi + fi + + _lock u + _lock xn && \ + rm -f $LOCKFILE +} + +_prepare_locking() { eval "exec $LOCKFD>\"$LOCKFILE\""; trap _no_more_locking EXIT; } + +_prepare_locking + +# Lock now. The lock is disabled automatically when the script exits (with any error code). +if ! _lock xn ; then + echo "=> ERROR: Could not obtain lock. Exiting." >&2 + exit 1 +fi + +date="$(date +%Y.%m.%d)" +current="${parabola_dir}-${date}" +local_useful=0 + +{ + +if [[ ${date_exclude} && ${forcerun} != 1 ]] ; then + if [[ $DATE == ${date_exclude} ]] ; then + echo "Manually disabled: ${date}. Exiting." + exit 0 + fi +fi + +# Test if ${parabola_dir} is an existing symlink pointing to an existing directory +if [[ -h ${parabola_dir} ]] ; then + last_path="$(readlink -f "${parabola_dir}")" + if [[ -d ${last_path} ]] ; then + last="${last_path##*/}" + local_useful=1 + else + echo "=> ERROR: ${parabola_dir} is a symlink which does not point to an existing directory." >&2 + exit 1 + fi +else + echo "=> ERROR: ${parabola_dir} does not exist or is not a symlink." >&2 + exit 1 +fi + + +echo +echo "=> Creating snapshot for date ${date}" + +if [[ -e "${current}" ]] ; then + echo "${current} already exists. Exiting." >&2 + exit 1 +fi + +if [[ -e "${parabola_dir}".tmp ]] ; then + echo "${parabola_dir}.tmp already exists. Resuming." +else + cp -al "${last_path}" "${parabola_dir}".tmp +fi + +} &> >(tee -a "${log_tmp}") + +_wait_log_tmp + +rsync "${repo}"/ -rtvlH ${terminal:+--progress} --log-file="${log_tmp}" --safe-links --delete --link-dest="$base_dir"/archlinux/ --link-dest="$parabola_dir" "$parabola_dir".tmp + +{ + +cd "$base_dir" + +echo "=> Delete versions older than the ${oldest_version} oldest version" +delete_list=( $(for dir in parabola-* ; do echo "$(find "$dir" -type f -printf '%T@\n' | sort -n | tail -1) $dir" ; done | awk '{print $2}' | head -n -"${oldest_version}") ) + +for dir in ${delete_list[@]} ; do + if [[ ${no_delete} != 1 ]] ; then + echo "$dir" + rm -rf "$dir" + else + echo "DRY-RUN: rm -rf $dir" + fi +done + +echo "=> Start serving the new repository version" +mv "${parabola_dir}.tmp" "${current}" + +if [[ ${local_useful} == 1 ]] ; then + echo " => Deleting ${parabola_dir} symlink" + rm -rf "${parabola_dir}" +fi + +# Create symlink +echo " => Creating symlink ${current} to ${parabola_dir}" +ln -s ${current##*/} ${parabola_dir} + +echo "=> Disk space report" +df -h / + +echo "=> ${script_filename} finished successfully. Finish time: $(date --rfc-3339=seconds)" + +} &> >(tee -a "${log_tmp}") + +_wait_log_tmp |