Commit 7171820f authored by Leigh B Stoller's avatar Leigh B Stoller
Browse files

Restore and fix bitrot in the firewall support.

<?xml version="1.0" encoding="UTF-8"?>
<rspec xmlns="http://www.protogeni.net/resources/rspec/2"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:firewall="http://www.protogeni.net/resources/rspec/ext/firewall/1"
       xsi:schemaLocation="http://www.protogeni.net/resources/rspec/2
                         http://www.protogeni.net/resources/rspec/2/request.xsd"
       type="request" >
  <node client_id="my-node"
        exclusive="true">
    <sliver_type name="raw-pc" />
  </node>
  <node client_id="fw"
        exclusive="true">
    <sliver_type name="firewall">
    	<firewall:firewall_config style="basic" />
    </sliver_type>
  </node>
</rspec>
parent 22d34f7c
......@@ -52,7 +52,7 @@ my $EVENTSYS = "$TB/bin/eventsys_control";
my $VNODESETUP = "$TB/sbin/vnode_setup";
my $POWER = "$TB/bin/power";
my $OSLOAD = "$TB/bin/os_load";
my $SNMPIT = "$TB/bin/snmpit";
my $SNMPIT = "$TB/bin/snmpit_test";
my $NAMEDSETUP = "$TB/sbin/named_setup";
my $EXPORTS_SETUP = "$TB/sbin/exports_setup";
my $GENTOPOFILE = "$TB/libexec/gentopofile";
......@@ -780,6 +780,16 @@ sub Start($$$)
my $pid = $experiment->pid();
my $eid = $experiment->eid();
#
# Look for a firewall that needs to be setup first.
#
my ($firewall, $firewall_sliver);
my $firewalled = $experiment->IsFirewalled(\$firewall);
if ($firewalled && !defined($firewall)) {
$msg .= "Could not determine firewall for experiment";
goto bad;
}
my @slivers = ();
if ($self->SliverList(\@slivers) != 0) {
$msg .= "Could not get sliver list for $self";
......@@ -789,8 +799,10 @@ sub Start($$$)
my %vnodes = ();
my %poweron = ();
my %reloads = ();
# See "bad" label below; want to know what sliver failed (if any).
my $sliver;
foreach my $sliver (@slivers) {
foreach $sliver (@slivers) {
if (ref($sliver) ne "GeniSliver::Node") {
next
if ($sliver->state() eq "started" && !$restart);
......@@ -799,6 +811,10 @@ sub Start($$$)
or return -1;
next;
}
# Remember which sliver is the firewall.
if ($firewall eq $sliver->resource_id()) {
$firewall_sliver = $sliver;
}
my $node = Node->Lookup($sliver->resource_id());
if (!defined($node)) {
......@@ -883,7 +899,7 @@ sub Start($$$)
#
my $tmp = $osinfo->ResolveNextOSID($experiment);
if (!defined($tmp)) {
print STDERR "No next mapping for $osinfo on $node!\n";
$msg .= "No next mapping for $osinfo on $node!";
goto bad;
}
print STDERR " Mapping $osinfo on $node to $tmp\n";
......@@ -911,10 +927,12 @@ sub Start($$$)
push(@{ $reloads{$image->imageid()} }, $node);
# Reload means reboot or power on.
# But skip the firewall; that is done specially since
# it has to come up before everything else.
if (!defined($vnode) && $sliver->state() eq "stopped") {
$poweron{$node->node_id} = $node;
}
else {
else {
$reboots{$node->node_id} = $node;
}
}
......@@ -963,6 +981,9 @@ sub Start($$$)
goto bad;
}
}
# See "bad" label below.
$sliver = undef;
#
# Cull out vnodes that are going to get rebooted cause the
# physnode is getting rebooted.
......@@ -1023,16 +1044,16 @@ sub Start($$$)
}
if (system("$GENTOPOFILE $pid $eid")) {
print STDERR "$GENTOPOFILE failed\n";
$msg .= "$GENTOPOFILE failed\n";
goto bad;
}
if (system("$EXPORTS_SETUP")) {
print STDERR "$EXPORTS_SETUP failed\n";
$msg .= "$EXPORTS_SETUP failed\n";
goto bad;
}
# The nodes will not boot locally unless there is a DNS record.
if (system("$NAMEDSETUP")) {
print STDERR "$NAMEDSETUP failed\n";
$msg .= "$NAMEDSETUP failed\n";
goto bad;
}
my @diff = ();
......@@ -1057,7 +1078,82 @@ sub Start($$$)
}
#
# First power on any physical nodes that had been stopped.
# Before anything, the firewall has to be turned on or rebooted.
# Then we have to wait for it to come up before we can let the
# rest of the nodes go.
#
if ($firewalled &&
(exists($poweron{$firewall}) || exists($reboots{$firewall}))) {
my $node_id;
require StateWait;
require EmulabConstants;
if (exists($poweron{$firewall})) {
my $node = $poweron{$firewall};
$node_id = $node->node_id();
print STDERR "Powering on the firewall: $node_id\n";
system("$POWER on $node_id");
if ($?) {
$msg .= "Failed to power on firewall: $node_id";
$firewall_sliver->SetStatus("failed");
goto bad;
}
delete($poweron{$firewall});
}
else {
my $node = $reboots{$firewall};
$node_id = $node->node_id();
print STDERR "Rebooting the firewall: $node_id\n";
system("$NODEREBOOT $node_id");
if ($?) {
$msg .= "Failed to reboot firewall: $node_id";
$firewall_sliver->SetStatus("failed");
goto bad;
}
delete($reboots{$firewall});
}
$StateWait::debug = 0;
my @states = (EmulabConstants::TBDB_NODESTATE_ISUP());
if (StateWait::initStateWait(\@states, $node_id)) {
$msg .= "Failed to initialize the statewait library!";
$firewall_sliver->SetStatus("failed");
goto bad;
}
my @finished = ();
my @failed = ();
# Now we can statewait.
print STDERR "Waiting for firewall ($node_id) to boot\n";
if (StateWait::waitForState(\@finished, \@failed, (15 * 60))) {
$msg .= "Failed in waitForState for firewall: $node_id!";
$firewall_sliver->SetStatus("failed");
goto bad;
}
StateWait::endStateWait();
#
# Note that waitForState does not view timeout as failure,
# so if both @finished and @failure are empty, we timed out.
# Timeout is failure in this case.
#
@failed = ($node_id)
if (! (@finished || @failed));
if (@failed) {
$msg .= "Firewall failed to boot properly: $node_id!";
$firewall_sliver->SetStatus("failed");
goto bad;
}
}
#
# Then power on any physical nodes that had been stopped.
# Then reboot the physical nodes, then any leftover virtual nodes.
#
if (keys(%poweron)) {
......@@ -1120,6 +1216,10 @@ sub Start($$$)
$self->SetErrorLog($msg);
print STDERR "$msg\n";
}
# Mark the offending sliver as failed.
if (defined($sliver)) {
$sliver->SetStatus("failed");
}
return -1;
}
......@@ -1890,7 +1990,7 @@ sub UnProvision($)
}
#
# Nothing to do yet.
#
#
sub Start($$)
{
......@@ -1960,7 +2060,7 @@ sub Start($$)
# user can call StartSliver() again after getting the slice started
# at the other CM.
#
my $count = 1000;
my $count = 600;
my $interval = 30;
my $manifest;
while ($count >= 0) {
......@@ -1981,7 +2081,7 @@ sub Start($$)
sleep($interval);
}
if (!defined($manifest)) {
$msg = "Could not get manifest for $dsturn from $authority";
$msg = "Timed out getting manifest for $dsturn from $authority";
goto bad;
}
$manifest = GeniXML::Parse($manifest);
......@@ -1999,7 +2099,7 @@ sub Start($$)
#
my $component_id = GeniXML::GetNodeId($ref);
my $nodeblob;
$count = 1000;
$count = 300;
$interval = 30;
while ($count >= 0) {
$nodeblob = $authority->Resolve($component_id);
......@@ -2013,7 +2113,7 @@ sub Start($$)
sleep($interval);
}
if (!defined($nodeblob)) {
$msg = "Could not resolve $component_id at $authority";
$msg = "Timed out resolving $component_id at $authority";
goto bad;
}
if (!exists($nodeblob->{'physctrl'}) ||
......
......@@ -79,7 +79,7 @@ my $IPASSIGN = "$TB/libexec/ipassign_wrapper";
my $TARFILES_SETUP = "$TB/bin/tarfiles_setup";
my $MAPPER = "$TB/bin/mapper";
my $VTOPGEN = "$TB/bin/vtopgen";
my $SNMPIT = "$TB/bin/snmpit";
my $SNMPIT = "$TB/bin/snmpit_test";
my $RESERVEVLANS = "$TB/sbin/protogeni/reservevlans";
my $NEWGROUP = "$TB/bin/newgroup";
my $NEWPROJECT = "$TB/sbin/newproj";
......@@ -91,6 +91,7 @@ my $XMLLINT = "/usr/local/bin/xmllint";
my $ADDAUTHORITY = "$TB/sbin/protogeni/addauthority";
my $EMULAB_PEMFILE = "@prefix@/etc/genicm.pem";
my $TARINSTALL = "/usr/local/bin/install-tarfile";
my $FWNAME = "fw";
my $API_VERSION = 1;
my $USELOCALPROJ = 0;
......@@ -685,17 +686,6 @@ sub GetTicketAuxAux($$$$$$$$$)
goto bad;
}
#
# Firewall hack; just a flag in the rspec for now.
#
my $needsfirewall = GeniXML::GetText("needsfirewall", $rspec);
if (defined($needsfirewall)) {
if ($slice->SetFirewallFlag($needsfirewall) != 0) {
$response = GeniResponse->Create(GENIRESPONSE_ERROR);
goto bad;
}
}
#
# We need this now so we can form a virtual topo.
#
......@@ -861,11 +851,13 @@ sub GetTicketAuxAux($$$$$$$$$)
my $virtualization_subtype
= GeniXML::GetVirtualizationSubtype($ref);
my $exclusive = GeniXML::GetExclusive($ref);
my $tarfiles = GeniXML::GetTarball($ref);
my $pctype;
my $osname;
my $node;
my $isbridge;
my $isbridge = 0;
my $isfirewall = 0;
# Always populate iface2node mapping, even if we let the node
# pass through.
foreach my $linkref (GeniXML::FindNodes("n:interface",
......@@ -880,6 +872,7 @@ sub GetTicketAuxAux($$$$$$$$$)
next;
}
#
#
# Lan nodes are fake and do not go into the virt topo. Need
# to remember them though, for when we do the links below.
......@@ -984,6 +977,12 @@ sub GetTicketAuxAux($$$$$$$$$)
$isbridge = 1;
$pctype = undef;
}
elsif ($virtualization_subtype eq "firewall") {
$isfirewall = 1;
$osname = "FW-IPFW2";
$pctype = "pc";
goto raw;
}
else {
$response
= GeniResponse->Create(GENIRESPONSE_BADARGS,
......@@ -1122,12 +1121,25 @@ sub GetTicketAuxAux($$$$$$$$$)
if ($isbridge) {
$nodeblob->{'role'} = "bridge";
}
elsif ($isfirewall) {
if ($slice->SetFirewallFlag(1) != 0) {
$response = GeniResponse->Create(GENIRESPONSE_ERROR);
goto bad;
}
$nodeblob->{'cmd_line'} = '/kernel.fw';
if (!defined($virtexperiment->NewTableRow("virt_firewalls",
{"fwname" => $node_nickname,
"type" => "ipfw2-vlan",
"style" => "basic"}))) {
$response = GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Error creating firewall definition");
goto bad;
}
}
# Tarball and startup command.
my $tarfiles = GeniXML::GetTarball($ref);
if (defined($tarfiles)) {
if (! TBcheck_dbslot($tarfiles, "virt_nodes", "tarfiles",
TBDB_CHECKDBSLOT_WARN|TBDB_CHECKDBSLOT_ERROR)) {
TBDB_CHECKDBSLOT_WARN|TBDB_CHECKDBSLOT_ERROR)){
$response =
GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
"Invalid tarfiles");
......@@ -1139,7 +1151,7 @@ sub GetTicketAuxAux($$$$$$$$$)
my $startupcmd = GeniXML::GetStartupCommand($ref);
if (defined($startupcmd)) {
if (! TBcheck_dbslot($startupcmd, "virt_nodes", "startupcmd",
TBDB_CHECKDBSLOT_WARN|TBDB_CHECKDBSLOT_ERROR)) {
TBDB_CHECKDBSLOT_WARN|TBDB_CHECKDBSLOT_ERROR)) {
$response =
GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
"Invalid startup command");
......@@ -1851,6 +1863,7 @@ sub GetTicketAuxAux($$$$$$$$$)
my $virtual_id = GeniXML::GetVirtualId($ref);
my $component_id = GeniXML::GetNodeId($ref);
my $vnode_id = GeniXML::GetVnodeId($ref);
if (!(exists($nodemap{$virtual_id}) ||
exists($external_nodemap{$virtual_id}))) {
$response =
......@@ -3303,12 +3316,23 @@ sub SliverWorkAux($$$$$$$)
# Do firewall stuff.
if ($slice->needsfirewall()) {
require Firewall;
my @nodeids = map { $_->node_id() } values(%newnodes);
if (@nodeids && doFWlans($experiment,
Firewall::FWADDNODES(), \@nodeids) != 0) {
print STDERR "FireWall setup failed\n";
if ($isupdate) {
#
# Add new nodes inside the firewall.
#
if (values(%newnodes)) {
my @nodeids = map { $_->node_id() } values(%newnodes);
if (Firewall::doFWlans($experiment,
Firewall::FWADDNODES(), \@nodeids)) {
print STDERR "FireWall update failed\n";
goto bad;
}
}
}
elsif (Firewall::doFWlans($experiment, Firewall::FWSETUP(), undef)) {
print STDERR "FireWall update failed\n";
goto bad;
}
$didfwsetup = 1;
......@@ -3500,8 +3524,9 @@ sub SliverWorkAux($$$$$$$)
my @oldnodeids = map { $_->node_id() } values(%newnodes);
if ($slice->needsfirewall() && $didfwsetup) {
if (@oldnodeids && doFWlans($experiment, Firewall::FWDELNODES(),
\@oldnodeids)) {
if (@oldnodeids &&
Firewall::doFWlans($experiment, Firewall::FWDELNODES(),
\@oldnodeids)) {
print STDERR "FireWall cleanup failed\n";
}
}
......@@ -3933,7 +3958,7 @@ sub DeleteSliverAux($$$)
# A firewalled slice gets special treatment.
#
if ($slice->needsfirewall()) {
if (undoFWNodes($experiment, 1) != 0) {
if (Firewall::undoFWNodes($experiment, 0) != 0) {
print STDERR "FireWall cleanup failed\n";
$response =
GeniResponse->Create(GENIRESPONSE_ERROR, undef,
......@@ -5139,7 +5164,7 @@ sub CleanupDeadSlice($;$)
if ($slice->needsfirewall()) {
print STDERR "Calling undoFWNodes ...\n";
if (undoFWNodes($experiment, 1) != 0) {
if (Firewall::undoFWNodes($experiment, 0) != 0) {
print STDERR "FireWall cleanup failed\n";
return -1;
}
......@@ -5279,7 +5304,6 @@ sub GeniExperiment($;$)
my ($slice, $creator) = @_;
my $uuid = $slice->uuid();
my $needsfirewall = $slice->needsfirewall();
my $urn = $slice->urn();
my ($pid, $gid, $eid);
my ($project, $group);
......@@ -5498,29 +5522,12 @@ sub GeniExperiment($;$)
GeniUtil::FlipToGeniUser($project->unix_gid());
}
#
# Need a way to can experiments.
#
my $nsfile = "";
if ($needsfirewall) {
$nsfile = "/tmp/$$.ns";
if (! open(NS, "> $nsfile")) {
print STDERR "Could not create $nsfile\n";
return GeniResponse->Create(GENIRESPONSE_ERROR);
}
print NS "source tb_compat.tcl\n";
print NS "set ns [new Simulator]\n";
print NS "tb-set-security-level Blue\n";
print NS "\$ns run\n";
close(NS);
}
# Note the -h option; allows experiment with no NS file.
system("$CREATEEXPT -N -q -i -k -w ".
"-S 'Geni Slice Experiment -- DO NOT SWAP OR TERMINATE' ".
"-E '$urn' ".
"-L 'Geni Slice Experiment -- DO NOT SWAP OR TERMINATE' ".
"-h '$uuid' -p $pid -g $gid -e $eid $nsfile");
"-h '$uuid' -p $pid -g $gid -e $eid");
my $saved_exitcode = $?;
# Flip back to geni user. Will reset later.
......
......@@ -910,7 +910,7 @@ sub SliverAction($$$$$)
}
bad:
$slice->UnLock();
return ($isasync ? $response->code() : $response);
return ($isasync ? $response->{'code'} : $response);
}
#
......
......@@ -273,6 +273,20 @@ sub sliver_urn($)
return GeniHRN::Generate("@OURDOMAIN@", "sliver", $self->idx());
}
#
# Equality test. Not strictly necessary in perl, but good form.
#
sub SameSliver($$)
{
my ($self, $other) = @_;
# Must be a real reference.
return -1
if (! (ref($self) && ref($other)));
return $self->idx() == $other->idx();
}
#
# Delete the sliver. The sliver should not be provisioned when this done.
#
......
<rspec xmlns="http://www.protogeni.net/resources/rspec/0.1">
<node virtual_id="geni1"
virtualization_type="emulab-vnode"
exclusive="1">
</node>
<needsfirewall>1</needsfirewall>
<?xml version="1.0" encoding="UTF-8"?>
<rspec xmlns="http://www.protogeni.net/resources/rspec/2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:firewall="http://www.protogeni.net/resources/rspec/ext/firewall/1"
xsi:schemaLocation="http://www.protogeni.net/resources/rspec/2
http://www.protogeni.net/resources/rspec/2/request.xsd"
type="request" >
<node client_id="my-node"
exclusive="true">
<sliver_type name="raw-pc" />
</node>
<node client_id="fw"
exclusive="true">
<sliver_type name="firewall">
<firewall:firewall_config style="basic" />
</sliver_type>
</node>
</rspec>
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