3 # Helper functions that minipulate the PLC api.
5 # Faiyaz Ahmed <faiyaza@cs.princeton.edu>
6 # Copyright (C) 2006, 2007 The Trustees of Princeton University
8 # $Id: plctool.py,v 1.2 2007/04/19 20:43:00 mef Exp $
11 from emailTxt import *
16 import getpass, getopt
19 logger = logging.getLogger("monitor")
20 XMLRPC_SERVER = 'https://www.planet-lab.org/PLCAPI/'
21 api = xmlrpclib.Server(XMLRPC_SERVER, verbose=False, allow_none = True)
25 """Returns list of nodes in dbg as reported by PLC"""
29 allnodes = api.GetNodes(auth, None, ['hostname','boot_state'])
31 if node['boot_state'] == 'dbg': dbgNodes.append(node['hostname'])
32 logger.info("%d nodes in debug according to PLC." %len(dbgNodes))
37 """Returns loginbase for given nodename"""
41 site_ids = api.GetNodes(auth, [nodename], ['site_id'])
42 if len(site_ids) == 1:
43 site_id = [site_ids[0]['site_id']]
44 loginbase = api.GetSites (auth, site_id, ["login_base"])
45 return loginbase[0]['login_base']
48 """Returns list of slices for a site."""
52 printUsage("not enough arguments; please provide loginbase")
57 printUsage("requires admin privs")
60 slices = api.GetSlices (auth, {'name':"%s_*"%loginbase},['name'])
61 slices = map(lambda x: x['name'],slices)
65 """Returns dict of PCU info of a given node."""
68 nodename = argv[0].lower()
70 printUsage("requires admin privs")
73 pcus = api.GetNodes(auth, [nodename], ['pcu_ids'])
75 pcus = map(lambda x: x['pcu_ids'],pcus)[0]
76 nodepcus = api.GetPCUs(auth,pcus)
82 def getSiteNodes(argv):
83 """Returns all site nodes for site id (loginbase)."""
86 printUsage("not enough arguments; please provide loginbase")
91 site_ids = api.GetSites(auth, {'login_base': "%s" % loginbase}, ['node_ids'])
92 if len(site_ids) == 1:
93 node_ids = site_ids[0]['node_ids']
94 nodes = api.GetNodes(auth,node_ids,['hostname'])
95 nodelist = map(lambda x: x['hostname'], nodes)
96 elif len(site_ids) == 0:
97 logger.info("getSiteNodes: can't find site %s" %loginbase)
101 def renewAllSlices (argv):
102 """Sets the expiration date of all slices to given date"""
106 # convert time string using fmt "%B %d %Y" to epoch integer
108 newexp = int(time.mktime(time.strptime(newexp,"%B %d %Y")))
109 except ValueError, e:
110 errormsg = """Expecting date to be in Month Day Year
112 new expiration date provided %s""" % newexp
116 slices = api.GetSlices(auth)
119 exp = int(slice['expires'])
120 olddate = time.asctime(time.localtime(exp))
121 slice_attributes = api.GetSliceAttributes(auth,slice['slice_attribute_ids'])
122 for slice_attribute in slice_attributes:
123 if slice_attribute['name'] == "enabled":
124 print "%s is suspended" % name
126 newdate = time.asctime(time.localtime(newexp))
127 ret = api.SliceRenew(auth,name,newexp)
129 print "failed to renew %s" %name
131 def nodeBootState(argv):
132 """Sets boot state of a node."""
136 printUsage("not enough arguments")
145 printUsage("requires admin privs")
148 node = api.GetNodes(auth, [nodename], ['node_id','boot_state'])
152 logger.info("%s boot_state=%s" %(nodename, node['boot_state']))
153 if len(argv) >=2 and not config.debug:
154 logger.info("Setting node %s boot_state=%s" %(nodename, state))
155 node_id = node['node_id']
156 api.UpdateNode(auth, node_id, {'boot_state': state})
157 except Exception, exc:
158 logger.info("nodeBootState: %s" % exc)
160 logger.info("Cant find node %s to toggle boot state" % nodename)
164 """Sends Ping Of Death to node."""
168 printUsage("not enough arguments")
173 printUsage("requires admin privs")
176 node = api.GetNodes(auth, [nodename], ['node_id'])
179 logger.info("Sending POD to %s" % nodename)
182 api.RebootNode(auth, node['node_id'])
183 except Exception, exc:
184 logger.info("nodePOD: %s" % exc)
186 logger.info("Cant find node %s to send POD." % nodename)
188 def suspendSlice(argv):
189 """Freeze specific slice."""
192 printUsage("requires admin privs")
196 logger.info("Suspending slice %s" % slice)
199 api.AddSliceAttribute(auth, slice, "enabled", "0")
200 except Exception, exc:
201 logger.info("suspendSlices: %s" % exc)
203 def suspendSlices(argv):
204 """Freeze all site slices."""
207 printUsage("requires admin privs")
210 if argv[0].find(".") <> -1: siteslices = slices([siteId(argv)])
211 else: siteslices = slices(argv)
213 for slice in siteslices:
214 suspendSlice([slice])
216 def __enableSlice(slice):
217 logger.info("unfreezing slice %s" % slice['name'])
218 slice_attributes = api.GetSliceAttributes(auth,slice['slice_attribute_ids'])
219 for slice_attribute in slice_attributes:
220 if slice_attribute['name'] == "enabled":
221 api.DeleteSliceAttribute(auth, slice_attribute['slice_attribute_id'])
223 def enableSlice(arg):
224 """Enable suspended slice."""
227 printUsage("requires admin privs")
231 gSlices = {'name':slicename}
232 slice = api.GetSlices(auth,gSlices)
234 __enableSlice(slice[0])
236 logger.info("slice %s not found" % slicename)
238 def enableSlices(argv):
239 """Enable suspended site slices."""
243 printUsage("requires admin privs")
246 if argv[0].find(".") <> -1:
247 slices = api.GetSlices(auth,[siteId(argv)])
249 gSlices = {'name':"%s_*"%argv[0]}
250 slices = api.GetSlices(auth,gSlices)
255 def setSliceMax(argv):
256 """Set max_slices for Slice. Returns previous max_slices"""
259 printUsage("requires admin privs")
264 if name.find(".") <> -1:
265 site_ids = api.GetNodes(auth, [name], ['site_id'])
266 if len(site_ids) == 1:
267 site_id = [site_ids[0]['site_id']]
268 loginbase = api.GetSites (auth, site_id, ["login_base"])
270 printUsage("invalid hostname %s" % name)
273 site_ids = api.GetSites(auth, {'login_base': "%s" % name}, ['site_id'])
274 if len(site_ids) == 1:
275 siteid = site_ids[0]['site_id']
278 numslices = api.GetSites(auth, [siteid], ["max_slices"])[0]['max_slices']
280 api.UpdateSite(auth, siteid, {'max_slices': val})
281 logger.info("_SetSliceMax: %s max_slices was %d set to %d" % (loginbase,numslices,val))
283 except Exception, exc:
284 logger.info("_SetSliceMax: %s" % exc)
288 """Enable suspended slice."""
291 printUsage("requires admin privs")
295 printUsage("incorrect arguments")
301 check['Username'] = user
302 check['AuthMethod'] = "password"
303 check['AuthString'] = pwd
304 for role in ['user','tech','pi','admin']:
306 res = api.AdmAuthCheck(check)
307 print "%s -> %s %d" % (user,role,res)
310 def cleanSlices(arg):
311 """Remove all disabled/deleted users from all slices."""
312 disabledUsers = {'enabled':False}
313 persons = api.GetPersons(auth,disabledUsers,['enabled','slice_ids','email','person_id'])
314 for person in persons:
315 assert (person['enabled']==False)
316 person_id = person['person_id']
317 if len(person['slice_ids'])>0:
318 for slice_id in person['slice_ids']:
319 print "deleting slice %d from %s" % (slice_id,person['email'])
320 api.DeletePersonFromSlice(auth,person_id,slice_id)
325 Usage: %s [-u user] [-p password] [-r role] CMD
328 -u PLC account username
329 -p PLC account password
334 def printUsage(error = None):
337 print "%s %s" %(sys.argv[0],error)
340 for name,function in funclist:
341 print "%20s\t%20s" % (name, function.__doc__)
351 (opts, argv) = getopt.getopt(sys.argv[1:], "u:p:r:h")
356 for (opt, optval) in opts:
370 password = getpass.getpass()
371 except (EOFError, KeyboardInterrupt):
375 auth['Username'] = user
376 auth['AuthMethod'] = "password"
377 auth['AuthString'] = password
380 cmd = functbl.get(argv[0], None)
385 logger.setLevel(logging.DEBUG)
386 ch = logging.StreamHandler()
387 ch.setLevel(logging.DEBUG)
388 formatter = logging.Formatter('logger - %(message)s')
389 ch.setFormatter(formatter)
390 logger.addHandler(ch)
391 result = cmd(argv[1:])
393 if argv[0] == "nodesDbg":
399 funclist = (("nodesDbg",nodesDbg),
403 ("siteNodes", getSiteNodes),
404 ("nodeBootState", nodeBootState),
405 ("nodePOD", nodePOD),
406 ("freezeSlice", suspendSlice),
407 ("unfreezeSlice", enableSlice),
408 ("freezeSlices", suspendSlices),
409 ("unfreezeSlices", enableSlices),
410 ("setSliceMax", setSliceMax),
411 ("authCheck", authCheck),
412 ("cleanSlices", cleanSlices),
413 ("renewAllSlices", renewAllSlices))
419 if __name__=="__main__":