def runDump(self, listDump): """ Permit to perform dump on each services with Docker command :param listDump: The list of service where to perform the dump :type listDump: list """ if isinstance(listDump, list) is False: raise KeyError("listDump must be a list") logger.debug("listDump: %s", listDump) commandService = Command() for dump in listDump: try: logger.info("Dumping %s/%s in %s" % (dump['service']['stack']['name'], dump['service']['name'], dump['target_dir'])) environments = "" for env in dump['environments']: environments += " -e '%s'" % env.replace(':', '=') if 'entrypoint' in dump: entrypoint = "--entrypoint='%s'" % dump['entrypoint'] else: entrypoint = '' # Check if folder to receive dump exist, else create it if os.path.isdir(dump['target_dir']) is False: os.makedirs(dump['target_dir']) logger.debug("Create directory '%s'", dump['target_dir']) else: logger.debug("Directory '%s' already exist", dump['target_dir']) commandService.runCmd("docker pull %s" % dump['image']) for command in dump['commands']: dockerCmd = "docker run --rm %s -v %s:%s %s %s %s" % ( entrypoint, dump['target_dir'], dump['target_dir'], environments, dump['image'], command) commandService.runCmd(dockerCmd) logger.info("Dump %s/%s is finished" % (dump['service']['stack']['name'], dump['service']['name'])) except Exception as e: logger.error("Error appear when dump '%s/%s', skip : %s" % (dump['service']['stack']['name'], dump['service']['name'], e.message)) # Don't beack backup if somethink wrong pass
def dumpRancherDatabase(self, backupPath, listDatabaseSettings): """ Permit to dump Rancher database :param backupPath: the backup path where store the database dump :param listDatabaseSettings: the database parameters to connect on it :type backupPath: basestring :type listDatabaseSettings: dict """ if backupPath is None or backupPath == "": raise KeyError("backupPath must be provided") if isinstance(listDatabaseSettings, dict) is False: raise KeyError("listDatabaseSettings must be provided") if "type" not in listDatabaseSettings: raise KeyError("You must provide the database type") if "host" not in listDatabaseSettings: raise KeyError("You must provide the database host") if "port" not in listDatabaseSettings: raise KeyError("You must provide the database port") if "user" not in listDatabaseSettings: raise KeyError("You must provide the database user") if "password" not in listDatabaseSettings: raise KeyError("You must provide the database password") if "name" not in listDatabaseSettings: raise KeyError("You must provide the database name") commandService = Command() target_dir = "%s/database" % (backupPath) image = "mysql:latest" logger.info("Dumping the Rancher database '%s' in '%s'", listDatabaseSettings['name'], target_dir) if os.path.isdir(target_dir) is False: os.makedirs(target_dir) logger.debug("Create directory '%s'", target_dir) else: logger.debug("Directory '%s' already exist", target_dir) commandService.runCmd("docker pull %s" % image) command = "sh -c 'mysqldump -h %s -P %s -u %s %s > %s/%s.dump'" % ( listDatabaseSettings['host'], listDatabaseSettings['port'], listDatabaseSettings['user'], listDatabaseSettings['name'], target_dir, listDatabaseSettings['name']) dockerCmd = "docker run --rm -v %s:%s -e 'MYSQL_PWD=%s' %s %s" % ( target_dir, target_dir, listDatabaseSettings['password'], image, command) commandService.runCmd(dockerCmd) logger.info("Dump Rancher database is finished")
def testRunCmd(self, mock_popen): commandService = Command() # When no error mock_popen.return_value.returncode = 0 mock_popen.return_value.communicate.return_value = ("output", None) result = commandService.runCmd("fake cmd") self.assertEqual("output", result) # With error mock_popen.return_value.returncode = 0 mock_popen.return_value.communicate.return_value = ("output", "Error") self.assertEqual("output", result) # With bad return code mock_popen.return_value.returncode = 1 mock_popen.return_value.communicate.return_value = ("output", None) self.assertRaises(Exception, commandService.runCmd, "fake cmd")
def initDuplicity(self, backupPath, backend): """ Permit to init Duplicity with the target :param backupPath: the path where dump is stored :param backend: the full URL of remote target where to store backup :type backupPath: str :type backend: str """ if backupPath is None or backupPath == "": raise KeyError("backupPath must be provided") if backend is None or backend == "": raise KeyError("backend must be provided") logger.debug("backupPath: %s", backupPath) logger.debug("backend: %s", backend) commandService = Command() result = commandService.runCmd("duplicity --no-encryption %s %s" % (backend, backupPath)) logger.info(result)
def runDuplicity(self, backupPath, backend, fullBackupFrequency, fullBackupKeep, incrementalBackupChainKeep, volumeSize, options=None): """ Permit to backup the dump on remote target :param backupPath: the path where dump is stored :param backend: the full URL of remote target where to store backup :param fullBackupFrequency: when run full backup :param fullBackupKeep: how many full backup to keep :param incrementalBackupChainKeep: how many incremental backup chain to keep :param volumeSize: how many size for each volume :param options: set some duplicity options :type backupPath: str :type backend: str :type fullBackupFrequency: str :type incrementalBackupChainKeep: str :type volumeSize: str :type options: str """ if backupPath is None or backupPath == "": raise KeyError("backupPath must be provided") if backend is None or backend == "": raise KeyError("backend must be provided") if fullBackupFrequency is None or fullBackupFrequency == "": raise KeyError("fullBackupFrequency must be provided") if isinstance(fullBackupKeep, int) is False: raise KeyError("fullBackupKeep must be provided") if isinstance(incrementalBackupChainKeep, int) is False: raise KeyError("incrementalBackupChainKeep must be provided") if isinstance(volumeSize, int) is False: raise KeyError("volumeSize must be provided") if options is None: options = "" if isinstance(options, basestring) is False: raise KeyError("Options mus be a None or string") logger.debug("backupPath: %s", backupPath) logger.debug("backend: %s", backend) logger.debug("fullBackupFrequency: %s", fullBackupFrequency) logger.debug("fullBackupKeep: %s", fullBackupKeep) logger.debug("incrementalBackupChainKeep: %s", incrementalBackupChainKeep) logger.debug("volumeSize: %s", volumeSize) logger.debug("options: %s", options) commandService = Command() logger.info("Start backup") result = commandService.runCmd( "duplicity %s --volsize %s --no-encryption --allow-source-mismatch --full-if-older-than %s %s %s" % (options, volumeSize, fullBackupFrequency, backupPath, backend)) logger.info(result) logger.info("Clean old full backup is needed") result = commandService.runCmd( "duplicity remove-all-but-n-full %s --force --allow-source-mismatch --no-encryption %s" % (fullBackupKeep, backend)) logger.info(result) logger.info("Clean old incremental backup if needed") result = commandService.runCmd( "duplicity remove-all-inc-of-but-n-full %s --force --allow-source-mismatch --no-encryption %s" % (incrementalBackupChainKeep, backend)) logger.info(result) logger.info("Cleanup backup") result = commandService.runCmd( "duplicity cleanup --force --no-encryption %s" % (backend)) logger.info(result)