From fc8feccc2faf54d20ec6240b16bd6d4803fd62aa Mon Sep 17 00:00:00 2001 From: James Slagle Date: Tue, 20 Apr 2021 09:38:27 -0400 Subject: [PATCH] Add heat launcher db backup/restore Add a database restore/backup. to when heat launcher is started/stopped. The behavior is toggled with the class parameters restore_db/backup_db. Change-Id: I195743213b931460b9a1addf2ffd590679a5495b Signed-off-by: James Slagle --- tripleoclient/heat_launcher.py | 56 +++++++++++++++++++--------- tripleoclient/v1/overcloud_deploy.py | 8 ++-- 2 files changed, 43 insertions(+), 21 deletions(-) diff --git a/tripleoclient/heat_launcher.py b/tripleoclient/heat_launcher.py index eb59d8fa3..a6e21faf7 100644 --- a/tripleoclient/heat_launcher.py +++ b/tripleoclient/heat_launcher.py @@ -14,6 +14,7 @@ # import datetime +import glob import grp import json import logging @@ -135,7 +136,8 @@ class HeatBaseLauncher(object): self.heat_dir = os.path.abspath(heat_dir) self.host = "127.0.0.1" self.db_dump_path = os.path.join( - self.heat_dir, 'heat-db-dump.sql') + self.heat_dir, 'heat-db-dump-{}.sql'.format( + datetime.datetime.utcnow().isoformat())) self.skip_heat_pull = skip_heat_pull if rm_heat: @@ -476,6 +478,10 @@ class HeatPodLauncher(HeatContainerLauncher): 'mysql', 'mysql', 'heat', '-e', 'grant all privileges on heat.* to \'heat\'@\'%\'' ]) + subprocess.check_call([ + 'sudo', 'podman', 'exec', '-it', '-u', 'root', + 'mysql', 'mysql', '-e', 'flush privileges;' + ]) cmd = [ 'sudo', 'podman', 'run', '--rm', '--user', 'heat', @@ -492,31 +498,45 @@ class HeatPodLauncher(HeatContainerLauncher): def do_restore_db(self, db_dump_path=None): if not db_dump_path: - db_dump_path = self.db_dump_path + # Find the latest dump from self.heat_dir + db_dumps = glob.glob('{}/heat-db-dump*'.format(self.heat_dir)) + if not db_dumps: + raise Exception('No db backups found to restore in %s' % + self.heat_dir) + db_dump_path = max(db_dumps, key=os.path.getmtime) + log.info("Restoring db from {}".format(db_dump_path)) subprocess.run([ 'sudo', 'podman', 'exec', '-i', '-u', 'root', 'mysql', 'mysql', 'heat'], stdin=open(db_dump_path), check=True) + def do_backup_db(self, db_dump_path=None): + if not db_dump_path: + db_dump_path = self.db_dump_path + if os.path.exists(db_dump_path): + raise Exception("Won't overwrite existing db dump at %s. " + "Remove it first." % db_dump_path) + with open(db_dump_path, 'w') as out: + subprocess.run([ + 'sudo', 'podman', 'exec', '-it', '-u', 'root', + 'mysql', 'mysqldump', 'heat'], stdout=out, + check=True) + def rm_heat(self, backup_db=False): if self.database_exists(): if backup_db: - try: - with open(self.db_dump_path, 'w') as out: - subprocess.run([ - 'sudo', 'podman', 'exec', '-it', '-u', 'root', - 'mysql', 'mysqldump', 'heat'], stdout=out, - check=True) - subprocess.check_call([ - 'sudo', 'podman', 'exec', '-it', '-u', 'root', - 'mysql', 'mysql', 'heat', '-e', - 'drop database heat']) - subprocess.check_call([ - 'sudo', 'podman', 'exec', '-it', '-u', 'root', - 'mysql', 'mysql', 'heat', '-e', - 'drop user \'heat\'@\'%\'']) - except subprocess.CalledProcessError: - pass + self.do_backup_db() + try: + subprocess.check_call([ + 'sudo', 'podman', 'exec', '-it', '-u', 'root', + 'mysql', 'mysql', 'heat', '-e', + 'drop database heat']) + subprocess.check_call([ + 'sudo', 'podman', 'exec', '-it', '-u', 'root', + 'mysql', 'mysql', '-e', + 'drop user \'heat\'@\'%\'']) + except subprocess.CalledProcessError: + pass subprocess.call([ 'sudo', 'podman', 'pod', 'rm', '-f', 'ephemeral-heat' ]) diff --git a/tripleoclient/v1/overcloud_deploy.py b/tripleoclient/v1/overcloud_deploy.py index 8e9d454a7..30fb1f26a 100644 --- a/tripleoclient/v1/overcloud_deploy.py +++ b/tripleoclient/v1/overcloud_deploy.py @@ -1009,6 +1009,8 @@ class DeployOvercloud(command.Command): api_container_image = parameters['ContainerHeatApiImage'] engine_container_image = \ parameters['ContainerHeatEngineImage'] + restore_db = (parsed_args.setup_only or + parsed_args.config_download_only) self.heat_launcher = utils.get_heat_launcher( parsed_args.heat_type, api_container_image=api_container_image, @@ -1019,7 +1021,7 @@ class DeployOvercloud(command.Command): rm_heat=parsed_args.rm_heat, skip_heat_pull=parsed_args.skip_heat_pull) self.orchestration_client = \ - utils.launch_heat(self.heat_launcher) + utils.launch_heat(self.heat_launcher, restore_db=restore_db) self.clients.orchestration = self.orchestration_client try: @@ -1043,7 +1045,7 @@ class DeployOvercloud(command.Command): if parsed_args.heat_type != 'installed' and self.heat_launcher: self.log.info("Stopping ephemeral heat.") utils.kill_heat(self.heat_launcher) - utils.rm_heat(self.heat_launcher) + utils.rm_heat(self.heat_launcher, backup_db=True) raise # Get a new copy of the stack after stack update/create. If it was @@ -1204,7 +1206,7 @@ class DeployOvercloud(command.Command): if parsed_args.heat_type != 'installed': self.log.info("Stopping ephemeral heat.") utils.kill_heat(self.heat_launcher) - utils.rm_heat(self.heat_launcher) + utils.rm_heat(self.heat_launcher, backup_db=True) if parsed_args.output_dir: ansible_dir = config_download_dir