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

I found an old scrap of paper on my desk that said to add a Save

ParamSet button to the instantiate page. So here it is.
parent 5ec7e2df
......@@ -1801,13 +1801,14 @@ sub Bindings()
#
sub ParamSet()
{
my $optlist = "u:m:bp";
my $optlist = "u:m:bpB:";
my $bound = 0;
my $asparamdefs= 0;
my $user;
my $description;
my $bindings;
my $errmsg;
my $instance;
my %options = ();
if (! getopts($optlist, \%options)) {
......@@ -1837,7 +1838,7 @@ sub ParamSet()
UserErrorSane({"name" => "Alphanumeric no greater then 32 characters"});
}
my $safe_name = DBQuoteSpecial($name);
my $profile = APT_Profile->Lookup(shift(@ARGV));
if (!defined($profile)) {
fatal("No such profile");
......@@ -1864,9 +1865,41 @@ sub ParamSet()
}
return 0;
}
usage()
if (@ARGV != 1);
#
# We either get an instance or a file with an XML fragment.
#
if (defined($options{"B"})) {
fatal("Bindings file cannot be read")
if (! -e $options{"B"});
my $xml = emutil::ReadFile($options{"B"});
fatal("Invalid bindings XML")
if (!defined($xml) || $xml eq "");
# I know, silly. But necessary.
$xml = "<rspec>$xml</rspec>";
if (APT_Profile::GetBindings($xml, \$bindings, \$errmsg, 0)) {
fatal($errmsg);
}
}
else {
usage()
if (@ARGV != 1);
$instance = APT_Instance->Lookup($ARGV[0]);
if (!$instance) {
$instance = APT_Instance::History->Lookup($ARGV[0]);
if (!$instance) {
fatal("No such instance");
}
}
my $rspec = GeniXML::Parse($instance->rspec());
if (! defined($rspec)) {
fatal("Could not parse rspec");
}
if (APT_Profile::GetBindings($rspec, \$bindings, \$errmsg, 0)) {
fatal($errmsg);
}
}
if (defined($options{"m"})) {
$description = $options{"m"};
if (! TBcheck_dbslot($description, "default", "tinytext",
......@@ -1881,6 +1914,7 @@ sub ParamSet()
if (defined($options{"b"})) {
$bound = 1;
}
# Ensure name is unique.
my $query_result =
DBQueryWarn("select uuid from apt_parameter_sets ".
......@@ -1892,20 +1926,6 @@ sub ParamSet()
UserErrorSane({"name" => "Already in use"});
}
my $instance = APT_Instance->Lookup($ARGV[0]);
if (!$instance) {
$instance = APT_Instance::History->Lookup($ARGV[0]);
if (!$instance) {
fatal("No such instance");
}
}
my $rspec = GeniXML::Parse($instance->rspec());
if (! defined($rspec)) {
fatal("Could not parse rspec");
}
if (APT_Profile::GetBindings($rspec, \$bindings, \$errmsg, 0)) {
fatal($errmsg);
}
print Dumper($bindings);
$bindings = eval { encode_json($bindings); };
if ($@) {
......@@ -1923,8 +1943,13 @@ sub ParamSet()
if ($bound) {
$query .= ",version_uuid=" . DBQuoteSpecial($profile->uuid());
if ($profile->repourl()) {
$query .= ",reporef=" . DBQuoteSpecial($instance->reporef());
$query .= ",repohash=" . DBQuoteSpecial($instance->repohash());
if (defined($instance)) {
$query .= ",reporef=" . DBQuoteSpecial($instance->reporef());
$query .= ",repohash=" . DBQuoteSpecial($instance->repohash());
}
else {
$query .= ",repohash=" . DBQuoteSpecial($profile->repohash());
}
}
}
$query_result = DBQueryWarn($query);
......
......@@ -554,7 +554,8 @@ if (!isset($create)) {
AddTemplateList(array("instantiate-new",
"aboutapt", "aboutcloudlab", "aboutpnet",
"waitwait-modal", "rspectextview-modal",
"picker-template","reservation-graph"));
"picker-template","reservation-graph",
"save-paramset-modal"));
SPITFOOTER();
return;
}
......
......@@ -270,6 +270,22 @@ $(function ()
container: 'body',
});
/*
* The save paramset bindings button. This will be hidden when
* the user selects a non-pp profle.
*/
$('#save_paramset_button')
.popover({
trigger: 'hover',
placement: 'auto',
container: 'body',
})
.click(function (event) {
paramsets.InitSaveParameterSet('#save_paramset_div',
selected_uuid,
selected_rspec);
});
// Format the step labels across the top to match the panel widths.
$('#stepsContainer .steps').addClass('col-lg-8 col-lg-offset-2 col-md-8 col-md-offset-2 col-sm-10 col-sm-offset-1 col-xs-12 col-xs-offset-0');
$('#stepsContainer .actions').addClass('col-lg-8 col-lg-offset-2 col-md-8 col-md-offset-2 col-sm-10 col-sm-offset-1 col-xs-12 col-xs-offset-0');
......@@ -1703,8 +1719,8 @@ $(function ()
$('#showtopo_title').html("<h3>" + profile_blob.name + "</h3>");
$('#showtopo_description').html(profile_blob.description);
$('#selected_profile_description').html(profile_blob.description);
$('#finalize_profile_name').text(profile_blob.name);
$('#finalize_profile_version').text(profile_blob.version);
$('#finalize_profile_name')
.text(profile_blob.name + ":" + profile_blob.version);
ispprofile = profile_blob.ispprofile;
isscript = profile_blob.isscript;
......@@ -1718,6 +1734,12 @@ $(function ()
else {
ppstart = window.ppstartOld;
}
if (ispprofile) {
$('#save_paramset_button').removeClass("hidden");
}
else {
$('#save_paramset_button').addClass("hidden");
}
// Not allowed to copy a repo based profile.
if (profile_blob.fromrepo) {
......
......@@ -5,29 +5,51 @@ $(function () {
window.paramsets = (function()
{
'use strict';
var PNS = "http://www.protogeni.net/resources/rspec" +
"/ext/profile-parameters/1";
/*
* Got this from:
* stackoverflow.com/questions/11892118/jquery-parsexml-and-print
*/
function xmlToString(xmlData)
{
var xmlString;
//IE
if (window.ActiveXObject){
xmlString = xmlData.xml;
}
// code for Mozilla, Firefox, Opera, etc.
else {
var node = xmlData.item(0);
xmlString = (new XMLSerializer()).serializeToString(node);
}
return xmlString;
}
//
// Throw up a modal to create and save a parameter set using the
// provided profile and instance uuid.
//
function InitSaveParameterSet(domid, profile_uuid, instance_uuid)
function InitSaveParameterSet(domid, profile_uuid, uuidORrspec)
{
console.info("InitSaveParameterSet", domid, profile_uuid,
instance_uuid);
var templates = APT_OPTIONS
console.info("InitSaveParameterSet", domid, profile_uuid);
var templates = APT_OPTIONS
.fetchTemplateList(['save-paramset-modal']);
$(domid).html(templates['save-paramset-modal']);
// Bind the save button.
$('#save-paramset-confirm').click(function (event) {
SaveParameterSet(profile_uuid, instance_uuid);
SaveParameterSet(profile_uuid, uuidORrspec);
});
sup.ShowModal('#save-paramset-modal', function () {
$('#save-paramset-confirm').off("click");
});
sup.ShowModal('#save-paramset-modal');
}
// Save a paramset set.
function SaveParameterSet(profile_uuid, instance_uuid)
function SaveParameterSet(profile_uuid, uuidORrspec)
{
var name = $.trim($('#paramset-name').val());
var desc = $.trim($('#paramset-description').val());
......@@ -53,11 +75,23 @@ $(function () {
}
var args = {
"profile_uuid" : profile_uuid,
"instance_uuid" : instance_uuid,
"name" : name,
"description" : desc,
"bound" : bound,
};
if (sup.IsUUID(uuidORrspec)) {
args["instance_uuid"] = uuidORrspec;
}
else {
var xmlDoc = $.parseXML(uuidORrspec);
var bindings = xmlDoc.getElementsByTagNameNS(PNS, 'data_set');
args["bindings"] = xmlToString(bindings);
}
console.info(args);
if (false) {
sup.HideModal('#save-paramset-modal');
return;
}
var callback = function (json) {
console.info(json);
if (json.code) {
......
......@@ -28,6 +28,11 @@ function ParseURN(urn)
return hrn;
}
function IsUUID(uuid)
{
return /^[\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12}$/.test(uuid);
}
function ShowModal(which, hidefunction)
{
var callback = function() {
......@@ -468,6 +473,7 @@ function ConfirmModal(args)
// Exports from this module for use elsewhere
return {
ParseURN: ParseURN,
IsUUID: IsUUID,
ShowModal: ShowModal,
HideModal: HideModal,
ShowWaitWait: ShowWaitWait,
......
......@@ -34,6 +34,8 @@ function Do_Create()
{
global $this_user, $ajax_args;
$errors = array();
$opts = "";
$args = "";
if (!isset($ajax_args["profile_uuid"])) {
SPITAJAX_ERROR(-1, "Missing profile uuid");
......@@ -49,22 +51,26 @@ function Do_Create()
SPITAJAX_ERROR(-1, "No such profile");
return;
}
if (!isset($ajax_args["instance_uuid"])) {
SPITAJAX_ERROR(-1, "Missing instance uuid");
if (! (isset($ajax_args["instance_uuid"]) ||
isset($ajax_args["bindings"]))) {
SPITAJAX_ERROR(-1, "Missing instance uuid or bindings xml");
return;
}
$instance_uuid = $ajax_args["instance_uuid"];
if (!IsValidUUID($instance_uuid)) {
SPITAJAX_ERROR(-1, "Not a valid instanceuuid");
return;
}
$record = Instance::Lookup($instance_uuid);
if (!$record) {
$record = InstanceHistory::Lookup($instance_uuid);
if (!$record) {
SPITAJAX_ERROR(-1, "No such record: $uuid");
if (isset($ajax_args["instance_uuid"])) {
$instance_uuid = $ajax_args["instance_uuid"];
if (!IsValidUUID($instance_uuid)) {
SPITAJAX_ERROR(-1, "Not a valid instance uuid");
return;
}
$record = Instance::Lookup($instance_uuid);
if (!$record) {
$record = InstanceHistory::Lookup($instance_uuid);
if (!$record) {
SPITAJAX_ERROR(-1, "No such record: $uuid");
return;
}
}
$args = $instance_uuid;
}
if (!isset($ajax_args["name"])) {
SPITAJAX_ERROR(-1, "Missing name");
......@@ -93,19 +99,33 @@ function Do_Create()
SPITAJAX_ERROR(2, $errors);
return;
}
if (isset($ajax_args["bindings"])) {
# This is an XML fragment. Write to a file and let the backend
# script decide if its a valid XML document.
$bindings = $ajax_args["bindings"];
$filename = tempnam("/tmp", "bindings");
$fp = fopen($filename, "w");
fwrite($fp, $bindings);
fclose($fp);
chmod($filename, 0666);
$opts = "-B $filename";
}
$safe_name = escapeshellarg($name);
$safe_description = escapeshellarg($description);
$webtask = WebTask::CreateAnonymous();
$webtask_id = $webtask->task_id();
$command = "webmanage_profile -t $webtask_id paramset ".
"-m $safe_description $bound ".
" add $safe_name $profile_uuid $instance_uuid";
"-m $safe_description $bound $opts ".
" add $safe_name $profile_uuid $args";
$retval = SUEXEC($this_user->uid(), "nobody",
$command, SUEXEC_ACTION_IGNORE);
$webtask->Refresh();
if (isset($filename)) {
unlink($filename);
}
if ($retval != 0) {
if (!$webtask->exited() || $retval < 0) {
SUEXECERROR(SUEXEC_ACTION_CONTINUE);
......
......@@ -313,26 +313,27 @@
class='col-lg-8 col-md-8 col-sm-8 col-xs-12'>
<div class='panel panel-default' style="margin-bottom: 5px">
<div class='panel-body'
style="padding-top: 5px; padding-bottom: 0px;">
<table class='table table-condensed nospaceafter border-none'
style="font-size: 14px; font-family: Arial,sans-serif;">
<tr>
<td style="padding: 0px; border: 0;">
<span style="font-weight: bolder;">Profile:</span>
<span id='finalize_profile_name'><%= profilename %></span>
</td>
<td style="padding: 0px; border: 0;">
<span style="font-weight: bolder;">Version:</span>
<span id='finalize_profile_version'><%= profilevers %>
</span>
</td>
<td style="padding: 0px; border: 0;">
<button class='btn btn-primary btn-xs'
type='button'
id="show_xml_modal_button">
Source</button></td>
</tr>
</table>
style="padding-top: 5px; padding-bottom: 5px;">
<span class="pull-left">
<span style="font-weight: bolder;">Profile:</span>
<span id='finalize_profile_name'></span>
</span>
<span class="pull-right">
<button class='btn btn-primary btn-xs hidden'
type='button'
id="save_paramset_button"
data-toggle='popover'
data-delay='{"hide":100, "show":300}'
data-content='Save the parameters used to create this
experiment, so you can quickly apply them
when starting a new experiment using this
profile. Click for more information.'>
Save Parameters</button>
<button class='btn btn-info btn-xs'
type='button'
id="show_xml_modal_button">
Source</button>
</span>
</div>
</div>
<% if (!registered) { %>
......@@ -1024,3 +1025,4 @@
<div id='ppmodal_div'></div>
<div id='instantiate_div'></div>
<div id='editmodal_div'></div>
<div id='save_paramset_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