summaryrefslogtreecommitdiffstats
path: root/src/lib/Bcfg2/Client/Tools/__init__.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/Bcfg2/Client/Tools/__init__.py')
-rw-r--r--src/lib/Bcfg2/Client/Tools/__init__.py117
1 files changed, 78 insertions, 39 deletions
diff --git a/src/lib/Bcfg2/Client/Tools/__init__.py b/src/lib/Bcfg2/Client/Tools/__init__.py
index c6cb6e239..026c7ade0 100644
--- a/src/lib/Bcfg2/Client/Tools/__init__.py
+++ b/src/lib/Bcfg2/Client/Tools/__init__.py
@@ -1,16 +1,27 @@
"""This contains all Bcfg2 Tool modules"""
import os
-import stat
import sys
-from subprocess import Popen, PIPE
+import stat
import time
+import pkgutil
+from subprocess import Popen, PIPE
import Bcfg2.Client.XML
-
-__all__ = [tool.split('.')[0] \
- for tool in os.listdir(os.path.dirname(__file__)) \
- if tool.endswith(".py") and tool != "__init__.py"]
-
+from Bcfg2.Bcfg2Py3k import input
+
+if hasattr(pkgutil, 'walk_packages'):
+ submodules = pkgutil.walk_packages(path=__path__)
+else:
+ # python 2.4
+ import glob
+ submodules = []
+ for path in __path__:
+ for submodule in glob.glob(os.path.join(path, "*.py")):
+ mod = os.path.splitext(os.path.basename(submodule))[0]
+ if mod not in ['__init__']:
+ submodules.append((None, mod, True))
+
+__all__ = [m[1] for m in submodules]
drivers = [item for item in __all__ if item not in ['rpmtools']]
default = [item for item in drivers if item not in ['RPM', 'Yum']]
@@ -36,7 +47,7 @@ class executor:
return (p.returncode, output.splitlines())
-class Tool:
+class Tool(object):
"""
All tools subclass this. It defines all interfaces that need to be defined.
"""
@@ -47,10 +58,6 @@ class Tool:
__important__ = []
def __init__(self, logger, setup, config):
- self.__important__ = [entry.get('name') \
- for struct in config for entry in struct \
- if entry.tag == 'Path' and \
- entry.get('important') in ['true', 'True']]
self.setup = setup
self.logger = logger
if not hasattr(self, '__ireq__'):
@@ -59,8 +66,15 @@ class Tool:
self.cmd = executor(logger)
self.modified = []
self.extra = []
- self.handled = [entry for struct in self.config for entry in struct \
- if self.handlesEntry(entry)]
+ self.__important__ = []
+ self.handled = []
+ for struct in config:
+ for entry in struct:
+ if (entry.tag == 'Path' and
+ entry.get('important', 'false').lower() == 'true'):
+ self.__important__.append(entry.get('name'))
+ if self.handlesEntry(entry):
+ self.handled.append(entry)
for filename in self.__execs__:
try:
mode = stat.S_IMODE(os.stat(filename)[stat.ST_MODE])
@@ -130,12 +144,24 @@ class Tool:
'''Build a list of potentially modified POSIX paths for this entry'''
return [entry.get('name') for struct in self.config.getchildren() \
for entry in struct.getchildren() \
- if entry.tag in ['Ignore', 'Path']]
+ if entry.tag == 'Path']
def gatherCurrentData(self, entry):
"""Default implementation of the information gathering routines."""
pass
+ def missing_attrs(self, entry):
+ required = self.__req__[entry.tag]
+ if isinstance(required, dict):
+ required = ["type"]
+ try:
+ required.extend(self.__req__[entry.tag][entry.get("type")])
+ except KeyError:
+ pass
+
+ return [attr for attr in required
+ if attr not in entry.attrib or not entry.attrib[attr]]
+
def canVerify(self, entry):
"""Test if entry has enough information to be verified."""
if not self.handlesEntry(entry):
@@ -148,13 +174,12 @@ class Tool:
entry.get('failure')))
return False
- missing = [attr for attr in self.__req__[entry.tag] \
- if attr not in entry.attrib]
+ missing = self.missing_attrs(entry)
if missing:
- self.logger.error("Incomplete information for entry %s:%s; cannot verify" \
- % (entry.tag, entry.get('name')))
- self.logger.error("\t... due to absence of %s attribute(s)" % \
- (":".join(missing)))
+ self.logger.error("Cannot verify entry %s:%s due to missing "
+ "required attribute(s): %s" %
+ (entry.tag, entry.get('name'),
+ ", ".join(missing)))
try:
self.gatherCurrentData(entry)
except:
@@ -167,6 +192,11 @@ class Tool:
"""Return a list of extra entries."""
return []
+ def primarykey(self, entry):
+ """ return a string that should be unique amongst all entries
+ in the specification """
+ return "%s:%s" % (entry.tag, entry.get("name"))
+
def canInstall(self, entry):
"""Test if entry has enough information to be installed."""
if not self.handlesEntry(entry):
@@ -177,13 +207,12 @@ class Tool:
(entry.tag, entry.get('name')))
return False
- missing = [attr for attr in self.__ireq__[entry.tag] \
- if attr not in entry.attrib or not entry.attrib[attr]]
+ missing = self.missing_attrs(entry)
if missing:
- self.logger.error("Incomplete information for entry %s:%s; cannot install" \
- % (entry.tag, entry.get('name')))
- self.logger.error("\t... due to absence of %s attribute" % \
- (":".join(missing)))
+ self.logger.error("Incomplete information for entry %s:%s; cannot "
+ "install due to absence of attribute(s): %s" %
+ (entry.tag, entry.get('name'),
+ ", ".join(missing)))
return False
return True
@@ -305,8 +334,7 @@ class SvcTool(Tool):
return self.cmd.run(self.get_svc_command(service, restart_target))[0]
def check_service(self, service):
- # not supported for this driver
- return 0
+ return self.cmd.run(self.get_svc_command(service, 'status'))[0] == 0
def Remove(self, services):
""" Dummy implementation of service removal method """
@@ -321,13 +349,12 @@ class SvcTool(Tool):
return
for entry in [ent for ent in bundle if self.handlesEntry(ent)]:
- mode = entry.get('mode', 'default')
- if (mode == 'manual' or
- (mode == 'interactive_only' and
+ restart = entry.get("restart", "true")
+ if (restart.lower() == "false" or
+ (restart.lower == "interactive" and
not self.setup['interactive'])):
continue
- # need to handle servicemode = (build|default)
- # need to handle mode = (default|supervised)
+
rc = None
if entry.get('status') == 'on':
if self.setup['servicemode'] == 'build':
@@ -336,11 +363,7 @@ class SvcTool(Tool):
if self.setup['interactive']:
prompt = ('Restart service %s?: (y/N): ' %
entry.get('name'))
- # py3k compatibility
- try:
- ans = raw_input(prompt)
- except NameError:
- ans = input(prompt)
+ ans = input(prompt)
if ans not in ['y', 'Y']:
continue
rc = self.restart_service(entry)
@@ -351,3 +374,19 @@ class SvcTool(Tool):
if rc:
self.logger.error("Failed to manipulate service %s" %
(entry.get('name')))
+
+ def Install(self, entries, states):
+ """Install all entries in sublist."""
+ for entry in entries:
+ if entry.get('install', 'true').lower() == 'false':
+ self.logger.info("Service %s installation is false. Skipping "
+ "installation." % (entry.get('name')))
+ continue
+ try:
+ func = getattr(self, "Install%s" % (entry.tag))
+ states[entry] = func(entry)
+ if states[entry]:
+ self.modified.append(entry)
+ except:
+ self.logger.error("Unexpected failure of install method for entry type %s"
+ % (entry.tag), exc_info=1)