From 16f2dc66eaa0d0de0a5d06bf4755e6368bbec0c4 Mon Sep 17 00:00:00 2001 From: Marc Fiuczynski Date: Wed, 24 Jan 2007 19:29:44 +0000 Subject: [PATCH] updated so that plc.py can be used also nicely from the command line --- mailer.py | 4 +- plc.py | 350 +++++++++++++++++++++++++++++++++++------------------- policy.py | 18 +-- reboot.py | 4 +- 4 files changed, 244 insertions(+), 132 deletions(-) diff --git a/mailer.py b/mailer.py index dc0799d..7d0b28f 100755 --- a/mailer.py +++ b/mailer.py @@ -4,7 +4,7 @@ # # Faiyaz Ahmed # -# $Id: mailer.py,v 1.4 2006/11/14 19:20:13 faiyaza Exp $ +# $Id: mailer.py,v 1.5 2007/01/17 16:03:30 faiyaza Exp $ from emailTxt import * import smtplib import config @@ -74,7 +74,7 @@ if __name__=="__main__": import smtplib import emailTxt import plc - id = plc.siteId("alice.cs.princeton.edu") + id = plc.siteId(["alice.cs.princeton.edu"]) print id #if id: #email('TEST', emailTxt.mailtxt.ssh % {'hostname': "ALICE.cs.princeton.edu"}, "tech-" + id + "@sites.planet-lab.org") diff --git a/plc.py b/plc.py index 42335aa..05ed20c 100644 --- a/plc.py +++ b/plc.py @@ -1,31 +1,32 @@ -# -# plc.py +#!/bin/env python # # Helper functions that minipulate the PLC api. # -# Faiyaz Ahmed +# Copyright (C) 2006, 2007 The Trustees of Princeton University # -# $Id: $ +# $Id: plc.py,v 1.1 2006/11/14 19:27:09 faiyaza Exp $ # from emailTxt import * import xml, xmlrpclib import logging -import auth import time import config +import getpass, getopt +import sys logger = logging.getLogger("monitor") - XMLRPC_SERVER = 'https://www.planet-lab.org/PLCAPI/' +api = xmlrpclib.Server(XMLRPC_SERVER, verbose=False) +anon = None +auth = None -''' -Returns list of nodes in dbg as reported by PLC -''' -def nodesDbg(): +def nodesDbg(argv): + """Returns list of nodes in dbg as reported by PLC""" + + global api, anon, auth dbgNodes = [] - api = xmlrpclib.Server(XMLRPC_SERVER, verbose=False) - anon = {'AuthMethod': "anonymous"} allnodes = api.AnonAdmGetNodes(anon, [], ['hostname','boot_state']) for node in allnodes: if node['boot_state'] == 'dbg': dbgNodes.append(node['hostname']) @@ -33,55 +34,53 @@ def nodesDbg(): return dbgNodes -''' -Returns loginbase for given nodename -''' -def siteId(nodename): - api = xmlrpclib.Server(XMLRPC_SERVER, verbose=False) - anon = {'AuthMethod': "anonymous"} +def siteId(argv): + """Returns loginbase for given nodename""" + + global api, anon, auth + nodename = argv[0] site_id = api.AnonAdmQuerySite (anon, {"node_hostname": nodename}) if len(site_id) == 1: loginbase = api.AnonAdmGetSites (anon, site_id, ["login_base"]) return loginbase[0]['login_base'] -''' -Returns list of slices for a site. -''' -def slices(loginbase): - api = xmlrpclib.Server(XMLRPC_SERVER, verbose=False) - return api.SliceListNames (auth.auth, loginbase) +def slices(argv): + """Returns list of slices for a site.""" + + global api, anon, auth + loginbase = argv[0] + if auth is None: + printUsage("requires admin privs") + sys.exit(1) + return api.SliceListNames (auth, loginbase) + +def getpcu(argv): + """Returns dict of PCU info of a given node.""" + + global api, anon, auth + nodename = argv[0].lower() + if auth is None: + printUsage("requires admin privs") + sys.exit(1) -''' -Returns dict of PCU info of a given node. -''' -def getpcu(nodename): - api = xmlrpclib.Server(XMLRPC_SERVER, verbose=False) - anon = {'AuthMethod': "anonymous"} nodes = [] site_id = api.AnonAdmQuerySite (anon, {"node_hostname": nodename}) if len(site_id) == 1: - # PCU uname, pw, etc try: - sitepcu = api.AdmGetSitePowerControlUnits(auth.auth, site_id[0])[0] - # returns node_id and port - sitepcuports = api.AdmGetPowerControlUnitNodes(auth.auth, sitepcu['pcu_id']) - # Joining feilds - for nodeidports in sitepcuports: - nodeidports.update(api.AnonAdmGetNodes(anon, - [nodeidports['node_id']], ["node_id", "hostname"])[0]) - nodes.append(nodeidports) - - # WHY THE FUCK DOES EVERY XMl+RPC RETURN A FUCKING ARRAY????? - # FURTHER, WHY THE FUCK WOULD YOU RETURN A NODE-ID WHEN SANITY WOULD SUGGEST - # FQDN???? /RANT - for node in nodes: - sitepcu[node['hostname']] = node['port_number'] - - # Sanity Check. Make sure the node is in the return, if not, barf. - if nodename in sitepcu.keys(): - return sitepcu - else: - raise Exception + sitepcus = api.AdmGetSitePowerControlUnits(auth, site_id[0]) + for sitepcu in sitepcus: + sitepcuports = api.AdmGetPowerControlUnitNodes(auth, sitepcu['pcu_id']) + for sitepcuport in sitepcuports: + node_id = [sitepcuport['node_id']] + node = api.AnonAdmGetNodes(anon,node_id,["hostname"]) + if len(node)==0: + continue + node = node[0] + hostname = node['hostname'].lower() + if hostname == nodename: + sitepcu['port_number']=sitepcuport['port_number'] + return sitepcu + except Exception, err: logger.debug("getpcu: %s" % err) return @@ -89,13 +88,11 @@ def getpcu(nodename): logger.info("Cant find site for %s" % nodename) -''' -Returns all site nodes for site id (loginbase). -''' -def getSiteNodes(loginbase): - api = xmlrpclib.Server(XMLRPC_SERVER, verbose=False) +def getSiteNodes(argv): + """Returns all site nodes for site id (loginbase).""" + global api, anon, auth + loginbase = argv[0] nodelist = [] - anon = {'AuthMethod': "anonymous"} try: site_id = api.AnonAdmQuerySite(anon, {'site_loginbase': "%s" % loginbase}) node_ids = api.AnonAdmGetSiteNodes(anon, site_id) @@ -103,122 +100,237 @@ def getSiteNodes(loginbase): nodelist.append(node['hostname']) except Exception, exc: logger.info("getSiteNodes: %s" % exc) + nodelist.sort() return nodelist -''' -Sets boot state of a node. -''' -def nodeBootState(nodename, state): - api = xmlrpclib.Server(XMLRPC_SERVER, verbose=False) - anon = {'AuthMethod': "anonymous"} +def nodeBootState(argv): + """Sets boot state of a node.""" + + global api, anon, auth + if len(argv) <> 2: + printUsage("not enough arguments") + sys.exit(1) + + nodename = argv[0] + state = argv[1] + + if auth is None: + printUsage("requires admin privs") + sys.exit(1) + node_id = api.AnonAdmQueryNode(anon, {'node_hostname' : nodename}) if len(node_id) == 1: logger.info("Setting node %s to %s" %(nodename, state)) try: if not config.debug: - api.AdmUpdateNode(auth.auth, node_id[0], {'boot_state': state}) + api.AdmUpdateNode(auth, node_id[0], {'boot_state': state}) except Exception, exc: logger.info("nodeBootState: %s" % exc) else: logger.info("Cant find node %s to toggle boot state" % nodename) -''' -Sends Ping Of Death to node. -''' -def nodePOD(nodename): - api = xmlrpclib.Server(XMLRPC_SERVER, verbose=False) - anon = {'AuthMethod': "anonymous"} +def nodePOD(argv): + """Sends Ping Of Death to node.""" + + global api, anon, auth + nodename = argv[0] + if auth is None: + printUsage("requires admin privs") + sys.exit(1) + node_id = api.AnonAdmQueryNode(anon, {'node_hostname' : nodename}) if len(node_id) == 1: logger.info("Sending POD to %s" % nodename) try: if not config.debug: - api.AdmRebootNode(auth.auth, node_id[0]) + api.AdmRebootNode(auth, node_id[0]) except Exception, exc: logger.info("nodePOD: %s" % exc) else: logger.info("Cant find node %s to send POD." % nodename) -''' -Freeze all site slices. -''' -def suspendSlices(nodename): - api = xmlrpclib.Server(XMLRPC_SERVER, verbose=False) - for slice in slices(siteId(nodename)): +def suspendSlices(argv): + """Freeze all site slices.""" + + global api, anon, auth + if auth is None: + printUsage("requires admin privs") + sys.exit(1) + + if argv[0].find(".") <> -1: siteslices = slices([siteId(argv)]) + else: siteslices = slices(argv) + + for slice in siteslices: logger.info("Suspending slice %s" % slice) try: if not config.debug: - api.SliceAttributeAdd(auth.auth, slice, "plc_slice_state", + api.SliceAttributeAdd(auth, slice, "plc_slice_state", {"state" : "suspended"}) except Exception, exc: logger.info("suspendSlices: %s" % exc) -#I'm commenting this because this really should be a manual process. -#''' -#Enable suspended site slices. -#''' -#def enableSlices(nodename, slicelist): -# api = xmlrpclib.Server(XMLRPC_SERVER, verbose=False) -# for slice in slices(siteId(nodename)): -# logger.info("Suspending slice %s" % slice) -# api.SliceAttributeAdd(auth.auth, slice, "plc_slice_state", {"state" : "suspended"}) -# +def enableSlices(argv): + """Enable suspended site slices.""" + + global api, anon, auth + if auth is None: + printUsage("requires admin privs") + sys.exit(1) -''' -Removes ability to create slices. Returns previous max_slices -''' -def removeSliceCreation(nodename): api = xmlrpclib.Server(XMLRPC_SERVER, verbose=False) - anon = {'AuthMethod': "anonymous"} - siteid = api.AnonAdmQuerySite (anon, {"node_hostname": nodename}) - numslices = api.AdmGetSites(auth.auth, siteid, ["max_slices"])[0]['max_slices'] + + if argv[0].find(".") <> -1: siteslices = slices([siteId(argv)]) + else: siteslices = slices(argv) + + for slice in siteslices: + logger.info("unfreezing slice %s" % slice) + api.SliceAttributeDelete(auth, slice, "plc_slice_state") + + +def removeSliceCreation(argv): + """Removes ability to create slices. Returns previous max_slices""" + + global api, anon, auth + if auth is None: + printUsage("requires admin privs") + sys.exit(1) + + name = argv[0] + if name.find(".") <> -1: + siteid = api.AnonAdmQuerySite (anon, {"node_hostname": name}) + loginbase = siteId(name) + else: + siteid = api.AnonAdmQuerySite (anon, {"site_loginbase": name}) + loginbase = name + + numslices = api.AdmGetSites(auth, siteid, ["max_slices"])[0]['max_slices'] if len(siteid) == 1: - logger.info("Removing slice creation for site %s" % siteId(nodename)) + logger.info("Removing slice creation for site %s" % loginbase) try: if not config.debug: - api.AdmUpdateSite(auth.auth, siteid[0], {'max_slices': 0}) + api.AdmUpdateSite(auth, siteid[0], {'max_slices': 0}) return numslices except Exception, exc: logger.info("removeSliceCreation: %s" % exc) else: - logger.debug("Cant find site for %s. Cannot revoke creation." % nodename) + logger.debug("Cant find site for %s. Cannot revoke creation." % loginbase) + +def enableSliceCreation(argv): + """QED""" + + global api, anon, auth + if auth is None: + printUsage("requires admin privs") + sys.exit(1) + + maxslices = int(argv[1]) + name = argv[0] + if name.find(".") <> -1: + siteid = api.AnonAdmQuerySite (anon, {"node_hostname": name}) + loginbase = siteId(name) + else: + siteid = api.AnonAdmQuerySite (anon, {"site_loginbase": name}) + loginbase = name -''' -QED -''' -def enableSliceCreation(nodename, maxslices): - api = xmlrpclib.Server(XMLRPC_SERVER, verbose=False) - anon = {'AuthMethod': "anonymous"} - siteid = api.AnonAdmQuerySite (anon, {"node_hostname": nodename}) if len(siteid) == 1: - logger.info("Enabling slice creation for site %s" % siteId(nodename)) + logger.info("Enabling slice creation for site %s" % loginbase) try: if not config.debug: - api.AdmUpdateSite(auth.auth, siteid[0], {"max_slices" : maxslices}) + api.AdmUpdateSite(auth, siteid[0], {"max_slices" : maxslices}) except Exception, exc: logger.info("API: %s" % exc) else: - logger.debug("Cant find site for %s. Cannot enable creation." % nodename) + logger.debug("Cant find site for %s. Cannot enable creation." % loginbase) + + +USAGE = """ +Usage: %s [-u user] [-p password] [-r role] CMD + +Options: +-u PLC account username +-p PLC account password +-r PLC account role +-h This message +""" % sys.argv[0] + +def printUsage(error = None): + global funclist + if error <> None: + print "%s %s" %(sys.argv[0],error) + print USAGE + print "CMD:" + for name,function in funclist: + print "%20s\t%20s" % (name, function.__doc__) + def main(): + global api, auth, anon + + anon = {"AuthMethod":"anonymous"} + auth = None + user = None + password = None + role = 'admin' + + (opts, argv) = getopt.getopt(sys.argv[1:], "u:p:r:h") + if len(argv)==0: + printUsage() + sys.exit(1) + + for (opt, optval) in opts: + if opt == '-u': + user = optval + elif opt == '-p': + password = optval + elif opt == '-r': + role = optval + elif opt == '-h': + print USAGE + sys.exit(0) + + if user <> None: + if password is None: + try: + password = getpass.getpass() + except (EOFError, KeyboardInterrupt): + print( "" ) + sys.exit(1) + auth = {} + auth['Username'] = user + auth['AuthMethod'] = "password" + auth['AuthString'] = password + auth['Role'] = role + + cmd = functbl.get(argv[0], None) + if cmd is None: + printUsage() + sys.exit(1) + logger.setLevel(logging.DEBUG) ch = logging.StreamHandler() ch.setLevel(logging.DEBUG) formatter = logging.Formatter('logger - %(message)s') ch.setFormatter(formatter) logger.addHandler(ch) - #print getpcu("kupl2.ittc.ku.edu") - #print getpcu("planetlab1.cse.msu.edu") - #print getpcu("alice.cs.princeton.edu") - #print nodesDbg() - #nodeBootState("alice.cs.princaeton.edu", "boot") - #freezeSite("alice.cs.princeton.edu") - #removeSliceCreation("alice.cs.princeton.edu") - #enableSliceCreation("alice.cs.princeton.edu", 1024) - print getSiteNodes("princeton") - #print siteId("alice.cs.princeton.edu") - #print nodePOD("planetlab5.warsaw.rd.tp.pl") + result = cmd(argv[1:]) + print result + +funclist = (("nodesDbg",nodesDbg), + ("siteId", siteId), + ("slices", slices), + ("pcu", getpcu), + ("siteNodes", getSiteNodes), + ("nodeBootState", nodeBootState), + ("nodePOD", nodePOD), + ("freezeSlices", suspendSlices), + ("unfreezeSlices", enableSlices), + ("disableSliceCreation",removeSliceCreation), + ("enableSliceCreation", enableSliceCreation)) + +functbl = {} +for f in funclist: + functbl[f[0]]=f[1] if __name__=="__main__": import reboot diff --git a/policy.py b/policy.py index 980f549..81fa2c8 100644 --- a/policy.py +++ b/policy.py @@ -3,7 +3,7 @@ # # Faiyaz Ahmed # -# $Id: policy.py,v 1.8 2007/01/17 19:33:04 faiyaza Exp $ +# $Id: policy.py,v 1.9 2007/01/17 19:46:40 faiyaza Exp $ # # Policy Engine. @@ -80,7 +80,7 @@ class Policy(Thread): logger.info("POLICY: %s in dbg, but acted on %s days ago" % (node, delta // SPERDAY)) return logger.info("POLICY: Node in dbg - " + node) - plc.nodeBootState(node, "rins") + plc.nodeBootState([node, "rins"]) # If it has a PCU return reboot.reboot(node) @@ -107,7 +107,7 @@ class Policy(Thread): # Grab a node from the queue (pushed by rt thread). node = self.sickNoTicket.get(block = True) # Get the login base - loginbase = plc.siteId(node) + loginbase = plc.siteId([node]) # Princeton Backdoor if loginbase == "princeton": return @@ -153,7 +153,7 @@ class Policy(Thread): if (delta >= PITHRESH) and (delta < SLICETHRESH): #remove slice creation if enough nodes arent up if not self.enoughUp(loginbase): - slices = plc.slices(loginbase) + slices = plc.slices([loginbase]) if len(slices) >= 1: for slice in slices: target.append(SLICEMAIL % slice) @@ -161,7 +161,7 @@ class Policy(Thread): tmp = emailTxt.mailtxt.removedSliceCreation sbj = tmp[0] msg = tmp[1] % {'loginbase': loginbase} - plc.removeSliceCreation(node) + plc.removeSliceCreation([node]) mailer.email(sbj, msg, target) self.squeezed[loginbase] = (time.time(), "creation") self.emailed[node] = ("creation", time.time()) @@ -173,7 +173,7 @@ class Policy(Thread): if (delta >= PITHRESH) and (delta > SLICETHRESH): target.append(PIEMAIL % loginbase) # Email slices at site. - slices = plc.slices(loginbase) + slices = plc.slices([loginbase]) if len(slices) >= 1: for slice in slices: target.append(SLICEMAIL % slice) @@ -183,7 +183,7 @@ class Policy(Thread): tmp = emailTxt.mailtxt.suspendSlices sbj = tmp[0] msg = tmp[1] % {'loginbase': loginbase} - plc.suspendSlices(node) + plc.suspendSlices([node]) self.squeezed[loginbase] = (time.time(), "freeze") mailer.email(sbj, msg, target) self.emailed[node] = ("freeze", time.time()) @@ -247,7 +247,7 @@ class Policy(Thread): Returns True if more than MINUP nodes are up at a site. ''' def enoughUp(self, loginbase): - allsitenodes = plc.getSiteNodes(loginbase) + allsitenodes = plc.getSiteNodes([loginbase]) if len(allsitenodes) == 0: logger.info("Node not in db") return @@ -293,7 +293,7 @@ def main(): #a.emailedStore("LOAD") #print a.emailed - print plc.slices(plc.siteId("alice.cs.princeton.edu")) + print plc.slices([plc.siteId(["alice.cs.princeton.edu"])]) os._exit(0) if __name__ == '__main__': import os diff --git a/reboot.py b/reboot.py index 297abe6..6b947bd 100755 --- a/reboot.py +++ b/reboot.py @@ -384,9 +384,9 @@ def racadm_reboot(ip, username, password, port): # Returns true if rebooted via PCU def reboot(nodename): - pcu = plc.getpcu(nodename) + pcu = plc.getpcu([nodename]) if not pcu: - plc.nodePOD(nodename) + plc.nodePOD([nodename]) return False # Try the PCU first logger.debug("Trying PCU %s %s" % (pcu['hostname'], pcu['model'])) -- 2.43.0