diff options
Diffstat (limited to 'src/lib/Client/Tools')
-rw-r--r-- | src/lib/Client/Tools/APT.py | 6 | ||||
-rw-r--r-- | src/lib/Client/Tools/Action.py | 7 | ||||
-rw-r--r-- | src/lib/Client/Tools/Chkconfig.py | 5 | ||||
-rw-r--r-- | src/lib/Client/Tools/DebInit.py | 9 | ||||
-rw-r--r-- | src/lib/Client/Tools/POSIX.py | 29 | ||||
-rw-r--r-- | src/lib/Client/Tools/Pacman.py | 2 | ||||
-rw-r--r-- | src/lib/Client/Tools/RcUpdate.py | 5 | ||||
-rw-r--r-- | src/lib/Client/Tools/SMF.py | 5 | ||||
-rw-r--r-- | src/lib/Client/Tools/Systemd.py | 59 | ||||
-rw-r--r-- | src/lib/Client/Tools/Upstart.py | 9 | ||||
-rw-r--r-- | src/lib/Client/Tools/VCS.py | 137 | ||||
-rw-r--r-- | src/lib/Client/Tools/YUM24.py | 54 | ||||
-rw-r--r-- | src/lib/Client/Tools/YUMng.py | 35 | ||||
-rw-r--r-- | src/lib/Client/Tools/__init__.py | 73 | ||||
-rw-r--r-- | src/lib/Client/Tools/launchd.py | 5 |
15 files changed, 337 insertions, 103 deletions
diff --git a/src/lib/Client/Tools/APT.py b/src/lib/Client/Tools/APT.py index fe1ef6fdd..a838f5e27 100644 --- a/src/lib/Client/Tools/APT.py +++ b/src/lib/Client/Tools/APT.py @@ -69,7 +69,11 @@ class APT(Bcfg2.Client.Tools.Tool): if self.setup['kevlar'] and not self.setup['dryrun']: self.cmd.run("%s --force-confold --configure --pending" % DPKG) self.cmd.run("%s clean" % APTGET) - self.pkg_cache = apt.cache.Cache() + try: + self.pkg_cache = apt.cache.Cache() + except SystemError, e: + self.logger.info("Failed to initialize APT cache: %s" % e) + raise Bcfg2.Client.Tools.toolInstantiationError self.pkg_cache.update() self.pkg_cache = apt.cache.Cache() diff --git a/src/lib/Client/Tools/Action.py b/src/lib/Client/Tools/Action.py index 452788f94..bc57a0e27 100644 --- a/src/lib/Client/Tools/Action.py +++ b/src/lib/Client/Tools/Action.py @@ -31,7 +31,12 @@ class Action(Bcfg2.Client.Tools.Tool): if self.setup['interactive']: prompt = ('Run Action %s, %s: (y/N): ' % (entry.get('name'), entry.get('command'))) - if raw_input(prompt) not in ['y', 'Y']: + # py3k compatibility + try: + ans = raw_input(prompt) + except NameError: + ans = input(prompt) + if ans not in ['y', 'Y']: return False if self.setup['servicemode'] == 'build': if entry.get('build', 'true') == 'false': diff --git a/src/lib/Client/Tools/Chkconfig.py b/src/lib/Client/Tools/Chkconfig.py index bf2a2c1e1..0c78b0fb5 100644 --- a/src/lib/Client/Tools/Chkconfig.py +++ b/src/lib/Client/Tools/Chkconfig.py @@ -76,6 +76,11 @@ class Chkconfig(Bcfg2.Client.Tools.SvcTool): def InstallService(self, entry): """Install Service entry.""" + # don't take any actions for mode='manual' + if entry.get('mode', 'default') == 'manual': + self.logger.info("Service %s mode set to manual. Skipping " + "installation." % (entry.get('name'))) + return False rcmd = "/sbin/chkconfig %s %s" self.cmd.run("/sbin/chkconfig --add %s"%(entry.attrib['name'])) self.logger.info("Installing Service %s" % (entry.get('name'))) diff --git a/src/lib/Client/Tools/DebInit.py b/src/lib/Client/Tools/DebInit.py index 119036b32..d6ce16c52 100644 --- a/src/lib/Client/Tools/DebInit.py +++ b/src/lib/Client/Tools/DebInit.py @@ -21,6 +21,10 @@ class DebInit(Bcfg2.Client.Tools.SvcTool): # implement entry (Verify|Install) ops def VerifyService(self, entry, _): """Verify Service status for entry.""" + + if entry.get('status') == 'ignore': + return True + rawfiles = glob.glob("/etc/rc*.d/[SK]*%s" % (entry.get('name'))) files = [] @@ -71,6 +75,11 @@ class DebInit(Bcfg2.Client.Tools.SvcTool): def InstallService(self, entry): """Install Service for entry.""" + # don't take any actions for mode='manual' + if entry.get('mode', 'default') == 'manual': + self.logger.info("Service %s mode set to manual. Skipping " + "installation." % (entry.get('name'))) + return False self.logger.info("Installing Service %s" % (entry.get('name'))) try: os.stat('/etc/init.d/%s' % entry.get('name')) diff --git a/src/lib/Client/Tools/POSIX.py b/src/lib/Client/Tools/POSIX.py index c883fc17a..af3d1a473 100644 --- a/src/lib/Client/Tools/POSIX.py +++ b/src/lib/Client/Tools/POSIX.py @@ -137,14 +137,14 @@ class POSIX(Bcfg2.Client.Tools.Tool): entry.get('owner') == None or \ entry.get('group') == None: self.logger.error('Entry %s not completely specified. ' - 'Try running bcfg2-repo-validate.' % (entry.get('name'))) + 'Try running bcfg2-lint.' % (entry.get('name'))) return False if entry.get('dev_type') in ['block', 'char']: # check if major/minor are properly specified if entry.get('major') == None or \ entry.get('minor') == None: self.logger.error('Entry %s not completely specified. ' - 'Try running bcfg2-repo-validate.' % (entry.get('name'))) + 'Try running bcfg2-lint.' % (entry.get('name'))) return False try: # check for file existence @@ -167,7 +167,7 @@ class POSIX(Bcfg2.Client.Tools.Tool): if entry.get('major') == None or \ entry.get('minor') == None: self.logger.error('Entry %s not completely specified. ' - 'Try running bcfg2-repo-validate.' % (entry.get('name'))) + 'Try running bcfg2-lint.' % (entry.get('name'))) return False major = int(entry.get('major')) minor = int(entry.get('minor')) @@ -218,7 +218,7 @@ class POSIX(Bcfg2.Client.Tools.Tool): if entry.get('major') == None or \ entry.get('minor') == None: self.logger.error('Entry %s not completely specified. ' - 'Try running bcfg2-repo-validate.' % (entry.get('name'))) + 'Try running bcfg2-lint.' % (entry.get('name'))) return False major = int(entry.get('major')) minor = int(entry.get('minor')) @@ -240,7 +240,7 @@ class POSIX(Bcfg2.Client.Tools.Tool): entry.get('owner') == None or \ entry.get('group') == None: self.logger.error('Entry %s not completely specified. ' - 'Try running bcfg2-repo-validate.' % (entry.get('name'))) + 'Try running bcfg2-lint.' % (entry.get('name'))) return False while len(entry.get('perms', '')) < 4: entry.set('perms', '0' + entry.get('perms', '')) @@ -348,7 +348,7 @@ class POSIX(Bcfg2.Client.Tools.Tool): entry.get('owner') == None or \ entry.get('group') == None: self.logger.error('Entry %s not completely specified. ' - 'Try running bcfg2-repo-validate.' % \ + 'Try running bcfg2-lint.' % \ (entry.get('name'))) return False self.logger.info("Installing directory %s" % (entry.get('name'))) @@ -542,7 +542,7 @@ class POSIX(Bcfg2.Client.Tools.Tool): return False # If we get here, then the parent directory should exist - if (entry.get("paranoid", False) == 'true') and \ + if (entry.get("paranoid", False) in ['true', 'True']) and \ self.setup.get("paranoid", False) and not \ (entry.get('current_exists', 'true') == 'false'): bkupnam = entry.get('name').replace('/', '_') @@ -550,7 +550,7 @@ class POSIX(Bcfg2.Client.Tools.Tool): bkuplist = [f for f in os.listdir(self.ppath) if f.startswith(bkupnam)] bkuplist.sort() - if len(bkuplist) == int(self.max_copies): + while len(bkuplist) >= int(self.max_copies): # remove the oldest backup available oldest = bkuplist.pop(0) self.logger.info("Removing %s" % oldest) @@ -563,7 +563,8 @@ class POSIX(Bcfg2.Client.Tools.Tool): try: # backup existing file shutil.copy(entry.get('name'), - "%s/%s_%s" % (self.ppath, bkupnam, datetime.now())) + "%s/%s_%s" % (self.ppath, bkupnam, + datetime.isoformat(datetime.now()))) self.logger.info("Backup of %s saved to %s" % (entry.get('name'), self.ppath)) except IOError, e: @@ -613,7 +614,7 @@ class POSIX(Bcfg2.Client.Tools.Tool): """Verify HardLink entry.""" if entry.get('to') == None: self.logger.error('Entry %s not completely specified. ' - 'Try running bcfg2-repo-validate.' % \ + 'Try running bcfg2-lint.' % \ (entry.get('name'))) return False try: @@ -636,7 +637,7 @@ class POSIX(Bcfg2.Client.Tools.Tool): """Install HardLink entry.""" if entry.get('to') == None: self.logger.error('Entry %s not completely specified. ' - 'Try running bcfg2-repo-validate.' % \ + 'Try running bcfg2-lint.' % \ (entry.get('name'))) return False self.logger.info("Installing Hardlink %s" % (entry.get('name'))) @@ -712,7 +713,7 @@ class POSIX(Bcfg2.Client.Tools.Tool): entry.get('owner') == None or \ entry.get('group') == None: self.logger.error('Entry %s not completely specified. ' - 'Try running bcfg2-repo-validate.' % (entry.get('name'))) + 'Try running bcfg2-lint.' % (entry.get('name'))) return False try: os.chown(entry.get('name'), normUid(entry), normGid(entry)) @@ -727,7 +728,7 @@ class POSIX(Bcfg2.Client.Tools.Tool): """Verify Path type='symlink' entry.""" if entry.get('to') == None: self.logger.error('Entry %s not completely specified. ' - 'Try running bcfg2-repo-validate.' % \ + 'Try running bcfg2-lint.' % \ (entry.get('name'))) return False try: @@ -750,7 +751,7 @@ class POSIX(Bcfg2.Client.Tools.Tool): """Install Path type='symlink' entry.""" if entry.get('to') == None: self.logger.error('Entry %s not completely specified. ' - 'Try running bcfg2-repo-validate.' % \ + 'Try running bcfg2-lint.' % \ (entry.get('name'))) return False self.logger.info("Installing symlink %s" % (entry.get('name'))) diff --git a/src/lib/Client/Tools/Pacman.py b/src/lib/Client/Tools/Pacman.py index be3fb0c94..082897934 100644 --- a/src/lib/Client/Tools/Pacman.py +++ b/src/lib/Client/Tools/Pacman.py @@ -73,7 +73,7 @@ class Pacman(Bcfg2.Client.Tools.PkgTool): for pkg in packages: pkgline += " " + pkg.get('name') - print "packages : " + pkgline + self.logger.info("packages : " + pkgline) try: self.logger.debug("Running : %s -S %s" % (self.pkgtool, pkgline)) diff --git a/src/lib/Client/Tools/RcUpdate.py b/src/lib/Client/Tools/RcUpdate.py index 159172b78..d832d98a8 100644 --- a/src/lib/Client/Tools/RcUpdate.py +++ b/src/lib/Client/Tools/RcUpdate.py @@ -57,6 +57,11 @@ class RcUpdate(Bcfg2.Client.Tools.SvcTool): In supervised mode we also take care it's (not) running. """ + # don't take any actions for mode='manual' + if entry.get('mode', 'default') == 'manual': + self.logger.info("Service %s mode set to manual. Skipping " + "installation." % (entry.get('name'))) + return False self.logger.info('Installing Service %s' % entry.get('name')) if entry.get('status') == 'on': # make sure it's running if in supervised mode diff --git a/src/lib/Client/Tools/SMF.py b/src/lib/Client/Tools/SMF.py index 96c7d9d28..944408326 100644 --- a/src/lib/Client/Tools/SMF.py +++ b/src/lib/Client/Tools/SMF.py @@ -74,6 +74,11 @@ class SMF(Bcfg2.Client.Tools.SvcTool): def InstallService(self, entry): """Install SMF Service entry.""" + # don't take any actions for mode='manual' + if entry.get('mode', 'default') == 'manual': + self.logger.info("Service %s mode set to manual. Skipping " + "installation." % (entry.get('name'))) + return False self.logger.info("Installing Service %s" % (entry.get('name'))) if entry.get('status') == 'off': if entry.get("FMRI").startswith('lrc'): diff --git a/src/lib/Client/Tools/Systemd.py b/src/lib/Client/Tools/Systemd.py new file mode 100644 index 000000000..e3f6a4169 --- /dev/null +++ b/src/lib/Client/Tools/Systemd.py @@ -0,0 +1,59 @@ +# This is the bcfg2 support for systemd + +"""This is systemd support.""" + +import Bcfg2.Client.Tools +import Bcfg2.Client.XML + +class Systemd(Bcfg2.Client.Tools.SvcTool): + """Systemd support for Bcfg2.""" + name = 'Systemd' + __execs__ = ['/bin/systemctl'] + __handles__ = [('Service', 'systemd')] + __req__ = {'Service': ['name', 'status']} + + def get_svc_command(self, service, action): + return "/bin/systemctl %s %s.service" % (action, service.get('name')) + + def VerifyService(self, entry, _): + """Verify Service status for entry.""" + cmd = "/bin/systemctl status %s.service " % (entry.get('name')) + raw = ''.join(self.cmd.run(cmd)[1]) + + if raw.find('Loaded: error') >= 0: + entry.set('current_status', 'off') + status = False + + elif raw.find('Active: active') >= 0: + entry.set('current_status', 'on') + if entry.get('status') == 'off': + status = False + else: + status = True + + else: + entry.set('current_status', 'off') + if entry.get('status') == 'on': + status = False + else: + status = True + + return status + + def InstallService(self, entry): + """Install Service entry.""" + # don't take any actions for mode = 'manual' + if entry.get('mode', 'default') == 'manual': + self.logger.info("Service %s mode set to manual. Skipping " + "installation." % (entry.get('name'))) + return True + + if entry.get('status') == 'on': + pstatus = self.cmd.run(self.get_svc_command(entry, 'enable'))[0] + pstatus = self.cmd.run(self.get_svc_command(entry, 'start'))[0] + + else: + pstatus = self.cmd.run(self.get_svc_command(entry, 'stop'))[0] + pstatus = self.cmd.run(self.get_svc_command(entry, 'disable'))[0] + + return not pstatus diff --git a/src/lib/Client/Tools/Upstart.py b/src/lib/Client/Tools/Upstart.py index b75b0927e..41a585c23 100644 --- a/src/lib/Client/Tools/Upstart.py +++ b/src/lib/Client/Tools/Upstart.py @@ -29,6 +29,10 @@ class Upstart(Bcfg2.Client.Tools.SvcTool): /etc/init/servicename.conf. All we need to do is make sure the service is running when it should be. """ + + if entry.get('status') == 'ignore': + return True + if entry.get('parameters'): params = entry.get('parameters') else: @@ -66,6 +70,11 @@ class Upstart(Bcfg2.Client.Tools.SvcTool): def InstallService(self, entry): """Install Service for entry.""" + # don't take any actions for mode='manual' + if entry.get('mode', 'default') == 'manual': + self.logger.info("Service %s mode set to manual. Skipping " + "installation." % (entry.get('name'))) + return False if entry.get('status') == 'on': pstatus = self.cmd.run(self.get_svc_command(entry, 'start'))[0] elif entry.get('status') == 'off': diff --git a/src/lib/Client/Tools/VCS.py b/src/lib/Client/Tools/VCS.py new file mode 100644 index 000000000..fa7748574 --- /dev/null +++ b/src/lib/Client/Tools/VCS.py @@ -0,0 +1,137 @@ +"""VCS support.""" + +# TODO: +# * git_write_index +# * add svn support +# * integrate properly with reports +missing = [] + +import os +import sys +# python-dulwich git imports +try: + import dulwich + import dulwich.index + from dulwich.errors import NotGitRepository +except: + missing.append('git') +# subversion import +try: + import pysvn +except: + missing.append('svn') + +import Bcfg2.Client.Tools + + +class VCS(Bcfg2.Client.Tools.Tool): + """VCS support.""" + name = 'VCS' + __handles__ = [('Path', 'vcs')] + __req__ = {'Path': ['name', + 'type', + 'vcstype', + 'sourceurl', + 'revision']} + + def __init__(self, logger, cfg, setup): + Bcfg2.Client.Tools.Tool.__init__(self, logger, cfg, setup) + self.cfg = cfg + + def git_write_index(self, entry): + """Write the git index""" + pass + + def Verifygit(self, entry, _): + """Verify git repositories""" + try: + repo = dulwich.repo.Repo(entry.get('name')) + except NotGitRepository: + self.logger.info("Repository %s does not exist" % + entry.get('name')) + return False + cur_rev = repo.head() + + if cur_rev != entry.get('revision'): + self.logger.info("At revision %s need to go to revision %s" % + (cur_rev, entry.get('revision'))) + return False + + return True + + def Installgit(self, entry): + """Checkout contents from a git repository""" + destname = entry.get('name') + destr = dulwich.repo.Repo.init(destname, mkdir=True) + cl, host_path = dulwich.client.get_transport_and_path(entry.get('sourceurl')) + remote_refs = cl.fetch(host_path, + destr, + determine_wants=destr.object_store.determine_wants_all, + progress=sys.stdout.write) + destr.refs['refs/heads/master'] = entry.get('revision') + dtree = destr[entry.get('revision')].tree + obj_store = destr.object_store + for fname, mode, sha in obj_store.iter_tree_contents(dtree): + fullpath = os.path.join(destname, fname) + try: + f = open(os.path.join(destname, fname), 'wb') + except IOError: + dir = os.path.split(fullpath)[0] + os.makedirs(dir) + f = open(os.path.join(destname, fname), 'wb') + f.write(destr[sha].data) + f.close() + os.chmod(os.path.join(destname, fname), mode) + return True + # FIXME: figure out how to write the git index properly + #iname = "%s/.git/index" % entry.get('name') + #f = open(iname, 'w+') + #entries = obj_store[sha].iteritems() + #try: + # dulwich.index.write_index(f, entries) + #finally: + # f.close() + + def Verifysvn(self, entry, _): + """Verify svn repositories""" + client = pysvn.Client() + try: + cur_rev = str(client.info(entry.get('name')).revision.number) + except: + self.logger.info("Repository %s does not exist" % entry.get('name')) + return False + + if cur_rev != entry.get('revision'): + self.logger.info("At revision %s need to go to revision %s" % + (cur_rev, entry.get('revision'))) + return False + + return True + + def Installsvn(self, entry): + """Checkout contents from a svn repository""" + try: + client = pysvn.Client.update(entry.get('name'), recurse=True) + except: + self.logger.error("Failed to update repository", exc_info=1) + return False + + return True + + def VerifyPath(self, entry, _): + vcs = entry.get('vcstype') + if vcs in missing: + self.logger.error("Missing %s python libraries. Cannot verify" % + vcs) + return False + ret = getattr(self, 'Verify%s' % vcs) + return ret(entry, _) + + def InstallPath(self, entry): + vcs = entry.get('vcstype') + if vcs in missing: + self.logger.error("Missing %s python libraries. " + "Unable to install" % vcs) + return False + ret = getattr(self, 'Install%s' % vcs) + return ret(entry) diff --git a/src/lib/Client/Tools/YUM24.py b/src/lib/Client/Tools/YUM24.py index efe92a059..04d9f5c07 100644 --- a/src/lib/Client/Tools/YUM24.py +++ b/src/lib/Client/Tools/YUM24.py @@ -30,6 +30,7 @@ except: if not hasattr(Bcfg2.Client.Tools.RPMng, 'RPMng'): raise ImportError + def build_yname(pkgname, inst): """Build yum appropriate package name.""" ypname = pkgname @@ -45,6 +46,7 @@ def build_yname(pkgname, inst): ypname += ".%s" % (inst.get('arch')) return ypname + class YUM24(Bcfg2.Client.Tools.RPMng.RPMng): """Support for Yum packages.""" pkgtype = 'yum' @@ -59,7 +61,8 @@ class YUM24(Bcfg2.Client.Tools.RPMng.RPMng): __ireq__ = {'Package': ['name']} #__ireq__ = {'Package': ['name', 'version']} - __new_req__ = {'Package': ['name'], 'Instance': ['version', 'release', 'arch']} + __new_req__ = {'Package': ['name'], + 'Instance': ['version', 'release', 'arch']} __new_ireq__ = {'Package': ['name'], \ 'Instance': []} #__new_ireq__ = {'Package': ['name', 'uri'], \ @@ -68,8 +71,10 @@ class YUM24(Bcfg2.Client.Tools.RPMng.RPMng): __gpg_req__ = {'Package': ['name', 'version']} __gpg_ireq__ = {'Package': ['name', 'version']} - __new_gpg_req__ = {'Package': ['name'], 'Instance': ['version', 'release']} - __new_gpg_ireq__ = {'Package': ['name'], 'Instance': ['version', 'release']} + __new_gpg_req__ = {'Package': ['name'], + 'Instance': ['version', 'release']} + __new_gpg_ireq__ = {'Package': ['name'], + 'Instance': ['version', 'release']} conflicts = ['YUMng', 'RPMng'] @@ -101,10 +106,14 @@ class YUM24(Bcfg2.Client.Tools.RPMng.RPMng): data = {pkg.arch: (pkg.epoch, pkg.version, pkg.release)} else: pname = pkg[0] - if pkg[1] is None: a = 'noarch' - else: a = pkg[1] - if pkg[2] is None: e = '0' - else: e = pkg[2] + if pkg[1] is None: + a = 'noarch' + else: + a = pkg[1] + if pkg[2] is None: + e = '0' + else: + e = pkg[2] data = {a: (e, pkg[3], pkg[4])} if pname in dest: dest[pname].update(data) @@ -137,24 +146,24 @@ class YUM24(Bcfg2.Client.Tools.RPMng.RPMng): if entry.get('type', False) == 'yum': # Check for virtual provides or packages. If we don't have # this package use Yum to resolve it to a real package name - knownPkgs = self.yum_installed.keys() + self.yum_avail.keys() + knownPkgs = list(self.yum_installed.keys()) + list(self.yum_avail.keys()) if entry.get('name') not in knownPkgs: # If the package name matches something installed # or available the that's the correct package. try: - pkgDict = dict( [ (i.name, i) for i in \ - self.yb.returnPackagesByDep(entry.get('name')) ] ) + pkgDict = dict([(i.name, i) for i in \ + self.yb.returnPackagesByDep(entry.get('name'))]) except yum.Errors.YumBaseError, e: self.logger.error('Yum Error Depsolving for %s: %s' % \ (entry.get('name'), str(e))) pkgDict = {} if len(pkgDict) > 1: - # What do we do with multiple packages? + # What do we do with multiple packages? s = "YUMng: returnPackagesByDep(%s) returned many packages" self.logger.info(s % entry.get('name')) s = "YUMng: matching packages: %s" - self.logger.info(s % str(pkgDict.keys())) + self.logger.info(s % str(list(pkgDict.keys()))) pkgs = set(pkgDict.keys()) & set(self.yum_installed.keys()) if len(pkgs) > 0: # Virtual packages matches an installed real package @@ -166,7 +175,7 @@ class YUM24(Bcfg2.Client.Tools.RPMng.RPMng): # and Yum should Do The Right Thing on package install pkg = None elif len(pkgDict) == 1: - pkg = pkgDict.values()[0] + pkg = list(pkgDict.values())[0] else: # len(pkgDict) == 0 s = "YUMng: returnPackagesByDep(%s) returned no results" self.logger.info(s % entry.get('name')) @@ -252,16 +261,16 @@ class YUM24(Bcfg2.Client.Tools.RPMng.RPMng): self.logger.error("GPG key has no simplefile attribute") continue key_arg = os.path.join(self.instance_status[inst].get('pkg').get('uri'), \ - inst.get('simplefile')) + inst.get('simplefile')) cmdrc, output = self.cmd.run("rpm --import %s" % key_arg) if cmdrc != 0: self.logger.debug("Unable to install %s-%s" % \ - (self.instance_status[inst].get('pkg').get('name'), \ - self.str_evra(inst))) + (self.instance_status[inst].get('pkg').get('name'), \ + self.str_evra(inst))) else: self.logger.debug("Installed %s-%s-%s" % \ - (self.instance_status[inst].get('pkg').get('name'), \ - inst.get('version'), inst.get('release'))) + (self.instance_status[inst].get('pkg').get('name'), \ + inst.get('version'), inst.get('release'))) self.RefreshPackages() self.gpg_keyids = self.getinstalledgpg() pkg = self.instance_status[gpg_keys[0]].get('pkg') @@ -374,9 +383,9 @@ class YUM24(Bcfg2.Client.Tools.RPMng.RPMng): pkg_arg = pkg_arg + '.' + inst.get('arch') erase_args.append(pkg_arg) else: - pkgspec = { 'name':pkg.get('name'), - 'version':inst.get('version'), - 'release':inst.get('release')} + pkgspec = {'name': pkg.get('name'), + 'version': inst.get('version'), + 'release': inst.get('release')} self.logger.info("WARNING: gpg-pubkey package not in configuration %s %s"\ % (pkgspec.get('name'), self.str_evra(pkgspec))) self.logger.info(" This package will be deleted in a future version of the RPMng driver.") @@ -395,7 +404,7 @@ class YUM24(Bcfg2.Client.Tools.RPMng.RPMng): for inst in pkg: if pkg.get('name') != 'gpg-pubkey': pkg_arg = pkg.get('name') + '-' - if inst.attrib.has_key('epoch'): + if 'epoch' in inst.attrib: pkg_arg = pkg_arg + inst.get('epoch') + ':' pkg_arg = pkg_arg + inst.get('version') + '-' + inst.get('release') if 'arch' in inst.attrib: @@ -416,6 +425,5 @@ class YUM24(Bcfg2.Client.Tools.RPMng.RPMng): if pkg_modified == True: self.modified.append(pkg) - self.RefreshPackages() self.extra = self.FindExtraPackages() diff --git a/src/lib/Client/Tools/YUMng.py b/src/lib/Client/Tools/YUMng.py index 44d56ff9f..c9e7aa15e 100644 --- a/src/lib/Client/Tools/YUMng.py +++ b/src/lib/Client/Tools/YUMng.py @@ -300,7 +300,7 @@ class YUMng(Bcfg2.Client.Tools.PkgTool): # Okay deal with a buggy yum multilib and verify packages = self.yb.rpmdb.searchNevra(name=po.name, epoch=po.epoch, - ver=po.version, rel=po.release) # find all arches of pkg + ver=po.version, rel=po.release) # find all arches of pkg if len(packages) == 1: return results # No mathcing multilib packages @@ -319,13 +319,13 @@ class YUMng(Bcfg2.Client.Tools.PkgTool): v = verify(p) self.verifyCache[k] = v - for fn, probs in v.items(): + for fn, probs in list(v.items()): # file problems must exist in ALL multilib packages to be real if fn in files: common[fn] = common.get(fn, 0) + 1 flag = len(packages) - 1 - for fn, i in common.items(): + for fn, i in list(common.items()): if i == flag: # this fn had verify problems in all but one of the multilib # packages. That means its correct in the package that's @@ -463,6 +463,14 @@ class YUMng(Bcfg2.Client.Tools.PkgTool): self.logger.debug(" Not checking version for virtual package") _POs = [po for po in POs] # Make a copy elif entry.get('name') == 'gpg-pubkey': + if 'version' not in nevra: + m = "Skipping verify: gpg-pubkey without an RPM version." + self.logger.warning(m) + continue + if 'release' not in nevra: + m = "Skipping verify: gpg-pubkey without an RPM release." + self.logger.warning(m) + continue _POs = [p for p in POs if p.version == nevra['version'] \ and p.release == nevra['release']] else: @@ -504,7 +512,7 @@ class YUMng(Bcfg2.Client.Tools.PkgTool): ignores = [ig.get('name') for ig in entry.findall('Ignore')] + \ [ig.get('name') for ig in inst.findall('Ignore')] + \ self.ignores - for fn, probs in vResult.items(): + for fn, probs in list(vResult.items()): if fn in modlist: self.logger.debug(" %s in modlist, skipping" % fn) continue @@ -529,7 +537,7 @@ class YUMng(Bcfg2.Client.Tools.PkgTool): "these files, revert the changes, or ignore " "false failures:") self.logger.debug(" Verify Problems:") - for fn, probs in stat['verify'].items(): + for fn, probs in list(stat['verify'].items()): self.logger.debug(" %s" % fn) for p in probs: self.logger.debug(" %s: %s" % p) @@ -569,7 +577,7 @@ class YUMng(Bcfg2.Client.Tools.PkgTool): extra_entry = Bcfg2.Client.XML.Element('Package', name=name, type=self.pkgtype) instances = self._buildInstances(entry) - _POs = [p for p in POs] # Shallow copy + _POs = [p for p in POs] # Shallow copy # Algorythm is sensitive to duplicates, check for them checked = [] @@ -580,7 +588,7 @@ class YUMng(Bcfg2.Client.Tools.PkgTool): flag = True if len(pkgs) > 0: if pkgs[0] in checked: - continue # We've already taken care of this Instance + continue # We've already taken care of this Instance else: checked.append(pkgs[0]) _POs.remove(pkgs[0]) @@ -601,16 +609,17 @@ class YUMng(Bcfg2.Client.Tools.PkgTool): packages = [e.get('name') for e in self.getSupportedEntries()] extras = [] - for p in self.installed.keys(): + for p in list(self.installed.keys()): if p not in packages: entry = Bcfg2.Client.XML.Element('Package', name=p, type=self.pkgtype) for i in self.installed[p]: - inst = Bcfg2.Client.XML.SubElement(entry, 'Instance', \ - epoch = i['epoch'], - version = i['version'], - release = i['release'], - arch = i['arch']) + inst = Bcfg2.Client.XML.SubElement(entry, + 'Instance', + epoch=i['epoch'], + version=i['version'], + release=i['release'], + arch=i['arch']) extras.append(entry) diff --git a/src/lib/Client/Tools/__init__.py b/src/lib/Client/Tools/__init__.py index b5120db71..88609c2f6 100644 --- a/src/lib/Client/Tools/__init__.py +++ b/src/lib/Client/Tools/__init__.py @@ -4,9 +4,9 @@ import warnings warnings.filterwarnings("ignore", "The popen2 module is deprecated.*", DeprecationWarning) import os -import popen2 import stat import sys +from subprocess import Popen, PIPE import time import Bcfg2.Client.XML @@ -25,26 +25,6 @@ class toolInstantiationError(Exception): pass -class readonlypipe(popen2.Popen4): - """This pipe sets up stdin --> /dev/null.""" - - def __init__(self, cmd, bufsize=-1): - popen2._cleanup() - c2pread, c2pwrite = os.pipe() - null = open('/dev/null', 'w+') - self.pid = os.fork() - if self.pid == 0: - # Child - os.dup2(null.fileno(), sys.__stdin__.fileno()) - #os.dup2(p2cread, 0) - os.dup2(c2pwrite, 1) - os.dup2(c2pwrite, 2) - self._run_child(cmd) - os.close(c2pwrite) - self.fromchild = os.fdopen(c2pread, 'r', bufsize) - popen2._active.append(self) - - class executor: """This class runs stuff for us""" @@ -53,30 +33,12 @@ class executor: def run(self, command): """Run a command in a pipe dealing with stdout buffer overloads.""" - self.logger.debug('> %s' % command) - - runpipe = readonlypipe(command, bufsize=16384) - output = [] - try:#macosx doesn't like this - runpipe.fromchild.flush() - except IOError: - pass - line = runpipe.fromchild.readline() - cmdstat = -1 - while cmdstat == -1: - while line: - if len(line) > 0: - self.logger.debug('< %s' % line[:-1]) - output.append(line[:-1]) - line = runpipe.fromchild.readline() - time.sleep(0.1) - cmdstat = runpipe.poll() - output += [line[:-1] for line in runpipe.fromchild.readlines() \ - if line] - # The exit code from the program is in the upper byte of the - # value returned by cmdstat. Shift it down for tools looking at - # the value. - return ((cmdstat >> 8), output) + p = Popen(command, shell=True, bufsize=16384, + stdin=PIPE, stdout=PIPE, close_fds=True) + output = p.communicate()[0] + for line in output.splitlines(): + self.logger.debug('< %s' % line) + return (p.returncode, output.splitlines()) class Tool: @@ -185,7 +147,9 @@ class Tool: if 'failure' in entry.attrib: self.logger.error("Entry %s:%s reports bind failure: %s" % \ - (entry.tag, entry.get('name'), entry.get('failure'))) + (entry.tag, + entry.get('name'), + entry.get('failure'))) return False missing = [attr for attr in self.__req__[entry.tag] \ @@ -198,7 +162,8 @@ class Tool: try: self.gatherCurrentData(entry) except: - self.logger.error("Unexpected error in gatherCurrentData", exc_info=1) + self.logger.error("Unexpected error in gatherCurrentData", + exc_info=1) return False return True @@ -255,7 +220,8 @@ class PkgTool(Tool): self.logger.info("Trying single pass package install for pkgtype %s" % \ self.pkgtype) - data = [tuple([pkg.get(field) for field in self.pkgtool[1][1]]) for pkg in packages] + data = [tuple([pkg.get(field) for field in self.pkgtool[1][1]]) + for pkg in packages] pkgargs = " ".join([self.pkgtool[1][0] % datum for datum in data]) self.logger.debug("Installing packages: :%s:" % pkgargs) @@ -348,7 +314,9 @@ class SvcTool(Tool): return for entry in [ent for ent in bundle if self.handlesEntry(ent)]: - if entry.get('mode', 'default') == 'manual': + mode = entry.get('mode', 'default') + if mode == 'manual' or \ + (mode == 'interactive_only' and not self.setup['interactive']): continue # need to handle servicemode = (build|default) # need to handle mode = (default|supervised) @@ -358,7 +326,12 @@ class SvcTool(Tool): else: if self.setup['interactive']: prompt = 'Restart service %s?: (y/N): ' % entry.get('name') - if raw_input(prompt) not in ['y', 'Y']: + # py3k compatibility + try: + ans = raw_input(prompt) + except NameError: + ans = input(prompt) + if ans not in ['y', 'Y']: continue rc = self.restart_service(entry) else: diff --git a/src/lib/Client/Tools/launchd.py b/src/lib/Client/Tools/launchd.py index db6d94c1b..03dd97e71 100644 --- a/src/lib/Client/Tools/launchd.py +++ b/src/lib/Client/Tools/launchd.py @@ -82,6 +82,11 @@ class launchd(Bcfg2.Client.Tools.Tool): def InstallService(self, entry): """Enable or disable launchd item.""" + # don't take any actions for mode='manual' + if entry.get('mode', 'default') == 'manual': + self.logger.info("Service %s mode set to manual. Skipping " + "installation." % (entry.get('name'))) + return False name = entry.get('name') if entry.get('status') == 'on': self.logger.error("Installing service %s" % name) |