Commit cfe1834d authored by Leigh Stoller's avatar Leigh Stoller

Checkpoint first working version of Image Tracking.

parent 8c41b683
......@@ -1552,9 +1552,10 @@ sub ConsoleURL($$)
#
# Create an Image,
#
sub CreateImage($$$$;$)
sub CreateImage($$$$;$$$)
{
my ($self, $sliver_urn, $imagename, $update_prepare, $bsname) = @_;
my ($self, $sliver_urn, $imagename, $update_prepare,
$copyback_uuid, $bsname) = @_;
my $authority = $self->GetGeniAuthority();
my $geniuser = $self->instance()->GetGeniUser();
my $slice = $self->instance()->GetGeniSlice();
......@@ -1581,6 +1582,8 @@ sub CreateImage($$$$;$)
if (defined($bsname));
$args->{'update_prepare'} = 1
if ($update_prepare);
$args->{'copyback_uuid'} = $copyback_uuid
if (defined($copyback_uuid));
my $cmurl = $authority->url();
$cmurl =~ s/protogeni/protogeni\/stoller/ if ($usemydevtree);
......
......@@ -688,7 +688,7 @@ sub Unlock($)
#
sub UpdateDiskImage($$@)
{
my ($self, $node_id, $image_url, $all) = @_;
my ($self, $node_id, $newimage, $all) = @_;
my $rspec = GeniXML::Parse($self->rspec());
if (! defined($rspec)) {
print STDERR "UpdateDiskImage: Could not parse rspec\n";
......@@ -756,7 +756,7 @@ sub UpdateDiskImage($$@)
}
if (defined($image_url)) {
push(@nodes, $ref)
if (defined($this_url) && $this_url eq $image_url);
if ((defined($this_url) && $this_url eq $image_url));
}
else {
push(@nodes, $ref)
......@@ -772,7 +772,7 @@ sub UpdateDiskImage($$@)
return -1;
}
foreach my $node (@nodes) {
GeniXML::SetDiskImage($node, $image_url);
GeniXML::SetDiskImage($node, $newimage);
}
if ($self->UpdateVersion({"rspec" => GeniXML::Serialize($rspec)})) {
print STDERR "UpdateDiskImage: Could not update rspec\n";
......
......@@ -59,6 +59,7 @@ my $xmlparse;
my $instance;
my $slice;
my $sitemap;
my $usetracker = 0;
my @aggregate_urns = ();
# Debugging
......@@ -114,6 +115,7 @@ use User;
use Project;
use OSinfo;
use emutil;
use libEmulab;
use GeniDB;
use GeniUser;
use GeniCertificate;
......@@ -126,6 +128,7 @@ use GeniResponse;
use GeniXML;
use WebTask;
use Logfile;
use EmulabFeatures;
#
# Parse command arguments. Once we return from getopts, all that should be
......@@ -559,6 +562,12 @@ if ($localuser) {
$project->pid());
}
$pid = $project->pid();
# Use of the Image Tracker is a Portal directive at the moment.
$usetracker = 1
if (GetSiteVar("protogeni/use_imagetracker") &&
EmulabFeatures->FeatureEnabled("APT_UseImageTracker",
$emulab_user, $project));
}
elsif (!$localuser) {
if (defined($sshkey)) { #
......@@ -1081,6 +1090,7 @@ sub CreateSliver($)
"certificate" => $alt_certificate->cert(),
"key" =>
$alt_certificate->PrivKeyDelimited(),
"usetracker" => $usetracker,
});
if (!defined($response) || $response->code() != GENIRESPONSE_SUCCESS) {
......
......@@ -709,7 +709,8 @@ sub DoSnapShotInternal($$$$$)
goto failed;
}
my $response = $aggregate->CreateImage($sliver_urn,
$dataset->dataset_id(), 0, $bsname);
$dataset->dataset_id(),
0, undef, $bsname);
if ($response->code() != GENIRESPONSE_SUCCESS) {
$errmsg = "SnapshotDataset failed: ". $response->output() . "\n";
goto failed;
......
......@@ -82,6 +82,7 @@ use lib "@prefix@/lib";
use EmulabConstants;
use emdb;
use emutil;
use libEmulab;
use libtestbed;
use User;
use Project;
......@@ -93,6 +94,7 @@ use GeniHRN;
use Genixmlrpc;
use GeniResponse;
use GeniSlice;
use GeniImage;
use WebTask;
use EmulabFeatures;
......@@ -109,6 +111,7 @@ sub DoLockdown();
sub DoManifests();
sub WriteCredentials();
sub StartMonitor();
sub DoImageTrackerStuff($$$$$);
#
# Parse command arguments. Once we return from getopts, all that should be
......@@ -191,7 +194,11 @@ sub DoSnapshot()
my $node_id;
my $imagename;
my $update_profile;
my $copyback_uuid;
my $copyback_urn;
my $update_prepare = 0;
my $doversions = 0;
my $usetracker = 0;
my $optlist = "n:i:u:U";
my %options = ();
......@@ -293,6 +300,26 @@ sub DoSnapshot()
$sliver_urn = GeniXML::GetSliverId($node);
$node_id = GeniXML::GetVirtualId($node);
$aggregate = $agg;
#
# Instruct the remote cluster to copy the image back to its origin,
# but we need to ask the IMS for uuid of the image that is running,
# so we can tell the cluster, which then tells the origin cluster.
#
if (GetSiteVar("protogeni/use_imagetracker") &&
EmulabFeatures->FeatureEnabled("APT_UseImageTracker",
$this_user, $project)) {
#
# If there is no diskinfo or if it references a system image,
# then we have to wait until the snapshot is done to find out
# what the image was called, via the return from CreateImage().
#
$usetracker = 1;
if (DoImageTrackerStuff($agg, $node, $project,
\$copyback_uuid, \$copyback_urn)) {
fatal("Image tracking error");
}
}
}
else {
# Find the node in its manifest.
......@@ -364,6 +391,10 @@ sub DoSnapshot()
}
}
}
# Do this here to avoid output to logfile.
$doversions =
EmulabFeatures->FeatureEnabled("APT_ProfileVersions",
$this_user, $project);
}
if ($slice->Lock()) {
fatal("Slice is busy, cannot lock it");
......@@ -385,7 +416,8 @@ sub DoSnapshot()
# the background at the aggregate.
#
my $response =
$aggregate->CreateImage($sliver_urn, $imagename, $update_prepare);
$aggregate->CreateImage($sliver_urn, $imagename,
$update_prepare, $copyback_uuid);
if (!defined($response)) {
$errmsg = "Internal error creating image";
$instance->SetStatus($old_status);
......@@ -531,10 +563,6 @@ sub DoSnapshot()
# that we expect the CM is doing image versioning, so do not
# bother to check if the image version is actually new.
#
my $doversions =
EmulabFeatures->FeatureEnabled("APT_ProfileVersions",
$this_user, $project);
if ($doversions) {
$profile = $profile->NewVersion($this_user);
if (!defined($profile)) {
......@@ -544,7 +572,14 @@ sub DoSnapshot()
exit(1);
}
}
$profile->UpdateDiskImage($node_id, $version_url,
# DoImageTrackerStuff determined that we use whatever the cluster
# tells us, it is the home of the image.
$copyback_urn = $version_urn
if ($usetracker && !defined($copyback_urn));
$profile->UpdateDiskImage($node_id,
(defined($copyback_urn) ?
$copyback_urn : $version_url),
($update_profile eq "all" ? 1 : 0));
}
$instance->SetStatus("ready");
......@@ -553,13 +588,20 @@ sub DoSnapshot()
$webtask->Exited(0)
if (defined($webtask));
$slice->UnLock();
if (defined($logfile)) {
if (defined($logfile) && -s $logfile) {
SENDMAIL($TBOPS,
"Instance Snapshot Complete",
"Finished taking snapshot of $instance.\n",
$TBOPS, undef, $logfile);
unlink($logfile);
}
if (!$sliver_ready) {
#
# Image is ready, but sliver is not. Start a monitor so that
# web interface is updated.
#
StartMonitor();
}
exit(0);
bad:
if ($sliver_ready) {
......@@ -591,6 +633,91 @@ sub DoSnapshot()
exit($errcode);
}
sub DoImageTrackerStuff($$$$$)
{
my ($aggregate, $node, $project, $puuid, $purn) = @_;
my $node_id = GeniXML::GetVirtualId($node);
my $errmsg;
#
# If we do not have a diskinfo section, we will use the URN we get back
# from the cluster (it is a snapshot of the default image).
#
my $diskinfo = GeniXML::GetDiskImage($node);
return 0
if (!defined($diskinfo));
#
# This one needs more thought, it might be a URL.
#
my $image_urn = GeniXML::GetText("name", $diskinfo);
return 0
if (!defined($diskinfo));
if (!GeniHRN::IsValid($image_urn)) {
print STDERR "Invalid disk image URN for $node_id\n";
return -1;
}
Genixmlrpc->SetContext(APT_Geni::GeniContext());
my $blob = GeniImage::GetImageData($image_urn, \$errmsg);
Genixmlrpc->SetContext(undef);
if (!defined($blob)) {
print STDERR "Could not get info from the IMS for ".
"$image_urn:\n" . $errmsg . "\n";
return -1;
}
#
# System Image? We use the URN we get back from CreateSliver().
# The cluster will be the origin for the new image.
#
return 0
if ($blob->{'issystem'});
my $copyback_uuid = $blob->{'version_uuid'};
my $copyback_urn = $image_urn;
my $hrn = GeniHRN->Parse($image_urn);
my (undef,$ospid,$os,$vers) = $hrn->ParseImage();
#
# What happens if the user is doing a snapshot on the cluster where
# the image lives? The copyback (import) makes no sense in that case,
# but what if its the same cluster but different projects? In this case
# a copyback is not wrong, but sure is inefficient.
#
# Aside; should we allow snapshots (in the web ui) across projects?
#
if ($hrn->domain() eq $aggregate->domain()) {
my $projhrn = GeniHRN->Parse($blob->{'project_urn'});
if (!defined($projhrn)) {
print STDERR "Could not parse " . $blob->{'project_urn'} . "\n";
return -1;
}
if ($projhrn->subauth() eq $project->pid()) {
# We use the URN we get back from CreateSliver().
return 0;
}
}
#
# If we are going to update the profile, we need to know what to
# change the image urn to, and that depends on what version the
# image is currently at (if the image is being versioned).
#
if ($blob->{'isversioned'}) {
if (defined($vers)) {
$vers++;
$copyback_urn = GeniHRN::GenerateImage($hrn->authority(),
$ospid, $os, $vers);
}
}
$$puuid = $copyback_uuid;
$$purn = $copyback_urn;
return 0;
}
#
# Ask the console URL for a node in an instance.
#
......@@ -1065,9 +1192,14 @@ sub DoRefresh()
#
# Check the exit codes.
#
foreach my $code (@return_codes) {
foreach my $agg (@agglist) {
my $code = shift(@return_codes);
if ($code) {
$errmsg = "Some slivers could not be refreshed";
if ($agg->output()) {
$errmsg .= ": " . $agg->output();
}
goto bad;
}
}
......@@ -1303,7 +1435,6 @@ sub DoManifests()
sub StartMonitor()
{
my $logfile;
my $needunlock = 0;
my $signaled = 0;
my $slice = $instance->GetGeniSlice();
......
......@@ -83,6 +83,7 @@ use lib "@prefix@/lib";
use EmulabConstants;
use emdb;
use emutil;
use libEmulab;
use User;
use Project;
use APT_Profile;
......@@ -462,9 +463,18 @@ if (defined($instance)) {
# The script helpfully put the new image urn in the webtask.
#
$webtask->Refresh();
my $image_url = $webtask->image_url();
if (!defined($image_url) ||
$profile->UpdateDiskImage($node_id, $image_url, 0)) {
my $newimage;
if (GetSiteVar("protogeni/use_imagetracker") &&
EmulabFeatures->FeatureEnabled("APT_UseImageTracker",
$this_user, $project)) {
$newimage = $webtask->image_urn();
}
else {
$newimage = $webtask->image_url();
}
if (!defined($newimage) ||
$profile->UpdateDiskImage($node_id, $newimage, 0)) {
$webtask->Delete()
if (!defined($webtask_id));
$profile->Delete(1);
......
......@@ -211,6 +211,9 @@ my %xmlfields =
"mbr_version", => ["mbr_version", $SLOT_OPTIONAL],
"metadata_url", => ["metadata_url", $SLOT_ADMINONLY],
"imagefile_url", => ["imagefile_url", $SLOT_ADMINONLY],
"origin_uuid", => ["origin_uuid", $SLOT_ADMINONLY],
"origin_name", => ["origin_name", $SLOT_ADMINONLY],
"origin_urn", => ["origin_urn", $SLOT_ADMINONLY],
"reboot_waittime", => ["reboot_waittime", $SLOT_OPTIONAL],
"hash", => ["hash", $SLOT_ADMINONLY],
"nextosid", => ["nextosid", $SLOT_ADMINONLY],
......
......@@ -507,7 +507,8 @@ sub Create($$$$$$$$)
# Pass-through optional slots, otherwise the DB default is used.
foreach my $key ("path", "shared", "global", "ezid", "mbr_version",
"metadata_url", "imagefile_url", "released",
"isdataset", "lba_size", "lba_low", "lba_high") {
"isdataset", "lba_size", "lba_low", "lba_high",
"origin_uuid", "origin_urn", "origin_name") {
if (exists($argref->{$key})) {
push(@arg_slots, $key);
}
......@@ -603,8 +604,8 @@ sub Create($$$$$$$$)
# us to track actual geni users, since all of that happens
# as geniuser. We do not bother to set this for local users.
#
if (exists($ENV{'GENIURN'}) && $ENV{'GENIURN'} ne "") {
$query .= ",creator_urn=". DBQuoteSpecial($ENV{'GENIURN'});
if (exists($ENV{'REALGENIURN'}) && $ENV{'REALGENIURN'} ne "") {
$query .= ",creator_urn=". DBQuoteSpecial($ENV{'REALGENIURN'});
}
# Create the main entry:
......@@ -743,8 +744,8 @@ sub NewVersion($$$$)
# us to track actual geni users, since all of that happens
# as geniuser. We do not bother to set this for local users.
#
if (exists($ENV{'GENIURN'}) && $ENV{'GENIURN'} ne "") {
$updater_urn = ",updater_urn=". DBQuoteSpecial($ENV{'GENIURN'});
if (exists($ENV{'REALGENIURN'}) && $ENV{'REALGENIURN'} ne "") {
$updater_urn = ",updater_urn=". DBQuoteSpecial($ENV{'REALGENIURN'});
}
#
......@@ -822,6 +823,8 @@ sub NewVersion($$$$)
" created=now(),nodetypes='$typelist', ".
" parent_imageid=$parent_imageid,".
" parent_version=$parent_version, ".
" origin_neednotify=0,origin_needupdate=0, ".
" origin_uuid=NULL,origin_name=NULL, ".
" updater='$uid',updater_idx='$uid_idx' $updater_urn ".
"where imageid='$osid'")
or goto bad;
......@@ -1184,6 +1187,10 @@ sub Delete($;$)
or goto bad;
DBQueryWarn("delete from web_tasks where object_uuid='$uuid'")
or goto bad;
DBQueryWarn("delete from image_notifications where imageid='$imageid'")
or goto bad;
DBQueryWarn("delete from image_updates where imageid='$imageid'")
or goto bad;
if ($purge || !$DOPROVENANCE) {
goto bad
......@@ -1573,8 +1580,8 @@ sub MarkUpdate($$;$)
# us to track actual geni users, since all of that happens
# as geniuser. We do not bother to set this for local users.
#
if (exists($ENV{'GENIURN'}) && $ENV{'GENIURN'} ne "") {
$updater_urn = ", updater_urn=". DBQuoteSpecial($ENV{'GENIURN'});
if (exists($ENV{'REALGENIURN'}) && $ENV{'REALGENIURN'} ne "") {
$updater_urn = ", updater_urn=". DBQuoteSpecial($ENV{'REALGENIURN'});
}
if (defined($stamp)) {
......@@ -1592,6 +1599,44 @@ sub MarkUpdate($$;$)
return 0;
}
#
# Mark the IMS update time in the record,
#
sub MarkIMSReported($)
{
my ($self) = @_;
# Must be a real reference.
return -1
if (! ref($self));
my $imageid = $self->imageid();
my $version = $self->version();
return -1
if (! DBQueryWarn("update image_versions set ims_reported=now() " .
"where imageid='$imageid' and version='$version'"));
return 0;
}
sub ClearIMSReported($)
{
my ($self) = @_;
# Must be a real reference.
return -1
if (! ref($self));
my $imageid = $self->imageid();
my $version = $self->version();
return -1
if (! DBQueryWarn("update image_versions set ims_reported=NULL " .
"where imageid='$imageid' and version='$version'"));
return 0;
}
#
# Set the hash.
#
......@@ -2219,6 +2264,25 @@ sub SetHash($$)
return 0;
}
sub SetNoVersioning($$)
{
my ($self, $value) = @_;
$value = ($value ? 1 : 0);
# Must be a real reference.
return -1
if (! ref($self));
my $imageid = $self->imageid();
return -1
if (! DBQueryWarn("update images set noversioning='$value' " .
"where imageid='$imageid'"));
$self->{'IMAGE'}->{'noversioning'} = $value;
return 0;
}
sub LocalURL($)
{
my ($self) = @_;
......
......@@ -41,8 +41,9 @@ LIB_SCRIPTS = GeniDB.pm GeniUser.pm \
GeniAuthority.pm GeniCertificate.pm GeniAggregate.pm \
GeniUtil.pm GeniRegistry.pm GeniUsage.pm GeniHRN.pm \
GeniSES.pm GeniResource.pm GeniXML.pm GeniAM.pm \
GeniEmulab.pm GeniFoam.pm GeniStitch.pm \
GeniStd.pm GeniMA.pm GeniStdSA.pm GeniSR.pm GeniPortal.pm
GeniEmulab.pm GeniFoam.pm GeniStitch.pm GeniIMS.pm \
GeniStd.pm GeniMA.pm GeniStdSA.pm GeniSR.pm GeniPortal.pm \
GeniImage.pm
SBIN_SCRIPTS = plabnodewrapper plabslicewrapper
SCRIPTS = genischemacheck.pl
......
......@@ -57,6 +57,7 @@ use GeniHRN;
use GeniXML;
use GeniStitch;
use GeniUsage;
use GeniImage;
use libtestbed;
use emutil;
use EmulabConstants;
......@@ -483,12 +484,12 @@ sub GetTicket($;$)
if (GeniResponse::IsResponse($ticket));
}
return GetTicketAux($credential,
$rspecstr, $isupdate, $impotent, 0, 1, $ticket);
$rspecstr, $isupdate, $impotent, 0, 1, 0, $ticket);
}
sub GetTicketAux($$$$$$$$@)
sub GetTicketAux($$$$$$$$$@)
{
my ($credential, $rspecstr, $isupdate, $impotent, $v2, $level,
my ($credential, $rspecstr, $isupdate, $impotent, $v2, $level, $usetracker,
$ticket, $speaksfor, @morecreds) = @_;
defined($credential) &&
......@@ -531,13 +532,14 @@ sub GetTicketAux($$$$$$$$@)
main::AddLogfileMetaDataFromSlice($slice);
return GetTicketAuxAux($slice, $user, $rspecstr,
$isupdate, $impotent, $v2, $level, $ticket,
[$credential, @morecreds], $speaksfor);
$isupdate, $impotent, $v2, $level, $usetracker,
$ticket, [$credential, @morecreds], $speaksfor);
}
sub GetTicketAuxAux($$$$$$$$$$)
sub GetTicketAuxAux($$$$$$$$$$$)
{
my ($slice, $user, $rspecstr, $isupdate,
$impotent, $v2, $level, $ticket, $credentials, $speaksfor) = @_;
$impotent, $v2, $level, $usetracker,
$ticket, $credentials, $speaksfor) = @_;
my $response = undef;
my $restorevirt = 0; # Flag to restore virtual state
my $restorephys = 0; # Flag to restore physical state
......@@ -593,6 +595,17 @@ sub GetTicketAuxAux($$$$$$$$$$)
$allow_externalusers = 0;
}
# Image tracker.
my $use_imagetracker;
if (!GetSiteVar('protogeni/use_imagetracker', \$use_imagetracker)) {
# Cannot get the value, say no.
$use_imagetracker = 0;
}
# But the Portal is currently the one telling us to use the tracker
# for specific slices.
$use_imagetracker = 1
if ($use_imagetracker && $usetracker);
# Figure out if user has a credentials that exempts him
# from the following policy. If external users are blocked access
# and he presents a credential that exempts him from it,
......@@ -1014,11 +1027,24 @@ sub GetTicketAuxAux($$$$$$$$$$)
}
$osinfo = OSinfo->Lookup($ospid, $os, $vers);
if (!defined($osinfo)) {
if ($use_imagetracker) {
my $image = GeniImage::MapToLocalImage($dname, $pid);
if (GeniResponse::IsError($image)) {
$response = $image;
goto bad;
}
$osname = ($image->IsLocal() ?
$image->versname() :
$image->metadata_url());
}
else {
$response =
GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
"Unknown image URN: $dname");
goto bad;
}
}
else {
#
# The OS must be in the current project, or it must
# be global (okay, shared).
......@@ -1038,6 +1064,7 @@ sub GetTicketAuxAux($$$$$$$$$$)
$osname .= ":${vers}" if (defined($vers));
}
}
}
if (defined($virtualization_type)) {
if ($virtualization_type eq "emulab-vnode") {
......@@ -5301,7 +5328,8 @@ sub SliceStatus($)
$details{$node_uuid} = "ready";
$detailsNew{$urn} = "ready";
}
elsif ($node->eventstate() eq TBDB_NODESTATE_TBFAILED()) {
elsif ($node->eventstate() eq TBDB_NODESTATE_TBFAILED() ||
$node->eventstate() eq TBDB_NODESTATE_RELOADFAILED()) {
$details{$node_uuid} = "failed";
$detailsNew{$urn} = "failed";
$summary = "failed";
......@@ -5497,7 +5525,8 @@ sub SliverStatus($)
$details{$node_uuid} = "ready";
$detailsNew{$urn} = "ready";
}
elsif ($node->eventstate() eq TBDB_NODESTATE_TBFAILED()) {
elsif ($node->eventstate() eq TBDB_NODESTATE_TBFAILED() ||
$node->eventstate() eq TBDB_NODESTATE_RELOADFAILED()) {
$details{$node_uuid} = "failed";
$detailsNew{$urn} = "failed";
$summary = "failed";
......
......@@ -57,6 +57,7 @@ use GeniXML;
use GeniStitch;
use GeniStd;
use emutil;
use libEmulab;
use English;
use libtestbed;
use Data::Dumper;
......@@ -105,6 +106,8 @@ my $WAP = "$TB/sbin/withadminprivs";
my $SHAREVLAN = "$TB/sbin/sharevlan";
my $XMLLINT = "/usr/local/bin/xmllint";
my $PRERENDER = "$TB/libexec/vis/prerender";
my $IMPORTER = "$TB/sbin/image_import";
my $POSTIMAGEDATA = "$TB/sbin/protogeni/postimagedata";
my $EMULAB_PEMFILE = "@prefix@/etc/genicm.pem";
# Just one of these, at Utah.
my $GENICH_PEMFILE = "@prefix@/etc/genich.pem";
......@@ -397,6 +400,7 @@ sub CreateSliver($)
my $credentials = $argref->{'credentials'};
my $keys = $argref->{'keys'};
my $impotent = $argref->{'impotent'} || 0;
my $usetracker = $argref->{'usetracker'} || 0;
require Node;
require Experiment;
require libtestbed;
......@@ -470,7 +474,7 @@ sub CreateSliver($)
}
}
my $rspec = GeniCM::GetTicketAux($credential, $rspecstr,
0, $impotent, 1, 0,
0, $impotent, 1, 0, $usetracker,
undef, $speaksfor, @morecreds);
return $rspec
if (GeniResponse::IsResponse($rspec));
......@@ -1366,6 +1370,7 @@ sub GetTicket($)
my $rspecstr = $argref->{'rspec'};
my $credentials = $argref->{'credentials'};
my $impotent = $argref->{'impotent'} || 0;
my $usetracker = $argref->{'usetracker'} || 0;
if (! (defined($credentials) &&
defined($slice_urn) && defined($rspecstr))) {
......@@ -1457,7 +1462,8 @@ sub GetTicket($)
# Slice does not exist yet.
}
return GeniCM::GetTicketAux($credential, $rspecstr,
0, $impotent, 1, 1, undef, $speaksfor);
0, $impotent, 1, 1, $usetracker,
undef, $speaksfor);
}
#
......@@ -1471,6 +1477,7 @@ sub UpdateTicket($)
my $rspecstr = $argref->{'rspec'};
my $credentials = $argref->{'credentials'};
my $impotent = $argref->{'impotent'} || 0;
my $usetracker = $argref->{'usetracker'} || 0;
if (! (defined($credentials) && defined($ticketstr) &&
defined($slice_urn) && defined($rspecstr))) {
......@@ -1565,7 +1572,8 @@ sub UpdateTicket($)
}
return GeniCM::GetTicketAuxAux($slice, $user,
$rspecstr, 1, $impotent, 1, 1, $ticket,
$rspecstr, 1, $impotent, 1, 1,
$usetracker, $ticket,
[$credential, @morecreds], $speaksfor);
}
......@@ -1579,6 +1587,7 @@ sub UpdateSliver($)
my $rspecstr = $argref->{'rspec'};
my $credentials = $argref->{'credentials'};
my $impotent = $argref->{'impotent'} || 0;
my $usetracker = $argref->{'usetracker'} || 0;
if (! (defined($credentials) &&
defined($sliver_urn) && defined($rspecstr))) {
......@@ -1647,7 +1656,8 @@ sub UpdateSliver($)
if (GeniResponse::IsResponse($user));
return GeniCM::GetTicketAuxAux($slice, $user,
$rspecstr, 1, $impotent, 1, 1, undef,
$rspecstr, 1, $impotent, 1, 1,
$usetracker, undef,
[$credential, @morecreds], $speaksfor);
}
......@@ -2469,6 +2479,7 @@ sub CreateImage($)
my $wholedisk = 0;
my $update_prepare = 0;
my $bsname;
my $copyback_uuid;
require EmulabConstants;
require Image;
......@@ -2491,6 +2502,12 @@ sub CreateImage($)
return GeniResponse->MalformedArgsResponse("Improper bsname argument")
if ($bsname !~ /^[-\w\.\+]*$/);
}
# Optional copyback directive.
if (exists($argref->{'copyback_uuid'})) {
$copyback_uuid = $argref->{'copyback_uuid'};
return GeniResponse->MalformedArgsResponse("Improper copyback argument")
if ($copyback_uuid !~ /^[-\w\.\+]*$/);
}
my ($credential,$speaksfor) = GeniStd::CheckCredentials($credentials