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 13c85de6 authored by Leigh B Stoller's avatar Leigh B Stoller

Powder license support. Just project level, easy to add user level

licensing later.
parent 33b207d3
...@@ -44,6 +44,7 @@ my $impotent= 0; ...@@ -44,6 +44,7 @@ my $impotent= 0;
my $silent = 0; my $silent = 0;
my $portal; my $portal;
my $resend; my $resend;
my %licenses = ();
# #
# Configure variables # Configure variables
...@@ -53,6 +54,7 @@ my $TBOPS = "@TBOPSEMAIL@"; ...@@ -53,6 +54,7 @@ my $TBOPS = "@TBOPSEMAIL@";
my $TBAUDIT = "@TBAUDITEMAIL@"; my $TBAUDIT = "@TBAUDITEMAIL@";
my $TBBASE = "@TBBASE@"; my $TBBASE = "@TBBASE@";
my $TBWWW = "@TBWWW@"; my $TBWWW = "@TBWWW@";
my $LICENSES = "$TB/sbin/manage_licenses";
# #
# This script is setuid, so please do not run it as root. Hard to track # This script is setuid, so please do not run it as root. Hard to track
...@@ -233,12 +235,28 @@ if (exists($xmlparse->{'attribute'}->{"portal"})) { ...@@ -233,12 +235,28 @@ if (exists($xmlparse->{'attribute'}->{"portal"})) {
fatal("Bad portal: $portal"); fatal("Bad portal: $portal");
} }
} }
# Licenses. Save for later, but need to delete.
foreach my $key (keys(%{ $xmlparse->{'attribute'} })) {
if ($key =~ /^license_([-\w]+)$/) {
my $value = $xmlparse->{'attribute'}->{"$key"}->{'value'};
my $name = $1;
if (lc($value) eq "yes") {
system("$LICENSES show $name");
if ($?) {
fatal("Invalid license name: $name");
}
$licenses{$name} = $name;
print "requested license $name\n";
}
delete($xmlparse->{'attribute'}->{"$key"});
}
}
# #
# Make sure all the required arguments were provided. # Make sure all the required arguments were provided.
# #
foreach my $key (keys(%required)) { foreach my $key (keys(%required)) {
fatal("Missing required attribute '$key'") fatal("Missing required attribute '$key'")
if (! exists($xmlparse->{'attribute'}->{"$key"})); if (! exists($xmlparse->{'attribute'}->{"$key"}));
} }
...@@ -386,6 +404,18 @@ if (!defined($newproj)) { ...@@ -386,6 +404,18 @@ if (!defined($newproj)) {
} }
my $new_idx = $newproj->pid_idx(); my $new_idx = $newproj->pid_idx();
#
# Add any licenses.
#
if (keys(%licenses)) {
foreach my $name (keys(%licenses)) {
system("$LICENSES require $name $new_pid");
if ($?) {
fatal("Invalid license name: $name");
}
}
}
# #
# See if we are in an initial Emulab setup. If so, no email sent. # See if we are in an initial Emulab setup. If so, no email sent.
# #
......
...@@ -36,7 +36,8 @@ BIN_SCRIPTS = manage_profile manage_instance manage_dataset \ ...@@ -36,7 +36,8 @@ BIN_SCRIPTS = manage_profile manage_instance manage_dataset \
manage_images rtecheck checkprofile manage_extensions \ manage_images rtecheck checkprofile manage_extensions \
create_slivers searchip create_slivers searchip
SBIN_SCRIPTS = apt_daemon aptevent_daemon portal_xmlrpc apt_checkup \ SBIN_SCRIPTS = apt_daemon aptevent_daemon portal_xmlrpc apt_checkup \
portal_monitor apt_scheduler portal_resources portal_monitor apt_scheduler portal_resources \
manage_licenses
LIB_SCRIPTS = APT_Profile.pm APT_Instance.pm APT_Dataset.pm APT_Geni.pm \ LIB_SCRIPTS = APT_Profile.pm APT_Instance.pm APT_Dataset.pm APT_Geni.pm \
APT_Aggregate.pm APT_Utility.pm APT_Rspec.pm APT_Aggregate.pm APT_Utility.pm APT_Rspec.pm
WEB_BIN_SCRIPTS = webmanage_profile webmanage_instance webmanage_dataset \ WEB_BIN_SCRIPTS = webmanage_profile webmanage_instance webmanage_dataset \
...@@ -44,7 +45,7 @@ WEB_BIN_SCRIPTS = webmanage_profile webmanage_instance webmanage_dataset \ ...@@ -44,7 +45,7 @@ WEB_BIN_SCRIPTS = webmanage_profile webmanage_instance webmanage_dataset \
webrspec2genilib webmanage_reservations webmanage_gitrepo \ webrspec2genilib webmanage_reservations webmanage_gitrepo \
webmanage_images webrtecheck websearchip webmanage_images webrtecheck websearchip
APACHEHOOKS = apt_gitrepo.hook APACHEHOOKS = apt_gitrepo.hook
WEB_SBIN_SCRIPTS= webportal_xmlrpc WEB_SBIN_SCRIPTS= webportal_xmlrpc webmanage_licenses
LIBEXEC_SCRIPTS = $(WEB_BIN_SCRIPTS) $(WEB_SBIN_SCRIPTS) LIBEXEC_SCRIPTS = $(WEB_BIN_SCRIPTS) $(WEB_SBIN_SCRIPTS)
USERLIBEXEC = rungenilib.proxy genilib-jail genilib-iocage gitrepo.proxy USERLIBEXEC = rungenilib.proxy genilib-jail genilib-iocage gitrepo.proxy
......
This diff is collapsed.
...@@ -1071,5 +1071,20 @@ sub ValidUUID($) ...@@ -1071,5 +1071,20 @@ sub ValidUUID($)
return 0; return 0;
} }
sub ReadFile($)
{
my ($filename) = @_;
my $contents = "";
open(L, $filename)
or return undef;
while (<L>) {
$contents .= $_;
}
close(L);
return $contents;
}
# _Always_ make sure that this 1 is at the end of the file... # _Always_ make sure that this 1 is at the end of the file...
1; 1;
...@@ -2989,6 +2989,26 @@ CREATE TABLE `lease_permissions` ( ...@@ -2989,6 +2989,26 @@ CREATE TABLE `lease_permissions` (
PRIMARY KEY (`lease_idx`,`permission_type`,`permission_idx`) PRIMARY KEY (`lease_idx`,`permission_type`,`permission_idx`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1; ) ENGINE=MyISAM DEFAULT CHARSET=latin1;
--
-- Table structure for table `licenses`
--
DROP TABLE IF EXISTS `licenses`;
CREATE TABLE `licenses` (
`license_idx` int(11) NOT NULL auto_increment,
`license_name` varchar(48) NOT NULL default '',
`license_level` enum('project','user') NOT NULL default 'project',
`created` datetime default NULL,
`validfor` int(11) NOT NULL default '0',
`form_text` tinytext,
`license_text` text,
`license_type` enum('md','text','html') NOT NULL default 'md',
`description_text` text,
`description_type` enum('md','text','html') NOT NULL default 'md',
PRIMARY KEY (`license_idx`),
UNIQUE KEY `license_name` (`license_name`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
-- --
-- Table structure for table `linkdelays` -- Table structure for table `linkdelays`
-- --
...@@ -4479,6 +4499,20 @@ CREATE TABLE `project_leases` ( ...@@ -4479,6 +4499,20 @@ CREATE TABLE `project_leases` (
UNIQUE KEY `uuid` (`uuid`) UNIQUE KEY `uuid` (`uuid`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1; ) ENGINE=MyISAM DEFAULT CHARSET=latin1;
--
-- Table structure for table `project_licenses`
--
DROP TABLE IF EXISTS `project_licenses`;
CREATE TABLE `project_licenses` (
`pid` varchar(48) NOT NULL default '',
`pid_idx` mediumint(8) unsigned NOT NULL default '0',
`license_idx` int(11) NOT NULL default '0',
`accepted` datetime default NULL,
`expiration` datetime default NULL,
PRIMARY KEY (`pid_idx`,`license_idx`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
-- --
-- Table structure for table `project_quotas` -- Table structure for table `project_quotas`
-- --
...@@ -5246,6 +5280,22 @@ CREATE TABLE `user_features` ( ...@@ -5246,6 +5280,22 @@ CREATE TABLE `user_features` (
PRIMARY KEY (`feature`,`uid_idx`) PRIMARY KEY (`feature`,`uid_idx`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1; ) ENGINE=MyISAM DEFAULT CHARSET=latin1;
--
-- Table structure for table `user_licenses`
--
DROP TABLE IF EXISTS `user_licenses`;
CREATE TABLE `user_licenses` (
`uid` varchar(48) NOT NULL default '',
`uid_idx` mediumint(8) unsigned NOT NULL default '0',
`license_idx` int(11) NOT NULL default '0',
`accepted` datetime default NULL,
`expiration` datetime default NULL,
PRIMARY KEY (`uid_idx`,`license_idx`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
-- --
-- Table structure for table `user_policies` -- Table structure for table `user_policies`
-- --
......
use strict;
use libdb;
sub DoUpdate($$$)
{
my ($dbhandle, $dbname, $version) = @_;
if (!DBTableExists("licenses")) {
DBQueryFatal("CREATE TABLE `licenses` ( ".
" `license_idx` int(11) NOT NULL auto_increment, ".
" `license_name` varchar(48) NOT NULL default '', ".
" `license_level` enum('project','user') ".
" NOT NULL default 'project', ".
" `created` datetime default NULL, ".
" `validfor` int(11) NOT NULL default '0', ".
" `form_text` tinytext, ".
" `license_text` text, ".
" `license_type` enum('md','text', 'html') ".
" NOT NULL default 'md', ".
" `description_text` text, ".
" `description_type` enum('md','text', 'html') ".
" NOT NULL default 'md', ".
" PRIMARY KEY (`license_idx`), ".
" UNIQUE KEY `license_name` (`license_name`) ".
") ENGINE=MyISAM DEFAULT CHARSET=latin1");
}
if (!DBTableExists("project_licenses")) {
DBQueryFatal("CREATE TABLE `project_licenses` ( ".
" `pid` varchar(48) NOT NULL default '', ".
" `pid_idx` mediumint(8) unsigned NOT NULL default '0', ".
" `license_idx` int(11) NOT NULL default '0', ".
" `accepted` datetime default NULL, ".
" `expiration` datetime default NULL, ".
" PRIMARY KEY (`pid_idx`,`license_idx`) ".
") ENGINE=MyISAM DEFAULT CHARSET=latin1");
}
if (!DBTableExists("user_licenses")) {
DBQueryFatal("CREATE TABLE `user_licenses` ( ".
" `uid` varchar(48) NOT NULL default '', ".
" `uid_idx` mediumint(8) unsigned NOT NULL default '0', ".
" `license_idx` int(11) NOT NULL default '0', ".
" `accepted` datetime default NULL, ".
" `expiration` datetime default NULL, ".
" PRIMARY KEY (`uid_idx`,`license_idx`) ".
") ENGINE=MyISAM DEFAULT CHARSET=latin1");
}
return 0;
}
1;
# Local Variables:
# mode:perl
# End:
#!/usr/bin/perl -wT #!/usr/bin/perl -wT
# #
# Copyright (c) 2000-2016 University of Utah and the Flux Group. # Copyright (c) 2000-2018 University of Utah and the Flux Group.
# #
# {{{EMULAB-LICENSE # {{{EMULAB-LICENSE
# #
...@@ -236,6 +236,7 @@ $EUID = 0; ...@@ -236,6 +236,7 @@ $EUID = 0;
# #
DBQueryFatal("delete FROM last_reservation where pid_idx='$pid_idx'"); DBQueryFatal("delete FROM last_reservation where pid_idx='$pid_idx'");
DBQueryFatal("delete FROM project_reservations where pid_idx='$pid_idx'"); DBQueryFatal("delete FROM project_reservations where pid_idx='$pid_idx'");
DBQueryFatal("delete FROM project_licenses where pid_idx='$pid_idx'");
DBQueryFatal("delete FROM nodetypeXpid_permissions where pid_idx='$pid_idx'"); DBQueryFatal("delete FROM nodetypeXpid_permissions where pid_idx='$pid_idx'");
DBQueryFatal("delete FROM project_stats where pid_idx='$pid_idx'"); DBQueryFatal("delete FROM project_stats where pid_idx='$pid_idx'");
DBQueryFatal("delete FROM group_stats where pid_idx='$pid_idx'"); DBQueryFatal("delete FROM group_stats where pid_idx='$pid_idx'");
......
...@@ -20,7 +20,8 @@ $(function () { ...@@ -20,7 +20,8 @@ $(function () {
* name to the wrapper so we can find it later to * name to the wrapper so we can find it later to
* add the error stuff. * add the error stuff.
*/ */
var wrapper = $("<div id='form-wrapper-' + key></div>"); var wrapper = $("<div id='form-wrapper-" + key + "'>" +
"</div>");
// How do I just move the item into the wrapper? // How do I just move the item into the wrapper?
wrapper.append($(item).clone()); wrapper.append($(item).clone());
......
$(function ()
{
'use strict';
var template_list = ["licenses", "oops-modal", "waitwait-modal"];
var templates = APT_OPTIONS.fetchTemplateList(template_list);
var licenses = [];
function initialize()
{
window.APT_OPTIONS.initialize(sup);
$('#main-body').html(templates["licenses"]);
$('#oops-div').html(templates["oops-modal"]);
$('#waitwait-div').html(templates["waitwait-modal"]);
GetLicenses();
}
function GetLicenses()
{
var callback = function(json) {
console.log("GetLicenses", json);
if (json.code) {
console.info("Could not list license: " + json.value);
return;
}
licenses = json.value;
if (! licenses.length) {
window.location.replace("landing.php");
return;
}
HandleLicense(licenses.shift());
};
var xmlthing = sup.CallServerMethod(null, "licenses", "List");
xmlthing.done(callback);
}
function HandleLicense(license)
{
console.info("HandleLicense", license);
// Clear for next license.
$('#description-panel .license').html("").addClass("hidden");
$('#license-panel .panel-body .license-text').html("");
// Reset handler for accept button.
$('#accept-license')
.off("click")
.click(function (event) {
event.preventDefault();
Accept(license);
});
$('#reject-license')
.off("click")
.click(function (event) {
event.preventDefault();
Reject(license);
});
if (license.description_text && license.description_text != "") {
var html;
if (license.description_type == "md") {
html = marked(license.description_text);
}
else if (license.description_type == "html") {
html = license.description_text;
}
else if (license.description_type == "text") {
html = "<pre>" + license.description_text + "</pre>";
}
$('#description-panel .license')
.html(html)
.removeClass("hidden");
}
var html;
if (license.license_type == "md") {
html = marked(license.license_text);
}
else if (license.license_type == "html") {
html = license.license_text;
}
else if (license.license_type == "text") {
html = "<pre>" + license.license_text + "</pre>";
}
$('#license-panel .panel-body .license-text').html(html);
}
function Accept(license)
{
console.info("Accept", license);
var callback = function(json) {
console.log(json);
if (json.code) {
console.info("Could not accept license: " + json.value);
return;
}
if (licenses.length) {
sup.ShowWaitWait("One moment please while we check to see if " +
"there are any more licenses to accept ...")
setTimeout(function () {
sup.HideWaitWait();
HandleLicense(licenses.shift());
}, 2000);
return;
}
window.location.replace("landing.php");
};
var xmlthing = sup.CallServerMethod(null,
"licenses", "Accept",
{"idx" : license.idx});
xmlthing.done(callback);
}
function Reject(license)
{
console.info("Reject", license);
var callback = function(json) {
console.log(json);
if (json.code) {
console.info("Could not reject license: " + json.value);
return;
}
if (licenses.length) {
sup.ShowWaitWait("One moment please while we check to see if " +
"there are any more licenses to accept ...")
setTimeout(function () {
sup.HideWaitWait();
HandleLicense(licenses.shift());
}, 2000);
return;
}
window.location.replace("landing.php");
};
var xmlthing = sup.CallServerMethod(null,
"licenses", "Reject",
{"idx" : license.idx});
xmlthing.done(callback);
}
$(document).ready(initialize);
});
...@@ -504,19 +504,29 @@ $(function () ...@@ -504,19 +504,29 @@ $(function ()
} }
var template = _.template(detailsString); var template = _.template(detailsString);
$('#admin_content') $('#project_content')
.html(template({"fields" : json.value})); .html(template({"fields" : json.value,
"isleader" : window.ISLEADER,
"isadmin" : window.ISADMIN}));
// Format dates with moment before display. // Format dates with moment before display.
$('#admin_table .format-date').each(function() { $('#project_table .format-date').each(function() {
var date = $.trim($(this).html()); var date = $.trim($(this).html());
if (date != "") { if (date != "") {
$(this).html(moment($(this).html()).format("ll")); $(this).html(moment($(this).html()).format("ll"));
} }
}); });
$('#admin_content .toggle').click(function() { $('#project_table [data-toggle="popover"]').popover({
trigger: 'hover',
placement: 'auto',
});
$('#project_content .toggle').click(function() {
Toggle(this); Toggle(this);
}); });
$('#project_content .request-license').click(function(event) {
event.preventDefault();
RequestLicense(this);
});
} }
var xmlthing = sup.CallServerMethod(null, var xmlthing = sup.CallServerMethod(null,
"show-project", "ProjectProfile", "show-project", "ProjectProfile",
...@@ -618,6 +628,31 @@ $(function () ...@@ -618,6 +628,31 @@ $(function ()
callback); callback);
} }
/*
* Request a license.
*/
function RequestLicense(target) {
var license_idx = $(target).data("license_idx");
var callback = function(json) {
if (json.code) {
sup.SpitOops("oops", json.value);
return;
}
// If this is the leader of the project, zap them to
// the license page. If an admin doing this, stay here.
if (window.ISLEADER) {
window.location.replace("licenses.php");
return;
}
$(target).closest('td').html("Acceptance pending");
};
sup.CallServerMethod(null, "licenses", "Request",
{"pid" : window.TARGET_PROJECT,
"idx" : license_idx},
callback);
}
$(document).ready(initialize); $(document).ready(initialize);
}); });
......
...@@ -16,11 +16,11 @@ $(function () ...@@ -16,11 +16,11 @@ $(function ()
var fields = JSON.parse(_.unescape($('#form-json')[0].textContent)); var fields = JSON.parse(_.unescape($('#form-json')[0].textContent));
var errors = JSON.parse(_.unescape($('#error-json')[0].textContent)); var errors = JSON.parse(_.unescape($('#error-json')[0].textContent));
var licenses = JSON.parse(_.unescape($('#licenses-json')[0].textContent));
console.info(fields); console.info(fields);
console.info(errors); console.info(errors);
renderForm(fields, errors, renderForm(fields, errors, licenses,
window.APT_OPTIONS.joinproject, window.APT_OPTIONS.joinproject,
window.APT_OPTIONS.ShowVerifyModal, window.APT_OPTIONS.ShowVerifyModal,
window.APT_OPTIONS.this_user, window.APT_OPTIONS.this_user,
...@@ -48,7 +48,7 @@ $(function () ...@@ -48,7 +48,7 @@ $(function ()
} }
} }
function renderForm(formfields, errors, joinproject, showVerify, function renderForm(formfields, errors, licenses, joinproject, showVerify,
thisUser, promoting) thisUser, promoting)
{ {
var buttonLabel = "Submit Request"; var buttonLabel = "Submit Request";
...@@ -68,7 +68,8 @@ $(function () ...@@ -68,7 +68,8 @@ $(function ()
}); });
var project_html = projectTemplate({ var project_html = projectTemplate({
joinproject: joinproject, joinproject: joinproject,
formfields: formfields formfields: formfields,
licenses: licenses,
}); });
var signup = signupTemplate({ var signup = signupTemplate({
button_label: buttonLabel, button_label: buttonLabel,
...@@ -106,6 +107,11 @@ $(function () ...@@ -106,6 +107,11 @@ $(function ()
aptforms.DisableUnsavedWarning('#quickvm_signup_form'); aptforms.DisableUnsavedWarning('#quickvm_signup_form');
}); });
} }
// This activates the popover subsystem.
$('[data-toggle="popover"]').popover({
trigger: 'hover',
placement: 'auto',
});
} }
$(document).ready(initialize); $(document).ready(initialize);
......
<?php
#
# Copyright (c) 2000-2018 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");
chdir("apt");