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 auth['AuthMethod']= 'hmac'
57 auth['node_id'] = vars['NODE_ID']
58 auth['node_ip'] = vars['INTERFACE_SETTINGS']['ip']
62 node_hmac= hmac.new(vars['NODE_KEY'], "[]".encode('utf-8'), sha).hexdigest()
63 auth['value']= node_hmac
66 if not vars.has_key('NODE_SESSION'):
67 session = vars['API_SERVER_INST'].GetSession(auth)
68 auth_session['session'] = session
69 vars['NODE_SESSION'] = session
70 # NOTE: save session value to /etc/planetlab/session for
71 # RunlevelAgent and future BootManager runs
72 sessionfile = open('/etc/planetlab/session', 'w')
73 sessionfile.write( vars['NODE_SESSION'] )
76 auth_session['session'] = vars['NODE_SESSION']
78 auth_session['AuthMethod'] = 'session'
82 # NOTE: BM has failed to authenticate utterly.
83 raise BootManagerAuthenticationException, "%s" % e
88 def serialize_params( call_params ):
90 convert a list of parameters into a format that will be used in the
91 hmac generation. both the boot manager and plc must have a common
92 format. full documentation is in the boot manager technical document,
93 but essentially we are going to take all the values (and keys for
94 dictionary objects), and put them into a list. sort them, and combine
95 them into one long string encased in a set of braces.
100 for param in call_params:
101 if isinstance(param,list) or isinstance(param,tuple):
102 values += serialize_params(param)
103 elif isinstance(param,dict):
104 values += serialize_params(param.values())
105 elif isinstance(param,xmlrpclib.Boolean):
106 # bool was not a real type in Python <2.3 and had to be
107 # marshalled as a custom type in xmlrpclib. Make sure that
108 # bools serialize consistently.
110 values.append("True")
112 values.append("False")
114 values.append(unicode(param))
119 def call_api_function( vars, function, user_params ):
121 call the named api function with params, and return the
122 value to the caller. the authentication structure is handled
123 automatically, and doesn't need to be passed in with params.
125 If the call fails, a BootManagerException is raised.
130 api_server= vars['API_SERVER_INST']
132 raise BootManagerException, "No connection to the API server exists."
134 if api_server is None:
138 if i[0] == function and i[1] == user_params:
140 raise BootManagerException, \
141 "Disconnected operation failed, insufficient stash."
143 auth= create_auth_structure(vars,user_params)
145 raise BootManagerException, \
146 "Could not create auth structure, missing values."
149 params= params + user_params
152 exec( "rc= api_server.%s(*params)" % function )
155 stash += [ [ function, user_params, rc ] ]
157 except xmlrpclib.Fault, fault:
158 raise BootManagerException, "API Fault: %s" % fault
159 except xmlrpclib.ProtocolError, err:
160 raise BootManagerException,"XML RPC protocol error: %s" % err
161 except xml.parsers.expat.ExpatError, err:
162 raise BootManagerException,"XML parsing error: %s" % err
166 mntpnt = '/tmp/stash'
167 def __init__(self, vars, mode):
168 utils.makedirs(self.mntpnt)
170 utils.sysexec('mount -t auto -U %s %s' % (vars['DISCONNECTED_OPERATION'], self.mntpnt))
171 # make sure it's not read-only
172 f = file('%s/api.cache' % self.mntpnt, 'a')
174 file.__init__(self, '%s/api.cache' % self.mntpnt, mode)
176 utils.sysexec_noerr('umount %s' % self.mntpnt)
177 raise BootManagerException, "Couldn't find API-cache for disconnected operation"
181 utils.sysexec_noerr('umount %s' % self.mntpnt)
186 stash = cPickle.load(s)
191 if vars['DISCONNECTED_OPERATION']:
193 cPickle.dump(stash, s)