summaryrefslogtreecommitdiffstats
path: root/build/lib/Bcfg2/Client/Tools/__init__.py
diff options
context:
space:
mode:
Diffstat (limited to 'build/lib/Bcfg2/Client/Tools/__init__.py')
-rw-r--r--build/lib/Bcfg2/Client/Tools/__init__.py370
1 files changed, 0 insertions, 370 deletions
diff --git a/build/lib/Bcfg2/Client/Tools/__init__.py b/build/lib/Bcfg2/Client/Tools/__init__.py
deleted file mode 100644
index 8a90e130c..000000000
--- a/build/lib/Bcfg2/Client/Tools/__init__.py
+++ /dev/null
@@ -1,370 +0,0 @@
-"""This contains all Bcfg2 Tool modules"""
-# suppress popen2 warnings for python 2.3
-import warnings
-warnings.filterwarnings("ignore", "The popen2 module is deprecated.*",
- DeprecationWarning)
-import os
-import popen2
-import stat
-import sys
-import time
-
-import Bcfg2.Client.XML
-__revision__ = '$Revision$'
-
-__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 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"""
-
- def __init__(self, logger):
- self.logger = logger
-
- 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)
-
-
-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)
- 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 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 = 'restart'
- if service.get('mode', 'default') == 'custom':
- 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 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)]:
- if entry.get('mode', 'default') == 'manual':
- continue
- # need to handle servicemode = (build|default)
- # need to handle mode = (default|supervised|custom)
- if entry.get('status') == 'on':
- if self.setup['servicemode'] == 'build':
- rc = self.stop_service(entry)
- else:
- if self.setup['interactive']:
- prompt = 'Restart service %s?: (y/N): ' % entry.get('name')
- if raw_input(prompt) not in ['y', 'Y']:
- continue
- rc = self.restart_service(entry)
- else:
- rc = self.stop_service(entry)
- if rc:
- self.logger.error("Failed to manipulate service %s" % \
- (entry.get('name')))