fixed broken slice-creation
[nodemanager.git] / plcapi.py
1 # $Id$
2 # $URL$
3
4 import safexmlrpc
5 import hmac, sha
6 import logger
7
8 class PLCAPI:
9     """
10     Wrapper around safexmlrpc.ServerProxy to automagically add an Auth
11     struct as the first argument to every XML-RPC call. Initialize
12     auth with either:
13
14     (node_id, key) => BootAuth
15     or
16     session => SessionAuth
17
18     To authenticate using the Boot Manager authentication method, or
19     the new session-based method.
20     """
21
22     def __init__(self, uri, cacert, auth, timeout = 90, **kwds):
23         self.uri = uri
24         self.cacert = cacert
25         self.timeout = timeout
26
27         if isinstance(auth, (tuple, list)):
28             (self.node_id, self.key) = auth
29             self.session = None
30         elif isinstance(auth, (str, unicode)):
31             self.node_id = self.key = None
32             self.session = auth
33         else:
34             self.node_id = self.key = self.session = None
35
36         self.server = safexmlrpc.ServerProxy(self.uri, self.cacert, self.timeout, allow_none = 1, **kwds)
37
38
39     def update_session(self, f="/usr/boot/plnode.txt"):
40         # try authenticatipopulate /etc.planetlab/session 
41         def plnode(key):
42             try:
43                 return [i[:-1].split('=') for i in open(f).readlines() if i.startswith(key)][0][1].strip('"')
44             except:
45                 return None
46
47         auth = (int(plnode("NODE_ID")), plnode("NODE_KEY"))
48         plc = PLCAPI(self.uri, self.cacert, auth, self.timeout)
49         open("/etc/planetlab/session", 'w').write(plc.GetSession().strip())
50         self.session = open("/etc/planetlab/session").read().strip()
51
52         
53     def check_authentication(self):
54         authstatus = False
55         if self.key or self.session:
56             try: 
57                 authstatus = self.AuthCheck()
58             except: 
59                 logger.log_exc("failed in plcapi.check_authentication")
60         return authstatus
61
62
63     def add_auth(self, function):
64         """
65         Returns a wrapper which adds an Auth struct as the first
66         argument when the function is called.
67         """
68
69         def canonicalize(args):
70             """
71             BootAuth canonicalization method. Parameter values are
72             collected, sorted, converted to strings, then hashed with
73             the node key.
74             """
75
76             values = []
77
78             for arg in args:
79                 if isinstance(arg, list) or isinstance(arg, tuple):
80                     # The old implementation did not recursively handle
81                     # lists of lists. But neither did the old API itself.
82                     values += canonicalize(arg)
83                 elif isinstance(arg, dict):
84                     # Yes, the comments in the old implementation are
85                     # misleading. Keys of dicts are not included in the
86                     # hash.
87                     values += canonicalize(arg.values())
88                 else:
89                     # We use unicode() instead of str().
90                     values.append(unicode(arg))
91
92             return values
93
94         def wrapper(*params):
95             """
96             Adds an Auth struct as the first argument when the
97             function is called.
98             """
99
100             if self.session is not None:
101                 # Use session authentication
102                 auth = {'AuthMethod': "session",
103                         'session': self.session}
104             else:
105                 # Yes, this is the "canonicalization" method used.
106                 args = canonicalize(params)
107                 args.sort()
108                 msg = "[" + "".join(args) + "]"
109
110                 # We encode in UTF-8 before calculating the HMAC, which is
111                 # an 8-bit algorithm.
112                 digest = hmac.new(self.key, msg.encode('utf-8'), sha).hexdigest()
113
114                 auth = {'AuthMethod': "hmac",
115                         'node_id': self.node_id,
116                         'value': digest}
117
118             # Automagically add auth struct to every call
119             params = (auth,) + params
120
121             return function(*params)
122
123         return wrapper
124
125     def __getattr__(self, methodname):
126         function = getattr(self.server, methodname)
127         return self.add_auth(function)