/** * Global variables */ var nodesTabs; // Node tabs var origAttrs = new Object(); // Original node attributes /** * Set the nodes tab * * @param obj * Tab object * @return Nothing */ function setNodesTab(obj) { nodesTabs = obj; } /** * Get the nodes tab * * @param Nothing * @return Tab object */ function getNodesTab() { return nodesTabs; } /** * Load nodes page * * @return Nothing */ function loadNodesPage() { // If groups are not already loaded if (!$('#groups').length) { // Create a groups division groupDIV = $('
'); nodesDIV = $('
'); $('#content').append(groupDIV); $('#content').append(nodesDIV); // Create loader var loader = createLoader(); groupDIV.append(loader); // Create info bar var info = createInfoBar('Select a group to view its nodes'); $('#nodes').append(info); // Get groups $.ajax( { url : 'lib/cmd.php', dataType : 'json', data : { cmd : 'extnoderange', tgt : '/.*', args : 'subgroups', msg : '' }, success : loadGroups }); // Get graphical view info $.ajax( { url : 'lib/cmd.php', dataType : 'json', data : { cmd : 'nodels', tgt : 'all', args : 'nodetype.nodetype;ppc.parent;vpd.mtm;nodelist.status;nodehm.mgt', msg : '' }, success : extractGraphicalData }); } } /** * Load groups * * @param data * Data returned from HTTP request * @return */ function loadGroups(data) { // Remove loader $('#groups').find('img').remove(); var groups = data.rsp; setGroupsCookies(data); // Create a list of groups var ul = $(''); var item = $('
  • Groups

  • '); ul.append(item); var subUL = $(''); item.append(subUL); // Create a link for each group for ( var i = groups.length; i--;) { var subItem = $('
  • '); var link = $('' + groups[i] + ''); subItem.append(link); subUL.append(subItem); } // Turn groups list into a tree $('#groups').append(ul); $('#groups').jstree( { core : { "initially_open" : [ "root" ] }, themes : { "theme" : "default", "dots" : false, // No dots "icons" : false // No icons } }); // Load nodes onclick $('#groups').bind('select_node.jstree', function(event, data) { // If there are subgroups, remove them data.rslt.obj.children('ul').remove(); var thisGroup = jQuery.trim(data.rslt.obj.text()); if (thisGroup) { // Clear nodes division $('#nodes').children().remove(); // Create loader var loader = $('
    ').append(createLoader()); var loader2 = $('
    ').append(createLoader()); // Create a tab for this group var tab = new Tab(); setNodesTab(tab); tab.init(); $('#nodes').append(tab.object()); tab.add('nodesTab', 'Nodes', loader, false); tab.add('graphTab', 'Graphical', loader2, false); // Get nodes within selected group $.ajax( { url : 'lib/cmd.php', dataType : 'json', data : { cmd : 'lsdef', tgt : '', args : thisGroup, msg : thisGroup }, success : loadNodes }); // Get subgroups within selected group // only when this is the parent group and not a subgroup if (data.rslt.obj.attr('id').indexOf('Subgroup') < 0) { $.ajax( { url : 'lib/cmd.php', dataType : 'json', data : { cmd : 'extnoderange', tgt : thisGroup, args : 'subgroups', msg : thisGroup }, success : loadSubgroups }); } // Get physical layout $.ajax({ url : 'lib/cmd.php', dataType : 'json', data : { cmd : 'lsdef', tgt : '', args : thisGroup + ';-s', msg : '' }, success : createPhysicalLayout }); } // End of if (thisGroup) }); // Create link to add nodes var addNodeLink = $('Add node'); addNodeLink.bind('click', function(event) { var info = createInfoBar('Select the hardware management for the new node range'); var addNodeForm = $('
    '); addNodeForm.append(info); addNodeForm.append('
    ' + '' + '
    ' ); // Open dialog to add node addNodeForm.dialog({ modal: true, width: 400, buttons: { "Ok": function(){ // Get hardware management var mgt = $(this).find('select[name=mgt]').val(); var plugin; switch(mgt) { case "blade": plugin = new bladePlugin(); break; case "fsp": plugin = new fspPlugin(); break; case "hmc": plugin = new hmcPlugin(); break; case "ipmi": plugin = new ipmiPlugin(); break; case "ivm": plugin = new ivmPlugin(); break; case "zvm": plugin = new zvmPlugin(); break; } plugin.addNode(); $(this).dialog( "close" ); }, "Cancel": function(){ $(this).dialog( "close" ); } } }); }); // Generate tooltips addNodeLink.tooltip({ position: "center right", // Place tooltip on the right edge offset: [-2, 10], // A little tweaking of the position effect: "fade", // Use the built-in fadeIn/fadeOut effect opacity: 0.7 // Custom opacity setting }); $('#groups').append(addNodeLink); } /** * Load subgroups belonging to a given group * * @param data * Data returned from HTTP request * @return Nothing */ function loadSubgroups(data) { // Data returned var rsp = data.rsp; // Group name var group = data.msg; // Go through each subgroup for ( var i in rsp) { // Do not put the same group in the subgroup if (rsp[i] != group && $('#' + group).length) { // Add subgroup inside group $('#groups').jstree('create', $('#' + group), 'inside', { 'attr': {'id': rsp[i] + 'Subgroup'}, 'data': rsp[i]}, '', true); } } // End of for } /** * Load nodes belonging to a given group * * @param data * Data returned from HTTP request * @return Nothing */ function loadNodes(data) { // Data returned var rsp = data.rsp; // Group name var group = data.msg; // Node attributes hash var attrs = new Object(); // Node attributes var headers = new Object(); // Clear cookie containing list of nodes where // their attributes need to be updated $.cookie('nodes2update', ''); // Clear hash table containing node attributes origAttrs = ''; var node; var args; for ( var i in rsp) { // Get the node var pos = rsp[i].indexOf('Object name:'); if (pos > -1) { var temp = rsp[i].split(': '); node = jQuery.trim(temp[1]); // Create a hash for the node attributes attrs[node] = new Object(); i++; } // Get key and value args = rsp[i].split('='); var key = jQuery.trim(args[0]); var val = jQuery.trim(args[1]); // Create a hash table attrs[node][key] = val; headers[key] = 1; } // Save attributes in hash table origAttrs = attrs; // Sort headers var sorted = new Array(); for ( var key in headers) { // Do not put in comments twice if (key != 'usercomment') { sorted.push(key); } } sorted.sort(); // Add column for check box, node, ping, power, and comments sorted.unshift('', 'node', 'ping', 'power', 'comments'); // Create a datatable var dTable = new DataTable('nodesDataTable'); dTable.init(sorted); // Go through each node for ( var node in attrs) { // Create a row var row = new Array(); // Create a check box var checkBx = ''; // Open node onclick var nodeLink = $('' + node + '').bind('click', loadNode); // Left align node link nodeLink.css('text-align', 'left'); // Push in checkbox, node link, ping, and power row.push(checkBx, nodeLink, '', ''); // Put in comments var comment = attrs[node]['usercomment']; var iconSrc; // If no comments exists, show 'No comments' and set icon image source if (!comment) { comment = 'No comments'; iconSrc = 'images/ui-icon-no-comment.png'; } else { iconSrc = 'images/ui-icon-comment.png'; } // Create comments icon var tipID = node + 'Tip'; var icon = $('').css({ 'width': '18px', 'height': '18px' }); // Create tooltip var tip = createCommentsToolTip(comment); // Create container to put icon and comment in var col = $('').append(icon); col.append(tip); row.push(col); // Generate tooltips icon.tooltip({ position: "center right", // Place tooltip on the right edge offset: [-2, 10], // A little tweaking of the position relative: true, effect: "fade", // Use the built-in fadeIn/fadeOut // effect opacity: 0.8 // Custom opacity setting }); // Go through each header for ( var i = 5; i < sorted.length; i++) { // Add the node attributes to the row var key = sorted[i]; // Do not put in comments twice if (key != 'usercomment') { var val = attrs[node][key]; if (val) { row.push(val); } else { row.push(''); } } // End of if } // Add the row to the table dTable.add(row); } // Clear the tab before inserting the table $('#nodesTab').children().remove(); // Create info bar for nodes tab var info = createInfoBar('Click on a cell to edit. Click outside the table to write to the cell. Hit the Escape key to ignore changes. Once you are satisfied with how the table looks, click on Save.'); $('#nodesTab').append(info); // Create action bar var actionBar = $('
    '); /** * The following actions are available to perform against a given node: * power, clone, delete, unlock, and advanced */ var powerLnk = $('Power'); // Power on (rpower) var powerOnLnk = $('Power on'); powerOnLnk.bind('click', function(event) { var tgtNodes = getNodesChecked('nodesDataTable'); if (tgtNodes) { powerNode(tgtNodes, 'on'); } }); // Power off (rpower) var powerOffLnk = $('Power off'); powerOffLnk.bind('click', function(event) { var tgtNodes = getNodesChecked('nodesDataTable'); if (tgtNodes) { powerNode(tgtNodes, 'off'); } }); // Clone var cloneLnk = $('Clone'); cloneLnk.bind('click', function(event) { var tgtNodes = getNodesChecked('nodesDataTable').split(','); for ( var i = 0; i < tgtNodes.length; i++) { var mgt = getNodeAttr(tgtNodes[i], 'mgt'); // Create an instance of the plugin var plugin; switch(mgt) { case "blade": plugin = new bladePlugin(); break; case "fsp": plugin = new fspPlugin(); break; case "hmc": plugin = new hmcPlugin(); break; case "ipmi": plugin = new ipmiPlugin(); break; case "ivm": plugin = new ivmPlugin(); break; case "zvm": plugin = new zvmPlugin(); break; } plugin.loadClonePage(tgtNodes[i]); } }); // Delete (rmvm) var deleteLnk = $('Delete'); deleteLnk.bind('click', function(event) { var tgtNodes = getNodesChecked('nodesDataTable'); if (tgtNodes) { deleteNode(tgtNodes); } }); // Unlock var unlockLnk = $('Unlock'); unlockLnk.bind('click', function(event) { var tgtNodes = getNodesChecked('nodesDataTable'); if (tgtNodes) { loadUnlockPage(tgtNodes); } }); // Run script (xdsh) var scriptLnk = $('Run script'); scriptLnk.bind('click', function(event) { var tgtNodes = getNodesChecked('nodesDataTable'); if (tgtNodes) { loadScriptPage(tgtNodes); } }); // Update (updatenode) var updateLnk = $('Update'); updateLnk.bind('click', function(event) { var tgtNodes = getNodesChecked('nodesDataTable'); if (tgtNodes) { loadUpdatenodePage(tgtNodes); } }); // Set boot state (nodeset) var setBootStateLnk = $('Set boot state'); setBootStateLnk.bind('click', function(event) { var tgtNodes = getNodesChecked('nodesDataTable'); if (tgtNodes) { loadNodesetPage(tgtNodes); } }); // Boot to network (rnetboot) var boot2NetworkLnk = $('Boot to network'); boot2NetworkLnk.bind('click', function(event) { var tgtNodes = getNodesChecked('nodesDataTable'); if (tgtNodes) { loadNetbootPage(tgtNodes); } }); // Remote console (rcons) var rcons = $('Open console'); rcons.bind('click', function(event){ var tgtNodes = getNodesChecked('nodesDataTable'); if (tgtNodes) { loadRconsPage(tgtNodes); } }); var advancedLnk = $('Advanced'); // Power actions var powerActions = [ powerOnLnk, powerOffLnk ]; var powerActionMenu = createMenu(powerActions); // Advanced actions var advancedActions; if ('compute' == group) { advancedActions = [ boot2NetworkLnk, scriptLnk, setBootStateLnk, updateLnk, rcons ]; } else { advancedActions = [ boot2NetworkLnk, scriptLnk, setBootStateLnk, updateLnk ]; } var advancedActionMenu = createMenu(advancedActions); /** * Create an action menu */ var actionsDIV = $('
    '); var actions = [ [ powerLnk, powerActionMenu ], cloneLnk, deleteLnk, unlockLnk, [ advancedLnk, advancedActionMenu ] ]; var actionMenu = createMenu(actions); actionMenu.superfish(); actionsDIV.append(actionMenu); actionBar.append(actionsDIV); $('#nodesTab').append(actionBar); // Insert table $('#nodesTab').append(dTable.object()); // Save changes var saveLnk = $('Save'); saveLnk.bind('click', function(event){ updateNodeAttrs(group); }); // Undo changes var undoLnk = $('Undo'); undoLnk.bind('click', function(event){ restoreNodeAttrs(); }); /** * Create menu to save and undo table changes */ // It will be hidden until a change is made var tableActionsMenu = createMenu([saveLnk, undoLnk]).hide(); tableActionsMenu.css('margin-left', '100px'); actionsDIV.append(tableActionsMenu); // Turn table into a datatable var myDataTable = $('#nodesDataTable').dataTable({ 'iDisplayLength': 50 }); // Do not sort ping, power, and comment column var pingCol = $('#nodesDataTable thead tr th').eq(2); var powerCol = $('#nodesDataTable thead tr th').eq(3); var commentCol = $('#nodesDataTable thead tr th').eq(4); pingCol.unbind('click'); powerCol.unbind('click'); commentCol.unbind('click'); // Create enough space for loader to be displayed $('#nodesDataTable tbody tr td:nth-child(3)').css('min-width', '60px'); $('#nodesDataTable tbody tr td:nth-child(4)').css('min-width', '60px'); // Instead refresh the ping status and power status pingCol.bind('click', function(event) { refreshPingStatus(group); }); powerCol.bind('click', function(event) { refreshPowerStatus(group); }); /** * Enable editable columns */ // Do not make 1st, 2nd, 3rd, 4th, or 5th column editable $('#nodesDataTable td:not(td:nth-child(1),td:nth-child(2),td:nth-child(3),td:nth-child(4),td:nth-child(5))').editable( function(value, settings) { // Change text color to red $(this).css('color', 'red'); // Get column index var colPos = this.cellIndex; // Get row index var dTable = $('#nodesDataTable').dataTable(); var rowPos = dTable.fnGetPosition(this.parentNode); // Update datatable dTable.fnUpdate(value, rowPos, colPos); // Get node name var node = $(this).parent().find('td a.node').text(); // Flag node to update flagNode2Update(node); // Show table menu actions tableActionsMenu.show(); return (value); }, { onblur : 'submit', // Clicking outside editable area submits // changes type : 'textarea', placeholder: ' ', height : '30px' // The height of the text area }); /** * Get power and ping for each node */ // Get power status $.ajax( { url : 'lib/cmd.php', dataType : 'json', data : { cmd : 'rpower', tgt : group, args : 'stat', msg : '' }, success : loadPowerStatus }); // Get ping status $.ajax( { url : 'lib/cmd.php', dataType : 'json', data : { cmd : 'webrun', tgt : '', args : 'pping ' + group, msg : '' }, success : loadPingStatus }); /** * Additional ajax requests need to be made for zVM */ // Get index of HCP column var i = $.inArray('hcp', sorted); if (i) { // Get hardware control point var rows = dTable.object().find('tbody tr'); var hcps = new Object(); for ( var j = 0; j < rows.length; j++) { var val = rows.eq(j).find('td').eq(i).html(); hcps[val] = 1; } var args; for ( var h in hcps) { // Get node without domain name args = h.split('.'); // Check if SMAPI is online $.ajax( { url : 'lib/cmd.php', dataType : 'json', data : { cmd : 'lsvm', tgt : args[0], args : '', msg : 'group=' + group + ';hcp=' + args[0] }, // Load hardware control point (HCP) specific info // Get disk pools and network names success : loadHcpInfo }); } // End of for } // End of if } /** * Load power status for each node * * @param data * Data returned from HTTP request * @return Nothing */ function loadPowerStatus(data) { // Get datatable var dTable = $('#nodesDataTable').dataTable(); var power = data.rsp; var rowNum, node, status, args; for ( var i in power) { // power[0] = nodeName and power[1] = state args = power[i].split(':'); node = jQuery.trim(args[0]); status = jQuery.trim(args[1]); // Get the row containing the node rowNum = getRowNum(node); // Update the power status column dTable.fnUpdate(status, rowNum, 3); } // Hide power loader var powerCol = $('#nodesDataTable thead tr th').eq(3); powerCol.find('img').hide(); } /** * Refresh power status for each node * * @param group * Group name * @return Nothing */ function refreshPowerStatus(group) { // Show power loader var powerCol = $('#nodesDataTable thead tr th').eq(3); powerCol.find('img').show(); // Get the power status $.ajax( { url : 'lib/cmd.php', dataType : 'json', data : { cmd : 'rpower', tgt : group, args : 'stat', msg : '' }, success : loadPowerStatus }); } /** * Load ping status for each node * * @param data * Data returned from HTTP request * @return Nothing */ function loadPingStatus(data) { // Get data table var dTable = $('#nodesDataTable').dataTable(); var ping = data.rsp; var rowPos, node, status; // Get all nodes within the datatable var rows = dTable.fnGetNodes(); for ( var i in ping) { // ping[0] = nodeName and ping[1] = state node = jQuery.trim(ping[i][0]); status = jQuery.trim(ping[i][1]); // Get the row containing the node rowPos = getRowNum(node); // Update the ping status column dTable.fnUpdate(status, rowPos, 2); } // Hide ping loader var pingCol = $('#nodesDataTable thead tr th').eq(2); pingCol.find('img').hide(); } /** * Refresh ping status for each node * * @param group * Group name * @return Nothing */ function refreshPingStatus(group) { // Show ping loader var pingCol = $('#nodesDataTable thead tr th').eq(2); pingCol.find('img').show(); // Get the ping status $.ajax( { url : 'lib/cmd.php', dataType : 'json', data : { cmd : 'webrun', tgt : '', args : 'pping ' + group, msg : '' }, success : loadPingStatus }); } /** * Load inventory for given node * * @param e * Windows event * @return Nothing */ function loadNode(e) { if (!e) { e = window.event; } // Get node that was clicked var node = (e.target) ? e.target.id : e.srcElement.id; var mgt = getNodeAttr(node, 'mgt'); // Create an instance of the plugin var plugin; switch(mgt) { case "blade": plugin = new bladePlugin(); break; case "fsp": plugin = new fspPlugin(); break; case "hmc": plugin = new hmcPlugin(); break; case "ipmi": plugin = new ipmiPlugin(); break; case "ivm": plugin = new ivmPlugin(); break; case "zvm": plugin = new zvmPlugin(); break; } // Get tab area where a new tab will be inserted var myTab = getNodesTab(); var inst = 0; var newTabId = 'nodeTab' + inst; while ($('#' + newTabId).length) { // If one already exists, generate another one inst = inst + 1; newTabId = 'nodeTab' + inst; } // Reset node process $.cookie(node + 'Processes', 0); // Add new tab, only if one does not exist var loader = createLoader(newTabId + 'TabLoader'); loader = $('
    ').append(loader); myTab.add(newTabId, node, loader, true); // Get node inventory var msg = 'out=' + newTabId + ',node=' + node; $.ajax( { url : 'lib/cmd.php', dataType : 'json', data : { cmd : 'rinv', tgt : node, args : 'all', msg : msg }, success : plugin.loadInventory }); // Select new tab myTab.select(newTabId); } /** * Unlock a node by setting the SSH keys * * @param tgtNodes * Nodes to unlock * @return Nothing */ function loadUnlockPage(tgtNodes) { // Get nodes tab var tab = getNodesTab(); // Generate new tab ID var instance = 0; var newTabId = 'UnlockTab' + instance; while ($('#' + newTabId).length) { // If one already exists, generate another one instance = instance + 1; newTabId = 'UnlockTab' + instance; } var unlockForm = $('
    '); // Create status bar, hide on load var statBarId = 'UnlockStatusBar' + instance; var statusBar = createStatusBar(statBarId).hide(); unlockForm.append(statusBar); // Create loader var loader = createLoader(''); statusBar.append(loader); // Create info bar var infoBar = createInfoBar('Give the root password for this node range to setup its SSH keys'); unlockForm.append(infoBar); unlockForm.append('
    '); unlockForm.append('
    '); // Generate tooltips unlockForm.find('div input[title]').tooltip({ position: "center right", // Place tooltip on the right edge offset: [-2, 10], // A little tweaking of the position effect: "fade", // Use the built-in fadeIn/fadeOut effect opacity: 0.7 // Custom opacity setting }); /** * Ok */ var okBtn = createButton('Ok'); okBtn.bind('click', function(event) { // Remove any warning messages $(this).parent().parent().find('.ui-state-error').remove(); // If form is complete var ready = formComplete(newTabId); if (ready) { var password = $('#' + newTabId + ' input[name=password]').val(); // Setup SSH keys $.ajax( { url : 'lib/cmd.php', dataType : 'json', data : { cmd : 'webrun', tgt : '', args : 'unlock;' + tgtNodes + ';' + password, msg : 'out=' + statBarId + ';cmd=unlock;tgt=' + tgtNodes }, success : updateStatusBar }); // Show status bar statusBar.show(); // Disable Ok button $(this).attr('disabled', 'true'); } else { // Show warning message var warn = createWarnBar('You are missing some values'); warn.prependTo($(this).parent().parent()); } }); unlockForm.append(okBtn); tab.add(newTabId, 'Unlock', unlockForm, true); tab.select(newTabId); } /** * Load script page * * @param tgtNodes * Targets to run script against * @return Nothing */ function loadScriptPage(tgtNodes) { // Get nodes tab var tab = getNodesTab(); // Generate new tab ID var inst = 0; var newTabId = 'scriptTab' + inst; while ($('#' + newTabId).length) { // If one already exists, generate another one inst = inst + 1; newTabId = 'scriptTab' + inst; } // Open new tab // Create remote script form var scriptForm = $('
    '); // Create status bar var barId = 'scriptStatusBar' + inst; var statBar = createStatusBar(barId); statBar.hide(); scriptForm.append(statBar); // Create loader var loader = createLoader('scriptLoader' + inst); statBar.append(loader); // Create info bar var infoBar = createInfoBar('Run a script against this node range'); scriptForm.append(infoBar); // Target node or group var tgt = $('
    '); scriptForm.append(tgt); // Upload file var upload = $('
    '); var label = $(''); var file = $(''); var subBtn = createButton('Load'); upload.append(label); upload.append(file); upload.append(subBtn); scriptForm.append(upload); // Generate tooltips scriptForm.find('div input[title]').tooltip({ position: "center right", // Place tooltip on the right edge offset: [-2, 10], // A little tweaking of the position effect: "fade", // Use the built-in fadeIn/fadeOut effect opacity: 0.7 // Custom opacity setting }); // Script var script = $('
    ').css({ 'font-size': '10px', 'height': '50px', 'width': '200px', 'background-color': '#000', 'color': '#fff', 'border': '0px', 'display': 'block' }); // Create links to save and cancel changes var lnkStyle = { 'color': '#58ACFA', 'font-size': '10px', 'display': 'inline-block', 'padding': '5px', 'float': 'right' }; var saveLnk = $('Save').css(lnkStyle).hide(); var cancelLnk = $('Cancel').css(lnkStyle).hide(); var infoSpan = $('Click to edit').css(lnkStyle); // Save changes onclick saveLnk.bind('click', function(){ // Get node and comment var node = $(this).parent().parent().find('img').attr('id').replace('Tip', ''); var comments = $(this).parent().find('textarea').val(); // Save comment $.ajax( { url : 'lib/cmd.php', dataType : 'json', data : { cmd : 'chdef', tgt : '', args : '-t;node;-o;' + node + ';usercomment=' + comments, msg : 'node=' + node }, success: showChdefOutput }); // Hide cancel and save links $(this).hide(); cancelLnk.hide(); }); // Cancel changes onclick cancelLnk.bind('click', function(){ // Get original comment and put it back var orignComments = $(this).parent().find('textarea').text(); $(this).parent().find('textarea').val(orignComments); // Hide cancel and save links $(this).hide(); saveLnk.hide(); infoSpan.show(); }); // Show save link when comment is edited txtArea.bind('click', function(){ saveLnk.show(); cancelLnk.show(); infoSpan.hide(); }); toolTip.append(txtArea); toolTip.append(cancelLnk); toolTip.append(saveLnk); toolTip.append(infoSpan); return toolTip; } /** * Show chdef output * * @param data * Data returned from HTTP request * @return Nothing */ function showChdefOutput(data) { // Get output var out = data.rsp; var node = data.msg.replace('node=', ''); // Find info bar on nodes tab, if any var info = $('#nodesTab').find('.ui-state-highlight'); if (!info.length) { // Create info bar if one does not exist info = createInfoBar(''); $('#nodesTab').append(info); } // Go through output and append to paragraph var node, status; var pg = $('

    '); for ( var i in out) { pg.append(node + ': ' + out[i] + '
    '); } info.append(pg); }