| 1 | '''Bcfg2 Support for RPMS''' |
|---|
| 2 | |
|---|
| 3 | __revision__ = '$Revision$' |
|---|
| 4 | |
|---|
| 5 | import ConfigParser |
|---|
| 6 | import os.path |
|---|
| 7 | import rpm |
|---|
| 8 | import rpmtools |
|---|
| 9 | import Bcfg2.Client.Tools |
|---|
| 10 | |
|---|
| 11 | # Fix for python2.3 |
|---|
| 12 | try: |
|---|
| 13 | set |
|---|
| 14 | except NameError: |
|---|
| 15 | from sets import Set as set |
|---|
| 16 | |
|---|
| 17 | class RPMng(Bcfg2.Client.Tools.PkgTool): |
|---|
| 18 | '''Support for RPM packages''' |
|---|
| 19 | name = 'RPMng' |
|---|
| 20 | |
|---|
| 21 | __execs__ = ['/bin/rpm', '/var/lib/rpm'] |
|---|
| 22 | __handles__ = [('Package', 'rpm')] |
|---|
| 23 | |
|---|
| 24 | __req__ = {'Package': ['name', 'version']} |
|---|
| 25 | __ireq__ = {'Package': ['url']} |
|---|
| 26 | |
|---|
| 27 | __new_req__ = {'Package': ['name'], 'Instance': ['version', 'release', 'arch']} |
|---|
| 28 | __new_ireq__ = {'Package': ['uri'], \ |
|---|
| 29 | 'Instance': ['simplefile']} |
|---|
| 30 | |
|---|
| 31 | __gpg_req__ = {'Package': ['name', 'version']} |
|---|
| 32 | __gpg_ireq__ = {'Package': ['name', 'version']} |
|---|
| 33 | |
|---|
| 34 | __new_gpg_req__ = {'Package': ['name'], 'Instance': ['version', 'release']} |
|---|
| 35 | __new_gpg_ireq__ = {'Package': ['name'], 'Instance': ['version', 'release']} |
|---|
| 36 | |
|---|
| 37 | conflicts = ['RPM'] |
|---|
| 38 | |
|---|
| 39 | pkgtype = 'rpm' |
|---|
| 40 | pkgtool = ("rpm --oldpackage --replacepkgs --quiet -U %s", ("%s", ["url"])) |
|---|
| 41 | |
|---|
| 42 | def __init__(self, logger, setup, config): |
|---|
| 43 | Bcfg2.Client.Tools.PkgTool.__init__(self, logger, setup, config) |
|---|
| 44 | |
|---|
| 45 | self.instance_status = {} |
|---|
| 46 | self.extra_instances = [] |
|---|
| 47 | self.modlists = {} |
|---|
| 48 | self.gpg_keyids = self.getinstalledgpg() |
|---|
| 49 | |
|---|
| 50 | # Process thee RPMng section from the config file. |
|---|
| 51 | RPMng_CP = ConfigParser.ConfigParser() |
|---|
| 52 | RPMng_CP.read(self.setup.get('setup')) |
|---|
| 53 | |
|---|
| 54 | # installonlypackages |
|---|
| 55 | self.installOnlyPkgs = [] |
|---|
| 56 | if RPMng_CP.has_option(self.name, 'installonlypackages'): |
|---|
| 57 | for i in RPMng_CP.get(self.name, 'installonlypackages').split(','): |
|---|
| 58 | self.installOnlyPkgs.append(i.strip()) |
|---|
| 59 | if self.installOnlyPkgs == []: |
|---|
| 60 | self.installOnlyPkgs = ['kernel', 'kernel-bigmem', 'kernel-enterprise', 'kernel-smp', |
|---|
| 61 | 'kernel-modules', 'kernel-debug', 'kernel-unsupported', |
|---|
| 62 | 'kernel-source', 'kernel-devel', 'kernel-default', |
|---|
| 63 | 'kernel-largesmp-devel', 'kernel-largesmp', 'kernel-xen', |
|---|
| 64 | 'gpg-pubkey'] |
|---|
| 65 | if 'gpg-pubkey' not in self.installOnlyPkgs: |
|---|
| 66 | self.installOnlyPkgs.append('gpg-pubkey') |
|---|
| 67 | self.logger.debug('installOnlyPackages = %s' % self.installOnlyPkgs) |
|---|
| 68 | |
|---|
| 69 | # erase_flags |
|---|
| 70 | self.erase_flags = [] |
|---|
| 71 | if RPMng_CP.has_option(self.name, 'erase_flags'): |
|---|
| 72 | for i in RPMng_CP.get(self.name, 'erase_flags').split(','): |
|---|
| 73 | self.erase_flags.append(i.strip()) |
|---|
| 74 | if self.erase_flags == []: |
|---|
| 75 | self.erase_flags = ['allmatches'] |
|---|
| 76 | self.logger.debug('erase_flags = %s' % self.erase_flags) |
|---|
| 77 | |
|---|
| 78 | # pkg_checks |
|---|
| 79 | if RPMng_CP.has_option(self.name, 'pkg_checks'): |
|---|
| 80 | self.pkg_checks = RPMng_CP.get(self.name, 'pkg_checks').lower() |
|---|
| 81 | else: |
|---|
| 82 | self.pkg_checks = 'true' |
|---|
| 83 | self.logger.debug('pkg_checks = %s' % self.pkg_checks) |
|---|
| 84 | |
|---|
| 85 | # pkg_verify |
|---|
| 86 | if RPMng_CP.has_option(self.name, 'pkg_verify'): |
|---|
| 87 | self.pkg_verify = RPMng_CP.get(self.name, 'pkg_verify').lower() |
|---|
| 88 | else: |
|---|
| 89 | self.pkg_verify = 'true' |
|---|
| 90 | self.logger.debug('pkg_verify = %s' % self.pkg_verify) |
|---|
| 91 | |
|---|
| 92 | # installed_action |
|---|
| 93 | if RPMng_CP.has_option(self.name, 'installed_action'): |
|---|
| 94 | self.installed_action = RPMng_CP.get(self.name, 'installed_action').lower() |
|---|
| 95 | else: |
|---|
| 96 | self.installed_action = 'install' |
|---|
| 97 | self.logger.debug('installed_action = %s' % self.installed_action) |
|---|
| 98 | |
|---|
| 99 | # version_fail_action |
|---|
| 100 | if RPMng_CP.has_option(self.name, 'version_fail_action'): |
|---|
| 101 | self.version_fail_action = RPMng_CP.get(self.name, 'version_fail_action').lower() |
|---|
| 102 | else: |
|---|
| 103 | self.version_fail_action = 'upgrade' |
|---|
| 104 | self.logger.debug('version_fail_action = %s' % self.version_fail_action) |
|---|
| 105 | |
|---|
| 106 | # verify_fail_action |
|---|
| 107 | if self.name == "RPMng": |
|---|
| 108 | if RPMng_CP.has_option(self.name, 'verify_fail_action'): |
|---|
| 109 | self.verify_fail_action = RPMng_CP.get(self.name, 'verify_fail_action').lower() |
|---|
| 110 | else: |
|---|
| 111 | self.verify_fail_action = 'reinstall' |
|---|
| 112 | else: # yum can't reinstall packages. |
|---|
| 113 | self.verify_fail_action = 'none' |
|---|
| 114 | self.logger.debug('verify_fail_action = %s' % self.verify_fail_action) |
|---|
| 115 | |
|---|
| 116 | # version_fail_action |
|---|
| 117 | if RPMng_CP.has_option(self.name, 'verify_flags'): |
|---|
| 118 | self.verify_flags = RPMng_CP.get(self.name, 'verify_flags').lower().split(',') |
|---|
| 119 | else: |
|---|
| 120 | self.verify_flags = [] |
|---|
| 121 | if '' in self.verify_flags: |
|---|
| 122 | self.verify_flags.remove('') |
|---|
| 123 | self.logger.debug('version_fail_action = %s' % self.version_fail_action) |
|---|
| 124 | # Force a re- prelink of all packages if prelink exists. |
|---|
| 125 | # Many, if not most package verifies can be caused by out of date prelinking. |
|---|
| 126 | if os.path.isfile('/usr/sbin/prelink') and not self.setup['dryrun']: |
|---|
| 127 | cmdrc, output = self.cmd.run('/usr/sbin/prelink -a -mR') |
|---|
| 128 | if cmdrc == 0: |
|---|
| 129 | self.logger.debug('Pre-emptive prelink succeeded') |
|---|
| 130 | else: |
|---|
| 131 | # FIXME : this is dumb - what if the output is huge? |
|---|
| 132 | self.logger.error('Pre-emptive prelink failed: %s' % output) |
|---|
| 133 | |
|---|
| 134 | |
|---|
| 135 | def RefreshPackages(self): |
|---|
| 136 | ''' |
|---|
| 137 | Creates self.installed{} which is a dict of installed packages. |
|---|
| 138 | |
|---|
| 139 | The dict items are lists of nevra dicts. This loosely matches the |
|---|
| 140 | config from the server and what rpmtools uses to specify pacakges. |
|---|
| 141 | |
|---|
| 142 | e.g. |
|---|
| 143 | |
|---|
| 144 | self.installed['foo'] = [ {'name':'foo', 'epoch':None, |
|---|
| 145 | 'version':'1', 'release':2, |
|---|
| 146 | 'arch':'i386'}, |
|---|
| 147 | {'name':'foo', 'epoch':None, |
|---|
| 148 | 'version':'1', 'release':2, |
|---|
| 149 | 'arch':'x86_64'} ] |
|---|
| 150 | ''' |
|---|
| 151 | self.installed = {} |
|---|
| 152 | refresh_ts = rpmtools.rpmtransactionset() |
|---|
| 153 | # Don't bother with signature checks at this stage. The GPG keys might |
|---|
| 154 | # not be installed. |
|---|
| 155 | refresh_ts.setVSFlags(rpm._RPMVSF_NODIGESTS|rpm._RPMVSF_NOSIGNATURES) |
|---|
| 156 | for nevra in rpmtools.rpmpackagelist(refresh_ts): |
|---|
| 157 | self.installed.setdefault(nevra['name'], []).append(nevra) |
|---|
| 158 | if self.setup['debug']: |
|---|
| 159 | print("The following package instances are installed:") |
|---|
| 160 | for name, instances in list(self.installed.items()): |
|---|
| 161 | self.logger.debug(" " + name) |
|---|
| 162 | for inst in instances: |
|---|
| 163 | self.logger.debug(" %s" %self.str_evra(inst)) |
|---|
| 164 | refresh_ts.closeDB() |
|---|
| 165 | del refresh_ts |
|---|
| 166 | |
|---|
| 167 | def VerifyPackage(self, entry, modlist, pinned_version=None): |
|---|
| 168 | ''' |
|---|
| 169 | Verify Package status for entry. |
|---|
| 170 | Performs the following: |
|---|
| 171 | - Checks for the presence of required Package Instances. |
|---|
| 172 | - Compares the evra 'version' info against self.installed{}. |
|---|
| 173 | - RPM level package verify (rpm --verify). |
|---|
| 174 | - Checks for the presence of unrequired package instances. |
|---|
| 175 | |
|---|
| 176 | Produces the following dict and list for RPMng.Install() to use: |
|---|
| 177 | For installs/upgrades/fixes of required instances: |
|---|
| 178 | instance_status = { <Instance Element Object>: |
|---|
| 179 | { 'installed': True|False, |
|---|
| 180 | 'version_fail': True|False, |
|---|
| 181 | 'verify_fail': True|False, |
|---|
| 182 | 'pkg': <Package Element Object>, |
|---|
| 183 | 'modlist': [ <filename>, ... ], |
|---|
| 184 | 'verify' : [ <rpm --verify results> ] |
|---|
| 185 | }, ...... |
|---|
| 186 | } |
|---|
| 187 | |
|---|
| 188 | For deletions of unrequired instances: |
|---|
| 189 | extra_instances = [ <Package Element Object>, ..... ] |
|---|
| 190 | |
|---|
| 191 | Constructs the text prompts for interactive mode. |
|---|
| 192 | ''' |
|---|
| 193 | instances = [inst for inst in entry if inst.tag == 'Instance' or inst.tag == 'Package'] |
|---|
| 194 | if instances == []: |
|---|
| 195 | # We have an old style no Instance entry. Convert it to new style. |
|---|
| 196 | instance = Bcfg2.Client.XML.SubElement(entry, 'Package') |
|---|
| 197 | for attrib in list(entry.attrib.keys()): |
|---|
| 198 | instance.attrib[attrib] = entry.attrib[attrib] |
|---|
| 199 | if self.pkg_checks == 'true' and entry.get('pkg_checks', 'true') == 'true': |
|---|
| 200 | if 'any' in [entry.get('version'), pinned_version]: |
|---|
| 201 | version, release = 'any', 'any' |
|---|
| 202 | elif entry.get('version') == 'auto': |
|---|
| 203 | if pinned_version != None: |
|---|
| 204 | version, release = pinned_version.split('-') |
|---|
| 205 | else: |
|---|
| 206 | return False |
|---|
| 207 | else: |
|---|
| 208 | version, release = entry.get('version').split('-') |
|---|
| 209 | instance.set('version', version) |
|---|
| 210 | instance.set('release', release) |
|---|
| 211 | if entry.get('verify', 'true') == 'false': |
|---|
| 212 | instance.set('verify', 'false') |
|---|
| 213 | instances = [ instance ] |
|---|
| 214 | |
|---|
| 215 | self.logger.debug("Verifying package instances for %s" % entry.get('name')) |
|---|
| 216 | package_fail = False |
|---|
| 217 | qtext_versions = '' |
|---|
| 218 | |
|---|
| 219 | if entry.get('name') in self.installed: |
|---|
| 220 | # There is at least one instance installed. |
|---|
| 221 | if self.pkg_checks == 'true' and entry.get('pkg_checks', 'true') == 'true': |
|---|
| 222 | if entry.get('name') in self.installOnlyPkgs: |
|---|
| 223 | # Packages that should only be installed or removed. |
|---|
| 224 | # e.g. kernels. |
|---|
| 225 | self.logger.debug(" Install only package.") |
|---|
| 226 | for inst in instances: |
|---|
| 227 | self.instance_status.setdefault(inst, {})['installed'] = False |
|---|
| 228 | self.instance_status[inst]['version_fail'] = False |
|---|
| 229 | if inst.tag == 'Package' and len(self.installed[entry.get('name')]) > 1: |
|---|
| 230 | self.logger.error("WARNING: Multiple instances of package %s are installed." % \ |
|---|
| 231 | (entry.get('name'))) |
|---|
| 232 | for pkg in self.installed[entry.get('name')]: |
|---|
| 233 | if inst.get('version') == 'any' or self.pkg_vr_equal(inst, pkg) \ |
|---|
| 234 | or self.inst_evra_equal(inst, pkg): |
|---|
| 235 | if inst.get('version') == 'any': |
|---|
| 236 | self.logger.error("got any version") |
|---|
| 237 | self.logger.debug(" %s" % self.str_evra(inst)) |
|---|
| 238 | self.instance_status[inst]['installed'] = True |
|---|
| 239 | |
|---|
| 240 | if self.pkg_verify == 'true' and \ |
|---|
| 241 | inst.get('pkg_verify', 'true') == 'true': |
|---|
| 242 | flags = inst.get('verify_flags', '').split(',') + self.verify_flags |
|---|
| 243 | if pkg.get('gpgkeyid', '')[-8:] not in self.gpg_keyids and \ |
|---|
| 244 | entry.get('name') != 'gpg-pubkey': |
|---|
| 245 | flags += ['nosignature', 'nodigest'] |
|---|
| 246 | self.logger.debug('WARNING: Package %s %s requires GPG Public key with ID %s'\ |
|---|
| 247 | % (pkg.get('name'), self.str_evra(pkg), \ |
|---|
| 248 | pkg.get('gpgkeyid', ''))) |
|---|
| 249 | self.logger.debug(' Disabling signature check.') |
|---|
| 250 | |
|---|
| 251 | if self.setup.get('quick', False): |
|---|
| 252 | if rpmtools.prelink_exists: |
|---|
| 253 | flags += ['nomd5', 'nosize'] |
|---|
| 254 | else: |
|---|
| 255 | flags += ['nomd5'] |
|---|
| 256 | self.logger.debug(" verify_flags = %s" % flags) |
|---|
| 257 | |
|---|
| 258 | if inst.get('verify', 'true') == 'false': |
|---|
| 259 | self.instance_status[inst]['verify'] = None |
|---|
| 260 | else: |
|---|
| 261 | vp_ts = rpmtools.rpmtransactionset() |
|---|
| 262 | self.instance_status[inst]['verify'] = \ |
|---|
| 263 | rpmtools.rpm_verify( vp_ts, pkg, flags) |
|---|
| 264 | vp_ts.closeDB() |
|---|
| 265 | del vp_ts |
|---|
| 266 | |
|---|
| 267 | if self.instance_status[inst]['installed'] == False: |
|---|
| 268 | self.logger.info(" Package %s %s not installed." % \ |
|---|
| 269 | (entry.get('name'), self.str_evra(inst))) |
|---|
| 270 | |
|---|
| 271 | qtext_versions = qtext_versions + 'I(%s) ' % self.str_evra(inst) |
|---|
| 272 | entry.set('current_exists', 'false') |
|---|
| 273 | else: |
|---|
| 274 | # Normal Packages that can be upgraded. |
|---|
| 275 | for inst in instances: |
|---|
| 276 | self.instance_status.setdefault(inst, {})['installed'] = False |
|---|
| 277 | self.instance_status[inst]['version_fail'] = False |
|---|
| 278 | |
|---|
| 279 | # Only installed packages with the same architecture are |
|---|
| 280 | # relevant. |
|---|
| 281 | if inst.get('arch', None) == None: |
|---|
| 282 | arch_match = self.installed[entry.get('name')] |
|---|
| 283 | else: |
|---|
| 284 | arch_match = [pkg for pkg in self.installed[entry.get('name')] \ |
|---|
| 285 | if pkg.get('arch', None) == inst.get('arch', None)] |
|---|
| 286 | |
|---|
| 287 | if len(arch_match) > 1: |
|---|
| 288 | self.logger.error("Multiple instances of package %s installed with the same achitecture." % \ |
|---|
| 289 | (entry.get('name'))) |
|---|
| 290 | elif len(arch_match) == 1: |
|---|
| 291 | # There is only one installed like there should be. |
|---|
| 292 | # Check that it is the right version. |
|---|
| 293 | for pkg in arch_match: |
|---|
| 294 | if inst.get('version') == 'any' or self.pkg_vr_equal(inst, pkg) or \ |
|---|
| 295 | self.inst_evra_equal(inst, pkg): |
|---|
| 296 | self.logger.debug(" %s" % self.str_evra(inst)) |
|---|
| 297 | self.instance_status[inst]['installed'] = True |
|---|
| 298 | |
|---|
| 299 | if self.pkg_verify == 'true' and \ |
|---|
| 300 | inst.get('pkg_verify', 'true') == 'true': |
|---|
| 301 | flags = inst.get('verify_flags', '').split(',') + self.verify_flags |
|---|
| 302 | if pkg.get('gpgkeyid', '')[-8:] not in self.gpg_keyids and \ |
|---|
| 303 | 'nosignature' not in flags: |
|---|
| 304 | flags += ['nosignature', 'nodigest'] |
|---|
| 305 | self.logger.info('WARNING: Package %s %s requires GPG Public key with ID %s'\ |
|---|
| 306 | % (pkg.get('name'), self.str_evra(pkg), \ |
|---|
| 307 | pkg.get('gpgkeyid', ''))) |
|---|
| 308 | self.logger.info(' Disabling signature check.') |
|---|
| 309 | |
|---|
| 310 | if self.setup.get('quick', False): |
|---|
| 311 | if rpmtools.prelink_exists: |
|---|
| 312 | flags += ['nomd5', 'nosize'] |
|---|
| 313 | else: |
|---|
| 314 | flags += ['nomd5'] |
|---|
| 315 | self.logger.debug(" verify_flags = %s" % flags) |
|---|
| 316 | |
|---|
| 317 | if inst.get('verify', 'true') == 'false': |
|---|
| 318 | self.instance_status[inst]['verify'] = None |
|---|
| 319 | else: |
|---|
| 320 | vp_ts = rpmtools.rpmtransactionset() |
|---|
| 321 | self.instance_status[inst]['verify'] = \ |
|---|
| 322 | rpmtools.rpm_verify( vp_ts, pkg, flags ) |
|---|
| 323 | vp_ts.closeDB() |
|---|
| 324 | del vp_ts |
|---|
| 325 | |
|---|
| 326 | else: |
|---|
| 327 | # Wrong version installed. |
|---|
| 328 | self.instance_status[inst]['version_fail'] = True |
|---|
| 329 | self.logger.info(" Wrong version installed. Want %s, but have %s"\ |
|---|
| 330 | % (self.str_evra(inst), self.str_evra(pkg))) |
|---|
| 331 | |
|---|
| 332 | qtext_versions = qtext_versions + 'U(%s -> %s) ' % \ |
|---|
| 333 | (self.str_evra(pkg), self.str_evra(inst)) |
|---|
| 334 | elif len(arch_match) == 0: |
|---|
| 335 | # This instance is not installed. |
|---|
| 336 | self.instance_status[inst]['installed'] = False |
|---|
| 337 | self.logger.info(" %s is not installed." % self.str_evra(inst)) |
|---|
| 338 | qtext_versions = qtext_versions + 'I(%s) ' % self.str_evra(inst) |
|---|
| 339 | |
|---|
| 340 | # Check the rpm verify results. |
|---|
| 341 | for inst in instances: |
|---|
| 342 | instance_fail = False |
|---|
| 343 | # Dump the rpm verify results. |
|---|
| 344 | #****Write something to format this nicely.***** |
|---|
| 345 | if self.setup['debug'] and self.instance_status[inst].get('verify', None): |
|---|
| 346 | self.logger.debug(self.instance_status[inst]['verify']) |
|---|
| 347 | |
|---|
| 348 | self.instance_status[inst]['verify_fail'] = False |
|---|
| 349 | if self.instance_status[inst].get('verify', None): |
|---|
| 350 | if len(self.instance_status[inst].get('verify')) > 1: |
|---|
| 351 | self.logger.info("WARNING: Verification of more than one package instance.") |
|---|
| 352 | |
|---|
| 353 | for result in self.instance_status[inst]['verify']: |
|---|
| 354 | |
|---|
| 355 | # Check header results |
|---|
| 356 | if result.get('hdr', None): |
|---|
| 357 | instance_fail = True |
|---|
| 358 | self.instance_status[inst]['verify_fail'] = True |
|---|
| 359 | |
|---|
| 360 | # Check dependency results |
|---|
| 361 | if result.get('deps', None): |
|---|
| 362 | instance_fail = True |
|---|
| 363 | self.instance_status[inst]['verify_fail'] = True |
|---|
| 364 | |
|---|
| 365 | # Check the rpm verify file results against the modlist |
|---|
| 366 | # and per Instance Ignores. |
|---|
| 367 | for file_result in result.get('files', []): |
|---|
| 368 | if file_result[-1] not in modlist + \ |
|---|
| 369 | [ignore.get('name') for ignore \ |
|---|
| 370 | in inst.findall('Ignore')]: |
|---|
| 371 | instance_fail = True |
|---|
| 372 | self.instance_status[inst]['verify_fail'] = True |
|---|
| 373 | else: |
|---|
| 374 | self.logger.debug(" Modlist/Ignore match: %s" % \ |
|---|
| 375 | (file_result[-1])) |
|---|
| 376 | |
|---|
| 377 | if instance_fail == True: |
|---|
| 378 | self.logger.debug("*** Instance %s failed RPM verification ***" % \ |
|---|
| 379 | self.str_evra(inst)) |
|---|
| 380 | qtext_versions = qtext_versions + 'R(%s) ' % self.str_evra(inst) |
|---|
| 381 | self.modlists[entry] = modlist |
|---|
| 382 | |
|---|
| 383 | # Attach status structure for return to server for reporting. |
|---|
| 384 | inst.set('verify_status', str(self.instance_status[inst])) |
|---|
| 385 | |
|---|
| 386 | if self.instance_status[inst]['installed'] == False or \ |
|---|
| 387 | self.instance_status[inst].get('version_fail', False)== True or \ |
|---|
| 388 | self.instance_status[inst].get('verify_fail', False) == True: |
|---|
| 389 | package_fail = True |
|---|
| 390 | self.instance_status[inst]['pkg'] = entry |
|---|
| 391 | self.modlists[entry] = modlist |
|---|
| 392 | |
|---|
| 393 | # Find Installed Instances that are not in the Config. |
|---|
| 394 | extra_installed = self.FindExtraInstances(entry, self.installed[entry.get('name')]) |
|---|
| 395 | if extra_installed != None: |
|---|
| 396 | package_fail = True |
|---|
| 397 | self.extra_instances.append(extra_installed) |
|---|
| 398 | for inst in extra_installed.findall('Instance'): |
|---|
| 399 | qtext_versions = qtext_versions + 'D(%s) ' % self.str_evra(inst) |
|---|
| 400 | self.logger.debug("Found Extra Instances %s" % qtext_versions) |
|---|
| 401 | |
|---|
| 402 | if package_fail == True: |
|---|
| 403 | self.logger.info(" Package %s failed verification." % \ |
|---|
| 404 | (entry.get('name'))) |
|---|
| 405 | qtext = 'Install/Upgrade/delete Package %s instance(s) - %s (y/N) ' % \ |
|---|
| 406 | (entry.get('name'), qtext_versions) |
|---|
| 407 | entry.set('qtext', qtext) |
|---|
| 408 | |
|---|
| 409 | bcfg2_versions = '' |
|---|
| 410 | for bcfg2_inst in [inst for inst in instances if inst.tag == 'Instance']: |
|---|
| 411 | bcfg2_versions = bcfg2_versions + '(%s) ' % self.str_evra(bcfg2_inst) |
|---|
| 412 | if bcfg2_versions != '': |
|---|
| 413 | entry.set('version', bcfg2_versions) |
|---|
| 414 | installed_versions = '' |
|---|
| 415 | |
|---|
| 416 | for installed_inst in self.installed[entry.get('name')]: |
|---|
| 417 | installed_versions = installed_versions + '(%s) ' % \ |
|---|
| 418 | self.str_evra(installed_inst) |
|---|
| 419 | |
|---|
| 420 | entry.set('current_version', installed_versions) |
|---|
| 421 | return False |
|---|
| 422 | |
|---|
| 423 | else: |
|---|
| 424 | # There are no Instances of this package installed. |
|---|
| 425 | self.logger.debug("Package %s has no instances installed" % (entry.get('name'))) |
|---|
| 426 | entry.set('current_exists', 'false') |
|---|
| 427 | bcfg2_versions = '' |
|---|
| 428 | for inst in instances: |
|---|
| 429 | qtext_versions = qtext_versions + 'I(%s) ' % self.str_evra(inst) |
|---|
| 430 | self.instance_status.setdefault(inst, {})['installed'] = False |
|---|
| 431 | self.modlists[entry] = modlist |
|---|
| 432 | self.instance_status[inst]['pkg'] = entry |
|---|
| 433 | if inst.tag == 'Instance': |
|---|
| 434 | bcfg2_versions = bcfg2_versions + '(%s) ' % self.str_evra(inst) |
|---|
| 435 | if bcfg2_versions != '': |
|---|
| 436 | entry.set('version', bcfg2_versions) |
|---|
| 437 | entry.set('qtext', "Install Package %s Instance(s) %s? (y/N) " % \ |
|---|
| 438 | (entry.get('name'), qtext_versions)) |
|---|
| 439 | |
|---|
| 440 | return False |
|---|
| 441 | return True |
|---|
| 442 | |
|---|
| 443 | def RemovePackages(self, packages): |
|---|
| 444 | ''' |
|---|
| 445 | Remove specified entries. |
|---|
| 446 | |
|---|
| 447 | packages is a list of Package Entries with Instances generated |
|---|
| 448 | by FindExtraPackages(). |
|---|
| 449 | ''' |
|---|
| 450 | self.logger.debug('Running RPMng.RemovePackages()') |
|---|
| 451 | |
|---|
| 452 | pkgspec_list = [] |
|---|
| 453 | for pkg in packages: |
|---|
| 454 | for inst in pkg: |
|---|
| 455 | if pkg.get('name') != 'gpg-pubkey': |
|---|
| 456 | pkgspec = { 'name':pkg.get('name'), |
|---|
| 457 | 'epoch':inst.get('epoch', None), |
|---|
| 458 | 'version':inst.get('version'), |
|---|
| 459 | 'release':inst.get('release'), |
|---|
| 460 | 'arch':inst.get('arch') } |
|---|
| 461 | pkgspec_list.append(pkgspec) |
|---|
| 462 | else: |
|---|
| 463 | pkgspec = { 'name':pkg.get('name'), |
|---|
| 464 | 'version':inst.get('version'), |
|---|
| 465 | 'release':inst.get('release')} |
|---|
| 466 | self.logger.info("WARNING: gpg-pubkey package not in configuration %s %s"\ |
|---|
| 467 | % (pkgspec.get('name'), self.str_evra(pkgspec))) |
|---|
| 468 | self.logger.info(" This package will be deleted in a future version of the RPMng driver.") |
|---|
| 469 | #pkgspec_list.append(pkg_spec) |
|---|
| 470 | |
|---|
| 471 | erase_results = rpmtools.rpm_erase(pkgspec_list, self.erase_flags) |
|---|
| 472 | if erase_results == []: |
|---|
| 473 | self.modified += packages |
|---|
| 474 | for pkg in pkgspec_list: |
|---|
| 475 | self.logger.info("Deleted %s %s" % (pkg.get('name'), self.str_evra(pkg))) |
|---|
| 476 | else: |
|---|
| 477 | self.logger.info("Bulk erase failed with errors:") |
|---|
| 478 | self.logger.debug("Erase results = %s" % erase_results) |
|---|
| 479 | self.logger.info("Attempting individual erase for each package.") |
|---|
| 480 | pkgspec_list = [] |
|---|
| 481 | for pkg in packages: |
|---|
| 482 | pkg_modified = False |
|---|
| 483 | for inst in pkg: |
|---|
| 484 | if pkg.get('name') != 'gpg-pubkey': |
|---|
| 485 | pkgspec = { 'name':pkg.get('name'), |
|---|
| 486 | 'epoch':inst.get('epoch', None), |
|---|
| 487 | 'version':inst.get('version'), |
|---|
| 488 | 'release':inst.get('release'), |
|---|
| 489 | 'arch':inst.get('arch') } |
|---|
| 490 | pkgspec_list.append(pkgspec) |
|---|
| 491 | else: |
|---|
| 492 | pkgspec = { 'name':pkg.get('name'), |
|---|
| 493 | 'version':inst.get('version'), |
|---|
| 494 | 'release':inst.get('release')} |
|---|
| 495 | self.logger.info("WARNING: gpg-pubkey package not in configuration %s %s"\ |
|---|
| 496 | % (pkgspec.get('name'), self.str_evra(pkgspec))) |
|---|
| 497 | self.logger.info(" This package will be deleted in a future version of the RPMng driver.") |
|---|
| 498 | continue # Don't delete the gpg-pubkey packages for now. |
|---|
| 499 | erase_results = rpmtools.rpm_erase([pkgspec], self.erase_flags) |
|---|
| 500 | if erase_results == []: |
|---|
| 501 | pkg_modified = True |
|---|
| 502 | self.logger.info("Deleted %s %s" % \ |
|---|
| 503 | (pkgspec.get('name'), self.str_evra(pkgspec))) |
|---|
| 504 | else: |
|---|
| 505 | self.logger.error("unable to delete %s %s" % \ |
|---|
| 506 | (pkgspec.get('name'), self.str_evra(pkgspec))) |
|---|
| 507 | self.logger.debug("Failure = %s" % erase_results) |
|---|
| 508 | if pkg_modified == True: |
|---|
| 509 | self.modified.append(pkg) |
|---|
| 510 | |
|---|
| 511 | self.RefreshPackages() |
|---|
| 512 | self.extra = self.FindExtraPackages() |
|---|
| 513 | |
|---|
| 514 | def FixInstance(self, instance, inst_status): |
|---|
| 515 | ''' |
|---|
| 516 | Control if a reinstall of a package happens or not based on the |
|---|
| 517 | results from RPMng.VerifyPackage(). |
|---|
| 518 | |
|---|
| 519 | Return True to reinstall, False to not reintstall. |
|---|
| 520 | ''' |
|---|
| 521 | fix = False |
|---|
| 522 | |
|---|
| 523 | if inst_status.get('installed', False) == False: |
|---|
| 524 | if instance.get('installed_action', 'install') == "install" and \ |
|---|
| 525 | self.installed_action == "install": |
|---|
| 526 | fix = True |
|---|
| 527 | else: |
|---|
| 528 | self.logger.debug('Installed Action for %s %s is to not install' % \ |
|---|
| 529 | (inst_status.get('pkg').get('name'), |
|---|
| 530 | self.str_evra(instance))) |
|---|
| 531 | |
|---|
| 532 | elif inst_status.get('version_fail', False) == True: |
|---|
| 533 | if instance.get('version_fail_action', 'upgrade') == "upgrade" and \ |
|---|
| 534 | self.version_fail_action == "upgrade": |
|---|
| 535 | fix = True |
|---|
| 536 | else: |
|---|
| 537 | self.logger.debug('Version Fail Action for %s %s is to not upgrade' % \ |
|---|
| 538 | (inst_status.get('pkg').get('name'), |
|---|
| 539 | self.str_evra(instance))) |
|---|
| 540 | |
|---|
| 541 | elif inst_status.get('verify_fail', False) == True and self.name == "RPMng": |
|---|
| 542 | # yum can't reinstall packages so only do this for rpm. |
|---|
| 543 | if instance.get('verify_fail_action', 'reinstall') == "reinstall" and \ |
|---|
| 544 | self.verify_fail_action == "reinstall": |
|---|
| 545 | for inst in inst_status.get('verify'): |
|---|
| 546 | # This needs to be a for loop rather than a straight get() |
|---|
| 547 | # because the underlying routines handle multiple packages |
|---|
| 548 | # and return a list of results. |
|---|
| 549 | self.logger.debug('reinstall_check: %s %s:%s-%s.%s' % inst.get('nevra')) |
|---|
| 550 | |
|---|
| 551 | if inst.get("hdr", False): |
|---|
| 552 | fix = True |
|---|
| 553 | |
|---|
| 554 | elif inst.get('files', False): |
|---|
| 555 | # Parse rpm verify file results |
|---|
| 556 | for file_result in inst.get('files', []): |
|---|
| 557 | self.logger.debug('reinstall_check: file: %s' % file_result) |
|---|
| 558 | if file_result[-2] != 'c': |
|---|
| 559 | fix = True |
|---|
| 560 | break |
|---|
| 561 | |
|---|
| 562 | # Shouldn't really need this, but included for clarity. |
|---|
| 563 | elif inst.get("deps", False): |
|---|
| 564 | fix = False |
|---|
| 565 | else: |
|---|
| 566 | self.logger.debug('Verify Fail Action for %s %s is to not reinstall' % \ |
|---|
| 567 | (inst_status.get('pkg').get('name'), |
|---|
| 568 | self.str_evra(instance))) |
|---|
| 569 | |
|---|
| 570 | return fix |
|---|
| 571 | |
|---|
| 572 | def Install(self, packages, states): |
|---|
| 573 | ''' |
|---|
| 574 | Try and fix everything that RPMng.VerifyPackages() found wrong for |
|---|
| 575 | each Package Entry. This can result in individual RPMs being |
|---|
| 576 | installed (for the first time), reinstalled, deleted, downgraded |
|---|
| 577 | or upgraded. |
|---|
| 578 | |
|---|
| 579 | packages is a list of Package Elements that has |
|---|
| 580 | states[<Package Element>] == False |
|---|
| 581 | |
|---|
| 582 | The following effects occur: |
|---|
| 583 | - states{} is conditionally updated for each package. |
|---|
| 584 | - self.installed{} is rebuilt, possibly multiple times. |
|---|
| 585 | - self.instance_statusi{} is conditionally updated for each instance |
|---|
| 586 | of a package. |
|---|
| 587 | - Each package will be added to self.modified[] if its states{} |
|---|
| 588 | entry is set to True. |
|---|
| 589 | ''' |
|---|
| 590 | self.logger.info('Runing RPMng.Install()') |
|---|
| 591 | |
|---|
| 592 | install_only_pkgs = [] |
|---|
| 593 | gpg_keys = [] |
|---|
| 594 | upgrade_pkgs = [] |
|---|
| 595 | |
|---|
| 596 | # Remove extra instances. |
|---|
| 597 | # Can not reverify because we don't have a package entry. |
|---|
| 598 | if len(self.extra_instances) > 0: |
|---|
| 599 | if (self.setup.get('remove') == 'all' or \ |
|---|
| 600 | self.setup.get('remove') == 'packages') and\ |
|---|
| 601 | not self.setup.get('dryrun'): |
|---|
| 602 | self.RemovePackages(self.extra_instances) |
|---|
| 603 | else: |
|---|
| 604 | self.logger.info("The following extra package instances will be removed by the '-r' option:") |
|---|
| 605 | for pkg in self.extra_instances: |
|---|
| 606 | for inst in pkg: |
|---|
| 607 | self.logger.info(" %s %s" % (pkg.get('name'), self.str_evra(inst))) |
|---|
| 608 | |
|---|
| 609 | # Figure out which instances of the packages actually need something |
|---|
| 610 | # doing to them and place in the appropriate work 'queue'. |
|---|
| 611 | for pkg in packages: |
|---|
| 612 | for inst in [instn for instn in pkg if instn.tag \ |
|---|
| 613 | in ['Instance', 'Package']]: |
|---|
| 614 | if self.FixInstance(inst, self.instance_status[inst]): |
|---|
| 615 | if pkg.get('name') == 'gpg-pubkey': |
|---|
| 616 | gpg_keys.append(inst) |
|---|
| 617 | elif pkg.get('name') in self.installOnlyPkgs: |
|---|
| 618 | install_only_pkgs.append(inst) |
|---|
| 619 | else: |
|---|
| 620 | upgrade_pkgs.append(inst) |
|---|
| 621 | |
|---|
| 622 | # Fix installOnlyPackages |
|---|
| 623 | if len(install_only_pkgs) > 0: |
|---|
| 624 | self.logger.info("Attempting to install 'install only packages'") |
|---|
| 625 | install_args = " ".join([os.path.join(self.instance_status[inst].get('pkg').get('uri'), \ |
|---|
| 626 | inst.get('simplefile')) \ |
|---|
| 627 | for inst in install_only_pkgs]) |
|---|
| 628 | self.logger.debug("rpm --install --quiet --oldpackage %s" % install_args) |
|---|
| 629 | cmdrc, output = self.cmd.run("rpm --install --quiet --oldpackage --replacepkgs %s" % \ |
|---|
| 630 | install_args) |
|---|
| 631 | if cmdrc == 0: |
|---|
| 632 | # The rpm command succeeded. All packages installed. |
|---|
| 633 | self.logger.info("Single Pass for InstallOnlyPkgs Succeded") |
|---|
| 634 | self.RefreshPackages() |
|---|
| 635 | |
|---|
| 636 | else: |
|---|
| 637 | # The rpm command failed. No packages installed. |
|---|
| 638 | # Try installing instances individually. |
|---|
| 639 | self.logger.error("Single Pass for InstallOnlyPackages Failed") |
|---|
| 640 | installed_instances = [] |
|---|
| 641 | for inst in install_only_pkgs: |
|---|
| 642 | install_args = os.path.join(self.instance_status[inst].get('pkg').get('uri'), \ |
|---|
| 643 | inst.get('simplefile')) |
|---|
| 644 | self.logger.debug("rpm --install --quiet --oldpackage %s" % install_args) |
|---|
| 645 | cmdrc, output = self.cmd.run("rpm --install --quiet --oldpackage --replacepkgs %s" % \ |
|---|
| 646 | install_args) |
|---|
| 647 | if cmdrc == 0: |
|---|
| 648 | installed_instances.append(inst) |
|---|
| 649 | else: |
|---|
| 650 | self.logger.debug("InstallOnlyPackage %s %s would not install." % \ |
|---|
| 651 | (self.instance_status[inst].get('pkg').get('name'), \ |
|---|
| 652 | self.str_evra(inst))) |
|---|
| 653 | |
|---|
| 654 | install_pkg_set = set([self.instance_status[inst].get('pkg') \ |
|---|
| 655 | for inst in install_only_pkgs]) |
|---|
| 656 | self.RefreshPackages() |
|---|
| 657 | |
|---|
| 658 | # Install GPG keys. |
|---|
| 659 | if len(gpg_keys) > 0: |
|---|
| 660 | for inst in gpg_keys: |
|---|
| 661 | self.logger.info("Installing GPG keys.") |
|---|
| 662 | key_arg = os.path.join(self.instance_status[inst].get('pkg').get('uri'), \ |
|---|
| 663 | inst.get('simplefile')) |
|---|
| 664 | cmdrc, output = self.cmd.run("rpm --import %s" % key_arg) |
|---|
| 665 | if cmdrc != 0: |
|---|
| 666 | self.logger.debug("Unable to install %s-%s" % \ |
|---|
| 667 | (self.instance_status[inst].get('pkg').get('name'), \ |
|---|
| 668 | self.str_evra(inst))) |
|---|
| 669 | else: |
|---|
| 670 | self.logger.debug("Installed %s-%s-%s" % \ |
|---|
| 671 | (self.instance_status[inst].get('pkg').get('name'), \ |
|---|
| 672 | inst.get('version'), inst.get('release'))) |
|---|
| 673 | self.RefreshPackages() |
|---|
| 674 | self.gpg_keyids = self.getinstalledgpg() |
|---|
| 675 | pkg = self.instance_status[gpg_keys[0]].get('pkg') |
|---|
| 676 | states[pkg] = self.VerifyPackage(pkg, []) |
|---|
| 677 | |
|---|
| 678 | # Fix upgradeable packages. |
|---|
| 679 | if len(upgrade_pkgs) > 0: |
|---|
| 680 | self.logger.info("Attempting to upgrade packages") |
|---|
| 681 | upgrade_args = " ".join([os.path.join(self.instance_status[inst].get('pkg').get('uri'), \ |
|---|
| 682 | inst.get('simplefile')) \ |
|---|
| 683 | for inst in upgrade_pkgs]) |
|---|
| 684 | cmdrc, output = self.cmd.run("rpm --upgrade --quiet --oldpackage --replacepkgs %s" % \ |
|---|
| 685 | upgrade_args) |
|---|
| 686 | if cmdrc == 0: |
|---|
| 687 | # The rpm command succeeded. All packages upgraded. |
|---|
| 688 | self.logger.info("Single Pass for Upgraded Packages Succeded") |
|---|
| 689 | upgrade_pkg_set = set([self.instance_status[inst].get('pkg') \ |
|---|
| 690 | for inst in upgrade_pkgs]) |
|---|
| 691 | self.RefreshPackages() |
|---|
| 692 | else: |
|---|
| 693 | # The rpm command failed. No packages upgraded. |
|---|
| 694 | # Try upgrading instances individually. |
|---|
| 695 | self.logger.error("Single Pass for Upgrading Packages Failed") |
|---|
| 696 | upgraded_instances = [] |
|---|
| 697 | for inst in upgrade_pkgs: |
|---|
| 698 | upgrade_args = os.path.join(self.instance_status[inst].get('pkg').get('uri'), \ |
|---|
| 699 | inst.get('simplefile')) |
|---|
| 700 | #self.logger.debug("rpm --upgrade --quiet --oldpackage --replacepkgs %s" % \ |
|---|
| 701 | # upgrade_args) |
|---|
| 702 | cmdrc, output = self.cmd.run("rpm --upgrade --quiet --oldpackage --replacepkgs %s" % upgrade_args) |
|---|
| 703 | if cmdrc == 0: |
|---|
| 704 | upgraded_instances.append(inst) |
|---|
| 705 | else: |
|---|
| 706 | self.logger.debug("Package %s %s would not upgrade." % \ |
|---|
| 707 | (self.instance_status[inst].get('pkg').get('name'), \ |
|---|
| 708 | self.str_evra(inst))) |
|---|
| 709 | |
|---|
| 710 | upgrade_pkg_set = set([self.instance_status[inst].get('pkg') \ |
|---|
| 711 | for inst in upgrade_pkgs]) |
|---|
| 712 | self.RefreshPackages() |
|---|
| 713 | |
|---|
| 714 | if not self.setup['kevlar']: |
|---|
| 715 | for pkg_entry in packages: |
|---|
| 716 | self.logger.debug("Reverifying Failed Package %s" % (pkg_entry.get('name'))) |
|---|
| 717 | states[pkg_entry] = self.VerifyPackage(pkg_entry, \ |
|---|
| 718 | self.modlists.get(pkg_entry, [])) |
|---|
| 719 | |
|---|
| 720 | for entry in [ent for ent in packages if states[ent]]: |
|---|
| 721 | self.modified.append(entry) |
|---|
| 722 | |
|---|
| 723 | def canInstall(self, entry): |
|---|
| 724 | ''' |
|---|
| 725 | test if entry has enough information to be installed |
|---|
| 726 | ''' |
|---|
| 727 | if not self.handlesEntry(entry): |
|---|
| 728 | return False |
|---|
| 729 | |
|---|
| 730 | if 'failure' in entry.attrib: |
|---|
| 731 | self.logger.error("Cannot install entry %s:%s with bind failure" % \ |
|---|
| 732 | (entry.tag, entry.get('name'))) |
|---|
| 733 | return False |
|---|
| 734 | |
|---|
| 735 | |
|---|
| 736 | instances = entry.findall('Instance') |
|---|
| 737 | |
|---|
| 738 | # If the entry wasn't verifiable, then we really don't want to try and fix something |
|---|
| 739 | # that we don't know is broken. |
|---|
| 740 | if not self.canVerify(entry): |
|---|
| 741 | self.logger.debug("WARNING: Package %s was not verifiable, not passing to Install()" \ |
|---|
| 742 | % entry.get('name')) |
|---|
| 743 | return False |
|---|
| 744 | |
|---|
| 745 | if not instances: |
|---|
| 746 | # Old non Instance format, unmodified. |
|---|
| 747 | if entry.get('name') == 'gpg-pubkey': |
|---|
| 748 | # gpg-pubkey packages aren't really pacakges, so we have to do |
|---|
| 749 | # something a little different. |
|---|
| 750 | # Check that the Package Level has what we need for verification. |
|---|
| 751 | if [attr for attr in self.__gpg_ireq__[entry.tag] if attr not in entry.attrib]: |
|---|
| 752 | self.logger.error("Incomplete information for entry %s:%s; cannot install" \ |
|---|
| 753 | % (entry.tag, entry.get('name'))) |
|---|
| 754 | return False |
|---|
| 755 | else: |
|---|
| 756 | if [attr for attr in self.__ireq__[entry.tag] if attr not in entry.attrib]: |
|---|
| 757 | self.logger.error("Incomplete information for entry %s:%s; cannot install" \ |
|---|
| 758 | % (entry.tag, entry.get('name'))) |
|---|
| 759 | return False |
|---|
| 760 | else: |
|---|
| 761 | if entry.get('name') == 'gpg-pubkey': |
|---|
| 762 | # gpg-pubkey packages aren't really pacakges, so we have to do |
|---|
| 763 | # something a little different. |
|---|
| 764 | # Check that the Package Level has what we need for verification. |
|---|
| 765 | if [attr for attr in self.__new_gpg_ireq__[entry.tag] if attr not in entry.attrib]: |
|---|
| 766 | self.logger.error("Incomplete information for entry %s:%s; cannot install" \ |
|---|
| 767 | % (entry.tag, entry.get('name'))) |
|---|
| 768 | return False |
|---|
| 769 | # Check that the Instance Level has what we need for verification. |
|---|
| 770 | for inst in instances: |
|---|
| 771 | if [attr for attr in self.__new_gpg_ireq__[inst.tag] \ |
|---|
| 772 | if attr not in inst.attrib]: |
|---|
| 773 | self.logger.error("Incomplete information for entry %s:%s; cannot install"\ |
|---|
| 774 | % (inst.tag, entry.get('name'))) |
|---|
| 775 | return False |
|---|
| 776 | else: |
|---|
| 777 | # New format with Instances. |
|---|
| 778 | # Check that the Package Level has what we need for verification. |
|---|
| 779 | if [attr for attr in self.__new_ireq__[entry.tag] if attr not in entry.attrib]: |
|---|
| 780 | self.logger.error("Incomplete information for entry %s:%s; cannot install" \ |
|---|
| 781 | % (entry.tag, entry.get('name'))) |
|---|
| 782 | self.logger.error(" Required attributes that may not be present are %s" \ |
|---|
| 783 | % (self.__new_ireq__[entry.tag])) |
|---|
| 784 | return False |
|---|
| 785 | # Check that the Instance Level has what we need for verification. |
|---|
| 786 | for inst in instances: |
|---|
| 787 | if inst.tag == 'Instance': |
|---|
| 788 | if [attr for attr in self.__new_ireq__[inst.tag] \ |
|---|
| 789 | if attr not in inst.attrib]: |
|---|
| 790 | self.logger.error("Incomplete information for %s of package %s; cannot install" \ |
|---|
| 791 | % (inst.tag, entry.get('name'))) |
|---|
| 792 | self.logger.error(" Required attributes that may not be present are %s" \ |
|---|
| 793 | % (self.__new_ireq__[inst.tag])) |
|---|
| 794 | return False |
|---|
| 795 | return True |
|---|
| 796 | |
|---|
| 797 | def canVerify(self, entry): |
|---|
| 798 | ''' |
|---|
| 799 | Test if entry has enough information to be verified. |
|---|
| 800 | |
|---|
| 801 | Three types of entries are checked. |
|---|
| 802 | Old style Package |
|---|
| 803 | New style Package with Instances |
|---|
| 804 | pgp-pubkey packages |
|---|
| 805 | |
|---|
| 806 | Also the old style entries get modified after the first |
|---|
| 807 | VerifyPackage() run, so there needs to be a second test. |
|---|
| 808 | ''' |
|---|
| 809 | if not self.handlesEntry(entry): |
|---|
| 810 | return False |
|---|
| 811 | |
|---|
| 812 | if 'failure' in entry.attrib: |
|---|
| 813 | self.logger.error("Entry %s:%s reports bind failure: %s" % \ |
|---|
| 814 | (entry.tag, entry.get('name'), entry.get('failure'))) |
|---|
| 815 | return False |
|---|
| 816 | |
|---|
| 817 | # We don't want to do any checks so we don't care what the entry has in it. |
|---|
| 818 | if self.pkg_checks == 'false' or \ |
|---|
| 819 | entry.get('pkg_checks', 'true').lower() == 'false': |
|---|
| 820 | return True |
|---|
| 821 | |
|---|
| 822 | instances = entry.findall('Instance') |
|---|
| 823 | |
|---|
| 824 | if not instances: |
|---|
| 825 | # Old non Instance format, unmodified. |
|---|
| 826 | if entry.get('name') == 'gpg-pubkey': |
|---|
| 827 | # gpg-pubkey packages aren't really pacakges, so we have to do |
|---|
| 828 | # something a little different. |
|---|
| 829 | # Check that the Package Level has what we need for verification. |
|---|
| 830 | if [attr for attr in self.__gpg_req__[entry.tag] if attr not in entry.attrib]: |
|---|
| 831 | self.logger.error("Incomplete information for entry %s:%s; cannot verify" \ |
|---|
| 832 | % (entry.tag, entry.get('name'))) |
|---|
| 833 | return False |
|---|
| 834 | else: |
|---|
| 835 | if [attr for attr in self.__req__[entry.tag] if attr not in entry.attrib]: |
|---|
| 836 | self.logger.error("Incomplete information for entry %s:%s; cannot verify" \ |
|---|
| 837 | % (entry.tag, entry.get('name'))) |
|---|
| 838 | return False |
|---|
| 839 | else: |
|---|
| 840 | if entry.get('name') == 'gpg-pubkey': |
|---|
| 841 | # gpg-pubkey packages aren't really pacakges, so we have to do |
|---|
| 842 | # something a little different. |
|---|
| 843 | # Check that the Package Level has what we need for verification. |
|---|
| 844 | if [attr for attr in self.__new_gpg_req__[entry.tag] if attr not in entry.attrib]: |
|---|
| 845 | self.logger.error("Incomplete information for entry %s:%s; cannot verify" \ |
|---|
| 846 | % (entry.tag, entry.get('name'))) |
|---|
| 847 | return False |
|---|
| 848 | # Check that the Instance Level has what we need for verification. |
|---|
| 849 | for inst in instances: |
|---|
| 850 | if [attr for attr in self.__new_gpg_req__[inst.tag] \ |
|---|
| 851 | if attr not in inst.attrib]: |
|---|
| 852 | self.logger.error("Incomplete information for entry %s:%s; cannot verify" \ |
|---|
| 853 | % (inst.tag, inst.get('name'))) |
|---|
| 854 | return False |
|---|
| 855 | else: |
|---|
| 856 | # New format with Instances, or old style modified. |
|---|
| 857 | # Check that the Package Level has what we need for verification. |
|---|
| 858 | if [attr for attr in self.__new_req__[entry.tag] if attr not in entry.attrib]: |
|---|
| 859 | self.logger.error("Incomplete information for entry %s:%s; cannot verify" \ |
|---|
| 860 | % (entry.tag, entry.get('name'))) |
|---|
| 861 | return False |
|---|
| 862 | # Check that the Instance Level has what we need for verification. |
|---|
| 863 | for inst in instances: |
|---|
| 864 | if inst.tag == 'Instance': |
|---|
| 865 | if [attr for attr in self.__new_req__[inst.tag] \ |
|---|
| 866 | if attr not in inst.attrib]: |
|---|
| 867 | self.logger.error("Incomplete information for entry %s:%s; cannot verify" \ |
|---|
| 868 | % (inst.tag, inst.get('name'))) |
|---|
| 869 | return False |
|---|
| 870 | return True |
|---|
| 871 | |
|---|
| 872 | def FindExtraPackages(self): |
|---|
| 873 | ''' |
|---|
| 874 | Find extra packages |
|---|
| 875 | ''' |
|---|
| 876 | packages = [entry.get('name') for entry in self.getSupportedEntries()] |
|---|
| 877 | extras = [] |
|---|
| 878 | |
|---|
| 879 | for (name, instances) in list(self.installed.items()): |
|---|
| 880 | if name not in packages: |
|---|
| 881 | extra_entry = Bcfg2.Client.XML.Element('Package', name=name, type=self.pkgtype) |
|---|
| 882 | for installed_inst in instances: |
|---|
| 883 | if self.setup['extra']: |
|---|
| 884 | self.logger.info("Extra Package %s %s." % \ |
|---|
| 885 | (name, self.str_evra(installed_inst))) |
|---|
| 886 | tmp_entry = Bcfg2.Client.XML.SubElement(extra_entry, 'Instance', \ |
|---|
| 887 | version = installed_inst.get('version'), \ |
|---|
| 888 | release = installed_inst.get('release')) |
|---|
| 889 | if installed_inst.get('epoch', None) != None: |
|---|
| 890 | tmp_entry.set('epoch', str(installed_inst.get('epoch'))) |
|---|
| 891 | if installed_inst.get('arch', None) != None: |
|---|
| 892 | tmp_entry.set('arch', installed_inst.get('arch')) |
|---|
| 893 | extras.append(extra_entry) |
|---|
| 894 | return extras |
|---|
| 895 | |
|---|
| 896 | |
|---|
| 897 | def FindExtraInstances(self, pkg_entry, installed_entry): |
|---|
| 898 | ''' |
|---|
| 899 | Check for installed instances that are not in the config. |
|---|
| 900 | Return a Package Entry with Instances to remove, or None if there |
|---|
| 901 | are no Instances to remove. |
|---|
| 902 | ''' |
|---|
| 903 | name = pkg_entry.get('name') |
|---|
| 904 | extra_entry = Bcfg2.Client.XML.Element('Package', name=name, type=self.pkgtype) |
|---|
| 905 | instances = [inst for inst in pkg_entry if inst.tag == 'Instance' or inst.tag == 'Package'] |
|---|
| 906 | if name in self.installOnlyPkgs: |
|---|
| 907 | for installed_inst in installed_entry: |
|---|
| 908 | not_found = True |
|---|
| 909 | for inst in instances: |
|---|
| 910 | if self.pkg_vr_equal(inst, installed_inst) or \ |
|---|
| 911 | self.inst_evra_equal(inst, installed_inst): |
|---|
| 912 | not_found = False |
|---|
| 913 | break |
|---|
| 914 | if not_found == True: |
|---|
| 915 | # Extra package. |
|---|
| 916 | self.logger.info("Extra InstallOnlyPackage %s %s." % \ |
|---|
| 917 | (name, self.str_evra(installed_inst))) |
|---|
| 918 | tmp_entry = Bcfg2.Client.XML.SubElement(extra_entry, 'Instance', \ |
|---|
| 919 | version = installed_inst.get('version'), \ |
|---|
| 920 | release = installed_inst.get('release')) |
|---|
| 921 | if installed_inst.get('epoch', None) != None: |
|---|
| 922 | tmp_entry.set('epoch', str(installed_inst.get('epoch'))) |
|---|
| 923 | if installed_inst.get('arch', None) != None: |
|---|
| 924 | tmp_entry.set('arch', installed_inst.get('arch')) |
|---|
| 925 | else: |
|---|
| 926 | # Normal package, only check arch. |
|---|
| 927 | for installed_inst in installed_entry: |
|---|
| 928 | not_found = True |
|---|
| 929 | for inst in instances: |
|---|
| 930 | if installed_inst.get('arch', None) == inst.get('arch', None) or\ |
|---|
| 931 | inst.tag == 'Package': |
|---|
| 932 | not_found = False |
|---|
| 933 | break |
|---|
| 934 | if not_found: |
|---|
| 935 | self.logger.info("Extra Normal Package Instance %s %s" % \ |
|---|
| 936 | (name, self.str_evra(installed_inst))) |
|---|
| 937 | tmp_entry = Bcfg2.Client.XML.SubElement(extra_entry, 'Instance', \ |
|---|
| 938 | version = installed_inst.get('version'), \ |
|---|
| 939 | release = installed_inst.get('release')) |
|---|
| 940 | if installed_inst.get('epoch', None) != None: |
|---|
| 941 | tmp_entry.set('epoch', str(installed_inst.get('epoch'))) |
|---|
| 942 | if installed_inst.get('arch', None) != None: |
|---|
| 943 | tmp_entry.set('arch', installed_inst.get('arch')) |
|---|
| 944 | |
|---|
| 945 | if len(extra_entry) == 0: |
|---|
| 946 | extra_entry = None |
|---|
| 947 | |
|---|
| 948 | return extra_entry |
|---|
| 949 | |
|---|
| 950 | def str_evra(self, instance): |
|---|
| 951 | ''' |
|---|
| 952 | Convert evra dict entries to a string. |
|---|
| 953 | ''' |
|---|
| 954 | if instance.get('epoch', '*') in ['*', None]: |
|---|
| 955 | return '%s-%s.%s' % (instance.get('version', '*'), |
|---|
| 956 | instance.get('release', '*'), |
|---|
| 957 | instance.get('arch', '*')) |
|---|
| 958 | else: |
|---|
| 959 | return '%s:%s-%s.%s' % (instance.get('epoch', '*'), |
|---|
| 960 | instance.get('version', '*'), |
|---|
| 961 | instance.get('release', '*'), |
|---|
| 962 | instance.get('arch', '*')) |
|---|
| 963 | |
|---|
| 964 | def pkg_vr_equal(self, config_entry, installed_entry): |
|---|
| 965 | ''' |
|---|
| 966 | Compare old style entry to installed entry. Which means ignore |
|---|
| 967 | the epoch and arch. |
|---|
| 968 | ''' |
|---|
| 969 | if (config_entry.tag == 'Package' and \ |
|---|
| 970 | config_entry.get('version') == installed_entry.get('version') and \ |
|---|
| 971 | config_entry.get('release') == installed_entry.get('release')): |
|---|
| 972 | return True |
|---|
| 973 | else: |
|---|
| 974 | return False |
|---|
| 975 | |
|---|
| 976 | def inst_evra_equal(self, config_entry, installed_entry): |
|---|
| 977 | ''' |
|---|
| 978 | Compare new style instance to installed entry. |
|---|
| 979 | ''' |
|---|
| 980 | |
|---|
| 981 | if config_entry.get('epoch', None) != None: |
|---|
| 982 | epoch = int(config_entry.get('epoch')) |
|---|
| 983 | else: |
|---|
| 984 | epoch = None |
|---|
| 985 | |
|---|
| 986 | if (config_entry.tag == 'Instance' and \ |
|---|
| 987 | (epoch == installed_entry.get('epoch', 0) or \ |
|---|
| 988 | (epoch == 0 and installed_entry.get('epoch', 0) == None) or \ |
|---|
| 989 | (epoch == None and installed_entry.get('epoch', 0) == 0)) and \ |
|---|
| 990 | config_entry.get('version') == installed_entry.get('version') and \ |
|---|
| 991 | config_entry.get('release') == installed_entry.get('release') and \ |
|---|
| 992 | config_entry.get('arch', None) == installed_entry.get('arch', None)): |
|---|
| 993 | return True |
|---|
| 994 | else: |
|---|
| 995 | return False |
|---|
| 996 | |
|---|
| 997 | def getinstalledgpg(self): |
|---|
| 998 | ''' |
|---|
| 999 | Create a list of installed GPG key IDs. |
|---|
| 1000 | |
|---|
| 1001 | The pgp-pubkey package version is the least significant 4 bytes |
|---|
| 1002 | (big-endian) of the key ID which is good enough for our purposes. |
|---|
| 1003 | ''' |
|---|
| 1004 | init_ts = rpmtools.rpmtransactionset() |
|---|
| 1005 | init_ts.setVSFlags(rpm._RPMVSF_NODIGESTS|rpm._RPMVSF_NOSIGNATURES) |
|---|
| 1006 | gpg_hdrs = rpmtools.getheadersbykeyword(init_ts, **{'name':'gpg-pubkey'}) |
|---|
| 1007 | keyids = [ header[rpm.RPMTAG_VERSION] for header in gpg_hdrs] |
|---|
| 1008 | keyids.append('None') |
|---|
| 1009 | init_ts.closeDB() |
|---|
| 1010 | del init_ts |
|---|
| 1011 | return keyids |
|---|