diff --git a/fstab b/fstab index 4bd233e..de95afc 100644 --- a/fstab +++ b/fstab @@ -1,4 +1,4 @@ -//USERNAME.your-storagebox.de/backup/backups /mnt/storagebox/backups smb3 uid=0,gid=1000,file_mode=0640,dir_mode=0750,credentials=/etc/storagebox-cifs-credentials.txt,iocharset=utf8,rw,mfsymlinks,vers=3,seal 0 0 +//USERNAME.your-storagebox.de/backup/backups /mnt/storagebox/backups smb3 uid=0,gid=1000,file_mode=0660,dir_mode=0770,credentials=/etc/storagebox-cifs-credentials.txt,iocharset=utf8,rw,mfsymlinks,vers=3,seal 0 0 //USERNAME.your-storagebox.de/backup /mnt/storagebox smb3 uid=0,gid=0,file_mode=0640,dir_mode=0755,credentials=/etc/storagebox-cifs-credentials.txt,iocharset=utf8,rw,mfsymlinks,vers=3,seal 0 0 //USERNAME.your-storagebox.de/backup/syncthing /mnt/storagebox/syncthing smb3 uid=101000,gid=101000,file_mode=0640,dir_mode=0750,credentials=/etc/storagebox-cifs-credentials.txt,iocharset=utf8,rw,mfsymlinks,vers=3,seal 0 0 //USERNAME.your-storagebox.de/backup/fireshare /mnt/storagebox/fireshare smb3 uid=101006,gid=101006,file_mode=0644,dir_mode=0755,credentials=/etc/storagebox-cifs-credentials.txt,iocharset=utf8,rw,mfsymlinks,vers=3,seal 0 0 diff --git a/manage.py b/manage.py index 20a2258..c98dfa9 100755 --- a/manage.py +++ b/manage.py @@ -4,6 +4,7 @@ import os, sys, re import filecmp from glob import glob from mako.template import Template +from pathlib import Path import subprocess import yaml @@ -13,6 +14,26 @@ def backupProj(project): # loop env.volumes & secrets.postgres +def borgCreate(name, path=None, database=None): + if path is None and database is None: + print(f"Backup failed, you must pass at least one parameter amongst: path, database (archive name = {name}).", file=sys.stderr) + return + + if path is not None: + absPath = Path(path).absolute() + + print(f"Creating archive '{name}' from path {absPath}.") + + parentDir = absPath.parent.absolute() + os.chdir(parentDir) + + runBorg(["create", "--compression=lzma", f"{env['borg_repo']}::{name}-" + '{now:%Y-%m-%d_%H-%M-%S}', absPath.relative_to(parentDir)]) + + runBorg(["prune", "--glob-archives", f"{name}-*"] + env['borg_prune_opts'] + [env['borg_repo']]) + + os.chdir(os.path.realpath(sys.path[0])) + + def getImageId (image): return runPodman("image", ["inspect", "--format", "{{.Id}}", image]).stdout.strip() @@ -56,6 +77,22 @@ def renderFile(templateFile): outputFile.close() +def runBorg(args): + if isinstance(args, str): + args = args.split(' ') + + env = {"BORG_PASSPHRASE": secrets['borg']} + child = subprocess.Popen(["borg"] + args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, env=env) + + child.wait() + + stderr = child.stderr.read().strip() + if stderr != '': + print(stderr, file=sys.stderr) + + return child + + def runPodman(cmd, args): if isinstance(args, str): args = args.split(' ') @@ -106,6 +143,7 @@ def setCertPerms(service): def setNftables(): + print() renderFile("nftables.conf.mako") if not filecmp.cmp("nftables.conf.rendered", "/etc/nftables.conf"): print("nftables.conf changed, copying new version.") @@ -230,10 +268,10 @@ def main(): target_projects = target_projects.split(' ') print(f"Target projects: {target_projects}") - setNftables() - match action: case '1' | 'S': + setNftables() + for project in target_projects: try: print() @@ -251,6 +289,24 @@ def main(): print(e, file=sys.stderr) print(f"Failed to update project {project}.", file=sys.stderr) + case '3' | 'B': + print() + if not os.path.exists(env['borg_repo']): + print(f"Creating borg repository {env['borg_repo']}.") + runBorg(["init", "--encryption", "repokey", env['borg_repo']]) + + borgCreate("secrets", path=secretsFile) + + for project in target_projects: + try: + print() + backupProj(project) + except Exception as e: + print(e, file=sys.stderr) + print(f"Failed to backup project {project}.", file=sys.stderr) + + runBorg(["compact", env['borg_repo']]) + if __name__ == "__main__": main() diff --git a/pyenv.yml b/pyenv.yml index 51c218c..1b5239f 100644 --- a/pyenv.yml +++ b/pyenv.yml @@ -20,8 +20,13 @@ socket: "/run/podman/podman.sock" % endif -borg_repodir: /mnt/storagebox/backups/borg -borg_passphrase_file: /etc/borg-passphrase.txt +borg_repo: /mnt/storagebox/backups/borg2 +borg_prune_opts: + - "--keep-within=1d" + - "--keep-daily=7" + - "--keep-weekly=4" + - "--keep-monthly=12" + - "--keep-yearly=86" certs: diff --git a/setup.sh b/setup.sh index f75c483..9c76d2d 100755 --- a/setup.sh +++ b/setup.sh @@ -15,14 +15,14 @@ declare -a podman_units=(podman.service podman.socket podman-auto-update.service if [[ "$podman_mode" == "rootless" ]]; then - sudo apt install -y aardvark-dns cifs-utils dbus-user-session nftables passt podman podman-compose python3-mako uidmap + sudo apt install -y aardvark-dns borgbackup cifs-utils dbus-user-session nftables passt podman podman-compose python3-mako uidmap sudo loginctl enable-linger "$USER" sudo systemctl disable --now "${podman_units[@]}" systemctl --user enable --now "${podman_units[@]}" else - sudo apt install -y aardvark-dns cifs-utils nftables podman podman-compose python3-mako + sudo apt install -y aardvark-dns borgbackup cifs-utils nftables podman podman-compose python3-mako systemctl --user disable --now "${podman_units[@]}" sudo systemctl enable --now "${podman_units[@]}"