nodecontrol_list.php3 18 KB
Newer Older
1
<?php
Leigh Stoller's avatar
Leigh Stoller committed
2
#
3
# Copyright (c) 2000-2017 University of Utah and the Flux Group.
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
# 
# {{{EMULAB-LICENSE
# 
# This file is part of the Emulab network testbed software.
# 
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
# 
# This file is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public
# License for more details.
# 
# You should have received a copy of the GNU Affero General Public License
# along with this file.  If not, see <http://www.gnu.org/licenses/>.
# 
# }}}
Leigh Stoller's avatar
Leigh Stoller committed
23
#
24
include("defs.php3");
25
include_once("node_defs.php");
26

27 28 29 30 31 32
#
# This page is used for both admin node control, and for mere user
# information purposes. Be careful about what you do outside of
# $isadmin tests.
# 

33 34 35
#
# Only known and logged in users can do this.
#
36 37 38
$this_user = CheckLoginOrDie();
$uid       = $this_user->uid();
$isadmin   = ISADMIN();
39 40

#
41
# Verify page arguments.
42 43 44
#
$optargs = OptionalPageArguments("target_user",	PAGEARG_USER,
				 "showtype",    PAGEARG_STRING,
45
				 "typefilter",  PAGEARG_STRING,
46 47 48 49
				 "bypid",       PAGEARG_STRING);

if (isset($target_user)) {
    if (! $target_user->AccessCheck($this_user, $TB_USERINFO_READINFO)) {
50 51 52 53
	USERERROR("You do not have permission to do this!", 1);
    }
    $target_uid  = $target_user->uid();
    $target_idx  = $target_user->uid_idx();
54 55
}
else {
56 57 58
    $target_uid  = $uid;
    $target_idx  = $this_user->uid_idx();
    $target_user = $this_user;
59
}
60

61 62 63 64 65
#
# Standard Testbed Header
#
PAGEHEADER("Node Control Center");

66
echo "<b>Tabular views: <a href='nodecontrol_list.php3?showtype=summary'>summary</a>,
67
               <a href='nodecontrol_list.php3?showtype=pcs'>pcs</a>,
68
               <a href='nodecontrol_list.php3?showtype=wireless'>
69
                                                        wireless</a>,";
70
if ($TBMAINSITE && !$ISALTDOMAIN) {
71
    echo "     <a href='nodecontrol_list.php3?showtype=widearea&typefilter=pcpg,pcpg-i2'>protogeni</a>,";
72 73
}
echo "         <a href='nodecontrol_list.php3?showtype=widearea'>widearea</a>";
74 75

if ($isadmin) {
76 77
    echo    ", <a href='nodeutilization.php'>utilization</a>,
               <a href='nodecontrol_list.php3?showtype=virtnodes'>virtual</a>,
78 79 80
               <a href='nodecontrol_list.php3?showtype=physical'>physical</a>,
               <a href='nodecontrol_list.php3?showtype=all'>all</a>";
}
81
echo ".</b><br>\n";
82

83 84 85
echo "<b>Map views: <a href='floormap.php3'>wireless</a>";
echo ".</b><br>\n";

86
if (!isset($showtype)) {
87
    $showtype='summary';
88 89
}

Chad Barb's avatar
Chad Barb committed
90 91 92
$additionalVariables = "";
$additionalLeftJoin  = "";

93 94 95 96 97 98 99
if (! strcmp($showtype, "summary")) {
    # Separate query below.
    $role   = "";
    $clause = "";
    $view   = "Free Node Summary";
}
elseif (! strcmp($showtype, "all")) {
100 101 102
    $role   = "(role='testnode' or role='virtnode')";
    $clause = "";
    $view   = "All";
103 104
}
elseif (! strcmp($showtype, "pcs")) {
105 106 107
    $role   = "(role='testnode')";
    $clause = "and (nt.class='pc')";
    $view   = "PCs";
108
}
109 110 111 112
elseif (! strcmp($showtype, "sharks")) {
    $role   = "(role='testnode')";
    $clause = "and (nt.class='shark')";
    $view   = "Sharks";
113 114
}
elseif (! strcmp($showtype, "virtnodes")) {
115 116 117 118
    $role   = "(role='virtnode')";
    $clause = "";
    $view   = "Virtual Nodes";
}
119 120 121 122 123
elseif (! strcmp($showtype, "physical")) {
    $role   = "";
    $clause = "(nt.isvirtnode=0)";
    $view   = "Physical Nodes";
}
124 125 126
elseif (! strcmp($showtype, "widearea")) {
    $role   = "(role='testnode')";
    $clause = "and (nt.isremotenode=1)";
Chad Barb's avatar
Chad Barb committed
127 128 129 130 131 132 133

    $additionalVariables = ",".
			   "wani.machine_type,".
			   "REPLACE(CONCAT_WS(', ',".
			   "wani.city,wani.state,wani.country,wani.zip), ".
		 	   "'USA, ','')".
			   "AS location, ".
134
	 		   "wani.connect_type, ".
135
			   "wani.hostname, " .
136 137 138
                           "wani.site, ".
	 		   "wani.latitude, ".
			   "wani.longitude";
Chad Barb's avatar
Chad Barb committed
139 140 141
    $additionalLeftJoin = "LEFT JOIN widearea_nodeinfo AS wani ".
			  "ON n.node_id=wani.node_id";

142
    $view   = "Widearea";
143
}
144 145 146 147 148 149 150 151 152
elseif (! strcmp($showtype, "wireless")) {
    $role   = "(role='testnode')";
    $clause = "and (loc.node_id is not null)";

    $additionalLeftJoin = "LEFT JOIN location_info AS loc ".
			  "ON n.node_id=loc.node_id";

    $view   = "Wireless";
}
153 154 155 156 157
elseif (preg_match("/^[-\w]+$/", $showtype)) {
    $role   = "(role='testnode')";
    $clause = "and (nt.type='$showtype')";
    $view   = "only <a href=shownodetype.php3?node_type=$showtype>$showtype</a>";
}
158
else {
159 160 161
    $role   = "(role='testnode')";
    $clause = "and (nt.class='pc')";
    $view   = "PCs";
162
}
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179

# If adding an additional type filter list, do that...
if (isset($typefilter)) {
    $types = explode(",",$typefilter);
    $typeclause = "and nt.type in (";
    foreach ($types as $t) {
	# Sanitize.
	if (!preg_match("/^[-\w]+$/", $t)) {
	    PAGEARGERROR("Invalid characters in typefilter argument '$t'.");
	}
	$typeclause .= "'$t',";
    }
    $typeclause = rtrim($typeclause,",");
    $typeclause .= ")";
    $clause .= " $typeclause";
}

180 181 182 183 184
# If admin or widearea, show the vname too. 
$showvnames = 0;
if ($isadmin || !strcmp($showtype, "widearea")) {
    $showvnames = 1;
}
185

186 187 188 189 190 191 192 193
#
# Summary info very different.
# 
if (! strcmp($showtype, "summary")) {
    # Get permissions table so as not to show nodes the user is not allowed
    # to see.
    $perms = array();
    
194
    if (!$isadmin || isset($bypid)) {
195 196 197 198 199 200
	$query_result =
	    DBQueryFatal("select type from nodetypeXpid_permissions");

	while ($row = mysql_fetch_array($query_result)) {
	    $perms{$row[0]} = 0;
	}
201 202 203 204 205 206

	$pidclause = "";
	if (isset($bypid)) {
	    if ($bypid == "" || !TBvalid_pid($bypid)) {
		PAGEARGERROR("Invalid characters in 'bypid' argument!");
	    }
207
	    if (! ($target_project = Project::Lookup($bypid))) {
208 209
		PAGEARGERROR("No such project '$bypid'!");
	    }
210 211
	    if (!$target_project->AccessCheck($this_user,
					      $TB_PROJECT_READINFO)){
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
		USERERROR("You are not a member of project '$bypid!", 1);
	    }
	    $pidclause = "and g.pid='$bypid'";
	}
	if ($isadmin) {
	    $query_result =
		DBQueryFatal("select distinct type ".
			     "  from nodetypeXpid_permissions ".
			     "where pid='$bypid'");
	}
	else {
	    $query_result =
		DBQueryFatal("select distinct type from group_membership as g ".
			     "left join nodetypeXpid_permissions as p ".
			     "     on g.pid=p.pid ".
227
			     "where uid_idx='$target_idx' $pidclause");
228
	}
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
	
	while ($row = mysql_fetch_array($query_result)) {
	    $perms{$row[0]} = 1;
	}
    }
    
    # Get totals by type.
    $query_result =
	DBQueryFatal("select n.type,count(*) from nodes as n ".
		     "left join node_types as nt on n.type=nt.type ".
		     "where (role='testnode') and ".
		     "      (nt.class!='shark' and nt.class!='pcRemote' ".
		     "      and nt.class!='pcplabphys') ".
		     "group BY n.type");

244 245
    $alltotal  = 0;
    $allfree   = 0;
Timothy Stack's avatar
Timothy Stack committed
246
    $allunknown = 0;
247
    $totals    = array();
Timothy Stack's avatar
Timothy Stack committed
248 249
    $freecounts = array();
    $unknowncounts = array();
250 251 252 253 254 255 256

    while ($row = mysql_fetch_array($query_result)) {
	$type  = $row[0];
	$count = $row[1];

	$totals[$type]    = $count;
	$freecounts[$type] = 0;
Timothy Stack's avatar
Timothy Stack committed
257
	$unknowncounts[$type] = 0;
258 259
    }

260 261
    # Get free totals by type.  Note we also check that the physical node
    # is free, see note on non-summary query for why.
262
    $query_result =
Timothy Stack's avatar
Timothy Stack committed
263
	DBQueryFatal("select n.eventstate,n.type,count(*) from nodes as n ".
264
		     "left join nodes as np on np.node_id=n.phys_nodeid ".
265 266
		     "left join node_types as nt on n.type=nt.type ".
		     "left join reserved as r on r.node_id=n.node_id ".
267 268
		     "left join reserved as rp on rp.node_id=n.phys_nodeid ".
		     "where (n.role='testnode') and ".
269 270
		     "      (nt.class!='shark' and nt.class!='pcRemote' ".
		     "      and nt.class!='pcplabphys') ".
271 272
		     "      and r.pid is null and rp.pid is null ".
		     "      and n.reserved_pid is null and np.reserved_pid is null ".
Timothy Stack's avatar
Timothy Stack committed
273
		     "group BY n.eventstate,n.type");
274 275

    while ($row = mysql_fetch_array($query_result)) {
Timothy Stack's avatar
Timothy Stack committed
276 277 278 279 280 281 282 283 284 285 286 287
	$type  = $row[1];
	$count = $row[2];
        # XXX Yeah, I'm a doofus and can't figure out how to do this in SQL.
	if (($row[0] == TBDB_NODESTATE_ISUP) ||
	    ($row[0] == TBDB_NODESTATE_PXEWAIT) ||
	    ($row[0] == TBDB_NODESTATE_ALWAYSUP) ||
	    ($row[0] == TBDB_NODESTATE_POWEROFF)) {
	    $freecounts[$type] += $count;
	}
	else {
	    $unknowncounts[$type] += $count;
	}
288 289
    }

290
    $projlist = $target_user->ProjectAccessList($TB_PROJECT_CREATEEXPT);
291 292 293 294 295 296 297 298 299 300 301 302
    if (count($projlist) > 1) {
	echo "<b>By Project Permission: ";
	while (list($project) = each($projlist)) {
	    echo "<a href='nodecontrol_list.php3?".
		"showtype=summary&bypid=$project'>$project</a>,\n";
	}
	echo "<a href='nodecontrol_list.php3?showtype=summary'>".
	    "combined membership</a>.\n";
	echo "</b><br>\n";
    }

    echo "<br><center>
303
          <b>Free Node Summary</b>
304 305 306 307 308
          <br>\n";
    if (isset($bypid)) {
	echo "($bypid)<br><br>\n";
    }
    echo "<table>
309 310 311 312 313 314 315 316 317 318 319 320
          <tr>
             <th>Type</th>
             <th align=center>Free<br>Nodes</th>
             <th align=center>Total<br>Nodes</th>
          </tr>\n";

    foreach($totals as $key => $value) {
	$freecount = $freecounts[$key];

	# Check perm entry.
	if (isset($perms[$key]) && !$perms[$key])
	    continue;
321 322

	$allfree   += $freecount;
Timothy Stack's avatar
Timothy Stack committed
323
	$allunknown += $unknowncounts[$key];
324
	$alltotal  += $value;
Timothy Stack's avatar
Timothy Stack committed
325 326 327 328 329

	if ($unknowncounts[$key])
	    $ast = "*";
	else
	    $ast = "";
330
	
331 332 333 334 335 336
	echo "<tr>\n";
	if ($isadmin)
	    echo "<td><a href=editnodetype.php3?node_type=$key>\n";
	else
	    echo "<td><a href=shownodetype.php3?node_type=$key>\n";
	echo "           $key</a></td>
Timothy Stack's avatar
Timothy Stack committed
337
              <td align=center>${freecount}${ast}</td>
338 339 340
              <td align=center>$value</td>
              </tr>\n";
    }
341 342 343 344 345 346
    echo "<tr></tr>\n";
    echo "<tr>
            <td><b>Totals</b></td>
              <td align=center>$allfree</td>
              <td align=center>$alltotal</td>
              </tr>\n";
347
    echo "</table>\n";
348 349 350

    echo "<center><a href=shownodetype_list.php>Node Type List</a></center>";

Timothy Stack's avatar
Timothy Stack committed
351 352 353 354
    if ($allunknown > 0) {
	    echo "<br><font size=-1><b>*</b> - Some nodes ($allunknown) are ".
		    "free, but currently in an unallocatable state.</font>";
    }
355 356 357 358
    PAGEFOOTER();
    exit();
}

359 360
#
# Suck out info for all the nodes.
361 362 363 364 365 366
#
# If a node is free we check to make sure that that the physical node
# is also.  This is based on the assumption that if a physical node is
# not available, neither is the node, such as the case with netpga2.
# This may not be true for virtual nodes, such as PlanetLab slices,
# but virtual nodes are allocated on demand, and thus are never free.
367
# 
Leigh Stoller's avatar
Leigh Stoller committed
368
$query_result =
369
    DBQueryFatal("select distinct n.node_id,n.phys_nodeid,n.type,ns.status, ".
370
		 "   n.def_boot_osid,n.reserved_pid, ".
371 372 373
		 "   if(r.pid is not null,r.pid,rp.pid) as pid, ".
	         "   if(r.pid is not null,r.eid,rp.eid) as eid, ".
		 "   nt.class, ".
374 375
	 	 "   if(r.pid is not null,r.vname,rp.vname) as vname, ".
                 "   n.priority ".
Chad Barb's avatar
Chad Barb committed
376 377
		 "$additionalVariables ".
		 "from nodes as n ".
378
		 "left join node_types as nt on n.type=nt.type ".
379
		 "left join node_status as ns on n.node_id=ns.node_id ".
380
		 "left join reserved as r on n.node_id=r.node_id ".
381
		 "left join reserved as rp on n.phys_nodeid=rp.node_id ".
Chad Barb's avatar
Chad Barb committed
382
		 "$additionalLeftJoin ".
383
		 "where $role $clause ".
384
		 "ORDER BY n.priority");
385 386 387 388

if (mysql_num_rows($query_result) == 0) {
    echo "<center>Oops, no nodes to show you!</center>";
    PAGEFOOTER();
389
    exit();
390
}
391

392
#
393
# First count up free nodes as well as status counts.
394
#
395 396 397 398 399
$num_free = 0;
$num_up   = 0;
$num_pd   = 0;
$num_down = 0;
$num_unk  = 0;
400
$freetypes= array();
401

402
while ($row = mysql_fetch_array($query_result)) {
403 404 405
    $pid                = $row["pid"];
    $status             = $row["status"];
    $type               = $row["type"];
406

407 408 409
    if (! isset($freetypes[$type])) {
	$freetypes[$type] = 0;
    }
410 411 412
    if (!$pid) {
	$num_free++;
	$freetypes[$type]++;
413
	continue;
414
    }
415 416 417 418 419 420 421 422 423 424 425 426 427 428
    switch ($status) {
    case "up":
	$num_up++;
	break;
    case "possibly down":
    case "unpingable":
	$num_pd++;
	break;
    case "down":
	$num_down++;
	break;
    default:
	$num_unk++;
	break;
429 430
    }
}
431
$num_total = ($num_free + $num_up + $num_down + $num_pd + $num_unk);
432 433
mysql_data_seek($query_result, 0);

434
if (! strcmp($showtype, "widearea")) {
435
    echo "<a href='$WIKIDOCURL/widearea'>
436 437 438 439
             Widearea Usage Notes</a>\n";
}

echo "<br><center><b>
440
       View: $view\n";
441 442 443

if (! strcmp($showtype, "widearea")) {
    echo "<br>
444
          <a href=widearea_nodeinfo.php3>(Widearea Link Metrics)</a><br>
Leigh Stoller's avatar
Leigh Stoller committed
445
          <a href=plabmetrics.php3>(PlanetLab Node Metrics)</a>\n";
446 447 448
}

echo "</b></center><br>\n";
449

450 451 452
SUBPAGESTART();

echo "<table>
453 454 455
       <tr><td align=right>
           <img src='/autostatus-icons/greenball.gif' alt=up>
           <b>Up</b></td>
456 457
           <td align=left>$num_up</td>
       </tr>
458 459 460
       <tr><td align=right nowrap>
           <img src='/autostatus-icons/yellowball.gif' alt='possibly down'>
           <b>Possibly Down</b></td>
461 462
           <td align=left>$num_pd</td>
       </tr>
463 464 465
       <tr><td align=right>
           <img src='/autostatus-icons/blueball.gif' alt=unknown>
           <b>Unknown</b></td>
466 467
           <td align=left>$num_unk</td>
       </tr>
468 469 470
       <tr><td align=right>
           <img src='/autostatus-icons/redball.gif' alt=down>
           <b>Down</b></td>
471 472
           <td align=left>$num_down</td>
       </tr>
473 474 475
       <tr><td align=right>
           <img src='/autostatus-icons/whiteball.gif' alt=free>
           <b>Free</b></td>
476 477
           <td align=left>$num_free</td>
       </tr>
478 479 480
       <tr><td align=right><b>Total</b></td>
           <td align=left>$num_total</td>
       </tr>
481 482 483 484 485
       <tr><td colspan=2 nowrap align=center>
               <b>Free Subtotals</b></td></tr>\n";

foreach($freetypes as $key => $value) {
    echo "<tr>
486
           <td align=right><a href=shownodetype.php3?node_type=$key>
487
                           $key</a></td>
488 489 490 491
           <td align=left>$value</td>
          </tr>\n";
}
echo "</table>\n";
492 493
SUBMENUEND_2B();

494
echo "<table border=2 cellpadding=2 cellspacing=2 id='nodelist'>\n";
495

496
echo "<thead class='sort'>";
497
echo "<tr>
498 499 500 501 502 503 504
          <th align=center>ID</th>\n";

if ($showvnames) {
    echo "<th align=center>Name</th>\n";
}

echo "    <th align=center>Type (Class)</th>
505
          <th align=center class='sorttable_nosort'>Up?</th>\n";
506 507

if ($isadmin) {
Chad Barb's avatar
Chad Barb committed
508 509 510
    echo "<th align=center>PID</th>
          <th align=center>EID</th>
          <th align=center>Default<br>OSID</th>\n";
511 512 513
    if (strcmp($showtype, "widearea")) {
	echo "<th align=center>Reserved<br>PID</th>\n";
    }
514
}
515 516
elseif (strcmp($showtype, "widearea")) {
    # Widearea nodes are always "free"
Chad Barb's avatar
Chad Barb committed
517
    echo "<th align=center>Free?</th>\n";
Chad Barb's avatar
Chad Barb committed
518 519 520
}

if (!strcmp($showtype, "widearea")) {
521
    echo "<th align=center>Site</th>
Chad Barb's avatar
Chad Barb committed
522
	  <th align=center>Connection</th>
523 524 525
	  <th align=center>Location</th>
	  <th align=center>Latitude</th>
	  <th align=center>Longitude</th>";
Chad Barb's avatar
Chad Barb committed
526 527
}
    
528
echo "</tr></thead>\n";
529

530
while ($row = mysql_fetch_array($query_result)) {
531 532 533
    $node_id            = $row["node_id"]; 
    $phys_nodeid        = $row["phys_nodeid"]; 
    $type               = $row["type"];
534
    $class              = $row["class"];
535 536 537 538 539
    $def_boot_osid      = $row["def_boot_osid"];
    $pid                = $row["pid"];
    $eid                = $row["eid"];
    $vname              = $row["vname"];
    $status             = $row["status"];
540
    $reserved_pid	= $row["reserved_pid"];
541

Chad Barb's avatar
Chad Barb committed
542
    if (!strcmp($showtype, "widearea")) {	
543 544 545 546 547
	$site         = $row["site"];
	$machine_type = $row["machine_type"];
	$location     = $row["location"];
	$connect_type = $row["connect_type"];
	$vname        = $row["hostname"];
548 549
	$latitude     = $row["latitude"];
	$longitude    = $row["longitude"];
Chad Barb's avatar
Chad Barb committed
550 551
    } 

552
    echo "<tr>";
553

554
    # Admins get a link to expand the node.
555 556
    if ($isadmin ||
	(OPSGUY() && (!$pid || $pid == $TBOPSPID))) {
557 558 559 560
	echo "<td><A href='shownode.php3?node_id=$node_id'>$node_id</a> " .
	    (!strcmp($node_id, $phys_nodeid) ? "" :
	     "(<A href='shownode.php3?node_id=$phys_nodeid'>$phys_nodeid</a>)")
	    . "</td>\n";
561 562
    }
    else {
563 564 565
	echo "<td>$node_id " .
  	      (!strcmp($node_id, $phys_nodeid) ? "" : "($phys_nodeid)") .
	      "</td>\n";
566
    }
567 568 569 570 571 572 573

    if ($showvnames) {
	if ($vname)
	    echo "<td>$vname</td>\n";
	else
	    echo "<td>--</td>\n";
    }
574
    
575 576
    echo "   <td>$type ($class)</td>\n";

577 578 579 580
    if (!$pid)
	echo "<td align=center>
                  <img src='/autostatus-icons/whiteball.gif' alt=free></td>\n";
    elseif (!$status)
581 582 583
	echo "<td align=center>
                  <img src='/autostatus-icons/blueball.gif' alt=unk></td>\n";
    elseif ($status == "up")
584 585
	echo "<td align=center>
                  <img src='/autostatus-icons/greenball.gif' alt=up></td>\n";
586
    elseif ($status == "down")
587 588
	echo "<td align=center>
                  <img src='/autostatus-icons/redball.gif' alt=down></td>\n";
589 590 591
    else
	echo "<td align=center>
                  <img src='/autostatus-icons/yellowball.gif' alt=unk></td>\n";
592 593 594 595

    # Admins get pid/eid/vname, but mere users yes/no.
    if ($isadmin) {
	if ($pid) {
596 597
	    echo "<td><a href=showproject.php3?pid=$pid>$pid</a></td>
                  <td><a href=showexp.php3?pid=$pid&eid=$eid>$eid</a></td>\n";
598 599 600 601 602
	}
	else {
	    echo "<td>--</td>
   	          <td>--</td>\n";
	}
603 604 605
	if ($def_boot_osid &&
	    ($osinfo = OSinfo::Lookup($def_boot_osid))) {
	    $osname = $osinfo->osname();
606
	    echo "<td>$osname</td>\n";
607
	}
608 609
	else
	    echo "<td>&nbsp</td>\n";
610 611 612 613 614 615
	if (strcmp($showtype, "widearea")) {
	    if ($reserved_pid)
		echo "<td>$reserved_pid</td>\n";
	    else
		echo "<td>&nbsp</td>\n";
	}
616
    }
617
    elseif (strcmp($showtype, "widearea")) {
618
	if ($pid)
619
	    echo "<td>--</td>\n";
620 621 622
	else
	    echo "<td>Yes</td>\n";
    }
Chad Barb's avatar
Chad Barb committed
623 624

    if (!strcmp($showtype, "widearea")) {	
625
	echo "<td>$site</td>
Chad Barb's avatar
Chad Barb committed
626
	      <td>$connect_type</td>
627 628 629
	      <td><font size='-1'>$location</font></td>
	      <td><font size='-1'>$latitude</font></td>
	      <td><font size='-1'>$longitude</font></td>\n";
Chad Barb's avatar
Chad Barb committed
630
    }
631
    
632
    echo "</tr>\n";
633 634 635
}

echo "</table>\n";
636 637 638
echo "<script type='text/javascript' language='javascript'>
         sorttable.makeSortable(getObjbyName('nodelist'));
      </script>\n";
639
SUBPAGEEND();
640 641 642 643 644

#
# Standard Testbed Footer
# 
PAGEFOOTER();
645 646 647
?>