Commit 0399cd8e authored by Leigh Stoller's avatar Leigh Stoller

The rest of the snapshot node changes.

parent c1d3f663
......@@ -682,18 +682,91 @@ sub Unlock($)
}
#
# Update the disk image inside a single node profile.
# Update the disk image inside a profile. We update the URL for the
# specified node, and if $all is set, we change all nodes with the
# same original disk image as the specified node.
#
sub UpdateDiskImage($$)
sub UpdateDiskImage($$@)
{
my ($self, $image_url) = @_;
my ($self, $node_id, $image_url, $all) = @_;
my $rspec = GeniXML::Parse($self->rspec());
if (! defined($rspec)) {
print STDERR "UpdateDiskImage: Could not parse rspec\n";
return -1;
}
my ($node) = GeniXML::FindNodes("n:node", $rspec)->get_nodelist();
#
# Find all the nodes we want to update, might be just the one or
# all with the same image.
#
my @nodes = ();
my $node;
# First find the specified node.
foreach my $ref (GeniXML::FindNodes("n:node", $rspec)->get_nodelist()) {
if (GeniXML::GetVirtualId($ref) eq $node_id) {
$node = $ref;
last;
}
}
if (!defined($node)) {
print STDERR "$node_id not in rspec\n";
return -1;
}
if ($all) {
#
# Pull out the disk url/urn of the specified node.
#
my $diskref = GeniXML::GetDiskImage($node);
my $image_urn;
my $image_url;
if (defined($diskref)) {
$image_url = GeniXML::GetText("url", $diskref);
$image_urn = GeniXML::GetText("name", $diskref);
if (defined($image_url) || defined($image_urn)) {
# Watch for url in the name, flipflop.
if (defined($image_urn) && $image_urn =~ /^http/) {
$image_url = $image_urn;
$image_urn = undef;
}
}
}
#
# Now find all nodes using the same disk urn/url and change.
#
foreach my $ref (GeniXML::FindNodes("n:node", $rspec)->get_nodelist()) {
my $diskref = GeniXML::GetDiskImage($ref);
next
if (!defined($diskref));
my $this_url = GeniXML::GetText("url", $diskref);
my $this_urn = GeniXML::GetText("name", $diskref);
next
if (!(defined($image_url) || defined($image_urn)));
# Watch for url in the name, flipflop.
if (defined($this_urn) && $this_urn =~ /^http/) {
$this_url = $this_urn;
$this_urn = undef;
}
if (defined($image_url)) {
push(@nodes, $ref)
if (defined($this_url) && $this_url eq $image_url);
}
else {
push(@nodes, $ref)
if (defined($this_urn) && $this_urn eq $image_urn);
}
}
}
else {
@nodes = ($node);
}
if (!@nodes) {
print STDERR "Could not find any nodes to update disk image\n";
return -1;
}
foreach my $node (@nodes) {
GeniXML::SetDiskImage($node, $image_url);
}
if ($self->UpdateVersion({"rspec" => GeniXML::Serialize($rspec)})) {
print STDERR "UpdateDiskImage: Could not update rspec\n";
return -1;
......
......@@ -35,7 +35,8 @@ use POSIX qw(setsid close);
#
sub usage()
{
print("Usage: manage_instance snapshot instance [imagename node_id]\n");
print("Usage: manage_instance snapshot ".
"[-s node_id] [-i imagename] [-u node|all] instance\n");
print("Usage: manage_instance consoleurl instance node\n");
print("Usage: manage_instance extend instance seconds\n");
print("Usage: manage_instance terminate instance\n");
......@@ -59,7 +60,7 @@ my $TBOPS = "@TBOPSEMAIL@";
my $QUICKVM = "$TB/sbin/protogeni/quickvm";
# Debugging
my $usemydevtree = 0;
my $usemydevtree = 1;
#
# Untaint the path
......@@ -174,6 +175,27 @@ sub DoSnapshot()
my $errcode = 1;
my $needunlock = 0;
my $old_status = $instance->status();
my $node_id;
my $imagename;
my $update_profile;
my $optlist = "n:i:u:";
my %options = ();
if (! getopts($optlist, \%options)) {
usage();
}
if (defined($options{"n"})) {
$node_id = $options{"n"};
}
if (defined($options{"i"})) {
$imagename = $options{"i"};
}
if (defined($options{"u"})) {
$update_profile = $options{"u"};
if ($update_profile !~ /^(node|all)$/) {
usage();
}
}
if ($old_status ne "ready") {
fatal("Instance must be in the ready state to take a snapshot");
......@@ -196,33 +218,27 @@ sub DoSnapshot()
}
#
# If we get an imagename on the command line, the caller is
# saying it is responsible (clone). If we do not get one, we
# create the name and update the underlying profile with the new
# image urn.
# Might be a clone (manage_profile).
#
my $project;
my $imagename;
my $node_id;
my $sliver_urn;
my $update_profile = 0;
my $profile = APT_Profile->Lookup($instance->profile_id());
if (!defined($profile)) {
fatal("Could not lookup profile for instance");
}
if (@ARGV) {
$imagename = shift(@ARGV);
if (@ARGV) {
$node_id = shift(@ARGV);
my $project = Project->Lookup($profile->pid_idx());
if (!defined($project)) {
fatal("Could not lookup project for profile");
}
if (defined($node_id)) {
if (!defined($imagename)) {
$imagename = $profile->name() . "." . $node_id;
}
}
else {
if (!defined($imagename)) {
$imagename = $profile->name();
$update_profile = 1;
$project = Project->Lookup($profile->pid_idx());
if (!defined($project)) {
fatal("Could not lookup project for profile");
}
}
......@@ -236,6 +252,7 @@ sub DoSnapshot()
my $node;
my @nodes = GeniXML::FindNodes("n:node", $manifest)->get_nodelist();
if (!defined($node_id)) {
# We snapshot the one node in the instance.
if (@nodes != 1) {
fatal("Too many nodes (> 1) to snapshot");
}
......@@ -243,10 +260,11 @@ sub DoSnapshot()
$sliver_urn = GeniXML::GetSliverId($node);
}
else {
foreach $node (@nodes) {
my $client_id = GeniXML::GetVirtualId($node);
foreach my $ref (@nodes) {
my $client_id = GeniXML::GetVirtualId($ref);
if ($node_id eq $client_id) {
$sliver_urn = GeniXML::GetSliverId($node);
$sliver_urn = GeniXML::GetSliverId($ref);
$node = $ref;
last;
}
}
......@@ -256,12 +274,11 @@ sub DoSnapshot()
}
#
# Really, a snapshot and not a clone. We are not going to allow this
# if the instance in on a different cluster then where the image was
# originally created, since otherwise the image provenance will look
# like spaghetti.
# We are not going to allow this if the instance is on a different
# cluster then where the image was originally created, since otherwise
# the image provenancewill look like spaghetti.
#
if ($update_profile) {
if (defined($update_profile)) {
my $diskref = GeniXML::GetDiskImage($node);
if (defined($diskref)) {
my $image_url = GeniXML::GetText("url", $diskref);
......@@ -476,7 +493,7 @@ sub DoSnapshot()
$errcode = 60;
goto bad;
}
elsif ($update_profile) {
elsif (defined($update_profile)) {
#
# If successful, we create a new version of the profile and
# update the rspec to reflect the new image version. Note
......@@ -496,7 +513,8 @@ sub DoSnapshot()
exit(1);
}
}
$profile->UpdateDiskImage($version_url);
$profile->UpdateDiskImage($node_id, $version_url,
($update_profile eq "all" ? 1 : 0));
}
$instance->SetStatus("ready");
# We garbage collect these later, so anyone waiting has a chance
......
......@@ -433,8 +433,8 @@ if (defined($instance)) {
fatal("Could not lock new profile");
}
my $command = "$MANAGEINSTANCE -t " . $webtask->task_id() . " ".
"snapshot $apt_uuid $imagename $node_id";
my $command = "$MANAGEINSTANCE -t " . $webtask->task_id() . " -- ".
"snapshot -s $node_id -i $imagename $apt_uuid";
#
# This returns pretty fast, and then the imaging takes place in
......@@ -456,7 +456,7 @@ if (defined($instance)) {
$webtask->Refresh();
my $image_url = $webtask->image_url();
if (!defined($image_url) ||
$profile->UpdateDiskImage($image_url)) {
$profile->UpdateDiskImage($node_id, $image_url, 0)) {
$webtask->Delete()
if (!defined($webtask_id));
$profile->Delete(1);
......
......@@ -954,7 +954,7 @@ function (_, sup, moment, marked, UriTemplate, ShowImagingModal,
" <li><a href='#' name='console'>Console</a></li> " +
" <li><a href='#' name='reboot'>Reboot</a></li> " +
" <li><a href='#' name='reload'>Reload</a></li> " +
" <li class=hidden><a href='#' name='snapshot'>Snapshot</a></li> " +
" <li><a href='#' name='snapshot'>Snapshot</a></li> " +
" </ul>" +
" </div>" +
" </td>" +
......
......@@ -35,7 +35,7 @@ $creator = null;
#
# Locate the objects and check permission.
#
function StatusSetupAjax()
function StatusSetupAjax($needmodify)
{
global $this_user, $ajax_args;
global $instance, $creator;
......@@ -58,17 +58,24 @@ function StatusSetupAjax()
SPITAJAX_ERROR(1, "no such instance creator");
return 1;
}
# Admin users do whatever the like.
# Admin users do whatever they like.
if (isset($this_user) && ISADMIN()) {
return 0;
}
# An experiment created by a real user, can be accessed by that user only.
# Ditto a guest user; must be the same guest.
if (! ((get_class($creator) == "User" &&
isset($this_user) && $creator->uuid() == $this_user->uuid()) ||
(get_class($creator) == "GeniUser" &&
isset($_COOKIE['quickvm_user']) &&
$_COOKIE['quickvm_user'] == $creator->uuid()))) {
# For a guest user; must be the same guest that created experiment.
if (get_class($creator) == "GeniUser") {
if (isset($_COOKIE['quickvm_user']) &&
$_COOKIE['quickvm_user'] == $creator->uuid()) {
return 0;
}
SPITAJAX_ERROR(1, "You do not have permission!");
return 1;
}
# An experiment created by a real user, can be accessed by other
# members of the project, subject to modify restrictions.
if (! (isset($this_user) && get_class($creator) == "User" &&
$instance->CanView($this_user) &&
(!$needmodify || $instance->CanModify($this_user)))) {
SPITAJAX_ERROR(1, "You do not have permission!");
return 1;
}
......@@ -82,7 +89,7 @@ function Do_GetInstanceStatus()
{
global $instance, $creator;
if (StatusSetupAjax()) {
if (StatusSetupAjax(0)) {
return;
}
$blob = array();
......@@ -121,7 +128,7 @@ function Do_TerminateInstance()
{
global $instance, $creator, $this_user, $ajax_args;
if (StatusSetupAjax()) {
if (StatusSetupAjax(1)) {
return;
}
$uuid = $instance->uuid();
......@@ -187,7 +194,7 @@ function Do_GetInstanceManifest()
{
global $instance, $creator;
if (StatusSetupAjax()) {
if (StatusSetupAjax(0)) {
return;
}
......@@ -208,7 +215,7 @@ function Do_GetSSHAuthObject()
}
$hostport = $ajax_args["hostport"];
if (StatusSetupAjax()) {
if (StatusSetupAjax(1)) {
return;
}
#
......@@ -245,7 +252,7 @@ function Do_RequestExtension()
$needapproval = 0;
$granted = 0;
if (StatusSetupAjax()) {
if (StatusSetupAjax(1)) {
goto bad;
}
$uuid = $instance->uuid();
......@@ -477,7 +484,7 @@ function Do_ConsoleURL()
}
$node = $ajax_args["node"];
if (StatusSetupAjax()) {
if (StatusSetupAjax(1)) {
return;
}
$uuid = $instance->uuid();
......@@ -562,7 +569,7 @@ function Do_Snapshot()
SPITAJAX_ERROR(1, "Bad node id");
return;
}
$optargs .= " -s $node_id ";
$optargs .= " -n $node_id ";
if (isset($ajax_args["update_profile"]) &&
$ajax_args["update_profile"]) {
......@@ -576,7 +583,7 @@ function Do_Snapshot()
$webtask_id = WebTask::GenerateID();
$retval = SUEXEC($this_user->uid(), "nobody",
"webmanage_instance -t $webtask_id -- ".
" snapshot $optargs $uuid",
" snapshot $uuid $optargs",
SUEXEC_ACTION_IGNORE);
$webtask = WebTask::Lookup($webtask_id);
......
......@@ -97,8 +97,7 @@ if (!$creator) {
if (! (isset($this_user) && ISADMIN())) {
# An experiment created by a real user, can be accessed by that user only.
# Ditto a guest user; must be the same guest.
if (! ((get_class($creator) == "User" &&
isset($this_user) && $creator->uuid() == $this_user->uuid()) ||
if (! ((get_class($creator) == "User" && $instance->CanView($this_user)) ||
(get_class($creator) == "GeniUser" &&
isset($_COOKIE['quickvm_user']) &&
$_COOKIE['quickvm_user'] == $creator->uuid()))) {
......
......@@ -78,7 +78,13 @@
</a>
</div>
<% if (isadmin) { %>
<div class='pull-left'>
<div class='pull-left'
data-toggle='popover'
data-delay='{"hide":1500, "show":500}'
data-html='true'
data-content="When checked, only administrator can extend
this experiment. No free time is granted to
user at all">
<label class="checkbox-inline" style='margin-right: 10px;'>
<input type="checkbox" id="lockout_checkbox"
<% if (lockout) { %>checked<% } %> >Lockout</label>
......@@ -247,7 +253,8 @@
Check this box if you want us to update your profile to use the
new disk image. All nodes running the same image will be
updated. If you uncheck the box, you will need to modify the
profile source code yourself.
profile source code yourself (you will receive email with the
name/url of the new image).
<br>
</div>
<div id='wholedisk_div' class='hidden'>
......@@ -281,7 +288,7 @@
<li><a tabindex="-1">Console</a></li>
<li><a tabindex="-1">Reboot</a></li>
<li><a tabindex="-1">Reload</a></li>
<li class=hidden><a tabindex="-1">Snapshot</a></li>
<li><a tabindex="-1">Snapshot</a></li>
</ul>
</div>
</div>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment