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

#
# EMULAB-COPYRIGHT
5
# Copyright (c) 2000-2009 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 22 23 24 25
 osid  OS identifier for the selected OS (see web interface for listing)
 node  Node identifiers (ie pcXX)
EOF
    exit(-1);
}
26
my $optlist = "hdc1tb";
27 28 29 30 31 32 33 34 35

# 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@";
36
my $TBOPS       = "@TBSTATEDEMAIL@";
37
my $TBLOG	= "@TBLOGFACIL@";
38 39 40 41 42

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

# Constants
50
my $MBKERNEL = TB_OSID_MBKERNEL;
51
my %osidmap = # Map some magic OSIDs to op_modes
52
    ( $MBKERNEL => "MINIMAL");
53

54 55 56 57 58 59 60 61 62 63 64
# Functions

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

65
# Global vars
66
my $debug	= 0; # debug/verbose
67 68 69
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).
70
my $default     = 0; # Reset back to default osid.
71
my @nodes       = ();
72 73
my $osid;
my $osinfo;
74

75
# Set up syslog
76
openlog("osselect", "pid", $TBLOG);
77

78
#
79 80
# Parse command arguments. Once we return from getopts, all that should be
# left are the required arguments.
81
#
82 83 84
%options = ();
if (! getopts($optlist, \%options)) { usage(); }
if (defined($options{"h"})) { usage(); }
85
if (defined($options{"d"})) { $debug++; }
86
if (defined($options{"1"})) { $oneshot=1; }
87 88
if (defined($options{"t"})) { $tempmode=1; }
if (defined($options{"c"})) { $clear=1; }
89
if (defined($options{"b"})) { $default=1; }
90 91

# In clearmode, there is no OSID. Just a list of nodes.
92
if (! ($clear || $default)) {
93 94 95 96 97 98 99 100 101 102
    usage()
	if (@ARGV < 2);
    $osid = shift();

    # Untaint args.
    if ($osid =~ /^([-\w\+\.]+)$/) {
	$osid = $1;
    }
    else {
	fatal("Bad data in osid: '$osid'");
103 104
    }
}
105 106 107
else {
    usage()
	if (@ARGV < 1);
108 109
}

110 111 112 113 114 115 116 117 118 119
# Untaint the nodes.
foreach my $node ( @ARGV ) {
    if ($node =~ /^([-\@\w]+)$/) {
	$node = $1;
    }
    else {
	fatal("Bad node name: $node");
    }
    push(@nodes, $node);
}
120

121
#
122 123
# Figure out who called us. Only root, people with admin status
# in the DB, or members of the right project can do this.
124 125 126 127 128 129 130 131 132 133
#
if ($UID && !TBAdmin($UID) &&
    !TBNodeAccessCheck($UID, TB_NODEACCESS_MODIFYINFO, @nodes)) {
    fatal("os_select: You do not have permission to modify ".
	  "one or more of the nodes.\n");
}

#
# Grab the info for the OSID. 
#
134
if (! ($clear || $default)) {
135
    $osinfo = OSinfo->Lookup($osid);
136 137
    fatal("Improper DB entry for OSID: $osid")
	if (!defined($osinfo));
138
}
139 140
elsif ($default) {
    $osinfo = "<DEFAULT>";
141
}
142

143 144
foreach my $node (@nodes) {
    my $nodeobject = Node->Lookup($node);
145

146
    # The field to change in the DB. 
147 148 149 150 151 152
    my $field  = "def_boot_osid";
    $field = "next_boot_osid"
	if ($oneshot);
    $field = "temp_boot_osid"
	if ($tempmode);

153 154
    if ($nodeobject->OSSelect($osinfo, $field, $debug) != 0) {
	fatal("OSSelect(): " . ($osinfo ? "$osinfo " : "") ."failed on $node");
155
    }
156
}
157
exit(0);
158

159 160 161 162 163 164 165 166 167 168
sub debug($;$)
{
    my $msg = shift;
    my $notice = shift || 0;
    my $prio="info";
    
    if ($notice) { $prio = "notice"; }
    
    syslog($prio, $msg);
    if ($debug) { print $msg; }
169 170
}

171 172 173 174 175 176 177 178
sub notify($)
{
    my $msg = shift;
    
    if (!$debug) {
	SENDMAIL($TBOPS, "os_select error", $msg);
    } 
    debug($msg, 1);
179 180
}

181 182 183 184 185
sub info($)
{
    my $msg = shift;
    
    debug($msg);
186 187
}

188 189 190 191 192 193
sub fatal($)
{
    my $msg = shift;
    
    notify("FATAL: $msg\n");
    exit(1);
194 195
}

196 197 198 199 200
sub warning($)
{
    my $msg = shift;
    
    info("WARNING: $msg\n");
201 202 203 204 205 206
}

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