Commit b4481cbd authored by Leigh B Stoller's avatar Leigh B Stoller

Sweeping (massive, huge, bigly?) changes to Classic path image pages.

The high level goal; redo all the classic image pages within the Portal
UI such that mere users never see the old crusty stale rotting pages.
Old fart admins (know any?) can still access the old pages, but I am
hoping that won't actually happen (hint, hint).

Another goal; allow editing of Geni created images (local images
only). It has always bothered me that Portal users have no way to get
info or do minor editing on Portal created images. Especially since
images are so central to everything we do. Only local images can be
edited, but in the Emulab portal, that is all images.

Mothership only for now. Lets see how much whining we get, might have to
adjust the interface a bit since Classic users are going to find
themselves in unfamiliar territory.
parent a5be936d
......@@ -4472,6 +4472,7 @@ sub ListImages($)
my $blob = {"urn" => $image_urn . ":" . $image->version(),
"url" => $image_url,
"uuid" => $image->uuid(),
"created" => emutil::TBDateStringGMT($image->created()),
"updated" => emutil::TBDateStringGMT($image->updated()),
"format" => $image->format(),
......
......@@ -59,7 +59,7 @@ sub usage()
" -w Wait for image to be created\n");
exit(-1);
}
my $optlist = "densg:wFr:b:UB:";
my $optlist = "densg:wFr:b:UB:t:";
my $debug = 0;
my $wholedisk = 0;
my $impotent = 0;
......@@ -74,6 +74,8 @@ my $origin_uuid;
my $bsname;
my $base_image;
my $image;
my $webtask_id;
my $webtask;
#
# Configure variables
......@@ -109,6 +111,7 @@ use Project;
use OSImage;
use Image; # For datasets
use Node;
use WebTask;
use EmulabFeatures;
# Protos
......@@ -163,6 +166,14 @@ if (defined($options{"b"})) {
fatal("Bad data in $bsname.");
}
}
if (defined($options{"t"})) {
$webtask_id = $options{"t"};
$webtask = WebTask->Lookup($webtask_id);
if (!defined($webtask)) {
fatal("No such webtask");
}
$webtask->AutoStore(1);
}
usage()
if (@ARGV != 2);
......@@ -393,9 +404,13 @@ if (defined($image)) {
if ($nosnapshot) {
print "Not taking a snapshot, as directed\n"
if ($debug);
if (defined($webtask)) {
$webtask->Exited(0);
}
exit(0);
}
my $opts = "-p $pid ";
$opts .= "-t $webtask_id " if (defined($webtask));
$opts .= "-w " if ($waitmode);
$opts .= "-F " if ($nodelta);
$opts .= "-U " if ($update_prepare);
......@@ -675,6 +690,9 @@ if ($debug) {
if ($nosnapshot) {
print "Not taking a snapshot, as directed\n"
if ($debug);
if (defined($webtask)) {
$webtask->Exited(0);
}
exit(0);
}
......@@ -685,6 +703,7 @@ if ($nosnapshot) {
$nodelta = 1;
my $opts = "-p $pid ";
$opts .= "-t $webtask_id " if (defined($webtask));
$opts .= "-w " if ($waitmode);
$opts .= "-F " if ($nodelta);
$opts .= "-U " if ($update_prepare);
......@@ -702,6 +721,17 @@ sub fatal($)
{
my ($mesg) = @_;
if (defined($webtask)) {
#
# If we threw an error in create_image, we do not want to
# overwrite that image.
#
$webtask->Refresh();
if (!$webtask->HasExited()) {
$webtask->output($mesg);
$webtask->Exited(1);
}
}
die("*** $0:\n".
" $mesg\n");
}
#!/usr/bin/perl -w
#
# Copyright (c) 2000-2018 University of Utah and the Flux Group.
# Copyright (c) 2000-2019 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
......@@ -1731,6 +1731,7 @@ sub fatal($)
$webtask->Refresh();
$webtask->status("failed");
$webtask->imagesize(0);
$webtask->output($mesg);
$webtask->Exited(1);
}
$image->Unlock()
......
<?php
#
# Copyright (c) 2000-2018 University of Utah and the Flux Group.
# Copyright (c) 2000-2019 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
......@@ -562,9 +562,7 @@ function ClassicImageList($target)
$blob["creator_idx"] = $row["creator_idx"];
$blob["format"] = $row["format"];
$blob["urn"] = $urn;
$blob["url"] = $TBBASE . "/" .
CreateURL("showimageid",
URLARG_IMAGEID, $imageid);
$blob["url"] = "show-image.php?imageid=$imageid";
$results[] = $blob;
}
return $results;
......
<?php
#
# Copyright (c) 2000-2019 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
# This file is part of the Emulab network testbed software.
#
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# This file is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
# License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this file. If not, see <http://www.gnu.org/licenses/>.
#
# }}}
#
chdir("..");
include("defs.php3");
include("imageid_defs.php");
include("osiddefs.php3");
include("node_defs.php");
chdir("apt");
include("quickvm_sup.php");
include_once("profile_defs.php");
# Must be after quickvm_sup.php since it changes the auth domain.
$page_title = "Clone Image";
#
# Get current user.
#
RedirectSecure();
$this_user = CheckLoginOrRedirect();
if (NOPROJECTMEMBERSHIP()) {
return NoProjectMembershipError($this_user);
}
$this_idx = $this_user->uid_idx();
$isadmin = (ISADMIN() ? "true" : "false");
#
# Verify page arguments.
#
$optargs = OptionalPageArguments("node", PAGEARG_NODE,
"baseimage", PAGEARG_IMAGE);
SPITHEADER(1);
#
# If starting from a specific node we can derive baseimage from it.
#
if (isset($node)) {
$baseimage = $node->def_boot_image();
if (!isset($baseimage)) {
USERERROR("Cannot determine base image from node", 1);
}
if (!$node->AccessCheck($this_user, $TB_NODEACCESS_LOADIMAGE)) {
USERERROR("No permission to clone this node", 1);
}
}
elseif (!isset($baseimage)) {
USERERROR("Must supply an image or a node to clone", 1);
}
$baseimage_uuid = $baseimage->uuid();
$baseimage_name = $baseimage->imagename();
$baseimage_version = $baseimage->version();
# Must be allowed to read the image.
if (! $baseimage->AccessCheck($this_user, $TB_IMAGEID_READINFO)) {
$errors["error"] = "Not enough permission to clone image";
}
# Place to hang the toplevel template.
echo "<div id='main-body'></div>\n";
#
# See what projects the user can do this in.
#
$projlist = $this_user->ProjectAccessList($TB_PROJECT_MAKEIMAGEID);
echo "<script type='text/plain' id='projects-json'>\n";
echo htmlentities(json_encode($projlist));
echo "</script>\n";
#
# Need a list of node types. We join this over the nodes table so that
# we get a list of just the nodes that currently in the testbed, not
# just in the node_types table.
#
$types_result =
DBQueryFatal("select distinct n.type from nodes as n ".
"left join node_type_attributes as a on a.type=n.type ".
"where a.attrkey='imageable' and ".
" a.attrvalue!='0'");
$alltypes = array();
while ($row = mysql_fetch_array($types_result)) {
$alltypes[] = $row["type"];
}
echo "<script type='text/plain' id='alltypes-json'>\n";
echo htmlentities(json_encode($alltypes));
echo "</script>\n";
echo "<script type='text/plain' id='oslist-json'>\n";
echo htmlentities(json_encode($osid_oslist));
echo "</script>\n";
echo "<script type='text/plain' id='osfeatures-json'>\n";
echo htmlentities(json_encode($osid_featurelist));
echo "</script>\n";
echo "<link rel='stylesheet'
href='css/jquery-ui.min.css'>\n";
echo "<script type='text/javascript'>\n";
echo " window.ISADMIN = $isadmin;\n";
echo " window.BASEIMAGE_UUID = '$baseimage_uuid';\n";
echo " window.BASEIMAGE_NAME = '$baseimage_name';\n";
echo " window.BASEIMAGE_VERSION = $baseimage_version;\n";
if (isset($node)) {
$node_id = $node->node_id();
echo " window.NODE = '$node_id';\n";
}
echo "</script>\n";
REQUIRE_UNDERSCORE();
REQUIRE_SUP();
REQUIRE_MOMENT();
REQUIRE_APTFORMS();
REQUIRE_IMAGE();
SPITREQUIRE("js/clone-image.js");
AddTemplateList(array("clone-image",
"oops-modal", "waitwait-modal"));
SPITFOOTER();
?>
<?php
#
# Copyright (c) 2000-2019 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
# This file is part of the Emulab network testbed software.
#
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# This file is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
# License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this file. If not, see <http://www.gnu.org/licenses/>.
#
# }}}
#
chdir("..");
include("defs.php3");
include("imageid_defs.php");
chdir("apt");
include("quickvm_sup.php");
# Must be after quickvm_sup.php since it changes the auth domain.
$page_title = "Show Image";
#
# Get current user.
#
RedirectSecure();
$this_user = CheckLoginOrRedirect();
$this_idx = $this_user->uid_idx();
$isadmin = (ISADMIN() ? "true" : "false");
#
# Verify page arguments.
#
$reqargs = RequiredPageArguments("image", PAGEARG_IMAGE);
$optargs = OptionalPageArguments("edit", PAGEARG_BOOLEAN,
"formfields", PAGEARG_ARRAY);
if (!$image) {
SPITUSERERROR("No such image!");
}
if (!$image->AccessCheck($this_user, $TB_IMAGEID_MODIFYINFO)) {
SPITUSERERROR("Not enough permission!");
}
$uuid = $image->uuid();
if ($edit) {
$action = "edit";
}
else {
$action = "view";
}
SPITHEADER(1);
# Place to hang the toplevel template.
echo "<div id='main-body'></div>\n";
echo "<link rel='stylesheet'
href='css/jquery-ui.min.css'>\n";
echo "<script type='text/javascript'>\n";
echo " window.UUID = '$uuid';\n";
echo " window.ACTION = '$action';\n";
echo " window.ISADMIN = $isadmin;\n";
echo "</script>\n";
REQUIRE_UNDERSCORE();
REQUIRE_SUP();
REQUIRE_MOMENT();
REQUIRE_APTFORMS();
SPITREQUIRE("js/create-image.js");
AddTemplateList(array("create-image",
"oops-modal", "waitwait-modal"));
SPITFOOTER();
?>
<?php
#
# Copyright (c) 2000-2019 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
# This file is part of the Emulab network testbed software.
#
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# This file is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
# License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this file. If not, see <http://www.gnu.org/licenses/>.
#
# }}}
#
chdir("..");
include_once("webtask.php");
include_once("imageid_defs.php");
include_once("osiddefs.php3");
include_once("node_defs.php");
chdir("apt");
#
# All functions take the image uuid,
#
$image = null;
function CheckPageArgs($write)
{
global $this_user, $ajax_args, $image;
global $TB_IMAGEID_MODIFYINFO, $TB_IMAGEID_READINFO;
if (!isset($ajax_args["uuid"])) {
SPITAJAX_ERROR(-1, "Missing image uuid");
return -1;
}
$uuid = $ajax_args["uuid"];
if (!IsValidUUID($uuid)) {
SPITAJAX_ERROR(-1, "Invalid image uuid");
return -1;
}
$image = Image::LookupByUUID($uuid);
if (!$image) {
SPITAJAX_ERROR(-1, "No such image");
return -1;
}
if (ISADMIN()) {
return 0;
}
if (($write &&
! $image->AccessCheck($this_user, $TB_IMAGEID_MODIFYINFO)) ||
! $image->AccessCheck($this_user, $TB_IMAGEID_READINFO)) {
SPITAJAX_ERROR(-1, "Not enough permission");
return -1;
}
return 0;
}
#
# Get the info for an image.
#
function Do_GetInfo()
{
global $this_user, $ajax_args, $image, $embedded;
global $TBBASE, $ISEMULAB, $TBMAINSITE, $OURDOMAIN;
if (CheckPageArgs(0)) {
return;
}
$embedded = isset($ajax_args["embedded"]) && $ajax_args["embedded"];
$domain = $OURDOMAIN;
if ($TBMAINSITE) {
$domain = "emulab.net";
}
$osinfo = $image->OSinfo();
$id = $image->imageid();
$vers = $image->version();
$uuid = $image->uuid();
$image_uuid = $image->image_uuid();
$pid = $image->pid();
$gid = $image->gid();
$name = $image->imagename();
if ($image->isdataset()) {
$domain .= ":${pid}";
if ($pid != $gid) {
$domain .= ":${gid}";
}
$urn = "urn:publicid:IDN+${domain}+imdataset+${name}";
}
else {
$urn = "urn:publicid:IDN+${domain}+image+${pid}//${name}";
}
$blob = array();
$blob["name"] = $image->imagename();
$blob["imageid"] = $image->imageid();
$blob["uuid"] = $image->uuid();
$blob["image_uuid"] = $image->image_uuid();
$blob["urn"] = $urn;
$blob["version"] = $image->version();
$blob["pid"] = $image->pid();
$blob["gid"] = $image->gid();
$blob["description"] = $image->description();
$blob["created"] = DateStringGMT($image->created());
$blob["creator"] = $image->creator();
$blob["creator_urn"] = $image->creator_urn();
$blob["updated"] = DateStringGMT($image->updated());
$blob["updater"] = $image->updater();
$blob["updater_urn"] = $image->updater_urn();
$blob["lastused"] = DateStringGMT($image->LastUsed());
$blob["path"] = $image->path();
$blob["shared"] = $image->shared() ? 1 : 0;
$blob["global"] = $image->isglobal() ? 1 : 0;
$blob["ready"] = $image->ready() ? 1 : 0;
$blob["released"] = $image->released() ? 1 : 0;
$blob["isdataset"] = $image->isdataset() ? 1 : 0;
$blob["hash"] = $image->hash();
$blob["version_url"] = "show-image.php?imageid=${id}&version=${vers}";
if ($embedded) {
$blob["version_url"] .= "&embedded=1";
}
$blob["version_file_url"] = "$TBBASE/image_metadata.php?uuid=$uuid";
$blob["image_file_url"] = "$TBBASE/image_metadata.php?uuid=$image_uuid";
if (!$image->isdataset()) {
if ($image->architecture()) {
$blob["architecture"] = $image->architecture();
}
$blob["loadpart"] = $image->loadpart();
$blob["loadlength"] = $image->loadlength();
$blob["mbr_version"] = $image->mbr_version();
$blob["types"] = $image->Types();
$blob["reboot_waittime"] = $osinfo->reboot_waittime();
$blob["op_mode"] = $osinfo->op_mode();
$blob["os"] = $osinfo->OS();
$blob["os_version"] = $osinfo->version();
$blob["os_features"] = split(",", $osinfo->osfeatures());
$blob["xen_capable"] = 0;
if ($osinfo->def_parentosid()) {
$n_image = Image::Lookup($osinfo->def_parentosid());
if ($n_image) {
$n_imageid = $n_image->imageid();
$n_version = $n_image->version();
$n_url = "show-image.php?imageid=${n_imageid}" .
"&version=${n_version}";
if ($embedded) {
$n_url .= "&embedded=1";
}
$blob["def_parent_image_uuid"] = $n_image->uuid();
$blob["def_parent_image_name"] = $n_image->imagename();
$blob["def_parent_image_vers"] = $n_image->version();
$blob["def_parent_image_url"] = $n_url;
if ($n_image->OSinfo()->FeatureSupported("xen-host")) {
$blob["xen_capable"] = 1;
}
}
}
$xenflip = ($blob["xen_capable"] ? 0 : 1);
$blob["xen_capable_url"] =
"toggle.php?imageid=${id}&type=imagedoesxen&value=$xenflip";
if ($image->notes() && $image->notes() != "") {
$blob["notes"] = $image->notes();
}
else {
$blob["notes"] = "";
}
if ($image->loadpart() == 0 && $image->loadlength() == 4) {
$blob["wholedisk"] = true;
}
else {
$blob["wholedisk"] = false;
}
}
if ($image->parent_imageid()) {
$p_imageid = $image->parent_imageid();
$p_version = $image->parent_version();
$p_image = Image::Lookup($p_imageid, $p_version);
# On an elabinelab we will not have the previous version.
# if it came in at creation time.
if ($p_image) {
$p_imagename = $p_image->imagename();
$p_url = "show-image.php?imageid=${p_imageid}" .
"&version=${p_version}";
if ($embedded) {
$p_url .= "&embedded=1";
}
$blob["parent_image_uuid"] = $p_image->uuid();
$blob["parent_image_name"] = $p_image->imagename();
$blob["parent_image_vers"] = $p_image->version();
$blob["parent_image_url"] = $p_url;
}
}
if ($image->version() > 0 &&
(is_null($image->parent_imageid()) ||
($image->parent_imageid() &&
$image->parent_imageid() != $image->imageid()))) {
$blob["previous_image_vers"] = $image->version() - 1;
}
# Look for an unreleased version of this image.
$unreleased = $image->LookupUnreleased();
if ($unreleased && $unreleased->version() != $image->version()) {
$blob["unreleased_image_vers"] = $unreleased->version();
}
SPITAJAX_RESPONSE($blob);
}
#
# Modify a single value.
#
function Do_Modify()
{
global $this_user, $ajax_args, $image;
global $TBBASE, $ISEMULAB, $TBMAINSITE, $OURDOMAIN;
global $osid_featurelist;
if (CheckPageArgs(1)) {
return;
}
$uuid = $image->uuid();
if (!isset($ajax_args["field"])) {
SPITAJAX_ERROR(-1, "Missing field name");
return -1;
}
$field = $ajax_args["field"];
if (!isset($ajax_args["value"])) {
SPITAJAX_ERROR(-1, "Missing new value");
return -1;
}
$value = $ajax_args["value"];
#
# We can handle these few fields. Value indicates adminonly
#
$allowed = array("reboot_waittime" => true,
"description" => false,
"path" => true,
"osfeatures" => true,
);
if (!array_key_exists($field, $allowed)) {
SPITAJAX_ERROR(-1, "Not allowed to change this field");
return -1;
}
if ($allowed[$field] && !ISADMIN()) {
SPITAJAX_ERROR(-1, "No permission to change this field");
return -1;
}
if ($field == "reboot_waittime" || $field == "osfeatures") {
$table = "os_info";
}
else {
$table = "images";
}
if (!TBcheck_dbslot($value, $table, $field,
TBDB_CHECKDBSLOT_WARN|TBDB_CHECKDBSLOT_ERROR)) {
SPITAJAX_ERROR(1, "Illegal value: " . TBFieldErrorString());
return 1;
}
if ($field == "osfeatures") {
foreach (preg_split("/,/", $value) as $feature) {
if (!array_key_exists($feature, $osid_featurelist)) {
SPITAJAX_ERROR(-1, "Invalid feature: $feature");
return -1;
}
}
}
$safe_value = DBQuoteSpecial($value);
if ($field == "osfeatures" || $field == "reboot_waittime") {
$imageid = $image->imageid();
$version = $image->version();
$query_result =
DBQueryWarn("update os_info_versions set ${field}='$safe_value' ".
"where osid='$imageid' and vers='$version'");
}
else {
$query_result =
DBQueryWarn("update image_versions set ${field}='$safe_value' ".
"where uuid='$uuid'");
}
if (!$query_result) {
SPITAJAX_ERROR(-1, "Internal error updating database");
return -1;
}
SPITAJAX_RESPONSE(1);
}
#
# Just the admin notes
#
function Do_SaveAdminNotes()
{
global $this_user, $ajax_args, $image;
global $TBBASE, $ISEMULAB, $TBMAINSITE, $OURDOMAIN;
if (CheckPageArgs(1)) {
return;
}
if (!ISADMIN()) {
SPITAJAX_ERROR(-1, "Not enough permission");
return -1;
}
$uuid = $image->uuid();
if (!isset($ajax_args["notes"])) {
SPITAJAX_ERROR(-1, "Missing the notes");
return -1;
}
$notes = $ajax_args["notes"];
if ($notes != "" && !TBvalid_fulltext($notes)) {
SPITAJAX_ERROR(-1, "Invalid characters in notes");