#!/usr/bin/perl -wT # # EMULAB-COPYRIGHT # Copyright (c) 2000-2009 University of Utah and the Flux Group. # All rights reserved. # # os_select sets the os that should boot next on a node, and sets # next_op_mode accordingly. sub usage() { print <<"EOF"; Usage: os_select [-h] [-d] [-c] [-1 | -t] [] [ ...] -h Display this help message -d Debug mode -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 -b Reset to default boot osid. Do not provide an osid. osid OS identifier for the selected OS (see web interface for listing) node Node identifiers (ie pcXX) EOF exit(-1); } my $optlist = "hdc1tb"; # 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@"; my $TBOPS = "@TBSTATEDEMAIL@"; my $TBLOG = "@TBLOGFACIL@"; # Testbed Support libraries use lib "@prefix@/lib"; use libdb; use libtestbed; use OSinfo; use Node; use English; use Getopt::Std; use Sys::Syslog; # Constants my $MBKERNEL = TB_OSID_MBKERNEL; my %osidmap = # Map some magic OSIDs to op_modes ( $MBKERNEL => "MINIMAL"); # Functions sub set_nextmode($;$); sub set_boot_osid($); sub node_opmode($); sub debug($;$); sub notify($); sub info($); sub fatal($); sub warning($); # Global vars my $debug = 0; # debug/verbose 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). my $default = 0; # Reset back to default osid. my @nodes = (); my $osid; my $osinfo; # Set up syslog openlog("osselect", "pid", $TBLOG); # # Parse command arguments. Once we return from getopts, all that should be # left are the required arguments. # %options = (); if (! getopts($optlist, \%options)) { usage(); } if (defined($options{"h"})) { usage(); } if (defined($options{"d"})) { $debug++; } if (defined($options{"1"})) { $oneshot=1; } if (defined($options{"t"})) { $tempmode=1; } if (defined($options{"c"})) { $clear=1; } if (defined($options{"b"})) { $default=1; } # In clearmode, there is no OSID. Just a list of nodes. if (! ($clear || $default)) { usage() if (@ARGV < 2); $osid = shift(); # Untaint args. if ($osid =~ /^([-\w\+\.]+)$/) { $osid = $1; } else { fatal("Bad data in osid: '$osid'"); } } else { usage() if (@ARGV < 1); } # Untaint the nodes. foreach my $node ( @ARGV ) { if ($node =~ /^([-\@\w]+)$/) { $node = $1; } else { fatal("Bad node name: $node"); } push(@nodes, $node); } # # Figure out who called us. Only root, people with admin status # in the DB, or members of the right project can do this. # 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. # if (! ($clear || $default)) { $osinfo = OSinfo->Lookup($osid); fatal("Improper DB entry for OSID: $osid") if (!defined($osinfo)); } elsif ($default) { $osinfo = ""; } foreach my $node (@nodes) { my $nodeobject = Node->Lookup($node); # The field to change in the DB. my $field = "def_boot_osid"; $field = "next_boot_osid" if ($oneshot); $field = "temp_boot_osid" if ($tempmode); if ($nodeobject->OSSelect($osinfo, $field, $debug) != 0) { fatal("OSSelect(): " . ($osinfo ? "$osinfo " : "") ."failed on $node"); } } exit(0); sub debug($;$) { my $msg = shift; my $notice = shift || 0; my $prio="info"; if ($notice) { $prio = "notice"; } syslog($prio, $msg); if ($debug) { print $msg; } } sub notify($) { my $msg = shift; if (!$debug) { SENDMAIL($TBOPS, "os_select error", $msg); } debug($msg, 1); } sub info($) { my $msg = shift; debug($msg); } sub fatal($) { my $msg = shift; notify("FATAL: $msg\n"); exit(1); } sub warning($) { my $msg = shift; info("WARNING: $msg\n"); } # This is called when we exit with exit() or die() END { closelog(); }