Commit ea51d7cd authored by Kirk Webb's avatar Kirk Webb
Browse files

Merge branch 'tainttrack'

parents c6395734 832e36be
......@@ -76,6 +76,9 @@ use vars qw(@ISA @EXPORT);
TB_OSID_DESTROY TB_OSID_MIN TB_OSID_MAX
TB_OSID_OSIDLEN TB_OSID_OSNAMELEN TB_OSID_VERSLEN
TB_TAINTSTATE_USERONLY TB_TAINTSTATE_BLACKBOX TB_TAINTSTATE_DANGEROUS
TB_TAINTSTATE_ALL
TB_IMAGEID_READINFO TB_IMAGEID_MODIFYINFO TB_IMAGEID_EXPORT
TB_IMAGEID_CREATE TB_IMAGEID_DESTROY
TB_IMAGEID_ACCESS TB_IMAGEID_MIN TB_IMAGEID_MAX
......@@ -375,6 +378,14 @@ sub TB_OSID_MBKERNEL() { "_KERNEL_"; } # multiboot kernel OSID
sub TB_OSID_FREEBSD_MFS() { "FREEBSD-MFS" };
sub TB_OSID_FRISBEE_MFS() { "FRISBEE-MFS" };
# OS/Node taint states
sub TB_TAINTSTATE_USERONLY() { "useronly"; };
sub TB_TAINTSTATE_BLACKBOX() { "blackbox"; };
sub TB_TAINTSTATE_DANGEROUS() { "dangerous"; };
sub TB_TAINTSTATE_ALL() { (TB_TAINTSTATE_USERONLY(),
TB_TAINTSTATE_BLACKBOX(),
TB_TAINTSTATE_DANGEROUS()); };
# ImageIDs
#
# Clarification:
......
......@@ -49,7 +49,8 @@ LIB_SCRIPTS = libdb.pm Node.pm libdb.py libadminctrl.pm Experiment.pm \
emdb.pm emutil.pm Firewall.pm VirtExperiment.pm libGeni.pm \
libEmulab.pm EmulabConstants.pm TraceUse.pm \
EmulabFeatures.pm Port.pm BlockstoreType.pm Blockstore.pm \
IPBuddyAlloc.pm IPBuddyWrapper.pm Lease.pm Quota.pm
IPBuddyAlloc.pm IPBuddyWrapper.pm Lease.pm Quota.pm \
libTaintStates.pm
# Stuff installed on plastic.
USERSBINS = genelists.proxy dumperrorlog.proxy backup
......
......@@ -3742,5 +3742,73 @@ sub ClrTipAclUrl($)
"where node_id='$node_id'");
}
# Stubs for calling "libTaintStates" common taint handling code
sub GetTaintStates($) {
my ($self) = @_;
require libTaintStates;
return libTaintStates::GetTaintStates($self);
}
sub IsTainted($;$) {
my ($self, $taint) = @_;
require libTaintStates;
return libTaintStates::IsTainted($self, $taint);
}
sub SetTaintStates($@) {
my ($self, @taint_states) = @_;
require libTaintStates;
return libTaintStates::SetTaintStates($self, @taint_states);
}
sub AddTaintState($$) {
my ($self, $taint) = @_;
require libTaintStates;
return libTaintStates::AddTaintState($self, $taint);
}
sub RemoveTaintState($;$) {
my ($self, $taint) = @_;
require libTaintStates;
return libTaintStates::RemoveTaintState($self, $taint);
}
sub InheritTaintStates($$) {
my ($self, $osinfo) = @_;
require libTaintStates;
return libTaintStates::InheritTaintStates($self, $osinfo);
}
#
# Synchornize the node's taint states based on the OSes listed
# for its partitions. Any existing taint states on the node are
# lost (unless they appear on one or more partition OSes).
#
sub SyncTaintStates($)
{
my ($self) = @_;
require OSinfo;
my $node_id = $self->node_id();
my $query_result =
DBQueryWarn("select osid from partitions ".
"where node_id='$node_id' and osid is not null");
return -1
if (!$query_result);
my @taint_states = ();
while (my ($osid) = $query_result->fetchrow_array()) {
my $osinfo = OSinfo->Lookup($osid);
if (defined($osinfo) && $osinfo->IsTainted()) {
push @taint_states, $osinfo->GetTaintStates();
}
}
return $self->SetTaintStates(@taint_states);
}
# _Always_ make sure that this 1 is at the end of the file...
1;
......@@ -730,5 +730,43 @@ sub MapToImage($$)
return Image->Lookup($imageid);
}
# Stubs for calling "libTaintStates" common taint handling code
sub GetTaintStates($) {
my ($self) = @_;
require libTaintStates;
return libTaintStates::GetTaintStates($self);
}
sub IsTainted($;$) {
my ($self, $taint) = @_;
require libTaintStates;
return libTaintStates::IsTainted($self, $taint);
}
sub SetTaintStates($@) {
my ($self, @taint_states) = @_;
require libTaintStates;
return libTaintStates::SetTaintStates($self, @taint_states);
}
sub AddTaintState($$) {
my ($self, $taint) = @_;
require libTaintStates;
return libTaintStates::AddTaintState($self, $taint);
}
sub RemoveTaintState($;$) {
my ($self, $taint) = @_;
require libTaintStates;
return libTaintStates::RemoveTaintState($self, $taint);
}
sub InheritTaintStates($$) {
my ($self, $osinfo) = @_;
require libTaintStates;
return libTaintStates::InheritTaintStates($self, $osinfo);
}
# _Always_ make sure that this 1 is at the end of the file...
1;
#!/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/>.
#
# }}}
#
#
# Common Emulab taint handling code. These functions are meant to
# work with DB object abstractions, such as 'OSinfo' and 'Node'
# objects. For an object abstraction to be compatible with this
# library, it needs to have a 'taint_states' DB column. This column
# must then be accessible via a taint_states() method, and must be
# defined as a SQL set with the same set member options as in the
# "nodes" and "os_info" tables. Finally, the object abstraction must
# have an Update() method, with the same semantics as those found in
# the Node and OSinfo objects.
#
package libTaintStates;
use strict;
use Exporter;
use vars qw(@ISA @EXPORT);
@ISA = qw(Exporter);
@EXPORT = qw();
use EmulabConstants;
use English;
# Function prototypes
sub GetTaintStates($);
sub IsTainted($;$);
sub SetTaintStates($@);
sub AddTaint($$);
sub RemoveTaint($;$);
#
# Return the current set of taint states as an array.
#
sub GetTaintStates($)
{
my ($obj) = @_;
if (!ref($obj)) {
warn "First argument is not an object!\n";
return undef;
}
my $taint_states = $obj->taint_states();
return ()
if (!defined($taint_states) || $taint_states eq "");
return split(',', $taint_states);
}
#
# Check to see if the object is tainted, or tainted in a
# particular way.
#
sub IsTainted($;$)
{
my ($obj, $taint) = @_;
if (!ref($obj)) {
warn "First argument is not an object!\n";
return -1;
}
my @taint_states = GetTaintStates($obj);
return 0
if (!@taint_states);
# Just looking to see if any taint is applied?
return 1
if (!defined($taint));
# Looking for a specific taint.
return grep {$_ eq $taint} @taint_states;
}
#
# Explicitly set the taint states based on an input array of states.
# Squash any duplicates or empty/undefined entries.
#
sub SetTaintStates($@)
{
my ($obj, @taint_states) = @_;
if (!ref($obj)) {
warn "First argument is not an object!\n";
return -1;
}
my %newtstates = ();
my %validtstates = map {$_ => 1} TB_TAINTSTATE_ALL();
foreach my $tstate (@taint_states) {
next if (!$tstate);
if (!exists($validtstates{$tstate})) {
warn "Invalid taint state: $tstate\n";
return -1;
}
$newtstates{$tstate} = 1;
}
my $upd_str = scalar(keys %newtstates) ?
join(',', keys %newtstates) : "NULL";
return $obj->Update({"taint_states" => $upd_str});
}
#
# Add a taint state to the object.
#
sub AddTaintState($$)
{
my ($obj, $taint) = @_;
if (!ref($obj)) {
warn "First argument is not an object!\n";
return -1;
}
return -1
if (!defined($taint));
if (!grep {$_ eq $taint} TB_TAINTSTATE_ALL()) {
warn "Invalid taint state: $taint\n";
return -1;
}
return 0
if (IsTainted($obj, $taint));
my @taint_states = GetTaintStates($obj);
push @taint_states, $taint;
return SetTaintStates($obj, @taint_states);
}
#
# Remove a taint state (or all taint states).
#
sub RemoveTaintState($;$)
{
my ($obj, $taint) = @_;
if (!ref($obj)) {
warn "First argument is not an object!\n";
return -1;
}
my @taint_states = GetTaintStates($obj);
return 0
if (!@taint_states);
my @ntstates = ();
if (defined($taint)) {
@ntstates = grep {$_ ne $taint} @taint_states;
}
return SetTaintStates($obj, @ntstates);
}
#
# Inherit the taint states from an OS. Take the union with whatever
# taint states are already set for the node.
#
sub InheritTaintStates($$)
{
my ($obj, $osinfo) = @_;
require OSinfo;
if (!ref($osinfo)) {
my $tmp = OSinfo->Lookup($osinfo);
if (!defined($tmp)) {
warn "Cannot lookup osinfo for $osinfo\n";
return -1;
}
$osinfo = $tmp;
}
my @taint_states = GetTaintStates($osinfo);
return 0
if (!@taint_states);
push @taint_states, GetTaintStates($obj);
return SetTaintStates($obj, @taint_states);
}
# Next line required by perl for modules
1;
......@@ -1161,6 +1161,7 @@ sub handleCtrlEvent($$) {
info("$node: Clearing reload info\n");
$nodeobj->ClearCurrentReload();
$nodeobj->FlushReserved();
$nodeobj->SyncTaintStates();
my $experiment = $nodeobj->Reservation();
if (defined($experiment) &&
$experiment->pid() eq NODERELOADING_PID &&
......
......@@ -2916,6 +2916,7 @@ CREATE TABLE `nodes` (
`uuid` varchar(40) NOT NULL default '',
`reserved_memory` int(10) unsigned default '0',
`nonfsmounts` tinyint(1) NOT NULL default '0',
`taint_states` set('useronly','blackbox','dangerous') default NULL,
PRIMARY KEY (`node_id`),
KEY `phys_nodeid` (`phys_nodeid`),
KEY `node_id` (`node_id`,`phys_nodeid`),
......@@ -3151,6 +3152,7 @@ CREATE TABLE `os_info` (
`mfs` tinyint(4) NOT NULL default '0',
`reboot_waittime` int(10) unsigned default NULL,
`protogeni_export` tinyint(1) NOT NULL default '0',
`taint_states` set('useronly','blackbox','dangerous') default NULL,
PRIMARY KEY (`osid`),
UNIQUE KEY `pid` (`pid`,`osname`),
KEY `OS` (`OS`),
......
......@@ -1161,6 +1161,7 @@ REPLACE INTO table_regex VALUES ('os_info','op_mode','text','regex','^[-\\w]*$',
REPLACE INTO table_regex VALUES ('os_info','nextosid','text','redirect','os_info:osid',0,0,NULL);
REPLACE INTO table_regex VALUES ('os_info','def_parentosid','text','redirect','os_info:osid',0,0,NULL);
REPLACE INTO table_regex VALUES ('os_info','reboot_waittime','int','redirect','default:int',0,2000,NULL);
REPLACE INTO table_regex VALUES ('os_info','taint_states','text','regex','^[-\\w,]*$',1,128,NULL);
REPLACE INTO table_regex VALUES ('sitevariables','name','text','regex','^[\\w\\/]+$',1,255,NULL);
REPLACE INTO table_regex VALUES ('sitevariables','value','text','redirect','default:text',0,0,NULL);
......
#
# Add "taint_states" column to nodes and os_info tables for taint tracking.
#
use strict;
use libdb;
my $impotent = 0;
sub DoUpdate($$$)
{
my ($dbhandle, $dbname, $version) = @_;
if (!DBSlotExists("os_info", "taint_states")) {
DBQueryFatal("alter table os_info add ".
" `taint_states` set('useronly','blackbox','dangerous') ".
" default NULL");
}
DBQueryFatal("REPLACE INTO table_regex VALUES ".
"('os_info','taint_states','text','regex',".
"'^[-\\\\w,]*\$',1,128,NULL)");
if (!DBSlotExists("nodes", "taint_states")) {
DBQueryFatal("alter table nodes add ".
" `taint_states` set('useronly','blackbox','dangerous') ".
" default NULL");
}
return 0;
}
# Local Variables:
# mode:perl
# End:
......@@ -252,6 +252,17 @@ sub osload ($$) {
tberror "$node: Could not map to object!";
goto failednode;
}
# Check to see if the node is tainted. If so, then the disk
# needs to be cleaned up (zeroed). If there was an explicit request
# to zero all node disks, then capture that here too.
my $zeronode = 0;
if ($nodeobject->IsTainted()) {
$zeronode = 2;
}
elsif ($zerofree) {
$zeronode = $zerofree;
}
# Get default imageid for this node.
# NOTE that virtnodes don't have default imageids -- they are only
......@@ -449,6 +460,22 @@ sub osload ($$) {
my $osid = $rowref->{$partname};
if (defined($osid)) {
# Have the node inherit taint states from each OS
# to be loaded on it (or that is already loaded on
# it). This action is additive, i.e. the node
# will end up with the union of taint states
# across all partition OSes. We also retain any
# taint states the node had previously; it's
# important not to clear these existing states
# until OS loading and disk zeroing have been
# performed.
my $osinfo = OSinfo->Lookup($osid);
if (defined($osinfo) && $osinfo->IsTainted()) {
$nodeobject->InheritTaintStates($osinfo) == 0 or
warn "Node $node could not inherit taint ".
"states from osid $osid\n";
}
my %part = (
'node_id' => $node,
'partition' => $i,
......@@ -545,7 +572,7 @@ sub osload ($$) {
$reload_mode = "UISP";
$reload_func = \&SetupReloadUISP;
$reboot_required = 0; # We don't reboot motes to reload them
$zerofree = 0; # and we don't zero "the disk"
$zeronode = 0; # and we don't zero "the disk"
} else {
$reload_mode = "Frisbee";
$reload_func = \&SetupReloadFrisbee;
......@@ -589,7 +616,7 @@ sub osload ($$) {
'osid' => $defosid,
'reboot' => $reboot_required,
'wait' => $wait_required,
'zerofree' => $zerofree,
'zerofree' => $zeronode,
'prepare' => $prepare,
'maxwait' => $maxwait,
'isremote' => $isremote,
......@@ -1010,7 +1037,7 @@ sub WaitTillReloadDone($$$$$@)
if (!$query_result->numrows) {
print STDERR "osload ($node): left reloading mode at ".`date`
if ($debug);
$count--;
$done{$node} = 1;
next;
......
......@@ -625,6 +625,14 @@ sub osload($$$) {
foreach my $k (keys(%{$nodeflags{$node}})) {
$nargs{$k} = $nodeflags{$node}{$k};
}
# XXX: this probably belongs in the code calling into libosload?
# Check to see if the node is tainted. If so, then the disk
# needs to be cleaned up (zeroed).
if ($nodeobject->IsTainted()) {
$nargs{'zerofree'} = 2;
}
# Wait, don't do this -- waitmode is global; nowait is per-node!
#
# XXX hack to handle that we would see a 'nowait' flag per-node,
......@@ -2077,6 +2085,22 @@ sub UpdatePartitions($$)
my $osid = $rowref->{$partname};
if (defined($osid)) {
# Have the node inherit taint states from each OS
# to be loaded on it (or that is already loaded on
# it). This action is additive, i.e. the node
# will end up with the union of all taint states
# across the OSes set for each disk partition. We
# also retain any taint states the node had
# previously; it's important not to clear these
# existing states until OS loading and disk
# zeroing have been performed.
my $osinfo = OSinfo->Lookup($osid);
if (defined($osinfo) && $osinfo->IsTainted()) {
$nodeobject->InheritTaintStates($osinfo) == 0 or
warn "Node $node_id could not inherit taint ".
"states from osid $osid\n";
}
my %part = (
'node_id' => $node_id,
'partition' => $i,
......
......@@ -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 libdb;
use EmulabConstants;
use User;
# Protos
sub usage();
sub fatal($);
sub ParseArgs(@);
sub DoAction($$$@);
sub GetObject($$);
sub PrintAllObjects($);
#
# Top level constants
#
my @ALLTAINTS = TB_TAINTSTATE_ALL();
my @TAINT_OBJECT_TYPES = ("node","os");
my @TAINT_ACTIONS = ("add","remove","set","clear","show","showall");
#
# Global variables
#
#
# Get, set, and display taint states for supported objects
#
sub usage()
{
print STDERR "Usage: managetaint <action> <objtype> [<OID> <taint> ...]\n";
print STDERR " -h This message\n";
print STDERR " Actions:\n";
print STDERR " add Apply one or more taint modes to an object.\n";
print STDERR " remove Remove one or more taint modes from an object.\n";
print STDERR " set Set a taint mode on specified object.\n";
print STDERR " clear Clear all taint states from an object.\n";
print STDERR " show Show all taint modes set for an object.\n";
print STDERR " showall Display all taint modes across all objects.\n";
print STDERR " Object Types (and associated object identifiers):\n";
print STDERR " Node Testbed Node\n";