2007-10-26 22:44:33 +00:00
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
package xCAT_plugin::destiny ;
2012-12-11 20:59:50 +00:00
BEGIN
{
$ ::XCATROOT = $ ENV { 'XCATROOT' } ? $ ENV { 'XCATROOT' } : '/opt/xcat' ;
}
use lib "$::XCATROOT/lib/perl" ;
2007-10-26 22:44:33 +00:00
use xCAT::NodeRange ;
use Data::Dumper ;
2008-02-07 21:48:21 +00:00
use xCAT::Utils ;
2012-08-09 04:07:40 +00:00
use xCAT::TableUtils ;
2007-10-26 22:44:33 +00:00
use Sys::Syslog ;
2008-09-25 03:04:56 +00:00
use xCAT::GlobalDef ;
2009-03-24 13:51:56 +00:00
use xCAT::Table ;
2008-09-25 03:04:56 +00:00
use xCAT_monitoring::monitorctrl ;
2013-07-04 05:09:44 +00:00
use Getopt::Long ;
2007-10-26 22:44:33 +00:00
use strict ;
my $ request ;
my $ callback ;
my $ subreq ;
my $ errored = 0 ;
2008-07-11 19:02:39 +00:00
#DESTINY SCOPED GLOBALS
my $ chaintab ;
my $ iscsitab ;
my $ bptab ;
my $ typetab ;
my $ restab ;
2012-05-22 06:32:20 +00:00
#my $sitetab;
2008-07-11 19:02:39 +00:00
my $ hmtab ;
2008-10-30 14:37:56 +00:00
my $ tftpdir = "/tftpboot" ;
2008-07-11 19:02:39 +00:00
2009-03-24 13:51:56 +00:00
my $ nonodestatus = 0 ;
2012-05-22 06:32:20 +00:00
#my $sitetab = xCAT::Table->new('site');
#if ($sitetab) {
#(my $ref1) = $sitetab->getAttribs({key => 'nodestatus'}, 'value');
2012-08-09 04:07:40 +00:00
my @ entries = xCAT::TableUtils - > get_site_attribute ( "nodestatus" ) ;
2012-05-22 06:32:20 +00:00
my $ site_entry = $ entries [ 0 ] ;
if ( defined ( $ site_entry ) ) {
if ( $ site_entry =~ /0|n|N/ ) { $ nonodestatus = 1 ; }
2009-03-24 13:51:56 +00:00
}
2012-05-22 06:32:20 +00:00
#}
2009-03-24 13:51:56 +00:00
2007-10-26 22:44:33 +00:00
sub handled_commands {
return {
setdestiny = > "destiny" ,
getdestiny = > "destiny" ,
nextdestiny = > "destiny"
}
}
sub process_request {
$ request = shift ;
$ callback = shift ;
$ subreq = shift ;
2013-04-01 19:11:28 +00:00
if ( not $ ::XCATSITEVALS { disablecredfilecheck } and xCAT::Utils - > isMN ( ) ) {
2012-08-09 04:07:40 +00:00
my $ result = xCAT::TableUtils - > checkCredFiles ( $ callback ) ;
2009-06-11 19:09:03 +00:00
}
2007-10-26 22:44:33 +00:00
if ( $ request - > { command } - > [ 0 ] eq 'getdestiny' ) {
2008-09-30 20:00:46 +00:00
getdestiny ( 0 ) ;
2007-10-26 22:44:33 +00:00
}
if ( $ request - > { command } - > [ 0 ] eq 'nextdestiny' ) {
2008-10-28 18:04:11 +00:00
nextdestiny ( 0 , 1 ) ; #it is called within dodestiny
2007-10-26 22:44:33 +00:00
}
if ( $ request - > { command } - > [ 0 ] eq 'setdestiny' ) {
2008-09-30 20:00:46 +00:00
setdestiny ( $ request , 0 ) ;
2007-10-26 22:44:33 +00:00
}
}
sub relay_response {
my $ resp = shift ;
$ callback - > ( $ resp ) ;
2008-05-07 20:45:48 +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 ;
}
2007-10-26 22:44:33 +00:00
}
}
sub setdestiny {
2012-12-11 20:59:50 +00:00
my $ req = shift ;
my $ flag = shift ;
my $ noupdate = shift ;
$ chaintab = xCAT::Table - > new ( 'chain' , - create = > 1 ) ;
my @ nodes = @ { $ req - > { node } } ;
2013-07-04 05:09:44 +00:00
2013-07-05 07:10:30 +00:00
@ ARGV = @ { $ req - > { arg } } ;
2013-07-04 05:09:44 +00:00
my $ noupdateinitrd ;
2013-11-19 11:27:11 +00:00
my $ ignorekernelchk ;
GetOptions ( 'noupdateinitrd' = > \ $ noupdateinitrd ,
'ignorekernelchk' = > \ $ ignorekernelchk , ) ;
2013-07-04 05:09:44 +00:00
my $ state = $ ARGV [ 0 ] ;
2013-06-09 09:17:39 +00:00
my $ reststates ;
# to support the case that the state could be runimage=xxx,runimage=yyy,osimage=xxx
( $ state , $ reststates ) = split ( /,/ , $ state , 2 ) ;
2012-12-11 20:59:50 +00:00
my % nstates ;
if ( $ state eq "enact" ) {
my $ nodetypetab = xCAT::Table - > new ( 'nodetype' , - create = > 1 ) ;
my % nodestates ;
my % stents = % { $ chaintab - > getNodesAttribs ( $ req - > { node } , "currstate" ) } ;
my % ntents = % { $ nodetypetab - > getNodesAttribs ( $ req - > { node } , "provmethod" ) } ;
my $ state ;
my $ sninit = 0 ;
if ( exists ( $ req - > { inittime } ) ) { # this is called in AAsn.pm
$ sninit = $ req - > { i nittime } - > [ 0 ] ;
}
foreach ( @ { $ req - > { node } } ) { #First, build a hash of all of the states to attempt to keep things as aggregated as possible
if ( $ stents { $ _ } - > [ 0 ] - > { currstate } ) {
$ state = $ stents { $ _ } - > [ 0 ] - > { currstate } ;
$ state =~ s/ .*// ;
#get the osimagename if nodetype.provmethod has osimage specified
2012-12-21 08:06:52 +00:00
#use it for both sninit and genesis operating
if ( ( $ state eq 'install' ) || ( $ state eq 'netboot' ) || ( $ state eq 'statelite' ) ) {
2012-12-11 20:59:50 +00:00
my $ osimage = $ ntents { $ _ } - > [ 0 ] - > { provmethod } ;
if ( ( $ osimage ) && ( $ osimage ne 'install' ) && ( $ osimage ne 'netboot' ) && ( $ osimage ne 'statelite' ) ) {
$ state = "osimage=$osimage" ;
}
}
push @ { $ nodestates { $ state } } , $ _ ;
}
}
foreach ( keys % nodestates ) {
$ req - > { arg } - > [ 0 ] = $ _ ;
$ req - > { node } = $ nodestates { $ _ } ;
setdestiny ( $ req , 30 , 1 ) ; #ludicrous flag to denote no table updates can be inferred.
}
return ;
} elsif ( $ state eq "next" ) {
return nextdestiny ( $ flag + 1 ) ; #this is special case where updateflag is called
} elsif ( $ state eq "iscsiboot" ) {
my $ iscsitab = xCAT::Table - > new ( 'iscsi' ) ;
unless ( $ iscsitab ) {
$ callback - > ( { error = > "Unable to open iscsi table to get iscsiboot parameters" , errorcode = > [ 1 ] } ) ;
}
my $ bptab = xCAT::Table - > new ( 'bootparams' , - create = > 1 ) ;
my $ nodetype = xCAT::Table - > new ( 'nodetype' ) ;
my $ ntents = $ nodetype - > getNodesAttribs ( $ req - > { node } , [ qw( os arch profile ) ] ) ;
my $ ients = $ iscsitab - > getNodesAttribs ( $ req - > { node } , [ qw( kernel kcmdline initrd ) ] ) ;
foreach ( @ { $ req - > { node } } ) {
my $ ient = $ ients - > { $ _ } - > [ 0 ] ; #$iscsitab->getNodeAttribs($_,[qw(kernel kcmdline initrd)]);
my $ ntent = $ ntents - > { $ _ } - > [ 0 ] ;
unless ( $ ient and $ ient - > { kernel } ) {
unless ( $ ntent and $ ntent - > { arch } =~ /x86/ and - f ( "$tftpdir/undionly.kpxe" or - f "$tftpdir/xcat/xnba.kpxe" ) ) { $ callback - > ( { error = > "$_: No iscsi boot data available" , errorcode = > [ 1 ] } ) ; } #If x86 node and undionly.kpxe exists, presume they know what they are doing
next ;
}
my $ hash ;
$ hash - > { kernel } = $ ient - > { kernel } ;
if ( $ ient - > { initrd } ) { $ hash - > { initrd } = $ ient - > { initrd } }
if ( $ ient - > { kcmdline } ) { $ hash - > { kcmdline } = $ ient - > { kcmdline } }
$ bptab - > setNodeAttribs ( $ _ , $ hash ) ;
}
} elsif ( $ state =~ /^install[=\$]/ or $ state eq 'install' or $ state =~ /^netboot[=\$]/ or $ state eq 'netboot' or $ state eq "image" or $ state eq "winshell" or $ state =~ /^osimage/ or $ state =~ /^statelite/ ) {
my % state_hash ;
chomp ( $ state ) ;
my $ target ;
my $ action ;
if ( $ state =~ /=/ ) {
( $ state , $ target ) = split '=' , $ state , 2 ;
if ( $ target =~ /:/ ) {
( $ target , $ action ) = split ':' , $ target , 2 ;
}
} else {
if ( $ state =~ /:/ ) {
( $ state , $ action ) = split ':' , $ state , 2 ;
}
}
2008-09-30 20:00:46 +00:00
2012-12-11 20:59:50 +00:00
foreach my $ tmpnode ( @ { $ req - > { node } } ) {
$ state_hash { $ tmpnode } = $ state ;
}
2009-09-22 15:37:40 +00:00
2012-12-11 20:59:50 +00:00
my $ nodetypetable = xCAT::Table - > new ( 'nodetype' , - create = > 1 ) ;
if ( $ state ne 'osimage' ) {
my $ updateattribs ;
if ( $ target ) {
my $ archentries = $ nodetypetable - > getNodesAttribs ( $ req - > { node } , [ 'supportedarchs' ] ) ;
if ( $ target =~ /^([^-]*)-([^-]*)-(.*)/ ) {
$ updateattribs - > { os } = $ 1 ;
$ updateattribs - > { arch } = $ 2 ;
$ updateattribs - > { profile } = $ 3 ;
my $ nodearch = $ 2 ;
foreach ( @ { $ req - > { node } } ) {
if ( $ archentries - > { $ _ } - > [ 0 ] - > { supportedarchs } and $ archentries - > { $ _ } - > [ 0 ] - > { supportedarchs } !~ /(^|,)$nodearch(\z|,)/ ) {
$ callback - > ( { errorcode = > 1 , error = > "Requested architecture " . $ nodearch . " is not one of the architectures supported by $_ (per nodetype.supportedarchs, it supports " . $ archentries - > { $ _ } - > [ 0 ] - > { supportedarchs } . ")" } ) ;
return ;
}
} #end foreach
2009-09-22 15:37:40 +00:00
} else {
2012-12-11 20:59:50 +00:00
$ updateattribs - > { profile } = $ target ;
}
} #end if($target)
$ updateattribs - > { provmethod } = $ state ;
my @ tmpnodelist = @ { $ req - > { node } } ;
$ nodetypetable - > setNodesAttribs ( \ @ tmpnodelist , $ updateattribs ) ;
} else { #state is osimage
if ( @ { $ req - > { node } } == 0 ) { return ; }
if ( $ target ) {
my $ osimagetable = xCAT::Table - > new ( 'osimage' ) ;
( my $ ref ) = $ osimagetable - > getAttribs ( { imagename = > $ target } , 'provmethod' , 'osvers' , 'profile' , 'osarch' ) ;
if ( $ ref ) {
if ( $ ref - > { provmethod } ) {
$ state = $ ref - > { provmethod } ;
} else {
$ errored = 1 ; $ callback - > ( { error = > "osimage.provmethod for $target must be set." } ) ;
return ;
}
} else {
$ errored = 1 ; $ callback - > ( { error = > "Cannot find the OS image $target on the osimage table." } ) ;
2009-09-22 15:37:40 +00:00
return ;
}
2012-12-11 20:59:50 +00:00
my $ updateattribs ;
$ updateattribs - > { provmethod } = $ target ;
$ updateattribs - > { profile } = $ ref - > { profile } ;
$ updateattribs - > { os } = $ ref - > { osvers } ;
$ updateattribs - > { arch } = $ ref - > { osarch } ;
my @ tmpnodelist = @ { $ req - > { node } } ;
$ nodetypetable - > setNodesAttribs ( \ @ tmpnodelist , $ updateattribs ) ;
foreach my $ tmpnode ( @ { $ req - > { node } } ) {
$ state_hash { $ tmpnode } = $ state ;
}
} else {
my @ errornodes = ( ) ;
my $ updatestuff ;
my $ nodetypetable = xCAT::Table - > new ( 'nodetype' , - create = > 1 ) ;
my % ntents = % { $ nodetypetable - > getNodesAttribs ( $ req - > { node } , "provmethod" ) } ;
foreach my $ tmpnode ( @ { $ req - > { node } } ) {
my $ osimage = $ ntents { $ tmpnode } - > [ 0 ] - > { provmethod } ;
if ( ( $ osimage ) && ( $ osimage ne 'install' ) && ( $ osimage ne 'netboot' ) && ( $ osimage ne 'statelite' ) ) {
if ( ! exists ( $ updatestuff - > { $ osimage } ) ) {
my $ osimagetable = xCAT::Table - > new ( 'osimage' ) ;
( my $ ref ) = $ osimagetable - > getAttribs ( { imagename = > $ osimage } , 'provmethod' , 'osvers' , 'profile' , 'osarch' ) ;
if ( $ ref ) {
if ( $ ref - > { provmethod } ) {
$ state = $ ref - > { provmethod } ;
$ state_hash { $ tmpnode } = $ state ;
$ updatestuff - > { $ osimage } - > { state } = $ state ;
$ updatestuff - > { $ osimage } - > { nodes } = [ $ tmpnode ] ;
$ updatestuff - > { $ osimage } - > { profile } = $ ref - > { profile } ;
$ updatestuff - > { $ osimage } - > { os } = $ ref - > { osvers } ;
$ updatestuff - > { $ osimage } - > { arch } = $ ref - > { osarch } ;
} else {
$ errored = 1 ; $ callback - > ( { error = > "osimage.provmethod for $osimage must be set." } ) ;
return ;
}
} else {
$ errored = 1 ; $ callback - > ( { error = > "Cannot find the OS image $osimage on the osimage table." } ) ;
return ;
}
} else {
my $ nodes = $ updatestuff - > { $ osimage } - > { nodes } ;
push ( @$ nodes , $ tmpnode ) ;
$ state_hash { $ tmpnode } = $ updatestuff - > { $ osimage } - > { state } ;
}
} else {
push ( @ errornodes , $ tmpnode ) ;
}
}
if ( @ errornodes ) {
$ errored = 1 ; $ callback - > ( { error = > "OS image name must be specified in nodetype.provmethod for nodes: @errornodes." } ) ;
return ;
} else {
foreach my $ tmpimage ( keys %$ updatestuff ) {
my $ updateattribs = $ updatestuff - > { $ tmpimage } ;
my @ tmpnodelist = @ { $ updateattribs - > { nodes } } ;
delete $ updateattribs - > { nodes } ; #not needed for nodetype table
delete $ updateattribs - > { state } ; #node needed for nodetype table
$ nodetypetable - > setNodesAttribs ( \ @ tmpnodelist , $ updateattribs ) ;
}
}
}
}
#print Dumper($req);
# if precreatemypostscripts=1, create each mypostscript for each node
# otherwise, create it during installation /updatenode
2013-05-16 13:55:55 +00:00
my $ notmpfiles = 0 ; # create tmp files if precreate=0
my $ nofiles = 0 ; # create files, do not return array
2012-12-11 20:59:50 +00:00
require xCAT::Postage ;
2013-05-16 13:55:55 +00:00
xCAT::Postage:: create_mypostscript_or_not ( $ request , $ callback , $ subreq , $ notmpfiles , $ nofiles ) ;
2012-12-11 20:59:50 +00:00
my % state_hash1 ;
foreach my $ tmpnode ( keys ( % state_hash ) ) {
push @ { $ state_hash1 { $ state_hash { $ tmpnode } } } , $ tmpnode ;
}
#print Dumper(%state_hash);
#print Dumper(%state_hash1);
foreach my $ tempstate ( keys % state_hash1 ) {
my $ samestatenodes = $ state_hash1 { $ tempstate } ;
#print "state=$tempstate nodes=@$samestatenodes\n";
$ errored = 0 ;
$ subreq - > ( { command = > [ "mk$tempstate" ] ,
2013-07-04 05:09:44 +00:00
node = > $ samestatenodes ,
2013-11-19 11:27:11 +00:00
noupdateinitrd = > $ noupdateinitrd ,
ignorekernelchk = > $ ignorekernelchk , } , \ & relay_response ) ;
2012-12-11 20:59:50 +00:00
if ( $ errored ) {
$ callback - > ( { error = > "Some nodes failed to set up $state resources, aborting" } ) ;
return ;
}
my $ ntents = $ nodetypetable - > getNodesAttribs ( $ samestatenodes , [ qw( os arch profile ) ] ) ;
foreach ( @ { $ samestatenodes } ) {
$ nstates { $ _ } = $ tempstate ; #local copy of state variable for mod
my $ ntent = $ ntents - > { $ _ } - > [ 0 ] ; #$nodetype->getNodeAttribs($_,[qw(os arch profile)]);
if ( $ tempstate ne "winshell" ) {
if ( $ ntent and $ ntent - > { os } ) {
$ nstates { $ _ } . = " " . $ ntent - > { os } ;
} else { $ errored = 1 ; $ callback - > ( { error = > "nodetype.os not defined for $_" } ) ; }
} else {
$ nstates { $ _ } . = " winpe" ;
}
if ( $ ntent and $ ntent - > { arch } ) {
$ nstates { $ _ } . = "-" . $ ntent - > { arch } ;
} else { $ errored = 1 ; $ callback - > ( { error = > "nodetype.arch not defined for $_" } ) ; }
2013-03-04 05:08:13 +00:00
if ( ( $ tempstate ne "winshell" ) && ( $ tempstate ne "sysclone" ) ) {
2012-12-11 20:59:50 +00:00
if ( $ ntent and $ ntent - > { profile } ) {
$ nstates { $ _ } . = "-" . $ ntent - > { profile } ;
} else { $ errored = 1 ; $ callback - > ( { error = > "nodetype.profile not defined for $_" } ) ; }
}
if ( $ errored ) { return ; }
#statelite
unless ( $ tempstate =~ /^netboot|^statelite/ ) { $ chaintab - > setNodeAttribs ( $ _ , { currchain = > "boot" } ) ; } ;
}
if ( $ action eq "reboot4deploy" ) {
# this action is used in the discovery process for deployment of the node
# e.g. set chain.chain to 'osimage=rhels6.2-x86_64-netboot-compute:reboot4deploy'
# Set the status of the node to be 'installing' or 'netbooting'
my % newnodestatus ;
my $ newstat = xCAT_monitoring::monitorctrl - > getNodeStatusFromNodesetState ( $ tempstate , "rpower" ) ;
$ newnodestatus { $ newstat } = $ samestatenodes ;
xCAT_monitoring::monitorctrl:: setNodeStatusAttributes ( \ % newnodestatus , 1 ) ;
}
}
} elsif ( $ state eq "shell" or $ state eq "standby" or $ state =~ /^runcmd/ or $ state =~ /^runimage/ ) {
$ restab = xCAT::Table - > new ( 'noderes' , - create = > 1 ) ;
my $ bootparms = xCAT::Table - > new ( 'bootparams' , - create = > 1 ) ;
my $ nodetype = xCAT::Table - > new ( 'nodetype' ) ;
#my $sitetab = xCAT::Table->new('site');
my $ nodehm = xCAT::Table - > new ( 'nodehm' ) ;
my $ hments = $ nodehm - > getNodesAttribs ( \ @ nodes , [ 'serialport' , 'serialspeed' , 'serialflow' ] ) ;
#(my $portent) = $sitetab->getAttribs({key=>'xcatdport'},'value');
my @ entries = xCAT::TableUtils - > get_site_attribute ( "xcatdport" ) ;
my $ port_entry = $ entries [ 0 ] ;
#(my $mastent) = $sitetab->getAttribs({key=>'master'},'value');
my @ entries = xCAT::TableUtils - > get_site_attribute ( "master" ) ;
my $ master_entry = $ entries [ 0 ] ;
my $ enthash = $ nodetype - > getNodesAttribs ( \ @ nodes , [ qw( arch ) ] ) ;
2013-12-05 01:47:39 +00:00
my $ resents = $ restab - > getNodesAttribs ( \ @ nodes , [ qw( xcatmaster ) ] ) ;
2012-12-11 20:59:50 +00:00
foreach ( @ nodes ) {
my $ ent = $ enthash - > { $ _ } - > [ 0 ] ; #$nodetype->getNodeAttribs($_,[qw(arch)]);
unless ( $ ent and $ ent - > { arch } ) {
$ callback - > ( { error = > [ "No archictecture defined in nodetype table for $_" ] , errorcode = > [ 1 ] } ) ;
2009-09-22 15:37:40 +00:00
return ;
}
2012-12-11 20:59:50 +00:00
my $ arch = $ ent - > { arch } ;
my $ ent = $ resents - > { $ _ } - > [ 0 ] ; #$restab->getNodeAttribs($_,[qw(xcatmaster)]);
my $ master ;
my $ kcmdline = "quiet " ;
if ( defined ( $ master_entry ) ) {
$ master = $ master_entry ;
}
if ( $ ent and $ ent - > { xcatmaster } ) {
$ master = $ ent - > { xcatmaster } ;
}
$ ent = $ hments - > { $ _ } - > [ 0 ] ; #$nodehm->getNodeAttribs($_,['serialport','serialspeed','serialflow']);
if ( $ ent and defined ( $ ent - > { serialport } ) ) {
$ kcmdline . = "console=tty0 console=ttyS" . $ ent - > { serialport } ;
#$ent = $nodehm->getNodeAttribs($_,['serialspeed']);
unless ( $ ent and defined ( $ ent - > { serialspeed } ) ) {
$ callback - > ( { error = > [ "Serial port defined in noderes, but no nodehm.serialspeed set for $_" ] , errorcode = > [ 1 ] } ) ;
return ;
}
$ kcmdline . = "," . $ ent - > { serialspeed } ;
#$ent = $nodehm->getNodeAttribs($_,['serialflow']);
$ kcmdline . = " " ;
}
unless ( $ master ) {
$ callback - > ( { error = > [ "No master in site table nor noderes table for $_" ] , errorcode = > [ 1 ] } ) ;
return ;
}
my $ xcatdport = "3001" ;
if ( defined ( $ port_entry ) ) {
$ xcatdport = $ port_entry ;
}
if ( - r "$tftpdir/xcat/genesis.kernel.$arch" ) {
2013-04-22 19:18:53 +00:00
my $ bestsuffix = "lzma" ;
my $ othersuffix = "gz" ;
if ( - r "$tftpdir/xcat/genesis.fs.$arch.lzma" and - r "$tftpdir/xcat/genesis.fs.$arch.gz" ) {
if ( - C "$tftpdir/xcat/genesis.fs.$arch.lzma" > - C "$tftpdir/xcat/genesis.fs.$arch.gz" ) { #here, lzma is older for whatever reason
$ bestsuffix = "gz" ;
$ othersuffix = "lzma" ;
}
}
if ( - r "$tftpdir/xcat/genesis.fs.$arch.$bestsuffix" ) {
2012-12-11 20:59:50 +00:00
$ bootparms - > setNodeAttribs ( $ _ , { kernel = > "xcat/genesis.kernel.$arch" ,
2013-04-22 19:18:53 +00:00
initrd = > "xcat/genesis.fs.$arch.$bestsuffix" ,
2012-12-11 20:59:50 +00:00
kcmdline = > $ kcmdline . "xcatd=$master:$xcatdport destiny=$state" } ) ;
} else {
$ bootparms - > setNodeAttribs ( $ _ , { kernel = > "xcat/genesis.kernel.$arch" ,
2013-04-22 19:18:53 +00:00
initrd = > "xcat/genesis.fs.$arch.$othersuffix" ,
2012-12-11 20:59:50 +00:00
kcmdline = > $ kcmdline . "xcatd=$master:$xcatdport destiny=$state" } ) ;
}
} else { #'legacy' environment
$ bootparms - > setNodeAttribs ( $ _ , { kernel = > "xcat/nbk.$arch" ,
initrd = > "xcat/nbfs.$arch.gz" ,
kcmdline = > $ kcmdline . "xcatd=$master:$xcatdport" } ) ;
}
}
2013-06-09 09:17:39 +00:00
# try to check the existence of the image for runimage
my @ runimgcmds ;
if ( $ state =~ /^runimage/ ) {
push @ runimgcmds , $ state ;
}
if ( $ reststates ) {
my @ rstates = split ( /,/ , $ reststates ) ;
foreach ( @ rstates ) {
if ( /^runimage/ ) {
push @ runimgcmds , $ _ ;
}
}
}
foreach ( @ runimgcmds ) {
my ( undef , $ path ) = split ( /=/ , $ _ ) ;
if ( $ path ) {
if ( $ path =~ /\$/ ) { next ; } # Ignore the path with including variable like $xcatmaster
my $ cmd = "wget --spider --timeout 3 --tries=1 $path" ;
my @ output = xCAT::Utils - > runcmd ( "$cmd" , - 1 ) ;
unless ( grep /^Remote file exists/ , @ output ) {
$ callback - > ( { error = > [ "Cannot get $path with wget. Could you confirm it's downloadable by wget?" ] , errorcode = > [ 1 ] } ) ;
return ;
}
} else {
$ callback - > ( { error = > "An image path should be specified to runnimage." , errorcode = > [ 1 ] } ) ;
return ;
}
}
2012-12-11 20:59:50 +00:00
} elsif ( $ state eq "offline" ) {
1 ;
} elsif ( ! ( $ state eq "boot" ) ) {
$ callback - > ( { error = > [ "Unknown state $state requested" ] , errorcode = > [ 1 ] } ) ;
return ;
2009-09-22 15:37:40 +00:00
}
2012-10-12 06:53:25 +00:00
2012-12-11 20:59:50 +00:00
#blank out the nodetype.provmethod if the previous provisioning method is not 'install'
if ( $ state eq "iscsiboot" or $ state eq "boot" ) {
my $ nodetype = xCAT::Table - > new ( 'nodetype' , - create = > 1 ) ;
my $ osimagetab = xCAT::Table - > new ( 'osimage' , - create = > 1 ) ;
my $ ntents = $ nodetype - > getNodesAttribs ( $ req - > { node } , [ qw( os arch profile provmethod ) ] ) ;
my @ nodestoblank = ( ) ;
my % osimage_hash = ( ) ;
foreach ( @ { $ req - > { node } } ) {
my $ ntent = $ ntents - > { $ _ } - > [ 0 ] ;
#if the previous nodeset staute is not install, then blank nodetype.provmethod
if ( $ ntent and $ ntent - > { provmethod } ) {
my $ provmethod = $ ntent - > { provmethod } ;
if ( ( $ provmethod ne 'install' ) && ( $ provmethod ne 'netboot' ) && ( $ provmethod ne 'statelite' ) ) {
if ( exists ( $ osimage_hash { $ provmethod } ) ) {
$ provmethod = $ osimage_hash { $ provmethod } ;
} else {
( my $ ref ) = $ osimagetab - > getAttribs ( { imagename = > $ provmethod } , 'provmethod' ) ;
if ( ( $ ref ) && $ ref - > { provmethod } ) {
$ osimage_hash { $ provmethod } = $ ref - > { provmethod } ;
$ provmethod = $ ref - > { provmethod } ;
}
}
}
if ( $ provmethod ne 'install' ) {
push ( @ nodestoblank , $ _ ) ;
}
}
} #end foreach
#now blank out the nodetype.provmethod
#print "nodestoblank=@nodestoblank\n";
if ( @ nodestoblank > 0 ) {
my $ newhash ;
$ newhash - > { provmethod } = "" ;
$ nodetype - > setNodesAttribs ( \ @ nodestoblank , $ newhash ) ;
}
2012-12-06 14:11:42 +00:00
}
2012-12-11 20:59:50 +00:00
if ( $ noupdate ) { return ; } #skip table manipulation if just doing 'enact'
2007-10-26 22:44:33 +00:00
foreach ( @ nodes ) {
2012-12-11 20:59:50 +00:00
my $ lstate = $ state ;
if ( $ nstates { $ _ } ) {
$ lstate = $ nstates { $ _ } ;
}
$ chaintab - > setNodeAttribs ( $ _ , { currstate = > $ lstate } ) ;
2013-06-09 09:17:39 +00:00
# if there are multiple actions in the state argument, set the rest of states (shift out the first one)
# to chain.currchain so that the rest ones could be used by nextdestiny command
if ( $ reststates ) {
$ chaintab - > setNodeAttribs ( $ _ , { currchain = > $ reststates } ) ;
}
2007-10-26 22:44:33 +00:00
}
2012-12-11 20:59:50 +00:00
return getdestiny ( $ flag + 1 ) ;
2007-10-26 22:44:33 +00:00
}
sub nextdestiny {
2008-09-30 20:00:46 +00:00
my $ flag = shift ;
2008-02-27 17:08:26 +00:00
my $ callnodeset = 0 ;
if ( scalar ( @ _ ) ) {
$ callnodeset = 1 ;
}
2007-10-26 22:44:33 +00:00
my @ nodes ;
if ( $ request and $ request - > { node } ) {
if ( ref ( $ request - > { node } ) ) {
@ nodes = @ { $ request - > { node } } ;
} else {
@ nodes = ( $ request - > { node } ) ;
}
#TODO: service third party getdestiny..
} else { #client asking to move along its own chain
#TODO: SECURITY with this, any one on a node could advance the chain, for node, need to think of some strategy to deal with...
2012-07-03 16:29:15 +00:00
my $ node ;
if ( $ ::XCATSITEVALS { nodeauthentication } ) { #if requiring node authentication, this request will have a certificate associated with it, use it instead of name resolution
unless ( ref $ request - > { username } ) { return ; } #TODO: log an attempt without credentials?
$ node = $ request - > { username } - > [ 0 ] ;
} else {
unless ( $ request - > { '_xcat_clienthost' } - > [ 0 ] ) {
#ERROR? malformed request
return ; #nothing to do here...
}
$ node = $ request - > { '_xcat_clienthost' } - > [ 0 ] ;
2007-10-26 22:44:33 +00:00
}
2012-07-03 16:29:15 +00:00
( $ node ) = noderange ( $ node ) ;
unless ( $ node ) {
2007-10-26 22:44:33 +00:00
#not a node, don't trust it
return ;
2012-07-03 16:29:15 +00:00
}
@ nodes = ( $ node ) ;
2007-10-26 22:44:33 +00:00
}
my $ node ;
2008-07-11 19:02:39 +00:00
$ chaintab = xCAT::Table - > new ( 'chain' ) ;
my $ chainents = $ chaintab - > getNodesAttribs ( \ @ nodes , [ qw( currstate currchain chain ) ] ) ;
2007-10-26 22:44:33 +00:00
foreach $ node ( @ nodes ) {
unless ( $ chaintab ) {
2013-10-18 11:42:10 +00:00
syslog ( "local4|err" , "ERROR: $node requested destiny update, no chain table" ) ;
2007-10-26 22:44:33 +00:00
return ; #nothing to do...
}
2008-07-11 19:02:39 +00:00
my $ ref = $ chainents - > { $ node } - > [ 0 ] ; #$chaintab->getNodeAttribs($node,[qw(currstate currchain chain)]);
2007-11-26 19:09:11 +00:00
unless ( $ ref - > { chain } or $ ref - > { currchain } ) {
2013-10-18 11:42:10 +00:00
syslog ( "local4|err" , "ERROR: node requested destiny update, no path in chain.currchain" ) ;
2007-10-26 22:44:33 +00:00
return ; #Can't possibly do anything intelligent..
}
unless ( $ ref - > { currchain } ) { #If no current chain, copy the default
$ ref - > { currchain } = $ ref - > { chain } ;
}
2008-02-27 16:47:12 +00:00
my @ chain = split /[,;]/ , $ ref - > { currchain } ;
2007-10-26 22:44:33 +00:00
$ ref - > { currstate } = shift @ chain ;
$ ref - > { currchain } = join ( ',' , @ chain ) ;
unless ( $ ref - > { currchain } ) { #If we've gone off the end of the chain, have currchain stick
$ ref - > { currchain } = $ ref - > { currstate } ;
}
2009-12-04 00:59:53 +00:00
$ chaintab - > setNodeAttribs ( $ node , $ ref ) ; #$ref is in a state to commit back to db
2008-09-25 03:04:56 +00:00
2007-10-26 22:44:33 +00:00
my % requ ;
$ requ { node } = [ $ node ] ;
$ requ { arg } = [ $ ref - > { currstate } ] ;
2008-09-30 20:00:46 +00:00
setdestiny ( \ % requ , $ flag + 1 ) ;
2007-10-26 22:44:33 +00:00
}
2008-09-25 03:04:56 +00:00
2008-02-27 17:08:26 +00:00
if ( $ callnodeset ) {
$ subreq - > ( { command = > [ 'nodeset' ] ,
node = > \ @ nodes ,
arg = > [ 'enact' ] } ) ;
}
2008-09-25 03:04:56 +00:00
2007-10-26 22:44:33 +00:00
}
sub getdestiny {
2008-09-30 20:00:46 +00:00
my $ flag = shift ;
# flag value:
# 0--getdestiny is called by dodestiny
# 1--called by nextdestiny in dodestiny. The node calls nextdestiny before boot and runcmd.
# 2--called by nodeset command
# 3--called by updateflag after the node finished installation and before booting
2007-10-26 22:44:33 +00:00
my @ args ;
my @ nodes ;
if ( $ request - > { node } ) {
if ( ref ( $ request - > { node } ) ) {
@ nodes = @ { $ request - > { node } } ;
} else {
@ nodes = ( $ request - > { node } ) ;
}
} else { # a client asking for it's own destiny.
2008-01-25 15:07:53 +00:00
unless ( $ request - > { '_xcat_clienthost' } - > [ 0 ] ) {
2007-10-26 22:44:33 +00:00
$ callback - > ( { destiny = > [ 'discover' ] } ) ;
return ;
}
2008-01-25 15:07:53 +00:00
my ( $ node ) = noderange ( $ request - > { '_xcat_clienthost' } - > [ 0 ] ) ;
2007-10-26 22:44:33 +00:00
unless ( $ node ) { # it had a valid hostname, but isn't a node
$ callback - > ( { destiny = > [ 'discover' ] } ) ;
return ;
}
@ nodes = ( $ node ) ;
}
my $ node ;
2008-07-11 19:02:39 +00:00
$ restab = xCAT::Table - > new ( 'noderes' ) ;
2008-07-22 12:45:41 +00:00
my $ chaintab = xCAT::Table - > new ( 'chain' ) ;
2008-07-11 19:02:39 +00:00
my $ chainents = $ chaintab - > getNodesAttribs ( \ @ nodes , [ qw( currstate chain ) ] ) ;
my $ nrents = $ restab - > getNodesAttribs ( \ @ nodes , [ qw( tftpserver xcatmaster ) ] ) ;
$ bptab = xCAT::Table - > new ( 'bootparams' , - create = > 1 ) ;
my $ bpents = $ bptab - > getNodesAttribs ( \ @ nodes , [ qw( kernel initrd kcmdline xcatmaster ) ] ) ;
2012-05-22 06:32:20 +00:00
#my $sitetab= xCAT::Table->new('site');
#(my $sent) = $sitetab->getAttribs({key=>'master'},'value');
2012-08-09 04:07:40 +00:00
my @ entries = xCAT::TableUtils - > get_site_attribute ( "master" ) ;
2012-05-22 06:32:20 +00:00
my $ master_value = $ entries [ 0 ] ;
2008-09-30 20:00:46 +00:00
my % node_status = ( ) ;
2007-10-26 22:44:33 +00:00
foreach $ node ( @ nodes ) {
unless ( $ chaintab ) { #Without destiny, have the node wait with ssh hopefully open at least
$ callback - > ( { node = > [ { name = > [ $ node ] , data = > [ 'standby' ] , destiny = > [ 'standby' ] } ] } ) ;
return ;
}
2008-07-11 19:02:39 +00:00
my $ ref = $ chainents - > { $ node } - > [ 0 ] ; #$chaintab->getNodeAttribs($node,[qw(currstate chain)]);
2007-10-26 22:44:33 +00:00
unless ( $ ref ) {
2008-09-30 20:00:46 +00:00
#collect node status for certain states
2009-03-24 13:51:56 +00:00
if ( ( $ nonodestatus == 0 ) && ( ( $ flag == 0 ) || ( $ flag == 3 ) ) ) {
2008-09-30 20:00:46 +00:00
my $ stat = xCAT_monitoring::monitorctrl - > getNodeStatusFromNodesetState ( "standby" , "getdestiny" ) ;
#print "node=$node, stat=$stat\n";
if ( $ stat ) {
if ( exists ( $ node_status { $ stat } ) ) {
my $ pa = $ node_status { $ stat } ;
push ( @$ pa , $ node ) ;
}
else { $ node_status { $ stat } = [ $ node ] ; }
}
}
2007-10-26 22:44:33 +00:00
$ callback - > ( { node = > [ { name = > [ $ node ] , data = > [ 'standby' ] , destiny = > [ 'standby' ] } ] } ) ;
2008-09-30 20:00:46 +00:00
next ;
2007-10-26 22:44:33 +00:00
}
unless ( $ ref - > { currstate } ) { #Has a record, but not yet in a state...
2010-01-21 06:11:24 +00:00
# we set a 1 here so that it does the nodeset to create tftpboot files
return nextdestiny ( 0 , 1 ) ; #Becomes a nextdestiny...
2008-10-03 23:16:57 +00:00
# my @chain = split /,/,$ref->{chain};
# $ref->{currstate} = shift @chain;
# $chaintab->setNodeAttribs($node,{currstate=>$ref->{currstate}});
2007-10-26 22:44:33 +00:00
}
my % response ;
$ response { name } = [ $ node ] ;
$ response { data } = [ $ ref - > { currstate } ] ;
$ response { destiny } = [ $ ref - > { currstate } ] ;
2008-07-11 19:02:39 +00:00
my $ nrent = $ nrents - > { $ node } - > [ 0 ] ; #$noderestab->getNodeAttribs($node,[qw(tftpserver xcatmaster)]);
my $ bpent = $ bpents - > { $ node } - > [ 0 ] ; #$bptab->getNodeAttribs($node,[qw(kernel initrd kcmdline xcatmaster)]);
2008-04-25 15:36:56 +00:00
if ( defined $ bpent - > { kernel } ) {
$ response { kernel } = $ bpent - > { kernel } ;
2007-10-26 22:44:33 +00:00
}
2008-04-25 15:36:56 +00:00
if ( defined $ bpent - > { initrd } ) {
$ response { initrd } = $ bpent - > { initrd } ;
2007-10-26 22:44:33 +00:00
}
2008-04-25 15:36:56 +00:00
if ( defined $ bpent - > { kcmdline } ) {
$ response { kcmdline } = $ bpent - > { kcmdline } ;
2007-10-26 22:44:33 +00:00
}
if ( defined $ nrent - > { tftpserver } ) {
$ response { imgserver } = $ nrent - > { tftpserver } ;
} elsif ( defined $ nrent - > { xcatmaster } ) {
$ response { imgserver } = $ nrent - > { xcatmaster } ;
2012-05-22 06:32:20 +00:00
} elsif ( defined ( $ master_value ) ) {
$ response { imgserver } = $ master_value ;
2008-02-07 21:48:21 +00:00
} else {
2012-08-09 04:07:40 +00:00
$ response { imgserver } = xCAT::NetworkUtils - > my_ip_facing ( $ node ) ;
2007-10-26 22:44:33 +00:00
}
2008-09-30 20:00:46 +00:00
#collect node status for certain states
if ( ( $ flag == 0 ) || ( $ flag == 3 ) ) {
my $ stat = xCAT_monitoring::monitorctrl - > getNodeStatusFromNodesetState ( $ response { destiny } - > [ 0 ] , "getdestiny" ) ;
#print "node=$node, stat=$stat\n";
if ( $ stat ) {
if ( exists ( $ node_status { $ stat } ) ) {
my $ pa = $ node_status { $ stat } ;
push ( @$ pa , $ node ) ;
}
else { $ node_status { $ stat } = [ $ node ] ; }
}
}
2007-10-26 22:44:33 +00:00
$ callback - > ( { node = > [ \ % response ] } ) ;
}
2008-09-30 20:00:46 +00:00
#setup the nodelist.status
2009-03-24 13:51:56 +00:00
if ( ( $ nonodestatus == 0 ) && ( ( $ flag == 0 ) || ( $ flag == 3 ) ) ) {
2008-09-30 20:00:46 +00:00
#print "save status\n";
if ( keys ( % node_status ) > 0 ) { xCAT_monitoring::monitorctrl:: setNodeStatusAttributes ( \ % node_status , 1 ) ; }
}
2007-10-26 22:44:33 +00:00
}
1 ;