Commit f6b16939 authored by Leigh Stoller's avatar Leigh Stoller

Checkpoint

parent 461c5029
......@@ -363,31 +363,6 @@ sub SetStatus($$)
return 0;
}
#
# Get the credential for the aggregate.
#
sub GetCredential($)
{
my ($self) = @_;
return undef
if (! ref($self));
return $self->{'CREDENTIAL'} if (defined($self->{'CREDENTIAL'}));
if (!defined($self->credential_idx())) {
print STDERR "No credential associated with $self\n";
return undef;
}
my $credential = GeniCredential->Lookup($self->credential_idx());
if (!defined($credential)) {
print STDERR "Could not get credential object associated with $self\n";
return undef;
}
$self->{'CREDENTIAL'} = $credential;
return $credential;
}
#
# Get the slice for the aggregate.
#
......@@ -465,9 +440,9 @@ sub Start($)
#
# Provision all the slivers in the aggregate.
#
sub Provision($)
sub Provision($;$)
{
my ($self) = @_;
my ($self, $extraargs) = @_;
return -1
if (! ref($self));
......@@ -478,7 +453,7 @@ sub Provision($)
return -1;
}
foreach my $sliver (@slivers) {
if ($sliver->Provision() != 0) {
if ($sliver->Provision($extraargs) != 0) {
print STDERR "Could not provision $sliver in $self\n";
next;
}
......@@ -537,9 +512,9 @@ sub Create($$)
#
# Provision all the slivers in the aggregate.
#
sub Provision($)
sub Provision($;$)
{
my ($self) = @_;
my ($self, $extraargs) = @_;
return -1
if (! ref($self));
......@@ -585,6 +560,7 @@ sub Provision($)
print STDERR "$self: Could not instantiate $vlan on switches\n";
goto bad;
}
$self->SetStatus("ready");
return 0;
bad:
......
......@@ -331,7 +331,10 @@ sub GetTicket($)
#
# An rspec is a structure that requests specific nodes. If those
# nodes are available, then reserve it. Otherwise the ticket
# cannot be granted.
# cannot be granted.
#
# XXX Simpleminded ... assumes only physical nodes for now. Need to deal
# with virtual nodes (vservers on shared nodes, planetlab nodes, etc).
#
my @nodeids = ();
my $pid = $experiment->pid();
......@@ -344,6 +347,15 @@ sub GetTicket($)
return GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
"Bad resource_uuid $resource_uuid");
}
#
# See if the node is already reserved.
#
my $reservation = $node->Reservation();
if (defined($reservation)) {
return GeniResponse->Create(GENIRESPONSE_UNAVAILABLE, undef,
"$resource_uuid ($node) is not available");
}
push(@nodeids, $node->node_id());
}
......@@ -394,6 +406,7 @@ sub RedeemTicket($)
my ($argref) = @_;
my $ticket = $argref->{'ticket'};
my $impotent = $argref->{'impotent'};
my $extraargs = $argref->{'extraargs'};
my $message = "Error creating sliver/aggregate";
$impotent = 0
......@@ -497,7 +510,6 @@ sub RedeemTicket($)
#
my %slivers = ();
foreach my $ref (@{$ticket->rspec()->{'node'}}) {
my $virtualization_type = $ref->{'virtualization_type'};
my $resource_uuid = $ref->{'uuid'};
my $node = Node->Lookup($resource_uuid);
if (!defined($node)) {
......@@ -580,7 +592,7 @@ sub RedeemTicket($)
# above when the ticket was granted). The add the sliver to the aggregate.
#
foreach my $sliver (values(%slivers)) {
if (!$impotent && $sliver->Provision() != 0) {
if (!$impotent && $sliver->Provision($extraargs) != 0) {
$message = "Could not provision $sliver";
goto bad;
......@@ -606,6 +618,14 @@ sub RedeemTicket($)
$message = "Could not create credential";
goto bad;
}
#
# The last step is to delete the ticket, since it is no longer needed.
# and will cause less confusion if it is not in the DB.
#
if ($ticket->Delete() != 0) {
print STDERR "Error deleting $ticket for $slice\n";
}
return GeniResponse->Create(GENIRESPONSE_SUCCESS, $credential->asString());
bad:
......@@ -620,6 +640,40 @@ sub RedeemTicket($)
return GeniResponse->Create(GENIRESPONSE_ERROR, undef, $message);
}
#
# Release a ticket.
#
sub ReleaseTicket($)
{
my ($argref) = @_;
my $ticket = $argref->{'ticket'};
if (! (defined($ticket) &&
!TBcheck_dbslot($ticket, "default", "text",
TBDB_CHECKDBSLOT_ERROR))) {
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"ticket: ". TBFieldErrorString());
}
$ticket = GeniTicket->CreateFromSignedTicket($ticket);
if (!defined($ticket)) {
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Could not create GeniTicket object");
}
#
# Make sure the credential was issued to the caller.
#
if ($ticket->owner_uuid() ne $ENV{'GENIUUID'}) {
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"This is not your credential!");
}
if ($ticket->Release() != 0) {
print STDERR "Error releasing $ticket\n";
return GeniResponse->Create(GENIRESPONSE_ERROR);
}
return GeniResponse->Create(GENIRESPONSE_SUCCESS);
}
#
# Start a sliver (not sure what this means yet, so reboot for now).
#
......@@ -740,6 +794,8 @@ sub CreateSliceFromRegistry($)
}
}
print Dumper($blob);
#
# The problem with HRNs is that people will tend to reuse them!
# So check to see if we have a slice with the hrn, and if so
......
......@@ -339,22 +339,49 @@ sub GetTicket($$$$$;$)
return GeniTicket->CreateFromSignedTicket($response->value(), $self, 1);
}
#
# Release a Ticket on a component;
#
sub ReleaseTicket($$$$)
{
my ($self, $slice, $context, $ticket) = @_;
# Must be a real reference.
return undef
if (! ref($self));
my $args = { "ticket" => $ticket->asString() };
my $response =
Genixmlrpc::CallMethod($self->url(), $context, "ReleaseTicket", $args);
return -1
if (!defined($response));
return -1
if ($response->code() != GENIRESPONSE_SUCCESS);
return 0;
}
#
# Create a sliver, given a ticket.
#
sub CreateSliver($$$$)
sub CreateSliver($$$$;$)
{
my ($self, $slice, $ticket, $context) = @_;
my ($self, $slice, $ticket, $context, $extraargs) = @_;
# Must be a real reference.
return undef
if (! ref($self));
my $args = { "ticket" => $ticket->asString(),
"impotent" => $impotent };
$args->{'extraargs'} = $extraargs
if (defined($extraargs));
my $response =
Genixmlrpc::CallMethod($self->url(), $context,
"RedeemTicket",
{ "ticket" => $ticket->asString(),
"impotent" => $impotent });
Genixmlrpc::CallMethod($self->url(), $context, "RedeemTicket", $args);
return undef
if (!defined($response));
......@@ -371,6 +398,16 @@ sub CreateSliver($$$$)
return undef;
}
#
# We need to store this credential (not the default) so we can
# operate on the sliver later.
#
if ($credential->Store() != 0) {
print STDER "Could not store $credential for new sliver\n";
$credential->Delete();
return undef;
}
my $sliver = GeniSliver::Client->Create($slice, $ticket->owner_uuid(),
$ticket->rspec(),
$credential, $self);
......@@ -393,7 +430,7 @@ sub DestroySliver($$$)
return -1
if (! ref($self));
my $credential = $sliver->GetCredential();
my $credential = $sliver->GetCredential($context->user());
return -1
if (!defined($credential));
......@@ -421,7 +458,7 @@ sub StartSliver($$$)
return -1
if (! ref($self));
my $credential = $sliver->GetCredential();
my $credential = $sliver->GetCredential($context->user());
return -1
if (!defined($credential));
......
......@@ -20,6 +20,7 @@ use vars qw(@ISA @EXPORT);
use lib '@prefix@/lib';
use GeniDB;
use GeniCertificate;
use GeniUser;
use libtestbed;
use libdb qw(TBGetUniqueIndex);
use English;
......@@ -27,6 +28,7 @@ use XML::Simple;
use XML::LibXML;
use Data::Dumper;
use File::Temp qw(tempfile);
use overload ('""' => 'Stringify');
# Exported variables
use vars qw(@EXPORT_OK $LOCALSA_FLAG $LOCALCM_FLAG $LOCALMA_FLAG);
......@@ -49,6 +51,8 @@ $LOCALCM_FLAG = 2;
$LOCALMA_FLAG = 3;
@EXPORT_OK = qw(LOCALSA_FLAG LOCALCM_FLAG LOCALMA_FLAG);
# Capability Flags.
#
# Look for a signed credential in the DB. At present, we store a credential
# by user/object (uuid/uuid), not worrying about different flavors of creds
......@@ -57,48 +61,60 @@ $LOCALMA_FLAG = 3;
#
sub Lookup($$$)
{
my ($class, $this, $owner) = @_;
my ($class, $target, $owner) = @_;
return undef
if (! (ref($this) && ref($owner)));
my $this_uuid = $this->uuid();
my $owner_uuid = $owner->uuid();
if (! (ref($target) && ref($owner)));
my $target_uuid = $target->uuid();
my $owner_uuid = $owner->uuid();
my $query_result =
DBQueryWarn("select * from geni_credentials ".
"where owner_uuid='$owner_uuid' and ".
" this_uuid='$this_uuid'");
" this_uuid='$target_uuid'");
return undef
if (!defined($query_result) || !$query_result->numrows);
my $row = $query_result->fetchrow_hashref();
my $credential =
GeniCredential->CreateFromSigned($row->{'credential_string'}, 1);
my $credential = GeniCredential->Create($this, $owner);
return undef
if (!defined($credential));
my $row = $query_result->fetchrow_hashref();
$credential->{'idx'} = $row->{'idx'};
$credential->{'string'} = $row->{'credential_string'};
if (ref($owner) eq "User") {
my $geniuser = GeniUser->CreateFromLocal($owner);
if (!defined($geniuser)) {
print STDERR "Could not create a geni user from $owner\n";
return undef;
}
$owner = $geniuser;
}
# Mark as coming from the DB.
$credential->{'idx'} = $row->{'idx'};
$credential->{'target'} = $target;
$credential->{'owner'} = $owner;
return $credential;
}
#
# Create an empty credential object.
#
sub Create($$$$)
{
my ($class, $this, $owner) = @_;
my ($class, $target, $owner) = @_;
return undef
if (! (ref($this) && ref($owner)));
if (! (ref($target) && ref($owner)));
my $self = {};
$self->{'this'} = $this;
$self->{'target'} = $target;
$self->{'owner'} = $owner;
$self->{'this_uuid'} = $this->uuid();
$self->{'target_uuid'} = $target->uuid();
$self->{'target_cert'} = $target->cert();
$self->{'owner_uuid'} = $owner->uuid();
$self->{'this_cert'} = $this->cert();
$self->{'owner_cert'} = $owner->cert();
$self->{'string'} = undef;
$self->{'capabilities'} = undef;
$self->{'idx'} = undef; # Only set when stored to DB.
......@@ -109,16 +125,28 @@ sub Create($$$$)
# accessors
sub field($$) { return ($_[0]->{$_[1]}); }
sub idx($) { return field($_[0], "idx"); }
sub this($) { return field($_[0], "this"); }
sub target($) { return field($_[0], "target"); }
sub owner($) { return field($_[0], "owner"); }
sub this_uuid($) { return field($_[0], "this_uuid"); }
sub target_uuid($) { return field($_[0], "this_uuid"); }
sub this_uuid($) { return field($_[0], "target_uuid"); }
sub target_uuid($) { return field($_[0], "target_uuid"); }
sub target_cert($) { return field($_[0], "target_cert"); }
sub owner_uuid($) { return field($_[0], "owner_uuid"); }
sub this_cert($) { return field($_[0], "this_cert"); }
sub owner_cert($) { return field($_[0], "owner_cert"); }
sub asString($) { return field($_[0], "string"); }
sub capabilities($) { return field($_[0], "capabilities"); }
#
# Stringify for output.
#
sub Stringify($)
{
my ($self) = @_;
my $target_uuid = $self->target_uuid();
my $owner_uuid = $self->owner_uuid();
return "[GeniCredential: $target_uuid, $owner_uuid]";
}
#
# Add a capability to the array.
#
......@@ -208,12 +236,12 @@ sub CreateFromSigned($$;$)
my $self = {};
$self->{'capabilities'} = $capabilities;
$self->{'this_uuid'} = $this_uuid;
$self->{'target_uuid'} = $this_uuid;
$self->{'target_cert'} = $this_cert;
$self->{'owner_uuid'} = $owner_uuid;
$self->{'this_cert'} = $this_cert;
$self->{'owner_cert'} = $owner_cert;
$self->{'string'} = $string;
$self->{'xmlref'} = $doc;
$self->{'target'} = undef;
$self->{'owner'} = undef;
$self->{'idx'} = undef; # Only set when stored to DB.
bless($self, $class);
......@@ -255,14 +283,26 @@ sub Sign($$)
}
# This little wrapup is for xmlout.
my $capabilities = {"capability" => $self->capabilities()};
my $cap_xml = XMLout($capabilities, "NoAttr" => 1);
$cap_xml =~ s/opt\>/capabilities\>/g;
# Every one gets a new unique index, which is used in the xml:id below.
my $idx = TBGetUniqueIndex('next_ticket', 1);
my $this_cert = $self->this_cert();
my $owner_cert = $self->owner_cert();
my $cap_xml = XMLout($capabilities, "NoAttr" => 1);
$cap_xml =~ s/opt\>/capabilities\>/g;
#
# Need the certificates for target and owner of the credential.
#
if (!defined($self->target())) {
print STDERR "No target object attached to $self\n";
return -1;
}
my $target_cert = $self->target()->cert();
if (!defined($self->owner())) {
print STDERR "No owner object attached to $self\n";
return -1;
}
my $owner_cert = $self->owner()->cert();
#
# Create a template xml file to sign.
......@@ -273,7 +313,7 @@ sub Sign($$)
" <type>capability</type>\n".
" <serial>$idx</serial>\n".
" <owner_uuid>$owner_cert</owner_uuid>\n".
" <this_uuid>$this_cert</this_uuid>\n".
" <this_uuid>$target_cert</this_uuid>\n".
" $cap_xml\n".
"</credential>\n";
......
......@@ -44,14 +44,11 @@ my $BOSSNODE = "@BOSSNODE@";
my $OURDOMAIN = "@OURDOMAIN@";
#
# Allocate the GENI slivers for an Emulab experiment. The nodes to be created
# are passed in, otherwise lookup the nodes for the experiment.
#
# XXX Need to deal with links between nodes.
# Initialize for using geni resources.
#
sub AllocateSlivers($$$)
sub Initialize($$$)
{
my ($class, $experiment, $nodelist) = @_;
my ($class, $experiment, $op) = @_;
my $thisuser = User->ThisUser();
#
......@@ -80,11 +77,30 @@ sub AllocateSlivers($$$)
}
#
# The slice should already be registered by this point, but it does
# not hurt anything to make sure.
# Create and register the slice.
#
my $slice = GeniSlice->Lookup($experiment->uuid());
my $slice = GeniSlice->LookupByExperiment($experiment);
if (defined($slice)) {
if ($op eq "swapin") {
#
# Remove from the clearing house.
#
print STDERR "Removing old slice for $experiment\n";
if ($slice->UnRegister()) {
print STDERR "Could not delete $slice from clearinghouse!\n";
return -1;
}
if ($slice->Delete()) {
print STDERR "Could not delete old $slice for $experiment!\n";
return -1;
}
undef($slice);
}
}
if (!defined($slice)) {
print STDERR "Creating new slice for $experiment\n";
$slice = GeniSlice->CreateFromLocal($experiment, $thisuser);
if (!defined($slice)) {
print STDERR
......@@ -98,6 +114,48 @@ sub AllocateSlivers($$$)
return -1;
}
}
return 0;
}
#
# Allocate the GENI slivers for an Emulab experiment. The nodes to be created
# are passed in, otherwise lookup the nodes for the experiment.
#
# XXX Need to deal with links between nodes.
#
sub AllocateSlivers($$$)
{
my ($class, $experiment, $nodelist) = @_;
my $thisuser = User->ThisUser();
#
# The RPC context for this test script is mostly as an SA.
#
Genixmlrpc->SetContext(Genixmlrpc->Context("@prefix@/etc/genisa.pem"));
#
# except when it has to be as the user.
#
my $context = Genixmlrpc->UserContext($thisuser);
#
# Create a Geni user from current user doing the operation.
#
my $geniuser = GeniUser->CreateFromLocal($thisuser);
if (!defined($geniuser)) {
print STDERR
"Could not create a geni user from current user $thisuser\n";
return -1;
}
#
# The slice should already be created and registered by this point.
#
my $slice = GeniSlice->LookupByExperiment($experiment);
if (!defined($slice)) {
print STDERR "Could not find a local slice record for $experiment\n";
return -1;
}
#
# Look for a credential. Should already exist, but if not, create one
......@@ -165,6 +223,8 @@ sub AllocateSlivers($$$)
#
# Get ticket from component.
#
print STDERR "Asking for ticket for $node from $component.\n";
my $ticket = $component->GetTicket($slice, $rspec,
$context, $credential);
......@@ -220,7 +280,7 @@ sub InstantiateSlivers($$$)
#
my $context = Genixmlrpc->UserContext($thisuser);
my $slice = GeniSlice->Lookup($experiment->uuid());
my $slice = GeniSlice->LookupByExperiment($experiment);
if (!defined($slice)) {
print STDERR "No slice exists for $experiment. \n";
return -1;
......@@ -253,10 +313,18 @@ sub InstantiateSlivers($$$)
}
my $component = $ticket->component();
#
# We need to pass in some extra stuff for Emulab federation.
#
my $args = {'tmcd_server' => $BOSSNODE,
'tmcd_nodeid' => $node->node_id() };
#
# Create sliver on component using the ticket.
#
$sliver = $component->CreateSliver($slice, $ticket, $context);
print STDERR "Redeeming ticket for $node on $component.\n";
$sliver = $component->CreateSliver($slice, $ticket, $context, $args);
if (!defined($sliver)) {
print STDERR "Could not create sliver on $component for $node\n";
if ($ticket->Delete() != 0) {
......@@ -303,7 +371,7 @@ sub StartSlivers($$$)
#
my $context = Genixmlrpc->UserContext($thisuser);
my $slice = GeniSlice->Lookup($experiment->uuid());
my $slice = GeniSlice->LookupByExperiment($experiment);
if (!defined($slice)) {
print STDERR "No slice exists for $experiment. \n";
return -1;
......@@ -324,9 +392,11 @@ sub StartSlivers($$$)
my $component = $sliver->GetComponent();
#
# Create sliver on component using the ticket.
# Start sliver on component using the ticket.
#
if ($component->StartSliver($slice, $sliver, $context) != 0) {
print STDERR "Starting $sliver on $component.\n";
if ($component->StartSliver($sliver, $context) != 0) {
print STDERR "Could not start $sliver on $component for $node\n";
return -1;
}
......@@ -353,7 +423,7 @@ sub DestroySlivers($$$)
#
my $context = Genixmlrpc->UserContext($thisuser);
my $slice = GeniSlice->Lookup($experiment->uuid());
my $slice = GeniSlice->LookupByExperiment($experiment);
if (!defined($slice)) {
print STDERR "No local slice record for $experiment\n";
return -1;
......@@ -380,12 +450,27 @@ sub DestroySlivers($$$)
"Could not find ticket for $node in $experiment\n";
$errors++;
}
elsif ($ticket->Delete() != 0) {
print STDERR "Could not delete $ticket\n";
$errors++;
else {
my $component = $ticket->component();
#
# Release the ticket.
#
print STDERR "Releasing $ticket for $node on $component.\n";
if ($component->ReleaseTicket($slice, $context, $ticket) != 0){
print STDERR "Could not release $ticket on $component\n";
$errors++;
}
if ($ticket->Delete() != 0) {
print STDERR "Could not delete $ticket\n";
$errors++;
}
}
next;
}
print STDERR "Releasing $sliver for $node.\n";
if ($sliver->Destroy() != 0) {
print STDERR "Could not destroy $sliver for $node\n";
$errors++;
......
......@@ -74,7 +74,7 @@ sub Lookup($$)
($idx) = $query_result->fetchrow_array();
}
elsif ($token =~ /^[\w\.]*$/) {
elsif ($token =~ /^[-\w\.]*$/) {
$query_result =
DBQueryWarn("select idx from geni_slices ".
"where hrn='$token'");
......@@ -125,8 +125,10 @@ sub uuid($) { return field($_[0], "uuid"); }
sub creator_uuid($) { return field($_[0], "creator_uuid"); }
sub created($) { return field($_[0], "created"); }
sub sa_uuid($) { return field($_[0], "sa_uuid"); }
sub exptidx($) { return field($_[0], "exptidx"); }
sub cert($) { return $_[0]->{'CERT'}->cert(); }
sub GetCertificate($) { return $_[0]->{'CERT'}; }
#
# Stringify for output.
#
......@@ -140,6 +142,24 @@ sub Stringify($)
return "[GeniSlice: $hrn, IDX: $idx]";
}
#
# Lookup slice by the experiment it is related to.
#
sub LookupByExperiment($$)
{
my ($class, $experiment) = @_;
my $exptidx = $experiment->idx();
my $query_result =
DBQueryWarn("select idx from geni_slices ".
"where exptidx='$exptidx'");
return undef
if (!defined($query_result) || !$query_result->numrows);
my ($idx) = $query_result->fetchrow_array();
return GeniSlice->Lookup($idx);
}
#
# Class method to check for an existing user that has the same
# uid/email. Lets not allow this for now. Return the number of
......@@ -164,9 +184,10 @@ sub CheckExisting($$$)
#
# Class function to create new Geni slice and return the object.
#
sub Create($$$$$$)
sub Create($$$$$$;$)
{
my ($class, $hrn, $uuid, $creator_uuid, $certificate, $authority) = @_;
my ($class, $hrn, $uuid, $creator_uuid, $certificate,
$authority, $exptidx) = @_;
my @insert_data = ();
# Every slice gets a new unique index.
......@@ -182,6 +203,8 @@ sub Create($$$$$$)
push(@insert_data, "created=now()");