Commit ffbc29d7 authored by Leigh B. Stoller's avatar Leigh B. Stoller

Move tbresize to the attic.

parent 6f948cec
......@@ -38,7 +38,6 @@ my $TB = "@prefix@";
"portstats" => "$TB/bin/portstats",
"readycount" => "$TB/bin/readycount",
"eventsys_control" => "$TB/bin/eventsys_control",
"tbresize" => "$TB/bin/tbresize",
"batchexp" => "$TB/bin/batchexp",
"nscheck" => "$TB/bin/nscheck"
);
......
......@@ -16,14 +16,14 @@ include $(OBJDIR)/Makeconf
SUBDIRS = checkpass ns2ir
BIN_STUFF = power snmpit tbend tbprerun tbreport \
tbresize os_load startexp endexp batchexp swapexp \
os_load startexp endexp batchexp swapexp \
node_reboot nscheck node_update savelogs node_control \
portstats checkports eventsys_control os_select tbrestart \
tbswap
# Stuff that mere users get on plastic.
USERBINS = os_load node_reboot nscheck node_update savelogs \
node_control portstats batchexp eventsys_control tbresize
node_control portstats batchexp eventsys_control
SBIN_STUFF = resetvlans console_setup.proxy sched_reload named_setup \
batch_daemon exports_setup reload_daemon sched_reserve \
......
#!/usr/bin/perl -wT
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2002 University of Utah and the Flux Group.
# All rights reserved.
#
use English;
use Getopt::Std;
sub usage() {
print STDOUT <<EOF;
Usage:
tbresize [-d] [-q] -a -e pid,eid -n num -t type [-p prefix] [-v n1,n2,...]
tbresize [-d] [-q] -r -e pid,eid <node> [<node> ...]
tbresize -h
Use -h to show this usage message.
Use -d to enable extra debugging output.
Use -q to enable quick mode (does not reboot nodes)
Adding nodes:
Use -a to add nodes to an experiment.
Use -e pid,eid to specify the experiment to resize.
Use -n to specify the number of nodes to add.
Use -t to specify the type of the nodes to be added (pc, pc850, pc600, etc).
Use -p to specify a prefix for vnames (i.e. "node" => node0 .. nodeN).
Use -v to specify a list of vnames (must match number of nodes to add)
Removing nodes:
Use -r to remove nodes from an experiment.
With -r, specify a list of one or more nodes to be removed (i.e. pcXX).
EOF
exit(-1);
}
my $optlist = "hdqare:n:t:p:v:";
# Configure variables
my $TB = "@prefix@";
my $TESTMODE = @TESTMODE@;
my $TBOPS = "@TBOPSEMAIL@";
# Load the Testbed support stuff.
use lib "@prefix@/lib";
use libdb;
use libtestbed;
# Define some "constants" for the op type
sub NONE() { 0; }
sub ADD() { 1; }
sub REMOVE() { 2; }
my $exportssetup = "$TB/sbin/exports_setup";
my $namedsetup = "$TB/sbin/named_setup";
my $nodereboot = "$TB/bin/node_reboot";
my $snmpit = "$TB/bin/snmpit";
my $avail = "$TB/sbin/avail";
my $nalloc = "$TB/bin/nalloc";
my $nfree = "$TB/bin/nfree";
my $op = NONE;
my $noreboot = 0;
my $pid = "";
my $eid = "";
my $num = 0;
my $type = "";
my $prefix = "";
my @nodes = ();
my @vnames = ();
my %v2p = (); # vname to phys node_id
my %p2v = (); # phys node_id to vname
# un-taint path
$ENV{'PATH'} = '/bin:/usr/bin:/usr/local/bin';
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
$| = 1; #Turn off line buffering on output
sub debug {
if ($d) { print @_; }
}
# Parse command arguments. Once we return from getopts, all that should be
# left are the required arguments.
my %options = ();
if (!@ARGV) { usage(); }
if (! getopts($optlist, \%options)) { usage(); }
if (defined($options{"h"})) { usage(); }
if (defined($options{"d"})) { $d++; debug("Debugging output enabled.\n"); }
if (defined($options{"q"})) { $noreboot++; debug("Not rebooting nodes.\n"); }
if (defined($options{"a"})) {
if (defined($options{"r"})) {
warn("Only one of -a or -r should be given\n");
usage();
}
$op = ADD;
debug("ADDING nodes.\n");
}
if (defined($options{"r"})) { $op = REMOVE; debug("REMOVING nodes.\n"); }
if (defined($options{"n"})) { $num=untaint($options{"n"});
debug("n=$num\n"); }
if (defined($options{"t"})) { $type=untaint($options{"t"});
debug("type $type\n"); }
if (defined($options{"p"})) { $prefix=untaint($options{"p"});
debug("prefix=$prefix\n"); }
if (defined($options{"e"})) {
my $pideid = $options{"e"};
if ($pideid =~ /([-\w]*),([-\w]*)/) {
$pid=$1;
$eid=$2;
} else {
warn("Invalid argument to -e option: $pideid\n");
usage();
}
debug("Experiment = $pid/$eid\n");
}
if (defined($options{"v"})) {
my $vstr = $options{"v"};
my @vlist = split(",",$vstr);
debug("vlist = ",join(" ",@vlist),"\n");
if (@vlist+0 != $num) {
warn("Invalid list for -v: Must have $num vnames\n");
usage();
}
my @usednames = ();
debug("usednames = ",join(" ",@usednames),"\n");
my $q = DBQueryFatal("select vname from reserved ".
"where pid='$pid' and eid='$eid'");
debug("usednames = ",join(" ",@usednames),"\n");
while (@r=$q->fetchrow_array()) {
if ($r[0]) {
debug("used name is '$r[0]'\n");
push(@usednames, $r[0]);
}
debug("bigger usednames = ",join(" ",@usednames),"\n");
}
debug("usednames = ",join(" ",@usednames),"\n");
foreach $vname (@vlist) {
if ( grep(/^$vname$/,@vnames,@usednames) > 0 ) {
die("Vname $vname cannot be used twice.\n");
}
push(@vnames,untaint($vname));
}
debug("vnames = ",join(" ",@vnames),"\n");
}
# Untaint nodes.
foreach my $node ( @ARGV ) {
if ($node =~ /^([-\@\w]+)$/ && TBValidNodeName($1)) { $node = $1; }
else { die("*** Bad node name: $node\n"); }
if ( ! NodeidToExp($node,\$npid,\$neid) ||
$npid ne $pid || $neid ne $eid) {
die("*** Node $node is not in $pid/$eid!\n");
}
push(@nodes, $node);
}
if ($op==ADD) {
if ((! ($num=~ /^\d+$/)) || $num==0) {
die("*** Missing number of nodes to add.\n");
}
if ($prefix eq "") { $prefix = "node"; }
if ($type eq "") { die("*** Missing type of nodes to add.\n"); }
} elsif ($op==REMOVE) {
if ( (@nodes+0)==0 ) { die("*** No nodes given for removal.\n"); }
} else {
die("*** You must select an operation (add or remove).\n");
}
# Figure out who called us. Root and admin types can do whatever they
# want. Normal users can only change expts they can MODIFY (local_root)
if ($UID && !TBAdmin($UID) &&
!TBExptAccessCheck($UID,$pid,$eid,TB_EXPT_MODIFY)) {
die("*** $0:\n You do not have permission to resize $pid/$eid\n");
}
if (ExpState($pid,$eid) ne EXPTSTATE_ACTIVE) {
die("*** $0:\n Experiment $pid/$eid is not active.\n");
}
# By now we've got all the info and we've checked permissions, so
# go ahead and carry out the operation
if ($d) {
print "OP = ".($op==ADD?"ADD":"REMOVE")."\n";
print "EXPT = $pid/$eid\n";
if ($op==ADD) {
print "NUM = $num\n";
print "TYPE = $type\n";
print "PRFX = $prefix\n";
print "VNMS = ".join(" ",@vnames)."\n";
} else {
print "NODES= ".join(" ",@nodes)."\n";
}
}
if ($op == ADD) {
# To add:
# pick some nodes (for now randomly from free nodes of the type they want)
# nalloc them
# set up db with new state for the nodes (esp. change the lan)
# rerun snmpit (delete and readd the vlan from the new db state)
# 1. Find random nodes of the right type:
@nodes = ();
open(AVAIL,"/usr/testbed/sbin/avail type=$type rand |");
while (<AVAIL>) {
if (! /^\|/) {next};
if (/node_id/) {next;}
($node,$type) = /^\|([-a-zA-Z0-9]+)\s*\|(\w+)\s*\|(\w+)\s*\|$/;
push(@nodes,$node);
if (@nodes == $num) { last; }
}
close(AVAIL);
if (@nodes < $num) {
die("*** Cannot resize $pid/$eid:\n".
" Less than $num free nodes of type $type.\n");
} elsif (@nodes > $num) {
die("*** Aargh! Got too many nodes:\n".
" Wanted $num of type $type, got this:\n".
join(" ",@nodes)."\n");
} else { print "Found $num nodes: ".join(" ",@nodes)."\n" if $d; }
# 2. Reserve them, and set vnames
fatal("$nalloc $pid $eid ".join(" ",@nodes));
my $n = 0;
my @nlist = @nodes;
while (@nlist) {
my $vname = (shift @vnames) || ($prefix.$n);
my $node="";
if (! VnameToNodeid($pid,$eid,$vname,\$node)) {
$node = shift @nlist;
$v2p{$vname}=$node;
$p2v{$node}=$vname;
print "Reserving $node as $vname.\n";
DBQueryWarn("update reserved set vname='$vname' ".
"where node_id='$node'");
}
$n++;
}
# 3. Add new state to the db as needed:
# - add entries to virt_nodes
# - check if there's one vlan
# - if one: update virt_lans, vlans, IPs in virt_nodes and interfaces
# - otherwise, leave new ones unconnected
# 3a. Add virt_nodes entries
foreach $p (@nodes) {
print " virt_nodes: $p = $pid/$eid/$p2v{$p},$type\n" if $d;
DBQueryWarn("insert into virt_nodes ".
"(pid, eid, vname, type, ips, osname, cmd_line, rpms, ".
"deltas, startupcmd, tarfiles, fixed) values ".
"('$pid','$eid','$p2v{$p}','$type',".
"'','','','','','','','')");
}
# 3b. Check vlans
my $q = DBQueryWarn("select count(*) from vlans ".
"where eid='$eid' and pid='$pid'");
my @r = $q->fetchrow_array();
my $c = $r[0];
if ($c==1) {
print "Adding network connection information to database...\n";
# XXX Hack: always use eth1 since it isn't control anywhere
my $ifc = "eth1";
my $port= 1;
# We need to add entries for it in virt_lans
my $q = DBQueryWarn("select virtual from vlans ".
"where eid='$eid' and pid='$pid'");
my @r = $q->fetchrow_array();
my $vlink = $r[0];
foreach $p (@nodes) {
DBQueryWarn("insert into virt_lans ".
"(pid,eid,vname,delay,bandwidth,lossrate,".
"rdelay,rbandwidth,rlossrate,member) values ".
"('$pid','$eid','$vlink',0,100000,0,0,100000,0,".
"'$p2v{$p}:$port')");
}
# Then update vlans
my $newmemb = join(" ",map("$_:$ifc",@nodes));
DBQueryWarn("update vlans set members = ".
"ltrim(concat(members,' $newmemb')) ".
"where pid='$pid' and eid='$eid'");
# Now figure out what IPs to use
$q = DBQueryWarn("select ips from virt_nodes ".
"where eid='$eid' and pid='$pid' ".
"and ips!='' and ips is not null");
my %ips = ();
my $subnet = "";
while (@r = $q->fetchrow_array()) {
my ($port,$ip) = split(":",$r[0]);
print " Found IP '$ip'\n" if $d;
$ip =~ /^(\d+\.\d+\.\d+)\.(\d+)$/ ||
warn("Bad IP! '$ip' \n") && next;
if ($subnet eq "") { $subnet=$1; }
$ips{$2}=1;
}
print " Subnet is $subnet\n" if $d;
if ($subnet eq "") { $subnet="192.168.1"; } # default, just in case
# now throw them in the db
my $i=2;
foreach $p (@nodes) {
while (defined($ips{$i})) { $i++; }
if ($i>254) { die("Too many nodes in subnet!\n"); }
print " $p => $p2v{$p} gets IP $subnet.$i\n" if $d;
$ips{$i}=1;
DBQueryWarn("update virt_nodes set ips='$port:$subnet.$i' ".
"where pid='$pid' and eid='$eid' ".
"and vname='$p2v{$p}'");
DBQueryWarn("update interfaces set IP='$subnet.$i' where ".
"node_id='$p' and iface='$ifc'");
}
} # else do nothing - leave it unconnected
# 4. Run snmpit to update the vlans
updateVLANs();
# All done for adding
} elsif ($op == REMOVE) {
# To remove:
# tweak the db state (remove the nodes from the links, etc)
# rerun snmpit (delete and readd the vlan from the new db state)
# nfree them (they'll get reloaded after this)
# 1. Change the db state as needed:
# - Clean nodes out of vlans carefully
# - Delete any rows for the nodes from virt_*
print "Removing ",@nodes+0," nodes from $pid/$eid:\n".
join(" ",@nodes)."\n";
foreach $p (@nodes) {
print " Clearing node $p\n" if $d;
# 1a. Get the nodes out of vlans
my $q = DBQueryWarn("select id, members from vlans ".
"where eid='$eid' and pid='$pid' ".
"and members like '%$p:%'");
while (my @r = $q->fetchrow_array()) {
my $id = $r[0];
print " VLAN $id: \t$r[1]\n" if $d;
my (@ports)= split(" ",$r[1]);
my @newports=();
foreach (@ports) {
if (/$p:/) { next; }
push(@newports,$_);
}
print " New vlan: \t".join(" ",@newports)."\n" if $d;
DBQueryWarn("update vlans set members='".join(" ",@newports).
"' where id='$id'");
}
$q = DBQueryWarn("select vname from reserved where node_id='$p'");
@r = $q->fetchrow_array();
my $vname=$r[0];
print " Clearing virt_* for vname '$vname'\n" if $d;
# 1b. Delete any rows for the nodes from virt_*
my @virt_tables = ("virt_agents", "virt_lans", "virt_nodes",
"virt_routes", "virt_trafgens");
foreach $t (@virt_tables) {
if ($t eq "virt_lans") {
DBQueryWarn("delete from $t where pid='$pid' and eid='$eid' ".
"and member like '$vname:%'");
} else {
DBQueryWarn("delete from $t where pid='$pid' and eid='$eid' ".
"and vname='$vname'");
}
}
}
# 2. Run snmpit to update the vlans
updateVLANs();
# 3. Free up the nodes
my $nlist = join(" ",@nodes);
if (length($nlist)==0) { warn("*** Found no nodes to free!\n"); }
else { run("$nfree $pid $eid $nlist"); }
# All done for removing
} else { die("Aaah! I'm extremely confused"); }
# Now reboot the nodes in the expt so they all pick up new values
if (!$noreboot) {
run("$nodereboot ".($d?"-d ":"")."-e $pid,$eid");
} else {
print "Not rebooting nodes in quick mode.\n";
}
# Before we're done we need to rerun a few things:
run("$exportssetup");
run("$namedsetup");
exit();
sub updateVLANs() {
# Here we just need to delete the vlan for the expt and
# recreate it from the db.
print "Updating VLANs...\n";
run("$snmpit -r $pid $eid");
run("$snmpit -t $pid $eid");
}
sub fatal($) {
my $cmd = shift;
if (run($cmd)) {
die("*** tbresize aborted!\n");
}
}
sub run($) {
my $cmd = shift;
if ($d) { print "Running '$cmd'\n"; }
my $rv = system($cmd);
if ($rv) {
warn("*** WARNING: $cmd failed!\n");
}
return $rv;
}
sub untaint($) {
my $str = shift;
if ($str =~ /^([-\@\w_]+)$/) { return $1; }
else { die("*** Invalid value: $str\n"); }
}
......@@ -38,7 +38,6 @@ my $TB = "@prefix@";
"portstats" => "$TB/bin/portstats",
"readycount" => "$TB/bin/readycount",
"eventsys_control" => "$TB/bin/eventsys_control",
"tbresize" => "$TB/bin/tbresize",
"batchexp" => "$TB/bin/batchexp",
"nscheck" => "$TB/bin/nscheck"
);
......
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