8877f410e7c034f24884a65b97feefd623220130
[sfa.git] / sfa / planetlab / plshell.py
1 import sys
2 import xmlrpclib
3 import socket
4 from urlparse import urlparse
5
6 from sfa.util.sfalogging import logger
7
8
9 class PlShell:
10     """
11     A simple xmlrpc shell to a myplc instance
12     This class can receive all PLCAPI calls to the underlying testbed
13     For safety this is limited to a set of hard-coded calls
14     """
15
16     direct_calls = ['AddNode', 'AddPerson', 'AddPersonKey', 'AddPersonToSite',
17                     'AddPersonToSlice', 'AddRoleToPerson', 'AddSite', 'AddSiteTag', 'AddSlice',
18                     'AddSliceTag', 'AddSliceToNodes', 'BindObjectToPeer', 'DeleteKey',
19                     'DeleteNode', 'DeletePerson', 'DeletePersonFromSlice', 'DeleteSite',
20                     'DeleteSlice', 'DeleteSliceFromNodes', 'DeleteSliceTag', 'GetInitScripts',
21                     'GetInterfaces', 'GetKeys', 'GetNodeTags', 'GetPeers',
22                     'GetPersons', 'GetSlices', 'GetSliceTags', 'GetTagTypes',
23                     'UnBindObjectFromPeer', 'UpdateNode', 'UpdatePerson', 'UpdateSite',
24                     'UpdateSlice', 'UpdateSliceTag',
25                     # also used as-is in importer
26                     'GetSites', 'GetNodes',
27                     # Lease management methods
28                     'GetLeases', 'GetLeaseGranularity', 'DeleteLeases', 'UpdateLeases',
29                     'AddLeases',
30                     # HRN management methods
31                     'SetPersonHrn', 'GetPersonHrn', 'SetSliceHrn', 'GetSliceHrn',
32                     'SetNodeHrn', 'GetNodeHrn', 'GetSiteHrn', 'SetSiteHrn',
33                     # Tag slice/person/site created by SFA
34                     'SetPersonSfaCreated', 'GetPersonSfaCreated', 'SetSliceSfaCreated',
35                     'GetSliceSfaCreated', 'SetNodeSfaCreated', 'GetNodeSfaCreated',
36                     'GetSiteSfaCreated', 'SetSiteSfaCreated',
37                     ]
38     # support for other names - this is experimental
39     alias_calls = {'get_authorities': 'GetSites',
40                    'get_nodes': 'GetNodes',
41                    }
42
43     # use the 'capability' auth mechanism for higher performance when the PLC
44     # db is local
45     def __init__(self, config):
46         url = config.SFA_PLC_URL
47         # try to figure if the url is local
48         hostname = urlparse(url).hostname
49         is_local = False
50         if hostname == 'localhost':
51             is_local = True
52         # otherwise compare IP addresses;
53         # this might fail for any number of reasons, so let's harden that
54         try:
55             # xxx todo this seems to result in a DNS request for each incoming request to the AM
56             # should be cached or improved
57             url_ip = socket.gethostbyname(hostname)
58             local_ip = socket.gethostbyname(socket.gethostname())
59             if url_ip == local_ip:
60                 is_local = True
61         except:
62             pass
63
64         if is_local:
65             try:
66                 # too bad this is not installed properly
67                 plcapi_path = "/usr/share/plc_api"
68                 if plcapi_path not in sys.path:
69                     sys.path.append(plcapi_path)
70                 import PLC.Shell
71                 plc_direct_access = True
72             except:
73                 plc_direct_access = False
74         if is_local and plc_direct_access:
75             logger.info('plshell access - capability')
76             self.plauth = {'AuthMethod': 'capability',
77                            'Username':   str(config.SFA_PLC_USER),
78                            'AuthString': str(config.SFA_PLC_PASSWORD),
79                            }
80             self.proxy = PLC.Shell.Shell()
81
82         else:
83             logger.info('plshell access - xmlrpc')
84             self.plauth = {'AuthMethod': 'password',
85                            'Username':   str(config.SFA_PLC_USER),
86                            'AuthString': str(config.SFA_PLC_PASSWORD),
87                            }
88             self.proxy = xmlrpclib.Server(url, verbose=False, allow_none=True)
89
90     def __getattr__(self, name):
91         def func(*args, **kwds):
92             actual_name = None
93             if name in PlShell.direct_calls:
94                 actual_name = name
95             if name in PlShell.alias_calls:
96                 actual_name = PlShell.alias_calls[name]
97             if not actual_name:
98                 raise Exception(
99                     "Illegal method call %s for PL driver" % (name))
100             result = getattr(self.proxy, actual_name)(
101                 self.plauth, *args, **kwds)
102             logger.debug('PlShell %s (%s) returned ... ' % (name, actual_name))
103             return result
104         return func