Commit 19dbd0fd authored by Timothy Stack's avatar Timothy Stack

Make the netlab client applet available to locals.

	* configure, configure.in: Add xmlrpcpipe.php3.

	* xmlrpc/emulabserver.py.in: Add missing virtual_tables.  Add
	getareas call to get the list of robot areas.  Add node.getlist
	and node.typeinfo methods for getting information about the nodes.
	Add a "nic" argument to node.available to get the count of
	wireless nodes.  Add "exclude" argument to
	experiment.virtual_topology so we don't have to download the
	massive route table, also delete the 'pid'/'eid' fields for the
	same reason.  Don't return string output of virtual_topology, it's
	huge.  Return some more info in experiment.getlist().

	* www/GNUmakefile.in: Add xmlrpcpipe.php3.

	* www/beginexp_form.php3, www/modifyexp.php3: Add links to the
	client gui.

	* www/netlab-client.jar: The client binary.
parent c81730eb
......@@ -2315,6 +2315,7 @@ outfiles="$outfiles Makeconf GNUmakefile \
utils/backupswitches utils/setbuildinfo utils/checkquota \
utils/spewconlog utils/webspewconlog utils/xlogin \
www/GNUmakefile www/defs.php3 www/dbdefs.php3 www/xmlrpc.php3 \
www/xmlrpcpipe.php3 \
www/swish.conf www/websearch www/garcia-telemetry/GNUmakefile \
vis/GNUmakefile vis/webvistopology vis/dbvistopology \
vis/prerender vis/prerender_all vis/render \
......
......@@ -753,6 +753,7 @@ outfiles="$outfiles Makeconf GNUmakefile \
utils/backupswitches utils/setbuildinfo utils/checkquota \
utils/spewconlog utils/webspewconlog utils/xlogin \
www/GNUmakefile www/defs.php3 www/dbdefs.php3 www/xmlrpc.php3 \
www/xmlrpcpipe.php3 \
www/swish.conf www/websearch www/garcia-telemetry/GNUmakefile \
vis/GNUmakefile vis/webvistopology vis/dbvistopology \
vis/prerender vis/prerender_all vis/render \
......
......@@ -28,7 +28,7 @@ SUBDIRS = garcia-telemetry
# is changed.
#
all: defs.php3 dbdefs.php3 swish.conf websearch htmlinstall xmlrpc.php3 \
all-subdirs
xmlrpcpipe.php3 all-subdirs
include $(TESTBED_SRCDIR)/GNUmakerules
......
......@@ -192,7 +192,19 @@ function SPITFORM($formfields, $errors)
}
else {
if (!isset($formfields[nsref]) && !isset($view['quiet'])) {
echo "<p><ul>
if (STUDLY()) {
echo "<p><ul>
<li><b>If you have an NS file:</b><br> You may want to
<b><a href='nscheck_form.php3'>syntax check it first</a></b>
<li><b>If you do not have an NS file:</b><br>
<b><a href='clientui.php3'>New GUI editor</a></b> - An enhanced Java applet for editing topologies.<br>
<b><a href='buildui/bui.php3'>The NetBuild GUI</a></b>
can be used to graphically create topologies.<font size=-2>
(<a href='$TBDOCBASE/faq.php3#netbuild'>Additional
information</a>)</font>.
</ul></p><br>";
} else {
echo "<p><ul>
<li><b>If you have an NS file:</b><br> You may want to
<b><a href='nscheck_form.php3'>syntax check it first</a></b>
<li><b>If you do not have an NS file:</b><br> You may want to
......@@ -204,6 +216,7 @@ function SPITFORM($formfields, $errors)
<a href='netlab/client.php3'><b>client</b></a> and graphically
create one from your desktop.
</ul></p><br>";
}
} else {
if (isset($view['plab_ns_message'])) {
echo "<p>To finish creating your slice, edit the following " .
......
<?php
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2002, 2004, 2005 University of Utah and the Flux Group.
# All rights reserved.
#
require("defs.php3");
#
# Define a stripped-down view of the web interface - less clutter
#
$view = array(
'hide_banner' => 1,
'hide_sidebar' => 1,
'hide_copyright' => 1
);
PAGEHEADER("NetlabClient", $view);
#
# Only known and logged in users can do this.
#
$uid = GETLOGIN();
LOGGEDINORDIE($uid);
$isadmin = ISADMIN($uid);
?>
<div id="clientblock" name="clientblock"></div>
<script language='JavaScript'>
<?php
if (isset($pid) && isset($eid) && TBValidExperiment($pid, $eid)) {
echo "var pid = '$pid';\n";
echo "var eid = '$eid';\n";
}
else {
echo "var pid = '';\n";
echo "var eid = '';\n";
}
?>
/* @return The innerHeight of the window. */
function ml_getInnerHeight() {
var retval;
if (self.innerHeight) {
// all except Explorer
retval = self.innerHeight;
}
else if (document.documentElement && document.documentElement.clientHeight) {
// Explorer 6 Strict Mode
retval = document.documentElement.clientHeight;
}
else if (document.body) {
// other Explorers
retval = document.body.clientHeight;
}
return retval;
}
function resize() {
var w_newWidth,w_newHeight;
var w_maxWidth=1600, w_maxHeight=1200;
if (navigator.appName.indexOf('Microsoft') != -1) {
w_newWidth=document.body.clientWidth;
w_newHeight=document.body.clientHeight;
} else {
var netscapeScrollWidth=15;
w_newWidth=window.innerWidth-netscapeScrollWidth;
w_newHeight=window.innerHeight-netscapeScrollWidth;
}
if (w_newWidth>w_maxWidth)
w_newWidth=w_maxWidth;
if (w_newHeight>w_maxHeight)
w_newHeight=w_maxHeight;
w_newWidth -= 75;
w_newHeight -= 140;
document.client.setOuterSize(w_newWidth, w_newHeight);
document.client.width = w_newWidth;
document.client.height = w_newHeight;
window.scroll(0,0);
}
var w_newWidth,w_newHeight;
var w_maxWidth=1600, w_maxHeight=1200;
if (navigator.appName.indexOf('Microsoft') != -1) {
w_newWidth=document.body.clientWidth;
} else {
var netscapeScrollWidth=15;
w_newWidth=window.innerWidth-netscapeScrollWidth;
}
w_newHeight = ml_getInnerHeight();
if (w_newWidth>w_maxWidth)
w_newWidth=w_maxWidth;
if (w_newHeight>w_maxHeight)
w_newHeight=w_maxHeight;
w_newWidth -= 75;
w_newHeight -= 140;
if (w_newHeight<650)
w_newHeight = 650;
app = document.createElement("applet");
app.setAttribute("width", w_newWidth);
app.setAttribute("height", w_newHeight);
app.setAttribute("archive", "netlab-client.jar");
app.setAttribute("code", "thinlet.AppletLauncher.class");
app.setAttribute("MAYSCRIPT", "MAYSCRIPT");
param = document.createElement("param");
param.setAttribute("name", "class");
param.setAttribute("value", "net.emulab.netlab.client.NetlabClient");
app.appendChild(param);
param = document.createElement("param");
param.setAttribute("name", "uid");
param.setAttribute("value", "<?php echo $uid?>");
app.appendChild(param);
param = document.createElement("param");
param.setAttribute("name", "auth");
param.setAttribute("value", "<?php echo $HTTP_COOKIE_VARS[$TBAUTHCOOKIE]?>");
app.appendChild(param);
if (pid != "" && eid != "") {
param = document.createElement("param");
param.setAttribute("name", "pid");
param.setAttribute("value", pid);
app.appendChild(param);
param = document.createElement("param");
param.setAttribute("name", "eid");
param.setAttribute("value", eid);
app.appendChild(param);
}
cb = document.getElementById("clientblock");
cb.appendChild(app);
window.onResize = resize;
window.onLoad = resize;
</script>
<?php if (isset($fallback)): ?>
<applet code='thinlet.AppletLauncher.class'
archive='netlab-client.jar'
width='800' height='600'
alt='You need java to run this applet'>
<param name="class" value="net.emulab.netlab.client.NetlabClient">
<param name="uid" value="<?php echo $uid?>">
<param name="auth" value="<?php echo $HTTP_COOKIE_VARS[$TBAUTHCOOKIE]?>">
<?php if (isset($pid)): ?>
<param name='pid' value='{$pid}'>
<?php endif; ?>
<?php if (isset($eid)): ?>
<param name='eid' value='{$eid}'>
<?php endif; ?>
</applet>
<?php endif; ?>
</body>
</html>
<?php
#
# Standard Testbed Footer
#
PAGEFOOTER();
?>
......@@ -117,6 +117,13 @@ if (! isset($go)) {
echo "<br>";
}
if (STUDLY()) {
echo "<font size='+1'>".
"<a href='clientui.php3?pid=$pid&eid=$eid'>GUI Editor</a>".
" - Edit the topology using a Java applet.</font>";
echo "<br>";
}
echo "<form action='modifyexp.php3' method='post'>";
echo "<textarea cols='100' rows='40' name='nsdata'>";
......
<?php
#
# EMULAB-COPYRIGHT
# Copyright (c) 2004, 2005 University of Utah and the Flux Group.
# All rights reserved.
#
# This is an included file. No headers or footers.
#
# Stuff to use the xmlrpc client/server. This is functionally equivalent
# to the perl stuff I wrote in xmlrpc/libxmlrpc.pm.in.
#
include("defs.php3");
$RPCSERVER = "@BOSSNODE@";
$RPCPORT = "@OUTERBOSS_XMLRPCPORT@";
$FSDIR_USERS = "@FSDIR_USERS@";
#
# Emulab XMLRPC defs.
#
# WARNING: If you change this stuff, also change defs in xmlrpc directory.
#
define("XMLRPC_RESPONSE_SUCCESS", 0);
define("XMLRPC_RESPONSE_BADARGS", 1);
define("XMLRPC_RESPONSE_ERROR", 2);
define("XMLRPC_RESPONSE_FORBIDDEN", 3);
define("XMLRPC_RESPONSE_BADVERSION", 4);
define("XMLRPC_RESPONSE_SERVERERROR", 5);
define("XMLRPC_RESPONSE_TOOBIG", 6);
define("XMLRPC_RESPONSE_REFUSED", 7);
define("XMLRPC_RESPONSE_TIMEDOUT", 8);
##
# The package version number
#
define("XMLRPC_PACKAGE_VERSION", 0.1);
$uid = GETLOGIN();
LOGGEDINORDIE($uid);
$isadmin = ISADMIN($uid);
#
# Invoke the ssl xmlrpc client in raw mode, passing it an encoded XMLRPC
# string, reading back an XMLRPC encoded response, which is converted to
# a PHP datatype with the ParseResponse() function above. In other words,
# we invoke a method on a remote xmlrpc server, and get back a response.
# Invoked as the current user, but the actual uid of the caller is contained
# in the ssl certificate we use, which for now is the elabinelab certificate
# of the creator (since that is the only place this code is being used).
#
$descriptorspec = array(0 => array("pipe", "r"),
1 => array("pipe", "w"));
$process = proc_open("$TBSUEXEC_PATH $uid nobody webxmlrpc -r ".
"-s $RPCSERVER -p $RPCPORT ".
"--cert $FSDIR_USERS/$uid/.ssl/emulab.pem",
$descriptorspec, $pipes);
if (! is_resource($process)) {
TBERROR("Could not invoke XMLRPC backend!\n".
"$uid nobody $method\n".
print_r($arghash, true), 1);
}
# $pipes now looks like this:
# 0 => writeable handle connected to child stdin
# 1 => readable handle connected to child stdout
$all_data = $HTTP_RAW_POST_DATA;
fwrite($pipes[0], $all_data);
fflush($pipes[0]);
fclose($pipes[0]);
$output = "";
#
# Now read back the results.
while(!feof($pipes[1])) {
$output .= fread($pipes[1], 1024); # XXX do this better
}
fclose($pipes[1]);
# It is important that you close any pipes before calling
# proc_close in order to avoid a deadlock.
$return_value = proc_close($process);
if ($return_value || $output == "") {
TBERROR("XMLRPC backend failure!\n".
"$uid returned $return_value\n".
"XML:\n" .
"$all_data\n\n" .
"Output:\n" .
"$output\n", 1);
}
header("content-length: " . strlen($output));
echo $output;
......@@ -109,6 +109,15 @@ virtual_tables = {
"eventlist" : { "rows" : None,
"tag" : "events",
"attrs" : [ "vname" ]},
"event_groups" : { "rows" : None,
"tag" : "event_groups",
"attrs" : [ "group_name", "agent-name" ]},
"virt_firewalls" : { "rows" : None,
"tag" : "virt_firewalls",
"attrs" : [ "fwname", "type", "style" ]},
"firewall_rules" : { "rows" : None,
"tag" : "firewall_rules",
"attrs" : [ "fwname", "ruleno", "rule" ]},
"virt_tiptunnels" : { "rows" : None,
"tag" : "tiptunnels",
"attrs" : [ "host", "vnode" ]},
......@@ -181,6 +190,14 @@ def CheckProjPermission(uid, pid):
return None
def GetProjects(uid):
res = DBQueryFatal("SELECT distinct pid FROM group_membership "
"WHERE uid=%s",
(uid,))
return [x[0] for x in res]
#
# Check user permission to access an experiment.
#
......@@ -371,6 +388,29 @@ class emulab:
value=result,
output=str(result))
def getareas(self, version, argdict):
if version != self.VERSION:
return EmulabResponse(RESPONSE_BADVERSION,
output="Client version mismatch!")
# Get the listing that is accessible to this user and
res = DBQueryFatal("SELECT distinct building FROM obstacles")
if len(res) == 0:
return EmulabResponse(RESPONSE_ERROR,
output="No areas?")
result = {}
for area in res:
result[area[0]] = {
"name" : area[0]
}
pass
return EmulabResponse(RESPONSE_SUCCESS,
value=result,
output=str(result))
def vision_config(self, version, argdict):
if version != self.VERSION:
return EmulabResponse(RESPONSE_BADVERSION,
......@@ -827,7 +867,7 @@ class osid:
return EmulabResponse(RESPONSE_SUCCESS,
value=result,
output=str(result))
output="")
def info(self, version, argdict):
# Check for valid arguments.
......@@ -951,9 +991,13 @@ class experiment:
# XXX Let the user specify the pid/gid
dbres = DBQueryFatal("SELECT e.pid,e.gid,e.eid,e.expt_name,e.state,"
"e.expt_head_uid "
"e.expt_head_uid,e.minimum_nodes,e.maximum_nodes,"
"count(r.node_id) as actual_nodes "
" FROM experiments AS e "
"WHERE e.expt_head_uid=%s",
"left join reserved as r on e.pid=r.pid and "
" e.eid=r.eid "
"WHERE e.expt_head_uid=%s "
"GROUP BY e.pid,e.eid",
(self.uid,))
# Build a dictionary of projects that refer to a dictionary of groups
......@@ -967,6 +1011,9 @@ class experiment:
desc = res[3]
state = res[4]
expt_head = res[5]
minimum_nodes = res[6]
maximum_nodes = res[7]
actual_nodes = res[8]
# ... make sure 'result' has the proper slots,
if not result.has_key(pid):
result[pid] = {
......@@ -990,11 +1037,14 @@ class experiment:
"description" : desc,
"state" : state,
"expt_head" : expt_head,
"minimum_nodes" : minimum_nodes,
"maximum_nodes" : maximum_nodes,
"actual_nodes" : actual_nodes,
}
pass
# ... append it to the group list.
result[pid][gid].append(expdata)
result[pid][gid].append(scrubdict(expdata))
pass
return EmulabResponse(RESPONSE_SUCCESS,
......@@ -2155,6 +2205,9 @@ class experiment:
if argdict.has_key("tables") and (tag not in argdict["tables"]):
continue
if argdict.has_key("exclude") and (tag in argdict["exclude"]):
continue
res = DBQuery("SELECT * FROM " + key + " " +
"WHERE pid=%s and eid=%s",
(argdict["proj"], argdict["exp"]), asDict=True);
......@@ -2165,7 +2218,10 @@ class experiment:
# Convert NULL to ""
#
for key2, val2 in row.items():
if val2 == None:
if key2 in ("pid", "eid"):
del row[key2]
pass
elif val2 == None:
row[key2] = ""
pass
elif isinstance(val2, datetime.datetime):
......@@ -2917,17 +2973,33 @@ class node:
pid_clause = " or p.pid='%s'" % (str(argdict["proj"]),)
pass
intf_join = ""
intf_clause = ""
if argdict.has_key("nic"):
nic = argdict["nic"]
if "wireless" in nic:
intf_join = (
"left join interfaces as i on a.node_id=i.node_id "
"left join interface_types as it on "
" i.interface_type=it.type ")
intf_clause = " and i.role='expt' and it.connector='Wireless'"
pass
pass
res = DBQueryFatal("SELECT count(a.node_id) FROM nodes AS a "
res = DBQueryFatal("SELECT distinct count(a.node_id) FROM nodes AS a "
"left join reserved as b on a.node_id=b.node_id "
"left join node_types as nt on a.type=nt.type "
"left join nodetypeXpid_permissions as p "
" on a.type=p.type "
+ intf_join +
"WHERE b.node_id is null and a.role='testnode' "
" and nt.class=%s and "
" (p.pid is null" + pid_clause + ") and "
" (a.eventstate='ISUP' or "
" a.eventstate='PXEWAIT')" + type_test,
" a.eventstate='PXEWAIT')"
+ type_test
+ intf_clause,
(argdict["class"],))
if len(res) == 0:
......@@ -2941,6 +3013,119 @@ class node:
value=result,
output=str(result))
def getlist(self, version, argdict):
if version != self.VERSION:
return EmulabResponse(RESPONSE_BADVERSION,
output="Client version mismatch!")
if argdict.has_key("class"):
if not re.match("^[-\w]*$", str(argdict["class"])):
return EmulabResponse(RESPONSE_BADARGS,
output="Improperly formed node class")
class_test = " and nt.class='"+str(argdict["class"])+"'"
pass
else:
class_test = " and nt.class!='pcplabphys'"
pass
type_test = ""
if argdict.has_key("type"):
if not re.match("^[-\w]*$", str(argdict["type"])):
return EmulabResponse(RESPONSE_BADARGS,
output="Improperly formed node type")
type_test = " and nt.type='%s'" % (str(argdict["type"]),)
pass
pid_clause = ""
if argdict.has_key("proj"):
permerror = CheckProjPermission(self.uid, argdict["proj"])
if permerror:
return permerror
pid_clause = " or p.pid='%s'" % (str(argdict["proj"]),)
pass
else:
pid_clause = (" or p.pid in ("
+ ",".join([("'" + x + "'")
for x in GetProjects(self.uid)])
+ ")")
pass
res = DBQueryFatal(
"SELECT a.node_id,a.type,b.node_id is null,"
" (a.eventstate='ISUP' or "
" a.eventstate='PXEWAIT' or "
" a.eventstate='POWEROFF') "
"FROM nodes AS a "
"left join reserved as b on a.node_id=b.node_id "
"left join node_types as nt on a.type=nt.type "
"left join nodetypeXpid_permissions as p on a.type=p.type "
"WHERE a.role='testnode' "
" "+ class_test +" and "
" (p.pid is null" + pid_clause + ") " + type_test)
if len(res) == 0:
result = {}
pass
else:
result = {}
# gotta enumerate the list of nodes of this type that are avail
for row in res:
result[row[0]] = {
"node_id" : row[0],
"type" : row[1],
"free" : (row[2] == 1 and row[3] == 1),
}
pass
pass
return EmulabResponse(RESPONSE_SUCCESS,
value=result,
output=str(result))
def typeinfo(self, version, argdict):
if version != self.VERSION:
return EmulabResponse(RESPONSE_BADVERSION,
output="Client version mismatch!")
if argdict.has_key("type"):
if not re.match("^[-\w]*$", str(argdict["type"])):
return EmulabResponse(RESPONSE_BADARGS,
output="Improperly formed node type")
type_test = " and type='%s'" % (str(argdict["type"]),)
pass
else:
type_test = ""
pass
res = DBQuery("SELECT distinct nt.* FROM node_types as nt "
"left join nodetypeXpid_permissions as p "
" on nt.type=p.type "
"left join group_membership as m on m.uid=%s "
"WHERE (p.pid is null or p.pid=m.pid) and "
" nt.isdynamic=0 and nt.class not in ("
" 'pcplabphys','switch','shark','power','misc')"
+ type_test,
(self.uid),
asDict=True)
if len(res) == 0:
result = {}
pass
else:
result = {}
for re in res:
result[re["type"]] = scrubdict(re, prunelist=["ismodelnet"])
pass
pass
return EmulabResponse(RESPONSE_SUCCESS,
value=result,
output=str(result))
#
# Get the console parameters.
#
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment