os_select.in 5.5 KB
Newer Older
1 2 3 4
#!/usr/bin/perl -wT

#
# EMULAB-COPYRIGHT
5
# Copyright (c) 2000-2011 University of Utah and the Flux Group.
6 7 8 9
# All rights reserved.
#

# os_select sets the os that should boot next on a node, and sets
10
# next_op_mode accordingly.
11 12 13

sub usage() {
    print <<"EOF";
14
Usage: os_select [-h] [-d] [-c] [-1 | -t] [<osid>] <node> [<node> ...]
15 16
 -h    Display this help message
 -d    Debug mode
17 18 19
 -c    Clear the specified boot osid for nodes. Do not provide an osid.
 -1    Apply change to one-time boot field
 -t    Apply change to temporary boot field
20
 -b    Reset to default boot osid. Do not provide an osid.
21
 -l    Show the current settings.
22 23 24
 -w    Put the nodes in PXEWAIT mode (clears all osids)
 osid  OS identifier for the selected OS. Must be either numeric ID or
       a string in the form <pid>/<osname> (see web interface for listing)
25 26 27 28
 node  Node identifiers (ie pcXX)
EOF
    exit(-1);
}
29
my $optlist = "hdc1tblw";
30 31 32 33 34 35 36 37 38

# un-taint path
$ENV{'PATH'} = '/bin:/usr/bin:/usr/local/bin';
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};

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

# Configure variables
my $TB          = "@prefix@";
39
my $TBOPS       = "@TBSTATEDEMAIL@";
40
my $TBLOG	= "@TBLOGFACIL@";
41 42 43 44 45

# Testbed Support libraries
use lib "@prefix@/lib";
use libdb;
use libtestbed;
46 47
use OSinfo;
use Node;
48
use English;
49 50
use Getopt::Std;
use Sys::Syslog;
51 52

# Constants
53
my $MBKERNEL = TB_OSID_MBKERNEL;
54
my %osidmap = # Map some magic OSIDs to op_modes
55
    ( $MBKERNEL => "MINIMAL");
56

57 58 59 60 61 62 63 64 65 66 67
# Functions

sub set_nextmode($;$);
sub set_boot_osid($);
sub node_opmode($);
sub debug($;$);
sub notify($);
sub info($);
sub fatal($);
sub warning($);

68
# Global vars
69
my $debug	= 0; # debug/verbose
70 71 72
my $oneshot	= 0; # apply change to next_boot_osid.
my $tempmode	= 0; # apply change to temp_boot_osid.
my $clear       = 0; # Clear the selected boot (def,temp,next).
73
my $default     = 0; # Reset back to default osid.
74
my $list	= 0; # Just list the current settings.
75
my $waitmode	= 0; # Send the node into PXEWAIT
76
my @nodes       = ();
77 78
my $osid;
my $osinfo;
79

80
# Set up syslog
81
openlog("osselect", "pid", $TBLOG);
82

83
#
84 85
# Parse command arguments. Once we return from getopts, all that should be
# left are the required arguments.
86
#
87 88 89
%options = ();
if (! getopts($optlist, \%options)) { usage(); }
if (defined($options{"h"})) { usage(); }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
90
if (defined($options{"d"})) { $debug=1; }
91
if (defined($options{"1"})) { $oneshot=1; }
92 93
if (defined($options{"t"})) { $tempmode=1; }
if (defined($options{"c"})) { $clear=1; }
94
if (defined($options{"b"})) { $default=1; }
95
if (defined($options{"l"})) { $list=1; }
96
if (defined($options{"w"})) { $waitmode=1; }
97

98 99 100 101 102 103 104
if ($waitmode + $list + $clear + $default > 1) {
    print STDERR "Should specify only one of -b, -c, -l, -w\n";
    usage();
}

# In certain modes, there is no OSID. Just a list of nodes.
if (! ($clear || $list || $default || $waitmode)) {
105 106 107 108 109
    usage()
	if (@ARGV < 2);
    $osid = shift();

    # Untaint args.
110
    if ($osid =~ /^([-\w\+\.\/]+)$/) {
111 112 113 114
	$osid = $1;
    }
    else {
	fatal("Bad data in osid: '$osid'");
115 116
    }
}
117 118 119
else {
    usage()
	if (@ARGV < 1);
120 121
}

122 123 124 125 126 127 128 129 130 131
# Untaint the nodes.
foreach my $node ( @ARGV ) {
    if ($node =~ /^([-\@\w]+)$/) {
	$node = $1;
    }
    else {
	fatal("Bad node name: $node");
    }
    push(@nodes, $node);
}
132

133
#
134 135
# Figure out who called us. Only root, people with admin status
# in the DB, or members of the right project can do this.
136
#
137 138 139 140 141 142 143 144 145
if ($UID && !TBAdmin($UID)) {
    if ($list && !TBNodeAccessCheck($UID, TB_NODEACCESS_READINFO, @nodes)) {
	fatal("os_select: You do not have permission to access ".
	      "one or more of the nodes.\n");
    }
    if (!$list && !TBNodeAccessCheck($UID, TB_NODEACCESS_MODIFYINFO, @nodes)) {
	fatal("os_select: You do not have permission to modify ".
	      "one or more of the nodes.\n");
    }
146 147 148 149 150
}

#
# Grab the info for the OSID. 
#
151
if (defined($osid)) {
152
    $osinfo = OSinfo->Lookup($osid);
153
    fatal("Unknown OSID: $osid")
154
	if (!defined($osinfo));
155
}
156 157
elsif ($default) {
    $osinfo = "<DEFAULT>";
158
}
159

160 161
foreach my $node (@nodes) {
    my $nodeobject = Node->Lookup($node);
162

163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
    # In list mode, show all the IDs
    if ($list) {
	my $tb = $nodeobject->temp_boot_osid();
	my $nb = $nodeobject->next_boot_osid();
	my $db = $nodeobject->def_boot_osid();
	print "$node: ";
	if ($tb) {
	    $info = OSinfo->Lookup($tb);
	    print "temp=$info";
	    print ", ";
	}
	if ($nb) {
	    $info = OSinfo->Lookup($nb);
	    print "next=$info";
	    print ", ";
	}
	if ($db) {
	    $info = OSinfo->Lookup($db);
	    print "default=$info";
	}
	print "\n";
	next;
    }

187 188 189 190 191 192 193
    if ($waitmode) {
	if ($nodeobject->OSSelect($osinfo, undef, $debug) != 0) {
	    fatal("OSSelect(): clearing all fields failed on $node");
	}
	next;
    }

194
    # The field to change in the DB. 
195 196 197 198 199 200
    my $field  = "def_boot_osid";
    $field = "next_boot_osid"
	if ($oneshot);
    $field = "temp_boot_osid"
	if ($tempmode);

201 202
    if ($nodeobject->OSSelect($osinfo, $field, $debug) != 0) {
	fatal("OSSelect(): " . ($osinfo ? "$osinfo " : "") ."failed on $node");
203
    }
204
}
205
exit(0);
206

207 208 209 210 211 212 213 214 215 216
sub debug($;$)
{
    my $msg = shift;
    my $notice = shift || 0;
    my $prio="info";
    
    if ($notice) { $prio = "notice"; }
    
    syslog($prio, $msg);
    if ($debug) { print $msg; }
217 218
}

219 220 221 222 223 224 225 226
sub notify($)
{
    my $msg = shift;
    
    if (!$debug) {
	SENDMAIL($TBOPS, "os_select error", $msg);
    } 
    debug($msg, 1);
227 228
}

229 230 231 232 233
sub info($)
{
    my $msg = shift;
    
    debug($msg);
234 235
}

236 237 238 239 240 241
sub fatal($)
{
    my $msg = shift;
    
    notify("FATAL: $msg\n");
    exit(1);
242 243
}

244 245 246 247 248
sub warning($)
{
    my $msg = shift;
    
    info("WARNING: $msg\n");
249 250 251 252 253 254
}

# This is called when we exit with exit() or die()
END {
  closelog();
}