def backup(self, name, config, dry_run=False): """Run a backup for the named backupset using the provided configuration :param name: name of the backupset :param config: dict-like object providing the backupset configuration :raises: BackupError if a backup fails """ for i in range(MAX_SPOOL_RETRIES): try: spool_entry = self.spool.add_backup(name) break except OSError as exc: if exc.errno != errno.EEXIST: raise BackupError("Failed to create spool: %s" % exc) LOG.debug("Failed to create spool. Retrying in %d seconds.", i + 1) time.sleep(i + 1) else: raise BackupError("Failed to create a new backup directory for %s" % name) spool_entry.config.merge(config) spool_entry.validate_config() if dry_run: # always purge the spool self.register_cb("post-backup", lambda *args, **kwargs: spool_entry.purge()) plugin = load_plugin(name, spool_entry.config, spool_entry.path, dry_run) spool_entry.config["holland:backup"]["start-time"] = time.time() spool_entry.flush() self.apply_cb("before-backup", spool_entry) spool_entry.config["holland:backup"]["failed"] = False try: estimated_size = self.check_available_space(plugin, spool_entry, dry_run) LOG.info( "Starting backup[%s] via plugin %s", spool_entry.name, spool_entry.config["holland:backup"]["plugin"], ) plugin.backup() except KeyboardInterrupt: LOG.warning("Backup aborted by interrupt") spool_entry.config["holland:backup"]["failed"] = True raise except BaseException as ex: LOG.warning(ex) spool_entry.config["holland:backup"]["failed"] = True spool_entry.config["holland:backup"]["stop-time"] = time.time() if not dry_run and not spool_entry.config["holland:backup"]["failed"]: final_size = float(directory_size(spool_entry.path)) LOG.info("Final on-disk backup size %s", format_bytes(final_size)) if estimated_size > 0: LOG.info( "%.2f%% of estimated size %s", (final_size / estimated_size) * 100.0, format_bytes(estimated_size), ) spool_entry.config["holland:backup"]["on-disk-size"] = final_size spool_entry.flush() start_time = spool_entry.config["holland:backup"]["start-time"] stop_time = spool_entry.config["holland:backup"]["stop-time"] if spool_entry.config["holland:backup"]["failed"]: LOG.error("Backup failed after %s", format_interval(stop_time - start_time)) else: LOG.info("Backup completed in %s", format_interval(stop_time - start_time)) if dry_run: spool_entry.purge() if sys.exc_info() != (None, None, None) or spool_entry.config["holland:backup"]["failed"]: LOG.debug("sys.exc_info(): %r", sys.exc_info()) self.apply_cb("failed-backup", spool_entry) raise BackupError("Failed backup: %s" % name) else: self.apply_cb("after-backup", spool_entry)
final_size = float(directory_size(spool_entry.path)) LOG.info("Final on-disk backup size %s", format_bytes(final_size)) if estimated_size > 0: LOG.info("%.2f%% of estimated size %s", (final_size / estimated_size)*100.0, format_bytes(estimated_size)) spool_entry.config['holland:backup']['on-disk-size'] = final_size spool_entry.flush() start_time = spool_entry.config['holland:backup']['start-time'] stop_time = spool_entry.config['holland:backup']['stop-time'] if spool_entry.config['holland:backup']['failed']: LOG.error("Backup failed after %s", format_interval(stop_time - start_time)) else: LOG.info("Backup completed in %s", format_interval(stop_time - start_time)) if dry_run: spool_entry.purge() if sys.exc_info() != (None, None, None): self.apply_cb('failed-backup', spool_entry) raise else: self.apply_cb('after-backup', spool_entry) def free_required_space(self, name, required_bytes, dry_run=False):
backupset_cfg.lookup('holland:backup.plugin')) plugin.backup() except KeyboardInterrupt: exc = BackupError("Interrupted") except Exception, exc: if not isinstance(exc, BackupError): LOGGER.debug("Unexpected exception when running backups.", exc_info=True) exc = BackupError(exc) backup_job.config['holland:backup']['stop-time'] = time.time() backup_interval = (backup_job.config['holland:backup']['stop-time'] - backup_job.config['holland:backup']['start-time']) if dry_run: LOGGER.info("Dry-run completed in %s", format_interval(backup_interval)) else: LOGGER.info("Backup completed in %s", format_interval(backup_interval)) if not dry_run and exc is None: final_size = directory_size(backup_job.path) LOGGER.info( "Final on-disk backup size: %s %.2f%% of estimated size %s", format_bytes(final_size), estimated_size and 100 * (float(final_size) / estimated_size) or 0.0, format_bytes(estimated_size)) backup_job.config['holland:backup']['on-disk-size'] = final_size LOGGER.debug("Flushing backup job") backup_job.flush() if exc is not None:
backup_job.name, backupset_cfg.lookup('holland:backup.plugin')) plugin.backup() except KeyboardInterrupt: exc = BackupError("Interrupted") except Exception, exc: if not isinstance(exc, BackupError): LOGGER.debug("Unexpected exception when running backups.", exc_info=True) exc = BackupError(exc) backup_job.config['holland:backup']['stop-time'] = time.time() backup_interval = (backup_job.config['holland:backup']['stop-time'] - backup_job.config['holland:backup']['start-time']) if dry_run: LOGGER.info("Dry-run completed in %s", format_interval(backup_interval)) else: LOGGER.info("Backup completed in %s", format_interval(backup_interval)) if not dry_run and exc is None: final_size = directory_size(backup_job.path) LOGGER.info("Final on-disk backup size: %s %.2f%% of estimated size %s", format_bytes(final_size), estimated_size and 100*(float(final_size)/estimated_size) or 0.0, format_bytes(estimated_size)) backup_job.config['holland:backup']['on-disk-size'] = final_size LOGGER.debug("Flushing backup job") backup_job.flush() if exc is not None:
final_size = directory_size(spool_entry.path) LOG.info("Final on-disk backup size %s", format_bytes(final_size)) if estimated_size > 0: LOG.info("%.2f%% of estimated size %s", (float(final_size) / estimated_size)*100.0, format_bytes(estimated_size)) spool_entry.config['holland:backup']['on-disk-size'] = final_size spool_entry.flush() start_time = spool_entry.config['holland:backup']['start-time'] stop_time = spool_entry.config['holland:backup']['stop-time'] if spool_entry.config['holland:backup']['failed']: LOG.error("Backup failed after %s", format_interval(stop_time - start_time)) else: LOG.info("Backup completed in %s", format_interval(stop_time - start_time)) if dry_run: spool_entry.purge() if sys.exc_info() != (None, None, None): self.apply_cb('failed-backup', spool_entry) raise else: self.apply_cb('after-backup', spool_entry) def check_available_space(self, plugin, dry_run=False):
break finally: if not opts.no_lock: try: fcntl.flock(config_file, fcntl.LOCK_UN) except OSError, exc: LOGGER.debug("Error when releasing backup lock: %s", exc) pass if not error_found: LOGGER.info("All backupsets run successfully") else: LOGGER.info("One or more backupsets failed to run successfully") LOGGER.info("This backup run of %d backupset%s took %s", len(backupsets), ('','s')[len(backupsets) > 1], format_interval(time.time() - start_time)) LOGGER.info("-----> Ending backup run <----") return error_found def run_backup(jobname, dry_run=False): try: backup(jobname, dry_run) except KeyboardInterrupt, e: LOGGER.info("Interrupt") except BackupError, exc: LOGGER.error("Backup %r failed: %s", jobname, exc) except Exception, exc: LOGGER.error("Unexpected exception caught. This is probably " "a bug. Please report to the holland " "development team.", exc_info=True)