From a9408ab0d17978228678645d5dd5b855c5be35ce Mon Sep 17 00:00:00 2001 From: phamt Date: Thu, 18 Oct 2012 14:18:28 +0000 Subject: [PATCH] Added support for native SCSI/FCP on xCAT-UI. git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/trunk@14048 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd --- xCAT-UI/css/style.css | 1 - xCAT-UI/js/custom/zvm.js | 155 +++- xCAT-UI/js/custom/zvmUtils.js | 1015 ++++++++++++++++++++++++--- xCAT-server/lib/xcat/plugins/zvm.pm | 60 +- 4 files changed, 1109 insertions(+), 122 deletions(-) diff --git a/xCAT-UI/css/style.css b/xCAT-UI/css/style.css index 09a47264c..ad52d320c 100644 --- a/xCAT-UI/css/style.css +++ b/xCAT-UI/css/style.css @@ -347,7 +347,6 @@ legend { .actionBar { display: inline-table; - width: 50%; } .actionBar div { diff --git a/xCAT-UI/js/custom/zvm.js b/xCAT-UI/js/custom/zvm.js index a3be98d58..795c2cde6 100644 --- a/xCAT-UI/js/custom/zvm.js +++ b/xCAT-UI/js/custom/zvm.js @@ -209,7 +209,7 @@ zvmPlugin.prototype.loadServiceInventory = function(data) { var inv = data.rsp[0].split(node + ':'); // Create array of property keys - var keys = new Array('userId', 'host', 'os', 'arch', 'hcp', 'priv', 'memory', 'proc', 'disk', 'nic'); + var keys = new Array('userId', 'host', 'os', 'arch', 'hcp', 'priv', 'memory', 'proc', 'disk', 'zfcp', 'nic'); // Create hash table for property names var attrNames = new Object(); @@ -222,6 +222,7 @@ zvmPlugin.prototype.loadServiceInventory = function(data) { attrNames['memory'] = 'Total Memory:'; attrNames['proc'] = 'Processors:'; attrNames['disk'] = 'Disks:'; + attrNames['zfcp'] = 'zFCP:'; attrNames['nic'] = 'NICs:'; // Create hash table for node attributes @@ -269,7 +270,10 @@ zvmPlugin.prototype.loadServiceInventory = function(data) { */ fieldSet = $('
'); legend = $('Monitoring [Refresh]'); - fieldSet.append(legend); + fieldSet.append(legend); +// var info = createInfoBar('No data available'); +// fieldSet.append(info.css('width', '300px')); + getMonitorMetrics(node); // Refresh monitoring charts on-click @@ -457,6 +461,51 @@ zvmPlugin.prototype.loadServiceInventory = function(data) { dasdTable.append(dasdBody); item.append(dasdTable); } + + /** + * zFCP section + */ + else if (keys[k] == 'zfcp') { + // Create a label - Property name + label = $(''); + item.append(label); + + // Create a table to hold NIC data + var zfcpTable = $('
'); + var zfcpBody = $(''); + + // Table columns - Virtual device, Adapter Type, Port Name, # of Devices, MAC Address, and LAN Name + var zfcpTabRow = $(' Virtual Device # Port Name Unit Number Size'); + zfcpTable.append(zfcpTabRow); + var zfcpVDev, zfcpPortName, zfcpLun, zfcpSize; + + // Loop through each zFCP device + if (attrs[keys[k]]) { + for (l = 0; l < attrs[keys[k]].length; l++) { + if (attrs[keys[k]][l]) { + args = attrs[keys[k]][l].split(' '); + + // Get zFCP virtual device, port name (WWPN), unit number (LUN), and size + zfcpVDev = $('' + args[1].replace('0.0.', '') + ''); + zfcpPortName = $('' + args[4] + ''); + zfcpLun = $('' + args[7] + ''); + zfcpSize = $('' + args[args.length - 2] + ' ' + args[args.length - 1] + ''); + + // Create a new row for each zFCP device + zfcpTabRow = $(''); + zfcpTabRow.append(zfcpVDev); + zfcpTabRow.append(zfcpPortName); + zfcpTabRow.append(zfcpLun); + zfcpTabRow.append(zfcpSize); + + zfcpBody.append(zfcpTabRow); + } + } + } + + zfcpTable.append(zfcpBody); + item.append(zfcpTable); + } /** * NIC section @@ -934,7 +983,7 @@ zvmPlugin.prototype.loadInventory = function(data) { statBar.hide(); // Create array of property keys - var keys = new Array('userId', 'host', 'os', 'arch', 'hcp', 'priv', 'memory', 'proc', 'disk', 'nic'); + var keys = new Array('userId', 'host', 'os', 'arch', 'hcp', 'priv', 'memory', 'proc', 'disk', 'zfcp', 'nic'); // Create hash table for property names var attrNames = new Object(); @@ -947,6 +996,7 @@ zvmPlugin.prototype.loadInventory = function(data) { attrNames['memory'] = 'Total Memory:'; attrNames['proc'] = 'Processors:'; attrNames['disk'] = 'Disks:'; + attrNames['zfcp'] = 'zFCP:'; attrNames['nic'] = 'NICs:'; // Create hash table for node attributes @@ -1143,6 +1193,7 @@ zvmPlugin.prototype.loadInventory = function(data) { // Open dialog to confirm var confirmDialog = $('

Are you sure you want to remove this processor?

'); confirmDialog.dialog({ + title: "Confirm", modal: true, width: 300, buttons: { @@ -1249,6 +1300,7 @@ zvmPlugin.prototype.loadInventory = function(data) { // Open dialog to confirm var confirmDialog = $('

Are you sure you want to remove this disk?

'); confirmDialog.dialog({ + title: "Confirm", modal: true, width: 300, buttons: { @@ -1315,6 +1367,100 @@ zvmPlugin.prototype.loadInventory = function(data) { item.append(dasdTable); } + + /** + * zFCP section + */ + else if (keys[k] == 'zfcp') { + // Create a label - Property name + label = $(''); + item.append(label); + + // Create a table to hold NIC data + var zfcpTable = $('
'); + var zfcpBody = $(''); + var zfcpFooter = $(''); + + /** + * Remove zFCP + */ + contextMenu = [ { + 'Remove' : function(menuItem, menu) { + var addr = $(this).text(); + var portName = $(this).parents('tr').find('td:eq(1)').text(); + var unitNo = $(this).parents('tr').find('td:eq(2)').text(); + + // Open dialog to confirm + var confirmDialog = $('

Are you sure you want to remove this zFCP device?

'); + confirmDialog.dialog({ + title: "Confirm", + modal: true, + width: 300, + buttons: { + "Ok": function(){ + removeZfcp(node, addr, portName, unitNo); + $(this).dialog("close"); + }, + "Cancel": function() { + $(this).dialog("close"); + } + } + }); + } + } ]; + + // Table columns - Virtual device, Adapter Type, Port Name, # of Devices, MAC Address, and LAN Name + var zfcpTabRow = $(' Virtual Device # Port Name Unit Number Size'); + zfcpTable.append(zfcpTabRow); + var zfcpVDev, zfcpPortName, zfcpLun, zfcpSize; + + // Loop through each zFCP device + if (attrs[keys[k]]) { + for (l = 0; l < attrs[keys[k]].length; l++) { + if (attrs[keys[k]][l]) { + args = attrs[keys[k]][l].split(' '); + + // Get zFCP virtual device, port name (WWPN), unit number (LUN), and size + zfcpVDev = $(''); + zfcpLink = $('' + args[1].replace('0.0.', '') + ''); + + // Append context menu to link + zfcpLink.contextMenu(contextMenu, { + theme : 'vista' + }); + zfcpVDev.append(zfcpLink); + + zfcpPortName = $('' + args[4] + ''); + zfcpLun = $('' + args[7] + ''); + zfcpSize = $('' + args[args.length - 2] + ' ' + args[args.length - 1] + ''); + + // Create a new row for each zFCP device + zfcpTabRow = $(''); + zfcpTabRow.append(zfcpVDev); + zfcpTabRow.append(zfcpPortName); + zfcpTabRow.append(zfcpLun); + zfcpTabRow.append(zfcpSize); + + zfcpBody.append(zfcpTabRow); + } + } + } + + zfcpTable.append(zfcpBody); + + /** + * Add zFCP device + */ + var addZfcpLink = $('Add zFCP'); + addZfcpLink.bind('click', function(event) { + var hcp = attrs['hcp'][0].split('.'); + openAddZfcpDialog(node, hcp[0]); + }); + zfcpFooter.append(addZfcpLink); + zfcpTable.append(zfcpFooter); + + item.append(zfcpTable); + } /** * NIC section @@ -1339,6 +1485,7 @@ zvmPlugin.prototype.loadInventory = function(data) { // Open dialog to confirm var confirmDialog = $('

Are you sure you want to remove this NIC?

'); confirmDialog.dialog({ + title: "Confirm", modal: true, width: 300, buttons: { @@ -1381,7 +1528,7 @@ zvmPlugin.prototype.loadInventory = function(data) { args = attrs[keys[k]][l + 1].split(' '); nicLanName = $('' + args[args.length - 2] + ' ' + args[args.length - 1] + ''); - // Create a new row for each DASD + // Create a new row for each NIC nicTabRow = $(''); nicTabRow.append(nicVDev); nicTabRow.append(nicType); diff --git a/xCAT-UI/js/custom/zvmUtils.js b/xCAT-UI/js/custom/zvmUtils.js index 9507bb49e..6d69fc69b 100644 --- a/xCAT-UI/js/custom/zvmUtils.js +++ b/xCAT-UI/js/custom/zvmUtils.js @@ -2,6 +2,7 @@ * Global variables */ var diskDatatable; // zVM datatable containing disks +var zfcpDatatable; // zVM datatable containing zFCP devices var networkDatatable; // zVM datatable containing networks /** @@ -22,6 +23,24 @@ function setDiskDataTable(table) { diskDatatable = table; } +/** + * Get the zFCP datatable + * + * @return Data table object + */ +function getZfcpDataTable() { + return zfcpDatatable; +} + +/** + * Set the zFCP datatable + * + * @param table Data table object + */ +function setZfcpDataTable(table) { + zfcpDatatable = table; +} + /** * Get the network datatable * @@ -73,6 +92,23 @@ function loadHcpInfo(data) { success : setDiskPoolCookies }); } + + // If there is no cookie for the zFCP pool names + if (!$.cookie(hcp + 'zfcppools')) { + // Get disk pools + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'lsvm', + tgt : hcp, + args : '--zfcppoolnames', + msg : hcp + }, + + success : setZfcpPoolCookies + }); + } // If there is no cookie for the network names if (!$.cookie(hcp + 'networks')) { @@ -324,23 +360,17 @@ function incrementNodeProcess(node) { * @param data Data returned from HTTP request */ function updateZProvisionNewStatus(data) { - // Get ajax response + // Parse ajax response var rsp = data.rsp; var args = data.msg.split(';'); - - // Get command invoked var cmd = args[0].replace('cmd=', ''); - // Get output ID var out2Id = args[1].replace('out=', ''); - // Get status bar ID + // IDs for status bar, tab, and loader var statBarId = 'zProvisionStatBar' + out2Id; - // Get provision tab ID var tabId = 'zvmProvisionTab' + out2Id; - // Get loader ID var loaderId = 'zProvisionLoader' + out2Id; - // Get node name var node = $('#' + tabId + ' input[name=nodeName]').val(); /** @@ -403,11 +433,9 @@ function updateZProvisionNewStatus(data) { // Write ajax response to status bar var prg = writeRsp(rsp, ''); $('#' + statBarId).find('div').append(prg); - - // Get user entry - var userEntry = $('#' + tabId + ' textarea').val(); // Create user entry + var userEntry = $('#' + tabId + ' textarea').val(); $.ajax( { url : 'lib/zCmd.php', dataType : 'json', @@ -431,20 +459,16 @@ function updateZProvisionNewStatus(data) { var prg = writeRsp(rsp, ''); $('#' + statBarId).find('div').append(prg); - // If there was an error, do not continue + // If there was an error, try again if (prg.html().indexOf('Error') > -1) { - // Try again var tries = parseInt($.cookie('tries4' + tabId)); if (tries < 2) { $('#' + statBarId).find('div').append('
Trying again...
'); - tries = tries + 1; - - // One more try + tries++; $.cookie('tries4' + tabId, tries); - // Get user entry - var userEntry = $('#' + tabId + ' textarea').val(); // Create user entry + var userEntry = $('#' + tabId + ' textarea').val(); $.ajax( { url : 'lib/zCmd.php', dataType : 'json', @@ -466,17 +490,16 @@ function updateZProvisionNewStatus(data) { $.cookie('tries4' + tabId, 0); // Set cookie for number of disks - var diskRows = $('#' + tabId + ' table:visible tbody tr'); + var diskRows = $('#' + tabId + ' table:eq(0):visible tbody tr'); $.cookie('disks2add' + out2Id, diskRows.length); if (diskRows.length > 0) { for ( var i = 0; i < diskRows.length; i++) { - // Get disk type, address, size, mode, pool, and password var diskArgs = diskRows.eq(i).find('td'); var type = diskArgs.eq(1).find('select').val(); var address = diskArgs.eq(2).find('input').val(); var size = diskArgs.eq(3).find('input').val(); var mode = diskArgs.eq(4).find('select').val(); - var pool = diskArgs.eq(5).find('input').val(); + var pool = diskArgs.eq(5).find('select').val(); var password = diskArgs.eq(6).find('input').val(); // Create ajax arguments @@ -492,7 +515,7 @@ function updateZProvisionNewStatus(data) { + password + ';' + password; } - // Add disk + // Attach disk to node $.ajax( { url : 'lib/cmd.php', dataType : 'json', @@ -500,7 +523,7 @@ function updateZProvisionNewStatus(data) { cmd : 'chvm', tgt : node, args : args, - msg : 'cmd=chvm;out=' + out2Id + msg : 'cmd=chvm-disk;out=' + out2Id }, success : updateZProvisionNewStatus @@ -511,26 +534,23 @@ function updateZProvisionNewStatus(data) { } } } - + /** - * (6) Set operating system for given node + * (6) Add zFCP devices */ - else if (cmd == 'chvm') { + else if (cmd == 'chvm-disk') { // Write ajax response to status bar var prg = writeRsp(rsp, ''); $('#' + statBarId).find('div').append(prg); - // If there was an error, do not continue + // If there was an error, try again if (prg.html().indexOf('Error') > -1) { - $('#' + loaderId).hide(); + $('#' + loaderId).hide(); - // Try again var tries = parseInt($.cookie('tries4' + tabId)); if (tries < 2) { $('#' + statBarId).find('div').append('
Trying again...
'); - tries = tries + 1; - - // One more try + tries++; $.cookie('tries4' + tabId, tries); // Set cookie for number of disks @@ -538,13 +558,12 @@ function updateZProvisionNewStatus(data) { $.cookie('disks2add' + out2Id, diskRows.length); if (diskRows.length > 0) { for ( var i = 0; i < diskRows.length; i++) { - // Get disk type, address, size, pool, and password var diskArgs = diskRows.eq(i).find('td'); var type = diskArgs.eq(1).find('select').val(); var address = diskArgs.eq(2).find('input').val(); var size = diskArgs.eq(3).find('input').val(); var mode = diskArgs.eq(4).find('select').val(); - var pool = diskArgs.eq(5).find('input').val(); + var pool = diskArgs.eq(5).find('select').val(); var password = diskArgs.eq(6).find('input').val(); // Create ajax arguments @@ -560,7 +579,7 @@ function updateZProvisionNewStatus(data) { + password + ';' + password; } - // Add disk + // Attach disk to node $.ajax( { url : 'lib/cmd.php', dataType : 'json', @@ -568,7 +587,7 @@ function updateZProvisionNewStatus(data) { cmd : 'chvm', tgt : node, args : args, - msg : 'cmd=chvm;out=' + out2Id + msg : 'cmd=chvm-disk;out=' + out2Id }, success : updateZProvisionNewStatus @@ -584,50 +603,163 @@ function updateZProvisionNewStatus(data) { // Reset number of tries $.cookie('tries4' + tabId, 0); - // Get operating system image - var osImage = $('#' + tabId + ' input[name=os]:visible').val(); - - // Get cookie for number of disks - var disks2add = $.cookie('disks2add' + out2Id); - // One less disk to add - disks2add = disks2add - 1; // Set cookie for number of disks + // One less disk to add + var disks2add = $.cookie('disks2add' + out2Id); + disks2add--; $.cookie('disks2add' + out2Id, disks2add); + + if (disks2add < 1) { + // Set cookie for number of zFCP devices + var zfcpRows = $('#' + tabId + ' table:eq(1):visible tbody tr'); + $.cookie('zfcp2add' + out2Id, zfcpRows.length); + if (zfcpRows.length > 0) { + for ( var i = 0; i < zfcpRows.length; i++) { + var diskArgs = zfcpRows.eq(i).find('td'); + var address = diskArgs.eq(1).find('input').val(); + var size = diskArgs.eq(2).find('input').val(); + var pool = diskArgs.eq(3).find('select').val(); + var tag = diskArgs.eq(4).find('input').val(); + var portName = diskArgs.eq(5).find('input').val(); + var unitNo = diskArgs.eq(6).find('input').val(); + + // Create ajax arguments + var args = '--addzfcp;' + pool + ';' + address + ';' + size; + if (tag && tag != "null") { + args += ';' + tag; + } if (portName && tag != "null") { + args += ';' + portName; + } if (unitNo && tag != "null") { + args += ';' + unitNo; + } + + // Attach zFCP device to node + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'chvm', + tgt : node, + args : args, + msg : 'cmd=chvm-zfcp;out=' + out2Id + }, + + success : updateZProvisionNewStatus + }); + } + } else { + $('#' + loaderId).hide(); + } + } + } + } + + /** + * (7) Set operating system for given node + */ + else if (cmd == 'chvm-zfcp') { + // Write ajax response to status bar + var prg = writeRsp(rsp, ''); + $('#' + statBarId).find('div').append(prg); - // If an operating system image is given - if (osImage) { - var tmp = osImage.split('-'); + // If there was an error, try again + if (prg.html().indexOf('Error') > -1) { + $('#' + loaderId).hide(); - // Get operating system, architecture, provision method, and profile - var os = tmp[0]; - var arch = tmp[1]; - var profile = tmp[3]; + var tries = parseInt($.cookie('tries4' + tabId)); + if (tries < 2) { + $('#' + statBarId).find('div').append('
Trying again...
'); + tries++; + $.cookie('tries4' + tabId, tries); - // If the last disk is added - if (disks2add < 1) { - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'nodeadd', - tgt : '', - args : node + ';noderes.netboot=zvm;nodetype.os=' - + os + ';nodetype.arch=' + arch - + ';nodetype.profile=' + profile, - msg : 'cmd=noderes;out=' + out2Id - }, + var zfcpRows = $('#' + tabId + ' table:eq(1):visible tbody tr'); + $.cookie('zfcp2add' + out2Id, zfcpRows.length); + if (zfcpRows.length > 0) { + for ( var i = 0; i < zfcpRows.length; i++) { + var diskArgs = zfcpRows.eq(i).find('td'); + var address = diskArgs.eq(1).find('input').val(); + var size = diskArgs.eq(2).find('input').val(); + var pool = diskArgs.eq(3).find('select').val(); + var tag = diskArgs.eq(4).find('input').val(); + var portName = diskArgs.eq(5).find('input').val(); + var unitNo = diskArgs.eq(6).find('input').val(); + + // Create ajax arguments + var args = '--addzfcp;' + pool + ';' + address + ';' + size; + if (tag && tag != "null") { + args += ';' + tag; + } if (portName && tag != "null") { + args += ';' + portName; + } if (unitNo && tag != "null") { + args += ';' + unitNo; + } - success : updateZProvisionNewStatus - }); + // Attach zFCP device to node + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'chvm', + tgt : node, + args : args, + msg : 'cmd=chvm-zfcp;out=' + out2Id + }, + + success : updateZProvisionNewStatus + }); + } + } else { + $('#' + loaderId).hide(); } } else { $('#' + loaderId).hide(); } + } else { + // Reset number of tries + $.cookie('tries4' + tabId, 0); + + // Set cookie for number of disks + // One less disk to add + var zfcp2add = $.cookie('zfcp2add' + out2Id); + zfcp2add--; + $.cookie('zfcp2add' + out2Id, zfcp2add); + + if (zfcp2add < 1) { + // If an operating system image is given + var osImage = $('#' + tabId + ' input[name=os]:visible').val(); + if (osImage) { + // Get operating system, architecture, provision method, and profile + var tmp = osImage.split('-'); + var os = tmp[0]; + var arch = tmp[1]; + var profile = tmp[3]; + + // If the last disk is added + if (disks2add < 1) { + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'nodeadd', + tgt : '', + args : node + ';noderes.netboot=zvm;nodetype.os=' + + os + ';nodetype.arch=' + arch + + ';nodetype.profile=' + profile, + msg : 'cmd=noderes;out=' + out2Id + }, + + success : updateZProvisionNewStatus + }); + } + } else { + $('#' + loaderId).hide(); + } + } } } /** - * (7) Update DHCP + * (8) Update DHCP */ else if (cmd == 'noderes') { // If there was an error, do not continue @@ -652,7 +784,7 @@ function updateZProvisionNewStatus(data) { } /** - * (8) Prepare node for boot + * (9) Prepare node for boot */ else if (cmd == 'makedhcp') { // Prepare node for boot @@ -671,7 +803,7 @@ function updateZProvisionNewStatus(data) { } /** - * (9) Boot node to network + * (10) Boot node to network */ else if (cmd == 'nodeset') { // Write ajax response to status bar @@ -699,7 +831,7 @@ function updateZProvisionNewStatus(data) { } /** - * (10) Done + * (11) Done */ else if (cmd == 'rnetboot') { // Write ajax response to status bar @@ -1047,6 +1179,42 @@ function getZResources(data) { success : getDiskPool }); } + }); + + // Create accordion panel for zFCP devices + var zfcpSection = $('
'); + var zfcpLnk = $('

zFCP

').click(function () { + // Do not load panel again if it is already loaded + if ($('#zfcpResource').children().length) + return; + else + $('#zfcpResource').append(createLoader('')); + + // Resize accordion + $('#zvmResourceAccordion').accordion('resize'); + + // Create a array for hardware control points + var hcps = new Array(); + if ($.cookie('hcp').indexOf(',') > -1) + hcps = $.cookie('hcp').split(','); + else + hcps.push($.cookie('hcp')); + + for ( var i in hcps) { + // Gather networks from hardware control points + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'lsvm', + tgt : hcps[i], + args : '--zfcppoolnames', + msg : hcps[i] + }, + + success : getZfcpPool + }); + } }); // Create accordion panel for network @@ -1085,7 +1253,7 @@ function getZResources(data) { } }); - resourcesAccordion.append(diskLnk, diskSection, networkLnk, networkSection); + resourcesAccordion.append(diskLnk, diskSection, zfcpLnk, zfcpSection, networkLnk, networkSection); // Append accordion to tab $('#' + tabId).append(resourcesAccordion); @@ -1366,6 +1534,124 @@ function openAddDiskDialog(node, hcp) { }); } +/** + * Create add zFCP device dialog + * + * @param node Node to add disk to + * @param hcp Hardware control point of node + */ +function openAddZfcpDialog(node, hcp) { + // Get list of disk pools + var cookie = $.cookie(hcp + 'zfcppools'); + var pools = cookie.split(','); + + // Create form to add disk + var addZfcpForm = $('
'); + // Create info bar + var info = createInfoBar('Add a SCSI|FCP disk to this virtual server.'); + addZfcpForm.append(info); + addZfcpForm.append('
'); + addZfcpForm.append('
'); + addZfcpForm.append('
'); + + // Create drop down for disk pool + var diskPool = $('
'); + diskPool.append(''); + var poolSelect = $(''); + for ( var i = 0; i < pools.length; i++) { + poolSelect.append(''); + } + diskPool.append(poolSelect); + addZfcpForm.append(diskPool); + + // Tag to identify where device will be used + addZfcpForm.append('
'); + + // Create advanced link to set advanced zFCP properties + var advancedLnk = $('
'); + addZfcpForm.append(advancedLnk); + var advanced = $('
').hide(); + addZfcpForm.append(advanced); + + var portName = $('
'); + var unitNo = $('
'); + advanced.append(portName, unitNo); + + // Toggle port name and unit number when clicking on advanced link + advancedLnk.click(function() { + advanced.toggle(); + }); + + // Open dialog to add disk + addZfcpForm.dialog({ + title:'Add zFCP device', + modal: true, + close: function(){ + $(this).remove(); + }, + width: 400, + buttons: { + "Ok": function(){ + // Remove any warning messages + $(this).find('.ui-state-error').remove(); + + // Get inputs + var node = $(this).find('input[name=diskNode]').val(); + var address = $(this).find('input[name=diskAddress]').val(); + var size = $(this).find('input[name=diskSize]').val(); + var pool = $(this).find('select[name=diskPool]').val(); + var tag = $(this).find('select[name=diskTag]').val(); + var portName = $(this).find('select[name=diskPortName]').val(); + var unitNo = $(this).find('select[name=diskUnitNo]').val(); + + // If inputs are not complete, show warning message + if (!node || !address || !size || !pool) { + var warn = createWarnBar('Please provide a value for each missing field.'); + warn.prependTo($(this)); + } else { + var args = '--addzfcp;' + pool + ';' + address + ';' + size; + if (tag && tag != "null") { + args += ';' + tag; + } if (portName && tag != "null") { + args += ';' + portName; + } if (unitNo && tag != "null") { + args += ';' + unitNo; + } + + // Add zFCP device + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'chvm', + tgt : node, + args : args, + msg : node + }, + + success : updateZNodeStatus + }); + + // Increment node process + incrementNodeProcess(node); + + // Show loader + var statusId = node + 'StatusBar'; + var statusBarLoaderId = node + 'StatusBarLoader'; + $('#' + statusBarLoaderId).show(); + $('#' + statusId).show(); + + // Close dialog + $(this).dialog( "close" ); + } // End of else + }, + "Cancel": function() { + $(this).dialog( "close" ); + } + } + }); +} + /** * Create add NIC dialog * @@ -1667,6 +1953,36 @@ function removeDisk(node, address) { $('#' + node + 'StatusBar').show(); } +/** + * Remove zFCP device + * + * @param node Node where disk is attached + * @param address Virtual address of zFCP device + * @param wwpn World wide port name of zFCP device + * @param lun Logical unit number of zFCP device + */ +function removeZfcp(node, address, wwpn, lun) { + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'chvm', + tgt : node, + args : '--removezfcp;' + address + ';' + wwpn + ';' + lun, + msg : node + }, + + success : updateZNodeStatus + }); + + // Increment node process + incrementNodeProcess(node); + + // Show loader + $('#' + node + 'StatusBarLoader').show(); + $('#' + node + 'StatusBar').show(); +} + /** * Remove NIC * @@ -1762,6 +2078,39 @@ function getDiskPool(data) { } } +/** + * Get contents of each zFCP pool + * + * @param data HTTP request data + */ +function getZfcpPool(data) { + if (data.rsp) { + var hcp = data.msg; + var pools = data.rsp[0].split(hcp + ': '); + + // Get contents of each disk pool + for ( var i in pools) { + if (pools[i]) { + pools[i] = jQuery.trim(pools[i]); + + // Query used and free space + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'lsvm', + tgt : hcp, + args : '--zfcppool;' + pools[i] + ';all', + msg : 'hcp=' + hcp + ';pool=' + pools[i] + }, + + success : loadZfcpPoolTable + }); + } // End of if + } // End of for + } +} + /** * Get details of each network * @@ -1827,7 +2176,7 @@ function loadDiskPoolTable(data) { // Create a datatable var table = new DataTable(tableId); // Resource headers: volume ID, device type, start address, and size - table.init( [ '', 'HCP', 'Pool', 'Status', 'Region', 'Device type', 'Starting address', 'Size' ]); + table.init( [ '', 'zHCP', 'Pool', 'Status', 'Region', 'Device type', 'Starting address', 'Size' ]); // Append datatable to panel $('#' + panelId).append(table.object()); @@ -1923,13 +2272,142 @@ function loadDiskPoolTable(data) { $('#zvmResourceAccordion').accordion('resize'); } +/** + * Load zFCP pool contents into a table + * + * @param data HTTP request data + */ +function loadZfcpPoolTable(data) { + // Delete loader + var panelId = 'zfcpResource'; + $('#' + panelId).find('img[src="images/loader.gif"]').remove(); + + var args = data.msg.split(';'); + var hcp = args[0].replace('hcp=', ''); + var pool = args[1].replace('pool=', ''); + var tmp = data.rsp[0].split(hcp + ': '); + + // Resource tab ID + var info = $('#' + panelId).find('.ui-state-highlight'); + // If there is no info bar, create info bar + if (!info.length) { + info = createInfoBar('Below are devices that are defined internally in the zFCP pools.'); + $('#' + panelId).append(info); + } + + // Get datatable + var tableId = 'zFcpDataTable'; + var dTable = getZfcpDataTable(); + if (!dTable) { + // Create a datatable + var table = new DataTable(tableId); + // Resource headers: status, WWPN, LUN, size, owner, channel, tag + table.init( [ '', 'zHCP', 'Pool', 'Status', 'Port name', 'Unit number', 'Size', 'Owner', 'Channel', 'Tag' ]); + + // Append datatable to panel + $('#' + panelId).append(table.object()); + + // Turn into datatable + dTable = $('#' + tableId).dataTable({ + "sScrollX": "100%", + "bAutoWidth": true + }); + setZfcpDataTable(dTable); + } + + // Skip index 0 and 1 because it contains nothing + for ( var i = 2; i < tmp.length; i++) { + tmp[i] = jQuery.trim(tmp[i]); + var diskAttrs = tmp[i].split(','); + dTable.fnAddData( [ '', hcp, pool, diskAttrs[0], diskAttrs[1], diskAttrs[2], diskAttrs[3], diskAttrs[4], diskAttrs[5], diskAttrs[6] ]); + } + + // Create actions menu + if (!$('#zFcpResourceActions').length) { + // Empty filter area + $('#' + tableId + '_length').empty(); + + // Add disk to pool + var addLnk = $('Add'); + addLnk.bind('click', function(event){ + openAddZfcp2PoolDialog(); + }); + + // Delete disk from pool + var removeLnk = $('Remove'); + removeLnk.bind('click', function(event){ + var disks = getNodesChecked(tableId); + openRemoveZfcpFromPoolDialog(disks); + }); + + // Refresh table + var refreshLnk = $('Refresh'); + refreshLnk.bind('click', function(event){ + $('#zfcpResource').empty().append(createLoader('')); + setZfcpDataTable(''); + + // Create a array for hardware control points + var hcps = new Array(); + if ($.cookie('hcp').indexOf(',') > -1) + hcps = $.cookie('hcp').split(','); + else + hcps.push($.cookie('hcp')); + + // Query the disk pools for each + for (var i in hcps) { + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'lsvm', + tgt : hcps[i], + args : '--zfcppoolnames', + msg : hcps[i] + }, + + success : getZfcpPool + }); + } + }); + + // Create action bar + var actionBar = $('
'); + + // Create an action menu + var actionsMenu = createMenu([addLnk, removeLnk, refreshLnk]); + actionsMenu.superfish(); + actionsMenu.css('display', 'inline-block'); + actionBar.append(actionsMenu); + + // Set correct theme for action menu + actionsMenu.find('li').hover(function() { + setMenu2Theme($(this)); + }, function() { + setMenu2Normal($(this)); + }); + + // Create a division to hold actions menu + var menuDiv = $(''); + $('#' + tableId + '_length').prepend(menuDiv); + $('#' + tableId + '_length').css({ + 'padding': '0px', + 'width': '500px' + }); + $('#' + tableId + '_filter').css('padding', '10px'); + menuDiv.append(actionBar); + } + + // Resize accordion + $('#zvmResourceAccordion').accordion('resize'); +} + /** * Open dialog to remove disk from pool * * @param disks2remove Disks selected in table */ function openRemoveDiskFromPoolDialog(disks2remove) { - // Create form to delete disk to pool + // Create form to delete disk from pool var dialogId = 'zvmDeleteDiskFromPool'; var deleteDiskForm = $('
'); @@ -2142,6 +2620,203 @@ function openAddDisk2PoolDialog() { }); } +/** + * Open dialog to remove zFCP from pool + * + * @param devices2remove Comman separated devices selected in table + */ +function openRemoveZfcpFromPoolDialog(devices2remove) { + // Create form to delete device from pool + var dialogId = 'zvmDeleteZfcpFromPool'; + var deleteDiskForm = $('
'); + + // Verify disks are in the same zFCP pool + var devices = devices2remove.split(','); + var tmp, tgtPool; + var tgtUnitNo = ""; + for (var i in devices) { + tmp = devices[i].split('-'); + + if (tgtPool && tmp[0] != tgtPool) { + openDialog("warn", "Please select devices in the same zFCP"); + return; + } else { + tgtPool = tmp[0]; + } + + tgtUnitNo += tmp[1] + ","; + } + + // Strip out last comma + tgtUnitNo = tgtUnitNo.slice(0, -1); + + // Create info bar + var info = createInfoBar('Remove a zFCP device that is defined in a zFCP pool.'); + deleteDiskForm.append(info); + + var hcp = $('
'); + var hcpSelect = $(''); + hcp.append(hcpSelect); + + var pool = $('
'); + var unitNo = $('
'); + deleteDiskForm.append(hcp, pool, unitNo); + + // Create a array for hardware control points + var hcps = new Array(); + if ($.cookie('hcp').indexOf(',') > -1) { + hcps = $.cookie('hcp').split(','); + } else { + hcps.push($.cookie('hcp')); + } + + // Append options for hardware control points + for (var i in hcps) { + hcpSelect.append($('')); + } + + // Open dialog to delete device + deleteDiskForm.dialog({ + title:'Delete device from pool', + modal: true, + close: function(){ + $(this).remove(); + }, + width: 500, + buttons: { + "Ok": function(){ + // Remove any warning messages + $(this).find('.ui-state-error').remove(); + + var hcp = $(this).find('select[name=hcp]').val(); + var pool = $(this).find('input[name=zfcpPool]').val(); + var unitNo = $(this).find('input[name=unitNo]').val(); + + // If inputs are not complete, show warning message + if (!hcp || !pool || !unitNo) { + var warn = createWarnBar('Please provide a value for each missing field.'); + warn.prependTo($(this)); + } else { + // Change dialog buttons + $(this).dialog('option', 'buttons', { + 'Close': function() {$(this).dialog("close");} + }); + + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'chvm', + tgt : hcp, + args : '--removezfcpfrompool;' + pool + ';' + unitNo, + msg : dialogId + }, + + success : updateResourceDialog + }); + } + }, + "Cancel": function() { + $(this).dialog( "close" ); + } + } + }); +} + +/** + * Open dialog to add zFCP to pool + */ +function openAddZfcp2PoolDialog() { + // Create form to add disk to pool + var dialogId = 'zvmAddDisk2Pool'; + var addDiskForm = $('
'); + var info = createInfoBar('Add a device to a zFCP pool defined in xCAT.'); + addDiskForm.append(info); + + var hcp = $('
'); + var hcpSelect = $(''); + hcp.append(hcpSelect); + + var pool = $('
'); + var status = $('
'); + var portName = $('
'); + var unitNo = $('
'); + var size = $('
'); + var owner = $('
'); + addDiskForm.append(hcp, pool, status, portName, unitNo, size, owner); + + // Create a array for hardware control points + var hcps = new Array(); + if ($.cookie('hcp').indexOf(',') > -1) { + hcps = $.cookie('hcp').split(','); + } else { + hcps.push($.cookie('hcp')); + } + + for (var i in hcps) { + hcpSelect.append($('')); + } + + // Open dialog to add disk + addDiskForm.dialog({ + title:'Add device to pool', + modal: true, + close: function(){ + $(this).remove(); + }, + width: 500, + buttons: { + "Ok": function(){ + // Delete any warning messages + $(this).find('.ui-state-error').remove(); + + var tgtHcp = $(this).find('select[name=hcp]').val(); + var tgtPool = $(this).find('input[name=zfcpPool]').val(); + var tgtStatus = $(this).find('select[name=zfcpStatus]').val(); + var tgtPortName = $(this).find('input[name=zfcpPortName]').val(); + var tgtUnitNo = $(this).find('input[name=zfcpUnitNo]').val(); + var tgtSize = $(this).find('input[name=zfcpSize]').val(); + + // Device owner is optional + var tgtOwner = ""; + if ($(this).find('input[name=zfcpOwner]').val()) { + tgtOwner = $(this).find('input[name=zfcpOwner]').val(); + } + + // If inputs are not complete, show warning message + if (!tgtHcp || !tgtPool || !tgtStatus || !tgtPortName || !tgtUnitNo || !tgtSize) { + var warn = createWarnBar('Please provide a value for each missing field.'); + warn.prependTo($(this)); + } else { + // Change dialog buttons + $(this).dialog('option', 'buttons', { + 'Close': function() {$(this).dialog("close");} + }); + + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'chvm', + tgt : tgtHcp, + args : '--addzfcp2pool;' + tgtPool + ';' + tgtStatus + ';' + tgtPortName + ';' + tgtUnitNo + ';' + tgtSize + ';' + tgtOwner, + msg : dialogId + }, + + success : updateResourceDialog + }); + } + }, + "Cancel": function() { + $(this).dialog( "close" ); + } + } + }); +} + /** * Update resource dialog * @@ -2192,11 +2867,17 @@ function updateResourceDialog(data) { * @param obj Object triggering event */ function selectAllDisk(event, obj) { - // Get datatable ID // This will ascend from var tableObj = obj.parents('.datatable'); var status = obj.attr('checked'); tableObj.find(' :checkbox').attr('checked', status); + + // Handle datatable scroll + tableObj = obj.parents('.dataTables_scroll'); + if (tableObj.length) { + tableObj.find(' :checkbox').attr('checked', status); + } + event.stopPropagation(); } @@ -2621,6 +3302,22 @@ function createZProvisionNew(inst) { success : setDiskPoolCookies }); } + + if (!$.cookie(args[0] + 'zfcppools')) { + // Get zFCP pools + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'lsvm', + tgt : args[0], + args : '--zfcppoolnames', + msg : args[0] + }, + + success : setZfcpPoolCookies + }); + } } }); hcpDiv.append(hcpLabel); @@ -2745,12 +3442,22 @@ function createZProvisionNew(inst) { }); var diskBody = $(''); var diskFooter = $(''); - + /** * Add disks */ var addDiskLink = $('Add disk'); addDiskLink.bind('click', function(event) { + // Get list of disk pools + var thisTabId = $(this).parents('.tab').attr('id'); + var thisHcp = $('#' + thisTabId + ' input[name=hcp]').val(); + var definedPools = null; + if (thisHcp) { + // Get node without domain name + var temp = thisHcp.split('.'); + definedPools = $.cookie(temp[0] + 'diskpools').split(','); + } + // Create a row var diskRow = $(''); @@ -2792,23 +3499,14 @@ function createZProvisionNew(inst) { ); diskMode.append(diskModeSelect); diskRow.append(diskMode); - - // Get list of disk pools - var thisTabId = $(this).parents('.tab').attr('id'); - var thisHcp = $('#' + thisTabId + ' input[name=hcp]').val(); - var definedPools = null; - if (thisHcp) { - // Get node without domain name - var temp = thisHcp.split('.'); - definedPools = $.cookie(temp[0] + 'diskpools'); + + // Create disk pool drop down + var diskPool = $(''); + var diskPoolSelect = $(''); + for (var i in definedPools) { + diskPoolSelect.append(''); } - - // Create disk pool input - // Turn on auto complete for disk pool - var diskPoolInput = $('').autocomplete({ - source: definedPools.split(',') - }); - var diskPool = $('').append(diskPoolInput); + diskPool.append(diskPoolSelect); diskRow.append(diskPool); // Create disk password input @@ -2843,6 +3541,103 @@ function createZProvisionNew(inst) { diskDiv.append(diskTable); hwAttr.append(diskDiv); + // Create zFCP table + var zfcpDiv = $('
'); + var zfcpLabel = $(''); + var zfcpTable = $('
'); + var zfcpHeader = $(' Address Size Pool Tag Port Name Unit #'); + // Adjust header width + zfcpHeader.find('th').css( { + 'width' : '80px' + }); + zfcpHeader.find('th').eq(0).css( { + 'width' : '20px' + }); + var zfcpBody = $(''); + var zfcpFooter = $(''); + + /** + * Add zFCP devices + */ + var addZfcpLink = $('Add zFCP'); + addZfcpLink.bind('click', function(event) { + // Get list of disk pools + var thisTabId = $(this).parents('.tab').attr('id'); + var thisHcp = $('#' + thisTabId + ' input[name=hcp]').val(); + var definedPools = null; + if (thisHcp) { + // Get node without domain name + var temp = thisHcp.split('.'); + definedPools = $.cookie(temp[0] + 'zfcppools').split(','); + } + + // Create a row + var zfcpRow = $(''); + + // Add remove button + var removeBtn = $(''); + var col = $('').append(removeBtn); + removeBtn.bind('click', function(event) { + zfcpRow.remove(); + }); + zfcpRow.append(col); + + // Create disk address input + var zfcpAddr = $(''); + zfcpRow.append(zfcpAddr); + + // Create disk size input + var zfcpSize = $(''); + zfcpRow.append(zfcpSize); + + // Create zFCP pool drop down + var zfcpPool = $(''); + var zfcpPoolSelect = $(''); + for (var i in definedPools) { + zfcpPoolSelect.append(''); + } + zfcpPool.append(zfcpPoolSelect); + zfcpRow.append(zfcpPool); + + // Create disk tag + var zfcpTag = $(''); + zfcpRow.append(zfcpTag); + + // Create device port name + var zfcpPortName = $(''); + zfcpRow.append(zfcpPortName); + + // Create device unit number + var zfcpUnitNo = $(''); + zfcpRow.append(zfcpUnitNo); + + zfcpBody.append(zfcpRow); + + // Generate tooltips + zfcpBody.find('td input[title]').tooltip({ + position: "top right", + offset: [-4, 4], + effect: "fade", + opacity: 0.7, + predelay: 800, + events: { + def: "mouseover,mouseout", + input: "mouseover,mouseout", + widget: "focus mouseover,blur mouseout", + tooltip: "mouseover,mouseout" + } + }); + }); + + zfcpFooter.append(addZfcpLink); + zfcpTable.append(zfcpHeader); + zfcpTable.append(zfcpBody); + zfcpTable.append(zfcpFooter); + + zfcpDiv.append(zfcpLabel); + zfcpDiv.append(zfcpTable); + hwAttr.append(zfcpDiv); + // Generate tooltips provNew.find('div input[title]').tooltip({ position: "center right", @@ -2875,12 +3670,16 @@ function createZProvisionNew(inst) { var inst = thisTabId.replace('zvmProvisionTab', ''); // Check node name, userId, hardware control point, and group + // Check disks and zFCP devices var inputs = $('#' + thisTabId + ' input:visible'); for ( var i = 0; i < inputs.length; i++) { // Do not check OS or disk password if (!inputs.eq(i).val() && inputs.eq(i).attr('name') != 'os' - && inputs.eq(i).attr('type') != 'password') { + && inputs.eq(i).attr('type') != 'password' + && inputs.eq(i).attr('name') != 'zfcpTag' + && inputs.eq(i).attr('name') != 'zfcpPortName' + && inputs.eq(i).attr('name') != 'zfcpUnitNo') { inputs.eq(i).css('border', 'solid #FF0000 1px'); ready = false; } else { @@ -2921,18 +3720,6 @@ function createZProvisionNew(inst) { errMsg = errMsg + 'You need to add at some disks.
'; ready = false; } - - // Check address, size, mode, pool, and password - var diskArgs = $('#' + thisTabId + ' table input:visible'); - for ( var i = 0; i < diskArgs.length; i++) { - if (!diskArgs.eq(i).val() - && diskArgs.eq(i).attr('type') != 'password') { - diskArgs.eq(i).css('border', 'solid #FF0000 1px'); - ready = false; - } else { - diskArgs.eq(i).css('border', 'solid #BDBDBD 1px'); - } - } // If inputs are valid, ready to provision if (ready) { @@ -3266,7 +4053,7 @@ function setzVMCookies(data) { } /** - * Set a cookie for disk pool names of a given node (service page) + * Set a cookie for disk pool names of a given node * * @param data Data from HTTP request */ @@ -3285,6 +4072,26 @@ function setDiskPoolCookies(data) { } } +/** + * Set a cookie for zFCP pool names of a given node + * + * @param data Data from HTTP request + */ +function setZfcpPoolCookies(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 + 'zfcppools', pools, { expires: exDate }); + } +} + /** * Create virtual machine (service page) * diff --git a/xCAT-server/lib/xcat/plugins/zvm.pm b/xCAT-server/lib/xcat/plugins/zvm.pm index 94de1de64..b97667d6b 100644 --- a/xCAT-server/lib/xcat/plugins/zvm.pm +++ b/xCAT-server/lib/xcat/plugins/zvm.pm @@ -535,6 +535,27 @@ sub removeVM { # Delete user entry $out = `ssh $hcp "$::DIR/smcli Image_Delete_DM -T $userId -e 1"`; xCAT::zvmUtils->printLn( $callback, "$node: $out" ); + + # Go through each pool and free zFCP devices belonging to node + my @pools = split("\n", `ssh $hcp "ls $::ZFCPPOOL"`); + my $pool; + my @luns; + my $update; + my $expression; + foreach (@pools) { + $pool = xCAT::zvmUtils->replaceStr( $_, ".conf", "" ); + + @luns = split("\n", `ssh $hcp "cat $::ZFCPPOOL/$_" | egrep -i $node`); + foreach (@luns) { + # Update entry: status,wwpn,lun,size,owner,channel,tag + my @info = split(',', $_); + $update = "free,$info[1],$info[2],$info[3],,,"; + $expression = "'s#" . $_ . "#" .$update . "#i'"; + $out = `ssh $hcp "sed --in-place -e $expression $::ZFCPPOOL/$pool.conf"`; + } + + xCAT::zvmUtils->printLn($callback, "$node: Updating FCP device pool $pool... Done"); + } # Check for errors my $rc = xCAT::zvmUtils->checkOutput( $callback, $out ); @@ -708,7 +729,7 @@ sub changeVM { } } - # addzfcp2pool [pool] [status] [wwpn] [lun] [size] [owner] + # addzfcp2pool [pool] [status] [wwpn] [lun] [size] [owner (optional)] elsif ( $args->[0] eq "--addzfcp2pool" ) { # zFCP disk pool located on zHCP at /var/opt/zhcp/zfcp/{pool}.conf # Entries contain: status,wwpn,lun,size,owner,channel,tag @@ -751,6 +772,7 @@ sub changeVM { if (!(`ssh $hcp "test -e $::ZFCPPOOL/$pool.conf && echo Exists"`)) { # Create pool configuration file $out = `ssh $hcp "echo '#status,wwpn,lun,size,owner,channel,tag' > $::ZFCPPOOL/$pool.conf"`; + xCAT::zvmUtils->printLn( $callback, "$node: New zFCP device pool $pool created" ); } # Do not update if the LUN already exists @@ -761,6 +783,7 @@ sub changeVM { # Update file with given WWPN, LUN, size, and owner $out = `ssh $hcp "echo \"$status,$wwpn,$lun,$size,$owner,,\" >> $::ZFCPPOOL/$pool.conf"`; + xCAT::zvmUtils->printLn( $callback, "$node: Adding zFCP device to $pool pool... Done" ); } # addnic [address] [type] [device count] @@ -908,7 +931,7 @@ sub changeVM { $sizeFound = $info[3]; $wwpn = $info[1]; $lun = $info[2]; - } elsif ($info[3] >= $size) { + } elsif (!$sizeFound && $info[3] >= $size) { $sizeFound = $info[3]; $wwpn = $info[1]; $lun = $info[2]; @@ -1453,23 +1476,34 @@ sub changeVM { return; } - # Make sure WWPN and LUN do not have 0x prefix - $lun = xCAT::zvmUtils->replaceStr($lun, "0x", ""); + my @luns; + if ($lun =~ m/,/i) { + @luns = split( ',', $lun ); + } else { + push(@luns, $lun); + } # Find disk pool (create one if non-existent) if (!(`ssh $hcp "test -e $::ZFCPPOOL/$pool.conf && echo Exists"`)) { xCAT::zvmUtils->printLn( $callback, "$node: (Error) zFCP pool does not exist" ); return; } - - # Do not update if LUN does not exists - if (!(`ssh $hcp "cat $::ZFCPPOOL/$pool.conf" | grep $lun`)) { - xCAT::zvmUtils->printLn( $callback, "$node: (Error) zFCP device does not exists" ); - return; + + # Go through each LUN + foreach (@luns) { + # Make sure WWPN and LUN do not have 0x prefix + $_ = xCAT::zvmUtils->replaceStr($_, "0x", ""); + + # Do not update if LUN does not exists + if (!(`ssh $hcp "cat $::ZFCPPOOL/$pool.conf" | grep $_`)) { + xCAT::zvmUtils->printLn( $callback, "$node: (Error) zFCP device $_ does not exists" ); + return; + } + + # Update file with given WWPN, LUN, size, and owner + $out = `ssh $hcp "sed --in-place -e /$_/d $::ZFCPPOOL/$pool.conf"`; + xCAT::zvmUtils->printLn( $callback, "$node: Removing zFCP device $_ from $pool pool... Done"); } - - # Update file with given WWPN, LUN, size, and owner - $out = `ssh $hcp "sed --in-place -e /$lun/d $::ZFCPPOOL/$pool.conf"`; } # removedisk [virtual address] @@ -2316,7 +2350,7 @@ sub listVM { # Go through each zFCP pool my @pools = split("\n", `ssh $hcp "ls $::ZFCPPOOL"`); foreach (@pools) { - $_ = uc(xCAT::zvmUtils->replaceStr( $_, ".conf", "" )); + $_ = xCAT::zvmUtils->replaceStr( $_, ".conf", "" ); $out .= "$_\n"; } }