From 4bfd5a3087a085766681419e30544774ff41b944 Mon Sep 17 00:00:00 2001 From: Narayan Desai Date: Wed, 11 Apr 2007 00:14:59 +0000 Subject: Latest version of RPMng from mbrady git-svn-id: https://svn.mcs.anl.gov/repos/bcfg/trunk/bcfg2@3029 ce84e21b-d406-0410-9b95-82705330c041 --- src/lib/Client/Tools/RPMng.py | 891 +++++++++++++++++++++++++++------------ src/lib/Client/Tools/rpmtools.py | 131 +++--- 2 files changed, 703 insertions(+), 319 deletions(-) diff --git a/src/lib/Client/Tools/RPMng.py b/src/lib/Client/Tools/RPMng.py index dcda1bed7..926e29c4d 100644 --- a/src/lib/Client/Tools/RPMng.py +++ b/src/lib/Client/Tools/RPMng.py @@ -2,7 +2,8 @@ __revision__ = '$Revision$' -import Bcfg2.Client.Tools, time, rpmtools, sys +import Bcfg2.Client.Tools, rpmtools, os.path, rpm, ConfigParser + class RPMng(Bcfg2.Client.Tools.PkgTool): '''Support for RPM packages''' @@ -17,26 +18,49 @@ class RPMng(Bcfg2.Client.Tools.PkgTool): __new_ireq__ = {'Package': ['name', 'uri'], \ 'Instance': ['simplefile', 'version', 'release', 'arch']} - __gpg_req__ = {'Package': ['name'], 'Instance': ['version', 'release']} - __gpg_ireq__ = {'Package': ['name'], 'Instance': ['version', 'release']} + __gpg_req__ = {'Package': ['name', 'version']} + __gpg_ireq__ = {'Package': ['name', 'version']} + + __new_gpg_req__ = {'Package': ['name'], 'Instance': ['version', 'release']} + __new_gpg_ireq__ = {'Package': ['name'], 'Instance': ['version', 'release']} conflicts = ['RPM'] pkgtype = 'rpm' pkgtool = ("rpm --oldpackage --replacepkgs --quiet -U %s", ("%s", ["url"])) - # This is mostly the default list from YUM on Centos 4. Check these are - # still correct. - # ***** Should probably put in bcfg2.config somewhere. ***** - installOnlyPkgs = ['kernel', 'kernel-bigmem', 'kernel-enterprise', 'kernel-smp', - 'kernel-modules', 'kernel-debug', 'kernel-unsupported', - 'kernel-source', 'kernel-devel', 'kernel-default', - 'kernel-largesmp-devel', 'kernel-largesmp', 'gpg-pubkey'] def __init__(self, logger, setup, config, states): Bcfg2.Client.Tools.PkgTool.__init__(self, logger, setup, config, states) + self.installOnlyPkgs = [] + self.erase_flags = [] self.instance_status = {} + self.extra_instances = [] + self.gpg_keyids = self.getinstalledgpg() + + # Process thee RPMng section from the config file. + RPMng_CP = ConfigParser.ConfigParser() + RPMng_CP.read(self.setup.get('setup')) + + # installonlypackages + if RPMng_CP.has_option('RPMng','installonlypackages'): + self.installOnlyPkgs = RPMng_CP.get('RPMng','installonlypackages').split(',') + \ + ['gpg-pubkey'] + if self.installOnlyPkgs == []: + self.installOnlyPkgs = ['kernel', 'kernel-bigmem', 'kernel-enterprise', 'kernel-smp', + 'kernel-modules', 'kernel-debug', 'kernel-unsupported', + 'kernel-source', 'kernel-devel', 'kernel-default', + 'kernel-largesmp-devel', 'kernel-largesmp', 'kernel-xen', + 'gpg-pubkey'] + self.logger.debug('installOnlyPackages = %s' % self.installOnlyPkgs) + + # erase_flags + if RPMng_CP.has_option('RPMng','erase_flags'): + self.installOnlyPkgs = RPMng_CP.get('RPMng','erase_flags').split(',') + if self.erase_flags == []: + self.erase_flags = ['allmatches'] + self.logger.debug('erase_flags = %s' % self.erase_flags) def RefreshPackages(self): ''' @@ -56,6 +80,9 @@ class RPMng(Bcfg2.Client.Tools.PkgTool): ''' self.installed = {} refresh_ts = rpmtools.rpmtransactionset() + # Don't bother with signature checks at this stage. The GPG keys might + # not be installed. + refresh_ts.setVSFlags(rpm._RPMVSF_NODIGESTS|rpm._RPMVSF_NOSIGNATURES) for nevra in rpmtools.rpmpackagelist(refresh_ts): self.installed.setdefault(nevra['name'], []).append(nevra) if self.setup['debug']: @@ -63,32 +90,48 @@ class RPMng(Bcfg2.Client.Tools.PkgTool): for name, instances in self.installed.iteritems(): self.logger.info(" " + name) for inst in instances: - self.logger.info(" %s:%s-%s.%s" % \ - (inst.get('epoch', None), inst.get('version', None), - inst.get('release', None), inst.get('arch', None))) + self.logger.info(" %s" %self.str_evra(inst)) refresh_ts.closeDB() + del refresh_ts def VerifyPackage(self, entry, modlist): ''' Verify Package status for entry. - Compares the 'version' info against self.installed{} and does - an rpm level package verify. - - Code for the old/new style Package Entries has been kept separate, - even though it has meant some code duplication, so that the old style - code can be easily removed at a later date. + 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 RPMng.Install() to use: + For installs/upgrades/fixes of required instances: + instance_status = { : + { 'installed': True|False, + 'version_fail': True|False, + 'verify_fail': True|False, + 'pkg': , + 'modlist': [ , ... ], + 'verify' : [ ] + }, ...... + } + + For deletions of unrequired instances: + extra_instances = [ , ..... ] + + Constructs the text prompts for interactive mode. ''' - - instances = entry.findall('Instance') - if not instances: - # We have an old style no Instance entry. - if entry.get('release', None) == None: - version, release = entry.get('version').split('-') - entry.set('version', version) - entry.set('release', release) - instances = [ entry ] - - vp_ts = rpmtools.rpmtransactionset() + if len(entry) == 0: + # We have an old style no Instance entry. Convert it to new style. + version, release = entry.get('version').split('-') + instance = Bcfg2.Client.XML.SubElement(entry, 'Package') + for attrib in entry.attrib.keys(): + instance.attrib[attrib] = entry.attrib[attrib] + instance.set('version', version) + instance.set('release', release) + instances = [ instance ] + else: + # We have a new style entry or a previously converted old style entry. + instances = [inst for inst in entry if inst.tag == 'Instance' or inst.tag == 'Package'] self.logger.info("Verifying package instances for %s" % entry.get('name')) package_fail = False @@ -104,43 +147,32 @@ class RPMng(Bcfg2.Client.Tools.PkgTool): self.instance_status.setdefault(inst, {})['installed'] = False self.instance_status[inst]['version_fail'] = False if inst.tag == 'Package' and len(self.installed[entry.get('name')]) > 1: - self.logger.error("WARNING: Multiple instances of package %s are installed." % (entry.get('name'))) + self.logger.error("WARNING: Multiple instances of package %s are installed." % \ + (entry.get('name'))) for pkg in self.installed[entry.get('name')]: - if inst.tag == 'Package': - # We have an old style Package entry that does not - # have an epoch or an arch, so scrub them from - # installed{}. - pkg.pop('arch', None) - pkg.pop('epoch', None) - if inst.get('epoch', None) != None: - epoch = int(inst.get('epoch')) - else: - epoch = None - if epoch == pkg.get('epoch') and \ - inst.get('version') == pkg.get('version') and \ - inst.get('release') == pkg.get('release') and \ - inst.get('arch', None) == pkg.get('arch', None): - self.logger.info(" %s:%s-%s.%s" % \ - (inst.get('epoch', None), inst.get('version'), - inst.get('release'), inst.get('arch', None))) + if self.pkg_vr_equal(inst, pkg) or self.inst_evra_equal(inst, pkg): + self.logger.info(" %s" % self.str_evra(inst)) self.logger.debug(" verify_flags = %s" % \ (inst.get('verify_flags', []))) self.instance_status[inst]['installed'] = True + + flags = inst.get('verify_flags', '').split(',') + if pkg.get('gpgkeyid', '')[-8:] not in self.gpg_keyids and \ + entry.get('name') != 'gpg-pubkey': + flags += ['nosignature', 'nodigest'] + self.logger.info('WARNING: Package %s %s requires GPG Public key with ID %s'\ + % (pkg.get('name'), self.str_evra(pkg), \ + pkg.get('gpgkeyid', ''))) + self.logger.info(' Disabling signature check.') + self.instance_status[inst]['verify'] = \ - rpmtools.rpm_verify( vp_ts, pkg, \ - inst.get('verify_flags', '').split(',')) + rpmtools.rpm_verify( self.vp_ts, pkg, flags) if self.instance_status[inst]['installed'] == False: - package_fail = True - self.logger.info(" Package %s %s:%s-%s.%s not installed." % \ - (entry.get('name'), - inst.get('epoch', None), inst.get('version'), - inst.get('release'), inst.get('arch', None))) + self.logger.info(" Package %s %s not installed." % \ + (entry.get('name'), self.str_evra(inst))) - qtext_versions = qtext_versions + '%s:%s-%s.%s ' % \ - (inst.get('epoch', ''), inst.get('version', ''),\ - inst.get('release', ''), inst.get('arch', '')) - + qtext_versions = qtext_versions + 'I(%s) ' % self.str_evra(inst) entry.set('current_exists', 'false') else: # Normal Packages that can be upgraded. @@ -163,57 +195,38 @@ class RPMng(Bcfg2.Client.Tools.PkgTool): # There is only one installed like there should be. # Check that it is the right version. for pkg in arch_match: - if inst.tag == 'Package': - # We have an old style Package entry that does not - # have an epoch or an arch, so scrub them from - # installed{}. - pkg.pop('arch', None) - pkg.pop('epoch', None) - if inst.get('epoch', None) != None: - epoch = int(inst.get('epoch')) - else: - epoch = None - if epoch == pkg.get('epoch', None) and \ - inst.get('version') == pkg.get('version') and \ - inst.get('release') == pkg.get('release'): - self.logger.info(" %s:%s-%s.%s" % \ - (inst.get('epoch', None), inst.get('version', ''), \ - inst.get('release', ''), inst.get('arch', None))) + if self.pkg_vr_equal(inst, pkg) or self.inst_evra_equal(inst, pkg): + self.logger.info(" %s" % self.str_evra(inst)) self.logger.debug(" verify_flags = %s" % \ (inst.get('verify_flags', []))) self.instance_status[inst]['installed'] = True + + flags = inst.get('verify_flags', '').split(',') + if pkg.get('gpgkeyid', '')[-8:] not in self.gpg_keyids: + flags += ['nosignature', 'nodigest'] + self.logger.info('WARNING: Package %s %s requires GPG Public key with ID %s'\ + % (pkg.get('name'), self.str_evra(pkg), \ + pkg.get('gpgkeyid', ''))) + self.logger.info(' Disabling signature check.') + self.instance_status[inst]['verify'] = \ - rpmtools.rpm_verify( vp_ts, pkg,\ - inst.get('verify_flags', '').split(',')) + rpmtools.rpm_verify( self.vp_ts, pkg, flags ) + else: - package_fail = True + # Wrong version installed. self.instance_status[inst]['version_fail'] = True - self.logger.info(" Wrong version installed. Want %s:%s-%s.%s, but have %s:%s-%s.%s" % \ - (inst.get('epoch', None), inst.get('version'), \ - inst.get('release'), inst.get('arch', None), \ - pkg.get('epoch'), pkg.get('version'), \ - pkg.get('release'), pkg.get('arch'))) + self.logger.info(" Wrong version installed. Want %s, but have %s"\ + % (self.str_evra(inst), self.str_evra(pkg))) - qtext_versions = qtext_versions + \ - '(%s:%s-%s.%s -> %s:%s-%s.%s) ' % \ - (pkg.get('epoch', ''), pkg.get('version'), \ - pkg.get('release'), pkg.get('arch', ''), \ - inst.get('epoch', ''), inst.get('version'), \ - inst.get('release'), inst.get('arch', '')) + qtext_versions = qtext_versions + 'U(%s -> %s) ' % \ + (self.str_evra(pkg), self.str_evra(inst)) elif len(arch_match) == 0: # This instance is not installed. self.instance_status[inst]['installed'] = False - - self.logger.info(" %s:%s-%s.%s is not installed." % \ - (inst.get('epoch', None), inst.get('version'), \ - inst.get('release'), inst.get('arch', None))) - - qtext_versions = qtext_versions + '%s:%s-%s.%s ' % \ - (inst.get('epoch', ''), inst.get('version'), \ - inst.get('release'), inst.get('arch', '')) - - entry.set('current_exists', 'false') + self.logger.info(" %s is not installed." % self.str_evra(inst)) + qtext_versions = qtext_versions + 'I(%s) ' % self.str_evra(inst) + # Check the rpm verify results. for inst in instances: instance_fail = False # Dump the rpm verify results. @@ -221,24 +234,21 @@ class RPMng(Bcfg2.Client.Tools.PkgTool): if self.setup['debug'] and self.instance_status[inst].get('verify', None): self.logger.debug(self.instance_status[inst]['verify']) - # Check the rpm verify results. + self.instance_status[inst]['verify_fail'] = False if self.instance_status[inst].get('verify', None): if len(self.instance_status[inst].get('verify')) > 1: self.logger.info("WARNING: Verification of more than one package instance.") - self.instance_status[inst]['verify_fail'] = False for result in self.instance_status[inst]['verify']: # Check header results - if result.get('hdr', []): - package_fail = True + if result.get('hdr', None): instance_fail = True self.instance_status[inst]['verify_fail'] = True # Check dependency results - if result.get('deps', []): - package_fail = True + if result.get('deps', None): instance_fail = True self.instance_status[inst]['verify_fail'] = True @@ -248,7 +258,6 @@ class RPMng(Bcfg2.Client.Tools.PkgTool): if file_result[-1] not in modlist and \ file_result[-1] not in \ [ignore.get('name') for ignore in inst.findall('Ignore')]: - package_fail = True instance_fail = True self.instance_status[inst]['verify_fail'] = True else: @@ -256,87 +265,355 @@ class RPMng(Bcfg2.Client.Tools.PkgTool): (file_result[-1])) if instance_fail == True: - self.logger.info("*** Instance %s:%s-%s.%s failed RPM verification ***" % \ - (inst.get('epoch', None), inst.get('version'), \ - inst.get('release'), inst.get('arch', None))) - - qtext_versions = qtext_versions + '%s:%s-%s.%s ' % \ - (inst.get('epoch', ''), inst.get('version'), \ - inst.get('release'), inst.get('arch', '')) + self.logger.info("*** Instance %s failed RPM verification ***" % \ + self.str_evra(inst)) + qtext_versions = qtext_versions + 'R(%s) ' % self.str_evra(inst) + self.instance_status[inst]['modlist'] = modlist if self.instance_status[inst]['installed'] == False or \ - self.instance_status[inst]['version_fail'] == True: + self.instance_status[inst].get('version_fail', False)== True or \ + self.instance_status[inst].get('verify_fail', False) == True: package_fail = True - + self.instance_status[inst]['pkg'] = entry + self.instance_status[inst]['modlist'] = modlist + + # Find Installed Instances that are not in the Config. + extra_installed = self.FindExtraInstances(entry, self.installed[entry.get('name')]) + if extra_installed != None: + package_fail = True + self.extra_instances.append(extra_installed) + for inst in extra_installed.findall('Instance'): + qtext_versions = qtext_versions + 'D(%s) ' % self.str_evra(inst) + self.logger.debug("Found Extra Instances %s" % qtext_versions) + if package_fail == True: - self.logger.info(" Package %s failed verification." % \ - (entry.get('name'))) - qtext = 'Upgrade/downgrade Package %s instance(s) - %s (y/N) ' % \ + self.logger.info(" Package %s failed verification." % (entry.get('name'))) + qtext = 'Install/Upgrade/delete Package %s instance(s) - %s (y/N) ' % \ (entry.get('name'), qtext_versions) entry.set('qtext', qtext) - entry.set('current_version', "%s:%s-%s.%s" % \ - (inst.get('epoch', None), inst.get('version'), - inst.get('release'), inst.get('arch', None))) + + bcfg2_versions = '' + for bcfg2_inst in [inst for inst in instances if inst.tag == 'Instance']: + bcfg2_versions = bcfg2_versions + '(%s) ' % self.str_evra(bcfg2_inst) + if bcfg2_versions != '': + entry.set('version', bcfg2_versions) + installed_versions = '' + + for installed_inst in self.installed[entry.get('name')]: + installed_versions = installed_versions + '(%s) ' % \ + self.str_evra(installed_inst) + + entry.set('current_version', installed_versions) return False else: # There are no Instances of this package installed. self.logger.debug("Package %s has no instances installed" % (entry.get('name'))) entry.set('current_exists', 'false') + bcfg2_versions = '' for inst in instances: - qtext_versions = qtext_versions + '%s:%s-%s.%s ' % \ - (inst.get('epoch', None), inst.get('version'), - inst.get('release'), inst.get('arch', None)) + qtext_versions = qtext_versions + 'I(%s) ' % self.str_evra(inst) self.instance_status.setdefault(inst, {})['installed'] = False - + self.instance_status[inst]['modlist'] = modlist + self.instance_status[inst]['pkg'] = entry + if inst.tag == 'Instance': + bcfg2_versions = bcfg2_versions + '(%s) ' % self.str_evra(inst) + if bcfg2_versions != '': + entry.set('version', bcfg2_versions) entry.set('qtext', "Install Package %s Instance(s) %s? (y/N) " % \ (entry.get('name'), qtext_versions)) - + return False return True def RemovePackages(self, packages): - '''Remove specified entries''' - #pkgnames = [pkg.get('name') for pkg in packages] - #if len(pkgnames) > 0: - # self.logger.info("Removing packages: %s" % pkgnames) - # if self.cmd.run("rpm --quiet -e --allmatches %s" % " ".join(pkgnames))[0] == 0: - # self.modified += packages - # else: - # for pkg in packages: - # if self.cmd.run("rpm --quiet -e --allmatches %s" % \ - # pkg.get('name'))[0] == 0: - # self.modified += pkg - # - # self.RefreshPackages() - # self.extra = self.FindExtraPackages() - print "The following package instances would have been deleted:" + ''' + Remove specified entries. + + packages is a list of Package Entries with Instances generated + by FindExtraPackages(). + ''' + self.logger.debug('Running RPMng.RemovePackages()') + + pkgspec_list = [] for pkg in packages: - print " %s:" % (pkg.get('name')) for inst in pkg: - print " %s:%s-%s.%s" % (inst.get('epoch', None), inst.get('version'), \ - inst.get('release'), inst.get('arch', None)) + if pkg.get('name') != 'gpg-pubkey': + pkgspec = { 'name':pkg.get('name'), + 'epoch':inst.get('epoch', None), + 'version':inst.get('version'), + 'release':inst.get('release'), + 'arch':inst.get('arch') } + pkgspec_list.append(pkgspec) + else: + pkgspec = { 'name':pkg.get('name'), + 'version':inst.get('version'), + 'release':inst.get('release')} + self.logger.info("WARNING: gpg-pubkey package not in configuration %s %s"\ + % (pkgspec.get('name'), self.str_evra(pkgspec))) + self.logger.info(" This package will be deleted in a future version of the RPMng driver.") + #pkgspec_list.append(pkg_spec) + + erase_results = rpmtools.rpm_erase(pkgspec_list, self.erase_flags) + if erase_results == []: + self.modified += packages + for pkg in pkgspec_list: + self.logger.info("Deleted %s %s" % (pkg.get('name'), self.str_evra(pkg))) + else: + self.logger.info("Bulk erase failed with errors:") + self.logger.debug("Erase results = %s" % erase_results) + self.logger.info("Attempting individual erase for each package.") + pkgspec_list = [] + for pkg in packages: + pkg_modified = False + for inst in pkg: + if pkg.get('name') != 'gpg-pubkey': + pkgspec = { 'name':pkg.get('name'), + 'epoch':inst.get('epoch', None), + 'version':inst.get('version'), + 'release':inst.get('release'), + 'arch':inst.get('arch') } + pkgspec_list.append(pkgspec) + else: + pkgspec = { 'name':pkg.get('name'), + 'version':inst.get('version'), + 'release':inst.get('release')} + self.logger.info("WARNING: gpg-pubkey package not in configuration %s %s"\ + % (pkgspec.get('name'), self.str_evra(pkgspec))) + self.logger.info(" This package will be deleted in a future version of the RPMng driver.") + continue # Don't delete the gpg-pubkey packages for now. + erase_results = rpmtools.rpm_erase([pkgspec], self.erase_flags) + if erase_results == []: + pkg_modified = True + self.logger.info("Deleted %s %s" % \ + (pkgspec.get('name'), self.str_evra(pkgspec))) + else: + self.logger.error("unable to delete %s %s" % \ + (pkgspec.get('name'), self.str_evra(pkgspec))) + self.logger.debug("Failure = %s" % erase_results) + if pkg_modified == True: + self.modified.append(pkg) + self.RefreshPackages() + self.extra = self.FindExtraPackages() + + def reinstall_check(self, verify_results): + ''' + Control if a reinstall of a package happens or not based on the + results from RPMng.VerifyPackage(). + + Return True to reinstall, False to not reintstall. + ''' + reinstall = False + + for inst in verify_results.get('verify'): + self.logger.debug('reinstall_check: %s %s:%s-%s.%s' % inst.get('nevra')) + + # Parse file results + for file_result in inst.get('files'): + self.logger.debug('reinstall_check: file: %s' % file_result) + if file_result[-2] != 'c': + reinstall = True + + return reinstall + def Install(self, packages): ''' + Try and fix everything that RPMng.VerifyPackages() found wrong for + each Package Entry. This can result in individual RPMs being + installed (for the first time), reinstalled, deleted, downgraded + or upgraded. + + packages is a list of Package Elements that has + self.states[] == False + + The following effects occur: + - self.states{} is conditionally updated for each package. + - self.installed{} is rebuilt, possibly multiple times. + - self.instance_statusi{} is conditionally updated for each instance + of a package. + - Each package will be added to self.modified[] if its self.states{} + entry is set to True. ''' - self.logger.info('''The following packages have something wrong with them and RPM.Install() - will try and do something to fix them if appropriate:''') + self.logger.info('Runing RPMng.Install()') + install_only_pkgs = [] + gpg_keys = [] + upgrade_pkgs = [] + + # Remove extra instances. + # Can not reverify because we don't have a package entry. + if len(self.extra_instances) > 0: + self.RemovePackages(self.extra_instances) + + # Figure out which instances of the packages actually need something + # doing to them and place in the appropriate work 'queue'. for pkg in packages: - instances = pkg.findall('Instance') - if not instances: - instances = [ pkg ] - for inst in instances: + for inst in [inst for inst in pkg if inst.tag == 'Instance' or inst.tag == 'Package']: if self.instance_status[inst].get('installed', False) == False or \ self.instance_status[inst].get('version_fail', False) == True or \ - self.instance_status[inst].get('verify_fail', False) == True: - print "%s: %s:%s-%s.%s installed = %s, Version_fail = %s, verify_fail = %s" % \ - (pkg.get('name'),inst.get('epoch', None), inst.get('version'), \ - inst.get('release'), inst.get('arch', None), \ - self.instance_status[inst].get('installed', None),\ - self.instance_status[inst].get('version_fail', None),\ - self.instance_status[inst].get('verify_fail', None)) + (self.instance_status[inst].get('verify_fail', False) == True and \ + self.reinstall_check(self.instance_status[inst])): + if pkg.get('name') == 'gpg-pubkey': + gpg_keys.append(inst) + elif pkg.get('name') in self.installOnlyPkgs: + install_only_pkgs.append(inst) + else: + upgrade_pkgs.append(inst) + + # Fix installOnlyPackages + if len(install_only_pkgs) > 0: + self.logger.info("Attempting to install 'install only packages'") + install_args = " ".join([os.path.join(self.instance_status[inst].get('pkg').get('uri'), \ + inst.get('simplefile')) \ + for inst in install_only_pkgs]) + self.logger.debug("rpm --install --quiet --oldpackage %s" % install_args) + cmdrc, output = self.cmd.run("rpm --install --quiet --oldpackage --replacepkgs %s" % \ + install_args) + if cmdrc == 0: + # The rpm command succeeded. All packages installed. + self.logger.info("Single Pass for InstallOnlyPkgs Succeded") + self.RefreshPackages() + + # Reverify all the packages that we might have just changed. + # There may be multiple instances per package, only do the + # verification once. + install_pkg_set = set([self.instance_status[inst].get('pkg') \ + for inst in install_only_pkgs]) + self.logger.info("Reverifying InstallOnlyPkgs") + for inst in install_only_pkgs: + pkg_entry = self.instance_status[inst].get('pkg') + if pkg_entry in install_pkg_set: + self.logger.debug("Reverifying InstallOnlyPkg %s" % \ + (pkg_entry.get('name'))) + install_pkg_set.remove(pkg_entry) + self.states[pkg_entry] = self.VerifyPackage(pkg_entry, \ + self.instance_status[inst].get('modlist')) + else: + # We already reverified this pacakge. + continue + else: + # The rpm command failed. No packages installed. + # Try installing instances individually. + self.logger.error("Single Pass for InstallOnlyPackages Failed") + installed_instances = [] + for inst in install_only_pkgs: + install_args = os.path.join(self.instance_status[inst].get('pkg').get('uri'), \ + inst.get('simplefile')) + self.logger.debug("rpm --install --quiet --oldpackage %s" % install_args) + cmdrc, output = self.cmd.run("rpm --install --quiet --oldpackage --replacepkgs %s" % \ + install_args) + if cmdrc == 0: + installed_instances.append(inst) + else: + self.logger.debug("InstallOnlyPackage %s %s would not install." % \ + (self.instance_status[inst].get('pkg').get('name'),\ + self.str_evra(inst))) + + install_pkg_set = set([self.instance_status[inst].get('pkg') \ + for inst in install_only_pkgs]) + self.RefreshPackages() + for inst in installed_instances: + pkg = inst.get('pkg') + # Reverify all the packages that we might have just changed. + # There may be multiple instances per package, only do the + # verification once. + if pkg in install_pkg_set: + self.logger.debug("Reverifying InstallOnlyPkg %s" % \ + (pkg_entry.get('name'))) + install_pkg_set.remove(pkg) + self.states[pkg_entry] = self.VerifyPackage(pkg, \ + self.instance_status[inst].get('modlist')) + else: + # We already reverified this pacakge. + continue + + # Install GPG keys. + if len(gpg_keys) > 0: + for inst in gpg_keys: + self.logger.info("Installing GPG keys.") + key_arg = os.path.join(self.instance_status[inst].get('pkg').get('uri'), \ + inst.get('simplefile')) + cmdrc, output = self.cmd.run("rpm --import %s" % key_arg) + if cmdrc != 0: + self.logger.debug("Unable to install %s-%s" % \ + (self.instance_status[inst].get('pkg').get('name'), \ + self.str_evra(inst))) + else: + self.logger.debug("Installed %s-%s-%s" % \ + (self.instance_status[inst].get('pkg').get('name'), \ + inst.get('version'), inst.get('release'))) + self.RefreshPackages() + self.gpg_keyids = self.getinstalledgpg() + pkg = self.instance_status[gpg_keys[0]].get('pkg') + self.states[pkg] = self.VerifyPackage(pkg, []) + + # Fix upgradeable packages. + if len(upgrade_pkgs) > 0: + self.logger.info("Attempting to upgrade packages") + upgrade_args = " ".join([os.path.join(self.instance_status[inst].get('pkg').get('uri'), \ + inst.get('simplefile')) \ + for inst in upgrade_pkgs]) + cmdrc, output = self.cmd.run("rpm --upgrade --quiet --oldpackage --replacepkgs %s" % \ + upgrade_args) + if cmdrc == 0: + # The rpm command succeeded. All packages upgraded. + self.logger.info("Single Pass for Upgraded Packages Succeded") + upgrade_pkg_set = set([self.instance_status[inst].get('pkg') \ + for inst in upgrade_pkgs]) + self.RefreshPackages() + for inst in upgrade_pkgs: + pkg_entry = self.instance_status[inst].get('pkg') + # Reverify all the packages that we might have just changed. + # There may be multiple instances per package, only do the + # verification once. + if pkg_entry in upgrade_pkg_set: + self.logger.debug("Reverifying Upgradable Package %s" % \ + (pkg_entry.get('name'))) + upgrade_pkg_set.remove(pkg_entry) + self.states[pkg_entry] = self.VerifyPackage(pkg_entry, + self.instance_status[inst].get('modlist')) + else: + # We already reverified this pacakge. + continue + else: + # The rpm command failed. No packages upgraded. + # Try upgrading instances individually. + self.logger.error("Single Pass for Upgrading Packages Failed") + upgraded_instances = [] + for inst in upgrade_pkgs: + upgrade_args = os.path.join(self.instance_status[inst].get('pkg').get('uri'), \ + inst.get('simplefile')) + #self.logger.debug("rpm --upgrade --quiet --oldpackage --replacepkgs %s" % \ + # upgrade_args) + cmdrc, output = self.cmd.run("rpm --upgrade --quiet --oldpackage --replacepkgs %s" % upgrade_args) + if cmdrc == 0: + upgraded_instances.append(inst) + else: + self.logger.debug("Package %s %s would not upgrade." % \ + (self.instance_status[inst].get('pkg').get('name'),\ + self.str_evra(inst))) + + upgrade_pkg_set = set([self.instance_status[inst].get('pkg') \ + for inst in upgrade_pkgs]) + self.RefreshPackages() + for inst in upgraded_instances: + pkg_entry = self.instance_status[inst].get('pkg') + # Reverify all the packages that we might have just changed. + # There may be multiple instances per package, only do the + # verification once. + if pkg_entry in upgrade_pkg_set: + self.logger.debug("Reverifying Upgradable Package %s" % \ + (pkg_entry.get('name'))) + upgrade_pkg_set.remove(pkg_entry) + self.states[pkg_entry] = self.VerifyPackage(pkg_entry, \ + self.instance_status[inst].get('modlist')) + else: + # We already reverified this pacakge. + continue + + for entry in [ent for ent in packages if self.states[ent]]: + self.modified.append(entry) def canInstall(self, entry): ''' @@ -348,39 +625,51 @@ class RPMng(Bcfg2.Client.Tools.PkgTool): instances = entry.findall('Instance') if not instances: - # Old non Instance format. - if [attr for attr in self.__ireq__[entry.tag] if attr not in entry.attrib]: - self.logger.error("Incomplete information for entry %s:%s; cannot verify" \ - % (entry.tag, entry.get('name'))) - return False - else: + # Old non Instance format, unmodified. if entry.get('name') == 'gpg-pubkey': # gpg-pubkey packages aren't really pacakges, so we have to do # something a little different. # Check that the Package Level has what we need for verification. if [attr for attr in self.__gpg_ireq__[entry.tag] if attr not in entry.attrib]: - self.logger.error("Incomplete information for entry %s:%s; cannot verify" \ + self.logger.error("Incomplete information for entry %s:%s; cannot install" \ + % (entry.tag, entry.get('name'))) + return False + else: + if [attr for attr in self.__ireq__[entry.tag] if attr not in entry.attrib]: + self.logger.error("Incomplete information for entry %s:%s; cannot install" \ + % (entry.tag, entry.get('name'))) + return False + else: + if entry.get('name') == 'gpg-pubkey': + # gpg-pubkey packages aren't really pacakges, so we have to do + # something a little different. + # Check that the Package Level has what we need for verification. + if [attr for attr in self.__new_gpg_ireq__[entry.tag] if attr not in entry.attrib]: + self.logger.error("Incomplete information for entry %s:%s; cannot install" \ % (entry.tag, entry.get('name'))) return False # Check that the Instance Level has what we need for verification. for inst in instances: - if [attr for attr in self.__gpg_ireq__[inst.tag] if attr not in inst.attrib]: - self.logger.error("Incomplete information for entry %s:%s; cannot verify" \ + if [attr for attr in self.__new_gpg_ireq__[inst.tag] \ + if attr not in inst.attrib]: + self.logger.error("Incomplete information for entry %s:%s; cannot install"\ % (inst.tag, inst.get('name'))) return False else: # New format with Instances. # Check that the Package Level has what we need for verification. if [attr for attr in self.__new_ireq__[entry.tag] if attr not in entry.attrib]: - self.logger.error("Incomplete information for entry %s:%s; cannot verify" \ + self.logger.error("Incomplete information for entry %s:%s; cannot install" \ % (entry.tag, entry.get('name'))) return False # Check that the Instance Level has what we need for verification. for inst in instances: - if [attr for attr in self.__new_ireq__[inst.tag] if attr not in inst.attrib]: - self.logger.error("Incomplete information for entry %s:%s; cannot verify" \ - % (inst.tag, inst.get('name'))) - return False + if inst.tag == 'Instance': + if [attr for attr in self.__new_ireq__[inst.tag] \ + if attr not in inst.attrib]: + self.logger.error("Incomplete information for entry %s:%s; cannot install" \ + % (inst.tag, inst.get('name'))) + return False return True def canVerify(self, entry): @@ -391,6 +680,9 @@ class RPMng(Bcfg2.Client.Tools.PkgTool): Old style Package New style Package with Instances pgp-pubkey packages + + Also the old style entries get modified after the first + VerifyPackage() run, so there needs to be a second test. ''' if not self.handlesEntry(entry): return False @@ -398,12 +690,7 @@ class RPMng(Bcfg2.Client.Tools.PkgTool): instances = entry.findall('Instance') if not instances: - # Old non Instance format. - if [attr for attr in self.__req__[entry.tag] if attr not in entry.attrib]: - self.logger.error("Incomplete information for entry %s:%s; cannot verify" \ - % (entry.tag, entry.get('name'))) - return False - else: + # Old non Instance format, unmodified. if entry.get('name') == 'gpg-pubkey': # gpg-pubkey packages aren't really pacakges, so we have to do # something a little different. @@ -412,14 +699,29 @@ class RPMng(Bcfg2.Client.Tools.PkgTool): self.logger.error("Incomplete information for entry %s:%s; cannot verify" \ % (entry.tag, entry.get('name'))) return False + else: + if [attr for attr in self.__req__[entry.tag] if attr not in entry.attrib]: + self.logger.error("Incomplete information for entry %s:%s; cannot verify" \ + % (entry.tag, entry.get('name'))) + return False + else: + if entry.get('name') == 'gpg-pubkey': + # gpg-pubkey packages aren't really pacakges, so we have to do + # something a little different. + # Check that the Package Level has what we need for verification. + if [attr for attr in self.__new_gpg_req__[entry.tag] if attr not in entry.attrib]: + self.logger.error("Incomplete information for entry %s:%s; cannot verify" \ + % (entry.tag, entry.get('name'))) + return False # Check that the Instance Level has what we need for verification. for inst in instances: - if [attr for attr in self.__gpg_req__[inst.tag] if attr not in inst.attrib]: + if [attr for attr in self.__new_gpg_req__[inst.tag] \ + if attr not in inst.attrib]: self.logger.error("Incomplete information for entry %s:%s; cannot verify" \ % (inst.tag, inst.get('name'))) return False else: - # New format with Instances. + # New format with Instances, or old style modified. # Check that the Package Level has what we need for verification. if [attr for attr in self.__new_req__[entry.tag] if attr not in entry.attrib]: self.logger.error("Incomplete information for entry %s:%s; cannot verify" \ @@ -427,108 +729,157 @@ class RPMng(Bcfg2.Client.Tools.PkgTool): return False # Check that the Instance Level has what we need for verification. for inst in instances: - if [attr for attr in self.__new_req__[inst.tag] if attr not in inst.attrib]: - self.logger.error("Incomplete information for entry %s:%s; cannot verify" \ - % (inst.tag, inst.get('name'))) - return False + if inst.tag == 'Instance': + if [attr for attr in self.__new_req__[inst.tag] \ + if attr not in inst.attrib]: + self.logger.error("Incomplete information for entry %s:%s; cannot verify" \ + % (inst.tag, inst.get('name'))) + return False return True def FindExtraPackages(self): ''' Find extra packages ''' - extra_packages = [] - packages = {} - for entry in self.getSupportedEntries(): - packages[entry.get('name')] = entry - - for name, pkg_list in self.installed.iteritems(): - extra_entry = Bcfg2.Client.XML.Element('Package', name=name, type=self.pkgtype) - if packages.get(name, None) != None: - # There is supposed to be at least one instance installed. - instances = packages[name].findall('Instance') - if not instances: - instances = [ packages[name] ] - if name in self.installOnlyPkgs: - for installed_inst in pkg_list: - not_found = True - for inst in instances: - if inst.get('epoch', None) != None: - epoch = int(inst.get('epoch')) - else: - epoch = None - if epoch == installed_inst.get('epoch') and \ - inst.get('version') == installed_inst.get('version') and \ - inst.get('release') == installed_inst.get('release') and \ - inst.get('arch', None) == installed_inst.get('arch'): - not_found = False - break - if not_found == True: - # Extra package. - self.logger.info("Extra InstallOnlyPackage %s %s:%s-%s.%s." % \ - (name, installed_inst.get('epoch'), \ - installed_inst.get('version'), \ - installed_inst.get('release'), \ - installed_inst.get('arch'))) - if inst.tag == 'Package': - Bcfg2.Client.XML.SubElement(extra_entry, \ - 'Instance', - version = installed_inst.get('version'), \ - release = installed_inst.get('release')) - else: - Bcfg2.Client.XML.SubElement(extra_entry, \ - 'Instance', - epoch = str(installed_inst.get('epoch')),\ - version = installed_inst.get('version'), \ - release = installed_inst.get('release'), \ - arch = installed_inst.get('arch', '')) - else: - # Normal package, only check arch. - for installed_inst in pkg_list: - not_found = True - for inst in instances: - if installed_inst.get('arch') == inst.get('arch'): - not_found = False - break - if not_found: - self.logger.info("Extra Normal Package Instance %s %s:%s-%s.%s." % \ - (name, installed_inst.get('epoch'), \ - installed_inst.get('version'), \ - installed_inst.get('release'), \ - installed_inst.get('arch'))) - if inst.tag == 'Package': - Bcfg2.Client.XML.SubElement(extra_entry, \ - 'Instance', - version = installed_inst.get('version'), \ - release = installed_inst.get('release')) - else: - Bcfg2.Client.XML.SubElement(extra_entry, \ - 'Instance', - epoch = str(installed_inst.get('epoch')),\ - version = installed_inst.get('version'), \ - release = installed_inst.get('release'), \ - arch = installed_inst.get('arch', '')) - else: - # Extra package. - self.logger.info("No instances of Package %s should be installed." % (name)) - for installed_inst in pkg_list: - if inst.tag == 'Package': - Bcfg2.Client.XML.SubElement(extra_entry, \ - 'Instance', + packages = [entry.get('name') for entry in self.getSupportedEntries()] + extras = [] + + for (name, instances) in self.installed.iteritems(): + if name not in packages: + extra_entry = Bcfg2.Client.XML.Element('Package', name=name, type=self.pkgtype) + for installed_inst in instances: + self.logger.info("Extra Package %s %s." % \ + (name, self.str_evra(installed_inst))) + Bcfg2.Client.XML.SubElement(extra_entry, \ + 'Instance', + epoch = str(installed_inst.get('epoch', '')),\ + version = installed_inst.get('version'), \ + release = installed_inst.get('release'), \ + arch = installed_inst.get('arch', '')) + extras.append(extra_entry) + return extras + + + def FindExtraInstances(self, pkg_entry, installed_entry): + ''' + Check for installed instances that are not in the config. + Return a Package Entry with Instances to remove, or None if there + are no Instances to remove. + ''' + name = pkg_entry.get('name') + extra_entry = Bcfg2.Client.XML.Element('Package', name=name, type=self.pkgtype) + instances = [inst for inst in pkg_entry if inst.tag == 'Instance' or inst.tag == 'Package'] + if name in self.installOnlyPkgs: + for installed_inst in installed_entry: + not_found = True + for inst in instances: + if self.pkg_vr_equal(inst, installed_inst) or \ + self.inst_evra_equal(inst, installed_inst): + not_found = False + break + if not_found == True: + # Extra package. + self.logger.info("Extra InstallOnlyPackage %s %s." % \ + (name, self.str_evra(installed_inst))) + tmp_entry = Bcfg2.Client.XML.SubElement(extra_entry, 'Instance', \ version = installed_inst.get('version'), \ release = installed_inst.get('release')) - else: - Bcfg2.Client.XML.SubElement(extra_entry, \ + if installed_inst.get('epoch', None) != None: + tmp_entry.set('epoch', str(installed_inst.get('epoch'))) + if installed_inst.get('arch', None) != None: + tmp_entry.set('arch', installed_inst.get('arch')) + else: + # Normal package, only check arch. + for installed_inst in installed_entry: + not_found = True + for inst in instances: + if installed_inst.get('arch', None) == inst.get('arch', None) or\ + inst.tag == 'Package': + not_found = False + break + if not_found: + self.logger.info("Extra Normal Package Instance %s %s" % \ + (name, self.str_evra(installed_inst))) + Bcfg2.Client.XML.SubElement(extra_entry, \ 'Instance', - epoch = str(installed_inst.get('epoch')),\ + epoch = str(installed_inst.get('epoch', '')),\ version = installed_inst.get('version'), \ release = installed_inst.get('release'), \ arch = installed_inst.get('arch', '')) - if len(extra_entry) > 0: - extra_packages.append(extra_entry) - else: - del extra_entry - return extra_packages + if len(extra_entry) == 0: + extra_entry = None - + return extra_entry + + def Inventory(self, structures=[]): + ''' + Wrap the Tool.Inventory() method with its own rpm.TransactionSet() + and an explicit closeDB() as the close wasn't happening and DB4 + locks were getting left behind on the RPM database creating a nice + mess. + + ***** Do performance comparison with the transctionset/closeDB + moved into rpmtools, which would mean a transactionset/closeDB + per VerifyPackage() call (meaning one per RPM package) rather + than one for the whole system. + ''' + self.vp_ts = rpmtools.rpmtransactionset() + Bcfg2.Client.Tools.Tool.Inventory(self) + # Tool is still an old style class, so super doesn't work. Change it. + #super(RPMng, self).Inventory() + self.vp_ts.closeDB() + + def str_evra(self, instance): + ''' + Convert evra dict entries to a string. + ''' + return '%s:%s-%s.%s' % (instance.get('epoch', '*'), instance.get('version', '*'), + instance.get('release', '*'), instance.get('arch', '*')) + + def pkg_vr_equal(self, config_entry, installed_entry): + ''' + Compare old style entry to installed entry. Which means ignore + the epoch and arch. + ''' + if (config_entry.tag == 'Package' and \ + config_entry.get('version') == installed_entry.get('version') and \ + config_entry.get('release') == installed_entry.get('release')): + return True + else: + return False + + def inst_evra_equal(self, config_entry, installed_entry): + ''' + Compare new style instance to installed entry. + ''' + + if config_entry.get('epoch', None) != None: + epoch = int(config_entry.get('epoch')) + else: + epoch = None + + if (config_entry.tag == 'Instance' and\ + epoch == installed_entry.get('epoch', None) and \ + config_entry.get('version') == installed_entry.get('version') and \ + config_entry.get('release') == installed_entry.get('release') and \ + config_entry.get('arch', None) == installed_entry.get('arch', None)): + return True + else: + return False + + def getinstalledgpg(self): + ''' + Create a list of installed GPG key IDs. + + The pgp-pubkey package version is the least significant 4 bytes + (big-endian) of the key ID which is good enough for our purposes. + ''' + init_ts = rpmtools.rpmtransactionset() + init_ts.setVSFlags(rpm._RPMVSF_NODIGESTS|rpm._RPMVSF_NOSIGNATURES) + gpg_hdrs = rpmtools.getheadersbykeyword(init_ts, **{'name':'gpg-pubkey'}) + keyids = [ header[rpm.RPMTAG_VERSION] for header in gpg_hdrs] + keyids.append('None') + init_ts.closeDB() + del init_ts + return keyids diff --git a/src/lib/Client/Tools/rpmtools.py b/src/lib/Client/Tools/rpmtools.py index 41a22cccc..06c15a2d1 100755 --- a/src/lib/Client/Tools/rpmtools.py +++ b/src/lib/Client/Tools/rpmtools.py @@ -18,7 +18,7 @@ Run 'rpmtools' -h for the options. """ -__revision__ = '0.3' +__revision__ = '$Revision$' import rpm, optparse, pwd, grp import sys, os, md5, stat @@ -164,13 +164,17 @@ def rpmpackagelist(rts): 'epoch':header[rpm.RPMTAG_EPOCH], 'version':header[rpm.RPMTAG_VERSION], 'release':header[rpm.RPMTAG_RELEASE], - 'arch':header[rpm.RPMTAG_ARCH] } + 'arch':header[rpm.RPMTAG_ARCH], + 'gpgkeyid':header.sprintf("%|SIGGPG?{%{SIGGPG:pgpsig}}:{None}|").split()[-1] } for header in rts.dbMatch()] def getindexbykeyword(index_ts, **kwargs): """ Return list of indexs from the rpmdb matching keywords ex: getHeadersByKeyword(name='foo', version='1', release='1') + + Can be passed any structure that can be indexed by the pkgspec + keyswords as other keys are filtered out. """ lst = [] @@ -180,18 +184,21 @@ def getindexbykeyword(index_ts, **kwargs): else: index_mi = index_ts.dbMatch() - # This is wrong! Yes its an issue, but you can't just ignore it. - # FIX THIS!!!! This is how it is in YUM. if kwargs.has_key('epoch'): - del(kwargs['epoch']) # epochs don't work here for None/0/'0' reasons + if kwargs['epoch'] != None and kwargs['epoch'] != 'None': + kwargs['epoch'] = int(kwargs['epoch']) + else: + del(kwargs['epoch']) - keywords = len(kwargs.keys()) + keywords = [ key for key in kwargs.keys() \ + if key in ('name', 'epoch', 'version', 'release', 'arch')] + keywords_len = len(keywords) for hdr in index_mi: match = 0 - for keyword in kwargs.keys(): + for keyword in keywords: if hdr[keyword] == kwargs[keyword]: match += 1 - if match == keywords: + if match == keywords_len: lst.append(index_mi.instance()) del index_mi return lst @@ -203,6 +210,9 @@ def getheadersbykeyword(header_ts, **kwargs): Return list of headers from the rpmdb matching keywords ex: getHeadersByKeyword(name='foo', version='1', release='1') + + Can be passed any structure that can be indexed by the pkgspec + keyswords as other keys are filtered out. """ lst = [] @@ -212,20 +222,21 @@ def getheadersbykeyword(header_ts, **kwargs): else: header_mi = header_ts.dbMatch() - # This is wrong! Yes its an issue, but you can't just ignore it. - # FIX THIS!!!! This is how it is in YUM. - # Fixed, I hope. MJTB 20070127. - if kwargs.has_key('epoch') and kwargs['epoch'] != None: - kwargs['epoch'] = int(kwargs['epoch']) - #del(kwargs['epoch']) # epochs don't work here for None/0/'0' reasons + if kwargs.has_key('epoch'): + if kwargs['epoch'] != None and kwargs['epoch'] != 'None': + kwargs['epoch'] = int(kwargs['epoch']) + else: + del(kwargs['epoch']) - keywords = len(kwargs.keys()) + keywords = [ key for key in kwargs.keys() \ + if key in ('name', 'epoch', 'version', 'release', 'arch')] + keywords_len = len(keywords) for hdr in header_mi: match = 0 - for keyword in kwargs.keys(): + for keyword in keywords: if hdr[keyword] == kwargs[keyword]: match += 1 - if match == keywords: + if match == keywords_len: lst.append(hdr) del header_mi return lst @@ -545,7 +556,7 @@ def rpm_verify_package(vp_ts, header, verify_options): vsflags = 0 if 'nodigest' in verify_options: vsflags |= rpm._RPMVSF_NODIGESTS - if 'nosifnature' in verify_options: + if 'nosignature' in verify_options: vsflags |= rpm._RPMVSF_NOSIGNATURES ovsflags = vp_ts.setVSFlags(vsflags) @@ -620,7 +631,7 @@ def rpm_verify_package(vp_ts, header, verify_options): else: file_stat.append(' ') - file_stat.append(fileinfo[0]) + file_stat.append(fileinfo[0]) # The filename. package_results.setdefault('files', []).append(file_stat) # Run the verify script if there is one. @@ -722,46 +733,61 @@ class Rpmtscallback(object): Generic rpmts call back. """ if reason == rpm.RPMCALLBACK_INST_OPEN_FILE: - print 'rpm.RPMCALLBACK_INST_OPEN_FILE' + pass + #print 'rpm.RPMCALLBACK_INST_OPEN_FILE' elif reason == rpm.RPMCALLBACK_INST_CLOSE_FILE: - print 'rpm.RPMCALLBACK_INST_CLOSE_FILE' + pass + #print 'rpm.RPMCALLBACK_INST_CLOSE_FILE' elif reason == rpm.RPMCALLBACK_INST_START: - print 'rpm.RPMCALLBACK_INST_START' + pass + #print 'rpm.RPMCALLBACK_INST_START' elif reason == rpm.RPMCALLBACK_TRANS_PROGRESS or \ reason == rpm.RPMCALLBACK_INST_PROGRESS: - print 'rpm.RPMCALLBACK_TRANS_PROGRESS or \ - rpm.RPMCALLBACK_INST_PROGRESS' + pass + #print 'rpm.RPMCALLBACK_TRANS_PROGRESS or \ + # rpm.RPMCALLBACK_INST_PROGRESS' elif reason == rpm.RPMCALLBACK_TRANS_START: - print 'rpm.RPMCALLBACK_TRANS_START' + pass + #print 'rpm.RPMCALLBACK_TRANS_START' elif reason == rpm.RPMCALLBACK_TRANS_STOP: - print 'rpm.RPMCALLBACK_TRANS_STOP' + pass + #print 'rpm.RPMCALLBACK_TRANS_STOP' elif reason == rpm.RPMCALLBACK_REPACKAGE_START: - print 'rpm.RPMCALLBACK_REPACKAGE_START' + pass + #print 'rpm.RPMCALLBACK_REPACKAGE_START' elif reason == rpm.RPMCALLBACK_REPACKAGE_PROGRESS: - print 'rpm.RPMCALLBACK_REPACKAGE_PROGRESS' + pass + #print 'rpm.RPMCALLBACK_REPACKAGE_PROGRESS' elif reason == rpm.RPMCALLBACK_REPACKAGE_STOP: - print 'rpm.RPMCALLBACK_REPACKAGE_STOP' + pass + #print 'rpm.RPMCALLBACK_REPACKAGE_STOP' elif reason == rpm.RPMCALLBACK_UNINST_PROGRESS: - print 'rpm.RPMCALLBACK_UNINST_PROGRESS' + pass + #print 'rpm.RPMCALLBACK_UNINST_PROGRESS' elif reason == rpm.RPMCALLBACK_UNINST_START: - print 'rpm.RPMCALLBACK_UNINST_START' + pass + #print 'rpm.RPMCALLBACK_UNINST_START' elif reason == rpm.RPMCALLBACK_UNINST_STOP: - print 'rpm.RPMCALLBACK_UNINST_STOP' - print '***Package ', key, ' deleted ***' + pass + #print 'rpm.RPMCALLBACK_UNINST_STOP' + #print '***Package ', key, ' deleted ***' # How do we get at this? # RPM.modified += key elif reason == rpm.RPMCALLBACK_UNPACK_ERROR: - print 'rpm.RPMCALLBACK_UNPACK_ERROR' + pass + #print 'rpm.RPMCALLBACK_UNPACK_ERROR' elif reason == rpm.RPMCALLBACK_CPIO_ERROR: - print 'rpm.RPMCALLBACK_CPIO_ERROR' + pass + #print 'rpm.RPMCALLBACK_CPIO_ERROR' elif reason == rpm.RPMCALLBACK_UNKNOWN: - print 'rpm.RPMCALLBACK_UNKNOWN' + pass + #print 'rpm.RPMCALLBACK_UNKNOWN' else: print 'ERROR - Fell through callBack' - print reason, amount, total, key, client_data + #print reason, amount, total, key, client_data -def rpm_erase(erase_pkgspec, erase_flags): +def rpm_erase(erase_pkgspecs, erase_flags): """ pkgspecs is a list of pkgspec dicts specifying packages e.g.: @@ -780,25 +806,32 @@ def rpm_erase(erase_pkgspec, erase_flags): erase_ts = rpmtransactionset() erase_ts.setFlags(erase_ts_flags) - idx_list = getindexbykeyword(erase_ts, **erase_pkgspec) - if len(idx_list) > 1 and not 'allmatches' in erase_flags: - print 'ERROR - Multiple package match for erase' - else: - for idx in idx_list: - erase_ts.addErase(idx) + for pkgspec in erase_pkgspecs: + idx_list = getindexbykeyword(erase_ts, **pkgspec) + if len(idx_list) > 1 and not 'allmatches' in erase_flags: + #pass + print 'ERROR - Multiple package match for erase', pkgspec + else: + for idx in idx_list: + erase_ts.addErase(idx) + #for te in erase_ts: + # print "%s %s:%s-%s.%s" % (te.N(), te.E(), te.V(), te.R(), te.A()) + + erase_problems = [] if 'nodeps' not in erase_flags: erase_problems = erase_ts.check() - if erase_problems: - print 'ERROR - Dependency failures on package erase' - print erase_problems - else: + if erase_problems == []: erase_ts.order() erase_callback = Rpmtscallback() erase_ts.run(erase_callback.callback, 'Erase') + #else: + # print 'ERROR - Dependency failures on package erase' + # print erase_problems erase_ts.closeDB() + del erase_ts return erase_problems def display_verify_file(file_results): @@ -1056,6 +1089,6 @@ if __name__ == "__main__": elif options.erase: if options.name: - rpm_erase(cmdline_pkgspec, rpm_options) + rpm_erase([cmdline_pkgspec], rpm_options) else: print 'You must specify the "--name" option' -- cgit v1.2.3-1-g7c22