diff --git a/xCAT-UI/js/configure/configure.js b/xCAT-UI/js/configure/configure.js index 97c83c150..11498acb9 100644 --- a/xCAT-UI/js/configure/configure.js +++ b/xCAT-UI/js/configure/configure.js @@ -78,6 +78,9 @@ function loadConfigPage() { // Add the discover tab tab.add('discoverTab', 'Discover', '', false); + + // Add the self-service tab + tab.add('serviceTab', 'Service', '', false); // Get list of tables and their descriptions $.ajax( { @@ -95,6 +98,7 @@ function loadConfigPage() { loadUpdatePage(); loadDiscoverPage(); + loadServicePage(); } /** diff --git a/xCAT-UI/js/configure/service.js b/xCAT-UI/js/configure/service.js new file mode 100644 index 000000000..4ab53ecd2 --- /dev/null +++ b/xCAT-UI/js/configure/service.js @@ -0,0 +1,539 @@ +/** + * Global variables + */ +var topPriority = 0; + +/** + * Load the service portal's provision page + * + * @param tabId + * Tab ID where page will reside + * @return Nothing + */ +function loadServicePage(tabId) { + // Create info bar + var infoBar = createInfoBar('Select a platform to configure, then click Ok.'); + + // Create self-service portal page + var tabId = 'serviceTab'; + var servicePg = $('
'); + $('#' + tabId).append(infoBar, servicePg); + + // Create radio buttons for platforms + var hwList = $('
    Platforms available:
'); + var esx = $('
  • ESX
  • '); + var kvm = $('
  • KVM
  • '); + var zvm = $('
  • z\/VM
  • '); + + hwList.append(esx); + hwList.append(kvm); + hwList.append(zvm); + servicePg.append(hwList); + + /** + * Ok + */ + var okBtn = createButton('Ok'); + okBtn.bind('click', function(event) { + var configTabs = getConfigTab(); + + // Get hardware that was selected + var hw = $(this).parent().find('input[name="hw"]:checked').val(); + var newTabId = hw + 'ProvisionTab'; + + if ($('#' + newTabId).size() > 0){ + configTabs.select(newTabId); + } else { + var title = ''; + + // Create an instance of the plugin + var plugin; + switch (hw) { + case "kvm": + plugin = new kvmPlugin(); + title = 'KVM'; + break; + case "esx": + plugin = new esxPlugin(); + title = 'ESX'; + break; + case "zvm": + plugin = new zvmPlugin(); + title = 'z/VM'; + + // Get zVM host names + if (!$.cookie('srv_zvm')){ + $.ajax( { + url : 'lib/srv_cmd.php', + dataType : 'json', + data : { + cmd : 'webportal', + tgt : '', + args : 'lszvm', + msg : '' + }, + + success : function(data) { + setzVMCookies(data); + } + }); + } + + break; + } + + // Select tab + configTabs.add(newTabId, title, '', true); + configTabs.select(newTabId); + plugin.loadConfigPage(newTabId); + } + }); + + servicePg.append(okBtn); +} + +/** + * Load the user panel where users can be created, modified, or deleted + * + * @param panelId + * Panel ID + * @return Nothing + */ +function loadUserPanel(panelId) { + // Get users list + $.ajax({ + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'tabdump', + tgt : '', + args : 'passwd', + msg : panelId + }, + + success : loadUserTable + }); +} + +/** + * Load user datatable + * + * @param data + * HTTP request data + * @return Nothing + */ +function loadUserTable(data) { + // Get response + var rsp = data.rsp; + // Get panel ID + var panelId = data.msg; + + // Wipe panel clean + $('#' + panelId).empty(); + + // Add info bar + $('#' + panelId).append(createInfoBar('Create, edit, and delete users for the self-service portal. Double-click on a cell to edit a users properties. Click outside the table to save changes. Hit the Escape key to ignore changes.')); + + // Get table headers + // The table headers in the passwd table are: key, username, password, cryptmethod, comments, and disable + var headers = new Array('priority', 'username', 'password', 'max-vm'); + + // Create a new datatable + var tableId = 'userDatatable'; + var table = new DataTable(tableId); + + // Add column for the checkbox + headers.unshift(''); + table.init(headers); + headers.shift(); + + // Append datatable to panel + $('#' + panelId).append(table.object()); + + // Add table rows + // Start with the 2nd row (1st row is the headers) + for ( var i = 1; i < rsp.length; i++) { + // Split into columns + var tmp = rsp[i].split(','); + + // Go through each column + for (var j = 0; j < tmp.length; j++) { + // Replace quote + tmp[j] = tmp[j].replace(new RegExp('"', 'g'), ''); + } + + // Only add users having the key = xcat + if (tmp[0] == 'xcat') { + // Columns are: priority, username, password, and max-vm + var cols = new Array('', tmp[1], tmp[2], ''); + + // Add remove button where id = user name + cols.unshift(''); + + // Add row + table.add(cols); + } + } + + // Turn table into datatable + $('#' + tableId).dataTable({ + 'iDisplayLength': 50, + 'bLengthChange': false, + "sScrollX": "100%", + "bAutoWidth": true + }); + + // Create action bar + var actionBar = $('
    '); + + var createLnk = $('Create'); + createLnk.click(function() { + openCreateUserDialog(); + }); + + var deleteLnk = $('Delete'); + deleteLnk.click(function() { + var users = getNodesChecked(tableId); + if (users) { + openDeleteUserDialog(users); + } + }); + + var refreshLnk = $('Refresh'); + refreshLnk.click(function() { + loadUserPanel(panelId); + }); + + // Create an action menu + var actionsMenu = createMenu([createLnk, deleteLnk, refreshLnk]); + actionsMenu.superfish(); + actionsMenu.css('display', 'inline-block'); + actionBar.append(actionsMenu); + + // Set correct theme for action menu + actionsMenu.find('li').hover(function() { + setMenu2Theme($(this)); + }, function() { + setMenu2Normal($(this)); + }); + + // Create a division to hold actions menu + var menuDiv = $(''); + $('#' + tableId + '_wrapper').prepend(menuDiv); + menuDiv.append(actionBar); + $('#' + tableId + '_filter').appendTo(menuDiv); + + // Get policy data + $.ajax({ + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'tabdump', + tgt : '', + args : 'policy', + msg : tableId + }, + + success : loadUserTable4Policy + }); + + /** + * Enable editable cells + */ + // Do not make 1st or 2nd column editable + $('#' + tableId + ' td:not(td:nth-child(1),td:nth-child(2))').editable( + function(value, settings) { + // If users did not make changes, return the value directly + // jeditable saves the old value in this.revert + if ($(this).attr('revert') == value){ + return value; + } + + var panelId = $(this).parents('.ui-accordion-content').attr('id'); + + // Get column index + var colPos = this.cellIndex; + + // Get row index + var dTable = $('#' + tableId).dataTable(); + var rowPos = dTable.fnGetPosition(this.parentNode); + + // Update datatable + dTable.fnUpdate(value, rowPos, colPos, false); + + // Get table headers + var headers = $('#' + nodesTableId).parents('.dataTables_scroll').find('.dataTables_scrollHead thead tr:eq(0) th'); + + // Get user attributes + var priority = $(this).parent().find('td:eq(1)').text(); + var user = $(this).parent().find('td:eq(2)').text(); + var password = $(this).parent().find('td:eq(3)').text(); + var maxVM = $(this).parent().find('td:eq(4)').text(); + + // Send command to change user attributes + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'webrun', + tgt : '', + args : 'updateuser;' + priority + ';' + user + ';' + password + ';' + maxVM, + msg : panelId + }, + success : updatePanel + }); + + return value; + }, { + onblur : 'submit', // Clicking outside editable area submits changes + type : 'textarea', + placeholder: ' ', + event : "dblclick", // Double click and edit + height : '30px' // The height of the text area + }); + + // Resize accordion + $('#' + tableId).parents('.ui-accordion').accordion('resize'); +} + +/** + * Update user datatable for policy + * + * @param data + * HTTP request data + * @return Nothing + */ +function loadUserTable4Policy(data) { + // Get response + var rsp = data.rsp; + // Get datatable ID + var tableId = data.msg; + + // Get datatable + var datatable = $('#' + tableId).dataTable(); + + // Update max-vm column + // The data coming back contains: priority, name, host, commands, noderange, parameters, time, rule, comments, disable + + // Start with the 2nd row (1st row is the headers) + topPriority = 0; + for ( var i = 1; i < rsp.length; i++) { + // Split into columns + var tmp = rsp[i].split(','); + + // Go through each column + for (var j = 0; j < tmp.length; j++) { + // Replace quote + tmp[j] = tmp[j].replace(new RegExp('"', 'g'), ''); + } + + // Get the row containing the user name + var rowPos = -1; + if (tmp[1]) + rowPos = findRow(tmp[1], '#' + tableId, 2); + + // Update the priority and max-vm columns + if (rowPos > -1) { + var maxVM = tmp[8].replace('max-vm:', ''); + maxVM = maxVM.replace(';', ''); + datatable.fnUpdate(maxVM, rowPos, 4, false); + + var priority = tmp[0]; + datatable.fnUpdate(priority, rowPos, 1, false); + + // Set the highest priority + if (priority > topPriority) + topPriority = priority; + } + } + + // Adjust column sizes + adjustColumnSize(tableId); + + // Resize accordion + $('#' + tableId).parents('.ui-accordion').accordion('resize'); +} + +/** + * Open a dialog to create a user + */ +function openCreateUserDialog() { + var dialogId = 'createUser'; + var dialog = $('
    '); + var info = createInfoBar('Create an xCAT user. A priority will be generated for the new user.'); + dialog.append(info); + + // Generate the user priority + var userPriority = parseFloat(topPriority) + 0.01; + userPriority = userPriority.toPrecision(3); + + // Create node inputs + dialog.append($('
    ')); + dialog.append($('
    ')); + dialog.append($('
    ')); + dialog.append($('
    ')); + + dialog.dialog({ + title: 'Create user', + modal: true, + width: 400, + close: function(){ + $(this).remove(); + }, + buttons: { + "OK" : function(){ + // Remove any warning messages + $(this).find('.ui-state-error').remove(); + + // Change dialog buttons + $('#' + dialogId).dialog('option', 'buttons', { + 'Close':function(){ + $(this).dialog('close'); + } + }); + + var priority = $(this).find('input[name="priority"]').val(); + var user = $(this).find('input[name="username"]').val(); + var password = $(this).find('input[name="password"]').val(); + var maxVM = $(this).find('input[name="maxvm"]').val(); + + // Verify inputs are provided + if (!user || !password || !maxVM) { + var warn = createWarnBar('Please provide a value for each missing field!'); + warn.prependTo($(this)); + } else { + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'webrun', + tgt : '', + args : 'updateuser;' + priority + ';' + user + ';' + password + ';' + maxVM, + msg : dialogId + }, + success : updatePanel + }); + + // Update highest priority + topPriority = priority; + } + }, + "Cancel": function(){ + $(this).dialog('close'); + } + } + }); +} + +/** + * Update dialog + * + * @param data + * HTTP request data + * @return Nothing + */ +function updatePanel(data) { + var dialogId = data.msg; + var infoMsg; + + // Create info message + if (jQuery.isArray(data.rsp)) { + infoMsg = ''; + for (var i in data.rsp) { + infoMsg += data.rsp[i] + '
    '; + } + } else { + infoMsg = data.rsp; + } + + // Create info bar with close button + var infoBar = $('
    ').css('margin', '5px 0px'); + var icon = $('').css({ + 'display': 'inline-block', + 'margin': '10px 5px' + }); + + // Create close button to close info bar + var close = $('').css({ + 'display': 'inline-block', + 'float': 'right' + }).click(function() { + $(this).parent().remove(); + }); + + var msg = $('
    ' + infoMsg + '
    ').css({ + 'display': 'inline-block', + 'width': '85%' + }); + + infoBar.append(icon, msg, close); + infoBar.prependTo($('#' + dialogId)); +} + +/** + * Open dialog to confirm user delete + * + * @param users + * Users to delete + * @return Nothing + */ +function openDeleteUserDialog(users) { + // Create form to delete disk to pool + var dialogId = 'deleteUser'; + var deleteForm = $('
    '); + + // Create info bar + var info = createInfoBar('Are you sure you want to delete ' + users.replace(new RegExp(',', 'g'), ', ') + '?'); + deleteForm.append(info); + + // Open dialog to delete user + deleteForm.dialog({ + title:'Delete user', + modal: true, + width: 400, + close: function(){ + $(this).remove(); + }, + buttons: { + "Ok": function(){ + // Remove any warning messages + $(this).find('.ui-state-error').remove(); + + // Change dialog buttons + $(this).dialog('option', 'buttons', { + 'Close': function() {$(this).dialog("close");} + }); + + // Delete user + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'webrun', + tgt : '', + args : 'deleteuser;' + users, + msg : dialogId + }, + success : updatePanel + }); + }, + "Cancel": function() { + $(this).dialog( "close" ); + } + } + }); +} + +/** + * Round a floating point to a given precision + * + * @param value + * Floating point + * @param precision + * Decimal precision + * @returns Floating point number + */ +function toFixed(value, precision) { + var power = Math.pow(10, precision || 0); + return String(Math.round(value * power) / power); +} \ No newline at end of file diff --git a/xCAT-UI/js/custom/esx.js b/xCAT-UI/js/custom/esx.js index 430a45a83..79f74bc00 100644 --- a/xCAT-UI/js/custom/esx.js +++ b/xCAT-UI/js/custom/esx.js @@ -14,6 +14,46 @@ var esxPlugin = function() { }; +/** + * Configure self-service page + */ +esxPlugin.prototype.loadConfigPage = function(tabId) { + var configAccordion = $('
    '); + + // Create accordion panel for user + var userSection = $('
    '); + var userLnk = $('

    Users

    ').click(function () { + // Do not load panel again if it is already loaded + if ($('#esxConfigUser').find('.dataTables_wrapper').length) + return; + else + $('#esxConfigUser').append(createLoader('')); + + // Get user data + loadUserPanel('esxConfigUser'); + }); + + // Create accordion panel for profiles + var profileSection = $('
    '); + profileSection.append(createInfoBar('Create, edit, and delete virtual machine profiles used in the self-service portal')); + var profileLnk = $('

    Profiles

    ').click(function () { + + }); + + // Create accordion panel for nodes + var nodeSection = $('
    '); + nodeSection.append(createInfoBar('Modify node attributes')); + var nodeLnk = $('

    Nodes

    ').click(function () { + + }); + + configAccordion.append(userLnk, userSection, profileLnk, profileSection, nodeLnk, nodeSection); + $('#' + tabId).append(configAccordion); + configAccordion.accordion(); + + userLnk.trigger('click'); +}; + /** * Clone node (service page) * diff --git a/xCAT-UI/js/custom/kvm.js b/xCAT-UI/js/custom/kvm.js index 25a745fe2..c81c906a4 100644 --- a/xCAT-UI/js/custom/kvm.js +++ b/xCAT-UI/js/custom/kvm.js @@ -14,6 +14,46 @@ var kvmPlugin = function() { }; +/** + * Configure self-service page + */ +kvmPlugin.prototype.loadConfigPage = function(tabId) { + var configAccordion = $('
    '); + + // Create accordion panel for user + var userSection = $('
    '); + var userLnk = $('

    Users

    ').click(function () { + // Do not load panel again if it is already loaded + if ($('#kvmConfigUser').find('.dataTables_wrapper').length) + return; + else + $('#kvmConfigUser').append(createLoader('')); + + // Get user data + loadUserPanel('kvmConfigUser'); + }); + + // Create accordion panel for profiles + var profileSection = $('
    '); + profileSection.append(createInfoBar('Create, edit, and delete virtual machine profiles used in the self-service portal')); + var profileLnk = $('

    Profiles

    ').click(function () { + + }); + + // Create accordion panel for nodes + var nodeSection = $('
    '); + nodeSection.append(createInfoBar('Modify node attributes')); + var nodeLnk = $('

    Nodes

    ').click(function () { + + }); + + configAccordion.append(userLnk, userSection, profileLnk, profileSection, nodeLnk, nodeSection); + $('#' + tabId).append(configAccordion); + configAccordion.accordion(); + + userLnk.trigger('click'); +}; + /** * Clone node (service page) * diff --git a/xCAT-UI/js/custom/zvm.js b/xCAT-UI/js/custom/zvm.js index 75e723fac..2dc03c6da 100644 --- a/xCAT-UI/js/custom/zvm.js +++ b/xCAT-UI/js/custom/zvm.js @@ -15,6 +15,46 @@ var zvmPlugin = function() { }; +/** + * Configure self-service configure page + */ +zvmPlugin.prototype.loadConfigPage = function(tabId) { + var configAccordion = $('
    '); + + // Create accordion panel for user + var userSection = $('
    '); + var userLnk = $('

    Users

    ').click(function () { + // Do not load panel again if it is already loaded + if ($('#zvmConfigUser').find('.dataTables_wrapper').length) + return; + else + $('#zvmConfigUser').append(createLoader('')); + + // Get user data + loadUserPanel('zvmConfigUser'); + }); + + // Create accordion panel for profiles + var profileSection = $('
    '); + profileSection.append(createInfoBar('Create, edit, and delete virtual machine profiles used in the self-service portal')); + var profileLnk = $('

    Profiles

    ').click(function () { + + }); + + // Create accordion panel for nodes + var nodeSection = $('
    '); + nodeSection.append(createInfoBar('Modify node attributes')); + var nodeLnk = $('

    Nodes

    ').click(function () { + + }); + + configAccordion.append(userLnk, userSection, profileLnk, profileSection, nodeLnk, nodeSection); + $('#' + tabId).append(configAccordion); + configAccordion.accordion(); + + userLnk.trigger('click'); +}; + /** * Clone node (service page) * diff --git a/xCAT-UI/js/nodes/nodes.js b/xCAT-UI/js/nodes/nodes.js index dff145741..e228e36b4 100644 --- a/xCAT-UI/js/nodes/nodes.js +++ b/xCAT-UI/js/nodes/nodes.js @@ -1139,10 +1139,11 @@ function getNodeAttrs(group) { }); // Create dialog to indicate table is updating - var update = $('
    ' - + '

    Updating table

    ' - +'
    '); + var update = $('
    '); + update.append(createInfoBar('Updating table ')); + update.dialog({ + title: 'Updating', modal: true, width: 300, position: 'center' @@ -1165,7 +1166,7 @@ function addNodes2Table(data) { // Hash of node attributes var attrs = new Object(); // Node attributes - var headers = $('#' + nodesTableId + ' thead tr th'); + var headers = $('#' + nodesTableId).parents('.dataTables_scroll').find('.dataTables_scrollHead thead tr th'); // Variable to send command and request node status var getNodeStatus = true; @@ -1200,15 +1201,16 @@ function addNodes2Table(data) { } } - // Set the first four headers + // Set the first five headers var headersCol = new Object(); headersCol['node'] = 1; headersCol['status'] = 2; headersCol['power'] = 3; - headersCol['comments'] = 4; + headersCol['monitor'] = 4; + headersCol['comments'] = 5; // Go through each header - for (var i = 5; i < headers.length; i++) { + for (var i = 6; i < headers.length; i++) { // Get the column index headersCol[headers.eq(i).html()] = i; } @@ -1218,7 +1220,7 @@ function addNodes2Table(data) { var rows = datatable.fnGetData(); for (var node in attrs) { // Get row containing node - var nodeRowPos; + var nodeRowPos = 0; for (var i in rows) { // If column contains node if (rows[i][1].indexOf('>' + node + '<') > -1) { @@ -1266,7 +1268,7 @@ function addNodes2Table(data) { // Create icon for node comments var tipID = node + 'Tip'; - var commentsCol = $('#' + node).parent().parent().find('td').eq(4); + var commentsCol = $('#' + node).parent().parent().find('td').eq(5); // Create tooltip var icon = $('').css({ diff --git a/xCAT-UI/js/service/service.js b/xCAT-UI/js/service/service.js index 4534556e4..477b018e6 100644 --- a/xCAT-UI/js/service/service.js +++ b/xCAT-UI/js/service/service.js @@ -155,48 +155,6 @@ function loadServicePage() { } }); } - - // Check if user has root privilege - // If so, add an admin tab - $.ajax( { - url : 'lib/srv_cmd.php', - dataType : 'json', - data : { - cmd : 'webportal', - tgt : '', - args : 'getuserprivilege;' + $.cookie('xcat_username'), - msg : '' - }, - - success : function(data) { - var rsp = jQuery.trim(data.rsp); - rsp = rsp.replace('Privilege:', ''); - var privilege = jQuery.trim(rsp); - - // If the user has root privilege, create an administrator tab - if (privilege == 'root') { - var configTabId = 'configTab'; - serviceTabs.add(configTabId, 'Configure', '', false); - loadConfigPage(configTabId); - } - } - }); -} - -/** - * Load the service portal's configure page - * - * @param tabId - * Tab ID where page will reside - * @return Nothing - */ -function loadConfigPage(tabId) { - // Create info bar - var infoBar = createInfoBar('Select a platform to configure, then click Ok.'); - - // Create configure page - var configPg = $('
    '); - $('#' + tabId).append(infoBar, configPg); } /** diff --git a/xCAT-UI/js/ui.js b/xCAT-UI/js/ui.js index 550260799..a3be06e64 100644 --- a/xCAT-UI/js/ui.js +++ b/xCAT-UI/js/ui.js @@ -611,6 +611,7 @@ function initPage() { if (page == 'configure.php') { includeJs("js/configure/update.js"); includeJs("js/configure/discover.js"); + includeJs("js/configure/service.js"); headers.eq(1).css(style); loadConfigPage(); } else if (page == 'provision.php') { diff --git a/xCAT-UI/xcat/plugins/web.pm b/xCAT-UI/xcat/plugins/web.pm index 5234291fb..548ec6501 100644 --- a/xCAT-UI/xcat/plugins/web.pm +++ b/xCAT-UI/xcat/plugins/web.pm @@ -62,7 +62,9 @@ sub process_request { 'addnode' => \&web_addnode, 'graph' => \&web_graphinfo, 'getdefaultuserentry' => \&web_getdefaultuserentry, - 'passwd' => \&web_passwd + 'passwd' => \&web_passwd, + 'updateuser' => \&web_updateuser, + 'deleteuser' => \&web_deleteuser ); #check whether the request is authorized or not @@ -2237,7 +2239,8 @@ sub web_passwd() { my $newPassword = $request->{arg}->[2]; # Generate encrypted password - my $encrypted = `perl -e "print crypt($newPassword, 03162012)"`; + my $random = rand(10000000); + my $encrypted = `perl -e "print crypt($newPassword, $random)"`; # Save in xCAT passwd table `chtab username=$user passwd.key=xcat passwd.password=$encrypted`; @@ -2245,4 +2248,40 @@ sub web_passwd() { $callback->( { info => $info } ); return; } + +sub web_updateuser() { + my ( $request, $callback, $sub_req ) = @_; + + # Get user attributes + my $priority = $request->{arg}->[1]; + my $user = $request->{arg}->[2]; + my $password = $request->{arg}->[3]; + my $maxVM = $request->{arg}->[4]; + + # Save in xCAT passwd and policy tables + `chtab username=$user passwd.key=xcat passwd.password=$password`; + `chtab name=$user policy.priority=$priority policy.comments="max-vm:$maxVM"`; + + my $info = "User successfully updated"; + $callback->( { info => $info } ); + return; +} + +sub web_deleteuser() { + my ( $request, $callback, $sub_req ) = @_; + + # Get user attributes + my $user = $request->{arg}->[1]; + my @users = split( ',', $user ); + + # Delete user from xCAT passwd and policy tables + foreach(@users) { + `chtab -d username=$_ passwd`; + `chtab -d name=$_ policy`; + } + + my $info = "User successfully deleted"; + $callback->( { info => $info } ); + return; +} 1;