diff --git a/xCAT-UI/css/style.css b/xCAT-UI/css/style.css index 1ffd880e4..1208d6c39 100644 --- a/xCAT-UI/css/style.css +++ b/xCAT-UI/css/style.css @@ -17,7 +17,6 @@ background-color: #000; border: 1px solid #fff; padding: 10px 15px; - width: 200px; display: none; color: #fff; text-align: left; @@ -27,6 +26,9 @@ -webkit-box-shadow: 0 0 10px #000; } +.tooltip h3 { + margin : 0px; +} /****************** Header ******************/ #header { height: 40px; @@ -95,6 +97,14 @@ color: #FF0000; } +#layoutselector{ + padding: 2px 10px 0px 2px; /* Top right left bottom*/ + text-align: right; + color: #FFC125; + text-decoration: none; + display: block; +} + /****************** Content section ******************/ body { background-color: #1C1C1C; @@ -152,6 +162,82 @@ body { display: inline-table; } +/****************** physical layout section ******************/ +.physicaltree { + width: 200px; + vertical-align: top; + float: left; + position: relative; + margin: 15px 0px 15px 15px; + overflow: auto; +} + +.physicalview{ + width : 700px; + display : inline-table; +} + +.frameDiv{ + width : 179px; + height : 500px; + font-size: 10px; + background :url(../images/bpa.jpg); + border-width:2px; +} + +.fspDiv2{ + margin: 0px 12px 2px 17px; + font-size: 12px; + height: 20px; + line-height : 20px; + width : 140px; + text-align: center; + background:url(../images/4ufsp.jpg); + border-style:solid; + border-width:1px; + cursor: pointer; +} + +.fspDiv4{ + margin: 0px 12px 2px 17px; + font-size: 12px; + height: 44px; + line-height : 44px; + width : 140px; + text-align: center; + background:url(../images/4ufsp.jpg); + border-style:solid; + border-width:1px; + cursor: pointer; +} + +.fspDiv42{ + width : 179px; + height : 500px; + font-size: 15px; + background :url(../images/42ufsp.jpg); + border-width:2px; + cursor: pointer; +} + +.lparDiv{ + margin: 5px 0px 0px 9px; + width : 80px; + height : 10px; + opacity: 1; +} + +.lparStatus{ + width : 5px; + height : 5px; + padding: 0px; + border-width: 1px; + border-color: transparent; + border-style: solid; + font-size:1 +} + + /****************** Info/warning bar ******************/ span.ui-icon-info { float: left; @@ -237,7 +323,7 @@ span.ui-icon-info { cursor: pointer; } -.tab fieldset { +fieldset { margin-bottom: 5px; border-width: 1px 0 0 0; border-style: solid none none none; @@ -252,7 +338,7 @@ span.ui-icon-info { width: 140px; } -.tab legend { +legend { font: 12px verdana, arial, helvetica, sans-serif; color: #424242; font-weight: bold; @@ -264,12 +350,6 @@ span.ui-icon-info { padding: 0; } -.tab li { - list-style: none; - padding: 5px; - margin: 0; -} - .tab textarea { font: 12px verdana, arial, helvetica, sans-serif; border: solid 0px #BDBDBD; @@ -298,6 +378,11 @@ span.ui-icon-info { cursor: pointer; } +.actionBar li { + list-style: none; + padding: 5px; + margin: 0; +} /****************** Status bar ******************/ .statusBar { border: solid 1px #F5D0A9; diff --git a/xCAT-UI/js/nodes/nodes.js b/xCAT-UI/js/nodes/nodes.js index 0caacb38e..e469e6ad3 100644 --- a/xCAT-UI/js/nodes/nodes.js +++ b/xCAT-UI/js/nodes/nodes.js @@ -54,11 +54,36 @@ function setNodesDataTable(table) { function loadNodesPage() { // If groups are not already loaded if (!$('#groups').length) { + + var layoutSelectorDiv = $('
'); + var logicalLayoutDiv = $('
'); + var physicalLayoutDiv = $('
'); + physicalLayoutDiv.hide(); + + $('#content').append(layoutSelectorDiv); + $('#content').append(logicalLayoutDiv); + $('#content').append(physicalLayoutDiv); + // Create layout selector + var groupRadio = $('Group'); + groupRadio.bind('click',function(){ + $('#physicalLayout').hide(); + $('#logicalLayout').show(); + }); + + var physicalRadio = $('Graphical'); + physicalRadio.bind('click', function(){ + $('#logicalLayout').hide(); + $('#physicalLayout').show(); + }); + layoutSelectorDiv.append(''); + layoutSelectorDiv.append(groupRadio); + layoutSelectorDiv.append(physicalRadio); + // Create a groups division groupDIV = $('
'); nodesDIV = $('
'); - $('#content').append(groupDIV); - $('#content').append(nodesDIV); + logicalLayoutDiv.append(groupDIV); + logicalLayoutDiv.append(nodesDIV); // Create loader var loader = createLoader(); @@ -81,6 +106,21 @@ function loadNodesPage() { success : loadGroups }); + + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'nodels', + tgt : 'all', + args : 'nodetype.nodetype;ppc.parent;vpd.mtm;nodelist.status', + msg : '' + }, + + success : function(data){ + createPhysicalLayout(data, $('#physicalLayout')); + } + }); } } diff --git a/xCAT-UI/js/nodes/physical.js b/xCAT-UI/js/nodes/physical.js new file mode 100644 index 000000000..aa42afe68 --- /dev/null +++ b/xCAT-UI/js/nodes/physical.js @@ -0,0 +1,711 @@ +var hardwareInfo = { + '7037-A50' : ['P5-185', '5' ], + '9115-505' : ['P5-505', '1' ], + '9110-510' : ['P5-510', '2' ], + '9110-51A' : ['P5-510', '2' ], + '9111-520' : ['P5-520', '4' ], + '913A-52A' : ['P5-52A', '4' ], + '9113-550' : ['P5-550', '4' ], + '9133-55A' : ['P5-55A', '4' ], + '9116-561' : ['P5-560Q', '4' ], + '9117-570' : ['P5-570', '4' ], + '9118-575' : ['P5-575', '42'], + '9119-590' : ['P5-590', '42'], + '9119-595' : ['P5-595', '42'], + + //P6 + '8203-E4A' : ['P6-520', '4' ], + '9407-M15' : ['P6-520', '4' ], + '9408-M25' : ['P6-520', '4' ], + '8204-E8A' : ['P6-550', '4' ], + '9409-M50' : ['P6-550', '4' ], + '8234-EMA' : ['P6-560', '4' ], + '9117-MMA' : ['P6-570', '4' ], + '9125-F2A' : ['P6-575', '42'], + '9119-FHA' : ['P6-595', '42'], + + //P7 + '8202-E4B' : ['P7-720', '4' ], + '8205-E6B' : ['P7-740', '4' ], + '8231-E2B' : ['P7-710/730', '2' ], + '8233-E8B' : ['P7-750', '4' ], + '8236-E8C' : ['P7-755', '4' ], + '9117-MMB' : ['P7-770', '4' ], + '9119-FHB' : ['P7-795', '42'], + '9179-MHB' : ['P7-780', '42'] +}; + +var bpaList; +var fspList; +var lparList; +var selectLpar = new Object(); +/** + * Get all nodes' nodetype and parent, and create the physical layout div + * + * @param data: the response from xcat command "nodels all nodetype.nodetype ppc.parent ..." + * area: the element to append tree and graphical layout + * @return + */ +function createPhysicalLayout(data, area){ + var nodes = data.rsp; + var tempList = new Object(); + bpaList = new Object(); + fspList = new Object(); + lparList = new Object(); + + //extract useful info into tempList + for (var i = 0; i < nodes.length; i++){ + var nodeName = nodes[i][0]; + if (undefined == tempList[nodeName]){ + tempList[nodeName] = new Object(); + } + + switch(nodes[i][2]){ + case 'nodetype.nodetype': { + tempList[nodeName]['type'] = nodes[i][1]; + } + break; + case 'ppc.parent' : { + tempList[nodeName]['parent'] = nodes[i][1]; + } + break; + case 'nodelist.status': { + tempList[nodeName]['status'] = nodes[i][1]; + } + break; + case 'vpd.mtm': { + tempList[nodeName]['mtm'] = nodes[i][1]; + } + default : + break; + } + } + + for (var nodeName in tempList){ + var parentName = tempList[nodeName]['parent']; + var mtm = tempList[nodeName]['mtm']; + var status = tempList[nodeName]['status']; + switch(tempList[nodeName]['type']){ + case 'bpa': { + if (undefined == bpaList[nodeName]){ + bpaList[nodeName] = new Array(); + } + } + break; + case 'lpar,osi': { + if ('' == parentName){ + break; + } + + if (undefined == fspList[parentName]){ + fspList[parentName] = new Array(); + //default is 4 units. so i select a 4u mtm randomly + fspList[parentName]['mtm'] = '8202-E4B'; + fspList[nodeName]['children'] = new Array(); + } + + fspList[parentName]['children'].push(nodeName); + lparList[nodeName] = status; + } + break; + case 'fsp': { + if (undefined == fspList[nodeName]){ + fspList[nodeName] = new Array(); + fspList[nodeName]['children'] = new Array(); + } + + fspList[nodeName]['mtm'] = mtm; + + if ('' == parentName){ + break; + } + + if (undefined == bpaList[parentName]){ + bpaList[parentName] = new Array(); + } + + bpaList[parentName].push(nodeName); + } + break; + default: + break; + } + } + + createTree(bpaList, fspList, area); + createGraphical(bpaList, fspList, area); + +} + +/** + * create the physical tree layout + * + * @param bpa : all bpa and there related fsps + * fsp : all fsp and there related lpars + * area: the element to append tree layout + * @return + */ +function createTree(bpa, fsp, area){ + //create tree and layout + var usedFsp = new Object(); + var bpaList = ''; + + var cecList = ''; + + var tree_area = $('
'); + + tree_area.append(''); + area.append(tree_area); + tree_area.tree({}); +} + +/** + * create the physical graphical layout + * + * @param bpa : all bpa and there related fsps + * fsp : all fsp and there related lpars + * fspinfo : all fsps' hardwareinfo + * area: the element to append graphical layout + * @return + */ +function createGraphical(bpa, fsp, area){ + var usedFsp = new Object(); + var graphField = $('
'); + graphField.append('Graphical Layout'); + var graphTable = $('
'); + var elementNum = 0; + var row; + for (var bpaName in bpa){ + if (0 == elementNum % 3){ + row = $(''); + graphTable.append(row); + } + elementNum ++; + var td = $(''); + var frameDiv = $('
'); + frameDiv.append('
' + bpaName + '
'); + for (var fspIndex in bpa[bpaName]){ + var fspName = bpa[bpaName][fspIndex]; + usedFsp[fspName] = 1; + + frameDiv.append(createFspDiv(fspName, fsp[fspName]['mtm'], fsp)); + } + td.append(frameDiv); + row.append(td); + } + + //find the single fsp and sort descend by units + var singleFsp = new Array(); + for (var fspName in fsp){ + if (usedFsp[fspName]) + { + continue; + } + + singleFsp.push([fspName, fsp[fspName]['mtm']]); + } + + singleFsp.sort(function(a, b){ + var unitNumA = 4; + var unitNumB = 4; + if (hardwareInfo[a[1]]){ + unitNumA = hardwareInfo[a[1]][1]; + } + + if (hardwareInfo[b[1]]){ + unitNumB = hardwareInfo[b[1]][1]; + } + + return (unitNumB - unitNumA); + }); + + elementNum = 0; + for (var fspIndex in singleFsp){ + var fspName = singleFsp[fspIndex][0]; + if (0 == elementNum % 3){ + row = $(''); + graphTable.append(row); + } + elementNum ++; + + var td = '' + createFspDiv(fspName, fsp[fspName]['mtm'], fsp) + ''; + row.append(td); + } + + graphField.append(graphTable); + + var graphical_area = $('
'); + var selectLparDiv = $('
'); + var temp = 0; + for (var i in selectLpar){ + temp ++; + break; + } + + //there is not selected lpars, show the info bar + if (0 == temp){ + selectLparDiv.append(createInfoBar('Click CEC and select lpars to do operations.')); + } + //show selected lpars + else{ + updateSelectLparDiv(); + } + graphical_area.append(selectLparDiv); + graphical_area.append(graphField); + area.append(graphical_area); + + $('.fspDiv2, .fspDiv4, .fspDiv42').tooltip({ + showURL: false, + showBody: " - ", + fade: 250 + }); + + $('.fspDiv2, .fspDiv4, .fspDiv42').bind('click', function(){ + var fspName = $(this).attr('value'); + showSelectDialog(fspList[fspName]['children']); + }); +} + +/** + * show the fsp's information in a dialog + * + * @param fspName : fsp's name + * + * @return + */ +function showSelectDialog(lpars){ + var diaDiv = $('
'); + + if (0 == lpars.length){ + diaDiv.append(createInfoBar('There is not any lpars defined.')); + } + else{ + //add the dialog content + var selectTable = $('
'); + selectTable.append('NameStatus'); + for (var lparIndex in lpars){ + var row = $(''); + var lparName = lpars[lparIndex]; + var color = statusMap(lparList[lparName]); + + if (selectLpar[lparName]){ + row.append(''); + } + else{ + row.append(''); + } + row.append('' + lparName + ''); + row.append('' + lparList[lparName] + ''); + selectTable.append(row); + } + diaDiv.append(selectTable); + } + + diaDiv.dialog({ + modal: true, + width: 400, + close: function(event, ui){ + $(this).remove(); + }, + buttons: { + cancel : function(){ + $(this).dialog('close'); + }, + ok : function(){ + $('#selectLparTable input[type=checkbox]').each(function(){ + var lparName = $(this).attr('id'); + if ('' == lparName){ + //continue + return true; + } + if (true == $(this).attr('checked')){ + selectLpar[lparName] = 1; + $('#graphTable #' + lparName).css('border-color', 'aqua'); + } + else{ + delete selectLpar[lparName]; + $('#graphTable #' + lparName).css('border-color', 'transparent'); + } + }); + updateSelectLparDiv(); + $(this).dialog('close'); + } + } + }); +} + +/** + * update the lpars' background in cec, lpars area and selectLpar + * + * @param + * @return + * + **/ +function updateSelectLparDiv(){ + var temp = 0; + $('#selectLparDiv').empty(); + + for (var LparName in selectLpar){ + temp ++; + break; + } + + if (0 == temp){ + $('#selectLparDiv').append(createInfoBar('Click CEC and select lpars to do operations.')); + return; + } + + temp =0; + //add buttons + var tempDiv = $('
'); + tempDiv.append(createActionMenu()); + $('#selectLparDiv').append(tempDiv); + $('#selectLparDiv').append('
Lpars: '); + for(var lparName in selectLpar){ + $('#selectLparDiv').append(lparName + ' '); + temp ++; + if (6 < temp){ + $('#selectLparDiv').append('...'); + break; + } + } + + var reselectButton = createButton('Reselect'); + $('#selectLparDiv').append(reselectButton); + reselectButton.bind('click', function(){ + reselectLpars(); + }); + +} + +/** + * create the action menu + * + * @param getNodesFunction + * the function that can find selected nodes name + * @return + * action menu object + */ +function createActionMenu(){ + // Create action bar + var actionBar = $('
'); + + /** + * The following actions are available to perform against a given node: + * power, clone, delete, unlock, and advanced + */ + /* + * Power + */ + var powerLnk = $('Power'); + + /* + * Power on + */ + var powerOnLnk = $('Power on'); + powerOnLnk.bind('click', function(event) { + var tgtNodes = getSelectLpars(); + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'rpower', + tgt : tgtNodes, + args : 'on', + msg : '' + } + }); + }); + + /* + * Power off + */ + var powerOffLnk = $('Power off'); + powerOffLnk.bind('click', function(event) { + var tgtNodes = getSelectLpars(); + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'rpower', + tgt : tgtNodes, + args : 'off', + msg : '' + } + }); + }); + + /* + * Clone + */ + var cloneLnk = $('Clone'); + cloneLnk.bind('click', function(event) { + var tgtNodes = getSelectLpars('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 + */ + var deleteLnk = $('Delete'); + deleteLnk.bind('click', function(event) { + }); + + /* + * Unlock + */ + var unlockLnk = $('Unlock'); + unlockLnk.bind('click', function(event) { + }); + + /* + * Run script + */ + var scriptLnk = $('Run script'); + scriptLnk.bind('click', function(event) { + }); + + /* + * Update node + */ + var updateLnk = $('Update'); + updateLnk.bind('click', function(event) { + }); + + /* + * Set boot state + */ + var setBootStateLnk = $('Set boot state'); + setBootStateLnk.bind('click', function(event) { + }); + + /* + * Boot to network + */ + var boot2NetworkLnk = $('Boot to network'); + boot2NetworkLnk.bind('click', function(event) { + }); + + /* + * Open the Rcons page + */ + var rcons = $('Open Rcons'); + rcons.bind('click', function(event){ + var tgtNodes = getSelectLpars(); + if (tgtNodes) { + loadRconsPage(tgtNodes); + } + }); + + /* + * Advanced + */ + var advancedLnk = $('Advanced'); + + // Power actions + var powerActions = [ powerOnLnk, powerOffLnk ]; + var powerActionMenu = createMenu(powerActions); + + // Advanced actions + var advancedActions; + advancedActions = [ boot2NetworkLnk, scriptLnk, setBootStateLnk, updateLnk, rcons ]; + 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); + + return actionBar; +} + +/** + * create the physical graphical layout + * + * @param bpaName : fsp's key + * fsp : all fsp and there related lpars + * fspinfo : all fsps' hardwareinfo + * @return + * fspDiv's html + */ +function createFspDiv(fspName, mtm, fsp){ + //create fsp title + var title = '

' + fspName; + var lparStatusRow = ''; + if (hardwareInfo[mtm]){ + title += '(' + hardwareInfo[mtm][0] + ')'; + } + + title += '


'; + + for (var lparIndex in fsp[fspName]['children']){ + var lparName = fsp[fspName]['children'][lparIndex]; + var color = statusMap(lparList[lparName]); + title += lparName + '
'; + lparStatusRow += '1'; + } + + //select the backgroud + var divClass = ''; + if (hardwareInfo[mtm][1]){ + divClass += 'fspDiv' + hardwareInfo[mtm][1]; + } + else{ + divClass += 'fspDiv4'; + } + + //create return value + var retHtml = '
'; + retHtml += '
' + lparStatusRow + '
'; + return retHtml; +} + +/** + * map the lpar's status into a color + * + * @param status : lpar's status in nodelist table + + * @return + * corresponding color name + */ +function statusMap(status){ + var color = 'gainsboro'; + + switch(status){ + case 'alive': + case 'ready': + case 'pbs': + case 'sshd': + case 'booting':{ + color = 'green'; + } + break; + case 'noping': + case 'unreachable':{ + color = 'red'; + } + break; + case 'ping':{ + color = 'yellow'; + } + break; + default: + break; + } + + return color; +} + +/** + * select all lpars checkbox in the dialog + * + * @param + + * @return + * + */ +function selectAllLpars(checkbox){ + var temp = checkbox.attr('checked'); + $('#selectLparTable input[type = checkbox]').attr('checked', temp); +} + +/** + * export all lpars' name from selectLpar + * + * @param + + * @return lpars' string + * + */ +function getSelectLpars(){ + var ret = ''; + for (var lparName in selectLpar){ + ret += lparName + ','; + } + + return ret.substring(0, ret.length-1); +} + +/** + * show all lpars' for users to delete + * + * @param + + * @return + */ +function reselectLpars(){ + var temp = new Array(); + + for (var lparName in selectLpar){ + temp.push(lparName); + } + + showSelectDialog(temp); +} \ No newline at end of file diff --git a/xCAT-UI/js/ui.js b/xCAT-UI/js/ui.js index 4b0113d4e..48c1c299f 100644 --- a/xCAT-UI/js/ui.js +++ b/xCAT-UI/js/ui.js @@ -454,7 +454,7 @@ function initPage() { includeJs("js/nodes/nodeset.js"); includeJs("js/nodes/rnetboot.js"); includeJs("js/nodes/updatenode.js"); - + includeJs("js/nodes/physical.js"); headers.eq(0).css('background-color', '#A9D0F5'); loadNodesPage(); } else if (page == 'configure.php') {