Commit 82e1d812 authored by Leigh B Stoller's avatar Leigh B Stoller

BIG reorganization of the install code.

* Split up boss/ops/fs install into indvidual modules; generally, what
  was a toplevel phase in the original files is not a file. This
  allowed for better code/variable reuse. No longer monolithic, which
  makes it easy to test and rerun parts.

* Incorporate "update" into the install process. Certain phase file
  can be used in update mode, as when the IP/subnet/domain changes.

* Moved the MFS setup from rc.mkelab into the normal install process.
  Users no longer have to do this themselves. Good thing.

* installvars.pm is a new library that has the merged set of the
  zillion variables that were at the top of boss/fs/ops install.
parent 21e7e909
......@@ -124,9 +124,6 @@ my @DAEMONS = ("emulab-watchdog", "progagent", "linktest",
my @SYSDAEMONS = ("cron", "mountd", "ntpd", "sendmail",
"syslogd", "nfsd", "rpcbind");
# "Standard" packages
my $PGENI_PKG = "emulab-protogeni-1.0";
# or this...
my $FSMOUNTDIR = "/q";
my $OPSMOUNTDIR = "/ops";
......@@ -171,6 +168,9 @@ my $NEEDMROUTED= -1;
# Is ops a VM (Jail) on boss.
my $OPSVM = 0;
# Are we a XEN VM?
my $XENVM = 0;
#
# Node to use as ntp server for inner nodes and other inner servers.
# This node will use the outside "ntp1" server as its server.
......@@ -192,6 +192,7 @@ my %emulabconfig = (
"MFSTARBALL" => "tftpboot-elabinelab.tar.gz",
"MFSVERSION" => "62",
"MFSCONSOLE" => "sio",
"PASSWORD" => "ElabInElab",
#
# Elabinelab configuration options:
......@@ -226,6 +227,10 @@ my %emulabconfig = (
"CONFIG_SHAREDFS" => $SHAREDFS,
"CONFIG_MROUTED" => $NEEDMROUTED,
"CONFIG_OPSVM" => $OPSVM,
"CONFIG_NODBINIT" => 0,
# Default protogeni package if LOAD_PROTOGENI is enabled.
"PGENI_PKG" => "emulab-protogeni-1.0",
#
# Elabinelab build options:
......@@ -359,6 +364,15 @@ sub doboot()
$emulabconfig{"MFSVERSION"} = "62";
}
# Determine if a XEN VM.
if (system("sysctl -n kern.vm_guest >/dev/null 2>&1") == 0) {
my $vm_guest = `sysctl -n kern.vm_guest`;
if ($vm_guest =~ /^xen$/) {
$XENVM = 1;
print "Running sinde a XEN VM\n";
}
}
#
# Need outer control router IP in lots of places.
#
......@@ -432,6 +446,10 @@ sub doboot()
$emulabconfig{"ROLE"} = "opsjail"
if ($opsjail);
# Override NTPSERVER when singlenet; okay to use inner ops.
$NTPSERVER = "ops"
if ($emulabconfig{"CONFIG_SINGLECNET"});
#
# XXX not-so-temporary: adjust package info.
#
......@@ -514,6 +532,7 @@ sub doboot()
$emulabconfig{OPS_PKG} = "emulab-ops-4.0";
$emulabconfig{BOSS_PKG} = "emulab-boss-4.0";
$emulabconfig{PACKAGE_TARBALL} = "FreeBSD-8.2-packages.tar.gz";
$emulabconfig{PGENI_PKG} = "emulab-protogeni-2.0";
}
if (exists($emulabconfig{"PACKAGE_TARBALL"})) {
$emulabconfig{FS_PKG_DIR} = "$TBDIR/packages";
......@@ -780,7 +799,7 @@ sub SetupFsNode()
#
# Load up packages if necessary
#
if (!$emulabconfig{"CONFIG_NOSETUP"} && $installpkgs) {
if ($installpkgs) {
# XXX fer now: if not set, derive from the OPS info
if (!$emulabconfig{FS_PKG_DIR} || !$emulabconfig{FS_PKG}) {
$emulabconfig{FS_PKG_DIR} = $emulabconfig{OPS_PKG_DIR};
......@@ -1024,11 +1043,11 @@ sub SetupFsNode()
mysystem("echo '/usr/local/etc/emulab/rc/rc.inelab' ".
" >> /etc/rc.local");
mysystem("cp -p $TBDIR/src/testbed/defs-elabinelab $TBDIR/src");
return
if ($emulabconfig{"CONFIG_NOSETUP"});
mysystem("cp -p $TBDIR/src/testbed/defs-elabinelab $TBDIR/src");
#
# Copy the mirror tree into place. Do not use rsync.
#
......@@ -1198,7 +1217,7 @@ sub SetupOpsNode($)
#
# And clear some other stuff.
#
#
mysystem("rm -rf $TBDIR/bin $TBDIR/lib");
unlink("/etc/rc.conf.d/dhclient")
if (-e "/etc/rc.conf.d/dhclient");
......@@ -1208,7 +1227,7 @@ sub SetupOpsNode($)
#
# Load up packages if necessary
#
if (!$emulabconfig{"CONFIG_NOSETUP"} && $installpkgs) {
if ($installpkgs) {
#
# Do this as a separate step because PKG_DIR might be an NFS path,
# but we must do the NFS unmounts before running ops-install.
......@@ -1420,8 +1439,9 @@ sub SetupOpsNode($)
}
my $pkg = "-P $emulabconfig{OPS_PKG} -p " . $ENV{"PKG_PATH"} . " " .
($isfs ? "-F $emulabconfig{FS_PKG}" : "");
my $pswd = $emulabconfig{"PASSWORD"};
mysystem("cd $TBDIR/obj/testbed/install; ".
" perl ops-install $pkg -b -w ElabInElab ");
" perl emulab-install $pkg -b -w $pswd ops");
#
# And install the ops side.
......@@ -1761,7 +1781,7 @@ sub SetupBossNode($)
#
# And clear some other stuff.
#
#
mysystem("rm -rf $TBDIR/bin $TBDIR/lib");
unlink("/etc/rc.conf.d/dhclient")
if (-e "/etc/rc.conf.d/dhclient");
......@@ -1771,7 +1791,7 @@ sub SetupBossNode($)
#
# Load up packages if necessary
#
if (!$emulabconfig{"CONFIG_NOSETUP"} && $installpkgs) {
if ($installpkgs) {
#
# Do this as a separate step because we need the NFS mounts, but
# must do the unmounts before running boss-install.
......@@ -1808,7 +1828,7 @@ sub SetupBossNode($)
print "Installing the protogeni metaport.\n";
# XXX lives in the boss package dir
$ENV{"PKG_PATH"} = $emulabconfig{BOSS_PKG_DIR};
mysystem("pkg_add -f $PGENI_PKG >>/tmp/perrs 2>&1");
mysystem("pkg_add -f $emulabconfig{PGENI_PKG} >>/tmp/perrs 2>&1");
}
}
......@@ -2047,19 +2067,10 @@ sub SetupBossNode($)
else {
$ENV{"PKG_PATH"} = "/packages";
}
my $pkg = "-P $emulabconfig{BOSS_PKG} -p " . $ENV{"PKG_PATH"};
my $pkg = "-P $emulabconfig{BOSS_PKG} -p " . $ENV{"PKG_PATH"};
my $pswd = $emulabconfig{"PASSWORD"};
mysystem("cd $TBDIR/obj/testbed/install; ".
" perl boss-install $pkg -b -w ElabInElab");
#
# The above script wiped out the outer emulab root ssh pub keys from ops.
# We want to add them back so we can ssh into the node from outer Emulab.
#
mysystem("cat /root/.ssh/authorized_keys | ssh " . $emulabconfig{"OPSIP"} .
" '(cat >> /root/.ssh/authorized_keys)'");
mysystem("cat /root/.ssh/authorized_keys | ssh " . $emulabconfig{"FSIP"} .
" '(cat >> /root/.ssh/authorized_keys)'")
if ($emulabconfig{"OPSIP"} ne $emulabconfig{"FSIP"} && !$isfs);
" perl emulab-install $pkg -b -w $pswd boss");
#
# Need to tweak mrouted.conf as appropriate for an inner-elab
......@@ -2078,16 +2089,6 @@ sub SetupBossNode($)
mysystem("echo 'phyint $outer_controlif force_leaf noflood deny 0/0 bidir' >> /usr/local/etc/mrouted.conf");
}
#
# XXX Remove conflicting package installed by boss-install.
# This can go away when the emulab-boss port has been updated.
#
if ($FBSD_VERSION >= 6) {
print "Removing conflicting bind package.\n";
system("pkg_delete -r -x bind9")
if (-e "/usr/local/sbin/rndc");
}
#
# Before we restart named, tweak the config to reflect the correct
# NTP server for the inner nodes.
......@@ -2097,12 +2098,6 @@ sub SetupBossNode($)
$ndbfile = "${domain}.internal.db.head";
mysystem("sed -i '.orig' -E -e 's/^(ntp[12])[[:space:]]+IN[[:space:]]+CNAME[[:space:]]+ops/\\1 IN CNAME $NTPSERVER/' /etc/namedb/$ndbfile");
#
# Setup up MFSes in /tftpboot. Must be done after boss-install as
# it needs the inner .pem files.
#
SetupMFS($stuffdir);
#
# Copy the creators ssl certificate into place. This allows the
# inner boss to invoke the XMLRPC server on the outer boss for
......@@ -2110,6 +2105,9 @@ sub SetupBossNode($)
#
mysystem("cp -p $stuffdir/emulab.pem $RPCCERT");
goto skipsetup
if ($emulabconfig{"CONFIG_NODBINIT"});
#
# Set up a bunch of DB stuff. This part will eventually be optional,
# resulting in a naked setup that will need to be configured the rest of
......@@ -2373,7 +2371,7 @@ sub SetupOpsJail()
#
# Load up packages if necessary
#
if (!$emulabconfig{"CONFIG_NOSETUP"} && $installpkgs) {
if ($installpkgs) {
#
# Do this as a separate step because PKG_DIR might be an NFS path,
# but we must do the NFS unmounts before running ops-install.
......@@ -2791,12 +2789,8 @@ sub CreateDefsFile($)
last SWITCH;
};
/^PROTOGENI_SUPPORT$/ && do {
if ($emulabconfig{"LOAD_PROTOGENI"} && $FBSD_VERSION >= 6.2) {
print OUTDEFS "PROTOGENI_SUPPORT=1\n";
}
else {
print OUTDEFS "PROTOGENI_SUPPORT=0\n";
}
# Does not work to turn this on during initial setup.
print OUTDEFS "PROTOGENI_SUPPORT=0\n";
last SWITCH;
};
/^FSDIR_SCRATCH$/ && do {
......@@ -2874,101 +2868,6 @@ sub CreateDefsFile($)
mysystem("mv -f /tmp/defs-elabinelab $defsfile");
}
sub SetupMFS($)
{
my ($stuffdir) = @_;
if ($emulabconfig{"LOAD_MFS"}) {
#
# Unpack the tftpboot directory. It would be nice if this was part
# of boss install too.
#
print "Copying over tftpboot tar file from web server and unpacking\n";
mysystem("wget -q -O $stuffdir/tftpboot.tar.gz ".
"http://$bossname/downloads/".
$emulabconfig{"MFSTARBALL"});
mysystem("tar xzf $stuffdir/tftpboot.tar.gz -C /tftpboot");
#
# Its the generic stuff; must localize.
#
my $fv = $emulabconfig{"MFSVERSION"};
if (! -e "/tftpboot/freebsd${fv}") {
$fv = "47";
}
my $pdir = ".";
if (-d "/tftpboot/pxeboot${fv}") {
$pdir = "pxeboot${fv}";
}
my $cons = $emulabconfig{"MFSCONSOLE"};
if (! -e "/tftpboot/$pdir/pxeboot.emu-${cons}") {
$cons = "sio";
}
mysystem("cd /tftpboot; mv $pdir/pxeboot.emu-${cons} pxeboot.emu");
print "Using ${cons} version of pxeboot...\n";
mysystem("cd /tftpboot; mv freebsd${fv} freebsd");
print "Using freebsd${fv} version of admin MFS...\n";
mysystem("cd /tftpboot; mv frisbee${fv} frisbee");
print "Using frisbee${fv} version of disk load MFS...\n";
#
# Older tarballs didn't have FBSD-specific versions of newnode MFS.
#
if (! -e "/tftpboot/freebsd.newnode") {
$fv = $emulabconfig{"MFSVERSION"};
if (! -e "/tftpboot/freebsd${fv}.newnode") {
$fv = "47";
}
mysystem("cd /tftpboot; mv freebsd${fv}.newnode freebsd.newnode");
print "Using freebsd${fv}.newnode version of newnode MFS...\n";
}
}
#
# Copy the inner SSL cert and root's public ssh keys to the MFSes
# so that they will talk to the inner boss properly.
# At Berkeley the frisbee MFS copies these to disk images,
# needing changes to slicefix, which always needs to be run now.
#
MungeMfsRoot("frisbee");
MungeMfsRoot("freebsd");
MungeMfsRoot("freebsd.newnode");
#
# Finally, create the compressed versions of the MFS files
#
mysystem("cd /tftpboot/frisbee/boot; ./prepare; ".
"cd /tftpboot/freebsd/boot; ./prepare; ".
"cd /tftpboot/freebsd.newnode/boot; ./prepare");
}
sub MungeMfsRoot($)
{
my $tftpdir = shift;
my ($mount, $release);
if ($FBSD_VERSION >= 5) {
$mount = "mdconfig -a -t vnode -f mfsroot -u 2; mount /dev/md2 /mnt;";
$release = "mdconfig -d -u 2;";
}
else {
$mount = "vnconfig -c vn1 mfsroot; mount /dev/vn1 /mnt;";
$release = "vnconfig -u vn1;";
}
# XXX assumes our caller will recompress the mfsrootball.
mysystem("cd /tftpboot/$tftpdir/boot; " .
$mount .
"cd /usr/testbed/etc;" .
"cat /root/.ssh/*.pub >> /mnt/root/.ssh/authorized_keys2;" .
"cp -p emulab.pem client.pem /mnt/etc/emulab;" .
"umount /mnt;" .
$release);
}
#
# Print error and exit.
#
......
......@@ -7260,7 +7260,7 @@ fi
outfiles="$outfiles Makeconf GNUmakefile \
assign/GNUmakefile \
named/GNUmakefile firewall/GNUmakefile \
ssl/GNUmakefile ssl/mksig ssl/usercert.cnf \
ssl/GNUmakefile ssl/mksig ssl/usercert.cnf ssl/mkserial \
capture/GNUmakefile \
db/GNUmakefile \
db/EmulabConstants.pm db/EmulabFeatures.pm db/Experiment.pm \
......@@ -7409,7 +7409,7 @@ outfiles="$outfiles Makeconf GNUmakefile \
flash/GNUmakefile \
dhcpd/dhcpd.conf.template dhcpd/GNUmakefile \
dhcpd/dhcpd.conf.subboss.template \
install/GNUmakefile \
install/GNUmakefile install/installvars.pm install/emulab-install \
install/ops-install install/boss-install install/fs-install \
install/load-descriptors install/dump-descriptors \
install/newnode_sshkeys/GNUmakefile install/smb.conf.head \
......
......@@ -964,7 +964,7 @@ AC_SUBST(MERGE_BUILD_SANDBOX)
outfiles="$outfiles Makeconf GNUmakefile \
assign/GNUmakefile \
named/GNUmakefile firewall/GNUmakefile \
ssl/GNUmakefile ssl/mksig ssl/usercert.cnf \
ssl/GNUmakefile ssl/mksig ssl/usercert.cnf ssl/mkserial \
capture/GNUmakefile \
db/GNUmakefile \
db/EmulabConstants.pm db/EmulabFeatures.pm db/Experiment.pm \
......@@ -1113,7 +1113,7 @@ outfiles="$outfiles Makeconf GNUmakefile \
flash/GNUmakefile \
dhcpd/dhcpd.conf.template dhcpd/GNUmakefile \
dhcpd/dhcpd.conf.subboss.template \
install/GNUmakefile \
install/GNUmakefile install/installvars.pm install/emulab-install \
install/ops-install install/boss-install install/fs-install \
install/load-descriptors install/dump-descriptors \
install/newnode_sshkeys/GNUmakefile install/smb.conf.head \
......
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2011 University of Utah and the Flux Group.
# Copyright (c) 2000-2012 University of Utah and the Flux Group.
# All rights reserved.
#
......@@ -13,7 +13,8 @@ include $(OBJDIR)/Makeconf
ifeq ($(STANDALONE_CLEARINGHOUSE),0)
TARGETS = libinstall.pm boss-install ops-install fs-install dump-descriptors \
load-descriptors update-install update-mfs update-testbed testbed-version
load-descriptors update-install update-mfs update-testbed testbed-version \
update-ipdomain installvars.pm emulab-install
else
TARGETS = clrhouse-install
endif
......@@ -27,10 +28,10 @@ all: $(TARGETS)
include $(TESTBED_SRCDIR)/GNUmakerules
install: $(INSTALL_LIBDIR)/libinstall.pm \
$(INSTALL_LIBDIR)/installvars.pm \
$(INSTALL_SBINDIR)/update-install \
$(INSTALL_SBINDIR)/update-testbed \
$(INSTALL_SBINDIR)/testbed-version
clean:
rm -f boss-install ops-install fs-install update-install
rm -f update-testbed
rm -f $(TARGETS)
This diff is collapsed.
#!/usr/bin/perl -w
#
# EMULAB-COPYRIGHT
# Copyright (c) 2010-2012 University of Utah and the Flux Group.
# All rights reserved.
#
use strict;
use English;
use Getopt::Std;
use Data::Dumper;
#
# Install Emulab.
#
sub usage()
{
print STDERR "Usage: emulab-install [-c] [-i script] boss|ops|fs\n";
print STDERR
"-c - Syntax check install scripts by loading them only\n" .
"-i <name> - Run (or check) just the one install script\n" .
"-b - Batch mode, do not ask for confirmation\n" .
"-s - Turn on makes. Huh?\n" .
"-P|-F - Set the name of the boss/ops and fs port\n" .
"-w <pswd> - Provide password instead of being asked for it\n" .
"-p <dir> - Set the package directory\n";
exit(-1);
}
my $optlist = "dsi:p:qcbP:F:w:nu";
my $debug = 0;
my $single = 0;
my $quiet = 0;
my $check = 0;
my $impotent = 0;
my $updatemode = 0;
my $batchmode = 0;
my $phasepath = "@srcdir@/phases";
my $phase;
#
# Configure variables
#
my $TB = "@prefix@";
my $TBOPS = "@TBOPSEMAIL@";
my $logfile = "/var/tmp/emulab-install.log";
my $logfp;
# Protos
sub Fatal($);
# un-taint path
$ENV{'PATH'} = '/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/site/bin';
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
#
# Turn off line buffering on output
#
$| = 1;
use libinstall;
use installvars;
#
# Parse command arguments.
#
my %options = ();
if (! getopts($optlist, \%options)) {
usage();
}
if (defined($options{"d"})) {
$debug = 1;
}
if (defined($options{"b"})) {
$batchmode = 1;
}
if (defined($options{"c"})) {
$check = 1;
}
if (defined($options{"n"})) {
$impotent = 1;
}
if (defined($options{"q"})) {
$quiet = 1;
}
if (defined($options{"u"})) {
$updatemode = 1;
}
if (defined($options{w})) {
$password = $options{w};
}
if (defined($options{"p"})) {
$packagedir = $options{"p"};
}
if (defined($options{"i"})) {
$single = 1;
$phase = $options{"i"};
}
if (defined($options{"s"})) {
$domakes = 1;
}
if (defined($options{"F"})) {
$FS_PORT = $options{"F"};
}
if (@ARGV != 1) {
usage();
}
# Don't just charge into making ports from source by default.
if (!($check || $single || $impotent || $updatemode) &&
$packagedir eq "" && $domakes eq 0) {
print "At least one of -p and -s must be given.\n";
usage();
}
if (!($check || $single || $impotent || $updatemode) &&
$packagedir ne "" && $domakes eq 1) {
print "Only one of -p and -s can be given.\n";
usage();
}
my $server = $ARGV[0];
usage()
if (! ($server eq $BOSS_SERVERNAME ||
$server eq $OPS_SERVERNAME ||
$server eq $FS_SERVERNAME));
# Do this after we know the server name.
if (defined($options{"P"})) {
if ($server eq "boss") {
$BOSS_PORT = $options{"P"};
}
else {
$OPS_PORT = $options{"P"};
}
}
#
# Must be root if actually doing this.
#
if ($UID && !($check || $impotent)) {
Fatal("This script must be run as root! Maybe use sudo?")
}
#
# Make sure they know what they're getting into...
#
if (! ($batchmode || $check || $impotent)) {
if ($updatemode) {
print STDERR
"WARNING: This script is ONLY intended to be run your $server node,\n".
"and only if you are updating the IP addresses/subnet and/or the\n",
"domain name of your installation. Continue? [y/N] ";
}
else {
print STDERR
"WARNING: This script is ONLY intended to be run on a machine\n".
"that is being set up as a dedicated $server node. Continue? [y/N] ";
}
my $response = <STDIN>;
die "Aborted!\n" unless ($response =~ /^y/i);
}
if ($impotent) {
open(LOGFP, "> $logfile")
or Fatal("Could not open $logfile");
$logfp = *LOGFP;
SET_IMPOTENT_MODE($logfp);
}
#
# Very simple list of files. Be fancy later.
#
my @files = ();
if ($single) {
# Just the one file.
@files = ($phase);
}
elsif ($server eq "boss") {
@files = ('sperl', 'usersgroups', 'dirs', 'tftp',
'boss/ports', 'boss/portfix', 'boss/patches', 'cracklib',
'apache', 'boss/rcfiles', 'boss/rcconf', 'boss/syslog',
'boss/database', 'etchosts', 'resolvetest',
'exports', 'nfsmounts', 'boss/mibs', 'boss/crontab', 'sudoers',
'boss/ssh', 'boss/rndc', 'boss/loaderconf', 'boss/sysctlconf',
'boss/sslcerts', 'boss/mailman', 'boss/pubsub',
'boss/software',
#
# The next few items must be after the software install since
# they use testbed libraries and such.
#
'boss/dhcpd', 'boss/named', 'boss/flyspray',
'boss/firstuser', 'boss/checkupuser', 'boss/wikidocs',
'boss/experiments',
);
}
elsif ($server eq "fs") {
@files = ('sperl', 'dirs',
'fs/ports', 'fs/portfix', 'ops/rcconf',
'etchosts', 'resolvetest', 'exports', 'quotas', 'sudoers',
'samba', 'ops/ssh');
}
elsif ($server eq "ops") {
@files = ('sperl', 'usersgroups', 'dirs', 'etchosts', 'resolvetest',
'ops/ports', 'ops/portfix', 'ops/patches', 'ops/rcconf',
'ops/sendmail', 'exports', 'nfsmounts', 'ops/syslog',
'ops/crontab', 'sudoers', 'samba', 'ops/ssh', 'capture',
'ops/rcfiles', 'apache', 'ops/database', 'ops/mailman',
'ops/cvsd', 'ops/flyspray', 'ops/twiki');
}
#
# In update mode, we want to run etchosts at the very end.
#
if ($updatemode) {
push(@files, "boss/update-ipdomain")
if ($server eq $BOSS_SERVERNAME);
@files = grep(!/^etchosts$/, @files);
push(@files, "etchosts");