Changeset 3029

Show
Ignore:
Timestamp:
04/10/07 19:14:59 (3 years ago)
Author:
desai
Message:

Latest version of RPMng from mbrady

Location:
trunk/bcfg2/src/lib/Client/Tools
Files:
2 modified

Legend:

Unmodified
Added
Removed
  • trunk/bcfg2/src/lib/Client/Tools/RPMng.py

    r3013 r3029  
    33__revision__ = '$Revision$' 
    44 
    5 import Bcfg2.Client.Tools, time, rpmtools, sys 
     5import Bcfg2.Client.Tools, rpmtools, os.path, rpm, ConfigParser 
     6 
    67 
    78class RPMng(Bcfg2.Client.Tools.PkgTool): 
     
    1819                    'Instance': ['simplefile', 'version', 'release', 'arch']} 
    1920     
    20     __gpg_req__ = {'Package': ['name'], 'Instance': ['version', 'release']} 
    21     __gpg_ireq__ = {'Package': ['name'], 'Instance': ['version', 'release']} 
     21    __gpg_req__ = {'Package': ['name', 'version']} 
     22    __gpg_ireq__ = {'Package': ['name', 'version']} 
     23     
     24    __new_gpg_req__ = {'Package': ['name'], 'Instance': ['version', 'release']} 
     25    __new_gpg_ireq__ = {'Package': ['name'], 'Instance': ['version', 'release']} 
    2226 
    2327    conflicts = ['RPM'] 
     
    2630    pkgtool = ("rpm --oldpackage --replacepkgs --quiet -U %s", ("%s", ["url"])) 
    2731 
    28     # This is mostly the default list from YUM on Centos 4.  Check these are  
    29     # still correct. 
    30     # ***** Should probably put in bcfg2.config somewhere. ***** 
    31     installOnlyPkgs = ['kernel', 'kernel-bigmem', 'kernel-enterprise', 'kernel-smp', 
    32                        'kernel-modules', 'kernel-debug', 'kernel-unsupported', 
    33                        'kernel-source', 'kernel-devel', 'kernel-default', 
    34                        'kernel-largesmp-devel', 'kernel-largesmp', 'gpg-pubkey'] 
    3532     
    3633    def __init__(self, logger, setup, config, states): 
    3734        Bcfg2.Client.Tools.PkgTool.__init__(self, logger, setup, config, states) 
    3835 
     36        self.installOnlyPkgs = [] 
     37        self.erase_flags = [] 
    3938        self.instance_status = {} 
     39        self.extra_instances = [] 
     40        self.gpg_keyids = self.getinstalledgpg() 
     41 
     42        # Process thee RPMng section from the config file. 
     43        RPMng_CP = ConfigParser.ConfigParser() 
     44        RPMng_CP.read(self.setup.get('setup')) 
     45 
     46        # installonlypackages 
     47        if RPMng_CP.has_option('RPMng','installonlypackages'): 
     48            self.installOnlyPkgs = RPMng_CP.get('RPMng','installonlypackages').split(',') + \ 
     49                                                                                   ['gpg-pubkey'] 
     50        if self.installOnlyPkgs == []: 
     51            self.installOnlyPkgs = ['kernel', 'kernel-bigmem', 'kernel-enterprise', 'kernel-smp', 
     52                               'kernel-modules', 'kernel-debug', 'kernel-unsupported', 
     53                               'kernel-source', 'kernel-devel', 'kernel-default', 
     54                               'kernel-largesmp-devel', 'kernel-largesmp', 'kernel-xen',  
     55                               'gpg-pubkey'] 
     56        self.logger.debug('installOnlyPackages = %s' % self.installOnlyPkgs) 
     57 
     58        # erase_flags 
     59        if RPMng_CP.has_option('RPMng','erase_flags'): 
     60            self.installOnlyPkgs = RPMng_CP.get('RPMng','erase_flags').split(',') 
     61        if self.erase_flags == []: 
     62            self.erase_flags = ['allmatches'] 
     63        self.logger.debug('erase_flags = %s' % self.erase_flags) 
    4064 
    4165    def RefreshPackages(self): 
     
    5781        self.installed = {} 
    5882        refresh_ts = rpmtools.rpmtransactionset() 
     83        # Don't bother with signature checks at this stage. The GPG keys might  
     84        # not be installed. 
     85        refresh_ts.setVSFlags(rpm._RPMVSF_NODIGESTS|rpm._RPMVSF_NOSIGNATURES) 
    5986        for nevra in rpmtools.rpmpackagelist(refresh_ts): 
    6087            self.installed.setdefault(nevra['name'], []).append(nevra) 
     
    6491                self.logger.info("    " + name) 
    6592                for inst in instances: 
    66                     self.logger.info("        %s:%s-%s.%s" % \ 
    67                                          (inst.get('epoch', None), inst.get('version', None),  
    68                                           inst.get('release', None), inst.get('arch', None))) 
     93                    self.logger.info("        %s" %self.str_evra(inst))  
    6994        refresh_ts.closeDB() 
     95        del refresh_ts 
    7096 
    7197    def VerifyPackage(self, entry, modlist): 
    7298        ''' 
    7399            Verify Package status for entry. 
    74             Compares the 'version' info against self.installed{} and does  
    75             an rpm level package verify. 
    76  
    77             Code for the old/new style Package Entries has been kept separate, 
    78             even though it has meant some code duplication, so that the old style  
    79             code can be easily removed at a later date. 
    80         ''' 
    81  
    82         instances = entry.findall('Instance') 
    83         if not instances: 
    84             # We have an old style no Instance entry. 
    85             if entry.get('release', None) == None: 
    86                 version, release = entry.get('version').split('-') 
    87                 entry.set('version', version) 
    88                 entry.set('release', release) 
    89             instances = [ entry ] 
    90  
    91         vp_ts = rpmtools.rpmtransactionset() 
     100            Performs the following: 
     101                - Checks for the presence of required Package Instances. 
     102                - Compares the evra 'version' info against self.installed{}. 
     103                - RPM level package verify (rpm --verify). 
     104                - Checks for the presence of unrequired package instances. 
     105 
     106            Produces the following dict and list for RPMng.Install() to use: 
     107              For installs/upgrades/fixes of required instances: 
     108                instance_status = { <Instance Element Object>: 
     109                                       { 'installed': True|False, 
     110                                         'version_fail': True|False, 
     111                                         'verify_fail': True|False, 
     112                                         'pkg': <Package Element Object>, 
     113                                         'modlist': [ <filename>, ... ], 
     114                                         'verify' : [ <rpm --verify results> ]   
     115                                       }, ...... 
     116                                  } 
     117 
     118              For deletions of unrequired instances: 
     119                extra_instances = [ <Package Element Object>, ..... ] 
     120 
     121              Constructs the text prompts for interactive mode. 
     122        ''' 
     123        if len(entry) == 0: 
     124            # We have an old style no Instance entry. Convert it to new style. 
     125            version, release = entry.get('version').split('-') 
     126            instance = Bcfg2.Client.XML.SubElement(entry, 'Package') 
     127            for attrib in entry.attrib.keys(): 
     128                instance.attrib[attrib] = entry.attrib[attrib] 
     129            instance.set('version', version) 
     130            instance.set('release', release) 
     131            instances = [ instance ] 
     132        else: 
     133            # We have a new style entry or a previously converted old style entry. 
     134            instances = [inst for inst in entry if inst.tag == 'Instance' or inst.tag == 'Package'] 
    92135 
    93136        self.logger.info("Verifying package instances for %s" % entry.get('name')) 
     
    105148                    self.instance_status[inst]['version_fail'] = False 
    106149                    if inst.tag == 'Package' and len(self.installed[entry.get('name')]) > 1: 
    107                         self.logger.error("WARNING: Multiple instances of package %s are installed." % (entry.get('name'))) 
     150                        self.logger.error("WARNING: Multiple instances of package %s are installed." % \ 
     151                                                                               (entry.get('name'))) 
    108152                    for pkg in self.installed[entry.get('name')]: 
    109                         if inst.tag == 'Package': 
    110                             # We have an old style Package entry that does not 
    111                             # have an epoch or an arch, so scrub them from  
    112                             # installed{}. 
    113                             pkg.pop('arch', None) 
    114                             pkg.pop('epoch', None) 
    115                         if inst.get('epoch', None) != None: 
    116                             epoch = int(inst.get('epoch')) 
    117                         else: 
    118                             epoch = None 
    119                         if epoch == pkg.get('epoch') and \ 
    120                            inst.get('version') == pkg.get('version') and \ 
    121                            inst.get('release') == pkg.get('release') and \ 
    122                            inst.get('arch', None) == pkg.get('arch', None): 
    123                             self.logger.info("        %s:%s-%s.%s" % \ 
    124                                      (inst.get('epoch', None), inst.get('version'),  
    125                                       inst.get('release'), inst.get('arch', None))) 
     153                        if self.pkg_vr_equal(inst, pkg) or self.inst_evra_equal(inst, pkg): 
     154                            self.logger.info("        %s" % self.str_evra(inst)) 
    126155                            self.logger.debug("        verify_flags = %s" % \ 
    127156                                                           (inst.get('verify_flags', []))) 
    128157                            self.instance_status[inst]['installed'] = True 
     158      
     159                            flags = inst.get('verify_flags', '').split(',') 
     160                            if pkg.get('gpgkeyid', '')[-8:] not in self.gpg_keyids and \ 
     161                               entry.get('name') != 'gpg-pubkey': 
     162                                flags += ['nosignature', 'nodigest'] 
     163                                self.logger.info('WARNING: Package %s %s requires GPG Public key with ID %s'\ 
     164                                                   % (pkg.get('name'), self.str_evra(pkg), \ 
     165                                                      pkg.get('gpgkeyid', ''))) 
     166                                self.logger.info('         Disabling signature check.') 
     167 
    129168                            self.instance_status[inst]['verify'] = \ 
    130                                   rpmtools.rpm_verify( vp_ts, pkg, \ 
    131                                                        inst.get('verify_flags', '').split(',')) 
     169                                                      rpmtools.rpm_verify( self.vp_ts, pkg, flags) 
    132170 
    133171                    if self.instance_status[inst]['installed'] == False: 
    134                         package_fail = True 
    135                         self.logger.info("        Package %s %s:%s-%s.%s not installed." % \ 
    136                                      (entry.get('name'), 
    137                                       inst.get('epoch', None), inst.get('version'),  
    138                                       inst.get('release'), inst.get('arch', None))) 
     172                        self.logger.info("        Package %s %s not installed." % \ 
     173                                     (entry.get('name'), self.str_evra(inst))) 
    139174                             
    140                         qtext_versions = qtext_versions + '%s:%s-%s.%s ' % \ 
    141                                             (inst.get('epoch', ''), inst.get('version', ''),\ 
    142                                              inst.get('release', ''), inst.get('arch', '')) 
    143                    
     175                        qtext_versions = qtext_versions + 'I(%s) ' % self.str_evra(inst) 
    144176                        entry.set('current_exists', 'false') 
    145177            else: 
     
    164196                        # Check that it is the right version. 
    165197                        for pkg in arch_match: 
    166                             if inst.tag == 'Package': 
    167                                 # We have an old style Package entry that does not 
    168                                 # have an epoch or an arch, so scrub them from  
    169                                 # installed{}. 
    170                                 pkg.pop('arch', None) 
    171                                 pkg.pop('epoch', None) 
    172                             if inst.get('epoch', None) != None: 
    173                                 epoch = int(inst.get('epoch')) 
    174                             else: 
    175                                 epoch = None 
    176                             if epoch == pkg.get('epoch', None) and \ 
    177                                inst.get('version') == pkg.get('version') and \ 
    178                                inst.get('release') == pkg.get('release'): 
    179                                 self.logger.info("        %s:%s-%s.%s" % \ 
    180                                             (inst.get('epoch', None), inst.get('version', ''), \ 
    181                                              inst.get('release', ''), inst.get('arch', None))) 
     198                            if self.pkg_vr_equal(inst, pkg) or self.inst_evra_equal(inst, pkg): 
     199                                self.logger.info("        %s" % self.str_evra(inst)) 
    182200                                self.logger.debug("        verify_flags = %s" % \ 
    183201                                                              (inst.get('verify_flags', []))) 
    184202                                self.instance_status[inst]['installed'] = True 
     203 
     204                                flags = inst.get('verify_flags', '').split(',')  
     205                                if pkg.get('gpgkeyid', '')[-8:] not in self.gpg_keyids: 
     206                                    flags += ['nosignature', 'nodigest'] 
     207                                    self.logger.info('WARNING: Package %s %s requires GPG Public key with ID %s'\ 
     208                                                       % (pkg.get('name'), self.str_evra(pkg), \ 
     209                                                          pkg.get('gpgkeyid', ''))) 
     210                                    self.logger.info('         Disabling signature check.') 
     211 
    185212                                self.instance_status[inst]['verify'] = \ 
    186                                    rpmtools.rpm_verify( vp_ts, pkg,\ 
    187                                                         inst.get('verify_flags', '').split(',')) 
     213                                                      rpmtools.rpm_verify( self.vp_ts, pkg, flags ) 
     214 
    188215                            else: 
    189                                 package_fail = True 
     216                                # Wrong version installed. 
    190217                                self.instance_status[inst]['version_fail'] = True 
    191                                 self.logger.info("        Wrong version installed.  Want %s:%s-%s.%s, but have %s:%s-%s.%s" % \ 
    192                                             (inst.get('epoch', None), inst.get('version'), \ 
    193                                              inst.get('release'), inst.get('arch', None), \ 
    194                                              pkg.get('epoch'), pkg.get('version'), \ 
    195                                              pkg.get('release'), pkg.get('arch'))) 
     218                                self.logger.info("        Wrong version installed.  Want %s, but have %s"\ 
     219                                                       % (self.str_evra(inst), self.str_evra(pkg))) 
    196220                         
    197                                 qtext_versions = qtext_versions + \ 
    198                                             '(%s:%s-%s.%s -> %s:%s-%s.%s) ' % \ 
    199                                             (pkg.get('epoch', ''), pkg.get('version'), \ 
    200                                              pkg.get('release'), pkg.get('arch', ''), \ 
    201                                              inst.get('epoch', ''), inst.get('version'), \ 
    202                                              inst.get('release'), inst.get('arch', '')) 
     221                                qtext_versions = qtext_versions + 'U(%s -> %s) ' % \ 
     222                                                          (self.str_evra(pkg), self.str_evra(inst)) 
    203223                    elif len(arch_match) == 0: 
    204224                        # This instance is not installed. 
    205225                        self.instance_status[inst]['installed'] = False 
    206                          
    207                         self.logger.info("        %s:%s-%s.%s is not installed." % \ 
    208                                             (inst.get('epoch', None), inst.get('version'), \ 
    209                                              inst.get('release'), inst.get('arch', None))) 
    210                          
    211                         qtext_versions = qtext_versions + '%s:%s-%s.%s ' % \ 
    212                                             (inst.get('epoch', ''), inst.get('version'), \ 
    213                                              inst.get('release'), inst.get('arch', '')) 
    214                    
    215                         entry.set('current_exists', 'false') 
    216  
     226                        self.logger.info("        %s is not installed." % self.str_evra(inst)) 
     227                        qtext_versions = qtext_versions + 'I(%s) ' % self.str_evra(inst) 
     228 
     229            # Check the rpm verify results. 
    217230            for inst in instances: 
    218231                instance_fail = False 
     
    222235                    self.logger.debug(self.instance_status[inst]['verify']) 
    223236 
    224                 # Check the rpm verify results. 
     237                self.instance_status[inst]['verify_fail'] = False 
    225238                if self.instance_status[inst].get('verify', None): 
    226239                    if len(self.instance_status[inst].get('verify')) > 1: 
    227240                        self.logger.info("WARNING: Verification of more than one package instance.") 
    228241                  
    229                     self.instance_status[inst]['verify_fail'] = False 
    230242 
    231243                    for result in self.instance_status[inst]['verify']: 
    232244 
    233245                        # Check header results 
    234                         if result.get('hdr', []): 
    235                             package_fail = True 
     246                        if result.get('hdr', None): 
    236247                            instance_fail = True 
    237248                            self.instance_status[inst]['verify_fail'] = True 
    238249     
    239250                        # Check dependency results 
    240                         if result.get('deps', []): 
    241                             package_fail = True 
     251                        if result.get('deps', None): 
    242252                            instance_fail = True 
    243253                            self.instance_status[inst]['verify_fail'] = True 
     
    249259                               file_result[-1] not in \ 
    250260                                          [ignore.get('name') for ignore in inst.findall('Ignore')]: 
    251                                 package_fail = True 
    252261                                instance_fail = True 
    253262                                self.instance_status[inst]['verify_fail'] = True 
     
    257266 
    258267                    if instance_fail == True: 
    259                         self.logger.info("*** Instance %s:%s-%s.%s failed RPM verification ***" % \ 
    260                                            (inst.get('epoch', None), inst.get('version'), \ 
    261                                             inst.get('release'), inst.get('arch', None))) 
    262                          
    263                         qtext_versions = qtext_versions + '%s:%s-%s.%s ' % \ 
    264                                             (inst.get('epoch', ''), inst.get('version'), \ 
    265                                              inst.get('release'), inst.get('arch', '')) 
     268                        self.logger.info("*** Instance %s failed RPM verification ***" % \ 
     269                                                                               self.str_evra(inst)) 
     270                        qtext_versions = qtext_versions + 'R(%s) ' % self.str_evra(inst) 
     271                        self.instance_status[inst]['modlist'] = modlist 
    266272 
    267273                if self.instance_status[inst]['installed'] == False or \ 
    268                    self.instance_status[inst]['version_fail'] == True: 
     274                   self.instance_status[inst].get('version_fail', False)== True or \ 
     275                   self.instance_status[inst].get('verify_fail', False) == True: 
    269276                    package_fail = True 
    270  
     277                    self.instance_status[inst]['pkg'] = entry 
     278                    self.instance_status[inst]['modlist'] = modlist 
     279 
     280            # Find Installed Instances that are not in the Config. 
     281            extra_installed = self.FindExtraInstances(entry, self.installed[entry.get('name')]) 
     282            if extra_installed != None: 
     283                package_fail = True 
     284                self.extra_instances.append(extra_installed) 
     285                for inst in extra_installed.findall('Instance'): 
     286                    qtext_versions = qtext_versions + 'D(%s) ' % self.str_evra(inst) 
     287                self.logger.debug("Found Extra Instances %s" % qtext_versions) 
     288            
    271289            if package_fail == True: 
    272                 self.logger.info("        Package %s failed verification." % \ 
    273                                                                         (entry.get('name'))) 
    274                 qtext = 'Upgrade/downgrade Package %s instance(s) - %s (y/N) ' % \ 
     290                self.logger.info("        Package %s failed verification." % (entry.get('name'))) 
     291                qtext = 'Install/Upgrade/delete Package %s instance(s) - %s (y/N) ' % \ 
    275292                                              (entry.get('name'), qtext_versions) 
    276293                entry.set('qtext', qtext) 
    277                 entry.set('current_version', "%s:%s-%s.%s" % \ 
    278                                 (inst.get('epoch', None), inst.get('version'),  
    279                                  inst.get('release'), inst.get('arch', None))) 
     294 
     295                bcfg2_versions = '' 
     296                for bcfg2_inst in [inst for inst in instances if inst.tag == 'Instance']: 
     297                    bcfg2_versions = bcfg2_versions + '(%s) ' % self.str_evra(bcfg2_inst) 
     298                if bcfg2_versions != '': 
     299                    entry.set('version', bcfg2_versions) 
     300                installed_versions = '' 
     301 
     302                for installed_inst in self.installed[entry.get('name')]: 
     303                    installed_versions = installed_versions + '(%s) ' % \ 
     304                                                                    self.str_evra(installed_inst) 
     305 
     306                entry.set('current_version', installed_versions) 
    280307                return False 
    281308 
     
    284311            self.logger.debug("Package %s has no instances installed" % (entry.get('name'))) 
    285312            entry.set('current_exists', 'false') 
     313            bcfg2_versions = '' 
    286314            for inst in instances: 
    287                 qtext_versions = qtext_versions + '%s:%s-%s.%s ' % \ 
    288                                 (inst.get('epoch', None), inst.get('version'), 
    289                                  inst.get('release'), inst.get('arch', None)) 
     315                qtext_versions = qtext_versions + 'I(%s) ' % self.str_evra(inst) 
    290316                self.instance_status.setdefault(inst, {})['installed'] = False 
    291  
     317                self.instance_status[inst]['modlist'] = modlist 
     318                self.instance_status[inst]['pkg'] = entry 
     319                if inst.tag == 'Instance': 
     320                    bcfg2_versions = bcfg2_versions + '(%s) ' % self.str_evra(inst) 
     321            if bcfg2_versions != '': 
     322                entry.set('version', bcfg2_versions) 
    292323            entry.set('qtext', "Install Package %s Instance(s) %s? (y/N) " % \ 
    293324                                                        (entry.get('name'), qtext_versions)) 
    294                            
     325 
    295326            return False 
    296327        return True 
    297328 
    298329    def RemovePackages(self, packages): 
    299         '''Remove specified entries''' 
    300         #pkgnames = [pkg.get('name') for pkg in packages] 
    301         #if len(pkgnames) > 0: 
    302         #    self.logger.info("Removing packages: %s" % pkgnames) 
    303         #    if self.cmd.run("rpm --quiet -e --allmatches %s" % " ".join(pkgnames))[0] == 0: 
    304         #        self.modified += packages 
    305         #    else: 
    306         #        for pkg in packages: 
    307         #            if self.cmd.run("rpm --quiet -e --allmatches %s" % \ 
    308         #                            pkg.get('name'))[0] == 0: 
    309         #                self.modified += pkg 
    310         # 
    311         # self.RefreshPackages() 
    312         #    self.extra = self.FindExtraPackages() 
    313         print "The following package instances would have been deleted:" 
     330        ''' 
     331           Remove specified entries. 
     332 
     333           packages is a list of Package Entries with Instances generated  
     334           by FindExtraPackages(). 
     335        ''' 
     336        self.logger.debug('Running RPMng.RemovePackages()') 
     337 
     338        pkgspec_list = [] 
    314339        for pkg in packages: 
    315             print "    %s:" % (pkg.get('name')) 
    316340            for inst in pkg: 
    317                 print "        %s:%s-%s.%s" % (inst.get('epoch', None), inst.get('version'), \ 
    318                                                inst.get('release'), inst.get('arch', None)) 
    319  
     341                if pkg.get('name') != 'gpg-pubkey': 
     342                    pkgspec = { 'name':pkg.get('name'), 
     343                            'epoch':inst.get('epoch', None), 
     344                            'version':inst.get('version'), 
     345                            'release':inst.get('release'), 
     346                            'arch':inst.get('arch') } 
     347                    pkgspec_list.append(pkgspec) 
     348                else: 
     349                    pkgspec = { 'name':pkg.get('name'), 
     350                            'version':inst.get('version'), 
     351                            'release':inst.get('release')} 
     352                    self.logger.info("WARNING: gpg-pubkey package not in configuration %s %s"\ 
     353                                                 % (pkgspec.get('name'), self.str_evra(pkgspec))) 
     354                    self.logger.info("         This package will be deleted in a future version of the RPMng driver.") 
     355                #pkgspec_list.append(pkg_spec) 
     356 
     357        erase_results = rpmtools.rpm_erase(pkgspec_list, self.erase_flags)  
     358        if erase_results == []: 
     359            self.modified += packages 
     360            for pkg in pkgspec_list: 
     361                self.logger.info("Deleted %s %s" % (pkg.get('name'), self.str_evra(pkg))) 
     362        else: 
     363            self.logger.info("Bulk erase failed with errors:") 
     364            self.logger.debug("Erase results = %s" % erase_results) 
     365            self.logger.info("Attempting individual erase for each package.") 
     366            pkgspec_list = [] 
     367            for pkg in packages: 
     368                pkg_modified = False 
     369                for inst in pkg: 
     370                    if pkg.get('name') != 'gpg-pubkey': 
     371                        pkgspec = { 'name':pkg.get('name'), 
     372                                'epoch':inst.get('epoch', None), 
     373                                'version':inst.get('version'), 
     374                                'release':inst.get('release'), 
     375                                'arch':inst.get('arch') } 
     376                        pkgspec_list.append(pkgspec) 
     377                    else: 
     378                        pkgspec = { 'name':pkg.get('name'), 
     379                                'version':inst.get('version'), 
     380                                'release':inst.get('release')} 
     381                        self.logger.info("WARNING: gpg-pubkey package not in configuration %s %s"\ 
     382                                                   % (pkgspec.get('name'), self.str_evra(pkgspec))) 
     383                        self.logger.info("         This package will be deleted in a future version of the RPMng driver.") 
     384                        continue # Don't delete the gpg-pubkey packages for now. 
     385                    erase_results = rpmtools.rpm_erase([pkgspec], self.erase_flags)  
     386                    if erase_results == []: 
     387                        pkg_modified = True 
     388                        self.logger.info("Deleted %s %s" % \ 
     389                                                   (pkgspec.get('name'), self.str_evra(pkgspec))) 
     390                    else: 
     391                        self.logger.error("unable to delete %s %s" % \ 
     392                                                   (pkgspec.get('name'), self.str_evra(pkgspec))) 
     393                        self.logger.debug("Failure = %s" % erase_results) 
     394                if pkg_modified == True: 
     395                    self.modified.append(pkg) 
     396 
     397        self.RefreshPackages() 
     398        self.extra = self.FindExtraPackages() 
     399 
     400    def reinstall_check(self, verify_results): 
     401        ''' 
     402           Control if a reinstall of a package happens or not based on the  
     403           results from RPMng.VerifyPackage(). 
     404 
     405           Return True to reinstall, False to not reintstall. 
     406        ''' 
     407        reinstall = False 
     408 
     409        for inst in verify_results.get('verify'): 
     410            self.logger.debug('reinstall_check: %s %s:%s-%s.%s' % inst.get('nevra')) 
     411 
     412            # Parse file results 
     413            for file_result in inst.get('files'): 
     414                self.logger.debug('reinstall_check: file: %s' % file_result) 
     415                if file_result[-2] != 'c': 
     416                    reinstall = True 
     417 
     418        return reinstall 
     419     
    320420    def Install(self, packages): 
    321421        ''' 
    322         ''' 
    323         self.logger.info('''The following packages have something wrong with them and RPM.Install() 
    324                  will try and do something to fix them if appropriate:''') 
    325  
     422           Try and fix everything that RPMng.VerifyPackages() found wrong for  
     423           each Package Entry.  This can result in individual RPMs being  
     424           installed (for the first time), reinstalled, deleted, downgraded  
     425           or upgraded. 
     426 
     427           packages is a list of Package Elements that has  
     428               self.states[<Package Element>] == False 
     429 
     430           The following effects occur: 
     431           - self.states{} is conditionally updated for each package. 
     432           - self.installed{} is rebuilt, possibly multiple times. 
     433           - self.instance_statusi{} is conditionally updated for each instance  
     434             of a package. 
     435           - Each package will be added to self.modified[] if its self.states{}  
     436             entry is set to True.  
     437        ''' 
     438        self.logger.info('Runing RPMng.Install()') 
     439 
     440        install_only_pkgs = [] 
     441        gpg_keys = [] 
     442        upgrade_pkgs = [] 
     443 
     444        # Remove extra instances. 
     445        # Can not reverify because we don't have a package entry. 
     446        if len(self.extra_instances) > 0: 
     447            self.RemovePackages(self.extra_instances) 
     448 
     449        # Figure out which instances of the packages actually need something 
     450        # doing to them and place in the appropriate work 'queue'. 
    326451        for pkg in packages: 
    327             instances = pkg.findall('Instance') 
    328             if not instances: 
    329                 instances = [ pkg ] 
    330             for inst in instances: 
     452            for inst in [inst for inst in pkg if inst.tag == 'Instance' or inst.tag == 'Package']: 
    331453                if self.instance_status[inst].get('installed', False) == False or \ 
    332454                   self.instance_status[inst].get('version_fail', False) == True or \ 
    333                    self.instance_status[inst].get('verify_fail', False) == True: 
    334                     print "%s: %s:%s-%s.%s installed = %s, Version_fail = %s, verify_fail = %s" % \ 
    335                         (pkg.get('name'),inst.get('epoch', None), inst.get('version'), \ 
    336                          inst.get('release'), inst.get('arch', None), \ 
    337                          self.instance_status[inst].get('installed', None),\ 
    338                          self.instance_status[inst].get('version_fail', None),\ 
    339                          self.instance_status[inst].get('verify_fail', None)) 
     455                   (self.instance_status[inst].get('verify_fail', False) == True and \ 
     456                    self.reinstall_check(self.instance_status[inst])): 
     457                    if pkg.get('name') == 'gpg-pubkey': 
     458                        gpg_keys.append(inst) 
     459                    elif pkg.get('name') in self.installOnlyPkgs: 
     460                        install_only_pkgs.append(inst) 
     461                    else: 
     462                        upgrade_pkgs.append(inst) 
     463 
     464        # Fix installOnlyPackages 
     465        if len(install_only_pkgs) > 0: 
     466            self.logger.info("Attempting to install 'install only packages'") 
     467            install_args = " ".join([os.path.join(self.instance_status[inst].get('pkg').get('uri'), \ 
     468                                                  inst.get('simplefile')) \ 
     469                                           for inst in install_only_pkgs]) 
     470            self.logger.debug("rpm --install --quiet --oldpackage %s" % install_args) 
     471            cmdrc, output = self.cmd.run("rpm --install --quiet --oldpackage --replacepkgs %s" % \ 
     472                                                                                     install_args) 
     473            if cmdrc == 0: 
     474                # The rpm command succeeded.  All packages installed. 
     475                self.logger.info("Single Pass for InstallOnlyPkgs Succeded") 
     476                self.RefreshPackages() 
     477 
     478                # Reverify all the packages that we might have just changed. 
     479                # There may be multiple instances per package, only do the  
     480                # verification once. 
     481                install_pkg_set = set([self.instance_status[inst].get('pkg') \ 
     482                                                      for inst in install_only_pkgs]) 
     483                self.logger.info("Reverifying InstallOnlyPkgs") 
     484                for inst in install_only_pkgs: 
     485                    pkg_entry = self.instance_status[inst].get('pkg') 
     486                    if pkg_entry in install_pkg_set: 
     487                        self.logger.debug("Reverifying InstallOnlyPkg %s" % \ 
     488                                                                      (pkg_entry.get('name'))) 
     489                        install_pkg_set.remove(pkg_entry) 
     490                        self.states[pkg_entry] = self.VerifyPackage(pkg_entry, \ 
     491                                                         self.instance_status[inst].get('modlist')) 
     492                    else: 
     493                        # We already reverified this pacakge. 
     494                        continue 
     495            else: 
     496                # The rpm command failed.  No packages installed. 
     497                # Try installing instances individually. 
     498                self.logger.error("Single Pass for InstallOnlyPackages Failed") 
     499                installed_instances = [] 
     500                for inst in install_only_pkgs: 
     501                    install_args = os.path.join(self.instance_status[inst].get('pkg').get('uri'), \ 
     502                                                     inst.get('simplefile')) 
     503                    self.logger.debug("rpm --install --quiet --oldpackage %s" % install_args) 
     504                    cmdrc, output = self.cmd.run("rpm --install --quiet --oldpackage --replacepkgs %s" % \ 
     505                                                                                      install_args) 
     506                    if cmdrc == 0: 
     507                        installed_instances.append(inst) 
     508                    else: 
     509                        self.logger.debug("InstallOnlyPackage %s %s would not install." % \ 
     510                                              (self.instance_status[inst].get('pkg').get('name'),\ 
     511                                               self.str_evra(inst))) 
     512 
     513                install_pkg_set = set([self.instance_status[inst].get('pkg') \ 
     514                                                      for inst in install_only_pkgs]) 
     515                self.RefreshPackages() 
     516                for inst in installed_instances: 
     517                    pkg = inst.get('pkg') 
     518                    # Reverify all the packages that we might have just changed. 
     519                    # There may be multiple instances per package, only do the 
     520                    # verification once. 
     521                    if pkg in install_pkg_set: 
     522                        self.logger.debug("Reverifying InstallOnlyPkg %s" % \ 
     523                                                                      (pkg_entry.get('name'))) 
     524                        install_pkg_set.remove(pkg) 
     525                        self.states[pkg_entry] = self.VerifyPackage(pkg, \ 
     526                                                         self.instance_status[inst].get('modlist')) 
     527                    else: 
     528                        # We already reverified this pacakge. 
     529                        continue 
     530 
     531        # Install GPG keys. 
     532        if len(gpg_keys) > 0: 
     533            for inst in gpg_keys: 
     534                self.logger.info("Installing GPG keys.") 
     535                key_arg = os.path.join(self.instance_status[inst].get('pkg').get('uri'), \ 
     536                                                     inst.get('simplefile')) 
     537                cmdrc, output = self.cmd.run("rpm --import %s" % key_arg) 
     538                if cmdrc != 0: 
     539                    self.logger.debug("Unable to install %s-%s" % \ 
     540                                              (self.instance_status[inst].get('pkg').get('name'), \ 
     541                                               self.str_evra(inst))) 
     542                else: 
     543                    self.logger.debug("Installed %s-%s-%s" % \ 
     544                                              (self.instance_status[inst].get('pkg').get('name'), \ 
     545                                               inst.get('version'), inst.get('release'))) 
     546            self.RefreshPackages() 
     547            self.gpg_keyids = self.getinstalledgpg() 
     548            pkg = self.instance_status[gpg_keys[0]].get('pkg') 
     549            self.states[pkg] = self.VerifyPackage(pkg, []) 
     550 
     551        # Fix upgradeable packages. 
     552        if len(upgrade_pkgs) > 0: 
     553            self.logger.info("Attempting to upgrade packages") 
     554            upgrade_args = " ".join([os.path.join(self.instance_status[inst].get('pkg').get('uri'), \ 
     555                                                  inst.get('simplefile')) \ 
     556                                           for inst in upgrade_pkgs]) 
     557            cmdrc, output = self.cmd.run("rpm --upgrade --quiet --oldpackage --replacepkgs %s" % \ 
     558                                                       upgrade_args) 
     559            if cmdrc == 0: 
     560                # The rpm command succeeded.  All packages upgraded. 
     561                self.logger.info("Single Pass for Upgraded Packages Succeded") 
     562                upgrade_pkg_set = set([self.instance_status[inst].get('pkg') \ 
     563                                                      for inst in upgrade_pkgs]) 
     564                self.RefreshPackages() 
     565                for inst in upgrade_pkgs: 
     566                    pkg_entry = self.instance_status[inst].get('pkg') 
     567                    # Reverify all the packages that we might have just changed. 
     568                    # There may be multiple instances per package, only do the  
     569                    # verification once. 
     570                    if pkg_entry in upgrade_pkg_set: 
     571                        self.logger.debug("Reverifying Upgradable Package %s" % \ 
     572                                                                      (pkg_entry.get('name'))) 
     573                        upgrade_pkg_set.remove(pkg_entry) 
     574                        self.states[pkg_entry] = self.VerifyPackage(pkg_entry,  
     575                                                          self.instance_status[inst].get('modlist')) 
     576                    else: 
     577                        # We already reverified this pacakge. 
     578                        continue 
     579            else: 
     580                # The rpm command failed.  No packages upgraded. 
     581                # Try upgrading instances individually. 
     582                self.logger.error("Single Pass for Upgrading Packages Failed") 
     583                upgraded_instances = [] 
     584                for inst in upgrade_pkgs: 
     585                    upgrade_args = os.path.join(self.instance_status[inst].get('pkg').get('uri'), \ 
     586                                                     inst.get('simplefile')) 
     587                    #self.logger.debug("rpm --upgrade --quiet --oldpackage --replacepkgs %s" % \ 
     588                    #                                                      upgrade_args) 
     589                    cmdrc, output = self.cmd.run("rpm --upgrade --quiet --oldpackage --replacepkgs %s" % upgrade_args) 
     590                    if cmdrc == 0: 
     591                        upgraded_instances.append(inst) 
     592                    else: 
     593                        self.logger.debug("Package %s %s would not upgrade." % \ 
     594                                              (self.instance_status[inst].get('pkg').get('name'),\ 
     595                                               self.str_evra(inst))) 
     596 
     597                upgrade_pkg_set = set([self.instance_status[inst].get('pkg') \ 
     598                                                      for inst in upgrade_pkgs]) 
     599                self.RefreshPackages() 
     600                for inst in upgraded_instances: 
     601                    pkg_entry = self.instance_status[inst].get('pkg') 
     602                    # Reverify all the packages that we might have just changed. 
     603                    # There may be multiple instances per package, only do the 
     604                    # verification once. 
     605                    if pkg_entry in upgrade_pkg_set: 
     606                        self.logger.debug("Reverifying Upgradable Package %s" % \ 
     607                                                                      (pkg_entry.get('name'))) 
     608                        upgrade_pkg_set.remove(pkg_entry) 
     609                        self.states[pkg_entry] = self.VerifyPackage(pkg_entry, \ 
     610                                                        self.instance_status[inst].get('modlist')) 
     611                    else: 
     612                        # We already reverified this pacakge. 
     613                        continue 
     614 
     615        for entry in [ent for ent in packages if self.states[ent]]: 
     616            self.modified.append(entry) 
    340617 
    341618    def canInstall(self, entry): 
     
    349626 
    350627        if not instances: 
    351             # Old non Instance format. 
    352             if [attr for attr in self.__ireq__[entry.tag] if attr not in entry.attrib]: 
    353                 self.logger.error("Incomplete information for entry %s:%s; cannot verify" \ 
    354                                   % (entry.tag, entry.get('name'))) 
    355                 return False 
     628            # Old non Instance format, unmodified. 
     629            if entry.get('name') == 'gpg-pubkey': 
     630                # gpg-pubkey packages aren't really pacakges, so we have to do 
     631                # something a little different. 
     632                # Check that the Package Level has what we need for verification. 
     633                if [attr for attr in self.__gpg_ireq__[entry.tag] if attr not in entry.attrib]: 
     634                    self.logger.error("Incomplete information for entry %s:%s; cannot install" \ 
     635                                      % (entry.tag, entry.get('name'))) 
     636                    return False 
     637            else: 
     638                if [attr for attr in self.__ireq__[entry.tag] if attr not in entry.attrib]: 
     639                    self.logger.error("Incomplete information for entry %s:%s; cannot install" \ 
     640                                      % (entry.tag, entry.get('name'))) 
     641                    return False 
    356642        else: 
    357643            if entry.get('name') == 'gpg-pubkey': 
     
    359645                # something a little different. 
    360646                # Check that the Package Level has what we need for verification. 
    361                 if [attr for attr in self.__gpg_ireq__[entry.tag] if attr not in entry.attrib]: 
    362                     self.logger.error("Incomplete information for entry %s:%s; cannot verify" \ 
     647                if [attr for attr in self.__new_gpg_ireq__[entry.tag] if attr not in entry.attrib]: 
     648                    self.logger.error("Incomplete information for entry %s:%s; cannot install" \ 
    363649                                      % (entry.tag, entry.get('name'))) 
    364650                    return False 
    365651                # Check that the Instance Level has what we need for verification. 
    366652                for inst in instances: 
    367                     if [attr for attr in self.__gpg_ireq__[inst.tag] if attr not in inst.attrib]: 
    368                         self.logger.error("Incomplete information for entry %s:%s; cannot verify" \ 
     653                    if [attr for attr in self.__new_gpg_ireq__[inst.tag] \ 
     654                                 if attr not in inst.attrib]: 
     655                        self.logger.error("Incomplete information for entry %s:%s; cannot install"\ 
    369656                                          % (inst.tag, inst.get('name'))) 
    370657                        return False 
     
    373660                # Check that the Package Level has what we need for verification. 
    374661                if [attr for attr in self.__new_ireq__[entry.tag] if attr not in entry.attrib]: 
    375                     self.logger.error("Incomplete information for entry %s:%s; cannot verify" \ 
     662                    self.logger.error("Incomplete information for entry %s:%s; cannot install" \ 
    376663                                      % (entry.tag, entry.get('name'))) 
    377664                    return False 
    378665                # Check that the Instance Level has what we need for verification. 
    379666                for inst in instances: 
    380                     if [attr for attr in self.__new_ireq__[inst.tag] if attr not in inst.attrib]: 
    381                         self.logger.error("Incomplete information for entry %s:%s; cannot verify" \ 
    382                                           % (inst.tag, inst.get('name'))) 
    383                         return False 
     667                    if inst.tag == 'Instance': 
     668                        if [attr for attr in self.__new_ireq__[inst.tag] \ 
     669                                     if attr not in inst.attrib]: 
     670                            self.logger.error("Incomplete information for entry %s:%s; cannot install" \ 
     671                                              % (inst.tag, inst.get('name'))) 
     672                            return False 
    384673        return True 
    385674 
     
    392681               New style Package with Instances 
    393682               pgp-pubkey packages 
     683 
     684           Also the old style entries get modified after the first  
     685           VerifyPackage() run, so there needs to be a second test. 
    394686        ''' 
    395687        if not self.handlesEntry(entry): 
     
    399691 
    400692        if not instances: 
    401             # Old non Instance format. 
    402             if [attr for attr in self.__req__[entry.tag] if attr not in entry.attrib]: 
    403                 self.logger.error("Incomplete information for entry %s:%s; cannot verify" \ 
    404                                   % (entry.tag, entry.get('name'))) 
    405                 return False 
    406         else: 
     693            # Old non Instance format, unmodified. 
    407694            if entry.get('name') == 'gpg-pubkey': 
    408695                # gpg-pubkey packages aren't really pacakges, so we have to do  
     
    413700                                      % (entry.tag, entry.get('name'))) 
    414701                    return False 
     702            else: 
     703                if [attr for attr in self.__req__[entry.tag] if attr not in entry.attrib]: 
     704                    self.logger.error("Incomplete information for entry %s:%s; cannot verify" \ 
     705                                      % (entry.tag, entry.get('name'))) 
     706                    return False 
     707        else: 
     708            if entry.get('name') == 'gpg-pubkey': 
     709                # gpg-pubkey packages aren't really pacakges, so we have to do  
     710                # something a little different. 
     711                # Check that the Package Level has what we need for verification. 
     712                if [attr for attr in self.__new_gpg_req__[entry.tag] if attr not in entry.attrib]: 
     713                    self.logger.error("Incomplete information for entry %s:%s; cannot verify" \ 
     714                                      % (entry.tag, entry.get('name'))) 
     715                    return False 
    415716                # Check that the Instance Level has what we need for verification. 
    416717                for inst in instances: 
    417                     if [attr for attr in self.__gpg_req__[inst.tag] if attr not in inst.attrib]: 
     718                    if [attr for attr in self.__new_gpg_req__[inst.tag] \ 
     719                                 if attr not in inst.attrib]: 
    418720                        self.logger.error("Incomplete information for entry %s:%s; cannot verify" \ 
    419721                                          % (inst.tag, inst.get('name'))) 
    420722                        return False 
    421723            else: 
    422                 # New format with Instances. 
     724                # New format with Instances, or old style modified. 
    423725                # Check that the Package Level has what we need for verification. 
    424726                if [attr for attr in self.__new_req__[entry.tag] if attr not in entry.attrib]: 
     
    428730                # Check that the Instance Level has what we need for verification. 
    429731                for inst in instances: 
    430                     if [attr for attr in self.__new_req__[inst.tag] if attr not in inst.attrib]: 
    431                         self.logger.error("Incomplete information for entry %s:%s; cannot verify" \ 
    432                                           % (inst.tag, inst.get('name'))) 
    433                         return False 
     732                    if inst.tag == 'Instance': 
     733                        if [attr for attr in self.__new_req__[inst.tag] \ 
     734                                     if attr not in inst.attrib]: 
     735                            self.logger.error("Incomplete information for entry %s:%s; cannot verify" \ 
     736                                              % (inst.tag, inst.get('name'))) 
     737                            return False 
    434738        return True 
    435739 
     
    438742           Find extra packages 
    439743        ''' 
    440         extra_packages = [] 
    441         packages = {} 
    442         for entry in self.getSupportedEntries(): 
    443             packages[entry.get('name')] = entry 
    444  
    445         for name, pkg_list in self.installed.iteritems(): 
    446             extra_entry = Bcfg2.Client.XML.Element('Package', name=name, type=self.pkgtype) 
    447             if packages.get(name, None) != None: 
    448                 # There is supposed to be at least one instance installed. 
    449                 instances = packages[name].findall('Instance') 
    450                 if not instances: 
    451                     instances = [ packages[name] ] 
    452                 if name in self.installOnlyPkgs: 
    453                     for installed_inst in pkg_list: 
    454                         not_found = True 
    455                         for inst in instances: 
    456                             if inst.get('epoch', None) != None: 
    457                                 epoch = int(inst.get('epoch')) 
    458                             else: 
    459                                 epoch = None 
    460                             if epoch == installed_inst.get('epoch') and \ 
    461                                inst.get('version') == installed_inst.get('version') and \ 
    462                                inst.get('release') == installed_inst.get('release') and \ 
    463                                inst.get('arch', None) == installed_inst.get('arch'): 
    464                                 not_found = False 
    465                                 break 
    466                         if not_found == True: 
    467                             # Extra package. 
    468                             self.logger.info("Extra InstallOnlyPackage %s %s:%s-%s.%s." % \ 
    469                                  (name, installed_inst.get('epoch'), \ 
    470                                         installed_inst.get('version'), \ 
    471                                         installed_inst.get('release'), \ 
    472                                         installed_inst.get('arch'))) 
    473                             if inst.tag == 'Package': 
    474                                 Bcfg2.Client.XML.SubElement(extra_entry, \ 
    475                                              'Instance',  
    476                                              version = installed_inst.get('version'), \ 
    477                                              release = installed_inst.get('release')) 
    478                             else: 
    479                                 Bcfg2.Client.XML.SubElement(extra_entry, \ 
    480                                              'Instance',  
    481                                              epoch = str(installed_inst.get('epoch')),\ 
    482                                              version = installed_inst.get('version'), \ 
    483                                              release = installed_inst.get('release'), \ 
    484                                              arch = installed_inst.get('arch', '')) 
    485                 else: 
    486                     # Normal package, only check arch. 
    487                     for installed_inst in pkg_list: 
    488                         not_found = True 
    489                         for inst in instances: 
    490                             if installed_inst.get('arch') == inst.get('arch'): 
    491                                 not_found = False 
    492                                 break 
    493                         if not_found: 
    494                             self.logger.info("Extra Normal Package Instance %s %s:%s-%s.%s." % \ 
    495                                  (name, installed_inst.get('epoch'), \ 
    496                                         installed_inst.get('version'), \ 
    497                                         installed_inst.get('release'), \ 
    498                                         installed_inst.get('arch'))) 
    499                             if inst.tag == 'Package': 
    500                                 Bcfg2.Client.XML.SubElement(extra_entry, \ 
    501                                              'Instance',  
    502                                              version = installed_inst.get('version'), \ 
    503                                              release = installed_inst.get('release')) 
    504                             else: 
    505                                 Bcfg2.Client.XML.SubElement(extra_entry, \ 
    506                                              'Instance',  
    507                                              epoch = str(installed_inst.get('epoch')),\ 
    508                                              version = installed_inst.get('version'), \ 
    509                                              release = installed_inst.get('release'), \ 
    510                                              arch = installed_inst.get('arch', '')) 
    511             else: 
    512                 # Extra package. 
    513                 self.logger.info("No instances of Package %s should be installed." % (name)) 
    514                 for installed_inst in pkg_list: 
    515                     if inst.tag == 'Package': 
    516                         Bcfg2.Client.XML.SubElement(extra_entry, \ 
    517                                      'Instance',  
     744        packages = [entry.get('name') for entry in self.getSupportedEntries()] 
     745        extras = [] 
     746 
     747        for (name, instances) in self.installed.iteritems(): 
     748            if name not in packages: 
     749                extra_entry = Bcfg2.Client.XML.Element('Package', name=name, type=self.pkgtype) 
     750                for installed_inst in instances: 
     751                    self.logger.info("Extra Package %s %s." % \ 
     752                                     (name, self.str_evra(installed_inst))) 
     753                    Bcfg2.Client.XML.SubElement(extra_entry, \ 
     754                                                'Instance',  
     755                                                epoch = str(installed_inst.get('epoch', '')),\ 
     756                                                version = installed_inst.get('version'), \ 
     757                                                release = installed_inst.get('release'), \ 
     758                                                arch = installed_inst.get('arch', '')) 
     759                    extras.append(extra_entry) 
     760        return extras 
     761 
     762 
     763    def FindExtraInstances(self, pkg_entry, installed_entry): 
     764        ''' 
     765            Check for installed instances that are not in the config. 
     766            Return a Package Entry with Instances to remove, or None if there 
     767            are no Instances to remove. 
     768        ''' 
     769        name = pkg_entry.get('name') 
     770        extra_entry = Bcfg2.Client.XML.Element('Package', name=name, type=self.pkgtype) 
     771        instances = [inst for inst in pkg_entry if inst.tag == 'Instance' or inst.tag == 'Package'] 
     772        if name in self.installOnlyPkgs: 
     773            for installed_inst in installed_entry: 
     774                not_found = True 
     775                for inst in instances: 
     776                    if self.pkg_vr_equal(inst, installed_inst) or \ 
     777                       self.inst_evra_equal(inst, installed_inst): 
     778                        not_found = False 
     779                        break 
     780                if not_found == True: 
     781                    # Extra package. 
     782                    self.logger.info("Extra InstallOnlyPackage %s %s." % \ 
     783                                               (name, self.str_evra(installed_inst))) 
     784                    tmp_entry = Bcfg2.Client.XML.SubElement(extra_entry, 'Instance', \ 
    518785                                     version = installed_inst.get('version'), \ 
    519786                                     release = installed_inst.get('release')) 
    520                     else: 
    521                         Bcfg2.Client.XML.SubElement(extra_entry, \ 
     787                    if installed_inst.get('epoch', None) != None: 
     788                        tmp_entry.set('epoch', str(installed_inst.get('epoch'))) 
     789                    if installed_inst.get('arch', None) != None: 
     790                        tmp_entry.set('arch', installed_inst.get('arch')) 
     791        else: 
     792            # Normal package, only check arch. 
     793            for installed_inst in installed_entry: 
     794                not_found = True 
     795                for inst in instances: 
     796                    if installed_inst.get('arch', None) == inst.get('arch', None) or\ 
     797                       inst.tag == 'Package': 
     798                        not_found = False 
     799                        break 
     800                if not_found: 
     801                    self.logger.info("Extra Normal Package Instance %s %s" % \ 
     802                                                        (name, self.str_evra(installed_inst))) 
     803                    Bcfg2.Client.XML.SubElement(extra_entry, \ 
    522804                                     'Instance',  
    523                                      epoch = str(installed_inst.get('epoch')),\ 
     805                                     epoch = str(installed_inst.get('epoch', '')),\ 
    524806                                     version = installed_inst.get('version'), \ 
    525807                                     release = installed_inst.get('release'), \ 
    526808                                     arch = installed_inst.get('arch', '')) 
    527             if len(extra_entry) > 0: 
    528                 extra_packages.append(extra_entry) 
    529             else: 
    530                 del extra_entry 
    531         return extra_packages 
    532  
    533  
    534   
     809 
     810        if len(extra_entry) == 0: 
     811            extra_entry = None 
     812 
     813        return extra_entry 
     814 
     815    def Inventory(self, structures=[]): 
     816        ''' 
     817           Wrap the Tool.Inventory() method with its own rpm.TransactionSet()  
     818           and an explicit closeDB() as the close wasn't happening and DB4  
     819           locks were getting left behind on the RPM database creating a nice  
     820           mess. 
     821 
     822           ***** Do performance comparison with the transctionset/closeDB 
     823                 moved into rpmtools, which would mean a transactionset/closeDB 
     824                 per VerifyPackage() call (meaning one per RPM package) rather  
     825                 than one for the whole system. 
     826        ''' 
     827        self.vp_ts = rpmtools.rpmtransactionset() 
     828        Bcfg2.Client.Tools.Tool.Inventory(self) 
     829        # Tool is still an old style class, so super doesn't work. Change it. 
     830        #super(RPMng, self).Inventory() 
     831        self.vp_ts.closeDB() 
     832 
     833    def str_evra(self, instance): 
     834        ''' 
     835            Convert evra dict entries to a string. 
     836        ''' 
     837        return '%s:%s-%s.%s' % (instance.get('epoch', '*'), instance.get('version', '*'), 
     838                                instance.get('release', '*'), instance.get('arch', '*')) 
     839 
     840    def pkg_vr_equal(self, config_entry, installed_entry): 
     841        ''' 
     842            Compare old style entry to installed entry.  Which means ignore 
     843            the epoch and arch. 
     844        ''' 
     845        if (config_entry.tag == 'Package' and \ 
     846            config_entry.get('version') == installed_entry.get('version') and \ 
     847            config_entry.get('release') == installed_entry.get('release')): 
     848            return True 
     849        else: 
     850            return False 
     851 
     852    def inst_evra_equal(self, config_entry, installed_entry): 
     853        ''' 
     854            Compare new style instance to installed entry. 
     855        ''' 
     856 
     857        if config_entry.get('epoch', None) != None: 
     858            epoch = int(config_entry.get('epoch')) 
     859        else: 
     860            epoch = None 
     861 
     862        if (config_entry.tag == 'Instance' and\ 
     863            epoch == installed_entry.get('epoch', None) and \ 
     864            config_entry.get('version') == installed_entry.get('version') and \ 
     865            config_entry.get('release') == installed_entry.get('release') and \ 
     866            config_entry.get('arch', None) == installed_entry.get('arch', None)): 
     867            return True 
     868        else: 
     869            return False 
     870 
     871    def getinstalledgpg(self): 
     872        '''  
     873           Create a list of installed GPG key IDs. 
     874 
     875           The pgp-pubkey package version is the least significant 4 bytes 
     876           (big-endian) of the key ID which is good enough for our purposes. 
     877        '''  
     878        init_ts = rpmtools.rpmtransactionset() 
     879        init_ts.setVSFlags(rpm._RPMVSF_NODIGESTS|rpm._RPMVSF_NOSIGNATURES) 
     880        gpg_hdrs = rpmtools.getheadersbykeyword(init_ts, **{'name':'gpg-pubkey'}) 
     881        keyids = [ header[rpm.RPMTAG_VERSION] for header in gpg_hdrs] 
     882        keyids.append('None') 
     883        init_ts.closeDB() 
     884        del init_ts 
     885        return keyids 
  • trunk/bcfg2/src/lib/Client/Tools/rpmtools.py

    r3013 r3029  
    1919 
    2020""" 
    21 __revision__ = '0.3' 
     21__revision__ = '$Revision$' 
    2222 
    2323import rpm, optparse, pwd, grp 
     
    165165               'version':header[rpm.RPMTAG_VERSION],  
    166166               'release':header[rpm.RPMTAG_RELEASE], 
    167                'arch':header[rpm.RPMTAG_ARCH] }  
     167               'arch':header[rpm.RPMTAG_ARCH], 
     168               'gpgkeyid':header.sprintf("%|SIGGPG?{%{SIGGPG:pgpsig}}:{None}|").split()[-1] } 
    168169               for header in rts.dbMatch()] 
    169170 
     
    172173        Return list of indexs from the rpmdb matching keywords 
    173174        ex: getHeadersByKeyword(name='foo', version='1', release='1') 
     175  
     176        Can be passed any structure that can be indexed by the pkgspec  
     177        keyswords as other keys are filtered out. 
    174178 
    175179    """ 
     
    181185        index_mi = index_ts.dbMatch() 
    182186 
    183     # This is wrong! Yes its an issue, but you can't just ignore it. 
    184     # FIX THIS!!!!  This is how it is in YUM. 
    185187    if kwargs.has_key('epoch'): 
    186         del(kwargs['epoch']) # epochs don't work here for None/0/'0' reasons 
    187  
    188     keywords = len(kwargs.keys()) 
     188        if kwargs['epoch'] != None and kwargs['epoch'] != 'None': 
     189            kwargs['epoch'] = int(kwargs['epoch']) 
     190        else: 
     191            del(kwargs['epoch']) 
     192 
     193    keywords = [ key for key in kwargs.keys() \ 
     194                         if key in ('name', 'epoch', 'version', 'release', 'arch')] 
     195    keywords_len = len(keywords) 
    189196    for hdr in index_mi: 
    190197        match = 0 
    191         for keyword in kwargs.keys(): 
     198        for keyword in keywords: 
    192199            if hdr[keyword] == kwargs[keyword]: 
    193200                match += 1 
    194         if match == keywords: 
     201        if match == keywords_len: 
    195202            lst.append(index_mi.instance()) 
    196203    del index_mi 
     
    204211        Return list of headers from the rpmdb matching keywords 
    205212        ex: getHeadersByKeyword(name='foo', version='1', release='1') 
     213  
     214        Can be passed any structure that can be indexed by the pkgspec  
     215        keyswords as other keys are filtered out. 
    206216 
    207217    """ 
     
    213223        header_mi = header_ts.dbMatch() 
    214224 
    215     # This is wrong! Yes its an issue, but you can't just ignore it. 
    216     # FIX THIS!!!!  This is how it is in YUM. 
    217     # Fixed, I hope. MJTB 20070127. 
    218     if kwargs.has_key('epoch') and kwargs['epoch'] != None: 
    219         kwargs['epoch'] = int(kwargs['epoch']) 
    220         #del(kwargs['epoch']) # epochs don't work here for None/0/'0' reasons 
    221  
    222     keywords = len(kwargs.keys()) 
     225    if kwargs.has_key('epoch'): 
     226        if kwargs['epoch'] != None and kwargs['epoch'] != 'None': 
     227            kwargs['epoch'] = int(kwargs['epoch']) 
     228        else: 
     229            del(kwargs['epoch']) 
     230 
     231    keywords = [ key for key in kwargs.keys() \ 
     232                         if key in ('name', 'epoch', 'version', 'release', 'arch')] 
     233    keywords_len = len(keywords) 
    223234    for hdr in header_mi: 
    224235        match = 0 
    225         for keyword in kwargs.keys(): 
     236        for keyword in keywords: 
    226237            if hdr[keyword] == kwargs[keyword]: 
    227238                match += 1 
    228         if match == keywords: 
     239        if match == keywords_len: 
    229240            lst.append(hdr) 
    230241    del header_mi 
     
    546557    if 'nodigest' in verify_options: 
    547558        vsflags |= rpm._RPMVSF_NODIGESTS 
    548     if 'nosifnature' in verify_options: 
     559    if 'nosignature' in verify_options: 
    549560        vsflags |= rpm._RPMVSF_NOSIGNATURES 
    550561    ovsflags = vp_ts.setVSFlags(vsflags) 
     
    621632                    file_stat.append(' ') 
    622633         
    623                 file_stat.append(fileinfo[0]) 
     634                file_stat.append(fileinfo[0]) # The filename. 
    624635                package_results.setdefault('files', []).append(file_stat) 
    625636 
     
    723734        """ 
    724735        if   reason == rpm.RPMCALLBACK_INST_OPEN_FILE: 
    725             print 'rpm.RPMCALLBACK_INST_OPEN_FILE' 
     736            pass 
     737            #print 'rpm.RPMCALLBACK_INST_OPEN_FILE' 
    726738        elif reason == rpm.RPMCALLBACK_INST_CLOSE_FILE: 
    727             print 'rpm.RPMCALLBACK_INST_CLOSE_FILE' 
     739            pass 
     740            #print 'rpm.RPMCALLBACK_INST_CLOSE_FILE' 
    728741        elif reason == rpm.RPMCALLBACK_INST_START: 
    729             print 'rpm.RPMCALLBACK_INST_START' 
     742            pass 
     743            #print 'rpm.RPMCALLBACK_INST_START' 
    730744        elif reason == rpm.RPMCALLBACK_TRANS_PROGRESS or \ 
    731745             reason == rpm.RPMCALLBACK_INST_PROGRESS: 
    732             print 'rpm.RPMCALLBACK_TRANS_PROGRESS or \ 
    733                    rpm.RPMCALLBACK_INST_PROGRESS' 
     746            pass 
     747            #print 'rpm.RPMCALLBACK_TRANS_PROGRESS or \ 
     748            #       rpm.RPMCALLBACK_INST_PROGRESS' 
    734749        elif reason == rpm.RPMCALLBACK_TRANS_START: 
    735             print 'rpm.RPMCALLBACK_TRANS_START' 
     750            pass 
     751            #print 'rpm.RPMCALLBACK_TRANS_START' 
    736752        elif reason == rpm.RPMCALLBACK_TRANS_STOP: 
    737             print 'rpm.RPMCALLBACK_TRANS_STOP' 
     753            pass 
     754            #print 'rpm.RPMCALLBACK_TRANS_STOP' 
    738755        elif reason == rpm.RPMCALLBACK_REPACKAGE_START: 
    739             print 'rpm.RPMCALLBACK_REPACKAGE_START' 
     756            pass 
     757            #print 'rpm.RPMCALLBACK_REPACKAGE_START' 
    740758        elif reason == rpm.RPMCALLBACK_REPACKAGE_PROGRESS: 
    741             print 'rpm.RPMCALLBACK_REPACKAGE_PROGRESS' 
     759            pass 
     760            #print 'rpm.RPMCALLBACK_REPACKAGE_PROGRESS' 
    742761        elif reason == rpm.RPMCALLBACK_REPACKAGE_STOP: 
    743             print 'rpm.RPMCALLBACK_REPACKAGE_STOP' 
     762            pass 
     763            #print 'rpm.RPMCALLBACK_REPACKAGE_STOP' 
    744764        elif reason == rpm.RPMCALLBACK_UNINST_PROGRESS: 
    745             print 'rpm.RPMCALLBACK_UNINST_PROGRESS' 
     765            pass 
     766            #print 'rpm.RPMCALLBACK_UNINST_PROGRESS' 
    746767        elif reason == rpm.RPMCALLBACK_UNINST_START: 
    747             print 'rpm.RPMCALLBACK_UNINST_START' 
     768            pass 
     769            #print 'rpm.RPMCALLBACK_UNINST_START' 
    748770        elif reason == rpm.RPMCALLBACK_UNINST_STOP: 
    749             print 'rpm.RPMCALLBACK_UNINST_STOP' 
    750             print '***Package ', key, ' deleted ***' 
     771            pass 
     772            #print 'rpm.RPMCALLBACK_UNINST_STOP' 
     773            #print '***Package ', key, ' deleted ***' 
    751774            # How do we get at this? 
    752775            # RPM.modified += key 
    753776        elif reason == rpm.RPMCALLBACK_UNPACK_ERROR: 
    754             print 'rpm.RPMCALLBACK_UNPACK_ERROR' 
     777            pass 
     778            #print 'rpm.RPMCALLBACK_UNPACK_ERROR' 
    755779        elif reason == rpm.RPMCALLBACK_CPIO_ERROR: 
    756             print 'rpm.RPMCALLBACK_CPIO_ERROR' 
     780            pass 
     781            #print 'rpm.RPMCALLBACK_CPIO_ERROR' 
    757782        elif reason == rpm.RPMCALLBACK_UNKNOWN: 
    758             print 'rpm.RPMCALLBACK_UNKNOWN' 
     783            pass 
     784            #print 'rpm.RPMCALLBACK_UNKNOWN' 
    759785        else: 
    760786            print 'ERROR - Fell through callBack' 
    761787     
    762         print reason, amount, total, key, client_data 
    763  
    764 def rpm_erase(erase_pkgspec, erase_flags): 
     788        #print reason, amount, total, key, client_data 
     789 
     790def rpm_erase(erase_pkgspecs, erase_flags): 
    765791    """ 
    766792       pkgspecs is a list of pkgspec dicts specifying packages 
     
    781807    erase_ts.setFlags(erase_ts_flags) 
    782808 
    783     idx_list = getindexbykeyword(erase_ts, **erase_pkgspec) 
    784     if len(idx_list) > 1 and not 'allmatches' in erase_flags: 
    785         print 'ERROR - Multiple package match for erase' 
    786     else: 
    787         for idx in idx_list: 
    788             erase_ts.addErase(idx) 
    789  
     809    for pkgspec in erase_pkgspecs: 
     810        idx_list = getindexbykeyword(erase_ts, **pkgspec) 
     811        if len(idx_list) > 1 and not 'allmatches' in erase_flags: 
     812            #pass 
     813            print 'ERROR - Multiple package match for erase', pkgspec 
     814        else: 
     815            for idx in idx_list: 
     816                erase_ts.addErase(idx) 
     817 
     818    #for te in erase_ts: 
     819    #    print "%s %s:%s-%s.%s" % (te.N(), te.E(), te.V(), te.R(), te.A()) 
     820 
     821    erase_problems = [] 
    790822    if 'nodeps' not in erase_flags: 
    791823        erase_problems = erase_ts.check() 
    792824 
    793     if erase_problems: 
    794         print 'ERROR - Dependency failures on package erase' 
    795         print erase_problems 
    796     else: 
     825    if erase_problems == []: 
    797826        erase_ts.order() 
    798827        erase_callback = Rpmtscallback()  
    799828        erase_ts.run(erase_callback.callback, 'Erase') 
     829    #else: 
     830    #    print 'ERROR - Dependency failures on package erase' 
     831    #    print erase_problems 
    800832 
    801833    erase_ts.closeDB() 
     834    del erase_ts 
    802835    return erase_problems 
    803836 
     
    10571090    elif options.erase: 
    10581091        if options.name: 
    1059             rpm_erase(cmdline_pkgspec, rpm_options) 
     1092            rpm_erase([cmdline_pkgspec], rpm_options) 
    10601093        else: 
    10611094            print 'You must specify the "--name" option'