From 7ca52f73741ab1d11b976a7f2eaf45512d020a20 Mon Sep 17 00:00:00 2001 From: lhahn Date: Tue, 23 Jul 2024 21:07:37 +0200 Subject: [PATCH 1/4] Save Authentik Backup and Restore Sketch --- .../usr/local/bin/authentik-backup.sh.j2 | 31 +++++++++++++++++++ templates/usr/local/bin/idp-backup.sh.j2 | 1 - ...mail-backup.sh.j2 => mailcow-backup.sh.j2} | 0 3 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 templates/usr/local/bin/authentik-backup.sh.j2 delete mode 100644 templates/usr/local/bin/idp-backup.sh.j2 rename templates/usr/local/bin/{email-backup.sh.j2 => mailcow-backup.sh.j2} (100%) diff --git a/templates/usr/local/bin/authentik-backup.sh.j2 b/templates/usr/local/bin/authentik-backup.sh.j2 new file mode 100644 index 0000000..2773659 --- /dev/null +++ b/templates/usr/local/bin/authentik-backup.sh.j2 @@ -0,0 +1,31 @@ +#!/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 \ No newline at end of file diff --git a/templates/usr/local/bin/idp-backup.sh.j2 b/templates/usr/local/bin/idp-backup.sh.j2 deleted file mode 100644 index cc1f786..0000000 --- a/templates/usr/local/bin/idp-backup.sh.j2 +++ /dev/null @@ -1 +0,0 @@ -#!/bin/bash \ No newline at end of file diff --git a/templates/usr/local/bin/email-backup.sh.j2 b/templates/usr/local/bin/mailcow-backup.sh.j2 similarity index 100% rename from templates/usr/local/bin/email-backup.sh.j2 rename to templates/usr/local/bin/mailcow-backup.sh.j2 -- 2.39.5 From 7bc0a29fa033222b625de8083cb940d547023757 Mon Sep 17 00:00:00 2001 From: Lars Hahn Date: Wed, 24 Jul 2024 13:47:46 +0200 Subject: [PATCH 2/4] templates/usr/local/bin/authentik-backup.sh.j2 aktualisiert Storing idea about having nice backup script --- .../usr/local/bin/authentik-backup.sh.j2 | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/templates/usr/local/bin/authentik-backup.sh.j2 b/templates/usr/local/bin/authentik-backup.sh.j2 index 2773659..32ea293 100644 --- a/templates/usr/local/bin/authentik-backup.sh.j2 +++ b/templates/usr/local/bin/authentik-backup.sh.j2 @@ -28,4 +28,30 @@ docker exec -i $POSTGRES_DOCKER_ID /usr/local/bin/dropdb --username {{ authentik 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 \ No newline at end of file +docker-compose up -d + + +( + 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 + + 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 -- 2.39.5 From 2e113e72196da480263fbf6d4d0b038701a4e1af Mon Sep 17 00:00:00 2001 From: Lars Hahn Date: Wed, 24 Jul 2024 13:49:50 +0200 Subject: [PATCH 3/4] templates/usr/local/bin/authentik-backup.sh.j2 aktualisiert --- templates/usr/local/bin/authentik-backup.sh.j2 | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/templates/usr/local/bin/authentik-backup.sh.j2 b/templates/usr/local/bin/authentik-backup.sh.j2 index 32ea293..3551f02 100644 --- a/templates/usr/local/bin/authentik-backup.sh.j2 +++ b/templates/usr/local/bin/authentik-backup.sh.j2 @@ -30,6 +30,9 @@ docker exec -i $POSTGRES_DOCKER_ID /usr/local/bin/psql --username {{ authentik_d docker-compose down docker-compose up -d +help (){ + echo "Here Help"; +} ( flock -n 9 || { @@ -42,6 +45,11 @@ docker-compose up -d exit 1; fi + if [ $# = 0 ]; then + help + exit 0; + fi + case $tooling in "atlassian") echo "blah"; -- 2.39.5 From 0a4716378976404e448867d0b0afc1c5d1eb1d86 Mon Sep 17 00:00:00 2001 From: lhahn Date: Wed, 24 Jul 2024 20:39:13 +0200 Subject: [PATCH 4/4] 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 | 147 ++++++++++++++++++ templates/usr/local/bin/mailcow-backup.sh.j2 | 26 ---- templates/usr/local/bin/vault-backup.sh.j2 | 20 --- 6 files changed, 159 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..65d27cd --- /dev/null +++ b/templates/usr/local/bin/cloud_backup.j2 @@ -0,0 +1,147 @@ +#!/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' | grep {{ backup_app }} | 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!"; + exit 1; + 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; + exit 0; + ;; + 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 -- 2.39.5