Commit 85cb063b authored by Leigh Stoller's avatar Leigh Stoller

Two co-mingled sets of changes:

1) Implement the latest dataset read/write access settings from frontend to
   backend. Also updates for simultaneous read-only usage.

2) New configure options: PROTOGENI_LOCALUSER and PROTOGENI_GENIWEBLOGIN.

   The first changes the way that projects and users are treated at the
   CM. When set, we create real accounts (marked as nonlocal) for users and
   also create real projects (also marked as nonlocal). Users are added to
   those projects according to their credentials. The underlying experiment
   is thus owned by the user and in the project, although all the work is
   still done by the geniuser pseudo user. The advantage of this approach
   is that we can use standard emulab access checks to control access to
   objects like datasets. Maybe images too at some point.

   NOTE: Users are not removed from projects once they are added; we are
   going to need to deal with this, perhaps by adding an expiration stamp
   to the groups_membership tables, and using the credential expiration to
   mark it.

   The second new configure option turns on the web login via the geni
   trusted signer. So, if I create a sliver on a backend cluster when both
   options are set, I can use the trusted signer to log into my newly
   created account on the cluster, and see it (via the emulab classic web
   interface).

   All this is in flux, might end up being a bogus approach in the end.
parent 8741f48a
......@@ -52,6 +52,9 @@ my $TB = "@prefix@";
my $TBOPS = "@TBOPSEMAIL@";
my $OURDOMAIN = "@OURDOMAIN@";
# Debugging
my $usemydevtree = 0;
#
# Lookup by uuid.
#
......@@ -83,6 +86,27 @@ sub Lookup($$;$)
return $self;
}
#
# Lookup by remote URN.
#
sub LookupByRemoteURN($$)
{
my ($class, $urn) = @_;
return undef
if (!GeniHRN::IsValid($urn));
my $safe_urn = DBQuoteSpecial($urn);
my $query_result =
DBQueryWarn("select uuid from apt_datasets ".
"where remote_urn=$safe_urn");
return undef
if (!$query_result || !$query_result->numrows);
my ($uuid) = $query_result->fetchrow_array();
return Lookup($class, $uuid);
}
AUTOLOAD {
my $self = $_[0];
my $type = ref($self) or croak "$self is not an object";
......@@ -108,9 +132,10 @@ sub DESTROY {
sub ValidBlockstoreBackend($)
{
my ($authority) = @_;
my ($domain,$subauth) = split(":", $authority);
return 1
if ($authority eq "emulab.net" || $authority eq "apt.emulab.net");
if ($domain eq "emulab.net" || $domain eq "apt.emulab.net");
return 0;
}
......@@ -431,6 +456,8 @@ sub CreateDataset($)
"size" => $self->size(),
"name" => $self->dataset_id(),
"type" => $self->type(),
"read_access" => $self->read_access(),
"write_access"=> $self->write_access(),
"credentials" => [$credential->asString(),
$speaksfor_credential->asString()],
};
......@@ -440,7 +467,7 @@ sub CreateDataset($)
if (defined($self->expires()));
my $cmurl = $authority->url();
# $cmurl =~ s/protogeni/protogeni\/stoller/;
$cmurl =~ s/protogeni/protogeni\/stoller/ if ($usemydevtree);
return Genixmlrpc::CallMethod($cmurl, $context, "CreateDataset", $args);
}
......@@ -471,7 +498,7 @@ sub DeleteDataset($)
$speaksfor_credential->asString()],
};
my $cmurl = $authority->url();
# $cmurl =~ s/protogeni/protogeni\/stoller/;
$cmurl =~ s/protogeni/protogeni\/stoller/ if ($usemydevtree);
return Genixmlrpc::CallMethod($cmurl, $context, "DeleteDataset", $args);
}
......@@ -498,15 +525,13 @@ sub ModifyDataset($)
my $args = {
"name" => $self->dataset_id(),
"read_access" => $self->read_access(),
"write_access"=> $self->write_access(),
"credentials" => [$credential->asString(),
$speaksfor_credential->asString()],
};
# This is all we can change right now.
$args->{"expires"} = emutil::TBDateStringGMT($self->expires())
if (defined($self->expires()));
my $cmurl = $authority->url();
# $cmurl =~ s/protogeni/protogeni\/stoller/;
$cmurl =~ s/protogeni/protogeni\/stoller/ if ($usemydevtree);
return Genixmlrpc::CallMethod($cmurl, $context, "ModifyDataset", $args);
}
......@@ -538,7 +563,7 @@ sub ExtendDataset($)
"extend" => 1,
};
my $cmurl = $authority->url();
# $cmurl =~ s/protogeni/protogeni\/stoller/;
$cmurl =~ s/protogeni/protogeni\/stoller/ if ($usemydevtree);
return Genixmlrpc::CallMethod($cmurl, $context, "ModifyDataset", $args);
}
......@@ -569,7 +594,7 @@ sub DescribeDataset($)
$speaksfor_credential->asString()],
};
my $cmurl = $authority->url();
# $cmurl =~ s/protogeni/protogeni\/stoller/;
$cmurl =~ s/protogeni/protogeni\/stoller/ if ($usemydevtree);
return Genixmlrpc::CallMethod($cmurl, $context, "DescribeDataset", $args);
}
......
......@@ -887,8 +887,11 @@ sub CheckDatasets($$$)
}
my $dataset = APT_Dataset->Lookup("$pid/$id");
if (!defined($dataset)) {
$$pmsg = "Persistent dataset '$pid/$id' does not exist";
return 1;
$dataset = APT_Dataset->LookupByRemoteURN($leaseurn);
if (!defined($dataset)) {
$$pmsg = "Persistent dataset '$pid/$id' does not exist";
return 1;
}
}
#
......@@ -898,20 +901,15 @@ sub CheckDatasets($$$)
# settings.
#
my ($d_authority) = GeniHRN::Parse($dataset->aggregate_urn());
if ($d_authority ne $authority) {
my ($domain,$subauth) = split(":", $authority);
if ($domain ne $d_authority) {
$$pmsg = "Persistent dataset '$pid/$id' in not on $authority";
return 1;
}
#
# Basic permission checks, very little support at the moment.
# Just make sure that the profile and the dataset are in the
# same pid.
# XXX Need basic frontend permission checks?
#
if ($ppid ne $dataset->pid()) {
$$pmsg = "Not allowed to use dataset '$pid/$id' in profile";
return 1;
}
}
}
return 0;
......
......@@ -91,6 +91,7 @@ $| = 1;
# Load the Testbed support stuff.
use lib "@prefix@/lib";
use EmulabConstants;
use libtestbed;
use libaudit;
use APT_Profile;
......@@ -98,6 +99,7 @@ use APT_Instance;
use APT_Geni;
use APT_Dataset;
use User;
use Project;
use OSinfo;
use emutil;
use GeniDB;
......@@ -251,7 +253,7 @@ foreach my $key ("username", "email", "profile") {
#
# Gather up args and sanity check.
#
my ($value, $user_urn, $user_uid, $user_hrn, $user_email,
my ($value, $user_urn, $user_uid, $user_hrn, $user_email, $project, $pid,
$sshkey, $profile, $profileid, $version, $rspecstr, $errmsg);
#
......@@ -456,6 +458,9 @@ if ($localuser) {
if (0) {
fatal("Could not update ssh keys for nonlocal user");
}
# Nonlocal users get the holding project.
$pid = "CloudLab";
}
elsif (defined($sshkey) && !$emulab_user->LookupSSHKey($sshkey)) {
#
......@@ -492,15 +497,32 @@ if ($localuser) {
$emulab_user->GenEncryptedCert()) {
fatal("Could not (re)generate encrypted certificate");
}
}
elsif (!$localuser && defined($sshkey)) {
#
# Guest user; remember key. For now we accept only one key. We store
# it simply so we can display it again for the user in the web interface.
# We allow key reuse for existing users, see above.
#
$geniuser->DeleteKeys();
$geniuser->AddKey($sshkey);
# Local users are required to select a project.
if (! exists($xmlparse->{'attribute'}->{"pid"})) {
fatal("No project provided for new instance");
}
$project = Project->Lookup($xmlparse->{'attribute'}->{"pid"}->{"value"});
if (!defined($project)) {
fatal("Project provided does not exist");
}
if (!$project->AccessCheck($emulab_user, TB_PROJECT_CREATEEXPT)) {
fatal("No permission to create experiments in project $pid");
}
$pid = $project->pid();
}
elsif (!$localuser) {
if (defined($sshkey)) { #
# Guest user; remember key. For now we accept only one key. We store
# it simply so we can display it again for the user in the web
# interface. We allow key reuse for existing users, see
# above.
#
$geniuser->DeleteKeys();
$geniuser->AddKey($sshkey);
}
# Guest users get a holding project.
$pid = "aptguests";
}
# There will be "internal" keys cause we pass the flag asking for them.
my @sshkeys;
......@@ -511,19 +533,22 @@ if ($geniuser->GetKeyBundle(\@sshkeys, 1) < 0 || !@sshkeys) {
# Generate the extra credentials that tells the backend this experiment
# can access the datasets.
my @dataset_credentials = ();
if (defined($profile) &&
CreateDatasetCreds($rspecstr,
$profile->pid(), $geniuser,
\$errmsg, \@dataset_credentials)) {
fatal($errmsg);
if (defined($profile)) {
my $retval = CreateDatasetCreds($rspecstr,
$profile->pid(), $geniuser,
\$errmsg, \@dataset_credentials);
if ($retval) {
($retval < 0 ? fatal($errmsg) : UserError($errmsg));
}
}
#
#
# Now generate a slice registration and credential
#
my $safe_uid = $user_uid; $safe_uid =~ s/_/-/;
my $slice_id = $safe_uid . "-QV" . TBGetUniqueIndex('next_quickvm', 1);
my $slice_urn = GeniHRN::Generate($OURDOMAIN, "slice", $slice_id);
my $slice_urn = GeniHRN::Generate("${OURDOMAIN}:${pid}", "slice", $slice_id);
my $slice_hrn = "${PGENIDOMAIN}.${slice_id}";
my $SERVER_NAME = (exists($ENV{"SERVER_NAME"}) ? $ENV{"SERVER_NAME"} : "");
......@@ -590,16 +615,22 @@ my $quickvm_uuid = (defined($quickuuid) ? $quickuuid : NewUUID());
if (!defined($quickvm_uuid)) {
fatal("Could not generate a new uuid");
}
my $instance = APT_Instance->Create({'uuid' => $quickvm_uuid,
'profile_id' => $profileid,
'profile_version' => $version,
'slice_uuid' => $slice_uuid,
'creator' => $geniuser->uid(),
'creator_idx' => $geniuser->idx(),
'creator_uuid' => $geniuser->uuid(),
'aggregate_urn'=> $CMURN,
'status' => "created",
'servername' => $SERVER_NAME});
my $blob = {'uuid' => $quickvm_uuid,
'profile_id' => $profileid,
'profile_version' => $version,
'slice_uuid' => $slice_uuid,
'creator' => $geniuser->uid(),
'creator_idx' => $geniuser->idx(),
'creator_uuid' => $geniuser->uuid(),
'aggregate_urn'=> $CMURN,
'status' => "created",
'servername' => $SERVER_NAME
};
if (defined($project)) {
$blob->{"pid"} = $project->pid();
$blob->{"pid_idx"} = $project->pid_idx();
}
my $instance = APT_Instance->Create($blob);
if (!defined($instance)) {
$slice->Delete();
fatal("Could not create instance record for $quickvm_uuid");
......@@ -796,8 +827,11 @@ sub CreateDatasetCreds($$$$$)
}
my $dataset = APT_Dataset->Lookup("$pid/$id");
if (!defined($dataset)) {
$$pmsg = "Persistent dataset '$pid/$id' does not exist";
return 1;
$dataset = APT_Dataset->LookupByRemoteURN($leaseurn);
if (!defined($dataset)) {
$$pmsg = "Persistent dataset '$pid/$id' does not exist";
return 1;
}
}
my $certificate = $dataset->GetCertificate();
if (!defined($certificate)) {
......
#!/usr/bin/perl -w
#
# Copyright (c) 2000-2014 University of Utah and the Flux Group.
# Copyright (c) 2000-2015 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
......@@ -155,7 +155,8 @@ sub DoCreate()
{
my $usage = sub {
print STDERR "Usage: manage_dataset create ".
"[-t type] [-f fstype] [-e expiration] [-p privacy] ".
"[-t type] [-f fstype] [-e expiration] ".
"[-R global|project] [-W creator|project] ".
"-s size pid/name\n";
exit(-1);
};
......@@ -164,12 +165,13 @@ sub DoCreate()
my $errmsg;
my $pid;
my $expires;
my $privacy = "private";
my $size;
my $type = "stdataset";
my $fstype;
my $read_access;
my $write_access;
my $optlist = "ds:t:e:f:w:p:";
my $optlist = "ds:t:e:f:w:p:R:W:";
my %options = ();
if (! getopts($optlist, \%options)) {
&$usage();
......@@ -187,10 +189,20 @@ sub DoCreate()
&$usage()
if ($fstype !~ /^(ext2|ext3|ext4|ufs|ufs2)$/);
}
if (defined($options{"p"})) {
$privacy = $options{"p"};
if (defined($options{"f"})) {
$fstype = $options{"f"};
&$usage()
if ($fstype !~ /^(ext2|ext3|ext4|ufs|ufs2)$/);
}
if (defined($options{"R"})) {
$read_access = $options{"R"};
&$usage()
if ($read_access !~ /^(global|project)$/);
}
if (defined($options{"W"})) {
$write_access = $options{"W"};
&$usage()
if ($privacy !~ /^(private|shared|public)$/);
if ($write_access !~ /^(creator|project)$/);
}
if (defined($options{"s"})) {
if ($options{"s"} =~ /^(\d+)$/) {
......@@ -253,12 +265,10 @@ sub DoCreate()
if (defined($fstype));
$blob->{"expires"} = TBDateStringLocal($expires)
if (defined($expires));
if ($privacy eq "shared") {
$blob->{'shared'} = 1;
}
elsif ($privacy eq "public") {
$blob->{'public'} = 1;
}
$blob->{"read_access"} = $read_access
if (defined($read_access));
$blob->{"write_access"} = $write_access
if (defined($write_access));
my $dataset = APT_Dataset->Create($blob);
if (!defined($dataset)) {
......@@ -275,7 +285,8 @@ sub DoCreate()
goto failed;
}
$blob = $response->value();
$dataset->Update({"remote_uuid" => $blob->{"uuid"}});
$dataset->Update({"remote_uuid" => $blob->{"uuid"},
"remote_urn" => $blob->{"urn"}});
#
# Okay, this is silly; there is no distinct state for resource allocation.
# It is unapproved and locked. The other side tells us its locked in the
......@@ -440,10 +451,10 @@ sub DoModify()
my $usage = sub {
print STDERR "Usage: manage_dataset modify ".
"[-e expiration] [-p privacy] pid/name\n";
"[-R global|project] [-W creator|project] pid/name\n";
exit(-1);
};
my $optlist = "e:p:";
my $optlist = "R:W:";
my %options = ();
if (! getopts($optlist, \%options)) {
&$usage();
......@@ -456,42 +467,28 @@ sub DoModify()
if (!defined($dataset)) {
fatal("No such dataset");
}
if (defined($options{"p"})) {
my $blob = {};
if (defined($options{"R"})) {
my $read_access = $options{"R"};
&$usage()
if ($options{"p"} !~ /^(private|shared|public)$/);
if ($read_access !~ /^(global|project)$/);
$blob->{'read_access'} = $read_access;
}
if (defined($options{"e"})) {
my $expires = str2time($options{"e"});
if (!defined($expires)) {
fatal("Could not parse expiration date.");
}
if (defined($options{"W"})) {
my $write_access = $options{"W"};
&$usage()
if ($write_access !~ /^(creator|project)$/);
$blob->{'write_access'} = $write_access;
}
if ($dataset->Lock()) {
fatal("dataset is busy, cannot lock it");
}
if (defined($options{"p"})) {
my $privacy = $options{"p"};
my $blob = {"shared" => 0, "public" => 0};
if ($privacy eq "shared") {
$blob->{'shared'} = 1;
}
elsif ($privacy eq "public") {
$blob->{'public'} = 1;
}
if ($dataset->Update($privacy)) {
if (keys(%$blob)) {
if ($dataset->Update($blob)) {
$errmsg = "Could not update privacy settings!";
goto failed;
}
}
if (defined($options{"e"})) {
my $expires = $options{"e"};
print "$expires\n";
if ($dataset->Update({"expires" => TBDateStringLocal($expires)})) {
$errmsg = "Could not update expiration!";
goto failed;
}
}
my $response = $dataset->ModifyDataset();
if ($response->code() != GENIRESPONSE_SUCCESS) {
if ($response->code() == GENIRESPONSE_SEARCHFAILED) {
......@@ -502,7 +499,7 @@ sub DoModify()
}
goto failed;
}
my $blob = $response->value();
$blob = $response->value();
$dataset->Update({"expires" => TBDateStringLocal($blob->{"expires"})});
$dataset->Unlock();
return 0;
......
#!/usr/bin/perl -wT
#
# Copyright (c) 2008-2014 University of Utah and the Flux Group.
# Copyright (c) 2008-2015 University of Utah and the Flux Group.
#
# {{{GENIPUBLIC-LICENSE
#
......@@ -62,6 +62,7 @@ use emutil;
use EmulabConstants;
use libEmulab;
use Lan;
use User;
use Experiment;
use NodeType;
use English;
......@@ -122,6 +123,7 @@ my $IMAGE_SETUP = "$TB/sbin/image_setup";
my $SHAREVLAN = "$TB/sbin/sharevlan";
my $FWNAME = "fw";
my $API_VERSION = 1;
my $PROTOGENI_LOCALUSER= @PROTOGENI_LOCALUSER@;
#
# Tell the client what API revision we support. The correspondence
......@@ -5494,11 +5496,17 @@ sub CreateUserFromCertificate($)
return GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
"Malformed URN");
}
my $urn = $certificate->urn();
my $urn = $certificate->urn();
my $email = $certificate->email();
# Local users always exist, so pass flag.
my $user = GeniUser->Lookup($certificate->urn(), 1);
if (defined($user)) {
if ($PROTOGENI_LOCALUSER && !$user->IsLocal()) {
# Already exists as a geni user, need to make a real user.
return GeniUtil::CreateLocalUser($urn, $email);
}
#
# See if the certificate changed. If it did, we have to update the
# user record, but we want to use the old uuid since that is our
......@@ -5553,7 +5561,6 @@ sub CreateUserFromCertificate($)
# the PLC to get it (and a proper name).
#
my $modify = 0;
my $email = $certificate->email();
my $username;
if (!defined($email) || $email eq "" || $email eq "unknown") {
if (! defined($authority->url()) || !$authority->IsSFA()) {
......@@ -5592,6 +5599,9 @@ sub CreateUserFromCertificate($)
if (exists($blob->{'last_name'}));
$modify = 1;
}
if ($PROTOGENI_LOCALUSER) {
return GeniUtil::CreateLocalUser($urn, $email);
}
$user = GeniUser->Create($certificate, $authority);
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Could not create user from your certificate")
......@@ -5830,7 +5840,12 @@ sub CleanupDeadSlice($;$)
$purge = 1
if (!defined($purge));
if (!defined(FlipToUser($slice))) {
my $creator = GeniUser->Lookup($slice->creator_uuid(), 1);
if (!defined($creator)) {
print STDERR "CleanupDeadSlice: Could not find creator\n";
return -1;
}
if (!defined(FlipToUser($slice, $creator))) {
print STDERR "CleanupDeadSlice: Could not flip to user\n";
return -1;
}
......@@ -6132,12 +6147,13 @@ sub GeniExperiment($;$)
else {
GeniUtil::FlipToGeniUser($project->unix_gid());
}
my $creator_arg = ($PROTOGENI_LOCALUSER ? "-C " . $creator->uid() : "");
# 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' ".
"-h '$uuid' -p $pid -g $gid -e $eid");
"-h '$uuid' $creator_arg -p $pid -g $gid -e $eid");
my $saved_exitcode = $?;
# Flip back to geni user. Will reset later.
......@@ -6176,26 +6192,26 @@ sub FlipToUser($$)
my $project = $experiment->GetProject();
return undef
if (!defined($project));
my $group = $project;
my $creator = $experiment->GetCreator();
return undef
if (!defined($creator));
$creator = GeniUser::LocalUser->Create($creator);
#
# Nonlocal projects, operate as geniuser with added gid.
# Nonlocal projects, operate as creator (with added gid).
# XXX watch for Legacy GeniSlices project.
#
if ($project->IsNonLocal() || $project->pid() eq "GeniSlices") {
require User;
my $group = $experiment->GetGroup();
$group = $experiment->GetGroup();
return undef
if (!defined($group));
my $geniuser = User->Lookup("geniuser");
$creator = User->Lookup("geniuser");
return undef
if (!defined($geniuser));
$geniuser = GeniUser::LocalUser->Create($geniuser);
return undef
if ($geniuser->FlipTo($group->unix_gid()));
return $geniuser;
if (!defined($creator));
$user = GeniUser::LocalUser->Create($creator);
goto flip;
}
#
......@@ -6204,29 +6220,22 @@ sub FlipToUser($$)
# geniuser has no permissions in (not a member of) the project.
#
if (!defined($user) || !$user->IsLocal()) {
usecreator:
$user = $experiment->GetCreator();
return undef
if (!defined($user));
# No subgroups yet.
return undef
if ($user->FlipTo($project->unix_gid()));
return $user;
$user = $creator;
goto flip;
}
#
# Local user, local project. Is the user a member of the project?
# If not, then like above we have to operate as the experiment
# creator since the user has no privs in the project. Generally,
# this will happen if a credential is delegated (rare) or if the
# this will happen if a credential is delegated or if the
# creator binds a user to a slice.
#
goto usecreator
if (!$experiment->AccessCheck($user->emulab_user(),
$Experiment::EXPT_ACCESS_MODIFY));
if (!$experiment->AccessCheck($user->emulab_user(),
$Experiment::EXPT_ACCESS_MODIFY)) {
$user = $creator;
}
flip:
return undef
if ($user->FlipTo($project->unix_gid()));
return $user;
......@@ -6838,14 +6847,22 @@ sub HandleBlockstore($$$$$$@)
my $gid = $pid;
#
# Look for a urn and possibly project qualified lease name.
# Look for a urn and possibly project/group qualified lease name.
#
if (GeniHRN::IsValid($leasename)) {
my (undef,$type,$id) = GeniHRN::Parse($leasename);
my ($domainsubauth,$type,$id) = GeniHRN::Parse($leasename);
if ($type ne "dataset") {
$message = "Illegal dataset urn for $leasename";
goto bad;
}
my ($domain,$subauth) = split(":", $domainsubauth);
if ($domain ne $OURDOMAIN) {
$message = "This is not the correct site for this dataset";
goto bad;
}
if (defined($subauth)) {
$pid = $subauth;
}
$leasename = $id;
if ($leasename =~ /^(.*)\/\/(.*)$/) {
......@@ -6867,6 +6884,17 @@ sub HandleBlockstore($$$$$$@)
$errorcode = GENIRESPONSE_SEARCHFAILED;
goto bad;
}
if ($PROTOGENI_LOCALUSER) {
#
# We use the Emulab permission system.
#
goto permokay
if ($lease->AccessCheck($geniuser->emulab_user(),
LEASE_ACCESS_READ()));
$message = "Not enough permission to use dataset: $leasename";
$errorcode = GENIRESPONSE_FORBIDDEN;
goto bad;
}
# Local user can use their own local lease.
goto permokay
if ($geniuser->IsLocal() &&
......@@ -6917,17 +6945,11 @@ sub HandleBlockstore($$$$$$@)
permokay:
#
# We do not have shared readonly leases yet, so if the lease
# is in use by another experiment, we have to fail.
# Only one read-write user at a time.
#
if ($lease->InUse()) {
# This will always be one for now.
my ($reservation) = @{ $lease->GetReservations() };
if (defined($reservation) &&
$reservation->exptidx() != $experiment->idx()) {
$message = "Dataset $leasename is already in use";
goto bad;
}
if ($readonly && $lease->InUseReadWrite()) {
$message = "Dataset $leasename is already in use RW";
goto bad;
}
# We need some stuff from the blockstore to fill out the
# virt tables below.
......
#!/usr/bin/perl -wT
#
# Copyright (c) 2008-2014 University of Utah and the Flux Group.
# Copyright (c) 2008-2015 University of Utah and the Flux Group.
#
# {{{GENIPUBLIC-LICENSE
#
......@@ -107,6 +107,7 @@ my $EMULAB_PEMFILE = "@prefix@/etc/genicm.pem";
# Just one of these, at Utah.
my $GENICH_PEMFILE = "@prefix@/etc/genich.pem";
my $WITHPROVENANCE = @IMAGEPROVENANCE@;
my $PROTOGENI_LOCALUSER = @PROTOGENI_LOCALUSER@;
my $API_VERSION = 2;
#
......@@ -1265,18 +1266,6 @@ sub Shutdown($)
if ($slice->Lock() != 0) {
return GeniResponse->BusyResponse();
}
#
# If a monitor process is running, then cancel it so that
# we do not leave it behind on a slice/experiment that is
# now gone.
#
if ($slice->monitor_pid()) {
my $response = GeniCM::KillMonitor($slice);
if (GeniResponse::IsResponse($response)) {
$slice->UnLock();
return $response;
}
}
if (GeniCM::CleanupDeadSlice($slice, 0) != 0) {
libtestbed::SENDMAIL($TBOPS, "Emergency Shutdown failed",