All new accounts created on Gitlab now require administrator approval. If you invite any collaborators, please let Flux staff know so they can approve the accounts.

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
function servername() { return $this->field('servername'); }
function aggregate_urn(){ return $this->field('aggregate_urn'); }
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 openstack_utilization() {
return $this->field('openstack_utilization');
......
......@@ -103,11 +103,22 @@ function Do_GetParameters()
SPITAJAX_ERROR(1, "Not enough permission to instantiate profile");
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");
return;
}
list ($formfrag, $defaults) = $profile->GenerateFormFragment();
else {
$paramdefs = $profile->paramdefs();
}
list ($formfrag, $defaults) = $profile->GenerateFormFragment($paramdefs);
SPITAJAX_RESPONSE(array("formfrag" => htmlentities($formfrag),
"defaults" => $defaults));
}
......@@ -820,8 +831,29 @@ function Do_Submit()
# we could get an rspec.
#
if ($profile->isParameterized() && $this_user &&
isset($formfields["pp_rspec"]) && $formfields["pp_rspec"] != "") {
$args["rspec"] = $formfields["pp_rspec"];
isset($formfields["rspec"]) && $formfields["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 = "";
......
......@@ -58,6 +58,7 @@ $optargs = OptionalPageArguments("create", PAGEARG_STRING,
"asguest", PAGEARG_BOOLEAN,
"default", PAGEARG_STRING,
"from", PAGEARG_STRING,
"refspec", PAGEARG_STRING,
"formfields", PAGEARG_ARRAY);
if ($ISAPT && !$this_user) {
......@@ -317,6 +318,7 @@ function SPITFORM($formfields, $newuser, $errors)
global $TBBASE, $APTMAIL, $ISAPT, $ISCLOUD, $ISPNET, $PORTAL_NAME;
global $profile_array, $this_user, $profilename, $profile;
global $projlist, $skipfirststep, $TBMAINSITE;
global $refspec;
$showabout = ($ISAPT && !$this_user ? 1 : 0);
$registered = (isset($this_user) ? "true" : "false");
......@@ -400,6 +402,15 @@ function SPITFORM($formfields, $newuser, $errors)
echo " window.SKIPFIRSTSTEP = " . ($skipfirststep ? "true" : "false") . ";\n";
echo " window.PORTAL_NAME = '$PORTAL_NAME';\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 src='js/lib/jquery-2.0.3.min.js'></script>\n";
......@@ -411,8 +422,10 @@ function SPITFORM($formfields, $newuser, $errors)
REQUIRE_FORMHELPERS();
REQUIRE_FILESTYLE();
REQUIRE_MARKED();
REQUIRE_MOMENT();
REQUIRE_JACKS();
REQUIRE_JQUERY_STEPS();
AddLibrary("js/gitrepo.js");
SPITREQUIRE("js/instantiate-new.js");
}
......
......@@ -63,6 +63,10 @@ $(function () {
if (_.has(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
......
......@@ -412,7 +412,9 @@ $(function ()
disabled: true,
versions: [],
withpublishing: false,
genilib_editor: true
genilib_editor: true,
canrepo: false,
fromrepo: false
});
manage_html = aptforms.FormatFormFieldsHorizontal(manage_html,
{"wide": false });
......@@ -464,7 +466,9 @@ $(function ()
disabled: true,
versions: [],
withpublishing: false,
genilib_editor: true
genilib_editor: true,
canrepo: false,
fromrepo: false
});
manage_html = aptforms.FormatFormFieldsHorizontal(manage_html,
{'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 ()
var amValueToKey = {};
var showpicker = 0;
var portal = null;
var fromrepo = false;
var registered = false;
var JACKS_NS = "http://www.protogeni.net/resources/rspec/ext/jacks/1";
var jacks = {
......@@ -59,6 +60,7 @@ $(function ()
multisite = window.MULTISITE;
portal = window.PORTAL;
ajaxurl = window.AJAXURL;
fromrepo = window.FROMREPO;
doconstraints = window.DOCONSTRAINTS;
showpicker = window.SHOWPICKER;
......@@ -1172,8 +1174,87 @@ $(function ()
var $xmlthing = sup.CallServerMethod(ajaxurl,
"instantiate", "GetProfile",
{"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);
}
}
//
// 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.
......@@ -1182,7 +1263,7 @@ $(function ()
// If not a registered user, we do not get an rspec back, since
// the user is not allowed to change the configuration.
if (newRspec) {
$('#pp_rspec_textarea').val(newRspec);
$('#rspec_textarea').val(newRspec);
selected_rspec = newRspec;
CreateAggregateSelectors(newRspec);
}
......
......@@ -24,6 +24,7 @@ $(function ()
var doconstraints = 0;
var amValueToKey = {};
var showpicker = 0;
var fromrepo = false;
var portal = null;
var registered = false;
var JACKS_NS = "http://www.protogeni.net/resources/rspec/ext/jacks/1";
......@@ -53,6 +54,7 @@ $(function ()
multisite = window.MULTISITE;
portal = window.PORTAL;
ajaxurl = window.AJAXURL;
fromrepo = window.FROMREPO;
doconstraints = window.DOCONSTRAINTS;
showpicker = window.SHOWPICKER;
......@@ -860,7 +862,7 @@ $(function ()
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
* rpc reply, which we will until all profiles converted over to
* new format rspecs.
......@@ -882,8 +884,29 @@ $(function ()
var $xmlthing = sup.CallServerMethod(ajaxurl,
"instantiate", "GetProfile",
{"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);
}
}
/*
* Callback from the PP configurator. Stash rspec into the form.
......@@ -892,7 +915,7 @@ $(function ()
// If not a registered user, we do not get an rspec back, since
// the user is not allowed to change the configuration.
if (newRspec) {
$('#pp_rspec_textarea').val(newRspec);
$('#rspec_textarea').val(newRspec);
selected_rspec = newRspec;
CreateAggregateSelectors(newRspec);
}
......
This diff is collapsed.
......@@ -654,6 +654,16 @@ $(function () {
// This clears any errors before new submit. Needs more thought.
GenerateModalBody(formfields, null);
//
// XXX: Look for paramdefs/script in the main form and pass along.
// This is for repo-based profiles.
//
if ($('#paramdefs').val() !== undefined) {
formfields["paramdefs"] = $('#paramdefs').val();
formfields["script"] = $('#script_textarea').val();
}
console.info("formfields", formfields);
// Not in checkform mode, this will take time.
if (!checkonly) {
sup.ShowModal("#waitwait-modal");
......@@ -714,9 +724,16 @@ $(function () {
ShowEditor();
}
}
var blob = {"uuid" : uuid};
//
// XXX: Look for paramdefs/script in the form and pass that along.
// This is for repo-based profiles.
//
if ($('#paramdefs').val() !== undefined) {
blob["paramdefs"] = $('#paramdefs').val();
}
var xmlthing = sup.CallServerMethod(null, "instantiate",
"GetParameters",
{"uuid" : uuid});
"GetParameters", blob);
xmlthing.done(callback);
}
......
......@@ -3,14 +3,19 @@ window.sup = (function () {
function ShowModal(which)
{
// console.log('Showing modal ' + which);
$( which ).modal('show');
$(which).modal('show');
}
function HideModal(which)
function HideModal(which, continuation)
{
// console.log('Hide modal ' + which);
$( which ).modal('hide');
var callback = function() {
$(which).off('hidden.bs.modal', callback);
continuation();
};
if (continuation !== undefined) {
$(which).on('hidden.bs.modal', callback);
}
$(which).modal('hide');
}
function ShowWaitWait(message)
......@@ -23,11 +28,15 @@ function ShowWaitWait(message)
ShowModal('#waitwait-modal-withmessage');
}
}
function HideWaitWait()
function HideWaitWait(continuation)
{
if ($('#waitwait-modal').is(':visible')) {
HideModal('#waitwait-modal', continuation);
}
else {
$('#waitwait-modal-withmessage-message').html("");
HideModal('#waitwait-modal-withmessage');
HideModal('#waitwait-modal');
HideModal('#waitwait-modal-withmessage', continuation);
}
}
function CallServerMethod(url, route, method, args, callback)
......
......@@ -19,6 +19,7 @@ $(function ()
var profile_version = '';
var version_uuid = null;
var gotscript = 0;
var fromrepo = 0;
var ajaxurl = "";
var amlist = null;
var isppprofile = false;
......@@ -54,6 +55,10 @@ $(function ()
if (_.has(fields, "profile_version")) {
profile_version = fields['profile_version'];
}
if (_.has(fields, "profile_repourl") &&
fields["profile_repourl"] != "") {
fromrepo = 1;
}
// Generate the templates.
var show_html = showTemplate({
......@@ -65,6 +70,7 @@ $(function ()
canedit: window.CANEDIT,
disabled: window.DISABLED,
withpublishing: window.WITHPUBLISHING,
fromrepo: fromrepo
});
show_html = aptforms.FormatFormFieldsHorizontal(show_html,
{"wide" : true});
......@@ -80,6 +86,11 @@ $(function ()
$('#oops_div').html(oopsString);
$('#share_div').html(shareTemplate({formfields: fields}))
// Fireoff repo stuff now.
if (fromrepo) {
SetupRepo();
}
// This activates the popover subsystem.
$('[data-toggle="popover"]').popover({
trigger: 'hover',
......@@ -135,7 +146,8 @@ $(function ()
// $('#rspec_modal_download_button')
// .attr("href", href + "&rspec=true");
}
if ($(this).attr("id") == "show_source_modal_button" && isScript) {
if ($(this).attr("id") == "show_source_modal_button" &&
isScript && !fromrepo) {
openEditor();
}
else
......@@ -165,7 +177,7 @@ $(function ()
$('#modal_profile_rspec_div').prepend(elt);
}, {
value: source,
lineNumbers: false,
lineNumbers: true,