bool was not a real type in Python <2.3 and had to be marshalled as a
[bootmanager.git] / source / BootAPI.py
1 #!/usr/bin/python2
2
3 # Copyright (c) 2003 Intel Corporation
4 # All rights reserved.
5 #
6 # Copyright (c) 2004-2006 The Trustees of Princeton University
7 # All rights reserved.
8
9
10 import xmlrpclib
11 import xml.parsers.expat
12 import hmac
13 import string
14 import sha
15
16 from Exceptions import *
17
18
19 def create_auth_structure( vars, call_params ):
20     """
21     create and return an authentication structure for a Boot API
22     call. Vars contains the boot manager runtime variables, and
23     call_params is a tuple of the parameters that will be passed to the
24     API call. Return None if unable to (typically due to missing
25     keys in vars, such as node_id or node_key)
26     """
27     
28     auth= {}
29     auth['AuthMethod']= 'hmac'
30
31     try:
32         network= vars['NETWORK_SETTINGS']
33         
34         auth['node_id']= vars['NODE_ID']
35         auth['node_ip']= network['ip']
36         node_key= vars['NODE_KEY']
37     except KeyError, e:
38         return None
39
40     params= serialize_params(call_params)
41     params.sort()
42     msg= "[" + "".join(params) + "]"
43     node_hmac= hmac.new(node_key,msg.encode('utf-8'),sha).hexdigest()
44     auth['value']= node_hmac
45
46     return auth
47
48
49
50 def serialize_params( call_params ):
51     """
52     convert a list of parameters into a format that will be used in the
53     hmac generation. both the boot manager and plc must have a common
54     format. full documentation is in the boot manager technical document,
55     but essentially we are going to take all the values (and keys for
56     dictionary objects), and put them into a list. sort them, and combine
57     them into one long string encased in a set of braces.
58     """
59
60     values= []
61     
62     for param in call_params:
63         if isinstance(param,list) or isinstance(param,tuple):
64             values += serialize_params(param)
65         elif isinstance(param,dict):
66             values += serialize_params(param.values())
67         elif isinstance(param,xmlrpclib.Boolean):
68             # bool was not a real type in Python <2.3 and had to be
69             # marshalled as a custom type in xmlrpclib. Make sure that
70             # bools serialize consistently.
71             if param:
72                 values.append("True")
73             else:
74                 values.append("False")
75         else:
76             values.append(unicode(param))
77                 
78     return values
79
80     
81 def call_api_function( vars, function, user_params ):
82     """
83     call the named api function with params, and return the
84     value to the caller. the authentication structure is handled
85     automatically, and doesn't need to be passed in with params.
86
87     If the call fails, a BootManagerException is raised.
88     """
89     
90     try:
91         api_server= vars['API_SERVER_INST']
92     except KeyError, e:
93         raise BootManagerException, "No connection to the API server exists."
94
95     auth= create_auth_structure(vars,user_params)
96     if auth is None:
97         raise BootManagerException, \
98               "Could not create auth structure, missing values."
99     
100     params= (auth,)
101     params= params + user_params
102
103     try:
104         exec( "rc= api_server.%s(*params)" % function )
105         return rc
106     except xmlrpclib.Fault, fault:
107         raise BootManagerException, "API Fault: %s" % fault
108     except xmlrpclib.ProtocolError, err:
109         raise BootManagerException,"XML RPC protocol error: %s" % err
110     except xml.parsers.expat.ExpatError, err:
111         raise BootManagerException,"XML parsing error: %s" % err