/** * Global variables */ var helpTab; // Help tabs var ivpChoices = new Array; var ivpChoiceValues = new Array; var selectInfo = new Object(); var xcatVerTabId = ''; /** * Load the help page and create the tabs. */ function loadHelpPage(){ createHelpTab(); createVerifyXCATTab(); } /** * Create the Help Tab * * @return Tab object */ function createHelpTab() { // Create help tab var tab = new Tab(); setHelpTab(tab); tab.init(); $('#content').append(tab.object()); var helpForm = $('
'); helpForm.append( '' + ''); tab.add('helpTab', 'Help', helpForm, false); } /** * Create the Verify xCAT Tab * * @return Tab object */ function createVerifyXCATTab() { var comments = 'Name of the IVP run'; var ivpEnabled = 'checked'; var ivpDisabled = ''; // Get the tab var tab = getHelpTab(); var fs, legend; // Generate new tab ID var instance = 0; xcatVerTabId = 'verifyXCATTab' + instance; // Build the list of IVPs in the table readIvpTable( 'NEW' ); // Create info bar and status bar var introBarId = 'verifyXCATIntroBar' + instance; var introBar = createStatusBar(introBarId); introBar.find('div').append( '' + 'The IVP consists of a basic IVP and a full IVP. ' + 'The basic IVP validates the xCAT and SMAPI environments with tests that include ' + 'checking for access to the ZHCP agents and verifying disk space. ' + 'The full IVP validates the OpenStack compute node in addition to the xCAT ' + 'and SMAPI environments. ' + '
' + 'The IVP is composed of multiple components which can take additional parameters '+ 'depending on the type of IVP. ' + 'The parameters shown on this panel will vary based on the type of IVP that is chosen. ' + '
' + '- The orchestrator, xCAT verifynode command, coordinates the functions of the IVP. ' + 'For a full IVP, the orchestrator transmits an analysis script known as the ' + 'preparation script for an OpenStack compute node, invokes it and obtains ' + 'the output of the script. ' + '
' + '- The IVP preparation script analyzes an OpenStack compute node and its OpenStack ' + 'configuration files as they related to z/VM. ' + 'The preparation script produces a driver script that is used to ' + 'continue IVP processing with information gathered during the analysis. ' + 'The preparations scripts are located in the /opt/xcat/share/xcat/tools/zvm/ ' + 'directory on the CMA system that is running xCAT. ' + 'The name of the script begins with \'prep_zxcatIVP_\' and ends with \'.pl\'. ' + 'The middle part of the name is the human readable identifier of the OpenStack release, ' + 'eg. prep_zxcatIVP_NEWTON.pl for the OpenStack Newton release. ' + '
' + '- The main IVP script, zxcatIVP.pl, handles the analysis of the xCAT environment. ' + 'When invoked as part of a basic IVP, it verifies the xCAT environment as it relates ' + 'to the xCAT Management Node, the ZHCP agent, z/VM SMAPI and CP. ' + 'When invoked as part of a full IVP, it is invoked by the driver script and uses the ' + 'OpenStack configuration options to verify the environment. This is similar to the tests ' + 'performed by the basic IVP but the tests relate to the OpenStack compute node, ' + 'the related z/VM and the ZHCP agent for that z/VM hypervisor ' + 'instead of running tests for all ZHCP agents and disk pools. ' + 'A full IVP drives a number of additional tests that are not part of the basic IVP. ' + '
' +
'Three buttons at the bottom of the panel drive the tasks:
' +
'\'Run...\' button immediately starts an IVP with the parameters specified on the panel.
' +
'\'Save...\' button schedules an IVP to be run or modifies the settings of an existing scheduled IVP.
' +
'\'Remove...\' button removes the indicated scheduled IVP. ' +
'Note: xCAT creates default IVPs when it detects that no IVPs are defined. ' +
'For this reason, you do not want to remove all IVPs unless you want xCAT to recreate the ' +
'default IVPs the next hour that it checks for IVPs to run.' +
'
' +
'ID of Run:
' +
'Begin by selecting the either \'New\' or the Id of an existing run. ' +
'Information about the run will be ' +
'be filled in from the details in the xCAT zvmivp table, if it exists.' +
'
' +
'Type of IVP Run:
' +
'Select the type of run based on whether a basic IVP of the xCAT MN and all of its ' +
'ZHCP agents or a full IVP related to OpenStack and the xCAT MN, and the ZHCP related to ' +
'the compute node. ' +
'
' +
'Orchestrator Parameters: ' +
'Preparation Script Parameters: ' +
'If you are running CMA as an OpenStack controller then no additional parameters ' +
'required to verify the controller\'s environment. If wish to verify an OpenStack ' +
'compute node on another system then some additional parameters will be required. ' +
' ' +
'OpenStack System IP Address: ' +
'OpenStack User: ' +
'Main IVP Script Parameters: ' +
'Scheduling related parameters: ' +
'Schedule: ' +
'Name: ' +
'Disable: '
+ '
' +
'The most often used orchestrator operand is the --ignore
' +
'The preparation script supports the --ignore
' +
'You need to provide the IP address of the compute node that you would like to test. ' +
'
' +
'The user name that is allowed to access the OpenStack configuration files. ' +
'The IVP uses that information to send the preparation script and run it on the ' +
'compute node. ' +
'
' +
'As with the orchestrator and preparation script, a field exists to provide ' +
'tailoring to the main IVP script. ' +
'The most commonly used operand is the --ignore
/opt/xcat/bin/zxcatIVP.pl --help '+
'
' +
'If you are going to schedule an IVP run then some additional operands are of interest ' +
'to you.' +
'
' +
'The schedule operand indicates when the IVP should be run. ' +
'You can select it to be run every hour of the day or specify the hours. ' +
'
' +
'The name operand allows you to associate a descriptive name with the run. ' +
'This allows you to easily recognize a specific run in the \'ID or Run\' field. ' +
'
' +
'The disable checkbox allows you to temporarily disable an IVP from running. '
);
var statBarId = 'verifyXCATStatusBar' + instance;
var statBar = createStatusBar(statBarId).hide();
var loader = createLoader( '' );
statBar.find('div').append( loader );
// Create the verify form and put info and status bars on the form.
var verifyXCATForm = $( '
'
+ 'Basic IVP: xCAT MN/ZHCP Verification
'
+ 'Full IVP: xCAT MN/ZHCP and OpenStack Verification'
+ '
'
+ '
'
+ ''
+ '
'
+ '
'
+ ''
+ '
'
+ ''
+ '
'
+ ''
+ ' Schedule '
+ 'Every hour '
+ ''
+ ' Midnight '
+ '1 am '
+ '2 am '
+ '3 am '
+ '4 am '
+ '5 am '
+ ''
+ ' 6 am '
+ '7 am '
+ '8 am '
+ '9 am '
+ '10 am '
+ '11 am '
+ ''
+ ' Noon '
+ '1 pm '
+ '2 pm '
+ '3 pm '
+ '4 pm '
+ '5 pm '
+ ''
+ ' '
+ '6 pm '
+ '7 pm '
+ '8 pm '
+ '9 pm '
+ '10 pm '
+ '11 pm '
+ '
'
+ 'Disable this run'
+ '
');
}
var openstackUser = $(this).parent().find('input[name=openstackUser]').val();
if ( openstackUser != '' ) {
argList += '||--openstackuser ' + hexEncode( openstackUser );
}
var prepParms = $(this).parent().find('input[name=prepParms]').val();
if ( prepParms != '' ) {
argList += '||--prepparms ' + hexEncode( prepParms );
}
} else {
// Show warning message
var warn = createWarnBar('You did not select a basic or full IVP.');
warn.prependTo($(this).parents('.ui-tabs-panel'));
driveFunction = 0;
}
var orchParms = $(this).parent().find('input[name=orchParms]').val();
if ( orchParms != '' ) {
argList += '||--orchparms ' + hexEncode( orchParms );
}
var mainParms = $(this).parent().find('input[name=mainParms]').val();
if ( mainParms != '' ) {
argList += '||--zxcatparms ' + hexEncode( mainParms );
}
argList += '||end';
if ( driveFunction == 1 ) {
$('#' + statBarId).find('div').append( 'Invoking verifynode to run the IVP.
' );
$('#' + statBarId).find('img').show();
$.ajax( {
url : 'lib/cmd.php',
dataType : 'json',
data : {
cmd : 'webrun',
tgt : '',
args : 'verifynode '+ argList,
msg : 'out=' + statBarId + ';cmd=verifynode'
},
success : function(data) {
data = decodeRsp(data);
updateStatusBar(data);
}
});
// Show status bar
statBar.show();
}
});
verifyXCATForm.append( verifyBtn );
//************************************************************************
// Function: Save an IVP button.
//************************************************************************
var scheduleBtn = createButton( 'Save this IVP Run' );
scheduleBtn.click(function() {
var driveFunction = 1;
var argList = '';
// Remove any warning messages
$(this).parents('.ui-tabs-panel').find('.ui-state-error').remove();
var ivpId = $(this).parent().find('select[name=ivpId]').val();
if ( ivpId != 'NEW' ) {
argList += '||--id ' + ivpId;
}
var runType = $(this).parent().find('input[name="runType"]:checked').val();
if ( runType == 'verifyBasic' ) {
argList += '||--type basicivp';
} else if ( runType == 'verifyOpenStack' ) {
argList += '||--type fullivp';
var openstackIP = $(this).parent().find('input[name=openstackIP]').val();
if ( openstackIP != '' ) {
argList = argList + '||--openstackip ' + openstackIP;
} else {
// Show an information message.
$('#' + statBarId).find('div').append(
'You did not specify the IP address of the OpenStack system. The IVP ' +
'will use the IP address of the system running the xCAT management node as ' +
'the OpenStack IP address.
');
}
var openstackUser = $(this).parent().find('input[name=openstackUser]').val();
if ( openstackUser != '' ) {
argList += '||--openstackuser ' + hexEncode( openstackUser );
} else {
argList += '||--openstackuser \'\'';
}
var prepParms = $(this).parent().find('input[name=prepParms]').val();
if ( prepParms != '' ) {
argList += '||--prepparms ' + hexEncode( prepParms );
} else {
argList += '||--prepparms \'\'';
}
} else {
// Show warning message
var warn = createWarnBar('You did not select a basic or full IVP.');
warn.prependTo($(this).parents('.ui-tabs-panel'));
driveFunction = 0;
}
var ivpSchedule = "";
var checkboxes = $(this).parent().find('input[name="ivpSchedule"]:checked');
var everyHourChecked = $(this).parent().find('input[name="ivpSchedule"][value=24]').is(':checked')
if ( everyHourChecked ) {
ivpSchedule = '0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23';
} else {
for ( var i=0, n=checkboxes.length; i
' );
$('#' + statBarId).find('img').show();
$.ajax( {
url : 'lib/cmd.php',
dataType : 'json',
data : {
cmd : 'webrun',
tgt : '',
args : 'verifynode '+ argList,
msg : 'out=' + statBarId + ';cmd=verifynode'
},
success : function( data ) {
data = decodeRsp(data);
updateStatusBar( data );
readIvpTable( 'NEW' );
}
});
// Show status bar
statBar.show();
}
});
verifyXCATForm.append( removeBtn );
tab.add( xcatVerTabId, 'Verify xCAT', verifyXCATForm, false );
}
/**
* Check each hour checkbox when the "Every Hour" checkbox is checked.
*
* @param cb checkbox object that was checked or unchecked.
*/
function everyHourClick( cb ) {
if ( cb.checked ) {
for (var i = 0; i <= 23; i++) {
var thisField = $( '#' + xcatVerTabId + ' input[name=ivpSchedule][value='+i+']' );
thisField.attr( 'checked', true );
}
}
}
/**
* Get node tab
*
* @return Tab object
*/
function getHelpTab() {
return helpTab;
}
/**
* Decodes a printable hex string back into the javascript
* unicode string that it represents.
*
* @param hexVal Printable hex string to convert
* back into its original javascript string form.
*/
hexDecode = function( hexVal ){
var result = "";
if ( hexVal.match("^HexEncoded:") ) {
hexVal = hexVal.replace( 'HexEncoded:', '' );
var hexes = hexVal.match(/.{1,4}/g) || [];
for( var i = 0; i < hexes.length; i++ ) {
result += String.fromCharCode( parseInt( hexes[i], 16 ) );
}
} else {
result = hexVal;
}
return result;
}
/**
* Encode a string into printable hex. This avoids
* an issues with escaping quotes or handling unicode.
*
* @param str String to encode into printable hex.
*/
function hexEncode( str ){
var hex;
var result = 'HexEncoded:';
for (var i=0; i < str.length; i++) {
hex = str.charCodeAt(i).toString(16);
result += ("000"+hex).slice(-4);
}
return result;
}
/**
* Handle click of an hour checkbox to uncheck the 24 hour checkbox, if this
* was an uncheck of the hour.
*
* @param cb checkbox object that was checked or unchecked.
*/
function hourClick( cb ) {
if ( ! cb.checked ) {
var thisField = $( '#' + xcatVerTabId + ' input[name=ivpSchedule][value="24"]' );
thisField.attr( 'checked', false );
}
}
/**
* Drive the tabdump API to obtain the scheduled IVP information.
*
* @param ivpId - Id of the IVP for which we should setup the panel fields
* after the read. Currently, it is required to be 'NEW'.
*/
function readIvpTable( ivpId ) {
if ( typeof console == "object" ) {
console.log( "Entering readIvpTable(" + ivpId + ")" );
}
// Get IVP information
$.ajax( {
url : 'lib/cmd.php',
dataType : 'json',
data : {
cmd : 'tabdump',
tgt : '',
args : 'zvmivp',
msg : 'ivpId=' + ivpId
},
success : function( data ) {
data = decodeRsp(data);
setArrays( data );
var ivpId = data.msg.replace('ivpId=', '');
setVarsForId( ivpId );
}
});
}
/**
* Setup the arrays/hashes with the data from the zvmivp table
*
* @param data Data from HTTP request
*/
function setArrays( data ) {
if ( typeof console == "object" ){
console.log( "Entering setArrays(" + data.rsp + ")" );
}
// Get response
var rsp = data.rsp;
// Clear the list of IVP information.
ivpChoices = new Array();
ivpChoiceValues = new Array();
selectInfo = new Object();
// Get column value
var idPos = 0;
var ipPos = 0;
var schedulePos = 0;
var lrPos = 0;
var torPos = 0;
var aUserPos = 0;
var oParmsPos = 0;
var pParmsPos = 0;
var mainParmsPos = 0;
var cmntPos = 0;
var colNameArray = rsp[0].substr(1).split(',');
for ( var i in colNameArray ) {
switch ( colNameArray[i] ) {
case 'id':
idPos = i;
break;
case 'ip':
ipPos = i;
break;
case 'schedule':
schedulePos = i;
break;
case 'last_run':
lrPos = i;
break;
case 'type_of_run':
typeOfRunPos = i;
break;
case 'access_user':
aUserPos = i;
break;
case 'orch_parms':
oParmsPos = i;
break;
case 'prep_parms':
pParmsPos = i;
break;
case 'main_ivp_parms':
mainParmsPos = i;
break;
case 'comments':
cmntPos = i;
break;
case 'disable':
disablePos = i;
break;
default :
break;
}
}
// Get IVP information from the table data.
for (var i = 1; i < rsp.length; i++) {
var cols = rsp[i].split(',');
var id = cols[idPos].replace(new RegExp('"', 'g'), '');
var ip = cols[ipPos].replace(new RegExp('"', 'g'), '');
var schedule = cols[schedulePos].replace(new RegExp('"', 'g'), '');
var typeOfRun = cols[typeOfRunPos].replace(new RegExp('"', 'g'), '');
var openstackUser = cols[aUserPos].replace(new RegExp('"', 'g'), '');
var orchParms = cols[oParmsPos].replace(new RegExp('"', 'g'), '');
var prepParms = cols[pParmsPos].replace(new RegExp('"', 'g'), '');
var mainParms = cols[mainParmsPos].replace(new RegExp('"', 'g'), '');
var comments = cols[cmntPos].replace(new RegExp('"', 'g'), '');
var disable = cols[disablePos].replace(new RegExp('"', 'g'), '');
ivpChoiceValues.push( id );
selectInfo[id] = new Object();
selectInfo[id]['id'] = id;
selectInfo[id]['ip'] = ip;
selectInfo[id]['schedule'] = schedule;
selectInfo[id]['typeOfRun'] = typeOfRun.toLowerCase();
selectInfo[id]['openstackUser'] = hexDecode( openstackUser );
selectInfo[id]['orchParms'] = hexDecode( orchParms );
selectInfo[id]['prepParms'] = hexDecode( prepParms );
selectInfo[id]['mainParms'] = hexDecode( mainParms );
selectInfo[id]['comments'] = hexDecode(comments);
selectInfo[id]['disable'] = disable.toLowerCase();
}
// Sort the choices so we get a pretty list and build the choice strings.
ivpChoiceValues.sort( function(a, b) {
if ( ! isNaN(a) && ! isNaN(b) ) {
// Both are numbers, do a numeric compare
return a-b;
} else if ( isNaN(a) && isNaN(b) ) {
// Both are strings, do a string compare
return a.localeCompare( b );
} else if ( isNaN(a) ) {
// Strings go after numbers
return 1;
} else {
// Numbers go before strings
return -1;
}
} );
ivpChoiceValues.forEach( function( id ) {
var idComments;
if ( selectInfo[id]['comments'] != '' ) {
idComments = id + ': ' + selectInfo[id]['comments'];
} else {
idComments = id + ': A comment was not specified.';
}
ivpChoices.push( idComments );
}, this);
// Clear out a hash element for the 'NEW' choice.
selectInfo['NEW'] = new Object();
selectInfo['NEW']['id'] = '';
selectInfo['NEW']['ip'] = '';
selectInfo['NEW']['schedule'] = '';
selectInfo['NEW']['typeOfRun'] = '';
selectInfo['NEW']['openstackUser'] = '';
selectInfo['NEW']['orchParms'] = '';
selectInfo['NEW']['prepParms'] = '';
selectInfo['NEW']['mainParms'] = '';
selectInfo['NEW']['comments'] = '';
selectInfo['NEW']['disable'] = '';
// Add in the NEW option at the top of the array.
ivpChoices.unshift( "NEW: New IVP" );
ivpChoiceValues.unshift( "NEW" );
// Construct the new Select option choices
var ivpChoicesLen = ivpChoices.length;
var selectIdOptions = '';
for ( var i = 0; i < ivpChoicesLen; i++ ) {
selectIdOptions += '';
}
// Find the division containing the select and replace its contents
var thisIvpSelect = $( '#' + xcatVerTabId + ' select[name=ivpId]' );
thisIvpSelect.children().remove();
thisIvpSelect.append( selectIdOptions );
}
/**
* Set node tab
*
* @param tab
* Tab object
* @return Nothing
*/
function setHelpTab(tab) {
helpTab = tab;
}
/**
* Set IVP variables based on the chosen Id
*
* @param data Data from HTTP request
*/
function setVarsForId( id ) {
if ( typeof console == "object" ) {
console.log( "Entering setVarsForId(" + id + ")" );
}
var thisField = $( '#' + xcatVerTabId + ' input[name="runType"]' );
if ( selectInfo[id]['typeOfRun'] == 'basicivp' ) {
thisField.val(['verifyBasic']);
} else if ( selectInfo[id]['typeOfRun'] == 'fullivp' ) {
thisField.val(['verifyOpenStack']);
} else {
thisField.val([]);
}
thisField = $( '#' + xcatVerTabId + ' input[name=orchParms]' );
thisField.val( selectInfo[id]['orchParms'] );
thisField = $( '#' + xcatVerTabId + ' input[name=prepParms]' );
thisField.val( selectInfo[id]['prepParms'] );
var thisfield = $( '#' + xcatVerTabId + ' input[name=mainParms]' );
thisfield.val( selectInfo[id]['mainParms'] );
thisField = $( '#' + xcatVerTabId + ' input[name=openstackIP]' );
thisField.val( selectInfo[id]['ip'] );
thisField = $( '#' + xcatVerTabId + ' input[name=openstackUser]' );
thisField.val( selectInfo[id]['openstackUser'] );
var hours = new Object();
var fullDay = 1;
var hour = selectInfo[id]['schedule'].split(' ');
for ( var j = 0; j < hour.length; j++ ) {
hours[hour[j]] = 1;
}
for (var i = 0; i <= 23; i++) {
thisField = $( '#' + xcatVerTabId + ' input[name=ivpSchedule][value='+i+']' );
if ( hours[i] == 1 ) {
thisField.attr( 'checked', true );
} else {
fullDay = 0;
thisField.attr( 'checked', false );
}
}
if ( fullDay == 1 ) {
thisField = $( '#' + xcatVerTabId + ' input[name=ivpSchedule][value=24]' );
thisField.attr( 'checked', true );
} else {
thisField = $( '#' + xcatVerTabId + " input[name=ivpSchedule][value=24]" );
thisField.attr( 'checked', false );
}
thisField = $( '#' + xcatVerTabId + ' input[name=comments]' );
thisField.val( selectInfo[id]['comments'] );
thisField = $( '#' + xcatVerTabId + ' input[name=disableRun][value=disabled]' );
if ( selectInfo[id]['disable'] == 1 || selectInfo[id]['disable'] == 'yes' ) {
thisField.attr( 'checked', true );
} else {
thisField.attr( 'checked', false );
}
}
/**
* Update status bar of a given tab
*
* @param data Data returned from HTTP request
*/
function updateStatusBar(data) {
if ( typeof console == "object" ) {
console.log( "Entering updateStatusBar(\nmsg: " + data.msg + "\nrsp: " + data.rsp + ")" );
}
// Get ajax response
var rsp = data.rsp;
var args = data.msg.split(';');
var statBarId = '';
var cmd = '';
for ( var i=0; i < args.length; i++ ) {
if ( args[i].match('^cmd=') ) {
cmd = args[i].replace('cmd=', '');
} else if ( args[i].match('^out=') ) {
statBarId = args[i].replace('out=', '');
}
}
if (cmd == 'verifynode') {
// Hide loader
$('#' + statBarId).find('img').hide();
// Write ajax response to status bar
var prg = writeRsp(rsp, '');
$('#' + statBarId).find('div').append(prg);
// Put a check box after the response.
var icon = $('').css({
'vertical-align': 'top'
});
$('#' + statBarId).find( 'div' ).append(icon);
$('#' + statBarId).find( 'div' ).append( '
' );
} else {
// Hide loader
$('#' + statBarId).find('img').hide();
// Write ajax response to status bar
var prg = writeRsp(rsp, '');
$('#' + statBarId).find('div').append(prg);
}
}