Files
botstrap/other-scripts/manual-copy-bootstrap.sh

399 lines
14 KiB
Bash
Executable File

#!/bin/bash
VERSION="1.0.0"
function init {
echo "Botstrap version ${VERSION}"
if ! which ssh-copy-id >/dev/null
then
echo "Installing ssh..."
sudo apt-get install ssh -y
fi
echo "Important: make sure you have run ssh-copy-id for each host or mirror before using this script."
CREATE_BOOTSTRAP_ERRORS=0
}
function reset {
BOOTSTRAP_PATH=""
BOOTSTRAP_CHECKSUM_PATH=""
}
function read_config {
CONFIG=$(cat "config.json")
NODE_HOST=$(echo "$CONFIG" | jq -r '.["nodeHost"]')
NODE_PORT=$(echo "$CONFIG" | jq -r '.["nodePort"]')
NODE_SERVICE=$(echo "$CONFIG" | jq -r '.["nodeService"]')
BOOTSTRAP_HOST=$(echo "$CONFIG" | jq -r '.["bootstrapHost"]')
BOOTSTRAP_HOST_MODE=$(echo "$CONFIG" | jq -r '.["bootstrapHostMode"]')
BOOTSTRAP_MIRRORS=$(echo "$CONFIG" | jq -r '.["bootstrapMirrors"]')
BOOTSTRAP_USER=$(echo "$CONFIG" | jq -r '.["bootstrapUser"]')
BOOTSTRAP_WEBROOT=$(echo "$CONFIG" | jq -r '.["bootstrapWebRoot"]')
TIMEOUT=$(echo "$CONFIG" | jq -r '.["timeout"]')
BOOTSTRAP_INTERVAL=$(echo "$CONFIG" | jq -r '.["bootstrapInterval"]')
RETRY_INTERVAL=$(echo "$CONFIG" | jq -r '.["retryInterval"]')
#echo "CONFIG: ${CONFIG}"
}
#function create_bootstrap {
# Check if we need to restart the node
# if [ "${CREATE_BOOTSTRAP_ERRORS} " -gt 10 ]; then
# CREATE_BOOTSTRAP_ERRORS=0
# # This relies on having a systemd service set up
# echo "Restarting node due to ${CREATE_BOOTSTRAP_ERRORS} consecutive errors..."
# sudo service "${NODE_SERVICE}" restart
# sleep 30
# fi
# echo "Attempting to create bootstrap..."
# URL="http://${NODE_HOST}:${NODE_PORT}/bootstrap/create"
# RESULT=$(curl -s -X POST --max-time "${TIMEOUT}" "${URL}")
# # echo "${RESULT}"
# if [ -z "${RESULT}" ]; then
# echo "Empty response from create bootstrap API"
# return 1
# fi
# ERROR=$(echo "${RESULT}" | jq -r '.["error"]')
# if [ ! -z "${ERROR}" ]; then
# ERROR_MESSAGE=$(echo "${RESULT}" | jq -r '.["message"]')
# echo "An error occurred: ${ERROR_MESSAGE}"
# return 2
# fi
# Get the path to the extracted bootstrap
# PATH_RESPONSE="${RESULT}"
# if [[ ! "${PATH_RESPONSE}" == *".7z" ]]; then
# echo "Error: invalid path: ${PATH_RESPONSE}"
# return 3
# fi
# echo "Bootstrap created at path: ${PATH_RESPONSE}"
# BOOTSTRAP_PATH="${PATH_RESPONSE}"
# BOOTSTRAP_CHECKSUM_PATH="${PATH_RESPONSE}.sha256"
# CREATE_BOOTSTRAP_ERRORS=0
# return 0
#}
BOOTSTRAP_PATH="/var/www/html/manual-copy/bootstrap-archive.7z"
BOOTSTRAP_CHECKSUM_PATH="/var/www/html/manual-copy/bootstrap-archive.7z.sha256"
function upload_to_main_host {
local BOOTSTRAP_FILENAME="$(basename -- $BOOTSTRAP_PATH)"
local BOOTSTRAP_CHECKSUM_FILENAME="$(basename -- $BOOTSTRAP_CHECKSUM_PATH)"
local BOOTSTRAP_FILENAME_NEW="${BOOTSTRAP_FILENAME}.new"
local BOOTSTRAP_CHECKSUM_FILENAME_NEW="${BOOTSTRAP_CHECKSUM_FILENAME}.new"
# Add the host to known hosts, to avoid terminal prompts when adding a new host in the config
ssh-keyscan "${BOOTSTRAP_HOST}" >> "${HOME}/.ssh/known_hosts"
# Upload the files
echo "Uploading ${BOOTSTRAP_PATH} to ${BOOTSTRAP_HOST}:${BOOTSTRAP_WEBROOT}/${BOOTSTRAP_FILENAME_NEW}..."
scp "${BOOTSTRAP_PATH}" "${BOOTSTRAP_USER}@${BOOTSTRAP_HOST}:${BOOTSTRAP_WEBROOT}/${BOOTSTRAP_FILENAME_NEW}"
echo "Uploading ${BOOTSTRAP_CHECKSUM_PATH} to ${BOOTSTRAP_HOST}:${BOOTSTRAP_WEBROOT}/${BOOTSTRAP_CHECKSUM_FILENAME_NEW}..."
scp "${BOOTSTRAP_CHECKSUM_PATH}" "${BOOTSTRAP_USER}@${BOOTSTRAP_HOST}:${BOOTSTRAP_WEBROOT}/${BOOTSTRAP_CHECKSUM_FILENAME_NEW}"
# Check the files are intact
local CHECKSUM_URL="http://${BOOTSTRAP_HOST}/${BOOTSTRAP_CHECKSUM_FILENAME_NEW}"
local CHECKSUM_REMOTE=$(curl -s "${CHECKSUM_URL}")
local CHECKSUM_LOCAL=$(sha256sum "${BOOTSTRAP_PATH}" | awk '{ print $1 }')
if [ -z "${CHECKSUM_REMOTE}" ]; then
echo "Error: no checksum could be found on the main server"
return 1
fi
if [[ "${CHECKSUM_REMOTE}" != "${CHECKSUM_LOCAL}" ]]; then
echo "Error: checksum files do not match"
echo "CHECKSUM_LOCAL: ${CHECKSUM_LOCAL}"
echo "CHECKSUM_REMOTE: ${CHECKSUM_REMOTE}"
echo "CHECKSUM_URL: ${CHECKSUM_URL}"
return 2
fi
# Check that the uploaded file matches its checksum file
COMPUTED_CHECKSUM_REMOTE=$(ssh "${BOOTSTRAP_USER}@${BOOTSTRAP_HOST}" "sha256sum ${BOOTSTRAP_WEBROOT}/${BOOTSTRAP_FILENAME_NEW}" | awk '{ print $1 }')
if [[ "${COMPUTED_CHECKSUM_REMOTE}" != "${CHECKSUM_LOCAL}" ]]; then
echo "Error: checksum of uploaded file does not match"
echo "CHECKSUM_LOCAL: ${CHECKSUM_LOCAL}"
echo "COMPUTED_CHECKSUM_REMOTE: ${COMPUTED_CHECKSUM_REMOTE}"
echo "BOOTSTRAP_FILENAME_NEW: ${BOOTSTRAP_FILENAME_NEW}"
return 3
fi
# All good
return 0
}
function move_to_local_host {
local BOOTSTRAP_FILENAME="$(basename -- $BOOTSTRAP_PATH)"
local BOOTSTRAP_CHECKSUM_FILENAME="$(basename -- $BOOTSTRAP_CHECKSUM_PATH)"
local BOOTSTRAP_FILENAME_NEW="${BOOTSTRAP_FILENAME}.new"
local BOOTSTRAP_CHECKSUM_FILENAME_NEW="${BOOTSTRAP_CHECKSUM_FILENAME}.new"
local CHECKSUM_FILE_SRC=$(cat ${BOOTSTRAP_CHECKSUM_PATH})
# Upload the files
echo "Moving ${BOOTSTRAP_PATH} to ${BOOTSTRAP_WEBROOT}/${BOOTSTRAP_FILENAME_NEW}..."
mv "${BOOTSTRAP_PATH}" "${BOOTSTRAP_WEBROOT}/${BOOTSTRAP_FILENAME_NEW}"
echo "Moving ${BOOTSTRAP_CHECKSUM_PATH} to ${BOOTSTRAP_WEBROOT}/${BOOTSTRAP_CHECKSUM_FILENAME_NEW}..."
mv "${BOOTSTRAP_CHECKSUM_PATH}" "${BOOTSTRAP_WEBROOT}/${BOOTSTRAP_CHECKSUM_FILENAME_NEW}"
# Check the source and destination match
echo "Checking relocated files..."
local CHECKSUM_FILE_DEST=$(cat ${BOOTSTRAP_WEBROOT}/${BOOTSTRAP_CHECKSUM_FILENAME_NEW})
if [[ "${CHECKSUM_FILE_SRC}" != "${CHECKSUM_FILE_DEST}" ]]; then
echo "Error: checksum of moved file does not match original"
echo "CHECKSUM_FILE_SRC: ${CHECKSUM_FILE_SRC}"
echo "CHECKSUM_FILE_DEST: ${CHECKSUM_FILE_DEST}"
echo "BOOTSTRAP_CHECKSUM_FILENAME_NEW: ${BOOTSTRAP_CHECKSUM_FILENAME_NEW}"
return 1
fi
# Check that the copied file matches its checksum file
echo "Validating checksum..."
local COMPUTED_CHECKSUM_LOCAL=$(sha256sum "${BOOTSTRAP_WEBROOT}/${BOOTSTRAP_FILENAME_NEW}" | awk '{ print $1 }')
if [[ "${COMPUTED_CHECKSUM_LOCAL}" != "${CHECKSUM_FILE_DEST}" ]]; then
echo "Error: checksum of moved file does not match its sha256 file"
echo "CHECKSUM_FILE_DEST: ${CHECKSUM_FILE_DEST}"
echo "COMPUTED_CHECKSUM_LOCAL: ${COMPUTED_CHECKSUM_LOCAL}"
echo "BOOTSTRAP_FILENAME_NEW: ${BOOTSTRAP_FILENAME_NEW}"
echo "BOOTSTRAP_CHECKSUM_FILENAME_NEW: ${BOOTSTRAP_CHECKSUM_FILENAME_NEW}"
return 2
fi
#
# All good
echo "Files copied successfully"
return 0
}
function upload {
# Ensure the files exist
if [ ! -f "${BOOTSTRAP_PATH}" ]; then
echo "Error: no file exists at path ${BOOTSTRAP_PATH}"
return 1
fi
if [ ! -f "${BOOTSTRAP_CHECKSUM_PATH}" ]; then
echo "Error: no checksum file exists at path ${BOOTSTRAP_CHECKSUM_PATH}"
return 2
fi
if [[ "${BOOTSTRAP_HOST_MODE}" == "remote" ]]; then
upload_to_main_host
EXIT_CODE=$?
elif [[ "${BOOTSTRAP_HOST_MODE}" == "local" ]]; then
move_to_local_host
EXIT_CODE=$?
else
echo "Unknown host mode: ${BOOTSTRAP_HOST_MODE}"
return 3
fi
if [ "${EXIT_CODE}" -ne 0 ]; then
return "${EXIT_CODE}"
fi
return 0
}
function sync_mirror {
MIRROR="${1}"
echo "Syncing mirror ${MIRROR}..."
local BOOTSTRAP_FILENAME="$(basename -- $BOOTSTRAP_PATH)"
local BOOTSTRAP_CHECKSUM_FILENAME="$(basename -- $BOOTSTRAP_CHECKSUM_PATH)"
local BOOTSTRAP_FILENAME_NEW="${BOOTSTRAP_FILENAME}.new"
local BOOTSTRAP_CHECKSUM_FILENAME_NEW="${BOOTSTRAP_CHECKSUM_FILENAME}.new"
# Add the host to known hosts, to avoid terminal prompts when adding a new host in the config
ssh-keyscan "${MIRROR}" >> "${HOME}/.ssh/known_hosts"
# # Upload the files
echo "Uploading ${BOOTSTRAP_WEBROOT}/${BOOTSTRAP_FILENAME_NEW} to mirror ${MIRROR}:${BOOTSTRAP_WEBROOT}/${BOOTSTRAP_FILENAME_NEW}..."
scp "${BOOTSTRAP_WEBROOT}/${BOOTSTRAP_FILENAME_NEW}" "${BOOTSTRAP_USER}@${MIRROR}:${BOOTSTRAP_WEBROOT}/${BOOTSTRAP_FILENAME_NEW}"
echo "Uploading ${BOOTSTRAP_WEBROOT}/${BOOTSTRAP_CHECKSUM_FILENAME_NEW} to mirror ${MIRROR}:${BOOTSTRAP_WEBROOT}/${BOOTSTRAP_CHECKSUM_FILENAME_NEW}..."
scp "${BOOTSTRAP_WEBROOT}/${BOOTSTRAP_CHECKSUM_FILENAME_NEW}" "${BOOTSTRAP_USER}@${MIRROR}:${BOOTSTRAP_WEBROOT}/${BOOTSTRAP_CHECKSUM_FILENAME_NEW}"
# Check the files are intact
echo "Checking copied files..."
local CHECKSUM_URL="http://${MIRROR}/${BOOTSTRAP_CHECKSUM_FILENAME_NEW}"
local CHECKSUM_REMOTE=$(curl -s "${CHECKSUM_URL}")
local CHECKSUM_LOCAL=$(cat "${BOOTSTRAP_WEBROOT}/${BOOTSTRAP_CHECKSUM_FILENAME_NEW}")
if [ -z "${CHECKSUM_REMOTE}" ]; then
echo "Error: no checksum could be found on mirror ${MIRROR}"
return 1
fi
if [[ "${CHECKSUM_REMOTE}" != "${CHECKSUM_LOCAL}" ]]; then
echo "Error: checksum files on mirror do not match the local checksum"
echo "CHECKSUM_LOCAL: ${CHECKSUM_LOCAL}"
echo "CHECKSUM_REMOTE: ${CHECKSUM_REMOTE}"
echo "CHECKSUM_URL: ${CHECKSUM_URL}"
return 2
fi
# Check that the uploaded file matches the checksum file
echo "Validating checksum..."
COMPUTED_CHECKSUM_REMOTE=$(ssh "${BOOTSTRAP_USER}@${MIRROR}" "sha256sum ${BOOTSTRAP_WEBROOT}/${BOOTSTRAP_FILENAME_NEW}" | awk '{ print $1 }')
if [[ "${COMPUTED_CHECKSUM_REMOTE}" != "${CHECKSUM_LOCAL}" ]]; then
echo "Error: checksum of file uploaded to mirror ${MIRROR} does not match"
echo "CHECKSUM_LOCAL: ${CHECKSUM_LOCAL}"
echo "COMPUTED_CHECKSUM_REMOTE: ${COMPUTED_CHECKSUM_REMOTE}"
echo "BOOTSTRAP_FILENAME_NEW: ${BOOTSTRAP_FILENAME_NEW}"
return 3
fi
# All good
return 0
}
function sync_mirrors {
# Loop through mirrors
BOOTSTRAP_MIRRORS_ARRAY=$(echo "${BOOTSTRAP_MIRRORS}" | jq -r @sh | xargs echo)
for MIRROR in ${BOOTSTRAP_MIRRORS_ARRAY}
do
sync_mirror "${MIRROR}"
EXIT_CODE=$?
if [ "${EXIT_CODE}" -ne 0 ]; then
# Don't enforce, as otherwise a single offline mirror would prevent bootstraps being updated
echo "Warning: mirror ${MIRROR} failed to sync. Proceeding anyway..."
fi
done
}
function deploy_to_remote_host {
echo "TODO: implement deploy_to_remote_host"
return 1
}
function deploy_to_local_host {
echo "Deploying to localhost..."
local BOOTSTRAP_FILENAME="$(basename -- $BOOTSTRAP_PATH)"
local BOOTSTRAP_CHECKSUM_FILENAME="$(basename -- $BOOTSTRAP_CHECKSUM_PATH)"
local BOOTSTRAP_FILENAME_NEW="${BOOTSTRAP_FILENAME}.new"
local BOOTSTRAP_CHECKSUM_FILENAME_NEW="${BOOTSTRAP_CHECKSUM_FILENAME}.new"
mv "${BOOTSTRAP_WEBROOT}/${BOOTSTRAP_FILENAME}" "${BOOTSTRAP_WEBROOT}/${BOOTSTRAP_FILENAME}.old"
mv "${BOOTSTRAP_WEBROOT}/${BOOTSTRAP_FILENAME_NEW}" "${BOOTSTRAP_WEBROOT}/${BOOTSTRAP_FILENAME}"
mv "${BOOTSTRAP_WEBROOT}/${BOOTSTRAP_CHECKSUM_FILENAME}" "${BOOTSTRAP_WEBROOT}/${BOOTSTRAP_CHECKSUM_FILENAME}.old"
mv "${BOOTSTRAP_WEBROOT}/${BOOTSTRAP_CHECKSUM_FILENAME_NEW}" "${BOOTSTRAP_WEBROOT}/${BOOTSTRAP_CHECKSUM_FILENAME}"
}
function deploy_to_mirror {
MIRROR="${1}"
echo "Deploying to mirror ${MIRROR}..."
local BOOTSTRAP_FILENAME="$(basename -- $BOOTSTRAP_PATH)"
local BOOTSTRAP_CHECKSUM_FILENAME="$(basename -- $BOOTSTRAP_CHECKSUM_PATH)"
local BOOTSTRAP_FILENAME_NEW="${BOOTSTRAP_FILENAME}.new"
local BOOTSTRAP_CHECKSUM_FILENAME_NEW="${BOOTSTRAP_CHECKSUM_FILENAME}.new"
# Create blank existing files if not already there
ssh "${BOOTSTRAP_USER}@${MIRROR}" "touch -a ${BOOTSTRAP_WEBROOT}/${BOOTSTRAP_FILENAME}"
ssh "${BOOTSTRAP_USER}@${MIRROR}" "touch -a ${BOOTSTRAP_WEBROOT}/${BOOTSTRAP_CHECKSUM_FILENAME}"
# Swap the old and the new bootstraps
ssh "${BOOTSTRAP_USER}@${MIRROR}" "mv '${BOOTSTRAP_WEBROOT}/${BOOTSTRAP_FILENAME}' '${BOOTSTRAP_WEBROOT}/${BOOTSTRAP_FILENAME}.old'" &&
ssh "${BOOTSTRAP_USER}@${MIRROR}" "mv '${BOOTSTRAP_WEBROOT}/${BOOTSTRAP_FILENAME_NEW}' '${BOOTSTRAP_WEBROOT}/${BOOTSTRAP_FILENAME}'" &&
ssh "${BOOTSTRAP_USER}@${MIRROR}" "mv '${BOOTSTRAP_WEBROOT}/${BOOTSTRAP_CHECKSUM_FILENAME}' '${BOOTSTRAP_WEBROOT}/${BOOTSTRAP_CHECKSUM_FILENAME}.old'" &&
ssh "${BOOTSTRAP_USER}@${MIRROR}" "mv '${BOOTSTRAP_WEBROOT}/${BOOTSTRAP_CHECKSUM_FILENAME_NEW}' '${BOOTSTRAP_WEBROOT}/${BOOTSTRAP_CHECKSUM_FILENAME}'"
}
function deploy {
# Switch out the old bootstraps for the new one
# Start with the main host
if [[ "${BOOTSTRAP_HOST_MODE}" == "remote" ]]; then
deploy_to_remote_host
EXIT_CODE=$?
elif [[ "${BOOTSTRAP_HOST_MODE}" == "local" ]]; then
deploy_to_local_host
EXIT_CODE=$?
fi
if [ "${EXIT_CODE}" -ne 0 ]; then
return "${EXIT_CODE}"
fi
# Now deploy to each mirror
BOOTSTRAP_MIRRORS_ARRAY=$(echo "${BOOTSTRAP_MIRRORS}" | jq -r @sh | xargs echo)
for MIRROR in ${BOOTSTRAP_MIRRORS_ARRAY}
do
deploy_to_mirror "${MIRROR}"
EXIT_CODE=$?
if [ "${EXIT_CODE}" -ne 0 ]; then
# Don't enforce, as otherwise a single offline mirror would prevent bootstraps being updated
echo "Warning: mirror ${MIRROR} failed to deploy. Proceeding anyway..."
fi
done
}
function run {
# Init
# reset
read_config
# Create
# create_bootstrap
# EXIT_CODE=$?
# if [ "${EXIT_CODE}" -ne 0 ]; then
# CREATE_BOOTSTRAP_ERRORS=$((CREATE_BOOTSTRAP_ERRORS+1))
# return "${EXIT_CODE}"
# fi
# Upload
upload
EXIT_CODE=$?
if [ "${EXIT_CODE}" -ne 0 ]; then
return "${EXIT_CODE}"
fi
sync_mirrors
# Go live
deploy
EXIT_CODE=$?
if [ "${EXIT_CODE}" -ne 0 ]; then
return "${EXIT_CODE}"
fi
return 0
}
run
#function loop {
# init
#
# while [ true ]; do
#
# run
# EXIT_CODE=$?
# if [ "${EXIT_CODE}" -ne 0 ]; then
# echo "Retrying in ${RETRY_INTERVAL} seconds..."
# sleep "${RETRY_INTERVAL}"
# else
# echo "Process completed successfully."
# echo "Sleeping for ${BOOTSTRAP_INTERVAL} seconds until next cycle..."
# sleep "${BOOTSTRAP_INTERVAL}"
# fi
# echo
#
# done
#
#}
#loop