6 # Copyright (c) 2003 Intel Corporation
9 # Copyright (c) 2004-2006 The Trustees of Princeton University
10 # All rights reserved.
14 import xml.parsers.expat
22 from Exceptions import *
26 def create_auth_structure( vars, call_params ):
28 create and return an authentication structure for a Boot API
29 call. Vars contains the boot manager runtime variables, and
30 call_params is a tuple of the parameters that will be passed to the
31 API call. Return None if unable to (typically due to missing
32 keys in vars, such as node_id or node_key)
39 auth_session['AuthMethod'] = 'session'
41 if not vars.has_key('NODE_SESSION'):
42 # Try to load /etc/planetlab/session if it exists.
43 sessionfile = open('/etc/planetlab/session', 'r')
44 session = sessionfile.read().strip()
46 auth_session['session'] = session
47 # Test session. Faults if it's no good.
48 vars['API_SERVER_INST'].AuthCheck(auth_session)
49 vars['NODE_SESSION'] = session
53 auth_session['session'] = vars['NODE_SESSION']
58 auth['AuthMethod']= 'hmac'
61 auth['node_id'] = vars['NODE_ID']
62 auth['node_ip'] = vars['INTERFACE_SETTINGS']['ip']
66 node_hmac= hmac.new(vars['NODE_KEY'], "[]".encode('utf-8'), sha).hexdigest()
67 auth['value']= node_hmac
70 if not vars.has_key('NODE_SESSION'):
71 session = vars['API_SERVER_INST'].GetSession(auth)
72 auth_session['session'] = session
73 vars['NODE_SESSION'] = session
74 # NOTE: save session value to /etc/planetlab/session for
75 # RunlevelAgent and future BootManager runs
76 if not os.path.exists("/etc/planetlab"):
77 os.makedirs("/etc/planetlab")
78 sessionfile = open('/etc/planetlab/session', 'w')
79 sessionfile.write( vars['NODE_SESSION'] )
82 auth_session['session'] = vars['NODE_SESSION']
84 auth_session['AuthMethod'] = 'session'
88 # NOTE: BM has failed to authenticate utterly.
89 raise BootManagerAuthenticationException, "%s" % e
94 def serialize_params( call_params ):
96 convert a list of parameters into a format that will be used in the
97 hmac generation. both the boot manager and plc must have a common
98 format. full documentation is in the boot manager technical document,
99 but essentially we are going to take all the values (and keys for
100 dictionary objects), and put them into a list. sort them, and combine
101 them into one long string encased in a set of braces.
106 for param in call_params:
107 if isinstance(param,list) or isinstance(param,tuple):
108 values += serialize_params(param)
109 elif isinstance(param,dict):
110 values += serialize_params(param.values())
111 elif isinstance(param,xmlrpclib.Boolean):
112 # bool was not a real type in Python <2.3 and had to be
113 # marshalled as a custom type in xmlrpclib. Make sure that
114 # bools serialize consistently.
116 values.append("True")
118 values.append("False")
120 values.append(unicode(param))
125 def call_api_function( vars, function, user_params ):
127 call the named api function with params, and return the
128 value to the caller. the authentication structure is handled
129 automatically, and doesn't need to be passed in with params.
131 If the call fails, a BootManagerException is raised.
136 api_server= vars['API_SERVER_INST']
138 raise BootManagerException, "No connection to the API server exists."
140 if api_server is None:
144 if i[0] == function and i[1] == user_params:
146 raise BootManagerException, \
147 "Disconnected operation failed, insufficient stash."
149 auth= create_auth_structure(vars,user_params)
151 raise BootManagerException, \
152 "Could not create auth structure, missing values."
155 params= params + user_params
158 exec( "rc= api_server.%s(*params)" % function )
161 stash += [ [ function, user_params, rc ] ]
163 except xmlrpclib.Fault, fault:
164 raise BootManagerException, "API Fault: %s" % fault
165 except xmlrpclib.ProtocolError, err:
166 raise BootManagerException,"XML RPC protocol error: %s" % err
167 except xml.parsers.expat.ExpatError, err:
168 raise BootManagerException,"XML parsing error: %s" % err
172 mntpnt = '/tmp/stash'
173 def __init__(self, vars, mode):
174 utils.makedirs(self.mntpnt)
176 utils.sysexec('mount -t auto -U %s %s' % (vars['DISCONNECTED_OPERATION'], self.mntpnt))
177 # make sure it's not read-only
178 f = file('%s/api.cache' % self.mntpnt, 'a')
180 file.__init__(self, '%s/api.cache' % self.mntpnt, mode)
182 utils.sysexec_noerr('umount %s' % self.mntpnt)
183 raise BootManagerException, "Couldn't find API-cache for disconnected operation"
187 utils.sysexec_noerr('umount %s' % self.mntpnt)
192 stash = cPickle.load(s)
197 if vars['DISCONNECTED_OPERATION']:
199 cPickle.dump(stash, s)