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

Checkpoint

parent 503bb661
...@@ -115,7 +115,8 @@ CREATE TABLE `geni_slices` ( ...@@ -115,7 +115,8 @@ CREATE TABLE `geni_slices` (
) ENGINE=MyISAM DEFAULT CHARSET=latin1; ) ENGINE=MyISAM DEFAULT CHARSET=latin1;
# #
# Geni Slivers. Created on components (by CMs of course). # Geni Slivers. Created on components (by CMs of course). Locally, a sliver
# corresponds to an allocated node.
# #
DROP TABLE IF EXISTS `geni_slivers`; DROP TABLE IF EXISTS `geni_slivers`;
CREATE TABLE `geni_slivers` ( CREATE TABLE `geni_slivers` (
...@@ -123,6 +124,7 @@ CREATE TABLE `geni_slivers` ( ...@@ -123,6 +124,7 @@ CREATE TABLE `geni_slivers` (
`uuid` varchar(40) NOT NULL default '', `uuid` varchar(40) NOT NULL default '',
`slice_uuid` varchar(40) NOT NULL default '', `slice_uuid` varchar(40) NOT NULL default '',
`creator_uuid` varchar(40) NOT NULL default '', `creator_uuid` varchar(40) NOT NULL default '',
`node_id` varchar(32) default NULL,
`created` datetime default NULL, `created` datetime default NULL,
`cm_idx` int(10) unsigned NOT NULL default '0', `cm_idx` int(10) unsigned NOT NULL default '0',
PRIMARY KEY (`idx`), PRIMARY KEY (`idx`),
...@@ -130,3 +132,20 @@ CREATE TABLE `geni_slivers` ( ...@@ -130,3 +132,20 @@ CREATE TABLE `geni_slivers` (
INDEX `slice_uuid` (`slice_uuid`) INDEX `slice_uuid` (`slice_uuid`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1; ) ENGINE=MyISAM DEFAULT CHARSET=latin1;
#
# Table to remember the tickets that a component manager hands out.
#
DROP TABLE IF EXISTS `geni_tickets`;
CREATE TABLE `geni_tickets` (
`idx` mediumint(8) unsigned NOT NULL default '0',
`owner_uuid` varchar(40) NOT NULL default '',
`slice_uuid` varchar(40) NOT NULL default '',
`created` datetime default NULL,
`redeem_before` datetime default NULL,
`valid_until` datetime default NULL,
`cm_idx` int(10) unsigned NOT NULL default '0',
`ticket_string` text,
PRIMARY KEY (`idx`),
INDEX `owner_uuid` (`owner_uuid`),
INDEX `slice_uuid` (`slice_uuid`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
...@@ -24,8 +24,11 @@ use Genixmlrpc; ...@@ -24,8 +24,11 @@ use Genixmlrpc;
use GeniResponse; use GeniResponse;
use GeniTicket; use GeniTicket;
use GeniSliver; use GeniSliver;
use GeniUser;
use libtestbed; use libtestbed;
use emutil; # Hate to import all this crap; need a utility library.
use libdb qw(TBGetUniqueIndex TBcheck_dbslot TBDB_CHECKDBSLOT_ERROR);
use User;
use English; use English;
use Data::Dumper; use Data::Dumper;
use Experiment; use Experiment;
...@@ -38,6 +41,8 @@ my $TBAUDIT = "@TBAUDITEMAIL@"; ...@@ -38,6 +41,8 @@ my $TBAUDIT = "@TBAUDITEMAIL@";
my $BOSSNODE = "@BOSSNODE@"; my $BOSSNODE = "@BOSSNODE@";
my $OURDOMAIN = "@OURDOMAIN@"; my $OURDOMAIN = "@OURDOMAIN@";
my $GENICENTRAL = "https://boss/protogeni/xmlrpc"; my $GENICENTRAL = "https://boss/protogeni/xmlrpc";
my $CREATEEXPT = "$TB/bin/batchexp";
my $NALLOC = "$TB/bin/nalloc";
# #
# Respond to a GetTicket request. No worries about credentials yet; we # Respond to a GetTicket request. No worries about credentials yet; we
...@@ -63,26 +68,75 @@ sub GetTicket($) ...@@ -63,26 +68,75 @@ sub GetTicket($)
} }
# #
# If the underlying experiment does not exist, need to create # XXX Should we create a local geni_slices record in the DB?
# a holding experiment.
# #
if (0) {
#
# If the underlying experiment does not exist, need to create
# a holding experiment. All these are going to go into the same
# project for now. Generally, users for non-local slices do not
# have local accounts or directories.
# #
# An rspec is a structure with a node count. :-) my $experiment = Experiment->Lookup($slice_uuid);
if (!defined($experiment)) {
#
# Form an eid for the experiment.
#
my $eid = "slice" . TBGetUniqueIndex('next_sliceid', 1);
# Note the -h option; allows experiment with no NS file.
system("$CREATEEXPT -q -i -w -E 'Geni Slice Experiment' ".
"-h '$slice_uuid' -p genislices -e $eid");
if ($?) {
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Internal Error");
}
$experiment = Experiment->Lookup($slice_uuid);
}
# #
# Find out how many nodes are available and grant that many. Silly, eh? # An rspec is a structure that requests a specific node. If that node
# is available, then reserve it. Otherwise the ticket cannot be
# granted.
# #
$rspec->{'granted'} = $rspec->{'requested'}; my $node_id = $rspec->{'node_id'};
my $pid = $experiment->pid();
my $eid = $experiment->eid();
if (defined($node_id) && $node_id =~ /^(\w*)$/) {
$node_id = $1;
}
else {
return GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
"Improper node id");
}
}
# #
# Return a signed ticket. # Create the ticket first, before allocating the node.
# #
my $ticket = GeniTicket->Create($slice_uuid, $owner_uuid, $rspec); my $ticket = GeniTicket->Create($slice_uuid, $owner_uuid, $rspec);
if (!defined($ticket)) { if (!defined($ticket)) {
return GeniResponse->Create(GENIRESPONSE_ERROR, undef, return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Could not create GeniTicket object"); "Could not create GeniTicket object");
} }
if (0) {
# Nalloc might fail if the node gets picked up by someone else.
# system("$NALLOC $pid $eid $node_id");
if (($? >> 8) < 0) {
$ticket->Delete();
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Allocation failure");
}
elsif (($? >> 8) > 0) {
$ticket->Delete();
return GeniResponse->Create(GENIRESPONSE_UNAVAILABLE, undef,
"Could not allocate node\n");
}
}
if ($ticket->Sign() != 0) { if ($ticket->Sign() != 0) {
# Release will free the node.
$ticket->Release();
return GeniResponse->Create(GENIRESPONSE_ERROR, undef, return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Could not sign Ticket"); "Could not sign Ticket");
} }
...@@ -110,6 +164,12 @@ sub CreateSliver($) ...@@ -110,6 +164,12 @@ sub CreateSliver($)
"Could not create GeniTicket object"); "Could not create GeniTicket object");
} }
my $experiment = Experiment->Lookup($ticket->slice_uuid());
if (!defined($experiment)) {
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"No local experiment for slice");
}
# #
# XXX TODO: Need to verify the invoking user is the one in the ticket. # XXX TODO: Need to verify the invoking user is the one in the ticket.
# #
...@@ -118,5 +178,17 @@ sub CreateSliver($) ...@@ -118,5 +178,17 @@ sub CreateSliver($)
return GeniResponse->Create(GENIRESPONSE_ERROR, undef, return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Could not create GeniSliver object"); "Could not create GeniSliver object");
} }
#
# Provision the slice. Okay, we already allocated the node above,
# so this should just work, unless the node has been released cause
# it has been too long.
#
if ($sliver->Provision() != 0) {
$sliver->Delete();
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Could not provision sliver");
}
return GeniResponse->Create(GENIRESPONSE_SUCCESS, 0, "Wow!"); return GeniResponse->Create(GENIRESPONSE_SUCCESS, 0, "Wow!");
} }
...@@ -36,7 +36,7 @@ my $TBAPPROVAL = "@TBAPPROVALEMAIL@"; ...@@ -36,7 +36,7 @@ my $TBAPPROVAL = "@TBAPPROVALEMAIL@";
my $TBAUDIT = "@TBAUDITEMAIL@"; my $TBAUDIT = "@TBAUDITEMAIL@";
my $BOSSNODE = "@BOSSNODE@"; my $BOSSNODE = "@BOSSNODE@";
my $OURDOMAIN = "@OURDOMAIN@"; my $OURDOMAIN = "@OURDOMAIN@";
my $GENICENTRAL = "https://boss/protogeni/xmlrpc"; my $GENICENTRAL = "https://myboss.little-emulab-bsd61.testbed.emulab.net/protogeni/xmlrpc";
# #
# Discover resources for a slice (local experiment). This contacts Geni # Discover resources for a slice (local experiment). This contacts Geni
...@@ -76,7 +76,7 @@ sub DiscoverResources($$) ...@@ -76,7 +76,7 @@ sub DiscoverResources($$)
# #
sub GetTicket($$$$) sub GetTicket($$$$)
{ {
my ($experiment, $component, $requested, $pref) = @_; my ($experiment, $component, $rspec, $pref) = @_;
# #
# XXX # XXX
...@@ -87,9 +87,6 @@ sub GetTicket($$$$) ...@@ -87,9 +87,6 @@ sub GetTicket($$$$)
return -1; return -1;
} }
my $rspec = { "requested" => $requested,
"granted" => 0};
my $response = my $response =
Genixmlrpc::CallMethodHTTP($component, "CM::GetTicket", Genixmlrpc::CallMethodHTTP($component, "CM::GetTicket",
{ "slice_uuid" => $experiment->uuid(), { "slice_uuid" => $experiment->uuid(),
...@@ -99,8 +96,6 @@ sub GetTicket($$$$) ...@@ -99,8 +96,6 @@ sub GetTicket($$$$)
return -1 return -1
if (!defined($response)); if (!defined($response));
print Dumper($response);
return -1 return -1
if ($response->code() != GENIRESPONSE_SUCCESS); if ($response->code() != GENIRESPONSE_SUCCESS);
......
...@@ -80,9 +80,7 @@ sub RegisterSlice($) ...@@ -80,9 +80,7 @@ sub RegisterSlice($)
{ "hrn" => $hrn, { "hrn" => $hrn,
"uuid" => $experiment->uuid(), "uuid" => $experiment->uuid(),
"creator_uuid" => $user->uuid()}); "creator_uuid" => $user->uuid()});
print Dumper($response); print Dumper($response);
return $response->code(); return $response->code();
} }
......
...@@ -164,7 +164,7 @@ sub Delete($) ...@@ -164,7 +164,7 @@ sub Delete($)
{ {
my ($self) = @_; my ($self) = @_;
return 0 return -1
if (! ref($self)); if (! ref($self));
my $idx = $self->idx(); my $idx = $self->idx();
......
...@@ -20,6 +20,8 @@ use GeniDB; ...@@ -20,6 +20,8 @@ use GeniDB;
# Hate to import all this crap; need a utility library. # Hate to import all this crap; need a utility library.
use libdb qw(TBGetUniqueIndex); use libdb qw(TBGetUniqueIndex);
use libtestbed; use libtestbed;
use Experiment;
use Node;
use English; use English;
use Data::Dumper; use Data::Dumper;
use File::Temp qw(tempfile); use File::Temp qw(tempfile);
...@@ -33,6 +35,9 @@ my $BOSSNODE = "@BOSSNODE@"; ...@@ -33,6 +35,9 @@ my $BOSSNODE = "@BOSSNODE@";
my $OURDOMAIN = "@OURDOMAIN@"; my $OURDOMAIN = "@OURDOMAIN@";
my $GENICENTRAL = "https://boss/protogeni/xmlrpc"; my $GENICENTRAL = "https://boss/protogeni/xmlrpc";
my $SIGNCRED = "$TB/sbin/signgenicred"; my $SIGNCRED = "$TB/sbin/signgenicred";
my $AVAIL = "$TB/sbin/avail";
my $NALLOC = "$TB/bin/nalloc";
my $NFREE = "$TB/bin/nfree";
# Cache of instances to avoid regenerating them. # Cache of instances to avoid regenerating them.
my %slivers = (); my %slivers = ();
...@@ -108,12 +113,13 @@ sub Create($$) ...@@ -108,12 +113,13 @@ sub Create($$)
} }
my $slice_uuid = $ticket->slice_uuid(); my $slice_uuid = $ticket->slice_uuid();
my $owner_uuid = $ticket->owner_uuid(); my $owner_uuid = $ticket->owner_uuid();
my $node_id = $ticket->rspec()->{'node_id'};
# Now tack on other stuff we need. # Now tack on other stuff we need.
push(@insert_data, "created=now()"); push(@insert_data, "created=now()");
push(@insert_data, "idx='$idx'"); push(@insert_data, "idx='$idx'");
push(@insert_data, "uuid='$uuid'"); push(@insert_data, "uuid='$uuid'");
push(@insert_data, "node_id='$node_id'");
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'");
...@@ -131,6 +137,72 @@ sub slice_uuid($) { return field($_[0], "slice_uuid"); } ...@@ -131,6 +137,72 @@ sub slice_uuid($) { return field($_[0], "slice_uuid"); }
sub creator_uuid($) { return field($_[0], "creator_uuid"); } sub creator_uuid($) { return field($_[0], "creator_uuid"); }
sub created($) { return field($_[0], "created"); } sub created($) { return field($_[0], "created"); }
sub cm_idx($) { return field($_[0], "cm_idx"); } sub cm_idx($) { return field($_[0], "cm_idx"); }
sub node_id($) { return field($_[0], "node_id"); }
#
# Delete the sliver. The sliver should not be provisioned when this done.
#
sub Delete($)
{
my ($self) = @_;
return -1
if (! ref($self));
my $idx = $self->idx();
DBQueryWarn("delete from geni_slivers where idx='$idx'")
or return -1;
return 0;
}
#
# Get the experiment for the slice this sliver belongs to.
#
sub GetExperiment($)
{
my ($self) = @_;
return undef
if (! ref($self));
return Experiment->Lookup($self->slice_uuid());
}
#
# Provision a slice. We actually did this when the ticket was requested.
#
sub Provision($)
{
return 0;
}
#
# Unprovision a sliver.
#
sub UnProvision($)
{
my ($self) = @_;
return -1
if (! ref($self));
my $experiment = Experiment->Lookup($self->slice_uuid());
my $node_id = $self->node_id();
my $node = Node->Lookup($node_id);
return -1
if (!defined($node));
my $reservation = Node->Reservation();
if (defined($reservation) && $reservation->SameExperiment($experiment)) {
my $pid = $experiment->pid();
my $eid = $experiment->eid();
system("$NFREE $pid $eid $node_id");
}
return 0;
}
# _Always_ make sure that this 1 is at the end of the file... # _Always_ make sure that this 1 is at the end of the file...
1; 1;
...@@ -20,6 +20,8 @@ use vars qw(@ISA @EXPORT); ...@@ -20,6 +20,8 @@ use vars qw(@ISA @EXPORT);
use lib '@prefix@/lib'; use lib '@prefix@/lib';
use GeniDB; use GeniDB;
use libtestbed; use libtestbed;
use Experiment;
use libdb qw(TBGetUniqueIndex);
use English; use English;
use XML::Simple; use XML::Simple;
use XML::LibXML; use XML::LibXML;
...@@ -35,12 +37,11 @@ my $BOSSNODE = "@BOSSNODE@"; ...@@ -35,12 +37,11 @@ my $BOSSNODE = "@BOSSNODE@";
my $OURDOMAIN = "@OURDOMAIN@"; my $OURDOMAIN = "@OURDOMAIN@";
my $GENICENTRAL = "https://boss/protogeni/xmlrpc"; my $GENICENTRAL = "https://boss/protogeni/xmlrpc";
my $SIGNCRED = "$TB/sbin/signgenicred"; my $SIGNCRED = "$TB/sbin/signgenicred";
my $NFREE = "$TB/bin/nfree";
# #
# Create an unsigned ticket object from the raw rspec. # Create an unsigned ticket object from the raw rspec.
# #
# Should we keep track of tickets locally in the DB?
#
sub Create($$$$;$$) sub Create($$$$;$$)
{ {
my ($class, $slice_uuid, $owner_uuid, my ($class, $slice_uuid, $owner_uuid,
...@@ -52,6 +53,7 @@ sub Create($$$$;$$) ...@@ -52,6 +53,7 @@ sub Create($$$$;$$)
$self->{'owner_uuid'} = $owner_uuid; $self->{'owner_uuid'} = $owner_uuid;
$self->{'ticket_string'} = $ticket_string; $self->{'ticket_string'} = $ticket_string;
$self->{'ticket'} = undef; $self->{'ticket'} = undef;
$self->{'idx'} = undef; # Only set when in DB.
$self->{'component'} = $component; $self->{'component'} = $component;
bless($self, $class); bless($self, $class);
...@@ -59,12 +61,14 @@ sub Create($$$$;$$) ...@@ -59,12 +61,14 @@ sub Create($$$$;$$)
} }
# accessors # accessors
sub field($$) { return ($_[0]->{$_[1]}); } sub field($$) { return ($_[0]->{$_[1]}); }
sub idx($) { return field($_[0], "idx"); }
sub rspec($) { return field($_[0], "rspec"); } sub rspec($) { return field($_[0], "rspec"); }
sub uuid($) { return field($_[0], "slice_uuid"); } sub uuid($) { return field($_[0], "slice_uuid"); }
sub slice_uuid($) { return field($_[0], "slice_uuid"); } sub slice_uuid($) { return field($_[0], "slice_uuid"); }
sub owner_uuid($) { return field($_[0], "owner_uuid"); } sub owner_uuid($) { return field($_[0], "owner_uuid"); }
sub ticket($) { return field($_[0], "ticket"); } sub ticket($) { return field($_[0], "ticket"); }
sub asString($) { return field($_[0], "ticket_string"); } sub asString($) { return field($_[0], "ticket_string"); }
sub ticket_string($) { return field($_[0], "ticket_string"); }
sub component($) { return field($_[0], "component"); } sub component($) { return field($_[0], "component"); }
# #
...@@ -108,6 +112,26 @@ sub CreateFromSignedTicket($$) ...@@ -108,6 +112,26 @@ sub CreateFromSignedTicket($$)
return undef; return undef;
} }
#
# We save copies of the tickets we hand out; lets find that record
# in the DB, just to verify.
#
my ($serial_node) = $doc->getElementsByTagName("serial");
return undef
if (!defined($serial_node));
my $serial = $serial_node->to_literal();
if (! ($serial =~ /^\w+$/)) {
print STDERR "Invalid serial in ticket\n";
return undef;
}
my $query_result =
DBQueryWarn("select * from geni_tickets where idx='$serial'");
if (!$query_result || !$query_result->numrows) {
print STDERR "Could not find the ticket in te DB\n";
return undef;
}
my $self = {}; my $self = {};
$self->{'rspec'} = $rspec; $self->{'rspec'} = $rspec;
$self->{'slice_uuid'} = $slice_uuid; $self->{'slice_uuid'} = $slice_uuid;
...@@ -115,6 +139,7 @@ sub CreateFromSignedTicket($$) ...@@ -115,6 +139,7 @@ sub CreateFromSignedTicket($$)
$self->{'ticket_string'} = $ticket_string; $self->{'ticket_string'} = $ticket_string;
$self->{'xmlref'} = $doc; $self->{'xmlref'} = $doc;
$self->{'component'} = undef; $self->{'component'} = undef;
$self->{'idx'} = $serial;
bless($self, $class); bless($self, $class);
print Dumper($self); print Dumper($self);
...@@ -122,6 +147,25 @@ sub CreateFromSignedTicket($$) ...@@ -122,6 +147,25 @@ sub CreateFromSignedTicket($$)
return $self; return $self;
} }
#
# Might have to delete this fron the DB, as with an error handing out a ticket.
#
sub Delete($)
{
my ($self) = @_;
return -1
if (! ref($self));
if (defined($self->idx())) {
my $idx = $self->idx();
DBQueryWarn("delete from geni_tickets where idx='$idx'")
or return -1;
}
return 0;
}
# #
# Populate the ticket with some stuff, which right now is just the # Populate the ticket with some stuff, which right now is just the
# number of node we are willing to grant. # number of node we are willing to grant.
...@@ -130,13 +174,44 @@ sub Grant($$) ...@@ -130,13 +174,44 @@ sub Grant($$)
{ {
my ($self, $count) = @_; my ($self, $count) = @_;
return 0 return -1
if (! ref($self)); if (! ref($self));
$self->{'count'} = $count; $self->{'count'} = $count;
return 0; return 0;
} }
#
# Store the given ticket in the DB. We only do this for signed tickets
# which we hand out, so we have a record of them.
#
sub Store($$)
{
my ($self, $idx) = @_;