node_admin.in 5.95 KB
Newer Older
1
#!/usr/bin/perl -wT
Leigh B. Stoller's avatar
Leigh B. Stoller committed
2
#
3
# Copyright (c) 2000-2018 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 B. Stoller's avatar
Leigh B. Stoller committed
23
#
Leigh B. Stoller's avatar
Leigh B. 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 38 39 40
    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";
    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";
41 42
    exit(-1);
}
43
my $optlist  = "hnwe:c:";
44 45
my $waitmode = 0;
my $reboot   = 1;
46
my $runcmd   = "";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
47
my $onoff;
48 49 50 51 52 53 54 55 56 57 58 59

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

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

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

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

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

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

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

    #
    # 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 B. Stoller's avatar
Leigh B. Stoller committed
145 146
    if ($UID && !$this_user->IsAdmin() &&
	! $experiment->AccessCheck($this_user, TB_EXPT_MODIFY)) {
147
	die("*** $0:\n".
Leigh B. Stoller's avatar
Leigh B. Stoller committed
148
	    "    You not have permission to reboot nodes in $experiment!\n");
149
    }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
150 151
    @nodes = $experiment->NodeList();
    if (! @nodes) {
152
	die("*** $0:\n".
Leigh B. Stoller's avatar
Leigh B. Stoller committed
153
            "    There are no nodes reserved in $experiment\n");
154
    }
155 156
}
else {
157 158 159
    if (! @ARGV) {
	usage();
    }
160

Leigh B. Stoller's avatar
Leigh B. Stoller committed
161 162 163
    foreach my $n (@ARGV) {
	my $node = Node->Lookup($n);
	if (!defined($node)) {
164
	    die("*** $0:\n".
Leigh B. Stoller's avatar
Leigh B. Stoller committed
165
		"    Node $n does not exist!\n");
166
	}
167 168 169
	if (!$node->IsReserved()) {
	    die("*** $0:\n".
		"    Node $n is not reserved; reserve it first!\n");
170 171 172 173 174 175 176 177 178 179 180 181
	}
	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");
	    }
182
	}
Leigh B. Stoller's avatar
Leigh B. Stoller committed
183
	push(@nodes, $node);
184 185 186
    }
}

Leigh B. Stoller's avatar
Leigh B. Stoller committed
187
my @nodeids = map($_->node_id(), @nodes);
188 189 190 191 192 193 194 195 196 197
my @bad;
my %args;

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

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

215 216 217 218 219 220 221 222
    #
    # 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();
    }

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

237 238 239
$args{'name'} = $0;
$args{'on'} = ($onoff eq "on");
$args{'clearall'} = 0;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
240
if (TBAdminMfsSelect(\%args, \@bad, @nodeids)) {
241 242 243
    die("*** $0:\n".
	"    Could not turn admin mode $onoff for @bad!\n");
}
244 245 246 247 248 249 250 251 252 253

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

254 255 256 257 258 259
if ($reboot) {
    %args = ();
    $args{'name'} = $0;
    $args{'on'} = ($onoff eq "on");
    $args{'reboot'} = $reboot;
    $args{'wait'} = $waitmode;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
260
    if (TBAdminMfsBoot(\%args, \@bad, @nodeids)) {
261
	die("*** $0:\n".
262
	    "    Did not properly reboot @bad!\n");
263
    }
264 265
}
exit(0);