3 # Copyright (c) 2003 Intel Corporation
6 # Copyright (c) 2004-2006 The Trustees of Princeton University
11 import xml.parsers.expat
19 from Exceptions import *
23 def create_auth_structure( vars, call_params ):
25 create and return an authentication structure for a Boot API
26 call. Vars contains the boot manager runtime variables, and
27 call_params is a tuple of the parameters that will be passed to the
28 API call. Return None if unable to (typically due to missing
29 keys in vars, such as node_id or node_key)
36 auth_session['AuthMethod'] = 'session'
38 if not vars.has_key('NODE_SESSION'):
39 # Try to load /etc/planetlab/session if it exists.
40 sessionfile = open('/etc/planetlab/session', 'r')
41 session = sessionfile.read().strip()
43 auth_session['session'] = session
44 # Test session. Faults if it's no good.
45 vars['API_SERVER_INST'].AuthCheck(auth_session)
46 vars['NODE_SESSION'] = session
50 auth_session['session'] = vars['NODE_SESSION']
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 if not os.path.exists("/etc/planetlab"):
74 os.makedirs("/etc/planetlab")
75 sessionfile = open('/etc/planetlab/session', 'w')
76 sessionfile.write( vars['NODE_SESSION'] )
79 auth_session['session'] = vars['NODE_SESSION']
81 auth_session['AuthMethod'] = 'session'
85 # NOTE: BM has failed to authenticate utterly.
86 raise BootManagerAuthenticationException, "%s" % e
91 def serialize_params( call_params ):
93 convert a list of parameters into a format that will be used in the
94 hmac generation. both the boot manager and plc must have a common
95 format. full documentation is in the boot manager technical document,
96 but essentially we are going to take all the values (and keys for
97 dictionary objects), and put them into a list. sort them, and combine
98 them into one long string encased in a set of braces.
103 for param in call_params:
104 if isinstance(param,list) or isinstance(param,tuple):
105 values += serialize_params(param)
106 elif isinstance(param,dict):
107 values += serialize_params(param.values())
108 elif isinstance(param,xmlrpclib.Boolean):
109 # bool was not a real type in Python <2.3 and had to be
110 # marshalled as a custom type in xmlrpclib. Make sure that
111 # bools serialize consistently.
113 values.append("True")
115 values.append("False")
117 values.append(unicode(param))
122 def call_api_function( vars, function, user_params ):
124 call the named api function with params, and return the
125 value to the caller. the authentication structure is handled
126 automatically, and doesn't need to be passed in with params.
128 If the call fails, a BootManagerException is raised.
133 api_server= vars['API_SERVER_INST']
135 raise BootManagerException, "No connection to the API server exists."
137 if api_server is None:
141 if i[0] == function and i[1] == user_params:
143 raise BootManagerException, \
144 "Disconnected operation failed, insufficient stash."
146 auth= create_auth_structure(vars,user_params)
148 raise BootManagerException, \
149 "Could not create auth structure, missing values."
152 params= params + user_params
155 exec( "rc= api_server.%s(*params)" % function )
158 stash += [ [ function, user_params, rc ] ]
160 except xmlrpclib.Fault, fault:
161 raise BootManagerException, "API Fault: %s" % fault
162 except xmlrpclib.ProtocolError, err:
163 raise BootManagerException,"XML RPC protocol error: %s" % err
164 except xml.parsers.expat.ExpatError, err:
165 raise BootManagerException,"XML parsing error: %s" % err
169 mntpnt = '/tmp/stash'
170 def __init__(self, vars, mode):
171 utils.makedirs(self.mntpnt)
173 utils.sysexec('mount -t auto -U %s %s' % (vars['DISCONNECTED_OPERATION'], self.mntpnt))
174 # make sure it's not read-only
175 f = file('%s/api.cache' % self.mntpnt, 'a')
177 file.__init__(self, '%s/api.cache' % self.mntpnt, mode)
179 utils.sysexec_noerr('umount %s' % self.mntpnt)
180 raise BootManagerException, "Couldn't find API-cache for disconnected operation"
184 utils.sysexec_noerr('umount %s' % self.mntpnt)
189 stash = cPickle.load(s)
194 if vars['DISCONNECTED_OPERATION']:
196 cPickle.dump(stash, s)