Commit f94fc9a2 authored by Leigh B. Stoller's avatar Leigh B. Stoller
Browse files

Move libsetup.pm down to common directory where it belongs. Note, I did

this by moving (well, copying) the rcs file in the CVS tree so that we do
not lose the history.
parent 13e6b16a
......@@ -49,6 +49,10 @@ tmcc: tmcc.c decls.h $(SSLOBJ)
$(CC) $(CFLAGS) $(SSLFLAGS) -static -g -o tmcc $< $(SSLOBJ) \
$(LFLAGS) $(TMLIBS)
tmcc-shared: tmcc.c decls.h $(SSLOBJ)
$(CC) $(CFLAGS) $(SSLFLAGS) -g -o tmcc $< $(SSLOBJ) \
$(LFLAGS) $(TMLIBS)
tmcc-nossl: tmcc.c decls.h
$(CC) $(CFLAGS) -static -g -o tmcc-nossl $< $(LFLAGS)
......
......@@ -64,7 +64,7 @@ path-install: dir-install
$(INSTALL) -m 755 $(SRCDIR)/paths.sh $(ETCDIR)/paths.sh
common-script-install: dir-install
$(INSTALL) -m 755 $(SRCDIR)/../libsetup.pm $(BINDIR)/libsetup.pm
$(INSTALL) -m 755 $(SRCDIR)/libsetup.pm $(BINDIR)/libsetup.pm
$(INSTALL) -m 755 $(SRCDIR)/libtmcc.pm $(BINDIR)/libtmcc.pm
$(INSTALL) -m 755 $(SRCDIR)/libtestbed.pm $(BINDIR)/libtestbed.pm
$(INSTALL) -m 755 $(SRCDIR)/tmcc.pl $(BINDIR)/tmcc
......@@ -105,6 +105,6 @@ remote-script-install: common-script-install
-chmod u+s $(BINDIR)/vnodesetup
control-script-install: dir-install
$(INSTALL) -m 755 $(SRCDIR)/../libsetup.pm $(BINDIR)/libsetup.pm
$(INSTALL) -m 755 $(SRCDIR)/libsetup.pm $(BINDIR)/libsetup.pm
$(INSTALL) -m 755 $(SRCDIR)/watchdog $(BINDIR)/watchdog
$(INSTALL) -m 755 $(SRCDIR)/update $(BINDIR)/update
#!/usr/bin/perl -wT
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2003 University of Utah and the Flux Group.
# All rights reserved.
#
# TODO: Signal handlers for protecting db files.
#
# Common routines and constants for the client bootime setup stuff.
#
package libsetup;
use Exporter;
@ISA = "Exporter";
@EXPORT =
qw ( libsetup_init libsetup_setvnodeid libsetup_settimeout cleanup_node
doifconfig dohostnames domounts dotunnels check_nickname
doaccounts dorpms dotarballs dostartupcmd install_deltas
bootsetup nodeupdate startcmdstatus whatsmynickname dosyncserver
TBBackGround TBForkCmd vnodejailsetup plabsetup vnodeplabsetup
dorouterconfig jailsetup dojailconfig JailedMounts findiface
tmcctimeout libsetup_getvnodeid dotrafficconfig dosimulatorconfig
ixpsetup dokeyhash donodeid libsetup_refresh
MFS REMOTE JAILED PLAB LOCALROOTFS IXP
CONFDIR TMCC TMIFC TMDELAY TMRPM TMTARBALLS TMHOSTS TMJAILNAME
TMNICKNAME HOSTSFILE TMSTARTUPCMD FINDIF TMTUNNELCONFIG
TMTRAFFICCONFIG TMROUTECONFIG TMLINKDELAY TMDELMAP TMMOUNTDB
TMPROGAGENTS TMPASSDB TMGROUPDB TMGATEDCONFIG
TMSYNCSERVER TMRCSYNCSERVER TMKEYHASH TMNODEID TMEVENTKEY
);
# Must come after package declaration!
use English;
# The tmcc library.
use libtmcc;
#
# This is the VERSION. We send it through to tmcd so it knows what version
# responses this file is expecting.
#
# BE SURE TO BUMP THIS AS INCOMPATIBILE CHANGES TO TMCD ARE MADE!
#
sub TMCD_VERSION() { 14; };
libtmcc::configtmcc("version", TMCD_VERSION());
# Control tmcc timeout.
sub libsetup_settimeout($) { libtmcc::configtmcc("timeout", $_[0]); };
# Redresh tmcc cache.
sub libsetup_refresh() { libtmcc::tmccgetconfig(); };
#
# For virtual (multiplexed nodes). If defined, tack onto tmcc command.
# and use in pathnames. Used in conjunction with jailed virtual nodes.
# I am also using this for subnodes; eventually everything will be subnodes.
#
my $vnodeid;
sub libsetup_setvnodeid($)
{
my ($vid) = @_;
if ($vid =~ /^([-\w]+)$/) {
$vid = $1;
}
else {
die("Bad data in vnodeid: $vid");
}
$vnodeid = $vid;
libtmcc::configtmcc("subnode", $vnodeid);
}
sub libsetup_getvnodeid()
{
return $vnodeid;
}
#
# True if running inside a jail. Set just below.
#
my $injail;
#
# True if running in a Plab vserver.
#
my $inplab;
#
# Ditto for IXP, although currently there is no "in" IXP setup; it
# is all done from outside.
#
my $inixp;
#
# The role of this pnode
#
my $role = "";
#
# Flag is true if simulator (NSE) based traffic generation is present
#
my $simtrafgen = 0;
#
# Inside, there might be a tmcc proxy socket.
#
my $tmccproxy;
# Load up the paths. Its conditionalized to be compatabile with older images.
# Note this file has probably already been loaded by the caller.
BEGIN
{
if (! -e "/etc/emulab/paths.pm") {
die("Yikes! Could not require /etc/emulab/paths.pm!\n");
}
require "/etc/emulab/paths.pm";
import emulabpaths;
#
# Determine if running inside a jail. This affects the paths below.
#
if (-e "$BOOTDIR/jailname") {
open(VN, "$BOOTDIR/jailname");
my $vid = <VN>;
close(VN);
libsetup_setvnodeid($vid);
$injail = 1;
#
# Temporary. Will move to tmcc library.
#
if (-e "$BOOTDIR/proxypath") {
open(PP, "$BOOTDIR/proxypath");
$tmccproxy = <PP>;
close(PP);
if ($tmccproxy =~ /^([-\w\.\/]+)$/) {
$tmccproxy = $1;
}
else {
die("Bad data in tmccproxy path: $tmccproxy");
}
}
}
# Determine if running inside a Plab vserver.
if (-e "$BOOTDIR/plabname") {
open(VN, "$BOOTDIR/plabname");
my $vid = <VN>;
close(VN);
libsetup_setvnodeid($vid);
$inplab = 1;
}
# Make sure these exist!
if (! -e "$VARDIR/logs") {
mkdir("$VARDIR", 0775);
mkdir("$VARDIR/jails", 0775);
mkdir("$VARDIR/db", 0755);
mkdir("$VARDIR/logs", 0775);
mkdir("$VARDIR/boot", 0775);
mkdir("$VARDIR/lock", 0775);
}
}
#
# The init routine. This is deprecated, but left behind in case an old
# liblocsetup is run against a new libsetup. Whenever a new libsetup
# is installed, better install the path module (see above) too!
#
sub libsetup_init($)
{
my($path) = @_;
$ETCDIR = $path;
$BINDIR = $path;
$VARDIR = $path;
$BOOTDIR = $path
}
#
# This "local" library provides the OS dependent part.
#
use liblocsetup;
#
# These are the paths of various files and scripts that are part of the
# setup library.
#
sub TMCC() { "$BINDIR/tmcc"; }
sub TMHOSTS() { "$ETCDIR/hosts"; }
sub FINDIF() { "$BINDIR/findif"; }
sub HOSTSFILE() { "/etc/hosts"; }
#
# This path is valid only *outside* the jail when its setup.
#
sub JAILDIR() { "$VARDIR/jails/$vnodeid"; }
#
# Also valid outside the jail, this is where we put local project storage.
#
sub LOCALROOTFS() { (REMOTE() ? "/users/local" : "$VARDIR/jails/local");}
#
# Okay, here is the path mess. There are three environments.
# 1. A local node where everything goes in one place ($VARDIR/boot).
# 2. A virtual node inside a jail or a Plab vserver ($VARDIR/boot).
# 3. A virtual (or sub) node, from the outside.
#
# As for #3, whether setting up a old-style virtual node or a new style
# jailed node, the code that sets it up needs a different per-vnode path.
#
sub CONFDIR() {
if ($injail || $inplab) {
return $BOOTDIR;
}
if ($vnodeid) {
return JAILDIR();
}
return $BOOTDIR;
}
#
# These go in /var/emulab. Good for all environments!
#
sub TMMOUNTDB() { $VARDIR . "/db/mountdb"; }
sub TMSFSMOUNTDB() { $VARDIR . "/db/sfsmountdb"; }
sub TMPASSDB() { $VARDIR . "/db/passdb"; }
sub TMGROUPDB() { $VARDIR . "/db/groupdb"; }
#
# The rest of these depend on the environment running in (inside/outside jail).
#
sub TMNICKNAME() { CONFDIR() . "/nickname";}
sub TMJAILNAME() { CONFDIR() . "/jailname";}
sub TMJAILCONFIG() { CONFDIR() . "/jailconfig";}
sub TMPLABCONFIG() { CONFDIR() . "/rc.plab";}
sub TMSTARTUPCMD() { CONFDIR() . "/startupcmd";}
sub TMPROGAGENTS() { CONFDIR() . "/progagents";}
sub TMIFC() { CONFDIR() . "/rc.ifc"; }
sub TMRPM() { CONFDIR() . "/rc.rpm";}
sub TMTARBALLS() { CONFDIR() . "/rc.tarballs";}
sub TMROUTECONFIG() { CONFDIR() . "/rc.route";}
sub TMGATEDCONFIG() { CONFDIR() . "/gated.conf";}
sub TMTRAFFICCONFIG() { CONFDIR() . "/rc.traffic";}
sub TMSIMULATORCONFIG() { CONFDIR() . "/rc.simulator";}
sub TMTUNNELCONFIG() { CONFDIR() . "/rc.tunnel";}
sub TMVTUNDCONFIG() { CONFDIR() . "/vtund.conf";}
sub TMDELAY() { CONFDIR() . "/rc.delay";}
sub TMLINKDELAY() { CONFDIR() . "/rc.linkdelay";}
sub TMDELMAP() { CONFDIR() . "/delay_mapping";}
sub TMSYNCSERVER() { CONFDIR() . "/syncserver";}
sub TMRCSYNCSERVER() { CONFDIR() . "/rc.syncserver";}
sub TMKEYHASH() { CONFDIR() . "/keyhash";}
sub TMEVENTKEY() { CONFDIR() . "/eventkey";}
sub TMNODEID() { CONFDIR() . "/nodeid";}
#
# Whether or not to use SFS (the self-certifying file system). If this
# is 0, fall back to NFS. Note that it doesn't hurt to set this to 1
# even if TMCD is not serving out SFS mounts, or if this node is not
# running SFS. It'll deal and fall back to NFS.
#
my $USESFS = 1;
#
# Some things never change.
#
my $TARINSTALL = "/usr/local/bin/install-tarfile %s %s %s";
my $RPMINSTALL = "/usr/local/bin/install-rpm %s %s";
my $VTUND = "/usr/local/sbin/vtund";
#
# This is a debugging thing for my home network.
#
my $NODE = "";
if (defined($ENV{'TMCCARGS'})) {
if ($ENV{'TMCCARGS'} =~ /^([-\w\s]*)$/) {
$NODE .= " $1";
}
else {
die("Tainted TMCCARGS from environment: $ENV{'TMCCARGS'}!\n");
}
}
# Locals
my $pid = "";
my $eid = "";
my $vname = "";
# When on the MFS, we do a much smaller set of stuff.
# Cause of the way the packages are loaded (which I do not understand),
# this is computed on the fly instead of once.
sub MFS() { if (-e "$ETCDIR/ismfs") { return 1; } else { return 0; } }
#
# Same for a remote node.
#
sub REMOTE() { if (-e "$ETCDIR/isrem") { return 1; } else { return 0; } }
#
# Same for a control node.
#
sub CONTROL() { if (-e "$ETCDIR/isctrl") { return 1; } else { return 0; } }
#
# Are we jailed? See above.
#
sub JAILED() { if ($injail) { return $vnodeid; } else { return 0; } }
#
# Are we on plab?
#
sub PLAB() { if ($inplab) { return $vnodeid; } else { return 0; } }
#
# Are we on an IXP
#
sub IXP() { if ($inixp) { return $vnodeid; } else { return 0; } }
#
# Are we hosting a simulator
#
sub SIMHOST() { if ($role eq "simhost") { return 1; } else { return 0; } }
#
# Do not try this on the MFS since it has such a wimpy perl installation.
#
if (!MFS()) {
require Socket;
import Socket;
}
#
# Reset to a moderately clean state.
#
sub cleanup_node ($) {
my ($scrub) = @_;
print STDOUT "Cleaning node; removing configuration files ...\n";
unlink TMIFC, TMRPM, TMSTARTUPCMD, TMTARBALLS;
unlink TMROUTECONFIG, TMTRAFFICCONFIG, TMTUNNELCONFIG;
unlink TMDELAY, TMLINKDELAY, TMPROGAGENTS, TMSYNCSERVER, TMRCSYNCSERVER;
unlink TMMOUNTDB . ".db";
unlink TMSFSMOUNTDB . ".db";
unlink "$VARDIR/db/rtabid";
unlink TMKEYHASH, TMEVENTKEY;
#
# If scrubbing, remove the password/group file DBs so that we revert
# to base set.
#
if ($scrub) {
unlink TMNICKNAME;
unlink TMPASSDB . ".db";
unlink TMGROUPDB . ".db";
}
if (! REMOTE()) {
printf STDOUT "Resetting %s file\n", HOSTSFILE;
if (system($CP, "-f", TMHOSTS, HOSTSFILE) != 0) {
printf "Could not copy default %s into place: $!\n", HOSTSFILE;
exit(1);
}
}
return os_cleanup_node($scrub);
}
#
# Check node allocation. If the nickname file has been created, use
# that to avoid load on tmcd.
#
# Returns 0 if node is free. Returns list (pid/eid/vname) if allocated.
#
sub check_status ()
{
my @tmccresults;
if (tmcc(TMCCCMD_STATUS, undef, \@tmccresults) < 0) {
warn("*** WARNING: Could not get status from server!\n");
return -1;
}
#
# This is possible if the boss node does not now about us yet.
# We want to appear free. Specifically, it could happen on the
# MFS when trying to bring in brand new nodes. tmcd will not know
# anything about us, and return no info.
#
return 0
if (! @tmccresults);
my $status = $tmccresults[0];
if ($status =~ /^FREE/) {
unlink TMNICKNAME;
return 0;
}
if ($status =~ /ALLOCATED=([-\@\w]*)\/([-\@\w]*) NICKNAME=([-\@\w]*)/) {
$pid = $1;
$eid = $2;
$vname = $3;
}
else {
warn "*** WARNING: Error getting reservation status\n";
return -1;
}
#
# Stick our nickname in a file in case someone wants it.
# Do not overwrite; we want to save the original info until later.
# See bootsetup; indicates project change!
#
if (! -e TMNICKNAME()) {
system("echo '$vname.$eid.$pid' > " . TMNICKNAME());
}
return ($pid, $eid, $vname);
}
#
# Check cached nickname. Its okay if we have been deallocated and the info
# is stale. The node will notice that later.
#
sub check_nickname()
{
if (-e TMNICKNAME) {
my $nickfile = TMNICKNAME;
my $nickinfo = `cat $nickfile`;
if ($nickinfo =~ /([-\@\w]*)\.([-\@\w]*)\.([-\@\w]*)/) {
$vname = $1;
$eid = $2;
$pid = $3;
return ($pid, $eid, $vname);
}
}
return check_status();
}
#
# Process mount directives from TMCD. We keep track of all the mounts we
# have added in here so that we delete just the mounts we added, when
# project membership changes. Same goes for project directories on shared
# nodes. We use a simple perl DB for that.
#
sub domounts()
{
my %MDB;
my %mounts;
my %deletes;
my %sfsmounts;
my %sfsdeletes;
my @tmccresults;
if (tmcc(TMCCCMD_MOUNTS, undef , \@tmccresults) < 0) {
warn("*** WARNING: Could not get mount list from server!\n");
return -1;
}
foreach my $str (@tmccresults) {
if ($str =~ /^REMOTE=([-:\@\w\.\/]+) LOCAL=([-\@\w\.\/]+)/) {
$mounts{$1} = $2;
}
elsif ($str =~ /^SFS REMOTE=([-:\@\w\.\/]+) LOCAL=([-\@\w\.\/]+)/) {
$sfsmounts{$1} = $2;
}
else {
warn "*** WARNING: Malformed mount information: $str\n";
}
}
#
# The MFS version does not support (or need) this DB stuff. Just mount
# them up.
#
if (MFS()) {
while (($remote, $local) = each %mounts) {
if (! -e $local) {
if (! os_mkdir($local, "0770")) {
warn "*** WARNING: Could not make directory $local: $!\n";
next;
}
}
print STDOUT " Mounting $remote on $local\n";
if (system("$NFSMOUNT $remote $local")) {
warn "*** WARNING: Could not $NFSMOUNT ".
"$remote on $local: $!\n";
next;
}
}
return 0;
}
dbmopen(%MDB, TMMOUNTDB, 0660);
#
# First mount all the mounts we are told to. For each one that is not
# currently mounted, and can be mounted, add it to the DB.
#
while (($remote, $local) = each %mounts) {
if (defined($MDB{$remote})) {
next;
}
if (! -d $local) {
# Leftover SFS link.
if (-l $local) {
unlink($local) or
warn "*** WARNING: Could not unlink $local: $!\n";
}
if (! os_mkdir($local, "0770")) {
warn "*** WARNING: Could not make directory $local: $!\n";
next;
}
}
print STDOUT " Mounting $remote on $local\n";
if (system("$NFSMOUNT $remote $local")) {
warn "*** WARNING: Could not $NFSMOUNT $remote on $local: $!\n";
next;
}
$MDB{$remote} = $local;
}
#
# Now unmount the ones that we mounted previously, but are now no longer
# in the mount set (as told to us by the TMCD). Note, we cannot delete
# them directly from MDB since that would mess up the foreach loop, so
# just stick them in temp and postpass it.
#
while (($remote, $local) = each %MDB) {
if (defined($mounts{$remote})) {
next;
}
print STDOUT " Unmounting $local\n";
if (system("$UMOUNT $local")) {
warn "*** WARNING: Could not unmount $local\n";
next;
}
#
# Only delete from set if we can actually unmount it. This way
# we can retry it later (or next time).
#
$deletes{$remote} = $local;
}
while (($remote, $local) = each %deletes) {
delete($MDB{$remote});
}
# Write the DB back out!
dbmclose(%MDB);
#
# Now, do basically the same thing over again, but this time for
# SFS mounted stuff
#
if (scalar(%sfsmounts)) {
dbmopen(%MDB, TMSFSMOUNTDB, 0660);
#
# First symlink all the mounts we are told to. For each one
# that is not currently symlinked, and can be, add it to the
# DB.
#
while (($remote, $local) = each %sfsmounts) {
if (-l $local) {
if (readlink($local) eq ("/sfs/" . $remote)) {
$MDB{$remote} = $local;
next;
}
if (readlink($local) ne ("/sfs/" . $remote)) {
print STDOUT " Unlinking incorrect symlink $local\n";
if (! unlink($local)) {
warn "*** WARNING: Could not unlink $local: $!\n";
next;
}
}
}
elsif (-d $local) {
if (! rmdir($local)) {
warn "*** WARNING: Could not rmdir $local: $!\n";
next;
}
}
$dir = $local;
$dir =~ s/(.*)\/[^\/]*$/$1/;
if ($dir ne "" && ! -e $dir) {
print STDOUT " Making directory $dir\n";
if (! os_mkdir($dir, "0755")) {
warn "*** WARNING: Could not make directory $local: $!\n";
next;
}
}