init repo
This commit is contained in:
commit
cb729381e7
175
backup.py
Normal file
175
backup.py
Normal file
@ -0,0 +1,175 @@
|
||||
from Crypto.Cipher import AES
|
||||
import base64
|
||||
import json
|
||||
import argparse
|
||||
import sys
|
||||
import string
|
||||
import random
|
||||
import datetime
|
||||
import os
|
||||
|
||||
windows = False
|
||||
if sys.platform == "win32":
|
||||
windows = True
|
||||
print("")
|
||||
print("####################################")
|
||||
print("Program does not run on Windows!")
|
||||
print("Falling back to Testing Mode!")
|
||||
print("####################################")
|
||||
print("")
|
||||
|
||||
def encrypt_val(clear_text, master):
|
||||
enc_secret = AES.new(master[:32])
|
||||
tag_string = (str(clear_text) +
|
||||
(AES.block_size -
|
||||
len(str(clear_text)) % AES.block_size) * "\0")
|
||||
cipher_text = base64.b64encode(enc_secret.encrypt(tag_string))
|
||||
return cipher_text
|
||||
|
||||
def decrypt_val(cipher_text, master):
|
||||
dec_secret = AES.new(master[:32])
|
||||
raw_decrypted = dec_secret.decrypt(base64.b64decode(cipher_text))
|
||||
clear_val = raw_decrypted.rstrip("\0".encode())
|
||||
return clear_val
|
||||
|
||||
parser = argparse.ArgumentParser(description="Backup Script")
|
||||
parser.add_argument("-c", "--config", help="config file", default="settings.json")
|
||||
parser.add_argument("-t", "--test", help="Start in testing mode", action='store_true', default=False)
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.test:
|
||||
print("")
|
||||
print("####################################")
|
||||
print("Program is now running in testing Mode!")
|
||||
print("####################################")
|
||||
print("")
|
||||
windows = True
|
||||
|
||||
try:
|
||||
json_data=open(args.config).read()
|
||||
except Exception as e:
|
||||
sys.exit("Cant open Config File:\n{0}".format(e))
|
||||
|
||||
try:
|
||||
data = json.loads(json_data)
|
||||
except Exception as e:
|
||||
sys.exit("Parser Error in JSON File {0}:\n{1}".format(args.config, e))
|
||||
|
||||
def save_json():
|
||||
global data
|
||||
global args
|
||||
with open(args.config, 'w') as outfile:
|
||||
json.dump(data, outfile, sort_keys=True, indent=4, separators=(',', ': '))
|
||||
|
||||
MASTER_KEY = ""
|
||||
if not "option" in data or not "masterpassword" in data["option"] or data["option"]["masterpassword"] == "":
|
||||
master_pw = ''.join(random.choice(string.ascii_uppercase + string.digits + string.ascii_lowercase) for _ in range(16))
|
||||
data["option"]["masterpassword"] = base64.b64encode(master_pw.encode()).decode("utf-8")
|
||||
print("MASTER PASSWORD automaticly generated. !!!DO NOT REMOVE IT FROM THE SETTINGS FILE!!!")
|
||||
save_json()
|
||||
|
||||
MASTER_KEY = data["option"]["masterpassword"]
|
||||
|
||||
ignore = ["option"]
|
||||
|
||||
for server in data:
|
||||
if server in ignore:
|
||||
continue
|
||||
host = server
|
||||
print("")
|
||||
print("")
|
||||
print("")
|
||||
print("--- {0} --".format(host))
|
||||
for type in data[server]["types"]:
|
||||
print("")
|
||||
user = ""
|
||||
authtype, password = ("", "")
|
||||
|
||||
if not "auth" in type:
|
||||
sys.exit("Server {0} has no authentication".format(server))
|
||||
|
||||
if not "destination" in type:
|
||||
sys.exit("Server {0} has no destination directory".format(server))
|
||||
|
||||
if not os.path.isdir(type["destination"]):
|
||||
sys.exit("Destination {0} for Server {1} not found".format(type["destination"], server))
|
||||
|
||||
if not "user" in type["auth"] or type["auth"]["user"] == "":
|
||||
sys.exit("Server {0} has no user".format(server))
|
||||
else:
|
||||
user = type["auth"]["user"]
|
||||
|
||||
if not "password" in type["auth"] or type["auth"]["password"] == "":
|
||||
if not "key" in type["auth"] or type["auth"]["key"] == "":
|
||||
sys.exit("Server {0} has no password or key".format(server))
|
||||
else:
|
||||
authtype, password = ("key", type["auth"]["key"])
|
||||
else:
|
||||
if type["auth"]["password"].endswith(".==="):
|
||||
authtype, password = ("password", decrypt_val((str(type["auth"]["password"])[:-2]).encode(), MASTER_KEY).decode("utf-8"))
|
||||
else:
|
||||
authtype, password = ("password", type["auth"]["password"])
|
||||
encrypted = encrypt_val(type["auth"]["password"], MASTER_KEY).decode("utf-8")
|
||||
print("Encrypted {0}")
|
||||
type["auth"]["password"] = "{0}.===".format(encrypted)
|
||||
save_json()
|
||||
|
||||
print("{0} {1}@{2} using {3} destination is {4}".format(type["type"], user, host, authtype, type["destination"]))
|
||||
|
||||
if type["type"] == "sftp":
|
||||
if not "backup" in type or type["backup"] == "":
|
||||
sys.exit("Server {0} has backup paths".format(server))
|
||||
|
||||
rsync_base = ["rsync", "-zavx", "--ignore-errors", "--delete", "--delete-excluded"]
|
||||
|
||||
bpaths = []
|
||||
expaths = []
|
||||
|
||||
bpaths.extend(type["backup"])
|
||||
|
||||
if "exclude" in type:
|
||||
for exclude in type["exclude"]:
|
||||
rsync_base.extend(["--exclude", exclude])
|
||||
|
||||
for bpath in bpaths:
|
||||
bpath = bpath.strip()
|
||||
full_path = bpath.strip()
|
||||
rsync_cmd = rsync_base[:]
|
||||
if authtype == "key":
|
||||
rsync_cmd.append("-e")
|
||||
rsync_cmd.append("'ssh -i {0} -p22'".format(password))
|
||||
bpath = user + "@" + host + ":" + bpath
|
||||
rsync_cmd.append(bpath)
|
||||
rsync_cmd.append(type["destination"] + os.sep + full_path.replace("/", "_").replace("\\", "_"))
|
||||
print("Running Rsync for {0}".format(bpath))
|
||||
if not windows:
|
||||
os.system(" ".join(rsync_cmd))
|
||||
else:
|
||||
print(" ".join(rsync_cmd))
|
||||
elif type["type"] == "mysql":
|
||||
if not "database" in type or type["database"] == "":
|
||||
sys.exit("Server {0} has database info".format(server))
|
||||
|
||||
tstamp = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
|
||||
skip = ["information_schema", "performance_schema"]
|
||||
for db in type["database"]:
|
||||
if db in skip:
|
||||
continue
|
||||
|
||||
if db == "all":
|
||||
db = "--all-databases"
|
||||
|
||||
dbbackup_name = "{0}_{1}.{2}".format(tstamp, ("all" if db == "--all-databases" else db), "sql")
|
||||
dbbackup_path = type["destination"] + os.sep + dbbackup_name
|
||||
|
||||
dump_cmd = "mysqldump -u " + user
|
||||
if host != None:
|
||||
dump_cmd += " -h " + "'" + host + "'"
|
||||
if authtype == "password" and password != "":
|
||||
dump_cmd += " -p" + password
|
||||
dump_cmd += " -e --opt -c " + db + " | gzip > " + dbbackup_path + ".gz"
|
||||
print("Dump db, %s to %s." % (db, dbbackup_path))
|
||||
if not windows:
|
||||
os.system(dump_cmd)
|
||||
else:
|
||||
print(dump_cmd)
|
37
settings.json.sample
Normal file
37
settings.json.sample
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"exampleHost": {
|
||||
"types": [
|
||||
{
|
||||
"auth": {
|
||||
"key": "/root/.ssh/id_rsa",
|
||||
"user": "backups"
|
||||
},
|
||||
"backup": [
|
||||
"/var/www/html"
|
||||
],
|
||||
"destination": "/mnt/backups/data",
|
||||
"exclude": [
|
||||
"*.filetype.to.exclude",
|
||||
"*.another.to.exclude",
|
||||
"/path/to/exclude",
|
||||
"/another/path/to/exclude"
|
||||
],
|
||||
"type": "sftp"
|
||||
},
|
||||
{
|
||||
"auth": {
|
||||
"password": "PlainTextPassword",
|
||||
"user": "root"
|
||||
},
|
||||
"database": [
|
||||
"wordpress",
|
||||
"userlist"
|
||||
],
|
||||
"destination": "/mnt/backups/db",
|
||||
"type": "mysql"
|
||||
}
|
||||
]
|
||||
},
|
||||
"option": {
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user