def pcmp(lhs, rhs): """ Compare packages by these NVRAEs. :param lhs, rhs: dict(name, version, release, epoch, arch) :note: It does not utilize rpm.versionCompare even if yum is not available. >>> lhs = dict(name="gpg-pubkey", version="00a4d52b", release="4cb9dd70", ... arch="noarch", epoch=0, ... ) >>> rhs = dict(name="gpg-pubkey", version="069c8460", release="4d5067bf", ... arch="noarch", epoch=0, ... ) >>> pcmp(lhs, lhs) == 0 True >>> pcmp(lhs, rhs) < 0 True >>> p3 = dict(name="kernel", version="2.6.38.8", release="32", ... arch="x86_64", epoch=0, ... ) >>> p4 = dict(name="kernel", version="2.6.38.8", release="35", ... arch="x86_64", epoch=0, ... ) >>> pcmp(p3, p4) < 0 True >>> p5 = dict(name="rsync", version="2.6.8", release="3.1", ... arch="x86_64", epoch=0, ... ) >>> p6 = dict(name="rsync", version="3.0.6", release="4.el5", ... arch="x86_64", epoch=0, ... ) >>> pcmp(p3, p4) < 0 True """ p2evr = operator.itemgetter("epoch", "version", "release") assert lhs["name"] == rhs["name"], "Trying to compare different packages!" return yum.compareEVR(p2evr(lhs), p2evr(rhs))
def pcmp(p1, p2): """Compare packages by NVRAEs. :param p1, p2: dict(name, version, release, epoch, arch) TODO: Make it fallback to rpm.versionCompare if yum is not available? >>> p1 = dict(name="gpg-pubkey", version="00a4d52b", release="4cb9dd70", ... arch="noarch", epoch=0, ... ) >>> p2 = dict(name="gpg-pubkey", version="069c8460", release="4d5067bf", ... arch="noarch", epoch=0, ... ) >>> pcmp(p1, p1) == 0 True >>> pcmp(p1, p2) < 0 True >>> p3 = dict(name="kernel", version="2.6.38.8", release="32", ... arch="x86_64", epoch=0, ... ) >>> p4 = dict(name="kernel", version="2.6.38.8", release="35", ... arch="x86_64", epoch=0, ... ) >>> pcmp(p3, p4) < 0 True >>> p5 = dict(name="rsync", version="2.6.8", release="3.1", ... arch="x86_64", epoch=0, ... ) >>> p6 = dict(name="rsync", version="3.0.6", release="4.el5", ... arch="x86_64", epoch=0, ... ) >>> pcmp(p3, p4) < 0 True """ p2evr = itemgetter("epoch", "version", "release") assert p1["name"] == p2["name"], "Trying to compare different packages!" return yum.compareEVR(p2evr(p1), p2evr(p2))
def pcmp(p1, p2): """Compare packages by these versions, releases and epoch numbers. :param p1, p2: (normalized) NVRE TODO: Fallback to rpm.versionCompare if yum is not available? # special cases: >>> p1 = dict(name="gpg-pubkey", version="00a4d52b", release="4cb9dd70", ... epoch=0, ... ) >>> p2 = dict(name="gpg-pubkey", version="069c8460", release="4d5067bf", ... epoch=0, ... ) >>> pcmp(p1, p1) == 0 True >>> pcmp(p1, p2) < 0 True >>> # compare by releases >>> p3 = dict(name="kernel", version="2.6.38.8", release="32", epoch=0) >>> p4 = dict(name="kernel", version="2.6.38.8", release="35", epoch=0) >>> pcmp(p3, p4) < 0 True >>> # compare by versions and releases >>> p5 = dict(name="rsync", version="2.6.8", release="3.1", epoch=0) >>> p6 = dict(name="rsync", version="3.0.6", release="4.el5", epoch=0) >>> pcmp(p3, p4) < 0 True >>> # compare by epoch numbers >>> p7 = dict(name="rsync", version="2.6.8", release="3.1", epoch=2) >>> p8 = dict(name="rsync", version="3.0.6", release="4.el5", epoch=0) >>> pcmp(p7, p8) > 0 True """ p2evr = lambda p: (p["epoch"], p["version"], p["release"]) assert p1["name"] == p2["name"], "Trying to compare different packages!" return yum.compareEVR(p2evr(p1), p2evr(p2))
def rpmcmp(p1, p2): p2evr = lambda p: (p["epoch"], p["version"], p["release"]) return yum.compareEVR(p2evr(p1), p2evr(p2))
yum.misc.prco_tuple_to_string(provides))) else: current_evr = (current_pkg.epoch, current_pkg.version, current_pkg.release) self.logger.info(" %s: Wrong version installed. " "Want %s, but have %s" % (entry.get("name"), nevra2string(nevra), nevra2string(current_pkg))) wanted_evr = (nevra.get('epoch', 'any'), nevra.get('version', 'any'), nevra.get('release', 'any')) entry.set('current_version', "%s:%s-%s" % current_evr) entry.set('version', "%s:%s-%s" % wanted_evr) if yum.compareEVR(current_evr, wanted_evr) == 1: entry.set("package_fail_action", "downgrade") else: entry.set("package_fail_action", "update") qtext_versions.append("U(%s)" % str(all_pkg_objs[0])) continue if Bcfg2.Options.setup.quick: # Passed -q on the command line continue if not (pkg_verify and inst.get('pkg_verify', 'true').lower() == 'true'): continue # XXX: We ignore GPG sig checking the package as it
def VerifyPackage(self, entry, modlist): """ Verify Package status for entry. Performs the following: * Checks for the presence of required Package Instances. * Compares the evra 'version' info against self.installed{}. * RPM level package verify (rpm --verify). * Checks for the presence of unrequired package instances. Produces the following dict and list for Yum.Install() to use: * For installs/upgrades/fixes of required instances:: instance_status = { <Instance Element Object>: { 'installed': True|False, 'version_fail': True|False, 'verify_fail': True|False, 'pkg': <Package Element Object>, 'modlist': [ <filename>, ... ], 'verify' : [ <rpm --verify results> ] }, ...... } * For deletions of unrequired instances:: extra_instances = [ <Package Element Object>, ..... ] Constructs the text prompts for interactive mode. """ if entry.get('version', False) == 'auto': self._fixAutoVersion(entry) if entry.get('group'): self.logger.debug("Verifying packages for group %s" % entry.get('group')) else: self.logger.debug("Verifying package instances for %s" % entry.get('name')) self.verify_cache = dict() # Used for checking multilib packages self.modlists[entry] = modlist instances = self._buildInstances(entry) pkg_cache = [] package_fail = False qtext_versions = [] virt_pkg = False pkg_checks = (Bcfg2.Options.setup.yum_pkg_checks and entry.get('pkg_checks', 'true').lower() == 'true') pkg_verify = (Bcfg2.Options.setup.yum_pkg_verify and entry.get('pkg_verify', 'true').lower() == 'true') yum_group = False if entry.get('name') == 'gpg-pubkey': all_pkg_objs = self._getGPGKeysAsPackages() pkg_verify = False # No files here to verify elif entry.get('group'): entry.set('name', 'group:%s' % entry.get('group')) yum_group = True all_pkg_objs = [] instances = [] if self.yumbase.comps.has_group(entry.get('group')): group = self.yumbase.comps.return_group(entry.get('group')) group_packages = [p for p, d in group.mandatory_packages.items() if d] group_type = entry.get('choose', 'default') if group_type in ['default', 'optional', 'all']: group_packages += [ p for p, d in group.default_packages.items() if d] if group_type in ['optional', 'all']: group_packages += [ p for p, d in group.optional_packages.items() if d] if len(group_packages) == 0: self.logger.error("No packages found for group %s" % entry.get("group")) for pkg in group_packages: # create package instances for each package in yum group instance = Bcfg2.Client.XML.SubElement(entry, 'Package') instance.attrib['name'] = pkg instance.attrib['type'] = 'yum' try: newest = \ self.yumbase.pkgSack.returnNewestByName(pkg)[0] instance.attrib['version'] = newest['version'] instance.attrib['epoch'] = newest['epoch'] instance.attrib['release'] = newest['release'] except: # pylint: disable=W0702 self.logger.info("Error finding newest package " "for %s" % pkg) instance.attrib['version'] = 'any' instances.append(instance) else: self.logger.error("Group not found: %s" % entry.get("group")) else: all_pkg_objs = \ self.yumbase.rpmdb.searchNevra(name=entry.get('name')) if len(all_pkg_objs) == 0 and yum_group is not True: # Some sort of virtual capability? Try to resolve it all_pkg_objs = self.yumbase.rpmdb.searchProvides(entry.get('name')) if len(all_pkg_objs) > 0: virt_pkg = True self.logger.info("%s appears to be provided by:" % entry.get('name')) for pkg in all_pkg_objs: self.logger.info(" %s" % pkg) for inst in instances: if yum_group: # the entry is not the name of the package nevra = build_yname(inst.get('name'), inst) all_pkg_objs = \ self.yumbase.rpmdb.searchNevra(name=inst.get('name')) else: nevra = build_yname(entry.get('name'), inst) if nevra in pkg_cache: continue # Ignore duplicate instances else: pkg_cache.append(nevra) self.logger.debug("Verifying: %s" % nevra2string(nevra)) # Set some defaults here stat = self.instance_status.setdefault(inst, {}) stat['installed'] = True stat['version_fail'] = False stat['verify'] = {} stat['verify_fail'] = False if yum_group: stat['pkg'] = inst else: stat['pkg'] = entry stat['modlist'] = modlist if inst.get('verify_flags'): # this splits on either space or comma verify_flags = \ inst.get('verify_flags').lower().replace(' ', ',').split(',') else: verify_flags = Bcfg2.Options.setup.yum_verify_flags if 'arch' in nevra: # If arch is specified use it to select the package pkg_objs = [p for p in all_pkg_objs if p.arch == nevra['arch']] else: pkg_objs = all_pkg_objs if len(pkg_objs) == 0: # Package (name, arch) not installed entry.set('current_exists', 'false') self.logger.debug(" %s is not installed" % nevra2string(nevra)) stat['installed'] = False package_fail = True qtext_versions.append("I(%s)" % nevra) continue if not pkg_checks: continue # Check EVR if virt_pkg: # we need to make sure that the version of the symbol # provided matches the one required in the # configuration vlist = [] for attr in ["epoch", "version", "release"]: vlist.append(nevra.get(attr)) if tuple(vlist) == (None, None, None): # we just require the package name, no particular # version, so just make a copy of all_pkg_objs since every # package that provides this symbol satisfies the # requirement pkg_objs = [po for po in all_pkg_objs] else: pkg_objs = [po for po in all_pkg_objs if po.checkPrco('provides', (nevra["name"], 'EQ', tuple(vlist)))] elif entry.get('name') == 'gpg-pubkey': if 'version' not in nevra: self.logger.warning("Skipping verify: gpg-pubkey without " "an RPM version") continue if 'release' not in nevra: self.logger.warning("Skipping verify: gpg-pubkey without " "an RPM release") continue pkg_objs = [p for p in all_pkg_objs if (p.version == nevra['version'] and p.release == nevra['release'])] else: pkg_objs = self.yumbase.rpmdb.searchNevra(**short_yname(nevra)) if len(pkg_objs) == 0: package_fail = True stat['version_fail'] = True # Just chose the first pkg for the error message current_pkg = all_pkg_objs[0] if virt_pkg: provides = \ [p for p in current_pkg.provides if p[0] == entry.get("name")][0] current_evr = provides[2] self.logger.info( " %s: Wrong version installed. " "Want %s, but %s provides %s" % (entry.get("name"), nevra2string(nevra), nevra2string(current_pkg), yum.misc.prco_tuple_to_string(provides))) else: current_evr = (current_pkg.epoch, current_pkg.version, current_pkg.release) self.logger.info(" %s: Wrong version installed. " "Want %s, but have %s" % (entry.get("name"), nevra2string(nevra), nevra2string(current_pkg))) wanted_evr = (nevra.get('epoch', 'any'), nevra.get('version', 'any'), nevra.get('release', 'any')) entry.set('current_version', "%s:%s-%s" % current_evr) entry.set('version', "%s:%s-%s" % wanted_evr) if yum.compareEVR(current_evr, wanted_evr) == 1: entry.set("package_fail_action", "downgrade") else: entry.set("package_fail_action", "update") qtext_versions.append("U(%s)" % str(all_pkg_objs[0])) continue if Bcfg2.Options.setup.quick: # Passed -q on the command line continue if not (pkg_verify and inst.get('pkg_verify', 'true').lower() == 'true'): continue # XXX: We ignore GPG sig checking the package as it # has nothing to do with the individual file hash/size/etc. # GPG checking the package only eaxmines some header/rpmdb # wacky-ness, and will not properly detect a compromised rpmdb. # Yum's verify routine does not support it for that reaosn. if len(pkg_objs) > 1: self.logger.debug(" Verify Instance found many packages:") for pkg in pkg_objs: self.logger.debug(" %s" % str(pkg)) try: vrfy_result = self._verifyHelper(pkg_objs[0]) except: # pylint: disable=W0702 err = sys.exc_info()[1] # Unknown Yum exception self.logger.warning(" Verify Exception: %s" % err) package_fail = True continue # Now take out the Yum specific objects / modlists / unproblems ignores = [ig.get('name') for ig in entry.findall('Ignore')] + \ [ig.get('name') for ig in inst.findall('Ignore')] + \ self.ignores for fname, probs in list(vrfy_result.items()): if fname in modlist: self.logger.debug(" %s in modlist, skipping" % fname) continue if fname in ignores: self.logger.debug(" %s in ignore list, skipping" % fname) continue tmp = [] for prob in probs: if prob.type == 'missing' and os.path.islink(fname): continue elif 'no' + prob.type in verify_flags: continue if prob.type not in ['missingok', 'ghost']: tmp.append((prob.type, prob.message)) if tmp != []: stat['verify'][fname] = tmp if stat['verify'] != {}: stat['verify_fail'] = True package_fail = True self.logger.info("It is suggested that you either manage " "these files, revert the changes, or ignore " "false failures:") self.logger.info(" Verify Problems: %s" % stat['pkg'].get('name')) for fname, probs in list(stat['verify'].items()): if len(probs) > 1: self.logger.info(" %s" % fname) for prob in probs: self.logger.info(" %s" % prob[1]) else: self.logger.info(" %s: %s" % (fname, probs[0])) if len(all_pkg_objs) > 0: # Is this an install only package? We just look at the first one provides = set([p[0] for p in all_pkg_objs[0].provides] + [all_pkg_objs[0].name]) install_only = len(set(self.installonlypkgs) & provides) > 0 else: install_only = False if virt_pkg or \ (install_only and not Bcfg2.Options.setup.kevlar) or \ yum_group: # virtual capability supplied, we are probably dealing # with multiple packages of different names. This check # doesn't make a lot of since in this case. # install_only: Yum may clean some of these up itself. # Otherwise having multiple instances of install only packages # is considered correct self.extra_instances = None else: self.extra_instances = self.FindExtraInstances(entry, all_pkg_objs) if self.extra_instances is not None: package_fail = True return not package_fail