diff --git a/xCAT-client/pods/man8/xcatsetup.8.pod b/xCAT-client/pods/man8/xcatsetup.8.pod new file mode 100644 index 000000000..499239232 --- /dev/null +++ b/xCAT-client/pods/man8/xcatsetup.8.pod @@ -0,0 +1,201 @@ +=head1 NAME + +B - Prime the xCAT database using naming conventions specified in a config file. + +=head1 SYNOPSIS + +B [I] + +B [B<-?> | B<-h> | B<--help> | B<-v> | B<--version>] + +=head1 DESCRIPTION + +The B command reads the specified config file that contains general information about the cluster being set up, +and naming conventions and IP addresses that you want to use. It then defines the basic objects in the xCAT database +representing this cluster configuration. The B command prepares the database for the step of discovering +the hardware that is connected to the service and cluster networks. + +The B command is intended as a quick way to fill out the database for a cluster that has very regular +naming patterns. The only thing is done is fill in database attributes. If your cluster does not follow consistent +naming patterns, or has some other special configuration, you should define attribute values manually instead of using +B. + +Note: currently the B command has only been implemented and tested for system p servers. + +The B is organized in stanza format and supports the keywords in the sample file below. Comment lines +begin with "#". Stanzas can be ommitted if you do not want to define that type of object. + + xcat-site: + domain = cluster.com + + xcat-hmcs: + hostname-range = hmc1-hmc3 + starting-ip = 10.201.0.1 + + xcat-frames: + # these are the connections to the BPCs + hostname-range = bpc1-bpc6 + starting-ip = 10.202.0.1 + num-frames-per-hmc = 2 + vpd-file = vpd.stanza + + xcat-cecs: + # these are the connections to the FSPs + hostname-range = cec01-cec60 + starting-ip = 10.203.0.1 + supernode-list = supernodelist.txt + + xcat-building-blocks: + num-frames-per-bb = 2 + num-cecs-per-bb = 20 + + xcat-lpars: + num-lpars-per-cec = 8 + + num-service-nodes-per-bb = 2 + # this is for the ethernet NIC on each SN + service-node-hostname-range = sn1-sn6 + service-node-starting-ip = 10.200.1.1 + # this value is the same format as the hosts.otherinterfaces attribute except + # the IP addresses are starting IP addresses + service-node-otherinterfaces = -hf0:10.10.1.1,-hf1:10.11.1.1,-hf2:10.12.1.1,-hf3:10.13.1.1 + + num-storage-nodes-per-bb = 3 + storage-node-hostname-range = stor01-stor09 + storage-node-starting-ip = 10.20.1.1 + storage-node-aliases = -hf0 + storage-node-otherinterfaces = -hf1:10.21.1.1,-hf2:10.22.1.1,-hf3:10.23.1.1 + + num-compute-nodes-per-bb = 155 + compute-node-hostname-range = n001-n465 + compute-node-starting-ip = 10.30.1.1 + compute-node-aliases = -hf0 + # ml0 is for aix. For linux, use bond0 instead. + compute-node-otherinterfaces = -hf1:10.31.1.1,-hf2:10.32.1.1,-hf3:10.33.1.1,-ml0:10.34.1.1 + +The B specifies the following vpd table attributes for the BPCs (frame power supplies): node, +serial, mtm, side. Use the same stanza format that accepted by the L command, as documented +in L. Here is a sample file: + + bpc01: + objtype=node + serial=99200G1 + mtm=9A00-100 + side=A + + bpc02: + objtype=node + serial=99200D1 + mtm=9A00-100 + side=A + +The supernode-list file lists what supernode numbers should be given to each CEC in each frame. +Here is a sample file: + + bpc01: 0, 1, 16 + bpc02: 17, 32 + bpc03: 33, 48, 49 + bpc04: 64 , 65, 80 + bpc05: 81, 96 + bpc06: 97(1), 112(1), 113(1) + +The name before the colon is the node name of the frame BPC. The numbers after the colon are the supernode numbers +to assign to the groups of CECs in that frame from bottom to top. Each supernode contains 4 CECs, unless it is immediately +followed by "(#)", in which case the number in parenthesis indicates how many CECs are in this supernode. + +The following lists which database attributes are filled in for each stanza: + +=over 15 + +=item B + +site table: domain, nameservers + +=item B + +nodelist table: node, groups + +hosts table: node, ip + +ppc table: node, comments + +nodetype table: node, nodetype + +=item B + +nodelist table: node, groups + +hosts table: node, ip + +ppc table: node, id, hcp + +nodetype table: node, nodetype + +nodehm table: node, mgt + +vpd table: node, serial, mtm, side + +=item B + +nodelist table: node, groups + +hosts table: node, ip + +ppc table: node, supernode + +nodetype table: node, nodetype + +nodehm table: node, mgt + +=item B + +site table: sharedtftp + +ppc table: node, parent (for frame) + +=item B + +nodelist table: node, groups + +hosts table: node, ip, hostnames, otherinterfaces + +ppc table: node, id + +nodetype table: node, nodetype, arch + +nodehm table: node, mgt, cons + +noderes table: netboot + +servicenode table: node, nameserver, dhcpserver, tftpserver, nfsserver, conserver, monserver, ftpserver, nimserver, ipforward + +=back + +=head1 OPTIONS + +=over 10 + +=item B<-v|--version> + +Command Version. + +=item B<-?|-h|--help> + +Display usage message. + +=back + +=head1 RETURN VALUE + +0 The command completed successfully. + +1 An error has occurred. + +=head1 FILES + +/opt/xcat/sbin/xcatsetup + +=head1 SEE ALSO + +L, L, L, L, L, L + diff --git a/xCAT-client/xCAT-client.spec b/xCAT-client/xCAT-client.spec index e130768e9..d6c971469 100644 --- a/xCAT-client/xCAT-client.spec +++ b/xCAT-client/xCAT-client.spec @@ -151,6 +151,7 @@ ln -sf ../bin/xcatclientnnr $RPM_BUILD_ROOT/%{prefix}/sbin/rmimage ln -sf ../bin/xcatclient $RPM_BUILD_ROOT/%{prefix}/sbin/makedns ln -sf ../bin/xcatclientnnr $RPM_BUILD_ROOT/%{prefix}/bin/gettab ln -sf ../bin/xcatclientnnr $RPM_BUILD_ROOT/%{prefix}/sbin/nodeadd +ln -sf ../bin/xcatclientnnr $RPM_BUILD_ROOT/%{prefix}/sbin/xcatsetup ln -sf ../bin/xcatclientnnr $RPM_BUILD_ROOT/%{prefix}/sbin/makenetworks ln -sf ../bin/xcatclientnnr $RPM_BUILD_ROOT/%{prefix}/sbin/copycds ln -sf ../bin/xcatclientnnr $RPM_BUILD_ROOT/%{prefix}/bin/regnotif diff --git a/xCAT-server/lib/xcat/plugins/setup.pm b/xCAT-server/lib/xcat/plugins/setup.pm new file mode 100644 index 000000000..134e8e92e --- /dev/null +++ b/xCAT-server/lib/xcat/plugins/setup.pm @@ -0,0 +1,600 @@ +#!/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: +# - +# +# Limitations on the values in the config file: +# - hostname ranges must have simple format +# - IP address incrementing for ranges must currently be confined to the last field +# - the supernode-list file must contain all frames and the frame nodenames must sort correctly +# +##################################################### +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; + + my $setup_usage = sub { + my $exitcode = shift @_; + my %rsp; + push @{$rsp{data}}, "Usage: xcatsetup [-v|--version] [-?|-h|--help] "; + if ($exitcode) { $rsp{errorcode} = $exitcode; } + $CALLBACK->(\%rsp); + }; + + # Process the cmd line args + if ($args) { @ARGV = @{$args}; } + else { @ARGV = (); } + if (!GetOptions('h|?|help' => \$HELP, 'v|version' => \$VERSION) ) { $setup_usage->(1); return; } + + 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; + } + + 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 + writedb($request->{cwd}->[0]); +} + + +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, + ); + +sub writedb { + my $cwd = shift; # the current dir from the request + #todo: add syntax checking for input values + + # 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}; + if ($domain) { writesite($domain); } + + # 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'}; + if ($hmcrange) { writehmc($hmcrange); } + + # Write frame info (hash key=xcat-frames) + my $framerange = $STANZAS{'xcat-frames'}->{'hostname-range'}; + if ($framerange) { writeframe($framerange, $cwd); } + + # Write CEC info (hash key=xcat-cecs) + my $cecrange = $STANZAS{'xcat-cecs'}->{'hostname-range'}; + if ($cecrange) { writecec($cecrange, $cwd); } + + # Write BB info (hash key=xcat-building-blocks) + my $framesperbb = $STANZAS{'xcat-building-blocks'}->{'num-frames-per-bb'}; + if ($framesperbb) { writebb($framesperbb); } + + # Write lpar info in ppc, noderes, servicenode + my $snrange = $STANZAS{'xcat-lpars'}->{'service-node-hostname-range'}; + if ($snrange) { writesn($snrange); } + my $storagerange = $STANZAS{'xcat-lpars'}->{'storage-node-hostname-range'}; + if ($storagerange) { writestorage($storagerange); } + my $computerange = $STANZAS{'xcat-lpars'}->{'compute-node-hostname-range'}; + if ($computerange) { writecompute($computerange); } + + # Close all the open common tables to finish up + foreach my $tab (keys %tables) { + if ($tables{$tab}) { $tables{$tab}->close(); } + } + + # Temporarily write out the contents of the hash + #foreach my $k (keys %STANZAS) { + # my $stanza = $STANZAS{$k}; + # print "$k\n"; + # foreach my $attr (keys %$stanza) { + # my $val = $$stanza{$attr}; + # print " $attr=$val\n"; + # } + #} +} + + +sub writesite { + #write: domain, nameservers= + 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} }); + } + $tables{'site'}->close(); +} + + +sub writehmc { + #using hostname-range, write: nodelist.node, nodelist.groups + my $hmcrange = shift; + infomsg('Defining HMCs...'); + my $nodes = [noderange($hmcrange, 0)]; + my ($hmcstartnum) = $$nodes[0] =~/^\D+(\d+)$/; # save this value for later + #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' }); + } + + #using hostname-range and starting-ip, write regex for: hosts.node, hosts.ip + my $hmcstartip = $STANZAS{'xcat-hmcs'}->{'starting-ip'}; + if ($hmcstartip) { + my ($ipbase, $ipstart) = $hmcstartip =~/^(\d+\.\d+\.\d+)\.(\d+)$/; + # take the number from the nodename, and as it increases, increase the ip addr + my $regex = '|\D+(\d+)|' . "$ipbase.($ipstart+" . '$1' . "-$hmcstartnum)|"; + $tables{'hosts'}->setNodeAttribs('hmc', {ip => $regex}); + } + + #using hostname-range, write regex for: ppc.node, nodetype.nodetype + $tables{'ppc'}->setNodeAttribs('hmc', {comments => 'hmc'}); + $tables{'nodetype'}->setNodeAttribs('hmc', {nodetype => 'hmc'}); +} + + +sub writeframe { + # write hostname-range in nodelist table + my ($framerange, $cwd) = @_; + infomsg('Defining frames...'); + my $nodes = [noderange($framerange, 0)]; + my ($framestartnum) = $$nodes[0] =~/^\D+(\d+)$/; # save this value for later + #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'}; + if ($framestartip) { + my ($ipbase, $ipstart) = $framestartip =~/^(\d+\.\d+\.\d+)\.(\d+)$/; + # take the number from the nodename, and as it increases, increase the ip addr + my $regex = '|\D+(\d+)|' . "$ipbase.($ipstart+" . '$1' . "-$framestartnum)|"; + $tables{'hosts'}->setNodeAttribs('frame', {ip => $regex}); + } + + # Using the frame group, write: nodetype.nodetype, nodehm.mgt + $tables{'nodetype'}->setNodeAttribs('frame', {nodetype => 'bpa'}); + $tables{'nodehm'}->setNodeAttribs('frame', {mgt => 'hmc'}); + + # 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 + my $idregex = '|\D+(\d+)|(0+$1)|'; + # Calculate which hmc manages this frame by dividing by num-frames-per-hmc + my $framesperhmc = $STANZAS{'xcat-frames'}->{'num-frames-per-hmc'}; + #todo: this is wrong! Switch frames and cecs over to direct attach + my $hmcregex = '|\D+(\d+)|((($1-1)/' . $framesperhmc . ')+1)|'; + $tables{'ppc'}->setNodeAttribs('frame', {id => $idregex, hcp => $hmcregex}); + + # Write vpd-file to vpd table + my $filename = fullpath($STANZAS{'xcat-frames'}->{'vpd-file'}, $cwd); + readwritevpd($filename); + +} + +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 = ) { $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)]; + my ($cecstartnum) = $$nodes[0] =~/^\D+(\d+)$/; # save this value for later + 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'}; + if ($cecstartip) { + my ($ipbase, $ipstart) = $cecstartip =~/^(\d+\.\d+\.\d+)\.(\d+)$/; + # take the number from the nodename, and as it increases, increase the ip addr + my $regex = '|\D+(\d+)|' . "$ipbase.($ipstart+" . '$1' . "-$cecstartnum)|"; + $tables{'hosts'}->setNodeAttribs('cec', {ip => $regex}); + } + + # Using the cec group, write: nodetype.nodetype, nodehm.mgt + $tables{'nodetype'}->setNodeAttribs('cec', {nodetype => 'fsp'}); + $tables{'nodehm'}->setNodeAttribs('cec', {mgt => 'hmc'}); + + # Do we need to write regex for ppc.hcp and ppc.parent? Of will lsslp do all that? + + # Write supernode-list in ppc.supernode + #todo: handle the !sequential option + $nodes = [noderange($cecrange, 0)]; # the setNodesAttribs() function blanks out the nodes array + my %framesupers; + my $filename = fullpath($STANZAS{'xcat-cecs'}->{'supernode-list'}, $cwd); + readsupers($filename, \%framesupers); + my $i=0; # the index into the array of cecs + my %nodehash; + # 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 + 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"; + $nodehash{$nodename} = { supernode => "$supernum,$j" }; + } + } + } + # Now write all of the supernode values to the ppc table + if (scalar(keys %framesupers)) { $tables{'ppc'}->setNodesAttribs(\%nodehash); } +} + +# 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); + return; + } + 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"; + $$framesup{$frame} = [split(/[\s,]+/, $supernums)]; + } + + else { + errormsg("syntax error on line $linenum.", 3); + return; + } + } # end while - go to next line + close($input); +} + + +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}); + + # Write num-frames-per-bb in ppc.parent for bpas + my $bbregex = '|\D+(\d+)|((($1-1)/' . $framesperbb . ')+1)|'; + $tables{'ppc'}->setNodeAttribs('frame', {parent => $bbregex}); +} + + +# Create service node definitions +sub writesn { + my $range = shift; + infomsg('Defining service nodes...'); + my $nodes = [noderange($range, 0)]; + my ($startnum) = $$nodes[0] =~/^\D+(\d+)$/; # save this value for later + if (scalar(@$nodes)) { + $tables{'nodelist'}->setNodesAttribs($nodes, { groups => 'service,all' }); + } + + # Write regex for: hosts.node, hosts.ip + my $startip = $STANZAS{'xcat-lpars'}->{'service-node-starting-ip'}; + if ($startip) { + my ($ipbase, $ipstart) = $startip =~/^(\d+\.\d+\.\d+)\.(\d+)$/; + # take the number from the nodename, and as it increases, increase the ip addr + my $regex = '|\D+(\d+)|' . "$ipbase.($ipstart+" . '$1' . "-$startnum)|"; + my %hash = (ip => $regex); + my $otherint = $STANZAS{'xcat-lpars'}->{'service-node-otherinterfaces'}; + 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); + ($ipbase, $ipstart) = $startip =~/^(\d+\.\d+\.\d+)\.(\d+)$/; + $if = "$nic:$ipbase.($ipstart+" . '$1' . "-$startnum)"; + } + $regex = '|\D+(\d+)|' . join(',', @ifs) . '|'; + #print "regex=$regex\n"; + $hash{otherinterfaces} = $regex; + } + + $tables{'hosts'}->setNodeAttribs('service', \%hash); + } + + # Write regex for: ppc.node, nodetype.nodetype + $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}); + } + + #todo: Write ppc.hcp and ppc.parent + #my $cecsperbb = $STANZAS{'xcat-building-blocks'}->{'num-cecs-per-bb'}; + #my $regex = '|\D+(\d+)|((($1-1)/' . $cecsperbb . ')+1)|'; + #$tables{'ppc'}->setNodeAttribs('service', {parent => $regex}); +} + + +# Create storage node definitions +sub writestorage { + my $range = shift; + infomsg('Defining storage nodes...'); + my $nodes = [noderange($range, 0)]; + my ($startnum) = $$nodes[0] =~/^\D+(\d+)$/; # save this value for later + if (scalar(@$nodes)) { + $tables{'nodelist'}->setNodesAttribs($nodes, { groups => 'storage,all' }); + } + + # Write regex for: hosts.node, hosts.ip + my $startip = $STANZAS{'xcat-lpars'}->{'storage-node-starting-ip'}; + if ($startip) { + my ($ipbase, $ipstart) = $startip =~/^(\d+\.\d+\.\d+)\.(\d+)$/; + # take the number from the nodename, and as it increases, increase the ip addr + my $regex = '|\D+(\d+)|' . "$ipbase.($ipstart+" . '$1' . "-$startnum)|"; + my %hash = (ip => $regex); + my $otherint = $STANZAS{'xcat-lpars'}->{'storage-node-otherinterfaces'}; + 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); + ($ipbase, $ipstart) = $startip =~/^(\d+\.\d+\.\d+)\.(\d+)$/; + $if = "$nic:$ipbase.($ipstart+" . '$1' . "-$startnum)"; + } + $regex = '|\D+(\d+)|' . join(',', @ifs) . '|'; + #print "regex=$regex\n"; + $hash{otherinterfaces} = $regex; + } + my $aliases = $STANZAS{'xcat-lpars'}->{'storage-node-aliases'}; + if ($aliases) { + #todo: support more than 1 alias + $regex = '|(.+)|($1)' . "$aliases|"; + $hash{hostnames} = $regex; + } + + $tables{'hosts'}->setNodeAttribs('storage', \%hash); + } + + # Write regex for: ppc.node, nodetype.nodetype + $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'}); + + #todo: Write regex for xcatmaster and servicenode to point it to its SN + + #todo: Write ppc.hcp and ppc.parent + #my $cecsperbb = $STANZAS{'xcat-building-blocks'}->{'num-cecs-per-bb'}; + #my $regex = '|\D+(\d+)|((($1-1)/' . $cecsperbb . ')+1)|'; + #$tables{'ppc'}->setNodeAttribs('service', {parent => $regex}); +} + + +# Create storage node definitions +sub writecompute { + my $range = shift; + infomsg('Defining compute nodes...'); + my $nodes = [noderange($range, 0)]; + my ($startnum) = $$nodes[0] =~/^\D+(\d+)$/; # save this value for later + if (scalar(@$nodes)) { + $tables{'nodelist'}->setNodesAttribs($nodes, { groups => 'compute,all' }); + } + + # Write regex for: hosts.node, hosts.ip + my $startip = $STANZAS{'xcat-lpars'}->{'compute-node-starting-ip'}; + if ($startip) { + my ($ipbase, $ipstart) = $startip =~/^(\d+\.\d+\.\d+)\.(\d+)$/; + # take the number from the nodename, and as it increases, increase the ip addr + my $regex = '|\D+(\d+)|' . "$ipbase.($ipstart+" . '$1' . "-$startnum)|"; + my %hash = (ip => $regex); + my $otherint = $STANZAS{'xcat-lpars'}->{'compute-node-otherinterfaces'}; + 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); + ($ipbase, $ipstart) = $startip =~/^(\d+\.\d+\.\d+)\.(\d+)$/; + $if = "$nic:$ipbase.($ipstart+" . '$1' . "-$startnum)"; + } + $regex = '|\D+(\d+)|' . join(',', @ifs) . '|'; + #print "regex=$regex\n"; + $hash{otherinterfaces} = $regex; + } + my $aliases = $STANZAS{'xcat-lpars'}->{'compute-node-aliases'}; + if ($aliases) { + #todo: support more than 1 alias + $regex = '|(.+)|($1)' . "$aliases|"; + $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'}); + + #todo: Write the lpar id + #$tables{'ppc'}->setNodeAttribs('compute', {id => '1'}); + + #todo: Write regex for xcatmaster and servicenode to point it to its SN + + #todo: Write ppc.hcp and ppc.parent + #my $cecsperbb = $STANZAS{'xcat-building-blocks'}->{'num-cecs-per-bb'}; + #my $regex = '|\D+(\d+)|((($1-1)/' . $cecsperbb . ')+1)|'; + #$tables{'ppc'}->setNodeAttribs('service', {parent => $regex}); +} + + +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;