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