From 0264ebafbbf1e4dc17f35168c9469b4c4605ab16 Mon Sep 17 00:00:00 2001 From: "Thierry bordaz (tbordaz)" Date: Wed, 6 Nov 2013 14:06:49 +0100 Subject: [PATCH] Ticket 47584: CI tests: add backup/restore of an instance Bug Description: A test case or a test suite needs to be isolated from side effects of others test cases run previously. For this we need to run a test case with "clean" instances. Fix Description: Creating/deleting instances is consuming time and could take much more time than the test case itself. The idea, is to create a kind of instance backup file. This backup file contains all components of the instance: config, schema, database environement, database files, certificates/keys... Before running a test case, the test reinit the instance it needs from this backup. So it gets rapidely "clean" instances https://fedorahosted.org/389/ticket/47584 Reviewed by: ? Platforms tested: Flag Day: no Doc impact: no --- lib389/tools.py | 127 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) diff --git a/lib389/tools.py b/lib389/tools.py index 0e5774c..47ad45e 100644 --- a/lib389/tools.py +++ b/lib389/tools.py @@ -21,6 +21,8 @@ import operator import select import time import shutil +import tarfile +import re import lib389 from lib389 import InvalidArgumentError @@ -254,6 +256,131 @@ class DirSrvTools(object): else: log.debug("Starting server %r" % self) return DirSrvTools.serverCmd(self, 'start', verbose, timeout) + + @staticmethod + def checkInstanceBackupFS(dirsrv, verbose=False): + """ + If it exits a backup file, it returns it + else it returns None + """ + postfix = [ 'tar.gz' ] + prefix = 'backup' + backupDir = "/tmp/slapd-%s.bck" % dirsrv.inst + + # First check it if already exists a backup file + if os.path.exists(backupDir): + for root, dirs, files in os.walk(backupDir): + for file in files: + if file[-6:] in postfix and prefix in file: + # any file like 'backup*tar.gz' is assumed to be + # a valid backup, just return it. + # If it is invalid, use must remove it manually + return os.path.join(root, file) + + return None + + @staticmethod + def instanceBackupFS(dirsrv, verbose=False): + """ + Saves the files of an instance under /tmp/slapd-.bck/backup_HHMMSS.tar.gz + and return the archive file name. + If it already exists a such file, it assums it is a valid backup and + returns its name + + dirsrv.sroot : root of the instance (e.g. /usr/lib64/dirsrv) + dirsrv.inst : instance name (e.g. standalone for /etc/dirsrv/slapd-standalone) + dirsrv.confdir : root of the instance config (e.g. /etc/dirsrv) + dirsrv.dbdir: directory where is stored the database (e.g. /var/lib/dirsrv/slapd-standalon/db + """ + + postfix = [ 'tar.gz' ] + prefix = 'backup' + backupDir = "/tmp/slapd-%s.bck" % dirsrv.inst + + # First check it if already exists a backup file + backupFile = DirSrvTools.checkInstanceBackupFS(dirsrv, verbose) + if backupFile is None: + if not os.path.exists(backupDir): + os.makedirs(backupDir) + + + # goes under the directory where the DS is deployed + listFilesToBackup = [] + here = os.getcwd() + os.chdir(dirsrv.prefix) + prefix_pattern = "%s/" % dirsrv.prefix + + instroot = "%s/slapd-%s" % (dirsrv.sroot, dirsrv.inst) + for dirToBackup in [ instroot, dirsrv.confdir, dirsrv.dbdir]: + for root, dirs, files in os.walk(dirToBackup): + for file in files: + name = os.path.join(root, file) + name = re.sub(prefix_pattern, '', name) + + if os.path.isfile(name): + listFilesToBackup.append(name) + if verbose: + log.debug("instanceBackupFS add = %s (%s)" % (name, dirsrv.prefix)) + + + # create the archive + name = "%s_%s.tar.gz" % (prefix, time.strftime("%H%M%S")) + backupFile = os.path.join(backupDir, name) + tar = tarfile.open(backupFile, "w:gz") + + + for name in listFilesToBackup: + if os.path.isfile(name): + tar.add(name) + tar.close() + if verbose: + log.debug("instanceBackupFS: archive done : %s" % backupFile) + + # return to the directory where we were + os.chdir(here) + + return backupFile + + @staticmethod + def instanceRestoreFS(dirsrv, backupfile, verbose): + """ + """ + + # First check the archive exists + if backupfile is None: + log.warning("Unable to restore the instance (missing backup)") + return 1 + if not os.path.isfile(backupfile): + log.warning("Unable to restore the instance (%s is not a file)" % backupfile) + return 1 + + # Then restore from the directory where DS was deployed + here = os.getcwd() + os.chdir(dirsrv.prefix) + + tar = tarfile.open(backupfile) + for member in tar.getmembers(): + if os.path.isfile(member.name): + # + # restore only writable files + # It could be a bad idea and preferably restore all. + # Now it will be easy to enhance that function. + if os.access(member.name, os.W_OK): + if verbose: + log.debug("instanceRestoreFS: restored %s" % member.name) + tar.extract(member.name) + else: + if verbose: + log.debug("instanceRestoreFS: not restored %s (no write access)" % member.name) + else: + if verbose: + log.debug("instanceRestoreFS: restored %s" % member.name) + tar.extract(member.name) + + tar.close() + + os.chdir(here) + @staticmethod def setupSSL(dirsrv, secport=636, sourcedir=None, secargs=None): -- 1.7.11.7