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