-
Notifications
You must be signed in to change notification settings - Fork 1
/
plcapi.py
129 lines (104 loc) · 4.2 KB
/
plcapi.py
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
import safexmlrpc
import hmac
try:
from hashlib import sha1 as sha
except ImportError:
import sha
import logger
class PLCAPI:
"""
Wrapper around safexmlrpc.ServerProxy to automagically add an Auth
struct as the first argument to every XML-RPC call. Initialize
auth with either:
(node_id, key) => BootAuth
or
session => SessionAuth
To authenticate using the Boot Manager authentication method, or
the new session-based method, respectively.
"""
def __init__(self, uri, cacert, auth, timeout = 90, **kwds):
self.uri = uri
self.cacert = cacert
self.timeout = timeout
if isinstance(auth, (tuple, list)):
(self.node_id, self.key) = auth
self.session = None
elif isinstance(auth, (str, unicode)):
self.node_id = self.key = None
self.session = auth
else:
self.node_id = self.key = self.session = None
self.server = safexmlrpc.ServerProxy(self.uri, self.cacert, self.timeout, allow_none = 1, **kwds)
logger.log("uri is %s"%self.uri)
def update_session(self, f="/usr/boot/plnode.txt"):
# try authenticatipopulate /etc.planetlab/session
def plnode(key):
try:
return [i[:-1].split('=') for i in open(f).readlines() if i.startswith(key)][0][1].strip('"')
except:
return None
auth = (int(plnode("NODE_ID")), plnode("NODE_KEY"))
plc = PLCAPI(self.uri, self.cacert, auth, self.timeout)
open("/etc/planetlab/session", 'w').write(plc.GetSession().strip())
self.session = open("/etc/planetlab/session").read().strip()
def check_authentication(self):
authstatus = False
if self.key or self.session:
try:
authstatus = self.AuthCheck()
except:
logger.log_exc("plcapi: failed in plcapi.check_authentication")
return authstatus
def add_auth(self, function):
"""
Returns a wrapper which adds an Auth struct as the first
argument when the function is called.
"""
def canonicalize(args):
"""
BootAuth canonicalization method. Parameter values are
collected, sorted, converted to strings, then hashed with
the node key.
"""
values = []
for arg in args:
if isinstance(arg, list) or isinstance(arg, tuple):
# The old implementation did not recursively handle
# lists of lists. But neither did the old API itself.
values += canonicalize(arg)
elif isinstance(arg, dict):
# Yes, the comments in the old implementation are
# misleading. Keys of dicts are not included in the
# hash.
values += canonicalize(arg.values())
else:
# We use unicode() instead of str().
values.append(unicode(arg))
return values
def wrapper(*params):
"""
Adds an Auth struct as the first argument when the
function is called.
"""
if self.session is not None:
# Use session authentication
auth = {'AuthMethod': "session",
'session': self.session}
else:
# Yes, this is the "canonicalization" method used.
args = canonicalize(params)
args.sort()
msg = "[" + "".join(args) + "]"
# We encode in UTF-8 before calculating the HMAC, which is
# an 8-bit algorithm.
digest = hmac.new(self.key, msg.encode('utf-8'), sha).hexdigest()
auth = {'AuthMethod': "hmac",
'node_id': self.node_id,
'value': digest}
# Automagically add auth struct to every call
params = (auth,) + params
return function(*params)
return wrapper
def __getattr__(self, methodname):
function = getattr(self.server, methodname)
return self.add_auth(function)