emulab-install.in 10.3 KB
Newer Older
1
2
#!/usr/bin/perl -w
#
3
# Copyright (c) 2010-2017 University of Utah and the Flux Group.
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 
# {{{EMULAB-LICENSE
# 
# This file is part of the Emulab network testbed software.
# 
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
# 
# This file is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public
# License for more details.
# 
# You should have received a copy of the GNU Affero General Public License
# along with this file.  If not, see <http://www.gnu.org/licenses/>.
# 
# }}}
23
24
25
26
27
28
29
30
31
32
33
#
use strict;
use English;
use Getopt::Std;
use Data::Dumper;

#
# Install Emulab.
#
sub usage()
{
34
    print STDERR "Usage: emulab-install [-c | -l] [-i script] boss|ops|fs\n";
35
36
    print STDERR
	"-c        - Syntax check install scripts by loading them only\n" .
37
	"-l        - Generate a complete log file in /tmp. Defaults on\n" .
38
39
	"-i <name> - Run (or check) just the one install script\n" .
	"-b        - Batch mode, do not ask for confirmation\n" .
Leigh B Stoller's avatar
Leigh B Stoller committed
40
	"-u        - Update mode, run script(s) for update\n" .
41
42
43
44
45
46
	"-s        - Turn on makes. Huh?\n" .
	"-P|-F     - Set the name of the boss/ops and fs port\n" .
	"-w <pswd> - Provide password instead of being asked for it\n" .
	"-p <dir>  - Set the package directory\n";
    exit(-1);
}
47
my $optlist	= "dsi:p:qcbP:F:w:nul";
48
49
50
51
52
53
my $debug	= 0;
my $single	= 0;
my $quiet	= 0;
my $check	= 0;
my $impotent    = 0;
my $updatemode  = 0;
54
my $logit       = 1;
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
my $batchmode	= 0;
my $phasepath	= "@srcdir@/phases";
my $phase;

#
# Configure variables
#
my $TB	      = "@prefix@";
my $TBOPS     = "@TBOPSEMAIL@";

my $logfile   = "/var/tmp/emulab-install.log";
my $logfp;

# Protos
sub Fatal($);

# un-taint path
$ENV{'PATH'} = '/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/site/bin';
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};

#
# Turn off line buffering on output
#
$| = 1;

Leigh B Stoller's avatar
Leigh B Stoller committed
80
#
81
# We want to use modules late in the install process. 
Leigh B Stoller's avatar
Leigh B Stoller committed
82
#
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
BEGIN
{
    if (-e "../Makeconf") {
	my $srcdir = "@top_srcdir@";
	my $objdir = `/bin/pwd`;
	chomp($objdir);
	unshift(@INC, "$objdir/../db");
	if ($srcdir =~ /^\//) {
	    unshift(@INC, "$srcdir/install");
	    unshift(@INC, "$srcdir/tbsetup");
	} else {
	    unshift(@INC, "$objdir/$srcdir/install");
	    unshift(@INC, "$objdir/$srcdir/tbsetup");
	}
	unshift(@INC, "$objdir/../tbsetup");
    }
}
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
use libinstall;
use installvars;

#
# Parse command arguments.
#
my %options = ();
if (! getopts($optlist, \%options)) {
    usage();
}
if (defined($options{"d"})) {
    $debug = 1;
}
if (defined($options{"b"})) {
    $batchmode = 1;
}
116
117
118
if (defined($options{"l"})) {
    $logit = 1;
}
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
if (defined($options{"c"})) {
    $check = 1;
}
if (defined($options{"n"})) {
    $impotent = 1;
}
if (defined($options{"q"})) {
    $quiet = 1;
}
if (defined($options{"u"})) {
    $updatemode = 1;
}
if (defined($options{w})) {
    $password = $options{w};
}
if (defined($options{"p"})) {
    $packagedir = $options{"p"};
}
if (defined($options{"i"})) {
    $single = 1;
    $phase  = $options{"i"};
}
if (defined($options{"s"})) {
    $domakes = 1;
}
if (defined($options{"F"})) {
    $FS_PORT = $options{"F"};
}
if (@ARGV != 1) {
    usage();
}
# Don't just charge into making ports from source by default.
if (!($check || $single || $impotent || $updatemode) &&
    $packagedir eq "" && $domakes eq 0) {
    print "At least one of -p and -s must be given.\n";
    usage();
}
if (!($check || $single || $impotent || $updatemode) &&
    $packagedir ne "" && $domakes eq 1) {
    print "Only one of -p and -s can be given.\n";
    usage();
}
my $server = $ARGV[0];
usage()
    if (! ($server eq $BOSS_SERVERNAME ||
	   $server eq $OPS_SERVERNAME ||
	   $server eq $FS_SERVERNAME));

# Do this after we know the server name.
if (defined($options{"P"})) {
    if ($server eq "boss") {
	$BOSS_PORT = $options{"P"};
    }
    else {
	$OPS_PORT = $options{"P"};
    }
}

#
# Must be root if actually doing this.
#
if ($UID && !($check || $impotent)) {
    Fatal("This script must be run as root! Maybe use sudo?")
}

#
# Make sure they know what they're getting into...
#
if (! ($batchmode || $check || $impotent)) {
    if ($updatemode) {
	print STDERR 
190
191
192
193
194
195
196
197
198
199
	    "WARNING: This script is ONLY intended to be run your $server node";
	if ($single) {
	    print STDERR ".\n" . "Continue? [y/N] ";
	}
	else {
	    print STDERR
		",\n".
		"and only if you are updating the IP addresses/subnet and/or\n".
		"domain name of your installation. Continue? [y/N] ";
	}
200
201
202
203
204
205
206
207
208
209
    }
    else {
	print STDERR 
	    "WARNING: This script is ONLY intended to be run on a machine\n".
	    "that is being set up as a dedicated $server node. Continue? [y/N] ";
    }
    my $response = <STDIN>;
    die "Aborted!\n" unless ($response =~ /^y/i);
}

210
211
212
213
214
215
if (($impotent || $logit) && !$check) {
    if (-e $logfile) {
	system("/bin/mv -f $logfile ${logfile}.$$") == 0
	    or Fatal("Could not back up $logfile");
    }
    
216
217
218
219
    open(LOGFP, "> $logfile")
	or Fatal("Could not open $logfile");
    $logfp = *LOGFP;

220
221
222
223
224
225
226
227
    if ($impotent) {
	SET_IMPOTENT_MODE($logfp);
    }
    else {
	SET_LOG_OUTPUT($logfp);
    }
    print "A more detailed log file is being written to $logfile\n";
    sleep(2);
228
229
230
231
232
233
234
235
236
237
238
}

#
# Very simple list of files. Be fancy later.
#
my @files = ();
if ($single) {
    # Just the one file.
    @files = ($phase);
}
elsif ($server eq "boss") {
239
    @files = ('perl', 'usersgroups', 'dirs', 'tftp',
240
	      'boss/ports', 'boss/portfix', 'boss/patches', 'cracklib',
241
	      'apache', 'boss/rcfiles', 'ntpd', 'boss/rcconf', 'boss/syslog',
242
	      'boss/database', 'etchosts', 'resolvetest',
243
244
	      'exports', 'automount', 'nfsmounts',
	      'boss/mibs', 'boss/crontab', 'sudoers',
Mike Hibler's avatar
Mike Hibler committed
245
	      'samba', 'boss/ssh', 'boss/hostkeys',
246
	      'boss/rndc', 'boss/loaderconf', 'boss/sysctlconf',
247
	      'boss/sslcerts', 'boss/pubsub', 'boss/software', 
248
249
250
251
252
253
              #
	      # The next few items must be after the software install since 
	      # they use testbed libraries and such.
	      #
	      'boss/dhcpd', 'boss/named', 'boss/flyspray',
	      'boss/firstuser', 'boss/checkupuser', 'boss/wikidocs',
Leigh B Stoller's avatar
Leigh B Stoller committed
254
	      'boss/updatesitevars', 'boss/logdirs',
255
	      'boss/mfs', 'boss/images', 'boss/xen',
Leigh B Stoller's avatar
Leigh B Stoller committed
256
	      'boss/experiments',
257
258
	      'boss/protogeni', 'boss/firewall', 'boss/servers',
	      'boss/shellinabox'
259
260
261
	     );
}
elsif ($server eq "fs") {
262
    @files = ('perl', 'usersgroups', 'dirs',
263
	      'fs/ports', 'fs/portfix', 'ntpd', 'ops/rcconf',
264
265
	      'etchosts', 'resolvetest', 'ops/syslog', 'exports', 'quotas',
	      'sudoers', 'samba', 'ops/ssh');
266
267
}
elsif ($server eq "ops") {
268
    @files = ('perl', 'usersgroups', 'dirs', 'etchosts', 'resolvetest',
269
	      'ops/ports', 'ops/portfix', 'ops/patches', 'ntpd', 'ops/rcconf',
270
271
	      'ops/sendmail', 'ops/syslog',
	      'exports', 'automount', 'nfsmounts',
272
	      'ops/crontab', 'sudoers', 'samba', 'ops/ssh', 'capture',
273
	      'ops/rcfiles', 'apache', 'ops/database',
274
275
	      'ops/cvsd', 'ops/flyspray', 'ops/twiki', 'ops/firewall',
	      'ops/shellinabox'
276
	     );
277
278
279
280
}

#
# In update mode, we want to run etchosts at the very end.
281
# Also allow running a single script in update mode. 
282
#
283
if ($updatemode && !$single) {
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
    push(@files, "boss/update-ipdomain")
	if ($server eq $BOSS_SERVERNAME);
    
    @files = grep(!/^etchosts$/, @files);
    push(@files, "etchosts");

    # We need other libraries for updating.
    unshift(@INC, "@prefix@/lib");
}

#
# Now process each file starting at the start version.
#
sub RunInstall()
{
    foreach my $file (@files) {
	my $fullpath = "$phasepath/$file";
	
	Fatal("No such file: $fullpath")
	    if (! -e "$fullpath");

	if ($check) {
	    print "Syntax checking update $fullpath\n";
	}

	# Undefine this to make sure we get a new version each file.
	undef &Install;

	# This just loads the file.
	my $return = do $fullpath;
	if (!defined($return)) {
	    Fatal("  could not parse $fullpath: $@") if $@;
	    Fatal("  could not do $fullpath: $!")    if $!;
	}
	next
	    if ($check);
	
	# Then we run it. Turn off update and impotent flags.
	my $result;
	eval { $result = Install($server, $updatemode, $impotent); };
	if ($result || $@) {
	    print STDERR "*** script failure: $fullpath\n";
	    Fatal("aborting install ...\n");
	}
    }
}

if ($check) {
    print "Syntax checking install scripts ...\n";
    RunInstall();
    exit(0);
}
if ($impotent) {
    print "Running (impotent mode) install scripts ...\n";
    print "More detailed info saved to $logfile\n";
    RunInstall();
    exit(0);
}
RunInstall();

#
# This stuff might go elsewhere ...
#
if ($updatemode) {
    print "-----------------------------------------------------------------\n";
    print "Update completed succesfully!\n\n";
    
Leigh B Stoller's avatar
Leigh B Stoller committed
351
    if (!PhaseWasSkipped("sslcerts") && !$single) {
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
	print
	    "Since your SSL certificates were regenerated, you will need to\n".
	    "regenerate the user SSL certificates as well.\n";
	
	if ($PGENISUPPORT) {
	    print
		"\n".
		"You also have ProtoGENI enabled, so those certificates were\n".
		"regenerated as well. Please be sure to send the new version\n".
		"of your root CA ($PREFIX/etc/emulab.pem) to $PROTOGENI_EMAIL\n".
		"Then you can reregister with the clearinghouse.\n";
	}
    }
    exit(0);
}

368
369
370
exit(0)
    if ($single);

371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
#
# Stuff to do at the end.
#
if ($server eq $OPS_SERVERNAME) {
    exit(0)
	if ($ELABINELAB);

    print "-----------------------------------------------------------------\n";
    print "Installation completed succesfully!\n";
    print "Please reboot this machine before proceeding with boss setup\n";
    print "Local mailing lists have been created, with no members, in\n";
    print "$LIST_DIR . Please add members to the following lists:\n";
    print map "$_\n", @LOCAL_MAILING_LISTS;
}
elsif ($server eq $FS_SERVERNAME) {
    print "-----------------------------------------------------------------\n";
    print "Installation completed succesfully!\n";
    print "Please reboot this machine before proceeding with ops and boss setup\n";
}
elsif ($server eq $BOSS_SERVERNAME) {
    print "-----------------------------------------------------------------\n";
    print "Installation completed succesfully!\n";
    print "Please reboot this machine before proceeding with boss setup\n";
}
exit(0);

sub Fatal($)
{
    my ($msg) = @_;

    die("*** $0:\n".
	"    $msg\n");
}