diff --git a/xCAT-UI/js/configure/configure.js b/xCAT-UI/js/configure/configure.js index 5e88d4174..97c83c150 100644 --- a/xCAT-UI/js/configure/configure.js +++ b/xCAT-UI/js/configure/configure.js @@ -342,7 +342,20 @@ function loadTable(data) { cont : newCont }, success : function(data) { - alert('Changes saved'); + // Create info message + var dialog = $('
').append(createInfoBar('Changes saved!')); + + // Open dialog + dialog.dialog({ + modal: true, + title: 'Info', + width: 400, + buttons: { + "Ok": function(){ + $(this).dialog("close"); + } + } + }); } }); }); @@ -428,12 +441,8 @@ function loadTable(data) { }); }); - // Actions - var actionsLnk = 'Actions'; - var actsMenu = createMenu([saveLnk, undoLnk, addLnk]); - // Create an action menu - var actionsMenu = createMenu([ [ actionsLnk, actsMenu ] ]); + var actionsMenu = createMenu([saveLnk, undoLnk, addLnk]); actionsMenu.superfish(); actionsMenu.css('display', 'inline-block'); actionBar.append(actionsMenu); diff --git a/xCAT-UI/js/custom/zvm.js b/xCAT-UI/js/custom/zvm.js index 814461ee9..75e723fac 100644 --- a/xCAT-UI/js/custom/zvm.js +++ b/xCAT-UI/js/custom/zvm.js @@ -1445,7 +1445,7 @@ zvmPlugin.prototype.loadProvisionPage = function(tabId) { * * @return Nothing */ -zvmPlugin.prototype.loadResources = function() { +zvmPlugin.prototype.loadResources = function() { // Reset resource table setDiskDataTable(''); setNetworkDataTable(''); diff --git a/xCAT-UI/js/custom/zvmUtils.js b/xCAT-UI/js/custom/zvmUtils.js index ca55c3ea1..7900b624b 100644 --- a/xCAT-UI/js/custom/zvmUtils.js +++ b/xCAT-UI/js/custom/zvmUtils.js @@ -1009,10 +1009,10 @@ function updateZCloneStatus(data) { function getZResources(data) { // Do not continue if there is no output if (data.rsp) { - // Loop through each line + // Push hardware control points into an array var node, hcp; var hcpHash = new Object(); - for ( var i in data.rsp) { + for (var i in data.rsp) { node = data.rsp[i][0]; hcp = data.rsp[i][1]; hcpHash[hcp] = 1; @@ -1020,42 +1020,98 @@ function getZResources(data) { // Create an array for hardware control points var hcps = new Array(); - for ( var key in hcpHash) { - hcps.push(key); + for (var key in hcpHash) { // Get the short host name hcp = key.split('.')[0]; - - // Get disk pools - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'lsvm', - tgt : hcp, - args : '--diskpoolnames', - msg : hcp - }, - - success : getDiskPool - }); - - // Get network names - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'lsvm', - tgt : hcp, - args : '--getnetworknames', - msg : hcp - }, - - success : getNetwork - }); + hcps.push(hcp); } - // Set cookie + // Set hardware control point cookie $.cookie('hcp', hcps); + + // Delete loader + var tabId = 'zvmResourceTab'; + $('#' + tabId).find('img[src="images/loader.gif"]').remove(); + + // Create accordion panel for disk + var resourcesAccordion = $('
'); + var diskSection = $('
'); + var diskLnk = $('

Disks

').click(function () { + // Do not load panel again if it is already loaded + if ($('#zvmDiskResource').children().length) + return; + else + $('#zvmDiskResource').append(createLoader('')); + + // Resize accordion + $('#zvmResourceAccordion').accordion('resize'); + + // Create a array for hardware control points + var hcps = new Array(); + if ($.cookie('hcp').indexOf(',') > -1) + hcps = $.cookie('hcp').split(','); + else + hcps.push($.cookie('hcp')); + + // Query the disk pools for each + for (var i in hcps) { + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'lsvm', + tgt : hcps[i], + args : '--diskpoolnames', + msg : hcps[i] + }, + + success : getDiskPool + }); + } + }); + + // Create accordion panel for network + var networkSection = $('
'); + var networkLnk = $('

Networks

').click(function () { + // Do not load panel again if it is already loaded + if ($('#zvmNetworkResource').children().length) + return; + else + $('#zvmNetworkResource').append(createLoader('')); + + // Resize accordion + $('#zvmResourceAccordion').accordion('resize'); + + // Create a array for hardware control points + var hcps = new Array(); + if ($.cookie('hcp').indexOf(',') > -1) + hcps = $.cookie('hcp').split(','); + else + hcps.push($.cookie('hcp')); + + for ( var i in hcps) { + // Gather networks from hardware control points + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'lsvm', + tgt : hcps[i], + args : '--getnetworknames', + msg : hcps[i] + }, + + success : getNetwork + }); + } + }); + + resourcesAccordion.append(diskLnk, diskSection, networkLnk, networkSection); + + // Append accordion to tab + $('#' + tabId).append(resourcesAccordion); + resourcesAccordion.accordion(); + diskLnk.trigger('click'); } } @@ -1785,48 +1841,39 @@ function getNetwork(data) { * @return Nothing */ function loadDiskPoolTable(data) { + // Remove loader + var panelId = 'zvmDiskResource'; + $('#' + panelId).find('img[src="images/loader.gif"]').remove(); + var args = data.msg.split(';'); var hcp = args[0].replace('hcp=', ''); var pool = args[1].replace('pool=', ''); var stat = args[2].replace('stat=', ''); var tmp = data.rsp[0].split(hcp + ': '); - // Remove loader - var loaderId = 'zvmResourceLoader'; - if ($('#' + loaderId).length) { - $('#' + loaderId).remove(); - } - - // Resource tab ID - var tabID = 'zvmResourceTab'; - var info = $('#' + tabID).find('.ui-state-highlight'); + // Resource tab ID + var info = $('#' + panelId).find('.ui-state-highlight'); // If there is no info bar if (!info.length) { // Create info bar - info = createInfoBar('Below are disks and networks found by the hardware control point. It shows disk pools defined in the EXTENT CONTROL file and LANs|VSWITCHes available to use.'); - $('#' + tabID).append(info); + info = createInfoBar('Below are disks that are defined in the EXTENT CONTROL file.'); + $('#' + panelId).append(info); } // Get datatable + var tableId = 'zDiskDataTable'; var dTable = getDiskDataTable(); if (!dTable) { - // Create disks section - var fieldSet = $('
'); - var legend = $('Disks'); - fieldSet.append(legend); - - // Create a datatable - var tableID = 'zDiskDataTable'; - var table = new DataTable(tableID); + // Create a datatable + var table = new DataTable(tableId); // Resource headers: volume ID, device type, start address, and size - table.init( [ 'HCP', 'Pool', 'Status', 'Volume ID', 'Device type', 'Start address', 'Size' ]); + table.init( [ '', 'HCP', 'Pool', 'Status', 'Region', 'Device type', 'Starting address', 'Size' ]); - // Append datatable to tab - fieldSet.append(table.object()); - $('#' + tabID).append(fieldSet); + // Append datatable to panel + $('#' + panelId).append(table.object()); // Turn into datatable - dTable = $('#' + tableID).dataTable(); + dTable = $('#' + tableId).dataTable(); setDiskDataTable(dTable); } @@ -1834,8 +1881,371 @@ function loadDiskPoolTable(data) { for ( var i = 2; i < tmp.length; i++) { tmp[i] = jQuery.trim(tmp[i]); var diskAttrs = tmp[i].split(' '); - dTable.fnAddData( [ hcp, pool, stat, diskAttrs[0], diskAttrs[1], diskAttrs[2], diskAttrs[3] ]); + dTable.fnAddData( [ '', hcp, pool, stat, diskAttrs[0], diskAttrs[1], diskAttrs[2], diskAttrs[3] ]); } + + // Create actions menu + if (!$('#zvmResourceActions').length) { + // Empty filter area + $('#' + tableId + '_length').empty(); + + // Add disk to pool + var addLnk = $('Add'); + addLnk.bind('click', function(event){ + openAddDisk2PoolDialog(); + }); + + // Delete disk from pool + var deleteLnk = $('Delete'); + deleteLnk.bind('click', function(event){ + openDeleteDiskFromPoolDialog(); + }); + + // Refresh table + var refreshLnk = $('Refresh'); + refreshLnk.bind('click', function(event){ + + }); + + // Create action bar + var actionBar = $('
'); + + // Create an action menu + var actionsMenu = createMenu([addLnk, 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 + '_length').prepend(menuDiv); + $('#' + tableId + '_length').css({ + 'padding': '0px', + 'width': '500px' + }); + $('#' + tableId + '_filter').css({'padding': '10px',}); + menuDiv.append(actionBar); + } + + /** + * Enable editable columns + */ + // Do not make 1st, 2nd, 4th, 5th, 6th, 7th, or 8th column editable + $('#' + tableId + ' td:not(td:nth-child(1),td:nth-child(2),td:nth-child(4),td:nth-child(5),td:nth-child(6),td:nth-child(7),td:nth-child(8))').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; + } + + // 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 node name + var node = $(this).parent().find('td a.node').text(); + // Get attribute name + var attrName = jQuery.trim(headers.eq(colPos).text()); + // Get column value + var value = $(this).text(); + + // Build argument + var args = attrName + '=' + value; + + // Send command to change node attributes +// $.ajax( { +// url : 'lib/cmd.php', +// dataType : 'json', +// data : { +// cmd : 'chdef', +// tgt : '', +// args : '-t;node;-o;' + node + ';' + args, +// msg : 'out=nodesTab;tgt=' + node +// }, +// +// success: showChdefOutput +// }); + + return value; + }, { + onblur : 'submit', // Clicking outside editable area submits changes + type : 'textarea', + placeholder: ' ', + event : "dblclick", // Double click and edit + height : '50px' // The height of the text area + }); + + // Resize accordion + $('#zvmResourceAccordion').accordion('resize'); +} + +/** + * Open dialog to delete disk from pool + */ +function openDeleteDiskFromPoolDialog() { + // Create form to delete disk to pool + var dialogId = 'zvmDeleteDiskFromPool'; + var deleteDiskForm = $('
'); + // Create info bar + var info = createInfoBar('Remove a disk from a disk pool defined in the EXTENT CONTROL.'); + deleteDiskForm.append(info); + var action = $('
'); + var actionSelect = $(''); + action.append(actionSelect); + + var hcp = $('
'); + var hcpSelect = $(''); + hcp.append(hcpSelect); + var region = $('
'); + var group = $('
'); + deleteDiskForm.append(action, hcp, region, group); + + // Create a array for hardware control points + var hcps = new Array(); + if ($.cookie('hcp').indexOf(',') > -1) + hcps = $.cookie('hcp').split(','); + else + hcps.push($.cookie('hcp')); + + // Append options for hardware control points + for (var i in hcps) { + hcpSelect.append($('')); + } + + actionSelect.change(function() { + if ($(this).val() == '1' || $(this).val() == '3') { + region.show(); + group.hide(); + } else if ($(this).val() == '2') { + region.show(); + group.show(); + } else if ($(this).val() == '7') { + region.val('FOOBAR'); + region.hide(); + group.show(); + } + }); + + // Open dialog to delete disk + deleteDiskForm.dialog({ + title:'Delete disk from pool', + modal: true, + width: 400, + buttons: { + "Ok": function(){ + // Remove any warning messages + $(this).find('.ui-state-error').remove(); + + // Get inputs + var action = $(this).find('select[name=action]').val(); + var hcp = $(this).find('select[name=hcp]').val(); + var region = $(this).find('input[name=region]').val(); + var group = $(this).find('input[name=group]').val(); + + // If inputs are not complete, show warning message + if (!action || !hcp) { + var warn = createWarnBar('Please provide a value for each missing field.'); + warn.prependTo($(this)); + } else { + // Change dialog buttons + $(this).dialog('option', 'buttons', { + 'Close': function() {$(this).dialog("close");} + }); + + var args; + if (action == '2' || action == '7') + args = region + ';' + group; + else + args = group; + + // Add disk to pool + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'chvm', + tgt : hcp, + args : '--removediskfrompool;' + action + ';' + args, + msg : dialogId + }, + + success : updateResourceDialog + }); + } + }, + "Cancel": function() { + $(this).dialog( "close" ); + } + } + }); +} + +/** + * Open dialog to add disk to pool + */ +function openAddDisk2PoolDialog() { + // Create form to add disk to pool + var dialogId = 'zvmAddDisk2Pool'; + var addDiskForm = $('
'); + // Create info bar + var info = createInfoBar('Add a disk to a disk pool defined in the EXTENT CONTROL. The disk has to already be attached to SYSTEM.'); + addDiskForm.append(info); + var action = $('
'); + var actionSelect = $(''); + action.append(actionSelect); + + var hcp = $('
'); + var hcpSelect = $(''); + hcp.append(hcpSelect); + var region = $('
'); + var volume = $('
'); + var group = $('
'); + addDiskForm.append(action, hcp, region, volume, group); + + // Create a array for hardware control points + var hcps = new Array(); + if ($.cookie('hcp').indexOf(',') > -1) + hcps = $.cookie('hcp').split(','); + else + hcps.push($.cookie('hcp')); + + // Append options for hardware control points + for (var i in hcps) { + hcpSelect.append($('')); + } + + actionSelect.change(function() { + if ($(this).val() == '4') { + volume.show(); + } else if ($(this).val() == '5') { + volume.hide(); + } + }); + + // Open dialog to add disk + addDiskForm.dialog({ + title:'Add disk to pool', + modal: true, + width: 400, + buttons: { + "Ok": function(){ + // Remove any warning messages + $(this).find('.ui-state-error').remove(); + + // Get inputs + var action = $(this).find('select[name=action]').val(); + var hcp = $(this).find('select[name=hcp]').val(); + var region = $(this).find('input[name=region]').val(); + var volume = $(this).find('input[name=volume]').val(); + var group = $(this).find('input[name=group]').val(); + + // If inputs are not complete, show warning message + if (!action || !hcp || !region || !group) { + var warn = createWarnBar('Please provide a value for each missing field.'); + warn.prependTo($(this)); + } else { + // Change dialog buttons + $(this).dialog('option', 'buttons', { + 'Close': function() {$(this).dialog("close");} + }); + + var args; + if (action == '4') + args = region + ';' + volume + ';' + group; + else + args = region + ';' + group; + + // Add disk to pool + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'chvm', + tgt : hcp, + args : '--adddisk2pool;' + action + ';' + args, + msg : dialogId + }, + + success : updateResourceDialog + }); + } + }, + "Cancel": function() { + $(this).dialog( "close" ); + } + } + }); +} + +/** + * Update resource dialog + * + * @param data + * HTTP request data + * @return Nothing + */ +function updateResourceDialog(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; + } + + // Append info to dialog + var info = createInfoBar(infoMsg); + info.prependTo($('#' + dialogId)); +} + +/** + * Select all checkboxes in the datatable + * + * @param event + * Event on element + * @param obj + * Object triggering event + * @return Nothing + */ +function selectAllDisk(event, obj) { + // Get datatable ID + // This will ascend from + var tableObj = obj.parents('.datatable'); + var status = obj.attr('checked'); + tableObj.find(' :checkbox').attr('checked', status); + event.stopPropagation(); } /** @@ -1846,44 +2256,35 @@ function loadDiskPoolTable(data) { * @return Nothing */ function loadNetworkTable(data) { + // Remove loader + var panelId = 'zvmNetworkResource'; + $('#' + panelId).find('img[src="images/loader.gif"]').remove(); + var args = data.msg.split(';'); var hcp = args[0].replace('hcp=', ''); var type = args[1].replace('type=', ''); var name = args[2].replace('network=', ''); var tmp = data.rsp[0].split(hcp + ': '); - // Remove loader - var loaderId = 'zvmResourceLoader'; - if ($('#' + loaderId).length) { - $('#' + loaderId).remove(); - } - - // Resource tab ID - var tabId = 'zvmResourceTab'; - var info = $('#' + tabId).find('.ui-state-highlight'); + // Resource tab ID + var info = $('#' + panelId).find('.ui-state-highlight'); // If there is no info bar if (!info.length) { // Create info bar - info = createInfoBar('Below are disks and networks found by the hardware control point. It shows disk pools defined in the EXTENT CONTROL file and LANs|VSWITCHes available to use.'); - $('#' + tabId).append(info); + info = createInfoBar('Below are LANs/VSWITCHes available to use.'); + $('#' + panelId).append(info); } // Get datatable var dTable = getNetworkDataTable(); - if (!dTable) { - // Create networks section - var fieldSet = $('
'); - var legend = $('Networks'); - fieldSet.append(legend); - + if (!dTable) { // Create table var tableId = 'zNetworkDataTable'; var table = new DataTable(tableId); table.init( [ 'HCP', 'Type', 'Name', 'Details' ]); // Append datatable to tab - fieldSet.append(table.object()); - $('#' + tabId).append(fieldSet); + $('#' + panelId).append(table.object()); // Turn into datatable dTable = $('#' + tableId).dataTable(); @@ -1904,7 +2305,10 @@ function loadNetworkTable(data) { } details += ''; - dTable.fnAddData( [ hcp, type, name, details ]); + dTable.fnAddData([ '
' + hcp + '
', '
' + type + '
', '
' + name + '
', details ]); + + // Resize accordion + $('#zvmResourceAccordion').accordion('resize'); } /** diff --git a/xCAT-UI/js/service/service.js b/xCAT-UI/js/service/service.js index b7c35e970..0a71e82da 100644 --- a/xCAT-UI/js/service/service.js +++ b/xCAT-UI/js/service/service.js @@ -138,7 +138,7 @@ function loadServicePage() { } }); } - + // Get contents of hosts table if (!$.cookie('srv_groups')) { $.ajax( { @@ -156,6 +156,48 @@ 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/xcat/plugins/webportal.pm b/xCAT-UI/xcat/plugins/webportal.pm index 54b96636f..16c1f8b90 100644 --- a/xCAT-UI/xcat/plugins/webportal.pm +++ b/xCAT-UI/xcat/plugins/webportal.pm @@ -38,7 +38,8 @@ sub process_request { 'provzlinux' => \&provzlinux, 'clonezlinux' => \&clonezlinux, 'genhostip' => \&genhostip, - 'getmaxvm' => \&getmaxvm + 'getmaxvm' => \&getmaxvm, + 'getuserprivilege' => \&getuserprivilege ); # Check if the request is authorized @@ -769,4 +770,39 @@ sub getmaxvm { $callback->( { data => "Max allowed: $max" } ); } + +sub getuserprivilege { + # Get the user privilege + my ( $request, $callback, $sub_req ) = @_; + my $user = $request->{arg}->[1]; + if (!$user) { + $callback->( { data => "(Error) No user name is specified" } ); + return; + } + + my @args; + my $privilege = "user"; + + # Look in 'policy' table + my $tab = xCAT::Table->new( 'policy', -create => 1, -autocommit => 0 ); + my @results = $tab->getAllAttribsWhere( "name='" . $user . "'", 'comments' ); + foreach (@results) { + if ( $_->{'comments'} ) { + @args = split( ';', $_->{'comments'} ); + + # Extract user privilege + foreach (@args) { + if ($_ =~ m/privilege:/i) { + $_ =~ s/privilege://g; + $privilege = $_; + $privilege =~ s/\s*$//; # Trim right + $privilege =~ s/^\s*//; # Trim left + last; + } + } + } + } + + $callback->( { data => "Privilege: $privilege" } ); +} 1; \ No newline at end of file