libsetup.pm 96.5 KB
Newer Older
1
#!/usr/bin/perl -w
2

Leigh B. Stoller's avatar
Leigh B. Stoller committed
3
#
4
# Copyright (c) 2000-2017 University of Utah and the Flux Group.
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
# 
# {{{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/>.
# 
# }}}
Leigh B. Stoller's avatar
Leigh B. Stoller committed
24
#
25
# TODO: Signal handlers for protecting db files.
Leigh B. Stoller's avatar
Leigh B. Stoller committed
26

27 28 29 30 31 32 33
#
# Common routines and constants for the client bootime setup stuff.
#
package libsetup;
use Exporter;
@ISA = "Exporter";
@EXPORT =
Ryan Jackson's avatar
Ryan Jackson committed
34
    qw ( libsetup_init libsetup_setvnodeid libsetup_settimeout cleanup_node
35
	 getifconfig getrouterconfig gettrafgenconfig gettunnelconfig
Ryan Jackson's avatar
Ryan Jackson committed
36
	 check_nickname	bootsetup startcmdstatus whatsmynickname
37
	 TBForkCmd vnodejailsetup plabsetup vnodeplabsetup
Ryan Jackson's avatar
Ryan Jackson committed
38
	 jailsetup dojailconfig findiface libsetup_getvnodeid
Timothy Stack's avatar
 
Timothy Stack committed
39
	 ixpsetup libsetup_refresh gettopomap getfwconfig gettiptunnelconfig
40
	 gettraceconfig genhostsfile getmotelogconfig calcroutes fakejailsetup
41
	 getlocalevserver genvnodesetup getgenvnodeconfig stashgenvnodeconfig
42
         getlinkdelayconfig getloadinfo getbootwhat getnodeattributes
43
	 copyfilefromnfs getnodeuuid getarpinfo
44
	 getstorageconfig getstoragediskinfo getimagesize
45
         getrcmanifest fetchrcmanifestblobs runbootscript runhooks 
46
         build_fake_macs getenvvars getpnetnodeattrs
47
         sortedlistallfilesindir sortedreadallfilesindir
48

49 50
	 TBDebugTimeStamp TBDebugTimeStampWithDate
	 TBDebugTimeStampsOn TBDebugTimeStampsOff
51

52 53
	 MFS REMOTE REMOTEDED CONTROL FSNODE WINDOWS JAILED PLAB LOCALROOTFS
	 IXP USESFS SHADOW FSRVTYPE PROJDIR EXPDIR
54

55
	 SIMTRAFGEN SIMHOST ISDELAYNODEPATH JAILHOST DELAYHOST STARGATE
56
	 ISFW FAKEJAILED LINUXJAILED GENVNODE GENVNODETYPE GENVNODEHOST
57
	 SHAREDHOST SUBBOSS STORAGEHOST
58

59
	 CONFDIR LOGDIR TMDELAY TMBRIDGES TMJAILNAME TMSIMRC TMCC TMCCBIN
60
	 TMNICKNAME TMSTARTUPCMD FINDIF
61
	 TMROUTECONFIG TMLINKDELAY TMDELMAP TMTOPOMAP TMLTMAP TMLTPMAP
62
	 TMGATEDCONFIG TMSYNCSERVER TMKEYHASH TMNODEID TMNODEUUID TMEVENTKEY
Ryan Jackson's avatar
Ryan Jackson committed
63
	 TMCREATOR TMSWAPPER TMFWCONFIG TMGENVNODECONFIG
64
	 TMSTORAGEMAP TMDISKINFO TMEXTRAFS
Leigh B Stoller's avatar
Leigh B Stoller committed
65
	 INXENVM INVZVM
66 67 68 69
       );

# Must come after package declaration!
use English;
70
use Errno;
71

72
my $debug = 0;
73

74 75
# The tmcc library.
use libtmcc;
76
use librc;
77 78 79 80 81 82 83

#
# This is the VERSION. We send it through to tmcd so it knows what version
# responses this file is expecting.
#
# BE SURE TO BUMP THIS AS INCOMPATIBILE CHANGES TO TMCD ARE MADE!
#
84 85 86
# IMPORTANT NOTE: if you change the version here, you must also change it
# in clientside/lib/tmcd/tmcd.h!
#
87
sub TMCD_VERSION()	{ 41; };
88 89 90 91 92
libtmcc::configtmcc("version", TMCD_VERSION());

# Control tmcc timeout.
sub libsetup_settimeout($) { libtmcc::configtmcc("timeout", $_[0]); };

93
# Refresh tmcc cache.
94 95
sub libsetup_refresh()	   { libtmcc::tmccgetconfig(); };

96
#
97 98
# For virtual (multiplexed nodes). If defined, tack onto tmcc command.
# and use in pathnames. Used in conjunction with jailed virtual nodes.
99
# I am also using this for subnodes; eventually everything will be subnodes.
100
#
101
my $vnodeid;
102 103
sub libsetup_setvnodeid($)
{
104 105 106 107 108 109 110 111 112 113 114
    my ($vid) = @_;

    if ($vid =~ /^([-\w]+)$/) {
	$vid = $1;
    }
    else {
	die("Bad data in vnodeid: $vid");
    }

    $vnodeid = $vid;
    libtmcc::configtmcc("subnode", $vnodeid);
115 116 117 118 119
}
sub libsetup_getvnodeid()
{
    return $vnodeid;
}
120

121
#
Ryan Jackson's avatar
Ryan Jackson committed
122 123
# True if running inside a jail. Set just below.
#
124 125
my $injail;

126 127 128 129 130 131
#
# True if $injail == TRUE and running on Linux.
# Right now this means vserves on RHL.
#
my $inlinuxjail;

132 133 134 135 136
#
# True if running inside a vm.
#
my $ingenvnode;

137 138
#
# True if running as a fake jail (no jail, just processes).
Ryan Jackson's avatar
Ryan Jackson committed
139
#
140 141
my $nojail;

142 143 144 145 146
#
# True if running in a Plab vserver.
#
my $inplab;

147 148 149 150 151 152
#
# Ditto for IXP, although currently there is no "in" IXP setup; it
# is all done from outside.
#
my $inixp;

153 154 155 156 157 158
#
# Shadow mode. Run the client side against a remote tmcd.
#
my $shadow;
my $SHADOWDIR = "$VARDIR/shadow";

159 160 161 162 163 164 165
#
# Fileserver type.
# Default is "racy NFS" (the historical only choice) until proven otherwise
# (via "mounts" tmcc call).
#
my $fsrvtype = "NFS-RACY";

166 167 168
#
# The role of this pnode
#
169
my $role;
170

171 172 173
# Load up the paths. Its conditionalized to be compatabile with older images.
# Note this file has probably already been loaded by the caller.
BEGIN
174
{
175 176 177 178 179
    if (! -e "/etc/emulab/paths.pm") {
	die("Yikes! Could not require /etc/emulab/paths.pm!\n");
    }
    require "/etc/emulab/paths.pm";
    import emulabpaths;
180
    $SHADOWDIR = "$VARDIR/shadow";
181

182
    # Make sure these exist! They will not exist on a PLAB vserver initially.
183 184
    mkdir("$VARDIR", 0775);
    mkdir("$VARDIR/jails", 0775);
185
    mkdir("$VARDIR/vms", 0775);
186 187 188 189
    mkdir("$VARDIR/db", 0755);
    mkdir("$VARDIR/logs", 0775);
    mkdir("$VARDIR/boot", 0775);
    mkdir("$VARDIR/lock", 0775);
190 191 192 193 194
    mkdir("$SHADOWDIR", 0775);
    mkdir("$SHADOWDIR/db", 0755);
    mkdir("$SHADOWDIR/logs", 0775);
    mkdir("$SHADOWDIR/boot", 0775);
    mkdir("$SHADOWDIR/lock", 0775);
195

196 197 198 199 200
    #
    # Shadow mode allows the client side to run against remote tmcd.
    #
    if (exists($ENV{'SHADOW'})) {
	$shadow = $ENV{'SHADOW'};
201
	my ($server,$idkey) = split(',', $shadow);
202 203 204 205 206 207 208 209 210
	#
	# Need to taint check these to avoid breakage later.
	#
	if ($server =~ /^([-\w\.]+)$/) {
	    $server = $1;
	}
	else {
	    die("Bad data in server: $server");
	}
211 212
	if ($idkey =~ /^([-\w\+\:\.]*)$/) {
	    $idkey = $1;
213 214
	}
	else {
215
	    die("Bad data in urn: $idkey");
216
	}
Ryan Jackson's avatar
Ryan Jackson committed
217

218 219 220
	# The cache needs to go in a difference location.
	libtmcc::configtmcc("cachedir", $SHADOWDIR);
	libtmcc::configtmcc("server", $server);
221
	libtmcc::configtmcc("idkey", $idkey);
222 223
	# No proxy.
	libtmcc::configtmcc("noproxy", 1);
224
    }
225 226 227
    #
    # Determine if running inside a jail. This affects the paths below.
    #
228
    if (-e "$BOOTDIR/jailname") {
229
	open(VN, "$BOOTDIR/jailname");
230
	my $vid = <VN>;
231 232
	close(VN);

233
	libsetup_setvnodeid($vid);
234
	$injail = 1;
235 236 237
	if ($^O eq "linux") {
	    $inlinuxjail = 1;
	}
238
    }
239 240 241 242 243 244 245
    elsif (exists($ENV{'FAKEJAIL'})) {
	# Fake jail.
	libsetup_setvnodeid($ENV{'FAKEJAIL'});
	$nojail = 1;
    }
    elsif (-e "$BOOTDIR/plabname") {
	# Running inside a Plab vserver.
246
	open(VN, "$BOOTDIR/plabname");
247
	my $vid = <VN>;
248 249
	close(VN);

250
	libsetup_setvnodeid($vid);
251 252
	$inplab = 1;
    }
253 254 255 256 257 258 259 260 261
    elsif (-e "$BOOTDIR/vmname") {
	open(VN, "$BOOTDIR/vmname");
	my $vid = <VN>;
	close(VN);

	libsetup_setvnodeid($vid);
	$ingenvnode = 1;

    }
262

263
    $role = "";
Ryan Jackson's avatar
Ryan Jackson committed
264
    # Get our role.
265 266 267 268
    if (-e "$BOOTDIR/role") {
	open(VN, "$BOOTDIR/role");
	$role = <VN>;
	close(VN);
269
	chomp($role);
270
    }
271 272
}

273
#
Ryan Jackson's avatar
Ryan Jackson committed
274
# This "local" library provides the OS dependent part.
275
#
276
use liblocsetup;
277

278 279 280 281
#
# These are the paths of various files and scripts that are part of the
# setup library.
#
282
sub TMCC()		{ "$BINDIR/tmcc"; }
283
sub TMCCBIN()		{ "$BINDIR/tmcc.bin"; }
284
sub FINDIF()		{ "$BINDIR/findif"; }
285
sub TMUSESFS()		{ "$BOOTDIR/usesfs"; }
286 287
sub ISSIMTRAFGENPATH()	{ "$BOOTDIR/simtrafgen"; }
sub ISDELAYNODEPATH()	{ "$BOOTDIR/isdelaynode"; }
288
sub TMTOPOMAP()		{ "$BOOTDIR/topomap";}
Timothy Stack's avatar
 
Timothy Stack committed
289
sub TMLTMAP()		{ "$BOOTDIR/ltmap";}
290
sub TMLTPMAP()		{ "$BOOTDIR/ltpmap";}
291 292 293
sub TMSTORAGEMAP()	{ "$BOOTDIR/storagemap";}
sub TMDISKINFO()	{ "$BOOTDIR/diskinfo";}
sub TMEXTRAFS()		{ "$BOOTDIR/extrafs";}
294

295
#
296
# This path is valid only *outside* the jail when its setup.
Ryan Jackson's avatar
Ryan Jackson committed
297
#
298 299
sub JAILDIR()		{ "$VARDIR/jails/$vnodeid"; }

300 301 302 303
#
# This path is valid only *outside* the vm.  Sucks, but this is the best we
# can do.  Probably the only way to make this vm-specific if necessary is to
# have them create their dir and symlink.
Ryan Jackson's avatar
Ryan Jackson committed
304
#
305 306 307 308 309 310 311 312 313 314 315 316 317 318 319
sub GENVNODEDIR()	{ "$VARDIR/vms/$vnodeid"; }

#
# XXX: eventually this needs to come from tmcd, but that's not ready yet.
#
sub GENVNODETYPE() {
    if (-e "$ETCDIR/genvmtype") {
	my $vmtype = `cat $ETCDIR/genvmtype`;
	chomp($vmtype);
	return $vmtype;
    }

    return undef;
}

320 321 322
#
# Also valid outside the jail, this is where we put local project storage.
#
323
sub LOCALROOTFS() {
Ryan Jackson's avatar
Ryan Jackson committed
324
    return "/users/local"
325
	if (REMOTE());
Ryan Jackson's avatar
Ryan Jackson committed
326
    return "$VARDIR/jails/local"
327
	if (JAILED());
Ryan Jackson's avatar
Ryan Jackson committed
328
    return "$VARDIR/vms/local"
329
	if (GENVNODE());
330
    return "/local";
331
}
332

333 334 335
#
# Okay, here is the path mess. There are three environments.
# 1. A local node where everything goes in one place ($VARDIR/boot).
336
# 2. A virtual node inside a jail or a Plab vserver ($VARDIR/boot).
Ryan Jackson's avatar
Ryan Jackson committed
337
# 3. A virtual (or sub) node, from the outside.
338
#
339
# As for #3, whether setting up a old-style (fake) virtual node or a new style
340 341 342
# jailed node, the code that sets it up needs a different per-vnode path.
#
sub CONFDIR() {
343 344
    return "$SHADOWDIR/boot"
	if ($shadow);
345
    return $BOOTDIR
346
	if ($injail || $inplab || $ingenvnode);
Ryan Jackson's avatar
Ryan Jackson committed
347
    return GENVNODEDIR()
348
	if ($vnodeid && GENVNODETYPE());
349 350
    return JAILDIR()
	if ($vnodeid);
351
    return $BOOTDIR;
352
}
353 354
# Cause of fakejails, we want log files in the right place.
sub LOGDIR() {
355 356
    return "$SHADOWDIR/logs"
	if ($shadow);
357
    return $LOGDIR
358
	if ($injail || $inplab || $ingenvnode);
Ryan Jackson's avatar
Ryan Jackson committed
359
    return GENVNODEDIR()
360
	if ($vnodeid && GENVNODETYPE());
Ryan Jackson's avatar
Ryan Jackson committed
361
    return JAILDIR()
362 363 364
	if ($vnodeid);
    return $LOGDIR;
}
365

366 367
#
# The rest of these depend on the environment running in (inside/outside jail).
Ryan Jackson's avatar
Ryan Jackson committed
368
#
369 370
sub TMNICKNAME()	{ CONFDIR() . "/nickname";}
sub TMJAILNAME()	{ CONFDIR() . "/jailname";}
371
sub TMFAKEJAILNAME()	{ CONFDIR() . "/fakejail";}
372
sub TMJAILCONFIG()	{ CONFDIR() . "/jailconfig";}
373
sub TMGENVNODECONFIG()  { CONFDIR() . "/genvnodeconfig";}
374 375
sub TMSTARTUPCMD()	{ CONFDIR() . "/startupcmd";}
sub TMROUTECONFIG()     { CONFDIR() . "/rc.route";}
376
sub TMGATEDCONFIG()     { CONFDIR() . "/gated.conf";}
377
sub TMBRIDGES()		{ CONFDIR() . "/rc.bridges";}
378 379
sub TMDELAY()		{ CONFDIR() . "/rc.delay";}
sub TMLINKDELAY()	{ CONFDIR() . "/rc.linkdelay";}
380
sub TMDELMAP()		{ CONFDIR() . "/delay_mapping";}
381
sub TMSYNCSERVER()	{ CONFDIR() . "/syncserver";}
382
sub TMKEYHASH()		{ CONFDIR() . "/keyhash";}
383
sub TMEVENTKEY()	{ CONFDIR() . "/eventkey";}
384
sub TMNODEID()		{ CONFDIR() . "/nodeid";}
385
sub TMNODEUUID()	{ CONFDIR() . "/nodeuuid";}
386 387
sub TMROLE()		{ CONFDIR() . "/role";}
sub TMSIMRC()		{ CONFDIR() . "/rc.simulator";}
388
sub TMCREATOR()		{ CONFDIR() . "/creator";}
389
sub TMSWAPPER()		{ CONFDIR() . "/swapper";}
390
sub TMFWCONFIG()	{ CONFDIR() . "/rc.fw";}
391 392 393

#
# This is a debugging thing for my home network.
394 395 396 397 398 399 400 401 402 403
#
my $NODE = "";
if (defined($ENV{'TMCCARGS'})) {
    if ($ENV{'TMCCARGS'} =~ /^([-\w\s]*)$/) {
	$NODE .= " $1";
    }
    else {
	die("Tainted TMCCARGS from environment: $ENV{'TMCCARGS'}!\n");
    }
}
404 405

# Locals
406 407 408
my $pid		= "";
my $eid		= "";
my $vname	= "";
409 410 411 412 413 414
my $TIMESTAMPS  = 0;

# Allow override from the environment;
if (defined($ENV{'TIMESTAMPS'})) {
    $TIMESTAMPS = $ENV{'TIMESTAMPS'};
}
415

416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439
#
# Any reason NOT to hardwire these?
#
sub PROJDIR() {
    my $p = $pid;
    if (!$p) {
	($p, undef, undef) = check_nickname();
	return ""
	    if (!$p);
    }
    return "/proj/$p";
}

sub EXPDIR() {
    my $p = $pid;
    my $e = $eid;
    if (!$p || !$e) {
	($p, $e, undef) = check_nickname();
	return ""
	    if (!$p || !$e);
    }
    return "/proj/$p/exp/$e";
}

440 441 442
# When on the MFS, we do a much smaller set of stuff.
# Cause of the way the packages are loaded (which I do not understand),
# this is computed on the fly instead of once.
443
sub MFS()	{ if (-e "$ETCDIR/ismfs") { return 1; } else { return 0; } }
444

445 446 447
#
# Same for a remote node.
#
448 449
sub REMOTE()	{ if (-e "$ETCDIR/isrem") { return 1; } else { return 0; } }

450 451 452 453 454
#
# Same for a dedicated remote node.
#
sub REMOTEDED()	{ if (-e "$ETCDIR/isremded") { return 1; } else { return 0; } }

455 456 457 458 459
#
# Same for a control node.
#
sub CONTROL()	{ if (-e "$ETCDIR/isctrl") { return 1; } else { return 0; } }

460 461 462 463 464
#
# Same for an FS node.
#
sub FSNODE()	{ if (-e "$ETCDIR/isfs") { return 1; } else { return 0; } }

465 466 467
#
# Same for a Windows (CygWinXP) node.
#
468
# XXX  If you change this, look in libtmcc::tmccgetconfig() as well.
469 470
sub WINDOWS()	{ if (-e "$ETCDIR/iscygwin") { return 1; } else { return 0; } }

Kirk Webb's avatar
 
Kirk Webb committed
471 472 473 474 475
#
# Same for a stargate/garcia node.
#
sub STARGATE()  { if (-e "$ETCDIR/isstargate") { return 1; } else { return 0; } }

476 477 478 479
#
# Are we jailed? See above.
#
sub JAILED()	{ if ($injail) { return $vnodeid; } else { return 0; } }
480
sub FAKEJAILED(){ if ($nojail) { return $vnodeid; } else { return 0; } }
481
sub LINUXJAILED(){ if ($injail && $inlinuxjail) { return $vnodeid; } else { return 0; } }
482

483 484 485 486 487
#
# Are we using the generic vm abstraction for this vnode?  See above.
#
sub GENVNODE()  { if ($ingenvnode) { return $vnodeid; } else { return 0; } }

488 489 490 491 492
#
# Are we on plab?
#
sub PLAB()	{ if ($inplab) { return $vnodeid; } else { return 0; } }

493 494 495 496 497
#
# Are we on an IXP
#
sub IXP()	{ if ($inixp) { return $vnodeid; } else { return 0; } }

498 499 500 501 502
#
# Are we a firewall node
#
sub ISFW()	{ if (-e TMFWCONFIG()) { return 1; } else { return 0; } }

503
#
504
# Are we hosting a simulator or maybe just a NSE based trafgen.
505 506
#
sub SIMHOST()   { if ($role eq "simhost") { return 1; } else { return 0; } }
507
sub SIMTRAFGEN(){ if (-e ISSIMTRAFGENPATH())  { return 1; } else { return 0; } }
508

Ryan Jackson's avatar
Ryan Jackson committed
509 510 511 512 513
#
# Are we a subboss?
#
sub SUBBOSS()   { if ($role eq "subboss") { return 1; } else { return 0; } }

514
# A jail host?
515 516 517 518
sub JAILHOST()     { return (($role eq "virthost" ||
			      $role eq "sharedhost") ? 1 : 0); }
sub GENVNODEHOST() { if ($role eq "virthost") { return 1; } else { return 0; }}
sub SHAREDHOST()   { return ($role eq "sharedhost" ? 1 : 0); }
519
sub STORAGEHOST()  { return ($role eq "storagehost" ? 1 : 0); }
520

521 522 523
# A delay host?  Either a delay node or a node using linkdelays
sub DELAYHOST()	{ if (-e ISDELAYNODEPATH()) { return 1; } else { return 0; } }

524 525 526
# A shadow?
sub SHADOW()	   { return (defined($shadow) ? 1 : 0); }

527
#
528
# Is this node using SFS. Several scripts need to know this.
529
#
530
sub USESFS()	{ if (-e TMUSESFS()) { return 1; } else { return 0; } }
531

532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559
#
# What type of fileserver is this node using.  Choices are:
#
# NFS-RACY	FreeBSD NFS server with mountd race (the default)
# NFS		NFS server
# LOCAL		No shared filesystems
#
# XXX should come from tmcd
#
sub FSRVTYPE() {
    if (-e "$BOOTDIR/fileserver") {
	open(FD, "$BOOTDIR/fileserver");
	$fsrvtype = <FD>;
	close(FD);
	chomp($fsrvtype);
    }
    return $fsrvtype;
}

# XXX fer now hack: comes from rc.mounts
sub setFSRVTYPE($) {
    $fsrvtype = shift;
    if (open(FD, ">$BOOTDIR/fileserver")) {
	print FD "$fsrvtype\n";
	close(FD);
    }
}

Mike Hibler's avatar
Mike Hibler committed
560
#
Leigh B Stoller's avatar
Leigh B Stoller committed
561
# XXX fernow hack so I can readily identify code that is special to VMs
Mike Hibler's avatar
Mike Hibler committed
562 563
#
sub INXENVM()	{ return ($ingenvnode && GENVNODETYPE() eq "xen"); }
Leigh B Stoller's avatar
Leigh B Stoller committed
564
sub INVZVM()	{ return ($ingenvnode && GENVNODETYPE() eq "openvz"); }
Mike Hibler's avatar
Mike Hibler committed
565

566 567 568
#
# Reset to a moderately clean state.
#
569 570
sub cleanup_node ($) {
    my ($scrub) = @_;
Ryan Jackson's avatar
Ryan Jackson committed
571

572
    print STDOUT "Cleaning node; removing configuration files\n";
573
    unlink TMUSESFS, TMROLE, ISSIMTRAFGENPATH, ISDELAYNODEPATH;
574
    unlink TMSTORAGEMAP, TMDISKINFO;
575

576
    #
577 578
    # If scrubbing, also remove the password/group files and DBs so
    # that we revert to base set.
Ryan Jackson's avatar
Ryan Jackson committed
579
    #
580
    if ($scrub) {
581
	unlink TMNICKNAME;
582 583
	# XXX !scrub allows this to be initialized from outside (libvnode)
	unlink TMEXTRAFS;
584 585 586 587
    }
}

#
588 589
# Check node allocation. If the nickname file has been created, use
# that to avoid load on tmcd.
590 591 592 593 594
#
# Returns 0 if node is free. Returns list (pid/eid/vname) if allocated.
#
sub check_status ()
{
595 596 597
    my @tmccresults;

    if (tmcc(TMCCCMD_STATUS, undef, \@tmccresults) < 0) {
598 599
	warn("*** WARNING: Could not get status from server!\n");
	return -1;
600
    }
601 602 603 604
    #
    # This is possible if the boss node does not now about us yet.
    # We want to appear free. Specifically, it could happen on the
    # MFS when trying to bring in brand new nodes. tmcd will not know
Ryan Jackson's avatar
Ryan Jackson committed
605
    # anything about us, and return no info.
606 607 608 609 610
    #
    return 0
	if (! @tmccresults);

    my $status = $tmccresults[0];
611

612
    if ($status =~ /^FREE/) {
613
	unlink TMNICKNAME;
614 615
	return 0;
    }
Ryan Jackson's avatar
Ryan Jackson committed
616

617
    if ($status =~ /ALLOCATED=([-\@\w]*)\/([-\@\w]*) NICKNAME=([-\@\w]*)/) {
618 619 620 621 622 623
	$pid   = $1;
	$eid   = $2;
	$vname = $3;
    }
    else {
	warn "*** WARNING: Error getting reservation status\n";
624
	return -1;
625
    }
Ryan Jackson's avatar
Ryan Jackson committed
626

627 628
    #
    # Stick our nickname in a file in case someone wants it.
629 630
    # Do not overwrite; we want to save the original info until later.
    # See bootsetup; indicates project change!
631
    #
632
    if (! -e TMNICKNAME()) {
633 634
	system("echo '$vname.$eid.$pid' > " . TMNICKNAME());
    }
Ryan Jackson's avatar
Ryan Jackson committed
635

636 637 638 639
    return ($pid, $eid, $vname);
}

#
640 641
# Check cached nickname. Its okay if we have been deallocated and the info
# is stale. The node will notice that later.
Ryan Jackson's avatar
Ryan Jackson committed
642
#
643
sub check_nickname()
644
{
645 646 647
    if (-e TMNICKNAME) {
	my $nickfile = TMNICKNAME;
	my $nickinfo = `cat $nickfile`;
648

649 650 651 652 653 654 655 656 657
	if ($nickinfo =~ /([-\@\w]*)\.([-\@\w]*)\.([-\@\w]*)/) {
	    $vname = $1;
	    $eid   = $2;
	    $pid   = $3;

	    return ($pid, $eid, $vname);
	}
    }
    return check_status();
658 659 660
}

#
661 662
# Do SFS hostid setup. If we have an SFS host key and we can get a hostid
# from the SFS daemon, then send it to TMCD.
Austin Clements's avatar
Austin Clements committed
663
#
664
sub initsfs()
Austin Clements's avatar
Austin Clements committed
665 666 667
{
    my $myhostid;

668 669 670
    # Default to no SFS unless we can determine we have it running.
    unlink TMUSESFS()
	if (-e TMUSESFS());
Ryan Jackson's avatar
Ryan Jackson committed
671

672
    # Do I have a host key?
Austin Clements's avatar
Austin Clements committed
673
    if (! -e "/etc/sfs/sfs_host_key") {
674
	return;
Austin Clements's avatar
Austin Clements committed
675 676 677
    }

    # Give hostid to TMCD
678 679 680 681 682 683
    if (-d "/usr/local/lib/sfs-0.6") {
	$myhostid = `sfskey hostid - 2>/dev/null`;
    }
    else {
	$myhostid = `sfskey hostid -s authserv - 2>/dev/null`;
    }
684
    if (! $?) {
Austin Clements's avatar
Austin Clements committed
685 686 687
	if ( $myhostid =~ /^([-\.\w_]*:[a-z0-9]*)$/ ) {
	    $myhostid = $1;
	    print STDOUT "  Hostid: $myhostid\n";
688
	    tmcc(TMCCCMD_SFSHOSTID, "$myhostid");
Austin Clements's avatar
Austin Clements committed
689
	}
690 691 692
	elsif ( $myhostid =~ /^(@[-\.\w_]*,[a-z0-9]*)$/ ) {
	    $myhostid = $1;
	    print STDOUT "  Hostid: $myhostid\n";
693
	    tmcc(TMCCCMD_SFSHOSTID, "$myhostid");
694
	}
Austin Clements's avatar
Austin Clements committed
695 696
	else {
	    warn "*** WARNING: Invalid hostid\n";
697
	    return;
Austin Clements's avatar
Austin Clements committed
698
	}
699
	system("touch " . TMUSESFS());
Austin Clements's avatar
Austin Clements committed
700 701
    }
    else {
702
	warn "*** WARNING: Could not retrieve this node's SFShostid!\n";
Austin Clements's avatar
Austin Clements committed
703
    }
704 705 706
}

#
Ryan Jackson's avatar
Ryan Jackson committed
707 708
# Get the role of the node and stash it for future libsetup load.
#
709 710 711
sub dorole()
{
    my @tmccresults;
Austin Clements's avatar
Austin Clements committed
712

713 714 715 716 717 718
    if (tmcc(TMCCCMD_ROLE, undef, \@tmccresults) < 0) {
	warn("*** WARNING: Could not get role from server!\n");
	return -1;
    }
    return 0
	if (! @tmccresults);
Ryan Jackson's avatar
Ryan Jackson committed
719

720 721 722 723 724 725 726 727 728 729 730 731 732 733 734
    #
    # There should be just one string. Ignore anything else.
    #
    if ($tmccresults[0] =~ /([\w]*)/) {
	# Storing the value into the global variable
	$role = $1;
    }
    else {
	warn "*** WARNING: Bad role line: $tmccresults[0]";
	return -1;
    }
    system("echo '$role' > " . TMROLE());
    if ($?) {
	warn "*** WARNING: Could not write role to " . TMROLE() . "\n";
    }
Austin Clements's avatar
Austin Clements committed
735 736 737
    return 0;
}

738 739
#
# Get the nodeid
Ryan Jackson's avatar
Ryan Jackson committed
740
#
741 742 743 744 745
sub donodeid()
{
    my $nodeid;
    my @tmccresults;

746 747 748
    # Do this too.
    donodeuuid();

749 750 751 752 753 754
    if (tmcc(TMCCCMD_NODEID, undef, \@tmccresults) < 0) {
	warn("*** WARNING: Could not get nodeid from server!\n");
	return -1;
    }
    return 0
	if (! @tmccresults);
Ryan Jackson's avatar
Ryan Jackson committed
755

756 757 758 759 760 761 762 763 764 765
    #
    # There should be just one string. Ignore anything else.
    #
    if ($tmccresults[0] =~ /([-\w]*)/) {
	$nodeid = $1;
    }
    else {
	warn "*** WARNING: Bad nodeid line: $tmccresults[0]";
	return -1;
    }
Ryan Jackson's avatar
Ryan Jackson committed
766

767 768 769 770 771 772 773
    system("echo '$nodeid' > ". TMNODEID);
    if ($?) {
	warn "*** WARNING: Could not write nodeid to " . TMNODEID() . "\n";
    }
    return 0;
}

774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806
#
# Get the nodeuuid
#
sub donodeuuid()
{
    my $nodeuuid;
    my @tmccresults;

    if (tmcc(TMCCCMD_NODEUUID, undef, \@tmccresults) < 0) {
	warn("*** WARNING: Could not get nodeuuid from server!\n");
	return -1;
    }
    return 0
	if (! @tmccresults);

    #
    # There should be just one string. Ignore anything else.
    #
    if ($tmccresults[0] =~ /([-\w]*)/) {
	$nodeuuid = $1;
    }
    else {
	warn "*** WARNING: Bad nodeuuid line: $tmccresults[0]";
	return -1;
    }

    system("echo '$nodeuuid' > ". TMNODEUUID);
    if ($?) {
	warn "*** WARNING: Could not write nodeuuid to " . TMNODEUUID() . "\n";
    }
    return 0;
}

807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869
sub rcordersort($$) {
    my ($a,$b) = @_;
    my $ca = substr($a,0,1);
    my $cb = substr($b,0,1);
    my $na = ($ca ge '0' && $ca le '9');
    my $nb = ($cb ge '0' && $cb le '9');

    if ($na && $nb) {
	return int($a) <=> int($b);
    }
    elsif ($na && !$nb) {
	return -1;
    }
    elsif (!$na && $nb) {
	return 1;
    }
    else {
	return $a cmp $b;
    }
}

sub sortedlistallfilesindir($$;$) {
    my ($dir,$rptr,$qualify) = @_;

    my $DIRH;
    my $rc = opendir($DIRH,$dir);
    if (!$rc) {
	return $rc;
    }
    my @files = grep { /^[^\.\#].*[^\~]$/ && -f "$dir/$_" } readdir($DIRH);
    closedir($DIRH);
    my @sfiles = sort rcordersort @files;
    if (defined($qualify) && $qualify != 0) {
	my @tfiles = ();
	for my $file (@sfiles) {
	    push(@tfiles,"$dir/$file");
	}
	@sfiles = @tfiles;
    }
    @$rptr = @sfiles;

    return 0;
}

sub sortedreadallfilesindir($$) {
    my ($dir,$rptr) = @_;

    my @sfiles = ();
    my $rc = sortedlistallfilesindir($dir,\@sfiles,1);
    return $rc if ($rc);
    for my $file (@sfiles) {
	my $FH;
	if (!open($FH,"$file")) {
	    next;
	}
	my @lines = <$FH>;
	close($FH);
	push(@$rptr,@lines);
    }

    return 0;
}

870 871 872 873
#
# Get the boot script manifest -- whether scripts are enabled, or hooked, and 
# how and when they or their hooks run!
#
874
sub getrcmanifest($;$)
875 876
{
    my ($rptr,$nofetch) = @_;
877
    my @tmccresults = ();
878
    my %manifest = ();
879
    my $retval = 0;
880 881 882 883 884 885

    print "Checking manifest...\n";

    if (tmcc(TMCCCMD_MANIFEST, undef, \@tmccresults) < 0) {
	warn("*** WARNING: Could not get manifest from server!\n");
	%$rptr = ();
886
	$retval = -1;
887
    }
888 889 890
    # Always allow local manifests to be run, so add them into our results.
    sortedreadallfilesindir("$DYNRUNDIR/rcmanifest.d",\@tmccresults);
    sortedreadallfilesindir("$STATICRUNDIR/rcmanifest.d",\@tmccresults);
891 892
    if (@tmccresults == 0) {
	%$rptr = ();
893
	return $retval;
894 895 896 897
    }

    my $servicepat = q(SERVICE NAME=([\w\.\-]+) ENV=(\w+) WHENCE=(\w+));
    $servicepat   .= q( ENABLED=(0|1) HOOKS_ENABLED=(0|1));
898 899 900 901
    $servicepat   .= q( FATAL=(0|1) (BLOBID)=([\w\-]*));
    my $servicepatfile = q(SERVICE NAME=([\w\.\-]+) ENV=(\w+) WHENCE=(\w+));
    $servicepatfile   .= q( ENABLED=(0|1) HOOKS_ENABLED=(0|1));
    $servicepatfile   .= q( FATAL=(0|1) (FILE)=([^ ]*));
902 903 904

    my $hookpat = q(HOOK SERVICE=([\w\.\-]+) ENV=(\w+) WHENCE=(\w+));
    $hookpat   .= q( OP=(\w+) POINT=(\w+));
905
    $hookpat   .= q( FATAL=(0|1) (BLOBID)=([\w\-]+));
906
    $hookpat   .= q( ARGV="([^"]*)");
907 908 909 910
    my $hookpatfile = q(HOOK SERVICE=([\w\.\-]+) ENV=(\w+) WHENCE=(\w+));
    $hookpatfile   .= q( OP=(\w+) POINT=(\w+));
    $hookpatfile   .= q( FATAL=(0|1) (FILE)=([^ ]+));
    $hookpatfile   .= q( ARGV="([^"]*)");
911 912 913

    my @loadinforesults = ();
    if (tmcc(TMCCCMD_LOADINFO, undef, \@loadinforesults) < 0) {
914
	warn("*** WARNING: getrcmanifest could not get loadinfo from server,\n".
915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949
	     "             unsure if node is in MFS and reloading, continuing!\n");
    }

    #
    # Are we in a loading environment?  If yes, filter the manifest
    # so that only the service and hook settings that apply to the 
    # loading MFS apply.
    #
    if (@loadinforesults && MFS()) {
	$manifest{'_ENV'} = 'load';
    }
    #
    # Otherwise, if we're not in an MFS, we must be booting!
    # NOTE: we don't do any configuration of the image in the 
    # admin MFS!
    #
    elsif (!MFS()) {
	$manifest{'_ENV'} = 'boot';
    }
    #
    # Otherwise, don't return *anything* -- the admin mfs doesn't do any
    # config of the node.
    #
    else {
	%$rptr = ();
	return 0;
    }

    #
    # Process our results.
    #
    for (my $i = 0; $i < @tmccresults; ++$i) {
	my $line = $tmccresults[$i];
	my %service;

950
	if ($line =~ /^$servicepat/ || $line =~ /^$servicepatfile/) {
951 952
	    my %service = ( 'ENABLED' => $4,
			    'HOOKS_ENABLED' => $5,
953
			    "$7" => $8,
954 955
			    'WHENCE' => $3,
			    'FATAL' => $6 );