summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/lib/Client/Tools/APT.py202
1 files changed, 120 insertions, 82 deletions
diff --git a/src/lib/Client/Tools/APT.py b/src/lib/Client/Tools/APT.py
index d73ed06dc..df11c81fc 100644
--- a/src/lib/Client/Tools/APT.py
+++ b/src/lib/Client/Tools/APT.py
@@ -1,11 +1,11 @@
'''This is the bcfg2 support for apt-get'''
__revision__ = '$Revision$'
-import apt_pkg
+import apt.cache
import os, re
import Bcfg2.Client.Tools
-class APT(Bcfg2.Client.Tools.PkgTool):
+class APT(Bcfg2.Client.Tools.Tool):
'''The Debian toolset implements package and service operations and inherits
the rest from Toolset.Toolset'''
__name__ = 'APT'
@@ -17,103 +17,141 @@ class APT(Bcfg2.Client.Tools.PkgTool):
'/etc/apt/apt.conf', '/etc/dpkg/dpkg.cfg']
__handles__ = [('Package', 'deb')]
__req__ = {'Package': ['name', 'version']}
- pkgtype = 'deb'
- pkgtool = ('apt-get '
- '-o DPkg::Options::=--force-overwrite '
- '-o DPkg::Options::=--force-confold '
- '--reinstall '
- '-q=2 '
- '--force-yes '
- '-y install %s',
- ('%s=%s', ['name', 'version']))
+ pkgcmd = 'apt-get ' + \
+ '-o DPkg::Options::=--force-overwrite ' + \
+ '-o DPkg::Options::=--force-confold ' + \
+ '--reinstall ' + \
+ '-q=2 ' + \
+ '--force-yes ' + \
+ '-y install %s'
- svcre = re.compile("/etc/.*/[SK]\d\d(?P<name>\S+)")
-
def __init__(self, logger, cfg, setup):
- Bcfg2.Client.Tools.PkgTool.__init__(self, logger, cfg, setup)
+ Bcfg2.Client.Tools.Tool.__init__(self, logger, cfg, setup)
self.cfg = cfg
os.environ["DEBIAN_FRONTEND"] = 'noninteractive'
- self.updated = False
+ self.pkg_cache = apt.cache.Cache()
+ self.actions = {}
+ if self.setup['kevlar'] and not self.setup['dryrun']:
+ self.cmd.run("dpkg --force-confold --configure --pending")
+ self.cmd.run("apt-get clean")
+ try:
+ self.pkg_cache.update()
+ except:
+ self.logger.error("Failed to update apt cache")
- def RefreshPackages(self):
- '''Refresh memory hashes of packages'''
- apt_pkg.init()
- cache = apt_pkg.GetCache()
- self.installed = {}
- for pkg in cache.Packages:
- if pkg.CurrentVer:
- self.installed[pkg.Name] = pkg.CurrentVer.VerStr
- self.extra = self.FindExtraPackages()
+ def FindExtra(self):
+ '''Find extra packages'''
+ packages = [entry.get('name') for entry in self.getSupportedEntries()]
+ extras = [(p.name, p.installedVersion) for p in self.pkg_cache
+ if p.isInstalled and p.name not in packages]
+ return [Bcfg2.Client.XML.Element('Package', name=name, \
+ type='deb', version=version) \
+ for (name, version) in extras]
+
+ def VerifyDebsums(self, entry, modlist):
+ output = self.cmd.run("/usr/bin/debsums -as %s" % entry.get('name'))[1]
+ if len(output) == 1 and "no md5sums for" in output[0]:
+ self.logger.info("Package %s has no md5sums. Cannot verify" % \
+ entry.get('name'))
+ entry.set('qtext', "Reinstall Package %s-%s to setup md5sums? (y/N) " \
+ % (entry.get('name'), entry.get('version')))
+ return False
+ files = []
+ for item in output:
+ if "checksum mismatch" in item:
+ files.append(item.split()[-1])
+ elif "can't open" in item:
+ files.append(item.split()[5])
+ elif "is not installed" in item:
+ self.logger.error("Package %s is not fully installed" \
+ % entry.get('name'))
+ else:
+ self.logger.error("Got Unsupported pattern %s from debsums" \
+ % item)
+ files.append(item)
+ # We check if there is file in the checksum to do
+ if files:
+ # if files are found there we try to be sure our modlist is sane
+ # with erroneous symlinks
+ modlist = [os.path.realpath(filename) for filename in modlist]
+ bad = [filename for filename in files if filename not in modlist]
+ if bad:
+ self.logger.info("Package %s failed validation. Bad files are:" % \
+ entry.get('name'))
+ self.logger.info(bad)
+ entry.set('qtext',
+ "Reinstall Package %s-%s to fix failing files? (y/N) " % \
+ (entry.get('name'), entry.get('version')))
+ return False
+ return True
- def VerifyPackage(self, entry, modlist):
+ def VerifyPackage(self, entry, modlist, checksums=True):
'''Verify package for entry'''
if not entry.attrib.has_key('version'):
self.logger.info("Cannot verify unversioned package %s" %
(entry.attrib['name']))
return False
- if self.installed.has_key(entry.attrib['name']):
- if self.installed[entry.attrib['name']] == entry.attrib['version']:
- if not self.setup['quick'] and entry.get('verify', 'true') == 'true':
- output = self.cmd.run("/usr/bin/debsums -as %s" % entry.get('name'))[1]
- if len(output) == 1 and "no md5sums for" in output[0]:
- self.logger.info("Package %s has no md5sums. Cannot verify" % \
- entry.get('name'))
- entry.set('qtext', "Reinstall Package %s-%s to setup md5sums? (y/N) " \
- % (entry.get('name'), entry.get('version')))
- return False
- files = []
- for item in output:
- if "checksum mismatch" in item:
- files.append(item.split()[-1])
- elif "can't open" in item:
- files.append(item.split()[5])
- elif "is not installed" in item:
- self.logger.error("Package %s is not fully installed" \
- % entry.get('name'))
- else:
- self.logger.error("Got Unsupported pattern %s from debsums" \
- % item)
- files.append(item)
- # We check if there is file in the checksum to do
- if files:
- # if files are found there we try to be sure our modlist is sane
- # with erroneous symlinks
- modlist = [os.path.realpath(filename) for filename in modlist]
- bad = [filename for filename in files if filename not in modlist]
- if bad:
- self.logger.info("Package %s failed validation. Bad files are:" % \
- entry.get('name'))
- self.logger.info(bad)
- entry.set('qtext',
- "Reinstall Package %s-%s to fix failing md5sums? (y/N) " % \
- (entry.get('name'), entry.get('version')))
- return False
- return True
+ pkgname = entry.get('name')
+ if not self.pkg_cache.has_key(pkgname) \
+ or not self.pkg_cache[pkgname].isInstalled:
+ self.logger.info("Package %s not installed" % (entry.get('name')))
+ entry.set('current_exists', 'false')
+ return False
+
+ pkg = self.pkg_cache[pkgname]
+ if entry.get('version') == 'auto':
+ if self.pkg_cache._depcache.IsUpgradable(pkg._pkg):
+ desiredVersion = pkg.candidateVersion
else:
- entry.set('current_version', self.installed[entry.get('name')])
- entry.set('qtext', "Upgrade/downgrade Package %s (%s -> %s)? (y/N) " % \
- (entry.get('name'), entry.get('current_version'),
- entry.get('version')))
- return False
- self.logger.info("Package %s not installed" % (entry.get('name')))
- entry.set('current_exists', 'false')
- return False
+ desiredVersion = pkg.installedVersion
+ else:
+ desiredVersion = entry.get('version')
+ if desiredVersion != pkg.installedVersion:
+ entry.set('current_version', pkg.installedVersion)
+ entry.set('qtext', "Modify Package %s (%s -> %s)? (y/N) " % \
+ (entry.get('name'), entry.get('current_version'),
+ entry.get('version')))
+ return False
+ else:
+ # version matches
+ if not self.setup['quick'] and entry.get('verify', 'true') == 'true' \
+ and checksums:
+ pkgsums = self.VerifyDebsums(entry, modlist)
+ return pkgsums
- def RemovePackages(self, packages):
+ def Remove(self, packages):
'''Deal with extra configuration detected'''
pkgnames = " ".join([pkg.get('name') for pkg in packages])
if len(packages) > 0:
self.logger.info('Removing packages:')
self.logger.info(pkgnames)
- if self.cmd.run("apt-get remove --purge -y --force-yes %s" % pkgnames)[0] == 0:
- self.modified += packages
- self.RefreshPackages()
- self.extra = self.FindExtraPackages()
+ for pkg in pkgnames:
+ self.pkg_cache[pkg].markDelete(purge=True)
+ self.pkg_cache.commit()
+ self.modified += packages
+ self.extra = self.FindExtra()
def Install(self, packages, states):
- if self.setup['kevlar'] and not self.setup['dryrun'] and not self.updated:
- self.cmd.run("dpkg --force-confold --configure --pending")
- self.cmd.run("apt-get clean")
- self.cmd.run("apt-get -q=2 -y update")
- self.updated = True
- Bcfg2.Client.Tools.PkgTool.Install(self, packages, states)
+ # it looks like you can't install arbitrary versions of software
+ # out of the pkg cache, we will still need to call apt-get
+ ipkgs = []
+ for pkg in packages:
+ if not self.pkg_cache.has_key(pkg.get('name')):
+ self.logger.error("APT has no information about package %s" % (pkg.get('name')))
+ continue
+ if pkg.get('version') == 'auto':
+ ipkgs.append("%s=%s" % (pkg.get('name'),
+ self.pkg_cache[pkg.get('name')].candidateVersion))
+ continue
+ if pkg.get('version') in \
+ [p.VerStr for p in self.pkg_cache[pkg.get('name')]._pkg.VersionList]:
+ ipkgs.append("%s=%s" % (pkg.get('name'), pkg.get('version')))
+ rc = self.cmd.run(self.pkgcmd % (" ".join(ipkgs)))[0]
+ if rc:
+ self.logger.error("APT command failed")
+ self.pkg_cache = apt.cache.Cache()
+ self.extra = self.FindExtra()
+ for package in packages:
+ states[package] = self.VerifyPackage(package, [], checksums=False)
+ if states[package]:
+ self.modified.append(package)