#!/usr/bin/env bash set -euo pipefail if [[ $# -ne 0 ]]; then echo "Usage: $0" >&2 exit 2 fi if [[ ${EUID} -ne 0 ]]; then echo "Run this rollback tool as root." >&2 exit 2 fi install_root="${NETFISHING_INSTALL_ROOT:-/opt/netfishing-server}" service_name="${NETFISHING_SERVICE_NAME:-netfishing-server.service}" releases_dir="${install_root}/releases" if [[ "${install_root}" != /* || "${install_root}" == "/" ]]; then echo "NETFISHING_INSTALL_ROOT must be a specific absolute directory." >&2 exit 2 fi if [[ ! -L "${install_root}/current" || ! -L "${install_root}/previous" ]]; then echo "Both current and previous release links are required." >&2 exit 1 fi current_target="$(readlink -f -- "${install_root}/current")" previous_target="$(readlink -f -- "${install_root}/previous")" for target in "${current_target}" "${previous_target}"; do if [[ ! -d "${target}" || "${target}" != "${releases_dir}/"* ]]; then echo "Refusing to use a release outside ${releases_dir}." >&2 exit 1 fi (cd -- "${target}" && sha256sum -c SHA256SUMS) done replace_symlink() { local target="$1" local link_path="$2" local temporary_link="${install_root}/.$(basename -- "${link_path}").new.$$" ln -s -- "${target}" "${temporary_link}" mv -Tf -- "${temporary_link}" "${link_path}" } service_active=false if systemctl is-active --quiet "${service_name}"; then service_active=true systemctl stop "${service_name}" fi replace_symlink "${previous_target}" "${install_root}/current" replace_symlink "${current_target}" "${install_root}/previous" if ${service_active}; then if ! systemctl start "${service_name}"; then start_succeeded=false else sleep 1 start_succeeded=true systemctl is-active --quiet "${service_name}" || start_succeeded=false fi if ! ${start_succeeded}; then echo "Rollback target failed to start; restoring the original release." >&2 replace_symlink "${current_target}" "${install_root}/current" replace_symlink "${previous_target}" "${install_root}/previous" systemctl start "${service_name}" || true exit 1 fi fi echo "Rolled back to $(basename -- "${previous_target}")."