openstack-ansible-galera_se.../templates/mariabackup_script.py.j2
Jonathan Rosser ef1bb11cb3 Update mariadb to 11.4.4
Depends-On: https://review.opendev.org/c/openstack/openstack-ansible/+/934430
Change-Id: Id20fa5e0b5dc0b2c1e5330799e0edbc20bbd2605
2024-11-08 14:20:39 +00:00

291 lines
11 KiB
Django/Jinja
Executable File

#!/usr/bin/python3
# {{ ansible_managed }}
from subprocess import Popen, PIPE, check_output, run
from argparse import ArgumentParser
from shutil import rmtree
from time import strftime, mktime, sleep
from datetime import datetime, timedelta
import os
def get_opts():
parser = ArgumentParser(
usage="python3 mariabackup_script <destdir> [--full-backup][--increment] [--suffix=<suffix>] [--defaults-file=<defaults-file>]",
prog="Mariadb Backup Script",
description="""
This program makes a mariadb backup with Mariabackup
""",)
parser.add_argument(
"destdir",
help="Specifying directory for storing backups",
)
parser.add_argument(
"-f",
"--full-backup",
action="store_true",
dest="fullbackup_flag",
default=False,
help="Flag for creation of full backup",
)
parser.add_argument(
"-i",
"--increment",
action="store_true",
dest="increment_flag",
default=False,
help="Flag to make incremental backup, based on the latest backup",
)
parser.add_argument(
"--compress",
dest="compress_flag",
default=False,
type=eval,
choices=[True, False],
help="Flag to compress created backups",
)
parser.add_argument(
"--compressor",
dest="compressor",
default="gzip",
type=str,
help="The compressor to use when compressing backups (default: gzip)",
)
parser.add_argument(
"-c",
"--copies",
dest="copies_flag",
default=False,
type=int,
help="Specifying how much copies to rotate",
)
parser.add_argument(
"--check",
action="store_true",
dest="check_flag",
default=False,
help="Checking last mariadb full backup for their relevancy",
)
parser.add_argument(
"--warning",
dest="warning_value",
default=False,
type=int,
help="When to raise warning (for --check) in days",
)
parser.add_argument(
"--critical",
dest="critical_value",
default=False,
type=int,
help="When to raise critical (for --check) in days",
)
parser.add_argument(
"-s",
"--suffix",
dest="suffix",
default=False,
type=str,
help="Added to the filename of backups"
)
parser.add_argument(
"--defaults-file",
dest="defaults_file",
type=str,
help="A cnf file can specified to the mariabackup process"
)
opts = parser.parse_args()
return opts
def check_backups(dest, warning, critical, full_backup_filename):
try:
last_mariabackup_full = datetime.strptime(max([os.path.normpath(dest+'/'+f) for f in os.listdir(dest) if f.startswith(full_backup_filename)], key=os.path.getmtime).split(full_backup_filename)[1], '%Y%m%d-%H%M%S')
except ValueError:
print("No files found, you may need to check your destination directory or add a suffix.")
raise SystemExit()
warning_time = datetime.today() - timedelta(days=warning)
critical_time = datetime.today() - timedelta(days=critical)
print_info = "Last mariadb backup date "+str(last_mariabackup_full)
if last_mariabackup_full < critical_time:
print(print_info)
raise SystemExit(2)
elif last_mariabackup_full < warning_time:
print(print_info)
raise SystemExit(1)
else:
print(print_info)
raise SystemExit(0)
def create_full_backup(dest, curtime, full_backup_filename, extra_mariabackup_args, compress, compressor):
check_lock_file()
get_lock_file()
try:
err = open(os.path.normpath(dest+"/backup.log"), "w")
if compress:
#Creating compressed full backup
os.makedirs(dest+"/"+full_backup_filename+curtime, exist_ok=True)
mariabackup_run = Popen(
["/usr/bin/mariadb-backup"] + extra_mariabackup_args + ["--backup", "--stream=xbstream", "--extra-lsndir="+os.path.normpath(dest+"/"+full_backup_filename+curtime)], stdout=PIPE, stderr=err
)
compressed_backup = open(os.path.normpath(dest+"/"+full_backup_filename+curtime+"/"+full_backup_filename+curtime), "wb")
run([compressor], stdin=mariabackup_run.stdout, stdout=compressed_backup)
mariabackup_run.wait()
mariabackup_res = mariabackup_run.communicate()
if mariabackup_run.returncode:
print(mariabackup_res[1])
compressed_backup.close()
else:
#Creating full backup
mariabackup_run = Popen(
["/usr/bin/mariadb-backup"] + extra_mariabackup_args + ["--backup", "--target-dir="+os.path.normpath(dest+"/"+full_backup_filename+curtime)], stdout=None, stderr=err
)
mariabackup_run.wait()
mariabackup_res = mariabackup_run.communicate()
if mariabackup_run.returncode:
print(mariabackup_res[1])
#Preparing full backup
err_p = open(os.path.normpath(dest+"/prepare.log"), "w")
mariabackup_prep = Popen(
["/usr/bin/mariadb-backup"] + extra_mariabackup_args + ["--prepare", "--target-dir="+os.path.normpath(dest+"/"+full_backup_filename+curtime)], stdout=None, stderr=err_p
)
mariabackup_prep.wait()
mariabackup_prep_res = mariabackup_prep.communicate()
if mariabackup_prep.returncode:
print(mariabackup_prep_res[1])
err_p.close()
err.close()
except OSError:
print("Please, check that Mariabackup is installed")
except Exception as e:
print(e)
finally:
os.unlink("/var/run/mariabackup-galera/db_backup.pid")
def create_increment_backup(dest, curtime, increment_backup_filename, extra_mariabackup_args, compress, compressor):
check_lock_file()
get_lock_file()
try:
basedir = max([ os.path.normpath(dest+'/'+f) for f in os.listdir(dest) if f.startswith('mariabackup-')], key=os.path.getmtime)
except ValueError:
print("No full backup found, cannot create incremental backup.")
os.unlink("/var/run/mariabackup-galera/db_backup.pid")
raise SystemExit(1)
try:
err = open(os.path.normpath(dest+"/increment.err"), "w")
if compress:
#Creating compressed incremental backup
os.makedirs(dest+"/"+increment_backup_filename+curtime, exist_ok=True)
mariabackup_run = Popen(
["/usr/bin/mariadb-backup"] + extra_mariabackup_args + ["--backup", "--stream=xbstream", "--incremental-basedir="+basedir, "--extra-lsndir="+os.path.normpath(dest+"/"+increment_backup_filename+curtime)], stdout=PIPE, stderr=err
)
compressed_backup = open(os.path.normpath(dest+"/"+increment_backup_filename+curtime+"/"+increment_backup_filename+curtime), "wb")
run([compressor], stdin=mariabackup_run.stdout, stdout=compressed_backup)
mariabackup_run.wait()
mariabackup_res = mariabackup_run.communicate()
if mariabackup_run.returncode:
print(mariabackup_res[1])
compressed_backup.close()
else:
#Creating incremental backup
mariabackup_run = Popen(
["/usr/bin/mariadb-backup"] + extra_mariabackup_args + ["--backup", "--target-dir="+os.path.normpath(dest+"/"+increment_backup_filename+curtime), "--incremental-basedir="+basedir], stdout=None, stderr=err
)
mariabackup_run.wait()
mariabackup_res = mariabackup_run.communicate()
if mariabackup_run.returncode:
print(mariabackup_res[1])
err.close()
except OSError:
print("Please, check that Mariabackup is installed")
except Exception as e:
print(e)
finally:
os.unlink("/var/run/mariabackup-galera/db_backup.pid")
def rotate_backups(dest, copies, full_backup_filename, increment_backup_filename):
check_lock_file()
get_lock_file()
full_list = [os.path.normpath(dest+'/'+f) for f in os.listdir(dest) if f.startswith(full_backup_filename)]
increment_list = [ os.path.normpath(dest+'/'+f) for f in os.listdir(dest) if f.startswith(increment_backup_filename)]
# Rotate full backups
if len(full_list) > copies:
full_list.sort()
while len(full_list) > copies:
oldest_full_backup = min(full_list, key=os.path.getmtime)
full_list.remove(oldest_full_backup)
rmtree(oldest_full_backup)
# Remove all incremental backups older than the oldest full backup
oldest_full_backup_timestamp = parsedate(oldest_full_backup.split(full_backup_filename)[1])
for increment in increment_list:
increment_timestamp = parsedate(increment.split(increment_backup_filename)[1])
if increment_timestamp < oldest_full_backup_timestamp:
rmtree(increment)
os.unlink("/var/run/mariabackup-galera/db_backup.pid")
def parsedate(s):
return mktime(datetime.strptime(s, '%Y%m%d-%H%M%S').timetuple())
def check_lock_file():
timer = 0
while os.path.isfile("/var/run/mariabackup-galera/db_backup.pid"):
sleep(60)
timer += 1
if timer == 120:
print("timeout of waiting another process is reached")
raise SystemExit(1)
def get_lock_file():
try:
pid = open('/var/run/mariabackup-galera/db_backup.pid', 'w')
pid.write(str(os.getpid()))
pid.close()
except Exception as e:
print(e)
def main():
opts = get_opts()
curtime = strftime("%Y%m%d-%H%M%S")
if not opts.copies_flag and opts.fullbackup_flag:
raise NameError("--copies flag is required for running full backup.")
full_backup_filename = "mariabackup-full_"
increment_backup_filename = "mariabackup-increment_"
if opts.suffix:
full_backup_filename = ("mariabackup-full-" + opts.suffix + "_")
increment_backup_filename = ("mariabackup-increment-" + opts.suffix + "_")
extra_mariabackup_args = []
# --defaults-file must be specified straight after the process
if opts.defaults_file:
extra_mariabackup_args = ["--defaults-file=" + opts.defaults_file] + extra_mariabackup_args
if opts.fullbackup_flag and opts.increment_flag:
raise NameError("Only one flag can be specified per operation")
elif opts.fullbackup_flag:
create_full_backup(opts.destdir, curtime, full_backup_filename, extra_mariabackup_args, opts.compress_flag, opts.compressor)
rotate_backups(opts.destdir, opts.copies_flag, full_backup_filename, increment_backup_filename)
raise SystemExit()
elif opts.increment_flag:
create_increment_backup(opts.destdir, curtime, increment_backup_filename, extra_mariabackup_args, opts.compress_flag, opts.compressor)
raise SystemExit()
elif opts.check_flag:
pass
else:
raise NameError("either --increment or --full-backup flag is required")
if opts.check_flag and (opts.warning_value and opts.critical_value):
check_backups(warning = opts.warning_value, critical = opts.critical_value, dest = opts.destdir, full_backup_filename = full_backup_filename)
else:
raise NameError("--warning and --critical thresholds should be specified for check")
if __name__ == "__main__":
main()