#!/bin/bash # This script contains the common code for the autocommands. MYID=$(id -u) MYGRP=$(id -g) _autocommandrun_volume() { local command="$1" local volume_name="$2" local backup_folder="$3" case "$command" in create) if docker volume ls | grep -q ${volume_name}; then echo "Volume ${volume_name} already exists - leaving unchanged" return fi echo "Creating volume ${volume_name}" docker volume create ${volume_name} ;; nuke) echo "Nuking volume ${volume_name}" docker volume rm ${volume_name} ;; backup) echo "Backing up volume ${volume_name}" docker run --rm -v ${volume_name}:/volume -v ${backup_folder}:/backup debian bash -c "tar -czvf /backup/backup.tgz -C /volume . && chown -R $MYID:$MYGRP /backup" ;; restore) echo "Restoring volume ${volume_name}" docker volume rm ${volume_name} docker volume create ${volume_name} docker run --rm -v ${volume_name}:/volume -v ${backup_folder}:/backup debian bash -c "tar -xzvf /backup/backup.tgz -C /volume --strip-components=1" ;; esac } _autocommandrun_path() { local command="$1" local path="$2" local backup_folder="$3" case "$command" in create) if [ -d "${path}" ]; then echo "Path ${path} already exists - unchanged" return fi echo "Creating path ${path}" mkdir -p ${path} ;; nuke) echo "Nuking path ${path}" local path_parent=$(dirname ${path}) local path_child=$(basename ${path}) if [ -d "${path_parent}/${path_child}" ]; then docker run --rm -v ${path_parent}:/volume debian bash -c "rm -rfv /volume/${path_child}" || echo "Failed to nuke path ${path}" else echo "Path ${path} does not exist - nothing to nuke" fi ;; backup) echo "Backing up path ${path}" if [ -d "${path}" ]; then docker run --rm -v ${path}:/path -v ${backup_folder}:/backup debian bash -c "tar -czvf /backup/backup.tgz -C /path . && chown -R $MYID:$MYGRP /backup" else echo "Path ${path} does not exist - nothing to backup" fi ;; restore) if [ ! -f "${backup_folder}/backup.tgz" ]; then echo "Backup file ${backup_folder}/backup.tgz does not exist - nothing to restore" else echo "Clearing existing data in path ${path}" docker run --rm -v ${path}:/path debian bash -c "rm -rfv /path/{*,.*}" echo "Restoring path ${path} from backup file ${backup_folder}/backup.tgz" tar -xzvf ${backup_folder}/backup.tgz -C ${path} --strip-components=1 fi ;; esac } _autocommandrun_file() { local command="$1" local filepath="$2" local backup_folder="$3" case "$command" in create) filepath_parent=$(dirname ${filepath}) filepath_child=$(basename ${filepath}) if [ ! -d "${filepath_parent}" ]; then echo "Parent directory ${filepath_parent} of ${filepath_child} does not exist - creating" mkdir -p ${filepath_parent} fi ;; nuke) rm -f ${filepath} ;; backup) echo "Backing up file ${filepath}" local file_parent=$(dirname ${filepath}) local file_name=$(basename ${filepath}) if [ -f "${file_parent}/${file_name}" ]; then docker run --rm -v ${file_parent}:/volume -v ${backup_folder}:/backup debian bash -c "cp /volume/${file_name} /backup/${file_name} && chown -R $MYID:$MYGRP /backup" else echo "File ${filepath} does not exist - nothing to backup" fi ;; restore) echo "Restoring file ${filepath}" local file_name=$(basename ${filepath}) rm -f ${filepath} || die "Unable to remove existing file ${filepath}, restore failed." cp ${backup_folder}/${file_name} ${filepath} || die "Unable to copy file ${backup_folder}/${file_name} to ${filepath}, restore failed." ;; esac } _autocommandparse() { # first argument is the command # if the command is backup or restore, then the last two arguments are the backup file and the temporary path # all other arguments are of form: # key=value # where key can be one of volume, path or file. # value is the path or volume name. # we iterate over the key=value arguments, and for each we call: # autorun local command="$1" shift local backup_temp_path="$1" shift echo "autocommandparse: command=$command backup_temp_path=$backup_temp_path" # Extract the backup file and temp path (last two arguments) local args=("$@") local arg_count=${#args[@]} # Process all key=value pairs for ((i=0; i<$arg_count; i++)); do local pair="${args[$i]}" # Skip if not in key=value format if [[ "$pair" != *"="* ]]; then continue fi local key="${pair%%=*}" local value="${pair#*=}" # create backup folder unique to key/value. local bfolder=$(echo "${key}_${value}" | tr -cd '[:alnum:]_-') local targetpath="${backup_temp_path}/${bfolder}" mkdir -p ${targetpath} # Key must be one of volume, path or file case "$key" in volume) _autocommandrun_volume "$command" "$value" "$targetpath" ;; path) _autocommandrun_path "$command" "$value" "$targetpath" ;; file) _autocommandrun_file "$command" "$value" "$targetpath" ;; *) _die "Unknown key $key passed to auto${command}. We only support volume, path and file." ;; esac done } datacreate() { _autocommandparse create none "$@" } datanuke() { _autocommandparse nuke none "$@" } databackup() { _check_required_env_vars "BACKUP_FILE" "TEMP_DIR" BACKUP_TEMP_PATH="$TEMP_DIR/backup" mkdir -p "$BACKUP_TEMP_PATH" echo "_autocommandparse [backup] [$BACKUP_TEMP_PATH] [$@]" _autocommandparse backup "$BACKUP_TEMP_PATH" "$@" tar zcvf "$BACKUP_FILE" -C "$BACKUP_TEMP_PATH" . } datarestore() { _check_required_env_vars "BACKUP_FILE" "TEMP_DIR" BACKUP_TEMP_PATH="$TEMP_DIR/restore" echo "_autocommandparse [restore] [$BACKUP_TEMP_PATH] [$@]" mkdir -p "$BACKUP_TEMP_PATH" tar zxvf "$BACKUP_FILE" -C "$BACKUP_TEMP_PATH" --strip-components=1 _autocommandparse restore "$BACKUP_TEMP_PATH" "$@" }