Commit 79387881 authored by Kirk Webb's avatar Kirk Webb

Support for reloading garcias.

Currently this is a total hack; we simply rsync the stargate as it is freed
from the experiment.  However, until we unravel os_load dependancies between
nodes and subnodes (motes and stargates in this case), doing this through
the appropriate setup channels won't work.

The tbrsync script borrows much of its infrastructure from Rob's tbuisp
script.
parent ce76dd93
......@@ -2133,6 +2133,7 @@ outfiles="$outfiles Makeconf GNUmakefile \
tbsetup/ipassign/GNUmakefile tbsetup/ipassign/src/GNUmakefile \
tbsetup/ipassign/ipassign_wrapper tbsetup/assign_prepass \
tbsetup/panic tbsetup/webpanic \
tbsetup/tbrsync \
tip/GNUmakefile \
tmcd/GNUmakefile tmcd/tmcd.restart \
tmcd/common/GNUmakefile tmcd/common/config/GNUmakefile \
......
......@@ -716,6 +716,7 @@ outfiles="$outfiles Makeconf GNUmakefile \
tbsetup/ipassign/GNUmakefile tbsetup/ipassign/src/GNUmakefile \
tbsetup/ipassign/ipassign_wrapper tbsetup/assign_prepass \
tbsetup/panic tbsetup/webpanic \
tbsetup/tbrsync \
tip/GNUmakefile \
tmcd/GNUmakefile tmcd/tmcd.restart \
tmcd/common/GNUmakefile tmcd/common/config/GNUmakefile \
......
......@@ -37,6 +37,8 @@ use Node;
my $consetup = "$TB/libexec/console_setup";
my $osselect = "$TB/bin/os_select";
my $tbrsync = "$TB/bin/tbrsync";
my $nodereboot = "$TB/bin/node_reboot";
my $reloadpid = "emulab-ops";
my $pendingeid = "reloadpending";
my $reloadeid = "reloading";
......@@ -366,6 +368,17 @@ foreach my $n (@freed_nodes) {
next;
}
# XXX stargate reload hack - totally gross..
if (TBNodeType($n) eq "garcia") {
# path to directory tree "image" hardcoded for now since
# users have no choice over OS selection when reloading
# isn't performed during swapin.
system("$tbrsync upload /usr/testbed/images/garcia $n") == 0 ||
print STDERR "Failed to rsync garcia node: $n\n";
system("$nodereboot $n") == 0 ||
print STDERR "Failed to reboot garcia after rsync: $n\n";
}
# No reloads or reservation changes, so really free the node
#
# This little sillyness is for disk reloading. Remember the last
......
......@@ -19,7 +19,7 @@ BIN_STUFF = power snmpit tbend tbprerun tbreport \
os_load endexp batchexp swapexp \
node_reboot nscheck node_update savelogs node_control \
portstats checkports eventsys_control os_select tbrestart \
tbswap nseswap tarfiles_setup node_history
tbswap nseswap tarfiles_setup node_history tbrsync
SBIN_STUFF = resetvlans console_setup.proxy sched_reload named_setup \
batch_daemon exports_setup reload_daemon sched_reserve \
......@@ -167,6 +167,8 @@ post-install:
chmod u+s $(INSTALL_BINDIR)/savelogs
chown root $(INSTALL_SBINDIR)/elabinelab
chmod u+s $(INSTALL_SBINDIR)/elabinelab
chown root $(INSTALL_BINDIR)/tbrsync
chmod u+s $(INSTALL_BINDIR)/tbrsync
#
# Control node installation (okay, plastic)
......
#!/usr/bin/perl -wT
#
# EMULAB-COPYRIGHT
# Copyright (c) 2004 University of Utah and the Flux Group.
# All rights reserved.
#
#
# tbrsync - An emulab frontend to rsync.
#
use lib '@prefix@/lib';
my $TB = '@prefix@';
use libdb;
use English;
use Getopt::Long;
use File::Basename;
#
# We have to be setuid root so that we can ssh into stargates as root
#
if ($EUID != 0) {
die("*** $0:\n".
" Must be root! Maybe its a development version?\n");
}
# un-taint path
$ENV{'PATH'} = "/bin:/usr/bin:/usr/local/bin:$TB/bin";
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
use strict;
#
# Constants
#
my $RSYNC = "/usr/local/bin/rsync";
my $SSHTB = "$TB/bin/sshtb";
my $DEBUG = 1;
#
# Handle command-line arguments
# TODO: Allow a user to specify some of their own arguments to uisp
#
sub usage() {
warn "Usage: $0 [-p <pid> -e <eid>] [--dry] [--nodelete] <operation> [dirname] <nodes...>\n";
warn "Supported operations: upload\n";
warn "[dirname] is required with the 'upload' operation\n";
return 1;
}
my %opt = ();
GetOptions(\%opt, 'p=s','e=s','dry','nodelete');
if (($opt{e} && ! $opt{p}) || (!$opt{e} && $opt{p})) {
warn "-e and -p must be used togehter\n";
die usage;
}
my ($eid, $pid);
if ($opt{e}) {
$eid = $opt{e};
$pid = $opt{p};
}
my ($dryrun, $delete) = (0, 1);
if ($opt{dry}) {
$dryrun = 1;
}
if ($opt{nodelete}) {
$delete = 0;
}
my $operation = shift @ARGV;
my $dirname;
if (!$operation) {
exit usage();
}
# Check the operation type
# XXX - support the other operations uisp supports, like downloading code
SWITCH: for ($operation) {
/^upload$/ && do {
$dirname = shift @ARGV;
if (!$dirname) {
exit usage();
}
last SWITCH;
};
# Default
warn "Uknown operation $operation\n";
exit usage();
}
# They have to give us at least one node, unless they gave a pid or eid, in
# which case we take that to mean all nodes in the experiment
my @nodes = @ARGV;
if (!@nodes && !$eid) {
exit usage();
}
# Perm check on the eid and pid
if ($eid) {
if (!TBExptAccessCheck($UID,$pid,$eid,TB_EXPT_READINFO)) {
die "*** You do not have permission to access nodes in\n" .
" $pid/$eid\n";
}
}
# If given an eid and a node list, translate the node names to physical ones
if ($eid && @nodes) {
my @tmp;
foreach my $node (@nodes) {
my $physnode;
if (!VnameToNodeid($pid,$eid,$node,\$physnode)) {
die "*** No such node $node in $pid/$eid\n";
}
push @tmp, $physnode;
}
@nodes = @tmp;
}
# If given an eid and no node list, grab all nodes in the experiment
if (!@nodes && $eid) {
@nodes = ExpNodes($pid, $eid);
if (!@nodes) {
die "*** Unable to get nodes in experiment $pid/$eid\n";
}
}
#
# Taint check the dirname
#
if ($dirname =~ /^([-\w\/.]+)$/) {
$dirname = $1;
} else {
die("*** Tainted directory name: $dirname\n");
}
# Strip trailing slash, if present
$dirname =~ s/(^.*)\/$/$1/;
#
# Taint check the node names
#
@nodes = map {
if (/^([-\w]+)$/) {
$1;
} else {
die("*** Tainted node name: $_\n");
}
} @nodes;
#
# Permission check
#
if ($UID && !TBNodeAccessCheck($UID,TB_NODEACCESS_LOADIMAGE,@nodes)) {
die "You do not have permission to modify one or more nodes\n";
}
#
# Check the file to make sure it's readable - note, we want to make sure it's
# readable by the real uid, since w'ere setuid root
#
if ($dirname) {
if (!-R $dirname) {
die "$dirname not readable\n";
}
}
#
# Rsync each node.
#
my $errors = 0;
NODE: foreach my $node (@nodes) {
#
# XXX: Need to check that the node is actually imageable via rsync!
#
#
# Figure out the parameters we need to pass to rsync for this node/op.
# global/common stuff added here..
#
my @rsync_args = "-ar";
# Are we deleting files that only exist at the destination?
if ($delete) {
push @rsync_args, "--delete";
}
# Are we doing this for real or testing?
if ($dryrun) {
push @rsync_args, "--dry-run";
}
#
# Check for the existence of rsync exclude/include lists
#
my $nameprefix = basename($dirname);
my $exclfile = $nameprefix . ".exclude";
my $inclfile = $nameprefix . ".include";
if (-R "$dirname/$exclfile") {
push @rsync_args, "--exclude-from=$dirname/$exclfile";
}
if (-R "$dirname/$inclfile") {
push @rsync_args, "--include-from=$dirname/$inclfile";
}
push @rsync_args, ("--exclude=$exclfile","--exclude=$inclfile");
#
# The operation we want to perform
#
my ($source, $dest);
OSWITCH: for ($operation) {
/^upload$/ && do {
$source = $dirname . "/";
$dest = "$node:/";
last OSWITCH;
};
# No default, we've checked for a valid operation above
}
#
# Actually run rsync
# TODO - Squelch output
# TODO - Allow for some parallelism
#
print "Synching $node with $dirname\n";
my $commandstr = "$RSYNC " . join(" ",@rsync_args) . " $source $dest";
# Need to be root for the next part
$UID = $EUID;
dprint("$commandstr\n");
if (system($commandstr)) {
$errors++;
warn "Failed to sync node $node";
}
}
if ($errors) {
exit 1;
} else {
exit 0;
}
sub dprint(@) {
if ($DEBUG) {
print @_;
}
}
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