node_admin.in 6.14 KB
Newer Older
1
#!/usr/bin/perl -wT
Leigh Stoller's avatar
Leigh Stoller committed
2
#
Leigh Stoller's avatar
Leigh Stoller committed
3
# Copyright (c) 2000-2019 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/>.
# 
# }}}
Leigh Stoller's avatar
Leigh Stoller committed
23
#
Leigh Stoller's avatar
Leigh Stoller committed
24
use strict;
25 26 27 28
use English;
use Getopt::Std;

#
29
# Turn on/off admin mode for nodes and optionally reboot/wait.
30 31 32
#
sub usage()
{
33
    print STDOUT "Usage: node_admin [-h] [-n | -w] <on | off> [node ....]\n";
34
    print STDOUT "       node_admin [-h] [-n | -w] -e pid,eid <on | off>\n";
35 36 37
    print STDOUT "-h     This message\n";
    print STDOUT "-n     Do not reboot node\n";
    print STDOUT "-w     Wait for node to come back up if rebooted\n";
Leigh Stoller's avatar
Leigh Stoller committed
38
    print STDOUT "-R     Boot node into 'recovery' MFS instead\n";
39 40 41
    print STDOUT "-e     Operate on all nodes in an experiment\n";
    print STDOUT "-c cmd Run command in MFS and wait for completion\n".
		 "       (-n and -w apply after the command is run).\n";
42 43
    exit(-1);
}
Leigh Stoller's avatar
Leigh Stoller committed
44
my $optlist  = "hnwe:c:R";
45
my $waitmode = 0;
Leigh Stoller's avatar
Leigh Stoller committed
46
my $recovery = 0;
47
my $reboot   = 1;
48
my $runcmd   = "";
Leigh Stoller's avatar
Leigh Stoller committed
49
my $onoff;
50 51 52 53 54 55 56 57 58 59 60 61

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

#
# Testbed Support libraries
#
use lib "@prefix@/lib";
use libdb;
use libtestbed;
62
use libadminmfs;
Leigh Stoller's avatar
Leigh Stoller committed
63 64 65
use User;
use Node;
use Experiment;
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81

#
# 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";
82
my $osselect    = "$TB/bin/os_select";
83
my @nodes       = ();
84 85 86 87 88

#
# Parse command arguments. Once we return from getopts, all that should be
# left are the required arguments.
#
Leigh Stoller's avatar
Leigh Stoller committed
89
my %options = ();
90 91 92
if (! getopts($optlist, \%options)) {
    usage();
}
93
if (defined($options{h})) {
94 95
    usage();
}
96 97 98 99 100 101
if (defined($options{"n"})) {
    $reboot = 0;
}
if (defined($options{"w"})) {
    $waitmode = 1;
}
Leigh Stoller's avatar
Leigh Stoller committed
102 103 104
if (defined($options{"R"})) {
    $recovery = 1;
}
105 106 107
if (defined($options{"c"})) {
    $runcmd = $options{"c"};
    $onoff = "on";
Leigh Stoller's avatar
Leigh Stoller committed
108 109
}
else {
110 111 112 113 114
    if (!@ARGV) {
	usage();
    }
    $onoff  = shift(@ARGV);
}
115 116 117 118 119

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

Leigh Stoller's avatar
Leigh Stoller committed
120 121 122
#
# Verify user and get his DB uid and other info for later.
#
123 124 125 126 127 128 129
my $this_user;
if ($UID) {
    $this_user = User->ThisUser();
    if (! defined($this_user)) {
	die("*** $0:\n".
	    "    You ($UID) do not exist!\n");
    }
Leigh Stoller's avatar
Leigh Stoller committed
130 131
}

132 133 134 135 136 137 138
if (defined($options{"e"})) {
    #
    # Reboot all nodes in an experiment
    #
    if (@ARGV) {
	usage();
    }
Leigh Stoller's avatar
Leigh Stoller committed
139 140
    my $experiment = Experiment->Lookup($options{"e"});
    if (!defined($experiment)) {
141
	die("*** $0:\n".
Leigh Stoller's avatar
Leigh Stoller committed
142
	    "    Unknown experiment!\n");
143 144 145 146 147 148 149
    }

    #
    # Verify permission to muck with this experiment. This is to head off
    # permission problems early; the nodes are indvidually checked later
    # in the library.
    #
Leigh Stoller's avatar
Leigh Stoller committed
150 151
    if ($UID && !$this_user->IsAdmin() &&
	! $experiment->AccessCheck($this_user, TB_EXPT_MODIFY)) {
152
	die("*** $0:\n".
Leigh Stoller's avatar
Leigh Stoller committed
153
	    "    You not have permission to reboot nodes in $experiment!\n");
154
    }
Leigh Stoller's avatar
Leigh Stoller committed
155 156
    @nodes = $experiment->NodeList();
    if (! @nodes) {
157
	die("*** $0:\n".
Leigh Stoller's avatar
Leigh Stoller committed
158
            "    There are no nodes reserved in $experiment\n");
159
    }
160 161
}
else {
162 163 164
    if (! @ARGV) {
	usage();
    }
165

Leigh Stoller's avatar
Leigh Stoller committed
166 167 168
    foreach my $n (@ARGV) {
	my $node = Node->Lookup($n);
	if (!defined($node)) {
169
	    die("*** $0:\n".
Leigh Stoller's avatar
Leigh Stoller committed
170
		"    Node $n does not exist!\n");
171
	}
172 173 174
	if (!$node->IsReserved()) {
	    die("*** $0:\n".
		"    Node $n is not reserved; reserve it first!\n");
175 176 177 178 179 180 181 182 183 184 185 186
	}
	if ($UID && !$this_user->IsAdmin()) {
	    if (! $node->AccessCheck($this_user, TB_NODEACCESS_LOADIMAGE)) {
		die("*** $0:\n".
		    "    You are not allowed to put $node into admin mode!\n");
	    }
	    if ($node->IsTainted("useronly") || 
		$node->IsTainted("blackbox")) {
		die("*** $0:\n".
		    "    $node is running a restricted image. Admin mode ".
		    "not allowed!\n");
	    }
187
	}
Leigh Stoller's avatar
Leigh Stoller committed
188
	push(@nodes, $node);
189 190 191
    }
}

Leigh Stoller's avatar
Leigh Stoller committed
192
my @nodeids = map($_->node_id(), @nodes);
193 194 195 196 197 198 199 200 201 202
my @bad;
my %args;

if ($runcmd ne "") {
    #
    # Reboot into admin more and run the command
    #
    %args = ();
    $args{'name'} = $0;
    $args{'command'} = $runcmd;
Leigh Stoller's avatar
Leigh Stoller committed
203
    if (TBAdminMfsRunCmd(\%args, undef, @nodeids)) {
204
	die("*** $0:\n".
Leigh Stoller's avatar
Leigh Stoller committed
205
	    "    Failed to run '$runcmd' on some of @nodeids!\n");
206
    }
207

208 209 210 211 212 213 214
    #
    # Turn admin mode back off and optionally reboot back to the old OS
    #
    %args = ();
    $args{'name'} = $0;
    $args{'on'} = 0;
    $args{'clearall'} = 0;
Leigh Stoller's avatar
Leigh Stoller committed
215
    if (TBAdminMfsSelect(\%args, \@bad, @nodeids)) {
216 217 218
	die("*** $0:\n".
	    "    Could not turn admin mode off for @bad!\n");
    }
219

220 221 222 223 224 225 226 227
    #
    # Restore the startupcmd from the virt_nodes table since MfsRunCmd()
    # cleared it. We need to do this after the MfsSelect call above.
    #
    foreach my $node (@nodes) {
	$node->SetStartupCmd();
    }

228 229 230 231 232 233
    if ($reboot) {
	%args = ();
	$args{'name'} = $0;
	$args{'on'} = 0;
	$args{'reboot'} = $reboot;
	$args{'wait'} = $waitmode;
Leigh Stoller's avatar
Leigh Stoller committed
234
	if (TBAdminMfsBoot(\%args, \@bad, @nodeids)) {
235
	    die("*** $0:\n".
236
		"    Did not properly reboot @bad after command!\n");
237 238
	}
    }
239 240
    exit(0);
}
241

242 243 244
$args{'name'} = $0;
$args{'on'} = ($onoff eq "on");
$args{'clearall'} = 0;
Leigh Stoller's avatar
Leigh Stoller committed
245
$args{'recovery'} = 1 if ($recovery && $onoff eq "on");
Leigh Stoller's avatar
Leigh Stoller committed
246
if (TBAdminMfsSelect(\%args, \@bad, @nodeids)) {
247 248 249
    die("*** $0:\n".
	"    Could not turn admin mode $onoff for @bad!\n");
}
250 251 252 253 254 255 256 257 258 259

#
# If turning off admin mode, reset the startupcmd.
#
if ($onoff eq "off") {
    foreach my $node (@nodes) {
	$node->SetStartupCmd();
    }
}

260 261 262 263 264 265
if ($reboot) {
    %args = ();
    $args{'name'} = $0;
    $args{'on'} = ($onoff eq "on");
    $args{'reboot'} = $reboot;
    $args{'wait'} = $waitmode;
Leigh Stoller's avatar
Leigh Stoller committed
266
    if (TBAdminMfsBoot(\%args, \@bad, @nodeids)) {
267
	die("*** $0:\n".
268
	    "    Did not properly reboot @bad!\n");
269
    }
270 271
}
exit(0);