falls jemand Lust hat darf er sehr gerne über meinen Code herfallen und jede noch so kleine Kleinigkeit bemängeln die gefunden werden kann.
Rahmenbedingungen: Ich habe an einem Raspberry Pi zwei externe Festplatten angeschlossen. Eine davon ist immer eingebunden und wir greifen als Netzwerklaufwerk auf die Daten zu. Die zweite Festplatte soll wöchentlich eingebunden werden, dann wird darauf ein Backup der ersten Platte gespeichert und dann wieder ausgebunden.
Da ich nicht immer alles neu sichern will und dann die Festplatte auch ziemlich schnell voll wäre, habe ich mir gedacht, ich mache jährlich ein "volles" Backup und nutze dann wöchentlich Hardlink-Backups. So sollen nur neu hinzugekommene oder geänderte Dateien gesichert werden. Was ich nicht will, es sollen keine Dateien gelöscht werden, wenn diese im zu sichernden Datenbestand nicht mehr da sind.
Ich würde dann jedes Jahr ein Backup extern sichern und dann mit einer leeren Platte wieder von vorne anfangen.
Soweit der Plan.
Unsicher bin ich mir bei meinen 'rsync'-Optionen. Könnt ihr mir sagen, ob ich da alles notwendige berücksichtigt habe?
Was mir nicht gefällt: Jetzt wird als Hardlink-Ordner immer der Ordner benutzt der 7 Tage älter als das aktuelle Datum ist. Das passt ja genau so lange, so lange ich das Backup nicht mal manuell aus irgendeinem Grund anstoße. Ich müsste als Hardlink-Ordner immer den Ordner nehmen, der am jüngsten ist. Ich weis gerade nur nicht wie ich das anstelle ohne 20 Zeilen Code zu brauchen. Hier wäre ich über Tipps sehr dankbar.
Mir wäre auch noch wichtig, das ich jeden möglichen Fehlerfall sinnvoll abdecke. Das sollte ein sehr zuverlässiges Programm werden.
So jetzt aber der Code:
Code: Alles auswählen
#!/usr/bin/env python3
import smtplib
import ssl
from datetime import date, timedelta
from subprocess import run
from email.mime.text import MIMEText
from pathlib import Path
BACKUP_PATH = Path("/media/Data_Backup/")
DATA_PATH = Path("/media/Data/")
def search_old_backups(date_today):
for folder in BACKUP_PATH.iterdir():
backup_date = folder.stem.split("-")
try:
#
# Only compare folders that starte with year
int(backup_date[0])
if not backup_date[0] == str(date_today).split("-")[0]:
return "full"
except ValueError:
pass
return "hardlinks"
def make_backup(backup_mode, date_today):
if backup_mode == "hardlinks":
hardlink_folder = date_today - timedelta(days=7)
try:
run(
[
"rsync",
"-vahHA",
f"--log-file={BACKUP_PATH}/Logs/{todays_date}.log",
f"--link-dest={BACKUP_PATH}/{hardlink_folder}",
DATA_PATH,
f"{BACKUP_PATH}/{todays_date}",
],
check=True,
)
return True, "Hardlinks-Backup"
except Exception as e:
return False, e
elif backup_mode == "full":
try:
run(
[
"rsync",
"-vahHA",
f"--log-file={BACKUP_PATH}/Logs/{todays_date}.log",
DATA_PATH,
f"{BACKUP_PATH}/{todays_date}",
],
check=True,
)
return True, "Full-Backup - Extern sichern!"
except Exception as e:
return False, e
def send_mail(state, text):
message = MIMEText(text)
message["Subject"] = state
message["From"] = "xxx@gmx.de"
message["To"] = "yyy@web.de"
context = ssl.create_default_context()
with smtplib.SMTP_SSL("mail.gmx.net", 465, context=context) as server:
server.login("xxx@gmx.de", "123456789")
server.sendmail(
"xxx@gmx.de", "yyy@web.de", message.as_string()
)
def main():
try:
run(["mount", BACKUP_PATH], check=True)
except:
send_mail("Backup nicht erfolgreich!", "Mount nicht erfolgreich")
date_today = date.today()
backup_mode = search_old_backups(date_today)
backup_state, text = make_backup(backup_mode, date_today)
if backup_state:
send_mail("Backup erfolgreich!", text)
else:
send_mail("Backup nicht erfolgreich!", text)
run(["umount", BACKUP_PATH], check=True)
if __name__ == "__main__":
main()
Grüße und Danke vorab
Dennis