Logo Search packages:      
Sourcecode: bcfg2 version File versions  Download package

Proxy.py

00001 '''Cobalt proxy provides client access to cobalt components'''
__revision__ = '$Revision: 2467 $'

import logging, socket, sys, time, xmlrpclib, ConfigParser, httplib

class Bcfg2HTTPSConnection(httplib.HTTPSConnection):

    def connect(self):
        "Connect to a host on a given (SSL) port binding the socket to a specific local address"

        _cfile = ConfigParser.ConfigParser()
        if '-C' in sys.argv:
            _cfpath = sys.argv[sys.argv.index('-C') + 1]
        else:
            _cfpath = '/etc/bcfg2.conf'
            _cfile.read([_cfpath])      
        _bindaddress = ""
        try:
            _bindaddress = _cfile.get('communication', 'bindaddress')
        except:
            self.log.error("%s doesn't contain a valid bindadress value" % (_cfpath))
            raise SystemExit, 1

        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

        # the following line is the sole modification in comparison to the
        # connect() in httplib.HTTPSConnection 
        sock.bind((_bindaddress,0))

        sock.connect((self.host, self.port))
        ssl = socket.ssl(sock, self.key_file, self.cert_file) 
        self.sock = httplib.FakeSocket(sock, ssl)

00034 class Bcfg2HTTPS(httplib.HTTPS):
    """Own HTTPS class for overriding the _connection_class value"""
    
    _connection_class = Bcfg2HTTPSConnection # instead of HTTPSConnection from httplib


00040 class Bcfg2SafeTransport(xmlrpclib.Transport):
    """Own SafeTransport class for overriding the HTTPS object"""

    def make_connection(self, host):

        # create a HTTPS connection object from a host descriptor
        # host may be a string, or a (host, x509-dict) tuple
        import httplib
        host, extra_headers, x509 = self.get_host_info(host)
        try:
            HTTPS = Bcfg2HTTPS  # instead of HTTPS from httplib
        except AttributeError:
            raise NotImplementedError(
                "your version of httplib doesn't support HTTPS"
                )
        else:
            return HTTPS(host, None, **(x509 or {}))


00059 class SafeProxy:
    '''Wrapper for proxy'''
    _cfile = ConfigParser.ConfigParser()
    if '-C' in sys.argv:
        _cfpath = sys.argv[sys.argv.index('-C') + 1]
    else:
        _cfpath = '/etc/bcfg2.conf'
    _cfile.read([_cfpath])
    try:
        _components = _cfile._sections['components']
    except KeyError:
        print "%s doesn't contain a valid components section" % (_cfpath)
        raise SystemExit, 1
    try:
        _authinfo = ('root', _cfile.get('communication', 'password'))
    except KeyError:
        print "%s doesn't contain a valid communication setup" % (_cfpath)
        raise SystemExit, 1

    _bindaddress = ""
    try:
        _bindaddress = _cfile.get('communication', 'bindaddress')
    except:
        pass
        
    _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:
            if self._bindaddress != "":
                self.log.info("Binding client to address %s" % self._bindaddress)
                self.proxy = xmlrpclib.ServerProxy(address, transport=Bcfg2SafeTransport())
            else:
                self.proxy = xmlrpclib.ServerProxy(address, transport=xmlrpclib.SafeTransport())
        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)

00105     def run_method(self, methodName, methodArgs):
        ''' Perform an XMLRPC invocation against the server'''
        method = getattr(self.proxy, methodName)
        for irs in range(self._retries):
            try:
                ret = apply(method, self._authinfo + methodArgs)
                if irs > 0:
                    self.log.warning("Required %d attempts to contact %s for operation %s" %
                                     (irs, self.component, methodName))
                self.log.debug("%s completed successfully" % (methodName))
                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" % (methodName))
                raise
            except socket.sslerror:
                self.log.debug("Attempt %d of %d failed due to SSL negotiation failure" %
                               ((irs + 1), self._retries))
            except socket.error, serr:
                self.log.debug("Attempting %s (%d of %d) failed because %s" % (methodName, (irs+1),
                                                                               self._retries, serr))
            except:
                self.log.error("Unknown failure", exc_info=1)
                break
            time.sleep(0.5)
        self.log.error("%s failed:\nCould not connect to %s" % (methodName, self.component))
        raise xmlrpclib.Fault(20, "Server Failure")
        
00135     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

00150     def dummy(self):
        '''dummy method for pylint'''
        return True
            
00154 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}))

00166 class service_location(ComponentProxy):
    '''service-location component-specific proxy'''
    name = 'service-location'
    methods = ['AssertService', 'LookupService', 'DeassertService']

00171 class allocation_manager(ComponentProxy):
    '''allocation manager specific component proxy'''
    name = 'allocation-manager'
    methods = ['GetProject']

00176 class file_stager(ComponentProxy):
    '''File staging component'''
    name = 'file-stager'
    methods = ['StageInit', 'FinalizeStage']

00181 class process_manager(ComponentProxy):
    '''process manager specific component proxy'''
    name = 'process-manager'
    methods = ['CreateProcessGroup', 'GetProcessGroup', 'KillProcessGroup', 'WaitProcessGroup']

00186 class queue_manager(ComponentProxy):
    '''queue manager proxy'''
    name = 'queue-manager'
    methods = ['AddJob', 'GetJobs', 'DelJobs', 'RunJobs', 'SetJobs', 'SetJobID']

00191 class scheduler(ComponentProxy):
    '''scheduler proxy'''
    name = 'scheduler'
    methods = ['AddReservation', 'DelReservation', 'GetPartition', 'AddPartition', 'DelPartition', 'Set']

00196 class bcfg2(ComponentProxy):
    '''bcfg2 client code'''
    name = 'bcfg2'
    methods = ['AssertProfile', 'GetConfig', 'GetProbes', 'RecvProbeData', 'RecvStats']

00201 class CommDict(dict):
    '''CommDict is a dictionary that automatically instantiates a component proxy upon access'''
    commnames = {'pm':process_manager, 'fs':file_stager, 'am':allocation_manager,
                 'sched':scheduler, 'qm':queue_manager}

    def __getitem__(self, name):
        if not self.has_key(name):
            self.__setitem__(name, self.commnames[name]())
        return dict.__getitem__(self, name)

Generated by  Doxygen 1.6.0   Back to index