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

The brave new world of client side configuration. Major highlights are

a "cleaner" separation of the OS independent and OS dependent parts.
Lots of stuff moved to common libsetup.pm, shared by linux and
freebsd. OS dependent stuff is in liblocsetup.pm in the subdirs.
Other major change was to add "update" ability so that mounts and
accounts can be updated on the fly, when directed to do so from boss.
This is in support of shared experiments, so that as projects are
added to the share list, the mounts and accounts can be updated
without having to reboot.
parent c9e79f63
This diff is collapsed.
......@@ -8,7 +8,7 @@
SRCDIR = @srcdir@
TESTBED_SRCDIR = @top_srcdir@
OBJDIR = ../..
SUBDIR = tmcd
SUBDIR = tmcd/freebsd
include $(OBJDIR)/Makeconf
......@@ -20,29 +20,41 @@ INSTALL_DIR = /etc/testbed
INSTALL_FILES = group master.passwd setup
INSTALL = /usr/bin/install -c
install:
install: misc-install script-install bin-install
dir-install:
-mkdir -p $(INSTALL_DIR)
misc-install: dir-install
-rm -rf $(INSTALL_DIR)/sup/sup
-mkdir -p $(INSTALL_DIR)/sup
$(INSTALL) -m 755 $(SRCDIR)/supfile $(INSTALL_DIR)/supfile
-mkdir -p /root/.cvsup
$(INSTALL) -m 600 $(SRCDIR)/cvsup.auth /root/.cvsup/auth
bin-install: dir-install
$(INSTALL) -m 755 ../tmcc $(INSTALL_DIR)/tmcc
$(INSTALL) -m 755 ../findif $(INSTALL_DIR)/findif
script-install: dir-install
$(INSTALL) -m 644 $(SRCDIR)/group $(INSTALL_DIR)/group
$(INSTALL) -m 600 $(SRCDIR)/master.passwd $(INSTALL_DIR)/master.passwd
$(INSTALL) -m 755 $(SRCDIR)/prepare $(INSTALL_DIR)/prepare
$(INSTALL) -m 755 $(SRCDIR)/setuplib.pm $(INSTALL_DIR)/setuplib.pm
$(INSTALL) -m 755 $(SRCDIR)/../libsetup.pm $(INSTALL_DIR)/libsetup.pm
$(INSTALL) -m 755 $(SRCDIR)/liblocsetup.pm \
$(INSTALL_DIR)/liblocsetup.pm
$(INSTALL) -m 755 $(SRCDIR)/setup $(INSTALL_DIR)/setup
$(INSTALL) -m 755 $(SRCDIR)/update $(INSTALL_DIR)/update
$(INSTALL) -m 755 $(SRCDIR)/rc.testbed $(INSTALL_DIR)/rc.testbed
$(INSTALL) -m 755 $(SRCDIR)/rc.setup $(INSTALL_DIR)/rc.setup
$(INSTALL) -m 755 $(SRCDIR)/rc.delta $(INSTALL_DIR)/rc.delta
$(INSTALL) -m 755 $(SRCDIR)/runstartup $(INSTALL_DIR)/runstartup
$(INSTALL) -m 755 $(SRCDIR)/sethostname $(INSTALL_DIR)/sethostname
$(INSTALL) -m 644 $(SRCDIR)/hosts $(INSTALL_DIR)/hosts
$(INSTALL) -m 755 ../tmcc $(INSTALL_DIR)/tmcc
$(INSTALL) -m 755 ../findif $(INSTALL_DIR)/findif
$(INSTALL) -m 755 $(SRCDIR)/supfile $(INSTALL_DIR)/supfile
-mkdir -p /root/.cvsup
$(INSTALL) -m 600 $(SRCDIR)/cvsup.auth /root/.cvsup/auth
$(INSTALL) -m 755 $(SRCDIR)/dhclient-exit-hooks \
/etc/dhclient-exit-hooks
$(INSTALL) -m 755 $(SRCDIR)/nodetype /etc/testbed/nodetype
$(INSTALL) -m 755 $(SRCDIR)/cpuspeed.awk /etc/testbed/cpuspeed.awk
$(INSTALL) -m 755 $(SRCDIR)/start_if.fxp0 /etc/start_if.fxp0
$(INSTALL) -m 755 $(SRCDIR)/start_if.fxp4 /etc/start_if.fxp4
......@@ -4,4 +4,6 @@
# See if the Testbed configuration software wants to change the hostname.
# Installed into /etc.
#
exec /etc/testbed/sethostname
/etc/testbed/sethostname $new_domain_name
exit 0
#!/usr/bin/perl -wT
#
# FreeBSD specific routines and constants for the client bootime setup stuff.
#
package liblocsetup;
use Exporter;
@ISA = "Exporter";
@EXPORT =
qw ( $CP $EGREP $MOUNT $UMOUNT $TMPASSWD
os_cleanup_node os_ifconfig_line os_etchosts_line
os_setup os_groupadd os_useradd os_userdel os_usermod
os_rpminstall_line
);
# Must come after package declaration!
use English;
#
# This is the FreeBSD dependent part of the setup library.
#
my $SETUPDIR = "/etc/testbed";
libsetup::libsetup_init($SETUPDIR);
#
# Various programs and things specific to FreeBSD and that we want to export.
#
$CP = "/bin/cp";
$EGREP = "/usr/bin/egrep -s -q";
$MOUNT = "/sbin/mount";
$UMOUNT = "/sbin/umount";
$TMGROUP = "$SETUPDIR/group";
$TMPASSWD = "$SETUPDIR/master.passwd";
#
# These are not exported
#
my $USERADD = "/usr/sbin/pw useradd";
my $USERDEL = "/usr/sbin/pw userdel";
my $USERMOD = "/usr/sbin/pw usermod";
my $GROUPADD = "/usr/sbin/pw groupadd";
my $CHPASS = "/usr/bin/chpass -p";
my $MKDB = "/usr/sbin/pwd_mkdb -p";
my $IFCONFIG = "/sbin/ifconfig %s inet %s netmask %s ".
"media 100baseTX mediaopt full-duplex";
my $RPMINSTALL = "/usr/local/bin/rpm -i %s";
#
# Delay node configuration goop.
#
my $KERNEL100 = "/kernel.100HZ";
my $KERNEL1000 = "/kernel.1000HZ";
my $KERNEL10000 = "/kernel.10000HZ";
my @KERNELS = ($KERNEL100, $KERNEL1000, $KERNEL10000);
my $kernel = $KERNEL100;
my $IFACE = "fxp";
my $CTLIFACENUM = "4";
my $CTLIFACE = "${IFACE}${CTLIFACENUM}";
my $TMDELAY = "$SETUPDIR/rc.delay";
my $TMCCCMD_DELAY = "delay";
#
# OS dependent part of cleanup node state.
#
sub os_cleanup_node () {
unlink $TMDELAY;
printf STDOUT "Resetting passwd and group files\n";
if (system("$CP -f $TMGROUP /etc/group") != 0) {
print STDERR "Could not copy default group file into place: $!\n";
exit(1);
}
if (system("$CP -f $TMPASSWD /etc/master.passwd_testbed") != 0) {
print STDERR "Could not copy default passwd file into place: $!\n";
exit(1);
}
if (system("$MKDB /etc/master.passwd_testbed") != 0) {
print STDERR "Failure running $MKDB on default password file: $!\n";
exit(1);
}
return 0;
}
#
# Generate and return an ifconfig line that is approriate for putting
# into a shell script (invoked at bootup).
#
sub os_ifconfig_line($$$)
{
my ($iface, $inet, $mask) = @_;
return sprintf($IFCONFIG, $iface, $inet, $mask);
}
#
# Generate and return an string that is approriate for putting
# into /etc/hosts.
#
sub os_etchosts_line($$$$)
{
my ($name, $link, $ip, $alias) = @_;
return sprintf("%s\t%s-%s %s", $ip, $name, $link, $alias);
}
#
# Add a new group
#
sub os_groupadd($$)
{
my($group, $gid) = @_;
return system("$GROUPADD $group -g $gid");
}
#
# Remove a user account.
#
sub os_userdel($)
{
my($login) = @_;
return system("$USERDEL $login");
}
#
# Modify user group membership.
#
sub os_usermod($$$$)
{
my($login, $gid, $glist, $root) = @_;
if ($root) {
$glist = join(',', split(/,/, $glist), "wheel");
}
if ($glist ne "") {
$glist = "-G $glist";
}
return system("$USERMOD $login -g $gid $glist");
}
#
# Add a user.
#
sub os_useradd($$$$$$$$)
{
my($login, $uid, $gid, $pswd, $glist, $homedir, $gcos, $root) = @_;
if ($root) {
$glist = join(',', split(/,/, $glist), "wheel");
}
if ($glist ne "") {
$glist = "-G $glist";
}
if (system("$USERADD $login -u $uid -g $gid $glist ".
"-d $homedir -s /bin/tcsh -c \"$gcos\"") != 0) {
warn "*** WARNING: $USERADD $login error.\n";
return -1;
}
if (system("$CHPASS $pswd $login") != 0) {
warn "*** WARNING: $CHPASS $login error.\n";
return -1;
}
return 0;
}
#
# Generate and return an RPM install line that is approriate for putting
# into a shell script (invoked at bootup).
#
sub os_rpminstall_line($)
{
my ($rpm) = @_;
return sprintf($RPMINSTALL, $rpm);
}
#
# OS Dependent configuration.
#
sub os_setup()
{
print STDOUT "Checking Testbed delay configuration ... \n";
dodelays();
}
sub dodelays ()
{
my @delays;
my $checkreplace;
my $TM = libsetup::OPENTMCC($TMCCCMD_DELAY);
while (<$TM>) {
push(@delays, $_);
}
close($TM);
if (@delays) {
$count = 69;
$mindelay = 10000;
open(DEL, ">$TMDELAY")
or die("Could not open $TMDELAY");
print DEL "#!/bin/sh\n";
print DEL "sysctl -w net.link.ether.bridge=0\n";
print DEL "sysctl -w net.link.ether.bridge_ipfw=0\n";
print DEL "sysctl -w net.link.ether.bridge_cfg=${CTLIFACE}:6,";
foreach $delay (@delays) {
$delay =~ /DELAY INT0=(\w+) INT1=(\w+) DELAY/;
print DEL "$1:$count,$2:$count,";
$count++;
}
print DEL "\n";
print DEL "sysctl -w net.link.ether.bridge=1\n";
print DEL "sysctl -w net.link.ether.bridge_ipfw=1\n";
print DEL "ipfw -f flush\n";
$count = 69;
$pipe = 100;
foreach $delay (@delays) {
$delay =~
/DELAY INT0=(\w+) INT1=(\w+) DELAY=(\d+) BW=([\d\.]+) PLR=([\d\.]+)/;
#
# tmcd returns the INTs as fxpX. Nice, eh?
#
$iface1 = $1;
$iface2 = $2;
$p1 = $pipe += 10;
$p2 = $pipe += 10;
$delay = $3;
$bandw = $4;
$plr = $5;
#
# We want to know what the minimum delay is so we can boot the
# the correct kernel.
#
if ($delay < $mindelay) {
$mindelay = $delay;
}
print DEL "ifconfig $iface1 media 100baseTX mediaopt full-duplex";
print DEL "\n";
print DEL "ifconfig $iface2 media 100baseTX mediaopt full-duplex";
print DEL "\n";
print DEL "ipfw add pipe $p1 ip from any to any in recv $iface1\n";
print DEL "ipfw add pipe $p2 ip from any to any in recv $iface2\n";
print DEL "ipfw pipe $p1 config delay ${delay}ms ";
print DEL "bw ${bandw}Mbit/s plr $plr\n";
print DEL "ipfw pipe $p2 config delay ${delay}ms ";
print DEL "bw ${bandw}Mbit/s plr $plr\n";
print STDOUT " $iface1/$iface2 pipe $p1/$p2 config delay ";
print STDOUT "${delay}ms bw ${bandw}Mbit/s plr $plr\n";
$count++;
}
#
# If a delay node, then lets report status and ready in so that batch
# experiments do not become stuck.
#
printf DEL "%s %s\n", libsetup::TMCC(), libsetup::TMCCCMD_READY();
printf DEL "%s %s 0\n", libsetup::TMCC(),libsetup::TMCCCMD_STARTSTAT();
print DEL "echo \"Delay Configuration Complete\"\n";
close(DEL);
chmod(0755, "$TMDELAY");
#
# Now do kernel configuration. All of the above work is wasted, but
# we needed to know the minimum delay. Eventually we will boot the
# correct kernel to start with via PXE.
#
$kernel = $KERNEL1000;
$checkreplace = 1;
}
else {
#
# Make sure we are running the correct non delay kernel. This
# is really only necessary in the absence of disk reloading.
# Further, we don't want to replace a user supplied kernel.
#
$kernel = $KERNEL100;
$checkreplace = 0;
foreach $kern (@KERNELS) {
if (system("cmp -s /kernel $kern") == 0) {
$checkreplace = 1;
}
}
}
print STDOUT "Checking kernel configuration ... \n";
if ($checkreplace) {
#
# Make sure we are running the correct kernel.
#
if (-e $kernel) {
if (system("cmp -s /kernel $kernel") != 0) {
if (system("cp -f /kernel /kernel.save")) {
print STDOUT
"Could not backup /kernel! Aborting kernel change\n";
}
else {
if (system("cp -f $kernel /kernel")) {
print STDOUT "Could not cp $kernel to /kernel! ".
"Aborting kernel change\n";
}
else {
system("sync");
system("reboot");
}
}
}
}
else {
print STDOUT "Kernel $kernel does not exist!\n";
}
}
return 0;
}
1;
......@@ -17,15 +17,16 @@ my $MAILFILE = "/var/mail/root";
my $LEASES = "/var/db/dhclient.leases";
#
# Load the testbed library.
#
push(@INC, "/etc/testbed");
require setuplib;
# Load the OS independent support library. It will load the OS dependent
# library and initialize itself.
#
use lib "/etc/rc.d/testbed";
use libsetup;
#
# Untaint path
#
$ENV{'PATH'} = '/bin:/sbin:/usr/bin:/usr/local/bin:/etc/rc.d/testbed';
$ENV{'PATH'} = '/bin:/sbin:/usr/bin:/usr/local/bin:/etc/testbed';
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
#
......
......@@ -7,10 +7,11 @@ use English;
my $reboot = 0;
#
# Load the testbed library.
#
push(@INC, "/etc/testbed");
require setuplib;
# Load the OS independent support library. It will load the OS dependent
# library and initialize itself.
#
use lib "/etc/testbed";
use libsetup;
#
# Untaint path
......@@ -23,25 +24,7 @@ delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
#
$| = 1;
#
# Inform the master that we have rebooted.
#
#
# Inform the master that we have rebooted.
#
inform_reboot();
#
# Check allocation. Exit now if not allocated.
#
if (! check_status()) {
exit(0);
}
#
# Mount the project directory.
#
mount_projdir();
print STDOUT "Checking Testbed Delta configuration ... \n";
#
# Delta configuration.
......
......@@ -2,17 +2,11 @@
use English;
#
# We are run out of the at daemon as root.
#
my $TMCC = "/etc/testbed/tmcc";
my $TMSTARTUPCMD = "/etc/testbed/startupcmd";
my $logname;
#
# Load the testbed library.
#
push(@INC, "/etc/testbed");
require setuplib;
# Load the OS independent support library. It will load the OS dependent
# library and initialize itself.
#
use lib "/etc/testbed";
use libsetup;
#
# Untaint path
......@@ -20,12 +14,17 @@ require setuplib;
$ENV{'PATH'} = '/bin:/sbin:/usr/bin:/usr/local/bin:/etc/testbed';
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
#
# Turn off line buffering on output
#
$| = 1;
#
# Get the config parameters so we can open up a log file in the proper
# location. See below.
#
my ($pid, $eid, $vname) = check_status();
if (! defined($pid)) {
my ($pid, $eid, $vname);
if (! (($pid, $eid, $vname) = check_status())) {
fatal("Could not determine pid/eid");
}
......@@ -42,8 +41,8 @@ if (background()) {
#
# Open up the command file, which tells us what to do.
#
open(CMD, "$TMSTARTUPCMD") or
fatal("Could not open $TMSTARTUPCMD: $!");
open(CMD, TMSTARTUPCMD) or
fatal("Could not open " . TMSTARTUPCMD . ": $!");
my $runcmd;
my $login;
......@@ -56,7 +55,7 @@ while (<CMD>) {
}
if (!defined($runcmd) || !defined($login)) {
fatal("$TMSTARTUPCMD not in proper format!");
fatal(TMSTARTUPCMD . " not in proper format!");
}
(undef,undef,$uid,$gid,undef,undef,undef,undef) = getpwnam($login) or
fatal("Could not determine UID for $login");
......@@ -83,8 +82,8 @@ else {
$EGID = $GID = $gid;
$EUID = $UID = $uid;
exec($runcmd);
fatal("Could not exec $runcmd");
exec($runcmd) or
fatal("Could not exec $runcmd: $!");
}
print STDOUT "$runcmd returned $stat\n";
......@@ -92,8 +91,7 @@ print STDOUT "$runcmd returned $stat\n";
#
# Use the TMCC to tell the TMCD what the exit status was.
#
system("$TMCC startstatus $stat");
startcmdstatus($stat);
exit(0);
sub fatal($)
......@@ -105,8 +103,7 @@ sub fatal($)
#
# Use the TMCC to tell the TMCD that we screwed the pooch.
#
system("$TMCC startstatus 666");
startcmdstatus(666);
exit(-1);
}
......
......@@ -3,19 +3,30 @@ use English;
#
# Set the hostname for the node according to the current experiment.
# Run from /etc/dhclient-exit-hooks
# Run from /etc/dhclient-exit-hooks.
#
# usage: sethostname [domain]
#
# We get the domain from dhclient script setup, and pass it through.
# Otherwise, we have no safe way to determine the domain.
#
push(@INC, "/etc/testbed");
require setuplib;
#
# Load the OS independent support library. It will load the OS dependent
# library and initialize itself.
#
use lib "/etc/testbed";
use libsetup;
#
# Untaint path
#
$ENV{'PATH'} = '/bin:/sbin:/usr/bin:/usr/local/bin:/etc/rc.d/testbed';
$ENV{'PATH'} = '/bin:/sbin:/usr/bin:/usr/local/bin:/etc/testbed';
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
#
# Turn off line buffering on output
#
$| = 1;
#
......@@ -30,29 +41,36 @@ if (! ($curname =~ /.+/)) {
}
#
# Inform the master that we have rebooted. THIS MUST BE DONE!
#
inform_reboot();
# Make sure we get a valid domainname. If not then do not reset the hostname.
#
if (! @ARGV) {
exit 0;
}
#
# Check allocation. Exit now if not allocated.
#
my ($pid, $eid, $vname) = check_status();
if (! $pid) {
$domain = $ARGV[0];
if ($domain =~ /\./) {
$domain = ".$domain";
}
else {
exit 0;
}
#
# Otherwise, sethostname
#
my $nickname= "$vname.$eid.$pid";
my $nickname = whatsmynickname();
if (! $nickname) {
print STDOUT "No Testbed nickname available!\n";
exit(0);
}
print STDOUT "Resetting hostname to $nickname ... ";
#
# No prints. Something screwy in dhclient causes these prints
# to go into resolv.conf!
#
#print STDOUT "Resetting hostname to ${nickname}${domain} ... ";
if (system("hostname $nickname")) {
print STDOUT "*** FAILED!\n";
if (system("hostname", "${nickname}${domain}")) {
# print STDOUT "*** FAILED!\n";
exit 1;
}
print STDOUT "Done!\n";
#print STDOUT "Done!\n";
exit 0;
#!/usr/bin/perl -wT
use English;
push(@INC, "/etc/testbed");
require setuplib;
#
# Untaint path
#
$ENV{'PATH'} = '/bin:/sbin:/usr/bin:/usr/local/bin:/etc/rc.d/testbed';
$ENV{'PATH'} = '/bin:/sbin:/usr/bin:/usr/local/bin:/etc/testbed';
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
#
# First clean up the node.
#
cleanup_node();
#
# Inform the master that we have rebooted.
#
inform_reboot();
#
# Check allocation. Exit now if not allocated.
#
if (! check_status()) {
exit(0);
}
#
# Setup a nicknames file.
#
create_nicknames();
#
# Mount the project directory.
#
mount_projdir();
#
# Okay, lets find out about interfaces.
#
doifconfig();
#
# Host names configuration (/etc/hosts).
#
dohostnames();
#
# Check for delay config.
#
dodelays();
#
# Do account stuff.
#
doaccounts();
#
# RPMS
#
dorpms();
#
# Tar Balls
# Load the OS independent support library. It will load the OS dependent
# library and initialize itself.
#
dotarballs();
use lib "/etc/testbed";
use libsetup;
#
# Experiment startup Command.
# Then invoke the bootsetup routine in the library. All the work happens
# in there.
#
dostartupcmd();
bootsetup();
exit(0);
exit 0;
This diff is collapsed.
......@@ -2,4 +2,4 @@
# When the release is bumped, be sure to remove sup/sup/FBSD43-STD/checkouts
# on the client.
#
FBSD43-STD host=boss.emulab.net base=/etc/testbed/sup prefix=/ preserve release=20010719
FBSD43-STD host=boss.emulab.net base=/etc/testbed/sup prefix=/ preserve release=20010924
#!/usr/bin/perl -wT
use English;
#
# Untaint path
#
$ENV{'PATH'} = '/bin:/sbin:/usr/bin:/usr/local/bin:/etc/testbed';
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
#
# Load the OS independent support library. It will load the OS dependent