diff --git a/xCAT-UI/css/service.css b/xCAT-UI/css/service.css new file mode 100644 index 000000000..721460bf7 --- /dev/null +++ b/xCAT-UI/css/service.css @@ -0,0 +1,365 @@ +/*--- Dialogs ---*/ +.ui-dialog input { + border: solid 1px; + font: 12px verdana, arial, helvetica, sans-serif; +} + +.ui-dialog label,.ui-dialog input,.ui-dialog p,.ui-dialog button,.ui-dialog td { + font: 12px verdana, arial, helvetica, sans-serif; +} + +.ui-widget { + font: 12px verdana, arial, helvetica, sans-serif; +} + +/*--- Tooltip ---*/ +.tooltip { + background-color: #000; + border: 1px solid #fff; + padding: 10px 15px; + display: none; + color: #fff; + text-align: left; + max-width: 300px; + font-size: 10px; + /* Outline radius for firefox only */ + -moz-box-shadow: 0 0 10px #000; + -webkit-box-shadow: 0 0 10px #000; +} + +.tooltip h3 { + margin: 0px; +} + +/*--- Login dialog ---*/ +#logdialog { + font: 12px verdana, arial, helvetica, sans-serif; + width: 600px; +} + +#logdialog table { + border: solid 0px; +} + +#logdialog td { + width: 100px; + height: 35px; + color: #0078AE; + font-weight: bold; + border: solid 0px; +} + +#logdialog input { + width: 210px; + border: solid 1px #0078AE; + font-size: 12px; + padding-bottom: 5px; +} + +#logdialog p { + font-size: 18px; +} + +#logdialog button { + font-weight: bold; + width: 90px; + float: right; +} + +#loginput { + background-color: #f5f5f5; + height: 300px; +} + +#loginfo { + margin: 5px 0px; + text-align: right; + color: #f5f5f5; + font-weight:bold; +} + +/*--- Header ---*/ +#header { + height: 40px; + width: 1000px; + margin: 0px auto; + -moz-border-radius: .3em; + -webkit-border-radius: .3em; + border-radius: .3em; +} + +/* User name and log out */ +#header div { + float: right; +} + +#header div span { + color: #424242; + padding: 2px 15px 0px 2px; /* Top right left bottom*/ + text-align: right; + text-decoration: none; + display: block; +} + +#header div a { + padding: 3px 15px 0px 3px; /* Top right left bottom*/ + text-align: right; + color: blue; + font-weight: normal; + text-decoration: none; + display: block; + cursor: pointer; +} + +#header div a:hover { + color: red; +} + +#layoutselector { + padding: 2px 10px 0px 2px; /* Top right left bottom*/ + text-align: right; + color: #FFC125; + text-decoration: none; + display: block; +} + +/*--- Body and content ---*/ +body { + background-color: #1C1C1C; + font: 12px verdana, arial, helvetica, sans-serif; +} + +.content { + -moz-border-radius: .3em; + -webkit-border-radius: .3em; + border-radius: .3em; + width: 1000px; + min-height: 600px; + margin: 10px auto; + background-color: white; + overflow: auto; +} + +#content ul.ui-widget-header { + border-color: #4297D7 #4297D7 #7BB642; + border-width: 1px 1px 4px; +} + +.ui-state-highlight { + vertical-align: top; + word-wrap: break-word; +} + +/*--- jQuery tabs ---*/ +.tab { + font: 12px verdana, arial, helvetica, sans-serif; + border-style: none; + overflow: visible; +} + +.ui-icon-close { + float: left; + margin: 0.4em 0.2em 0 0; + cursor: pointer; +} + +/*--- Inventory and user entry ---*/ +table { + border-width: 1px; + border-spacing: 0px; + border-style: solid; + border-collapse: collapse; +} + +/*--- jQuery datatable ---*/ +.dataTables_wrapper { + overflow: auto; + width: auto; + margin: 10px auto; +} + +/*** Show X entries ***/ +.dataTables_length { + width: 40%; + float: left; + padding: 10px 20px; + text-align: left; +} + +/*** Search ***/ +.dataTables_filter { + width: 40%; + margin: 10px 0px; + display: block; + float: right; + text-align: right; +} + +.tab input,select { + font: 12px verdana, arial, helvetica, sans-serif; + border: solid 1px; + padding: 4px; +} + +.sorting,.sorting_asc,.sorting_desc { + background: none; +} + +/*** Showing X to X of X entries ***/ +.dataTables_info { + padding: 10px 20px; + width: 40%; + float: left; +} + +/*** < > buttons ***/ +.paginate_disabled_previous,.paginate_enabled_previous,.paginate_disabled_next,.paginate_enabled_next + { + height: 19px; + width: 19px; + margin-left: 2px; + float: left; +} + +/*** Table ***/ +.datatable { + width: 100%; + border-width: 1px; + border-spacing: 0px; + border-style: solid; + border-collapse: collapse; + display: inline-table; +} + +/*** Row color (odd) ***/ +.datatable tr.odd { + background-color: white; +} + +.datatable tr.odd td.sorting_1 { + background-color: white; +} + +/*** Row color (even) ***/ +.datatable tr.even { + background-color: white; +} + +.datatable tr.even td.sorting_1 { + background-color: white; +} + +.datatable a { + text-decoration: none; + color: blue; + cursor: pointer; +} + +.datatable a:hover { + color: red; +} + +/*--- Superfish menu ---*/ +.sf-menu { + background : none repeat scroll 0 0 #2191C0; + border :1px solid #f5f5f5; + border-radius: 0.3em 0.3em 0.3em 0.3em; +} + +.sf-menu a { + color: white; + padding: 10px 25px; + font-weight: bold; +} + +.sf-sub-indicator{ + right:0; +} + +.sf-shadow ul { + padding: 0px; +} + +.sf-menu li:hover, .sf-menu li.sfHover { + background: #79C9EC; +} + +/*--- Generic tags ---*/ +p { + word-wrap: break-word; +} + +a { + cursor: pointer; + color: blue; +} + +th { + font: bold 12px verdana, arial, helvetica, sans-serif; + border-width: 1px; + padding: 8px 0px; + min-width: 50px; + border-style: solid; + vertical-align: middle; + text-align: center; +} + +td { + font: 12px verdana, arial, helvetica, sans-serif; + color: #424242; + padding: 8px 0px; + border-width: 1px; + border-style: solid; + vertical-align: middle; + text-align: center; +} + +fieldset { + margin-bottom: 5px; + border-width: 1px 0 0 0; + border-style: solid none none none; +} + +label { + color: #424242; + display: inline-block; + line-height: 1.5; + vertical-align: top; + width: 140px; +} + +legend { + font: 12px verdana, arial, helvetica, sans-serif; + color: #424242; + font-weight: bold; + padding: 10px 15px; +} + +ol { + margin: 0; + padding: 0; +} + +li { + list-style: none; + padding: 5px 5px 5px 20px; + margin: 0; +} + +input,textarea,select { + font: 12px verdana, arial, helvetica, sans-serif; + border: solid 1px; + padding: 5px; + display: inline-table; +} + +table a { + font: 12px verdana, arial, helvetica, sans-serif; + text-decoration: none; + color: blue; + cursor: pointer; +} + +table a:hover { + color: red; +} \ No newline at end of file diff --git a/xCAT-UI/css/style.css b/xCAT-UI/css/style.css index 95552110f..611ebb816 100644 --- a/xCAT-UI/css/style.css +++ b/xCAT-UI/css/style.css @@ -31,43 +31,50 @@ margin: 0px; } -/*--------------- login dialog ---------*/ +/*--- Login dialog ---*/ #logdialog { + font: 12px verdana, arial, helvetica, sans-serif; width: 600px; } -#logdialog td{ - width: 110px; - height: 30px; +#logdialog table { + border: solid 0px; + margin: 0px auto; +} + +#logdialog td { + width: 100px; + height: 35px; color: #0078AE; - font-size: 14px; font-weight: bold; - border-width: 0px; + border: solid 0px; } -#logdialog input{ - width: 219px; +#logdialog input { + width: 210px; border: solid 1px #0078AE; - font-size: 14px; + font-size: 12px; + padding-bottom: 5px; } -#logdialog p{ - +#logdialog p { font-size: 18px; } -#logdialog button{ +#logdialog button { font-weight: bold; width: 90px; + float: right; } #loginput { background-color: #f5f5f5; - height: 260px; + height: 280px; } -#loginfo{ - text-align:right; +#loginfo { + margin: 5px 0px; + text-align: right; color: #f5f5f5; font-weight:bold; } @@ -77,7 +84,7 @@ height: 39px; width: 1000px; margin: 0px auto; - background: url(../images/header-gloss-wave.png) 50% 50% repeat-x; + background: url(../images/jquery/default/ui-bg_highlight-soft_75_2191c0_1x100.png) 50% 50% repeat-x; -moz-border-radius: .5em; -webkit-border-radius: .5em; border-radius: .5em; @@ -149,7 +156,7 @@ /*--------------- Body and content ---------------*/ body { - background-color: #1C1C1C; + background: #1C1C1C; font: 12px verdana, arial, helvetica, sans-serif; } diff --git a/xCAT-UI/js/custom/hmc.js b/xCAT-UI/js/custom/hmc.js index ad5afbd3c..c96aefc95 100644 --- a/xCAT-UI/js/custom/hmc.js +++ b/xCAT-UI/js/custom/hmc.js @@ -122,7 +122,7 @@ hmcPlugin.prototype.loadProvisionPage = function(tabId) { var provForm = $('
'); // Create info bar - var infoBar = createInfoBar('Provision a node on system P server.'); + var infoBar = createInfoBar('Provision a node on System p.'); provForm.append(infoBar); // Append to provision tab @@ -369,7 +369,7 @@ function addHmcNode(){ } /** - * Add system p node, contains frame, cec, lpar + * Add System p node, contains frame, cec, lpar * * @return Nothing */ diff --git a/xCAT-UI/js/service/service.js b/xCAT-UI/js/service/service.js new file mode 100644 index 000000000..8faffbe40 --- /dev/null +++ b/xCAT-UI/js/service/service.js @@ -0,0 +1,2350 @@ +/** + * Global variables + */ +var serviceTabs; +var nodeName; +var nodePath; +var nodeStatus; +var gangliaTimer; + +/** + * Initialize service page + */ +function initServicePage() { + // Reuqired JQuery plugins + includeJs("js/jquery/jquery.dataTables.min.js"); + includeJs("js/jquery/jquery.cookie.min.js"); + includeJs("js/jquery/tooltip.min.js"); + includeJs("js/jquery/superfish.min.js"); + includeJs("js/jquery/jquery.jqplot.min.js"); + includeJs("js/jquery/jqplot.dateAxisRenderer.min.js"); + + // Show service page + $("#content").children().remove(); + includeJs("js/service/service.js"); + includeJs("js/service/utils.js"); + loadServicePage(); +} + +/** + * Load service page + */ +function loadServicePage() { + // If the page is loaded + if ($('#content').children().length) { + // Do not load again + return; + } + + // Create manage and provision tabs + serviceTabs = new Tab(); + serviceTabs.init(); + $('#content').append(serviceTabs.object()); + + var manageTabId = 'manageTab'; + serviceTabs.add(manageTabId, 'Manage', '', false); + loadManagePage(manageTabId); + + var provTabId = 'provisionTab'; + serviceTabs.add(provTabId, 'Provision', '', false); + loadzProvisionPage(provTabId); + + serviceTabs.select(manageTabId); + + // 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); + loadzVMs(); + } + }); + } else { + loadzVMs(); + } + + // Get OS image names + if (!$.cookie('srv_imagenames')){ + $.ajax( { + url : 'lib/srv_cmd.php', + dataType : 'json', + data : { + cmd : 'tabdump', + tgt : '', + args : 'osimage', + msg : '' + }, + + success : function(data) { + setOSImageCookies(data); + loadOSImages(); + } + }); + } else { + loadOSImages(); + } + + // Get contents of hosts table + if (!$.cookie('srv_groups')) { + $.ajax( { + url : 'lib/srv_cmd.php', + dataType : 'json', + data : { + cmd : 'tabdump', + tgt : '', + args : 'hosts', + msg : '' + }, + + success : function(data) { + setGroupCookies(data); + loadGroups(); + } + }); + } else { + loadGroups(); + } + + // Get nodes owned by user + $.ajax( { + url : 'lib/srv_cmd.php', + dataType : 'json', + data : { + cmd : 'tabdump', + tgt : '', + args : 'nodetype', + msg : '' + }, + + success : function(data) { + setUserNodes(data); + getUserNodesDef(); + getNodesCurrentLoad(); + } + }); + + +} + +/** + * Load manage page + * + * @param tabId + * Tab ID where page will reside + * @return Nothing + */ +function loadManagePage(tabId) { + // Create manage form + var loader = createLoader(''); + var manageForm = $('
').append(loader); + + // Append to manage tab + $('#' + tabId).append(manageForm); +} + +/** + * Get the user nodes definitions + */ +function getUserNodesDef() { + var userName = $.cookie('srv_usrname'); + var userNodes = $.cookie(userName + '_usrnodes'); + if (userNodes) { + // Get nodes definitions + $.ajax( { + url : 'lib/srv_cmd.php', + dataType : 'json', + data : { + cmd : 'lsdef', + tgt : '', + args : userNodes, + msg : '' + }, + + success : loadNodesTable + }); + } else { + prompt('Warning', $('

Your session has expired! Please log out and back in.

')); + } +} + +/** + * Load user nodes definitions into a table + * + * @param data + * Data from HTTP request + * @return Nothing + */ +function loadNodesTable(data) { + // Clear the tab before inserting the table + $('#manageTab').children().remove(); + + // Nodes datatable ID + var nodesDTId = 'userNodesDT'; + + // Hash of node attributes + var attrs = new Object(); + // Node attributes + var headers = new Object(); + var node, args; + // Create hash of node attributes + for (var i in data.rsp) { + // Get node name + if (data.rsp[i].indexOf('Object name:') > -1) { + var temp = data.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 = data.rsp[i].split('=', 2); + var key = jQuery.trim(args[0]); + var val = jQuery.trim(data.rsp[i].substring(data.rsp[i].indexOf('=') + 1, data.rsp[i].length)); + + // Create a hash table + attrs[node][key] = val; + headers[key] = 1; + } + + // Sort headers + var sorted = new Array(); + var attrs2hide = new Array('status', 'statustime', 'appstatus', 'appstatustime', 'usercomment'); + var attrs2show = new Array('arch', 'groups', 'hcp', 'hostnames', 'ip', 'os', 'userid'); + for (var key in headers) { + // Show node attributes + if (jQuery.inArray(key, attrs2show) > -1) { + sorted.push(key); + } + } + sorted.sort(); + + // Add column for check box, node, ping, power, monitor, and comments + sorted.unshift('', + 'node', + 'status', + 'power', + 'monitor', + 'comments'); + + // Create a datatable + var nodesDT = new DataTable(nodesDTId); + nodesDT.init(sorted); + + // Go through each node + for (var node in attrs) { + // Create a row + var row = new Array(); + + // Create a check box, node link, and get node status + var checkBx = $(''); + var nodeLink = $('' + node + '').bind('click', loadNode); + + // If there is no status attribute for the node, do not try to access hash table + // Else the code will break + var status = ''; + if (attrs[node]['status']) { + status = attrs[node]['status'].replace('sshd', 'ping'); + } + + // Push in checkbox, node, status, monitor, and power + row.push(checkBx, nodeLink, status, '', ''); + + // If the node attributes are known (i.e the group is known) + if (attrs[node]['groups']) { + // Put in comments + var comments = attrs[node]['usercomment']; + // If no comments exists, show 'No comments' and set icon image source + var iconSrc; + if (!comments) { + comments = 'No comments'; + iconSrc = 'images/nodes/ui-icon-no-comment.png'; + } else { + iconSrc = 'images/nodes/ui-icon-comment.png'; + } + + // Create comments icon + var tipID = node + 'Tip'; + var icon = $('').css({ + 'width': '18px', + 'height': '18px' + }); + + // Create tooltip + var tip = createCommentsToolTip(comments); + var col = $('').append(icon); + col.append(tip); + row.push(col); + + // Generate tooltips + icon.tooltip({ + position: "center right", + offset: [-2, 10], + effect: "fade", + opacity: 0.8, + relative: true, + delay: 500 + }); + } else { + // Do not put in comments if attributes are not known + row.push(''); + } + + // Go through each header + for (var i = 6; i < sorted.length; i++) { + // Add the node attributes to the row + var key = sorted[i]; + + // Do not put comments and status in twice + if (key != 'usercomment' && key != 'status' && key.indexOf('statustime') < 0) { + var val = attrs[node][key]; + if (val) { + row.push($('' + val + '')); + } else { + row.push(''); + } + } + } + + // Add the row to the table + nodesDT.add(row); + } + + // Create info bar + var infoBar = createInfoBar('Manage and monitor your Linux virtual machines on System z.'); + $('#manageTab').append(infoBar); + + // Insert action bar and nodes datatable + $('#manageTab').append(nodesDT.object()); + + // Turn table into a datatable + $('#' + nodesDTId).dataTable({ + 'iDisplayLength': 50, + 'bLengthChange': false, + "sScrollX": "100%", + "sScrollXInner": "110%" + }); + + // Set datatable header class to add color + $('.datatable thead').attr('class', 'ui-widget-header'); + + // Do not sort ping, power, and comment column + var cols = $('#' + nodesDTId + ' thead tr th').click(function() { + getNodeAttrs(group); + }); + var checkboxCol = $('#' + nodesDTId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(0)'); + var pingCol = $('#' + nodesDTId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(2)'); + var powerCol = $('#' + nodesDTId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(3)'); + var monitorCol = $('#' + nodesDTId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(4)'); + var commentCol = $('#' + nodesDTId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(5)'); + checkboxCol.unbind('click'); + pingCol.unbind('click'); + powerCol.unbind('click'); + monitorCol.unbind('click'); + commentCol.unbind('click'); + + // Refresh the node ping, power, and monitor status on-click + var nodes = getNodesShown(nodesDTId); + pingCol.find('span a').click(function() { + refreshNodeStatus(nodes); + }); + powerCol.find('span a').click(function() { + refreshPowerStatus(nodes); + }); + monitorCol.find('span a').click(function() { + refreshGangliaStatus(nodes); + }); + + // Create actions menu + // Power on + var powerOnLnk = $('Power on'); + powerOnLnk.click(function() { + var tgtNodes = getNodesChecked(nodesDTId); + if (tgtNodes) { + powerNode(tgtNodes, 'on'); + } + }); + + // Power off + var powerOffLnk = $('Power off'); + powerOffLnk.click(function() { + var tgtNodes = getNodesChecked(nodesDTId); + if (tgtNodes) { + powerNode(tgtNodes, 'off'); + } + }); + + // Turn monitoring on + var monitorOnLnk = $('Monitor on'); + monitorOnLnk.click(function() { + var tgtNodes = getNodesChecked(nodesDTId); + if (tgtNodes) { + monitorNode(tgtNodes, 'on'); + } + }); + + // Turn monitoring off + var monitorOffLnk = $('Monitor off'); + monitorOffLnk.click(function() { + var tgtNodes = getNodesChecked(nodesDTId); + if (tgtNodes) { + monitorNode(tgtNodes, 'off'); + } + }); + + // Delete + var deleteLnk = $('Delete'); + deleteLnk.click(function() { + var tgtNodes = getNodesChecked(nodesDTId); + if (tgtNodes) { + deleteNode(tgtNodes); + } + }); + + // Unlock + var unlockLnk = $('Unlock'); + unlockLnk.click(function() { + var tgtNodes = getNodesChecked(nodesDTId); + if (tgtNodes) { + unlockNode(tgtNodes); + } + }); + + // Prepend menu to datatable + var actionsLnk = 'Actions'; + var actionMenu = createMenu([deleteLnk, powerOnLnk, powerOffLnk, monitorOnLnk, monitorOffLnk, unlockLnk]); + var menu = createMenu([[actionsLnk, actionMenu]]); + menu.superfish(); + $('#' + nodesDTId + '_filter').css('display', 'inline-block'); + $('#' + nodesDTId + '_wrapper').prepend(menu); + + $('.sf-menu li:hover, .sf-menu li.sfHover').attr('class', 'ui-widget-header'); + + // Get power and monitor status + var nodes = getNodesShown(nodesDTId); + refreshPowerStatus(nodes); + refreshGangliaStatus(nodes); +} + +/** + * Refresh ping status for each node + * + * @param nodes + * Nodes to get ping status + * @return Nothing + */ +function refreshNodeStatus(nodes) { + // Show ping loader + var nodesDTId = 'userNodesDT'; + var pingCol = $('#' + nodesDTId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(2)'); + pingCol.find('img').show(); + + // Get the node ping status + $.ajax( { + url : 'lib/srv_cmd.php', + dataType : 'json', + data : { + cmd : 'nodestat', + tgt : nodes, + args : '-u', + msg : '' + }, + + success : loadNodePing + }); +} + +/** + * Load node ping status for each node + * + * @param data + * Data returned from HTTP request + * @return Nothing + */ +function loadNodePing(data) { + var nodesDTId = 'userNodesDT'; + var datatable = $('#' + nodesDTId).dataTable(); + var rsp = data.rsp; + var args, rowPos, node, status; + + // Get all nodes within datatable + for (var i in rsp) { + args = rsp[i].split(':'); + + // args[0] = node and args[1] = status + node = jQuery.trim(args[0]); + status = jQuery.trim(args[1]).replace('sshd', 'ping'); + + // Get row containing node + rowPos = findRow(node, '#' + nodesDTId, 1); + + // Update ping status column + datatable.fnUpdate(status, rowPos, 2, false); + } + + // Hide status loader + var pingCol = $('#' + nodesDTId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(2)'); + pingCol.find('img').hide(); + datatable.fnDraw(); +} + +/** + * Refresh power status for each node + * + * @param nodes + * Nodes to get power status + * @return Nothing + */ +function refreshPowerStatus(nodes) { + // Show power loader + var nodesDTId = 'userNodesDT'; + var powerCol = $('#' + nodesDTId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(3)'); + powerCol.find('img').show(); + + // Get power status + $.ajax( { + url : 'lib/srv_cmd.php', + dataType : 'json', + data : { + cmd : 'rpower', + tgt : nodes, + args : 'stat', + msg : '' + }, + + success : loadPowerStatus + }); +} + +/** + * Load power status for each node + * + * @param data + * Data returned from HTTP request + * @return Nothing + */ +function loadPowerStatus(data) { + var nodesDTId = 'userNodesDT'; + var datatable = $('#' + nodesDTId).dataTable(); + var power = data.rsp; + var rowPos, 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 + rowPos = findRow(node, '#' + nodesDTId, 1); + + // Update the power status column + datatable.fnUpdate(status, rowPos, 3, false); + } + + // Hide power loader + var powerCol = $('#' + nodesDTId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(3)'); + powerCol.find('img').hide(); + datatable.fnDraw(); +} + +/** + * Refresh the status of Ganglia for each node + * + * @param nodes + * Nodes to get Ganglia status + * @return Nothing + */ +function refreshGangliaStatus(nodes) { + // Show ganglia loader + var nodesDTId = 'userNodesDT'; + var gangliaCol = $('#' + nodesDTId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(4)'); + gangliaCol.find('img').show(); + + // Get the status of Ganglia + $.ajax( { + url : 'lib/srv_cmd.php', + dataType : 'json', + data : { + cmd : 'webrun', + tgt : '', + args : 'gangliastatus;' + nodes, + msg : '' + }, + + success : loadGangliaStatus + }); +} + +/** + * Load the status of Ganglia for a given group + * + * @param data + * Data returned from HTTP request + * @return Nothing + */ +function loadGangliaStatus(data) { + // Get datatable + var nodesDTId = 'userNodesDT'; + var datatable = $('#' + nodesDTId).dataTable(); + var ganglia = data.rsp; + var rowNum, node, status; + + for ( var i in ganglia) { + // ganglia[0] = nodeName and ganglia[1] = state + node = jQuery.trim(ganglia[i][0]); + status = jQuery.trim(ganglia[i][1]); + + // Get the row containing the node + rowNum = findRow(node, '#' + nodesDTId, 1); + + // Update the power status column + datatable.fnUpdate(status, rowNum, 4); + } + + // Hide Ganglia loader + var gangliaCol = $('#' + nodesDTId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(4)'); + gangliaCol.find('img').hide(); + datatable.fnDraw(); +} + +/** + * 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; + + // Create a new tab to show inventory + var tabId = node + '_inventory'; + + if(!$('#' + tabId).length) { + // Add new tab, only if one does not exist + var loader = createLoader(node + 'Loader'); + loader = $('
').append(loader); + serviceTabs.add(tabId, node, loader, true); + + // Get node inventory + var msg = 'out=' + tabId + ',node=' + node; + $.ajax( { + url : 'lib/srv_cmd.php', + dataType : 'json', + data : { + cmd : 'rinv', + tgt : node, + args : 'all', + msg : msg + }, + + success : showInventory + }); + } + + // Select new tab + serviceTabs.select(tabId); +} + +/** + * Show node inventory + * + * @param data + * Data from HTTP request + * @return Nothing + */ +function showInventory(data) { + var args = data.msg.split(','); + + // Get tab ID + var tabId = args[0].replace('out=', ''); + // Get node + var node = args[1].replace('node=', ''); + // Get node inventory + var inv = data.rsp[0].split(node + ':'); + + // Remove loader + $('#' + tabId).find('img').remove(); + + // Create array of property keys + var keys = new Array('userId', 'host', 'os', 'arch', 'hcp', 'priv', 'memory', 'proc', 'disk', 'nic'); + + // Create hash table for property names + var attrNames = new Object(); + attrNames['userId'] = 'z/VM UserID:'; + attrNames['host'] = 'z/VM Host:'; + attrNames['os'] = 'Operating System:'; + attrNames['arch'] = 'Architecture:'; + attrNames['hcp'] = 'HCP:'; + attrNames['priv'] = 'Privileges:'; + attrNames['memory'] = 'Total Memory:'; + attrNames['proc'] = 'Processors:'; + attrNames['disk'] = 'Disks:'; + attrNames['nic'] = 'NICs:'; + + // Create hash table for node attributes + var attrs = getAttrs(keys, attrNames, inv); + + // Create division to hold inventory + var invDivId = node + 'Inventory'; + var invDiv = $('
'); + + var infoBar = createInfoBar('Below is the inventory for the virtual machine you selected.'); + invDiv.append(infoBar); + + /** + * General info section + */ + var fieldSet = $('
'); + var legend = $('General'); + fieldSet.append(legend); + var oList = $('
    '); + var item, label, args; + + // Loop through each property + for ( var k = 0; k < 5; k++) { + // Create a list item for each property + item = $('
  1. '); + + // Create a label - Property name + label = $(''); + item.append(label); + + for ( var l = 0; l < attrs[keys[k]].length; l++) { + // Create a input - Property value(s) + // Handle each property uniquely + item.append(attrs[keys[k]][l]); + } + + oList.append(item); + } + // Append to inventory form + fieldSet.append(oList); + invDiv.append(fieldSet); + + /** + * Monitoring section + */ + fieldSet = $('
    '); + legend = $('Monitoring'); + fieldSet.append(legend); + getMonitorMetrics(node); + + // Append to inventory form + invDiv.append(fieldSet); + + /** + * Hardware info section + */ + var hwList, hwItem; + fieldSet = $('
    '); + legend = $('Hardware'); + fieldSet.append(legend); + oList = $('
      '); + + // Loop through each property + var label; + for (k = 5; k < keys.length; k++) { + // Create a list item + item = $('
    1. '); + + // Create a list to hold the property value(s) + hwList = $(''); + hwItem = $('
    2. '); + + /** + * Privilege section + */ + if (keys[k] == 'priv') { + // Create a label - Property name + label = $(''); + item.append(label); + + // Loop through each line + for (l = 0; l < attrs[keys[k]].length; l++) { + // Create a new list item for each line + hwItem = $('
    3. '); + + // Determine privilege + args = attrs[keys[k]][l].split(' '); + if (args[0] == 'Directory:') { + label = $(''); + hwItem.append(label); + hwItem.append(args[1]); + } else if (args[0] == 'Currently:') { + label = $(''); + hwItem.append(label); + hwItem.append(args[1]); + } + + hwList.append(hwItem); + } + + item.append(hwList); + } + + /** + * Memory section + */ + else if (keys[k] == 'memory') { + // Create a label - Property name + label = $(''); + item.append(label); + + // Loop through each value line + for (l = 0; l < attrs[keys[k]].length; l++) { + // Create a new list item for each line + hwItem = $('
    4. '); + hwItem.append(attrs[keys[k]][l]); + hwList.append(hwItem); + } + + item.append(hwList); + } + + /** + * Processor section + */ + else if (keys[k] == 'proc') { + // Create a label - Property name + label = $(''); + item.append(label); + + // Create a table to hold processor data + var procTable = $('
      '); + var procBody = $(''); + + // Table columns - Type, Address, ID, Base, Dedicated, and Affinity + var procTabRow = $(' Type Address ID Base Dedicated Affinity '); + procTable.append(procTabRow); + var procType, procAddr, procId, procAff; + + // Loop through each processor + var n, temp; + for (l = 0; l < attrs[keys[k]].length; l++) { + if (attrs[keys[k]][l]) { + args = attrs[keys[k]][l].split(' '); + + // Get processor type, address, ID, and affinity + n = 3; + temp = args[args.length - n]; + while (!jQuery.trim(temp)) { + n = n + 1; + temp = args[args.length - n]; + } + procType = $('' + temp + ''); + procAddr = $('' + args[1] + ''); + procId = $('' + args[5] + ''); + procAff = $('' + args[args.length - 1] + ''); + + // Base processor + if (args[6] == '(BASE)') { + baseProc = $('' + true + ''); + } else { + baseProc = $('' + false + ''); + } + + // Dedicated processor + if (args[args.length - 3] == 'DEDICATED') { + dedicatedProc = $('' + true + ''); + } else { + dedicatedProc = $('' + false + ''); + } + + // Create a new row for each processor + procTabRow = $(''); + procTabRow.append(procType); + procTabRow.append(procAddr); + procTabRow.append(procId); + procTabRow.append(baseProc); + procTabRow.append(dedicatedProc); + procTabRow.append(procAff); + procBody.append(procTabRow); + } + } + + procTable.append(procBody); + item.append(procTable); + } + + /** + * Disk section + */ + else if (keys[k] == 'disk') { + // Create a label - Property name + label = $(''); + item.append(label); + + // Create a table to hold disk (DASD) data + var dasdTable = $('
      '); + var dasdBody = $(''); + + // Table columns - Virtual Device, Type, VolID, Type of Access, and Size + var dasdTabRow = $(' Virtual Device # Type VolID Type of Access Size '); + dasdTable.append(dasdTabRow); + var dasdVDev, dasdType, dasdVolId, dasdAccess, dasdSize; + + // Loop through each DASD + for (l = 0; l < attrs[keys[k]].length; l++) { + if (attrs[keys[k]][l]) { + args = attrs[keys[k]][l].split(' '); + + // Get DASD virtual device, type, volume ID, access, and size + dasdVDev = $('' + args[1] + ''); + dasdType = $('' + args[2] + ''); + dasdVolId = $('' + args[3] + ''); + dasdAccess = $('' + args[4] + ''); + dasdSize = $('' + args[args.length - 9] + ' ' + args[args.length - 8] + ''); + + // Create a new row for each DASD + dasdTabRow = $(''); + dasdTabRow.append(dasdVDev); + dasdTabRow.append(dasdType); + dasdTabRow.append(dasdVolId); + dasdTabRow.append(dasdAccess); + dasdTabRow.append(dasdSize); + dasdBody.append(dasdTabRow); + } + } + + dasdTable.append(dasdBody); + item.append(dasdTable); + } + + /** + * NIC section + */ + else if (keys[k] == 'nic') { + // Create a label - Property name + label = $(''); + item.append(label); + + // Create a table to hold NIC data + var nicTable = $('
      '); + var nicBody = $(''); + + // Table columns - Virtual device, Adapter Type, Port Name, # of Devices, MAC Address, and LAN Name + var nicTabRow = $('Virtual Device # Adapter Type Port Name # of Devices LAN Name'); + nicTable.append(nicTabRow); + var nicVDev, nicType, nicPortName, nicNumOfDevs, nicLanName; + + // Loop through each NIC (Data contained in 2 lines) + for (l = 0; l < attrs[keys[k]].length; l = l + 2) { + if (attrs[keys[k]][l]) { + args = attrs[keys[k]][l].split(' '); + + // Get NIC virtual device, type, port name, and number of devices + nicVDev = $('' + args[1] + ''); + nicType = $('' + args[3] + ''); + nicPortName = $('' + args[10] + ''); + nicNumOfDevs = $('' + args[args.length - 1] + ''); + + args = attrs[keys[k]][l + 1].split(' '); + nicLanName = $('' + args[args.length - 2] + ' ' + args[args.length - 1] + ''); + + // Create a new row for each DASD + nicTabRow = $(''); + nicTabRow.append(nicVDev); + nicTabRow.append(nicType); + nicTabRow.append(nicPortName); + nicTabRow.append(nicNumOfDevs); + nicTabRow.append(nicLanName); + + nicBody.append(nicTabRow); + } + } + + nicTable.append(nicBody); + item.append(nicTable); + } + + oList.append(item); + } + + // Append inventory to division + fieldSet.append(oList); + invDiv.append(fieldSet); + invDiv.find('th').css({ + 'padding': '5px 10px', + 'font-weight': 'bold' + }); + + // Append to tab + $('#' + tabId).append(invDiv); +} + +/** + * Load provision page (z) + * + * @param tabId + * Tab ID where page will reside + * @return Nothing + */ +function loadzProvisionPage(tabId) { + // Create provision form + var provForm = $('
      '); + + // Create info bar + var infoBar = createInfoBar('Provision a Linux virtual machine on System z by selecting the appropriate choices below. Once you are ready, click on Provision to provision the virtual machine.'); + provForm.append(infoBar); + + // Append to provision tab + $('#' + tabId).append(provForm); + + // Create provision table + var provTable = $(''); + var provBody = $(''); + var provFooter = $(''); + provTable.append(provHeader, provBody, provFooter); + provForm.append(provTable); + + provHeader.children('th').css({ + 'font': 'bold 12px verdana, arial, helvetica, sans-serif' + }); + + // Create row to contain selections + var provRow = $(''); + provBody.append(provRow); + // Create columns for zVM, group, and image + var zvmCol = $(''); + provRow.append(zvmCol); + var groupCol = $(''); + provRow.append(groupCol); + var imageCol = $(''); + provRow.append(imageCol); + + provRow.children('td').css({ + 'min-width': '250px' + }); + + /** + * Provision VM + */ + var provisionBtn = createButton('Provision'); + provisionBtn.bind('click', function(event) { + var hcp = $('#select-table tbody tr:eq(0) td:eq(0) input[name="hcp"]:checked').val(); + var group = $('#select-table tbody tr:eq(0) td:eq(1) input[name="group"]:checked').val(); + var img = $('#select-table tbody tr:eq(0) td:eq(2) input[name="image"]:checked').val(); + var owner = $.cookie('srv_usrname');; + + // Begin by creating VM + createVM(tabId, group, hcp, img, owner); + }); + provForm.append(provisionBtn); +} + +/** + * Create virtual machine + * + * @param tabId + * Tab ID + * @param group + * Group + * @param hcp + * Hardware control point + * @param img + * OS image + * @return Nothing + */ +function createVM(tabId, group, hcp, img, owner) { + var statBar = createStatusBar('provsionStatBar'); + var loader = createLoader('provisionLoader'); + statBar.find('div').append(loader); + statBar.prependTo($('#provisionTab')); + + // Submit request to create VM + // webportal provzlinux [group] [hcp] [image] [owner] + $.ajax({ + url : 'lib/srv_cmd.php', + dataType : 'json', + data : { + cmd : 'webportal', + tgt : '', + args : 'provzlinux;' + group + ';' + hcp + ';' + img + ';' + owner, + msg : '' + }, + success:function(data){ + $('#provisionLoader').remove(); + for(var i in data.rsp){ + $('#provsionStatBar').find('div').append('
      ' + data.rsp[i] + '
      '); + } + + // Refresh nodes table + $.ajax( { + url : 'lib/srv_cmd.php', + dataType : 'json', + data : { + cmd : 'tabdump', + tgt : '', + args : 'nodetype', + msg : '' + }, + + success : function(data) { + setUserNodes(data); + } + }); + } + }); +} + +/** + * Load zVMs into column + */ +function loadzVMs() { + var zvmCol = $('#select-table tbody tr:eq(0) td:eq(0)'); + + // Get group names and description and append to group column + var groupNames = $.cookie('srv_zvms').split(','); + var radio, zvmBlock, args, zvm, hcp; + for (var i in groupNames) { + args = groupNames[i].split(':'); + zvm = args[0]; + hcp = args[1]; + + // Create block for each group + zvmBlock = $('
      ').css({ + 'border': '1px solid', + 'max-width': '200px', + 'margin': '5px auto', + 'padding': '5px', + 'display': 'inline-block', + 'vertical-align': 'middle', + 'cursor': 'pointer' + }).click(function(){ + $(this).children('input:radio').attr('checked', 'checked'); + $(this).parents('td').find('div').attr('class', 'ui-state-default'); + $(this).attr('class', 'ui-state-active'); + }); + radio = $('').css('display', 'none'); + zvmBlock.append(radio, $('Name: ' + zvm + ''), $('zHCP: ' + hcp + '')); + zvmBlock.children('span').css({ + 'display': 'block', + 'margin': '5px' + }); + zvmCol.append(zvmBlock); + } +} + +/** + * Load groups into column + */ +function loadGroups() { + var groupCol = $('#select-table tbody tr:eq(0) td:eq(1)'); + + // Get group names and description and append to group column + var groupNames = $.cookie('srv_groups').split(','); + var groupBlock, radio, args, name, ip, hostname, desc; + for (var i in groupNames) { + args = groupNames[i].split(':'); + name = args[0]; + ip = args[1]; + hostname = args[2]; + desc = args[3]; + + // Create block for each group + groupBlock = $('
      ').css({ + 'border': '1px solid', + 'max-width': '200px', + 'margin': '5px auto', + 'padding': '5px', + 'display': 'inline-block', + 'vertical-align': 'middle', + 'cursor': 'pointer' + }).click(function(){ + $(this).children('input:radio').attr('checked', 'checked'); + $(this).parents('td').find('div').attr('class', 'ui-state-default'); + $(this).attr('class', 'ui-state-active'); + }); + radio = $('').css('display', 'none'); + groupBlock.append(radio, $('Name: ' + name + ''), $('Description: ' + desc + '')); + groupBlock.children('span').css({ + 'display': 'block', + 'margin': '5px' + }); + groupCol.append(groupBlock); + } +} + +/** + * Load OS images into column + */ +function loadOSImages() { + var imgCol = $('#select-table tbody tr:eq(0) td:eq(2)'); + + // Get group names and description and append to group column + var imgNames = $.cookie('srv_imagenames').split(','); + var imgBlock, radio, args, name, desc; + for (var i in imgNames) { + args = imgNames[i].split(':'); + name = args[0]; + desc = args[1]; + + // Create block for each image + imgBlock = $('
      ').css({ + 'border': '1px solid', + 'max-width': '200px', + 'margin': '5px auto', + 'padding': '5px', + 'display': 'inline-block', + 'vertical-align': 'middle', + 'cursor': 'pointer' + }).click(function(){ + $(this).children('input:radio').attr('checked', 'checked'); + $(this).parents('td').find('div').attr('class', 'ui-state-default'); + $(this).attr('class', 'ui-state-active'); + }); + radio = $('').css('display', 'none'); + imgBlock.append(radio, $('Name: ' + name + ''), $('Description: ' + desc + '')); + imgBlock.children('span').css({ + 'display': 'block', + 'margin': '5px' + }); + imgCol.append(imgBlock); + } +} + +/** + * Set a cookie for zVM host names + * + * @param data + * Data from HTTP request + * @return Nothing + */ +function setzVMCookies(data) { + if (data.rsp) { + var zvms = new Array(); + for ( var i = 0; i < data.rsp.length; i++) { + zvms.push(data.rsp[i]); + } + + // Set cookie to expire in 60 minutes + var exDate = new Date(); + exDate.setTime(exDate.getTime() + (240 * 60 * 1000)); + $.cookie('srv_zvms', zvms, { expires: exDate }); + } +} + +/** + * Set a cookie for disk pool names + * + * @param data + * Data from HTTP request + * @return Nothing + */ +function setGroupCookies(data) { + if (data.rsp) { + var groups = new Array(); + + // Index 0 is the table header + var cols, name, ip, hostname, desc; + for ( var i = 1; i < data.rsp.length; i++) { + // Split into columns: + // node, ip, hostnames, otherinterfaces, comments, disable + cols = data.rsp[i].split(','); + name = cols[0].replace(new RegExp('"', 'g'), ''); + ip = cols[1].replace(new RegExp('"', 'g'), ''); + hostname = cols[2].replace(new RegExp('"', 'g'), ''); + desc = cols[4].replace(new RegExp('"', 'g'), ''); + groups.push(name + ':' + ip + ':' + hostname + ':' + desc); + } + + // Set cookie to expire in 60 minutes + var exDate = new Date(); + exDate.setTime(exDate.getTime() + (240 * 60 * 1000)); + $.cookie('srv_groups', groups, { expires: exDate }); + } +} + +/** + * Set a cookie for the OS images + * + * @param data + * Data from HTTP request + * @return Nothing + */ +function setOSImageCookies(data) { + // Get response + var rsp = data.rsp; + + var imageNames = new Array; + var profilesHash = new Object(); + var osVersHash = new Object(); + var osArchsHash = new Object(); + var imagePos = 0; + var profilePos = 0; + var osversPos = 0; + var osarchPos = 0; + var provMethodPos = 0; + var comments = 0; + // Get the column value + var colNameArray = rsp[0].substr(1).split(','); + for (var i in colNameArray){ + switch (colNameArray[i]){ + case 'imagename': { + imagePos = i; + } + break; + + case 'profile':{ + profilePos = i; + } + break; + + case 'osvers':{ + osversPos = i; + } + break; + + case 'osarch':{ + osarchPos = i; + } + break; + + case 'comments':{ + comments = i; + } + break; + + case 'provmethod':{ + provMethodPos = i; + } + break; + + default : + break; + } + } + + // Go through each index + for (var i = 1; i < rsp.length; i++) { + // Get image name + var cols = rsp[i].split(','); + var osImage = cols[imagePos].replace(new RegExp('"', 'g'), ''); + var profile = cols[profilePos].replace(new RegExp('"', 'g'), ''); + var provMethod = cols[provMethodPos].replace(new RegExp('"', 'g'), ''); + var osVer = cols[osversPos].replace(new RegExp('"', 'g'), ''); + var osArch = cols[osarchPos].replace(new RegExp('"', 'g'), ''); + var osComments = cols[comments].replace(new RegExp('"', 'g'), ''); + + // Only save compute profile and install boot + if (profile.indexOf('compute') > -1 && provMethod.indexOf('install') > -1) { + if (!osComments) + osComments = 'No descritption'; + imageNames.push(osImage + ':' + osComments); + profilesHash[profile] = 1; + osVersHash[osVer] = 1; + osArchsHash[osArch] = 1; + } + + + } + + // Save image names in a cookie + $.cookie('srv_imagenames', imageNames); + + // Save profiles in a cookie + var tmp = new Array; + for (var key in profilesHash) { + tmp.push(key); + } + $.cookie('srv_profiles', tmp); + + // Save OS versions in a cookie + tmp = new Array; + for (var key in osVersHash) { + tmp.push(key); + } + $.cookie('srv_osvers', tmp); + + // Save OS architectures in a cookie + tmp = new Array; + for (var key in osArchsHash) { + tmp.push(key); + } + $.cookie('srv_osarchs', tmp); +} + +/** + * Set a cookie for disk pool names of a given node + * + * @param data + * Data from HTTP request + * @return Nothing + */ +function setDiskPoolCookies(data) { + if (data.rsp) { + var node = data.msg; + var pools = data.rsp[0].split(node + ': '); + for (var i in pools) { + pools[i] = jQuery.trim(pools[i]); + } + + // Set cookie to expire in 60 minutes + var exDate = new Date(); + exDate.setTime(exDate.getTime() + (240 * 60 * 1000)); + $.cookie(node + 'diskpools', pools, { expires: exDate }); + } +} + +/** + * Set a cookie for user nodes + * + * @param data + * Data from HTTP request + * @return Nothing + */ +function setUserNodes(data) { + if (data.rsp) { + // Get user name that is logged in + var userName = $.cookie('srv_usrname'); + var usrNodes = new Array(); + + // Ignore first columns because it is the header + for ( var i = 1; i < data.rsp.length; i++) { + // Go through each column + // where column names are: node, os, arch, profile, provmethod, supportedarchs, nodetype, comments, disable + var cols = data.rsp[i].split(','); + var node = cols[0].replace(new RegExp('"', 'g'), ''); + var owner = cols[7].replace(new RegExp('"', 'g'), ''); + owner = owner.replace('owner:', ''); + + if (owner == userName) { + usrNodes.push(node); + } + } // End of for + + // Set cookie to expire in 240 minutes + var exDate = new Date(); + exDate.setTime(exDate.getTime() + (240 * 60 * 1000)); + $.cookie(userName + '_usrnodes', usrNodes, { expires: exDate }); + } // End of if +} + +/** + * Power on a given node + * + * @param node + * Node to power on or off + * @param power2 + * Power node to given state + * @return Nothing + */ +function powerNode(node, power2) { + $.ajax({ + url : 'lib/srv_cmd.php', + dataType : 'json', + data : { + cmd : 'rpower', + tgt : node, + args : power2, + msg : node + }, + + success : updatePowerStatus + }); +} + +/** + * Update power status of a node in the datatable + * + * @param data + * Data from HTTP request + * @return Nothing + */ +function updatePowerStatus(data) { + // Get datatable + var nodesDTId = 'userNodesDT'; + var dTable = $('#' + nodesDTId).dataTable(); + + // Get xCAT response + var rsp = data.rsp; + // Loop through each line + var node, status, rowPos, strPos; + for (var i in rsp) { + // Get node name + node = rsp[i].split(":")[0]; + + // If there is no error + if (rsp[i].indexOf("Error") < 0 || rsp[i].indexOf("Failed") < 0) { + // Get the row containing the node link + rowPos = findRow(node, '#' + nodesDTId, 1); + + // If it was power on, then the data return would contain "Starting" + strPos = rsp[i].indexOf("Starting"); + if (strPos > -1) { + status = 'on'; + } else { + status = 'off'; + } + + // Update the power status column + dTable.fnUpdate(status, rowPos, 3, false); + } else { + // Power on/off failed + alert(rsp[i]); + } + } +} + +/** + * Turn on monitoring for a given node + * + * @param node + * Node to monitor on or off + * @param monitor + * Monitor state, on or off + * @return Nothing + */ +function monitorNode(node, monitor) { + if (monitor == 'on') { + // Append loader to warning bar + var gangliaLoader = createLoader(''); + var warningBar = $('#nodesTab').find('.ui-state-error p'); + if (warningBar.length) { + warningBar.append(gangliaLoader); + } + + if (node) { + // Check if ganglia RPMs are installed + $.ajax( { + url : 'lib/srv_cmd.php', + dataType : 'json', + data : { + cmd : 'webrun', + tgt : '', + args : 'gangliacheck;' + node, + msg : node // Node range will be passed along in data.msg + }, + + /** + * Start ganglia on a given node range + * + * @param data + * Data returned from HTTP request + * @return Nothing + */ + success : function(data) { + // Get response + var out = data.rsp[0].split(/\n/); + + // Go through each line + var warn = false; + var warningMsg = ''; + for (var i in out) { + // If an RPM is not installed + if (out[i].indexOf('not installed') > -1) { + warn = true; + + if (warningMsg) { + warningMsg += '
      ' + out[i]; + } else { + warningMsg = out[i]; + } + } + } + + // If there are warnings + if (warn) { + // Create warning bar + var warningBar = createWarnBar(warningMsg); + warningBar.css('margin-bottom', '10px'); + warningBar.prependTo($('#nodesTab')); + } else { + $.ajax( { + url : 'lib/srv_cmd.php', + dataType : 'json', + data : { + cmd : 'webrun', + tgt : '', + args : 'gangliastart;' + data.msg, + msg : data.msg + }, + + success : function(data) { + // Remove any warnings + $('#nodesTab').find('.ui-state-error').remove(); + refreshGangliaStatus(data.msg); + } + }); + } // End of if (warn) + } // End of function(data) + }); + } + } else { + var args; + if (node) { + args = 'gangliastop;' + node; + $.ajax( { + url : 'lib/srv_cmd.php', + dataType : 'json', + data : { + cmd : 'webrun', + tgt : '', + args : args, + msg : node + }, + + success : function(data) { + refreshGangliaStatus(data.msg); + } + }); + } + } +} + +/** + * Open a dialog to delete node + * + * @param tgtNodes + * Nodes to delete + * @return Nothing + */ +function deleteNode(tgtNodes) { + var nodes = tgtNodes.split(','); + + // Loop through each node and create target nodes string + var tgtNodesStr = ''; + for (var i in nodes) { + if (i == 0 && i == nodes.length - 1) { + // If it is the 1st and only node + tgtNodesStr += nodes[i]; + } else if (i == 0 && i != nodes.length - 1) { + // If it is the 1st node of many nodes, append a comma to the string + tgtNodesStr += nodes[i] + ', '; + } else { + if (i == nodes.length - 1) { + // If it is the last node, append nothing to the string + tgtNodesStr += nodes[i]; + } else { + // Append a comma to the string + tgtNodesStr += nodes[i] + ', '; + } + } + } + + // Confirm delete + var confirmMsg = $('

      Are you sure you want to delete ' + tgtNodesStr + '?

      ').css({ + 'display': 'inline', + 'margin': '5px', + 'vertical-align': 'middle', + 'word-wrap': 'break-word' + }); + + var style = { + 'display': 'inline-block', + 'margin': '5px', + 'vertical-align': 'middle' + }; + + var dialog = $('
      '); + var icon = $('').css(style); + dialog.append(icon); + dialog.append(confirmMsg); + + // Open dialog + dialog.dialog({ + title: "Confirm", + modal: true, + width: 400, + buttons: { + "Yes": function(){ + // Create status bar and append to tab + var instance = 0; + var statBarId = 'deleteStat' + instance; + while ($('#' + statBarId).length) { + // If one already exists, generate another one + instance = instance + 1; + statBarId = 'deleteStat' + instance; + } + + var statBar = createStatusBar(statBarId); + var loader = createLoader(''); + statBar.find('div').append(loader); + statBar.prependTo($('#manageTab')); + + // Delete the virtual server + $.ajax( { + url : 'lib/srv_cmd.php', + dataType : 'json', + data : { + cmd : 'rmvm', + tgt : tgtNodes, + args : '', + msg : 'out=' + statBarId + ';cmd=rmvm;tgt=' + tgtNodes + }, + + success : function(data) { + var args = data.msg.split(';'); + var statBarId = args[0].replace('out=', ''); + var tgts = args[2].replace('tgt=', '').split(','); + + // Get data table + var nodesDTId = 'userNodesDT'; + var dTable = $('#' + nodesDTId).dataTable(); + var failed = false; + + // Create an info box to show output + var output = writeRsp(data.rsp, ''); + output.css('margin', '0px'); + // Remove loader and append output + $('#' + statBarId + ' img').remove(); + $('#' + statBarId + ' div').append(output); + + // If there was an error, do not continue + if (output.html().indexOf('Error') > -1) { + failed = true; + } + + // Update data table + var rowPos; + for (var i in tgts) { + if (!failed) { + // Get row containing the node link and delete it + rowPos = findRow(tgts[i], '#' + nodesDTId, 1); + dTable.fnDeleteRow(rowPos); + } + } + + // Refresh nodes owned by user + $.ajax( { + url : 'lib/srv_cmd.php', + dataType : 'json', + data : { + cmd : 'tabdump', + tgt : '', + args : 'nodetype', + msg : '' + }, + + success : function(data) { + setUserNodes(data); + } + }); + } + }); + + $(this).dialog("close"); + }, + "No": function() { + $(this).dialog("close"); + } + } + }); +} + +/** + * Unlock a node by setting the ssh keys + * + * @param tgtNodes + * Nodes to unlock + * @return Nothing + */ +function unlockNode(tgtNodes) { + var nodes = tgtNodes.split(','); + + // Loop through each node and create target nodes string + var tgtNodesStr = ''; + for (var i in nodes) { + if (i == 0 && i == nodes.length - 1) { + // If it is the 1st and only node + tgtNodesStr += nodes[i]; + } else if (i == 0 && i != nodes.length - 1) { + // If it is the 1st node of many nodes, append a comma to the string + tgtNodesStr += nodes[i] + ', '; + } else { + if (i == nodes.length - 1) { + // If it is the last node, append nothing to the string + tgtNodesStr += nodes[i]; + } else { + // Append a comma to the string + tgtNodesStr += nodes[i] + ', '; + } + } + } + + var dialog = $('
      '); + var infoBar = createInfoBar('Give the root password for this node range to setup its SSH keys.'); + dialog.append(infoBar); + + var unlockForm = $('
      ').css('margin', '5px'); + unlockForm.append('
      '); + unlockForm.append('
      '); + dialog.append(unlockForm); + + dialog.find('div input').css('margin', '5px'); + + // Generate tooltips + unlockForm.find('div input[title]').tooltip({ + position: "center right", + offset: [-2, 10], + effect: "fade", + opacity: 0.7, + predelay: 800, + events : { + def : "mouseover,mouseout", + input : "mouseover,mouseout", + widget : "focus mouseover,blur mouseout", + tooltip : "mouseover,mouseout" + } + }); + + // Open dialog + dialog.dialog({ + title: "Confirm", + modal: true, + width: 450, + buttons: { + "Ok": function(){ + // Create status bar and append to tab + var instance = 0; + var statBarId = 'unlockStat' + instance; + while ($('#' + statBarId).length) { + // If one already exists, generate another one + instance = instance + 1; + statBarId = 'unlockStat' + instance; + } + + var statBar = createStatusBar(statBarId); + var loader = createLoader(''); + statBar.find('div').append(loader); + statBar.prependTo($('#manageTab')); + + // If a password is given + var password = unlockForm.find('input[name=password]:eq(0)'); + if (password.val()) { + // Setup SSH keys + $.ajax( { + url : 'lib/srv_cmd.php', + dataType : 'json', + data : { + cmd : 'webrun', + tgt : '', + args : 'unlock;' + tgtNodes + ';' + password.val(), + msg : 'out=' + statBarId + ';cmd=unlock;tgt=' + tgtNodes + }, + + success : function(data) { + // Create an info box to show output + var output = writeRsp(data.rsp, ''); + output.css('margin', '0px'); + // Remove loader and append output + $('#' + statBarId + ' img').remove(); + $('#' + statBarId + ' div').append(output); + } + }); + + $(this).dialog("close"); + } + }, + "Cancel": function() { + $(this).dialog("close"); + } + } + }); +} + +/** + * Get nodes current load information + */ +function getNodesCurrentLoad(){ + var userName = $.cookie('srv_usrname'); + var nodes = $.cookie(userName + '_usrnodes'); + + // Get nodes current status + $.ajax({ + url : 'lib/srv_cmd.php', + dataType : 'json', + data : { + cmd : 'webrun', + tgt : '', + args : 'gangliacurrent;node;' + nodes, + msg : '' + }, + + success: saveNodeLoad + }); +} + +/** + * Save node load data + * + * @param status + * Data returned from HTTP request + */ +function saveNodeLoad(status){ + // Save node path and status for future use + nodePath = new Object(); + nodeStatus = new Object(); + + // Get nodes status + var nodes = status.rsp[0].split(';'); + + var i = 0, pos = 0; + var node = '', tmpStr = ''; + var tmpArry; + + for (i = 0; i < nodes.length; i++){ + tmpStr = nodes[i]; + pos = tmpStr.indexOf(':'); + node = tmpStr.substring(0, pos); + tmpArry = tmpStr.substring(pos + 1).split(','); + + switch(tmpArry[0]){ + case 'UNKNOWN':{ + nodeStatus[node] = -2; + } + break; + case 'ERROR':{ + nodeStatus[node] = -1; + } + break; + case 'WARNING':{ + nodeStatus[node] = 0; + nodePath[node] = tmpArry[1]; + } + break; + case 'NORMAL':{ + nodeStatus[node] = 1; + nodePath[node] = tmpArry[1]; + } + break; + } + } +} + +/** + * Get monitoring metrics and load into inventory fieldset + * + * @param node + * Node to collect metrics + * @return Nothing + */ +function getMonitorMetrics(node) { + $('#' + node + '_monitor').children().remove(); + + // Get monitoring metrics + $.ajax({ + url : 'lib/srv_cmd.php', + dataType : 'json', + data : { + cmd : 'webrun', + tgt : '', + args : 'gangliashow;' + nodePath[node] + ';hour;_summary_', + msg : node + }, + + success: drawMonitoringCharts + }); +} + +/** + * Draw monitoring charts based on node metrics + * + * @param data + * Data returned from HTTP request + * @return Nothing + */ +function drawMonitoringCharts(data){ + var nodeMetrics = new Object(); + var metricData = data.rsp[0].split(';'); + var node = data.msg; + + var metricName = ''; + var metricVal = ''; + var pos = 0; + + // Go through the metrics returned + for (var m = 0; m < metricData.length; m++){ + pos = metricData[m].indexOf(':'); + + // Get metric name + metricName = metricData[m].substr(0, pos); + nodeMetrics[metricName] = new Array(); + // Get metric values + metricVal = metricData[m].substr(pos + 1).split(','); + // Save node metrics + for (var i = 0; i < metricVal.length; i++){ + nodeMetrics[metricName].push(Number(metricVal[i])); + } + } + + drawLoadFlot(node, nodeMetrics['load_one'], nodeMetrics['cpu_num']); + drawCpuFlot(node, nodeMetrics['cpu_idle']); + drawMemFlot(node, nodeMetrics['mem_free'], nodeMetrics['mem_total']); + drawDiskFlot(node, nodeMetrics['disk_free'], nodeMetrics['disk_total']); + drawNetworkFlot(node, nodeMetrics['bytes_in'], nodeMetrics['bytes_out']); +} + +/** + * Draw load metrics flot + * + * @param node + * Node name + * @param loadpair + * Load timestamp and value pair + * @param cpupair + * CPU number and value pair + * @return Nothing + */ +function drawLoadFlot(node, loadPair, cpuPair){ + var load = new Array(); + var cpu = new Array(); + + var i = 0; + var yAxisMax = 0; + var interval = 1; + + // Append flot to node monitoring fieldset + var loadFlot = $('
      ').css({ + 'float': 'left', + 'height': '150px', + 'margin': '0 0 10px', + 'width': '300px' + }); + $('#' + node + '_monitor').append(loadFlot); + $('#' + node + '_load').empty(); + + // Parse load pair where: + // timestamp must be mutiplied by 1000 and Javascript timestamp is in ms + for (i = 0; i < loadPair.length; i += 2){ + load.push([loadPair[i] * 1000, loadPair[i + 1]]); + if (loadPair[i + 1] > yAxisMax){ + yAxisMax = loadPair[i + 1]; + } + } + + // Parse CPU pair + for (i = 0; i < cpuPair.length; i += 2){ + cpu.push([cpuPair[i] * 1000, cpuPair[i + 1]]); + if (cpuPair[i + 1] > yAxisMax){ + yAxisMax = cpuPair[i + 1]; + } + } + + interval = parseInt(yAxisMax / 3); + if (interval < 1){ + interval = 1; + } + + $.jqplot(node + '_load', [load, cpu],{ + title: ' Loads/Procs Last Hour', + axes:{ + xaxis:{ + renderer : $.jqplot.DateAxisRenderer, + numberTicks: 4, + tickOptions : { + formatString : '%R', + show : true + } + }, + yaxis: { + min : 0, + tickInterval : interval + } + }, + legend : { + show: true, + location: 'nw' + }, + series:[{label:'Load'}, {label: 'CPU Number'}], + seriesDefaults : {showMarker: false} + }); +} + +/** + * Draw CPU usage flot + * + * @param node + * Node name + * @param cpuPair + * CPU timestamp and value pair + * @return Nothing + */ +function drawCpuFlot(node, cpuPair){ + var cpu = new Array(); + + // Append flot to node monitoring fieldset + var cpuFlot = $('
      ').css({ + 'float': 'left', + 'height': '150px', + 'margin': '0 0 10px', + 'width': '300px' + }); + $('#' + node + '_monitor').append(cpuFlot); + $('#' + node + '_cpu').empty(); + + // Time stamp should by mutiplied by 1000 + // CPU idle comes from server, subtract 1 from idle + for(var i = 0; i < cpuPair.length; i +=2){ + cpu.push([(cpuPair[i] * 1000), (100 - cpuPair[i + 1])]); + } + + $.jqplot(node + '_cpu', [cpu],{ + title: 'CPU Use Last Hour', + axes:{ + xaxis:{ + renderer : $.jqplot.DateAxisRenderer, + numberTicks: 4, + tickOptions : { + formatString : '%R', + show : true + } + }, + yaxis: { + min : 0, + max : 100, + tickOptions:{formatString : '%d\%'} + } + }, + seriesDefaults : {showMarker: false} + }); +} + +/** + * Draw memory usage flot + * + * @param node + * Node name + * @param freePair + * Free memory timestamp and value pair + * @param totalPair + * Total memory timestamp and value pair + * @return Nothing + */ +function drawMemFlot(node, freePair, totalPair){ + var used = new Array(); + var total = new Array(); + var size = 0; + + // Append flot to node monitoring fieldset + var memoryFlot = $('
      ').css({ + 'float': 'left', + 'height': '150px', + 'margin': '0 0 10px', + 'width': '300px' + }); + $('#' + node + '_monitor').append(memoryFlot); + $('#' + node + '_memory').empty(); + + if(freePair.length < totalPair.length){ + size = freePair.length; + } else { + size = freePair.length; + } + + var tmpTotal, tmpUsed; + for(var i = 0; i < size; i+=2){ + tmpTotal = totalPair[i+1]; + tmpUsed = tmpTotal-freePair[i+1]; + tmpTotal = tmpTotal/1000000; + tmpUsed = tmpUsed/1000000; + total.push([totalPair[i]*1000, tmpTotal]); + used.push([freePair[i]*1000, tmpUsed]); + } + + $.jqplot(node + '_memory', [used, total],{ + title: 'Memory Use Last Hour', + axes:{ + xaxis:{ + renderer : $.jqplot.DateAxisRenderer, + numberTicks: 4, + tickOptions : { + formatString : '%R', + show : true + } + }, + yaxis: { + min : 0, + tickOptions:{formatString : '%.2fG'} + } + }, + legend : { + show: true, + location: 'nw' + }, + series:[{label:'Used'}, {label: 'Total'}], + seriesDefaults : {showMarker: false} + }); +} + +/** + * Draw disk usage flot + * + * @param node + * Node name + * @param freePair + * Free disk space (Ganglia only logs free data) + * @param totalPair + * Total disk space + * @return Nothing + */ +function drawDiskFlot(node, freePair, totalPair) { + var used = new Array(); + var total = new Array(); + var size = 0; + + // Append flot to node monitoring fieldset + var diskFlot = $('
      ').css({ + 'float' : 'left', + 'height' : '150px', + 'margin' : '0 0 10px', + 'width' : '300px' + }); + $('#' + node + '_monitor').append(diskFlot); + $('#' + node + '_disk').empty(); + + if (freePair.length < totalPair.length) { + size = freePair.length; + } else { + size = freePair.length; + } + + var tmpTotal, tmpUsed; + for ( var i = 0; i < size; i += 2) { + tmpTotal = totalPair[i + 1]; + tmpUsed = tmpTotal - freePair[i + 1]; + total.push([ totalPair[i] * 1000, tmpTotal ]); + used.push([ freePair[i] * 1000, tmpUsed ]); + } + + $.jqplot(node + '_disk', [ used, total ], { + title : 'Disk Use Last Hour', + axes : { + xaxis : { + renderer : $.jqplot.DateAxisRenderer, + numberTicks : 4, + tickOptions : { + formatString : '%R', + show : true + } + }, + yaxis : { + min : 0, + tickOptions : { + formatString : '%.2fG' + } + } + }, + legend : { + show : true, + location : 'nw' + }, + series : [ { + label : 'Used' + }, { + label : 'Total' + } ], + seriesDefaults : { + showMarker : false + } + }); +} + +/** + * Draw network usage flot + * + * @param node + * Node name + * @param freePair + * Free memory timestamp and value pair + * @param totalPair + * Total memory timestamp and value pair + * @return Nothing + */ +function drawNetworkFlot(node, inPair, outPair) { + var inArray = new Array(); + var outArray = new Array(); + var maxVal = 0; + var unitName = 'B'; + var divisor = 1; + + // Append flot to node monitoring fieldset + var diskFlot = $('
      ').css({ + 'float' : 'left', + 'height' : '150px', + 'margin' : '0 0 10px', + 'width' : '300px' + }); + $('#' + node + '_monitor').append(diskFlot); + $('#' + node + '_network').empty(); + + for (var i = 0; i < inPair.length; i += 2) { + if (inPair[i + 1] > maxVal) { + maxVal = inPair[i + 1]; + } + } + + for (var i = 0; i < outPair.length; i += 2) { + if (outPair[i + 1] > maxVal) { + maxVal = outPair[i + 1]; + } + } + + if (maxVal > 3000000) { + divisor = 1000000; + unitName = 'GB'; + } else if (maxVal >= 3000) { + divisor = 1000; + unitName = 'MB'; + } else { + // Do nothing + } + + for (i = 0; i < inPair.length; i += 2) { + inArray.push([ (inPair[i] * 1000), (inPair[i + 1] / divisor) ]); + } + + for (i = 0; i < outPair.length; i += 2) { + outArray.push([ (outPair[i] * 1000), (outPair[i + 1] / divisor) ]); + } + + $.jqplot(node + '_network', [ inArray, outArray ], { + title : 'Network Last Hour', + axes : { + xaxis : { + renderer : $.jqplot.DateAxisRenderer, + numberTicks : 4, + tickOptions : { + formatString : '%R', + show : true + } + }, + yaxis : { + min : 0, + tickOptions : { + formatString : '%d' + unitName + } + } + }, + legend : { + show : true, + location : 'nw' + }, + series : [ { + label : 'In' + }, { + label : 'Out' + } ], + seriesDefaults : { + showMarker : false + } + }); +} \ No newline at end of file diff --git a/xCAT-UI/js/service/utils.js b/xCAT-UI/js/service/utils.js new file mode 100644 index 000000000..557e795c4 --- /dev/null +++ b/xCAT-UI/js/service/utils.js @@ -0,0 +1,321 @@ +/** + * Get nodes currently shown in datatable + * + * @param tableId + * Datatable ID + * @return String of nodes shown + */ +function getNodesShown(tableId) { + // String of nodes shown + var shownNodes = ''; + + // Get rows of shown nodes + var nodes = $('#' + tableId + ' tbody tr'); + + // Go through each row + var cols; + for (var i = 0; i < nodes.length; i++) { + // Get second column containing node name + cols = nodes.eq(i).find('td'); + shownNodes += cols.eq(1).text() + ','; + } + + // Remove last comma + shownNodes = shownNodes.substring(0, shownNodes.length-1); + return shownNodes; +} + +/** + * Find the row index containing a column with a given string + * + * @param str + * String to search for + * @param table + * Table to check + * @param col + * Column to find string under + * @return The row index containing the search string + */ +function findRow(str, table, col){ + var dTable, rows; + + // Get datatable + dTable = $(table).dataTable(); + rows = dTable.fnGetData(); + + // Loop through each row + for (var i in rows) { + // If the column contains the search string + if (rows[i][col].indexOf(str) > -1) { + return i; + } + } + + return -1; +} + +/** + * Select all checkboxes in the datatable + * + * @param event + * Event on element + * @param obj + * Object triggering event + * @return Nothing + */ +function selectAll(event, obj) { + var status = obj.attr('checked'); + var checkboxes = obj.parents('.dataTables_scroll').find('.dataTables_scrollBody input:checkbox'); + if (status) { + checkboxes.attr('checked', true); + } else { + checkboxes.attr('checked', false); + } + + event.stopPropagation(); +} + +/** + * Get node attributes from HTTP request data + * + * @param propNames + * Hash table of property names + * @param keys + * Property keys + * @param data + * Data from HTTP request + * @return Hash table of property values + */ +function getAttrs(keys, propNames, data) { + // Create hash table for property values + var attrs = new Object(); + + // Go through inventory and separate each property out + var curKey; // Current property key + var addLine; // Add a line to the current property? + for ( var i = 1; i < data.length; i++) { + addLine = true; + + // Loop through property keys + // Does this line contains one of the properties? + for ( var j = 0; j < keys.length; j++) { + // Find property name + if (data[i].indexOf(propNames[keys[j]]) > -1) { + attrs[keys[j]] = new Array(); + + // Get rid of property name in the line + data[i] = data[i].replace(propNames[keys[j]], ''); + // Trim the line + data[i] = jQuery.trim(data[i]); + + // Do not insert empty line + if (data[i].length > 0) { + attrs[keys[j]].push(data[i]); + } + + curKey = keys[j]; + addLine = false; // This line belongs to a property + } + } + + // Line does not contain a property + // Must belong to previous property + if (addLine && data[i].length > 1) { + data[i] = jQuery.trim(data[i]); + attrs[curKey].push(data[i]); + } + } + + return attrs; +} + +/** + * Create a tool tip for comments + * + * @param comment + * Comments to be placed in a tool tip + * @return Tool tip + */ +function createCommentsToolTip(comment) { + // Create tooltip container + var toolTip = $('
      '); + // Create textarea to hold comment + var txtArea = $('').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/srv_cmd.php', + dataType : 'json', + data : { + cmd : 'chdef', + tgt : '', + args : '-t;node;-o;' + node + ';usercomment=' + comments, + msg : 'out=manageTab;tgt=' + 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; +} + +/** + * Open a dialog and show given message + * + * @param type + * Type of dialog, i.e. warn or info + * @param msg + * Message to show + * @return Nothing + */ +function prompt(type, msg) { + var style = { + 'display': 'inline-block', + 'margin': '5px', + 'vertical-align': 'middle' + }; + msg.css({ + 'display': 'inline', + 'margin': '5px', + 'vertical-align': 'middle' + }); + + // Append icon + var icon; + var dialog = $('
      '); + if (type == "Warning") { + icon = $('').css(style); + } else { + icon = $('').css(style); + } + + dialog.append(icon); + dialog.append(msg); + + // Open dialog + dialog.dialog({ + title: type, + modal: true, + width: 400, + buttons: { + "Ok": function(){ + $(this).dialog("close"); + } + } + }); +} + +/** + * Get nodes that are checked in a given datatable + * + * @param dTableId + * The datatable ID + * @return Nodes that were checked + */ +function getNodesChecked(dTableId) { + var tgts = ''; + + // Get nodes that were checked + var nodes = $('#' + dTableId + ' input[type=checkbox]:checked'); + for (var i in nodes) { + var tgtNode = nodes.eq(i).attr('name'); + + if (tgtNode){ + tgts += tgtNode; + + // Add a comma at the end + if (i < nodes.length - 1) { + tgts += ','; + } + } + } + + return tgts; +} + +/** + * Show chdef output + * + * @param data + * Data returned from HTTP request + * @return Nothing + */ +function showChdefOutput(data) { + // Get output + var out = data.rsp; + var args = data.msg.split(';'); + var tabID = args[0].replace('out=', ''); + var tgt = args[1].replace('tgt=', ''); + + // Find info bar on nodes tab, if any + var info = $('#' + tabID).find('.ui-state-highlight'); + if (!info.length) { + // Create info bar if one does not exist + info = createInfoBar(''); + $('#' + tabID).append(info); + } + + // Go through output and append to paragraph + var prg = $('

      '); + for (var i in out) { + prg.append(tgt + ': ' + out[i] + '
      '); + } + + info.append(prg); +} \ No newline at end of file diff --git a/xCAT-UI/js/srv_xcatauth.js b/xCAT-UI/js/srv_xcatauth.js new file mode 100644 index 000000000..d0ea19c74 --- /dev/null +++ b/xCAT-UI/js/srv_xcatauth.js @@ -0,0 +1,90 @@ +/** + * Open login dialog + */ +$(document).ready(function() { + $('#header').remove(); + $('#content').remove(); + + var winHeight = document.body.clientHeight; + var diagHeight = $('#logdialog').css('height'); + diagHeight = diagHeight.substr(0, diagHeight.length - 2); + diagHeight = Number(diagHeight); + + // The window's height is to small to show the dialog + var tmpHeight = 0; + if ((winHeight - 50) < diagHeight){ + tmpHeight = 0; + } else { + tmpHeight = parseInt((winHeight - diagHeight - 50) / 2); + } + + $('#logdialog').css('margin', tmpHeight + 'px auto'); + $('button').bind('click', function(){ + authenticate(); + }).button(); + + if (document.location.protocol == 'http:') { + $('#logstatus').html('You are using an unencrypted session!'); + $('#logstatus').css('color', 'red'); + } + + if (!$('#username').val()) { + $('#username').focus(); + } else { + $('#password').focus(); + } + + // When enter is hit while in username, advance to password + $('#username').keydown(function(event) { + if (event.keyCode == 13) { + $('#password').focus(); + } + }); + + // Submit authentication if enter is pressed in password field + $('#password').keydown(function(event) { + if (event.keyCode == 13) { + authenticate(); + } + }); +}); + +/** + * Update login dialog + * + * @param data + * Data returned from AJAX call + * @param txtStatus + * Status of login + */ +function onlogin(data, txtStatus) { + // Clear password field regardless of what happens + var usrName = $('#username').val(); + $('#password').val(''); + if (data.authenticated == 'yes') { + $('#logstatus').text('Login successful'); + window.location = 'service.php'; + + // Set user name cookie + var exDate = new Date(); + exDate.setTime(exDate.getTime() + (240 * 60 * 1000)); + $.cookie('srv_usrname', usrName, { expires: exDate }); + } else { + $('#logstatus').text('Authentication failure'); + $('#logstatus').css('color', '#FF0000'); + } +} + +/** + * Authenticate user for new session + */ +function authenticate() { + $('#logstatus').css('color', '#000000'); + $('#logstatus').html('Authenticating...'); + + var passwd = $('#password').val(); + $.post('lib/srv_log.php', { + username : $('#username').val(), + password : passwd + }, onlogin, 'json'); +} diff --git a/xCAT-UI/lib/srv_cmd.php b/xCAT-UI/lib/srv_cmd.php new file mode 100644 index 000000000..3798fab27 --- /dev/null +++ b/xCAT-UI/lib/srv_cmd.php @@ -0,0 +1,192 @@ +children() as $child) { + foreach ($child->children() as $data) { + if($data->name) { + $node = $data->name; + + if($data->data->contents){ + $cont = $data->data->contents; + } + else{ + $cont = $data->data; + } + + $cont = str_replace(":|:", "\n", $cont); + array_push($rsp, "$node: $cont"); + } else if(strlen("$data") > 2) { + $data = str_replace(":|:", "\n", $data); + array_push($rsp, "$data"); + } + } + } + } + + // Reply in the form of JSON + $rtn = array("rsp" => $rsp, "msg" => $msg); + echo json_encode($rtn); +} + +/** + * Extract the output for a webrun command + * + * @param $xml The XML output from docmd() + * @return An array containing the output + */ +function extractWebrun($xml) { + $rsp = array(); + $i = 0; + + // Extract data returned + foreach($xml->children() as $nodes){ + foreach($nodes->children() as $node){ + // Get the node name + $name = $node->name; + + // Get the content + $status = $node->data; + $status = str_replace(":|:", "\n", $status); + + // Add to return array + $rsp[$i] = array("$name", "$status"); + $i++; + } + } + + return $rsp; +} + +/** + * Extract the output for a nodels command + * + * @param $xml The XML output from docmd() + * @return An array containing the output + */ +function extractNodels($xml) { + $rsp = array(); + $i = 0; + + // Extract data returned + foreach($xml->children() as $nodes){ + foreach($nodes->children() as $node){ + // Get the node name + $name = $node->name; + // Get the content + $status = $node->data->contents; + $status = str_replace(":|:", "\n", $status); + + $description = $node->data->desc; + // Add to return array + $rsp[$i] = array("$name", "$status", "$description"); + $i++; + } + } + + return $rsp; +} + +/** + * Extract the output for a extnoderange command + * + * @param $xml The XML output from docmd() + * @return The nodes and groups + */ +function extractExtnoderange($xml) { + $rsp = array(); + + // Extract data returned + foreach ($xml->xcatresponse->intersectinggroups as $group) { + array_push($rsp, "$group"); + } + + return $rsp; +} +?> \ No newline at end of file diff --git a/xCAT-UI/lib/srv_functions.php b/xCAT-UI/lib/srv_functions.php new file mode 100644 index 000000000..e2eb01a3a --- /dev/null +++ b/xCAT-UI/lib/srv_functions.php @@ -0,0 +1,324 @@ +You are not logged in! Failed to run command.

      "; + return simplexml_load_string('', 'SimpleXMLElement', LIBXML_NOCDATA); + } + + // Create xCAT request + // Add command, node range, and arguments to request + $request = simplexml_load_string(''); + $request->addChild('command', $cmd); + if(!empty($nr)) { $request->addChild('noderange', $nr); } + if (!empty($args_array)) { + foreach ($args_array as $a) { + $request->addChild('arg',$a); + } + } + + // Add user and password to request + $usernode=$request->addChild('becomeuser'); + $usernode->addChild('username',$_SESSION["srv_username"]); + $usernode->addChild('password',getpassword()); + + $xml = submit_request($request, 0, $opts_array); + return $xml; +} + +/** + * Used by docmd() to submit request to xCAT + * + * @param $req Tree of SimpleXML objects + * @param $opts_array Request options + * @return A tree of SimpleXML objects + */ +function submit_request($req, $skipVerify, $opts_array){ + $xcathost = "localhost"; + $port = "3001"; + $rsp = FALSE; + $response = ''; + $cleanexit = 0; + + // Determine whether to flush output or not + $flush = false; + if ($opts_array && in_array("flush", $opts_array)) { + $flush = true; + } + + // Determine how to handle the flush output + // You can specify a function name, in place of TBD, to handle the flush output + $flush_format = ""; + if ($opts_array && in_array("flush-format=TBD", $opts_array)) { + $flush_format = "TBD"; + } + + // Open syslog, include the process ID and also send + // the log to standard error, and use a user defined + // logging mechanism + openlog("xCAT-UI", LOG_PID | LOG_PERROR, LOG_LOCAL0); + + // Open a socket to xcatd + syslog(LOG_INFO, "Opening socket to xcatd..."); + if($fp = stream_socket_client('ssl://'.$xcathost.':'.$port, $errno, $errstr, 30, STREAM_CLIENT_CONNECT)){ + $reqXML = $req->asXML(); + $nr = $req->noderange; + $cmd = $req->command; + + syslog(LOG_INFO, "Sending request: $cmd $nr"); + stream_set_blocking($fp, 0); // Set as non-blocking + fwrite($fp,$req->asXML()); // Send XML to xcatd + set_time_limit(900); // Set 15 minutes timeout (for long running requests) + // The default is 30 seconds which is too short for some requests + + // Turn on output buffering + ob_start(); + while(!feof($fp)) { // Read until there is no more + // Remove newlines and add it to the response + $str = fread($fp, 8192); + if ($str) { + $response .= preg_replace('/>\n\s*<', $str); + + // Flush output to browser + if ($flush) { + // Strip HTML tags from output + if ($tmp = trim(strip_tags($str))) { + // Format the output based on what was given for $flush_format + if ($flush_format == "TDB") { + format_TBD($tmp); + } else { + // Print out output by default + echo '
      ' . $tmp . '
      '; + ob_flush(); + flush(); + } + } + } + } + + // Look for serverdone response + $fullpattern = '/\s*\s*<\/serverdone>\s*<\/xcatresponse>/'; + $mixedpattern = '/\s*<\/serverdone>.*<\/xcatresponse>/'; + $recentpattern = '/<\/xcatresponse>/'; + if(preg_match($recentpattern,$str) && preg_match($mixedpattern,$response)) { + // Transaction is done, + // Package up XML and return it + // Remove the serverdone response and put an xcat tag around the rest + $count = 0; + $response = preg_replace($fullpattern,'', $response, -1, $count); // 1st try to remove the long pattern + if (!$count) { $response = preg_replace($mixedpattern,'', $response) . '/'; } // if its not there, then remove the short pattern + $response = "$response"; + //delete the \n between '>' and '<' + $response = preg_replace('/>\n\s*<', $response); + //replace the '\n' by ':|:' in the data area. + $response = preg_replace('/\n/', ':|:', $response); + $rsp = simplexml_load_string($response,'SimpleXMLElement', LIBXML_NOCDATA); + $cleanexit = 1; + break; + } + } // End of while(!feof($fp)) + + syslog(LOG_INFO, "($cmd $nr) Sending response"); + fclose($fp); + } else { + echo "

      xCAT submit request socket error: $errno - $errstr

      "; + } + + // Flush (send) the output buffer and turn off output buffering + ob_end_flush(); + + // Close syslog + closelog(); + + if(! $cleanexit) { + if (preg_match('/^\s*.*<\/xcatresponse>\s*$/',$response)) { + // Probably an error message + $response = "$response"; + $rsp = simplexml_load_string($response,'SimpleXMLElement', LIBXML_NOCDATA); + } + elseif(!$skipVerify) { + echo "

      (Error) xCAT response ended prematurely: ", htmlentities($response), "

      "; + $rsp = FALSE; + } + } + return $rsp; +} + +/** + * Enable password storage to split between cookie and session variable + * + * @param $data + * @param $key + * @return + */ +function xorcrypt($data, $key) { + $datalen = strlen($data); + $keylen = strlen($key); + for ($i=0;$i<$datalen;$i++) { + $data[$i] = chr(ord($data[$i])^ord($key[$i])); + } + + return $data; +} + +/** + * Get RAND characters + * + * @param $length Length of characters + * @return RAND characters + */ +function getrandchars($length) { + $charset = '0123456789abcdefghijklmnopqrstuvwxyz!@#$%^&*'; + $charsize = strlen($charset); + srand(); + $chars = ''; + for ($i=0;$i<$length;$i++) { + $num=rand()%$charsize; + $chars=$chars.substr($charset,$num,1); + } + + return $chars; +} + +/** + * Format a given string and echo it back to the browser + * + * @param $str String + * @return Nothing + */ +function format_TBD($str) { + // Format a given string however you want it + echo $tmp . '
      '; + flush(); +} + +/** + * Get password + * + * @param Nothing + * @return + */ +function getpassword() { + if (isset($GLOBALS['xcatauthsecret'])) { + $cryptext = $GLOBALS['xcatauthsecret']; + } else if (isset($_COOKIE["xcatauthsecret"])) { + $cryptext = $_COOKIE["xcatauthsecret"]; + } else { + return false; + } + + return xorcrypt($_SESSION["secretkey"], base64_decode($cryptext)); +} + +/** + * Get the password splitting knowledge between server + * and client side persistant storage. Caller should regenerate + * session ID when contemplating a new user/password, to preclude + * session fixation, though fixation is limited without the secret. + * + * @param $password Password + * @return Nothing + */ +function setpassword($password) { + $randlen = strlen($password); + $key = getrandchars($randlen); + $cryptext = xorcrypt($password,$key); + + // Non-ascii characters, encode it in base64 + $cryptext = base64_encode($cryptext); + setcookie("xcatauthsecret",$cryptext,0,'/'); + $GLOBALS["xcatauthsecret"] = $cryptext; + $_SESSION["secretkey"] = $key; +} + +/** + * Determine if a user/password session exists + * + * @param Nothing + * @return True If user has a session. + * False Otherwise + */ +function is_logged() { + if (isset($_SESSION["srv_username"]) and !is_bool(getpassword())) { + return true; + } else { + return false; + } +} + +/** + * Determine if a user is currently logged in successfully + * + * @param Nothing + * @return True If the user is currently logged in successfully + * False Otherwise + */ +function isAuthenticated() { + if (is_logged()) { + if ($_SESSION["srv_xcatpassvalid"] != 1) { + $testcred = docmd("authcheck", "", NULL, NULL); + if (isset($testcred->{'xcatresponse'}->{'data'})) { + $result = "".$testcred->{'xcatresponse'}->{'data'}; + if (is_numeric(strpos("Authenticated",$result))) { + // Logged in successfully + $_SESSION["srv_xcatpassvalid"] = 1; + } else { + // Not logged in + $_SESSION["srv_xcatpassvalid"] = 0; + } + } + } + } + + if (isset($_SESSION["srv_xcatpassvalid"]) and $_SESSION["srv_xcatpassvalid"]==1) { + return true; + } else { + return false; + } +} + +/** + * Log out of the current user session + * + * @param Nothing + * @return Nothing + */ +function logout() { + // Clear the secret cookie from browser + if (isset($_COOKIE["xcatauthsecret"])) { + setcookie("xcatauthsecret",'',time()-86400*7,'/'); + } + + // Expire session cookie + if (isset($_COOKIE[session_name()])) { + setcookie(session_name(),"",time()-86400*7,"/"); + } + + // Clear server store of data + $_SESSION=array(); + session_destroy(); +} +?> diff --git a/xCAT-UI/lib/srv_log.php b/xCAT-UI/lib/srv_log.php new file mode 100644 index 000000000..33a376cdc --- /dev/null +++ b/xCAT-UI/lib/srv_log.php @@ -0,0 +1,39 @@ + + diff --git a/xCAT-UI/lib/srv_logout.php b/xCAT-UI/lib/srv_logout.php new file mode 100644 index 000000000..beb493c3e --- /dev/null +++ b/xCAT-UI/lib/srv_logout.php @@ -0,0 +1,10 @@ + diff --git a/xCAT-UI/lib/ui.php b/xCAT-UI/lib/ui.php index 422162cef..452c31b50 100644 --- a/xCAT-UI/lib/ui.php +++ b/xCAT-UI/lib/ui.php @@ -5,21 +5,21 @@ * @param Nothing * @return Nothing */ -function loadPage(){ +function loadPage() { // Include CSS and Javascripts echo ' xCAT Console - + - - + + '; diff --git a/xCAT-UI/service.php b/xCAT-UI/service.php new file mode 100644 index 000000000..7c4e5e8d1 --- /dev/null +++ b/xCAT-UI/service.php @@ -0,0 +1,87 @@ + + + xCAT Service Portal + + + + + + + + + + + '; + +// Create header menu +echo +' + '; + +// Create content area +echo '
      '; + +// End of page +echo + ' +'; + +// Login user +if (!isAuthenticated()) { + // xcatauth.js will open a dialog box asking for the user name and password + echo + ' + +
      +
      +
      zVM Group Image
      + + + + + + + +

      eXtreme Cloud Administration Toolkit

      + +
      Open Source. EPL License.
      + '; +} else { + // Initialize page + echo + ''; +} +?>