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 ;
use xCAT::NodeRange ;
use Data::Dumper ;
2008-02-07 21:48:21 +00:00
use xCAT::Utils ;
2007-10-26 22:44:33 +00:00
use Sys::Syslog ;
2008-09-25 03:04:56 +00:00
use xCAT::GlobalDef ;
use xCAT_monitoring::monitorctrl ;
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 ;
my $ sitetab ;
my $ hmtab ;
2008-10-30 14:37:56 +00:00
my $ tftpdir = "/tftpboot" ;
2008-07-11 19:02:39 +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 ;
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 {
my $ req = shift ;
2008-09-30 20:00:46 +00:00
my $ flag = shift ;
2008-07-11 19:02:39 +00:00
$ chaintab = xCAT::Table - > new ( 'chain' , - create = > 1 ) ;
2007-10-26 22:44:33 +00:00
my @ nodes = @ { $ req - > { node } } ;
my $ state = $ req - > { arg } - > [ 0 ] ;
2007-11-29 21:57:24 +00:00
my % nstates ;
2007-10-26 22:44:33 +00:00
if ( $ state eq "next" ) {
2008-09-30 20:00:46 +00:00
return nextdestiny ( $ flag + 1 ) ; #this is special case where updateflag is called
2008-02-07 21:48:21 +00:00
} 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 ] } ) ;
}
2008-07-11 19:02:39 +00:00
my $ bptab = xCAT::Table - > new ( 'bootparams' , - create = > 1 ) ;
2008-10-30 14:37:56 +00:00
my $ nodetype = xCAT::Table - > new ( 'nodetype' ) ;
my $ ntents = $ nodetype - > getNodesAttribs ( $ req - > { node } , [ qw( os arch profile ) ] ) ;
2008-07-11 19:02:39 +00:00
my $ ients = $ iscsitab - > getNodesAttribs ( $ req - > { node } , [ qw( kernel kcmdline initrd ) ] ) ;
2008-02-07 21:48:21 +00:00
foreach ( @ { $ req - > { node } } ) {
2008-07-11 19:02:39 +00:00
my $ ient = $ ients - > { $ _ } - > [ 0 ] ; #$iscsitab->getNodeAttribs($_,[qw(kernel kcmdline initrd)]);
2008-10-30 14:37:56 +00:00
my $ ntent = $ ntents - > { $ _ } - > [ 0 ] ;
2008-02-07 21:48:21 +00:00
unless ( $ ient and $ ient - > { kernel } ) {
2008-10-30 14:37:56 +00:00
unless ( $ ntent and $ ntent - > { arch } =~ /x86/ and - f "$tftpdir/undionly.kpxe" ) { $ callback - > ( { error = > "$_: No iscsi boot data available" , errorcode = > [ 1 ] } ) ; } #If x86 node and undionly.kpxe exists, presume they know what they are doing
2008-02-07 21:48:21 +00:00
next ;
}
my $ hash ;
$ hash - > { kernel } = $ ient - > { kernel } ;
if ( $ ient - > { initrd } ) { $ hash - > { initrd } = $ ient - > { initrd } }
if ( $ ient - > { kcmdline } ) { $ hash - > { kcmdline } = $ ient - > { kcmdline } }
2008-05-05 15:41:47 +00:00
$ bptab - > setNodeAttribs ( $ _ , $ hash ) ;
2008-02-07 21:48:21 +00:00
}
2008-09-20 22:26:48 +00:00
} elsif ( $ state =~ /^install$/ or $ state eq "install" or $ state eq "netboot" or $ state eq "image" or $ state eq "winshell" ) {
2007-11-06 21:28:02 +00:00
chomp ( $ state ) ;
$ subreq - > ( { command = > [ "mk$state" ] ,
node = > $ req - > { node } } , \ & relay_response ) ;
if ( $ errored ) { return ; }
2007-10-26 22:44:33 +00:00
my $ nodetype = xCAT::Table - > new ( 'nodetype' ) ;
2008-07-11 19:02:39 +00:00
my $ ntents = $ nodetype - > getNodesAttribs ( $ req - > { node } , [ qw( os arch profile ) ] ) ;
2007-10-26 22:44:33 +00:00
foreach ( @ { $ req - > { node } } ) {
2007-11-29 21:57:24 +00:00
$ nstates { $ _ } = $ state ; #local copy of state variable for mod
2008-07-11 19:02:39 +00:00
my $ ntent = $ ntents - > { $ _ } - > [ 0 ] ; #$nodetype->getNodeAttribs($_,[qw(os arch profile)]);
2008-10-27 13:50:19 +00:00
if ( $ state ne "winshell" ) {
if ( $ ntent and $ ntent - > { os } ) {
$ nstates { $ _ } . = " " . $ ntent - > { os } ;
} else { $ errored = 1 ; $ callback - > ( { error = > "nodetype.os not defined for $_" } ) ; }
} else {
$ nstates { $ _ } . = " winpe" ;
}
2007-10-26 22:44:33 +00:00
if ( $ ntent and $ ntent - > { arch } ) {
2007-11-29 21:57:24 +00:00
$ nstates { $ _ } . = "-" . $ ntent - > { arch } ;
2008-01-19 16:38:03 +00:00
} else { $ errored = 1 ; $ callback - > ( { error = > "nodetype.arch not defined for $_" } ) ; }
2008-10-27 13:50:19 +00:00
if ( $ state ne "winshell" ) {
if ( $ ntent and $ ntent - > { profile } ) {
$ nstates { $ _ } . = "-" . $ ntent - > { profile } ;
} else { $ errored = 1 ; $ callback - > ( { error = > "nodetype.profile not defined for $_" } ) ; }
}
2008-01-19 16:38:03 +00:00
if ( $ errored ) { return ; }
2007-11-06 21:28:02 +00:00
unless ( $ state =~ /^netboot/ ) { $ chaintab - > setNodeAttribs ( $ _ , { currchain = > "boot" } ) ; } ;
2007-10-26 22:44:33 +00:00
}
2008-02-27 16:22:32 +00:00
} elsif ( $ state eq "shell" or $ state eq "standby" or $ state =~ /^runcmd/ or $ state =~ /^runimage/ ) {
2008-07-11 19:02:39 +00:00
$ restab = xCAT::Table - > new ( 'noderes' , - create = > 1 ) ;
2008-04-25 15:36:56 +00:00
my $ bootparms = xCAT::Table - > new ( 'bootparams' , - create = > 1 ) ;
2007-10-26 22:44:33 +00:00
my $ nodetype = xCAT::Table - > new ( 'nodetype' ) ;
my $ sitetab = xCAT::Table - > new ( 'site' ) ;
2008-01-29 13:50:41 +00:00
my $ nodehm = xCAT::Table - > new ( 'nodehm' ) ;
2008-07-11 19:02:39 +00:00
my $ hments = $ nodehm - > getNodesAttribs ( \ @ nodes , [ 'serialport' , 'serialspeed' , 'serialflow' ] ) ;
2007-10-26 22:44:33 +00:00
( my $ portent ) = $ sitetab - > getAttribs ( { key = > 'xcatdport' } , 'value' ) ;
( my $ mastent ) = $ sitetab - > getAttribs ( { key = > 'master' } , 'value' ) ;
2008-07-11 19:02:39 +00:00
my $ enthash = $ nodetype - > getNodesAttribs ( \ @ nodes , [ qw( arch ) ] ) ;
my $ resents = $ restab - > getNodeAttribs ( \ @ nodes , [ qw( xcatmaster ) ] ) ;
2007-10-26 22:44:33 +00:00
foreach ( @ nodes ) {
2008-07-11 19:02:39 +00:00
my $ ent = $ enthash - > { $ _ } - > [ 0 ] ; #$nodetype->getNodeAttribs($_,[qw(arch)]);
2007-10-26 22:44:33 +00:00
unless ( $ ent and $ ent - > { arch } ) {
$ callback - > ( { error = > [ "No archictecture defined in nodetype table for $_" ] , errorcode = > [ 1 ] } ) ;
return ;
}
my $ arch = $ ent - > { arch } ;
2008-07-11 19:02:39 +00:00
my $ ent = $ resents - > { $ _ } - > [ 0 ] ; #$restab->getNodeAttribs($_,[qw(xcatmaster)]);
2007-10-26 22:44:33 +00:00
my $ master ;
2008-04-09 21:12:36 +00:00
my $ kcmdline = "quiet " ;
2007-10-26 22:44:33 +00:00
if ( $ mastent and $ mastent - > { value } ) {
$ master = $ mastent - > { value } ;
}
if ( $ ent and $ ent - > { xcatmaster } ) {
$ master = $ ent - > { xcatmaster } ;
}
2008-07-11 19:02:39 +00:00
$ ent = $ hments - > { $ _ } - > [ 0 ] ; #$nodehm->getNodeAttribs($_,['serialport','serialspeed','serialflow']);
2008-01-29 13:50:41 +00:00
if ( $ ent and defined ( $ ent - > { serialport } ) ) {
2008-04-09 21:12:36 +00:00
$ kcmdline . = "console=ttyS" . $ ent - > { serialport } ;
2008-04-25 15:36:56 +00:00
#$ent = $nodehm->getNodeAttribs($_,['serialspeed']);
2008-01-29 13:50:41 +00:00
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 } ;
2008-04-25 15:36:56 +00:00
#$ent = $nodehm->getNodeAttribs($_,['serialflow']);
2008-01-29 13:50:41 +00:00
if ( $ ent and ( $ ent - > { serialflow } eq 'hard' or $ ent - > { serialflow } eq 'rtscts' ) ) {
$ kcmdline . = "n8r" ;
}
$ kcmdline . = " " ;
}
2007-10-26 22:44:33 +00:00
unless ( $ master ) {
$ callback - > ( { error = > [ "No master in site table nor noderes table for $_" ] , errorcode = > [ 1 ] } ) ;
return ;
}
my $ xcatdport = "3001" ;
if ( $ portent and $ portent - > { value } ) {
$ xcatdport = $ portent - > { value } ;
}
2008-04-25 15:36:56 +00:00
$ bootparms - > setNodeAttribs ( $ _ , { kernel = > "xcat/nbk.$arch" ,
2007-10-26 22:44:33 +00:00
initrd = > "xcat/nbfs.$arch.gz" ,
2008-01-29 13:50:41 +00:00
kcmdline = > $ kcmdline . "xcatd=$master:$xcatdport" } ) ;
2007-10-26 22:44:33 +00:00
}
} elsif ( ! ( $ state eq "boot" ) ) {
$ callback - > ( { error = > [ "Unknown state $state requested" ] , errorcode = > [ 1 ] } ) ;
return ;
}
foreach ( @ nodes ) {
2007-11-29 21:57:24 +00:00
my $ lstate = $ state ;
if ( $ nstates { $ _ } ) {
$ lstate = $ nstates { $ _ } ;
}
$ chaintab - > setNodeAttribs ( $ _ , { currstate = > $ lstate } ) ;
2007-10-26 22:44:33 +00:00
}
2008-09-30 20:00:46 +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...
2008-01-25 15:07:53 +00:00
unless ( $ request - > { '_xcat_clienthost' } - > [ 0 ] ) {
2007-10-26 22:44:33 +00:00
#ERROR? malformed request
return ; #nothing to do here...
}
2008-01-25 15:07:53 +00:00
my $ node = $ request - > { '_xcat_clienthost' } - > [ 0 ] ;
2007-10-26 22:44:33 +00:00
( $ node ) = noderange ( $ node ) ;
unless ( $ node ) {
#not a node, don't trust it
return ;
}
@ nodes = ( $ node ) ;
}
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 ) {
syslog ( "local1|err" , "ERROR: $node requested destiny update, no chain table" ) ;
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 } ) {
2007-11-26 15:44:23 +00:00
syslog ( "local1|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 } ;
}
$ 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 ) ] ) ;
my $ sitetab = xCAT::Table - > new ( 'site' ) ;
( my $ sent ) = $ sitetab - > getAttribs ( { key = > 'master' } , 'value' ) ;
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
if ( ( $ flag == 0 ) || ( $ flag == 3 ) ) {
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...
2008-10-03 23:16:57 +00:00
return nextdestiny ( 0 ) ; #Becomes a nextdestiny...
# 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 } ;
} elsif ( defined ( $ sent - > { value } ) ) {
$ response { imgserver } = $ sent - > { value } ;
2008-02-07 21:48:21 +00:00
} else {
$ response { imgserver } = xCAT::Utils - > 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
if ( ( $ flag == 0 ) || ( $ flag == 3 ) ) {
#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 ;