root/trunk/bcfg2/src/lib/Client/Tools/APT.py

Revision 5546, 8.3 KB (checked in by desai, 3 weeks ago)

APT: suppress apt driver api warnings

  • Property svn:keywords set to Revision Id
Line 
1'''This is the bcfg2 support for apt-get'''
2__revision__ = '$Revision$'
3
4# suppress apt API warnings
5import warnings
6warnings.filterwarnings("ignore", "apt API not stable yet",
7                        FutureWarning)
8warnings.filterwarnings("ignore", "Accessed deprecated property Package.installedVersion, please see the Version class for alternatives.", DeprecationWarning)
9warnings.filterwarnings("ignore", "Accessed deprecated property Package.candidateVersion, please see the Version class for alternatives.", DeprecationWarning)
10import apt.cache
11import os
12import Bcfg2.Client.Tools
13
14class APT(Bcfg2.Client.Tools.Tool):
15    '''The Debian toolset implements package and service operations and inherits
16    the rest from Toolset.Toolset'''
17    name = 'APT'
18    __execs__ = ['/usr/bin/debsums', '/usr/bin/apt-get', '/usr/bin/dpkg']
19    __important__ = ["/etc/apt/sources.list",
20                     "/var/cache/debconf/config.dat",
21                     "/var/cache/debconf/templates.dat",
22                     '/etc/passwd', '/etc/group',
23                     '/etc/apt/apt.conf', '/etc/dpkg/dpkg.cfg']
24    __handles__ = [('Package', 'deb')]
25    __req__ = {'Package': ['name', 'version']}
26    pkgcmd = 'apt-get ' + \
27             '-o DPkg::Options::=--force-overwrite ' + \
28             '-o DPkg::Options::=--force-confold ' + \
29             '--reinstall ' + \
30             '-q=2 ' + \
31             '--force-yes ' + \
32             '-y install %s'
33
34    def __init__(self, logger, cfg, setup):
35        Bcfg2.Client.Tools.Tool.__init__(self, logger, cfg, setup)
36        self.cfg = cfg
37        os.environ["DEBIAN_FRONTEND"] = 'noninteractive'
38        self.actions = {}
39        if self.setup['kevlar'] and not self.setup['dryrun']:
40            self.cmd.run("dpkg --force-confold --configure --pending")
41            self.cmd.run("apt-get clean")
42            self.pkg_cache = apt.cache.Cache()
43            self.pkg_cache.update()
44        self.pkg_cache = apt.cache.Cache()
45
46    def FindExtra(self):
47        '''Find extra packages'''
48        packages = [entry.get('name') for entry in self.getSupportedEntries()]
49        extras = [(p.name, p.installedVersion) for p in self.pkg_cache
50                  if p.isInstalled and p.name not in packages]
51        return [Bcfg2.Client.XML.Element('Package', name=name, \
52                                         type='deb', version=version) \
53                                         for (name, version) in extras]
54
55    def VerifyDebsums(self, entry, modlist):
56        output = self.cmd.run("/usr/bin/debsums -as %s" % entry.get('name'))[1]
57        if len(output) == 1 and "no md5sums for" in output[0]:
58            self.logger.info("Package %s has no md5sums. Cannot verify" % \
59                             entry.get('name'))
60            entry.set('qtext', "Reinstall Package %s-%s to setup md5sums? (y/N) " \
61                      % (entry.get('name'), entry.get('version')))
62            return False
63        files = []
64        for item in output:
65            if "checksum mismatch" in item:
66                files.append(item.split()[-1])
67            elif "can't open" in item:
68                files.append(item.split()[5])
69            elif "is not installed" in item:
70                self.logger.error("Package %s is not fully installed" \
71                                  % entry.get('name'))
72            else:
73                self.logger.error("Got Unsupported pattern %s from debsums" \
74                                  % item)
75                files.append(item)
76        # We check if there is file in the checksum to do
77        if files:
78            # if files are found there we try to be sure our modlist is sane
79            # with erroneous symlinks
80            modlist = [os.path.realpath(filename) for filename in modlist]
81            bad = [filename for filename in files if filename not in modlist]
82            if bad:
83                self.logger.info("Package %s failed validation. Bad files are:" % \
84                                 entry.get('name'))
85                self.logger.info(bad)
86                entry.set('qtext',
87                          "Reinstall Package %s-%s to fix failing files? (y/N) " % \
88                          (entry.get('name'), entry.get('version')))
89                return False
90        return True
91
92    def VerifyPackage(self, entry, modlist, checksums=True):
93        '''Verify package for entry'''
94        if not 'version' in entry.attrib:
95            self.logger.info("Cannot verify unversioned package %s" %
96                             (entry.attrib['name']))
97            return False
98        pkgname = entry.get('name')
99        if not self.pkg_cache.has_key(pkgname) \
100               or not self.pkg_cache[pkgname].isInstalled:
101            self.logger.info("Package %s not installed" % (entry.get('name')))
102            entry.set('current_exists', 'false')
103            return False
104
105        pkg = self.pkg_cache[pkgname]
106        if entry.get('version') == 'auto':
107            if self.pkg_cache._depcache.IsUpgradable(pkg._pkg):
108                desiredVersion = pkg.candidateVersion
109            else:
110                desiredVersion = pkg.installedVersion
111        elif entry.get('version') == 'any':
112            desiredVersion = pkg.installedVersion
113        else:
114            desiredVersion = entry.get('version')
115        if desiredVersion != pkg.installedVersion:
116            entry.set('current_version', pkg.installedVersion)
117            entry.set('qtext', "Modify Package %s (%s -> %s)? (y/N) " % \
118                      (entry.get('name'), entry.get('current_version'),
119                       entry.get('version')))
120            return False
121        else:
122            # version matches
123            if not self.setup['quick'] and entry.get('verify', 'true') == 'true' \
124                   and checksums:
125                pkgsums = self.VerifyDebsums(entry, modlist)
126                return pkgsums
127            return True
128
129    def Remove(self, packages):
130        '''Deal with extra configuration detected'''
131        pkgnames = " ".join([pkg.get('name') for pkg in packages])
132        self.pkg_cache = apt.cache.Cache()
133        if len(packages) > 0:
134            self.logger.info('Removing packages:')
135            self.logger.info(pkgnames)
136            for pkg in pkgnames.split(" "):
137                try:
138                    self.pkg_cache[pkg].markDelete(purge=True)
139                except:
140                    self.pkg_cache[pkg].markDelete()
141            try:
142                self.pkg_cache.commit()
143            except SystemExit:
144                # thank you python-apt 0.6
145                pass
146            self.pkg_cache = apt.cache.Cache()
147            self.modified += packages
148            self.extra = self.FindExtra()
149
150    def Install(self, packages, states):
151        # it looks like you can't install arbitrary versions of software
152        # out of the pkg cache, we will still need to call apt-get
153        ipkgs = []
154        bad_pkgs = []
155        for pkg in packages:
156            if not self.pkg_cache.has_key(pkg.get('name')):
157                self.logger.error("APT has no information about package %s" % (pkg.get('name')))
158                continue
159            if pkg.get('version') in ['auto', 'any']:
160                ipkgs.append("%s=%s" % (pkg.get('name'),
161                                        self.pkg_cache[pkg.get('name')].candidateVersion))
162                continue
163            avail_vers = [x.VerStr for x in \
164                          self.pkg_cache[pkg.get('name')]._pkg.VersionList]
165            if pkg.get('version') in avail_vers:
166                ipkgs.append("%s=%s" % (pkg.get('name'), pkg.get('version')))
167                continue
168            else:
169                self.logger.error("Package %s: desired version %s not in %s" \
170                                  % (pkg.get('name'), pkg.get('version'),
171                                     avail_vers))
172            bad_pkgs.append(pkg.get('name'))
173        if bad_pkgs:
174            self.logger.error("Cannot find correct versions of packages:")
175            self.logger.error(bad_pkgs)
176        if not ipkgs:
177            return
178        rc = self.cmd.run(self.pkgcmd % (" ".join(ipkgs)))[0]
179        if rc:
180            self.logger.error("APT command failed")
181        self.pkg_cache = apt.cache.Cache()
182        self.extra = self.FindExtra()
183        for package in packages:
184            states[package] = self.VerifyPackage(package, [], checksums=False)
185            if states[package]:
186                self.modified.append(package)
Note: See TracBrowser for help on using the browser.