Commit dfd2ca98 authored by David Johnson's avatar David Johnson
Browse files

Merge branch 'libosload'

This is the big osload_new commit.  It's not enabled by default; you have
to enable the NewOsload feature to get access to it.  Moreover, it
requires the NewOsSetup feature.

Conflicts:
	db/EmulabConstants.pm.in
parents e5359665 12005979
......@@ -108,7 +108,7 @@ int handleupload(void);
#define DEVNAME "%s/%s"
#define BUFSIZE 4096
#define DROP_THRESH (32*1024)
#define MAX_UPLOAD_SIZE (1 * 1024 * 1024)
#define MAX_UPLOAD_SIZE (32 * 1024 * 1024)
#define DEFAULT_CERTFILE PREFIX"/etc/capture.pem"
#define DEFAULT_CLIENT_CERTFILE PREFIX"/etc/client.pem"
#define DEFAULT_CAFILE PREFIX"/etc/emulab.pem"
......@@ -1562,9 +1562,14 @@ clientconnect(void)
secretkey_t key;
capret_t capret;
#ifdef WITHSSL
int dorelay = 0, doupload = 0;
int dorelay = 0, doupload = 0, dooptions = 0;
int newspeed = 0;
speed_t newsymspeed;
int opterr = 0;
int ret;
SSL *newssl;
struct termios serial_opts;
char *caddr;
#endif
newfd = accept(sockfd, (struct sockaddr *)&sin, &length);
......@@ -1588,6 +1593,7 @@ clientconnect(void)
if (cc == sizeof(key) &&
(0 == strncmp( key.key, "USESSL", 6 ) ||
(dorelay = (0 == strncmp( key.key, "RELAY", 5 ))) ||
(dooptions = (0 == strncmp( key.key, "OPTIONS", 7 ))) ||
(doupload = (0 == strncmp( key.key, "UPLOAD", 6 ))))) {
/*
dolog(LOG_NOTICE, "Client %s wants to use SSL",
......@@ -1663,6 +1669,56 @@ clientconnect(void)
return 0;
}
}
else if (dooptions) {
/*
* Just handle these quick inline -- then don't have to
* worry about multiple option changes cause they all
* happen "atomically" from the client point of view.
*/
caddr = inet_ntoa(sin.sin_addr);
sscanf(key.key,"OPTIONS SPEED=%d",&newspeed);
newsymspeed = val2speed(newspeed);
dolog(LOG_NOTICE,"%s changing speed to %d.",
caddr,newspeed);
if (newspeed == 0) {
dolog(LOG_ERR,"%s invalid speed option %d.",
caddr,newspeed);
opterr = 1;
}
if (opterr == 0 && tcgetattr(devfd,&serial_opts) == -1) {
dolog(LOG_ERR,"%s failed to get attrs before speed change: %s.",
caddr,strerror(errno));
opterr = 1;
}
// XXX testing
//serial_opts.c_lflag |= ECHO | ECHONL;
if (opterr) {
}
else if (cfsetispeed(&serial_opts,newsymspeed) == -1) {
dolog(LOG_ERR,"%s cfsetispeed(%d) failed: %s.",
caddr,newspeed,strerror(errno));
opterr = 1;
}
else if (cfsetospeed(&serial_opts,newsymspeed) == -1) {
dolog(LOG_ERR,"%s cfsetospeed(%d) failed: %s.",
caddr,newspeed,strerror(errno));
opterr = 1;
}
else if (tcsetattr(devfd,TCSANOW,&serial_opts) == -1) {
dolog(LOG_ERR,"%s tcsetattr(%d) failed: %s.",
caddr,newspeed,strerror(errno));
opterr = 1;
}
SSL_free(newssl);
shutdown(newfd, SHUT_RDWR);
close(newfd);
return opterr;
}
else if (dorelay) {
if (devfd >= 0) {
dolog(LOG_NOTICE, "%s relay already connected.",
......@@ -1837,7 +1893,7 @@ handleupload(void)
}
}
else if ((upfilesize + rc) > MAX_UPLOAD_SIZE) {
dolog(LOG_NOTICE, "upload to large");
dolog(LOG_NOTICE, "upload too large");
drop = 1;
}
else if (rc == 0) {
......
......@@ -101,7 +101,7 @@ use vars qw(@ISA @EXPORT);
TBDB_NODEOPMODE_UNKNOWNOS TBDB_NODEOPMODE_RELOADING
TBDB_NODEOPMODE_NORMALv1 TBDB_NODEOPMODE_MINIMAL TBDB_NODEOPMODE_PCVM
TBDB_NODEOPMODE_RELOAD TBDB_NODEOPMODE_RELOADMOTE
TBDB_NODEOPMODE_RELOADPCVM
TBDB_NODEOPMODE_RELOADPCVM TBDB_NODEOPMODE_RELOADPUSH
TBDB_NODEOPMODE_SECUREBOOT TBDB_NODEOPMODE_SECURELOAD
TBDB_NODEOPMODE_DELAY
TBDB_NODEOPMODE_BOOTWHAT
......@@ -420,6 +420,7 @@ sub TBDB_NODEOPMODE_RELOADMOTE { "RELOAD-MOTE"; }
sub TBDB_NODEOPMODE_SECUREBOOT { "SECUREBOOT"; }
sub TBDB_NODEOPMODE_SECURELOAD { "SECURELOAD"; }
sub TBDB_NODEOPMODE_RELOADPCVM { "RELOAD-PCVM"; }
sub TBDB_NODEOPMODE_RELOADPUSH { "RELOAD-PUSH"; }
sub TBDB_NODEOPMODE_DELAY { "DELAY"; }
sub TBDB_NODEOPMODE_BOOTWHAT { "_BOOTWHAT_"; } # A redirection opmode
sub TBDB_NODEOPMODE_UNKNOWN { "UNKNOWN"; }
......
......@@ -1215,11 +1215,11 @@ sub inner_elab_role($) {
return L__reservation($_[0], 'inner_elab_role'); }
#
# Lookup a specific attribute in the node_attributes table,
# Load all attributes from the node_attributes table,
#
sub NodeAttribute($$$;$)
sub LoadNodeAttributes($)
{
my ($self, $attrkey, $pattrvalue, $pattrtype) = @_;
my ($self) = @_;
return -1
if (!ref($self));
......@@ -1241,6 +1241,27 @@ sub NodeAttribute($$$;$)
$self->{"ATTRS"}->{$key} = $row;
}
}
return 0;
}
#
# Lookup a specific attribute in the node_attributes table,
#
sub NodeAttribute($$$;$)
{
my ($self, $attrkey, $pattrvalue, $pattrtype) = @_;
return -1
if (!ref($self));
my $node_id = $self->node_id();
if (!defined($self->{"ATTRS"})) {
if ($self->LoadNodeAttributes()) {
return -1;
}
}
if (!exists($self->{"ATTRS"}->{$attrkey})) {
$$pattrvalue = undef;
......@@ -1255,6 +1276,27 @@ sub NodeAttribute($$$;$)
return 0;
}
#
# Return a hash of the node attributes for this node.
#
sub GetNodeAttributes($)
{
my ($self) = @_;
return undef
if (!ref($self));
my $node_id = $self->node_id();
if (!defined($self->{"ATTRS"})) {
if ($self->LoadNodeAttributes()) {
return undef;
}
}
return $self->{"ATTRS"};
}
#
# Return type info. We cache this in the instance since node_type stuff
# does not change much.
......@@ -1297,6 +1339,24 @@ sub NodeTypeAttribute($$$;$)
return $typeinfo->GetAttribute($attrkey, $pattrvalue, $pattrtype);
}
#
# Returns a hash of node type attributes in the nodetype info.
#
sub GetNodeTypeAttributes($)
{
my ($self) = @_;
return undef
if (!ref($self));
my $typeinfo = $self->NodeTypeInfo();
return undef
if (!defined($typeinfo));
return $typeinfo->GetAttributes();
}
#
# Shortcuts to "common" type information.
# Later these might be overriden by node attributes.
......
......@@ -279,6 +279,23 @@ sub GetAttribute($$;$$)
$$pattrvalue = undef;
return -1;
}
#
# Look for an attribute.
#
sub GetAttributes($)
{
my ($self) = @_;
return undef
if (!ref($self));
$self->LoadAttributes() == 0
or return undef;
return $self->{"ATTRS"};
}
# Shortcuts for typical attributes.
sub default_osid($;$) {return GetAttribute($_[0], "default_osid", $_[1]); }
sub default_imageid($;$){return GetAttribute($_[0], "default_imageid",$_[1]); }
......
......@@ -1076,6 +1076,41 @@ sub GetSSHKeys($$)
return 0;
}
#
# Get (hopefully) unencrypted, locally-generated user ssh keys. This is
# bogus; I am making sure to only return locally-generated keys.
#
sub GetDefaultSSHKeys($$;$)
{
my ($self, $pref, $onlylatest) = @_;
my @result = ();
# Must be a real reference.
return -1
if (! (ref($self) && ref($pref)));
my $uid_idx = $self->uid_idx();
my $extra = '';
if (defined($onlylatest) && $onlylatest) {
$extra = 'order by stamp desc limit 1';
}
my $query_result =
DBQueryWarn("select pubkey from user_pubkeys ".
"where uid_idx='$uid_idx' and ".
" comment like '%\@${OURDOMAIN}' $extra");
return -1
if (!defined($query_result));
while (my ($key) = $query_result->fetchrow_array()) {
push(@result, $key);
}
@$pref = @result;
return 0;
}
#
# Get the passphrase for the encrypted key.
#
......
......@@ -89,7 +89,8 @@ LIB_STUFF = libtbsetup.pm exitonwarn.pm libtestbed.pm snmpit_intel.pm \
libadminmfs.pm libtblog.pm libtblog_simple.pm libArchive.pm \
power_mail.pm power_whol.pm Template.pm power_rmcp.pm \
power_ilo.pm libvtop.pm libptop.pm libossetup.pm \
power_ipmi.pm
power_ipmi.pm libosload_new.pm libosload_switch.pm \
libossetup_switch.pm
# These scripts installed setuid, with sudo.
SETUID_BIN_SCRIPTS = node_reboot eventsys_control tarfiles_setup savelogs \
......
This diff is collapsed.
This diff is collapsed.
......@@ -28,6 +28,7 @@ use NodeType;
use libtblog;
use English;
use Data::Dumper;
use EmulabFeatures;
# Configure variables
my $TB = "@prefix@";
......@@ -73,6 +74,7 @@ sub New($$$@)
my $self = {};
$self->{'USER'} = $user;
$self->{'EXPT'} = $experiment;
$self->{'GROUP'} = (defined($experiment)) ? $experiment->GetGroup() : undef;
$self->{'HASH'} = {};
$self->{'NODES'} = {};
$self->{'PHYSNODES'} = {};
......@@ -99,6 +101,14 @@ sub New($$$@)
# XXX
$self->noretry(0);
$self->canceled(0);
if (EmulabFeatures->FeatureEnabled("NewOsload",$user,
$self->{'GROUP'},$experiment)) {
require libosload_new;
# XXX -- @nodelist
$self->loadobj(libosload_new->New());
}
return $self;
}
# Break circular reference someplace to avoid exit errors.
......@@ -118,6 +128,7 @@ sub sharednodes($) { return $_[0]->{'SHAREDNODES'}; }
sub oplist($) { return $_[0]->{'OPLIST'}; }
sub user($) { return $_[0]->{'USER'}; }
sub experiment($) { return $_[0]->{'EXPT'}; }
sub group($) { return $_[0]->{'GROUP'}; }
sub IncrFailCount($) { $_[0]->{'FAILCOUNT'}++ }
sub failed($) { return $_[0]->{'FAILCOUNT'}; }
......@@ -529,8 +540,29 @@ sub LightUpNodes($@)
$reload_args{'nodelist'} = [ @list ];
$reload_args{'nodeflags'} = \%nodeflags;
my $pid = osload(\%reload_args, $reload_failures);
push(@children, [ $pid, \&osload_wait,
my $pid;
my $coderef;
if (EmulabFeatures->FeatureEnabled("NewOsload",$self->user(),
$self->group(),
$self->experiment())) {
($self->loadobj())->debug($self->debug());
# add a few more things for feature checks down the line:
$reload_args{user} = $self->user();
$reload_args{group} = $self->group();
$reload_args{experiment} = $self->experiment();
$pid = ($self->loadobj())->osload(\%reload_args, $reload_failures);
$coderef = sub {
my $childpid = shift;
return ($self->loadobj())->osload_wait($childpid);
};
}
else {
$pid = osload(\%reload_args, $reload_failures);
$coderef = \&osload_wait;
}
push(@children, [ $pid, $coderef, ,
[ @list ], $reload_failures ]);
sleep(5);
}
......@@ -800,12 +832,17 @@ sub NewType($$)
my $newtype = eval { $packname->New($self); };
# Not loaded?
if ($@) {
#print STDERR $@;
return undef;
#print STDERR "module load failed: " . $@ . "\n";
eval "require libossetup_$type";
$newtype = eval { $packname->New($self); };
if ($@) {
print STDERR "$self NewType($type): module load failed: " . $@ . "\n";
return undef;
}
}
$self->{'TYPECACHE'}->{$type} = $newtype;
print STDERR "Created type object $type\n"
print STDERR "Created type object $type with parent $self\n"
if ($self->debug());
return $newtype;
......@@ -854,6 +891,8 @@ use English;
use Data::Dumper;
use overload ('""' => 'Stringify');
use vars qw($AUTOLOAD);
sub New($$$)
{
my ($class, $type, $parent) = @_;
......@@ -877,6 +916,23 @@ sub todo($) { return $_[0]->{'TODOLIST'}; }
sub todolist($) { return values(%{ $_[0]->{'TODOLIST'} }); }
sub IncrFailCount($) { $_[0]->{'FAILCOUNT'}++ }
sub AUTOLOAD {
my $self = shift;
my $type = ref($self) or die("$self is not an object\n");
my $name = $AUTOLOAD;
$name =~ s/.*://; # strip fully-qualified portion
if (@_) {
return $self->{'HASH'}->{$name} = shift;
}
elsif (exists($self->{'HASH'}->{$name})) {
return $self->{'HASH'}->{$name};
}
print STDERR "$self: tried to access unknown slot $name\n";
return undef;
}
#
# Add a node to the list.
#
......@@ -1262,7 +1318,21 @@ sub AddNode($$)
$reload_args{'imageid'} = $image->imageid();
$reload_args{'nodelist'} = [ $node_id ];
osload(\%reload_args, $reload_failures);
if (EmulabFeatures->FeatureEnabled("NewOsload",$self->user(),
$self->group(),
$self->experiment())) {
($parent->loadobj())->debug($self->debug());
# add a few more things for feature checks down the line:
$reload_args{user} = $self->user();
$reload_args{group} = $self->group();
$reload_args{experiment} = $self->experiment();
($parent->loadobj())->osload(\%reload_args, $reload_failures);
}
else {
osload(\%reload_args, $reload_failures)
}
# Reset this. Updated in Volunteers() below.
$node->_setupoperation($libossetup::NOSTATE);
......
This diff is collapsed.
......@@ -130,6 +130,7 @@ sub nodereboot($$)
my $reconfig = 0;
my $asyncmode = 0;
my $pipemode = 0;
my $force = 0;
$powercycle = $args->{'powercycle'} if (exists($args->{'powercycle'}));
$rebootmode = $args->{'rebootmode'} if (exists($args->{'rebootmode'}));
......@@ -141,6 +142,7 @@ sub nodereboot($$)
$prepare = $args->{'prepare'} if (exists($args->{'prepare'}));
$reconfig = $args->{'reconfig'} if (exists($args->{'reconfig'}));
$asyncmode = $args->{'asyncmode'} if (exists($args->{'asyncmode'}));
$force = $args->{'force'} if (exists($args->{'force'}));
#
# If pipeno is specified in the environment, we write the results to
......@@ -179,7 +181,7 @@ sub nodereboot($$)
my $rebootable = $nodeobject->rebootable();
$nodeobjects{$node} = $nodeobject;
push(@temp,$node) if $rebootable;
push(@temp,$node) if ($rebootable || $force);
}
@nodes = @temp;
# END XXX
......@@ -1029,6 +1031,8 @@ sub nodereboot_exec($$)
if (exists($args->{'reconfig'}) && $args->{'reconfig'});
$cmdline .= " -W$args->{waittime}"
if (exists($args->{'waittime'}) && $args->{'waittime'});
$cmdline .= " -F"
if (exists($args->{'force'}));
$cmdline .= " @{ $args->{'nodelist'}}";
$asyncmode = $args->{'asyncmode'} if (exists($args->{'asyncmode'}));
......
......@@ -28,12 +28,13 @@ sub usage()
"Use the -b option to reboot nodes in PXEWAIT mode\n" .
"Use the -a option to reboot all free nodes\n".
"Use the -c option to reconfig nodes instead of rebooting\n".
"Use the -f option to power cycle (and not wait for nodes to die)\n");
"Use the -f option to power cycle (and not wait for nodes to die)\n".
"Use the -F option to reboot even if the type is marked nonrebootable\n");
exit(-1);
}
# The hidden -r option runs this in "realmode", ie don't send an event, but
# really do the work instead. Hidden -W option specifies the waittime.
my $optlist = "dfe:wrkacbpsW:";
my $optlist = "dfe:wrkacbpsW:F";
my $debug = 0;
my $silent = 0;
my $powercycle = 0;
......@@ -43,6 +44,7 @@ my $killmode = 0;
my $reconfig = 0;
my $rebootmode = 0;
my $prepare = 0;
my $force = 0;
my $waittime;
#
......@@ -129,6 +131,9 @@ if (defined($options{"c"})) {
if (defined($options{"W"})) {
$waittime = $options{"W"};
}
if (defined($options{"F"})) {
$force = 1;
}
if (defined($options{"a"})) {
usage()
......@@ -253,6 +258,7 @@ $args{'killmode'} = $killmode;
$args{'reconfig'} = $reconfig;
$args{'prepare'} = $prepare;
$args{'waittime'} = $waittime if defined $waittime;
$args{'force'} = $force;
$args{'nodelist'} = [ @nodes ];
exit(nodereboot(\%args, \%status));
......@@ -32,10 +32,14 @@ sub usage()
" style==0: do not zero (same as not using -z)\n".
" style==1: let frisbee do the zeroing\n".
" style==2: zero disk before running frisbee\n".
"Use -P to prepare the disk as if a whole disk image was loaded\n");
"Use -P to prepare the disk as if a whole disk image was loaded\n".
"Use -F to force the load if Emulab tries to optimize it away\n".
"Use -R to push a reconfig to the node after the reload\n".
"Use -D to set a specific debug level\n".
"Use -o <opt1=foo,opt2=bar,...> to set custom options\n");
exit(-1);
}
my $optlist = "swldi:e:p:m:rz:Pc";
my $optlist = "swldD:i:e:p:m:rz:PcRFo:";
my $waitmode = 1;
my $listonly = 0;
my $debug = 0;
......@@ -43,6 +47,9 @@ my $noreboot = 0;
my $zerofree = 0;
my $prepare = 0;
my $usecurrent= 0;
my $reconfig = 0;
my $force = 0;
my %reload_args = ();
my @nodes = ();
my $imagepid;
my $pid;
......@@ -62,6 +69,8 @@ use Experiment;
use Node;
use OSinfo;
use Image;
use EmulabFeatures;
use User;
# Be careful not to exit on transient error
$libdb::DBQUERY_MAXTRIES = 30;
......@@ -83,6 +92,9 @@ if (! getopts($optlist, \%options)) {
}
$debug = 1
if (defined($options{"d"}));
if (defined($options{"D"}) && $options{"D"} =~ /^(\d+)$/) {
$debug = $1;
}
# List only mode. No need to do anymore argument processing.
sub dolisting();
......@@ -103,11 +115,29 @@ $prepare = 1
if (defined($options{"P"}));
$usecurrent = 1
if (defined($options{"c"}));
$reconfig = 1
if (defined($options{"R"}));
$force = 1
if (defined($options{"F"}));
if (defined($options{"o"})) {
my @kva = split(/,/,$options{"o"});
foreach my $kv (@kva) {
if ($kv =~ /^([\w\-]+)=([^,]+)$/) {
$reload_args{$1} = $2;
}
else {
print STDERR "Improper -o custom option '$kv'!\n";
usage();
}
}
}
#
# Figure out which nodes. Choice of nodes on command line, or all nodes in an
# experiment. To get all free nodes, must use sched_reload.
#
my $experiment;
my $group;
if (defined($options{"e"})) {
usage()
if (@ARGV);
......@@ -118,11 +148,12 @@ if (defined($options{"e"})) {
$pid = $1;
$eid = $2;
my $experiment = Experiment->Lookup($pid, $eid);
$experiment = Experiment->Lookup($pid, $eid);
if (!defined($experiment)) {
die("*** $0:\n".
" No such experiment $pid/$eid!\n");
}
$group = $experiment->GetGroup();
if (! (@nodes = $experiment->NodeList(0, 1))) {
die("*** $0:\n".
" There are no nodes in $pid/$eid!\n");
......@@ -147,7 +178,12 @@ else {
if (!$node->IsReserved()) {
die("*** $0:\n".
" Node $nodeid is not reserved; reserve it first!\n");
}
}
else {
$experiment = $node->Reservation();
$group = $experiment->GetGroup();
}
push(@nodes, $node);
}
}
......@@ -322,6 +358,38 @@ $osloadargs{'imageids'} = [ @imageids ]
$osloadargs{'swapinfo'} = 1;
$osloadargs{'usecurrent'} = $usecurrent;
#
# Allow command-line osloadargs overrides
#
foreach my $key (keys(%reload_args)) {
$osloadargs{$key} = $reload_args{$key};
}
my $user = User->ThisUser();
if (EmulabFeatures->FeatureEnabled("NewOsload",$user,$group,$experiment)) {
require libosload_new;
my $loadobj = libosload_new->New();
$loadobj->debug($debug);
#
# XXX basically, tell devices that try not to reload (like switches)
# that they really need to do it -- if the user or reload daemon actually
# invokes this script, we *have* to reload!