summaryrefslogtreecommitdiffstats
path: root/src/lib/Client/Proxy.py
blob: a809e70f837c3a0f6430a38eb9573e170d776176 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
'''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/bcfg2.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, serr:
                self.log.debug("Attempting %s (%d of %d) failed because %s" % (method_name, (irs+1),
                                                                               self._retries, serr))
                time.sleep(0.5)                
            except:
                self.log.error("Unknown failure", exc_info=1)
                break
        raise xmlrpclib.Fault(20, 'Server Failure')
        
    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']

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