diff --git a/backup-module/backup_controller.php b/backup-module/backup_controller.php index c4c6094..02266ee 100644 --- a/backup-module/backup_controller.php +++ b/backup-module/backup_controller.php @@ -92,7 +92,7 @@ function backup_controller() if ($route->action == "download") { header("Content-type: application/zip"); - $backup_filename="emoncms-backup-".date("Y-m-d").".tar.gz"; + $backup_filename="emoncms-backup-".gethostname()."-".date("Y-m-d").".tar.gz"; header("Content-Disposition: attachment; filename=$backup_filename"); header("Pragma: no-cache"); header("Expires: 0"); @@ -120,7 +120,7 @@ function backup_controller() if ((move_uploaded_file($_FILES['file']['tmp_name'], $target_path)) && ($uploadOk == 1)) { $redis->rpush("service-runner","$import_script $import_flag>$import_logfile"); - header('Location: '.$path.'backup#import'); + header('Location: '.$path.'backup#import-archive'); } else { return "
Error: Import archive not selected
"; } diff --git a/backup-module/backup_view.php b/backup-module/backup_view.php index e80c52b..c2d2788 100644 --- a/backup-module/backup_view.php +++ b/backup-module/backup_view.php @@ -74,7 +74,7 @@


Right Click > Download:
'.$backup_filename.''; } @@ -161,7 +161,7 @@ function export_log_update() { $("#export-log").html(result); document.getElementById("export-log-bound").scrollTop = document.getElementById("export-log-bound").scrollHeight - if (result.indexOf("=== Emoncms export complete! ===")!=-1) { + if (result.indexOf("=== Emoncms export complete! ===")!=-1 || result.indexOf("=== Emoncms export completed with ERRORS! ===")!=-1) { clearInterval(export_updater); } } diff --git a/emoncms-export.sh b/emoncms-export.sh index 883e77c..0b20192 100755 --- a/emoncms-export.sh +++ b/emoncms-export.sh @@ -1,47 +1,79 @@ #!/bin/bash -script_location="`dirname $0`" -date=$(date +"%Y-%m-%d") +# Set the shell to trigger errors when commands within a pipe have a non-zero return code +set -o pipefail + +# The errors variable is set when error_handler() is called, the variable is used by the finish() function for success or failure messages +errors=false + +# This error handler function display information of what happened and where, but does NOT stop the script execution +error_handler() { + echo "Error: RC=$1 occurred on line $2" + errors=true +} + +# Set trap for ERR to pass the return code and line number to error_handler() +trap 'error_handler $? $LINENO' ERR + +# Exit handler used to ensure the exit message AJAX expects is found, whilst summarising if errors were found +# This also picks up the natural exit when reaching end of script + +function finish() { + if [[ "${errors}" == "false" && $? == 0 ]]; then + echo "=== Emoncms export complete! ===" +# The strings output are identified in the interface to stop ongoing AJAX calls, please ammend in interface if changed here + else + echo "=== Emoncms export completed with ERRORS! ===" +# The strings output are identified in the interface to stop ongoing AJAX calls, please ammend in interface if changed here + fi +} + +# Set trap for whenever EXIT is called to call finish() +trap finish EXIT + +declare -a included not_found +script_location="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" +config_location=${script_location}/config.cfg echo "=== Emoncms export start ===" date echo "Backup module version:" -cat $script_location/backup-module/module.json | grep version +grep version "${script_location}/module.json" echo "EUID: $EUID" -echo "Reading $script_location/config.cfg...." -if [ -f "$script_location/config.cfg" ] +echo "Reading ${config_location}...." + +if [ ! -f "${config_location}" ] then - source "$script_location/config.cfg" - echo "Location of databases: $database_path" - echo "Location of emonhub.conf: $emonhub_config_path" - echo "Location of Emoncms: $emoncms_location" - echo "Backup destination: $backup_location" -else - echo "ERROR: Backup $script_location/backup/config.cfg file does not exist" + echo "ERROR: Backup config file ${config_location} does not exist" exit 1 - sudo systemctl start feedwriter > /dev/null fi +source "${config_location}" +echo "Location of databases: $database_path" +echo "Location of emonhub.conf: $emonhub_config_path" +echo "Location of Emoncms: $emoncms_location" +echo "Backup destination: $backup_location" + +tar_filename="${backup_location}/emoncms-backup-$(hostname)-$(date +"%Y-%m-%d").tar" + module_location="${emoncms_location}/Modules/backup" echo "emoncms backup module location $module_location" #----------------------------------------------------------------------------------------------- # Remove Old backup files #----------------------------------------------------------------------------------------------- -if [ -f $backup_location/emoncms.sql ] -then - sudo rm $backup_location/emoncms.sql -fi - -if [ -f $backup_location/emoncms-backup-$date.tar ] -then - sudo rm $backup_location/emoncms-backup-$date.tar -fi +for file in "${backup_location}/emoncms.sql" "${tar_filename}" +do + if [ -f "${file}" ] + then + sudo rm "${file}" + fi +done #----------------------------------------------------------------------------------------------- # Check emonPi / emonBase image version #----------------------------------------------------------------------------------------------- -image_version=$(ls /boot | grep emonSD) +image_version=$(cd /boot && echo *emonSD* ) # Check first 16 characters of filename image_date=${image_version:0:16} @@ -63,8 +95,8 @@ fi sudo systemctl stop feedwriter # Get MYSQL authentication details from settings.php -if [ -f $script_location/get_emoncms_mysql_auth.php ]; then - auth=$(echo $emoncms_location | php $script_location/get_emoncms_mysql_auth.php php) +if [ -f "${script_location}/get_emoncms_mysql_auth.php" ]; then + auth=$(echo "${emoncms_location}" | php "${script_location}/get_emoncms_mysql_auth.php" php) IFS=":" read username password database <<< "$auth" else echo "Error: cannot read MYSQL authentication details from Emoncms $script_location/get_emoncms_mysql_auth.php php & settings.php" @@ -75,7 +107,7 @@ fi # MYSQL Dump Emoncms database if [ -n "$username" ]; then # if username string is not empty - mysqldump -u$username -p$password $database > $backup_location/emoncms.sql + mysqldump -u"${username}" -p"${password}" "${database}" > "${backup_location}/emoncms.sql" if [ $? -ne 0 ]; then echo "Error: failed to export mysql data" echo "emoncms export failed" @@ -88,85 +120,53 @@ else exit 1 fi -if [ -f $backup_location/emoncms.sql ] -then - echo "-- adding $backup_location/emoncms.sql to archive --" - tar -c --file=$backup_location/emoncms-backup-$date.tar $backup_location/emoncms.sql --transform 's?.*/??g' 2>&1 -else - echo "no file $backup_location/emoncms.sql" -fi - -if [ -f $emonhub_config_path/emonhub.conf ] -then - echo "-- adding $emonhub_config_path/emonhub.conf to archive --" - tar -vr --file=$backup_location/emoncms-backup-$date.tar $emonhub_config_path/emonhub.conf --transform 's?.*/??g' 2>&1 -else - echo "no file $emonhub_config_path/emonhub.conf" -fi - -if [ -f $emoncms_location/settings.ini ] -then - echo "-- adding $emoncms_location/settings.ini to archive --" - tar -vr --file=$backup_location/emoncms-backup-$date.tar $emoncms_location/settings.ini --transform 's?.*/??g' 2>&1 -else - echo "no file $emoncms_location/settings.ini" -fi - -if [ -f $emoncms_location/settings.php ] -then - echo "-- adding $emoncms_location/settings.php to archive --" - tar -vr --file=$backup_location/emoncms-backup-$date.tar $emoncms_location/settings.php --transform 's?.*/??g' 2>&1 -else - echo "no file $emoncms_location/settings.php" -fi +# +for file in "${backup_location}/emoncms.sql" "${emonhub_config_path}/emonhub.conf" "${emoncms_location}/settings.ini" "${emoncms_location}/settings.php" +do + if [ -f "${file}" ] + then + echo "-- adding ${file} to archive --" + tar -vr --file="${tar_filename}" "${file}" --transform 's?.*/??g' 2>&1 + included+=("${file}") + else + echo "no ${file} to backup" + not_found+=("${file}") + fi +done # Append database folder to the archive with absolute path -if [ -d $database_path/phpfina ] -then - echo "-- adding $database_path/phpfina to archive --" - tar -vr --file=$backup_location/emoncms-backup-$date.tar -C $database_path phpfina 2>&1 - if [ $? -ne 0 ]; then - echo "Error: failed to tar phpfina" - fi -else - echo "no phpfina directory" -fi - -if [ -d $database_path/phpfiwa ] -then - echo "-- adding $database_path/phpfiwa to archive --" - tar -vr --file=$backup_location/emoncms-backup-$date.tar -C $database_path phpfiwa 2>&1 - if [ $? -ne 0 ]; then - echo "Error: failed to tar phpfiwa" - fi -else - echo "no phpfiwa directory" -fi +for dir in phpfina phpfiwa phptimeseries +do + if [ -d "${database_path}/${dir}" ] + then + echo "-- adding ${database_path}/${dir} to archive --" + tar -vr --file="${tar_filename}" -C "${database_path}" "${dir}" 2>&1 + if [ $? -ne 0 ]; then + echo "Error: failed to tar ${dir}" + fi + included+=("${dir}") + else + echo "no ${database_path}/${dir} directory to backup" + not_found+=("${dir}") + fi +done -if [ -d $database_path/phptimeseries ] -then - echo "-- adding $database_path/phptimeseries to archive --" - tar -vr --file=$backup_location/emoncms-backup-$date.tar -C $database_path phptimeseries 2>&1 - if [ $? -ne 0 ]; then - echo "Error: failed to tar phptimeseries" - fi -else - echo "no phptimeseries directory $database_path/phptimeseries" -fi +sudo systemctl start feedwriter > /dev/null # Compress backup echo "Compressing archive..." -gzip -fv $backup_location/emoncms-backup-$date.tar 2>&1 +gzip -fv "${tar_filename}" 2>&1 if [ $? -ne 0 ]; then echo "Error: failed to compress tar file" echo "emoncms export failed" - sudo systemctl start feedwriter > /dev/null exit 1 fi -sudo systemctl start feedwriter > /dev/null - -echo "Backup saved: $backup_location/emoncms-backup-$date.tar.gz" +echo "Backup saved: ${tar_filename}.gz" date +echo -e "\nBackup included components: ${included[*]}" +echo -e "INFO: These components couldn't be found to backup: ${not_found[*]}\n" + echo "Export finished...refresh page to view download link" -echo "=== Emoncms export complete! ===" # This string is identified in the interface to stop ongoing AJAX calls, please ammend in interface if changed here + +# The exit trap will pickup the natural exit and display the string to stop ongoing AJAX calls diff --git a/emoncms-import.sh b/emoncms-import.sh index abfc04a..a5ba544 100755 --- a/emoncms-import.sh +++ b/emoncms-import.sh @@ -1,23 +1,24 @@ #!/bin/bash -script_location="`dirname $0`" +script_location="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" +config_location=${script_location}/config.cfg echo "=== Emoncms import start ===" date +"%Y-%m-%d-%T" echo "Backup module version:" -cat $script_location/backup/module.json | grep version +grep version "${script_location}/module.json" echo "EUID: $EUID" -echo "Reading $script_location/config.cfg...." -if [ -f "$script_location/config.cfg" ] +echo "Reading ${config_location}...." +if [ -f "${config_location}" ] then - source "$script_location/config.cfg" + source "${config_location}" echo "Location of data databases: $database_path" echo "Location of emonhub.conf: $emonhub_config_path" echo "Location of Emoncms: $emoncms_location" echo "Backup destination: $backup_location" echo "Backup source path: $backup_source_path" else - echo "ERROR: Backup $script_location/backup/config.cfg file does not exist" + echo "ERROR: Backup config file ${config_location} does not exist" exit 1 fi @@ -52,24 +53,24 @@ fi # Get latest backup filename -if [ ! -d $backup_source_path ]; then - echo "Error: $backup_source_path does not exist, nothing to import" +if [ ! -d "${backup_source_path}" ]; then + echo "Error: ${backup_source_path} does not exist, nothing to import" exit 1 fi -backup_filename=$((cd $backup_source_path && ls -t *.tar.gz) | head -1) -if [[ -z "$backup_filename" ]] #if backup does not exist (empty filename string) +backup_filename=$(ls -t "${backup_source_path}"/*.tar.gz | head -1) +if [[ -z "${backup_filename}" ]] #if backup does not exist (empty filename string) then echo "Error: cannot find backup, stopping import" exit 1 fi # if backup exists -echo "Backup found: $backup_filename starting import.." +echo "Backup found: ${backup_filename} starting import.." echo "Read MYSQL authentication details from settings.php" -if [ -f $script_location/get_emoncms_mysql_auth.php ]; then - auth=$(echo $emoncms_location | php $script_location/get_emoncms_mysql_auth.php php) +if [ -f "${script_location}/get_emoncms_mysql_auth.php" ]; then + auth=$(echo "${emoncms_location}" | php "${script_location}/get_emoncms_mysql_auth.php" php) IFS=":" read username password database <<< "$auth" else echo "Error: cannot read MYSQL authentication details from Emoncms settings.php" @@ -79,27 +80,31 @@ fi echo "Decompressing backup.." -if [ ! -d $backup_location/import ]; then - mkdir $backup_location/import - sudo chown $user $backup_location/import -R +import_location="${backup_location}/import" +if [ -d "${import_location}" ]; then + sudo rm -rf "${import_location}" + # Belt and braces cleanup in case any '.' prefixed files exist fi -tar xfzv $backup_source_path/$backup_filename -C $backup_location/import 2>&1 +mkdir "${import_location}" +sudo chown "${user}" "${import_location}" + +tar xfzv "${backup_filename}" -C "${import_location}" 2>&1 if [ $? -ne 0 ]; then echo "Error: failed to decompress backup" - echo "$backup_source_path/$backup_filename has not been removed for diagnotics" - echo "Removing files in $backup_location/import" - sudo rm -Rf $backup_location/import/* + echo "${backup_filename} has not been removed for diagnotics" + echo "Removing files in ${import_location}" + sudo rm -Rf "${import_location}/*" echo "Import failed" exit 1 fi echo "Removing compressed backup to save disk space.." -sudo rm $backup_source_path/$backup_filename +sudo rm "${backup_filename}" if [ -n "$password" ] then # if username sring is not empty - if [ -f $backup_location/import/emoncms.sql ]; then + if [ -f "${import_location}/emoncms.sql" ]; then echo "Stopping services.." if [[ $emonhub == "loaded" ]]; then sudo systemctl stop emonhub @@ -114,7 +119,7 @@ then # if username sring is not empty sudo systemctl stop emoncms_mqtt fi echo "Emoncms MYSQL database import..." - mysql -u$username -p$password $database < $backup_location/import/emoncms.sql + mysql -u"${username}" -p"${password}" "${database}" < "${import_location}/emoncms.sql" if [ $? -ne 0 ]; then echo "Error: failed to import mysql data" echo "Import failed" @@ -130,27 +135,31 @@ else fi echo "Import feed meta data.." -sudo rm -rf $database_path/{phpfina,phptimeseries} 2> /dev/null +sudo rm -rf "${database_path}"/{phpfina,phptimeseries} 2> /dev/null echo "Restore phpfina and phptimeseries data folders..." -if [ -d $backup_location/import/phpfina ]; then - sudo mv $backup_location/import/phpfina $database_path - sudo chown -R www-data:root $database_path/phpfina +if [ -d "${import_location}/phpfina" ]; then + sudo mv "${import_location}/phpfina" "${database_path}" + sudo chown -R www-data:root "${database_path}/phpfina" fi -if [ -d $backup_location/import/phptimeseries ]; then - sudo mv $backup_location/import/phptimeseries $database_path - sudo chown -R www-data:root $database_path/phptimeseries +if [ -d "${import_location}/phptimeseries" ]; then + sudo mv "${import_location}/phptimeseries" "${database_path}" + sudo chown -R www-data:root "${database_path}/phptimeseries" fi # cleanup -sudo rm $backup_location/import/emoncms.sql +sudo rm "${import_location}/emoncms.sql" # Save previous config settings as old.emonhub.conf -if [ -f $backup_location/import/emonhub.conf ]; then - echo "Import emonhub.conf > $emonhub_config_path/emohub.conf" - sudo mv $backup_location/import/emonhub.conf $emonhub_config_path/emonhub.conf - sudo chmod 666 $emonhub_config_path/emonhub.conf +if [ -f "${import_location}/emonhub.conf" ]; then + if [ -d "${emonhub_config_path}" ]; then + echo "Import emonhub.conf > ${emonhub_config_path}/emohub.conf" + sudo mv "${import_location}/emonhub.conf" "${emonhub_config_path}/emonhub.conf" + sudo chmod 666 "${emonhub_config_path}/emonhub.conf" + else + echo "WARNING: emonhub.conf found in backup, but no emonHub directory (${emonhub_config_path}) found" + fi fi # Start with blank emonhub.conf diff --git a/readme.md b/readme.md index b2555b7..648b703 100644 --- a/readme.md +++ b/readme.md @@ -32,6 +32,7 @@ Install this module in /opt/emoncms/modules: Run backup module installation script to modify php.ini and setup uploads folder: + cd backup ./install.sh ## Manual Export Instructions diff --git a/usb-import.sh b/usb-import.sh index 97d5a85..0649d7b 100755 --- a/usb-import.sh +++ b/usb-import.sh @@ -1,21 +1,22 @@ #!/bin/bash script_location="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" +config_location=${script_location}/config.cfg echo "=== USB Emoncms import start ===" date +"%Y-%m-%d-%T" echo "Backup module version:" -cat $script_location/backup-module/module.json | grep version +grep version ${script_location}/module.json echo "EUID: $EUID" -echo "Reading $script_location/config.cfg...." -if [ -f "$script_location/config.cfg" ] +echo "Reading ${config_location}...." +if [ -f "${config_location}" ] then - source "$script_location/config.cfg" + source "${config_location}" echo "Location of data databases: $database_path" echo "Location of emonhub.conf: $emonhub_config_path" echo "Location of Emoncms: $emoncms_location" else - echo "ERROR: Backup $script_location/backup/config.cfg file does not exist" + echo "ERROR: Backup config file ${config_location} does not exist" exit 1 fi