Ticket #764: YUMng.py.txt

File YUMng.py.txt, 15.7 KB (added by Chris Stankaitis <[email protected]…>, 13 years ago)

Working Version given to me by desai

Line 
1'''This provides bcfg2 support for yum'''
2__revision__ = '$Revision: $'
3
4import ConfigParser
5import copy
6import os.path
7import sys
8import yum
9import Bcfg2.Client.XML
10import Bcfg2.Client.Tools.RPMng
11
12# Fix for python2.3
13try:
14    set
15except NameError:
16    from sets import Set as set
17
18YAD = True
19CP = ConfigParser.ConfigParser()
20try:
21    if '-C' in sys.argv:
22        CP.read([sys.argv[sys.argv.index('-C') + 1]])
23    else:
24        CP.read(['/etc/bcfg2.conf'])
25    if CP.get('YUMng', 'autodep').lower() == 'false':
26        YAD = False
27except:
28    pass
29
30if not hasattr(Bcfg2.Client.Tools.RPMng, 'RPMng'):
31    raise ImportError
32
33def build_yname(pkgname, inst):
34    '''build yum appropriate package name'''
35    ypname = pkgname
36    if inst.get('version') != 'any':
37        ypname += '-'
38    if inst.get('epoch', False):
39        ypname += "%s:" % inst.get('epoch')
40    if inst.get('version', False) and inst.get('version') != 'any':
41        ypname += "%s" % (inst.get('version'))
42    if inst.get('release', False) and inst.get('release') != 'any':
43        ypname += "-%s" % (inst.get('release'))
44    if inst.get('arch', False) and inst.get('arch') != 'any':
45        ypname += ".%s" % (inst.get('arch'))
46    return ypname
47
48class YUMng(Bcfg2.Client.Tools.RPMng.RPMng):
49    '''Support for Yum packages'''
50    pkgtype = 'yum'
51
52    name = 'YUMng'
53    __execs__ = ['/usr/bin/yum', '/var/lib/rpm']
54    __handles__ = [('Package', 'yum'), ('Package', 'rpm')]
55 
56    __req__ = {'Package': ['name', 'version']}
57    __ireq__ = {'Package': ['name']}
58    #__ireq__ = {'Package': ['name', 'version']}
59 
60    __new_req__ = {'Package': ['name'], 'Instance': ['version', 'release', 'arch']}
61    __new_ireq__ = {'Package': ['name'], \
62                    'Instance': []}
63    #__new_ireq__ = {'Package': ['name', 'uri'], \
64    #                'Instance': ['simplefile', 'version', 'release', 'arch']}
65
66    __gpg_req__ = {'Package': ['name', 'version']}
67    __gpg_ireq__ = {'Package': ['name', 'version']}
68
69    __new_gpg_req__ = {'Package': ['name'], 'Instance': ['version', 'release']}
70    __new_gpg_ireq__ = {'Package': ['name'], 'Instance': ['version', 'release']}
71
72    conflicts = ['RPMng']
73
74    def __init__(self, logger, setup, config):
75        Bcfg2.Client.Tools.RPMng.RPMng.__init__(self, logger, setup, config)
76        self.yum_avail = dict()
77        self.yum_installed = dict()
78        self.yb = yum.YumBase()
79        if hasattr(self.yb, 'doGenericSetup'):
80            self.yb.doGenericSetup()
81        else:
82            self.yb.doConfigSetup()
83            self.yb.doTsSetup()
84            self.yb.doRpmDBSetup()
85        yup = self.yb.doPackageLists(pkgnarrow='updates')
86        if hasattr(self.yb.rpmdb, 'pkglist'):
87            yinst = self.yb.rpmdb.pkglist
88        else:
89            yinst = self.yb.rpmdb.getPkgList()
90        for dest, source in [(self.yum_avail, yup.updates),
91                             (self.yum_installed, yinst)]:
92            for pkg in source:
93                if dest is self.yum_avail:
94                    pname = pkg.name
95                    data = [(pkg.arch, (pkg.epoch, pkg.version, pkg.release))]
96                else:
97                    pname = pkg[0]
98                    data = [(pkg[1], (pkg[2], pkg[3], pkg[4]))]
99                if pname in dest:
100                    dest[pname].update(data)
101                else:
102                    dest[pname] = dict(data)
103
104    def VerifyPackage(self, entry, modlist):
105        pinned_version = None
106        if entry.get('version', False) == 'auto':
107            # old style entry; synthesize Instances from current installed
108            if entry.get('name') not in self.yum_installed and \
109                   entry.get('name') not in self.yum_avail:
110                # new entry; fall back to default
111                entry.set('version', 'any')
112            else:
113                data = copy.copy(self.yum_installed[entry.get('name')])
114                if entry.get('name') in self.yum_avail:
115                    # installed but out of date
116                    data.update(self.yum_avail[entry.get('name')])
117                for (arch, (epoch, vers, rel)) in list(data.items()):
118                    x= Bcfg2.Client.XML.SubElement(entry, "Instance",
119                                                   name=entry.get('name'),
120                                                   version=vers, arch=arch,
121                                                   release=rel, epoch=epoch)
122                    if 'verify_flags' in entry.attrib:
123                        x.set('verify_flags', entry.get('verify_flags'))
124        return Bcfg2.Client.Tools.RPMng.RPMng.VerifyPackage(self, entry,
125                                                            modlist)
126       
127    def Install(self, packages, states):
128        '''
129           Try and fix everything that RPMng.VerifyPackages() found wrong for
130           each Package Entry.  This can result in individual RPMs being
131           installed (for the first time), deleted, downgraded
132           or upgraded.
133
134           NOTE: YUM can not reinstall a package that it thinks is already
135                 installed.
136
137           packages is a list of Package Elements that has
138               states[<Package Element>] == False
139
140           The following effects occur:
141           - states{} is conditionally updated for each package.
142           - self.installed{} is rebuilt, possibly multiple times.
143           - self.instance_status{} is conditionally updated for each instance
144             of a package.
145           - Each package will be added to self.modified[] if its states{}
146             entry is set to True.
147        '''
148        self.logger.info('Running YUMng.Install()')
149
150        install_pkgs = []
151        gpg_keys = []
152        upgrade_pkgs = []
153
154        # Remove extra instances.
155        # Can not reverify because we don't have a package entry.
156        if len(self.extra_instances) > 0:
157            if (self.setup.get('remove') == 'all' or \
158                self.setup.get('remove') == 'packages'):
159                self.RemovePackages(self.extra_instances)
160            else:
161                self.logger.info("The following extra package instances will be removed by the '-r' option:")
162                for pkg in self.extra_instances:
163                    for inst in pkg:
164                        self.logger.info("    %s %s" % \
165                                         ((pkg.get('name'), self.str_evra(inst))))
166
167        # Figure out which instances of the packages actually need something
168        # doing to them and place in the appropriate work 'queue'.
169        for pkg in packages:
170            insts = [pinst for pinst in pkg \
171                     if pinst.tag in ['Instance', 'Package']]
172            if insts:
173                for inst in insts:
174                    if self.FixInstance(inst, self.instance_status[inst]):
175                        if self.instance_status[inst].get('installed', False) \
176                               == False:
177                            if pkg.get('name') == 'gpg-pubkey':
178                                gpg_keys.append(inst)
179                            else:
180                                install_pkgs.append(inst)
181                        elif self.instance_status[inst].get('version_fail', \
182                                                            False) == True:
183                            upgrade_pkgs.append(inst)
184            else:
185                install_pkgs.append(pkg)
186
187        # Install GPG keys.
188        # Alternatively specify the required keys using 'gpgkey' in the
189        # repository definition in yum.conf.  YUM will install the keys
190        # automatically.
191        if len(gpg_keys) > 0:
192            for inst in gpg_keys:
193                self.logger.info("Installing GPG keys.")
194                if inst.get('simplefile') is None:
195                    self.logger.error("GPG key has no simplefile attribute")
196                    continue
197                key_arg = os.path.join(self.instance_status[inst].get('pkg').get('uri'), \
198                                                     inst.get('simplefile'))
199                cmdrc, output = self.cmd.run("rpm --import %s" % key_arg)
200                if cmdrc != 0:
201                    self.logger.debug("Unable to install %s-%s" % \
202                                              (self.instance_status[inst].get('pkg').get('name'), \
203                                               self.str_evra(inst)))
204                else:
205                    self.logger.debug("Installed %s-%s-%s" % \
206                                              (self.instance_status[inst].get('pkg').get('name'), \
207                                               inst.get('version'), inst.get('release')))
208            self.RefreshPackages()
209            self.gpg_keyids = self.getinstalledgpg()
210            pkg = self.instance_status[gpg_keys[0]].get('pkg')
211            states[pkg] = self.VerifyPackage(pkg, [])
212
213        # Install packages.
214        if len(install_pkgs) > 0:
215            self.logger.info("Attempting to install packages")
216
217            if YAD:
218                pkgtool = "/usr/bin/yum -d0 -y install %s"
219            else:
220                pkgtool = "/usr/bin/yum -d0 install %s"
221
222            install_args = []
223            for inst in install_pkgs:
224                pkg_arg = self.instance_status[inst].get('pkg').get('name')
225                install_args.append(build_yname(pkg_arg, inst))
226           
227            cmdrc, output = self.cmd.run(pkgtool % " ".join(install_args))
228            if cmdrc == 0:
229                # The yum command succeeded.  All packages installed.
230                self.logger.info("Single Pass for Install Succeded")
231                self.RefreshPackages()
232            else:
233                # The yum command failed.  No packages installed.
234                # Try installing instances individually.
235                self.logger.error("Single Pass Install of Packages Failed")
236                installed_instances = []
237                for inst in install_pkgs:
238                    pkg_arg = build_yname(self.instance_status[inst].get('pkg').get('name'), inst)
239   
240                    cmdrc, output = self.cmd.run(pkgtool % pkg_arg)
241                    if cmdrc == 0:
242                        installed_instances.append(inst)
243                    else:
244                        self.logger.debug("%s %s would not install." % \
245                                              (self.instance_status[inst].get('pkg').get('name'), \
246                                               self.str_evra(inst)))
247                self.RefreshPackages()
248
249        # Fix upgradeable packages.
250        if len(upgrade_pkgs) > 0:
251            self.logger.info("Attempting to upgrade packages")
252
253            if YAD:
254                pkgtool = "/usr/bin/yum -d0 -y update %s"
255            else:
256                pkgtool = "/usr/bin/yum -d0 update %s"
257
258            upgrade_args = []
259            for inst in upgrade_pkgs:
260                pkg_arg = build_yname(self.instance_status[inst].get('pkg').get('name'), inst)
261                upgrade_args.append(pkg_arg)
262           
263            cmdrc, output = self.cmd.run(pkgtool % " ".join(upgrade_args))
264            if cmdrc == 0:
265                # The yum command succeeded.  All packages installed.
266                self.logger.info("Single Pass for Install Succeded")
267                self.RefreshPackages()
268            else:
269                # The yum command failed.  No packages installed.
270                # Try installing instances individually.
271                self.logger.error("Single Pass Install of Packages Failed")
272                installed_instances = []
273                for inst in upgrade_pkgs:
274                    pkg_arg = build_yname(self.instance_status[inst].get('pkg').get('name'), inst)
275                    cmdrc, output = self.cmd.run(pkgtool % pkg_arg)
276                    if cmdrc == 0:
277                        installed_instances.append(inst)
278                    else:
279                        self.logger.debug("%s %s would not install." % \
280                                              (self.instance_status[inst].get('pkg').get('name'), \
281                                               self.str_evra(inst)))
282
283                self.RefreshPackages()
284
285        if not self.setup['kevlar']:
286            for pkg_entry in [p for p in packages if self.canVerify(p)]:
287                self.logger.debug("Reverifying Failed Package %s" % (pkg_entry.get('name')))
288                states[pkg_entry] = self.VerifyPackage(pkg_entry, \
289                                                       self.modlists.get(pkg_entry, []))
290
291        for entry in [ent for ent in packages if states[ent]]:
292            self.modified.append(entry)
293
294    def RemovePackages(self, packages):
295        '''
296           Remove specified entries.
297
298           packages is a list of Package Entries with Instances generated
299           by FindExtraPackages().
300        '''
301        self.logger.debug('Running YUMng.RemovePackages()')
302
303        if YAD:
304            pkgtool = "/usr/bin/yum -d0 -y erase %s"
305        else:
306            pkgtool = "/usr/bin/yum -d0 erase %s"
307
308        erase_args = []
309        for pkg in packages:
310            for inst in pkg:
311                if pkg.get('name') != 'gpg-pubkey':
312                    pkg_arg = pkg.get('name') + '-'
313                    if inst.get('epoch', False):
314                        pkg_arg = pkg_arg + inst.get('epoch') + ':'
315                    pkg_arg = pkg_arg + inst.get('version') + '-' + inst.get('release')
316                    if inst.get('arch', False):
317                        pkg_arg = pkg_arg + '.' + inst.get('arch')
318                    erase_args.append(pkg_arg)
319                else:
320                    pkgspec = { 'name':pkg.get('name'),
321                            'version':inst.get('version'),
322                            'release':inst.get('release')}
323                    self.logger.info("WARNING: gpg-pubkey package not in configuration %s %s"\
324                                                 % (pkgspec.get('name'), self.str_evra(pkgspec)))
325                    self.logger.info("         This package will be deleted in a future version of the RPMng driver.")
326
327        cmdrc, output = self.cmd.run(pkgtool % " ".join(erase_args))
328        if cmdrc == 0:
329            self.modified += packages
330            for pkg in erase_args:
331                self.logger.info("Deleted %s" % (pkg))
332        else:
333            self.logger.info("Bulk erase failed with errors:")
334            self.logger.debug("Erase results = %s" % output)
335            self.logger.info("Attempting individual erase for each package.")
336            for pkg in packages:
337                pkg_modified = False
338                for inst in pkg:
339                    if pkg.get('name') != 'gpg-pubkey':
340                        pkg_arg = pkg.get('name') + '-'
341                        if inst.haskey('epoch'):
342                            pkg_arg = pkg_arg + inst.get('epoch') + ':'
343                        pkg_arg = pkg_arg + inst.get('version') + '-' + inst.get('release')
344                        if 'arch' in inst.attrib:
345                            pkg_arg = pkg_arg + '.' + inst.get('arch')
346                    else:
347                        self.logger.info("WARNING: gpg-pubkey package not in configuration %s %s"\
348                                                 % (pkg.get('name'), self.str_evra(pkg)))
349                        self.logger.info("         This package will be deleted in a future version of the RPMng driver.")
350                        continue
351
352                    cmdrc, output = self.cmd.run(self.pkgtool % pkg_arg)
353                    if cmdrc == 0:
354                        pkg_modified = True
355                        self.logger.info("Deleted %s" % pkg_arg)
356                    else:
357                        self.logger.error("unable to delete %s" % pkg_arg)
358                        self.logger.debug("Failure = %s" % output)
359                if pkg_modified == True:
360                    self.modified.append(pkg)
361
362
363        self.RefreshPackages()
364        self.extra = self.FindExtraPackages()