def __collect_files(self): """Fill snapshot's include and exclude lists and retrieve some information about the snapshot (uncompressed size, file count). """ self.logger.info(_("Inspect file system and collect file infos")) _collector = self.__create_collector_obj() _collector.collect_files() _stats = _collector.get_stats() _snpsize = _stats.get_size_payload() + _stats.get_size_overhead(size_per_item = constants.TAR_BLOCKSIZE) self.__state.set_space_required(_snpsize) self.__snapshot.set_space_required(_snpsize) _sizefs, _freespace = self.__fam_target_hdl.query_dest_fs_info() _snpsize_hr = util.get_humanreadable_size_str(size_in_bytes = _snpsize, binary_prefixes = True) self.logger.info(_("Summary of backup")) self.logger.info(_("Number of directories: %s.") % _stats.get_count_dirs()) self.logger.info(_("Total number of files: %s.") % _stats.get_count_files_total()) self.logger.info(_("Number of symlinks: %s.") % _stats.get_count_symlinks()) self.logger.info(_("Number of files included in snapshot: %s.") % _stats.get_count_files_incl()) self.logger.info(_("Number of new files (also included): %s.") % _stats.get_count_files_new()) self.logger.info(_("Number of files skipped in incremental snapshot: %s.") % _stats.get_count_files_skip()) self.logger.info(_("Number of items forced to be excluded: %s.") % _stats.get_count_items_excl_forced()) self.logger.info(_("Number of items to be excluded by config: %s.") % _stats.get_count_items_excl_config()) self.logger.info(_("Maximum free size required is '%s'.") % _snpsize_hr) if _freespace == constants.FREE_SPACE_UNKNOWN: self.logger.warning("Unable to query available space on target: Operation not supported") else: _freespace_hr = util.get_humanreadable_size_str(size_in_bytes = _freespace, binary_prefixes = True) self.logger.info(_("Available disk size is '%s'.") % _freespace_hr) if _freespace <= _snpsize: raise exceptions.SBException(_("Not enough free space in the target directory for the planned backup (free: %(freespace)s, required: %(neededspace)s).")\ % { 'freespace' : _freespace_hr, 'neededspace' : _snpsize_hr})
def __get_space_required_str(self): if self._space_required > 0: space_str = util.get_humanreadable_size_str( size_in_bytes=self._space_required, binary_prefixes=True) else: space_str = _("unknown") return space_str
class BackupProfileHandler(object): """Class that handles/manages the backup process of a single profile. """ def __init__(self, configmanager, backupstate, dbus_connection=None, use_indicator=False, full_snapshot=False): """The `BackupProfileHandler` Constructor. :param configmanager : The current configuration manager :param backupstate: object that stores the current state of the process :note: Make sure to call for the appropriate logger before\ instantiating this class! """ self.logger = log.LogFactory.getLogger() #TODO: Simplify/refactor these attributes. self.__dbus_conn = dbus_connection self.__use_indicator = use_indicator self.__full_snp = full_snapshot self.config = configmanager self.__state = backupstate self.__state.clear_backup_properties() self.__profilename = self.config.getProfileName() self.__state.set_profilename(self.__profilename) self.__snpman = None self.__snapshot = None self.__fam_target_hdl = fam.get_fam_target_handler_facade_instance() self.logger.debug("Instance of BackupProfileHandler created.") def do_hook(self, hookname): """Runs scripts optionally defined in section 'hooks' of configuration file. Currently defined are * pre-backup - before preparation of backup starts * post-backup - after completion and finishing of backup """ #LP #173490 import commands hooks = None if self.config.has_option('hooks', hookname): hooks = str(self.config.get('hooks', hookname)).split(",") if hooks is not None: self.logger.info(_("Running of hooks: %s") % hookname) for hook in hooks: result = commands.getstatusoutput(hook) if (0 != result[0]): raise exceptions.HookedScriptError(\ "Hook %s returned error: '%s' (exit code=%s)" % (hookname, result[1], result[0])) def prepare(self): self.logger.info(_("Preparation of backup process")) _uri = self.config.get_destination_path() try: self.__fam_target_hdl.set_destination(_uri) self.__fam_target_hdl.set_configuration_ref(self.config) self.__fam_target_hdl.set_use_mainloop(use=True) self.__fam_target_hdl.initialize() except exceptions.FileAccessException: self.__fam_target_hdl.terminate() raise self.__check_target() def process(self): """Runs the whole backup process: 1. check pre-conditions 3. purge snapshots (if configured) 4. open new snapshot containing common metadata (full or incr. depending on existing one, base, settings etc.) 5. fill new snapshot (with packages list, include lists, exclude lists, size prediction) 6. commit new snapshot to disk (creates the actual tar archive and writes everything into the snapshot directory). """ assert self.__fam_target_hdl.is_initialized() self.__snpman = SnapshotManager( self.__fam_target_hdl.query_mount_uri()) # get basic informations about new snapshot self.__state.set_state('prepare') (snppath, base) = self.__retrieve_basic_infos(force_full_snp=self.__full_snp) # Create a new snapshot self.__snapshot = snapshot.Snapshot(snppath) self.logger.info( _("Snapshot '%(name)s' is being made.") % {'name': str(self.__snapshot)}) # Set the base file if base is not None: if self.__snapshot.isfull(): self.logger.debug( "Base is not being set for this full snapshot.") else: self.logger.info( _("Setting Base to '%(value)s'.") % {'value': str(base)}) self.__snapshot.setBase(base.getName()) # Backup list of installed packages _packagecmd = "dpkg --get-selections" if self.config.has_option("general", "packagecmd"): _packagecmd = self.config.get("general", "packagecmd") if _packagecmd: try: self.logger.info(_("Setting packages File.")) s = os.popen(_packagecmd) pkg = s.read() s.close() self.__snapshot.setPackages(pkg) except Exception, _exc: self.logger.warning( _("Problem when setting the packages list: ") + str(_exc)) # set Excludes # TODO: improve handling of Regex containing ',' (delimiter); currently this will crash self.logger.info(_("Setting Excludes File.")) if self.config.has_option("exclude", "regex"): gexclude = str(self.config.get("exclude", "regex")).split(",") else: gexclude = "" self.__snapshot.setExcludes(gexclude) _compr = self.config.get_compress_format() self.logger.info(_("Setting compression format to `%s`") % _compr) self.__snapshot.setFormat(_compr) if self.config.has_option("general", "splitsize"): _chunks = int(self.config.get("general", "splitsize")) self.__snapshot.setSplitedSize(_chunks) if _chunks: self.logger.info(_("Setting size of archive chunks to %s")\ % util.get_humanreadable_size_str(size_in_bytes = (_chunks * 1024), binary_prefixes = True)) # set followlinks self.__snapshot.setFollowLinks(self.config.get_followlinks()) if self.__snapshot.isFollowLinks(): self.logger.info(_("Option 'Follow symbolic links' is enabled.")) else: self.logger.info(_("Option 'Follow symbolic links' is disabled.")) self.__collect_files() _publish_progress = True if self.__dbus_conn is None: _publish_progress = False _supports_publish = self.__fam_target_hdl.get_supports_publish() self.logger.info(_("Snapshot is being committed")) self.__state.set_state('start') # self.__state.set_state('commit') self.__snapshot.commit(self.__fam_target_hdl, _publish_progress, _supports_publish) #TODO: add state purging # purge purge = None if self.config.has_option("general", "purge"): purge = self.config.get("general", "purge") if purge is not None: try: self.__snpman.purge( purge, self.__snapshot.getName()) # do not purge created snapshot except exceptions.SBException, sberror: self.logger.error( _("Error while purging old snapshots: %s") % sberror)
def process(self): """Runs the whole backup process: 1. check pre-conditions 3. purge snapshots (if configured) 4. open new snapshot containing common metadata (full or incr. depending on existing one, base, settings etc.) 5. fill new snapshot (with packages list, include lists, exclude lists, size prediction) 6. commit new snapshot to disk (creates the actual tar archive and writes everything into the snapshot directory). """ assert self.__fam_target_hdl.is_initialized() self.__snpman = SnapshotManager(self.__fam_target_hdl.query_mount_uri()) # get basic informations about new snapshot self.__state.set_state('prepare') (snppath, base) = self.__retrieve_basic_infos(force_full_snp = self.__full_snp) # Create a new snapshot self.__snapshot = snapshot.Snapshot(snppath) self.logger.info(_("Snapshot '%(name)s' is being made.") % {'name' :str(self.__snapshot)}) # Set the base file if base is not None: if self.__snapshot.isfull(): self.logger.debug("Base is not being set for this full snapshot.") else: self.logger.info(_("Setting Base to '%(value)s'.") % {'value' : str(base)}) self.__snapshot.setBase(base.getName()) # Backup list of installed packages _packagecmd = "dpkg --get-selections" if self.config.has_option("general", "packagecmd"): _packagecmd = self.config.get("general", "packagecmd") if _packagecmd: try: self.logger.info(_("Setting packages File.")) s = os.popen(_packagecmd) pkg = s.read() s.close() self.__snapshot.setPackages(pkg) except Exception as _exc: self.logger.warning(_("Problem when setting the packages list: ") + str(_exc)) # set Excludes # TODO: improve handling of Regex containing ',' (delimiter); currently this will crash self.logger.info(_("Setting Excludes File.")) if self.config.has_option("exclude", "regex"): gexclude = str(self.config.get("exclude", "regex")).split(",") else: gexclude = "" self.__snapshot.setExcludes(gexclude) _compr = self.config.get_compress_format() self.logger.info(_("Setting compression format to `%s`") % _compr) self.__snapshot.setFormat(_compr) if self.config.has_option("general", "splitsize"): _chunks = int(self.config.get("general", "splitsize")) self.__snapshot.setSplitedSize(_chunks) if _chunks: self.logger.info(_("Setting size of archive chunks to %s")\ % util.get_humanreadable_size_str(size_in_bytes = (_chunks * 1024), binary_prefixes = True)) # set followlinks self.__snapshot.setFollowLinks(self.config.get_followlinks()) if self.__snapshot.isFollowLinks(): self.logger.info(_("Option 'Follow symbolic links' is enabled.")) else: self.logger.info(_("Option 'Follow symbolic links' is disabled.")) self.__collect_files() _publish_progress = True if self.__dbus_conn is None: _publish_progress = False _supports_publish = self.__fam_target_hdl.get_supports_publish() self.logger.info(_("Snapshot is being committed")) self.__state.set_state('start') # self.__state.set_state('commit') self.__snapshot.commit(self.__fam_target_hdl, _publish_progress, _supports_publish) #TODO: add state purging # purge purge = None if self.config.has_option("general", "purge"): purge = self.config.get("general", "purge") if purge is not None: try: self.__snpman.purge(purge, self.__snapshot.getName()) # do not purge created snapshot except exceptions.SBException as sberror: self.logger.error(_("Error while purging old snapshots: %s") % sberror) self.logger.info(_("Backup process finished.")) self.__state.set_state('finish')