Commit fd6d8cc9 authored by Kirk Webb's avatar Kirk Webb

Snapshot.

* incompatible option handling and use removed from gen purpose libs
* Global PLC mutex implemented, but currently disabled
* plabmonitord parallelization cut in half (for now)

I'm still very frustrated with option handling/passing.  Needs more thought,
but the primary issue is that there really isn't a global variable space in
python (global to file, yes, but not global to interpreter invocation).

I've learned that __builtin__ might work for this, but it seems hacky..
parent 8af58167
# -*- python -*-
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2003 University of Utah and the Flux Group.
# All rights reserved.
#
#
# Database functions
......@@ -11,13 +16,20 @@ import pwd
import MySQLdb
import libtestbed
from libtestbed import *
#
# Debug vars.
#
verbose = 0;
debug = 0;
#
# DB variables.
#
__dbName = "@TBDBNAME@"
__dbQueryMaxtries = 1
__dbConnMaxtries = 5
__debug = 0
__dbConnection = None
......@@ -35,7 +47,7 @@ def TBDBConnect():
name = "uid%d" % uid
dbuser = "%s:%s:%d" % (sys.argv[0], name, os.getpid())
if __debug:
if debug:
print "Connecting to db %s as %s" % (__dbName, dbuser)
# Connect, with retries
......@@ -57,7 +69,7 @@ def DBQuery(queryPat, querySub = (), asDict = False):
else:
cursor = __dbConnection.cursor()
if __debug:
if debug:
print "Executing DB query %s" % queryPat
tries = __dbQueryMaxtries
......@@ -65,7 +77,7 @@ def DBQuery(queryPat, querySub = (), asDict = False):
try:
cursor.execute(queryPat, querySub)
ret = cursor.fetchall()
if __debug:
if debug:
rs = `ret`
if len(rs) > 60:
rs = rs[:60] + "..."
......
......@@ -10,6 +10,7 @@ import os
import time
import signal
import syslog
import socket
import traceback
import xmlrpclib
......@@ -35,25 +36,27 @@ DEF_TIMEOUT = 1*60 # default timeout interval
MAXCONSECEXC = 3
#
# Global Variable "namespace" and command line argument parser setup
# Output control variables.
#
gv = False
parser = OptionParser()
parser.add_option("-v", "--verbose", dest="verbose", default=False,
action="store_true", help="Say more about internal stuff")
parser.add_option("-d", "--debug", dest="debug", default=False,
action="store_true", help="Say A LOT about internal stuff")
def handleArgs(args):
verbose = 0
debug = 0
class TBParser (OptionParser):
"""
Takes a list of command-line arguments, interprets those at the
beginning that are meant for libplab (-vd), and returns the remainder
of the arguments.
Slightly modified OptionParser that simply adds some universally
useful options. May want to extend to have different error behavior.
"""
global parser, gv
gv, unparsed_args = parser.parse_args(args)
return unparsed_args
def __init__(self):
OptionParser.__init__(self)
self.add_option("-v", "--verbose", dest="verbose", default=False,
action="store_true", help="Say more about internal stuff")
self.add_option("-d", "--debug", dest="debug", default=False,
action="store_true", help="Say A LOT about internal stuff")
return
pass
def SENDMAIL(To, Subj, Msg, From = None, Headers = None, Files = ()):
"""
Sends email to someone about something :)
......@@ -184,7 +187,7 @@ def enable_sigs(osigs):
#
class TimeoutError: pass
def alrmhandler(signum, frame):
if gv.debug:
if debug:
print "Timeout! Raising TimeoutError."
raise TimeoutError
......@@ -285,7 +288,7 @@ def ForkCmd(cmd, args=(), timeout=DEF_TIMEOUT,
try: exval = os.wait()[1]
except: exval = 256
else:
if gv.debug:
if debug:
if os.WIFEXITED(exval):
print "Process complete, exit value: %d" % \
os.WEXITSTATUS(exval)
......@@ -301,7 +304,7 @@ def ForkCmd(cmd, args=(), timeout=DEF_TIMEOUT,
# child
else:
def sigusrexit(signum, frame):
if gv.debug:
if debug:
print "Received SIGUSR1, bailing out"
os._exit(1)
......@@ -355,7 +358,7 @@ def tryXmlrpcCmd(cmd, args = (),
tries = inittries
if gv.debug:
if debug:
print "About to perform command %s with args:\n\t%s" % \
(cmd, args)
while 1:
......@@ -378,14 +381,14 @@ def tryXmlrpcCmd(cmd, args = (),
e.triesleft = tries
raise xmlrpclib.Fault, e
except TimeoutError, e:
if gv.debug:
if debug:
print "Caught a timeout error, setting triesleft and raising."
e.triesleft = tries
raise TimeoutError, e
except (socket.error, xmlrpclib.ProtocolError), e:
print "Encountered problem communicating with agent " \
"while executing command: %s" % cmd.func_name
if gv.debug:
if debug:
print "Exception is of type: %s" % e
if tries > 0:
......
# -*- python -*-
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2003 University of Utah and the Flux Group.
# All rights reserved.
#
#
# Database functions
......@@ -11,13 +16,20 @@ import pwd
import MySQLdb
import libtestbed
from libtestbed import *
#
# Debug vars.
#
verbose = 0;
debug = 0;
#
# DB variables.
#
__dbName = "@TBDBNAME@"
__dbQueryMaxtries = 1
__dbConnMaxtries = 5
__debug = 0
__dbConnection = None
......@@ -35,7 +47,7 @@ def TBDBConnect():
name = "uid%d" % uid
dbuser = "%s:%s:%d" % (sys.argv[0], name, os.getpid())
if __debug:
if debug:
print "Connecting to db %s as %s" % (__dbName, dbuser)
# Connect, with retries
......@@ -57,7 +69,7 @@ def DBQuery(queryPat, querySub = (), asDict = False):
else:
cursor = __dbConnection.cursor()
if __debug:
if debug:
print "Executing DB query %s" % queryPat
tries = __dbQueryMaxtries
......@@ -65,7 +77,7 @@ def DBQuery(queryPat, querySub = (), asDict = False):
try:
cursor.execute(queryPat, querySub)
ret = cursor.fetchall()
if __debug:
if debug:
rs = `ret`
if len(rs) > 60:
rs = rs[:60] + "..."
......
......@@ -33,7 +33,6 @@ from warnings import warn
#
# Testbed and DB access libs
#
import libtestbed
from libtestbed import *
from libdb import *
......@@ -46,6 +45,12 @@ from mod_dslice import mod_dslice
agents = {'PLC' : mod_PLC,
'dslice' : mod_dslice}
#
# output control vars
#
verbose = 0
debug = 0
#
# Constants
#
......@@ -95,13 +100,6 @@ NODEPREFIX = "plab"
BADSITECHARS = re.compile(r"\W+")
PLABBASEPRIO = 20000
#
# Additions to parser
#
parser.add_option("--pollNode", action="store_true", dest="pollNode",
default=False,
help="Poll node before attempting to set it up.")
#
# var to track failed renewals
#
......@@ -188,7 +186,7 @@ class Plab:
if not agent:
self.agent = agents[DEF_AGENT]()
pass
if libtestbed.gv.debug:
if debug:
print "Using module: %s" % self.agent.modname
pass
pass
......@@ -241,12 +239,12 @@ class Plab:
except:
extype, exval, extrace = sys.exc_info()
print "Error talking to agent: %s: %s" % (extype, exval)
if libtestbed.gv.debug:
if debug:
print extrace
print "Going back to sleep until next scheduled poll"
return
if libtestbed.gv.debug:
if debug:
print "Got advertisement list:"
print avail
pass
......@@ -265,7 +263,7 @@ class Plab:
# Get node info we already have.
known = self.__getKnownPnodes()
if libtestbed.gv.debug:
if debug:
print "Got known pnodes:"
print known
pass
......@@ -299,7 +297,7 @@ class Plab:
if len(toadd):
# Are we ignoring new entries?
if ignorenew:
if libtestbed.gv.verbose:
if verbose:
print "%d new Plab nodes, but ignored for now" % len(toadd)
pass
pass
......@@ -311,7 +309,7 @@ class Plab:
for nodeent, update in toadd:
# Get the linktype here so we can report it in email.
self.__findLinkType(nodeent)
if libtestbed.gv.debug:
if debug:
print "Found linktype %s for node %s" % \
(nodeent['LINKTYPE'], nodeent['IP'])
pass
......@@ -505,7 +503,7 @@ class Plab:
vprio = (priority * 100) + (n+1)
sshdport = 38000+(n+1)
vnodeid = "%s-%d" % (nodeid, n+1)
if libtestbed.gv.verbose:
if verbose:
print "Creating vnode %s, priority %d" % (vnodeid, vprio)
pass
......@@ -556,7 +554,7 @@ class Plab:
it doesn't change.
"""
if not hasattr(self, "__getNodetypeInfoCache"):
if libtestbed.gv.debug:
if debug:
print "Getting node type info"
pass
res = DBQueryFatal("select osid, control_iface"
......@@ -574,7 +572,7 @@ class Plab:
addNode helper function. Returns a (nodeid, priority) tuple of
the next free nodeid and priority for Plab nodes.
"""
if libtestbed.gv.debug:
if debug:
print "Getting next free nodeid"
DBQueryFatal("lock tables nextfreenode write")
try:
......@@ -764,7 +762,7 @@ class Slice:
XXX This should probably be made lazy, since not all operations
really need it
"""
if libtestbed.gv.verbose:
if verbose:
print "Loading slice for pid/eid %s/%s" % (self.pid, self.eid)
res = DBQueryFatal("select slicename, slicemeta from plab_slices"
" where pid = %s and eid = %s",
......@@ -871,16 +869,12 @@ class Slice:
#
class Node:
def __init__(self, slice, nodeid):
def __init__(self, slice, nodeid, pollNode = False):
self.slice = slice
self.nodeid = nodeid
self.IP = self.__findIP()
self.nodemeta = None
self.pollNode = False
if hasattr(gv,"pollNode"):
self.pollNode = gv.pollNode
pass
self.pollNode = pollNode
return
# XXX: may want to rethink signal handling here.
......@@ -939,7 +933,7 @@ class Node:
Loads an already allocated node from the DB. Don't call this
directly, use Slice.loadNode instead.
"""
if libtestbed.gv.verbose:
if verbose:
print "Loading node %s" % self.nodeid
res = DBQueryFatal("select slicename, nodemeta"
" from plab_slice_nodes where node_id = %s",
......@@ -1028,7 +1022,7 @@ class Node:
TIMESTAMP("emulabify finished on %s." % self.nodeid)
def addToGroup(self, user, group):
if libtestbed.gv.verbose:
if verbose:
print "Adding %s to group %s on node %s" % \
(user, group, self.nodeid)
self.__perform("sudo /usr/sbin/usermod -G %s %s" % (group, user))
......@@ -1038,11 +1032,11 @@ class Node:
Unpacks a locally stored gzip'd tarball to the specified path
(default /) on the remote node. Always done as remote root.
"""
if libtestbed.gv.verbose:
if verbose:
print "Unpacking tgz %s to %s on %s" % \
(tgzpath, destpath, self.nodeid)
try:
if libtestbed.gv.debug:
if debug:
print "Trying to grab rootball through loopback service"
self.__perform("sudo wget -q -nH -P /tmp " +
ROOTBALL_URL + tgzname)
......@@ -1057,7 +1051,7 @@ class Node:
"""
Executes the given command on the remote node via sshtb
"""
if libtestbed.gv.debug:
if debug:
print "Performing '%s' on %s" % (command, self.nodeid)
if os.spawnl(os.P_WAIT, SSH, SSH, "-host", self.nodeid, command):
raise RuntimeError, "ssh '%s' failed" % command
......@@ -1068,7 +1062,7 @@ class Node:
as root.
"""
import popen2
if libtestbed.gv.debug:
if debug:
print "Copying %s to %s on %s" % \
(localfile, remotefile, self.nodeid)
# dd is a bit overbearing for this job, but I can't do something
......@@ -1087,15 +1081,15 @@ class Node:
"""
Figures out and returns the IP of the remote node.
"""
res = DBQueryFatal("select i.IP from interfaces as i"
" left join nodes as nv on"
" i.node_id=nv.phys_nodeid"
res = DBQueryFatal("select i.IP from nodes as nv"
" left join interfaces as i on"
" nv.phys_nodeid=i.node_id"
" where nv.node_id=%s"
" limit 1",
(self.nodeid))
assert (len(res) > 0), \
assert (res and len(res) > 0), \
"No IP found for nodeid %s" % self.nodeid
((IP, ), ) = res
if libtestbed.gv.debug:
if debug:
print "Found IP %s for node %s" % (IP, self.nodeid)
return IP
......@@ -10,6 +10,7 @@ import os
import time
import signal
import syslog
import socket
import traceback
import xmlrpclib
......@@ -35,25 +36,27 @@ DEF_TIMEOUT = 1*60 # default timeout interval
MAXCONSECEXC = 3
#
# Global Variable "namespace" and command line argument parser setup
# Output control variables.
#
gv = False
parser = OptionParser()
parser.add_option("-v", "--verbose", dest="verbose", default=False,
action="store_true", help="Say more about internal stuff")
parser.add_option("-d", "--debug", dest="debug", default=False,
action="store_true", help="Say A LOT about internal stuff")
def handleArgs(args):
verbose = 0
debug = 0
class TBParser (OptionParser):
"""
Takes a list of command-line arguments, interprets those at the
beginning that are meant for libplab (-vd), and returns the remainder
of the arguments.
Slightly modified OptionParser that simply adds some universally
useful options. May want to extend to have different error behavior.
"""
global parser, gv
gv, unparsed_args = parser.parse_args(args)
return unparsed_args
def __init__(self):
OptionParser.__init__(self)
self.add_option("-v", "--verbose", dest="verbose", default=False,
action="store_true", help="Say more about internal stuff")
self.add_option("-d", "--debug", dest="debug", default=False,
action="store_true", help="Say A LOT about internal stuff")
return
pass
def SENDMAIL(To, Subj, Msg, From = None, Headers = None, Files = ()):
"""
Sends email to someone about something :)
......@@ -184,7 +187,7 @@ def enable_sigs(osigs):
#
class TimeoutError: pass
def alrmhandler(signum, frame):
if gv.debug:
if debug:
print "Timeout! Raising TimeoutError."
raise TimeoutError
......@@ -285,7 +288,7 @@ def ForkCmd(cmd, args=(), timeout=DEF_TIMEOUT,
try: exval = os.wait()[1]
except: exval = 256
else:
if gv.debug:
if debug:
if os.WIFEXITED(exval):
print "Process complete, exit value: %d" % \
os.WEXITSTATUS(exval)
......@@ -301,7 +304,7 @@ def ForkCmd(cmd, args=(), timeout=DEF_TIMEOUT,
# child
else:
def sigusrexit(signum, frame):
if gv.debug:
if debug:
print "Received SIGUSR1, bailing out"
os._exit(1)
......@@ -355,7 +358,7 @@ def tryXmlrpcCmd(cmd, args = (),
tries = inittries
if gv.debug:
if debug:
print "About to perform command %s with args:\n\t%s" % \
(cmd, args)
while 1:
......@@ -378,14 +381,14 @@ def tryXmlrpcCmd(cmd, args = (),
e.triesleft = tries
raise xmlrpclib.Fault, e
except TimeoutError, e:
if gv.debug:
if debug:
print "Caught a timeout error, setting triesleft and raising."
e.triesleft = tries
raise TimeoutError, e
except (socket.error, xmlrpclib.ProtocolError), e:
print "Encountered problem communicating with agent " \
"while executing command: %s" % cmd.func_name
if gv.debug:
if debug:
print "Exception is of type: %s" % e
if tries > 0:
......
......@@ -10,16 +10,16 @@ sys.path.append("@prefix@/lib")
import xmlrpclib
import getopt
import fcntl
import time
import libtestbed
from libtestbed import *
#
# Setup mod_PLC's parse args
# output control vars
#
parser.add_option("--noIS", dest="noIS", action="store_true",
default=False,
help="Don't run InstantiateSliver() in mod_PLC")
verbose = 0
debug = 0
#
# PLC constants
......@@ -28,9 +28,57 @@ DEF_PLC_URI = "https://www.planet-lab.org/db/slices/dynamicprog.php"
DEF_PLC_USER = "lepreau@cs.utah.edu"
DEF_PLC_PASS = "phurds"
DEF_PLC_LEASELEN = 1*30*24*60*60 # add one month (XXX: for now)
DEF_PLC_SHARES = 30
DEF_PLC_SHARES = 30 # XXX: totally arbitrary
EMULABMAN_EMAIL = "emulabman@emulab.net"
PLC_LOCKFILE = "/tmp/.PLC-lock"
DEF_PLC_SPACING = 3 # seconds
#
# Reflective wrapper class for real PLCagent.
# This class forces global, mutually exclusive access to PLC
# function calls.
#
# XXX: Created per Jay's request, then deactivated per Jay's
# subsequent request.
#
class __PLCagent:
class __PLCMutexMethod:
def __init__(self, funcname, obj):
self.__lockfile = open(PLC_LOCKFILE, "w")
self.__meth = eval("obj.%s" % funcname)
self.func_name = funcname
return
def __call__(self, *args):
retval = None
if debug:
TIMESTAMP("Acquiring PLC lock")
pass
fcntl.lockf(self.__lockfile, fcntl.LOCK_EX)
if debug:
TIMESTAMP("Lock acquired.")
pass
time.sleep(DEF_PLC_SPACING)
fcntl.lockf(self.__lockfile, fcntl.LOCK_UN)
if debug:
TIMESTAMP("PLC lock released")
pass
return self.__meth(*args)
pass
def __init__(self, *args):
self.__myPLC = _PLCagent(*args)
return
def __getattr__(self, name):
return self.__PLCMutexMethod(name, self.__myPLC)
#
# The real PLC agent. Wraps up standard arguments to the
# PLC XMLRPC interface.
#
class PLCagent:
def __init__(self, slicename,
uri = DEF_PLC_URI,
......@@ -49,6 +97,7 @@ class PLCagent:
except:
print "Failed to create XML-RPC proxy"
raise
return
def createSlice(self):
return self.__server.createSlice(self.__slice, self.__auth)
......@@ -104,12 +153,9 @@ class PLCagent:
class mod_PLC:
def __init__(self):
def __init__(self, noIS = False):
self.modname = "mod_PLC"
self.noIS = False
if hasattr(libtestbed.gv,"noIS"):
self.noIS = libtestbed.gv.noIS
pass
self.noIS = noIS
return
def createSlice(self, slice):
......@@ -119,7 +165,7 @@ class mod_PLC:
try:
res = tryXmlrpcCmd(agent.createSlice)
if libtestbed.gv.debug:
if debug:
print res
pass
pass
......@@ -130,7 +176,7 @@ class mod_PLC:
try:
res = tryXmlrpcCmd(agent.AssignUsers,
EMULABMAN_EMAIL)
if libtestbed.gv.debug:
if debug:
print res
pass
pass
......@@ -142,7 +188,7 @@ class mod_PLC:
res = tryXmlrpcCmd(agent.AssignShares,
(DEF_PLC_LEASELEN,
DEF_PLC_SHARES))
if libtestbed.gv.debug:
if debug:
print res
pass
pass
......@@ -166,7 +212,7 @@ class mod_PLC:
res = tryXmlrpcCmd(agent.AssignShares,
(DEF_PLC_LEASELEN,
DEF_PLC_SHARES))
if libtestbed.gv.debug:
if debug:
print res
pass
pass
......@@ -187,7 +233,7 @@ class mod_PLC:
try:
res = tryXmlrpcCmd(agent.AssignNodes, node.IP,
inittries=tries, raisefault=True)
if libtestbed.gv.debug:
if debug:
print res
pass
pass
......@@ -217,7 +263,7 @@ class mod_PLC:
TIMESTAMP("InstantiateSliver() starting on %s." % node.nodeid)
res = tryXmlrpcCmd(agent.InstantiateSliver, node.IP)
TIMESTAMP("InstantiateSliver() complete on %s." % node.nodeid)
if libtestbed.gv.debug:
if debug:
print res
pass
pass
......@@ -239,7 +285,7 @@ class mod_PLC:
try:
res = tryXmlrpcCmd(agent.UnAssignNodes, node.IP,
inittries=tries, raisefault=True)
if libtestbed.gv.debug:
if debug:
print res
pass
pass
......
......@@ -16,9 +16,14 @@ import nodemgr, nodemgrproxy
import lease
import cPickle
import libtestbed
from libtestbed import *
#
# output control vars
#
verbose = 0
debug = 0
#
# Constants
#
......@@ -61,7 +66,7 @@ class mod_dslice:
1, LEASELEN, (node.IP,)))
assert (len(tickets) == 1), "%d tickets returned" % len(tickets)
ticketdata = tickets[0]
if libtestbed.gv.debug:
if debug:
print "Obtained ticket:"
print ticketdata
pass
......@@ -108,7 +113,7 @@ class mod_dslice:
break
pass
if libtestbed.gv.debug:
if debug:
print "Obtained lease/vm:"
print leasedata
pass
......@@ -163,7 +168,7 @@ class mod_dslice:
should be one of the keys that ssh naturally knows about, or
those commands will fail.
"""
if libtestbed.gv.verbose:
if verbose:
print "Adding pubkey to node %s" % node.nodeid
pass
if not identityfile.endswith(".pub"):
......@@ -172,7 +177,7 @@ class mod_dslice:
pubkey = file(identityfile, "rb").read().strip()
nodemgr = self.__createNodemgrProxy(node.IP)
ret = tryXmlrpcCmd(nodemgr.addkey, (node.slice.slicename, pubkey))
if libtestbed.gv.debug:
if debug:
print "Added key: %s" % `ret`
pass
return ret
......@@ -207,7 +212,7 @@ class mod_dslice:
else:
break
if libtestbed.gv.debug:
if debug:
print "Obtained new lease:"
print self.leasedata
self.lease = lease.lease(self.leasedata)
......@@ -222,11 +227,11 @@ class mod_dslice:
# XXX This is a workaround for a bug in M2Crypto
import tempfile
if libtestbed.gv.verbose:
if verbose:
print "Generating slice keypair"
# pdssi = Plab Dynamic Slice SSH Identity
fname = tempfile.mktemp("pdssi%d" % os.getpid())
if libtestbed.