4 # Helper functions that minipulate the PLC api.
6 # Faiyaz Ahmed <faiyaza@cs.princeton.edu
8 # $Id: plc.py,v 1.18 2007/08/29 17:26:50 soltesz Exp $
15 from monitor import database
22 logger = logging.getLogger("monitor")
26 self.auth = {'AuthMethod': "anonymous"}
28 # NOTE: this host is used by default when there are no auth files.
29 XMLRPC_SERVER="https://boot.planet-lab.org/PLCAPI/"
31 # NOTE: by default, use anonymous access, but if auth files are
32 # configured, use them, with their auth definitions.
35 from monitor import config
36 auth.auth = {'Username' : config.API_AUTH_USER,
37 'AuthMethod' : 'password',
38 'AuthString' : config.API_AUTH_PASSWORD}
39 auth.server = config.API_SERVER
43 auth.server = auth.plc
46 auth.server = XMLRPC_SERVER
48 api = xmlrpclib.Server(auth.server, verbose=False, allow_none=True)
51 def __init__(self, auth, url):
54 self.api = xmlrpclib.Server(self.url, verbose=False, allow_none=True)
56 def __getattr__(self, name):
57 method = getattr(self.api, name)
59 raise AssertionError("method does not exist")
61 return lambda *params : method(self.auth, *params)
64 return self.api.__repr__()
68 def _param_to_str(self, name, *params):
71 retstr += "%s-" % name
76 def __getattr__(self, name):
77 method = getattr(self.api, name)
79 raise AssertionError("method does not exist")
81 def run_or_returncached(*params):
82 cachename = self._param_to_str(name, *params)
83 #print "cachename is %s" % cachename
85 if not database.cachedRecently(cachename):
86 load_old_cache = False
88 values = method(self.auth, *params)
90 print "Call %s FAILED: Using old cached data" % cachename
94 values = database.dbLoad(cachename)
96 database.dbDump(cachename, values)
100 values = database.dbLoad(cachename)
103 return method(self.auth, *params)
105 return run_or_returncached
109 return xmlrpclib.Server(url, verbose=False, allow_none=True)
112 return PLC(auth.auth, auth.server)
114 def getCachedAuthAPI():
115 return CachedPLC(auth.auth, auth.server)
117 def getTechEmails(loginbase):
119 For the given site, return all user email addresses that have the 'tech' role.
123 s = api.GetSites(loginbase)[0]
125 p = api.GetPersons(s['person_ids'])[0]
126 # pull out those with the right role.
127 emails = [ person['email'] for person in filter(lambda x: 'tech' in x['roles'], p) ]
130 def getPIEmails(loginbase):
132 For the given site, return all user email addresses that have the 'tech' role.
136 s = api.GetSites(loginbase)[0]
138 p = api.GetPersons(s['person_ids'])[0]
139 # pull out those with the right role.
140 emails = [ person['email'] for person in filter(lambda x: 'pi' in x['roles'], p) ]
143 def getSliceUserEmails(loginbase):
145 For the given site, return all user email addresses that have the 'tech' role.
149 s = api.GetSites(loginbase)[0]
151 slices = api.GetSlices(s['slice_ids'])
154 people += api.GetPersons(slice['person_ids'])
155 # pull out those with the right role.
156 emails = [ person['email'] for person in filter(lambda x: 'pi' in x['roles'], people) ]
157 unique_emails = [ x for x in set(emails) ]
161 Returns list of nodes in dbg as reported by PLC
165 api = xmlrpclib.Server(auth.server, verbose=False)
166 anon = {'AuthMethod': "anonymous"}
167 for node in api.GetNodes(anon, {"boot_state":"dbg"},["hostname"]):
168 dbgNodes.append(node['hostname'])
169 logger.info("%s nodes in debug according to PLC." %len(dbgNodes))
174 Returns loginbase for given nodename
176 def siteId(nodename):
177 api = xmlrpclib.Server(auth.server, verbose=False)
178 anon = {'AuthMethod': "anonymous"}
179 site_id = api.GetNodes (anon, {"hostname": nodename}, ['site_id'])
180 if len(site_id) == 1:
181 loginbase = api.GetSites (anon, site_id[0], ["login_base"])
182 return loginbase[0]['login_base']
185 Returns list of slices for a site.
187 def slices(loginbase):
189 api = xmlrpclib.Server(auth.server, verbose=False)
190 sliceids = api.GetSites (auth.auth, {"login_base" : loginbase}, ["slice_ids"])[0]['slice_ids']
191 for slice in api.GetSlices(auth.auth, {"slice_id" : sliceids}, ["name"]):
192 siteslices.append(slice['name'])
196 Returns dict of PCU info of a given node.
198 def getpcu(nodename):
199 api = xmlrpclib.Server(auth.server, verbose=False)
200 anon = {'AuthMethod': "anonymous"}
201 nodeinfo = api.GetNodes(auth.auth, {"hostname": nodename}, ["pcu_ids", "ports"])[0]
202 if nodeinfo['pcu_ids']:
203 sitepcu = api.GetPCUs(auth.auth, nodeinfo['pcu_ids'])[0]
204 sitepcu[nodename] = nodeinfo["ports"][0]
207 logger.info("%s doesn't have PCU" % nodename)
210 def GetPCUs(filter=None, fields=None):
211 api = xmlrpclib.Server(auth.server, verbose=False, allow_none=True)
212 pcu_list = api.GetPCUs(auth.auth, filter, fields)
216 Returns all site nodes for site id (loginbase).
218 def getSiteNodes(loginbase, fields=None):
219 api = xmlrpclib.Server(auth.server, verbose=False)
221 anon = {'AuthMethod': "anonymous"}
223 nodeids = api.GetSites(anon, {"login_base": loginbase}, fields)[0]['node_ids']
224 for node in api.GetNodes(anon, {"node_id": nodeids}, ['hostname']):
225 nodelist.append(node['hostname'])
226 except Exception, exc:
227 logger.info("getSiteNodes: %s" % exc)
228 print "getSiteNodes: %s" % exc
232 def getPersons(filter=None, fields=None):
233 api = xmlrpclib.Server(auth.server, verbose=False, allow_none=True)
236 persons = api.GetPersons(auth.auth, filter, fields)
237 except Exception, exc:
238 print "getPersons: %s" % exc
239 logger.info("getPersons: %s" % exc)
242 def getSites(filter=None, fields=None):
243 api = xmlrpclib.Server(auth.server, verbose=False, allow_none=True)
245 anon = {'AuthMethod': "anonymous"}
247 #sites = api.GetSites(anon, filter, fields)
248 sites = api.GetSites(auth.auth, filter, fields)
249 except Exception, exc:
250 traceback.print_exc()
251 print "getSites: %s" % exc
252 logger.info("getSites: %s" % exc)
255 def getSiteNodes2(loginbase):
256 api = xmlrpclib.Server(auth.server, verbose=False)
258 anon = {'AuthMethod': "anonymous"}
260 nodeids = api.GetSites(anon, {"login_base": loginbase})[0]['node_ids']
261 nodelist += getNodes({'node_id':nodeids})
262 except Exception, exc:
263 logger.info("getSiteNodes2: %s" % exc)
266 def getNodeNetworks(filter=None):
267 api = xmlrpclib.Server(auth.server, verbose=False, allow_none=True)
268 nodenetworks = api.GetNodeNetworks(auth.auth, filter, None)
271 def getNodes(filter=None, fields=None):
272 api = xmlrpclib.Server(auth.server, verbose=False, allow_none=True)
273 nodes = api.GetNodes(auth.auth, filter, fields)
274 #['boot_state', 'hostname',
275 #'site_id', 'date_created', 'node_id', 'version', 'nodenetwork_ids',
276 #'last_updated', 'peer_node_id', 'ssh_rsa_key' ])
280 Sets boot state of a node.
282 def nodeBootState(nodename, state):
283 api = xmlrpclib.Server(auth.server, verbose=False)
285 return api.UpdateNode(auth.auth, nodename, {'boot_state': state})
286 except Exception, exc:
287 logger.info("nodeBootState: %s" % exc)
289 def updateNodeKey(nodename, key):
290 api = xmlrpclib.Server(auth.server, verbose=False)
292 return api.UpdateNode(auth.auth, nodename, {'key': key})
293 except Exception, exc:
294 logger.info("updateNodeKey: %s" % exc)
297 Sends Ping Of Death to node.
299 def nodePOD(nodename):
300 api = xmlrpclib.Server(auth.server, verbose=False)
301 logger.info("Sending POD to %s" % nodename)
304 return api.RebootNode(auth.auth, nodename)
305 except Exception, exc:
306 logger.info("nodePOD: %s" % exc)
309 Freeze all site slices.
311 def suspendSlices(nodename):
312 api = xmlrpclib.Server(auth.server, verbose=False)
313 for slice in slices(siteId(nodename)):
314 logger.info("Suspending slice %s" % slice)
317 api.AddSliceAttribute(auth.auth, slice, "enabled", "0")
318 except Exception, exc:
319 logger.info("suspendSlices: %s" % exc)
321 def enableSlices(nodename):
322 api = xmlrpclib.Server(auth.server, verbose=False, allow_none=True)
323 for slice in slices(siteId(nodename)):
324 logger.info("Enabling slices %s" % slice)
327 slice_list = api.GetSlices(auth.auth, {'name': slice}, None)
328 if len(slice_list) == 0:
330 slice_id = slice_list[0]['slice_id']
331 l_attr = api.GetSliceAttributes(auth.auth, {'slice_id': slice_id}, None)
333 if "enabled" == attr['name'] and attr['value'] == "0":
334 logger.info("Deleted enable=0 attribute from slice %s" % slice)
335 api.DeleteSliceAttribute(auth.auth, attr['slice_attribute_id'])
336 except Exception, exc:
337 logger.info("enableSlices: %s" % exc)
338 print "exception: %s" % exc
340 #I'm commenting this because this really should be a manual process.
342 #Enable suspended site slices.
344 #def enableSlices(nodename, slicelist):
345 # api = xmlrpclib.Server(auth.server, verbose=False)
346 # for slice in slices(siteId(nodename)):
347 # logger.info("Suspending slice %s" % slice)
348 # api.SliceAttributeAdd(auth.auth, slice, "plc_slice_state", {"state" : "suspended"})
350 def enableSliceCreation(nodename):
351 api = xmlrpclib.Server(auth.server, verbose=False, allow_none=True)
353 loginbase = siteId(nodename)
354 logger.info("Enabling slice creation for site %s" % loginbase)
356 logger.info("\tcalling UpdateSite(%s, enabled=True)" % loginbase)
357 api.UpdateSite(auth.auth, loginbase, {'enabled': True})
358 except Exception, exc:
359 print "ERROR: enableSliceCreation: %s" % exc
360 logger.info("ERROR: enableSliceCreation: %s" % exc)
363 Removes ability to create slices. Returns previous max_slices
365 def removeSliceCreation(nodename):
366 print "removeSliceCreation(%s)" % nodename
367 api = xmlrpclib.Server(auth.server, verbose=False)
369 loginbase = siteId(nodename)
370 #numslices = api.GetSites(auth.auth, {"login_base": loginbase},
371 # ["max_slices"])[0]['max_slices']
372 logger.info("Removing slice creation for site %s" % loginbase)
374 #api.UpdateSite(auth.auth, loginbase, {'max_slices': 0})
375 api.UpdateSite(auth.auth, loginbase, {'enabled': False})
376 except Exception, exc:
377 logger.info("removeSliceCreation: %s" % exc)
382 #def enableSliceCreation(nodename, maxslices):
383 # api = xmlrpclib.Server(auth.server, verbose=False)
384 # anon = {'AuthMethod': "anonymous"}
385 # siteid = api.AnonAdmQuerySite (anon, {"node_hostname": nodename})
386 # if len(siteid) == 1:
387 # logger.info("Enabling slice creation for site %s" % siteId(nodename))
390 # api.AdmUpdateSite(auth.auth, siteid[0], {"max_slices" : maxslices})
391 # except Exception, exc:
392 # logger.info("API: %s" % exc)
394 # logger.debug("Cant find site for %s. Cannot enable creation." % nodename)
397 logger.setLevel(logging.DEBUG)
398 ch = logging.StreamHandler()
399 ch.setLevel(logging.DEBUG)
400 formatter = logging.Formatter('logger - %(message)s')
401 ch.setFormatter(formatter)
402 logger.addHandler(ch)
403 #print getpcu("kupl2.ittc.ku.edu")
404 #print getpcu("planetlab1.cse.msu.edu")
405 #print getpcu("alice.cs.princeton.edu")
407 #nodeBootState("alice.cs.princeton.edu", "boot")
408 #freezeSite("alice.cs.princeton.edu")
409 print removeSliceCreation("alice.cs.princeton.edu")
410 #enableSliceCreation("alice.cs.princeton.edu", 1024)
411 #print getSiteNodes("princeton")
412 #print siteId("alice.cs.princeton.edu")
413 #print nodePOD("alice.cs.princeton.edu")
414 #print slices("princeton")
416 if __name__=="__main__":