Commit 645dccd7 authored by Leigh B Stoller's avatar Leigh B Stoller

The Web UI part of repository-based profiles.

parent 92d64446
...@@ -131,6 +131,9 @@ class Instance ...@@ -131,6 +131,9 @@ class Instance
function servername() { return $this->field('servername'); } function servername() { return $this->field('servername'); }
function aggregate_urn(){ return $this->field('aggregate_urn'); } function aggregate_urn(){ return $this->field('aggregate_urn'); }
function private_key() { return $this->field('privkey'); } function private_key() { return $this->field('privkey'); }
function repourl() { return $this->field('repourl'); }
function reporef() { return $this->field('reporef'); }
function repohash() { return $this->field('repohash'); }
function isopenstack() { return $this->field('isopenstack'); } function isopenstack() { return $this->field('isopenstack'); }
function openstack_utilization() { function openstack_utilization() {
return $this->field('openstack_utilization'); return $this->field('openstack_utilization');
......
...@@ -103,11 +103,22 @@ function Do_GetParameters() ...@@ -103,11 +103,22 @@ function Do_GetParameters()
SPITAJAX_ERROR(1, "Not enough permission to instantiate profile"); SPITAJAX_ERROR(1, "Not enough permission to instantiate profile");
return; return;
} }
if (!$profile->isParameterized()) { #
# For a repo-based profile, the paramdefs will be passed in.
# Note that different refspecs might be parameterized, but others not.
#
if ($profile->repourl() &&
isset($ajax_args["paramdefs"]) && $ajax_args["paramdefs"] != "") {
$paramdefs = $ajax_args["paramdefs"];
}
elseif (!$profile->isParameterized()) {
SPITAJAX_ERROR(1, "Not a parameterized profile"); SPITAJAX_ERROR(1, "Not a parameterized profile");
return; return;
} }
list ($formfrag, $defaults) = $profile->GenerateFormFragment(); else {
$paramdefs = $profile->paramdefs();
}
list ($formfrag, $defaults) = $profile->GenerateFormFragment($paramdefs);
SPITAJAX_RESPONSE(array("formfrag" => htmlentities($formfrag), SPITAJAX_RESPONSE(array("formfrag" => htmlentities($formfrag),
"defaults" => $defaults)); "defaults" => $defaults));
} }
...@@ -820,8 +831,29 @@ function Do_Submit() ...@@ -820,8 +831,29 @@ function Do_Submit()
# we could get an rspec. # we could get an rspec.
# #
if ($profile->isParameterized() && $this_user && if ($profile->isParameterized() && $this_user &&
isset($formfields["pp_rspec"]) && $formfields["pp_rspec"] != "") { isset($formfields["rspec"]) && $formfields["rspec"] != "") {
$args["rspec"] = $formfields["pp_rspec"]; $args["rspec"] = $formfields["rspec"];
}
#
# For a repo-based profile, we might get an rspec and/or a script.
# Need to deal with the paramdefs block too.
#
if ($profile->repourl() && $this_user) {
if (isset($formfields["script"]) && $formfields["script"] != "") {
$args["script"] = $formfields["script"];
}
if (isset($formfields["rspec"]) && $formfields["rspec"] != "") {
$args["rspec"] = $formfields["rspec"];
}
# If the user is instantiating the profile version, we will not
# get these.
if (isset($formfields["reporef"]) && $formfields["reporef"] != "") {
$args["reporef"] = $formfields["reporef"];
}
if (isset($formfields["repohash"]) && $formfields["repohash"] != "") {
$args["repohash"] = $formfields["repohash"];
}
} }
$aggregate_urn = ""; $aggregate_urn = "";
......
...@@ -58,6 +58,7 @@ $optargs = OptionalPageArguments("create", PAGEARG_STRING, ...@@ -58,6 +58,7 @@ $optargs = OptionalPageArguments("create", PAGEARG_STRING,
"asguest", PAGEARG_BOOLEAN, "asguest", PAGEARG_BOOLEAN,
"default", PAGEARG_STRING, "default", PAGEARG_STRING,
"from", PAGEARG_STRING, "from", PAGEARG_STRING,
"refspec", PAGEARG_STRING,
"formfields", PAGEARG_ARRAY); "formfields", PAGEARG_ARRAY);
if ($ISAPT && !$this_user) { if ($ISAPT && !$this_user) {
...@@ -317,6 +318,7 @@ function SPITFORM($formfields, $newuser, $errors) ...@@ -317,6 +318,7 @@ function SPITFORM($formfields, $newuser, $errors)
global $TBBASE, $APTMAIL, $ISAPT, $ISCLOUD, $ISPNET, $PORTAL_NAME; global $TBBASE, $APTMAIL, $ISAPT, $ISCLOUD, $ISPNET, $PORTAL_NAME;
global $profile_array, $this_user, $profilename, $profile; global $profile_array, $this_user, $profilename, $profile;
global $projlist, $skipfirststep, $TBMAINSITE; global $projlist, $skipfirststep, $TBMAINSITE;
global $refspec;
$showabout = ($ISAPT && !$this_user ? 1 : 0); $showabout = ($ISAPT && !$this_user ? 1 : 0);
$registered = (isset($this_user) ? "true" : "false"); $registered = (isset($this_user) ? "true" : "false");
...@@ -400,6 +402,15 @@ function SPITFORM($formfields, $newuser, $errors) ...@@ -400,6 +402,15 @@ function SPITFORM($formfields, $newuser, $errors)
echo " window.SKIPFIRSTSTEP = " . ($skipfirststep ? "true" : "false") . ";\n"; echo " window.SKIPFIRSTSTEP = " . ($skipfirststep ? "true" : "false") . ";\n";
echo " window.PORTAL_NAME = '$PORTAL_NAME';\n"; echo " window.PORTAL_NAME = '$PORTAL_NAME';\n";
echo " window.USERNAME = '" . $formfields["username"] . "';\n"; echo " window.USERNAME = '" . $formfields["username"] . "';\n";
if (isset($profile) && $profile->repourl()) {
echo " window.FROMREPO = true;\n";
if (isset($refspec)) {
echo " window.REFSPEC = '$refspec';\n";
}
}
else {
echo " window.FROMREPO = false;\n";
}
echo "</script>\n"; echo "</script>\n";
echo "<script src='js/lib/jquery-2.0.3.min.js'></script>\n"; echo "<script src='js/lib/jquery-2.0.3.min.js'></script>\n";
...@@ -411,8 +422,10 @@ function SPITFORM($formfields, $newuser, $errors) ...@@ -411,8 +422,10 @@ function SPITFORM($formfields, $newuser, $errors)
REQUIRE_FORMHELPERS(); REQUIRE_FORMHELPERS();
REQUIRE_FILESTYLE(); REQUIRE_FILESTYLE();
REQUIRE_MARKED(); REQUIRE_MARKED();
REQUIRE_MOMENT();
REQUIRE_JACKS(); REQUIRE_JACKS();
REQUIRE_JQUERY_STEPS(); REQUIRE_JQUERY_STEPS();
AddLibrary("js/gitrepo.js");
SPITREQUIRE("js/instantiate-new.js"); SPITREQUIRE("js/instantiate-new.js");
} }
......
...@@ -63,6 +63,10 @@ $(function () { ...@@ -63,6 +63,10 @@ $(function () {
if (_.has(item.dataset, "colsize")) { if (_.has(item.dataset, "colsize")) {
colsize = item.dataset['colsize'];; colsize = item.dataset['colsize'];;
} }
// Override wide setting per field
if (_.has(item.dataset, "wide")) {
wide = item.dataset['wide'];;
}
/* /*
* Wrap in a div we can name. We assume the form * Wrap in a div we can name. We assume the form
......
...@@ -412,7 +412,9 @@ $(function () ...@@ -412,7 +412,9 @@ $(function ()
disabled: true, disabled: true,
versions: [], versions: [],
withpublishing: false, withpublishing: false,
genilib_editor: true genilib_editor: true,
canrepo: false,
fromrepo: false
}); });
manage_html = aptforms.FormatFormFieldsHorizontal(manage_html, manage_html = aptforms.FormatFormFieldsHorizontal(manage_html,
{"wide": false }); {"wide": false });
...@@ -464,7 +466,9 @@ $(function () ...@@ -464,7 +466,9 @@ $(function ()
disabled: true, disabled: true,
versions: [], versions: [],
withpublishing: false, withpublishing: false,
genilib_editor: true genilib_editor: true,
canrepo: false,
fromrepo: false
}); });
manage_html = aptforms.FormatFormFieldsHorizontal(manage_html, manage_html = aptforms.FormatFormFieldsHorizontal(manage_html,
{'wide': false }); {'wide': false });
......
$(function () {
window.gitrepo = (function () {
var repoString = APT_OPTIONS.fetchTemplate('gitrepo-picker');
var repoTemplate = _.template(repoString);
var branchlist = null;
var taglist = null;
/*
* Get the branches and tags for a profile, and draw the picker.
*/
function InitRepoPicker(uuid, change_callback)
{
var callback = function(json) {
console.info(json);
if (json.code) {
console.info(json.value);
return;
}
branchlist = json.value.branchlist;
taglist = json.value.taglist;
ShowRepoPicker(uuid, change_callback);
}
// Visible cue that something is happening
$('#gitpicker-div table').css("opacity", 0.4);
var xmlthing = sup.CallServerMethod(null,
"manage_profile",
"GetBranchList",
{"uuid" : uuid});
xmlthing.done(callback);
}
function ShowRepoPicker(uuid, change_callback)
{
var html = repoTemplate({"branches" : branchlist,
"tags" : taglist,
"uuid" : uuid});
$('#gitpicker-div').removeClass("hidden");
$('#gitpicker-div table').css("opacity", '');
$('#gitrepo-picker').html(html);
if (change_callback !== undefined) {
$('.branch-button').click(function (event) {
event.preventDefault();
change_callback($(this).data("which"));
});
}
}
/*
* Get source code for a branch or tag and send it back to caller.
* Also update the info panel as on the manage/show page.
*/
function GetRepoSource(uuid, refspec, caller_callback)
{
var callback = function(json) {
console.info(json);
if (json.code) {
sup.HideWaitWait();
sup.SpitOops(json.value);
caller_callback(null);
return;
}
sup.HideWaitWait(function() {
caller_callback(json.value.script, json.value.hash);
});
GetCommitInfo(uuid, refspec);
}
sup.ShowWaitWait("We are getting the source code from the " +
"repository. Patience please.");
var xmlthing = sup.CallServerMethod(null,
"manage_profile",
"GetRepoSource",
{"uuid" : uuid,
"refspec" : refspec});
xmlthing.done(callback);
}
/*
* The manage/show page both have a panel for the currently
* loaded commit. Update that panel when we get new source.
*/
function UpdateInfoPanel(blob)
{
$('#repoinfo-panel .commit-hash').text(blob.hash);
$('#repoinfo-panel .commit-author').html(blob.author);
$('#repoinfo-panel .commit-refspec').html(blob.refspec);
$('#repoinfo-panel .commit-date')
.html(moment(blob.date).format("lll"));
var log = blob.log;
if (log.length <= 20) {
$('#repoinfo-panel .commit-log-start').html(log);
$('#repoinfo-panel .commit-log .log').addClass("hidden");
}
else {
$('#repoinfo-panel .commit-log-start').html(log.substr(0,20));
$('#repoinfo-panel .commit-log .log').popover('destroy');
// DUMB! destroy is async.
setTimeout(function () {
$('#repoinfo-panel .commit-log .log').popover({
trigger: 'hover',
placement: 'auto',
container: 'body',
content: "<pre>" + log + "</pre>",
});}, 200);
$('#repoinfo-panel .commit-log .log').removeClass("hidden");
}
$('#repoinfo-panel .panel-body').css("opacity", '');
$('#repoinfo-panel').removeClass("hidden");
}
/*
* Ask for commit info, then update the info panel.
*/
function GetCommitInfo(uuid, refspec)
{
if (refspec === undefined) {
refspec = "refs/heads/master";
}
var callback = function(json) {
console.info(json);
if (json.code) {
console.info("GetCommitInfo", json.value);
return;
}
json.value.refspec = refspec;
UpdateInfoPanel(json.value);
}
// Visible cue that something is happening
$('#repoinfo-panel .panel-body').css("opacity", 0.4);
var args = {"uuid" : uuid, "refspec" : refspec}
var xmlthing = sup.CallServerMethod(null,
"manage_profile",
"GetCommitInfo", args);
xmlthing.done(callback);
}
/*
* Update from repo, possibly getting a new script or rspec.
*/
function UpdateRepo(uuid, caller_callback)
{
var callback = function(json) {
console.info(json);
if (json.code) {
sup.HideWaitWait();
sup.SpitOops(json.value);
caller_callback(null);
return;
}
sup.HideWaitWait(function() {
caller_callback(json.value);
});
}
sup.ShowWaitWait("We are attempting to pull from your repository. "+
"Patience please.");
var xmlthing = sup.CallServerMethod(null,
"manage_profile",
"UpdateRepository",
{uuid : uuid});
xmlthing.done(callback);
}
// Exports from this module for use elsewhere
return {
InitRepoPicker: InitRepoPicker,
GetRepoSource: GetRepoSource,
UpdateRepo: UpdateRepo,
GetCommitInfo: GetCommitInfo,
};
})();
});
...@@ -31,6 +31,7 @@ $(function () ...@@ -31,6 +31,7 @@ $(function ()
var amValueToKey = {}; var amValueToKey = {};
var showpicker = 0; var showpicker = 0;
var portal = null; var portal = null;
var fromrepo = false;
var registered = false; var registered = false;
var JACKS_NS = "http://www.protogeni.net/resources/rspec/ext/jacks/1"; var JACKS_NS = "http://www.protogeni.net/resources/rspec/ext/jacks/1";
var jacks = { var jacks = {
...@@ -59,6 +60,7 @@ $(function () ...@@ -59,6 +60,7 @@ $(function ()
multisite = window.MULTISITE; multisite = window.MULTISITE;
portal = window.PORTAL; portal = window.PORTAL;
ajaxurl = window.AJAXURL; ajaxurl = window.AJAXURL;
fromrepo = window.FROMREPO;
doconstraints = window.DOCONSTRAINTS; doconstraints = window.DOCONSTRAINTS;
showpicker = window.SHOWPICKER; showpicker = window.SHOWPICKER;
...@@ -1172,8 +1174,87 @@ $(function () ...@@ -1172,8 +1174,87 @@ $(function ()
var $xmlthing = sup.CallServerMethod(ajaxurl, var $xmlthing = sup.CallServerMethod(ajaxurl,
"instantiate", "GetProfile", "instantiate", "GetProfile",
{"uuid" : profile}); {"uuid" : profile});
/*
* If a repo-based and we got a specific branch/tag, we have to
* get the source for that, since it will be different then what
* is stored in the profile descriptor.
*/
if (fromrepo && window.REFSPEC !== undefined) {
var which = window.REFSPEC;
$xmlthing.done(function(json) {
gitrepo.GetRepoSource(profile, which, function(source, hash) {
var pythonRe = /^import/m;
$('#repohash').val(hash);
$('#reporef').val(which);
if (pythonRe.test(source)) {
ConvertScript(source, function(rspec, paramdefs) {
// Need to pass these along at submit.
$('#rspec_textarea').val(rspec);
$('#script_textarea').val(source);
json.value.rspec = rspec;
json.value.isscript = true;
//
// We can get a parameterized profile, or not.
//
if (paramdefs === undefined) {
json.value.ispprofile = false;
}
else {
$('#paramdefs').val(paramdefs);
json.value.ispprofile = true;
}
callback(json);
});
}
else {
// New rspec, proceed
json.value.rspec = source;
// Need to pass this along at submit.
$('#rspec_textarea').val(source);
callback(json);
}
});
});
}
else {
$xmlthing.done(callback); $xmlthing.done(callback);
} }
}
//
// Pass a geni-lib script to the server to run (convert to XML).
// We use this on repo-based profiles, where we have to get the
// source code from the repo, and convert to an rspec.
//
function ConvertScript(script, continuation)
{
var callback = function(json) {
sup.HideWaitWait();
if (json.code) {
sup.SpitOops("oops",
"<pre><code>" +
$('<div/>').text(json.value).html() +
"</code></pre>");
return;
}
if (json.value.rspec != "") {
continuation(json.value.rspec, json.value.paramdefs);
}
}
sup.ShowWaitWait("We are converting the geni-lib script to an rspec. " +
"Patience please.");
var xmlthing = sup.CallServerMethod(null,
"manage_profile",
"CheckScript",
{"script" : script,
"getparams" : true});
xmlthing.done(callback);
}
/* /*
* Callback from the PP configurator. Stash rspec into the form. * Callback from the PP configurator. Stash rspec into the form.
...@@ -1182,7 +1263,7 @@ $(function () ...@@ -1182,7 +1263,7 @@ $(function ()
// If not a registered user, we do not get an rspec back, since // If not a registered user, we do not get an rspec back, since
// the user is not allowed to change the configuration. // the user is not allowed to change the configuration.
if (newRspec) { if (newRspec) {
$('#pp_rspec_textarea').val(newRspec); $('#rspec_textarea').val(newRspec);
selected_rspec = newRspec; selected_rspec = newRspec;
CreateAggregateSelectors(newRspec); CreateAggregateSelectors(newRspec);
} }
......
...@@ -24,6 +24,7 @@ $(function () ...@@ -24,6 +24,7 @@ $(function ()
var doconstraints = 0; var doconstraints = 0;
var amValueToKey = {}; var amValueToKey = {};
var showpicker = 0; var showpicker = 0;
var fromrepo = false;
var portal = null; var portal = null;
var registered = false; var registered = false;
var JACKS_NS = "http://www.protogeni.net/resources/rspec/ext/jacks/1"; var JACKS_NS = "http://www.protogeni.net/resources/rspec/ext/jacks/1";
...@@ -53,6 +54,7 @@ $(function () ...@@ -53,6 +54,7 @@ $(function ()
multisite = window.MULTISITE; multisite = window.MULTISITE;
portal = window.PORTAL; portal = window.PORTAL;
ajaxurl = window.AJAXURL; ajaxurl = window.AJAXURL;
fromrepo = window.FROMREPO;
doconstraints = window.DOCONSTRAINTS; doconstraints = window.DOCONSTRAINTS;
showpicker = window.SHOWPICKER; showpicker = window.SHOWPICKER;
...@@ -860,7 +862,7 @@ $(function () ...@@ -860,7 +862,7 @@ $(function ()
var xml = $(xmlDoc); var xml = $(xmlDoc);
/* /*
* We now use the desciption from inside the rspec, unless there * We now use the description from inside the rspec, unless there
* is none, in which case look to see if the we got one in the * is none, in which case look to see if the we got one in the
* rpc reply, which we will until all profiles converted over to * rpc reply, which we will until all profiles converted over to
* new format rspecs. * new format rspecs.
...@@ -882,8 +884,29 @@ $(function () ...@@ -882,8 +884,29 @@ $(function ()
var $xmlthing = sup.CallServerMethod(ajaxurl, var $xmlthing = sup.CallServerMethod(ajaxurl,
"instantiate", "GetProfile", "instantiate", "GetProfile",
{"uuid" : profile}); {"uuid" : profile});
/*
* If a repo-based and we got a specific branch/tag, we have to
* get the source for that, since it will be different then what
* is stored in the profile descriptor.
*/
console.info("fee", fromrepo, window.BRANCH, window.TAG);
if (fromrepo &&
(window.BRANCH !== undefined || window.TAG !== undefined)) {
var which =
(window.BRANCH !== undefined ? window.BRANCH : window.TAG);
$xmlthing.done(function(json) {
gitrepo.GetRepoSource(uuid, which, function(source) {
console.info("foo");
callback(json);
});
});
}
else {
$xmlthing.done(callback); $xmlthing.done(callback);
} }
}
/* /*
* Callback from the PP configurator. Stash rspec into the form. * Callback from the PP configurator. Stash rspec into the form.
...@@ -892,7 +915,7 @@ $(function () ...@@ -892,7 +915,7 @@ $(function ()
// If not a registered user, we do not get an rspec back, since // If not a registered user, we do not get an rspec back, since
// the user is not allowed to change the configuration. // the user is not allowed to change the configuration.
if (newRspec) { if (newRspec) {
$('#pp_rspec_textarea').val(newRspec); $('#rspec_textarea').val(newRspec);
selected_rspec = newRspec; selected_rspec = newRspec;
CreateAggregateSelectors(newRspec); CreateAggregateSelectors(newRspec);
} }
......
...@@ -2,7 +2,7 @@ $(function () ...@@ -2,7 +2,7 @@ $(function ()
{ {
'use strict'; 'use strict';
var templates = APT_OPTIONS.fetchTemplateList(['manage-profile', 'waitwait-modal', 'renderer-modal', 'showtopo-modal', 'oops-modal', 'rspectextview-modal', 'guest-instantiate', 'publish-modal', 'instantiate-modal', 'share-modal']); var templates = APT_OPTIONS.fetchTemplateList(['manage-profile', 'waitwait-modal', 'renderer-modal', 'showtopo-modal', 'oops-modal', 'rspectextview-modal', 'guest-instantiate', 'publish-modal', 'instantiate-modal', 'share-modal', 'gitrepo-picker']);
var manageString = templates['manage-profile']; var manageString = templates['manage-profile'];
var waitwaitString = templates['waitwait-modal']; var waitwaitString = templates['waitwait-modal'];
var rendererString = templates['renderer-modal']; var rendererString = templates['renderer-modal'];
...@@ -13,7 +13,7 @@ $(function () ...@@ -13,7 +13,7 @@ $(function ()
var publishString = templates['publish-modal']; var publishString = templates['publish-modal'];
var instantiateString = templates['instantiate-modal']; var instantiateString = templates['instantiate-modal'];
var shareString = templates['share-modal']; var shareString = templates['share-modal'];
var gitrepoString = templates['gitrepo-picker'];
var profile_uuid = null; var profile_uuid = null;
var profile_name = ''; var profile_name = '';
...@@ -23,6 +23,8 @@ $(function () ...@@ -23,6 +23,8 @@ $(function ()
var snapping = 0; var snapping = 0;
var gotrspec = 0; var gotrspec = 0;
var gotscript = 0; var gotscript = 0;