All new accounts created on Gitlab now require administrator approval. If you invite any collaborators, please let Flux staff know so they can approve the accounts.

Commit 0c587f68 authored by Leigh B. Stoller's avatar Leigh B. Stoller

Checkpoint latest working code in case anyone wants to take a looksie.

parent 838b119b
......@@ -14,7 +14,8 @@ include $(OBJDIR)/Makeconf
BIN_SCRIPTS = sshxmlrpc_client.py
SBIN_SCRIPTS = sshxmlrpc_server.py
LIB_STUFF = sshxmlrpc.py emulabserver.py
LIB_STUFF = sshxmlrpc.py emulabserver.py emulabclient.py
LIBEXEC_STUFF = webxmlrpc
#
# These are the ones installed on plastic (users, control, etc).
......@@ -25,12 +26,13 @@ USERBINS = sshxmlrpc_client.py
# Force dependencies on the scripts so that they will be rerun through
# configure if the .in file is changed.
#
all: $(BIN_SCRIPTS) $(SBIN_SCRIPTS) $(LIB_STUFF)
all: $(BIN_SCRIPTS) $(SBIN_SCRIPTS) $(LIB_STUFF) $(LIBEXEC_STUFF)
include $(TESTBED_SRCDIR)/GNUmakerules
install: $(addprefix $(INSTALL_BINDIR)/, $(BIN_SCRIPTS)) \
$(addprefix $(INSTALL_SBINDIR)/, $(SBIN_SCRIPTS)) \
$(addprefix $(INSTALL_LIBEXECDIR)/, $(LIBEXEC_STUFF)) \
$(addprefix $(INSTALL_LIBDIR)/, $(LIB_STUFF))
#
......
#! /usr/bin/env python
#
# EMULAB-COPYRIGHT
# Copyright (c) 2004 University of Utah and the Flux Group.
# All rights reserved.
#
import sys
import socket
import os
import popen2
import getopt
MAXNSFILESIZE = (1024 * 512)
#
# This class defines a simple structure to return back to the caller.
# It includes the exit status of the command, and any output that it
# wants to send back. Why not return a tuple? Well, it appears that the
# python xmlrpc library requires that a singleton be returned from the
# server.
#
class ResponseBlock:
def __init__(self, exitval, output):
self.exitval = exitval
self.output = output
return
#
# This class implements the client side of the XMLRPC interface to Emulab.
# We do not try to do any serious argument processing here, but just pass
# it all through to the server. This may not be ideal, but I do not want to
# do argument processing and checking in multiple places! This whole approach
# will need another look at some point, but the goal right now is to get
# something that looks like an RPC interface running quickly.
#
class emulabclient:
#
# Initialize the object. The server argument is intended to
# make this class independent of how we talk to the server. It just needs
# to export the same interface as the xmlrpclib ServerProxy class.
#
def __init__(self, server, debug):
self.VERSION = 0.1
self.server = server
self.debug = debug
return
##
# Echo a message, basically, prepend the host name to the parameter list.
#
# @param args The argument list to echo back.
# @return The 'msg' value with this machine's name prepended.
#
def echo(self, *args):
argdict = {};
argdict["list"] = args
response = self.server.echo(self.VERSION, argdict)
print response["output"]
return 0
#
# Start an experiment using batchexp. The wrinkle is that we have to
# package up the NS file and pass it inline.
#
def batchexp(self, *args):
# The args are read-only, but I want a mutable version.
arglist = [a for a in args];
if len(arglist) == 0:
print "batchexp: Must provide some arguments"
return -1
#
# Parse args. We do not try to do any checking, but rather just
# convert them to functional arguments and place them into the
# Dict that is passed along.
#
argdict = {};
opt_args, req_args = getopt.getopt(arglist, "iE:g:e:p:S:L:a:l:fw")
for opt, val in opt_args:
if opt in ("-i"):
argdict["batchmode"] = 0
pass
elif opt in ("-E"):
argdict["description"] = val
pass
elif opt in ("-g"):
argdict["gid"] = val
pass
elif opt in ("-e"):
argdict["eid"] = val
pass
elif opt in ("-p"):
argdict["pid"] = val
pass
elif opt in ("-S"):
argdict["swapable"] = 0
argdict["noswap_reason"] = val
pass
elif opt in ("-L"):
argdict["idleswap"] = 0
argdict["noidleswap_reason"] = val
pass
elif opt in ("-a"):
argdict["autoswap"] = val
pass
elif opt in ("-l"):
argdict["idleswap"] = val
pass
elif opt in ("-f"):
argdict["frontend"] = 1
pass
elif opt in ("-w"):
argdict["waitmode"] = 1
pass
pass
if len(req_args) == 1:
nsfilename = req_args[0]
nsfilestr = readnsfile(nsfilename, self.debug)
# Watch for error reading NS file.
if not nsfilestr:
return -1
if len(nsfilestr) > MAXNSFILESIZE:
print "batchexp: NS file too big; server will reject it."
return -1
argdict["nsfilestr"] = nsfilestr
pass
response = self.server.batchexp(self.VERSION, argdict)
if len(response["output"]):
print response["output"]
pass
return response["exitval"]
#
# startexp is an alias for batchexp.
#
def startexp(self, *args):
return self.batchexp(*args)
#
# swapexp. Also does swapmod. The wrinkle is that like above, we need to
# pakcage up the NS file and pass it inline. The difference is that the
# NS file is optional, dependent on the previous options; swapmod only.
#
def swapexp(self, *args):
# The args are read-only, but I want a mutable version.
arglist = [a for a in args];
if len(arglist) == 0:
print "swapexp: Must provide some arguments"
return -1
#
# Parse args. We do not try to do any checking, but rather just
# convert them to functional arguments and place them into the
# Dict that is passed along.
#
argdict = {};
opt_args, req_args = getopt.getopt(arglist, "wres:")
for opt, val in opt_args:
if opt in ("-w"):
argdict["waitmode"] = 1
pass
elif opt in ("-r"):
argdict["reboot_nodes"] = 1
pass
elif opt in ("-e"):
argdict["restart_eventsys"] = 1
pass
elif opt in ("-s"):
argdict["swapop"] = val
pass
pass
if len(req_args) < 2 or len(req_args) > 3:
print "swapexp: Must provide pid and eid and an optiona NS file!"
return -1
argdict["pid"] = req_args[0]
argdict["eid"] = req_args[1]
if len(req_args) == 3:
nsfilename = req_args[2]
nsfilestr = readnsfile(nsfilename, self.debug)
# Watch for error reading NS file.
if not nsfilestr:
return -1
if len(nsfilestr) > MAXNSFILESIZE:
print "batchexp: NS file too big; server will reject it."
return -1
argdict["nsfilestr"] = nsfilestr
pass
response = self.server.swapexp(self.VERSION, argdict)
if len(response["output"]):
print response["output"]
pass
return response["exitval"]
#
# endexp.
#
def endexp(self, *args):
# The args are read-only, but I want a mutable version.
arglist = [a for a in args];
if len(arglist) == 0:
print "endexp: Must provide some arguments"
return -1
#
# Parse args. We do not try to do any checking, but rather just
# convert them to functional arguments and place them into the
# Dict that is passed along.
#
argdict = {};
opt_args, req_args = getopt.getopt(arglist, "w")
for opt, val in opt_args:
if opt in ("-w"):
argdict["waitmode"] = 1
pass
pass
if len(req_args) != 2:
print "swapexp: Must provide pid and eid!"
return -1
argdict["pid"] = req_args[0]
argdict["eid"] = req_args[1]
response = self.server.endexp(self.VERSION, argdict)
if len(response["output"]):
print response["output"]
pass
return response["exitval"]
#
# nscheck. Syntax check an NS file. The wrinkle is that like above, we
# need to pakcage up the NS file and pass it inline.
##
def nscheck(self, *args):
# The args are read-only, but I want a mutable version.
arglist = [a for a in args];
if len(arglist) != 1:
print "nscheck: Must provide an NS file!"
return -1
argdict = {};
nsfilename = arglist[0]
nsfilestr = readnsfile(nsfilename, self.debug)
# Watch for error reading NS file.
if not nsfilestr:
return -1
if len(nsfilestr) > MAXNSFILESIZE:
print "nscheck: NS file too big; server will reject it."
return -1
argdict["nsfilestr"] = nsfilestr
response = self.server.nscheck(self.VERSION, argdict)
if len(response["output"]):
print response["output"]
pass
return response["exitval"]
#
# nscheck. Syntax check an NS file. The wrinkle is that like above, we
# need to pakcage up the NS file and pass it inline.
#
def create_image(self, *args):
# The args are read-only, but I want a mutable version.
arglist = [a for a in args];
if len(arglist) == 0:
print "create_image: Must provide some arguments!"
return -1
#
# Parse args. We do not try to do any checking, but rather just
# convert them to functional arguments and place them into the
# Dict that is passed along.
#
argdict = {};
opt_args, req_args = getopt.getopt(arglist, "p")
for opt, val in opt_args:
if opt in ("-p"):
argdict["pid"] = val
pass
pass
if len(req_args) != 2:
print "create_image: Must provide imageid and nodeid!"
return -1
argdict["imageid"] = req_args[0]
argdict["nodeid"] = req_args[1]
response = self.server.create_image(self.VERSION, argdict)
if len(response["output"]):
print response["output"]
pass
return response["exitval"]
pass
#
# Utility functions
#
#
# Read an nsfile and return a single string.
#
def readnsfile(nsfilename, debug):
nsfilestr = ""
try:
fp = os.open(nsfilename, os.O_RDONLY)
while True:
str = os.read(fp, 1024)
if not str:
break
nsfilestr = nsfilestr + str
pass
os.close(fp)
except:
if debug:
print "%s:%s" % (sys.exc_type, sys.exc_value)
pass
print "batchexp: Cannot read NS file '" + nsfilename + "'"
return None
pass
return nsfilestr
#! /usr/bin/env python
#
# EMULAB-COPYRIGHT
# Copyright (c) 2004 University of Utah and the Flux Group.
# All rights reserved.
#
import sys
import socket
import os
import popen2
import tempfile
import time
sys.path.append("@prefix@/lib")
import libdb
from libtestbed import SENDMAIL, TBOPS
from emulabclient import ResponseBlock
# Configure variables
TBDIR = "@prefix@"
#
# This class implements the server side of the XMLRPC interface to Emulab.
#
# Arguments passed as a Dictionary. This converts to a XML "struct"
# which in Perl/PHP/Ruby would be a hash. So, a client written in
# pretty much any language should be able to talk to this class.
#
class emulabserver:
##
# Initialize the object. Currently only sets the objects 'VERSION' value.
#
def __init__(self):
self.VERSION = 0.1
return
##
# Echo a message, basically, prepend the host name to the parameter list.
#
# @param args The argument list to echo back.
# @return The 'msg' value with this machine's name prepended.
#
def echo(self, version, argdict):
return ResponseBlock(0, socket.gethostname() + ": " + str(version)
+ " " + str(argdict["list"]))
#
# Start an experiment using batchexp. We get the NS file inline, which
# we have to write to a temp file first.
#
def batchexp(self, version, argdict):
if version != self.VERSION:
return ResponseBlock(-1, "Client version mismatch!");
pass
nsfilename = None
argstr = ""
for opt, val in argdict.items():
if opt in ("batchmode"):
if val == 0:
argstr += " -i"
pass
pass
elif opt in ("description"):
argstr += " -E "
argstr += val
pass
elif opt in ("gid"):
argstr += " -g "
argstr += val
pass
elif opt in ("eid"):
argstr += " -e "
argstr += val
pass
elif opt in ("pid"):
argstr += " -p "
argstr += val
pass
elif opt in ("idleswap"):
if opt == 0:
argstr += " -S "
argstr += argdict["noswap_reason"]
pass
pass
elif opt in ("noswap_reason"):
pass
elif opt in ("idleswap"):
if opt == 0:
argstr += " -L "
argstr += argdict["noidleswap_reason"]
pass
else:
argstr += " -l "
argstr += val
pass
pass
elif opt in ("noidleswap_reason"):
pass
elif opt in ("autoswap"):
argstr += " -a "
argstr += val
pass
elif opt in ("frontend"):
argstr += " -f "
pass
elif opt in ("waitmode"):
argstr += " -w "
pass
elif opt in ("nsfilepath"):
# Backend script will verify this local path.
nsfilename = val
pass
elif opt in ("nsfilestr"):
nsfilestr = val
if len(nsfilestr) > (1024 * 512):
return ResponseBlock(-1, "NS File way too big!");
(nsfp, nsfilename) = writensfile(nsfilestr)
if not nsfilename:
return ResponseBlock(-1, "Server Error")
pass
pass
if nsfilename:
argstr += " "
argstr += nsfilename
pass
(exitval, output) = runcommand(TBDIR + "/bin/batchexp " + argstr)
return ResponseBlock(exitval >> 8, output)
#
# swap an experiment using swapexp. We get the NS file inline, which
# we have to write to a temp file first.
#
def swapexp(self, version, argdict):
if version != self.VERSION:
return ResponseBlock(-1, "Client version mismatch!");
pass
nsfilename = None
argstr = ""
for opt, val in argdict.items():
if opt in ("waitmode"):
argstr += " -w "
pass
elif opt in ("reboot_nodes"):
argstr += " -r "
pass
elif opt in ("restart_eventsys"):
argstr += " -e "
pass
elif opt in ("swapop"):
argstr += " -s "
argstr += val
pass
elif opt in ("nsfilepath"):
# Backend script will verify this local path.
nsfilename = val
pass
elif opt in ("nsfilestr"):
nsfilestr = val
if len(nsfilestr) > (1024 * 512):
return ResponseBlock(-1, "NS File way too big!");
(nsfp, nsfilename) = writensfile(nsfilestr)
if not nsfilename:
return ResponseBlock(-1, "Server Error")
pass
pass
if argdict.has_key("pid"):
argstr += " "
argstr += argdict["pid"]
pass
if argdict.has_key("eid"):
argstr += " "
argstr += argdict["eid"]
pass
if nsfilename:
argstr += " "
argstr += nsfilename
pass
(exitval, output) = runcommand(TBDIR + "/bin/swapexp " + argstr)
return ResponseBlock(exitval >> 8, output)
#
# end an experiment using endexp.
#
def endexp(self, version, argdict):
if version != self.VERSION:
return ResponseBlock(-1, "Client version mismatch!");
pass
argstr = ""
for opt, val in argdict.items():
if opt in ("waitmode"):
argstr += " -w "
pass
pass
if argdict.has_key("pid"):
argstr += " "
argstr += argdict["pid"]
pass
if argdict.has_key("eid"):
argstr += " "
argstr += argdict["eid"]
pass
(exitval, output) = runcommand(TBDIR + "/bin/endexp " + argstr)
return ResponseBlock(exitval >> 8, output)
#
# nscheck an NS file.
#
def nscheck(self, version, argdict):
if version != self.VERSION:
return ResponseBlock(-1, "Client version mismatch!");
pass
argstr = ""
if argdict.has_key("nsfilestr"):
nsfilestr = argdict["nsfilestr"]
if len(nsfilestr) > (1024 * 512):
return ResponseBlock(-1, "NS File way too big!");
(nsfp, nsfilename) = writensfile(nsfilestr)
if not nsfilename:
return ResponseBlock(-1, "Server Error")
argstr += nsfilename
pass
elif argdict.has_key("nsfilepath"):
# Backend script will verify this local path.
argstr += escapeshellarg(argdict["nsfilepath"])
pass
(exitval, output) = runcommand(TBDIR + "/bin/nscheck " + argstr)
return ResponseBlock(exitval >> 8, output)
#
# create_image.
#
def create_image(self, version, argdict):
if version != self.VERSION:
return ResponseBlock(-1, "Client version mismatch!");
pass
argstr = ""
for opt, val in argdict.items():
if opt in ("pid"):
argstr += " -p "
argstr += escapeshellarg(val)
pass
pass
if argdict.has_key("imageid"):
argstr += " "
argstr += argdict["imageid"]
pass
if argdict.has_key("nodeid"):