the f*ck rants about stuff

Small automatic Backup using python

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
comments?

If you liked this, I think you might be interested in some of these related articles:

¡ En Español !