summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxengineering <me@xengineering.eu>2021-10-06 08:43:07 +0200
committerxengineering <me@xengineering.eu>2021-10-07 07:50:36 +0200
commit5220b95a03db1edc348d719c683d179962acd0d5 (patch)
treeddb8053091e1861837047901f585b1b9fa679a05
parente5aeb1b18945868ef21c63f1e1dfbb46408acb58 (diff)
downloadxbackup-5220b95a03db1edc348d719c683d179962acd0d5.tar
xbackup-5220b95a03db1edc348d719c683d179962acd0d5.tar.zst
xbackup-5220b95a03db1edc348d719c683d179962acd0d5.zip
Implement manual Backup
-rw-r--r--.gitignore2
-rw-r--r--README.md9
-rw-r--r--config/debug.json21
-rw-r--r--config/default.json20
-rw-r--r--src/debug.py2
-rw-r--r--src/xbackup/backup.py100
-rw-r--r--src/xbackup/config.py2
-rw-r--r--src/xbackup/script.py37
8 files changed, 181 insertions, 12 deletions
diff --git a/.gitignore b/.gitignore
index eeb8a6e..5f8400c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,3 @@
**/__pycache__
+backups
+fakeroot
diff --git a/README.md b/README.md
index e529901..8a32160 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,8 @@ This is a convenience wrapper around the Borg backup tool.
## Expected Environment
-This tool is designed for Arch Linux. Because it is written in Python and has minimal dependencies it should be easy to adapt it to other Linux distributions.
+This tool is designed for Arch Linux. Because it is written in Python and has
+minimal dependencies it should be easy to adapt it to other Linux distributions.
## Installation
@@ -20,13 +21,15 @@ cd xbackup/archlinux
make install
```
-This will create the Arch Linux package for xbackup and installs it as a foreign / unofficial package (like the AUR packages).
+This will create the Arch Linux package for xbackup and installs it as a
+foreign / unofficial package (like the AUR packages).
## Done / Features
(Last finished task first)
+- [x] manual backup functionality / MVP
- [x] config parsing
- [x] argument parsing
- [x] implement Arch Linux Packaging
@@ -37,8 +40,6 @@ This will create the Arch Linux package for xbackup and installs it as a foreign
(Highest priority first)
-- [ ] manual backup functionality / MVP
-- [ ] software list file support (generates list of all linux packages)
- [ ] XMPP notification via [xbot](https://gitea.xengineering.eu/xengineering/xbot)
- [ ] MariaDB fullbackup
- [ ] backup systemd daemon
diff --git a/config/debug.json b/config/debug.json
new file mode 100644
index 0000000..948b432
--- /dev/null
+++ b/config/debug.json
@@ -0,0 +1,21 @@
+{
+ "backup":{
+ "backup_source":"fakeroot",
+ "borg_repos_folder":"fakeroot/var/lib/xbackup/borg",
+ "blacklist":[
+ "dev/*",
+ "lost+found/*",
+ "media/*",
+ "mnt/*",
+ "proc/*",
+ "run/*",
+ "sys/*",
+ "tmp/*"
+ ],
+ "keep-hourly":null,
+ "keep-daily":7,
+ "keep-weekly":4,
+ "keep-monthly":6,
+ "keep-yearly":null
+ }
+}
diff --git a/config/default.json b/config/default.json
index 2bfd471..fd0b5b4 100644
--- a/config/default.json
+++ b/config/default.json
@@ -1,3 +1,21 @@
{
- "test":4
+ "backup":{
+ "backup_source":"/",
+ "borg_repos_folder":"/var/lib/xbackup/borg",
+ "blacklist":[
+ "dev/*",
+ "lost+found/*",
+ "media/*",
+ "mnt/*",
+ "proc/*",
+ "run/*",
+ "sys/*",
+ "tmp/*"
+ ],
+ "keep-hourly":null,
+ "keep-daily":7,
+ "keep-weekly":4,
+ "keep-monthly":6,
+ "keep-yearly":null
+ }
}
diff --git a/src/debug.py b/src/debug.py
index f075e25..6daa264 100644
--- a/src/debug.py
+++ b/src/debug.py
@@ -1,5 +1,5 @@
#!/usr/bin/python3
-# vim: shiftwidth=4 tabstop=4 expandtab
+# vim: shiftwidth=4 softtabstop=4 tabstop=4 expandtab
"""A Debug Script for Development Purposes"""
diff --git a/src/xbackup/backup.py b/src/xbackup/backup.py
new file mode 100644
index 0000000..b56e0cc
--- /dev/null
+++ b/src/xbackup/backup.py
@@ -0,0 +1,100 @@
+#!/usr/bin/python3
+# vim: shiftwidth=4 softtabstop=4 tabstop=4 expandtab
+
+
+"""Backup Functionality of xbackup"""
+
+
+import os
+import sys
+import subprocess
+
+
+def backup(config):
+ """perform a file-based full system backup"""
+
+ # generate all necessary paths based on config
+ paths = Filepaths(config)
+ print(paths)
+
+ # init borg repository (accepting failure on already existing repo)
+ shell("borg init -e none {}".format(paths.borg_repo), panic=False)
+
+ # run backup
+ command = "borg create -v --stats --compression zstd \\"
+ command += """
+ {repo}::'{{hostname}}-{{user}}-{{now:%Y-%m-%d_%H:%M:%S}}' \\""".format(
+ repo=paths.borg_repo
+ )
+ command += "\n {} \\".format(paths.backup_source)
+ for key,value in enumerate(paths.blacklist):
+ command += "\n --exclude '{}'".format(value)
+ if key != len(paths.blacklist) -1:
+ command += " \\"
+
+ shell(command)
+
+
+class Filepaths(object):
+ """A Container Class to hold Filepaths for the Borg Backup Tool"""
+
+ def __init__(self, config):
+ """The Constructor"""
+
+ # parse backup source (usually / for system backups)
+ self.backup_source = config["backup_source"]
+
+ #
+ self.borg_repos_folder = config["borg_repos_folder"]
+
+ # path to the borg repository
+ hostname = os.uname()[1]
+ self.borg_repo = os.path.join(self.borg_repos_folder, hostname)
+
+ # create blacklist of folders to be excluded from the backup
+ self.blacklist = []
+ for entry in config["blacklist"]:
+ self.blacklist.append(os.path.join(self.backup_source, entry))
+
+ # avoid matroska-style backups of backups (yes, it is important)
+ self.blacklist.append(self.borg_repos_folder)
+
+ def __str__(self):
+ """Converts an Object based on this Class to a String"""
+
+ retval = ""
+
+ retval += "\nbackup_source:\n" + self.backup_source + "\n"
+
+ retval += "\nblacklist:\n"
+ for item in self.blacklist:
+ retval += item + "\n"
+
+ retval += "\nborg_repo:\n" + self.borg_repo + "\n"
+
+ return retval
+
+
+def shell(command, panic=True):
+ """Savely execute a Shell Command
+
+ - set panic=False to continue with execution on non-zero return code
+ """
+
+ # print command
+ print("\nExecuting '" + command + "' ...")
+
+ # command execution
+ return_code = subprocess.call(command, shell=True)
+
+ # handle non-zero return code
+ if return_code != 0 and panic:
+ print("Command '{}'\nfailed with return code {}".format(
+ command,
+ str(return_code)
+ ))
+ sys.exit(return_code)
+
+ # final message and return
+ print("... done!")
+ return
diff --git a/src/xbackup/config.py b/src/xbackup/config.py
index 1e115a5..4c72915 100644
--- a/src/xbackup/config.py
+++ b/src/xbackup/config.py
@@ -1,5 +1,5 @@
#!/usr/bin/python3
-# vim: shiftwidth=4 tabstop=4 expandtab
+# vim: shiftwidth=4 softtabstop=4 tabstop=4 expandtab
"""Module for Configuration Parsing Functionality of xbackup"""
diff --git a/src/xbackup/script.py b/src/xbackup/script.py
index b69da00..c8e619b 100644
--- a/src/xbackup/script.py
+++ b/src/xbackup/script.py
@@ -1,5 +1,5 @@
#!/usr/bin/python3
-# vim: shiftwidth=4 tabstop=4 expandtab
+# vim: shiftwidth=4 softtabstop=4 tabstop=4 expandtab
"""Module for the Script Functionality of xbackup"""
@@ -10,6 +10,7 @@ import time
import sys
from xbackup import config
+from xbackup import backup
def run():
@@ -18,15 +19,16 @@ def run():
args = parse_arguments()
cfg = config.get(args.config)
+ welcome()
+
if args.command == "backup":
- print("Performing dummy backup based on '{}'".format(args.config))
- print("Config is:\n{}".format(config.dump(cfg)))
- time.sleep(1)
- print("Done!")
+ backup.backup(cfg["backup"])
else:
print("Unknown command '{}'".format(args.command))
sys.exit(1)
+ bye()
+
def parse_arguments():
"""handles argument parsing with the argparse module"""
@@ -53,3 +55,28 @@ def parse_arguments():
# argument parsing
args = parser.parse_args()
return args
+
+
+def welcome():
+ """Print Welcome Text"""
+
+ print("""
+################################################################################
+ _ _
+ __ _| |__ __ _ ___| | ___ _ _ __
+ \ \/ / '_ \ / _` |/ __| |/ / | | | '_ \
+ > <| |_) | (_| | (__| <| |_| | |_) |
+ /_/\_\_.__/ \__,_|\___|_|\_\\\\__,_| .__/
+ |_|
+
+################################################################################
+""", end="")
+
+
+def bye():
+ """Print final Text"""
+
+ print("""
+################################################################################
+
+""", end="")