node_admin.in 4.85 KB
Newer Older
1
#!/usr/bin/perl -wT
Leigh B. Stoller's avatar
Leigh B. Stoller committed
2
3
#
# EMULAB-COPYRIGHT
4
# Copyright (c) 2000-2004 University of Utah and the Flux Group.
Leigh B. Stoller's avatar
Leigh B. Stoller committed
5
6
# All rights reserved.
#
7
8
9
10
use English;
use Getopt::Std;

#
11
# Turn on/off admin mode for nodes and optionally reboot/wait.
12
13
14
#
sub usage()
{
15
16
    print STDOUT "Usage: node_admin [-h] [-n | -w] <on | off> [node ....]\n";
    print STDOUT "       node_admin [-h] [-n | -w] -p pid,eid <on | off>\n";
17
    print STDOUT "-h   This message\n";
18
19
    print STDOUT "-n   Do not reboot node\n";
    print STDOUT "-w   Wait for node to come back up if rebooted\n";
20
    print STDOUT "-e   Operate on all nodes in an experiment\n";
21
22
    exit(-1);
}
23
24
25
my $optlist  = "hnwe:";
my $waitmode = 0;
my $reboot   = 1;
26
27
28
29
30
31
32
33
34
35
36
37

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

#
# Testbed Support libraries
#
use lib "@prefix@/lib";
use libdb;
use libtestbed;
38
use StateWait;
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

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

#
# Untaint the path
# 
$ENV{'PATH'} = "/bin:/sbin:/usr/bin:";
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};

#
# 
#
my $nodereboot	= "$TB/bin/node_reboot";
55
my $osselect    = "$TB/bin/os_select";
56
my $ADMINOSID   = TB_OSID_FREEBSD_MFS;
57
my @nodes       = ();
58
59
60
61
62
63
64
65
66

#
# Parse command arguments. Once we return from getopts, all that should be
# left are the required arguments.
#
%options = ();
if (! getopts($optlist, \%options)) {
    usage();
}
67
if (defined($options{h})) {
68
69
    usage();
}
70
71
72
73
74
75
76
if (defined($options{"n"})) {
    $reboot = 0;
}
if (defined($options{"w"})) {
    $waitmode = 1;
}

77
if (!@ARGV) {
78
79
80
    usage();
}

81
my $onoff  = shift(@ARGV);
82
83
84
85
86

if ($onoff ne "on" && $onoff ne "off") {
    usage();
}

87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
if (defined($options{"e"})) {
    #
    # Reboot all nodes in an experiment
    #
    if (@ARGV) {
	usage();
    }

    my $eidmode = $options{"e"};
    my $pid;
    my $eid;
    
    if ($eidmode =~ /([-\w]*),([-\w]*)/) {
	$pid = $1;
	$eid = $2;
    }
    else {
	die("*** $0:\n".
	    "    Invalid argument to -e option: $eidmode\n");
    }

    #
    # Verify permission to muck with this experiment. This is to head off
    # permission problems early; the nodes are indvidually checked later
    # in the library.
    #
    if ($UID && !TBAdmin($UID) &&
	! TBExptAccessCheck($UID, $pid, $eid, TB_EXPT_MODIFY)) {
	die("*** $0:\n".
	    "    You not have permission to reboot nodes in $pid/$eid!\n");
    }

    my $query_result =
	DBQueryFatal("select node_id from reserved where ".
		     "pid='$pid' and eid='$eid'");

    if ($query_result->numrows == 0) {
	die("*** $0:\n".
            "    There are no nodes reserved in pid/eid $pid/$eid\n");
    }
    
    while (my ($nodeid) = $query_result->fetchrow_array()) {
	push(@nodes, $nodeid);
    }
131
132
}
else {
133
134
135
    if (! @ARGV) {
	usage();
    }
136

137
138
139
140
141
142
143
144
145
146
147
148
149
150
    # Untaint the nodes.
    foreach my $node ( @ARGV ) {
	if ($node =~ /^([-\w]+)$/) {
	    $node = $1;
	}
	else {
	    die("*** Tainted node name: $node\n");
	}
	if (!TBValidNodeName($node)) {
	    die("*** $0:\n".
		"    Node does not exist: $node\n");
	}
	push(@nodes, $node);
    }
151

152
153
154
155
156
157
158
159
160
    #
    # Root and admin types can do whatever they want. Normal users
    # can only run this on nodes in their own experiments.
    #
    if ($UID && !TBAdmin($UID)) {
	if (! TBNodeAccessCheck($UID, TB_NODEACCESS_LOADIMAGE, @nodes)) {
	    die("*** $0:\n".
		"    You are not allowed to put some nodes into admin mode\n");
	}
161
162
163
    }
}

164
# Switcheroo the osids on the nodes.
165
if ($onoff eq "on") {
166
167
168
    system("$osselect -t $ADMINOSID @nodes") and
	die("*** $0:\n".
	    "    Failed to set temp boot to $ADMINOSID for some nodes!\n");
169
170
}
else {
171
172
173
    system("$osselect -c -t @nodes") and
	die("*** $0:\n".
	    "    Failed to clear temp boot for some nodes!\n");
174
}
175
176

# Is this needed anymore? 
177
DBQueryFatal("update nodes set startupcmd='', startstatus='none' ".
178
	     "where " . join(" or ", map("node_id='$_'", @nodes)));
179
180

#
181
# Reboot nodes
182
#
183
184
if ($reboot) {
    if ($waitmode) {
185
186
	$StateWait::debug = 0;
	
187
188
189
	#
	# Initialize the statewait library.
	#
190
	my @states   = ();
191
192
	my @finished = ();
	my @failed   = ();
193
194
195
196
197
198
199
200

	#
	# Only wait for MFSSETUP when going into the MFS. When coming out
	# of MFS, just wait for generic ISUP.
	# 
	push(@states, TBDB_NODESTATE_MFSSETUP())
	    if ($onoff eq "on");
	push(@states, TBDB_NODESTATE_ISUP());
201
202
203
204
205
206
207
208
209
    
	if (initStateWait(\@states, @nodes)) {
	    die("*** $0:\n".
		"    Failed to initialize the statewait library!\n");
	}
    }

    # Reboot nodes *after* setting up statewait above.
    if (system("$nodereboot @nodes")) {
210
	die("*** $0:\n".
211
	    "    WARNING: Could not reboot some nodes!\n");
212
    }
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228

    if ($waitmode) {
	#
	# Initialize the statewait library.
	#
	my @finished = ();
	my @failed   = ();
	my $timeout  = 6 * 60;

	print STDOUT "node_admin: Waiting for nodes to come up.\n";
	
	# Now we can statewait.
	if (waitForState(\@finished, \@failed, $timeout)) {
	    die("*** $0:\n".
		"    Failed in waitForState!\n");
	}
229
230
	endStateWait();
	
231
232
233
234
	if (@failed) {
	    die("*** $0:\n".
		"    Failed to boot MFS: @failed\n");
	}
235
	
236
    }
237
238
239
}
exit(0);