3 # Copyright (c) 2003 Intel Corporation
6 # Copyright (c) 2004-2006 The Trustees of Princeton University
11 import xml.parsers.expat
18 from Exceptions import *
22 def create_auth_structure( vars, call_params ):
24 create and return an authentication structure for a Boot API
25 call. Vars contains the boot manager runtime variables, and
26 call_params is a tuple of the parameters that will be passed to the
27 API call. Return None if unable to (typically due to missing
28 keys in vars, such as node_id or node_key)
35 auth_session['AuthMethod'] = 'session'
37 if not vars.has_key('NODE_SESSION'):
38 # Try to load /etc/planetlab/session if it exists.
39 sessionfile = open('/etc/planetlab/session', 'r')
40 session = sessionfile.read().strip()
42 auth_session['session'] = session
43 # Test session. Faults if it's no good.
44 vars['API_SERVER_INST'].AuthCheck(auth_session)
45 vars['NODE_SESSION'] = session
49 auth_session['session'] = vars['NODE_SESSION']
54 import traceback; traceback.print_exc()
55 auth['AuthMethod']= 'hmac'
58 auth['node_id'] = vars['NODE_ID']
59 auth['node_ip'] = vars['INTERFACE_SETTINGS']['ip']
63 node_hmac= hmac.new(vars['NODE_KEY'], "[]".encode('utf-8'), sha).hexdigest()
64 auth['value']= node_hmac
67 if not vars.has_key('NODE_SESSION'):
68 session = vars['API_SERVER_INST'].GetSession(auth)
69 auth_session['session'] = session
70 vars['NODE_SESSION'] = session
71 # NOTE: save session value to /etc/planetlab/session for
72 # RunlevelAgent and future BootManager runs
73 sessionfile = open('/etc/planetlab/session', 'w')
74 sessionfile.write( vars['NODE_SESSION'] )
77 auth_session['session'] = vars['NODE_SESSION']
79 auth_session['AuthMethod'] = 'session'
89 def serialize_params( call_params ):
91 convert a list of parameters into a format that will be used in the
92 hmac generation. both the boot manager and plc must have a common
93 format. full documentation is in the boot manager technical document,
94 but essentially we are going to take all the values (and keys for
95 dictionary objects), and put them into a list. sort them, and combine
96 them into one long string encased in a set of braces.
101 for param in call_params:
102 if isinstance(param,list) or isinstance(param,tuple):
103 values += serialize_params(param)
104 elif isinstance(param,dict):
105 values += serialize_params(param.values())
106 elif isinstance(param,xmlrpclib.Boolean):
107 # bool was not a real type in Python <2.3 and had to be
108 # marshalled as a custom type in xmlrpclib. Make sure that
109 # bools serialize consistently.
111 values.append("True")
113 values.append("False")
115 values.append(unicode(param))
120 def call_api_function( vars, function, user_params ):
122 call the named api function with params, and return the
123 value to the caller. the authentication structure is handled
124 automatically, and doesn't need to be passed in with params.
126 If the call fails, a BootManagerException is raised.
131 api_server= vars['API_SERVER_INST']
133 raise BootManagerException, "No connection to the API server exists."
135 if api_server is None:
139 if i[0] == function and i[1] == user_params:
141 raise BootManagerException, \
142 "Disconnected operation failed, insufficient stash."
144 auth= create_auth_structure(vars,user_params)
146 raise BootManagerException, \
147 "Could not create auth structure, missing values."
150 params= params + user_params
153 exec( "rc= api_server.%s(*params)" % function )
156 stash += [ [ function, user_params, rc ] ]
158 except xmlrpclib.Fault, fault:
159 raise BootManagerException, "API Fault: %s" % fault
160 except xmlrpclib.ProtocolError, err:
161 raise BootManagerException,"XML RPC protocol error: %s" % err
162 except xml.parsers.expat.ExpatError, err:
163 raise BootManagerException,"XML parsing error: %s" % err
167 mntpnt = '/tmp/stash'
168 def __init__(self, vars, mode):
169 utils.makedirs(self.mntpnt)
171 utils.sysexec('mount -t auto -U %s %s' % (vars['DISCONNECTED_OPERATION'], self.mntpnt))
172 # make sure it's not read-only
173 f = file('%s/api.cache' % self.mntpnt, 'a')
175 file.__init__(self, '%s/api.cache' % self.mntpnt, mode)
177 utils.sysexec_noerr('umount %s' % self.mntpnt)
178 raise BootManagerException, "Couldn't find API-cache for disconnected operation"
182 utils.sysexec_noerr('umount %s' % self.mntpnt)
187 stash = cPickle.load(s)
192 if vars['DISCONNECTED_OPERATION']:
194 cPickle.dump(stash, s)