boss-install.in 22.7 KB
Newer Older
1 2 3 4
#!/usr/bin/perl -w

#
# EMULAB-COPYRIGHT
5
# Copyright (c) 2003, 2004 University of Utah and the Flux Group.
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
# All rights reserved.
#

#
# install-boss.sh - Script to do the initial install of a boss node
#
# The main things it does not do yet:
# * Figure out where to put directories such as /usr/testbed - they must
#   already exist
# * Set up named - we probably have to do that later, when the interfaces table
#   is filled in
# * Set up a sup tree. Not sure what the right thing to do here is!
# * Doesn't do anything about SSL certificates for the web

#
# Configure variables
#
my $PREFIX     = '@prefix@';
my $SRCDIR     = '@srcdir@';
my $TOP_SRCDIR = '@top_srcdir@';
my $DBNAME     = "@TBDBNAME@";

my $OURDOMAIN  = '@OURDOMAIN@';

30 31
my $LOGFACIL   = '@TBLOGFACIL@';

32 33 34 35 36 37 38 39 40 41
my $USERNODE   = '@USERNODE@';
my $FSNODE     = '@FSNODE@';
my $BOSSNODE   = '@BOSSNODE@';

#
# Some programs we use
#
my $SH         = "/bin/sh";
my $CHMOD      = "/bin/chmod";
my $CHGRP      = "/usr/bin/chgrp";
42
my $CHOWN      = "/usr/sbin/chown";
43 44 45 46 47
my $PWD        = "/bin/pwd";
my $PW         = "/usr/sbin/pw";
my $PATCH      = "/usr/bin/patch";
my $SSH_KEYGEN = "/usr/bin/ssh-keygen";
my $PKG_INFO   = "/usr/sbin/pkg_info";
48
my $PKG_ADD    = "/usr/sbin/pkg_add";
49
my $TOUCH      = "/usr/bin/touch";
50
my $SSH        = "/usr/bin/ssh";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
51
my $SCP        = "/usr/bin/scp";
52
my $CP         = "/bin/cp";
53
my $ENV        = "/usr/bin/env";
54
my $MOUNT      = "/sbin/mount";
55 56 57 58 59 60 61 62 63 64

my $SUIDPERL   = "/usr/bin/suidperl";

my $MYSQL      = "/usr/local/bin/mysql";
my $MYSQLADMIN = "/usr/local/bin/mysqladmin";
my $MYSQLSHOW  = "/usr/local/bin/mysqlshow";
my $MYSQLDUMP  = "/usr/local/bin/mysqldump";

my $GMAKE      = "/usr/local/bin/gmake";

Robert Ricci's avatar
Robert Ricci committed
65
my $RNDC_CONFGEN = "/usr/local/sbin/rndc-confgen";
66

67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
#
# Some files we edit/create
#
my $CRONTAB         = "/etc/crontab";
my $FSTAB           = "/etc/fstab";
my $RCCONF          = "/etc/rc.conf";
my $SYSLOG_CONF     = "/etc/syslog.conf";
my $NEWSYSLOG_CONF  = "/etc/newsyslog.conf";

my $ROOT_PRIVKEY    = "/root/.ssh/identity";
my $ROOT_PUBKEY     = "$ROOT_PRIVKEY.pub";
my $ROOT_AUTHKEY    = "/root/.ssh/authorized_keys";

my $SUDOERS         = "/usr/local/etc/sudoers";
my $HTTPD_CONF      = "/usr/local/etc/apache/httpd.conf";
Robert Ricci's avatar
Robert Ricci committed
82
my $PHP_INI         = "/usr/local/etc/php.ini";
83 84 85 86

my $CRACKLIB_DICT   = "/usr/local/lib/pw_dict.pwd";

my $STL_PATCH       = "$TOP_SRCDIR/patches/g++.patch";
87
my $M2CRYPTO_PATCH  = "$TOP_SRCDIR/patches/m2crypto.patch";
88
my $PHP4_PATCH      = "$TOP_SRCDIR/patches/php4-Makefile.patch";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
89
my $INIT_PRIVKEY    = "$TOP_SRCDIR/install/identity";
90

Robert Ricci's avatar
Robert Ricci committed
91 92
my $SSH_CONFIG      = "/etc/ssh/ssh_config";

93 94
my $RNDC_KEY        = "/usr/local/etc/rndc.key";

95 96
my $LOADER_CONF	    = "/boot/loader.conf";

97 98
my $SYSCTL_CONF	    = "/etc/sysctl.conf";

99
my $EMULAB_PEM	    = "emulab.pem";
100 101 102
my $CLIENT_PEM	    = "client.pem";
my $CTRLNODE_PEM    = "ctrlnode.pem";
my $ETC_EMULAB_DIR  = "/etc/emulab";
103

104 105 106
#
# Some directories we care about
#
107 108 109 110 111 112 113 114 115
my $LOGDIR        = "$PREFIX/log";
my $MYSQL_LOGDIR  = "$LOGDIR/mysql";
my $RCDIR         = "/usr/local/etc/rc.d";
my $USERSVAR_DIR  = "$PREFIX/usersvar";
my $OPSDIR_DIR    = "$PREFIX/opsdir";
my $PORTSDIR      = "/usr/ports/misc";
my $MIBPATH       = "/usr/local/share/snmp/mibs";
my $TFTP_DIR      = "$PREFIX/tftpboot";
my $TFTP_PROJ_DIR = "$TFTP_DIR/proj";
116 117 118 119 120 121 122 123 124 125 126

#
# URLs
#
my $CISCO_MIB_FTP = "ftp://ftp.cisco.com/pub/mibs/v2";

#
# And some lists that we use
#
my @TESTBED_DIRS = ($PREFIX);

Leigh B. Stoller's avatar
Leigh B. Stoller committed
127 128
my @MOUNTPOINTS = ("$PREFIX/usersvar", "$PREFIX/opsdir",
		   "/users", "/proj", "/groups", "/share");
Robert Ricci's avatar
Robert Ricci committed
129

130 131
my @LOGFILES = ("$LOGDIR/bootinfo.log", "$LOGDIR/tmcd.log",
    "$LOGDIR/capture.log", "$LOGDIR/dhcpd.log", "$LOGDIR/capserver.log",
132
    "$LOGDIR/frisbeed.log", "$LOGDIR/proxydhcpd.log",
133
    "$LOGDIR/elvind.log", "$LOGDIR/stated.log", "$LOGDIR/osselect.log",
134
    "$LOGDIR/tftpd.log", "$LOGDIR/sdcollectd.log", "$LOGDIR/genlastlog.log",
135
    "$LOGDIR/sshxmlrpc.log", "$LOGDIR/plabgetfree.log", "$LOGDIR/xmlrpcbag.log",
136
    "$LOGDIR/plabrenew.log", "$LOGDIR/sslxmlrpc.log");
137 138 139 140

my @CISCO_MIBS = ("CISCO-SMI", "CISCO-TC", "CISCO-VTP-MIB", "CISCO-PAGP-MIB",
    "CISCO-PRIVATE-VLAN-MIB", "CISCO-STACK-MIB", "CISCO-VLAN-MEMBERSHIP-MIB");

Robert Ricci's avatar
Robert Ricci committed
141 142
my @OPS_NAMES = ($FSNODE, $USERNODE);

143 144 145 146
#
# The meta-port (name and version) that drags in all the dependancies for
# a boss node
#
Robert Ricci's avatar
Robert Ricci committed
147
my $BOSS_PORT = "emulab-boss-1.7";
148

149 150 151 152 153 154 155 156
#
# Figure out which directory we live in, so that some stages can do thing
# relative to it.
#
my $OBJDIR = `/usr/bin/dirname $0`;
chomp $OBJDIR;
my $TOP_OBJDIR = "$OBJDIR/..";

157 158 159
my $ELVIND_CONF     = "/usr/local/etc/elvind.conf";
my $BOSS_ELVIND_CONF = "$TOP_OBJDIR/event/etc/elvind-boss.conf";

160 161 162 163 164 165 166
#
# Allow this to work if the library is left in the source directory
#
use lib '@srcdir@';
   
use English;
use libinstall;
167 168 169 170 171 172 173 174 175 176 177
use Getopt::Std;

#
# Handle command-line options
#
sub usage {
    print "Usage: ops-install [-p packagedir]\n";
    exit(1);
}

my $packagedir = "";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
178
my $batchmode  = 0;
179 180
my %opts;

Leigh B. Stoller's avatar
Leigh B. Stoller committed
181 182 183 184 185 186 187 188
if (! getopts("p:b", \%opts)) {
    usage();
}
if (defined($opts{p})) {
    $packagedir = $opts{p};
}
if (defined($opts{b})) {
    $batchmode = 1;
189 190 191 192 193
}

if (@ARGV) {
    usage();
}
194 195 196 197

#
# Make sure they know what they're getting into...
#
Leigh B. Stoller's avatar
Leigh B. Stoller committed
198 199 200 201 202 203 204 205 206 207
if (! $batchmode) {
    warn "***** Please run install-ops on ops, and reboot it, before running\n";
    warn "this script!\n\n";
    print STDERR
	"WARNING: This script is ONLY intended to be run on a machine\n";
    print STDERR
	"that is being set up as a dedicated boss node. Continue? [y/N] ";
    my $response = <>;
    die "Installation aborted!\n" unless ($response =~ /^y/i);
}
208 209 210 211 212

if ($UID != 0) {
    die "This script must be run as root.\n";
}

Leigh B. Stoller's avatar
Leigh B. Stoller committed
213
Phase "usersgroups", "Creating users and groups", sub {
214 215 216 217 218 219 220 221 222 223 224 225
    Phase "tbadmin", "Creating tbadmin group", sub {
	if (getgrnam("tbadmin")) {
	    PhaseSkip("tbadmin group already exists");
	}
	ExecQuietFatal("$PW groupadd tbadmin -g 101");
    };
    Phase "root", "Creating root group", sub {
	if (getgrnam("root")) {
	    PhaseSkip("root group already exists");
	}
	ExecQuietFatal("$PW groupadd root -g 103");
    };
Leigh B. Stoller's avatar
Leigh B. Stoller committed
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
    # Added next two cause the mysql package does not do this (port does).
    Phase "mysqlgroup", "Creating mysql group", sub {
	if (getgrnam("mysql")) {
	    PhaseSkip("mysql group already exists");
	}
	ExecQuietFatal("$PW groupadd mysql -g 88");
    };
    Phase "mysqluser", "Creating mysql user", sub {
	if (getpwnam("mysql")) {
	    PhaseSkip("mysql user already exists");
	}
	ExecQuietFatal("$PW useradd mysql -g 88 -g 88 -h - ".
		       "-d /var/db/mysql -s /sbin/nologin -c 'MySQL Daemon'");
	ExecQuietFatal("$CHOWN mysql:mysql /var/db/mysql");	
    };
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
};

Phase "dirs", "Setting directory permissions", sub {
    foreach my $dir (@TESTBED_DIRS) {
	Phase $dir, $dir, sub {
	    if (!-d $dir) {
		PhaseFail("Directory $dir does not exist");
	    }
	    my ($mode,$group) = (stat($dir))[2,5];
	    # Fix up the mode (strip file type)
	    $mode = $mode & 0777;
	    if ($mode == 0775 && $group eq getgrnam("tbadmin")) {
		PhaseSkip("Already done");
	    }
	    ExecQuietFatal("$CHGRP tbadmin $dir");
	    ExecQuietFatal("$CHMOD 0775 $dir");
	};
    }
};

Robert Ricci's avatar
Robert Ricci committed
261 262 263 264 265 266 267
Phase "tftp", "Setting up directories for tftp", sub {
    Phase "tftpboot", "Creating $TFTP_DIR", sub {
	DoneIfExists($TFTP_DIR);
	mkdir $TFTP_DIR,0775 or
	    PhaseFail("Unable to create $TFTP_DIR : $!");
	ExecQuietFatal("$CHGRP tbadmin $TFTP_DIR");
    };
268 269 270 271 272 273
    Phase "tftpproj", "Creating $TFTP_PROJ_DIR", sub {
	DoneIfExists($TFTP_PROJ_DIR);
	mkdir $TFTP_PROJ_DIR,0775 or
	    PhaseFail("Unable to create $TFTP_PROJ_DIR : $!");
	ExecQuietFatal("$CHGRP tbadmin $TFTP_PROJ_DIR");
    };
Robert Ricci's avatar
Robert Ricci committed
274 275 276 277
    Phase "tftplink", "Linking /tftpboot", sub {
	DoneIfExists("/tftpboot");
	ExecQuietFatal("ln -s $TFTP_DIR /tftpboot");
    };
278 279 280
};

Phase "ports", "Installing ports", sub {
281 282 283 284 285 286 287 288
    # Ick. The php4 port is broken with SSL, so we have to patch it - hopefully
    # it'll get fixed someday, and we remove this
    Phase "php4patch", "Patching php4 port", sub {
	if (!ExecQuiet("$PATCH -C -f -l -R -p0 -i $PHP4_PATCH")) {
	    PhaseSkip("$PHP4_PATCH already applied");
	}
	ExecQuietFatal("$PATCH -f -l -p0 -i $PHP4_PATCH");
    };
289 290 291 292 293 294 295 296 297
    Phase "packages", "Installing packages", sub {
	if (!ExecQuiet("$PKG_INFO -e $BOSS_PORT")) {
	    PhaseSkip("Ports already installed");
	}
	if (!$packagedir) {
	    PhaseSkip("No package directory provided");
	}
	ExecQuietFatal("$ENV PKG_PATH=$packagedir $PKG_ADD $BOSS_PORT");
    };
298
    Phase "pcopy", "Copying ports into place", sub {
299 300 301
	if ($packagedir) {
	    PhaseSkip("Package directory provided");
	}
302 303 304 305
	DoneIfExists("$PORTSDIR/emulab-boss");
	ExecQuietFatal("$SH $SRCDIR/ports/ports-install");
    };
    Phase "pinstall", "Checking for port installation", sub {
306
	if (!ExecQuiet("$PKG_INFO -e $BOSS_PORT")) {
307 308
	    PhaseSkip("Ports already installed");
	}
309 310 311 312
	if ($packagedir) {
	    PhaseSkip("Package directory provided");
	}

313 314 315 316 317 318 319 320 321 322 323 324 325 326
	PhaseFail("Please install ports manually, since some\n of them are " .
	    "interactive. Run: \n" .
	    "cd $PORTSDIR/emulab-boss && make install\n" .
	    "then re-run this script.");
    };
};

Phase "patches", "Applying patches", sub {
    Phase "g++patch", "Patching g++'s STL", sub {
	if (!ExecQuiet("$PATCH -C -f -R -p0 -i $STL_PATCH")) {
	    PhaseSkip("$STL_PATCH already applied");
	}
	ExecQuietFatal("$PATCH -f -p0 -i $STL_PATCH");
    };
327
    Phase "m2cryptopatch", "Patching m2crypto", sub {
328
	if (!ExecQuiet("$PATCH -C -f -l -R -p0 -i $M2CRYPTO_PATCH")) {
329 330
	    PhaseSkip("$M2CRYPTO_PATCH already applied");
	}
331
	ExecQuietFatal("$PATCH -f -l -p0 -i $M2CRYPTO_PATCH");
332
    };
333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365
};

Phase "cracklib", "Installing cracklib", sub {
    DoneIfExists("$CRACKLIB_DICT");
    my $pwd = `$PWD`;
    chomp $pwd;
    chdir "$TOP_SRCDIR/tbsetup/checkpass/cracklib,2.7" or
	PhaseFail "Unable to change to " .
	    "$TOP_SRCDIR/tbsetup/checkpass/cracklib,2.7: $!";
    ExecQuietFatal("make install clean");
    chdir $pwd;
};

Phase "apache", "Installing apache config file", sub {
    DoneIfEdited("$HTTPD_CONF");
    # ICK!!! If we installed apache AFTER we unpacked the source tarball,
    # make will not properly install the new apache config file! So, we use
    # this shameful hack to force it to do so!
    ExecQuietFatal("$TOUCH -t 01010000 $HTTPD_CONF");
    ExecQuietFatal("$GMAKE -C $TOP_OBJDIR/apache install");
};

Phase "rc.d", "Setting up rc.d scripts", sub {
    Phase "my-client", "Moving $RCDIR/mysql-client.sh", sub {
	DoneIfDoesntExist("$RCDIR/mysql-client.sh");
	ExecQuietFatal("mv $RCDIR/mysql-client.sh $RCDIR/1.mysql-client.sh");
    };
    Phase "my-server", "Removing $RCDIR/mysql-server.sh", sub {
	DoneIfDoesntExist("$RCDIR/mysql-server.sh");
	if (!unlink "$RCDIR/mysql-server.sh") {
	    PhaseFail("Unable to remove $RCDIR/mysql-server.sh: $!");
	}
    };
366
    Phase "snmpd", "Removing snmpd startup script",  sub {
367 368 369 370 371
	DoneIfDoesntExist("$RCDIR/snmpd.sh");
	if (!unlink "$RCDIR/snmpd.sh") {
	    PhaseFail("Unable to remove $RCDIR/snmpd.sh: $!");
	}
    };
372 373 374 375 376 377 378
    Phase "rsyncd", "Removing rsyncd startup script",  sub {
	DoneIfDoesntExist("$RCDIR/rsyncd.sh");
	if (!unlink "$RCDIR/rsyncd.sh") {
	    PhaseFail("Unable to remove $RCDIR/rsyncd.sh: $!");
	}
    };
    Phase "dhcpd", "Removing isc-dhcpd startup script",  sub {
379 380 381 382 383
	DoneIfDoesntExist("$RCDIR/isc-dhcpd.sh");
	if (!unlink "$RCDIR/isc-dhcpd.sh") {
	    PhaseFail("Unable to remove $RCDIR/isc-dhcpd.sh: $!");
	}
    };
384
    Phase "rc.testbed", "Installing testbed RC scripts", sub {
385 386 387 388
        Phase "elvind.sh", "Removing port version of elvind.sh", sub {
	    DoneIfDoesntExist("$RCDIR/elvind.sh");
            ExecQuietFatal("/bin/rm -f $RCDIR/elvind.sh");
        };
389 390 391 392 393
	DoneIfExists("$RCDIR/3.testbed.sh");
	ExecQuietFatal("$GMAKE -C $TOP_OBJDIR/rc.d install");
    };
};

394 395 396
Phase "syslog", "Setting up syslog", sub {
    Phase "sysconf", "Editing $SYSLOG_CONF", sub {
	DoneIfEdited($SYSLOG_CONF);
397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417

	#
	# Modify the /var/log/messages line to exclude testbed stuff
	#
	open(SC,"+<$SYSLOG_CONF") or
	    PhaseFail("Unable to open $SYSLOG_CONF : $!");
	my @sc = <SC>;
	if (scalar(grep(/$LOGFACIL/, @sc)) != 0) {
	    PhaseFail("Testbed chosen facility $LOGFACIL already in use in /etc/syslog.conf!");
	}
	seek(SC,0,0);
	truncate(SC,0);
	foreach my $line (@sc) {
	    my $pat = q(\s+/var/log/messages);
	    if ($line =~ /^[^#].*$pat/) {
		$line =~ s/($pat)/\;$LOGFACIL.none$1/;
	    }
	    print SC $line;
	}
	close(SC);

418 419 420 421 422
	AppendToFileFatal($SYSLOG_CONF,
	    "!bootinfo",  "*.*\t\t\t\t\t\t$LOGDIR/bootinfo.log",
	    "!tmcd",      "*.*\t\t\t\t\t\t$LOGDIR/tmcd.log",
	    "!capture",   "*.*\t\t\t\t\t\t$LOGDIR/capture.log",
	    "!dhcpd",     "*.*\t\t\t\t\t\t$LOGDIR/dhcpd.log",
423 424
	    "!proxydhcpd","*.*\t\t\t\t\t\t$LOGDIR/proxydhcpd.log",
	    "!tftpd",     "*.*\t\t\t\t\t\t$LOGDIR/tftpd.log",
425 426 427 428
	    "!capserver", "*.*\t\t\t\t\t\t$LOGDIR/capserver.log",
	    "!frisbeed",  "*.*\t\t\t\t\t\t$LOGDIR/frisbeed.log",
	    "!elvind",    "*.*\t\t\t\t\t\t$LOGDIR/elvind.log",
	    "!stated",    "*.*\t\t\t\t\t\t$LOGDIR/stated.log",
429 430
	    "!osselect",  "*.*\t\t\t\t\t\t$LOGDIR/osselect.log",
	    "!genlastlog","*.*\t\t\t\t\t\t$LOGDIR/genlastlog.log",
431
	    "!sdcollectd","*.*\t\t\t\t\t\t$LOGDIR/sdcollectd.log",
432
	    "!plabgetfree","*.*\t\t\t\t\t\t$LOGDIR/plabgetfree.log",
433
	    "!plabrenew", "*.*\t\t\t\t\t\t$LOGDIR/plabrenew.log",
434
	    "!xmlrpcbag", "*.*\t\t\t\t\t\t$LOGDIR/xmlrpcbag.log",
435 436
	    "!sshxmlrpc", "*.*\t\t\t\t\t\t$LOGDIR/sshxmlrpc.log",
	    "!sslxmlrpc", "*.*\t\t\t\t\t\t$LOGDIR/sslxmlrpc.log");
437 438 439 440 441 442
    };

    Phase "logdir", "Creating log directory", sub {
	DoneIfExists($LOGDIR);
	mkdir $LOGDIR, 0775 or PhaseFail("Unable to create $LOGDIR : $!");
	ExecQuietFatal("$CHGRP tbadmin $LOGDIR");
443
	ExecQuietFatal("$CHMOD 775 $LOGDIR");
444 445 446 447 448 449
    };

    Phase "logdir", "Creating mysql log directory", sub {
	DoneIfExists($MYSQL_LOGDIR);
	mkdir $MYSQL_LOGDIR, 0775 or
	    PhaseFail("Unable to create $MYSQL_LOGDIR : $!");
450 451
	ExecQuietFatal("$CHOWN mysql:mysql $MYSQL_LOGDIR");
	ExecQuietFatal("$CHMOD 775 $MYSQL_LOGDIR");
452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478
    };

    Phase "logfiles", "Creating log files", sub {
	foreach my $logfile (@LOGFILES) {
	    Phase $logfile, $logfile, sub {
		DoneIfExists($logfile);
		CreateFileFatal($logfile);
		ExecQuietFatal("$CHGRP tbadmin $logfile");
		ExecQuietFatal("$CHMOD 640 $logfile");
	    };
	}
    };

    Phase "newsyslog", "Setting up $NEWSYSLOG_CONF", sub {
	DoneIfEdited($NEWSYSLOG_CONF);
	AppendToFileFatal($NEWSYSLOG_CONF,
	    "$LOGDIR/tmcd.log               640  9     1000 *     Z",
	    "$LOGDIR/stated.log             640  9     300  *     Z",
	    "$LOGDIR/osselect.log           640  9     300  *     Z",
	    "$LOGDIR/power.log              640  7     300  *     Z",
	    "$LOGDIR/frisbeed.log           640  7     300  *     Z",
	    "$LOGDIR/tftpd.log              640  7     200  *     Z",
	    "$LOGDIR/dhcpd.log              640  7     200  *     Z",
	    "$LOGDIR/bootinfo.log           640  7     200  *     Z",
	    "$LOGDIR/capserver.log          640  5     200  *     Z",
	    "$LOGDIR/elvind.log             640  5     1000 *     Z",
	    "$LOGDIR/suexec.log             640  3     200  *     Z",
479
	    "$LOGDIR/genlastlog.log         640  3     200  *     Z",
480
	    "$LOGDIR/genlastlog             640  3     200  *     Z " .
481 482
	        "/var/run/lastlog_daemon.pid",
	    "$LOGDIR/plabmetrics.log        640  7     1000 *     Z",
483
	    "$LOGDIR/plablinkdata.log       640  7     1000 *     Z",
484
	    "$LOGDIR/xmlrpcbag.log          640  7     300  *     Z",
485 486
	    "$LOGDIR/sshxmlrpc.log          640  7     300  *     Z",
	    "$LOGDIR/sslxmlrpc.log          640  7     300  *     Z");
487 488 489
    };
};

490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522
Phase "database", "Setting up database", sub {
    Phase "mysql", "Starting mysql", sub {
	if (!ExecQuiet("$MYSQLADMIN ping")) {
	    PhaseSkip("mysqld already running");
	}
	ExecQuietFatal("$RCDIR/2.mysql-server.sh start");
	# Give mysqld some time to start, then make sure it did
	sleep 5;
	ExecQuietFatal("$MYSQLADMIN ping");
    };
    Phase "$DBNAME", "Creating $DBNAME", sub {
	if (!ExecQuiet("$MYSQLSHOW $DBNAME")) {
	    PhaseSkip("tbdb already exists");
	}
	ExecQuietFatal("$MYSQLADMIN create $DBNAME");
    };
    Phase "tables", "Creating tables in $DBNAME", sub {
	if (!ExecQuiet("$MYSQLDUMP -d $DBNAME users")) {
	    PhaseSkip("Tables have already been created");
	}
	ExecQuietFatal("$MYSQL $DBNAME < $TOP_SRCDIR/sql/database-create.sql");
    };
    Phase "dbdata", "Filling tables with initial data", sub {
	my ($exitval, @rows) = ExecQuiet("echo 'select * from " .
	    "exported_tables' | $MYSQL -s $DBNAME");
	if ($exitval) {
	    PhaseFail("Error running query");
	}
	if (scalar @rows) {
	    PhaseSkip("Already done");
	}
	ExecQuietFatal("$MYSQL $DBNAME < $TOP_SRCDIR/sql/database-fill.sql");
    };
523 524 525 526 527 528 529 530 531 532 533 534
    Phase "sdbdata", "Filling tables with supplemental data", sub {
	my ($exitval, @rows) = ExecQuiet("echo 'select * from " .
	    "os_info' | $MYSQL -s $DBNAME");
	if ($exitval) {
	    PhaseFail("Error running query");
	}
	if (scalar @rows) {
	    PhaseSkip("Already done");
	}
	ExecQuietFatal("$MYSQL $DBNAME < " .
	    "$TOP_SRCDIR/sql/database-fill-supplemental.sql");
    };
Robert Ricci's avatar
Robert Ricci committed
535 536 537 538 539 540 541 542 543 544 545
    Phase "sitevars", "Setting sitevars to default values", sub {
	my ($exitval, @rows) = ExecQuiet("echo 'select * from " .
	    "sitevariables' | $MYSQL -s $DBNAME");
	if ($exitval) {
	    PhaseFail("Error running query");
	}
	if (scalar @rows) {
	    PhaseSkip("Already done");
	}
	ExecQuietFatal("$MYSQL $DBNAME < $TOP_SRCDIR/sql/sitevars-create.sql");
    };
546 547 548 549 550
};

Phase "rc.conf", "Adding testbed content to $RCCONF", sub {
    DoneIfEdited($RCCONF);
    AppendToFileFatal($RCCONF,
Robert Ricci's avatar
Robert Ricci committed
551 552 553 554 555
	qq|nfs_server_enable="YES"|,
	qq|nfs_server_flags="-u -t -n 16"|,
	qq|nfs_client_enable="YES"|,
	qq|inetd_enable="YES"|,
	qq|inetd_flags="-wW -R 0"|,
556
	qq|named_enable="NO"|,
Robert Ricci's avatar
Robert Ricci committed
557 558
	qq|xntpd_enable="YES"|,
	qq|syslogd_flags=""|,
559 560
	qq|tftpd_flags="-lvvvv -C 40 -s /tftpboot"|,
    	qq|apache_enable="YES"|);
561 562 563 564 565 566 567
};

Phase "suidperl", "Setting the suid bit on $SUIDPERL", sub {
    PhaseSkip("Already done") if (-u $SUIDPERL);
    ExecQuietFatal("$CHMOD u+s $SUIDPERL");
};

Robert Ricci's avatar
Robert Ricci committed
568 569 570 571 572 573 574 575 576 577 578 579 580
Phase "resolve", "Checking to make sure names for ops resolve", sub {
    foreach my $name (@OPS_NAMES) {
	Phase $name, $name, sub {
	    if (gethostbyname($name)) {
		PhaseSkip("$name resolves");
	    } else {
		PhaseFail("$name does not resolve - please see setup.txt\n" .
		    "for further instructions!");
	    }
	};
    }
};

581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610
Phase "NFSmounts", "Setting up NFS mounts", sub {
    Phase "mountpoints", "Creating mountpoints", sub {
	foreach my $dir (@MOUNTPOINTS) {
	    Phase $dir, $dir, sub {
		DoneIfExists($dir);
		mkdir $dir, 0777 or
		    PhaseFail("Unable to create $dir : $!");
	    };
	}
    };
    Phase "fstab", "Adding NFS mounts to $FSTAB", sub {
	DoneIfEdited($FSTAB);
	AppendToFileFatal($FSTAB,
		"$FSNODE:/users\t\t/users\tnfs\trw,nodev,nosuid\t0\t0",
		"$FSNODE:/proj\t\t/proj\tnfs\trw,nodev,nosuid\t0\t0",
		"$FSNODE:/groups\t\t/groups\tnfs\trw,nodev,nosuid\t0\t0",
		"$FSNODE:/share\t\t/share\tnfs\trw,nodev,nosuid\t0\t0",
		"$USERNODE:/usr/testbed\t\t$OPSDIR_DIR\tnfs\trw,soft,".
			  "-b,nodev,nosuid\t0\t0",
		"$USERNODE:/var\t\t$USERSVAR_DIR\tnfs\tro,soft,".
			  "-b,nodev,nosuid\t0\t0");
    };
    Phase "mounts", "Mounting NFS filesystems", sub {
	foreach my $dir (@MOUNTPOINTS) {
	    Phase $dir, $dir, sub {
		DoneIfMounted($dir);
		ExecQuietFatal("$MOUNT -o '-R 1' $dir");
	    };
	}
    };
611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627
};

Phase "mibs", "Fetching Cisco MIBs", sub {
    foreach my $mib (@CISCO_MIBS) {
	my $localfile = "$MIBPATH/$mib.txt";
	my $mibURL = "$CISCO_MIB_FTP/$mib.my";
	Phase "$mib", "Fetching $mib", sub {
	    DoneIfExists($localfile);
	    FetchFileFatal($mibURL,$localfile);
	};
    }
};

Phase "cron", "Adding cron jobs", sub {
    Phase "crontab", "Editing $CRONTAB", sub {
	DoneIfEdited($CRONTAB);
	AppendToFileFatal($CRONTAB,
628 629 630
	    "45 \t1\t*\t*\t*\troot\t$PREFIX/sbin/backup",
	    "*/5\t*\t*\t*\t*\troot\t$PREFIX/sbin/node_status",
	    "*/5\t*\t*\t*\t*\troot\t$PREFIX/sbin/idlemail");
631 632 633 634 635 636 637 638
    };
};

Phase "sudoers", "Editing $SUDOERS", sub {
    DoneIfEdited($SUDOERS);
    AppendToFileFatal($SUDOERS,"%wheel    ALL=(ALL) NOPASSWD: ALL");
};

Robert Ricci's avatar
Robert Ricci committed
639 640 641 642 643 644 645 646 647 648 649 650 651 652
Phase "php.ini", "Creating php.ini file", sub {
    DoneIfExists($PHP_INI);
    CreateFileFatal($PHP_INI,
	"[PHP]","",
	";",
	"; So that quotes are not escaped. Needed for netbuild application.",
	";", 
	"magic_quotes_gpc        =       Off","",
	";",
	"; Our scripts depend on this!",
	";",
	"register_globals        =       On");
};

653
Phase "ssh", "Setting up root ssh from boss to ops", sub {
Robert Ricci's avatar
Robert Ricci committed
654 655 656 657 658 659 660 661 662 663 664
    Phase "keygen", "Creating root private key", sub {
	DoneIfExists($ROOT_PRIVKEY);
	ExecQuietFatal("$SSH_KEYGEN -t rsa1 -P '' -f $ROOT_PRIVKEY");
    };
    Phase "ssh", "Editing ssh config file", sub {
	DoneIfEdited($SSH_CONFIG);
	AppendToFileFatal($SSH_CONFIG,
	    "Host *",
	    "   StrictHostKeyChecking no",
	    "   Protocol 1,2");
    };
665
    Phase "keycopy", "Copy root ssh keys to ops", sub {
Leigh B. Stoller's avatar
Leigh B. Stoller committed
666
	if (! ExecQuiet("$SSH -o 'BatchMode=yes' root\@${USERNODE} pwd")) {
667 668
	    PhaseSkip("Key already copied");
	} else {
Leigh B. Stoller's avatar
Leigh B. Stoller committed
669 670 671 672 673 674 675 676 677 678
	    ExecQuietFatal("$SCP -i $INIT_PRIVKEY ".
			   "$ROOT_PUBKEY ${USERNODE}:$ROOT_AUTHKEY");

	    if (ExecQuiet("$SSH -o 'BatchMode=yes' root\@${USERNODE} pwd")) {
		PhaseFail("You'll need to manually copy boss's public SSH key\n".
			  "over to ops print so boss can get into ops without\n".
			  "a password. Run the following print as root:\n" .
			  "scp $ROOT_PUBKEY ${USERNODE}:$ROOT_AUTHKEY");
	    }
	};
679
    };
680 681
};

682 683 684 685 686
Phase "rndc", "Setting up rndc for control of nameserver", sub {
    DoneIfExists($RNDC_KEY);
    ExecQuietFatal("$RNDC_CONFGEN -a -r /dev/urandom");
};

687 688 689 690 691 692 693
Phase "loader.conf", "Setting up $LOADER_CONF", sub {
    DoneIfEdited($LOADER_CONF);
    AppendToFileFatal($LOADER_CONF,
	"kern.hz=1000"
    );
};

694 695 696 697 698 699 700 701
Phase "sysctl.conf", "Setting up $SYSCTL_CONF", sub {
    DoneIfEdited($SYSCTL_CONF);
    AppendToFileFatal($SYSCTL_CONF,
	"net.local.dgram.maxdgram=65536",
	"net.local.dgram.recvspace=65536"
    );
};

702 703 704 705 706 707 708 709 710
Phase "sslcerts", "Setting up SSL certificates", sub {
    Phase "sslgen", "Generating SSL certificates", sub {
	DoneIfExists("$TOP_OBJDIR/ssl/$EMULAB_PEM");
	ExecQuietFatal("$GMAKE -C $TOP_OBJDIR/ssl remote-site");
    };
    Phase "sslinstall", "Installing SSL certificates", sub {
	DoneIfExists("$PREFIX/etc/$EMULAB_PEM");
	ExecQuietFatal("$GMAKE -C $TOP_OBJDIR/ssl remote-site-boss-install");
    };
711 712 713 714 715 716 717 718 719
    Phase "sslopscopy", "Copying SSL certificates to ops", sub {
 	ExecQuietFatal("$SCP $PREFIX/etc/$EMULAB_PEM ".
 		       "     ${USERNODE}:${ETC_EMULAB_DIR}");
 	ExecQuietFatal("$SCP $TOP_OBJDIR/ssl/$CTRLNODE_PEM".
		       "     ${USERNODE}:${ETC_EMULAB_DIR}/${CLIENT_PEM}");
 	ExecQuietFatal("$SSH -o 'BatchMode=yes' root\@${USERNODE} ".
		       "     chmod 640 ${ETC_EMULAB_DIR}/${CLIENT_PEM}; ".
		       "     chmod 640 ${ETC_EMULAB_DIR}/${EMULAB_PEM}  ");
    };
720 721
};

722 723
Phase "event", "Setting up event system", sub {
    Phase "elvinconf", "Installing elvind config file", sub {
724
	DoneIfIdentical($ELVIND_CONF,$BOSS_ELVIND_CONF);
725 726 727 728
	ExecQuietFatal("$CP $BOSS_ELVIND_CONF $ELVIND_CONF");
    };
};

729 730 731 732 733
print "----------------------------------------------------------------------\n";
print "Installation completed succesfully!\n";
print "Please reboot this machine before proceeding with boss setup\n";

exit 0;