2009-09-25 15:55:53 +00:00
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
2009-09-25 20:27:52 +00:00
package xCAT_plugin::xnba ;
2012-01-05 20:20:24 +00:00
use strict ;
2009-09-25 15:55:53 +00:00
use Sys::Syslog ;
use Socket ;
use File::Copy ;
use File::Path ;
2012-03-01 14:31:10 +00:00
use xCAT::Scope ;
2012-03-16 10:31:33 +00:00
use xCAT::MsgUtils ;
2009-09-25 15:55:53 +00:00
use Getopt::Long ;
2012-08-09 04:07:40 +00:00
use xCAT::Utils ;
use xCAT::TableUtils ;
2013-08-27 17:12:19 +00:00
use xCAT::ServiceNodeUtils ;
2009-09-25 15:55:53 +00:00
my $ addkcmdlinehandled ;
my $ request ;
my $ callback ;
my $ dhcpconf = "/etc/dhcpd.conf" ;
2010-03-01 16:32:22 +00:00
#my $tftpdir = "/tftpboot";
2012-08-09 04:07:40 +00:00
my $ globaltftpdir = xCAT::TableUtils - > getTftpDir ( ) ;
2009-09-25 15:55:53 +00:00
#my $dhcpver = 3;
my % usage = (
2012-12-11 20:59:50 +00:00
"nodeset" = > "Usage: nodeset <noderange> [install|shell|boot|runcmd=bmcsetup|netboot|iscsiboot|osimage[=<imagename>]|statelite|offline]" ,
2009-09-25 15:55:53 +00:00
) ;
sub handled_commands {
return {
nodeset = > "noderes:netboot"
}
}
sub check_dhcp {
return 1 ;
#TODO: omapi magic to do things right
my $ node = shift ;
my $ dhcpfile ;
open ( $ dhcpfile , $ dhcpconf ) ;
while ( <$dhcpfile> ) {
if ( /host $node\b/ ) {
close $ dhcpfile ;
return 1 ;
}
}
close $ dhcpfile ;
return 0 ;
}
2012-03-29 18:08:49 +00:00
sub _slow_get_tftpdir { #make up for paths where tftpdir is not passed in
2012-03-29 19:12:25 +00:00
my $ node = shift ;
my $ nrtab = xCAT::Table - > new ( 'noderes' , - create = > 0 ) ; #in order to detect per-node tftp directories
2012-03-29 18:08:49 +00:00
unless ( $ nrtab ) { return $ globaltftpdir ; }
my $ ent = $ nrtab - > getNodeAttribs ( $ node , [ "tftpdir" ] ) ;
if ( $ ent and $ ent - > { tftpdir } ) {
return $ ent - > { tftpdir } ;
} else {
return $ globaltftpdir ;
}
}
2009-09-25 15:55:53 +00:00
sub getstate {
my $ node = shift ;
2012-02-15 21:04:42 +00:00
my $ tftpdir = shift ;
2012-03-29 18:08:49 +00:00
unless ( $ tftpdir ) { $ tftpdir = _slow_get_tftpdir ( $ node ) ; }
2009-09-25 15:55:53 +00:00
if ( check_dhcp ( $ node ) ) {
if ( - r $ tftpdir . "/xcat/xnba/nodes/" . $ node ) {
my $ fhand ;
open ( $ fhand , $ tftpdir . "/xcat/xnba/nodes/" . $ node ) ;
my $ headline = <$fhand> ;
$ headline = <$fhand> ; #second line is the comment now...
close $ fhand ;
$ headline =~ s/^#// ;
chomp ( $ headline ) ;
return $ headline ;
} elsif ( - r $ tftpdir . "/pxelinux.cfg/" . $ node ) {
my $ fhand ;
open ( $ fhand , $ tftpdir . "/pxelinux.cfg/" . $ node ) ;
my $ headline = <$fhand> ;
close $ fhand ;
$ headline =~ s/^#// ;
chomp ( $ headline ) ;
return $ headline ;
} else {
return "boot" ;
}
} else {
return "discover" ;
}
}
sub setstate {
= pod
This function will manipulate the pxelinux . cfg structure to match what the noderes / chain tables indicate the node should be booting .
= cut
my $ node = shift ;
my % bphash = % { shift ( ) } ;
my % chainhash = % { shift ( ) } ;
my % machash = % { shift ( ) } ;
2009-09-25 20:27:52 +00:00
my % iscsihash = % { shift ( ) } ;
2012-02-15 21:04:42 +00:00
my $ tftpdir = shift ;
2013-04-26 14:07:02 +00:00
my % linuximghash = ( ) ;
my $ linuximghashref = shift ;
if ( ref $ linuximghashref ) { % linuximghash = % { $ linuximghashref } ; }
2013-04-25 12:15:09 +00:00
my $ imgaddkcmdline = ( $ linuximghash { 'boottarget' } ) ? undef : $ linuximghash { 'addkcmdline' } ;
2009-09-25 15:55:53 +00:00
my $ kern = $ bphash { $ node } - > [ 0 ] ; #$bptab->getNodeAttribs($node,['kernel','initrd','kcmdline']);
unless ( $ addkcmdlinehandled - > { $ node } ) { #Tag to let us know the plugin had a special syntax implemented for addkcmdline
2013-04-25 12:15:09 +00:00
if ( $ kern - > { addkcmdline } or ( $ imgaddkcmdline ) ) {
2010-03-01 16:32:22 +00:00
#Implement the kcmdline append here for
#most generic, least code duplication
###hack start
# This is my comment. There are many others like it, but this one is mine.
# My comment is my best friend. It is my life. I must master it as I must master my life.
# Without me, my comment is useless. Without my comment, I am useless.
# Jarrod to clean up. It really should be in Table.pm and support
# the new statelite $table notation.
#I dislike spaces, tabs are cleaner, I'm too tired to change all the xCAT code.
#I give in.
2013-04-25 12:15:09 +00:00
my $ kcmdlinehack = ( $ imgaddkcmdline ) ? $ kern - > { addkcmdline } . " " . $ imgaddkcmdline : $ kern - > { addkcmdline } ;
2010-03-01 16:32:22 +00:00
while ( $ kcmdlinehack =~ /#NODEATTRIB:([^:#]+):([^:#]+)#/ ) {
my $ natab = xCAT::Table - > new ( $ 1 ) ;
my $ naent = $ natab - > getNodeAttribs ( $ node , [ $ 2 ] ) ;
my $ naval = $ naent - > { $ 2 } ;
$ kcmdlinehack =~ s/#NODEATTRIB:([^:#]+):([^:#]+)#/$naval/ ;
}
while ( $ kcmdlinehack =~ /#TABLE:([^:#]+):([^:#]+):([^:#]+)#/ ) {
my $ tabname = $ 1 ;
my $ keyname = $ 2 ;
my $ colname = $ 3 ;
if ( $ 2 =~ /THISNODE/ or $ 2 =~ /\$NODE/ ) {
my $ natab = xCAT::Table - > new ( $ tabname ) ;
my $ naent = $ natab - > getNodeAttribs ( $ node , [ $ colname ] ) ;
my $ naval = $ naent - > { $ colname } ;
$ kcmdlinehack =~ s/#TABLE:([^:#]+):([^:#]+):([^:#]+)#/$naval/ ;
} else {
my $ msg = "Table key of $2 not yet supported by boottarget mini-template" ;
$ callback - > ( {
error = > [ "$msg" ] ,
errorcode = > [ 1 ]
} ) ;
}
}
#$kern->{kcmdline} .= " ".$kern->{addkcmdline};
$ kern - > { kcmdline } . = " " . $ kcmdlinehack ;
###hack end
2009-09-25 15:55:53 +00:00
}
}
2011-09-29 19:41:32 +00:00
my $ elilokcmdline = $ kern - > { kcmdline } ; #track it separate, since vars differ
2011-10-04 18:13:37 +00:00
my $ pxelinuxkcmdline = $ kern - > { kcmdline } ; #track it separate, since vars differ
2009-09-25 15:55:53 +00:00
if ( $ kern - > { kcmdline } =~ /!myipfn!/ ) {
my $ ipfn = '${next-server}' ; #xCAT::Utils->my_ip_facing($node);
$ kern - > { kcmdline } =~ s/!myipfn!/$ipfn/g ;
2012-01-05 20:20:24 +00:00
$ elilokcmdline =~ s/!myipfn!/%N/g ;
2012-08-09 04:07:40 +00:00
$ ipfn = xCAT::NetworkUtils - > my_ip_facing ( $ node ) ;
2011-10-04 18:13:37 +00:00
unless ( $ ipfn ) { $ ipfn = $ ::XCATSITEVALS { master } ; }
if ( $ ipfn ) {
2012-01-05 20:20:24 +00:00
$ pxelinuxkcmdline =~ s/!myipfn!/$ipfn/g ;
2011-10-04 18:13:37 +00:00
}
2009-09-25 15:55:53 +00:00
}
my $ pcfg ;
unlink ( $ tftpdir . "/xcat/xnba/nodes/" . $ node . ".pxelinux" ) ;
open ( $ pcfg , '>' , $ tftpdir . "/xcat/xnba/nodes/" . $ node ) ;
my $ cref = $ chainhash { $ node } - > [ 0 ] ; #$chaintab->getNodeAttribs($node,['currstate']);
print $ pcfg "#!gpxe\n" ;
if ( $ cref - > { currstate } ) {
print $ pcfg "#" . $ cref - > { currstate } . "\n" ;
}
if ( $ cref and $ cref - > { currstate } eq "boot" ) {
2009-09-25 20:27:52 +00:00
my $ ient = $ iscsihash { $ node } - > [ 0 ] ;
if ( $ ient and $ ient - > { server } and $ ient - > { target } ) {
print $ pcfg "hdboot\n" ;
} else {
print $ pcfg "exit\n" ;
}
2009-09-25 15:55:53 +00:00
close ( $ pcfg ) ;
} elsif ( $ kern and $ kern - > { kernel } ) {
if ( $ kern - > { kernel } =~ /!/ ) { #TODO: deprecate this, do stateless Xen like stateless ESXi
my $ hypervisor ;
my $ kernel ;
( $ kernel , $ hypervisor ) = split /!/ , $ kern - > { kernel } ;
print $ pcfg " set 209:string xcat/xnba/nodes/$node.pxelinux\n" ;
print $ pcfg " set 210:string http://" . '${next-server}' . "/tftpboot/\n" ;
print $ pcfg " imgfetch -n pxelinux.0 http://" . '${next-server}' . "/tftpboot/xcat/pxelinux.0\n" ;
print $ pcfg " imgload pxelinux.0\n" ;
print $ pcfg " imgexec pxelinux.0\n" ;
close ( $ pcfg ) ;
open ( $ pcfg , '>' , $ tftpdir . "/xcat/xnba/nodes/" . $ node . ".pxelinux" ) ;
print $ pcfg "DEFAULT xCAT\nLABEL xCAT\n KERNEL mboot.c32\n" ;
2011-10-04 18:13:37 +00:00
print $ pcfg " APPEND $hypervisor --- $kernel " . $ pxelinuxkcmdline . " --- " . $ kern - > { initrd } . "\n" ;
2009-09-25 15:55:53 +00:00
} else {
if ( $ kern - > { kernel } =~ /\.c32\z/ or $ kern - > { kernel } =~ /memdisk\z/ ) { #gPXE comboot support seems insufficient, chain pxelinux instead
print $ pcfg " set 209:string xcat/xnba/nodes/$node.pxelinux\n" ;
print $ pcfg " set 210:string http://" . '${next-server}' . "/tftpboot/\n" ;
print $ pcfg " imgfetch -n pxelinux.0 http://" . '${next-server}' . "/tftpboot/xcat/pxelinux.0\n" ;
print $ pcfg " imgload pxelinux.0\n" ;
print $ pcfg " imgexec pxelinux.0\n" ;
close ( $ pcfg ) ;
open ( $ pcfg , '>' , $ tftpdir . "/xcat/xnba/nodes/" . $ node . ".pxelinux" ) ;
#It's time to set pxelinux for this node to boot the kernel..
print $ pcfg "DEFAULT xCAT\nLABEL xCAT\n" ;
print $ pcfg " KERNEL " . $ kern - > { kernel } . "\n" ;
if ( $ kern - > { initrd } or $ kern - > { kcmdline } ) {
print $ pcfg " APPEND " ;
}
if ( $ kern and $ kern - > { initrd } ) {
print $ pcfg "initrd=" . $ kern - > { initrd } . " " ;
}
if ( $ kern and $ kern - > { kcmdline } ) {
2011-10-04 18:13:37 +00:00
print $ pcfg $ pxelinuxkcmdline . "\n" ;
2009-09-25 15:55:53 +00:00
} else {
print $ pcfg "\n" ;
}
2010-05-03 20:37:39 +00:00
print $ pcfg "IPAPPEND 2\n" ;
2011-09-19 19:11:10 +00:00
if ( $ kern - > { kernel } =~ /esxi5/ ) { #Make uefi boot provisions
my $ ucfg ;
open ( $ ucfg , '>' , $ tftpdir . "/xcat/xnba/nodes/" . $ node . ".uefi" ) ;
if ( $ kern - > { kcmdline } =~ / xcat\/netboot/ ) {
$ kern - > { kcmdline } =~ s/xcat\/netboot/\/tftpboot\/xcat\/netboot/ ;
}
print $ ucfg "#!gpxe\n" ;
print $ ucfg 'chain http://${next-server}/tftpboot/xcat/esxboot-x64.efi ' . $ kern - > { kcmdline } . "\n" ;
close ( $ ucfg ) ;
}
2009-09-25 15:55:53 +00:00
} else { #other than comboot/multiboot, we won't have need of pxelinux
print $ pcfg "imgfetch -n kernel http://" . '${next-server}/tftpboot/' . $ kern - > { kernel } . "\n" ;
print $ pcfg "imgload kernel\n" ;
if ( $ kern - > { kcmdline } ) {
2011-05-03 15:40:37 +00:00
print $ pcfg "imgargs kernel " . $ kern - > { kcmdline } . ' BOOTIF=01-${netX/machyp}' . "\n" ;
2010-05-03 20:37:39 +00:00
} else {
2010-05-07 15:02:24 +00:00
print $ pcfg "imgargs kernel BOOTIF=" . '${netX/mac}' . "\n" ;
2009-09-25 15:55:53 +00:00
}
if ( $ kern - > { initrd } ) {
print $ pcfg "imgfetch http://" . '${next-server}' . "/tftpboot/" . $ kern - > { initrd } . "\n" ;
}
print $ pcfg "imgexec kernel\n" ;
2011-09-19 17:21:32 +00:00
if ( $ kern - > { kcmdline } and $ kern - > { initrd } ) { #only a linux kernel/initrd pair should land here, write elilo config and uefi variant of xnba config file
my $ ucfg ;
open ( $ ucfg , '>' , $ tftpdir . "/xcat/xnba/nodes/" . $ node . ".uefi" ) ;
print $ ucfg "#!gpxe\n" ;
print $ ucfg 'chain http://${next-server}/tftpboot/xcat/elilo-x64.efi -C /tftpboot/xcat/xnba/nodes/' . $ node . ".elilo\n" ;
close ( $ ucfg ) ;
open ( $ ucfg , '>' , $ tftpdir . "/xcat/xnba/nodes/" . $ node . ".elilo" ) ;
print $ ucfg 'default="xCAT"' . "\n" ;
print $ ucfg "delay=0\n\n" ;
print $ ucfg "image=/tftpboot/" . $ kern - > { kernel } . "\n" ;
print $ ucfg " label=\"xCAT\"\n" ;
print $ ucfg " initrd=/tftpboot/" . $ kern - > { initrd } . "\n" ;
2011-09-29 19:41:32 +00:00
print $ ucfg " append=\"" . $ elilokcmdline . ' BOOTIF=%B"' . "\n" ;
2011-09-19 17:21:32 +00:00
close ( $ ucfg ) ;
}
2009-09-25 15:55:53 +00:00
}
}
close ( $ pcfg ) ;
} else { #TODO: actually, should possibly default to xCAT image?
print $ pcfg "LOCALBOOT 0\n" ;
close ( $ pcfg ) ;
}
}
my $ errored = 0 ;
sub pass_along {
my $ resp = shift ;
2012-05-09 14:12:20 +00:00
if ( $ resp - > { error } and not ref $ resp - > { error } ) {
$ resp - > { error } = [ $ resp - > { error } ] ;
}
2009-09-25 15:55:53 +00:00
if ( $ resp and ( $ resp - > { errorcode } and $ resp - > { errorcode } - > [ 0 ] ) or ( $ resp - > { error } and $ resp - > { error } - > [ 0 ] ) ) {
$ errored = 1 ;
}
foreach ( @ { $ resp - > { node } } ) {
if ( $ _ - > { error } or $ _ - > { errorcode } ) {
$ errored = 1 ;
}
if ( $ _ - > { _addkcmdlinehandled } ) {
$ addkcmdlinehandled - > { $ _ - > { name } - > [ 0 ] } = 1 ;
return ; #Don't send back to client this internal hint
}
}
$ callback - > ( $ resp ) ;
}
sub preprocess_request {
my $ req = shift ;
if ( $ req - > { _xcatpreprocessed } - > [ 0 ] == 1 ) { return [ $ req ] ; }
my $ callback1 = shift ;
my $ command = $ req - > { command } - > [ 0 ] ;
my $ sub_req = shift ;
2013-08-27 17:12:19 +00:00
my $ nodes = $ req - > { node } ;
2009-09-25 15:55:53 +00:00
my @ args = ( ) ;
if ( ref ( $ req - > { arg } ) ) {
@ args = @ { $ req - > { arg } } ;
} else {
@ args = ( $ req - > { arg } ) ;
}
@ ARGV = @ args ;
#use Getopt::Long;
Getopt::Long:: Configure ( "bundling" ) ;
Getopt::Long:: Configure ( "pass_through" ) ;
2012-01-05 20:20:24 +00:00
my $ HELP ;
my $ VERSION ;
2009-09-25 15:55:53 +00:00
if ( ! GetOptions ( 'h|?|help' = > \ $ HELP , 'v|version' = > \ $ VERSION ) ) {
if ( $ usage { $ command } ) {
my % rsp ;
$ rsp { data } - > [ 0 ] = $ usage { $ command } ;
$ callback1 - > ( \ % rsp ) ;
}
return ;
}
if ( $ HELP ) {
if ( $ usage { $ command } ) {
my % rsp ;
$ rsp { data } - > [ 0 ] = $ usage { $ command } ;
$ callback1 - > ( \ % rsp ) ;
}
return ;
}
if ( $ VERSION ) {
my $ ver = xCAT::Utils - > Version ( ) ;
my % rsp ;
$ rsp { data } - > [ 0 ] = "$ver" ;
$ callback1 - > ( \ % rsp ) ;
return ;
}
if ( @ ARGV == 0 ) {
if ( $ usage { $ command } ) {
my % rsp ;
$ rsp { data } - > [ 0 ] = $ usage { $ command } ;
$ callback1 - > ( \ % rsp ) ;
}
return ;
}
#Assume shared tftp directory for boring people, but for cool people, help sync up tftpdirectory contents when
#they specify no sharedtftp in site table
2012-08-09 04:07:40 +00:00
my @ entries = xCAT::TableUtils - > get_site_attribute ( "sharedtftp" ) ;
2012-05-23 06:53:34 +00:00
my $ t_entry = $ entries [ 0 ] ;
2014-02-20 12:09:50 +00:00
if ( defined ( $ t_entry ) and ( $ t_entry eq "0" or $ t_entry eq "no" or $ t_entry eq "NO" ) ) {
2013-08-27 17:12:19 +00:00
# check for computenodes and servicenodes from the noderange, if so error out
2013-12-12 16:15:15 +00:00
my @ SN ;
my @ CN ;
xCAT::ServiceNodeUtils - > getSNandCPnodes ( \ @$ nodes , \ @ SN , \ @ CN ) ;
unless ( ( $ args [ 0 ] eq 'stat' ) or ( $ args [ 0 ] eq 'enact' ) ) { # mix is ok for these options
2013-08-27 17:12:19 +00:00
if ( ( @ SN > 0 ) && ( @ CN > 0 ) ) { # there are both SN and CN
my $ rsp ;
$ rsp - > { data } - > [ 0 ] =
"Nodeset was run with a noderange containing both service nodes and compute nodes. This is not valid. You must submit with either compute nodes in the noderange or service nodes. \n" ;
xCAT::MsgUtils - > message ( "E" , $ rsp , $ callback1 ) ;
return ;
2013-12-12 16:15:15 +00:00
}
}
2013-08-27 17:12:19 +00:00
2009-09-25 15:55:53 +00:00
$ req - > { '_disparatetftp' } = [ 1 ] ;
if ( $ req - > { inittime } - > [ 0 ] ) {
return [ $ req ] ;
}
2013-09-13 12:00:12 +00:00
if ( @ CN > 0 ) { # if compute nodes broadcast to all servicenodes
return xCAT::Scope - > get_broadcast_scope ( $ req , @ _ ) ;
}
2009-09-25 15:55:53 +00:00
}
return [ $ req ] ;
}
sub process_request {
$ request = shift ;
$ callback = shift ;
my $ sub_req = shift ;
my @ args ;
my @ nodes ;
my @ rnodes ;
if ( ref ( $ request - > { node } ) ) {
@ rnodes = @ { $ request - > { node } } ;
} else {
if ( $ request - > { node } ) { @ rnodes = ( $ request - > { node } ) ; }
}
unless ( @ rnodes ) {
if ( $ usage { $ request - > { command } - > [ 0 ] } ) {
$ callback - > ( { data = > $ usage { $ request - > { command } - > [ 0 ] } } ) ;
}
return ;
}
#if not shared, then help sync up
if ( $ request - > { '_disparatetftp' } - > [ 0 ] ) { #reading hint from preprocess_command
@ nodes = ( ) ;
foreach ( @ rnodes ) {
2012-08-09 04:07:40 +00:00
if ( xCAT::NetworkUtils - > nodeonmynet ( $ _ ) ) {
2009-09-25 15:55:53 +00:00
push @ nodes , $ _ ;
2011-12-05 14:53:13 +00:00
} else {
2012-03-16 10:31:33 +00:00
xCAT::MsgUtils - > message ( "S" , "$_: xnba netboot: stop configuration because of none sharedtftp and not on same network with its xcatmaster." ) ;
2009-09-25 15:55:53 +00:00
}
}
} else {
@ nodes = @ rnodes ;
}
2012-03-16 10:31:33 +00:00
# return directly if no nodes in the same network
unless ( @ nodes ) {
xCAT::MsgUtils - > message ( "S" , "xCAT: xnba netboot: no valid nodes. Stop the operation on this server." ) ;
return ;
}
2009-09-25 15:55:53 +00:00
if ( ref ( $ request - > { arg } ) ) {
@ args = @ { $ request - > { arg } } ;
} else {
@ args = ( $ request - > { arg } ) ;
}
#now run the begin part of the prescripts
unless ( $ args [ 0 ] eq 'stat' ) { # or $args[0] eq 'enact') {
$ errored = 0 ;
if ( $ request - > { '_disparatetftp' } - > [ 0 ] ) { #the call is distrubuted to the service node already, so only need to handles my own children
$ sub_req - > ( { command = > [ 'runbeginpre' ] ,
node = > \ @ nodes ,
arg = > [ $ args [ 0 ] , '-l' ] } , \ & pass_along ) ;
} else { #nodeset did not distribute to the service node, here we need to let runednpre to distribute the nodes to their masters
$ sub_req - > ( { command = > [ 'runbeginpre' ] ,
node = > \ @ rnodes ,
arg = > [ $ args [ 0 ] ] } , \ & pass_along ) ;
}
2011-05-16 19:59:10 +00:00
if ( $ errored ) {
my $ rsp ;
$ rsp - > { errorcode } - > [ 0 ] = 1 ;
$ rsp - > { error } - > [ 0 ] = "Failed in running begin prescripts.\n" ;
$ callback - > ( $ rsp ) ;
return ;
}
2009-09-25 15:55:53 +00:00
}
#back to normal business
2012-02-15 21:04:42 +00:00
if ( ! - r "$globaltftpdir/xcat/pxelinux.0" ) {
2009-09-25 15:55:53 +00:00
unless ( - r $ ::XCATROOT . "/share/xcat/netboot/syslinux/pxelinux.0" ) {
$ callback - > ( { error = > [ "Unable to find pxelinux.0 at " . $ ::XCATROOT . "/share/xcat/netboot/syslinux/pxelinux.0" ] , errorcode = > [ 1 ] } ) ;
return ;
}
2012-02-15 21:04:42 +00:00
copy ( $ ::XCATROOT . "/share/xcat/netboot/syslinux/pxelinux.0" , "$globaltftpdir/xcat/pxelinux.0" ) ;
chmod ( 0644 , "$globaltftpdir/xcat/pxelinux.0" ) ;
2009-09-25 15:55:53 +00:00
}
2012-02-15 21:04:42 +00:00
unless ( - r "$globaltftpdir/xcat/pxelinux.0" ) {
2012-04-27 14:45:26 +00:00
$ callback - > ( { error = > [ "Unable to find pxelinux.0 from syslinux" ] , errorcode = > [ 1 ] } ) ;
2009-09-25 15:55:53 +00:00
return ;
}
my $ inittime = 0 ;
if ( exists ( $ request - > { inittime } ) ) { $ inittime = $ request - > { inittime } - > [ 0 ] ; }
if ( ! $ inittime ) { $ inittime = 0 ; }
$ errored = 0 ;
unless ( $ args [ 0 ] eq 'stat' ) { # or $args[0] eq 'enact') {
$ sub_req - > ( { command = > [ 'setdestiny' ] ,
node = > \ @ nodes ,
inittime = > [ $ inittime ] ,
2013-07-04 05:17:03 +00:00
arg = > \ @ args } , \ & pass_along ) ;
2009-09-25 15:55:53 +00:00
}
if ( $ errored ) { return ; }
#Time to actually configure the nodes, first extract database data with the scalable calls
my $ bptab = xCAT::Table - > new ( 'bootparams' , - create = > 1 ) ;
my $ chaintab = xCAT::Table - > new ( 'chain' ) ;
2012-02-15 21:04:42 +00:00
my $ noderestab = xCAT::Table - > new ( 'noderes' ) ; #in order to detect per-node tftp directories
2009-09-25 15:55:53 +00:00
my $ mactab = xCAT::Table - > new ( 'mac' ) ; #to get all the hostnames
2012-02-15 21:04:42 +00:00
my % nrhash = % { $ noderestab - > getNodesAttribs ( \ @ nodes , [ qw( tftpdir ) ] ) } ;
2009-09-25 15:55:53 +00:00
my % bphash = % { $ bptab - > getNodesAttribs ( \ @ nodes , [ qw( kernel initrd kcmdline addkcmdline ) ] ) } ;
my % chainhash = % { $ chaintab - > getNodesAttribs ( \ @ nodes , [ qw( currstate ) ] ) } ;
2009-09-25 20:27:52 +00:00
my % iscsihash ;
my $ iscsitab = xCAT::Table - > new ( 'iscsi' ) ;
if ( $ iscsitab ) {
% iscsihash = % { $ iscsitab - > getNodesAttribs ( \ @ nodes , [ qw( server target ) ] ) } ;
}
2013-04-25 12:15:09 +00:00
my $ typetab = xCAT::Table - > new ( 'nodetype' , - create = > 1 ) ;
my $ typehash = $ typetab - > getNodesAttribs ( \ @ nodes , [ 'provmethod' ] ) ;
my $ linuximgtab = xCAT::Table - > new ( 'linuximage' , - create = > 1 ) ;
2009-09-25 15:55:53 +00:00
my % machash = % { $ mactab - > getNodesAttribs ( \ @ nodes , [ qw( mac ) ] ) } ;
foreach ( @ nodes ) {
2012-02-15 21:04:42 +00:00
my $ tftpdir ;
if ( $ nrhash { $ _ } - > [ 0 ] and $ nrhash { $ _ } - > [ 0 ] - > { tftpdir } ) {
$ tftpdir = $ nrhash { $ _ } - > [ 0 ] - > { tftpdir } ;
} else {
$ tftpdir = $ globaltftpdir ;
}
mkpath ( $ tftpdir . "/xcat/xnba/nodes/" ) ;
2009-09-25 15:55:53 +00:00
my % response ;
$ response { node } - > [ 0 ] - > { name } - > [ 0 ] = $ _ ;
if ( $ args [ 0 ] eq 'stat' ) {
2012-02-15 21:04:42 +00:00
$ response { node } - > [ 0 ] - > { data } - > [ 0 ] = getstate ( $ _ , $ tftpdir ) ;
2009-09-25 15:55:53 +00:00
$ callback - > ( \ % response ) ;
} elsif ( $ args [ 0 ] ) { #If anything else, send it on to the destiny plugin, then setstate
2012-01-05 20:20:24 +00:00
my $ rc ;
my $ errstr ;
2013-04-25 12:15:09 +00:00
my $ ent = $ typehash - > { $ _ } - > [ 0 ] ;
my $ osimgname = $ ent - > { 'provmethod' } ;
my $ linuximghash = undef ;
unless ( $ osimgname =~ /^(install|netboot|statelite)$/ ) {
$ linuximghash = $ linuximgtab - > getAttribs ( { imagename = > $ osimgname } , 'boottarget' , 'addkcmdline' ) ;
}
( $ rc , $ errstr ) = setstate ( $ _ , \ % bphash , \ % chainhash , \ % machash , \ % iscsihash , $ tftpdir , $ linuximghash ) ;
2011-11-03 14:54:59 +00:00
#currently, it seems setstate doesn't return error codes...
#if ($rc) {
# $response{node}->[0]->{errorcode}->[0]= $rc;
# $response{node}->[0]->{errorc}->[0]= $errstr;
# $callback->(\%response);
#}
2010-11-01 17:56:57 +00:00
if ( $ args [ 0 ] eq 'offline' ) {
2010-11-04 20:00:56 +00:00
unlink ( $ tftpdir . "/xcat/xnba/nodes/" . $ _ ) ;
unlink ( $ tftpdir . "/xcat/xnba/nodes/" . $ _ . ".pxelinux" ) ;
2011-09-19 19:11:10 +00:00
unlink ( $ tftpdir . "/xcat/xnba/nodes/" . $ _ . ".uefi" ) ;
unlink ( $ tftpdir . "/xcat/xnba/nodes/" . $ _ . ".elilo" ) ;
2010-11-01 17:56:57 +00:00
}
2009-09-25 15:55:53 +00:00
}
}
#dhcp stuff -- inittime is set when xcatd on sn is started
2010-03-03 18:20:33 +00:00
unless ( ( $ args [ 0 ] eq 'stat' ) || ( $ inittime ) || ( $ args [ 0 ] eq 'offline' ) ) {
2009-09-25 15:55:53 +00:00
my $ do_dhcpsetup = 1 ;
2012-05-23 06:53:34 +00:00
#my $sitetab = xCAT::Table->new('site');
#if ($sitetab) {
#(my $ref) = $sitetab->getAttribs({key => 'dhcpsetup'}, 'value');
2012-08-09 04:07:40 +00:00
my @ entries = xCAT::TableUtils - > get_site_attribute ( "dhcpsetup" ) ;
2012-05-23 06:53:34 +00:00
my $ t_entry = $ entries [ 0 ] ;
if ( defined ( $ t_entry ) ) {
if ( $ t_entry =~ /0|n|N/ ) { $ do_dhcpsetup = 0 ; }
2009-09-25 15:55:53 +00:00
}
2012-05-23 06:53:34 +00:00
#}
2009-09-25 15:55:53 +00:00
if ( $ do_dhcpsetup ) {
if ( $ request - > { '_disparatetftp' } - > [ 0 ] ) { #reading hint from preprocess_command
$ sub_req - > ( { command = > [ 'makedhcp' ] , arg = > [ '-l' ] ,
node = > \ @ nodes } , $ callback ) ;
} else {
$ sub_req - > ( { command = > [ 'makedhcp' ] ,
node = > \ @ nodes } , $ callback ) ;
}
}
}
#now run the end part of the prescripts
unless ( $ args [ 0 ] eq 'stat' ) { # or $args[0] eq 'enact')
$ errored = 0 ;
if ( $ request - > { '_disparatetftp' } - > [ 0 ] ) { #the call is distrubuted to the service node already, so only need to handles my own children
$ sub_req - > ( { command = > [ 'runendpre' ] ,
node = > \ @ nodes ,
arg = > [ $ args [ 0 ] , '-l' ] } , \ & pass_along ) ;
} else { #nodeset did not distribute to the service node, here we need to let runednpre to distribute the nodes to their masters
$ sub_req - > ( { command = > [ 'runendpre' ] ,
node = > \ @ rnodes ,
arg = > [ $ args [ 0 ] ] } , \ & pass_along ) ;
}
2011-05-16 19:59:10 +00:00
if ( $ errored ) {
my $ rsp ;
$ rsp - > { errorcode } - > [ 0 ] = 1 ;
$ rsp - > { error } - > [ 0 ] = "Failed in running end prescripts.\n" ;
$ callback - > ( $ rsp ) ;
return ;
}
2009-09-25 15:55:53 +00:00
}
}
#----------------------------------------------------------------------------
= head3 getNodesetStates
returns the nodeset state for the given nodes . The possible nodeset
states are: netboot , install , boot and discover .
Arguments:
nodes - - - a pointer to an array of nodes
states - - a pointer to a hash table . This hash will be filled by this
function . The key is the nodeset status and the value is a pointer
to an array of nodes .
Returns:
( return code , error message )
= cut
#-----------------------------------------------------------------------------
sub getNodesetStates {
my $ noderef = shift ;
if ( $ noderef =~ /xCAT_plugin::pxe/ ) {
$ noderef = shift ;
}
my @ nodes = @$ noderef ;
my $ hashref = shift ;
2012-03-29 18:08:49 +00:00
my $ noderestab = xCAT::Table - > new ( 'noderes' ) ; #in order to detect per-node tftp directories
my % nrhash = % { $ noderestab - > getNodesAttribs ( \ @ nodes , [ qw( tftpdir ) ] ) } ;
2009-09-25 15:55:53 +00:00
if ( @ nodes > 0 ) {
foreach my $ node ( @ nodes ) {
2012-03-29 18:08:49 +00:00
my $ tftpdir ;
if ( $ nrhash { $ node } - > [ 0 ] and $ nrhash { $ node } - > [ 0 ] - > { tftpdir } ) {
$ tftpdir = $ nrhash { $ node } - > [ 0 ] - > { tftpdir } ;
} else {
$ tftpdir = $ globaltftpdir ;
}
my $ tmp = getstate ( $ node , $ tftpdir ) ;
2009-09-25 15:55:53 +00:00
my @ a = split ( ' ' , $ tmp ) ;
2012-01-05 20:20:24 +00:00
my $ stat = $ a [ 0 ] ;
2009-09-25 15:55:53 +00:00
if ( exists ( $ hashref - > { $ stat } ) ) {
my $ pa = $ hashref - > { $ stat } ;
push ( @$ pa , $ node ) ;
}
else {
$ hashref - > { $ stat } = [ $ node ] ;
}
}
}
return ( 0 , "" ) ;
}
1 ;