'Discover Hardware',
'patterns' => 'Cluster Patterns',
'patterns1b' => 'Switch Ports',
'patterns2' => 'More Cluster Patterns',
'preparemn' => 'Prepare Management Node',
'prediscover' => 'Power On Hardware',
'discover' => 'Discover HW Control Points',
'updatedefs' => 'Update Definitions',
'configurehcps' => 'Configure HW Control Points',
'createnodes' => 'Create Nodes',
/* 'testhcps' => 'Test HW Control', */
'done' => 'Complete',
);
if (isset($_REQUEST['page'])) { displayWizard($pages); }
else { // initial display of the wizard, show the whole page
insertHeader('Discover New Nodes', array('discover.css',"$TOPDIR/lib/wizard.css"), array("$TOPDIR/lib/wizard.js"), array('machines','discover'));
echo "
\n";
displayWizard($pages);
echo "
\n"; // end the content div
insertFooter();
}
//-----------------------------------------------------------------------------
// Save the values sent up from the previous wizard page into the session.
function savePostVars() {
foreach ($_POST as $k => $v) {
if ($k != 'action' && $k != 'page') { $_SESSION[$k] = $v; }
}
}
//-----------------------------------------------------------------------------
// Expand the noderange for non-existing nodes
function expandNR($nr) {
//todo: use xcatd to expand this. Change xcatd around line 998: } elsif ($req->{command}->[0] eq "noderange" and $req->{noderange}) {
// see pping as an example of the client/server for noderange expansion
$a = array();
if (empty($nr)) return $a;
list($begin, $end) = explode('-', $nr);
$begParts = array();
if (!preg_match('/^(\D+)(\d+)$/', $begin, $begParts)) { msg('E',"Error in noderange syntax: $nr"); return NULL; }
$endParts = array();
if (!preg_match('/^(\D+)(\d+)$/', $end, $endParts)) { msg('E',"Error in noderange syntax: $nr"); return NULL; }
if ($begParts[1] != $endParts[1]) { msg('E',"Error in noderange syntax: $nr"); return NULL; }
$numlen = strlen($begParts[2]);
for ($i=$begParts[2]; $i<=$endParts[2]; $i++) {
$istr = "$i";
if (strlen($istr) < $numlen) { $istr = substr('000000',0,$numlen-strlen($istr)) . $istr; }
$a[] = "$begParts[1]$istr";
}
return $a;
}
//-----------------------------------------------------------------------------
function intro($action, $step) {
echo "This wizard will guide you through the process of defining the naming conventions within your cluster, discovering the hardware on your network, and automatically defining it in the xCAT database.";
echo " Choose which type of hardware you want to discover, and then click Next.
\n";
// The least hacky way to get this list left justified, but have the block in the center, is to use a table. CSS snobs, just deal with it.
echo "\n";
}
//-----------------------------------------------------------------------------
function patterns($action, $step) {
echo "\n";
//todo: get HCP userids/pws from the user
}
//-----------------------------------------------------------------------------
function patterns1b($action, $step) {
//todo: do validation of all pages that have input
savePostVars();
// Figure out how many switches there need to be
$hmcs = expandNR($_SESSION['hmcHostname']);
$bpas = expandNR($_SESSION['bpaHostname']);
$fsps = expandNR($_SESSION['fspHostname']);
//echo "", implode(',',$hmcs), "
\n";
$total = count($hmcs) + count($bpas) + count($fsps);
if (!$_SESSION['portsPerSwitch']) { $numswitches = 1; }
else { $numswitches = (integer) ((($total-1) / $_SESSION['portsPerSwitch']) + 1); }
//echo "$numswitches
\n";
echo "\n";
}
//-----------------------------------------------------------------------------
function patterns2($action, $step) {
savePostVars();
echo "\n";
// do we need to get any info about the resources that should be in each lpar, or do we just divide them evenly?
}
//-----------------------------------------------------------------------------
function preparemn($action, $step) {
global $TOPDIR;
if ($step == 0) {
savePostVars();
insertProgressTable(array('Write xCAT switch table.',
'Write xCAT hosts table.',
'Define networks.',
'Configure DHCP.',
));
if ($action != 'back') { echo ""; }
}
elseif ($step == 1) { writeSwitchTable($step); }
elseif ($step == 2) { writeHostsTable($step); }
elseif ($step == 3) { setDynRange($_SESSION["dynamicIP"], $step); }
elseif ($step == 4) { makedhcp($step); }
}
//-----------------------------------------------------------------------------
// Using the hcp and switch ranges, write out the switch table
//todo: maybe should not use tabrestore in case we are just discovery additional hw
function writeSwitchTable($step) {
$hmcs = expandNR($_SESSION['hmcHostname']);
$bpas = expandNR($_SESSION['bpaHostname']);
$fsps = expandNR($_SESSION['fspHostname']);
$switches = expandNR($_SESSION['switchHostname']);
$numports = $_SESSION['portsPerSwitch'];
$data = array(array('#node,switch,port,vlan,interface,comments,disable'));
//echo "\n";
foreach ($switches as $k => $sw) {
$num = $k + 1;
$sequence = $_SESSION["switchSequence$num"];
$seq = preg_split('/[\s,]+/', $sequence);
$port = 1;
foreach ($seq as $s) { // each $s is something like: FSP:5
list($type, $num) = explode(':', $s);
if (preg_match('/^hmc$/i',$type)) $ar=&$hmcs;
elseif (preg_match('/^bpa$/i',$type)) $ar=&$bpas;
elseif (preg_match('/^fsp$/i',$type)) $ar=&$fsps;
else { msg('E', "Invalid HW control point type in $s"); return; }
if ($num == '*') { $num = count($ar); }
for ($i=1; $i<=$num; $i++) {
$node = array_shift($ar);
$data[] = array($node,$sw,$port);
/* $xml = docmd('nodeadd',NULL,array($node,'groups=all',"switch.node=$node","switch.switch=$sw","switch.port=$port"));
if (getXmlErrors($xml,$errors)) { msg('E',"nodeadd failed: " . implode(' ',$errors)); return; }
else { echo "Wrote: $node,$sw,$port
\n"; }*/
if (++$port > $numports) break 2;
}
}
}
//echo "
\n"; ob_flush(); flush();
//array_unshift($data, array('#node,switch,port,vlan,interface,comments,disable'));
$xml = doTabrestore('switch', $data);
//$errors = array();
if (getXmlErrors($xml,$errors)) { msg('E',"tabrestore switch failed: " . implode(' ',$errors)); return; }
// Send JSON data back to the browser. Todo: handle the errors too.
echo json_encode(array('step' => (integer)++$step, 'done' => FALSE, 'error' => ''));
}
//-----------------------------------------------------------------------------
// Using the hcp ranges, write out the hosts table
function writeHostsTable($step) {
$machines = array();
$machines[$_SESSION['switchIP']] = expandNR($_SESSION['switchHostname']);
$machines[$_SESSION['hmcIP']] = expandNR($_SESSION['hmcHostname']);
$machines[$_SESSION['bpaIP']] = expandNR($_SESSION['bpaHostname']);
$machines[$_SESSION['fspIP']] = expandNR($_SESSION['fspHostname']);
$machines[$_SESSION['subnet']] = expandNR($_SESSION['computeNodename']);
$data = array(array('#node,ip,hostnames,comments,disable'));
//echo "\n";
foreach ($machines as $ip => $ar) { // this loop goes thru each type of hw
foreach ($ar as $hostname) { // this loop goes thru each of the hostnames for that type of hw
$data[] = array($hostname,$ip);
//echo "Wrote: $hostname,$ip
\n";
incrementIP($ip);
}
}
//echo "
\n"; ob_flush(); flush();
$xml = doTabrestore('hosts', $data);
$errors = array();
if (getXmlErrors($xml,$errors)) { msg('E',"tabrestore hosts failed: " . implode(' ',$errors)); return; }
// Send JSON data back to the browser. Todo: handle the errors too.
echo json_encode(array('step' => (integer)++$step, 'done' => FALSE, 'error' => ''));
}
//-----------------------------------------------------------------------------
function incrementIP(& $ip) {
$parts = explode('.', $ip);
$parts[3]++;
if ($parts[3] >= 255) {
$parts[2]++; $parts[3] = 1;
if ($parts[3] >= 255) { $parts[1]++; $parts[2] = 1; } // assume parts[1] is not 255, because we never increment the 1st field
}
$ip = implode('.', $parts);
}
//-----------------------------------------------------------------------------
//todo: we need a better way to change the networks table than tabdump/tabrestore. We can not use chtab because its not client/svr. We can not use chdef because there is no netname defined by makenetworks.
function setDynRange($range, $step) {
// Get the whole table via tabdump
$xml = docmd('tabdump','',array('networks'));
$data = array();
foreach ($xml->children() as $response) foreach ($response->children() as $line) {
$line = (string) $line;
if(ereg("^#", $line)) { // handle the header specially
$data[] = array($line);
continue;
}
$values = splitTableFields($line);
$values[8] = '"' . $range . '"'; // dynamicrange is the 9th field
$data[] = $values;
}
// Now restore that data back into the networks table
$xml = doTabrestore('networks', $data);
$errors = array();
if (getXmlErrors($xml,$errors)) { msg('E',"tabrestore networks failed: " . implode(' ',$errors)); return; }
// Send JSON data back to the browser. Todo: handle the errors too.
echo json_encode(array('step' => (integer)++$step, 'done' => FALSE, 'error' => ''));
}
//-----------------------------------------------------------------------------
function makedhcp($step) {
$xml = docmd('makedhcp',NULL,array('-n'));
$errors = array();
if (getXmlErrors($xml,$errors)) { msg('E',"makedhcp failed: " . implode(' ',$errors)); return; }
// Send JSON data back to the browser. Todo: handle the errors too.
echo json_encode(array('step' => (integer)++$step, 'done' => TRUE, 'error' => ''));
}
//-----------------------------------------------------------------------------
function prediscover($action, $step) {
echo "\n";
echo " Do the following manual steps now: \n";
echo "- Power on all of the HMCs.
\n";
echo "- Then power on all of frames.
\n";
echo "- Then click Next to discover the hardware on the service network.
\n";
echo "
|
\n";
}
//-----------------------------------------------------------------------------
function discover($action, $step) {
global $TOPDIR;
if ($step == 0) {
insertProgressTable(array('Discover HMCs, BPAs, and FSPs.'));
if ($action != 'back') { echo ""; }
}
elseif ($step == 1) { lsslp($step); }
}
//-----------------------------------------------------------------------------
//todo: we are just simulating lsslp right now
function lsslp($step) {
/* todo: show this
echo "";
echo "Discovered HMCs: ", $_SESSION['hmcHostname'], "
\n";
echo "Discovered BPAs: ", $_SESSION['bpaHostname'], "
\n";
echo "Discovered FSPs: ", $_SESSION['fspHostname'], "
\n";
echo "
\n";
*/
//$errors = array();
$xml = docmd('nodeadd',NULL,array($_SESSION['hmcHostname'],'groups=hmc,all','nodetype.nodetype=hmc'));
if (getXmlErrors($xml,$errors)) { msg('E',"nodeadd hmc failed: " . implode(' ',$errors)); return; }
$xml = docmd('nodeadd',NULL,array($_SESSION['bpaHostname'],'groups=bpa,all','nodetype.nodetype=bpa','nodehm.mgt=hmc','nodehm.power=hmc','ppc.comments=bpa','vpd.serial=|(\D+)(\d+)|($2)|','vpd.mtm=|(\D+)(\d+)|($1)|'));
if (getXmlErrors($xml,$errors)) { msg('E',"nodeadd bpa failed: " . implode(' ',$errors)); return; }
// We are assuming there are 4 fsps in each bpa
$xml = docmd('nodeadd',NULL,array($_SESSION['fspHostname'],'groups=fsp,all','nodetype.nodetype=fsp','nodehm.mgt=hmc','nodehm.power=hmc','ppc.id=|\D+(\d+)|((($1-1)%4)+1)|','ppc.parent=|(\D+)(\d+)|b((($2-1)/4)+1)|','vpd.serial=|(\D+)(\d+)|($2)|','vpd.mtm=|(\D+)(\d+)|($1)|'));
if (getXmlErrors($xml,$errors)) { msg('E',"nodeadd fsp failed: " . implode(' ',$errors)); return; }
/*
$xml = docmd('chdef',NULL,array('-t','group','bpa','serial=|(\D+)(\d+)|($2)|','mtm=|(\D+)(\d+)|($1)|'));
if (getXmlErrors($xml,$errors)) { msg('E',"chdef bpa failed: " . implode(' ',$errors)); return; }
$xml = docmd('chdef',NULL,array('-t','group','fsp','serial=|(\D+)(\d+)|($2)|','mtm=|(\D+)(\d+)|($1)|'));
if (getXmlErrors($xml,$errors)) { msg('E',"chdef fsp failed: " . implode(' ',$errors)); return; }
*/
// Send JSON data back to the browser. Todo: handle the errors too.
echo json_encode(array('step' => (integer)++$step, 'done' => TRUE, 'error' => ''));
}
//-----------------------------------------------------------------------------
function updatedefs($action, $step) {
global $TOPDIR;
if ($step == 0) {
insertProgressTable(array('Determine which CECs each HMC should manage.',
'Create HW control point node groups.',
'Assign frame numbers.',
/* 'Assign supernode numbers and building block numbers.',
'Assign building block subnets.', */
'Update name resolution.',
));
if ($action != 'back') { echo ""; }
}
elseif ($step == 1) { assigncecs($step); }
elseif ($step == 2) { createhcpgroups($step); }
elseif ($step == 3) { assignframenums($step); }
elseif ($step == 4) { nameres($step); }
}
//-----------------------------------------------------------------------------
function assigncecs($step) {
$numCECs = $_SESSION['numCECs'];
$hmcs = expandNR($_SESSION['hmcHostname']);
$bpas = expandNR($_SESSION['bpaHostname']);
$fsps = expandNR($_SESSION['fspHostname']);
$h = 0; // start with the 1st hmc
$f = 0;
$errors = array();
// Go thru the fsps taking groups of numCECs and assigning them to the next hmc
while (TRUE) {
// Get the next group of fsps
$length = min($numCECs, count($fsps)-$f);
$fslice = array_slice($fsps, $f, $length);
$xml = docmd('nodech',implode(',',$fslice),array("ppc.hcp=$hmcs[$h]"));
if (getXmlErrors($xml,$errors)) { msg('E',"nodech fsp failed: " . implode(' ',$errors)); return; }
// Decide if we are all out of fsps
$h++;
$f += $length;
if ($h>=count($hmcs) || $f>=count($fsps)) break;
}
//todo: how do we decide what bpas to assign to which hmcs?
// Send JSON data back to the browser. Todo: handle the errors too.
echo json_encode(array('step' => (integer)++$step, 'done' => FALSE, 'error' => ''));
}
//-----------------------------------------------------------------------------
function createhcpgroups($step) {
//todo: may need to do this once we are using the real lsslp
// Send JSON data back to the browser. Todo: handle the errors too.
echo json_encode(array('step' => (integer)++$step, 'done' => FALSE, 'error' => ''));
}
//-----------------------------------------------------------------------------
// Give frame numbers to each bpa
function assignframenums($step) {
$errors = array();
$xml = docmd('nodech','bpa',array('ppc.id=|\D+(\d+)|($1)|'));
if (getXmlErrors($xml,$errors)) { msg('E',"nodech bpa failed: " . implode(' ',$errors)); return; }
// Send JSON data back to the browser. Todo: handle the errors too.
echo json_encode(array('step' => (integer)++$step, 'done' => FALSE, 'error' => ''));
}
//-----------------------------------------------------------------------------
// Run makehosts and makedns
function nameres($step) {
$errors = array();
$xml = docmd('makehosts',NULL,NULL);
if (getXmlErrors($xml,$errors)) { msg('E',"makehosts failed: " . implode(' ',$errors)); return; }
$xml = docmd('makedns',NULL,NULL);
if (getXmlErrors($xml,$errors)) { msg('E',"makedns failed: " . implode(' ',$errors)); return; }
// Send JSON data back to the browser. Todo: handle the errors too.
echo json_encode(array('step' => (integer)++$step, 'done' => TRUE, 'error' => ''));
}
//-----------------------------------------------------------------------------
function configurehcps($action, $step) {
global $TOPDIR;
if ($step == 0) {
insertProgressTable(array('Assign CECs to their HMC.',
'Set frame numbers in BPAs.',
'Power on CECs to Standby.',
));
if ($action != 'back') { echo ""; }
}
elseif ($step == 1) { cecs2hmcs($step); }
elseif ($step == 2) { setframenum($step); }
elseif ($step == 3) { cecs2standby($step); }
//todo: set HCP userids/pws
}
function cecs2hmcs($step) {echo json_encode(array('step' => (integer)++$step, 'done' => FALSE, 'error' => ''));}
function setframenum($step) {echo json_encode(array('step' => (integer)++$step, 'done' => FALSE, 'error' => ''));}
function cecs2standby($step) {echo json_encode(array('step' => (integer)++$step, 'done' => TRUE, 'error' => ''));}
//-----------------------------------------------------------------------------
function createnodes($action, $step) {
global $TOPDIR;
//todo: need to show progress for each CEC
if ($step == 0) {
insertProgressTable(array('Create LPARs in each CEC and save node definitions in xCAT database.'));
if ($action != 'back') { echo ""; }
}
elseif ($step == 1) { createlpars($step); }
}
//-----------------------------------------------------------------------------
function createlpars($step) {
$numlpars = $_SESSION['numLPARs'];
$fsps = expandNR($_SESSION['fspHostname']);
$nodes = expandNR($_SESSION['computeNodename']);
$samplenode = ''; //todo: ???
$errors = array();
$n = 0; // index into the nodes array
foreach ($fsps as $f) {
$length = min($numlpars, count($nodes)-$n);
$nslice = array_slice($nodes, $n, $length);
//todo: actually make the lpars
//$xml = docmd('mkvm',NULL,array($samplenode,'-i','1','-n',implode(',',$nslice)));
//if (getXmlErrors($xml,$errors)) { msg('E',"mkvm failed: " . implode(' ',$errors)); return; }
// Decide if we are all out of nodes
$n += $length;
if ($n >= count($nodes)) break;
}
//todo: Change this when mkvm is creating the base node definition.
// Also, the following assumes the node range starts with 1 and the fsp node range is simple.
// Really need to do individual nodeadd for each node.
$parts = array();
preg_match('/^(\D+)/', $_SESSION['fspHostname'], $parts);
$fsp = $parts[1];
$xml = docmd('nodeadd',NULL,array($_SESSION['computeNodename'],'groups=lpar,all','nodetype.nodetype=lpar,osi',
'nodehm.mgt=hmc','nodehm.power=hmc','nodehm.cons=hmc','noderes.netboot=yaboot',
'nodetype.arch=ppc64','ppc.id=|\D+(\d+)|((($1-1)%'.$numlpars.')+1)|',
'ppc.parent=|(\D+)(\d+)|'.$fsp.'((($2-1)/'.$numlpars.')+1)|'));
if (getXmlErrors($xml,$errors)) { msg('E',"nodeadd nodes failed: " . implode(' ',$errors)); return; }
echo json_encode(array('step' => (integer)++$step, 'done' => TRUE, 'error' => ''));
}
//-----------------------------------------------------------------------------
// Currently not used.
function testhcps($action, $step) {
global $TOPDIR;
echo "\n";
echo "- (Output for rpower stat for sample nodes)
\n";
echo "- (Output for rinv for sample nodes)
\n";
echo "- (Output for rvitals for sample nodes)
\n";
echo "
\n";
}
//-----------------------------------------------------------------------------
function done($action, $step) {
global $TOPDIR;
echo "Cluster set up successfully completed!
\n";
echo "You can now view your node definitions and start to deploy nodes.
\n";
}
?>