diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/lib/Client/Proxy.py | 92 | ||||
-rw-r--r-- | src/lib/Client/__init__.py | 2 | ||||
-rwxr-xr-x | src/sbin/bcfg2 | 56 |
3 files changed, 98 insertions, 52 deletions
diff --git a/src/lib/Client/Proxy.py b/src/lib/Client/Proxy.py new file mode 100644 index 000000000..d300eac72 --- /dev/null +++ b/src/lib/Client/Proxy.py @@ -0,0 +1,92 @@ +'''Cobalt proxy provides client access to cobalt components''' +__revision__ = '$Revision:$' + +import logging, socket, time, xmlrpclib, ConfigParser + +class CobaltComponentError(Exception): + '''This error signals component connection errors''' + pass + +class SafeProxy: + '''Wrapper for proxy''' + _cfile = ConfigParser.ConfigParser() + _cfile.read(['/etc/cobalt.conf']) + _components = _cfile._sections['components'] + _authinfo = ('root', _cfile.get('communication', 'password')) + _retries = 4 + + def __init__(self, component, url=None): + self.component = component + self.log = logging.getLogger(component) + if url != None: + address = url + else: + address = self.__get_location(component) + try: + self.proxy = xmlrpclib.ServerProxy(address) + except IOError, io_error: + self.log.error("Invalid server URL %s: %s" % (address, io_error)) + raise CobaltComponentError + except: + self.log.error("Failed to initialize xml-rpc", exc_info=1) + + def run_method(self, method_name, method_args): + ''' Perform an XMLRPC invocation against the server''' + method = getattr(self.proxy, method_name) + for irs in range(self._retries): + try: + ret = apply(method, self._authinfo + method_args) + if irs > 0: + self.log.warning("Required %d attempts to contact %s for operation %s" % + (irs, self.component, method_name)) + self.log.debug("%s completed successfully" % (method_name)) + return ret + except xmlrpclib.ProtocolError: + self.log.error("Server failure: Protocol Error") + raise xmlrpclib.Fault(20, "Server Failure") + except xmlrpclib.Fault: + self.log.debug("Operation %s completed with fault" % (method_name)) + raise + except socket.error: + self.log.debug("Attempting %s (%d of %d) failed" % (method_name, (irs+1), self._retries)) + time.sleep(0.5) + except: + break + self.log.error("%s failed:\nCould not connect to %s" % (method_name, self.component)) + + def __get_location(self, name): + '''Perform component location lookups if needed''' + if self._components.has_key(name): + return self._components[name] + slp = SafeProxy('service-location', url=self._cfile.get('components', 'service-location')) + try: + sdata = slp.run_method('LookupService', + ([{'tag':'location', 'name':name, 'url':'*'}],)) + except xmlrpclib.Fault: + raise CobaltComponentError, "No Such Component" + if sdata: + curl = sdata[0]['url'] + self._components[name] = curl + return curl + +class ComponentProxy(SafeProxy): + '''Component Proxy instantiates a SafeProxy to a component and registers local functions + based on its definition''' + name = 'dummy' + methods = [] + + def __init__(self, url=None): + SafeProxy.__init__(self, self.name, url) + for method in self.methods: + setattr(self, method, eval('lambda *x:self.run_method(method, x)', + {'self':self, 'method':method})) + +class service_location(ComponentProxy): + '''service-location component-specific proxy''' + name = 'service-location' + methods = ['AssertService', 'LookupService', 'DeassertService'] + +class process_manager(ComponentProxy): + '''process manager specific component proxy''' + name = 'process-manager' + methods = ['CreateProcessGroup', 'GetProcessGroup'] diff --git a/src/lib/Client/__init__.py b/src/lib/Client/__init__.py index 0435249f7..bfdbc0e98 100644 --- a/src/lib/Client/__init__.py +++ b/src/lib/Client/__init__.py @@ -1,4 +1,4 @@ '''This contains all Bcfg2 Client modules''' __revision__ = '$Revision$' -__all__ = ["Toolset", "Debian", "Solaris", "Redhat", "Gentoo"] +__all__ = ["Proxy", "Toolset", "Debian", "Solaris", "Redhat", "Gentoo"] diff --git a/src/sbin/bcfg2 b/src/sbin/bcfg2 index fcc3a757c..842c5666b 100755 --- a/src/sbin/bcfg2 +++ b/src/sbin/bcfg2 @@ -9,12 +9,13 @@ from signal import signal, SIGINT from sys import argv from tempfile import mktemp from ConfigParser import ConfigParser, NoSectionError, NoOptionError -from xmlrpclib import ServerProxy, Fault from lxml.etree import Element, XML, tostring, XMLSyntaxError -from time import sleep, time +from time import time from sys import exc_info from traceback import extract_tb -import socket + +import xmlrpclib +import Bcfg2.Client.Proxy def cb_sigint_handler(signum, frame): '''Exit upon CTRL-C''' @@ -27,53 +28,6 @@ def if_then(cond, value_if, value_else): else: return value_else -class SafeProxy: - '''Wrapper for proxy''' - def __init__(self, setup, client): - self.retryCount = 0 - self.client = client - self.setup = setup - try: - self.proxy = ServerProxy(self.setup["server"]) - except IOError, io_error: - self.client.fatal_error("Invalid server URL %s: %s" % - (self.setup["server"], io_error)) - except: - self.client.critical_error("initialising XML-RPC") - - def run_method(self, operation_desc, method_name, method_args): - ''' Perform an XMLRPC invocation against the server''' - method = getattr(self.proxy, method_name) - instance_retries = 0 - for i in xrange(int(self.setup["retries"])): - try: - self.client.cond_print("debug", "Attempting %s (%d of %d)" % - (operation_desc,(i+1), - int(self.setup["retries"]))) - ret = apply(method, (self.setup['user'], - self.setup['password']) + method_args) - if instance_retries > 0: - self.client.warning_error( - "during %s:\nRequired %d attempts to contact server (%s)" - % (operation_desc, instance_retries, - self.setup["server"])) - self.client.cond_print("debug", "%s completed successfully" % - (operation_desc)) - return ret - except Fault, fault: - self.client.fatal_error("%s encountered a server error:\n%s" % - (operation_desc, fault)) - except socket.error: - instance_retries += 1 - self.retryCount += 1 - sleep(1.0) - except: - self.client.critical_error(operation_desc) - - self.client.fatal_error("%s failed:\nCould not connect to server (%s)" % - (operation_desc, self.setup["server"])) - - class Client: ''' The main bcfg2 client class ''' def __init__(self, args): @@ -354,7 +308,7 @@ class Client: % (self.setup['file'])) else: # retrieve config from server - proxy = SafeProxy(self.setup, self) + proxy = Bcfg2.Client.Proxy.SafeProxy(self.setup, self) probe_data = proxy.run_method("probe download", "GetProbes", ()) |