Пример #1
0
    def checkdev_cb(self, f, result, mnt):
        treeinfo = Treeinfo()

        try:
            tdata = f.load_contents_finish(result)
            treeinfo.read_str(tdata)
            ver = treeinfo.get("general", "version")
        except GLib.GError as e:
            log.info("can't read .treeinfo in %s: %s", mnt.mnt, str(e))
        except TreeinfoError as e:
            log.info("invalid .treeinfo in %s: %s", mnt.mnt, str(e))
        else:
            log.info("%s is install media", mnt.dev)
            # figure out what kind of device it is
            if isloop(mnt.dev):
                devtype = 'loop'
            if iscd(mnt.dev):
                devtype = 'dvd'
            else:
                devtype = 'usb'
            # remove placeholder, if it exists
            for row in self.srclist:
                if row[0] == devtype:
                    self.srclist.remove(row.iter)
            # add item to srclist
            self.srclist.insert(0, FedupSource(mnt.dev, icon=devtype))

        # remove the item from the work queue
        self.to_check.remove(mnt)
        if not self.to_check:
            self.populate_srclist_finished()
Пример #2
0
    def checkdev_cb(self, f, result, mnt):
        treeinfo = Treeinfo()

        try:
            tdata = f.load_contents_finish(result)
            treeinfo.read_str(tdata)
            ver = treeinfo.get("general", "version")
        except GLib.GError as e:
            log.info("can't read .treeinfo in %s: %s", mnt.mnt, str(e))
        except TreeinfoError as e:
            log.info("invalid .treeinfo in %s: %s", mnt.mnt, str(e))
        else:
            log.info("%s is install media", mnt.dev)
            # figure out what kind of device it is
            if isloop(mnt.dev):
                devtype = 'loop'
            if iscd(mnt.dev):
                devtype = 'dvd'
            else:
                devtype = 'usb'
            # remove placeholder, if it exists
            for row in self.srclist:
                if row[0] == devtype:
                    self.srclist.remove(row.iter)
            # add item to srclist
            self.srclist.insert(0, FedupSource(mnt.dev, icon=devtype))

        # remove the item from the work queue
        self.to_check.remove(mnt)
        if not self.to_check:
            self.populate_srclist_finished()
Пример #3
0
 def treeinfo(self):
     if self._treeinfo is None:
         mkdir_p(cachedir)
         outfile = os.path.join(cachedir, '.treeinfo')
         if self.cacheonly:
             log.debug("using cached .treeinfo %s", outfile)
             self._treeinfo = Treeinfo(outfile)
         else:
             log.debug("fetching .treeinfo from repo '%s'", self.instrepoid)
             if os.path.exists(outfile):
                 os.remove(outfile)
             fn = self.instrepo.grab.urlgrab('.treeinfo', outfile,
                                             reget=None)
             self._treeinfo = Treeinfo(fn)
             log.debug(".treeinfo saved at %s", fn)
         self._treeinfo.checkvalues()
     return self._treeinfo
Пример #4
0
class FedupDownloader(yum.YumBase):
    '''Yum-based downloader class for fedup. Based roughly on AnacondaYum.'''
    def __init__(self, version=None, cachedir=cachedir, cacheonly=False):
        # TODO: special handling for version='test' where we just synthesize
        #       a bunch of fake RPMs with interesting properties
        log.info("FedupDownloader(version=%s, cachedir=%s)", version, cachedir)
        yum.YumBase.__init__(self)
        self.use_txmbr_in_callback = True
        self.preconf.debuglevel = -1
        self.preconf.enabled_plugins = enabled_plugins
        self.preconf.disabled_plugins = disabled_plugins
        self.version = version
        if version:
            self.preconf.releasever = version
        self.cacheonly = cacheonly
        self.prerepoconf.cachedir = cachedir
        self.prerepoconf.cache = cacheonly
        log.debug("prerepoconf.cache=%i", self.prerepoconf.cache)
        self.instrepoid = None
        self.disabled_repos = []
        self._treeinfo = None
        self.failstate = URLGrabFailureState()
        self.prerepoconf.failure_callback = self.failstate.callback
        self._repoprogressbar = None
        # TODO: locking to prevent multiple instances
        # TODO: override logging objects so we get yum logging

    def _getConfig(self):
        firstrun = hasattr(self, 'preconf')
        conf = yum.YumBase._getConfig(self)
        if firstrun:
            # override some of yum's defaults
            conf.disable_excludes = ['all']
            conf.cache = self.cacheonly
            log.debug("conf.cache=%i", conf.cache)
        return conf

    def add_repo(self, repoid, baseurls=[], mirrorlist=None, **kwargs):
        '''like add_enable_repo, but doesn't do initial repo setup and doesn't
        make unnecessary changes'''
        r = yum.yumRepo.YumRepository(repoid)
        r.name = repoid
        r.base_persistdir = cachedir
        r.basecachedir = cachedir
        r.cache = self.cacheonly
        r.callback = kwargs.get('callback') or self._repoprogressbar
        r.failure_obj = self.failstate.callback
        r.baseurl = [varReplace(u, self.conf.yumvar) for u in baseurls if u]
        if mirrorlist:
            r.mirrorlist = varReplace(mirrorlist, self.conf.yumvar)
        self._repos.add(r)
        self._repos.enableRepo(repoid)

    def setup_repos(self, callback=None, progressbar=None, repos=[]):
        '''Return a list of repos that had problems setting up.'''
        # These will set up progressbar and callback when we actually do setup
        self.prerepoconf.progressbar = progressbar
        self.prerepoconf.callback = callback
        self._repoprogressbar = progressbar

        # TODO invalidate cache if the version doesn't match previous version
        log.info("checking repos")

        # Add default instrepo if needed
        if self.instrepoid is None:
            self.instrepoid = 'default-installrepo'
            mirrorurl = mirrorlist('fedora-install-$releasever')
            repos.append(('add', '%s=@%s' % (self.instrepoid, mirrorurl)))

        # We need to read .repo files before we can enable/disable them, so:
        self.repos # implicit repo setup! ha ha! what fun!

        if self.version is None: # i.e. no --network arg
            self.repos.disableRepo('*')

        # user overrides to enable/disable repos.
        # NOTE: will raise YumBaseError if there are problems
        for action, repo in repos:
            if action == 'enable':
                self.repos.enableRepo(repo)
            elif action == 'disable':
                self.repos.disableRepo(repo)
            elif action == 'add':
                (repoid, url) = repo.split('=',1)
                if url[0] == '@':
                    self.add_repo(repoid, mirrorlist=url[1:])
                else:
                    self.add_repo(repoid, baseurls=[url])
                if self.conf.proxy:
                    repo = self.repos.getRepo(repoid)
                    repo.proxy = self.conf.proxy
                    repo.proxy_username = self.conf.proxy_username
                    repo.proxy_password = self.conf.proxy_password

        # check enabled repos
        for repo in self.repos.listEnabled():
            try:
                md_types = repo.repoXML.fileTypes()
            except yum.Errors.RepoError:
                log.info("can't find valid repo metadata for %s", repo.id)
                repo.disable()
                self.disabled_repos.append(repo.id)
            else:
                log.info("repo %s seems OK" % repo.id)

        log.debug("repos.cache=%i", self.repos.cache)

        return self.disabled_repos

    # XXX currently unused
    def save_repo_configs():
        '''save repo configuration files for later use'''
        repodir = os.path.join(cachedir, 'yum.repos.d')
        mkdir_p(repodir)
        for repo in self.repos.listEnabled():
            repofile = os.path.join(repodir, "%s.repo" % repo.id)
            try:
                repo.write(open(repofile), 'w')
            except IOError as e:
                log.warn("couldn't write repofile for %s: %s", repo.id, str(e))

    # NOTE: could raise RepoError if metadata is missing/busted
    def build_update_transaction(self, callback=None):
        log.info("looking for updates")
        self.dsCallback = callback
        self.update()
        (rv, msgs) = self.buildTransaction(unfinished_transactions_check=False)
        log.info("buildTransaction returned %i", rv)
        for m in msgs:
            log.info("    %s", m)
        # NOTE: we ignore errors, as anaconda did before us.
        self.dsCallback = None
        return [t.po for t in self.tsInfo.getMembers()
                     if t.ts_state in ("i", "u")]

    def download_packages(self, pkgs, callback=None):
        # Verifying a full upgrade payload of ~2000 pkgs takes a good 90-120
        # seconds with no callback. Unacceptable!
        # So: here we have our own verifyPkg loop, with callback.
        # The results get cached, so when yum does it again in the real
        # _downloadPackages function it's a negligible delay.
        localpkgs = [p for p in pkgs if os.path.exists(p.localPkg())]
        total = len(localpkgs)
        # XXX: multithreading?
        for num, p in enumerate(localpkgs, 1):
            local = p.localPkg()
            if hasattr(callback, "verify") and callable(callback.verify):
                callback.verify(num, total, local, None)
            ok = self.verifyPkg(local, p, False) # result will be cached by yum
        log.info("beginning package download...")
        updates = self._downloadPackages(callback)
        if set(updates) != set(pkgs):
            log.debug("differences between requested pkg set and downloaded:")
            for p in set(pkgs).difference(updates):
                log.debug("  -%s", p)
            for p in set(updates).difference(pkgs):
                log.debug("  +%s", p)
        # TODO check signatures of downloaded packages

    def clean_cache(self, keepfiles):
        log.info("checking for unneeded rpms in cache")
        # Find all the packages in the caches (not on media though)
        localpkgs = set(f for r in self.repos.listEnabled() if not r.mediaid
                          for f in listdir(r.pkgdir) if f.endswith(".rpm"))
        for f in localpkgs.difference(keepfiles):
            try:
                log.debug("removing %s", f)
                os.remove(f)
            except IOError as e:
                log.info("failed to remove %s", f)
        # TODO remove dirs that don't belong to any repo

    @property
    def instrepo(self):
        return self.repos.getRepo(self.instrepoid)

    @property
    def treeinfo(self):
        if self._treeinfo is None:
            mkdir_p(cachedir)
            outfile = os.path.join(cachedir, '.treeinfo')
            if self.cacheonly:
                log.debug("using cached .treeinfo %s", outfile)
                self._treeinfo = Treeinfo(outfile)
            else:
                log.debug("fetching .treeinfo from repo '%s'", self.instrepoid)
                if os.path.exists(outfile):
                    os.remove(outfile)
                fn = self.instrepo.grab.urlgrab('.treeinfo', outfile,
                                                reget=None)
                self._treeinfo = Treeinfo(fn)
                log.debug(".treeinfo saved at %s", fn)
            self._treeinfo.checkvalues()
        return self._treeinfo

    def download_boot_images(self, arch=None):
        # helper function to grab and checksum image files listed in .treeinfo
        def grab_and_check(imgarch, imgtype, outpath):
            relpath = self.treeinfo.get_image(imgarch, imgtype)
            log.debug("grabbing %s %s", imgarch, imgtype)
            log.info("downloading %s to %s", relpath, outpath)
            if self.treeinfo.checkfile(outpath, relpath):
                log.debug("file already exists and checksum OK")
                return outpath
            def checkfile(cb):
                log.debug("checking %s", relpath)
                if not self.treeinfo.checkfile(cb.filename, relpath):
                    log.info("checksum doesn't match - retrying")
                    raise yum.URLGrabError(-1)
            return self.instrepo.grab.urlgrab(relpath, outpath,
                                              checkfunc=checkfile,
                                              reget=None,
                                              copy_local=True)

        # download the images
        try:
            if not arch:
                arch = self.treeinfo.get('general', 'arch')
            kernel = grab_and_check(arch, 'kernel', kernelpath)
            initrd = grab_and_check(arch, 'upgrade', initrdpath)
        except TreeinfoError as e:
            raise YumBaseError(_("invalid data in .treeinfo: %s") % str(e))
        except yum.URLGrabError as e:
            f = os.path.basename(self.failstate.lasturl)
            if e.errno >= 256:
                err = str(self.failstate.lastexc)
            else:
                err = str(e)
            raise YumBaseError(_("couldn't get %s:\n  %s") % (f, err))

        # Save kernel/initrd info so we can clean it up later
        mkdir_p(os.path.dirname(upgradeconf))
        with Config(upgradeconf) as conf:
            conf.set("boot", "kernel", kernel)
            conf.set("boot", "initrd", initrd)

        return kernel, initrd