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

#
# EMULAB-COPYRIGHT
5
# Copyright (c) 2003-2007 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
# 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@";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
27
my $ELABINELAB = @ELABINELAB@;
28
my $WINSUPPORT = @WINSUPPORT@;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
29
my $MAILMANSUPPORT = @MAILMANSUPPORT@;
30
my $BUGDBSUPPORT = @BUGDBSUPPORT@;
31
my $ARCHSUPPORT = @ARCHIVESUPPORT@;
32
my $OURDOMAIN  = '@OURDOMAIN@';
33
my $EXPOSETEMPLATES = $ELABINELAB;
34

35
36
my $LOGFACIL   = '@TBLOGFACIL@';

37
38
39
my $USERNODE   = '@USERNODE@';
my $FSNODE     = '@FSNODE@';
my $BOSSNODE   = '@BOSSNODE@';
40
41
my $BOSSNODE_IP= '@BOSSNODE_IP@';
my $USERNODE_IP= '@USERNODE_IP@';
42
my $FSNODE_IP=   '@FSNODE_IP@';
43
44
45
46
47
48
49
50
51
52
my $SCRATCHDIR = '@FSDIR_SCRATCH@';

#
# Fixed paths for clients
#
my $PROJROOT    = "@PROJROOT_DIR@";
my $GROUPROOT   = "@GROUPSROOT_DIR@";
my $USERROOT    = "@USERSROOT_DIR@";
my $SCRATCHROOT	= "@SCRATCHROOT_DIR@";
my $SHAREROOT	= "@SHAREROOT_DIR@";
53
54
55
56
57
58
59

#
# Some programs we use
#
my $SH         = "/bin/sh";
my $CHMOD      = "/bin/chmod";
my $CHGRP      = "/usr/bin/chgrp";
60
my $CHOWN      = "/usr/sbin/chown";
61
62
63
64
65
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";
66
my $PKG_ADD    = "/usr/sbin/pkg_add";
67
my $PKG_DEL    = "/usr/sbin/pkg_delete";
68
my $TOUCH      = "/usr/bin/touch";
69
70
71
72
my $SSH_INIT   = "/usr/bin/ssh -1";
my $SCP_INIT   = "/usr/bin/scp -1";
my $SSH        = "/usr/bin/ssh -2";
my $SCP        = "/usr/bin/scp -2";
73
my $CP         = "/bin/cp";
74
my $ENV        = "/usr/bin/env";
75
my $MOUNT      = "/sbin/mount";
76
my $SUDO       = "/usr/local/bin/sudo";
77
78
79
80
81
82
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";
83
84
my $MYSQLINSTALL = "/usr/local/bin/mysql_install_db";
my $MYSQLDBDIR = "/var/db/mysql";
85
86

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

88
89
90
91
#
# Some files we edit/create
#
my $CRONTAB         = "/etc/crontab";
92
my $HOSTS           = "/etc/hosts";
93
94
95
96
my $FSTAB           = "/etc/fstab";
my $RCCONF          = "/etc/rc.conf";
my $SYSLOG_CONF     = "/etc/syslog.conf";
my $NEWSYSLOG_CONF  = "/etc/newsyslog.conf";
97
my $INETD_CONF      = "/etc/inetd.conf";
98

99
100
my $PROTOUSER       = "elabman";
my $PROTOUSER_KEY   = "$TOP_SRCDIR/install/elabman_dsa.pub";
101
my $ROOT_PRIVKEY    = "/root/.ssh/id_rsa";
102
103
104
my $ROOT_PUBKEY     = "$ROOT_PRIVKEY.pub";
my $ROOT_AUTHKEY    = "/root/.ssh/authorized_keys";

105
my $APACHE_ETCDIR   = "/usr/local/etc/apache";
106
my $SUDOERS         = "/usr/local/etc/sudoers";
107
my $HTTPD_CONF      = "$APACHE_ETCDIR/httpd.conf";
Robert Ricci's avatar
Robert Ricci committed
108
my $PHP_INI         = "/usr/local/etc/php.ini";
109
110
111
112
my $DHCPD_CONF	    = "/usr/local/etc/dhcpd.conf";
my $DHCPD_TEMPLATE  = "/usr/local/etc/dhcpd.conf.template";
my $DHCPD_LEASES    = "/var/db/dhcpd.leases";
my $DHCPD_MAKECONF  = "$PREFIX/sbin/dhcpd_makeconf";
113
114
115
my $BATCHEXP        = "$PREFIX/bin/batchexp";
my $WAP             = "$PREFIX/sbin/withadminprivs";
my $NAMED_SETUP     = "$PREFIX/sbin/named_setup";
116
117
my $ADDPUBKEY       = "$PREFIX/sbin/addpubkey";
my $TBACCT          = "$PREFIX/sbin/tbacct";
118
119
120
121

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

my $STL_PATCH       = "$TOP_SRCDIR/patches/g++.patch";
122
my $M2CRYPTO_PATCH  = "$TOP_SRCDIR/patches/m2crypto.patch";
Kevin Atkinson's avatar
   
Kevin Atkinson committed
123
my $MYSQL_PM_PATCH  = "$TOP_SRCDIR/patches/Mysql.pm.patch";
124
my $PHP4_PATCH      = "$TOP_SRCDIR/patches/php4-Makefile.patch";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
125
my $INIT_PRIVKEY    = "$TOP_SRCDIR/install/identity";
126

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

129
130
my $LOADER_CONF	    = "/boot/loader.conf";

131
132
my $SYSCTL_CONF	    = "/etc/sysctl.conf";

133
my $EMULAB_PEM	    = "emulab.pem";
134
135
136
my $CLIENT_PEM	    = "client.pem";
my $CTRLNODE_PEM    = "ctrlnode.pem";
my $ETC_EMULAB_DIR  = "/etc/emulab";
137
138
139
140
141
142
143
144
145
146

# Apache certs on both boss and ops
my $APACHE_CERTPEM      = "apache_cert.pem";
my $APACHE_KEYPEM       = "apache_key.pem";
my $APACHE_CERTFILE     = "$APACHE_ETCDIR/ssl.crt/www.${OURDOMAIN}.crt";
my $APACHE_KEYFILE      = "$APACHE_ETCDIR/ssl.key/www.${OURDOMAIN}.key";
my $APACHE_CERTPEM_OPS  = "apache-ops_cert.pem";
my $APACHE_KEYPEM_OPS   = "apache-ops_key.pem";
my $APACHE_CERTFILE_OPS = "$APACHE_ETCDIR/ssl.crt/${USERNODE}.crt";
my $APACHE_KEYFILE_OPS  = "$APACHE_ETCDIR/ssl.key/${USERNODE}.key";
147

148
149
150
151
152
#
# XXX temporary for tftp
#
my $TFTPD_PKG	  = "emulab-tftp-hpa-0.48";

153
154
155
#
# Some directories we care about
#
156
157
158
159
160
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";
161
162
my $PORTSDIR      = "/usr/ports";
my $PORTSMISCDIR  = "$PORTSDIR/misc";
163
164
165
my $MIBPATH       = "/usr/local/share/snmp/mibs";
my $TFTP_DIR      = "$PREFIX/tftpboot";
my $TFTP_PROJ_DIR = "$TFTP_DIR/proj";
166
my $VARRUN        = "/var/run";
167
my $ETCSSH	  = "/etc/ssh";
168
169
170
171
172
173
174
175
176
177
178

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

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

179
180
181
182
183
my @MOUNTPOINTS = ("$USERSVAR_DIR", "$OPSDIR_DIR",
		   "$USERROOT", "$PROJROOT", "$GROUPROOT", "$SHAREROOT");
if ($SCRATCHDIR) {
    push(@MOUNTPOINTS, "$SCRATCHROOT");
}
Robert Ricci's avatar
Robert Ricci committed
184

185
186
my @LOGFILES = ("$LOGDIR/bootinfo.log", "$LOGDIR/tmcd.log",
    "$LOGDIR/capture.log", "$LOGDIR/dhcpd.log", "$LOGDIR/capserver.log",
187
    "$LOGDIR/frisbeed.log", "$LOGDIR/proxydhcpd.log",
188
    "$LOGDIR/elvind.log", "$LOGDIR/stated.log", "$LOGDIR/osselect.log",
189
    "$LOGDIR/tftpd.log", "$LOGDIR/sdcollectd.log", "$LOGDIR/genlastlog.log",
190
    "$LOGDIR/sshxmlrpc.log", "$LOGDIR/plabgetfree.log", "$LOGDIR/xmlrpcbag.log",
191
    "$LOGDIR/plabrenew.log", "$LOGDIR/sslxmlrpc.log");
192
193

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

197
198
199
200
201
202
203
204
205
206
207
208
# Initial experiments to create. Indexed by eid.
my %EXPERIMENTS =
    ("hwdown"	     => {"pid"	       => "emulab-ops",
			 "description" => "Node reported as down"},
     "reloading"     => {"pid"	       => "emulab-ops",
			 "description" => "Nodes reloading images"},
     "reloadpending" => {"pid"	       => "emulab-ops",
			 "description" => "Nodes waiting for reload"},
     "oldreserved"   => {"pid"	       => "emulab-ops",
			 "description" => "Nodes in limbo during swap modify"},
     "nfree-leases"  => {"pid"	       => "emulab-ops",
			 "description" => "Nodes in limbo during nfree"},
209
210
     "nfree-locked"  => {"pid"	       => "emulab-ops",
			 "description" => "Nodes in limbo during nfree"},
211
212
213
214
     "opsnodes"	     => {"pid"	       => "emulab-ops",
			 "description" => "Nodes designated as Ops Nodes"},
    );

215
216
217
218
#
# List of names that goes into $HOSTS and which must resolve.
# 
my @OPS_NAMES = ($USERNODE, "users", "ops");
219
220
221
if ($USERNODE eq $FSNODE) {
    push(@OPS_NAMES, "fs");
}
Robert Ricci's avatar
Robert Ricci committed
222

223
224
225
226
227
228
229
230
231
# Version of FreeBSD.
my $FBSD_VERSION = 4;
if (`uname -r` =~ /^(\d)/) {
    $FBSD_VERSION = $1;
}
else {
    die("Could not determine what version of FreeBSD you are running!\n");
}

232
#
233
234
# The meta-ports (name and version) that drag in all the dependancies for
# a boss node. These are OS dependent as we upgrade.
235
#
236
237
my $BOSS_PORT = (($FBSD_VERSION == 4) ? "emulab-boss-1.8" : "emulab-boss-2.0");
my $PHP4_PORT = "php4-extensions-1.0";
238

239
240
241
242
243
244
245
246
#
# 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/..";

247
248
249
my $ELVIND_CONF     = "/usr/local/etc/elvind.conf";
my $BOSS_ELVIND_CONF = "$TOP_OBJDIR/event/etc/elvind-boss.conf";

250
251
252
253
254
255
256
#
# Allow this to work if the library is left in the source directory
#
use lib '@srcdir@';
   
use English;
use libinstall;
257
258
259
260
261
262
use Getopt::Std;

#
# Handle command-line options
#
sub usage {
263
264
    print "Usage: boss-install [-b] [-p packagedir] [-s] [-P portname]\n";
    print "  Required: -p (for binary packages) or -s (for source makes.)\n";
265
266
267
268
    exit(1);
}

my $packagedir = "";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
269
my $batchmode  = 0;
270
my $domakes  = 0;
271
my $password;
272
273
my %opts;

274
if (! getopts("P:p:bsw:", \%opts)) {
Leigh B. Stoller's avatar
Leigh B. Stoller committed
275
276
277
278
279
280
281
    usage();
}
if (defined($opts{p})) {
    $packagedir = $opts{p};
}
if (defined($opts{b})) {
    $batchmode = 1;
282
}
283
284
285
if (defined($opts{s})) {
    $domakes = 1;
}
286
287
288
if (defined($opts{w})) {
    $password = $opts{w};
}
289
290
291
if (defined($opts{P})) {
    $BOSS_PORT = $opts{P};
}
292
293
294
295
296
297
298
299
300
# Don't just charge into making ports from source by default.
if ($packagedir eq "" and $domakes eq 0) {
    print "At least one of -p and -s must be given.\n";
    usage();
}
if ($packagedir ne "" and $domakes eq 1) {
    print "Only one of -p and -s can be given.\n";
    usage();
}
301
302
303
if (@ARGV) {
    usage();
}
304
305
306
307

#
# Make sure they know what they're getting into...
#
Leigh B. Stoller's avatar
Leigh B. Stoller committed
308
309
310
311
312
313
314
315
316
317
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);
}
318
319
320
321
322

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

Leigh B. Stoller's avatar
Leigh B. Stoller committed
323
Phase "usersgroups", "Creating users and groups", sub {
324
325
    Phase "tbadmin", "Creating tbadmin group", sub {
	if (getgrnam("tbadmin")) {
326
	    PhaseSkip("Group already exists");
327
328
329
330
331
	}
	ExecQuietFatal("$PW groupadd tbadmin -g 101");
    };
    Phase "root", "Creating root group", sub {
	if (getgrnam("root")) {
332
	    PhaseSkip("Group already exists");
333
334
335
	}
	ExecQuietFatal("$PW groupadd root -g 103");
    };
Leigh B. Stoller's avatar
Leigh B. Stoller committed
336
337
338
    # Added next two cause the mysql package does not do this (port does).
    Phase "mysqlgroup", "Creating mysql group", sub {
	if (getgrnam("mysql")) {
339
	    PhaseSkip("Group already exists");
Leigh B. Stoller's avatar
Leigh B. Stoller committed
340
341
342
343
344
	}
	ExecQuietFatal("$PW groupadd mysql -g 88");
    };
    Phase "mysqluser", "Creating mysql user", sub {
	if (getpwnam("mysql")) {
345
	    PhaseSkip("User already exists");
Leigh B. Stoller's avatar
Leigh B. Stoller committed
346
347
	}
	ExecQuietFatal("$PW useradd mysql -g 88 -g 88 -h - ".
348
		       "-d $MYSQLDBDIR -s /sbin/nologin -c 'MySQL Daemon'");
Leigh B. Stoller's avatar
Leigh B. Stoller committed
349
    };
350
351
    ExecQuietFatal("$CHOWN mysql:mysql $MYSQLDBDIR")
	if (-e $MYSQLDBDIR);
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
};

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
372
Phase "tftp", "Setting up directories for tftp", sub {
373
    Phase "tftpoff", "Disabling BSD tftpd", sub {
374
375
	PhaseSkip("No inetd.conf!?") unless (-e $INETD_CONF);
	PhaseSkip("Already disabled") unless `grep '^tftp' $INETD_CONF`;
376
377
378
	ExecQuietFatal("sed -i .orig -e '/^tftp/s/^/#/' $INETD_CONF");
	HUPDaemon("inetd");
    };
Robert Ricci's avatar
Robert Ricci committed
379
380
381
382
383
384
    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");
    };
385
386
387
388
389
390
    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
391
392
393
394
    Phase "tftplink", "Linking /tftpboot", sub {
	DoneIfExists("/tftpboot");
	ExecQuietFatal("ln -s $TFTP_DIR /tftpboot");
    };
395
396
397
};

Phase "ports", "Installing ports", sub {
398
    Phase "packages", "Installing packages", sub {
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
	Phase "main", "Installing main package", sub {
	    if (!ExecQuiet("$PKG_INFO -e $BOSS_PORT")) {
		PhaseSkip("Package already installed");
	    }
	    if (!$packagedir) {
		PhaseSkip("No package directory provided");
	    }
	    ExecQuietFatal("$ENV PKG_PATH=$packagedir $PKG_ADD $BOSS_PORT");
	};
	if ($FBSD_VERSION > 4) {
	    Phase "php4", "Installing php4 package", sub {
		if (!ExecQuiet("$PKG_INFO -e $PHP4_PORT")) {
		    PhaseSkip("Port already installed");
		}
		if (!$packagedir) {
		    PhaseSkip("No package directory provided");
		}
		ExecQuietFatal("$ENV PKG_PATH=$packagedir ".
			       "     $PKG_ADD $PHP4_PORT");
	    };
419
420
421
422
423
424
425
426
427
428
429
430
431
432
	    # XXX temporary: only needed til emulab-boss package updated
	    Phase "tftpd", "Updating tftpd installation", sub {
		my $pname = `$PKG_INFO -E 'emulab-tftp-hpa-*' 2>/dev/null`;
		chomp($pname);
		if ($pname eq $TFTPD_PKG) {
		    PhaseSkip("tftpd already up to date");
		}
		if (!$packagedir) {
		    PhaseSkip("No package directory provided");
		}
		ExecQuietFatal("$ENV PKG_PATH=$packagedir $PKG_DEL -f $pname")
		    if ($pname);
		ExecQuietFatal("$ENV PKG_PATH=$packagedir $PKG_ADD $TFTPD_PKG");
	    };
433
434
	}
    };
435
    PhaseSkip("Package directory provided; not installing from sources")
Leigh B. Stoller's avatar
Leigh B. Stoller committed
436
437
	if ($packagedir);

438
    Phase "pcopy", "Copying ports into place", sub {
439
	DoneIfExists("$PORTSMISCDIR/emulab-boss");
440
441
	ExecQuietFatal("$SH $SRCDIR/ports/ports-install");
    };
442
443
444
445
446
    if ($FBSD_VERSION == 4) {
	# 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")) {
447
		PhaseSkip("Patch already applied");
448
449
450
451
	    }
	    ExecQuietFatal("$PATCH -f -l -p0 -i $PHP4_PATCH");
	};
    }
452
453
    PhaseFail("Please install ports manually, since some\n of them are " .
	      "interactive. Run: \n" .
454
455
	      "    cd $PORTSMISCDIR/emulab-boss && make install\n" .
	      "    cd $PORTSMISCDIR/emulab-php4 && make install\n" .
456
	      "then re-run this script.");
457
458
};

459
460
461
462
463
Phase "portfixup", "Fixing up packages", sub {
    Phase "rsync", "Looking for rsync", sub {
	if (!ExecQuiet("$PKG_INFO -x rsync")) {
	    PhaseSkip("rsync already installed");
	}
464
465
	my $pname = GetPackage("rsync", $packagedir);
	ExecQuietFatal("$ENV PKG_PATH=$packagedir $PKG_ADD $pname");
466
    };
467
    if ($FBSD_VERSION == 6) {
468
	# Temporary for template stuff
469
470
471
472
	Phase "Simple", "Looking for Simple XML Parser", sub {
	    if (!ExecQuiet("$PKG_INFO -x p5-XML-Simple")) {
		PhaseSkip("p5-XML-Simple already installed");
	    }
473
474
	    my $pname = GetPackage("p5-XML-Simple", $packagedir);
	    ExecQuietFatal("$ENV PKG_PATH=$packagedir $PKG_ADD $pname");
475
	};
476
477
478
479
480
481
482
483
484
	if ($ARCHSUPPORT) {
	    Phase "Subversion", "Looking for Subversion", sub {
		if (!ExecQuiet("$PKG_INFO -x subversion")) {
		    PhaseSkip("subversion already installed");
		}
		my $pname = GetPackage("subversion-python", $packagedir);
		ExecQuietFatal("$ENV PKG_PATH=$packagedir $PKG_ADD $pname");
	    };
	}
485
    }
486
487
    if ($WINSUPPORT) {
	Phase "gcc30", "Looking for GCC 3.0 and installing", sub {
488
489
	    if ($FBSD_VERSION > 4 ||
		!ExecQuiet("$PKG_INFO -x gcc30")) {
490
491
		PhaseSkip("GCC 3.0 already installed");
	    }
492
493
	    my $pname = GetPackage("gcc30", $packagedir);
	    ExecQuietFatal("$ENV PKG_PATH=$packagedir $PKG_ADD $pname");
494
495
	};
    }
496
497
};

498
Phase "patches", "Applying patches", sub {
499
500
501
    if ($FBSD_VERSION == 4) {
	Phase "g++patch", "Patching g++'s STL", sub {
	    if (!ExecQuiet("$PATCH -C -f -R -p0 -i $STL_PATCH")) {
502
		PhaseSkip("Patch already applied");
503
504
505
506
	    }
	    ExecQuietFatal("$PATCH -f -p0 -i $STL_PATCH");
	};
    }
507
    Phase "m2cryptopatch", "Patching m2crypto", sub {
508
509
510
511
512
513
	my $patchfile = $M2CRYPTO_PATCH;
	
	if (ExecQuiet("$PKG_INFO -I -x m2crypto | fgrep -q -s '0.13'") == 0) {
	    $patchfile = "${patchfile}-0.13";
	}
	if (!ExecQuiet("$PATCH -C -f -l -R -p0 -i $patchfile")) {
514
	    PhaseSkip("Patch already applied");
515
	}
516
	ExecQuietFatal("$PATCH -f -l -p0 -i $patchfile");
517
    };
Kevin Atkinson's avatar
   
Kevin Atkinson committed
518
519
    Phase "Mysql.pm.patch", "Patching Mysql.pm", sub {
	my $patchfile = $MYSQL_PM_PATCH;
520
	$patchfile = `realpath $patchfile`;
Kevin Atkinson's avatar
   
Kevin Atkinson committed
521
522
523
524
525
526
527
528
529
530
531
532
533
534
	chomp $patchfile;

	my $dir;
	foreach $prefix (@INC) {
	    if (-e "$prefix/Mysql.pm") {
		$dir = $prefix;
		last;
	    }
	}
	if (!defined($dir)) {
	    PhaseFail("Unable to find Mysql.pm");
	}

	if (!ExecQuiet("$PATCH -d $dir -C -f -l -R -i $patchfile")) {
535
	    PhaseSkip("Patch already applied");
Kevin Atkinson's avatar
   
Kevin Atkinson committed
536
537
538
	}
	ExecQuietFatal("$PATCH -d $dir -f -l -i $patchfile");
    };
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
};

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: $!");
	}
    };
572
573
574
575
576
577
    Phase "my-server2", "Removing $RCDIR/mysql-server", sub {
	DoneIfDoesntExist("$RCDIR/mysql-server");
	if (!unlink "$RCDIR/mysql-server") {
	    PhaseFail("Unable to remove $RCDIR/mysql-server: $!");
	}
    };
578
    Phase "snmpd", "Removing snmpd startup script",  sub {
579
580
581
582
583
	DoneIfDoesntExist("$RCDIR/snmpd.sh");
	if (!unlink "$RCDIR/snmpd.sh") {
	    PhaseFail("Unable to remove $RCDIR/snmpd.sh: $!");
	}
    };
584
585
586
587
588
589
590
    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 {
591
592
593
594
595
	DoneIfDoesntExist("$RCDIR/isc-dhcpd.sh");
	if (!unlink "$RCDIR/isc-dhcpd.sh") {
	    PhaseFail("Unable to remove $RCDIR/isc-dhcpd.sh: $!");
	}
    };
596
    Phase "rc.testbed", "Installing testbed RC scripts", sub {
597
598
599
600
        Phase "elvind.sh", "Removing port version of elvind.sh", sub {
	    DoneIfDoesntExist("$RCDIR/elvind.sh");
            ExecQuietFatal("/bin/rm -f $RCDIR/elvind.sh");
        };
601
602
603
604
605
	DoneIfExists("$RCDIR/3.testbed.sh");
	ExecQuietFatal("$GMAKE -C $TOP_OBJDIR/rc.d install");
    };
};

606
607
608
Phase "syslog", "Setting up syslog", sub {
    Phase "sysconf", "Editing $SYSLOG_CONF", sub {
	DoneIfEdited($SYSLOG_CONF);
609
610

	#
611
612
	# Modify the /dev/console and /var/log/messages lines to exclude
	# testbed stuff
613
614
615
616
617
618
619
620
621
622
	#
	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) {
623
624
625
626
627
628
629
	    my $cpat = q(\s+/dev/console);
	    my $mpat = q(\s+/var/log/messages);
	    if ($line =~ /^[^#].*$cpat/) {
		$line =~ s/($cpat)/\;$LOGFACIL.none$1/;
	    }
	    elsif ($line =~ /^[^#].*$mpat/) {
		$line =~ s/($mpat)/\;$LOGFACIL.none$1/;
630
631
632
633
634
	    }
	    print SC $line;
	}
	close(SC);

635
636
637
638
639
	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",
640
641
	    "!proxydhcpd","*.*\t\t\t\t\t\t$LOGDIR/proxydhcpd.log",
	    "!tftpd",     "*.*\t\t\t\t\t\t$LOGDIR/tftpd.log",
642
643
644
645
	    "!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",
646
647
	    "!osselect",  "*.*\t\t\t\t\t\t$LOGDIR/osselect.log",
	    "!genlastlog","*.*\t\t\t\t\t\t$LOGDIR/genlastlog.log",
648
	    "!sdcollectd","*.*\t\t\t\t\t\t$LOGDIR/sdcollectd.log",
649
	    "!plabgetfree","*.*\t\t\t\t\t\t$LOGDIR/plabgetfree.log",
650
	    "!plabrenew", "*.*\t\t\t\t\t\t$LOGDIR/plabrenew.log",
651
	    "!xmlrpcbag", "*.*\t\t\t\t\t\t$LOGDIR/xmlrpcbag.log",
652
653
	    "!sshxmlrpc", "*.*\t\t\t\t\t\t$LOGDIR/sshxmlrpc.log",
	    "!sslxmlrpc", "*.*\t\t\t\t\t\t$LOGDIR/sslxmlrpc.log");
654
655
656
657
658
659
    };

    Phase "logdir", "Creating log directory", sub {
	DoneIfExists($LOGDIR);
	mkdir $LOGDIR, 0775 or PhaseFail("Unable to create $LOGDIR : $!");
	ExecQuietFatal("$CHGRP tbadmin $LOGDIR");
660
	ExecQuietFatal("$CHMOD 775 $LOGDIR");
661
662
663
664
665
666
    };

    Phase "logdir", "Creating mysql log directory", sub {
	DoneIfExists($MYSQL_LOGDIR);
	mkdir $MYSQL_LOGDIR, 0775 or
	    PhaseFail("Unable to create $MYSQL_LOGDIR : $!");
667
668
	ExecQuietFatal("$CHOWN mysql:mysql $MYSQL_LOGDIR");
	ExecQuietFatal("$CHMOD 775 $MYSQL_LOGDIR");
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
    };

    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",
696
	    "$LOGDIR/genlastlog.log         640  3     200  *     Z",
697
	    "$LOGDIR/genlastlog             640  3     200  *     Z " .
698
699
	        "/var/run/lastlog_daemon.pid",
	    "$LOGDIR/plabmetrics.log        640  7     1000 *     Z",
700
	    "$LOGDIR/plablinkdata.log       640  7     1000 *     Z",
701
	    "$LOGDIR/xmlrpcbag.log          640  7     300  *     Z",
702
703
	    "$LOGDIR/sshxmlrpc.log          640  7     300  *     Z",
	    "$LOGDIR/sslxmlrpc.log          640  7     300  *     Z");
704
705
706
    };
};

707
Phase "database", "Setting up database", sub {
708
709
710
711
712
713
714
    Phase "initialize", "Initializing mysql", sub {
	PhaseSkip("mysqld already initialzed")
	    if (-d "$MYSQLDBDIR/mysql");

	ExecQuietFatal("$MYSQLINSTALL --ldata=${MYSQLDBDIR}");
	ExecQuietFatal("$CHOWN -R mysql:mysql $MYSQLDBDIR");
    };
Leigh B. Stoller's avatar
Leigh B. Stoller committed
715
    Phase "mysql", "Starting mysqld", sub {
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
	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");
    };
747
748
749
750
751
752
753
754
755
756
757
758
    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
759
760
761
762
763
764
765
766
767
768
769
    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");
    };
Leigh B. Stoller's avatar
Leigh B. Stoller committed
770
771
772
773
774
775
776
777
778
779
780
781
    Phase "knowlbase", "Filling knowledge_base_entries table", sub {
	my ($exitval, @rows) = ExecQuiet("echo 'select * from " .
	    "knowledge_base_entries' | $MYSQL -s $DBNAME");
	if ($exitval) {
	    PhaseFail("Error running query");
	}
	if (scalar @rows) {
	    PhaseSkip("Already done");
	}
	ExecQuietFatal("$MYSQL $DBNAME < ".
		       "$TOP_SRCDIR/sql/knowlbase-create.sql");
    };
782
783
784
785
};

Phase "rc.conf", "Adding testbed content to $RCCONF", sub {
    DoneIfEdited($RCCONF);
786
787
788
789
790
791
792
793
794
795
796
797
    my @strings = (qq|rpcbind_enable="YES"|,
		   qq|mountd_enable="YES"|,
		   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"|,
		   qq|xntpd_enable="YES"|,
		   qq|syslogd_flags=""|,
		   qq|tftpd_flags="-lvvvv -C 40 -s /tftpboot"|,
		   qq|apache_enable="YES"|);

798
799
    # Starting at FreeBSD 6 we use the default version of bind, not the port.
    if ($FBSD_VERSION < 6) {
800
801
802
803
804
	push(@strings, qq|named_enable="NO"|);
    }
    else {
	push(@strings, (qq|named_enable="YES"|,
			qq|named_chrootdir=""|,
805
			qq|named_flags=""|,
806
807
808
			qq|named_uid="root"|));
    }
    AppendToFileFatal($RCCONF, @strings);
809
810
};

811
#
812
813
# New version perl does not appear to require this anymore. In fact, it
# seems to break things if it is!
814
815
816
817
818
819
820
#
if ($FBSD_VERSION == 4) {
    Phase "suidperl", "Setting the suid bit on $SUIDPERL", sub {
	PhaseSkip("Already done") if (-u $SUIDPERL);
	ExecQuietFatal("$CHMOD u+s $SUIDPERL");
    };
}
821
822
823
824
825
826
else {
    Phase "suidperl", "UnSetting the suid bit on $SUIDPERL", sub {
	PhaseSkip("Already done") if (! -u $SUIDPERL);
	ExecQuietFatal("$CHMOD u-s $SUIDPERL");
    };
}
827

828
Phase "hosts", "Adding boss/ops/fs IP addresses to $HOSTS", sub {
829
    DoneIfEdited($HOSTS);
830
831
832
833
834
835
    my $hstr = "${BOSSNODE_IP}\t${BOSSNODE} boss".
	      "\n${USERNODE_IP}\t@OPS_NAMES";
    if ($USERNODE ne $FSNODE) {
	$hstr .= "\n${FSNODE_IP}\t${FSNODE} fs";
    }
    AppendToFileFatal($HOSTS, $hstr);
836
837
};

838
839
840
841
842
843
Phase "resolve", "Checking to make sure names for boss/ops/fs resolve", sub {
    my @hnames = (@OPS_NAMES, ${BOSSNODE}, "boss");
    if ($USERNODE ne $FSNODE) {
	push @hnames, ${FSNODE}, "fs";
    }
    foreach my $name (@hnames) {
Robert Ricci's avatar
Robert Ricci committed
844
845
	Phase $name, $name, sub {
	    if (gethostbyname($name)) {
846
		PhaseSucceed("$name resolves");
Robert Ricci's avatar
Robert Ricci committed
847
848
849
850
851
852
853
854
	    } else {
		PhaseFail("$name does not resolve - please see setup.txt\n" .
		    "for further instructions!");
	    }
	};
    }
};

855
856
857
858
859
860
861
862
863
864
865
866
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);
867
868
869
870
871
872
873
874
875
876
877
878
879
880
	my @lines = ("$FSNODE:$USERROOT\t\t$USERROOT\tnfs\trw,nodev,nosuid\t0\t0",
		     "$FSNODE:$PROJROOT\t\t$PROJROOT\tnfs\trw,nodev,nosuid\t0\t0",
		     "$FSNODE:$GROUPROOT\t\t$GROUPROOT\tnfs\trw,nodev,nosuid\t0\t0",
		     "$FSNODE:$SHAREROOT\t\t$SHAREROOT\tnfs\trw,nodev,nosuid\t0\t0");
	if ($SCRATCHDIR) {
	    push(@lines,
		 "$FSNODE:$SCRATCHROOT\t\t$SCRATCHROOT\tnfs\trw,nodev,nosuid\t0\t0");
	}
	push(@lines,
	     "$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");
	AppendToFileFatal($FSTAB, @lines);
881
882
883
884
885
886
887
888
889
    };
    Phase "mounts", "Mounting NFS filesystems", sub {
	foreach my $dir (@MOUNTPOINTS) {
	    Phase $dir, $dir, sub {
		DoneIfMounted($dir);
		ExecQuietFatal("$MOUNT -o '-R 1' $dir");
	    };
	}
    };
890
891
};

Leigh B. Stoller's avatar
Leigh B. Stoller committed
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
#
# Not needed in an inner elab, and it takes a long time.
#
if (! $ELABINELAB) {
    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);
	    };
	}
    };
}
907
908
909
910
911

Phase "cron", "Adding cron jobs", sub {
    Phase "crontab", "Editing $CRONTAB", sub {
	DoneIfEdited($CRONTAB);
	AppendToFileFatal($CRONTAB,
912
	    "0  \t6\t*\t*\t*\troot\t$PREFIX/sbin/audit",
913
	    "0  \t1\t*\t*\t*\troot\t$PREFIX/sbin/dbcheck",
914
915
916
	    "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");
917
918
919
920
921
    };
};

Phase "sudoers", "Editing $SUDOERS", sub {
    DoneIfEdited($SUDOERS);
Russ Fish's avatar
Russ Fish committed
922
923
924
    AppendToFileFatal($SUDOERS,
		      "%wheel    ALL=(ALL) NOPASSWD: ALL",
		      "Defaults  logfile=/var/log/sudo.log");
925
926
};

Robert Ricci's avatar
Robert Ricci committed
927
928
929
930
931
932
933
934
935
936
937
938
939
940
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");
};

941
Phase "ssh", "Setting up root ssh from boss to ops", sub {
Robert Ricci's avatar
Robert Ricci committed
942
943
    Phase "keygen", "Creating root private key", sub {
	DoneIfExists($ROOT_PRIVKEY);
944
	ExecQuietFatal("$SSH_KEYGEN -t rsa -P '' -f $ROOT_PRIVKEY");
Robert Ricci's avatar
Robert Ricci committed
945
    };
946
947
948
949
950
951
952
953
954
955
956
    #
    # Stick it into the DB.
    # WARNING: This sitevar (node/ssh_pubkey) is referenced in tmcd.c
    #
    Phase "sitevar", "Inserting pubkey into DB", sub {
	my $pubkey = `cat $ROOT_PUBKEY`;
	chomp $pubkey;
	ExecQuietFatal("echo \"update sitevariables set value='$pubkey' ".
		       "       where name='node/ssh_pubkey'\" | ".
		       "$MYSQL $DBNAME");
    };
Robert Ricci's avatar
Robert Ricci committed
957
958
959
960
961
    Phase "ssh", "Editing ssh config file", sub {
	DoneIfEdited($SSH_CONFIG);
	AppendToFileFatal($SSH_CONFIG,
	    "Host *",
	    "   StrictHostKeyChecking no",
962
	    "   Protocol 2,1");
Robert Ricci's avatar
Robert Ricci committed
963
    };
964
    Phase "keycopy", "Copy root ssh keys to ops and fs", sub {
Leigh B. Stoller's avatar
Leigh B. Stoller committed
965
	if (! ExecQuiet("$SSH -o 'BatchMode=yes' root\@${USERNODE} pwd")) {
966
967
	    PhaseSkip("Key already copied");
	} else {
968
	    ExecQuietFatal("$SCP_INIT -i $INIT_PRIVKEY ".
Leigh B. Stoller's avatar
Leigh B. Stoller committed
969
970
			   "$ROOT_PUBKEY ${USERNODE}:$ROOT_AUTHKEY");

971
972
973
974
	    # Copy hosts keys to ops.
	    ExecQuietFatal("cat ${ETCSSH}/*.pub | $SSH ${USERNODE} ".
			   "  '(cat > ${ETCSSH}/ssh_known_hosts)'");

Leigh B. Stoller's avatar
Leigh B. Stoller committed
975
	    if (ExecQuiet("$SSH -o 'BatchMode=yes' root\@${USERNODE} pwd")) {
976
977
978
		PhaseFail("You need to manually copy boss's public SSH key\n".
			  "over to $USERNODE so boss can get into it without\n".
			  "a password. Run the following as root:\n" .
Leigh B. Stoller's avatar
Leigh B. Stoller committed
979
980
			  "scp $ROOT_PUBKEY ${USERNODE}:$ROOT_AUTHKEY");
	    }
981
	}
982
    };
983
984
985
986
987
988
989
    Phase "keycopy2", "Copy root ssh keys to fs", sub {
	if ($USERNODE eq $FSNODE) {
	    PhaseSkip("FS node is ops node");
	}
	if (! ExecQuiet("$SSH -o 'BatchMode=yes' root\@${FSNODE} pwd")) {
	    PhaseSkip("Key already copied");
	} else {
990
	    ExecQuietFatal("$SCP_INIT -i $INIT_PRIVKEY ".
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
			   "$ROOT_PUBKEY ${FSNODE}:$ROOT_AUTHKEY");

	    # Copy hosts keys to fs.
	    ExecQuietFatal("cat ${ETCSSH}/*.pub | $SSH ${FSNODE} ".
			   "  '(cat > ${ETCSSH}/ssh_known_hosts)'");

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

1007
Phase "rndc", "Setting up rndc for control of nameserver", sub {
1008
1009
1010
1011
1012
1013
1014
1015
    my $RNDC_KEY     = "/etc/namedb/rndc.key";
    my $RNDC_CONFGEN = "/usr/sbin/rndc-confgen";

    # Bind9 port prior to FreeBSD6
    if ($FBSD_VERSION < 6) {
	$RNDC_KEY     = "/usr/local/etc/rndc.key";
	$RNDC_CONFGEN = "/usr/local/sbin/rndc-confgen";
    }
1016
1017
1018
1019
    DoneIfExists($RNDC_KEY);
    ExecQuietFatal("$RNDC_CONFGEN -a -r /dev/urandom");
};

1020
1021
1022
1023
1024
1025
1026
Phase "loader.conf", "Setting up $LOADER_CONF", sub {
    DoneIfEdited($LOADER_CONF);
    AppendToFileFatal($LOADER_CONF,
	"kern.hz=1000"
    );
};

1027
1028
1029
1030
1031
1032
1033
1034
Phase "sysctl.conf", "Setting up $SYSCTL_CONF", sub {
    DoneIfEdited($SYSCTL_CONF);
    AppendToFileFatal($SYSCTL_CONF,
	"net.local.dgram.maxdgram=65536",
	"net.local.dgram.recvspace=65536"
    );
};

1035
1036
1037
1038
1039
1040
1041
1042
1043
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");
    };
1044
    Phase "sslopscopy", "Copying SSL certificates to ops", sub {
1045
1046
 	ExecQuietFatal("$SSH -o 'BatchMode=yes' root\@${USERNODE} ".
		       "     mkdir -p ${ETC_EMULAB_DIR} ");
1047
1048
1049
1050
1051
 	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} ".
1052
1053
		       "     'chmod 640 ${ETC_EMULAB_DIR}/${CLIENT_PEM}; ".
		       "      chmod 640 ${ETC_EMULAB_DIR}/${EMULAB_PEM}'  ");
1054
    };
1055
    Phase "apache", "Setting up Apache on boss", sub {
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
	Phase "cert", "Installing Apache SSL certificate", sub {
	    DoneIfExists("$APACHE_CERTFILE");
	    ExecQuietFatal("$CP $TOP_OBJDIR/ssl/$APACHE_CERTPEM ".
			   "    $APACHE_CERTFILE");
	};
	Phase "key", "Installing Apache SSL key", sub {
	    DoneIfExists("$APACHE_KEYFILE");
	    ExecQuietFatal("$CP $TOP_OBJDIR/ssl/$APACHE_KEYPEM ".
			   "    $APACHE_KEYFILE");
	};
1066
	Phase "rc.d", "Installing Apache startup file", sub {
1067
1068
	    DoneIfExists("$RCDIR/apache.sh");
	    ExecQuietFatal("mv $RCDIR/apache.sh.sample $RCDIR/apache.sh");
1069
	    if ($FBSD_VERSION == 6) {
1070
1071
		ExecQuietFatal("sed -i .orig ".
			       "-e 's/^apache_enable/#apache_enable/' ".
1072
			       "$RCDIR/apache.sh");
1073
		ExecQuietFatal("/bin/rm -f $RCDIR/apache.sh.orig");
1074
	    }
1075
	};
1076
1077
1078
1079
	Phase "starting", "Starting Apache server", sub {
	    DoneIfExists("$VARRUN/httpd.pid");
	    ExecQuietFatal("$RCDIR/apache.sh start");
	};
1080
    };
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
    if ($FBSD_VERSION > 4) {
	Phase "apache", "Setting up Apache on ops", sub {
	    Phase "cert", "Installing Apache SSL certificate", sub {
		ExecQuietFatal("$SCP $TOP_OBJDIR/ssl/$APACHE_CERTPEM_OPS ".
			       "     ${USERNODE}:$APACHE_CERTFILE_OPS");
	    };
	    Phase "key", "Installing Apache SSL key", sub {
		ExecQuietFatal("$SCP $TOP_OBJDIR/ssl/$APACHE_KEYPEM_OPS ".
			       "     ${USERNODE}:$APACHE_KEYFILE_OPS");
	    };
	    Phase "rc.d", "Installing Apache startup file", sub {
1092
1093
		ExecQuietFatal("$SCP $RCDIR/apache.sh ".
			       "     ${USERNODE}:$RCDIR/apache.sh");
1094
1095
1096
	    };
	};
    }
1097
1098
};

Leigh B. Stoller's avatar
Leigh B. Stoller committed
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
if ($MAILMANSUPPORT) {
    my $secret = substr(GenSecretKey(), 0, 10);
    
    Phase "Mailman", "Setting up Mailman admin Password", sub {
	ExecQuietFatal("echo \"update sitevariables set value='$secret' ".
		       "       where name='general/mailman/password'\" | ".
		       "$MYSQL $DBNAME");
    };
}

1109
1110
Phase "event", "Setting up event system", sub {
    Phase "elvinconf", "Installing elvind config file", sub {
1111
	DoneIfIdentical($ELVIND_CONF,$BOSS_ELVIND_CONF);
1112
1113
	ExecQuietFatal("$CP $BOSS_ELVIND_CONF $ELVIND_CONF");
    };
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
    # For elabinelab, be sure to kill off running event system. Harmless.
    Phase "stopping", "Stopping event system", sub {
	if (ExecQuiet("killall -s elvind")) {
	    PhaseSkip("elvind not running");
	}
	ExecQuietFatal("$RCDIR/2.elvind.sh stop");
    };
    Phase "starting", "Starting event system", sub {
	ExecQuietFatal("$RCDIR/2.elvind.sh start");
    };
1124
1125
};

1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
#
# Build and install software. Note that I am not looking to see if its
# been done; I suppose we could touch a file to indicate that build has
# been completed, but maybe that is not such a good idea.
#
Phase "Software", "Building and Installing Software", sub {
    Phase "building", "Building (please be patient)", sub {
	ExecQuietFatal("cd $TOP_OBJDIR; $GMAKE");
    };
    Phase "installing", "Installing (please be patient)", sub {
	ExecQuietFatal("cd $TOP_OBJDIR; $GMAKE boss-install");
    };
    Phase "postinstall", "Post Installing Testbed Software", sub {
	ExecQuietFatal("cd $TOP_OBJDIR; $GMAKE post-install");
    };
};

1143
1144
1145
1146
#
# The next few items must be after the software install since they use
# testbed libraries and such.
#
1147
1148
Phase "dhcpd", "Setting up initial dhcpd configuration", sub {
    Phase "template", "Installing $DHCPD_TEMPLATE", sub {
Leigh B. Stoller's avatar
Leigh B. Stoller committed
1149
	ExecQuietFatal("cd $TOP_OBJDIR/dhcpd; $GMAKE install");
1150
1151
    };
    Phase "config", "Creating $DHCPD_CONF from template", sub {
Leigh B. Stoller's avatar
Leigh B. Stoller committed
1152
	ExecQuietFatal("$DHCPD_MAKECONF -i");
1153
1154
1155
1156
1157
1158
1159
1160
    };
    # How silly is this?
    Phase "leases", "Creating stub leases file", sub {
	DoneIfExists("$DHCPD_LEASES");
	ExecQuietFatal("touch $DHCPD_LEASES");
    };
};

1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
Phase "named", "Setting up initial named configuration", sub {
    Phase "building", "Building named files and templates", sub {
	ExecQuietFatal("cd $TOP_OBJDIR/named; $GMAKE");
    };
    Phase "installing", "Installing named files and templates", sub {
	ExecQuietFatal("cd $TOP_OBJDIR/named; $GMAKE install-real");
    };
    Phase "generating", "Generating named zone files", sub {
	ExecQuietFatal("$NAMED_SETUP -norestart");
    };
1171
    
1172
1173
    # Starting at 6.0 we use the default version of bind, not the port.
    my $named_control = ($FBSD_VERSION < 6 ?
1174
1175
			 "$RCDIR/1.named.sh" : "/etc/rc.d/named");
    
1176
1177
1178
1179
    Phase "stopping", "Stopping named", sub {
	if (ExecQuiet("killall -s named")) {
	    PhaseSkip("named not running");
	}
1180
	ExecQuietFatal("$named_control stop");
1181
1182
    };
    Phase "starting", "Starting named", sub {
1183
	ExecQuietFatal("$named_control start");
1184
    };
1185
1186

    # Lets make sure that old file is gone!
1187
    if ($FBSD_VERSION >= 6) {
1188
1189
1190
1191
1192
1193
1194
1195
1196
	Phase "cleanup", "Cleaning up old files", sub {
	    DoneIfDoesntExist("$RCDIR/1.named.sh");
	
	    if (!unlink "$RCDIR/1.named.sh") {
		PhaseFail("Unable to remove $RCDIR/1.named.sh: $!");
	    }
	};
    }
    
1197
1198
1199
1200
    Phase "copying", "Copying resolv.conf over to ops", sub {
 	ExecQuietFatal("$SCP $TOP_OBJDIR/named/resolv.conf.ops ".
		       "     ${USERNODE}:/etc/resolv.conf");
    };
1201
1202
1203
1204
1205
1206
1207
    Phase "copying2", "Copying resolv.conf over to fs", sub {
	if ($USERNODE eq $FSNODE) {
	    PhaseSkip("FS node is ops node");
	}
 	ExecQuietFatal("$SCP $TOP_OBJDIR/named/resolv.conf.ops ".
		       "     ${FSNODE}:/etc/resolv.conf");
    };
1208
1209
};

1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
if ($BUGDBSUPPORT) {
    my $BUGDBPROXY  = "$PREFIX/sbin/bugdbproxy";

    Phase "flyspray", "Finalizing flyspray installation", sub {
	PhaseSkip("flyspray not supported")
	    if ($FBSD_VERSION < 6);

 	ExecQuietFatal("$SSH -o 'BatchMode=yes' root\@${USERNODE} ".
		       "     '$BUGDBPROXY setup' ");
    };
}

1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
Phase "firstuser", "Setting up initial user ($PROTOUSER)", sub {
    Phase "firstuser", "Calling 'firstuser' to create account", sub {
	PhaseSkip("$PROTOUSER already created")
	    if (-d "$USERROOT/$PROTOUSER");
	ExecQuietFatal("perl $TOP_OBJDIR/utils/firstuser -b ".
		       (defined($password) ? " -p $password" : ""));
    };
    Phase "Fixing", "Fixing up DB state for $PROTOUSER", sub {
	my ($exitval, @rows) =
	    ExecQuiet("echo 'select uid from users ".
		      "  where uid=\"$PROTOUSER\" and webonly=0' ".
		      "| $MYSQL -s $DBNAME");
	if ($exitval) {
	    PhaseFail("Error running query");
	}
	if (scalar @rows) {
	    PhaseSkip("Already done");
	}
	ExecQuietFatal("echo 'update users set webonly=0 ".
		       "  where uid=\"$PROTOUSER\"' | $MYSQL -s $DBNAME");
    };
    Phase "Thawing", "Thawing $PROTOUSER", sub {
	my ($exitval, @rows) =
	    ExecQuiet("echo 'select uid from users ".
		      "  where uid=\"$PROTOUSER\" and status=\"active\"' ".
		      "| $MYSQL -s $DBNAME");
	if ($exitval) {
	    PhaseFail("Error running query");
	}
	if (scalar @rows) {
	    PhaseSkip("Already done");
	}
	ExecQuietFatal("echo 'update users set status=\"active\" ".
		       "  where uid=\"$PROTOUSER\"' | $MYSQL -s $DBNAME");
	ExecQuietFatal("$SUDO -u $PROTOUSER $WAP $TBACCT -b thaw $PROTOUSER");
    };
    Phase "DSAKey", "Adding DSA key to $PROTOUSER account", sub {
	my ($exitval, @rows) =
	    ExecQuiet("echo 'select * from user_pubkeys ".
		      " where uid=\"$PROTOUSER\"' | $MYSQL -s $DBNAME");
	if ($exitval) {
	    PhaseFail("Error running query");
	}
	if (scalar @rows) {
	    PhaseSkip("Already done");
	}
	ExecQuietFatal("$SUDO -u $PROTOUSER $WAP ".
		       "  $ADDPUBKEY -f -u $PROTOUSER $PROTOUSER_KEY");
    };
    Phase "authkeys", "Generating authorized_keys for $PROTOUSER", sub {
	ExecQuietFatal("$SUDO -u $PROTOUSER $WAP $ADDPUBKEY -w $PROTOUSER");
    };
1274
1275
};

1276
1277
	exit(0);

Timothy Stack's avatar
   
Timothy Stack committed
1278
1279
Phase "chkupuser", "Setting up checkup user (elabckup)", sub {
    PhaseSkip("elabckup already created")
1280
	if (-d "$USERROOT/elabckup");
Timothy Stack's avatar
   
Timothy Stack committed
1281
1282
    ExecQuietFatal("perl $TOP_OBJDIR/utils/firstuser -b ".
		   (defined($password) ? " -p $password" : "").
Timothy Stack's avatar
Timothy Stack committed
1283
		   " -u elabckup -n 'Emulab Checkup User' ".
Timothy Stack's avatar
   
Timothy Stack committed
1284
1285
1286
		   "-e '@TBTESTSUITEEMAIL@'");
};

1287
1288
1289
1290
1291
1292
1293
Phase "experiments", "Setting up system experiments", sub {
    foreach my $eid (keys(%EXPERIMENTS)) {
	my $pid  = $EXPERIMENTS{$eid}->{"pid"};
	my $desc = $EXPERIMENTS{$eid}->{"description"};
	
	Phase "$pid/$eid", "$pid/$eid", sub {
	    PhaseSkip("Experiment Created")
1294
		if (-d "$PROJROOT/$pid/exp/$eid");
1295
	    ExecQuietFatal("$SUDO -u $PROTOUSER $WAP $BATCHEXP ".
1296
			   "  -q -i -w -f -n -S 'System Experiment' ".
1297
1298
1299
1300
1301
1302
1303
			   "  -L 'System Experiment' ".
			   "  -E '$desc - DO NOT DELETE' ".
			   "  -p $pid -e $eid");
	};
    }
};

1304
1305
1306
1307
1308
print "----------------------------------------------------------------------\n";
print "Installation completed succesfully!\n";
print "Please reboot this machine before proceeding with boss setup\n";

exit 0;