def run(self): if self.settings["disabled"]: log.info("Skipping disabled task") return if "lvm" in self.settings: lvm_volume = self.settings["lvm"]["caller"].get_volume( self.settings["source_path"]) real_source = lvm_volume.get_snapshot( self.settings["lvm"]["snapshot_name"], self.settings["lvm"]["snapshot_size"]) else: real_source = self.settings["source_path"] try: bdsync_run(real_source, self.settings["target_path"], self.settings["connection_command"], self.settings["local_bdsync_bin"], self.settings["remote_bdsync_bin"], self.settings["bdsync_args"], self.settings["target_patch_dir"], self.settings["create_target_if_missing"], self.settings["apply_patch_in_place"]) except ProcessExecutionError as exc: raise TaskProcessingError("Failed to run command: {0}".format(exc)) finally: if "lvm" in self.settings: lvm_volume.remove_snapshot()
def _create_snapshot(self, snapshot_name, snapshot_size): assert self._snapshot_name is None log.info("Creating LVM snapshot: %s/%s", self._group, snapshot_name) cmd = self._caller["lvcreate", "--snapshot", "--name", snapshot_name, "--size", snapshot_size, self._get_path()] log.debug("LVM snapshot create command: %s", cmd) try: cmd() except plumbum.commands.processes.ProcessExecutionError as exc: raise TaskProcessingError("Failed to create LVM snapshot: {0}".format(exc)) self._snapshot_name = snapshot_name
def remove_snapshot(self): # the name should not be None or empty assert self._snapshot_name lv_path = "%s/%s" % (self._group, self._snapshot_name) log.debug("Verifying status of snapshot volume before removing: %s", lv_path) cmd = self._caller["lvdisplay", "--columns", "--noheading", "--select", "origin=%s" % self._volume, lv_path] if self._snapshot_name not in cmd(): log.error("Refusing to remove LVM snapshot due to its unclear state: %s", lv_path) else: log.info("Removing LVM snapshot: %s", lv_path) cmd = self._caller["lvremove", "--force", lv_path] log.debug("LVM snapshot remove command: %s", cmd) cmd() self._snapshot_name = None
def bdsync_run(source_filename, target_filename, connection_command, local_bdsync, remote_bdsync, bdsync_args, target_patch_dir, create_if_missing, apply_in_place, bandwidth_limit): """ Run bdsync in one or two phases. With one phase changes are applied in-place. With two phases there are separate stages of patch generation / transfer followed by the application of the patch. """ source = SyncSource(source_filename, local_bdsync, bdsync_args) target = SyncTarget(target_filename, remote_bdsync if connection_command else local_bdsync, bdsync_args, connection_command) # preparations if not target.exists(): if create_if_missing: log.warning("Creating missing target file: %s", target.filename) target.create_empty() else: raise NotFoundError( "The target does not exist (while 'create_target_if_missing' " "is disabled)") generate_patch_cmd = source.get_generate_patch_command(target) if bandwidth_limit: generate_patch_cmd = generate_patch_cmd | get_command_from_tokens( ["pv", "--rate-limit", str(bandwidth_limit), "--quiet"]) if apply_in_place: start_time = time.time() operation = generate_patch_cmd | target.get_apply_patch_command() log.debug("Applying changes in-place: %s", operation) operation() change_apply_time = datetime.timedelta(seconds=(time.time() - start_time)) log.info("Change Apply Time: %s", change_apply_time) else: patch = SyncPatch(target_patch_dir, connection_command) # generate and store the patch start_time = time.time() generate_patch_command = generate_patch_cmd | patch.get_store_command() log.debug("Generating Patch: %s", generate_patch_command) generate_patch_command() patch_generate_time = datetime.timedelta(seconds=(time.time() - start_time)) log.info("Patch Generate Time: %s", patch_generate_time) log.info("Patch Size: %s", sizeof_fmt(patch.get_size())) # apply the new patch start_time = time.time() apply_patch_command = target.get_apply_patch_command(patch) apply_patch_command() patch_apply_time = datetime.timedelta(seconds=(time.time() - start_time)) log.info("Patch Apply Time: %s", patch_apply_time) patch.cleanup()
if not tasks: log.warning( "There is nothing to be done (no tasks found in config file).") processing_error = False # late import: avoid import problems before dependency checks (see above) from bdsync_manager.task import Task for task_name in tasks: task = Task(settings.tasks[task_name]) bdsync_manager.utils.set_log_format( "[Task {0}] %(levelname)s: %(message)s".format(task_name)) try: task.run() except bdsync_manager.TaskProcessingError as error: log.error(str(error)) processing_error = True except KeyboardInterrupt: log.error("Terminated via user input") return EXITCODE_CANCELLED if processing_error: return EXITCODE_TASK_PROCESSING_ERROR else: return EXITCODE_SUCCESS if __name__ == "__main__": try: exit(main()) except KeyboardInterrupt: log.info("Cancelled task") exit(EXITCODE_CANCELLED)