EDIT: Newer version available
problem definition
An automatic backup of a database file inside a legacy windows virtual machine without internet access.
The client doesnt have a dedicated online machine for backups and the backup should “leave the building”
solution
A shared folder using virtuabox shared folders facilities. The database will be copied once a day
Outside the VM systemd will monitor the copy and launch the backup script
The backup will be compress using XZ and encrypted using gpg with an asymetric key
Finally, it will be sent for storage to one mail account where they can check if the backup was made
code
backup.py
#!/usr/bin/env python3
from datetime import datetime, timedelta
from os import path, remove
from subprocess import run
from sys import exit
now = datetime.now()
TO = "info@company.com"
BODY = "mail.body"
FILENAME = 'database.mdb'
PATH = '/home/company/shared'
FILE = path.join(PATH, FILENAME)
FILEXZ = FILE + ".xz"
OUTPUT = path.join(PATH, 'backup_{:%Y%m%d_%H%M%S}.gpg'.format(now))
XZ_CMD = "xz -k {}"
GPG_CMD = "gpg -q --batch --yes -e -r rk -o {} {}"
MAIL_CMD = "mutt -a {} -s '{}' -- {} < {}"
error = ""
# sanity file exists
if path.exists(FILE):
print("New file {} detected. Trying to generate {}".format(FILE, OUTPUT))
else:
exit("{} not found. Aborting".format(FILE))
filedate = datetime.fromtimestamp(path.getmtime(FILE))
# sanity date
if now - timedelta(hours=1) > filedate:
error = """The file you are sending was created 1+ hour ago
file date : {:%Y-%m-%d %H:%M:%S}
current date: {:%Y-%m-%d %H:%M:%S}
Please check if its the correct one
""".format(filedate, now)
# Compress
if path.isfile(FILEXZ):
remove(FILEXZ)
run(XZ_CMD.format(FILE).split())
# encrypt
run(GPG_CMD.format(OUTPUT, FILEXZ).split())
remove(FILEXZ)
# sanity size
filesize = path.getsize(OUTPUT)
if filesize < 5000000:
error += """"The size of the file you are sending is < 5Mb
File size in bytes: ({})
Please, Check if its the correct one
""".format(filesize)
subjectstr = "Backup {}ok with date {:%Y-%m-%d %H:%M:%S}"
subject = subjectstr.format("NOT " if error else "", now)
body = """Everything seems okay, but dont forget to check
manually if the saved file works okay once in a while!
"""
if error:
body = error
with open(BODY, "w") as f:
f.write(body)
print("{} generated correctly. Trying to send it to {}".format(OUTPUT, TO))
run(MAIL_CMD.format(OUTPUT, subject, TO, BODY), shell=True)
remove(OUTPUT)
Inside the VM using the scheduler
backup.bat
@echo off
xcopy /Y C:\program\database.mdb z:\
mutt conf file
.muttrc
set sendmail="/usr/bin/msmtp"
set use_from=yes
set realname="Backup"
set from=backup@company.com
set envelope_from=yes
systemd files
shared.service
[Unit]
Description=company backup service
[Service]
Type=oneshot
ExecStart=/root/backup/backup.py
shared.path
[Unit]
Description=shared file
[Path]
PathChanged=/home/company/shared/database.mdb
Unit=shared.service
[Install]
WantedBy=multi-user.target
If you liked this, I think you might be interested in some of these related articles:
- DEBIAN - How to clone a server using just rsync
- DEBIAN - Get a nearly fresh debian install without reinstalling
- DEBIAN - Destructive git behaviour
- DEBIAN - Copy list of packages installed to another debian machine
- PYTHON - No more bash