commit 443bb2b77c43c62da243f20f35fe7fa903230cf0 Author: Madeorsk Date: Mon Dec 25 21:08:03 2023 +0100 Initial commit, first working program. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f674684 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +# IDEA +*.iml +.idea/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..630a9b3 --- /dev/null +++ b/README.md @@ -0,0 +1,10 @@ +# Backscripts + +Scripts to manage backups. + +```shell +ksrackup {backup_name} init :: Initialize backup repository. +ksrackup {backup_name} backup :: Perform a new backup. +ksrackup {backup_name} prune :: Prune outdated backups. +ksrackup {backup_name} restic :: Execute an arbitrary restic command. +``` diff --git a/ksrackup b/ksrackup new file mode 100755 index 0000000..2709367 --- /dev/null +++ b/ksrackup @@ -0,0 +1,82 @@ +#!/bin/python3 + +import json +import subprocess +import sys +import os + +if len(sys.argv) < 3: + # Check commands arguments. + print("Usage: ") + print("ksrackup {backup_name} init :: Initialize backup repository.") + print("ksrackup {backup_name} backup :: Perform a new backup.") + print("ksrackup {backup_name} prune :: Prune outdated backups.") + print("ksrackup {backup_name} restic :: Execute an arbitrary restic command.") + exit(1) + +# Get command parameters. +backup_name = sys.argv[1] +command = sys.argv[2] # The executed command. + +# Open and read a backup configuration file. +backup_file = open(backup_name + ".json") +backup_data = json.load(backup_file) + +# Setup the restic environment from backup configuration. +restic_environment = { + "RESTIC_REPOSITORY": backup_data["restic"]["repository"], + "RESTIC_PASSWORD": backup_data["restic"]["password"], + "AWS_ACCESS_KEY_ID": backup_data["restic"]["access_key_id"], + "AWS_SECRET_ACCESS_KEY": backup_data["restic"]["secret_access_key"], +} + +# Create the backup directory. +os.makedirs(backup_name, exist_ok=True) +# Move to the backup directory. +os.chdir(backup_name) + +# Open error log file. +error_log = open("error.log", "a") + +# Execute the command. +if command == "init": + # Initialize a backup repository. + subprocess.run(["restic", "init"], env=restic_environment) +elif command == "backup": + + # Perform the right backup operations depending on its type. + if backup_data["type"] == "postgresql": + with open("database.sql", "w") as database_sql: + # Dump of the PostgreSQL database. + subprocess.run([ + "docker", "exec", backup_data["postgresql"]["container_name"], + "pg_dump", "-U", backup_data["postgresql"]["username"], backup_data["postgresql"]["database"], + ], stdout=database_sql, stderr=error_log) + # Save the dump in the restic repository. + subprocess.run(["restic", "backup", "database.sql"], env=restic_environment, stderr=error_log) + elif backup_data["type"] == "mysql": + with open("database.sql", "w") as database_sql: + # Dump of the MySQL database. + subprocess.run([ + "docker", "exec", backup_data["mysql"]["container_name"], + "mysqldump", "-u", backup_data["mysql"]["username"], "-p" + backup_data["mysql"]["password"], backup_data["mysql"]["database"], + ], stdout=database_sql, stderr=error_log) + # Save the dump in the restic repository. + subprocess.run(["restic", "backup", "database.sql"], env=restic_environment, stderr=error_log) + elif backup_data["type"] == "files": + # Save the files in the restic repository. + subprocess.run(["restic", "backup", backup_data["files"]["path"]], env=restic_environment, stderr=error_log) + +elif command == "prune": + # Define backups conservation policy. + prune_params = [ + "--keep-within", "28d", + "--keep-within-daily", "4m", + "--keep-within-weekly", "2y", + "--keep-monthly", "100", + ] + # Remove outdated backups. + subprocess.run(["restic", "forget", "--prune"] + prune_params, env=restic_environment, stderr=error_log) +elif command == "restic": + # Execute the arbitrary restic command. + subprocess.run(["restic"] + sys.argv[3:], env=restic_environment)