From 8d57815b79240985ced6a7d81046b99536d5696c Mon Sep 17 00:00:00 2001 From: lhahn Date: Wed, 24 Jul 2024 20:39:13 +0200 Subject: [PATCH] Refactor borg to be backup and restore script. --- defaults/main.yml | 10 +- tasks/client.yml | 8 +- .../usr/local/bin/authentik-backup.sh.j2 | 65 -------- templates/usr/local/bin/cloud_backup.j2 | 145 ++++++++++++++++++ templates/usr/local/bin/mailcow-backup.sh.j2 | 26 ---- templates/usr/local/bin/vault-backup.sh.j2 | 20 --- 6 files changed, 157 insertions(+), 117 deletions(-) delete mode 100644 templates/usr/local/bin/authentik-backup.sh.j2 create mode 100644 templates/usr/local/bin/cloud_backup.j2 delete mode 100644 templates/usr/local/bin/mailcow-backup.sh.j2 delete mode 100755 templates/usr/local/bin/vault-backup.sh.j2 diff --git a/defaults/main.yml b/defaults/main.yml index b82ff09..8f8d5ed 100755 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -17,6 +17,12 @@ backup_run_folder: "{{ cloud_storage }}" backup_storage_key: "MyStorageKey" backup_client: true -backup_host: "example" +backup_app: app backup_cron_specialtime: "daily" -backup_cron_owner: "{{ backup_owner }}" \ No newline at end of file +backup_cron_owner: "{{ backup_owner }}" + +backup_script: + prework_backup: | + echo "This is executed before borg backup. Please collect data for backup in path: {{ backup_storage }}" + postwork_restore: | + echo "This is executed after borg restore. Please collect data during restore from path: {{ backup_storage }}" diff --git a/tasks/client.yml b/tasks/client.yml index e2bd338..18852cd 100644 --- a/tasks/client.yml +++ b/tasks/client.yml @@ -32,15 +32,15 @@ - name: setup backup script template: - src: "./usr/local/bin/{{ backup_host }}-backup.sh.j2" - dest: "/usr/local/bin/backup.sh" + src: "./usr/local/bin/cloud_backup.j2" + dest: "/usr/local/bin/cloud_backup" owner: "{{ backup_owner }}" group: "{{ backup_group }}" mode: "0750" - name: setup cron backup job cron: - name: "{{ backup_host }} backup" + name: "cloud backup" user: "{{ backup_cron_owner }}" - job: "/usr/local/bin/backup.sh" + job: "/usr/local/bin/cloud_backup backup" special_time: "{{ backup_cron_specialtime }}" \ No newline at end of file diff --git a/templates/usr/local/bin/authentik-backup.sh.j2 b/templates/usr/local/bin/authentik-backup.sh.j2 deleted file mode 100644 index 3551f02..0000000 --- a/templates/usr/local/bin/authentik-backup.sh.j2 +++ /dev/null @@ -1,65 +0,0 @@ -#!/bin/bash - -BORGUSER="{{ backup_owner }}"; -RUNFOLDER="{{ backup_run_folder }}"; -TARGETFOLDER="{{ backup_storage }}"; -REPOLOCATION="{{ backup_location }}"; -ARCHIVENAME="authentik-$(date '+%s')"; - -cd $RUNFOLDER; -POSTGRES_DOCKER_ID=$(docker ps --format '{{.ID}} {{.Names}}' | grep postgres | cut -f 1 -d ' '); - -mkdir $TARGETFOLDER/$ARCHIVENAME; -docker exec -i $POSTGRES_DOCKER_ID /usr/local/bin/pg_dump --username {{ authentik_db.user }} {{ authentik_db.name }} > $TARGETFOLDER/authentik-postgres-backup.sql - -sudo -H -u $BORGUSER bash -c ' -TARGETFOLDER='$TARGETFOLDER'; -REPOLOCATION='$REPOLOCATION'; -ARCHIVENAME='$ARCHIVENAME'; -export BORG_PASSPHRASE=$(cat {{ backup_home }}/.borg.key); -borg create -C lzma $REPOLOCATION::$ARCHIVENAME $TARGETFOLDER/$ARCHIVENAME'; -rm -rf $TARGETFOLDER/$ARCHIVENAME; - - -### RESTORE!!! ### -SHUTDOWN_CONTAINER_IDS=$(docker ps --format '{{.ID}} {{.Names}}' | cut -f 1 -d ' ' | grep -v $POSTGRES_DOCKER_ID | tr '\n' ' '); -docker stop $SHUTDOWN_CONTAINER_IDS -docker exec -i $POSTGRES_DOCKER_ID /usr/local/bin/dropdb --username {{ authentik_db.user }} '{{ authentik_db.name }}' -docker exec -i $POSTGRES_DOCKER_ID /usr/local/bin/createdb --username {{ authentik_db.user }} '{{ authentik_db.name }}' -docker exec -i $POSTGRES_DOCKER_ID /usr/local/bin/psql --username {{ authentik_db.user }} -d {{ authentik_db.name }} < $TARGETFOLDER/authentik-postgres-backup.sql -docker-compose down -docker-compose up -d - -help (){ - echo "Here Help"; -} - -( - flock -n 9 || { - echo "PERFORMANCE TEST ABORTED! ALREADY RUNNING!"; - exit 1; - } - - if [[ $(id -u) != 0 ]]; then - echo "Performance test aborted; please become root in order to run a performance test."; - exit 1; - fi - - if [ $# = 0 ]; then - help - exit 0; - fi - - case $tooling in - "atlassian") - echo "blah"; - ;; - *) - # I know this looks stupid, only one case, but in future we want to use TaaS/TReX aswell... - # So let's make it future safe! - echo -e "Invalid tooling '$tooling'.Please check help for correct list." - exit 1 - ;; - esac - echo "" -) 9>/var/run/lock/devstack-loadtest.lock; \ No newline at end of file diff --git a/templates/usr/local/bin/cloud_backup.j2 b/templates/usr/local/bin/cloud_backup.j2 new file mode 100644 index 0000000..684d659 --- /dev/null +++ b/templates/usr/local/bin/cloud_backup.j2 @@ -0,0 +1,145 @@ +#!/bin/bash + +BORGUSER="{{ backup_owner }}"; +RUNFOLDER="{{ backup_run_folder }}"; +TARGETFOLDER="{{ backup_storage }}"; +REPOLOCATION="{{ backup_location }}"; +ARCHIVENAME="{{ backup_app }}-$(date '+%s')"; + +help (){ + echo "cloud_backup - backup and restore script on cloud with borg target v1.0 by L.Hahn. + +Usage: $0 COMMAND [ARCHIVENAME] + +COMMAND: + - list List available archives in remote borg repository for your host. + - backup Perform backup of your host and create a new archive in borg repository. + - restore [ARCHIVENAME] Download backup from borg repository to your host and restore files. + May turn off your application if still running. + If no ARCHIVENAME is provided, the latest one based on timestamp is taken. + IF ARCHIVENAME is provided, will try to download it; throws error if not found. +"; +} + + +### INDIVIDUAL TEMPLATE PART ### +prework_backup () { + {{ backup_script.prework_backup | indent( width=4) }} +} + +postwork_restore () { + {{ backup_script.postwork_restore | indent( width=4) }} +} + + +### SHARED TEMPLATE PART ### +get_archives () { + ARCHIVEIDS=$( + sudo -H -u $BORGUSER bash -c ' + REPOLOCATION='$REPOLOCATION'; + export BORG_PASSPHRASE=$(cat {{ backup_home }}/.borg.key); + borg list $REPOLOCATION' | sort -r); + echo "$ARCHIVEIDS"; +} + +cloud_backup () { + mkdir -p $TARGETFOLDER/$ARCHIVENAME; + prework_backup; + cd /; + sudo -H -u $BORGUSER bash -c ' + TARGETFOLDER='$TARGETFOLDER'; + REPOLOCATION='$REPOLOCATION'; + ARCHIVENAME='$ARCHIVENAME'; + export BORG_PASSPHRASE=$(cat {{ backup_home }}/.borg.key); + borg create -C lzma $REPOLOCATION::$ARCHIVENAME $TARGETFOLDER/$ARCHIVENAME'; + + rm -rf $TARGETFOLDER/$ARCHIVENAME; +} + +cloud_restore () { + ARCHIVENAME=$1; + ARCHIVEIDS=$(get_archives | cut -f 1 -d ' '); + if [[ "${ARCHIVENAME,,}" == "latest" ]]; + then + ARCHIVENAME=$(echo "$ARCHIVEIDS" | head -n 1); + else + if [[ "$ARCHIVEIDS" != *$ARCHIVENAME* ]]; + then + echo "ERROR! Provided archivename '$ARCHIVENAME' is not part of the available archives! Aborting."; + exit 1; + fi + fi + + mkdir -p $TARGETFOLDER/$ARCHIVENAME; + chown -R $BORGUSER: $TARGETFOLDER + + cd /; + sudo -H -u $BORGUSER bash -c ' + REPOLOCATION='$REPOLOCATION'; + ARCHIVENAME='$ARCHIVENAME'; + export BORG_PASSPHRASE=$(cat {{ backup_home }}/.borg.key); + borg extract $REPOLOCATION::$ARCHIVENAME --list'; + + postwork_restore; + rm -rf $TARGETFOLDER/$ARCHIVENAME; +} + +cloud_backup_delete () { + ARCHIVENAME=$1; + ARCHIVEIDS=$(get_archives | cut -f 1 -d ' '); + if [[ "$ARCHIVEIDS" != *$ARCHIVENAME* ]]; + then + echo "ERROR! Provided archivename '$ARCHIVENAME' is not part of the available archives! Aborting."; + exit 1; + fi + + sudo -H -u $BORGUSER bash -c ' + REPOLOCATION='$REPOLOCATION'; + ARCHIVENAME='$ARCHIVENAME'; + export BORG_PASSPHRASE=$(cat {{ backup_home }}/.borg.key); + borg delete $REPOLOCATION::$ARCHIVENAME'; + +} + +has_argument () { + if [[ -z "$1" ]]; + then + echo "Missing required paramter!"; + fi +} + +( + flock -n 9 || { + echo "BACKUP ALREADY RUNNING! ABORTING."; + exit 1; + } + + if [ $# = 0 ]; then + help; + exit 0; + fi + + action=$1 + case $action in + "list") + get_archives; + ;; + + "backup") + cloud_backup; + ;; + + "restore") + has_argument $2; + cloud_restore $2; + ;; + "delete") + has_argument $2; + cloud_backup_delete $2; + ;; + *) + help; + ;; + esac + echo "" +) 9>/var/run/lock/cloud-backup.lock; diff --git a/templates/usr/local/bin/mailcow-backup.sh.j2 b/templates/usr/local/bin/mailcow-backup.sh.j2 deleted file mode 100644 index 6798d91..0000000 --- a/templates/usr/local/bin/mailcow-backup.sh.j2 +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash - -BORGUSER="{{ backup_owner }}"; -RUNFOLDER="{{ backup_run_folder }}"; -TARGETFOLDER="{{ backup_storage }}"; -REPOLOCATION="{{ backup_location }}"; -ARCHIVENAME="mailcow-$(date '+%s')"; - -cd $RUNFOLDER; -MAILCOW_BACKUP_LOCATION="$TARGETFOLDER/" ./helper-scripts/backup_and_restore.sh backup all; -LATESTBACKUP="$(ls -t $TARGETFOLDER | head -n 1)"; - -if [[ "$LATESTBACKUP" != *"mailcow"* ]]; -then - echo "NOT MAILCOW! ABORT!"; - exit 1; -fi - -chown -R $BORGUSER: $TARGETFOLDER/$LATESTBACKUP; -sudo -H -u $BORGUSER bash -c ' -TARGETFOLDER='$TARGETFOLDER'; -REPOLOCATION='$REPOLOCATION'; -ARCHIVENAME='$ARCHIVENAME'; -export BORG_PASSPHRASE=$(cat {{ backup_home }}/.borg.key); -borg create -C lzma $REPOLOCATION::$ARCHIVENAME $TARGETFOLDER/$LATESTBACKUP'; -rm -rf $TARGETFOLDER/$LATESTBACKUP; diff --git a/templates/usr/local/bin/vault-backup.sh.j2 b/templates/usr/local/bin/vault-backup.sh.j2 deleted file mode 100755 index ee809b2..0000000 --- a/templates/usr/local/bin/vault-backup.sh.j2 +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - -BORGUSER="{{ backup_owner }}"; -RUNFOLDER="{{ backup_run_folder }}"; -TARGETFOLDER="{{ backup_storage }}"; -REPOLOCATION="{{ backup_location }}"; -ARCHIVENAME="vault-$(date '+%s')"; - -cd $RUNFOLDER; - -cp -r $RUNFOLDER/home $TARGETFOLDER/$ARCHIVENAME; -chown -R $BORGUSER: $TARGETFOLDER/$ARCHIVENAME; - -sudo -H -u $BORGUSER bash -c ' -TARGETFOLDER='$TARGETFOLDER'; -REPOLOCATION='$REPOLOCATION'; -ARCHIVENAME='$ARCHIVENAME'; -export BORG_PASSPHRASE=$(cat {{ backup_home }}/.borg.key); -borg create -C lzma $REPOLOCATION::$ARCHIVENAME $TARGETFOLDER/$ARCHIVENAME'; -rm -rf $TARGETFOLDER/$ARCHIVENAME; \ No newline at end of file