2010-09-16 02:05:28 +00:00
#!/usr/bin/env perl -w
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
#####################################################
#
# Reads the cluster configuration file and primes the database in prep
# for HW discovery and node deployment.
#
# Preconditions before running the xcatsetup cmd:
# -
#
2010-10-14 16:00:20 +00:00
# Todo: Limitations on the values in the config file:
2010-09-23 12:52:29 +00:00
# - do not yet support redundant bpcs or fsps
2010-09-16 02:05:28 +00:00
#
#####################################################
package xCAT_plugin::setup ;
use strict ;
#use warnings;
use xCAT::NodeRange ;
use xCAT::Schema ;
use xCAT::Table ;
use xCAT::Utils ;
use xCAT::MsgUtils ;
use Data::Dumper ;
use xCAT::DBobjUtils ;
my $ CALLBACK ;
my % STANZAS ;
sub handled_commands {
return ( { xcatsetup = > "setup" } ) ;
}
sub process_request
{
use Getopt::Long ;
Getopt::Long:: Configure ( "bundling" ) ;
#Getopt::Long::Configure("pass_through");
Getopt::Long:: Configure ( "no_pass_through" ) ;
my $ request = shift ;
$ CALLBACK = shift ;
#my $nodes = $request->{node};
#my $command = $request->{command}->[0];
my $ args = $ request - > { arg } ;
my $ VERSION ;
my $ HELP ;
2010-10-14 16:00:20 +00:00
my % SECTIONS ; # which stanzas should be processed
my $ SECT ;
2010-09-16 02:05:28 +00:00
my $ setup_usage = sub {
my $ exitcode = shift @ _ ;
my % rsp ;
push @ { $ rsp { data } } , "Usage: xcatsetup [-v|--version] [-?|-h|--help] <cluster-config-file>" ;
if ( $ exitcode ) { $ rsp { errorcode } = $ exitcode ; }
$ CALLBACK - > ( \ % rsp ) ;
} ;
# Process the cmd line args
if ( $ args ) { @ ARGV = @ { $ args } ; }
else { @ ARGV = ( ) ; }
2010-10-14 16:00:20 +00:00
if ( ! GetOptions ( 'h|?|help' = > \ $ HELP , 'v|version' = > \ $ VERSION , 's|stanzas=s' = > \ $ SECT ) ) { $ setup_usage - > ( 1 ) ; return ; }
2010-09-16 02:05:28 +00:00
if ( $ HELP || scalar ( @ ARGV ) == 0 ) { $ setup_usage - > ( 0 ) ; return ; }
if ( $ VERSION ) {
my % rsp ;
my $ version = xCAT::Utils - > Version ( ) ;
$ rsp { data } - > [ 0 ] = $ version ;
$ CALLBACK - > ( \ % rsp ) ;
return ;
}
2010-10-14 16:00:20 +00:00
if ( $ SECT ) {
foreach my $ s ( split ( /[\s,]+/ , $ SECT ) ) { $ SECTIONS { $ s } = 1 ; }
}
2010-09-16 02:05:28 +00:00
my $ input ;
my $ filename = fullpath ( $ ARGV [ 0 ] , $ request - > { cwd } - > [ 0 ] ) ;
if ( ! open ( $ input , $ filename ) ) {
errormsg ( "Can not open file $filename." , 2 ) ;
return ;
}
# Parse the config file
my $ success = readFileInput ( $ input ) ;
close ( $ input ) ;
if ( ! $ success ) { return ; }
# Write the db entries
2010-10-14 16:00:20 +00:00
writedb ( $ request - > { cwd } - > [ 0 ] , \ % SECTIONS ) ;
2010-09-16 02:05:28 +00:00
}
sub readFileInput {
my $ input = shift ;
my $ l ;
my $ stanza ;
my $ linenum = 0 ;
while ( $ l = <$input> ) {
$ linenum + + ;
# skip blank and comment lines
next if ( $ l =~ /^\s*$/ || $ l =~ /^\s*#/ ) ;
# process a real line
if ( $ l =~ /^\s*(\S+)\s*=\s*(.*)\s*$/ ) {
my $ attr = $ 1 ;
my $ val = $ 2 ;
#$attr =~ s/^\s*//; # Remove any leading whitespace - already did that
#$attr =~ s/\s*$//; # Remove any trailing whitespace - already did that
$ attr =~ tr /A-Z/ a - z / ; # Convert to lowercase
#$val =~ s/^\s*//;
#$val =~ s/\s*$//;
# set the value in the hash for this stanza
if ( ! defined ( $ stanza ) ) { errormsg ( "expected stanza header at line $linenum." , 3 ) ; return ; }
$ STANZAS { $ stanza } - > { $ attr } = $ val ;
}
elsif ( $ l =~ /^\s*(\S+)\s*:\s*$/ ) {
$ stanza = $ 1 ;
}
else {
errormsg ( "syntax error on line $linenum." , 3 ) ;
return 0 ;
}
} # end while - go to next line
return 1 ;
}
# A few global variables for common tables that a lot of functions need
my % tables = ( 'site' = > 0 ,
'nodelist' = > 0 ,
'hosts' = > 0 ,
'ppc' = > 0 ,
'nodetype' = > 0 ,
'nodehm' = > 0 ,
'noderes' = > 0 ,
2010-10-28 11:59:22 +00:00
'postscripts' = > 0 ,
2010-10-29 19:09:18 +00:00
'nodepos' = > 0 ,
2010-09-16 02:05:28 +00:00
) ;
2010-10-29 19:09:18 +00:00
my $ CECPOSITIONS ; # a hash of the cec values in the nodepos table
2010-09-16 02:05:28 +00:00
sub writedb {
2010-10-14 16:00:20 +00:00
my ( $ cwd , $ sections ) = @ _ ; # the current dir from the request and the stanzas that should be processed
2010-09-16 02:05:28 +00:00
# Open some common tables that several of the stanzas need
foreach my $ tab ( keys % tables ) {
$ tables { $ tab } = xCAT::Table - > new ( $ tab , - create = > 1 ) ;
if ( ! $ tables { $ tab } ) { errormsg ( "Can not open $tab table in database. Exiting config file processing." , 3 ) ; return ; }
}
# Write site table attrs (hash key=xcat-site)
my $ domain = $ STANZAS { 'xcat-site' } - > { domain } ;
2010-10-14 16:00:20 +00:00
if ( $ domain && ( ! scalar ( keys ( %$ sections ) ) || $$ sections { 'xcat-site' } ) ) { writesite ( $ domain ) ; }
2010-09-16 02:05:28 +00:00
# Write service LAN info (hash key=xcat-service-lan)
#using hostname-range, write: nodelist.node, nodelist.groups, switches.switch
#using hostname-range and starting-ip, write regex for: hosts.node, hosts.ip
#using num-ports-per-switch, switch-port-prefix, switch-port-sequence, write: switch.node, switch.switch, switch.port
#using dhcp-dynamic-range, write: networks.dynamicrange for the service network.
# * Note: for AIX the permanent IPs for HMCs/FSPs/BPAs (specified in later stanzas) should be within this dynamic range, at the high end. For linux the permanent IPs should be outside this dynamic range.
# * use the first IP in the specified dynamic range to locate the service network in the networks table
#on aix stop bootp - see section 2.2.1.1 of p hw mgmt doc
#run makedhcp -n
# Write HMC info (hash key=xcat-hmcs)
my $ hmcrange = $ STANZAS { 'xcat-hmcs' } - > { 'hostname-range' } ;
2010-10-29 19:09:18 +00:00
if ( $ hmcrange && ( ! scalar ( keys ( %$ sections ) ) || $$ sections { 'xcat-hmcs' } ) ) {
unless ( writehmc ( $ hmcrange ) ) { closetables ( ) ; return ; }
}
2010-09-16 02:05:28 +00:00
# Write frame info (hash key=xcat-frames)
my $ framerange = $ STANZAS { 'xcat-frames' } - > { 'hostname-range' } ;
2010-10-29 19:09:18 +00:00
if ( $ framerange && ( ! scalar ( keys ( %$ sections ) ) || $$ sections { 'xcat-frames' } ) ) {
unless ( writeframe ( $ framerange , $ cwd ) ) { closetables ( ) ; return ; }
}
2010-09-16 02:05:28 +00:00
# Write CEC info (hash key=xcat-cecs)
my $ cecrange = $ STANZAS { 'xcat-cecs' } - > { 'hostname-range' } ;
2010-10-29 19:09:18 +00:00
if ( $ cecrange && ( ! scalar ( keys ( %$ sections ) ) || $$ sections { 'xcat-cecs' } ) ) {
unless ( writecec ( $ cecrange , $ cwd ) ) { closetables ( ) ; return ; }
}
# Save the CEC positions for all the node definitions later
if ( $ cecrange ) {
$ CECPOSITIONS = $ tables { 'nodepos' } - > getNodesAttribs ( [ noderange ( $ cecrange ) ] , [ 'rack' , 'u' ] ) ;
#print Dumper($CECPOSITIONS);
}
2010-09-16 02:05:28 +00:00
# Write BB info (hash key=xcat-building-blocks)
my $ framesperbb = $ STANZAS { 'xcat-building-blocks' } - > { 'num-frames-per-bb' } ;
2010-10-29 19:09:18 +00:00
if ( $ framesperbb && ( ! scalar ( keys ( %$ sections ) ) || $$ sections { 'xcat-building-blocks' } ) ) {
unless ( writebb ( $ framesperbb ) ) { closetables ( ) ; return ; }
}
2010-09-16 02:05:28 +00:00
# Write lpar info in ppc, noderes, servicenode
2010-10-14 16:00:20 +00:00
my $ snrange = $ STANZAS { 'xcat-service-nodes' } - > { 'hostname-range' } ;
2010-10-29 19:09:18 +00:00
if ( $ snrange && ( ! scalar ( keys ( %$ sections ) ) || $$ sections { 'xcat-service-nodes' } ) ) {
unless ( writesn ( $ snrange ) ) { closetables ( ) ; return ; }
}
2010-10-14 16:00:20 +00:00
my $ storagerange = $ STANZAS { 'xcat-storage-nodes' } - > { 'hostname-range' } ;
2010-10-29 19:09:18 +00:00
if ( $ storagerange && ( ! scalar ( keys ( %$ sections ) ) || $$ sections { 'xcat-storage-nodes' } ) ) {
unless ( writestorage ( $ storagerange ) ) { closetables ( ) ; return ; }
}
2010-10-14 16:00:20 +00:00
my $ computerange = $ STANZAS { 'xcat-compute-nodes' } - > { 'hostname-range' } ;
2010-10-29 19:09:18 +00:00
if ( $ computerange && ( ! scalar ( keys ( %$ sections ) ) || $$ sections { 'xcat-compute-nodes' } ) ) {
unless ( writecompute ( $ computerange ) ) { closetables ( ) ; return ; }
}
closetables ( ) ;
}
sub closetables {
2010-09-16 02:05:28 +00:00
# Close all the open common tables to finish up
foreach my $ tab ( keys % tables ) {
if ( $ tables { $ tab } ) { $ tables { $ tab } - > close ( ) ; }
}
}
sub writesite {
#write: domain, nameservers=<MN>
my $ domain = shift ;
infomsg ( 'Defining site attributes...' ) ;
# set the domain specified in the config file
#print "domain=$domain\n";
$ tables { 'site' } - > setAttribs ( { key = > 'domain' } , { value = > $ domain } ) ;
# set the site.nameservers value to the site.master value
my $ ref = $ tables { 'site' } - > getAttribs ( { key = > 'master' } , 'value' ) ;
if ( $ ref ) {
$ tables { 'site' } - > setAttribs ( { key = > 'nameservers' } , { value = > $ ref - > { value } } ) ;
}
2010-10-28 11:59:22 +00:00
# set the HFI switch topology
if ( $ STANZAS { 'xcat-site' } - > { topology } ) {
$ tables { 'site' } - > setAttribs ( { key = > 'topology' } , { value = > $ STANZAS { 'xcat-site' } - > { topology } } ) ;
}
2010-09-23 17:57:35 +00:00
#todo: put dynamic range in networks table
#todo: set site.dhcpinterfaces
2010-10-29 19:09:18 +00:00
return 1 ;
2010-09-16 02:05:28 +00:00
}
sub writehmc {
2010-10-28 11:59:22 +00:00
# using hostname-range, write: nodelist.node, nodelist.groups
2010-09-16 02:05:28 +00:00
my $ hmcrange = shift ;
infomsg ( 'Defining HMCs...' ) ;
2010-10-29 19:09:18 +00:00
my $ hmchash ;
unless ( $ hmchash = parsenoderange ( $ hmcrange ) ) { return 0 ; }
2010-09-16 02:05:28 +00:00
my $ nodes = [ noderange ( $ hmcrange , 0 ) ] ;
#print "$$nodes[0], $hmcstartnum\n";
if ( scalar ( @$ nodes ) ) {
#my %nodehash;
#foreach my $n (@$nodes) { print "n=$n\n"; $nodehash{$n} = { node => $n, groups => 'hmc,all' }; }
$ tables { 'nodelist' } - > setNodesAttribs ( $ nodes , { groups = > 'hmc,all' } ) ;
}
2010-10-28 11:59:22 +00:00
# using hostname-range and starting-ip, write regex for: hosts.node, hosts.ip
2010-09-16 02:05:28 +00:00
my $ hmcstartip = $ STANZAS { 'xcat-hmcs' } - > { 'starting-ip' } ;
2010-10-29 19:09:18 +00:00
if ( $ hmcstartip && isIP ( $ hmcstartip ) ) {
2010-10-21 20:05:11 +00:00
my $ hmcstartnum = $$ hmchash { 'primary-start' } ;
2010-09-16 02:05:28 +00:00
my ( $ ipbase , $ ipstart ) = $ hmcstartip =~ /^(\d+\.\d+\.\d+)\.(\d+)$/ ;
# take the number from the nodename, and as it increases, increase the ip addr
2010-10-21 20:05:11 +00:00
my $ regex = '|\S+?(\d+)$|' . "$ipbase.($ipstart+" . '$1' . "-$hmcstartnum)|" ;
2010-09-16 02:05:28 +00:00
$ tables { 'hosts' } - > setNodeAttribs ( 'hmc' , { ip = > $ regex } ) ;
}
2010-10-28 11:59:22 +00:00
# using hostname-range, write regex for: ppc.node, nodetype.nodetype
2010-09-16 02:05:28 +00:00
$ tables { 'ppc' } - > setNodeAttribs ( 'hmc' , { comments = > 'hmc' } ) ;
$ tables { 'nodetype' } - > setNodeAttribs ( 'hmc' , { nodetype = > 'hmc' } ) ;
2010-10-28 11:59:22 +00:00
# Set the 1st two hmcs as the ones CNM should send service events to
$ nodes = [ noderange ( $ hmcrange , 0 ) ] ;
$ tables { 'site' } - > setAttribs ( { key = > 'ea_primary_hmc' } , { value = > $$ nodes [ 0 ] } ) ;
if ( scalar ( @$ nodes ) >= 2 ) { $ tables { 'site' } - > setAttribs ( { key = > 'ea_backup_hmc' } , { value = > $$ nodes [ 1 ] } ) ; }
2010-10-29 19:09:18 +00:00
return 1 ;
2010-09-16 02:05:28 +00:00
}
sub writeframe {
# write hostname-range in nodelist table
my ( $ framerange , $ cwd ) = @ _ ;
infomsg ( 'Defining frames...' ) ;
my $ nodes = [ noderange ( $ framerange , 0 ) ] ;
#print "$$nodes[0], $framestartnum\n";
if ( scalar ( @$ nodes ) ) {
#my %nodehash;
#foreach my $n (@$nodes) { print "n=$n\n"; $nodehash{$n} = { node => $n, groups => 'hmc,all' }; }
$ tables { 'nodelist' } - > setNodesAttribs ( $ nodes , { groups = > 'frame,all' } ) ;
}
# Using the frame group, write starting-ip in hosts table
my $ framestartip = $ STANZAS { 'xcat-frames' } - > { 'starting-ip' } ;
2010-10-29 19:09:18 +00:00
if ( $ framestartip && isIP ( $ framestartip ) ) {
2010-10-21 20:05:11 +00:00
my $ framehash = parsenoderange ( $ framerange ) ;
my $ framestartnum = $$ framehash { 'primary-start' } ;
2010-09-16 02:05:28 +00:00
my ( $ ipbase , $ ipstart ) = $ framestartip =~ /^(\d+\.\d+\.\d+)\.(\d+)$/ ;
# take the number from the nodename, and as it increases, increase the ip addr
2010-10-21 20:05:11 +00:00
my $ regex = '|\S+?(\d+)$|' . "$ipbase.($ipstart+" . '$1' . "-$framestartnum)|" ;
2010-09-16 02:05:28 +00:00
$ tables { 'hosts' } - > setNodeAttribs ( 'frame' , { ip = > $ regex } ) ;
}
# Using the frame group, write: nodetype.nodetype, nodehm.mgt
$ tables { 'nodetype' } - > setNodeAttribs ( 'frame' , { nodetype = > 'bpa' } ) ;
# Using the frame group, num-frames-per-hmc, hmc hostname-range, write regex for: ppc.node, ppc.hcp, ppc.id
# The frame # should come from the nodename
2010-10-21 20:05:11 +00:00
my $ idregex = '|\S+?(\d+)$|(0+$1)|' ;
2010-09-16 22:26:39 +00:00
my % hash = ( id = > $ idregex ) ;
if ( $ STANZAS { 'xcat-site' } - > { 'use-direct-fsp-control' } ) {
2010-10-21 20:32:14 +00:00
$ tables { 'nodehm' } - > setNodeAttribs ( 'frame' , { mgt = > 'bpa' } ) ;
2010-09-16 22:26:39 +00:00
my $ hcpregex = '|(.+)|($1)|' ; # its managed by itself
$ hash { hcp } = $ hcpregex ;
}
else {
$ tables { 'nodehm' } - > setNodeAttribs ( 'frame' , { mgt = > 'hmc' } ) ;
# let lsslp fill in the hcp
}
2010-09-16 02:05:28 +00:00
# Calculate which hmc manages this frame by dividing by num-frames-per-hmc
2010-09-16 22:26:39 +00:00
#my $framesperhmc = $STANZAS{'xcat-frames'}->{'num-frames-per-hmc'};
$ tables { 'ppc' } - > setNodeAttribs ( 'frame' , \ % hash ) ;
2010-09-16 02:05:28 +00:00
# Write vpd-file to vpd table
2010-10-29 19:09:18 +00:00
if ( $ STANZAS { 'xcat-frames' } - > { 'vpd-file' } ) {
my $ filename = fullpath ( $ STANZAS { 'xcat-frames' } - > { 'vpd-file' } , $ cwd ) ;
readwritevpd ( $ filename ) ;
}
return 1 ;
2010-09-16 02:05:28 +00:00
}
sub readwritevpd {
my $ filename = shift ;
if ( ! defined ( $ filename ) ) { return ; }
my $ content ;
if ( ! open ( STANZAF , $ filename ) ) { errormsg ( "Can not open file $filename." , 2 ) ; return ; }
while ( my $ line = <STANZAF> ) { $ content . = $ line ; }
close STANZAF ;
#print "content=$content";
my $ rc = xCAT::DBobjUtils - > readFileInput ( $ content ) ;
if ( $ rc ) { errormsg ( "Error in processing stanza file $filename, rc=$rc." , 2 ) ; return ; }
$ rc = xCAT::DBobjUtils - > setobjdefs ( \ % ::FILEATTRS ) ;
if ( $ rc ) { errormsg ( "Error setting database attributes from stanza file $filename, rc=$rc." , 2 ) ; return ; }
}
sub writecec {
# write hostname-range in nodelist table
my ( $ cecrange , $ cwd ) = @ _ ;
infomsg ( 'Defining CECs...' ) ;
my $ nodes = [ noderange ( $ cecrange , 0 ) ] ;
2010-10-14 16:00:20 +00:00
if ( $$ nodes [ 0 ] =~ /\[/ ) {
errormsg ( "hostname ranges with 2 sets of '[]' are not supported in xCAT 2.5 and below." , 21 ) ;
2010-10-29 19:09:18 +00:00
return 0 ;
2010-10-14 16:00:20 +00:00
}
2010-09-16 02:05:28 +00:00
if ( scalar ( @$ nodes ) ) {
#my %nodehash;
#foreach my $n (@$nodes) { print "n=$n\n"; $nodehash{$n} = { node => $n, groups => 'hmc,all' }; }
$ tables { 'nodelist' } - > setNodesAttribs ( $ nodes , { groups = > 'cec,all' } ) ;
}
# Using the cec group, write starting-ip in hosts table
my $ cecstartip = $ STANZAS { 'xcat-cecs' } - > { 'starting-ip' } ;
2010-10-29 19:09:18 +00:00
if ( $ cecstartip && isIP ( $ cecstartip ) ) {
2010-09-25 15:14:10 +00:00
my ( $ ipbase , $ ip3rd , $ ip4th ) = $ cecstartip =~ /^(\d+\.\d+)\.(\d+)\.(\d+)$/ ;
2010-09-16 02:05:28 +00:00
# take the number from the nodename, and as it increases, increase the ip addr
2010-09-25 15:14:10 +00:00
my $ cechash = parsenoderange ( $ cecrange ) ;
2010-10-14 16:00:20 +00:00
#print Dumper($cechash);
my $ regex ;
if ( defined ( $$ cechash { 'secondary-start' } ) ) {
# using name like f1c1
my $ primstartnum = $$ cechash { 'primary-start' } ;
my $ secstartnum = $$ cechash { 'secondary-start' } ;
# Math for 3rd field: ip3rd+primnum-primstartnum
# Math for 4th field: ip4th+secnum-secstartnum
$ regex = '|\D+(\d+)\D+(\d+)$|' . "$ipbase.($ip3rd+" . '$1' . "-$primstartnum).($ip4th+" . '$2' . "-$secstartnum)|" ;
}
else {
# using name like cec01
my $ cecstartnum = $$ cechash { 'primary-start' } ;
# Math for 4th field: (ip4th-1+cecnum-cecstartnum)%254 + 1
# Math for 3rd field: (ip4th-1+cecnum-cecstartnum)/254 + ip3rd
2010-10-21 20:05:11 +00:00
$ regex = '|\S+?(\d+)$|' . "$ipbase.((${ip4th}-1+" . '$1' . "-$cecstartnum)/254+$ip3rd).((${ip4th}-1+" . '$1' . "-$cecstartnum)%254+1)|" ;
2010-10-14 16:00:20 +00:00
}
2010-09-16 02:05:28 +00:00
$ tables { 'hosts' } - > setNodeAttribs ( 'cec' , { ip = > $ regex } ) ;
}
2010-10-14 16:00:20 +00:00
# Using the cec group, write: nodetype.nodetype
2010-09-16 02:05:28 +00:00
$ tables { 'nodetype' } - > setNodeAttribs ( 'cec' , { nodetype = > 'fsp' } ) ;
2010-10-15 20:08:12 +00:00
# Write regex for ppc.hcp, nodehm.mgt
2010-09-16 22:26:39 +00:00
if ( $ STANZAS { 'xcat-site' } - > { 'use-direct-fsp-control' } ) {
$ tables { 'nodehm' } - > setNodeAttribs ( 'cec' , { mgt = > 'fsp' } ) ;
my $ hcpregex = '|(.+)|($1)|' ; # its managed by itself
$ tables { 'ppc' } - > setNodeAttribs ( 'cec' , { hcp = > $ hcpregex } ) ;
}
else {
$ tables { 'nodehm' } - > setNodeAttribs ( 'cec' , { mgt = > 'hmc' } ) ;
# let lsslp fill in the hcp
}
2010-09-16 02:05:28 +00:00
2010-10-29 19:09:18 +00:00
# Create dynamic groups for the nodes in each cec
my $ ntab = xCAT::Table - > new ( 'nodegroup' , - create = > 1 , - autocommit = > 0 ) ;
if ( ! $ ntab ) { errormsg ( "Can not open nodegroup table in database." , 3 ) ; }
else {
$ nodes = [ noderange ( $ cecrange , 0 ) ] ; # the setNodesAttribs() function blanks out the nodes array
foreach my $ n ( @$ nodes ) {
$ ntab - > setAttribs ( { groupname = > "${n}nodes" } , { grouptype = > 'dynamic' , members = > 'dynamic' , wherevals = > "parent==$n" } ) ;
}
$ ntab - > commit ( ) ;
$ ntab - > close ( ) ;
}
2010-09-23 12:52:29 +00:00
# Write supernode-list in ppc.supernode. While we are at it, also assign the cage id and parent.
2010-09-16 02:05:28 +00:00
$ nodes = [ noderange ( $ cecrange , 0 ) ] ; # the setNodesAttribs() function blanks out the nodes array
my % framesupers ;
2010-10-29 19:09:18 +00:00
if ( ! ( $ STANZAS { 'xcat-cecs' } - > { 'supernode-list' } ) ) { return 1 ; }
2010-09-16 02:05:28 +00:00
my $ filename = fullpath ( $ STANZAS { 'xcat-cecs' } - > { 'supernode-list' } , $ cwd ) ;
2010-10-29 19:09:18 +00:00
unless ( readsupers ( $ filename , \ % framesupers ) ) { return ; }
2010-09-16 02:05:28 +00:00
my $ i = 0 ; # the index into the array of cecs
2010-10-14 16:00:20 +00:00
my % ppchash ;
2010-09-16 02:05:28 +00:00
my % nodehash ;
2010-10-29 19:09:18 +00:00
my % nodeposhash ;
2010-09-16 02:05:28 +00:00
# Collect each nodes supernode num into a hash
foreach my $ k ( sort keys % framesupers ) {
my $ f = $ framesupers { $ k } ; # $f is a ptr to an array of super node numbers
if ( ! $ f ) { next ; } # in case some frame nums did not get filled in by user
2010-10-15 20:08:12 +00:00
my $ cageid = 3 ; #todo: p7 ih starts at 3, but what about other models?
2010-09-16 02:05:28 +00:00
foreach my $ s ( @$ f ) { # loop thru the supernode nums in this frame
my $ supernum = $ s ;
my $ numnodes = 4 ;
if ( $ s =~ /\(\d+\)/ ) { ( $ supernum , $ numnodes ) = $ s =~ /^(\d+)\((\d+)\)/ ; }
for ( my $ j = 0 ; $ j < $ numnodes ; $ j + + ) { # assign the next few nodes to this supernode num
my $ nodename = $$ nodes [ $ i + + ] ;
#print "Setting $nodename supernode attribute to $supernum,$j\n";
2010-10-14 16:00:20 +00:00
$ ppchash { $ nodename } = { supernode = > "$supernum,$j" , id = > $ cageid , parent = > $ k } ;
$ nodehash { $ nodename } = { groups = > "${k}cecs,cec,all" } ;
2010-10-29 19:09:18 +00:00
my ( $ framenum ) = $ k =~ /\S+?(\d+)$/ ;
$ nodeposhash { $ nodename } = { rack = > $ framenum + 0 , u = > $ cageid } ;
2010-09-23 17:57:35 +00:00
$ cageid += 2 ;
2010-09-16 02:05:28 +00:00
}
}
}
# Now write all of the supernode values to the ppc table
2010-10-14 16:00:20 +00:00
if ( scalar ( keys % framesupers ) ) {
$ tables { 'ppc' } - > setNodesAttribs ( \ % ppchash ) ;
$ tables { 'nodelist' } - > setNodesAttribs ( \ % nodehash ) ;
2010-10-29 19:09:18 +00:00
$ tables { 'nodepos' } - > setNodesAttribs ( \ % nodeposhash ) ;
2010-10-14 16:00:20 +00:00
}
2010-10-29 19:09:18 +00:00
return 1 ;
2010-09-16 02:05:28 +00:00
}
# Read/parse the supernode-list file and return the values in a hash of arrays
sub readsupers {
my $ filename = shift ;
my $ framesup = shift ;
if ( ! defined ( $ filename ) ) { return ; }
my $ input ;
if ( ! open ( $ input , $ filename ) ) {
errormsg ( "Can not open file $filename." , 2 ) ;
2010-10-29 19:09:18 +00:00
return 0 ;
2010-09-16 02:05:28 +00:00
}
my $ l ;
my $ linenum = 0 ;
while ( $ l = <$input> ) {
$ linenum + + ;
# skip blank and comment lines
next if ( $ l =~ /^\s*$/ || $ l =~ /^\s*#/ ) ;
#print "l=$l\n";
# process a real line - name, then colon, then only whitespace, numbers, and parens
my ( $ frame , $ supernums ) ;
if ( ( $ frame , $ supernums ) = $ l =~ /^\s*(\S+)\s*:\s*([\s,\(\)\d]+)$/ ) {
#print "frame=$frame, supernums=$supernums\n";
2010-10-29 19:09:18 +00:00
my $ supers = [ split ( /[\s,]+/ , $ supernums ) ] ;
# check the format of the super number entries
foreach my $ s ( @$ supers ) {
unless ( $ s =~ /^\d+$/ || $ s =~ /^\d+\(\d+\)$/ ) { errormsg ( "invalid supernode specification $s in supernode-list file line $linenum." , 8 ) ; return 0 ; }
}
# store the entries
$$ framesup { $ frame } = $ supers ;
2010-09-16 02:05:28 +00:00
}
else {
2010-10-29 19:09:18 +00:00
errormsg ( "syntax error on supernode-list file line $linenum." , 3 ) ;
return 0 ;
2010-09-16 02:05:28 +00:00
}
} # end while - go to next line
close ( $ input ) ;
2010-10-29 19:09:18 +00:00
return 1 ;
2010-09-16 02:05:28 +00:00
}
sub writebb {
my $ framesperbb = shift ;
infomsg ( 'Defining building blocks...' ) ;
# Set site.sharedtftp=1 since we have bldg blocks
$ tables { 'site' } - > setAttribs ( { key = > 'sharedtftp' } , { value = > 1 } ) ;
2010-10-14 16:00:20 +00:00
# Using num-frames-per-bb write ppc.parent (frame #) for bpas
2010-10-29 19:09:18 +00:00
if ( $ framesperbb !~ /^\d+$/ ) { errormsg ( "invalid non-integer value for num-frames-per-bb: $framesperbb" , 7 ) ; return 0 ; }
2010-10-21 20:05:11 +00:00
my $ bbregex = '|\S+?(\d+)$|((($1-1)/' . $ framesperbb . ')+1)|' ;
2010-09-16 02:05:28 +00:00
$ tables { 'ppc' } - > setNodeAttribs ( 'frame' , { parent = > $ bbregex } ) ;
2010-10-29 19:09:18 +00:00
return 1 ;
2010-09-16 02:05:28 +00:00
}
# Create service node definitions
sub writesn {
my $ range = shift ;
infomsg ( 'Defining service nodes...' ) ;
2010-10-14 16:00:20 +00:00
# We support name formats: sn01 or (todo:) b1s1
2010-09-16 02:05:28 +00:00
my $ nodes = [ noderange ( $ range , 0 ) ] ;
2010-10-14 16:00:20 +00:00
my $ rangeparts = parsenoderange ( $ range ) ;
my ( $ startnum ) = $$ rangeparts { 'primary-start' } ; # save this value for later
2010-09-16 02:05:28 +00:00
if ( scalar ( @$ nodes ) ) {
$ tables { 'nodelist' } - > setNodesAttribs ( $ nodes , { groups = > 'service,all' } ) ;
}
# Write regex for: hosts.node, hosts.ip
2010-10-14 16:00:20 +00:00
my $ startip = $ STANZAS { 'xcat-service-nodes' } - > { 'starting-ip' } ;
2010-10-29 19:09:18 +00:00
if ( $ startip && isIP ( $ startip ) ) {
2010-09-16 02:05:28 +00:00
my ( $ ipbase , $ ipstart ) = $ startip =~ /^(\d+\.\d+\.\d+)\.(\d+)$/ ;
# take the number from the nodename, and as it increases, increase the ip addr
2010-10-21 20:05:11 +00:00
my $ regex = '|\S+?(\d+)$|' . "$ipbase.($ipstart+" . '$1' . "-$startnum)|" ;
2010-09-16 02:05:28 +00:00
my % hash = ( ip = > $ regex ) ;
2010-10-14 16:00:20 +00:00
my $ otherint = $ STANZAS { 'xcat-service-nodes' } - > { 'otherinterfaces' } ;
2010-09-16 02:05:28 +00:00
if ( $ otherint ) {
# need to replace each ip addr in otherinterfaces with a regex
my @ ifs = split ( /[\s,]+/ , $ otherint ) ;
foreach my $ if ( @ ifs ) {
my ( $ nic , $ startip ) = split ( /:/ , $ if ) ;
2010-10-29 19:09:18 +00:00
if ( ! isIP ( $ startip ) ) { next ; }
2010-09-16 02:05:28 +00:00
( $ ipbase , $ ipstart ) = $ startip =~ /^(\d+\.\d+\.\d+)\.(\d+)$/ ;
$ if = "$nic:$ipbase.($ipstart+" . '$1' . "-$startnum)" ;
}
2010-10-21 20:05:11 +00:00
$ regex = '|\S+?(\d+)$|' . join ( ',' , @ ifs ) . '|' ;
2010-09-16 02:05:28 +00:00
#print "regex=$regex\n";
$ hash { otherinterfaces } = $ regex ;
}
$ tables { 'hosts' } - > setNodeAttribs ( 'service' , \ % hash ) ;
}
2010-10-14 16:00:20 +00:00
# Write regex for: ppc.id, nodetype.nodetype, etc.
2010-09-16 02:05:28 +00:00
$ tables { 'ppc' } - > setNodeAttribs ( 'service' , { id = > '1' } ) ;
$ tables { 'nodetype' } - > setNodeAttribs ( 'service' , { nodetype = > 'osi' , arch = > 'ppc64' } ) ;
$ tables { 'nodehm' } - > setNodeAttribs ( 'service' , { mgt = > 'fsp' , cons = > 'fsp' } ) ;
$ tables { 'noderes' } - > setNodeAttribs ( 'service' , { netboot = > 'yaboot' } ) ;
my $ sntab = xCAT::Table - > new ( 'servicenode' , - create = > 1 ) ;
if ( ! $ sntab ) { errormsg ( "Can not open servicenode table in database." , 3 ) ; }
else {
$ sntab - > setNodeAttribs ( 'service' , { nameserver = > 1 , dhcpserver = > 1 , tftpserver = > 1 , nfsserver = > 1 , conserver = > 1 , monserver = > 1 , ftpserver = > 1 , nimserver = > 1 , ipforward = > 1 } ) ;
}
2010-10-28 11:59:22 +00:00
if ( $ STANZAS { 'll-config' } - > { 'central_manager_list' } ) { # write the LL postscript for service nodes
my $ ref = $ tables { 'postscripts' } - > getNodeAttribs ( 'service' , 'postscripts' ) ;
#print Dumper($ref);
my $ posts ;
if ( $ ref && $ ref - > { postscripts } =~ /\S/ ) {
$ posts = $ ref - > { postscripts } ;
if ( $ posts !~ /(^|,)llserver\.sh(,|$)/ ) { $ posts . = ",llserver.sh" ; }
}
else { $ posts = "llserver.sh" ; }
$ tables { 'postscripts' } - > setNodeAttribs ( 'service' , { postscripts = > $ posts } ) ;
}
2010-09-16 02:05:28 +00:00
2010-10-14 16:00:20 +00:00
# Figure out what cec each sn is in and write ppc.hcp and ppc.parent
# Math for SN in BB: cecnum = ( ( (snnum-1) / snsperbb) * cecsperbb) + cecstart-1 + snpositioninbb
2010-09-25 15:14:10 +00:00
my $ cecsperbb = $ STANZAS { 'xcat-building-blocks' } - > { 'num-cecs-per-bb' } ;
2010-10-29 19:09:18 +00:00
if ( $ cecsperbb !~ /^\d+$/ ) { errormsg ( "invalid non-integer value for num-cecs-per-bb: $cecsperbb" , 7 ) ; return 0 ; }
2010-10-14 16:00:20 +00:00
my $ snsperbb = $ STANZAS { 'xcat-service-nodes' } - > { 'num-service-nodes-per-bb' } ;
2010-10-29 19:09:18 +00:00
if ( $ snsperbb !~ /^\d+$/ ) { errormsg ( "invalid non-integer value for num-service-nodes-per-bb: $snsperbb" , 7 ) ; return 0 ; }
2010-10-14 16:00:20 +00:00
my @ positions = split ( /[\s,]+/ , $ STANZAS { 'xcat-service-nodes' } - > { 'cec-positions-in-bb' } ) ;
2010-10-29 19:09:18 +00:00
if ( scalar ( @ positions ) != $ snsperbb ) { errormsg ( "invalid number of positions specified for xcat-service-nodes:cec-positions-in-bb." , 3 ) ; return 0 ; }
2010-09-25 15:14:10 +00:00
my $ cechash = parsenoderange ( $ STANZAS { 'xcat-cecs' } - > { 'hostname-range' } ) ;
2010-10-14 16:00:20 +00:00
my $ cecbase = $$ cechash { 'primary-base' } ;
my $ cecstart = $$ cechash { 'primary-start' } ;
my $ ceclen = length ( $$ cechash { 'primary-start' } ) ;
# these are only needed for names like f2c3
my $ secbase = $$ cechash { 'secondary-base' } ;
my $ secstart = $$ cechash { 'secondary-start' } ;
my $ secend = $$ cechash { 'secondary-end' } ;
my $ seclen = length ( $$ cechash { 'secondary-start' } ) ;
$ nodes = [ noderange ( $ range , 0 ) ] ;
my % nodehash ;
2010-10-29 19:09:18 +00:00
my % nodeposhash ;
2010-10-14 16:00:20 +00:00
my % grouphash ;
# Go thru each service node and calculate which cec it is in
for ( my $ i = 0 ; $ i < scalar ( @$ nodes ) ; $ i + + ) {
# figure out the BB num to add this node to that group
my $ bbnum = int ( $ i / $ snsperbb ) + 1 ;
2010-10-15 20:08:12 +00:00
my $ bbname = "bb$bbnum" ;
2010-10-14 16:00:20 +00:00
$ grouphash { $$ nodes [ $ i ] } = { groups = > "${bbname}service,service,all" } ;
# figure out the CEC num
my $ snpositioninbb = $ positions [ $ i % $ snsperbb ] ; # the offset within the BB
my $ cecnum = ( int ( $ i / $ snsperbb ) * $ cecsperbb ) + $ snpositioninbb ; # which cec num, counting from the beginning
my $ cecname ;
if ( ! $ secbase ) {
$ cecname = $ cecbase . sprintf ( "%0${ceclen}d" , $ cecnum ) ;
}
else { # calculate the 2 indexes for a name like f2c3
# we essentially have to do base n math, where n is the size of the second range
my $ n = $ secend - $ secstart + 1 ;
my $ primary = int ( ( $ cecnum - 1 ) / $ n ) + 1 ;
my $ secondary = ( $ cecnum - 1 ) % $ n + 1 ;
$ cecname = $ cecbase . sprintf ( "%0${ceclen}d" , $ primary ) . $ secbase . sprintf ( "%0${seclen}d" , $ secondary ) ;
}
#print "sn=$$nodes[$i], cec=$cecname\n";
$ nodehash { $$ nodes [ $ i ] } = { hcp = > $ cecname , parent = > $ cecname } ;
2010-10-29 19:09:18 +00:00
#print Dumper($CECPOSITIONS);
#print "cecname=$cecname\n";
$ nodeposhash { $$ nodes [ $ i ] } = { rack = > $ CECPOSITIONS - > { $ cecname } - > [ 0 ] - > { rack } , u = > $ CECPOSITIONS - > { $ cecname } - > [ 0 ] - > { u } } ;
2010-10-14 16:00:20 +00:00
}
$ tables { 'ppc' } - > setNodesAttribs ( \ % nodehash ) ;
$ tables { 'nodelist' } - > setNodesAttribs ( \ % grouphash ) ;
2010-10-29 19:09:18 +00:00
$ tables { 'nodepos' } - > setNodesAttribs ( \ % nodeposhash ) ;
2010-10-28 11:59:22 +00:00
# Create dynamic groups for the nodes in each cec
my $ ntab = xCAT::Table - > new ( 'nodegroup' , - create = > 1 , - autocommit = > 0 ) ;
if ( ! $ ntab ) { errormsg ( "Can not open nodegroup table in database." , 3 ) ; }
else {
$ nodes = [ noderange ( $ range , 0 ) ] ; # the setNodesAttribs() function blanks out the nodes array
foreach my $ n ( @$ nodes ) {
$ ntab - > setAttribs ( { groupname = > "${n}nodes" } , { grouptype = > 'dynamic' , members = > 'dynamic' , wherevals = > "xcatmaster==$n" } ) ;
}
$ ntab - > commit ( ) ;
$ ntab - > close ( ) ;
}
2010-10-29 19:09:18 +00:00
return 1 ;
2010-09-16 02:05:28 +00:00
}
# Create storage node definitions
sub writestorage {
my $ range = shift ;
infomsg ( 'Defining storage nodes...' ) ;
my $ nodes = [ noderange ( $ range , 0 ) ] ;
2010-10-14 16:00:20 +00:00
my $ rangeparts = parsenoderange ( $ range ) ;
my ( $ startnum ) = $$ rangeparts { 'primary-start' } ; # save this value for later
2010-09-16 02:05:28 +00:00
if ( scalar ( @$ nodes ) ) {
$ tables { 'nodelist' } - > setNodesAttribs ( $ nodes , { groups = > 'storage,all' } ) ;
}
# Write regex for: hosts.node, hosts.ip
2010-10-14 16:00:20 +00:00
my $ startip = $ STANZAS { 'xcat-storage-nodes' } - > { 'starting-ip' } ;
2010-10-29 19:09:18 +00:00
if ( $ startip && isIP ( $ startip ) ) {
2010-09-16 02:05:28 +00:00
my ( $ ipbase , $ ipstart ) = $ startip =~ /^(\d+\.\d+\.\d+)\.(\d+)$/ ;
# take the number from the nodename, and as it increases, increase the ip addr
2010-10-21 20:05:11 +00:00
my $ regex = '|\S+?(\d+)$|' . "$ipbase.($ipstart+" . '$1' . "-$startnum)|" ;
2010-09-16 02:05:28 +00:00
my % hash = ( ip = > $ regex ) ;
2010-10-14 16:00:20 +00:00
my $ otherint = $ STANZAS { 'xcat-storage-nodes' } - > { 'otherinterfaces' } ;
2010-09-16 02:05:28 +00:00
if ( $ otherint ) {
# need to replace each ip addr in otherinterfaces with a regex
my @ ifs = split ( /[\s,]+/ , $ otherint ) ;
foreach my $ if ( @ ifs ) {
my ( $ nic , $ startip ) = split ( /:/ , $ if ) ;
2010-10-29 19:09:18 +00:00
if ( ! isIP ( $ startip ) ) { next ; }
2010-09-16 02:05:28 +00:00
( $ ipbase , $ ipstart ) = $ startip =~ /^(\d+\.\d+\.\d+)\.(\d+)$/ ;
$ if = "$nic:$ipbase.($ipstart+" . '$1' . "-$startnum)" ;
}
2010-10-21 20:05:11 +00:00
$ regex = '|\S+?(\d+)$|' . join ( ',' , @ ifs ) . '|' ;
2010-09-16 02:05:28 +00:00
#print "regex=$regex\n";
$ hash { otherinterfaces } = $ regex ;
}
2010-10-14 16:00:20 +00:00
my $ aliases = $ STANZAS { 'xcat-storage-nodes' } - > { 'aliases' } ;
2010-09-16 02:05:28 +00:00
if ( $ aliases ) {
2010-10-29 19:09:18 +00:00
# support more than 1 alias
my @ alist = split ( /[\s,]+/ , $ aliases ) ;
foreach my $ a ( @ alist ) { $ a = '($1)' . $ a ; } # prepend the hostname
$ regex = '|(.+)|' . join ( ',' , @ alist ) . '|' ;
2010-09-16 02:05:28 +00:00
$ hash { hostnames } = $ regex ;
}
$ tables { 'hosts' } - > setNodeAttribs ( 'storage' , \ % hash ) ;
}
2010-10-14 16:00:20 +00:00
# Write ppc.id, nodetype.nodetype, etc.
2010-09-16 02:05:28 +00:00
$ tables { 'ppc' } - > setNodeAttribs ( 'storage' , { id = > '1' } ) ;
$ tables { 'nodetype' } - > setNodeAttribs ( 'storage' , { nodetype = > 'osi' , arch = > 'ppc64' } ) ;
$ tables { 'nodehm' } - > setNodeAttribs ( 'storage' , { mgt = > 'fsp' , cons = > 'fsp' } ) ;
$ tables { 'noderes' } - > setNodeAttribs ( 'storage' , { netboot = > 'yaboot' } ) ;
2010-10-14 16:00:20 +00:00
# Figure out what cec each storage node is in and write ppc.hcp, ppc.parent, noderes.xcatmaster, noderes.servicenode
# Math for SN in BB: cecnum = ( ( (snnum-1) / snsperbb) * cecsperbb) + cecstart-1 + snpositioninbb
my $ cecsperbb = $ STANZAS { 'xcat-building-blocks' } - > { 'num-cecs-per-bb' } ;
2010-10-29 19:09:18 +00:00
if ( $ cecsperbb !~ /^\d+$/ ) { errormsg ( "invalid non-integer value for num-cecs-per-bb: $cecsperbb" , 7 ) ; return 0 ; }
2010-10-14 16:00:20 +00:00
my $ snsperbb = $ STANZAS { 'xcat-storage-nodes' } - > { 'num-storage-nodes-per-bb' } ;
2010-10-29 19:09:18 +00:00
if ( $ snsperbb !~ /^\d+$/ ) { errormsg ( "invalid non-integer value for num-storage-nodes-per-bb: $snsperbb" , 7 ) ; return 0 ; }
2010-10-14 16:00:20 +00:00
my @ positions = split ( /[\s,]+/ , $ STANZAS { 'xcat-storage-nodes' } - > { 'cec-positions-in-bb' } ) ;
2010-10-29 19:09:18 +00:00
if ( scalar ( @ positions ) != $ snsperbb ) { errormsg ( "invalid number of positions specified for xcat-storage-nodes:cec-positions-in-bb." , 3 ) ; return 0 ; }
2010-10-14 16:00:20 +00:00
my $ cechash = parsenoderange ( $ STANZAS { 'xcat-cecs' } - > { 'hostname-range' } ) ;
my $ cecbase = $$ cechash { 'primary-base' } ;
my $ cecstart = $$ cechash { 'primary-start' } ;
my $ ceclen = length ( $$ cechash { 'primary-start' } ) ;
# these are only needed for names like f2c3
my $ secbase = $$ cechash { 'secondary-base' } ;
my $ secstart = $$ cechash { 'secondary-start' } ;
my $ secend = $$ cechash { 'secondary-end' } ;
my $ seclen = length ( $$ cechash { 'secondary-start' } ) ;
my $ sns = [ noderange ( $ STANZAS { 'xcat-service-nodes' } - > { 'hostname-range' } , 0 ) ] ;
$ nodes = [ noderange ( $ range , 0 ) ] ;
my % nodehash ;
2010-10-29 19:09:18 +00:00
my % nodeposhash ;
2010-10-14 16:00:20 +00:00
my % grouphash ;
my % nodereshash ;
# Go thru each storage node and calculate which cec it is in
for ( my $ i = 0 ; $ i < scalar ( @$ nodes ) ; $ i + + ) {
# figure out the BB num to add this node to that group
my $ bbnum = int ( $ i / $ snsperbb ) + 1 ;
2010-10-15 20:08:12 +00:00
my $ bbname = "bb$bbnum" ;
2010-10-14 16:00:20 +00:00
$ grouphash { $$ nodes [ $ i ] } = { groups = > "${bbname}storage,storage,all" } ;
# figure out the CEC num
my $ snpositioninbb = $ positions [ $ i % $ snsperbb ] ; # the offset within the BB
my $ cecnum = ( int ( $ i / $ snsperbb ) * $ cecsperbb ) + $ snpositioninbb ; # which cec num, counting from the beginning
my $ cecname ;
if ( ! $ secbase ) {
$ cecname = $ cecbase . sprintf ( "%0${ceclen}d" , $ cecnum ) ;
}
else { # calculate the 2 indexes for a name like f2c3
# we essentially have to do base n math, where n is the size of the second range
my $ n = $ secend - $ secstart + 1 ;
my $ primary = int ( ( $ cecnum - 1 ) / $ n ) + 1 ;
my $ secondary = ( $ cecnum - 1 ) % $ n + 1 ;
$ cecname = $ cecbase . sprintf ( "%0${ceclen}d" , $ primary ) . $ secbase . sprintf ( "%0${seclen}d" , $ secondary ) ;
}
#print "sn=$$nodes[$i], cec=$cecname\n";
$ nodehash { $$ nodes [ $ i ] } = { hcp = > $ cecname , parent = > $ cecname } ;
2010-10-29 19:09:18 +00:00
$ nodeposhash { $$ nodes [ $ i ] } = { rack = > $ CECPOSITIONS - > { $ cecname } - > [ 0 ] - > { rack } , u = > $ CECPOSITIONS - > { $ cecname } - > [ 0 ] - > { u } } ;
2010-10-14 16:00:20 +00:00
# Now determine the service node this compute node is under
#my $bbnum = int(($cecnum-1) / $cecsperbb) + 1;
my $ cecinthisbb = ( $ cecnum - 1 ) % $ cecsperbb + 1 ;
my $ servsperbb = $ STANZAS { 'xcat-service-nodes' } - > { 'num-service-nodes-per-bb' } ;
my $ cecspersn = int ( $ cecsperbb / $ servsperbb ) ;
my $ snoffset = int ( ( $ cecinthisbb - 1 ) / $ cecspersn ) + 1 ;
my $ snsbeforethisbb = ( $ bbnum - 1 ) * $ servsperbb ;
my $ snnum = $ snsbeforethisbb + $ snoffset ;
my $ snname = $$ sns [ $ snnum - 1 ] ;
# generate a list of the other SNs in this BB
my $ othersns ;
for ( my $ s = $ snsbeforethisbb + 1 ; $ s <= $ snsbeforethisbb + $ servsperbb ; $ s + + ) {
if ( $ s != $ snnum ) { $ othersns . = ',' . $$ sns [ $ s - 1 ] ; }
}
$ nodereshash { $$ nodes [ $ i ] } = { xcatmaster = > $ snname , servicenode = > "$snname$othersns" } ;
}
$ tables { 'ppc' } - > setNodesAttribs ( \ % nodehash ) ;
$ tables { 'nodelist' } - > setNodesAttribs ( \ % grouphash ) ;
$ tables { 'noderes' } - > setNodesAttribs ( \ % nodereshash ) ;
2010-10-29 19:09:18 +00:00
$ tables { 'nodepos' } - > setNodesAttribs ( \ % nodeposhash ) ;
return 1 ;
2010-09-16 02:05:28 +00:00
}
2010-10-14 16:00:20 +00:00
# Create compute node definitions
2010-09-16 02:05:28 +00:00
sub writecompute {
my $ range = shift ;
infomsg ( 'Defining compute nodes...' ) ;
my $ nodes = [ noderange ( $ range , 0 ) ] ;
if ( scalar ( @$ nodes ) ) {
$ tables { 'nodelist' } - > setNodesAttribs ( $ nodes , { groups = > 'compute,all' } ) ;
}
# Write regex for: hosts.node, hosts.ip
2010-10-14 16:00:20 +00:00
my $ nodehash = parsenoderange ( $ range ) ;
my $ startip = $ STANZAS { 'xcat-compute-nodes' } - > { 'starting-ip' } ;
2010-10-29 19:09:18 +00:00
if ( $ startip && isIP ( $ startip ) ) {
2010-09-26 10:24:49 +00:00
my ( $ ipbase , $ ip3rd , $ ip4th ) = $ startip =~ /^(\d+\.\d+)\.(\d+)\.(\d+)$/ ;
2010-09-16 02:05:28 +00:00
# take the number from the nodename, and as it increases, increase the ip addr
2010-09-26 10:24:49 +00:00
my $ startnum = $$ nodehash { 'primary-start' } ;
# Math for 4th field: (ip4th-1+nodenum-startnum)%254 + 1
# Math for 3rd field: (ip4th-1+nodenum-startnum)/254 + ip3rd
2010-10-21 20:05:11 +00:00
my $ regex = '|\S+?(\d+)$|' . "$ipbase.((${ip4th}-1+" . '$1' . "-$startnum)/254+$ip3rd).((${ip4th}-1+" . '$1' . "-$startnum)%254+1)|" ;
2010-09-26 10:24:49 +00:00
#my $regex = '|\D+(\d+)|' . "$ipbase.($ipstart+" . '$1' . "-$startnum)|";
2010-09-16 02:05:28 +00:00
my % hash = ( ip = > $ regex ) ;
2010-10-14 16:00:20 +00:00
my $ otherint = $ STANZAS { 'xcat-compute-nodes' } - > { 'otherinterfaces' } ;
2010-09-16 02:05:28 +00:00
if ( $ otherint ) {
# need to replace each ip addr in otherinterfaces with a regex
my @ ifs = split ( /[\s,]+/ , $ otherint ) ;
foreach my $ if ( @ ifs ) {
my ( $ nic , $ startip ) = split ( /:/ , $ if ) ;
2010-10-29 19:09:18 +00:00
if ( ! isIP ( $ startip ) ) { next ; }
2010-09-26 10:24:49 +00:00
( $ ipbase , $ ip3rd , $ ip4th ) = $ startip =~ /^(\d+\.\d+)\.(\d+)\.(\d+)$/ ;
#$if = "$nic:$ipbase.($ipstart+" . '$1' . "-$startnum)";
2010-10-15 20:08:12 +00:00
$ if = "$nic:$ipbase.((${ip4th}-1+" . '$1' . "-$startnum)/254+$ip3rd).((${ip4th}-1+" . '$1' . "-$startnum)%254+1)" ;
2010-09-16 02:05:28 +00:00
}
2010-10-21 20:05:11 +00:00
$ regex = '|\S+?(\d+)$|' . join ( ',' , @ ifs ) . '|' ;
2010-09-16 02:05:28 +00:00
#print "regex=$regex\n";
$ hash { otherinterfaces } = $ regex ;
}
2010-10-14 16:00:20 +00:00
my $ aliases = $ STANZAS { 'xcat-compute-nodes' } - > { 'aliases' } ;
2010-09-16 02:05:28 +00:00
if ( $ aliases ) {
2010-10-29 19:09:18 +00:00
# support more than 1 alias
my @ alist = split ( /[\s,]+/ , $ aliases ) ;
foreach my $ a ( @ alist ) { $ a = '($1)' . $ a ; } # prepend the hostname
$ regex = '|(.+)|' . join ( ',' , @ alist ) . '|' ;
2010-09-16 02:05:28 +00:00
$ hash { hostnames } = $ regex ;
}
$ tables { 'hosts' } - > setNodeAttribs ( 'compute' , \ % hash ) ;
}
# Write regex for: nodetype.nodetype, etc.
$ tables { 'nodetype' } - > setNodeAttribs ( 'compute' , { nodetype = > 'osi' , arch = > 'ppc64' } ) ;
$ tables { 'nodehm' } - > setNodeAttribs ( 'compute' , { mgt = > 'fsp' , cons = > 'fsp' } ) ;
$ tables { 'noderes' } - > setNodeAttribs ( 'compute' , { netboot = > 'yaboot' } ) ;
2010-10-28 11:59:22 +00:00
if ( $ STANZAS { 'll-config' } - > { 'central_manager_list' } ) { # write the LL postscript for compute nodes
my $ ref = $ tables { 'postscripts' } - > getNodeAttribs ( 'compute' , 'postscripts' ) ;
#print Dumper($ref);
my $ posts ;
if ( $ ref && $ ref - > { postscripts } =~ /\S/ ) {
$ posts = $ ref - > { postscripts } ;
if ( $ posts !~ /(^|,)llcompute\.sh(,|$)/ ) { $ posts . = ",llcompute.sh" ; }
}
else { $ posts = "llcompute.sh" ; }
$ tables { 'postscripts' } - > setNodeAttribs ( 'compute' , { postscripts = > $ posts } ) ;
}
2010-09-16 02:05:28 +00:00
2010-10-14 16:00:20 +00:00
# Figure out what cec each compute node is in and write ppc.hcp, ppc.parent, ppc.id, noderes.xcatmaster, noderes.servicenode
my $ cecsperbb = $ STANZAS { 'xcat-building-blocks' } - > { 'num-cecs-per-bb' } ;
2010-10-29 19:09:18 +00:00
if ( $ cecsperbb !~ /^\d+$/ ) { errormsg ( "invalid non-integer value for num-cecs-per-bb: $cecsperbb" , 7 ) ; return 0 ; }
2010-09-25 15:14:10 +00:00
my $ lparspercec = $ STANZAS { 'xcat-lpars' } - > { 'num-lpars-per-cec' } ;
2010-10-29 19:09:18 +00:00
if ( $ lparspercec !~ /^\d+$/ ) { errormsg ( "invalid non-integer value for num-lpars-per-cec: $lparspercec" , 7 ) ; return 0 ; }
2010-10-14 16:00:20 +00:00
my $ snsperbb = $ STANZAS { 'xcat-service-nodes' } - > { 'num-service-nodes-per-bb' } ;
# store the positions of service and storage nodes, so we can avoid those
my % snpositions ;
my @ positions = split ( /[\s,]+/ , $ STANZAS { 'xcat-service-nodes' } - > { 'cec-positions-in-bb' } ) ;
foreach ( @ positions ) { $ snpositions { $ _ } = 1 ; }
@ positions = split ( /[\s,]+/ , $ STANZAS { 'xcat-storage-nodes' } - > { 'cec-positions-in-bb' } ) ;
foreach ( @ positions ) { $ snpositions { $ _ } = 1 ; }
my $ cecs = [ noderange ( $ STANZAS { 'xcat-cecs' } - > { 'hostname-range' } , 0 ) ] ;
my $ sns = [ noderange ( $ STANZAS { 'xcat-service-nodes' } - > { 'hostname-range' } , 0 ) ] ;
$ nodes = [ noderange ( $ range , 0 ) ] ;
my % nodehash ;
2010-10-29 19:09:18 +00:00
my % nodeposhash ;
2010-10-14 16:00:20 +00:00
my % nodereshash ;
# set these incrementers to the imaginary position just before the 1st position
my $ cecnum = 0 ;
my $ lparid = $ lparspercec ;
# Go thru each compute node and calculate which cec it is in
for ( my $ i = 0 ; $ i < scalar ( @$ nodes ) ; $ i + + ) {
if ( $ lparid >= $ lparspercec ) { $ cecnum + + ; $ lparid = 1 ; } # at the end of the cec
else { $ lparid + + }
if ( $ lparid == 1 ) { # check if this is a service or storage node position
my $ pos = ( $ cecnum - 1 ) % $ cecsperbb + 1 ;
if ( $ snpositions { $ pos } ) {
if ( $ lparid >= $ lparspercec ) { $ cecnum + + ; $ lparid = 1 ; } # at the end of the cec
else { $ lparid + + }
}
}
my $ cecname = $$ cecs [ $ cecnum - 1 ] ;
my $ id = $ lparid ;
if ( $ lparspercec == 8 ) {
#todo: for now assume 8 means a p7 IH. Make a different way to determine this is a p7 IH
$ id = ( ( $ lparid - 1 ) * 4 ) + 1 ;
}
#print "sn=$$nodes[$i], cec=$cecname\n";
$ nodehash { $$ nodes [ $ i ] } = { hcp = > $ cecname , parent = > $ cecname , id = > $ id } ;
2010-10-29 19:09:18 +00:00
$ nodeposhash { $$ nodes [ $ i ] } = { rack = > $ CECPOSITIONS - > { $ cecname } - > [ 0 ] - > { rack } , u = > $ CECPOSITIONS - > { $ cecname } - > [ 0 ] - > { u } } ;
2010-10-14 16:00:20 +00:00
# Now determine the service node this compute node is under
my $ bbnum = int ( ( $ cecnum - 1 ) / $ cecsperbb ) + 1 ;
my $ cecinthisbb = ( $ cecnum - 1 ) % $ cecsperbb + 1 ;
my $ cecspersn = int ( $ cecsperbb / $ snsperbb ) ;
my $ snoffset = int ( ( $ cecinthisbb - 1 ) / $ cecspersn ) + 1 ;
my $ snsbeforethisbb = ( $ bbnum - 1 ) * $ snsperbb ;
my $ snnum = $ snsbeforethisbb + $ snoffset ;
my $ snname = $$ sns [ $ snnum - 1 ] ;
# generate a list of the other SNs in this BB
my $ othersns ;
for ( my $ s = $ snsbeforethisbb + 1 ; $ s <= $ snsbeforethisbb + $ snsperbb ; $ s + + ) {
if ( $ s != $ snnum ) { $ othersns . = ',' . $$ sns [ $ s - 1 ] ; }
}
$ nodereshash { $$ nodes [ $ i ] } = { xcatmaster = > $ snname , servicenode = > "$snname$othersns" } ;
2010-09-25 15:14:10 +00:00
}
2010-10-14 16:00:20 +00:00
$ tables { 'ppc' } - > setNodesAttribs ( \ % nodehash ) ;
$ tables { 'noderes' } - > setNodesAttribs ( \ % nodereshash ) ;
2010-10-29 19:09:18 +00:00
$ tables { 'nodepos' } - > setNodesAttribs ( \ % nodeposhash ) ;
return 1 ;
2010-09-25 15:14:10 +00:00
}
# Parse a noderange like n01-n20, n[01-20], or f[1-2]c[01-10].
# Returns a hash that contains: primary-base, primary-start, primary-end, primary-pad, secondary-base, secondary-start, secondary-end, secondary-pad
sub parsenoderange {
my $ nr = shift ;
my $ ret = { } ;
# Check for a 2 square bracket range, e.g. f[1-2]c[01-10]
2010-10-21 20:05:11 +00:00
if ( $ nr =~ /^\s*(\S+?)\[(\d+)[\-\:](\d+)\](\S+?)\[(\d+)[\-\:](\d+)\]\s*$/ ) {
( $$ ret { 'primary-base' } , $$ ret { 'primary-start' } , $$ ret { 'primary-end' } , $$ ret { 'secondary-base' } , $$ ret { 'secondary-start' } , $$ ret { 'secondary-end' } ) = ( $ 1 , $ 2 , $ 3 , $ 4 , $ 5 , $ 6 ) ;
2010-10-29 19:09:18 +00:00
if ( ( length ( $$ ret { 'primary-start' } ) != length ( $$ ret { 'primary-end' } ) ) || ( length ( $$ ret { 'secondary-start' } ) != length ( $$ ret { 'secondary-end' } ) ) ) { errormsg ( "invalid noderange format: $nr. The beginning and ending numbers of the range must have the same number of digits." , 5 ) ; return undef ; }
if ( ( $$ ret { 'primary-start' } != 1 ) || ( $$ ret { 'secondary-start' } != 1 ) ) { errormsg ( "invalid noderange format: $nr. Currently noderanges must start at 1." , 5 ) ; return undef ; }
2010-09-25 15:14:10 +00:00
return $ ret ;
}
# Check for a square bracket range, e.g. n[01-20]
2010-10-21 20:05:11 +00:00
if ( $ nr =~ /^\s*(\S+?)\[(\d+)[\-\:](\d+)\]\s*$/ ) {
( $$ ret { 'primary-base' } , $$ ret { 'primary-start' } , $$ ret { 'primary-end' } ) = ( $ 1 , $ 2 , $ 3 ) ;
2010-10-29 19:09:18 +00:00
if ( length ( $$ ret { 'primary-start' } ) != length ( $$ ret { 'primary-end' } ) ) { errormsg ( "invalid noderange format: $nr. The beginning and ending numbers of the range must have the same number of digits." , 5 ) ; return undef ; }
if ( $$ ret { 'primary-start' } != 1 ) { errormsg ( "invalid noderange format: $nr. Currently noderanges must start at 1." , 5 ) ; return undef ; }
2010-09-25 15:14:10 +00:00
return $ ret ;
}
# Check for normal range, e.g. n01-n20
my $ base2 ;
2010-10-21 20:05:11 +00:00
if ( $ nr =~ /^\s*(\S+?)(\d+)\-(\S+?)(\d+)\s*$/ ) {
( $$ ret { 'primary-base' } , $$ ret { 'primary-start' } , $ base2 , $$ ret { 'primary-end' } ) = ( $ 1 , $ 2 , $ 3 , $ 4 ) ;
2010-10-29 19:09:18 +00:00
if ( $$ ret { 'primary-base' } ne $ base2 ) { errormsg ( "invalid noderange format: $nr" , 5 ) ; return undef ; }
if ( length ( $$ ret { 'primary-start' } ) != length ( $$ ret { 'primary-end' } ) ) { errormsg ( "invalid noderange format: $nr. The beginning and ending numbers of the range must have the same number of digits." , 5 ) ; return undef ; }
if ( $$ ret { 'primary-start' } != 1 ) { errormsg ( "invalid noderange format: $nr. Currently noderanges must start at 1." , 5 ) ; return undef ; }
2010-09-25 15:14:10 +00:00
return $ ret ;
}
2010-10-21 20:05:11 +00:00
# It may be a simple single nodename
if ( $ nr =~ /^\s*([^\[\]\-\:\s]+?)(\d+)\s*$/ ) {
( $$ ret { 'primary-base' } , $$ ret { 'primary-start' } , $$ ret { 'primary-end' } ) = ( $ 1 , $ 2 , $ 2 ) ;
return $ ret ;
}
errormsg ( "invalid noderange format: $nr" , 5 ) ;
2010-09-25 15:14:10 +00:00
return undef ; # range did not match any of the cases above
2010-09-16 02:05:28 +00:00
}
2010-10-29 19:09:18 +00:00
# Verify this is valid IP address format (ipv4 only for right now).
# If not, print error msg and return 0.
sub isIP {
my $ ip = shift ;
if ( $ ip =~ /^\d+\.\d+\.\d+\.\d+$/ ) { return 1 ; }
errormsg ( "invalid IP address format: $ip" , 6 ) ;
return 0 ;
}
2010-09-16 02:05:28 +00:00
sub errormsg {
my $ msg = shift ;
my $ exitcode = shift ;
my % rsp ;
push @ { $ rsp { error } } , $ msg ;
xCAT::MsgUtils - > message ( 'E' , \ % rsp , $ CALLBACK , $ exitcode ) ;
return ;
}
sub infomsg {
my $ msg = shift ;
my % rsp ;
push @ { $ rsp { info } } , $ msg ;
xCAT::MsgUtils - > message ( 'I' , \ % rsp , $ CALLBACK ) ;
return ;
}
sub fullpath {
my ( $ filename , $ cwd ) = @ _ ;
if ( $ filename =~ /^\s*\// ) { return $ filename ; } # it was already a full path
return xCAT::Utils - > full_path ( $ filename , $ cwd ) ;
}
1 ;