node_admin.in 5.56 KB
Newer Older
1
#!/usr/bin/perl -wT
Leigh B. Stoller's avatar
Leigh B. Stoller committed
2
#
3
# Copyright (c) 2000-2009 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 118 119 120 121 122 123
#
# Verify user and get his DB uid and other info for later.
#
my $this_user = User->ThisUser();
if (! defined($this_user)) {
    die("*** $0:\n".
	"    You ($UID) do not exist!\n");
}

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

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

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

Leigh B. Stoller's avatar
Leigh B. Stoller committed
184
my @nodeids = map($_->node_id(), @nodes);
185 186 187 188 189 190 191 192 193 194
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
195
    if (TBAdminMfsRunCmd(\%args, undef, @nodeids)) {
196
	die("*** $0:\n".
Leigh B. Stoller's avatar
Leigh B. Stoller committed
197
	    "    Failed to run '$runcmd' on some of @nodeids!\n");
198
    }
199

200 201 202 203 204 205 206
    #
    # 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
207
    if (TBAdminMfsSelect(\%args, \@bad, @nodeids)) {
208 209 210
	die("*** $0:\n".
	    "    Could not turn admin mode off for @bad!\n");
    }
211

212 213 214 215 216 217
    if ($reboot) {
	%args = ();
	$args{'name'} = $0;
	$args{'on'} = 0;
	$args{'reboot'} = $reboot;
	$args{'wait'} = $waitmode;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
218
	if (TBAdminMfsBoot(\%args, \@bad, @nodeids)) {
219
	    die("*** $0:\n".
220
		"    Did not properly reboot @bad after command!\n");
221 222
	}
    }
223 224
    exit(0);
}
225

226 227 228
$args{'name'} = $0;
$args{'on'} = ($onoff eq "on");
$args{'clearall'} = 0;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
229
if (TBAdminMfsSelect(\%args, \@bad, @nodeids)) {
230 231 232 233 234 235 236 237 238
    die("*** $0:\n".
	"    Could not turn admin mode $onoff for @bad!\n");
}
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
239
    if (TBAdminMfsBoot(\%args, \@bad, @nodeids)) {
240
	die("*** $0:\n".
241
	    "    Did not properly reboot @bad!\n");
242
    }
243 244
}
exit(0);