Commit 80118387 authored by Leigh B. Stoller's avatar Leigh B. Stoller
Browse files

Checkpoint before radically new approach

parent f354c7d2
...@@ -79,6 +79,7 @@ sub Lookup($$) ...@@ -79,6 +79,7 @@ sub Lookup($$)
$self->{'AGGREGATE'} = $query_result->fetchrow_hashref(); $self->{'AGGREGATE'} = $query_result->fetchrow_hashref();
$self->{'CREDENTIAL'} = undef; $self->{'CREDENTIAL'} = undef;
$self->{'SLICE'} = undef; $self->{'SLICE'} = undef;
$self->{'PARENT'} = undef;
bless($self, $class); bless($self, $class);
# #
...@@ -158,6 +159,7 @@ sub creator_uuid($) { return field($_[0], "creator_uuid"); } ...@@ -158,6 +159,7 @@ sub creator_uuid($) { return field($_[0], "creator_uuid"); }
sub created($) { return field($_[0], "created"); } sub created($) { return field($_[0], "created"); }
sub credential_idx($) { return field($_[0], "credential_idx"); } sub credential_idx($) { return field($_[0], "credential_idx"); }
sub ticket_idx($) { return field($_[0], "ticket_idx"); } sub ticket_idx($) { return field($_[0], "ticket_idx"); }
sub aggregate_idx($) { return field($_[0], "aggregate_idx"); }
sub cert($) { return $_[0]->{'CERTIFICATE'}->cert(); } sub cert($) { return $_[0]->{'CERTIFICATE'}->cert(); }
sub GetCertificate($) { return $_[0]->{'CERTIFICATE'}; } sub GetCertificate($) { return $_[0]->{'CERTIFICATE'}; }
...@@ -186,11 +188,76 @@ sub SliverList($$) ...@@ -186,11 +188,76 @@ sub SliverList($$)
} }
push(@result, $sliver); push(@result, $sliver);
} }
#
# And any aggregates that are children.
#
$query_result =
DBQueryWarn("select idx from geni_aggregates ".
"where aggregate_idx='$idx'");
return -1
if (!$query_result);
while (my ($aggregate_idx) = $query_result->fetchrow_array()) {
my $aggregate = GeniAggregate->Lookup($aggregate_idx);
if (!defined($aggregate_idx)) {
print STDERR
"Could not find aggregate object for $aggregate_idx\n";
return -1;
}
push(@result, $aggregate);
}
@$pref = @result; @$pref = @result;
return 0; return 0;
} }
#
# Set the aggregate for an aggregate.
#
sub SetAggregate($$)
{
my ($self, $aggregate) = @_;
return -1
if (! (ref($self) && ref($aggregate)));
my $idx = $self->idx();
my $agg_idx = $aggregate->idx();
return -1
if (!DBQueryWarn("update geni_aggregates set ".
" aggregate_idx='$agg_idx' ".
"where idx='$idx'"));
$self->{'AGGREGATE'}->{'aggregate_idx'} = $agg_idx;
$self->{'PARENT'} = $aggregate;
return 0;
}
#
# Get the aggregate for a sliver.
#
sub GetAggregate($)
{
my ($self) = @_;
return undef
if (! ref($self));
return $self->{'PARENT'} if (defined($self->{'PARENT'}));
return undef
if (!defined($self->aggregate_idx()));
my $aggregate = GeniAggregate->Lookup($self->aggregate_idx());
if (!defined($aggregate)) {
print STDERR "Could not get aggregate object associated with $self\n";
return undef;
}
$self->{'PARENT'} = $aggregate;
return $aggregate;
}
# #
# Get the credential for the aggregate. # Get the credential for the aggregate.
# #
......
...@@ -34,6 +34,7 @@ use libtestbed; ...@@ -34,6 +34,7 @@ use libtestbed;
use libdb qw(TBGetUniqueIndex TBcheck_dbslot TBDB_CHECKDBSLOT_ERROR); use libdb qw(TBGetUniqueIndex TBcheck_dbslot TBDB_CHECKDBSLOT_ERROR);
use User; use User;
use Node; use Node;
use Interface;
use English; use English;
use Data::Dumper; use Data::Dumper;
use XML::Simple; use XML::Simple;
...@@ -108,6 +109,18 @@ sub DiscoverResources($) ...@@ -108,6 +109,18 @@ sub DiscoverResources($)
$xml .= "<node uuid=\"$uuid\" name=\"$nodeid\">". $xml .= "<node uuid=\"$uuid\" name=\"$nodeid\">".
"<available>true</available></node>\n"; "<available>true</available></node>\n";
my @interfaces = Interface->LookupAll($node);
foreach my $interface (@interfaces) {
my $iface_uuid = $interface->uuid();
my $iface = $interface->iface();
next
if (! $interface->IsExperimental());
$xml .= "<interface uuid=\"$iface_uuid\" node_name=\"$nodeid\">".
"<iface>$iface</iface></interface>\n";
}
} }
$xml .= "</rspec>"; $xml .= "</rspec>";
...@@ -124,6 +137,7 @@ sub GetTicket($) ...@@ -124,6 +137,7 @@ sub GetTicket($)
my $rspec = $argref->{'rspec'}; my $rspec = $argref->{'rspec'};
my $impotent = $argref->{'impotent'}; my $impotent = $argref->{'impotent'};
my $credential = $argref->{'credential'}; my $credential = $argref->{'credential'};
my $vtopo = $argref->{'virtual_topology'};
my $owner_uuid = $ENV{'GENIUSER'}; my $owner_uuid = $ENV{'GENIUSER'};
my $slice_uuid; my $slice_uuid;
...@@ -251,6 +265,13 @@ sub GetTicket($) ...@@ -251,6 +265,13 @@ sub GetTicket($)
"Could not allocate node\n"); "Could not allocate node\n");
} }
} }
if (defined($vtopo) && $experiment->InsertVirtTopo($vtopo) != 0) {
# Release will free the nodes.
$ticket->Release();
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Could not insert virt topology");
}
if ($ticket->Sign() != 0) { if ($ticket->Sign() != 0) {
# Release will free the nodes. # Release will free the nodes.
$ticket->Release(); $ticket->Release();
...@@ -325,45 +346,50 @@ sub CreateSliver($) ...@@ -325,45 +346,50 @@ sub CreateSliver($)
$owner->BindToSlice($slice) == 0 $owner->BindToSlice($slice) == 0
or return GeniResponse->Create(GENIRESPONSE_ERROR, undef, or return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Error binding user to slice"); "Error binding user to slice");
# #
# We are actually an Aggregate, so return an aggregate of slivers, # We are actually an Aggregate, so return an aggregate of slivers,
# even if there is just one node (simpler). # unless there is just one node.
# #
my $aggregate = GeniAggregate->Create($ticket); my $aggregate;
if (!defined($aggregate)) { if (scalar(keys(%{$ticket->rspec()->{'node'}})) > 1) {
return GeniResponse->Create(GENIRESPONSE_ERROR, undef, $aggregate = GeniAggregate->Create($ticket);
if (!defined($aggregate)) {
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Could not create GeniAggregate object"); "Could not create GeniAggregate object");
}
} }
# #
# Now for each resource (okay, node) in the ticket create a sliver and # Now for each resource (okay, node) in the ticket create a sliver and
# add it to the aggregate. # add it to the aggregate.
# #
my @slivers = (); my %slivers = ();
foreach my $resource_uuid (keys(%{$ticket->rspec()->{'node'}})) { foreach my $resource_uuid (keys(%{$ticket->rspec()->{'node'}})) {
if (! ($resource_uuid =~ /^[-\w]*$/)) { if (! ($resource_uuid =~ /^[-\w]*$/)) {
$message = "Improper resource_uuid in ticket: $resource_uuid"; $message = "Improper resource_uuid in ticket: $resource_uuid";
goto bad; goto bad;
} }
my $sliver = GeniSliver->Create($slice, $owner, $resource_uuid); my $sliver = GeniSliver::Node->Create($slice, $owner, $resource_uuid);
if (!defined($sliver)) { if (!defined($sliver)) {
$message = "Could not create GeniSliver object for $resource_uuid"; $message = "Could not create GeniSliver object for $resource_uuid";
goto bad; goto bad;
} }
push(@slivers, $sliver); $slivers{$resource_uuid} = $sliver;
} }
# #
# Now do the provisioning (note that we actually allocated the node # Now do the provisioning (note that we actually allocated the node
# above when the ticket was granted). The add the sliver to the aggregate. # above when the ticket was granted). The add the sliver to the aggregate.
# #
foreach my $sliver (@slivers) { foreach my $sliver (values(%slivers)) {
if (!$impotent && $sliver->Provision() != 0) { if (!$impotent && $sliver->Provision() != 0) {
$message = "Could not provision $sliver"; $message = "Could not provision $sliver";
goto bad; goto bad;
} }
if ($sliver->SetAggregate($aggregate) != 0) { if (defined($aggregate) &&
$sliver->SetAggregate($aggregate) != 0) {
$message = "Could not aggregate for $sliver to $aggregate"; $message = "Could not aggregate for $sliver to $aggregate";
goto bad; goto bad;
} }
...@@ -378,25 +404,76 @@ sub CreateSliver($) ...@@ -378,25 +404,76 @@ sub CreateSliver($)
# tbswap only once, or at least no more then one at a time. # tbswap only once, or at least no more then one at a time.
# #
if (!$impotent) { if (!$impotent) {
system("$SWAPEXP -s modify -r -g $pid $eid"); system("$SWAPEXP -s modify -g $pid $eid");
if ($?) { if ($?) {
$message = "Failed to tbswap $pid,$eid"; $message = "Failed to tbswap $pid,$eid";
goto bad; goto bad;
} }
} }
#
# Grab the links after swapmod since we do not know what interfaces
# assign will pick until now.
#
# XXX Not sure how to deal with users picking interfaces themselves.
#
foreach my $linkname (keys(%{$ticket->rspec()->{'link'}})) {
my @linkslivers = ();
if (! ($linkname =~ /^[-\w]*$/)) {
$message = "Bad name for link: $linkname";
goto bad;
}
my $linkaggregate = GeniAggregate->Create($ticket);
if (!defined($linkaggregate)) {
$message = "Could not create aggregate for $linkname";
goto bad;
}
$slivers{$linkaggregate->uuid()} = $linkaggregate;
#
# Grab the endpoints of the links, which are supposed to refer to
# nodes we have already seen.
#
my @interfaces;
if ($experiment->LinkInterfaces($linkname, \@interfaces) != 0) {
$message = "Could not find interfaces for $linkname";
goto bad;
}
foreach my $interface (@interfaces) {
my $sliver = GeniSliver::Interface->Create($slice, $owner,
$interface->uuid());
if (!defined($sliver)) {
$message = "Could not create GeniSliver ".
"$interface in $linkname";
goto bad;
}
if ($sliver->SetAggregate($linkaggregate) != 0) {
$message = "Could not add link sliver $sliver to $aggregate";
goto bad;
}
}
}
# #
# The API states we return a credential to control the sliver/aggregate. # The API states we return a credential to control the sliver/aggregate.
# #
my $credential = $aggregate->NewCredential($owner); my $credential;
if (defined($aggregate)) {
$credential = $aggregate->NewCredential($owner);
}
else {
$credential = ((values(%slivers))[0])->NewCredential($owner);
}
if (!defined($credential)) { if (!defined($credential)) {
$message = "Could not create credential for $aggregate"; $message = "Could not create credential";
goto bad; goto bad;
} }
return GeniResponse->Create(GENIRESPONSE_SUCCESS, $credential->asString()); return GeniResponse->Create(GENIRESPONSE_SUCCESS, $credential->asString());
bad: bad:
foreach my $sliver (@slivers) { foreach my $sliver (values(%slivers)) {
$sliver->UnProvision() $sliver->UnProvision()
if (! $impotent); if (! $impotent);
$sliver->Delete(); $sliver->Delete();
......
...@@ -242,7 +242,7 @@ sub DiscoverResources($$$$$) ...@@ -242,7 +242,7 @@ sub DiscoverResources($$$$$)
return -1 return -1
if (!defined($response) || $response->code() != GENIRESPONSE_SUCCESS); if (!defined($response) || $response->code() != GENIRESPONSE_SUCCESS);
my $rspec = XMLin($response->value(), ForceArray => ["node"]); my $rspec = XMLin($response->value(), ForceArray => ["node", "interface"]);
$$pref = $rspec; $$pref = $rspec;
return 0; return 0;
...@@ -309,9 +309,9 @@ sub UnBindUser($$$$) ...@@ -309,9 +309,9 @@ sub UnBindUser($$$$)
# #
# Get a Ticket from a component; # Get a Ticket from a component;
# #
sub GetTicket($$$$$) sub GetTicket($$$$$;$)
{ {
my ($self, $slice, $rspec, $user, $credential) = @_; my ($self, $slice, $rspec, $user, $credential, $vtopo) = @_;
my $rspec_xml = $rspec; my $rspec_xml = $rspec;
# Must be a real reference. # Must be a real reference.
...@@ -322,15 +322,16 @@ sub GetTicket($$$$$) ...@@ -322,15 +322,16 @@ sub GetTicket($$$$$)
if (ref($rspec_xml)) { if (ref($rspec_xml)) {
$rspec_xml = XMLout($rspec_xml, RootName => "rspec"); $rspec_xml = XMLout($rspec_xml, RootName => "rspec");
} }
my $args = { "slice" => $slice->cert(),
"credential" => $credential->asString(),
"impotent" => $impotent,
"rspec" => $rspec_xml };
$args->{'virtual_topology'} = $vtopo
if (defined($vtopo));
my $response = my $response =
Genixmlrpc::CallMethodHTTP($self->url(), Genixmlrpc::CallMethodHTTP($self->url(),
$user, $user, "CM::GetTicket", $args);
"CM::GetTicket",
{ "slice" => $slice->cert(),
"credential" => $credential->asString(),
"impotent" => $impotent,
"rspec" => $rspec_xml });
return undef return undef
if (!defined($response)); if (!defined($response));
...@@ -376,7 +377,8 @@ sub CreateSliver($$$$) ...@@ -376,7 +377,8 @@ sub CreateSliver($$$$)
return undef; return undef;
} }
my $sliver = GeniSliver->Create($slice, $user, undef, $credential, $self); my $sliver = GeniSliver->Create($slice, $user, undef, undef,
$credential, $self);
if (!defined($sliver)) { if (!defined($sliver)) {
print STDERR "Could not create local sliver object.\n"; print STDERR "Could not create local sliver object.\n";
return undef; return undef;
......
...@@ -23,7 +23,7 @@ use GeniCredential; ...@@ -23,7 +23,7 @@ use GeniCredential;
use GeniCertificate; use GeniCertificate;
use GeniAggregate; use GeniAggregate;
# Hate to import all this crap; need a utility library. # Hate to import all this crap; need a utility library.
use libdb qw(TBGetUniqueIndex TBDB_ALLOCSTATE_RES_INIT_DIRTY); use libdb qw(TBGetUniqueIndex);
use libtestbed; use libtestbed;
use Experiment; use Experiment;
use Node; use Node;
...@@ -100,7 +100,15 @@ sub Lookup($$) ...@@ -100,7 +100,15 @@ sub Lookup($$)
return undef; return undef;
} }
$self->{'CERTIFICATE'} = $certificate; $self->{'CERTIFICATE'} = $certificate;
bless($self, $class);
# Bless into sub package if called for.
my $resource_type = $self->{'SLIVER'}->{'resource_type'};
if (defined($resource_type) && $resource_type ne "") {
bless($self, $class . "::" . $self->{'SLIVER'}->{'resource_type'});
}
else {
bless($self, $class);
}
# Add to cache. # Add to cache.
$slivers{$self->{'SLIVER'}->{'idx'}} = $self; $slivers{$self->{'SLIVER'}->{'idx'}} = $self;
...@@ -125,9 +133,10 @@ sub Stringify($) ...@@ -125,9 +133,10 @@ sub Stringify($)
# Create a sliver record in the DB. On the client side we save the credential # Create a sliver record in the DB. On the client side we save the credential
# that allows control of it, for later operations. # that allows control of it, for later operations.
# #
sub Create($$$;$$) sub Create($$$$;$$$)
{ {
my ($class, $slice, $user, $resource_uuid, $credential, $component) = @_; my ($class, $slice, $user, $resource_uuid, $resource_type,
$credential, $component) = @_;
my @insert_data = (); my @insert_data = ();
my $uuid; my $uuid;
my $certificate; my $certificate;
...@@ -165,6 +174,8 @@ sub Create($$$;$$) ...@@ -165,6 +174,8 @@ sub Create($$$;$$)
push(@insert_data, "uuid='$uuid'"); push(@insert_data, "uuid='$uuid'");
push(@insert_data, "resource_uuid='$resource_uuid'") push(@insert_data, "resource_uuid='$resource_uuid'")
if (defined($resource_uuid)); if (defined($resource_uuid));
push(@insert_data, "resource_type='$resource_type'")
if (defined($resource_type));
push(@insert_data, "creator_uuid='$owner_uuid'"); push(@insert_data, "creator_uuid='$owner_uuid'");
push(@insert_data, "slice_uuid='$slice_uuid'"); push(@insert_data, "slice_uuid='$slice_uuid'");
...@@ -204,6 +215,7 @@ sub creator_uuid($) { return field($_[0], "creator_uuid"); } ...@@ -204,6 +215,7 @@ sub creator_uuid($) { return field($_[0], "creator_uuid"); }
sub created($) { return field($_[0], "created"); } sub created($) { return field($_[0], "created"); }
sub credential_idx($) { return field($_[0], "credential_idx"); } sub credential_idx($) { return field($_[0], "credential_idx"); }
sub resource_uuid($) { return field($_[0], "resource_uuid"); } sub resource_uuid($) { return field($_[0], "resource_uuid"); }
sub resource_type($) { return field($_[0], "resource_type"); }
sub ticket_idx($) { return field($_[0], "ticket_idx"); } sub ticket_idx($) { return field($_[0], "ticket_idx"); }
sub component_idx($) { return field($_[0], "component_idx"); } sub component_idx($) { return field($_[0], "component_idx"); }
sub aggregate_idx($) { return field($_[0], "aggregate_idx"); } sub aggregate_idx($) { return field($_[0], "aggregate_idx"); }
...@@ -452,6 +464,54 @@ sub UnBindUser($$) ...@@ -452,6 +464,54 @@ sub UnBindUser($$)
return 0; return 0;
} }
#
# Create a signed credential for this sliver, issued to the provided user.
# The credential will grant all permissions for now.
#
# Should we store these credentials in the DB, recording what we hand out?
#
sub NewCredential($$)
{
my ($self, $owner) = @_;
return undef
if (! (ref($self) && ref($owner)));
my $credential = GeniCredential->Create($self, $owner);
if (!defined($credential)) {
print STDERR "Could not create credential for $self, $owner\n";
return undef;
}
if ($credential->Sign($self->GetCertificate()) != 0) {
print STDERR "Could not sign credential for $self, $owner\n";
return undef;
}
return $credential;
}
############################################################################
#
# The server side methods are in packages which inherit from above.
#
package GeniSliver::Node;
use vars qw(@ISA);
@ISA = "GeniSliver";
use GeniDB;
use GeniComponent;
use GeniSlice;
use GeniCredential;
use GeniCertificate;
use GeniAggregate;
use libdb qw(TBDB_ALLOCSTATE_RES_INIT_DIRTY);
sub Create()
{
my ($class, $slice, $user, $resource_uuid) = @_;
return GeniSliver->Create($slice, $user, $resource_uuid, "Node");
}
# #
# Provision a slice. We actually did this when the ticket was requested. # Provision a slice. We actually did this when the ticket was requested.
# We fill in some virt table stuff so that tbswap will work. # We fill in some virt table stuff so that tbswap will work.
...@@ -487,10 +547,6 @@ sub Provision($) ...@@ -487,10 +547,6 @@ sub Provision($)
return -1; return -1;
} }
if ($reservation->SameExperiment($experiment)) { if ($reservation->SameExperiment($experiment)) {
if ($experiment->InsertVirtNode($node) != 0) {
print STDERR "Could not add virtnode entry for $node to $self\n";
return -1;
}
# Set sliver_idx in the reservation so that Emulab knows. # Set sliver_idx in the reservation so that Emulab knows.
if ($node->ModifyReservation({"genisliver_idx" => $self->idx()}) != 0){ if ($node->ModifyReservation({"genisliver_idx" => $self->idx()}) != 0){
return -1; return -1;
...@@ -508,31 +564,6 @@ sub Provision($) ...@@ -508,31 +564,6 @@ sub Provision($)
return 0; return 0;
} }
#
# Create a signed credential for this sliver, issued to the provided user.
# The credential will grant all permissions for now.
#
# Should we store these credentials in the DB, recording what we hand out?
#
sub NewCredential($$)
{
my ($self, $owner) = @_;