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

Checkpoint more of version two API.

parent 27aed939
......@@ -348,6 +348,10 @@ sub GetTicket($;$)
if (!defined($rspecstr)) {
return GeniResponse->MalformedArgsResponse();
}
if (! ($rspecstr =~ /^[\040-\176\012\015\011]+$/)) {
return GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
"Improper characters in rspec");
}
my $credential = GeniCredential->CreateFromSigned($credstr);
if (!defined($credential)) {
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
......@@ -369,16 +373,13 @@ sub GetTicket($;$)
$ticket->SetSlice($credential->target_uuid());
}
return GetTicketAux($credential,
$rspecstr, $isupdate, $impotent, 0, $ticket);
$rspecstr, $isupdate, $impotent, 0, 1, $ticket);
}
sub GetTicketAux($$$$$$)
sub GetTicketAux($$$$$$$)
{
my ($credential, $rspec_string, $isupdate, $impotent, $v2, $ticket) = @_;
my $owner_uuid = $ENV{'GENIUSER'};
my $response = undef;
my $restorevirt = 0; # Flag to restore virtual state
my $restorephys = 0; # Flag to restore physical state
my ($credential, $rspecstr, $isupdate, $impotent, $v2, $level,
$ticket) = @_;
defined($credential) &&
($credential->HasPrivilege( "pi" ) or
......@@ -386,35 +387,10 @@ sub GetTicketAux($$$$$$)
$credential->HasPrivilege( "bind" ) or
return GeniResponse->Create( GENIRESPONSE_FORBIDDEN, undef,
"Insufficient privilege" ));
if (! ($rspec_string =~ /^[\040-\176\012\015\011]+$/)) {
return GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
"Improper characters in rspec");
}
my $rspec =
eval { XMLin($rspec_string, KeyAttr => [],
ForceArray => ["node", "link", "interface",
"interface_ref", "linkendpoints"]) };
if ($@) {
print STDERR "XMLin error: $@\n";
return GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
"XML error in rspec");
}
my $slice_uuid = $credential->target_uuid();
my $user_uuid = $credential->owner_uuid();
print STDERR $credential->target_cert() . "\n";
print STDERR $credential->owner_cert() . "\n";
#
# We need this below to sign the ticket.
#
my $authority = GeniCertificate->LoadFromFile($EMULAB_PEMFILE);
if (!defined($authority)) {
print STDERR " Could not get uuid from $EMULAB_PEMFILE\n";
return GeniResponse->Create(GENIRESPONSE_ERROR);
}
#
# Create slice from the certificate.
#
......@@ -450,6 +426,35 @@ sub GetTicketAux($$$$$$)
"Could not get user info from ClearingHouse");
}
}
return GetTicketAuxAux($slice, $user, $rspecstr,
$isupdate, $impotent, $v2, $level, $ticket);
}
sub GetTicketAuxAux($$$$$$$$)
{
my ($slice, $user,
$rspecstr, $isupdate, $impotent, $v2, $level, $ticket) = @_;
my $response = undef;
my $restorevirt = 0; # Flag to restore virtual state
my $restorephys = 0; # Flag to restore physical state
#
# We need this below to sign the ticket.
#
my $authority = GeniCertificate->LoadFromFile($EMULAB_PEMFILE);
if (!defined($authority)) {
print STDERR " Could not get uuid from $EMULAB_PEMFILE\n";
return GeniResponse->Create(GENIRESPONSE_ERROR);
}
my $rspec =
eval { XMLin($rspecstr, KeyAttr => [],
ForceArray => ["node", "link", "interface",
"interface_ref", "linkendpoints"]) };
if ($@) {
print STDERR "XMLin error: $@\n";
return GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
"XML error in rspec");
}
#
# A sitevar controls whether external users can get any nodes.
......@@ -526,14 +531,19 @@ sub GetTicketAux($$$$$$)
# For now, there can be only a single toplevel aggregate per slice.
# The existence of an aggregate means the slice is active here.
#
my $aggregate = GeniAggregate->SliceAggregate($slice);
if (!$isupdate) {
my $aggregate = GeniAggregate->SliceAggregate($slice);
if (defined($aggregate)) {
$response = GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
"Already have an aggregate for slice");
goto bad;
}
}
elsif ($v2 && $level && !defined($ticket) && !defined($aggregate)) {
print STDERR "No aggregate for $slice in version two API\n";
$response = GeniResponse->Create(GENIRESPONSE_ERROR);
goto bad;
}
#
# Firewall hack; just a flag in the rspec for now.
......@@ -623,8 +633,15 @@ sub GetTicketAux($$$$$$)
$response = GeniResponse->Create(GENIRESPONSE_ERROR);
goto bad;
}
my $oldrspec;
if ($v2 && defined($aggregate)) {
$oldrspec = $aggregate->GetManifest(0);
}
else {
$oldrspec = $ticket->rspec();
}
foreach my $ref (@{$ticket->rspec()->{'node'}}) {
foreach my $ref (@{$oldrspec->{'node'}}) {
my $resource_uuid = $ref->{'component_uuid'} || $ref->{'uuid'};
my $manager_uuid = $ref->{'component_manager_uuid'};
my $node_nickname = $ref->{'virtual_id'} || $ref->{'nickname'};
......@@ -1155,9 +1172,9 @@ sub GetTicketAux($$$$$$)
}
#
# For the version 2 API, just return the annotated rspec.
# For the version 2 minimal API, just return the annotated rspec.
#
if ($v2) {
if ($v2 && $level == 0) {
# Bad, should leave it locked, but Redeem below would fail, and
# this whole arrangement is temporary, so lets not worry about it.
$slice->UnLock();
......@@ -1174,7 +1191,7 @@ sub GetTicketAux($$$$$$)
"Could not create GeniTicket object");
goto bad;
}
$newticket->SetSlice($slice_uuid);
$newticket->SetSlice($slice->uuid());
if ($newticket->Sign()) {
$response = GeniResponse->Create(GENIRESPONSE_ERROR, undef,
......@@ -1187,7 +1204,7 @@ sub GetTicketAux($$$$$$)
goto bad;
}
if ($isupdate) {
if ($isupdate && defined($ticket)) {
#
# Delete (not release) the old ticket.
#
......@@ -1234,7 +1251,7 @@ sub GetTicketAux($$$$$$)
$slice_experiment->RemoveVirtualState()
if (defined($slice_experiment));
}
if ($v2) {
if ($v2 && $level == 0) {
CleanupDeadSlice($slice, 1)
if (defined($slice));
return $response;
......@@ -1316,19 +1333,20 @@ sub SliverWork($$)
return GeniResponse->Create(GENIRESPONSE_FORBIDDEN, undef,
"This ticket is for another authority!");
}
return SliverWorkAux($credential, $ticket, $keys, $isupdate, $impotent, 0);
return SliverWorkAux($credential, $ticket,
$keys, $isupdate, $impotent, 0, 0);
}
sub SliverWorkAux($$$$$$)
sub SliverWorkAux($$$$$$$)
{
my ($credential, $object, $keys, $isupdate, $impotent, $v2) = @_;
my ($credential, $object, $keys, $isupdate, $impotent, $v2, $level) = @_;
my $didfwsetup = 0;
my $restorephys = 0; # Flag to restore physical state
my $ticket;
my $rspec;
# V2 API support.
if ($v2) {
if ($v2 && $level == 0) {
$rspec = $object;
}
else {
......@@ -2502,19 +2520,6 @@ sub DeleteSliverAux($$$)
return GeniResponse->BusyResponse();
}
#
# In the V2 api, cleanup the entire slice and return.
#
if ($v2) {
if (CleanupDeadSlice($slice) != 0) {
$slice->UnLock();
print STDERR "DeleteSliver: CleanupDeadSlice failed\n";
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Could not delete sliver");
}
return GeniResponse->Create(GENIRESPONSE_SUCCESS);
}
my $experiment = $slice->GetExperiment();
my $pid = $experiment->pid();
my $eid = $experiment->eid();
......@@ -2540,7 +2545,7 @@ sub DeleteSliverAux($$$)
goto bad;
}
}
if ($aggregate->UnProvision() != 0) {
if ($aggregate->UnProvision($v2) != 0) {
$response =
GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Could not unprovision sliver");
......@@ -2551,13 +2556,28 @@ sub DeleteSliverAux($$$)
"Could not delete sliver");
goto bad;
}
DBQueryWarn("delete from geni_manifests ".
"where slice_uuid='$slice_uuid'");
$experiment->RemovePhysicalState();
$experiment->SetState(EXPTSTATE_SWAPPED());
if (system("$EXPORTS_SETUP")) {
print STDERR "$EXPORTS_SETUP failed\n";
}
if (system("$NAMEDSETUP")) {
print STDERR "$NAMEDSETUP failed\n";
}
#
# In the v2 API, caller returns a new ticket for the resources
# (which were not released).
#
if ($v2) {
# Slice still locked.
return 0;
}
$experiment->RemoveVirtualState();
$experiment->RemovePhysicalState();
DBQueryWarn("delete from geni_manifests ".
"where slice_uuid='$slice_uuid'");
}
$experiment->SetState(EXPTSTATE_SWAPPED());
$slice->UnLock();
return GeniResponse->Create(GENIRESPONSE_SUCCESS);
......
......@@ -102,6 +102,7 @@ sub Resolve($)
my ($argref) = @_;
my $credentials = $argref->{'credentials'};
my $urn = $argref->{'urn'};
my $admin = 0;
if (! (defined($credentials) && defined($urn))) {
return GeniResponse->MalformedArgsResponse("Missing arguments");
......@@ -119,6 +120,16 @@ sub Resolve($)
"Authority mismatch")
if ($auth ne $OURDOMAIN);
$type = lc($type);
#
# This is a convenience for testing. If a local user and that
# user is an admin person, then do whatever it says. This is
# easier then trying to do this with credential privs.
#
my $user = GeniUser->Lookup($credential->owner_uuid(), 1);
if (defined($user) && $user->IsLocal() && $user->admin()) {
$admin = 1;
}
if ($type eq "node") {
my $node = GeniCM::LookupNode($urn);
......@@ -156,7 +167,7 @@ sub Resolve($)
# In this implementation, the caller must hold a valid slice
# credential for the slice being looked up.
#
if ($slice->uuid() ne $credential->target_uuid()) {
if (! ($admin || $slice->uuid() eq $credential->target_uuid())) {
return GeniResponse->Create(GENIRESPONSE_FORBIDDEN());
}
# Return a blob.
......@@ -164,13 +175,11 @@ sub Resolve($)
my $aggregate = GeniAggregate->SliceAggregate($slice);
if (defined($aggregate)) {
$blob->{'sliver_urn'} =
GeniHRN::Generate($OURDOMAIN, "sliver", $aggregate->idx());
$blob->{'sliver_urn'} = $aggregate->urn();
}
my $ticket = GeniTicket->SliceTicket($slice);
if (defined($ticket)) {
$blob->{'ticket_urn'} =
GeniHRN::Generate($OURDOMAIN, "ticket", $ticket->idx());
$blob->{'ticket_urn'} = $ticket->urn();
}
return GeniResponse->Create(GENIRESPONSE_SUCCESS, $blob);
}
......@@ -184,11 +193,12 @@ sub Resolve($)
# In this implementation, the caller must hold a valid slice
# or sliver credential for the slice being looked up.
#
if (! ($aggregate->uuid() eq $credential->target_uuid() ||
if (! ($admin ||
$aggregate->uuid() eq $credential->target_uuid() ||
$aggregate->slice_uuid() eq $credential->target_uuid())) {
return GeniResponse->Create(GENIRESPONSE_FORBIDDEN);
}
my $manifest = $aggregate->GetManifest();
my $manifest = $aggregate->GetManifest(1);
if (!defined($aggregate)) {
return GeniResponse->Create(GENIRESPONSE_ERROR);
}
......@@ -213,7 +223,7 @@ sub Resolve($)
print STDERR "Could not find slice for $ticket\n";
return GeniResponse->Create(GENIRESPONSE_ERROR);
}
if ($slice->uuid() ne $credential->target_uuid()) {
if (! ($admin || $slice->uuid() eq $credential->target_uuid())) {
#
# See if its the sliver credential.
#
......@@ -262,20 +272,43 @@ sub CreateSliver($)
my $impotent = $argref->{'impotent'} || 0;
# For now, I am not worrying about the slice_urn argument.
if (! (defined($credentials) && defined($rspecstr))) {
if (! (defined($credentials) &&
defined($slice_urn) && defined($rspecstr))) {
return GeniResponse->MalformedArgsResponse("Missing arguments");
}
if (! ($rspecstr =~ /^[\040-\176\012\015\011]+$/)) {
return GeniResponse->MalformedArgsResponse("Bad characters in rspec");
}
if (! GeniHRN::IsValid($slice_urn)) {
return GeniResponse->MalformedArgsResponse("Bad characters in URN");
}
my $credential = CheckCredentials($credentials);
return $credential
if (GeniResponse::IsResponse($credential));
#
# In this implementation, the user must provide a slice credential,
# so we ignore the slice_urn. For CreateSliver(), the slice must not
# be instantiated.
#
my ($slice,$aggregate) = Credential2SliceAggregate($credential);
if (defined($slice)) {
if ($slice_urn ne $slice->urn()) {
return GeniResponse->Create(GENIRESPONSE_FORBIDDEN(), undef,
"Credential does not match the URN");
}
if (defined($aggregate)) {
return GeniResponse->Create(GENIRESPONSE_REFUSED, undef,
"Must delete existing slice first");
}
}
my $rspec = GeniCM::GetTicketAux($credential,
$rspecstr, 0, $impotent, 1, undef);
$rspecstr, 0, $impotent, 1, 0, undef);
return $rspec
if (GeniResponse::IsResponse($rspec));
my $response = GeniCM::SliverWorkAux($credential,
$rspec, $keys, 0, $impotent, 1);
$rspec, $keys, 0, $impotent, 1, 0);
if (GeniResponse::IsError($response)) {
#
......@@ -296,7 +329,7 @@ sub CreateSliver($)
#
# Leave the slice intact on error, so we can go look at it.
#
my $slice = GeniSlice->Lookup($credential->target_uuid());
$slice = GeniSlice->Lookup($credential->target_uuid());
if (!defined($slice)) {
print STDERR "CreateSliver: Could not find slice for $credential\n";
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
......@@ -307,7 +340,7 @@ sub CreateSliver($)
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Internal Error");
}
my $aggregate = GeniAggregate->SliceAggregate($slice);
$aggregate = GeniAggregate->SliceAggregate($slice);
if (!defined($aggregate)) {
print STDERR "CreateSliver: Could not find aggregate for $slice\n";
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
......@@ -325,21 +358,148 @@ sub CreateSliver($)
# Delete a Sliver.
#
sub DeleteSliver($)
{
my ($argref) = @_;
my $sliver_urn = $argref->{'sliver_urn'};
my $credentials = $argref->{'credentials'};
my $impotent = $argref->{'impotent'} || 0;
if (! (defined($credentials) && defined($sliver_urn))) {
return GeniResponse->MalformedArgsResponse("Missing arguments");
}
if (! GeniHRN::IsValid($sliver_urn)) {
return GeniResponse->MalformedArgsResponse("Bad characters in URN");
}
my $credential = CheckCredentials($credentials);
return $credential
if (GeniResponse::IsResponse($credential));
#
# In this implementation, the user must provide a slice or sliver
# credential
#
my ($slice, $aggregate) = Credential2SliceAggregate($credential);
if (! (defined($slice) && defined($aggregate))) {
return GeniResponse->Create(GENIRESPONSE_SEARCHFAILED, undef,
"Sliver does not exist");
}
if ($sliver_urn ne $aggregate->urn()) {
return GeniResponse->Create(GENIRESPONSE_FORBIDDEN(), undef,
"Credential does not match the URN");
}
#
# We need this below to sign the ticket.
#
my $authority = GeniCertificate->LoadFromFile($EMULAB_PEMFILE);
if (!defined($authority)) {
print STDERR " Could not get uuid from $EMULAB_PEMFILE\n";
return GeniResponse->Create(GENIRESPONSE_ERROR);
}
#
# We need the user to sign the new ticket to.
#
my $user = GeniUser->Lookup($credential->owner_uuid(), 1);
if (!defined($user)) {
$user = GeniCM::CreateUserFromCertificate($credential->owner_cert());
if (!defined($user)) {
print STDERR "Could not create user from $credential\n";
return GeniResponse->Create(GENIRESPONSE_ERROR);
}
}
my $response = GeniCM::DeleteSliverAux($credential, $impotent, 1);
return $response
if (GeniResponse::IsResponse($response));
#
# In the v2 API, return a new ticket for the resources
# (which were not released). As with all tickets, it will
# expire very quickly.
#
#
# Create a new ticket from the manifest.
#
my $manifest = $aggregate->GetManifest(0);
if (!defined($manifest)) {
print STDERR "No manifest found for $aggregate\n";
$response = GeniResponse->Create(GENIRESPONSE_ERROR);
goto bad;
}
my $ticket = GeniTicket->Create($authority, $user, $manifest);
if (!defined($ticket)) {
print STDERR "Could not create new ticket for $slice\n";
$response = GeniResponse->Create(GENIRESPONSE_ERROR);
goto bad;
}
$ticket->SetSlice($slice->uuid());
if ($ticket->Sign()) {
$ticket->Delete();
print STDERR "Could not sign new ticket $ticket\n";
$response = GeniResponse->Create(GENIRESPONSE_ERROR);
goto bad;
}
if ($ticket->Store()) {
$ticket->Delete();
print STDERR "Could not store new ticket $ticket\n";
$response = GeniResponse->Create(GENIRESPONSE_ERROR);
goto bad;
}
my $slice_uuid = $slice->uuid();
DBQueryWarn("delete from geni_manifests ".
"where slice_uuid='$slice_uuid'");
$slice->UnLock();
return GeniResponse->Create(GENIRESPONSE_SUCCESS, $ticket->asString());
bad:
if (GeniCM::CleanupDeadSlice($slice) != 0) {
print STDERR "Could not cleanup slice\n";
}
return $response;
}
#
# Delete a Slice
#
sub DeleteSlice($)
{
my ($argref) = @_;
my $slice_urn = $argref->{'slice_urn'};
my $credentials = $argref->{'credentials'};
my $impotent = $argref->{'impotent'} || 0;
# For now, I am not worrying about the slice_urn argument.
if (! (defined($credentials))) {
if (! (defined($credentials) && defined($slice_urn))) {
return GeniResponse->MalformedArgsResponse("Missing arguments");
}
if (! GeniHRN::IsValid($slice_urn)) {
return GeniResponse->MalformedArgsResponse("Bad characters in URN");
}
my $credential = CheckCredentials($credentials);
return $credential
if (GeniResponse::IsResponse($credential));
return GeniCM::DeleteSliverAux($credential, $impotent, 1);
#
# In this implementation, the user must provide a slice credential.
#
my ($slice, $aggregate) = Credential2SliceAggregate($credential);
if (! defined($slice)) {
return GeniResponse->Create(GENIRESPONSE_SEARCHFAILED, undef,
"No such slice here");
}
if ($slice_urn ne $slice->urn()) {
return GeniResponse->Create(GENIRESPONSE_FORBIDDEN(), undef,
"Credential does not match the URN");
}
if ($slice->Lock() != 0) {
return GeniResponse->BusyResponse();
}
if (GeniCM::CleanupDeadSlice($slice) != 0) {
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Could not cleanup slice");
}
return GeniResponse->Create(GENIRESPONSE_SUCCESS);
}
#
......@@ -351,29 +511,43 @@ sub GetSliver($)
my $slice_urn = $argref->{'slice_urn'};
my $credentials = $argref->{'credentials'};
# For now, I am not worrying about the slice_urn argument.
if (! (defined($credentials))) {
if (! (defined($credentials) && defined($slice_urn))) {
return GeniResponse->MalformedArgsResponse("Missing arguments");
}
if (! GeniHRN::IsValid($slice_urn)) {
return GeniResponse->MalformedArgsResponse("Bad characters in URN");
}
my $credential = CheckCredentials($credentials);
return $credential
if (GeniResponse::IsResponse($credential));
#
# In this implementation, the user must provide a slice credential.
#
my ($slice, $aggregate) = Credential2SliceAggregate($credential);
if (! (defined($slice) && defined($aggregate))) {
return GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
"No slice or aggregate here");
}
if ($slice_urn ne $slice->urn()) {
return GeniResponse->Create(GENIRESPONSE_FORBIDDEN(), undef,
"Credential does not match the URN");
}
return GeniCM::GetSliverAux($credential);
}
#
# Get sliver status
# Start a sliver (not sure what this means yet, so reboot for now).
#
sub SliverStatus($)
sub StartSliver($)
{
my ($argref) = @_;
my $slice_urn = $argref->{'slice_urn'};
my $sliver_urns = $argref->{'component_urns'};
my $credentials = $argref->{'credentials'};
my $aggregate;
# For now, I am not worrying about the slice_urn argument.
if (! (defined($credentials))) {
if (! (defined($credentials) &&
(defined($slice_urn) || defined($sliver_urns)))) {
return GeniResponse->MalformedArgsResponse("Missing arguments");
}
my $credential = CheckCredentials($credentials);
......@@ -388,38 +562,75 @@ sub SliverStatus($)
#
# For now, only allow top level aggregate or the slice
#
my $slice = GeniSlice->Lookup($credential->target_uuid());
if (!defined($slice)) {