summaryrefslogtreecommitdiffstats
path: root/src/lib/Client/Tools/__init__.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/Client/Tools/__init__.py')
-rw-r--r--src/lib/Client/Tools/__init__.py353
1 files changed, 0 insertions, 353 deletions
diff --git a/src/lib/Client/Tools/__init__.py b/src/lib/Client/Tools/__init__.py
deleted file mode 100644
index c6cb6e239..000000000
--- a/src/lib/Client/Tools/__init__.py
+++ /dev/null
@@ -1,353 +0,0 @@
-"""This contains all Bcfg2 Tool modules"""
-import os
-import stat
-import sys
-from subprocess import Popen, PIPE
-import time
-
-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"]
-
-drivers = [item for item in __all__ if item not in ['rpmtools']]
-default = [item for item in drivers if item not in ['RPM', 'Yum']]
-
-
-class toolInstantiationError(Exception):
- """This error is called if the toolset cannot be instantiated."""
- pass
-
-
-class executor:
- """This class runs stuff for us"""
-
- def __init__(self, logger):
- self.logger = logger
-
- def run(self, command):
- """Run a command in a pipe dealing with stdout buffer overloads."""
- 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:
- """
- All tools subclass this. It defines all interfaces that need to be defined.
- """
- name = 'Tool'
- __execs__ = []
- __handles__ = []
- __req__ = {}
- __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__'):
- self.__ireq__ = self.__req__
- self.config = config
- self.cmd = executor(logger)
- self.modified = []
- self.extra = []
- self.handled = [entry for struct in self.config for entry in struct \
- if self.handlesEntry(entry)]
- for filename in self.__execs__:
- try:
- mode = stat.S_IMODE(os.stat(filename)[stat.ST_MODE])
- if mode & stat.S_IEXEC != stat.S_IEXEC:
- self.logger.debug("%s: %s not executable" % \
- (self.name, filename))
- raise toolInstantiationError
- except OSError:
- raise toolInstantiationError
- except:
- self.logger.debug("%s failed" % filename, exc_info=1)
- raise toolInstantiationError
-
- def BundleUpdated(self, _, states):
- """This callback is used when bundle updates occur."""
- return
-
- def BundleNotUpdated(self, _, states):
- """This callback is used when a bundle is not updated."""
- return
-
- def Inventory(self, states, structures=[]):
- """Dispatch verify calls to underlying methods."""
- if not structures:
- structures = self.config.getchildren()
- mods = self.buildModlist()
- for (struct, entry) in [(struct, entry) for struct in structures \
- for entry in struct.getchildren() \
- if self.canVerify(entry)]:
- try:
- func = getattr(self, "Verify%s" % (entry.tag))
- states[entry] = func(entry, mods)
- except:
- self.logger.error(
- "Unexpected failure of verification method for entry type %s" \
- % (entry.tag), exc_info=1)
- self.extra = self.FindExtra()
-
- def Install(self, entries, states):
- """Install all entries in sublist."""
- for entry in entries:
- 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)
-
- def Remove(self, entries):
- """Remove specified extra entries"""
- pass
-
- def getSupportedEntries(self):
- """Return a list of supported entries."""
- return [entry for struct in \
- self.config.getchildren() for entry in \
- struct.getchildren() \
- if self.handlesEntry(entry)]
-
- def handlesEntry(self, entry):
- """Return if entry is handled by this tool."""
- return (entry.tag, entry.get('type')) in self.__handles__
-
- def buildModlist(self):
- '''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']]
-
- def gatherCurrentData(self, entry):
- """Default implementation of the information gathering routines."""
- pass
-
- def canVerify(self, entry):
- """Test if entry has enough information to be verified."""
- if not self.handlesEntry(entry):
- return False
-
- if 'failure' in entry.attrib:
- self.logger.error("Entry %s:%s reports bind failure: %s" % \
- (entry.tag,
- entry.get('name'),
- entry.get('failure')))
- return False
-
- missing = [attr for attr in self.__req__[entry.tag] \
- if attr not in entry.attrib]
- 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)))
- try:
- self.gatherCurrentData(entry)
- except:
- self.logger.error("Unexpected error in gatherCurrentData",
- exc_info=1)
- return False
- return True
-
- def FindExtra(self):
- """Return a list of extra entries."""
- return []
-
- def canInstall(self, entry):
- """Test if entry has enough information to be installed."""
- if not self.handlesEntry(entry):
- return False
-
- if 'failure' in entry.attrib:
- self.logger.error("Cannot install entry %s:%s with bind failure" % \
- (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]]
- 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)))
- return False
- return True
-
-
-class PkgTool(Tool):
- """
- PkgTool provides a one-pass install with
- fallback for use with packaging systems
- """
- pkgtool = ('echo %s', ('%s', ['name']))
- pkgtype = 'echo'
- name = 'PkgTool'
-
- def __init__(self, logger, setup, config):
- Tool.__init__(self, logger, setup, config)
- self.installed = {}
- self.Remove = self.RemovePackages
- self.FindExtra = self.FindExtraPackages
- self.RefreshPackages()
-
- def VerifyPackage(self, dummy, _):
- """Dummy verification method"""
- return False
-
- def Install(self, packages, states):
- """
- Run a one-pass install, followed by
- single pkg installs in case of failure.
- """
- 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]
- pkgargs = " ".join([self.pkgtool[1][0] % datum for datum in data])
-
- self.logger.debug("Installing packages: :%s:" % pkgargs)
- self.logger.debug("Running command ::%s::" % (self.pkgtool[0] % pkgargs))
-
- cmdrc = self.cmd.run(self.pkgtool[0] % pkgargs)[0]
- if cmdrc == 0:
- self.logger.info("Single Pass Succeded")
- # set all package states to true and flush workqueues
- pkgnames = [pkg.get('name') for pkg in packages]
- for entry in [entry for entry in list(states.keys())
- if entry.tag == 'Package'
- and entry.get('type') == self.pkgtype
- and entry.get('name') in pkgnames]:
- self.logger.debug('Setting state to true for pkg %s' % \
- (entry.get('name')))
- states[entry] = True
- self.RefreshPackages()
- else:
- self.logger.error("Single Pass Failed")
- # do single pass installs
- self.RefreshPackages()
- for pkg in packages:
- # handle state tracking updates
- if self.VerifyPackage(pkg, []):
- self.logger.info("Forcing state to true for pkg %s" % \
- (pkg.get('name')))
- states[pkg] = True
- else:
- self.logger.info("Installing pkg %s version %s" %
- (pkg.get('name'), pkg.get('version')))
- cmdrc = self.cmd.run(self.pkgtool[0] %
- (self.pkgtool[1][0] %
- tuple([pkg.get(field) for field in self.pkgtool[1][1]])))
- if cmdrc[0] == 0:
- states[pkg] = True
- else:
- self.logger.error("Failed to install package %s" % \
- (pkg.get('name')))
- self.RefreshPackages()
- for entry in [ent for ent in packages if states[ent]]:
- self.modified.append(entry)
-
- def RefreshPackages(self):
- """Dummy state refresh method."""
- pass
-
- def RemovePackages(self, packages):
- """Dummy implementation of package removal method."""
- pass
-
- def FindExtraPackages(self):
- """Find extra packages."""
- packages = [entry.get('name') for entry in self.getSupportedEntries()]
- extras = [data for data in list(self.installed.items()) \
- if data[0] not in packages]
- return [Bcfg2.Client.XML.Element('Package', name=name, \
- type=self.pkgtype, version=version) \
- for (name, version) in extras]
-
-
-class SvcTool(Tool):
- """This class defines basic Service behavior"""
- name = 'SvcTool'
-
- def __init__(self, logger, setup, config):
- Tool.__init__(self, logger, setup, config)
- self.restarted = []
-
- def get_svc_command(self, service, action):
- """Return the basename of the command used to start/stop services."""
- return '/etc/init.d/%s %s' % (service.get('name'), action)
-
- def start_service(self, service):
- self.logger.debug('Starting service %s' % service.get('name'))
- return self.cmd.run(self.get_svc_command(service, 'start'))[0]
-
- def stop_service(self, service):
- self.logger.debug('Stopping service %s' % service.get('name'))
- return self.cmd.run(self.get_svc_command(service, 'stop'))[0]
-
- def restart_service(self, service):
- self.logger.debug('Restarting service %s' % service.get('name'))
- restart_target = service.get('target', 'restart')
- return self.cmd.run(self.get_svc_command(service, restart_target))[0]
-
- def check_service(self, service):
- # not supported for this driver
- return 0
-
- def Remove(self, services):
- """ Dummy implementation of service removal method """
- if self.setup['servicemode'] != 'disabled':
- for entry in services:
- entry.set("status", "off")
- self.InstallService(entry)
-
- def BundleUpdated(self, bundle, states):
- """The Bundle has been updated."""
- if self.setup['servicemode'] == 'disabled':
- 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
- 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':
- rc = self.stop_service(entry)
- elif entry.get('name') not in self.restarted:
- 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)
- if ans not in ['y', 'Y']:
- continue
- rc = self.restart_service(entry)
- if not rc:
- self.restarted.append(entry.get('name'))
- else:
- rc = self.stop_service(entry)
- if rc:
- self.logger.error("Failed to manipulate service %s" %
- (entry.get('name')))