From f2867954b69215e0f8c3cc70d030de0c2e4b927c Mon Sep 17 00:00:00 2001 From: jaydee Date: Thu, 12 Dec 2024 18:27:53 +0100 Subject: [PATCH] initial --- omv_backups copy.py | 73 +++++++++ omv_backups.py | 139 +++++++++++++++++ omv_backups_v3.py | 356 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 568 insertions(+) create mode 100644 omv_backups copy.py create mode 100644 omv_backups.py create mode 100644 omv_backups_v3.py diff --git a/omv_backups copy.py b/omv_backups copy.py new file mode 100644 index 0000000..258bcc0 --- /dev/null +++ b/omv_backups copy.py @@ -0,0 +1,73 @@ +import subprocess +import time +import datetime + +backups = { + "__GITHUB":"admin@192.168.77.106:/share/Data/__GITHUB", + "Photo":"admin@192.168.77.106:/share/Photo/Years" +} + +for b in backups: + SOURCE_DIR=backups[b] + now = datetime.datetime.now() + BACKUP_DIR="/srv/dev-disk-by-uuid-02fbe97a-cd9a-4511-8bd5-21f8516353ee/{}".format(b) + DATETIME = now.strftime("%Y-%m-%d_%H:%M:%S") + BACKUP_PATH="{}/{}".format(BACKUP_DIR, DATETIME) + LATEST_LINK="{}/latest".format(BACKUP_DIR) + + + cmnd = "mkdir -p {}".format(BACKUP_DIR) + status, output = subprocess.getstatusoutput(cmnd) + print(cmnd) + + #cmnd = "rsync -av --delete {}/ --link-dest {} --exclude=\".cache\" {}".format(SOURCE_DIR, LATEST_LINK, BACKUP_PATH) + cmnd = ["rsync", '--info=progress2', "-avz", "--delete", SOURCE_DIR, "--link-dest", LATEST_LINK, "--exclude=\".cache\"", BACKUP_PATH] + print(cmnd) + + #run_list = ['rsync', '--info=progress2', '-a', 'src/', 'dest/'] + # with subprocess.Popen( + # cmnd, stdout=subprocess.PIPE, bufsize=1, text=True + # ) as process: + # for line in iter(p.stdout.readline, b''): + # print(line.strip()) + + + + process = subprocess.Popen(cmnd, + stdout=subprocess.PIPE) + + while process.poll() is None: + line = process.stdout.readline() + l = line.splitlines() + i = -1 + a = len(l) + #print(l[-1]) + time.sleep(3) + print(len(l)) + while True: + for line in reversed(l): + print(len(line.split())) + e = str(line).split() + if len(e) > 4: + print(e[2]) + print(line) + break + break + + # print(l[-1]) + # #print(str(line)) + # time.sleep(3) + #print(cmnd) + #status, output = subprocess.getstatusoutput(cmnd) + # rsync -av --delete \ + # "${SOURCE_DIR}/" \ + # --link-dest "${LATEST_LINK}" \ + # --exclude=".cache" \ + # "${BACKUP_PATH}" + cmnd = "rm -rf {}".format(LATEST_LINK) + print(cmnd) + status, output = subprocess.getstatusoutput(cmnd) + + cmnd = "ln -s {} {}".format(BACKUP_PATH, LATEST_LINK) + print(cmnd) + status, output = subprocess.getstatusoutput(cmnd) \ No newline at end of file diff --git a/omv_backups.py b/omv_backups.py new file mode 100644 index 0000000..896541f --- /dev/null +++ b/omv_backups.py @@ -0,0 +1,139 @@ +import datetime +import logging +from paho.mqtt import client as mqtt_client +import getopt +import json +import time +import subprocess +import sys +import os +pid = os.getpid() + + +cmnd = "ps -ef|grep omv_backups.py|grep -v grep |grep -v {}|wc -l".format(pid) +status, output = subprocess.getstatusoutput(cmnd) + +print(output) +if int(output) > 0: + print("Running already!") + sys.exit() +broker = '192.168.77.106' +port = 1883 +topic_sum = "sectorq/omv/backups" +mqtt_username = 'jaydee' +mqtt_password = 'jaydee1' + +try: + opts, args = getopt.getopt(sys.argv[1:], "am", ["command=", "help", "output="]) +except getopt.GetoptError as err: + #usage() + sys.exit(2) +output = None +# QJ : getopts +_MODE = "manual" +for o, a in opts: + if o == "-a": + _MODE = "auto" + elif o in ("-m", "--manual"): + _MODE = "manual" + + +client = mqtt_client.Client() +client.username_pw_set(mqtt_username, mqtt_password) +client.connect(broker,1883,60) +now = datetime.datetime.now() +STARTTIME = now.strftime("%Y-%m-%d_%H:%M:%S") +msg = {"mode":_MODE, "status":"started","bak_name":"complete","start_time":STARTTIME,"end_time":"in progress","progress":0} +client.publish(topic_sum, json.dumps(msg)); +client.disconnect() + +backups = { + "github": + {"source":"admin@192.168.77.106:/share/Data/__GITHUB", + "exclude":"", + "active": True + }, + "photo": { + "source":"admin@192.168.77.106:/share/Photo/Years", + "exclude":"", + "active":True + }, + "docker_data":{ + "source":"admin@192.168.77.106:/share/docker_data/", + "exclude":"", + "active":True + } +} +BACKUP_FS = "/srv/dev-disk-by-uuid-02fbe97a-cd9a-4511-8bd5-21f8516353ee" +for b in backups: + topic = "sectorq/omv/backups/{}".format(b.lower()) + if not backups[b]["active"]: + print("Backup {} is not active!".format(b)) + client.connect(broker,1883,60) + msg = {"status":"inactive","bak_name":b,"start_time":"inactive","end_time":"inactive","progress":0} + + client.publish(topic, json.dumps(msg)) + client.disconnect() + continue + + SOURCE_DIR = backups[b]["source"] + now = datetime.datetime.now() + BACKUP_DIR="/srv/dev-disk-by-uuid-02fbe97a-cd9a-4511-8bd5-21f8516353ee/{}".format(b) + DATETIME = now.strftime("%Y-%m-%d_%H:%M:%S") + BACKUP_PATH="{}/{}".format(BACKUP_DIR, DATETIME) + LATEST_LINK="{}/latest".format(BACKUP_DIR) + msg = {"status":"started","bak_name":b,"start_time":DATETIME,"end_time":"in progress", "progress":0} + client.connect(broker,1883,60) + client.publish(topic, json.dumps(msg)); + client.disconnect() + + cmnd = "mkdir -p {}".format(BACKUP_DIR) + status, output = subprocess.getstatusoutput(cmnd) + print(cmnd) + + + #cmnd = "rsync -av --delete {}/ --link-dest {} --exclude=\".cache\" {}".format(SOURCE_DIR, LATEST_LINK, BACKUP_PATH) + cmnd = "rsync --info=progress2 -avz --delete {} --link-dest {} --exclude=\".cache\" --exclude=\".git\" --exclude=\"var_lib_motioneye\" {}".format(SOURCE_DIR, LATEST_LINK, BACKUP_PATH) + print(cmnd) + status, output = subprocess.getstatusoutput(cmnd) + cmnd = "rm -rf {}".format(LATEST_LINK) + print(cmnd) + status, output = subprocess.getstatusoutput(cmnd) + + cmnd = "ln -s {} {}".format(BACKUP_PATH, LATEST_LINK) + print(cmnd) + status, output = subprocess.getstatusoutput(cmnd) + + + #Remove old + print("Removing old dirs") + + #cmnd = "find {} -maxdepth 1 -type d -mtime +30 -exec rm -rf {{}} \;".format(BACKUP_DIR) + cmnd = "find {} -maxdepth 1 -type d -mmin +30 -exec rm -rf {{}} \;".format(BACKUP_DIR) + print(cmnd) + #status, output = subprocess.getstatusoutput(cmnd) + now = datetime.datetime.now() + ENDTIME = now.strftime("%Y-%m-%d_%H:%M:%S") + msg = {"status":"finished","bak_name":b,"start_time":DATETIME,"end_time":ENDTIME,"progress":0} + client.connect(broker,1883,10) + client.publish(topic, json.dumps(msg)) + client.disconnect() + +print("Getting size of FS") +#cmnd = "du -h --max-depth=0 {}".format(BACKUP_FS) +cmnd = "df -h /srv/dev-disk-by-uuid-02fbe97a-cd9a-4511-8bd5-21f8516353ee |awk '{ print $3 }'|tail -1" +status, output = subprocess.getstatusoutput(cmnd) +used_space = (output.split())[0] +now = datetime.datetime.now() +ENDJOB = now.strftime("%Y-%m-%d_%H:%M:%S") +print("Size : {}".format(used_space)) +print("Sending finished status") +msg = {"mode":_MODE,"status":"finished","bak_name":"complete","start_time":STARTTIME,"end_time":ENDJOB,"progress":0,"used_space":used_space} +print(msg) +client.connect(broker,1883,10) +client.publish(topic_sum, json.dumps(msg)) +client.disconnect() + +if _MODE == "auto": + cmnd = "systemctl suspend" + status, output = subprocess.getstatusoutput(cmnd) \ No newline at end of file diff --git a/omv_backups_v3.py b/omv_backups_v3.py new file mode 100644 index 0000000..5b89a5d --- /dev/null +++ b/omv_backups_v3.py @@ -0,0 +1,356 @@ +import datetime +import logging +from paho.mqtt import client as mqtt_client +import getopt +import json +import time +import socket +import subprocess +import sys +import os +import platform +import requests +from wakeonlan import send_magic_packet +pid = os.getpid() + +host = platform.node().lower() +cmnd = "ps -ef|grep omv_backups.py|grep -v grep |grep -v {}|wc -l".format(pid) +status, output = subprocess.getstatusoutput(cmnd) + +def is_port_open(host, port): + try: + sock = socket.create_connection((host, port)) + sock.close() + return True + except socket.error: + return False + +print(output) +if int(output) > 0: + print("Running already!") + sys.exit() +broker = 'mqtt.home.lan' +port = 1883 +topic_sum = "sectorq/omv/backups" +mqtt_username = 'jaydee' +mqtt_password = 'jaydee1' +print("1") +try: + opts, args = getopt.getopt(sys.argv[1:], "amftdr:b", ["command=", "help", "output="]) +except getopt.GetoptError as err: + #usage() + sys.exit(2) +output = None +# QJ : getopts +_MODE = "manual" +_FIRST = _TEST = _RESTORE = _BACKUP = False +_EXECUTE = True +for o, a in opts: + if o == "-a": + _MODE = "auto" + elif o in ("-m", "--manual"): + _MODE = "manual" + elif o in ("-f", "--first"): + _FIRST = True + elif o in ("-t", "--test"): + _TEST = True + elif o in ("-r", "--restore"): + _RESTORE = True + _APP = a + elif o in ("-b", "--backup"): + _BACKUP = True + elif o in ("-d", "--dry"): + _EXECUTE = False + +print("2") +client = mqtt_client.Client() +client.username_pw_set(mqtt_username, mqtt_password) +client.connect(broker,1883,60) +now = datetime.datetime.now() +STARTTIME = now.strftime("%Y-%m-%d_%H:%M:%S") +msg = {"mode":_MODE, "status":"started","bak_name":"complete","start_time":STARTTIME,"end_time":"in progress","progress":0} +client.publish(topic_sum, json.dumps(msg)); +client.disconnect() + +backups = { + "nas": { + "github": + {"source":"/share/Data/__GITHUB", + "exclude":"", + "active": True + }, + "photo": { + "source":"/share/Photo/Years", + "exclude":"", + "active":True + }, + }, + "m-server":{ + "docker_data":{ + "source":"/share/docker_data/", + "exclude":"", + "active":True + }, + "fail2ban":{ + "source":"/etc/fail2ban/", + "exclude":"", + "active":True + } + }, + "rpi5.home.lan":{ + "docker_data":{ + "source":"/share/docker_data/", + "exclude":"", + "active":True + }, + "fail2ban":{ + "source":"/etc/fail2ban/", + "exclude":"", + "active":True + } + } +} +BACKUP_FS = "/srv/dev-disk-by-uuid-2f843500-95b6-43b0-bea1-9b67032989b8" +BACKUP_HOST = "omv.home.lan" +#BACKUP_HOST = "morefine.home.lan" +if not host in backups and _BACKUP: + print(f"No backup jobs for {host}") + sys.exit() +print("Test connection") +print("3") +hm = socket.gethostbyaddr(BACKUP_HOST) + +hostdown = True +n=0 + +try: + data = {"camera":"door_camera"} + url = "http://m-server.home.lan:8123/api/webhook/-0eWYFhSTzdusAO8jwQS9t1AT" + + x = requests.post(url, data) + + print(x.text) +except: + pass +while hostdown: + #HOST_UP = os.system(f"ping -c 1 -w 2 omv.home.lan") == 0 + cmnd = f"ping -c 1 -w 2 {BACKUP_HOST}" + status, output = subprocess.getstatusoutput(cmnd) + # print(status) + # print(output) + + + if status != 0: + send_magic_packet('88:c9:b3:b5:23:d8') + print(f"Backup host down, waiting - {n}\r", end="") + time.sleep(5) + n += 1 + else: + print("Backup host up " ) + hostdown = False + +port = 22 # Replace with the port you want to test +n=0 +while not is_port_open(BACKUP_HOST, port): + print(f"Port {port} on {BACKUP_HOST} is closed. {n}\r", end="") + time.sleep(5) + n += 1 +print(f"Port {port} on {BACKUP_HOST} is open.") + +print("Starting") + +if _RESTORE: + topic = "sectorq/omv/restore/{}".format(_APP) + client.connect(broker,1883,60) + msg = {"status":"inactive","bak_name":_APP,"start_time":"inactive","end_time":"inactive","progress":0} + + client.publish(topic, json.dumps(msg)) + client.disconnect() + now = datetime.datetime.now() + BACKUP_HOST = "root@omv.home.lan" + BACKUP_DEVICE = "/srv/dev-disk-by-uuid-2f843500-95b6-43b0-bea1-9b67032989b8" + BACKUP_DIR = f"/backup/{host}" + NEW_BACKUP_DIR = f"/backup/m-server/docker_data/latest/{_APP}" + DATETIME = now.strftime("%Y-%m-%d_%H-%M-%S") + SOURCE_DIR = f"/share/docker_data/" + if _FIRST: + BACKUP_PATH="{}/initial".format(BACKUP_DIR) + else: + BACKUP_PATH="{}/{}".format(BACKUP_DIR, DATETIME) + LATEST_LINK="{}/latest".format(BACKUP_DIR) + FULL_BACKUP_LATEST = f"{NEW_BACKUP_DIR}/latest" + LATEST_LINK = f"/{host}/{_APP}/latest" + + + msg = {"status":"started","bak_name":_APP,"start_time":DATETIME,"end_time":"in progress", "progress":0} + client.connect(broker,1883,60) + client.publish(topic, json.dumps(msg)) + client.disconnect() + + cmnd = "ssh root@omv.home.lan 'mkdir -p " + NEW_BACKUP_DIR + "'" + + if _EXECUTE: + status, output = subprocess.getstatusoutput(cmnd) + print("Create backup dir") + print(cmnd) + + + #cmnd = "rsync -av --delete {}/ --link-dest {} --exclude=\".cache\" {}".format(SOURCE_DIR, LATEST_LINK, BACKUP_PATH) + cmnd = f"rsync -avz --delete rsync://{BACKUP_HOST}{NEW_BACKUP_DIR} {SOURCE_DIR}" + + ans = "y" + print(cmnd) + print("Sync files") + if _TEST: + + + ans = input("continue?") or "n" + if ans == "y" and _EXECUTE: + status, output = subprocess.getstatusoutput(cmnd) + + now = datetime.datetime.now() + ENDTIME = now.strftime("%Y-%m-%d_%H:%M:%S") + msg = {"status":"finished","bak_name":_APP,"start_time":DATETIME,"end_time":ENDTIME,"progress":0} + client.connect(broker,1883,10) + client.publish(topic, json.dumps(msg)) + client.disconnect() + + print("Getting size of FS") + #cmnd = "du -h --max-depth=0 {}".format(BACKUP_FS) + cmnd = "ssh root@omv.home.lan 'df -h /srv/dev-disk-by-uuid-2f843500-95b6-43b0-bea1-9b67032989b8|awk '\\''{ print $3 }'\\''|tail -1'" + print(cmnd) + status, output = subprocess.getstatusoutput(cmnd) + used_space = (output.split())[0] + now = datetime.datetime.now() + ENDJOB = now.strftime("%Y-%m-%d_%H:%M:%S") + print("Size : {}".format(used_space)) + print("Sending finished status") + msg = {"mode":_MODE,"status":"finished","bak_name":"complete","start_time":STARTTIME,"end_time":ENDJOB,"progress":0,"used_space":used_space} + print(msg) + client.connect(broker,1883,10) + client.publish(topic_sum, json.dumps(msg)) + client.disconnect() + + if _MODE == "auto": + cmnd = "ssh root@omv.home.lan 'systemctl suspend &'" + status, output = subprocess.getstatusoutput(cmnd) + + + +if _BACKUP: + print("Backup") + for b in backups[host]: + topic = "sectorq/omv/backups/{}".format(b.lower()) + if not backups[host][b]["active"]: + print("Backup {} is not active!".format(b)) + client.connect(broker,1883,60) + msg = {"status":"inactive","bak_name":b,"start_time":"inactive","end_time":"inactive","progress":0} + + client.publish(topic, json.dumps(msg)) + client.disconnect() + continue + + SOURCE_DIR = backups[host][b]["source"] + now = datetime.datetime.now() + BACKUP_HOST = "root@omv.home.lan" + BACKUP_DEVICE = "/srv/dev-disk-by-uuid-2f843500-95b6-43b0-bea1-9b67032989b8" + BACKUP_DIR = f"/backup/{host}/{b}" + NEW_BACKUP_DIR = f"{BACKUP_DEVICE}/backup/{host}/{b}" + DATETIME = now.strftime("%Y-%m-%d_%H-%M-%S") + if _FIRST: + BACKUP_PATH="{}/initial".format(BACKUP_DIR) + else: + BACKUP_PATH="{}/{}".format(BACKUP_DIR, DATETIME) + LATEST_LINK="{}/latest".format(BACKUP_DIR) + FULL_BACKUP_LATEST = f"{NEW_BACKUP_DIR}/latest" + LATEST_LINK = f"/{host}/{b}/latest" + + + msg = {"status":"started","bak_name":b,"start_time":DATETIME,"end_time":"in progress", "progress":0} + client.connect(broker,1883,60) + client.publish(topic, json.dumps(msg)) + client.disconnect() + + cmnd = "ssh root@omv.home.lan 'mkdir -p " + NEW_BACKUP_DIR + "'" + + if _EXECUTE: + status, output = subprocess.getstatusoutput(cmnd) + print("Create backup dir") + print(cmnd) + + + #cmnd = "rsync -av --delete {}/ --link-dest {} --exclude=\".cache\" {}".format(SOURCE_DIR, LATEST_LINK, BACKUP_PATH) + if _FIRST: + cmnd = f"rsync -avz --delete {SOURCE_DIR} --exclude=\"gitlab/logs/prometheus\" --exclude=\"home-assistant.log\" --exclude=\"gitlab/logs/*\" --exclude=\"esphome/config/.esphome\" --exclude=\".cache\" --exclude=\".git\" --exclude=\"var_lib_motioneye\" rsync://{BACKUP_HOST}{BACKUP_PATH}" + else: + cmnd = f"rsync -avz --delete {SOURCE_DIR} --link-dest {LATEST_LINK} --exclude=\"gitlab/logs/prometheus\" --exclude=\"home-assistant.log\" --exclude=\"gitlab/logs/*\" --exclude=\"esphome/config/.esphome\" --exclude=\".cache\" --exclude=\".git\" --exclude=\"var_lib_motioneye\" rsync://{BACKUP_HOST}{BACKUP_PATH}" + + ans = "y" + print(cmnd) + print("Sync files") + if _TEST: + + + ans = input("continue?") or "n" + if ans == "y" and _EXECUTE: + + # rsync --info=progress2 -avz --delete /share/docker_data/ --link-dest /m-server/docker_data/latest --exclude="gitlab/data/" --exclude="esphome/config/.esphome" --exclude="gitlab/logs/prometheus" --exclude=".cache" --exclude=".git" --exclude="var_lib_motioneye" /m-server/m-server/docker_data/newone1 + + + # input("????") + + status, output = subprocess.getstatusoutput(cmnd) + + cmnd = f"ssh root@omv.home.lan 'rm -rf {FULL_BACKUP_LATEST}'" + + #print(cmnd) + print("Removing latest link") + # input("????") + if _EXECUTE: + status, output = subprocess.getstatusoutput(cmnd) + if _FIRST: + cmnd = f"ssh root@omv.home.lan 'cd {NEW_BACKUP_DIR}; ln -s initial latest'" + else: + cmnd = f"ssh root@omv.home.lan 'cd {NEW_BACKUP_DIR}; ln -s {DATETIME} latest'" + print("Creating new latest link") + #print(cmnd) + # input("????") + if _EXECUTE: + status, output = subprocess.getstatusoutput(cmnd) + + + #Remove old + print("Removing old dirs") + # input("????") + #cmnd = "find {} -maxdepth 1 -type d -mtime +30 -exec rm -rf {{}} \;".format(BACKUP_DIR) + cmnd = f"cd {NEW_BACKUP_DIR} find ./ -maxdepth 1 -type d -mmin +30 -exec rm -rf {{}} \\;" + #print(cmnd) + # input("????") + if _EXECUTE: + status, output = subprocess.getstatusoutput(cmnd) + now = datetime.datetime.now() + ENDTIME = now.strftime("%Y-%m-%d_%H:%M:%S") + msg = {"status":"finished","bak_name":b,"start_time":DATETIME,"end_time":ENDTIME,"progress":0} + client.connect(broker,1883,10) + client.publish(topic, json.dumps(msg)) + client.disconnect() + + print("Getting size of FS") + #cmnd = "du -h --max-depth=0 {}".format(BACKUP_FS) + cmnd = "ssh root@omv.home.lan 'df -h /srv/dev-disk-by-uuid-2f843500-95b6-43b0-bea1-9b67032989b8|awk '\\''{ print $3 }'\\''|tail -1'" + print(cmnd) + status, output = subprocess.getstatusoutput(cmnd) + used_space = (output.split())[0] + now = datetime.datetime.now() + ENDJOB = now.strftime("%Y-%m-%d_%H:%M:%S") + print("Size : {}".format(used_space)) + print("Sending finished status") + msg = {"mode":_MODE,"status":"finished","bak_name":"complete","start_time":STARTTIME,"end_time":ENDJOB,"progress":0,"used_space":used_space} + print(msg) + client.connect(broker,1883,10) + client.publish(topic_sum, json.dumps(msg)) + client.disconnect() + + if _MODE == "auto": + cmnd = "ssh root@omv.home.lan 'systemctl suspend &'" + status, output = subprocess.getstatusoutput(cmnd)