Commit 93c518e3 authored by Kirk Webb's avatar Kirk Webb
Browse files

Add "managetaint" command line utility to manage taint states

This will currently work with os descriptors and nodes.
parent 662972cd
......@@ -84,7 +84,7 @@ sub IsTainted($;$)
return -1;
}
my @taint_states = GetTaintStates(@obj);
my @taint_states = GetTaintStates($obj);
return 0
if (!@taint_states);
......@@ -129,7 +129,7 @@ sub SetTaintStates($@)
#
# Add a taint state to the object.
#
sub AddTaint($$)
sub AddTaintState($$)
{
my ($obj, $taint) = @_;
......@@ -158,7 +158,7 @@ sub AddTaint($$)
#
# Remove a taint state (or all taint states).
#
sub RemoveTaint($;$)
sub RemoveTaintState($;$)
{
my ($obj, $taint) = @_;
......
......@@ -53,7 +53,7 @@ SBIN_SCRIPTS = vlandiff vlansync withadminprivs export_tables cvsupd.pl \
prereserve_check tcppd addexternalnetwork \
update_sitevars delete_image sitecheckin sitecheckin_client \
mktestbedtest fixrootcert addservers poolmonitor \
node_exclude
node_exclude managetaint
WEB_SBIN_SCRIPTS= webnewnode webdeletenode webspewconlog webarchive_list \
webwanodecheckin webspewimage webdumpdescriptor \
......
#!/usr/bin/perl -wT
#
# Copyright (c) 2014 University of Utah and the Flux Group.
#
# {{{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/>.
#
# }}}
#
#
# This utility manages setting, removing and displaying taint states for
# any Emulab objects that support them (e.g., nodes and OS descriptors).
#
use strict;
use English;
use Getopt::Std;
#
# Configure variables
#
my $TB = "@prefix@";
#
# Testbed Support libraries
#
use lib "@prefix@/lib";
use EmulabConstants;
use User;
# Protos
sub usage();
sub fatal($);
sub ParseArgs(@);
sub DoAction($$$@);
sub GetObject($$);
#
# Top level constants
#
my @ALLTAINTS = TB_TAINTSTATE_ALL();
my @TAINT_OBJECT_TYPES = ("node","os");
my @TAINT_ACTIONS = ("add","remove","set","clear","show");
#
# Global variables
#
#
# Get, set, and display taint states for supported objects
#
sub usage()
{
print STDERR "Usage: managetaint <object> <OID> <action> [<taint> ...]\n";
print STDERR " -h This message\n";
print STDERR " Objects:\n";
print STDERR " Node Testbed Node\n";
print STDERR " OID node_id\n";
print STDERR " OS OS Descriptor\n";
print STDERR " OID <project>/<osname>";
print STDERR " Actions:\n";
print STDERR " add Apply one or more taint modes to the object.\n";
print STDERR " remove Remove one or more taint modes from the object.\n";
print STDERR " set Set a taint mode on the object.\n";
print STDERR " clear Clear all taint states from the object.\n";
print STDERR " show Show all taint modes set for the object.\n";
print STDERR " Taint States: ". join(",",@ALLTAINTS) ."\n";
exit(-1);
}
my $optlist = "h";
my $debug = 0;
#
# Please do not run as root. Hard to track what has happened.
#
if ($UID == 0) {
die("*** $0:\n".
" Please do not run this as root!\n");
}
#
# Turn off line buffering on output
#
$| = 1;
#
# Untaint the path
#
$ENV{'PATH'} = "/bin:/sbin:/usr/bin:";
#
# Verify user, must be admin.
#
my $this_user = User->ThisUser();
if (! defined($this_user)) {
fatal("You ($UID) do not exist!");
}
# Probably will need to relax this so that regular users can add taint states.
if (!$this_user->IsAdmin()) {
fatal("You are not a testbed administrator!");
}
#
# Parse command arguments. Once we return from getopts, all that should be
# left are the required arguments.
#
my %options = ();
if (! getopts($optlist, \%options)) {
usage();
}
if (defined($options{h})) {
usage();
}
usage()
if (@ARGV < 3);
my ($objtype, $oid, $action, @in_states) = ParseArgs(@ARGV);
fatal("Argument parsing failed!")
if (!defined($objtype));
DoAction($objtype, $oid, $action, @in_states) or
fatal("Failed to perform $action on $objtype object $oid");
exit 0;
#
# Input argument parsing and sanity checking.
#
sub ParseArgs(@) {
my @UARGV = ();
# Untaint arguments
foreach my $targ (@_) {
if ($targ =~ /^[-\w_\/]+$/) {
push @UARGV, lc($targ);
} else {
fatal("Malformed argument provided on command line: $targ");
}
}
my ($objtype, $oid, $action, @in_states) = @UARGV;
# Argument sanity checks.
if (!grep {$_ eq $objtype} @TAINT_OBJECT_TYPES) {
fatal("Invalid taint object type: $objtype");
}
if (!grep {$_ eq $action} @TAINT_ACTIONS) {
fatal("Invalid action: $action");
}
if (@in_states) {
foreach my $tstate (@in_states) {
if (!grep {$_ eq $tstate} @ALLTAINTS) {
fatal("Unknown taint state: $tstate");
}
}
}
if (($action eq "set" || $action eq "remove" || $action eq "add")
&& !scalar(@in_states)) {
fatal("You must supply one or more taint states when using the ".
"'add', 'remove', or 'set' actions");
}
return ($objtype, $oid, $action, @in_states);
}
#
# Perform $action on the object of type $objtype identified by $oid.
# @in_states are taint states to be applied / removed (based on $action).
#
sub DoAction($$$@) {
my ($objtype, $oid, $action, @in_states) = @_;
# Any objects returned are expected to implement the 'libTaintStates'
# interface.
my $obj = GetObject($objtype,$oid) or
fatal("Could not lookup object with type '$objtype' ".
"and identity '$oid'");
ACTION: for ($action) {
/add/ && do {
foreach my $tstate (@in_states) {
$obj->AddTaintState($tstate) == 0 or
fatal("Failed to apply '$tstate' taint to '$oid'");
}
last ACTION;
};
/remove/ && do {
foreach my $tstate (@in_states) {
$obj->RemoveTaintState($tstate) == 0 or
fatal("Failed to remove '$tstate' taint from '$oid'");
}
last ACTION;
};
/set/ && do {
$obj->SetTaintStates(@in_states) == 0 or
fatal("Failed to set taint states for '$oid'");
last ACTION;
};
/clear/ && do {
$obj->SetTaintStates(()) == 0 or
fatal("Failed to clear taint states from '$oid'");
last ACTION;
};
/show/ && do {
my @taint_states = $obj->GetTaintStates();
if (@taint_states) {
my $pstr = join(", ", @taint_states);
print "Taint states on '$oid': $pstr\n";
} else {
print "No taint states set on '$oid'\n";
}
last ACTION;
};
# Default
fatal("Unknown action: $action");
}
return 1;
}
#
# Return the Emulab DB abstraction object based on the object type
# specified and the lookup id provided. Returns undef if not found.
#
sub GetObject($$) {
my ($objtype, $oid) = @_;
my $retobj;
TYPE: for ($objtype) {
/node/ && do {
require Node;
$retobj = Node->Lookup($oid);
last TYPE;
};
/os/ && do {
require OSinfo;
my ($ospid, $osname) = split("/", $oid);
fatal("OS identifier must be specified as '<project_id>/<os_name>'")
if (!defined($osname));
$retobj = OSinfo->Lookup($ospid, $osname);
last TYPE;
};
}
return $retobj;
}
sub fatal($)
{
my ($mesg) = $_[0];
die("*** $0:\n".
" $mesg\n");
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment