summaryrefslogtreecommitdiffstats
path: root/src/lib/Client
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/Client')
-rw-r--r--src/lib/Client/Frame.py33
-rw-r--r--src/lib/Client/Tools/APT.py6
-rw-r--r--src/lib/Client/Tools/Action.py7
-rw-r--r--src/lib/Client/Tools/Chkconfig.py5
-rw-r--r--src/lib/Client/Tools/DebInit.py9
-rw-r--r--src/lib/Client/Tools/POSIX.py29
-rw-r--r--src/lib/Client/Tools/Pacman.py2
-rw-r--r--src/lib/Client/Tools/RcUpdate.py5
-rw-r--r--src/lib/Client/Tools/SMF.py5
-rw-r--r--src/lib/Client/Tools/Systemd.py59
-rw-r--r--src/lib/Client/Tools/Upstart.py9
-rw-r--r--src/lib/Client/Tools/VCS.py137
-rw-r--r--src/lib/Client/Tools/YUM24.py54
-rw-r--r--src/lib/Client/Tools/YUMng.py35
-rw-r--r--src/lib/Client/Tools/__init__.py73
-rw-r--r--src/lib/Client/Tools/launchd.py5
16 files changed, 361 insertions, 112 deletions
diff --git a/src/lib/Client/Frame.py b/src/lib/Client/Frame.py
index 545d4b584..60d158eb1 100644
--- a/src/lib/Client/Frame.py
+++ b/src/lib/Client/Frame.py
@@ -8,6 +8,7 @@ import logging
import time
import Bcfg2.Client.Tools
+
def cmpent(ent1, ent2):
"""Sort entries."""
if ent1.tag != ent2.tag:
@@ -15,6 +16,7 @@ def cmpent(ent1, ent2):
else:
return cmp(ent1.get('name'), ent2.get('name'))
+
def promptFilter(prompt, entries):
"""Filter a supplied list based on user input."""
ret = []
@@ -25,7 +27,12 @@ def promptFilter(prompt, entries):
else:
iprompt = prompt % (entry.tag, entry.get('name'))
try:
- if raw_input(iprompt) in ['y', 'Y']:
+ # py3k compatibility
+ try:
+ ans = raw_input(iprompt)
+ except NameError:
+ ans = input(iprompt)
+ if ans in ['y', 'Y']:
ret.append(entry)
except EOFError:
# python 2.4.3 on CentOS doesn't like ^C for some reason
@@ -35,6 +42,7 @@ def promptFilter(prompt, entries):
continue
return ret
+
def matches_entry(entryspec, entry):
# both are (tag, name)
if entryspec == entry:
@@ -52,11 +60,16 @@ def matches_entry(entryspec, entry):
return False
return True
+
def matches_white_list(entry, whitelist):
- return True in [matches_entry(we, (entry.tag, entry.get('name'))) for we in whitelist]
+ return True in [matches_entry(we, (entry.tag, entry.get('name')))
+ for we in whitelist]
+
def passes_black_list(entry, blacklist):
- return True not in [matches_entry(be, (entry.tag, entry.get('name'))) for be in blacklist]
+ return True not in [matches_entry(be, (entry.tag, entry.get('name')))
+ for be in blacklist]
+
class Frame:
"""Frame is the container for all Tool objects and state information."""
@@ -134,8 +147,10 @@ class Frame:
self.logger.error(["%s:%s:%s" % (entry.tag, entry.get('type'), \
entry.get('name')) for entry in problems])
self.logger.error("")
- entries = [(entry.tag, entry.get('name')) for struct in config for entry in struct]
- pkgs = [(entry.get('name'), entry.get('origin')) for struct in config for entry in struct if entry.tag == 'Package']
+ entries = [(entry.tag, entry.get('name'))
+ for struct in config for entry in struct]
+ pkgs = [(entry.get('name'), entry.get('origin'))
+ for struct in config for entry in struct if entry.tag == 'Package']
multi = []
for entry in entries[:]:
if entries.count(entry) > 1:
@@ -151,7 +166,6 @@ class Frame:
self.logger.debug("The following packages are prereqs added by Packages:")
self.logger.debug([pkg[0] for pkg in pkgs if pkg[1] == 'Packages'])
-
def __getattr__(self, name):
if name in ['extra', 'handled', 'modified', '__important__']:
ret = []
@@ -186,10 +200,10 @@ class Frame:
if self.setup['remove']:
if self.setup['remove'] == 'all':
self.removal = self.extra
- elif self.setup['remove'] == 'services':
+ elif self.setup['remove'] in ['services', 'Services']:
self.removal = [entry for entry in self.extra \
if entry.tag == 'Service']
- elif self.setup['remove'] == 'packages':
+ elif self.setup['remove'] in ['packages', 'Packages']:
self.removal = [entry for entry in self.extra \
if entry.tag == 'Package']
@@ -268,7 +282,8 @@ class Frame:
if b_to_remv:
self.logger.info("Not installing entries from Bundle %s" % \
(bundle.get('name')))
- self.logger.info(["%s:%s" % (e.tag, e.get('name')) for e in b_to_remv])
+ self.logger.info(["%s:%s" % (e.tag, e.get('name'))
+ for e in b_to_remv])
[self.whitelist.remove(ent) for ent in b_to_remv]
if self.setup['interactive']:
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)