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

#
# EMULAB-COPYRIGHT
5
# Copyright (c) 2003-2011 University of Utah and the Flux Group.
6 7 8 9
# All rights reserved.
#

#
Robert Ricci's avatar
Robert Ricci committed
10
# ops-install - Script to do the initial install of an ops node
11 12 13 14 15
#
# The main things it does not do yet:
# * Figure out where to put directories such as /users /proj - they must
#   already exist
# * Fill out mailing list files - presumably, it's easier to just get the
16
#   User to edit them himself
17 18 19 20 21 22 23
#

#
# Configure variables
#
my $PREFIX = '@prefix@';

Robert Ricci's avatar
Robert Ricci committed
24
my @MAILING_LISTS = ("@TBOPSEMAIL@","@TBLOGSEMAIL@","@TBWWWEMAIL@",
25
    "@TBAPPROVALEMAIL@","@TBAUDITEMAIL@","@TBSTATEDEMAIL@",
26
    "@TBTESTSUITEEMAIL@", "@TBERRORSEMAIL@", "@TBAUTOMAILEMAIL@");
Robert Ricci's avatar
Robert Ricci committed
27

28

29 30 31 32 33 34
my $OURDOMAIN   = '@OURDOMAIN@';
my $USERNODE    = '@USERNODE@';
my $FSNODE      = '@FSNODE@';
my $BOSSNODE    = '@BOSSNODE@';
my $BOSSNODE_IP = '@BOSSNODE_IP@';
my $USERNODE_IP = '@USERNODE_IP@';
35
my $FSNODE_IP   = '@FSNODE_IP@';
36
my $LOGFACIL    = '@TBLOGFACIL@';
37
my $TBOPSEMAIL  = '@TBOPSEMAIL@';
38
my $ELABINELAB  = @ELABINELAB@;
39
my $WINSUPPORT  = @WINSUPPORT@;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
40
my $MAILMANSUPPORT = @MAILMANSUPPORT@;
41
my $CVSSUPPORT  = @CVSSUPPORT@;
42
my $BUGDBSUPPORT= @BUGDBSUPPORT@;
43
my $WIKISUPPORT = @WIKISUPPORT@;
44
my $QUOTA_FSLIST= '@FS_WITH_QUOTAS@';
45
my $ETCDIR      = "$PREFIX/etc";
46
my $LIBDIR      = "$PREFIX/lib";
47
my $SCRATCHDIR =  '@FSDIR_SCRATCH@';
Mike Hibler's avatar
Mike Hibler committed
48
my $NOSHAREDFS  = @NOSHAREDFS@;
Robert Ricci's avatar
Robert Ricci committed
49 50 51
my $OUTER_BOSS = '@OUTERBOSS_NODENAME@';
if ($OUTER_BOSS eq '')
    { $OUTER_BOSS = "www.emulab.net"; }
52 53 54 55 56 57 58 59

#
# Fixed paths for clients
#
my $GROUPROOT   = "@GROUPSROOT_DIR@";
my $USERROOT    = "@USERSROOT_DIR@";
my $SCRATCHROOT	= "@SCRATCHROOT_DIR@";
my $SHAREROOT	= "@SHAREROOT_DIR@";
60
my $ELVIN_COMPAT= @ELVIN_COMPAT@;
61

62
# True if we are also the FS node
63
my $ISFS	= ($USERNODE_IP eq $FSNODE_IP) ? 1 : 0;
64

65 66 67
# Are we a VM on boss?
my $OPSVM_ENABLE = @OPSVM_ENABLE@;

68 69 70 71
# For /share export below.
my $CONTROL_NETWORK = "@CONTROL_NETWORK@";
my $CONTROL_NETMASK = "@CONTROL_NETMASK@";

72 73 74
# Should be configure variable
my $TBADMINGID  = 101;

Mike Hibler's avatar
Mike Hibler committed
75 76 77
# XXX temporary for perl DBD mysql access
my $P5DBD_PKG	  = "p5-DBD-mysql50-3.0002";

78
#
Robert Ricci's avatar
Robert Ricci committed
79
# Allow this to work if the library is left in the source directory
80
#
Robert Ricci's avatar
Robert Ricci committed
81 82 83 84
use lib '@srcdir@';
   
use English;
use libinstall;
85 86 87 88 89 90
use Getopt::Std;

#
# Handle command-line options
#
sub usage {
91 92 93
    print "Usage: ops-install [-b] [-p packagedir] [-s] " .
	"[-P ops-portname] [-F fs-portname]\n";
    print "  Required: -p (for binary packages) or -s (for source makes.)\n";
94 95 96
    exit(1);
}

97
# Version of FreeBSD.
98 99 100 101 102
my $FBSD_MAJOR = 4;
my $FBSD_MINOR = 10;
if (`uname -r` =~ /^(\d+)\.(\d+)/) {
    $FBSD_MAJOR = $1;
    $FBSD_MINOR = $2;
103 104 105 106 107
}
else {
    die("Could not determine what version of FreeBSD you are running!\n");
}

108
#
109 110
# The meta-ports (name and version) that drag in all the dependancies for
# an ops/fs node. These are OS dependent as we upgrade.
111
#
112 113 114
my $OPS_PORT = "emulab-ops-1.4"; 
my $FS_PORT = "emulab-fs-1.4";
if ($FBSD_MAJOR > 4) {
Mike Hibler's avatar
Mike Hibler committed
115 116 117 118 119 120 121 122
    if ($FBSD_MAJOR > 7) {
	# XXX someday...
	$OPS_PORT = "emulab-ops-4.0";
	$FS_PORT = "emulab-fs-4.0";
    } elsif ($FBSD_MAJOR == 7 && $FBSD_MINOR > 2) {
	$OPS_PORT = "emulab-ops-3.1";
	$FS_PORT = "emulab-fs-3.1";
    } elsif ($FBSD_MAJOR == 7) {
123 124 125
	$OPS_PORT = "emulab-ops-3.0";
	$FS_PORT = "emulab-fs-3.0";
    } elsif ($FBSD_MAJOR == 6 && $FBSD_MINOR > 2) {
126 127 128 129 130 131 132
	$OPS_PORT = "emulab-ops-2.1";
	$FS_PORT = "emulab-fs-2.1";
    } else {
	$OPS_PORT = "emulab-ops-2.0";
	$FS_PORT = "emulab-fs-2.0";
    }
}
Mike Hibler's avatar
Mike Hibler committed
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152

# PHP5 is the only alternative at the moment and only for newer OSes
my $PHP_VERSION = 4;
my $PHP_PORT = "php4-extensions-1.0";
if ($FBSD_MAJOR > 7 || ($FBSD_MAJOR == 7 && $FBSD_MINOR > 2)) {
    $PHP_VERSION = 5;
    $PHP_PORT = "php5-extensions-1.3";
}

#
# Version dependent python-fu 
#
my $PYM2_PKG = "py25-m2crypto-0.19.1";
my $PY_VER = "python2.5";
if ($FBSD_MAJOR > 7 || ($FBSD_MAJOR == 7 && $FBSD_MINOR > 2)) {
    $PYM2_PKG = "py26-m2crypto-0.20";
    $PY_VER = "python2.6";
}
# XXX temporary until someone extracts their head from the dark regions
my $EASYINSTALL	  = "/usr/local/bin/easy_install";
153

154
my $packagedir = "";
155
my $batchmode  = 0;
156
my $domakes  = 0;
157
my $password;
158
my %opts;
159
if (! getopts("P:p:bsw:F:", \%opts)) {
160 161 162 163
    usage();
}
if (defined($opts{p})) {
    $packagedir = $opts{p};
164
}
165
if (defined($opts{b})) {
166 167
    $batchmode = 1;
}
168 169 170
if (defined($opts{s})) {
    $domakes = 1;
}
171 172 173
if (defined($opts{P})) {
    $OPS_PORT = $opts{P};
}
174 175 176 177 178 179
if (defined($opts{F})) {
    $FS_PORT = $opts{F};
}
if (defined($opts{w})) {
    $password = $opts{w};
}
180 181 182 183 184 185 186 187 188
# 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();
}
189 190 191
if (@ARGV) {
    usage();
}
192

193 194 195 196 197 198 199 200
#
# 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/..";

201
#
Robert Ricci's avatar
Robert Ricci committed
202
# Some programs we use
203
#
Robert Ricci's avatar
Robert Ricci committed
204 205
my $CHGRP      = "/usr/bin/chgrp";
my $CHMOD      = "/bin/chmod";
206
my $CHOWN      = "/usr/sbin/chown";
Robert Ricci's avatar
Robert Ricci committed
207
my $PW         = "/usr/sbin/pw";
208
my $PATCH      = "/usr/bin/patch";
Robert Ricci's avatar
Robert Ricci committed
209
my $NEWALIASES = "/usr/bin/newaliases";
210
my $SH         = "/bin/sh";
211
my $PKG_ADD    = "/usr/sbin/pkg_add";
Mike Hibler's avatar
Mike Hibler committed
212
my $PKG_DEL    = "/usr/sbin/pkg_delete";
213
my $PWD        = "/bin/pwd";
214
my $CP         = "/bin/cp";
215
my $MV         = "/bin/mv";
216
my $ENV        = "/usr/bin/env";
217
my $MOUNT      = "/sbin/mount";
218 219
my $TAR	       = "/usr/bin/tar";
my $MD5	       = "/sbin/md5";
220 221

#
Robert Ricci's avatar
Robert Ricci committed
222
# Some files we edit/create
223
#
Robert Ricci's avatar
Robert Ricci committed
224
my $RCCONF          = "/etc/rc.conf";
225
my $HOSTS           = "/etc/hosts";
226
my $FSTAB           = "/etc/fstab";
Robert Ricci's avatar
Robert Ricci committed
227 228
my $RCLOCAL         = "/etc/rc.local";
my $RCCAPTURE       = "$PREFIX/etc/rc.capture";
Robert Ricci's avatar
Robert Ricci committed
229 230
my $LOCAL_HOSTNAMES = "/etc/mail/local-host-names";
my $ALIASES_FILE    = "/etc/mail/aliases";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
231
my $SENDMAIL_CF     = "/etc/mail/sendmail.cf";
Robert Ricci's avatar
Robert Ricci committed
232 233 234 235 236
my $EXPORTS_FILE    = "/etc/exports";
my $EXPORTS_HEAD    = "$EXPORTS_FILE.head";
my $SYSLOG_CONF     = "/etc/syslog.conf";
my $NEWSYSLOG_CONF  = "/etc/newsyslog.conf";
my $SUDOERS         = "/usr/local/etc/sudoers";
237
my $SSHD_CONFIG     = "/etc/ssh/sshd_config";
238
my $CRONTAB         = "/etc/crontab";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
239
my $AUTHKEYS	    = "/root/.ssh/authorized_keys";
Kirk Webb's avatar
 
Kirk Webb committed
240 241
my $SMBCONF_FILE    = "/usr/local/etc/smb.conf";
my $SMBCONF_HEAD    = "$SMBCONF_FILE.head";
242 243
my $APACHE_ETCDIR   = "/usr/local/etc/apache";
my $HTTPD_CONF      = "$APACHE_ETCDIR/httpd.conf";
244
my $PHP_INI         = "/usr/local/etc/php.ini";
245
my $WWWDIR          = "/usr/local/www/data";
246 247 248 249 250 251 252 253

# For installing mysqld
my $MYSQLADMIN      = "/usr/local/bin/mysqladmin";
my $MYSQLSHOW       = "/usr/local/bin/mysqlshow";
my $MYSQLDUMP       = "/usr/local/bin/mysqldump";
my $MYSQLINSTALL    = "/usr/local/bin/mysql_install_db";
my $MYSQLDBDIR      = "/var/db/mysql";
my $MYSQL_LOGDIR    = "$LOGDIR/mysql";
254 255

#
Robert Ricci's avatar
Robert Ricci committed
256
# Some directories we care about
257
#
258 259 260 261
my $LIST_DIR      = "/etc/mail/lists";
my $TIPLOG_DIR    = "/var/log/tiplogs";
my $PORTSMISCDIR  = "$PORTSDIR/misc";
my $SRCDIR        = '@srcdir@';
262 263

#
Robert Ricci's avatar
Robert Ricci committed
264
# And some lists that we use
265
#
266 267
my @LOCAL_HOSTS        = ($OURDOMAIN,$BOSSNODE,$USERNODE,$FSNODE);
my @LOGFILES           = ("/var/log/logins","/var/log/tiplogs/capture.log",
268 269
    "/var/log/mountd.log", "$LOGDIR/pubsubd.log", "$LOGDIR/elvin_gateway.log");

270 271
my @LOCAL_MAILING_LISTS = grep(/$OURDOMAIN$/,@MAILING_LISTS);
my @MAILING_LIST_NAMES  = map { /^([\w-]+)\@/ } @LOCAL_MAILING_LISTS;
Robert Ricci's avatar
Robert Ricci committed
272

273 274 275
my @TESTBED_DIRS       = ([$PREFIX, "0775"], [$USERROOT, "0755"],
			  [$PROJROOT, "0755"], [$GROUPROOT, "0755"],
			  [$SHAREROOT, "0775"]);
276

277 278 279 280 281 282
my @MOUNTPOINTS        = ($USERROOT, $PROJROOT, $GROUPROOT, $SHAREROOT);

if ($SCRATCHDIR) {
    push(@TESTBED_DIRS, [$SCRATCHROOT, "0755"]);
    push(@MOUNTPOINTS, $SCRATCHROOT);
}
283

284 285 286
#
# A few files we have to deal with
#
287
my $M2CRYPTO_PATCH  = "$TOP_SRCDIR/patches/m2crypto.patch";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
288
my $MAILMAN_PATCH   = "$TOP_SRCDIR/patches/mailman.patch";
289
my $SELFLOAD_PATCH  = "$TOP_SRCDIR/patches/SelfLoader.patch";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
290
my $IDENTPUB        = "$TOP_SRCDIR/install/identity.pub";
291

292 293 294 295
#
# List of names that goes into $HOSTS and which must resolve.
# 
my @OPS_NAMES = ($USERNODE, "users", "ops");
296 297 298
if ($ISFS) {
    push(@OPS_NAMES, "fs");
}
299

300
#
Robert Ricci's avatar
Robert Ricci committed
301
# Make sure they know what they're getting into...
302
#
303 304 305 306
if (! $batchmode) {
    print STDERR
	"WARNING: This script is ONLY intended to be run on a machine\n";
    print STDERR
307
	"that is being set up as a dedicated ops or ops+fs node. Continue? [y/N] ";
308 309 310
    my $response = <>;
    die "Installation aborted!\n" unless ($response =~ /^y/i);
}
311

Robert Ricci's avatar
Robert Ricci committed
312 313
if ($UID != 0) {
    die "This script must be run as root.\n";
314 315 316
}

#
Robert Ricci's avatar
Robert Ricci committed
317
# The phases are fairly self-explanatory
318
#
319 320 321 322 323 324 325
Phase "sperl", "Checking for setuid perl", sub {
    if (ExecQuiet("$PKG_INFO -L -x perl-5 | fgrep -q -s sperl") == 0) {
	PhaseSkip("Perl is okay");
    }
    PhaseFail("setuid perl is not set up properly. Read the wiki!");
};

326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348
Phase "usersgroups", "Creating users and groups", sub {
    Phase "tbadmin", "Creating tbadmin group", sub {
	if (getgrnam("tbadmin")) {
	    PhaseSkip("tbadmin group already exists");
	}
	ExecQuietFatal("$PW groupadd tbadmin -g $TBADMINGID");
    };
    # 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 $MYSQLDBDIR -s /sbin/nologin -c 'MySQL Daemon'");
    };
    ExecQuietFatal("$CHOWN mysql:mysql $MYSQLDBDIR")
	if (-e $MYSQLDBDIR);
Robert Ricci's avatar
Robert Ricci committed
349 350 351
};

Phase "dirs", "Setting directory permissions", sub {
Robert Ricci's avatar
Robert Ricci committed
352 353
    foreach my $dirref (@TESTBED_DIRS) {
	my ($dir, $newmode) = @$dirref;
Robert Ricci's avatar
Robert Ricci committed
354 355 356 357
	Phase $dir, $dir, sub {
	    if (!-d $dir) {
		PhaseFail("Directory $dir does not exist");
	    }
Robert Ricci's avatar
Robert Ricci committed
358 359 360 361
	    # Use the real path, to avoid symlink problems
	    my $realdir = `realpath $dir`;
	    chomp $realdir;
	    my ($mode,$group) = (stat($realdir))[2,5];
Robert Ricci's avatar
Robert Ricci committed
362 363
	    # Fix up the mode (strip file type)
	    $mode = $mode & 0777;
Robert Ricci's avatar
Robert Ricci committed
364
	    if ($mode == eval $newmode && $group eq getgrnam("tbadmin")) {
Robert Ricci's avatar
Robert Ricci committed
365 366
		PhaseSkip("Already done");
	    }
Robert Ricci's avatar
Robert Ricci committed
367 368
	    ExecQuietFatal("$CHGRP tbadmin $realdir");
	    ExecQuietFatal("$CHMOD $newmode $realdir");
Robert Ricci's avatar
Robert Ricci committed
369
	};
370
    }
Robert Ricci's avatar
Robert Ricci committed
371
};
372

373
Phase "ports", "Installing ports", sub {
374
    Phase "packages", "Installing packages", sub {
375 376 377 378 379 380 381 382 383
	Phase "main", "Installing main package", sub {
	    if (!ExecQuiet("$PKG_INFO -e $OPS_PORT")) {
		PhaseSkip("Package already installed");
	    }
	    if (!$packagedir) {
		PhaseSkip("No package directory provided");
	    }
	    ExecQuietFatal("$ENV PKG_PATH=$packagedir $PKG_ADD $OPS_PORT");
	};
384
	if ($FBSD_MAJOR > 4) {
Mike Hibler's avatar
Mike Hibler committed
385 386
	    Phase "php", "Installing php${PHP_VERSION} package", sub {
		if (!ExecQuiet("$PKG_INFO -e $PHP_PORT")) {
387 388 389 390 391
		    PhaseSkip("Package already installed");
		}
		if (!$packagedir) {
		    PhaseSkip("No package directory provided");
		}
Mike Hibler's avatar
Mike Hibler committed
392 393 394 395
		# XXX ugh, make sure an older version is not installed
		if ($PHP_VERSION > 4) {
		    ExecQuiet("$PKG_DEL -f -x php4-");
		}
396
		ExecQuietFatal("$ENV PKG_PATH=$packagedir ".
Mike Hibler's avatar
Mike Hibler committed
397
			       "     $PKG_ADD $PHP_PORT");
398
	    };
399
	}
400 401
	# XXX Also temporary
	Phase "pubsub", "Installing pubsub package", sub {
402 403 404
	    my $pspkg = $ELVIN_COMPAT ? "pubsub-elvincompat" : "pubsub";
	    if (!ExecQuiet("$PKG_INFO -x $pspkg")) {
		PhaseSkip("$pspkg already installed");
405
	    }
406
	    my $pname = GetPackage($pspkg, $packagedir);
407 408
	    ExecQuietFatal("$ENV PKG_PATH=$packagedir $PKG_ADD $pname");
	};
Mike Hibler's avatar
Mike Hibler committed
409
	# XXX Ditto
410
	if ($FBSD_MAJOR > 6 || ($FBSD_MAJOR == 6 && $FBSD_MINOR > 2)) {
Mike Hibler's avatar
Mike Hibler committed
411 412 413 414 415 416 417 418 419 420 421 422 423
	    Phase "p5-DBD-mysql50", "Installing old Perl Mysql package", sub {
		my $pname = `$PKG_INFO -E 'p5-DBD-mysql50-*' 2>/dev/null`;
		chomp($pname);
		if ($pname eq $P5DBD_PKG) {
		    PhaseSkip("p5-DBD-mysql50 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 $P5DBD_PKG");
	    };
Mike Hibler's avatar
Mike Hibler committed
424
	    # XXX cannot seem to get these dependencies into emulab-ops
425 426
	    if ($FBSD_MAJOR > 6) {
		Phase "py-m2crypto", "Installing python m2crypto package", sub {
Mike Hibler's avatar
Mike Hibler committed
427
		    my $pname = `$PKG_INFO -E 'py*-m2crypto-*' 2>/dev/null`;
428 429
		    chomp($pname);
		    if ($pname eq $PYM2_PKG) {
Mike Hibler's avatar
Mike Hibler committed
430
			PhaseSkip("py-m2crypto already up to date");
431 432 433 434 435 436 437 438 439
		    }
		    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 $PYM2_PKG");
		};
	    }
Mike Hibler's avatar
Mike Hibler committed
440
	}
441
    };
442 443 444 445 446 447 448 449 450 451 452 453
    Phase "fs-packages", "Installing FS packages", sub {
	if (!$ISFS) {
	    PhaseSkip("Not FS Node");
	}
	if (!ExecQuiet("$PKG_INFO -e $FS_PORT")) {
	    PhaseSkip("FS ports already installed");
	}
	if (!$packagedir) {
	    PhaseSkip("No package directory provided");
	}
	ExecQuietFatal("$ENV PKG_PATH=$packagedir $PKG_ADD $FS_PORT");
    };
Leigh B. Stoller's avatar
Leigh B. Stoller committed
454 455
    if ($MAILMANSUPPORT) {
	Phase "mailman", "Installing Mailman package", sub {
456
	    if (!ExecQuiet("$PKG_INFO -x -E mailman")) {
Leigh B. Stoller's avatar
Leigh B. Stoller committed
457 458 459 460 461
		PhaseSkip("Mailman package already installed");
	    }
	    if (!$packagedir) {
		PhaseSkip("No package directory provided");
	    }
462
	    my $pname = GetPackage("mailman", $packagedir);
Leigh B. Stoller's avatar
Leigh B. Stoller committed
463 464 465
	    ExecQuietFatal("$ENV PKG_PATH=$packagedir $PKG_ADD $pname");
	};
    }
466 467 468
    if ($CVSSUPPORT) {
	Phase "cvsd", "Installing cvsd package", sub {
	    PhaseSkip("cvsd not supported on ops")
469
		if ($FBSD_MAJOR < 6);
470

471
	    if (!ExecQuiet("$PKG_INFO -x -E cvsd")) {
472 473 474 475 476
		PhaseSkip("cvsd package already installed");
	    }
	    if (!$packagedir) {
		PhaseSkip("No package directory provided");
	    }
477
	    my $pname = GetPackage("cvsd", $packagedir);
478 479 480
	    ExecQuietFatal("$ENV PKG_PATH=$packagedir $PKG_ADD $pname");
	};
    }
481 482 483
    if ($BUGDBSUPPORT) {
	Phase "flyspray", "Installing flyspray package support", sub {
	    PhaseSkip("flyspray not supported on ops")
484
		if ($FBSD_MAJOR < 6);
485

486
	    if (!ExecQuiet("$PKG_INFO -x -E adodb")) {
487 488 489 490 491
		PhaseSkip("adodb package already installed");
	    }
	    if (!$packagedir) {
		PhaseSkip("No package directory provided");
	    }
492
	    my $pname = GetPackage("adodb", $packagedir);
493 494 495
	    ExecQuietFatal("$ENV PKG_PATH=$packagedir $PKG_ADD $pname");
	};
    }
496
    PhaseSkip("Package directory provided; not installing from sources")
Leigh B. Stoller's avatar
Leigh B. Stoller committed
497 498
	if ($packagedir);
    
499
    Phase "pcopy", "Copying ports into place", sub {
500
	DoneIfExists("$PORTSMISCDIR/emulab-ops");
501 502
	ExecQuietFatal("$SH $SRCDIR/ports/ports-install");
    };
503 504
    my $pwd = `$PWD`;
    chomp $pwd;
505
    Phase "pinstall", "Installing ports (may take a while)", sub {
506
	if (!ExecQuiet("$PKG_INFO -e $OPS_PORT")) {
507 508 509 510 511 512
	    PhaseSkip("Ports already installed");
	}

	#
	# This port is dead-simple, so it's safe to do it from this script
	#
513 514
	chdir "$PORTSMISCDIR/emulab-ops" or
		PhaseFail "Unable to change to $PORTSMISCDIR/emulab-ops: $!";
515
	ExecQuietFatal("make -DBATCH install");
516
    };
517 518 519 520 521 522 523 524 525 526 527
    Phase "fs-pinstall", "Installing FS ports (may take a while)", sub {
	if (!$ISFS) {
	    PhaseSkip("Not FS Node");
	}
	if (!ExecQuiet("$PKG_INFO -e $FS_PORT")) {
	    PhaseSkip("Ports already installed");
	}
	chdir "$PORTSMISCDIR/emulab-fs" or
	    PhaseFail "Unable to change to $PORTSMISCDIR/emulab-fs: $!";
	ExecQuietFatal("make -DBATCH install");
    };
Mike Hibler's avatar
Mike Hibler committed
528 529
    Phase "php-pinstall", "Installing PHP${PHP_VERSION} ports (may take a while)", sub {
	if (!ExecQuiet("$PKG_INFO -e $PHP_PORT")) {
Leigh B. Stoller's avatar
Leigh B. Stoller committed
530 531
	    PhaseSkip("Ports already installed");
	}
Mike Hibler's avatar
Mike Hibler committed
532 533 534 535 536 537
	# XXX ugh, make sure an older version is not installed
	if ($PHP_VERSION > 4) {
	    ExecQuiet("$PKG_DEL -f -x php4-");
	}
	chdir "$PORTSMISCDIR/emulab-php${PHP_VERSION}" or
	    PhaseFail "Unable to change to $PORTSMISCDIR/emulab-php${PHP_VERSION}: $!";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
538 539 540 541 542 543 544 545 546 547 548 549 550
	ExecQuietFatal("make -DBATCH install");
    };
    if ($MAILMANSUPPORT) {
	Phase "mailman-pinstall", "Installing mailman ports", sub {
	    if (!ExecQuiet("$PKG_INFO -x -e mailman")) {
		PhaseSkip("Ports already installed");
	    }
	    chdir "$PORTSMISCDIR/emulab-mailman" or
		PhaseFail("Unable to change to ".
			  "$PORTSMISCDIR/emulab-mailman: $!");
	    ExecQuietFatal("make -DBATCH install");
	};
    }
551
    chdir $pwd;
552 553
};

554 555
# XXX Temporary.
Phase "portfixup", "Fixing up packages", sub {
556
    Phase "rsync", "Looking for rsync and installing", sub {
557 558 559
	if (!ExecQuiet("$PKG_INFO -x rsync")) {
	    PhaseSkip("rsync already installed");
	}
560 561
	my $pname = GetPackage("rsync", $packagedir);
	ExecQuietFatal("$ENV PKG_PATH=$packagedir $PKG_ADD $pname");
562
    };
563 564
    if ($WINSUPPORT) {
	Phase "samba", "Looking for Samba and installing", sub {
565 566 567
	    if (!$ISFS) {
		PhaseSkip("Not FS Node");
	    }
568 569 570
	    if (!ExecQuiet("$PKG_INFO -x samba")) {
		PhaseSkip("samba already installed");
	    }
571 572
	    my $pname = GetPackage("samba", $packagedir);
	    ExecQuietFatal("$ENV PKG_PATH=$packagedir $PKG_ADD $pname");
573 574
	};
	Phase "gcc30", "Looking for GCC 3.0 and installing", sub {
575
	    if ($FBSD_MAJOR > 4 ||
576
		!ExecQuiet("$PKG_INFO -x gcc30")) {
577
		PhaseSkip("GCC 3.0 or greater already installed");
578
	    }
579 580
	    my $pname = GetPackage("gcc30", $packagedir);
	    ExecQuietFatal("$ENV PKG_PATH=$packagedir $PKG_ADD $pname");
581 582
	};
    }
583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602
    if ($FBSD_MAJOR > 6) {
	#
	# What a crock!  First, that the FreeBSD ports system
	# defaults to installing the zipped .egg files that have
	# to be unzipped per-user before use.  Second, that it
	# offers no easy way at package creation to override this.
	# Third, that there is no easy way that I could find in
	# the python eggs system to set a global cache directory
	# into which to unpack all eggs; you have to set
	# PYTHON_EGG_CACHE in the environment of every script.
	# Fourth, that the per-user default value might be in an
	# unwritable location.
	#
	# So, I am reduced to manually unpacking all .egg files
	# into the corresponding .egg directories after the
	# install!  Since this would totally screw any attempt
	# to update those packages, I just do it to the one
	# package that I know will fail otherwise.
	#
	Phase "m2crypto-egg", "Unpacking python m2crypto .egg", sub {
Mike Hibler's avatar
Mike Hibler committed
603 604
	    my $pydir = "/usr/local/lib/$PY_VER/site-packages";
	    my $egg = `ls -d $pydir/M2Crypto-*-py*-*.egg 2>/dev/null | tail -1`;
605 606 607 608 609
	    chomp($egg);
	    if (! -x $EASYINSTALL) {
		PhaseSkip("python easy_install missing");
	    }
	    if ($egg eq "") {
Mike Hibler's avatar
Mike Hibler committed
610
		PhaseSkip("egg not found");
611 612
	    }
	    if (-d "$egg") {
Mike Hibler's avatar
Mike Hibler committed
613
		PhaseSkip("egg already unpacked");
614
	    }
Mike Hibler's avatar
Mike Hibler committed
615 616 617 618 619 620
	    # XXX swig must be installed for easyinstall to exit correctly
	    Phase "swig", "Installing swig", sub {
		DoneIfPackageInstalled("swig");
		my $pname = GetPackage("swig", $packagedir);
		ExecQuietFatal("$ENV PKG_PATH=$packagedir $PKG_ADD $pname");
	    };
621 622
	    ExecQuietFatal("mv $egg /var/tmp/");
	    $egg =~ s/$pydir//;
Mike Hibler's avatar
Mike Hibler committed
623
	    ExecQuietFatal("$EASYINSTALL -N -H None -Z /var/tmp$egg");
624 625 626
	    ExecQuietFatal("mv /var/tmp$egg $pydir/$egg.bak");
	};
    }
627 628
};

629
Phase "patches", "Applying patches", sub {
630 631 632
    if ($FBSD_MAJOR < 7) {
	Phase "m2cryptopatch", "Patching m2crypto", sub {
	    my $patchfile = $M2CRYPTO_PATCH;
633

634 635 636 637 638 639 640 641 642 643 644 645
	    if (ExecQuiet("$PKG_INFO -I -x m2crypto | fgrep -q -s '0.17'") == 0) {
		$patchfile = "${patchfile}-0.17";
	    }
	    elsif (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")) {
		PhaseSkip("Patch already applied");
	    }
	    ExecQuietFatal("$PATCH -f -l -p0 -i $patchfile");
	};
    }
646 647 648
    Phase "perlselfloaderpatch", "Fixing perl self-loader", sub {
	my $perldir = "/usr/local/lib/perl5/5.10.1";
	DoneIfDoesntExist("$perldir/SelfLoader.pm");
649 650 651 652
	my $ver = `fgrep 'our \$VERSION =' $perldir/SelfLoader.pm 2>/dev/null`;
	if ($? == 0 && $ver =~ /1\.18/) {
	    PhaseSkip("Patch already applied");
	}
653 654
	ExecQuietFatal("$PATCH -d $perldir -i $SELFLOAD_PATCH");
    };
Leigh B. Stoller's avatar
Leigh B. Stoller committed
655 656 657 658 659
    if ($MAILMANSUPPORT) {
	Phase "mailmanpatch", "Patching mailman", sub {
	    my $patchfile = $MAILMAN_PATCH;
	
	    if (!ExecQuiet("$PATCH -C -f -l -R -p0 -i $patchfile")) {
660
		PhaseSkip("Patch already applied");
Leigh B. Stoller's avatar
Leigh B. Stoller committed
661 662 663 664
	    }
	    ExecQuietFatal("$PATCH -f -l -p0 -i $patchfile");
	};
    }
665 666
}; 

Robert Ricci's avatar
Robert Ricci committed
667 668 669
Phase "rc.conf", "Adding testbed content to rc.conf", sub {
    DoneIfEdited($RCCONF);
    AppendToFileFatal($RCCONF,
Robert Ricci's avatar
Robert Ricci committed
670
		      qq|sendmail_enable="YES"|,
671 672
		      qq|rpcbind_enable="YES"|,
		      qq|mountd_enable="YES"|,
Robert Ricci's avatar
Robert Ricci committed
673 674
		      qq|nfs_server_enable="YES"|,
		      qq|nfs_server_flags="-u -t -n 16"|,
675
		      qq|mountd_flags="-r -p 900"|,
676
		      (($ISFS && $WINSUPPORT) ? qq|smbd_enable="YES"| : ()),
677
		      qq|apache_enable="YES"|,
Mike Hibler's avatar
Mike Hibler committed
678
		      qq|syslogd_flags=""|,
679 680
		      ($CVSSUPPORT ? qq|cvsd_enable="YES"| : ()),
		      qq|pubsubd_flags="-T 10"|);
Robert Ricci's avatar
Robert Ricci committed
681
};
682

683
Phase "hosts", "Adding boss/ops/fs IP addresses to $HOSTS", sub {
684
    DoneIfEdited($HOSTS);
685 686 687 688 689 690 691 692
    # XXX get rid of any existing lines with boss/ops/fs
    if ($ELABINELAB) {
	my $dellist = "-e '/^${BOSSNODE_IP}/d' -e '/^${USERNODE_IP}/d'";
	if (!$ISFS) {
	    $dellist .= " -e '/^${FSNODE_IP}/d'";
	}
	ExecQuietFatal("sed -i.orig $dellist $HOSTS");
    }
693 694 695 696 697 698
    my $hstr = "${BOSSNODE_IP}\t${BOSSNODE} boss" .
	"\n${USERNODE_IP}\t@OPS_NAMES";
    if (!$ISFS) {
	$hstr .= "\n${FSNODE_IP}\t${FSNODE} fs";
    }
    AppendToFileFatal($HOSTS, $hstr);
699 700
};

701 702 703 704 705 706 707
Phase "resolve", "Checking to make sure names for boss/ops/fs resolve", sub {
    my @hnames = (@OPS_NAMES, $BOSSNODE, "boss");

    if (!$ISFS) {
	push @hnames, $FSNODE, "fs";
    }
    foreach my $name (@hnames) {
708 709
	Phase $name, $name, sub {
	    if (gethostbyname($name)) {
710
		PhaseSucceed("$name resolves");
711 712 713 714 715 716 717
	    } else {
		PhaseFail("$name does not resolve");
	    }
	};
    }
};

Robert Ricci's avatar
Robert Ricci committed
718 719 720 721 722 723 724 725 726 727
Phase "sendmail","Configuring sendmail", sub {
    Phase "localhosts", "Setting up $LOCAL_HOSTNAMES", sub {
	DoneIfExists($LOCAL_HOSTNAMES);
	CreateFileFatal($LOCAL_HOSTNAMES,@LOCAL_HOSTS);
    };
    Phase "maillists", "Setting up mailing lists", sub {
	Phase "listdir", "Creating $LIST_DIR", sub { 
	    DoneIfExists($LIST_DIR);
	    mkdir($LIST_DIR,0755) or
		PhaseFail("Unable to create $LIST_DIR: $!");
728 729
	    ExecQuietFatal("$CHGRP mailnull $LIST_DIR");
	    ExecQuietFatal("$CHMOD 750 $LIST_DIR");
Robert Ricci's avatar
Robert Ricci committed
730 731 732 733 734 735 736 737 738 739 740 741 742 743 744
	};
	Phase "listfiles", "Creating mailing list files", sub {
	    foreach my $list (@MAILING_LIST_NAMES) {
		Phase $list, $list, sub {
		    DoneIfExists("$LIST_DIR/$list");
		    CreateFileFatal("$LIST_DIR/$list");
		};
	    }
	};
	Phase "aliases", "Adding lists to $ALIASES_FILE", sub {
	    DoneIfEdited($ALIASES_FILE);
	    AppendToFileFatal($ALIASES_FILE,
		map("$_:\t:include:$LIST_DIR/$_",@MAILING_LIST_NAMES));
	};
	Phase "newaliases", "Running newaliases", sub {
745
	    PhaseSkip("No new aliases") unless @MAILING_LIST_NAMES;
Robert Ricci's avatar
Robert Ricci committed
746 747 748 749 750 751 752 753 754 755 756 757
	    PhaseSkip("No new aliases") if PhaseWasSkipped("aliases");
	    ExecQuietFatal($NEWALIASES);
	};
    };
};

Phase "exports", "Setting up exports", sub {
    Phase "ex.head", "Creating $EXPORTS_HEAD", sub {
	DoneIfExists($EXPORTS_HEAD);

	#
	# Figure out which of these directories are on the same
758 759
	# filesystems.  Note: we cannot do /share on the same exports line
	# as the other filesystems because of the RO mount below (trust me).
Robert Ricci's avatar
Robert Ricci committed
760
	#
761
	my @dirs = ('/var', $PREFIX);
762
	if ($ISFS) {
763
	    @dirs = (grep(!/^$SHAREROOT$/, @MOUNTPOINTS), @dirs);
764
	}
Robert Ricci's avatar
Robert Ricci committed
765 766 767 768 769 770 771 772 773 774 775 776 777 778
	@dirs = map {`realpath $_`} @dirs;
	chomp @dirs;
	my %filesystems;
	foreach my $dir (@dirs) {
	    my ($dev,@junk) = stat $dir;
	    push @{$filesystems{$dev}}, $dir;
	}

	#
	# Use that knowledge to create lines for /etc/exports.head
	#
	my @exports_lines;
	foreach my $key (keys %filesystems) {
	    push @exports_lines,
779 780
		join(" ",@{$filesystems{$key}}) .
		    "\t$BOSSNODE -maproot=root";
Robert Ricci's avatar
Robert Ricci committed
781 782
	}

783 784 785 786 787
	if ($ISFS) {
	    #
	    # /share is special. We want to export to boss read-write,
	    # but to the control network read-only.
	    #
788
	    my $realdir = `realpath $SHAREROOT`;
789 790 791
	    chomp($realdir);
	    push(@exports_lines,
		 "$realdir\t$BOSSNODE -maproot=root");
Mike Hibler's avatar
Mike Hibler committed
792 793 794 795 796 797 798
	    if (!$NOSHAREDFS) {
		my ($a,$b,$c,$d) =
		    ($CONTROL_NETWORK =~ /^(\d*)\.(\d*)\.(\d*)\.(\d*)/);
		push(@exports_lines,
		     "$realdir\t-network ${a}.${b}.${c} ".
		     "-mask $CONTROL_NETMASK -maproot=root -ro -alldirs");
	    }
799
	}
800

801 802 803 804 805
	#
	# Add localhost mount to proj/cvsrepos.
	#
	if ($CVSSUPPORT) {
	    my $pdir;
806
	    my $dfout = `df $PROJROOT | fgrep '/dev'`;
807
	    if ($?) {
808
		PhaseFail("'df $PROJROOT' failed!");
809 810 811 812 813
	    }
	    if ($dfout =~ /\s+([\/\w]*)$/) {
		$pdir = $1;
	    }
	    else {
814
		PhaseFail("Could not determine where $PROJROOT is mounted!");
815 816 817 818
	    }
	    push(@exports_lines, "$pdir\tlocalhost -alldirs");
	}

Robert Ricci's avatar
Robert Ricci committed
819 820 821 822 823 824 825
	#
	# Put them in exports.head, and copy that to /etc/exports
	#
	CreateFileFatal($EXPORTS_HEAD, @exports_lines);
	ExecQuietFatal("cp $EXPORTS_HEAD $EXPORTS_FILE");
    };

826
    # XXX Newhup
Robert Ricci's avatar
Robert Ricci committed
827 828 829 830 831 832
    Phase "mountd", "HUPing mountd", sub {
	PhaseSkip("No new exports file") if PhaseWasSkipped("ex.head");
	PhaseSkip("mountd not running") unless `ps -auxw | grep mountd | grep -v grep`;
	ExecQuietFatal("killall -HUP mountd");
    };
};
833

834 835 836 837
Phase "NFSmounts", "Setting up NFS mounts", sub {
    if ($ISFS) {
	PhaseSkip("FSes are local");
    }
838 839 840
    if ($OPSVM_ENABLE) {
	PhaseSkip("FSes are mounted from outside the VM");
    }
841 842 843 844 845 846 847 848 849 850 851 852

    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);
Mike Hibler's avatar
Mike Hibler committed
853 854 855 856 857 858 859
	my $nfsopt = "nosuid";
	$nfsopt .= ",nodev"
	    if ($FBSD_MAJOR < 7);
	my @lines = ("$FSNODE:$USERROOT\t\t$USERROOT\tnfs\trw,$nfsopt\t0\t0",
		     "$FSNODE:$PROJROOT\t\t$PROJROOT\tnfs\trw,$nfsopt\t0\t0",
		     "$FSNODE:$GROUPROOT\t\t$GROUPROOT\tnfs\trw,$nfsopt\t0\t0",
		     "$FSNODE:$SHAREROOT\t\t$SHAREROOT\tnfs\trw,$nfsopt\t0\t0");
860 861
	if ($SCRATCHDIR) {
	    push(@lines,
Mike Hibler's avatar
Mike Hibler committed
862
		 "$FSNODE:$SCRATCHROOT\t\t$SCRATCHROOT\tnfs\trw,$nfsopt\t0\t0");
863 864 865
	}

	AppendToFileFatal($FSTAB, @lines);
866 867 868 869 870 871 872 873 874 875 876
    };
    Phase "mounts", "Mounting NFS filesystems", sub {
	foreach my $dir (@MOUNTPOINTS) {
	    Phase $dir, $dir, sub {
		DoneIfMounted($dir);
		ExecQuietFatal("$MOUNT -o '-R 1' $dir");
	    };
	}
    };
};

877 878 879
#
# Set up syslog
#
Robert Ricci's avatar
Robert Ricci committed
880 881 882 883 884 885 886 887 888 889 890
Phase "syslog", "Setting up syslog", sub {
    Phase "sysconf", "Editing $SYSLOG_CONF", sub {
	DoneIfEdited($SYSLOG_CONF);
	
	#
	# Can't just append to this file, unfortunately. Have to put some of
	# the lines in the middle of the file
	#
	open(SC,"+<$SYSLOG_CONF") or
	    PhaseFail("Unable to open $SYSLOG_CONF : $!");
	my @sc = <SC>;
891 892 893
	if (scalar(grep(/$LOGFACIL/, @sc)) != 0) {
	    PhaseFail("Testbed chosen facility $LOGFACIL already in use in /etc/syslog.conf!");
	}
Robert Ricci's avatar
Robert Ricci committed
894 895
	if (scalar(grep(/^cron/, @sc)) != 1) {
	    PhaseFail("Unable to find marker in /etc/syslog.conf!");
896 897
	}

Robert Ricci's avatar
Robert Ricci committed
898 899 900 901 902
	#
	# Clobber and re-write
	#
	seek(SC,0,0);
	truncate(SC,0);
903

Robert Ricci's avatar
Robert Ricci committed
904
	foreach my $line (@sc) {
905 906 907 908 909 910 911
	    #
	    # Modify the /var/log/messages line to exclude testbed stuff
	    #
	    my $pat = q(\s+/var/log/messages);
	    if ($line =~ /^[^#].*$pat/) {
		$line =~ s/($pat)/\;$LOGFACIL.none$1/;
	    }
912 913 914 915 916 917 918 919 920 921 922 923

	    #
	    # XXX don't send anything to logged in root users.
	    # Per-user linktest proxies run on ops as root in a "full"
	    # ssh ("-t -t") which appears as a login shell.  Thus the
	    # linktest output given to the user might include syslog
	    # messages.
	    #
	    if ($line =~ /root$/) {
		$line =~ s/^/#/;
	    }

Robert Ricci's avatar
Robert Ricci committed
924
	    print SC $line;
925 926 927 928

	    #
	    # Find the cron line, after which we place our auth.info line
	    #
Robert Ricci's avatar
Robert Ricci committed
929
	    if ($line =~ /^cron/) {
930
		print SC "# " . MAGIC_TESTBED_START() . "\n";
Robert Ricci's avatar
Robert Ricci committed
931
		print SC "auth.info\t\t\t\t\t/var/log/logins\n";
932
		print SC "# " . MAGIC_TESTBED_END() . "\n";
Robert Ricci's avatar
Robert Ricci committed
933 934
	    }
	}
935

Robert Ricci's avatar
Robert Ricci committed
936 937 938
	#
	# Put a few more lines at the end
	#
939
	print SC "# " . MAGIC_TESTBED_START() . "\n";
Robert Ricci's avatar
Robert Ricci committed
940 941 942 943
	print SC "!capture\n";
	print SC "*.*\t\t\t\t\t\t/var/log/tiplogs/capture.log\n";
	print SC "!mountd\n";
	print SC "*.*\t\t\t\t\t\t/var/log/mountd.log\n";
944
	print SC "!pubsubd\n";
945
	print SC "*.*\t\t\t\t\t\t${LOGDIR}/pubsubd.log\n";
946
	print SC "!elvin_gateway\n";
947
	print SC "*.*\t\t\t\t\t\t${LOGDIR}/elvin_gateway.log\n";
948
	print SC "# " . MAGIC_TESTBED_END() . "\n";
Robert Ricci's avatar
Robert Ricci committed
949 950 951 952 953 954 955 956
	close SC;
    };

    Phase "tiplog", "Creating $TIPLOG_DIR", sub {
	DoneIfExists($TIPLOG_DIR);
	mkdir($TIPLOG_DIR,0755) or PhaseFail("Unable to make $TIPLOG_DIR : $!");
    };
    
957 958 959 960 961 962 963 964 965 966 967 968 969 970 971
    Phase "logdir", "Creating log directory", sub {
	DoneIfExists($LOGDIR);
	mkdir $LOGDIR, 0775 or PhaseFail("Unable to create $LOGDIR : $!");
	ExecQuietFatal("$CHGRP tbadmin $LOGDIR");
	ExecQuietFatal("$CHMOD 775 $LOGDIR");
    };

    Phase "mysql-logdir", "Creating mysql log directory", sub {
	DoneIfExists($MYSQL_LOGDIR);
	mkdir $MYSQL_LOGDIR, 0775 or
	    PhaseFail("Unable to create $MYSQL_LOGDIR : $!");
	ExecQuietFatal("$CHOWN mysql:mysql $MYSQL_LOGDIR");
	ExecQuietFatal("$CHMOD 775 $MYSQL_LOGDIR");
    };

Robert Ricci's avatar
Robert Ricci committed
972 973 974 975 976
    Phase "logfiles", "Creating log files", sub {
	foreach my $logfile (@LOGFILES) {
	    Phase $logfile, $logfile, sub {
		DoneIfExists($logfile);
		CreateFileFatal($logfile);
977
		ExecQuietFatal("$CHGRP tbadmin $logfile");
Robert Ricci's avatar
Robert Ricci committed
978 979 980 981 982 983 984 985 986 987
		ExecQuietFatal("$CHMOD 640 $logfile");
	    };
	}
    };

    Phase "newsyslog", "Setting up $NEWSYSLOG_CONF", sub {
	DoneIfEdited($NEWSYSLOG_CONF);
	AppendToFileFatal($NEWSYSLOG_CONF,
	    "/var/log/logins\t\t\t\t640  7     200 *      Z",
	    "/var/log/mountd.log\t\t\t640  5     200 *      Z",
988 989
	    "$LOGDIR/pubsubd.log\t\t\t640  5     1000 *     Z",
	    "$LOGDIR/elvin_gateway.log\t\t\t640  5     1000 *     Z",
Robert Ricci's avatar
Robert Ricci committed
990 991 992 993
	    "/var/log/tiplogs/capture.log\t\t644  7     *    168   Z");
    };
};

994 995
Phase "cron", "Adding cron jobs", sub {
    Phase "crontab", "Editing $CRONTAB", sub {
996 997 998
	if ($QUOTA_FSLIST eq "") {
	    PhaseSkip("No filesystem quotas");
	}
999
	DoneIfEdited($CRONTAB);
1000 1001 1002 1003 1004 1005 1006 1007

	my @cronlist = ("0 \t6\t*\t*\t*\troot\t$PREFIX/sbin/quotamail");
	if ($WIKISUPPORT) {
	    push(@cronlist,
		 "*/15 \t*\t*\t*\t*\troot\t(cd /usr/local/www/data/twiki/bin;".
		 " ./mailnotify -q >> /var/tmp/mailnotify.log 2>&1)");
	}
	AppendToFileFatal($CRONTAB, @cronlist);
1008 1009 1010 1011 1012 1013 1014
    };
    Phase "cronhup", "HUPing cron", sub {
	if (PhaseWasSkipped("crontab")) { PhaseSkip("No new crontab"); }
	HUPDaemon("cron");
    };
};

1015
Phase "sudoers", "Editing $SUDOERS to allow wheel group", sub {
Robert Ricci's avatar
Robert Ricci committed
1016
    DoneIfEdited($SUDOERS);
Russ Fish's avatar
Russ Fish committed
1017 1018 1019
    AppendToFileFatal($SUDOERS,
		      "%wheel    ALL=(ALL) NOPASSWD: ALL",
		      "Defaults  logfile=/var/log/sudo.log");
Robert Ricci's avatar
Robert Ricci committed
1020
};
1021

1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034
Phase "samba", "Setting up Samba", sub {
    if (!$ISFS) {
	PhaseSkip("Not FS node");
    }
    if (!$WINSUPPORT) {
	PhaseSkip("Windows support not enabled");
    }
    Phase "smb.conf", "Installing smb.conf[.head]", sub {
	DoneIfEdited($SMBCONF_HEAD);
	ExecQuietFatal("$CP -pf $TOP_OBJDIR/install/smb.conf.head $SMBCONF_HEAD");
	AppendToFileFatal($SMBCONF_HEAD,
			  "# This file created by Emulab Control");
	ExecQuietFatal("$CP -pf $SMBCONF_HEAD $SMBCONF_FILE");
1035
    };
1036 1037 1038 1039 1040 1041 1042
    Phase "samba.sh", "Installing samba.sh", sub {
	DoneIfExists("$RCDIR/samba.sh");
	DoneIfDoesntExist("$RCDIR/samba.sh.sample");
	ExecQuietFatal("$MV -f $RCDIR/samba.sh.sample $RCDIR/samba.sh");
    };
    if ($ELABINELAB) {	
	Phase "starting", "Starting Samba", sub {
1043 1044 1045 1046 1047 1048 1049 1050
	    my $sscript;
	    if (-x "$RCDIR/samba.sh") {
		$sscript = "samba.sh";
	    } elsif (-x "$RCDIR/samba") {
		$sscript = "samba";
	    } else {
		PhaseFail("No samba startup script!?");
	    }
1051
	    DoneIfExists("$VARRUN/smbd.pid");
1052
	    ExecQuietFatal("$RCDIR/$sscript start");
1053 1054 1055
	};
    }
};
1056

Robert Ricci's avatar
Robert Ricci committed
1057
Phase "ssh", "Allowing root ssh", sub {
Robert Ricci's avatar
Robert Ricci committed
1058 1059
    Phase "sshdconfig", "Permitting root login through ssh", sub {
	DoneIfEdited($SSHD_CONFIG);
1060 1061 1062 1063
	# modern versions of FBSD explicitly turn off proto 1 by default
	if ($FBSD_MAJOR > 6) {
	    ExecQuietFatal("sed -i.orig -e 's/Protocol/#Protocol/' $SSHD_CONFIG");
	}