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

#
# EMULAB-COPYRIGHT
5
# Copyright (c) 2003, 2004, 2005 University of Utah and the Flux Group.
6 7 8 9 10 11 12 13 14 15
# All rights reserved.
#

#
# install-ops.sh - Script to do the initial install of an ops node
#
# 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@",
Robert Ricci's avatar
Robert Ricci committed
26 27
    "@TBTESTSUITEEMAIL@");

28

29 30 31 32 33 34 35
my $OURDOMAIN   = '@OURDOMAIN@';
my $USERNODE    = '@USERNODE@';
my $FSNODE      = '@FSNODE@';
my $BOSSNODE    = '@BOSSNODE@';
my $BOSSNODE_IP = '@BOSSNODE_IP@';
my $USERNODE_IP = '@USERNODE_IP@';
my $LOGFACIL    = '@TBLOGFACIL@';
36
my $ELABINELAB  = @ELABINELAB@;
37
my $WINSUPPORT  = @WINSUPPORT@;
38

39 40 41 42
# For /share export below.
my $CONTROL_NETWORK = "@CONTROL_NETWORK@";
my $CONTROL_NETMASK = "@CONTROL_NETMASK@";

43
#
Robert Ricci's avatar
Robert Ricci committed
44
# Allow this to work if the library is left in the source directory
45
#
Robert Ricci's avatar
Robert Ricci committed
46 47 48 49
use lib '@srcdir@';
   
use English;
use libinstall;
50 51 52 53 54 55
use Getopt::Std;

#
# Handle command-line options
#
sub usage {
56
    print "Usage: ops-install [-b] [-p packagedir] [-P portname]\n";
57 58 59
    exit(1);
}

60 61 62 63
#
# The default meta-port (name and version) that drags in all the dependancies
# for an ops node
#
64
my $OPS_PORT = "emulab-ops-1.4";
65

66
my $packagedir = "";
67
my $batchmode  = 0;
68
my %opts;
69
if (! getopts("P:p:b", \%opts)) {
70 71 72 73
    usage();
}
if (defined($opts{p})) {
    $packagedir = $opts{p};
74
}
75
if (defined($opts{b})) {
76 77
    $batchmode = 1;
}
78 79 80
if (defined($opts{P})) {
    $OPS_PORT = $opts{P};
}
81 82 83 84

if (@ARGV) {
    usage();
}
85

86 87 88 89 90 91 92 93
#
# 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/..";

94
#
Robert Ricci's avatar
Robert Ricci committed
95
# Some programs we use
96
#
Robert Ricci's avatar
Robert Ricci committed
97 98 99
my $CHGRP      = "/usr/bin/chgrp";
my $CHMOD      = "/bin/chmod";
my $PW         = "/usr/sbin/pw";
100
my $PATCH      = "/usr/bin/patch";
Robert Ricci's avatar
Robert Ricci committed
101
my $NEWALIASES = "/usr/bin/newaliases";
102 103
my $SH         = "/bin/sh";
my $PKG_INFO   = "/usr/sbin/pkg_info";
104
my $PKG_ADD    = "/usr/sbin/pkg_add";
105
my $PWD        = "/bin/pwd";
106
my $CP         = "/bin/cp";
107
my $MV         = "/bin/mv";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
108
my $GMAKE      = "/usr/local/bin/gmake";
109
my $ENV        = "/usr/bin/env";
110 111

#
Robert Ricci's avatar
Robert Ricci committed
112
# Some files we edit/create
113
#
Robert Ricci's avatar
Robert Ricci committed
114
my $RCCONF          = "/etc/rc.conf";
115
my $HOSTS           = "/etc/hosts";
Robert Ricci's avatar
Robert Ricci committed
116 117
my $RCLOCAL         = "/etc/rc.local";
my $RCCAPTURE       = "$PREFIX/etc/rc.capture";
Robert Ricci's avatar
Robert Ricci committed
118 119 120 121 122 123 124
my $LOCAL_HOSTNAMES = "/etc/mail/local-host-names";
my $ALIASES_FILE    = "/etc/mail/aliases";
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";
125
my $SSHD_CONFIG     = "/etc/ssh/sshd_config";
126
my $CRONTAB         = "/etc/crontab";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
127
my $AUTHKEYS	    = "/root/.ssh/authorized_keys";
Kirk Webb's avatar
 
Kirk Webb committed
128 129
my $SMBCONF_FILE    = "/usr/local/etc/smb.conf";
my $SMBCONF_HEAD    = "$SMBCONF_FILE.head";
130 131

#
Robert Ricci's avatar
Robert Ricci committed
132
# Some directories we care about
133
#
134 135 136 137 138 139 140
my $LIST_DIR      = "/etc/mail/lists";
my $TIPLOG_DIR    = "/var/log/tiplogs";
my $PORTSDIR      = "/usr/ports";
my $PORTSMISCDIR  = "$PORTSDIR/misc";
my $SRCDIR        = '@srcdir@';
my $TOP_SRCDIR    = "@top_srcdir@";
my $RCDIR         = "/usr/local/etc/rc.d";
141 142

#
Robert Ricci's avatar
Robert Ricci committed
143
# And some lists that we use
144
#
145 146
my @LOCAL_HOSTS        = ($OURDOMAIN,$BOSSNODE,$USERNODE,$FSNODE);
my @LOGFILES           = ("/var/log/logins","/var/log/tiplogs/capture.log",
Robert Ricci's avatar
Robert Ricci committed
147
    "/var/log/mountd.log");
148 149
my @LOCAL_MAILING_LISTS = grep(/$OURDOMAIN$/,@MAILING_LISTS);
my @MAILING_LIST_NAMES  = map { /^([\w-]+)\@/ } @LOCAL_MAILING_LISTS;
Robert Ricci's avatar
Robert Ricci committed
150 151 152

my @TESTBED_DIRS       = ([$PREFIX, "0775"], ["/users", "0755"],
    ["/proj", "0755"], ["/groups", "0755"], ["/share", "0775"]);
153

154 155 156 157 158
#
# A few files we have to deal with
#
my $ELVIND_CONF     = "/usr/local/etc/elvind.conf";
my $OPS_ELVIND_CONF = "$TOP_OBJDIR/event/etc/elvind-ops.conf";
159
my $M2CRYPTO_PATCH  = "$TOP_SRCDIR/patches/m2crypto.patch";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
160
my $IDENTPUB        = "$TOP_SRCDIR/install/identity.pub";
161

162 163 164 165 166 167 168
#
# List of names that goes into $HOSTS and which must resolve.
# 
my @OPS_NAMES = ($USERNODE, "users", "ops");
push(@OPS_NAMES, $FSNODE)
    if ($USERNODE ne $FSNODE);

169
#
Robert Ricci's avatar
Robert Ricci committed
170
# Make sure they know what they're getting into...
171
#
172 173 174 175 176 177 178 179
if (! $batchmode) {
    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 ops node. Continue? [y/N] ";
    my $response = <>;
    die "Installation aborted!\n" unless ($response =~ /^y/i);
}
180

Robert Ricci's avatar
Robert Ricci committed
181 182
if ($UID != 0) {
    die "This script must be run as root.\n";
183 184 185
}

#
Robert Ricci's avatar
Robert Ricci committed
186
# The phases are fairly self-explanatory
187 188
#

Robert Ricci's avatar
Robert Ricci committed
189 190 191
Phase "groups", "Creating admin group", sub {
    if (getgrnam("tbadmin")) {
	PhaseSkip("tbadmin group already exists");
192
    }
Robert Ricci's avatar
Robert Ricci committed
193 194 195 196
    ExecQuietFatal("$PW groupadd tbadmin -g 101");
};

Phase "dirs", "Setting directory permissions", sub {
Robert Ricci's avatar
Robert Ricci committed
197 198
    foreach my $dirref (@TESTBED_DIRS) {
	my ($dir, $newmode) = @$dirref;
Robert Ricci's avatar
Robert Ricci committed
199 200 201 202
	Phase $dir, $dir, sub {
	    if (!-d $dir) {
		PhaseFail("Directory $dir does not exist");
	    }
Robert Ricci's avatar
Robert Ricci committed
203 204 205 206
	    # 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
207 208
	    # Fix up the mode (strip file type)
	    $mode = $mode & 0777;
Robert Ricci's avatar
Robert Ricci committed
209
	    if ($mode == eval $newmode && $group eq getgrnam("tbadmin")) {
Robert Ricci's avatar
Robert Ricci committed
210 211
		PhaseSkip("Already done");
	    }
Robert Ricci's avatar
Robert Ricci committed
212 213
	    ExecQuietFatal("$CHGRP tbadmin $realdir");
	    ExecQuietFatal("$CHMOD $newmode $realdir");
Robert Ricci's avatar
Robert Ricci committed
214
	};
215
    }
Robert Ricci's avatar
Robert Ricci committed
216
};
217

218
Phase "ports", "Installing ports", sub {
219 220 221 222 223 224 225 226 227
    Phase "packages", "Installing packages", sub {
	if (!ExecQuiet("$PKG_INFO -e $OPS_PORT")) {
	    PhaseSkip("Ports already installed");
	}
	if (!$packagedir) {
	    PhaseSkip("No package directory provided");
	}
	ExecQuietFatal("$ENV PKG_PATH=$packagedir $PKG_ADD $OPS_PORT");
    };
228
    Phase "pcopy", "Copying ports into place", sub {
229 230 231
	if ($packagedir) {
	    PhaseSkip("Package directory provided");
	}
232
	DoneIfExists("$PORTSMISCDIR/emulab-ops");
233 234 235
	ExecQuietFatal("$SH $SRCDIR/ports/ports-install");
    };
    Phase "pinstall", "Installing ports (may take a while)", sub {
236
	if (!ExecQuiet("$PKG_INFO -e $OPS_PORT")) {
237 238
	    PhaseSkip("Ports already installed");
	}
239 240 241
	if ($packagedir) {
	    PhaseSkip("Package directory provided");
	}
242 243 244 245 246 247

	#
	# This port is dead-simple, so it's safe to do it from this script
	#
	my $pwd = `$PWD`;
	chomp $pwd;
248 249
	chdir "$PORTSMISCDIR/emulab-ops" or
		PhaseFail "Unable to change to $PORTSMISCDIR/emulab-ops: $!";
250
	ExecQuietFatal("make -DBATCH install");
251 252 253 254
	chdir $pwd;
    };
};

255 256
# XXX Temporary.
Phase "portfixup", "Fixing up packages", sub {
257
    Phase "rsync", "Looking for rsync and installing", sub {
258 259 260 261
	if (!ExecQuiet("$PKG_INFO -x rsync")) {
	    PhaseSkip("rsync already installed");
	}

262 263 264 265
	PhaseFail("Must have a PKG_PATH variable set in your environment")
	    if (!exists($ENV{"PKG_PATH"}));
	
	ExecQuietFatal("$PKG_ADD rsync-2.6.3_1");
266
    };
267 268 269 270 271
    if ($WINSUPPORT) {
	Phase "samba", "Looking for Samba and installing", sub {
	    if (!ExecQuiet("$PKG_INFO -x samba")) {
		PhaseSkip("samba already installed");
	    }
272 273 274 275 276 277 278 279 280
	    
	    PhaseFail("Must have a PKG_PATH variable set in your environment")
		if (!exists($ENV{"PKG_PATH"}));
	
	    ExecQuietFatal("$PKG_ADD samba-3.0.7,1");
	};
	Phase "gcc30", "Looking for GCC 3.0 and installing", sub {
	    if (!ExecQuiet("$PKG_INFO -x gcc30")) {
		PhaseSkip("GCC 3.0 already installed");
281
	    }
282 283 284 285 286
	    
	    PhaseFail("Must have a PKG_PATH variable set in your environment")
		if (!exists($ENV{"PKG_PATH"}));
	
	    ExecQuietFatal("$PKG_ADD gcc30-3.0.4_1");
287 288
	};
    }
289 290
};

291 292
Phase "patches", "Applying patches", sub {
    Phase "m2cryptopatch", "Patching m2crypto", sub {
293
        if (!ExecQuiet("$PATCH -C -f -l -R -p0 -i $M2CRYPTO_PATCH")) {
294 295
            PhaseSkip("$M2CRYPTO_PATCH already applied");
        }
296
        ExecQuietFatal("$PATCH -f -p0 -l -i $M2CRYPTO_PATCH");
297 298 299
    };
}; 

Robert Ricci's avatar
Robert Ricci committed
300 301 302
Phase "rc.conf", "Adding testbed content to rc.conf", sub {
    DoneIfEdited($RCCONF);
    AppendToFileFatal($RCCONF,
Robert Ricci's avatar
Robert Ricci committed
303 304
		      qq|sendmail_enable="YES"|,
		      qq|nfs_server_enable="YES"|,
Leigh B. Stoller's avatar
Leigh B. Stoller committed
305
		      ($WINSUPPORT ? qq|smbd_enable="YES"| : ()),
Robert Ricci's avatar
Robert Ricci committed
306 307
		      qq|nfs_server_flags="-u -t -n 16"|,
		      qq|syslogd_flags=""|);
Robert Ricci's avatar
Robert Ricci committed
308
};
309

310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328
Phase "hosts", "Adding boss/ops IP addresses to $HOSTS", sub {
    DoneIfEdited($HOSTS);
    AppendToFileFatal($HOSTS,
		      "${BOSSNODE_IP}\t${BOSSNODE} boss",
		      "${USERNODE_IP}\t@OPS_NAMES");
};

Phase "resolve", "Checking to make sure names for boss/ops resolve", sub {
    foreach my $name (@OPS_NAMES, ${BOSSNODE}, "boss") {
	Phase $name, $name, sub {
	    if (gethostbyname($name)) {
		PhaseSkip("$name resolves");
	    } else {
		PhaseFail("$name does not resolve");
	    }
	};
    }
};

Robert Ricci's avatar
Robert Ricci committed
329 330 331 332 333 334 335 336 337 338
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: $!");
339 340
	    ExecQuietFatal("$CHGRP mailnull $LIST_DIR");
	    ExecQuietFatal("$CHMOD 750 $LIST_DIR");
Robert Ricci's avatar
Robert Ricci committed
341 342 343 344 345 346 347 348 349 350 351 352 353 354 355
	};
	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 {
356
	    PhaseSkip("No new aliases") unless @MAILING_LIST_NAMES;
Robert Ricci's avatar
Robert Ricci committed
357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
	    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
	# filesystems
	#
372
	my @dirs = ('/users','/groups','/proj','/share','/var','/usr/testbed');
Robert Ricci's avatar
Robert Ricci committed
373 374 375 376 377 378 379 380 381 382 383 384 385 386
	@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,
Robert Ricci's avatar
Robert Ricci committed
387
		join(" ",@{$filesystems{$key}}) . "\t$BOSSNODE -maproot=root";
Robert Ricci's avatar
Robert Ricci committed
388 389
	}

390 391 392 393 394 395 396 397 398 399 400
	#
	# /share is special. We want to export that to the control network
	# read-only (it is exported to boss r/w, above).
	#
	my ($a,$b,$c,$d) = ($CONTROL_NETWORK =~ /^(\d*)\.(\d*)\.(\d*)\.(\d*)/);
	my $realdir = `realpath /share`;
	chomp($realdir);
	push(@exports_lines,
	     "$realdir\t-network ${a}.${b}.${c} -mask $CONTROL_NETMASK ".
	     "-maproot=root -ro");

Robert Ricci's avatar
Robert Ricci committed
401 402 403 404 405 406 407
	#
	# Put them in exports.head, and copy that to /etc/exports
	#
	CreateFileFatal($EXPORTS_HEAD, @exports_lines);
	ExecQuietFatal("cp $EXPORTS_HEAD $EXPORTS_FILE");
    };

408
    # XXX Newhup
Robert Ricci's avatar
Robert Ricci committed
409 410 411 412 413 414
    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");
    };
};
415 416 417 418

#
# Set up syslog
#
Robert Ricci's avatar
Robert Ricci committed
419 420 421 422 423 424 425 426 427 428 429
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>;
430 431 432
	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
433 434
	if (scalar(grep(/^cron/, @sc)) != 1) {
	    PhaseFail("Unable to find marker in /etc/syslog.conf!");
435 436
	}

Robert Ricci's avatar
Robert Ricci committed
437 438 439 440 441
	#
	# Clobber and re-write
	#
	seek(SC,0,0);
	truncate(SC,0);
442

Robert Ricci's avatar
Robert Ricci committed
443
	foreach my $line (@sc) {
444 445 446 447 448 449 450
	    #
	    # 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/;
	    }
451 452 453 454 455 456 457 458 459 460 461 462

	    #
	    # 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
463
	    print SC $line;
464 465 466 467

	    #
	    # Find the cron line, after which we place our auth.info line
	    #
Robert Ricci's avatar
Robert Ricci committed
468 469 470 471 472 473
	    if ($line =~ /^cron/) {
		print SC "# " . MAGIC_TESTBED_START . "\n";
		print SC "auth.info\t\t\t\t\t/var/log/logins\n";
		print SC "# " . MAGIC_TESTBED_END . "\n";
	    }
	}
474

Robert Ricci's avatar
Robert Ricci committed
475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496
	#
	# Put a few more lines at the end
	#
	print SC "# " . MAGIC_TESTBED_START . "\n";
	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";
	print SC "# " . MAGIC_TESTBED_END . "\n";
	close SC;
    };

    Phase "tiplog", "Creating $TIPLOG_DIR", sub {
	DoneIfExists($TIPLOG_DIR);
	mkdir($TIPLOG_DIR,0755) or PhaseFail("Unable to make $TIPLOG_DIR : $!");
    };
    
    Phase "logfiles", "Creating log files", sub {
	foreach my $logfile (@LOGFILES) {
	    Phase $logfile, $logfile, sub {
		DoneIfExists($logfile);
		CreateFileFatal($logfile);
497
		ExecQuietFatal("$CHGRP tbadmin $logfile");
Robert Ricci's avatar
Robert Ricci committed
498 499 500 501 502 503 504 505 506 507 508 509 510 511
		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",
	    "/var/log/tiplogs/capture.log\t\t644  7     *    168   Z");
    };
};

512 513 514 515
Phase "cron", "Adding cron jobs", sub {
    Phase "crontab", "Editing $CRONTAB", sub {
	DoneIfEdited($CRONTAB);
	AppendToFileFatal($CRONTAB,
516
	    "0 \t6\t*\t*\t*\troot\t$PREFIX/sbin/quotamail");
517 518 519 520 521 522 523
    };
    Phase "cronhup", "HUPing cron", sub {
	if (PhaseWasSkipped("crontab")) { PhaseSkip("No new crontab"); }
	HUPDaemon("cron");
    };
};

Robert Ricci's avatar
Robert Ricci committed
524 525 526 527
Phase "sudoers", "Editing $SUDOERS", sub {
    DoneIfEdited($SUDOERS);
    AppendToFileFatal($SUDOERS,"%wheel    ALL=(ALL) NOPASSWD: ALL");
};
528

529 530
if ($WINSUPPORT) {
    Phase "samba", "Setting up Samba", sub {
Kirk Webb's avatar
 
Kirk Webb committed
531 532 533 534
	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,
535
			      "# This file created by Emulab Control");
Kirk Webb's avatar
 
Kirk Webb committed
536
            ExecQuietFatal("$CP -pf $SMBCONF_HEAD $SMBCONF_FILE");
537 538 539 540 541 542
	};
	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");
	};
543 544 545 546 547
	if ($ELABINELAB) {	
	    Phase "starting", "Starting Samba", sub {
		ExecQuietFatal("$RCDIR/samba.sh start");
	    };
	}
548 549 550
    };
}

Robert Ricci's avatar
Robert Ricci committed
551
Phase "ssh", "Allowing root ssh", sub {
Robert Ricci's avatar
Robert Ricci committed
552 553 554 555 556 557 558 559 560
    Phase "sshdconfig", "Permitting root login through ssh", sub {
	DoneIfEdited($SSHD_CONFIG);
	AppendToFileFatal($SSHD_CONFIG,"PermitRootLogin yes");
    };
    Phase "dotssh", "Making root's .ssh directory", sub {
	DoneIfExists("/root/.ssh");
	mkdir("/root/.ssh",0700) or
	    PhaseFail("Unable to create /root/.ssh: $!");
    };
Leigh B. Stoller's avatar
Leigh B. Stoller committed
561 562 563 564 565 566
   Phase "authkeys", "Adding stub identity to /root/.ssh/authorized_keys", sub {
       DoneIfEdited($AUTHKEYS);
       my $ident = `cat $IDENTPUB`;
       PhaseFail("Could not read $IDENTPUB")
	   if ($?);
       chomp($ident);
567 568 569
       if (! -e $AUTHKEYS) {
	   CreateFileFatal($AUTHKEYS);
       }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
570 571 572
       AppendToFileFatal($AUTHKEYS,
			 "from=\"${BOSSNODE}\" $ident");
   };
Robert Ricci's avatar
Robert Ricci committed
573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597
};

Phase "capture", "Setting up capture", sub {
    Phase "rc.local", "Creating $RCLOCAL", sub {
	DoneIfExists($RCLOCAL);
	CreateFileFatal($RCLOCAL,
	    "if [ -f /etc/defaults/rc.conf ]; then",
	    "\t. /etc/defaults/rc.conf",
	    "fi",
	    "",
	    "if [ -x $RCCAPTURE ]; then",
	    "\techo -n \" capture\"",
	    "\t$RCCAPTURE",
	    "fi");
    };
    Phase "etc", "Creating $PREFIX/etc", sub {
	DoneIfExists("$PREFIX/etc");
	mkdir("$PREFIX/etc",0755) or
	    PhaseFail("Unable to create $PREFIX/etc: $!");
    };
    Phase "rc.capture", "Creating empty $RCCAPTURE", sub {
	DoneIfExists($RCCAPTURE);
	CreateFileFatal($RCCAPTURE,"#!/bin/sh");
	ExecQuietFatal("$CHMOD a+rx $RCCAPTURE");
    };
598 599
};

600 601
Phase "event", "Setting up event system", sub {
    Phase "elvinconf", "Installing elvind config file", sub {
602
	DoneIfIdentical($ELVIND_CONF,$OPS_ELVIND_CONF);
603 604 605 606
	ExecQuietFatal("$CP $OPS_ELVIND_CONF $ELVIND_CONF");
    };
};

607
Phase "rc.d", "Setting up rc.d scripts", sub {
608 609 610 611 612 613
    Phase "rsyncd", "Removing rsyncd startup script",  sub {
	DoneIfDoesntExist("$RCDIR/rsyncd.sh");
	if (!unlink "$RCDIR/rsyncd.sh") {
	    PhaseFail("Unable to remove $RCDIR/rsyncd.sh: $!");
	}
    };
614
    Phase "rc.testbed", "Installing testbed RC scripts", sub {
615 616 617 618
        Phase "elvind.sh", "Removing port version of elvind.sh", sub {
	    DoneIfDoesntExist("$RCDIR/elvind.sh");
            ExecQuietFatal("/bin/rm -f $RCDIR/elvind.sh");
        };
619 620 621 622 623
	DoneIfExists("$RCDIR/2.elvind.sh");
	ExecQuietFatal("$GMAKE -C $TOP_OBJDIR/rc.d control-install");
    };
};

624 625 626
print "----------------------------------------------------------------------\n";
print "Installation completed succesfully!\n";
print "Please reboot this machine before proceeding with boss setup\n";
Robert Ricci's avatar
Robert Ricci committed
627
if (!PhaseWasSkipped("maillists")) {
628
    print "Local mailing lists have been created, with no members, in\n";
Robert Ricci's avatar
Robert Ricci committed
629
    print "$LIST_DIR . Please add members to the following lists:\n";
630
    print map "$_\n", @LOCAL_MAILING_LISTS;
631
}