예제 #1
0
    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})
예제 #2
0
 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)
예제 #4
0
    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')