fix bug that prevented penalty escallation from occurring.
[monitor.git] / plc.py
1 #
2 # plc.py
3 #
4 # Helper functions that minipulate the PLC api.
5
6 # Faiyaz Ahmed <faiyaza@cs.princeton.edu
7 #
8 # $Id: plc.py,v 1.18 2007/08/29 17:26:50 soltesz Exp $
9 #
10
11 import xml, xmlrpclib
12 import logging
13 import time
14 import traceback
15 try:
16         import config
17         debug = config.debug
18 except:
19         debug = False
20 logger = logging.getLogger("monitor")
21         
22 class Auth:
23         def __init__(self):
24                 self.auth = {'AuthMethod': "anonymous"}
25
26 # NOTE: this host is used by default when there are no auth files.
27 XMLRPC_SERVER="https://boot.planet-lab.org/PLCAPI/"
28
29 # NOTE: by default, use anonymous access, but if auth files are 
30 #       configured, use them, with their auth definitions.
31 auth = Auth()
32 try:
33         from monitor import config
34         auth.auth = {'Username' : config.API_AUTH_USER,
35                      'AuthMethod' : 'password',
36                                  'AuthString' : config.API_AUTH_PASSWORD}
37         auth.server = config.API_SERVER
38 except:
39         try:
40                 import auth
41                 auth.server = auth.plc
42         except:
43                 auth = Auth()
44                 auth.server = XMLRPC_SERVER
45
46 api = xmlrpclib.Server(auth.server, verbose=False, allow_none=True)
47
48 class PLC:
49         def __init__(self, auth, url):
50                 self.auth = auth
51                 self.url = url
52                 self.api = xmlrpclib.Server(self.url, verbose=False, allow_none=True)
53
54         def __getattr__(self, name):
55                 method = getattr(self.api, name)
56                 if method is None:
57                         raise AssertionError("method does not exist")
58
59                 return lambda *params : method(self.auth, *params)
60
61         def __repr__(self):
62                 return self.api.__repr__()
63
64 def getAPI(url):
65         return xmlrpclib.Server(url, verbose=False, allow_none=True)
66
67 def getAuthAPI():
68         return PLC(auth.auth, auth.server)
69
70
71 def getTechEmails(loginbase):
72         """
73                 For the given site, return all user email addresses that have the 'tech' role.
74         """
75         api = getAuthAPI()
76         # get site details.
77         s = api.GetSites(loginbase)[0]
78         # get people at site
79         p = api.GetPersons(s['person_ids'])
80         # pull out those with the right role.
81         emails = [ person['email'] for person in filter(lambda x: 'tech' in x['roles'], p) ]
82         return emails
83
84 def getPIEmails(loginbase):
85         """
86                 For the given site, return all user email addresses that have the 'tech' role.
87         """
88         api = getAuthAPI()
89         # get site details.
90         s = api.GetSites(loginbase)[0]
91         # get people at site
92         p = api.GetPersons(s['person_ids'])
93         # pull out those with the right role.
94         emails = [ person['email'] for person in filter(lambda x: 'pi' in x['roles'], p) ]
95         return emails
96
97 def getSliceUserEmails(loginbase):
98         """
99                 For the given site, return all user email addresses that have the 'tech' role.
100         """
101         api = getAuthAPI()
102         # get site details.
103         s = api.GetSites(loginbase)[0]
104         # get people at site
105         slices = api.GetSlices(s['slice_ids'])
106         people = []
107         for slice in slices:
108                 people += api.GetPersons(slice['person_ids'])
109         # pull out those with the right role.
110         emails = [ person['email'] for person in filter(lambda x: 'pi' in x['roles'], people) ]
111         unique_emails = [ x for x in set(emails) ]
112         return unique_emails
113
114 '''
115 Returns list of nodes in dbg as reported by PLC
116 '''
117 def nodesDbg():
118         dbgNodes = []
119         api = xmlrpclib.Server(auth.server, verbose=False)
120         anon = {'AuthMethod': "anonymous"}
121         for node in api.GetNodes(anon, {"boot_state":"dbg"},["hostname"]):
122                 dbgNodes.append(node['hostname'])
123         logger.info("%s nodes in debug according to PLC." %len(dbgNodes))
124         return dbgNodes
125
126
127 '''
128 Returns loginbase for given nodename
129 '''
130 def siteId(nodename):
131         api = xmlrpclib.Server(auth.server, verbose=False, allow_none=True)
132         site_id = api.GetNodes (auth.auth, {"hostname": nodename}, ['site_id'])
133         if len(site_id) == 1:
134                 loginbase = api.GetSites (auth.auth, site_id[0], ["login_base"])
135                 return loginbase[0]['login_base']
136         else:
137                 print "Not nodes returned!!!!"
138
139 '''
140 Returns list of slices for a site.
141 '''
142 def slices(loginbase):
143         siteslices = []
144         api = xmlrpclib.Server(auth.server, verbose=False, allow_none=True)
145         sliceids = api.GetSites (auth.auth, {"login_base" : loginbase}, ["slice_ids"])[0]['slice_ids']
146         for slice in api.GetSlices(auth.auth, {"slice_id" : sliceids}, ["name"]):
147                 siteslices.append(slice['name'])
148         return siteslices
149
150 '''
151 Returns dict of PCU info of a given node.
152 '''
153 def getpcu(nodename):
154         api = xmlrpclib.Server(auth.server, verbose=False, allow_none=True)
155         anon = {'AuthMethod': "anonymous"}
156         nodeinfo = api.GetNodes(auth.auth, {"hostname": nodename}, ["pcu_ids", "ports"])[0]
157         if nodeinfo['pcu_ids']:
158                 sitepcu = api.GetPCUs(auth.auth, nodeinfo['pcu_ids'])[0]
159                 sitepcu[nodename] = nodeinfo["ports"][0]
160                 return sitepcu
161         else:
162                 logger.info("%s doesn't have PCU" % nodename)
163                 return False
164
165 def GetPCUs(filter=None, fields=None):
166         api = xmlrpclib.Server(auth.server, verbose=False, allow_none=True)
167         pcu_list = api.GetPCUs(auth.auth, filter, fields)
168         return pcu_list 
169
170 '''
171 Returns all site nodes for site id (loginbase).
172 '''
173 def getSiteNodes(loginbase, fields=None):
174         api = xmlrpclib.Server(auth.server, verbose=False)
175         nodelist = []
176         anon = {'AuthMethod': "anonymous"}
177         try:
178                 nodeids = api.GetSites(anon, {"login_base": loginbase}, fields)[0]['node_ids']
179                 for node in api.GetNodes(anon, {"node_id": nodeids}, ['hostname']):
180                         nodelist.append(node['hostname'])
181         except Exception, exc:
182                 logger.info("getSiteNodes:  %s" % exc)
183                 print "getSiteNodes:  %s" % exc
184         return nodelist
185
186
187 def getPersons(filter=None, fields=None):
188         api = xmlrpclib.Server(auth.server, verbose=False, allow_none=True)
189         persons = []
190         try:
191                 persons = api.GetPersons(auth.auth, filter, fields)
192         except Exception, exc:
193                 print "getPersons:  %s" % exc
194                 logger.info("getPersons:  %s" % exc)
195         return persons
196
197 def getSites(filter=None, fields=None):
198         api = xmlrpclib.Server(auth.server, verbose=False, allow_none=True)
199         sites = []
200         anon = {'AuthMethod': "anonymous"}
201         try:
202                 #sites = api.GetSites(anon, filter, fields)
203                 sites = api.GetSites(auth.auth, filter, fields)
204         except Exception, exc:
205                 traceback.print_exc()
206                 print "getSites:  %s" % exc
207                 logger.info("getSites:  %s" % exc)
208         return sites
209
210 def getSiteNodes2(loginbase):
211         api = xmlrpclib.Server(auth.server, verbose=False)
212         nodelist = []
213         anon = {'AuthMethod': "anonymous"}
214         try:
215                 nodeids = api.GetSites(anon, {"login_base": loginbase})[0]['node_ids']
216                 nodelist += getNodes({'node_id':nodeids})
217         except Exception, exc:
218                 logger.info("getSiteNodes2:  %s" % exc)
219         return nodelist
220
221 def getNodeNetworks(filter=None):
222         api = xmlrpclib.Server(auth.server, verbose=False, allow_none=True)
223         nodenetworks = api.GetNodeNetworks(auth.auth, filter, None)
224         return nodenetworks
225
226 def getNodes(filter=None, fields=None):
227         api = xmlrpclib.Server(auth.server, verbose=False, allow_none=True)
228         nodes = api.GetNodes(auth.auth, filter, fields) 
229                         #['boot_state', 'hostname', 
230                         #'site_id', 'date_created', 'node_id', 'version', 'nodenetwork_ids',
231                         #'last_updated', 'peer_node_id', 'ssh_rsa_key' ])
232         return nodes
233
234 '''
235 Sets boot state of a node.
236 '''
237 def nodeBootState(nodename, state):
238         api = xmlrpclib.Server(auth.server, verbose=False)
239         try:
240                 return api.UpdateNode(auth.auth, nodename, {'boot_state': state})
241         except Exception, exc:
242                 logger.info("nodeBootState:  %s" % exc)
243
244 def updateNodeKey(nodename, key):
245         api = xmlrpclib.Server(auth.server, verbose=False)
246         try:
247                 return api.UpdateNode(auth.auth, nodename, {'key': key})
248         except Exception, exc:
249                 logger.info("updateNodeKey:  %s" % exc)
250
251 '''
252 Sends Ping Of Death to node.
253 '''
254 def nodePOD(nodename):
255         api = xmlrpclib.Server(auth.server, verbose=False)
256         logger.info("Sending POD to %s" % nodename)
257         try:
258                 if not debug:
259                         return api.RebootNode(auth.auth, nodename)
260         except Exception, exc:
261                         logger.info("nodePOD:  %s" % exc)
262
263 '''
264 Freeze all site slices.
265 '''
266 def suspendSlices(nodename):
267         api = xmlrpclib.Server(auth.server, verbose=False)
268         for slice in slices(siteId(nodename)):
269                 logger.info("Suspending slice %s" % slice)
270                 try:
271                         if not debug:
272                                 api.AddSliceAttribute(auth.auth, slice, "enabled", "0")
273                 except Exception, exc:
274                         logger.info("suspendSlices:  %s" % exc)
275
276 def enableSlices(nodename):
277         api = xmlrpclib.Server(auth.server, verbose=False, allow_none=True)
278         for slice in slices(siteId(nodename)):
279                 logger.info("Enabling slices %s" % slice)
280                 try:
281                         if not debug:
282                                 slice_list = api.GetSlices(auth.auth, {'name': slice}, None)
283                                 if len(slice_list) == 0:
284                                         return
285                                 slice_id = slice_list[0]['slice_id']
286                                 l_attr = api.GetSliceAttributes(auth.auth, {'slice_id': slice_id}, None)
287                                 for attr in l_attr:
288                                         if "enabled" == attr['name'] and attr['value'] == "0":
289                                                 logger.info("Deleted enable=0 attribute from slice %s" % slice)
290                                                 api.DeleteSliceAttribute(auth.auth, attr['slice_attribute_id'])
291                 except Exception, exc:
292                         logger.info("enableSlices: %s" % exc)
293                         print "exception: %s" % exc
294
295 #I'm commenting this because this really should be a manual process.  
296 #'''
297 #Enable suspended site slices.
298 #'''
299 #def enableSlices(nodename, slicelist):
300 #       api = xmlrpclib.Server(auth.server, verbose=False)
301 #       for slice in  slices(siteId(nodename)):
302 #               logger.info("Suspending slice %s" % slice)
303 #               api.SliceAttributeAdd(auth.auth, slice, "plc_slice_state", {"state" : "suspended"})
304 #
305 def enableSliceCreation(nodename):
306         api = xmlrpclib.Server(auth.server, verbose=False, allow_none=True)
307         try:
308                 loginbase = siteId(nodename)
309                 logger.info("Enabling slice creation for site %s" % loginbase)
310                 if not debug:
311                         logger.info("\tcalling UpdateSite(%s, enabled=True)" % loginbase)
312                         api.UpdateSite(auth.auth, loginbase, {'enabled': True})
313         except Exception, exc:
314                 print "ERROR: enableSliceCreation:  %s" % exc
315                 logger.info("ERROR: enableSliceCreation:  %s" % exc)
316
317 '''
318 Removes ability to create slices. Returns previous max_slices
319 '''
320 def removeSliceCreation(nodename):
321         print "removeSliceCreation(%s)" % nodename
322         api = xmlrpclib.Server(auth.server, verbose=False)
323         try:
324                 loginbase = siteId(nodename)
325                 #numslices = api.GetSites(auth.auth, {"login_base": loginbase}, 
326                 #               ["max_slices"])[0]['max_slices']
327                 logger.info("Removing slice creation for site %s" % loginbase)
328                 if not debug:
329                         #api.UpdateSite(auth.auth, loginbase, {'max_slices': 0})
330                         api.UpdateSite(auth.auth, loginbase, {'enabled': False})
331         except Exception, exc:
332                 logger.info("removeSliceCreation:  %s" % exc)
333
334 '''
335 QED
336 '''
337 #def enableSliceCreation(nodename, maxslices):
338 #       api = xmlrpclib.Server(auth.server, verbose=False)
339 #       anon = {'AuthMethod': "anonymous"}
340 #       siteid = api.AnonAdmQuerySite (anon, {"node_hostname": nodename})
341 #       if len(siteid) == 1:
342 #               logger.info("Enabling slice creation for site %s" % siteId(nodename))
343 #               try:
344 #                       if not debug:
345 #                               api.AdmUpdateSite(auth.auth, siteid[0], {"max_slices" : maxslices})
346 #               except Exception, exc:
347 #                       logger.info("API:  %s" % exc)
348 #       else:
349 #               logger.debug("Cant find site for %s.  Cannot enable creation." % nodename)
350
351 def main():
352         logger.setLevel(logging.DEBUG)
353         ch = logging.StreamHandler()
354         ch.setLevel(logging.DEBUG)
355         formatter = logging.Formatter('logger - %(message)s')
356         ch.setFormatter(formatter)
357         logger.addHandler(ch)
358         #print getpcu("kupl2.ittc.ku.edu")
359         #print getpcu("planetlab1.cse.msu.edu")
360         #print getpcu("alice.cs.princeton.edu")
361         #print nodesDbg()
362         #nodeBootState("alice.cs.princeton.edu", "boot")
363         #freezeSite("alice.cs.princeton.edu")
364         print removeSliceCreation("alice.cs.princeton.edu")
365         #enableSliceCreation("alice.cs.princeton.edu", 1024)
366         #print getSiteNodes("princeton")
367         #print siteId("alice.cs.princeton.edu")
368         #print nodePOD("alice.cs.princeton.edu")
369         #print slices("princeton")
370
371 if __name__=="__main__":
372         main()