2008-09-08 18:54:30 +00:00
#!/usr/bin/env perl
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
package xCAT_plugin::updatenode ;
2009-11-12 20:13:34 +00:00
2008-09-08 18:54:30 +00:00
BEGIN
{
2009-11-12 20:13:34 +00:00
$ ::XCATROOT = $ ENV { 'XCATROOT' } ? $ ENV { 'XCATROOT' } : '/opt/xcat' ;
2008-09-08 18:54:30 +00:00
}
use lib "$::XCATROOT/lib/perl" ;
use xCAT::Table ;
use xCAT::Schema ;
use Data::Dumper ;
use xCAT::Utils ;
2009-11-12 20:13:34 +00:00
use xCAT::InstUtils ;
2008-09-08 18:54:30 +00:00
use Getopt::Long ;
use xCAT::GlobalDef ;
use Sys::Hostname ;
2009-11-12 20:13:34 +00:00
use File::Basename ;
2008-09-25 03:04:56 +00:00
use xCAT::GlobalDef ;
use xCAT_monitoring::monitorctrl ;
2009-11-12 20:13:34 +00:00
use Socket ;
2008-09-08 18:54:30 +00:00
1 ;
#-------------------------------------------------------------------------------
2009-11-12 20:13:34 +00:00
2008-09-08 18:54:30 +00:00
= head1 xCAT_plugin:updatenode
= head2 Package Description
xCAT plug - in module . It handles the updatenode command .
= cut
2009-11-12 20:13:34 +00:00
2008-09-08 18:54:30 +00:00
#------------------------------------------------------------------------------
#--------------------------------------------------------------------------------
2009-11-12 20:13:34 +00:00
2008-09-08 18:54:30 +00:00
= head3 handled_commands
It returns a list of commands handled by this plugin .
Arguments:
none
Returns:
a list of commands .
= cut
2009-11-12 20:13:34 +00:00
#------------------------------------------------------------------------------
2008-09-08 18:54:30 +00:00
sub handled_commands
{
2009-11-12 20:13:34 +00:00
return {
updatenode = > "updatenode" ,
updatenodestat = > "updatenode"
} ;
2008-09-08 18:54:30 +00:00
}
#-------------------------------------------------------
2009-11-12 20:13:34 +00:00
2008-09-08 18:54:30 +00:00
= head3 preprocess_request
Check and setup for hierarchy
= cut
2009-11-12 20:13:34 +00:00
2008-09-08 18:54:30 +00:00
#-------------------------------------------------------
sub preprocess_request
{
my $ request = shift ;
my $ callback = shift ;
2009-11-12 20:13:34 +00:00
$ ::subreq = shift ;
my $ command = $ request - > { command } - > [ 0 ] ;
2009-07-15 19:12:07 +00:00
if ( $ request - > { _xcatpreprocessed } - > [ 0 ] == 1 ) { return [ $ request ] ; }
2009-11-12 20:13:34 +00:00
my @ requests = ( ) ;
2008-09-08 18:54:30 +00:00
if ( $ command eq "updatenode" )
{
2009-11-12 20:13:34 +00:00
return & preprocess_updatenode ( $ request , $ callback , $ ::subreq ) ;
}
elsif ( $ command eq "updatenodestat" )
{
return [ $ request ] ;
}
else
{
my $ rsp = { } ;
$ rsp - > { data } - > [ 0 ] = "Unsupported command: $command." ;
$ callback - > ( $ rsp ) ;
return \ @ requests ;
2008-09-25 03:04:56 +00:00
}
2008-09-08 18:54:30 +00:00
}
2009-11-12 20:13:34 +00:00
#-----------------------------------------------------------------------------
2008-09-08 18:54:30 +00:00
= head3 process_request
2009-11-12 20:13:34 +00:00
It processes the updatenode command .
2008-09-08 18:54:30 +00:00
Arguments:
request - - a hash table which contains the command name and the arguments .
callback - - a callback pointer to return the response to .
Returns:
2009-11-12 20:13:34 +00:00
0 - for success . The output is returned through the callback pointer .
1 - for error . The error messages are returns through the
callback pointer .
2008-09-08 18:54:30 +00:00
= cut
2009-11-12 20:13:34 +00:00
#------------------------------------------------------------------------------
2008-09-08 18:54:30 +00:00
sub process_request
{
my $ request = shift ;
my $ callback = shift ;
2009-11-12 20:13:34 +00:00
$ ::subreq = shift ;
my $ command = $ request - > { command } - > [ 0 ] ;
my $ localhostname = hostname ( ) ;
if ( $ command eq "updatenode" )
{
return updatenode ( $ request , $ callback , $ ::subreq ) ;
}
elsif ( $ command eq "updatenodestat" )
{
return updatenodestat ( $ request , $ callback ) ;
}
else
{
my $ rsp = { } ;
$ rsp - > { data } - > [ 0 ] = "$localhostname: Unsupported command: $command." ;
$ callback - > ( $ rsp ) ;
return 1 ;
}
return 0 ;
2008-09-08 18:54:30 +00:00
}
2009-11-12 20:13:34 +00:00
#-----------------------------------------------------------------------------
2008-09-08 18:54:30 +00:00
= head3 preprocess_updatenode
This function checks for the syntax of the updatenode command
2009-11-12 20:13:34 +00:00
and distributes the command to the right server .
2008-09-08 18:54:30 +00:00
Arguments:
2009-11-12 20:13:34 +00:00
request - the request .
2008-09-08 18:54:30 +00:00
callback - the pointer to the callback function .
2009-11-12 20:13:34 +00:00
subreq - the sub request
2008-09-08 18:54:30 +00:00
Returns:
A pointer to an array of requests .
= cut
2009-11-12 20:13:34 +00:00
#------------------------------------------------------------------------------
sub preprocess_updatenode
{
my $ request = shift ;
my $ callback = shift ;
my $ subreq = shift ;
my $ args = $ request - > { arg } ;
my @ requests = ( ) ;
2010-02-24 08:23:36 +00:00
my $ installdir = xCAT::Utils - > getInstallDir ( ) ;
2009-11-12 20:13:34 +00:00
# subroutine to display the usage
sub updatenode_usage
{
my $ cb = shift ;
my $ rsp = { } ;
2010-03-21 13:11:47 +00:00
my $ usage_string = xCAT::Usage - > getUsage ( "updatenode" ) ;
push @ { $ rsp - > { data } } , $ usage_string ;
2009-11-12 20:13:34 +00:00
$ cb - > ( $ rsp ) ;
}
@ ARGV = ( ) ;
if ( $ args )
{
@ ARGV = @ { $ args } ;
}
# parse the options
Getopt::Long:: Configure ( "bundling" ) ;
Getopt::Long:: Configure ( "no_pass_through" ) ;
if (
! GetOptions (
2010-03-21 13:11:47 +00:00
'c|cmdlineonly' = > \ $ ::CMDLINE ,
'h|help' = > \ $ ::HELP ,
'v|version' = > \ $ ::VERSION ,
'V|verbose' = > \ $ ::VERBOSE ,
'F|sync' = > \ $ ::FILESYNC ,
'S|sw' = > \ $ ::SWMAINTENANCE ,
's|sn' = > \ $ ::SETSERVER ,
'P|scripts:s' = > \ $ ::RERUNPS ,
'security' = > \ $ ::SECURITY ,
'user=s' = > \ $ ::USER ,
'devicetype=s' = > \ $ ::DEVICETYPE ,
2009-11-12 20:13:34 +00:00
)
)
{
& updatenode_usage ( $ callback ) ;
return \ @ requests ;
}
# display the usage if -h or --help is specified
if ( $ ::HELP )
{
& updatenode_usage ( $ callback ) ;
return \ @ requests ;
}
# display the version statement if -v or --verison is specified
if ( $ ::VERSION )
{
my $ rsp = { } ;
$ rsp - > { data } - > [ 0 ] = xCAT::Utils - > Version ( ) ;
$ callback - > ( $ rsp ) ;
return \ @ requests ;
}
2010-03-21 13:11:47 +00:00
# -c must work with -S for AIX node
if ( $ ::CMDLINE && ! $ ::SWMAINTENANCE ) {
& updatenode_usage ( $ callback ) ;
return \ @ requests ;
}
# -s must work with -P or -S or --security
if ( $ ::SETSERVER && ! ( $ ::SWMAINTENANCE || $ ::RERUNPS || $ ::SECURITY ) ) {
& updatenode_usage ( $ callback ) ;
return \ @ requests ;
}
# --user and --devicetype must work with --security
if ( ( $ ::USER || $ ::DEVICETYPE ) && ! ( $ ::SECURITY && $ ::USER && $ ::DEVICETYPE ) ) {
& updatenode_usage ( $ callback ) ;
return \ @ requests ;
}
# --security cannot work with -S -P -F
if ( $ ::SECURITY && ( $ ::SWMAINTENANCE || $ ::RERUNPS || defined ( $ ::RERUNPS ) ) ) {
& updatenode_usage ( $ callback ) ;
return \ @ requests ;
}
2009-11-12 20:13:34 +00:00
# the -P flag is omitted when only postscritps are specified,
# so if there are parameters without any flags, it may mean
# to re-run the postscripts.
if ( @ ARGV )
{
# we have one or more operands on the cmd line
if ( $# ARGV == 0
2010-03-21 13:11:47 +00:00
&& ! ( $ ::FILESYNC || $ ::SWMAINTENANCE || defined ( $ ::RERUNPS ) || $ ::SECURIT ) )
2009-11-12 20:13:34 +00:00
{
# there is only one operand
# if it doesn't contain an = sign then it must be postscripts
if ( ! ( $ ARGV [ 0 ] =~ /=/ ) )
{
$ ::RERUNPS = $ ARGV [ 0 ] ;
2010-03-21 13:11:47 +00:00
$ ARGV [ 0 ] = "" ;
2009-11-12 20:13:34 +00:00
}
}
}
else
{
# no flags and no operands
2010-03-21 13:11:47 +00:00
if ( ! ( $ ::FILESYNC || $ ::SWMAINTENANCE || defined ( $ ::RERUNPS ) || $ ::SECURITY ) )
2009-11-12 20:13:34 +00:00
{
$ ::FILESYNC = 1 ;
$ ::SWMAINTENANCE = 1 ;
$ ::RERUNPS = "" ;
}
}
2010-03-21 13:11:47 +00:00
if ( $ ::SECURITY && ! ( $ ::USER || $ ::DEVICETYPE ) ) {
$ ::RERUNPS = "allkeys44444444security" ;
}
2009-11-12 20:13:34 +00:00
my $ nodes = $ request - > { node } ;
if ( ! $ nodes )
{
& updatenode_usage ( $ callback ) ;
return \ @ requests ;
}
#
2010-03-21 13:11:47 +00:00
# process @ARGV for the software maintenance of AIX node, it should
# be the list of attr=val, put attr=val operands in %attrvals hash
2009-11-12 20:13:34 +00:00
#
2008-09-08 18:54:30 +00:00
2009-11-12 20:13:34 +00:00
my % attrvals ;
2010-03-21 13:11:47 +00:00
if ( $ ::SWMAINTENANCE ) {
while ( my $ a = shift ( @ ARGV ) )
2009-11-12 20:13:34 +00:00
{
2010-03-21 13:11:47 +00:00
if ( $ a =~ /=/ )
2009-11-12 20:13:34 +00:00
{
2010-03-21 13:11:47 +00:00
# if it has an "=" sign its an attr=val - we hope
my ( $ attr , $ value ) = $ a =~ /^\s*(\S+?)\s*=\s*(\S*.*)$/ ;
if ( ! defined ( $ attr ) || ! defined ( $ value ) )
{
my $ rsp ;
$ rsp - > { data } - > [ 0 ] = "Incorrect \'attr=val\' pair - $a\n" ;
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::callback ) ;
return 3 ;
}
# put attr=val in hash
$ attrvals { $ attr } = $ value ;
2009-11-12 20:13:34 +00:00
}
}
}
my @ nodes = @$ nodes ;
my $ postscripts ;
2010-03-21 13:11:47 +00:00
# handle the validity of postscripts
2009-11-12 20:13:34 +00:00
if ( defined ( $ ::RERUNPS ) )
{
if ( $ ::RERUNPS eq "" )
{
$ postscripts = "" ;
}
else
{
$ postscripts = $ ::RERUNPS ;
2010-03-21 13:11:47 +00:00
my @ posts = ( ) ;
if ( $ postscripts eq "allkeys44444444security" ) {
@ posts = ( "remoteshell" , "aixremoteshell" , "servicenode" , "xcatserver" , "xcatclient" ) ;
} else {
@ posts = split ( ',' , $ postscripts ) ;
}
2009-11-12 20:13:34 +00:00
foreach ( @ posts )
{
2010-02-24 08:23:36 +00:00
if ( ! - e "$installdir/postscripts/$_" )
2009-11-12 20:13:34 +00:00
{
my $ rsp = { } ;
$ rsp - > { data } - > [ 0 ] =
2010-02-24 08:23:36 +00:00
"The postcript $installdir/postscripts/$_ does not exist." ;
2009-11-12 20:13:34 +00:00
$ callback - > ( $ rsp ) ;
return \ @ requests ;
}
}
}
}
# If -F option specified, sync files to the noderange.
2010-03-21 13:11:47 +00:00
# Note: This action only happens on MN, since xdcp, xdsh handles the
# hierarchical scenario inside
2009-11-12 20:13:34 +00:00
if ( $ ::FILESYNC )
{
my $ reqcopy = { %$ request } ;
$ reqcopy - > { FileSyncing } - > [ 0 ] = "yes" ;
push @ requests , $ reqcopy ;
}
2010-03-21 13:11:47 +00:00
# when specified -S or -P or --security
2010-01-27 10:23:03 +00:00
# find service nodes for requested nodes
# build an individual request for each service node
2010-03-21 13:11:47 +00:00
unless ( defined ( $ ::SWMAINTENANCE ) || defined ( $ ::RERUNPS ) || $ ::SECURITY )
2010-01-27 10:23:03 +00:00
{
return \ @ requests ;
}
my % insttype_node = ( ) ;
# get the nodes installation type
xCAT::SvrUtils - > getNodesetStates ( $ nodes , \ % insttype_node ) ;
# figure out the diskless nodes list and non-diskless nodes
foreach my $ type ( keys % insttype_node ) {
if ( $ type eq "netboot" || $ type eq "diskless" ) {
push @ dsklsnodes , @ { $ insttype_node { $ type } } ;
} else {
push @ notdsklsnodes , @ { $ insttype_node { $ type } } ;
}
}
if ( defined ( $ ::SWMAINTENANCE ) && scalar ( @ dsklsnodes ) > 0 ) {
my $ rsp ;
my $ outdsklsnodes = join ( ',' , @ dsklsnodes ) ;
push @ { $ rsp - > { data } } , "updatenode command does not support software maintenance to diskless node. Following diskless nodes will be skipped to perform software maintenance:\n$outdsklsnodes" ;
xCAT::MsgUtils - > message ( "E" , $ rsp , $ callback ) ;
}
2009-11-12 20:13:34 +00:00
# - need to consider the mixed cluster case
# - can't depend on the os of the MN - need to split out the AIX
2010-01-27 10:23:03 +00:00
# nodes from the node list which are not diskless
my ( $ rc , $ AIXnodes , $ Linuxnodes ) = xCAT::InstUtils - > getOSnodes ( \ @ notdsklsnodes ) ;
2009-11-12 20:13:34 +00:00
my @ aixnodes = @$ AIXnodes ;
2010-01-27 10:23:03 +00:00
2009-11-12 20:13:34 +00:00
# for AIX nodes we need to copy software to SNs first - if needed
my ( $ rc , $ imagedef , $ updateinfo ) ;
if ( defined ( $ ::SWMAINTENANCE ) && scalar ( @ aixnodes ) )
{
( $ rc , $ imagedef , $ updateinfo ) =
& doAIXcopy ( $ callback , \ % attrvals , $ AIXnodes , $ subreq ) ;
if ( $ rc != 0 )
{
2009-11-18 06:51:59 +00:00
# Do nothing when doAIXcopy failed
return undef ;
2009-11-12 20:13:34 +00:00
}
}
2010-03-21 13:11:47 +00:00
2009-11-12 20:13:34 +00:00
my $ sn = xCAT::Utils - > get_ServiceNode ( \ @ nodes , "xcat" , "MN" ) ;
if ( $ ::ERROR_RC )
{
my $ rsp ;
push @ { $ rsp - > { data } } , "Could not get list of xCAT service nodes." ;
xCAT::MsgUtils - > message ( "E" , $ rsp , $ callback ) ;
return \ @ requests ;
# return undef; ???
}
2010-03-21 13:11:47 +00:00
# for security update, we need to handle the service node first
my @ good_sns = ( ) ;
my @ MNip = xCAT::Utils - > determinehostname ;
my @ sns = ( ) ;
foreach my $ s ( keys %$ sn ) {
if ( ! grep ( /^$s$/ , @ MNip ) ) {
push @ sns , $ s ;
}
}
if ( scalar ( @ sns ) && $ ::SECURITY ) {
$ ::CALLBACK = $ callback ;
$ ::NODEOUT = ( ) ;
# setup the ssh keys
my $ req_sshkey = { %$ request } ;
$ req_sshkey - > { node } = \ @ sns ;
$ req_sshkey - > { security } - > [ 0 ] = "yes" ;
if ( $ ::USER ) {
$ req_sshkey - > { user } - > [ 0 ] = $ ::USER ;
}
if ( $ ::DEVICETYPE ) {
$ req_sshkey - > { devicetype } - > [ 0 ] = $ ::DEVICETYPE ;
}
updatenode ( $ req_sshkey , \ & updatenode_cb , $ subreq ) ;
# run the postscripts: remoteshell, servicenode, xcatserver, xcatclient
if ( $ postscripts eq "allkeys44444444security" ) {
my ( $ rc , $ AIXnodes , $ Linuxnodes ) = xCAT::InstUtils - > getOSnodes ( \ @ sns ) ;
my $ req_rs = { %$ request } ;
my $ ps ;
if ( scalar ( @ { $ AIXnodes } ) ) {
$ ps = "aixremoteshell,servicenode" ;
$ req_rs - > { rerunps } - > [ 0 ] = "yes" ;
$ req_rs - > { rerunps4security } - > [ 0 ] = "yes" ;
$ req_rs - > { node } = $ AIXnodes ;
$ req_rs - > { postscripts } = [ $ ps ] ;
updatenode ( $ req_rs , \ & updatenode_cb , $ subreq ) ;
}
if ( scalar ( @ { $ Linuxnodes } ) ) {
$ ps = "remoteshell,servicenode,xcatserver,xcatclient" ;
$ req_rs - > { rerunps } - > [ 0 ] = "yes" ;
$ req_rs - > { rerunps4security } - > [ 0 ] = "yes" ;
$ req_rs - > { node } = $ Linuxnodes ;
$ req_rs - > { postscripts } = [ $ ps ] ;
updatenode ( $ req_rs , \ & updatenode_cb , $ subreq ) ;
}
}
# parse the output of update security for sns
foreach my $ sn ( keys % { $ ::NODEOUT } ) {
if ( ! grep /^$sn$/ , @ sns ) {
next ;
}
if ( ( grep /ps ok/ , @ { $ ::NODEOUT - > { $ sn } } )
&& ( grep /ssh ok/ , @ { $ ::NODEOUT - > { $ sn } } ) ) {
push @ good_sns , $ sn ;
}
}
if ( $ ::VERBOSE ) {
my $ rsp ;
push @ { $ rsp - > { data } } , "Update security for following service nodes: @sns." ;
push @ { $ rsp - > { data } } , " Following service nodes have been updated successfully: @good_sns" ;
xCAT::MsgUtils - > message ( "I" , $ rsp , $ callback ) ;
}
}
2009-11-12 20:13:34 +00:00
# build each request for each service node
foreach my $ snkey ( keys %$ sn )
{
2010-03-21 13:11:47 +00:00
if ( $ ::SECURITY
&& ! ( grep /^$snkey$/ , @ good_sns )
&& ! ( grep /^$snkey$/ , @ MNip ) ) {
my $ rsp ;
push @ { $ rsp - > { data } } , "The security update for service node $snkey encountered error, update security for following nodes will be skipped: @{$sn->{$snkey}}" ;
xCAT::MsgUtils - > message ( "E" , $ rsp , $ callback ) ;
next ;
}
2009-11-12 20:13:34 +00:00
2010-03-21 13:11:47 +00:00
# remove the service node which have been handled before
if ( $ ::SECURITY && ( grep /^$snkey$/ , @ MNip ) ) {
delete @ { $ sn - > { $ snkey } } [ @ sns ] ;
if ( scalar ( @ { $ sn - > { $ snkey } } ) == 0 ) {
next ;
}
}
2009-11-12 20:13:34 +00:00
my $ reqcopy = { %$ request } ;
$ reqcopy - > { node } = $ sn - > { $ snkey } ;
$ reqcopy - > { '_xcatdest' } = $ snkey ;
$ reqcopy - > { _xcatpreprocessed } - > [ 0 ] = 1 ;
if ( defined ( $ ::SWMAINTENANCE ) )
{
2010-01-27 10:23:03 +00:00
# skip the diskless nodes
my @ validnode = ( ) ;
foreach my $ node ( @ { $ sn - > { $ snkey } } ) {
if ( ! grep /^$node$/ , @ dsklsnodes ) {
push @ validnode , $ node ;
}
2009-11-12 20:13:34 +00:00
}
2010-01-27 10:23:03 +00:00
if ( scalar ( @ validnode ) > 0 ) {
$ reqcopy - > { nondsklsnode } = \ @ validnode ;
$ reqcopy - > { swmaintenance } - > [ 0 ] = "yes" ;
# send along the update info and osimage defs
if ( $ imagedef )
{
xCAT::InstUtils - > taghash ( $ imagedef ) ;
$ reqcopy - > { imagedef } = [ $ imagedef ] ;
}
if ( $ updateinfo )
{
xCAT::InstUtils - > taghash ( $ updateinfo ) ;
$ reqcopy - > { updateinfo } = [ $ updateinfo ] ;
}
2009-11-12 20:13:34 +00:00
}
}
if ( defined ( $ ::RERUNPS ) )
{
$ reqcopy - > { rerunps } - > [ 0 ] = "yes" ;
$ reqcopy - > { postscripts } = [ $ postscripts ] ;
2010-03-21 13:11:47 +00:00
if ( defined ( $ ::SECURITY ) ) {
$ reqcopy - > { rerunps4security } - > [ 0 ] = "yes" ;
}
}
if ( defined ( $ ::SECURITY ) ) {
$ reqcopy - > { security } - > [ 0 ] = "yes" ;
if ( $ ::USER ) {
$ reqcopy - > { user } - > [ 0 ] = $ ::USER ;
}
if ( $ ::DEVICETYPE ) {
$ reqcopy - > { devicetype } - > [ 0 ] = $ ::DEVICETYPE ;
}
2009-11-12 20:13:34 +00:00
}
push @ requests , $ reqcopy ;
}
return \ @ requests ;
}
2008-09-08 18:54:30 +00:00
2010-03-21 13:11:47 +00:00
#--------------------------------------------------------------------------------
= head3 updatenode_cb
A callback function which is used to handle the output of updatenode function
when run updatenode - - secruity for service node inside
= cut
#-----------------------------------------------------------------------------
sub updatenode_cb
{
my $ resp = shift ;
# call the original callback function
$ ::CALLBACK - > ( $ resp ) ;
foreach my $ line ( @ { $ resp - > { data } } ) {
my $ node ;
my $ msg ;
if ( $ line =~ /(.*):(.*)/ ) {
$ node = $ 1 ;
$ msg = $ 2 ;
}
if ( $ msg =~ /Redeliver certificates has completed/ ) {
push @ { $ ::NODEOUT - > { $ node } } , "ps ok" ;
} elsif ( $ msg =~ /Setup ssh keys has completed/ ) {
push @ { $ ::NODEOUT - > { $ node } } , "ssh ok" ;
}
}
}
2008-09-08 18:54:30 +00:00
#--------------------------------------------------------------------------------
2009-11-12 20:13:34 +00:00
2008-09-08 18:54:30 +00:00
= head3 updatenode
This function implements the updatenode command .
Arguments:
request - the request .
callback - the pointer to the callback function .
2009-11-12 20:13:34 +00:00
subreq - the sub request
2008-09-08 18:54:30 +00:00
Returns:
2009-11-12 20:13:34 +00:00
0 - for success . The output is returned through the callback pointer .
1 - for error . The error messages are returned through the
callback pointer .
2008-09-08 18:54:30 +00:00
= cut
2009-11-12 20:13:34 +00:00
#-----------------------------------------------------------------------------
sub updatenode
{
my $ request = shift ;
my $ callback = shift ;
my $ subreq = shift ;
#print Dumper($request);
my $ nodes = $ request - > { node } ;
2010-01-27 10:23:03 +00:00
my $ nondsklsnodes = $ request - > { nondsklsnode } ;
2009-11-12 20:13:34 +00:00
my $ localhostname = hostname ( ) ;
# in a mixed cluster we could potentially have both AIX and Linux
# nodes provided on the command line ????
my ( $ rc , $ AIXnodes , $ Linuxnodes ) = xCAT::InstUtils - > getOSnodes ( $ nodes ) ;
my $ args = $ request - > { arg } ;
@ ARGV = ( ) ;
if ( $ args )
{
@ ARGV = @ { $ args } ;
2009-08-24 09:53:55 +00:00
}
2010-02-24 08:23:36 +00:00
# Lookup Install dir location at this Mangment Node.
# XXX: Suppose that compute nodes has the same Install dir location.
my $ installdir = xCAT::Utils - > getInstallDir ( ) ;
2009-11-12 20:13:34 +00:00
# convert the hashes back to the way they were passed in
my $ flatreq = xCAT::InstUtils - > restore_request ( $ request , $ callback ) ;
my $ imgdefs ;
my $ updates ;
if ( $ flatreq - > { imagedef } )
{
$ imgdefs = $ flatreq - > { imagedef } ;
}
if ( $ flatreq - > { updateinfo } )
{
$ updates = $ flatreq - > { updateinfo } ;
}
# get the NIM primary server name
my $ nimprime = xCAT::InstUtils - > getnimprime ( ) ;
chomp $ nimprime ;
# parse the options - really just need VERBOSE?
Getopt::Long:: Configure ( "bundling" ) ;
Getopt::Long:: Configure ( "no_pass_through" ) ;
if (
! GetOptions (
2009-11-13 14:55:25 +00:00
'c|cmdlineonly' = > \ $ ::CMDLINE ,
2009-11-12 20:13:34 +00:00
'h|help' = > \ $ ::HELP ,
'v|version' = > \ $ ::VERSION ,
'V|verbose' = > \ $ ::VERBOSE ,
'F|sync' = > \ $ ::FILESYNC ,
2009-12-01 18:21:30 +00:00
's|sn' = > \ $ ::SETSERVER ,
2009-11-12 20:13:34 +00:00
'S|sw' = > \ $ ::SWMAINTENANCE ,
'P|scripts:s' = > \ $ ::RERUNPS
)
)
{
}
#
# process @ARGV
#
# - put attr=val operands in %::attrres hash
while ( my $ a = shift ( @ ARGV ) )
{
if ( $ a =~ /=/ )
{
# if it has an "=" sign its an attr=val - we hope
my ( $ attr , $ value ) = $ a =~ /^\s*(\S+?)\s*=\s*(\S*.*)$/ ;
if ( ! defined ( $ attr ) || ! defined ( $ value ) )
{
my $ rsp ;
$ rsp - > { data } - > [ 0 ] = "Incorrect \'attr=val\' pair - $a\n" ;
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::callback ) ;
return 3 ;
}
# put attr=val in hash
$ ::attrres { $ attr } = $ value ;
}
}
#
# handle file synchronization
#
if ( $ request - > { FileSyncing } && $ request - > { FileSyncing } - > [ 0 ] eq "yes" )
{
my % syncfile_node = ( ) ;
my % syncfile_rootimage = ( ) ;
my $ node_syncfile = xCAT::SvrUtils - > getsynclistfile ( $ nodes ) ;
foreach my $ node ( @$ nodes )
{
my $ synclist = $$ node_syncfile { $ node } ;
if ( $ synclist )
{
push @ { $ syncfile_node { $ synclist } } , $ node ;
}
}
# Check the existence of the synclist file
foreach my $ synclist ( keys % syncfile_node )
{
if ( ! ( - r $ synclist ) )
{
my $ rsp = { } ;
$ rsp - > { data } - > [ 0 ] =
"The Synclist file $synclist which specified for certain node does NOT existed." ;
xCAT::MsgUtils - > message ( "E" , $ rsp , $ callback ) ;
return 1 ;
}
}
# Sync files to the target nodes
foreach my $ synclist ( keys % syncfile_node )
{
if ( defined ( $ ::VERBOSE ) )
{
my $ rsp = { } ;
$ rsp - > { data } - > [ 0 ] =
2010-03-21 13:11:47 +00:00
" $localhostname: Internal call command: xdcp -F $synclist" ;
2009-11-12 20:13:34 +00:00
$ callback - > ( $ rsp ) ;
}
my $ args = [ "-F" , "$synclist" ] ;
my $ env = [ "DSH_RSYNC_FILE=$synclist" ] ;
$ subreq - > (
{
command = > [ 'xdcp' ] ,
node = > $ syncfile_node { $ synclist } ,
arg = > $ args ,
env = > $ env
} ,
$ callback
) ;
}
my $ rsp = { } ;
$ rsp - > { data } - > [ 0 ] = "File synchronization has completed." ;
2009-09-18 11:21:12 +00:00
$ callback - > ( $ rsp ) ;
2009-11-12 20:13:34 +00:00
}
2009-11-23 10:59:29 +00:00
if ( scalar ( @$ AIXnodes ) )
{
if ( xCAT::Utils - > isLinux ( ) )
{
# mixed cluster enviornment, Linux MN=>AIX node
# linux nfs client can not mount AIX nfs directory with default settings.
# settting nfs_use_reserved_ports=1 could solve the problem
my $ cmd = qq~nfso -o nfs_use_reserved_ports=1~ ;
my $ output =
xCAT::InstUtils - > xcmd ( $ callback , $ subreq , "xdsh" , $ AIXnodes , $ cmd , 0 ) ;
if ( $ ::RUNCMD_RC != 0 )
{
my $ rsp ;
push @ { $ rsp - > { data } } ,
"Could not set nfs_use_reserved_ports=1 on nodes. Error message is:\n" ;
push @ { $ rsp - > { data } } , "$output\n" ;
xCAT::MsgUtils - > message ( "E" , $ rsp , $ callback ) ;
return 1 ;
}
}
}
2009-11-12 20:13:34 +00:00
#
# handle software updates
#
if ( $ request - > { swmaintenance } && $ request - > { swmaintenance } - > [ 0 ] eq "yes" )
{
my $ rsp ;
push @ { $ rsp - > { data } } ,
"Performing software maintenance operations. This could take a while.\n" ;
xCAT::MsgUtils - > message ( "I" , $ rsp , $ callback ) ;
2010-01-27 10:23:03 +00:00
my ( $ rc , $ AIXnodes_nd , $ Linuxnodes_nd ) = xCAT::InstUtils - > getOSnodes ( $ nondsklsnodes ) ;
if ( scalar ( @$ Linuxnodes_nd ) )
2009-11-12 20:13:34 +00:00
{ # we have a list of linux nodes
my $ cmd ;
2009-12-04 21:22:07 +00:00
# get server names as known by the nodes
2010-01-27 10:23:03 +00:00
my % servernodes = % { xCAT::InstUtils - > get_server_nodes ( $ callback , \ @$ Linuxnodes_nd ) } ;
2009-12-04 21:22:07 +00:00
# it's possible that the nodes could have diff server names
# do all the nodes for a particular server at once
foreach my $ snkey ( keys % servernodes ) {
my $ nodestring = join ( ',' , @ { $ servernodes { $ snkey } } ) ;
my $ cmd ;
if ( $ ::SETSERVER ) {
$ cmd =
2010-03-21 13:11:47 +00:00
"XCATBYPASS=Y $::XCATROOT/bin/xdsh $nodestring -s -e $installdir/postscripts/xcatdsklspost 2 -M $snkey otherpkgs 2>&1" ;
2009-12-04 21:22:07 +00:00
} else {
$ cmd =
2010-03-21 13:11:47 +00:00
"XCATBYPASS=Y $::XCATROOT/bin/xdsh $nodestring -s -e $installdir/postscripts/xcatdsklspost 2 -m $snkey otherpkgs 2>&1" ;
2009-12-04 21:22:07 +00:00
}
if ( defined ( $ ::VERBOSE ) )
{
my $ rsp = { } ;
2010-03-21 13:11:47 +00:00
$ rsp - > { data } - > [ 0 ] = " $localhostname: Internal call command: $cmd" ;
2009-12-04 21:22:07 +00:00
$ callback - > ( $ rsp ) ;
}
if ( $ cmd && ! open ( CMD , "$cmd |" ) )
{
my $ rsp = { } ;
2010-03-21 13:11:47 +00:00
$ rsp - > { data } - > [ 0 ] = "$localhostname: Cannot run command $cmd" ;
2009-12-04 21:22:07 +00:00
$ callback - > ( $ rsp ) ;
}
else
{
while ( <CMD> )
{
my $ rsp = { } ;
my $ output = $ _ ;
chomp ( $ output ) ;
$ output =~ s/\\cM// ;
if ( $ output =~ /returned from postscript/ )
{
$ output =~
s/returned from postscript/Running of Software Maintenance has completed./ ;
}
$ rsp - > { data } - > [ 0 ] = "$output" ;
$ callback - > ( $ rsp ) ;
}
close ( CMD ) ;
}
}
2009-11-12 20:13:34 +00:00
}
2010-01-27 10:23:03 +00:00
if ( scalar ( @$ AIXnodes_nd ) )
2009-11-12 20:13:34 +00:00
{ # we have AIX nodes
# update the software on an AIX node
if (
& updateAIXsoftware (
$ callback , $ imgdefs , $ updates ,
2010-01-27 10:23:03 +00:00
$ AIXnodes_nd , $ subreq
2009-11-12 20:13:34 +00:00
) != 0
)
{
# my $rsp;
# push @{$rsp->{data}}, "Could not update software for AIX nodes \'@$AIXnodes\'.";
# xCAT::MsgUtils->message("E", $rsp, $callback);;
return 1 ;
}
}
} # end sw maint section
2010-03-21 13:11:47 +00:00
#
# handle of setting up ssh keys
#
if ( $ request - > { security } && $ request - > { security } - > [ 0 ] eq "yes" ) {
# generate the arguments
my @ args = ( "-K" ) ;
if ( $ request - > { user } - > [ 0 ] ) {
push @ args , "--user" ;
push @ args , $ request - > { user } - > [ 0 ] ;
}
if ( $ request - > { devicetype } - > [ 0 ] ) {
push @ args , "--devicetype" ;
push @ args , $ request - > { devicetype } - > [ 0 ] ;
}
# remove the host key from known_hosts
xCAT::Utils - > runxcmd ( {
command = > [ 'makeknownhosts' ] ,
node = > \ @$ nodes ,
arg = > [ '-r' ] ,
} , $ subreq , 0 , 1 ) ;
if ( defined ( $ ::VERBOSE ) )
{
my $ rsp = { } ;
$ rsp - > { data } - > [ 0 ] =
" $localhostname: run makeknownhosts to clean known_hosts file for nodes: @$nodes" ;
$ callback - > ( $ rsp ) ;
}
# call the xdsh -K to set up the ssh keys
my @ envs = @ { $ request - > { environment } } ;
my $ res = xCAT::Utils - > runxcmd ( {
command = > [ 'xdsh' ] ,
node = > \ @$ nodes ,
arg = > \ @ args ,
env = > \ @ envs ,
} , $ subreq , 0 , 1 ) ;
if ( defined ( $ ::VERBOSE ) )
{
my $ rsp = { } ;
$ rsp - > { data } - > [ 0 ] =
" $localhostname: Internal call command: xdsh -K. nodes = @$nodes, arguments = @args, env = @envs" ;
$ rsp - > { data } - > [ 1 ] =
" $localhostname: return messages of last command: @$res" ;
$ callback - > ( $ rsp ) ;
}
# parse the output of xdsh -K
my @ failednodes = @$ nodes ;
foreach my $ line ( @$ res ) {
chomp ( $ line ) ;
if ( $ line =~ /SSH setup failed for the following nodes: (.*)\./ ) {
@ failednodes = split ( /,/ , $ 1 ) ;
} elsif ( $ line =~ /setup is complete/ ) {
@ failednodes = ( ) ;
}
}
my $ rsp = { } ;
foreach my $ node ( @$ nodes ) {
if ( grep /^$node$/ , @ failednodes ) {
push @ { $ rsp - > { data } } , "$node: Setup ssh keys failed." ;
} else {
push @ { $ rsp - > { data } } , "$node: Setup ssh keys has completed." ;
}
}
$ callback - > ( $ rsp ) ;
}
2009-11-12 20:13:34 +00:00
#
# handle the running of cust scripts
#
if ( $ request - > { rerunps } && $ request - > { rerunps } - > [ 0 ] eq "yes" )
{
my $ postscripts = "" ;
2010-03-21 13:11:47 +00:00
my $ orig_postscripts = "" ;
2009-11-12 20:13:34 +00:00
if ( ( $ request - > { postscripts } ) && ( $ request - > { postscripts } - > [ 0 ] ) )
{
2010-03-21 13:11:47 +00:00
$ orig_postscripts = $ request - > { postscripts } - > [ 0 ] ;
2009-11-12 20:13:34 +00:00
}
if ( scalar ( @$ Linuxnodes ) )
2010-03-21 13:11:47 +00:00
{
if ( $ orig_postscripts eq "allkeys44444444security" ) {
$ postscripts = "remoteshell,servicenode,xcatserver,xcatclient" ;
} else {
$ postscripts = $ orig_postscripts ;
}
# we have Linux nodes
my $ cmd ;
2009-12-04 21:22:07 +00:00
# get server names as known by the nodes
my % servernodes = % { xCAT::InstUtils - > get_server_nodes ( $ callback , \ @$ Linuxnodes ) } ;
# it's possible that the nodes could have diff server names
# do all the nodes for a particular server at once
foreach my $ snkey ( keys % servernodes ) {
my $ nodestring = join ( ',' , @ { $ servernodes { $ snkey } } ) ;
my $ cmd ;
2010-03-21 13:11:47 +00:00
my $ mode ;
if ( $ request - > { rerunps4security } && $ request - > { rerunps4security } - > [ 0 ] eq "yes" ) {
# for updatenode --security
$ mode = "5" ;
} else {
# for updatenode -P
$ mode = "1" ;
}
2009-12-04 21:22:07 +00:00
if ( $ ::SETSERVER ) {
$ cmd =
2010-03-21 13:11:47 +00:00
"XCATBYPASS=Y $::XCATROOT/bin/xdsh $nodestring -s -e $installdir/postscripts/xcatdsklspost $mode -M $snkey $postscripts 2>&1" ;
2009-12-04 21:22:07 +00:00
} else {
$ cmd =
2010-03-21 13:11:47 +00:00
"XCATBYPASS=Y $::XCATROOT/bin/xdsh $nodestring -s -e $installdir/postscripts/xcatdsklspost $mode -m $snkey $postscripts 2>&1" ;
2009-12-04 21:22:07 +00:00
}
if ( defined ( $ ::VERBOSE ) )
{
my $ rsp = { } ;
2010-03-21 13:11:47 +00:00
$ rsp - > { data } - > [ 0 ] = " $localhostname: Internal call command: $cmd" ;
2009-12-04 21:22:07 +00:00
$ callback - > ( $ rsp ) ;
}
if ( ! open ( CMD , "$cmd |" ) )
{
my $ rsp = { } ;
2010-03-21 13:11:47 +00:00
$ rsp - > { data } - > [ 0 ] = "$localhostname: Cannot run command $cmd" ;
2009-12-04 21:22:07 +00:00
$ callback - > ( $ rsp ) ;
}
else
{
2010-03-21 13:11:47 +00:00
my $ rsp = { } ;
2009-12-04 21:22:07 +00:00
while ( <CMD> )
{
my $ output = $ _ ;
chomp ( $ output ) ;
$ output =~ s/\\cM// ;
if ( $ output =~ /returned from postscript/ )
{
$ output =~
s/returned from postscript/Running of postscripts has completed./ ;
}
2010-03-21 13:11:47 +00:00
if ( $ request - > { rerunps4security } && $ request - > { rerunps4security } - > [ 0 ] eq "yes" ) {
if ( $ output =~ /Running of postscripts has completed/ ) {
$ output =~ s/Running of postscripts has completed/Redeliver certificates has completed/ ;
push @ { $ rsp - > { data } } , $ output ;
} elsif ( $ output !~ /Running postscript|Error loading module/ ) {
push @ { $ rsp - > { data } } , "$output" ;
}
} else {
push @ { $ rsp - > { data } } , "$output" ;
}
2009-12-04 21:22:07 +00:00
}
close ( CMD ) ;
2010-03-21 13:11:47 +00:00
$ callback - > ( $ rsp ) ;
2009-12-04 21:22:07 +00:00
}
}
2009-11-12 20:13:34 +00:00
}
if ( scalar ( @$ AIXnodes ) )
2010-03-21 13:11:47 +00:00
{
# we have AIX nodes
if ( $ orig_postscripts eq "allkeys44444444security" ) {
$ postscripts = "aixremoteshell,servicenode" ;
} else {
$ postscripts = $ orig_postscripts ;
}
2009-12-04 21:22:07 +00:00
# need to pass the name of the server on the xcataixpost cmd line
# get server names as known by the nodes
my % servernodes = % { xCAT::InstUtils - > get_server_nodes ( $ callback , \ @$ AIXnodes ) } ;
# it's possible that the nodes could have diff server names
# do all the nodes for a particular server at once
foreach my $ snkey ( keys % servernodes ) {
$ nodestring = join ( ',' , @ { $ servernodes { $ snkey } } ) ;
2009-11-25 16:29:21 +00:00
my $ cmd ;
2010-03-21 13:11:47 +00:00
my $ mode ;
if ( $ request - > { rerunps4security } && $ request - > { rerunps4security } - > [ 0 ] eq "yes" ) {
# for updatenode --security
$ mode = "5" ;
} else {
# for updatenode -P
$ mode = "1" ;
}
2009-12-04 21:22:07 +00:00
if ( $ ::SETSERVER ) {
2010-03-21 13:11:47 +00:00
$ cmd = "XCATBYPASS=Y $::XCATROOT/bin/xdsh $nodestring -s -e $installdir/postscripts/xcataixpost -M $snkey -c $mode $postscripts 2>&1" ;
2009-12-04 21:22:07 +00:00
} else {
2010-03-21 13:11:47 +00:00
$ cmd = "XCATBYPASS=Y $::XCATROOT/bin/xdsh $nodestring -s -e $installdir/postscripts/xcataixpost -m $snkey -c $mode $postscripts 2>&1" ;
2009-12-04 21:22:07 +00:00
}
2009-11-25 16:29:21 +00:00
if ( defined ( $ ::VERBOSE ) )
{
2009-12-04 21:22:07 +00:00
my $ rsp = { } ;
2010-03-21 13:11:47 +00:00
$ rsp - > { data } - > [ 0 ] = " $localhostname: Internal call command: $cmd" ;
2009-12-04 21:22:07 +00:00
$ callback - > ( $ rsp ) ;
2009-11-25 16:29:21 +00:00
}
2009-12-04 21:22:07 +00:00
2009-11-25 16:29:21 +00:00
if ( ! open ( CMD , "$cmd |" ) )
{
2009-12-04 21:22:07 +00:00
my $ rsp = { } ;
2010-03-21 13:11:47 +00:00
$ rsp - > { data } - > [ 0 ] = "$localhostname: Cannot run command $cmd" ;
2009-12-04 21:22:07 +00:00
$ callback - > ( $ rsp ) ;
2009-11-25 16:29:21 +00:00
}
else
{
2010-03-21 13:11:47 +00:00
my $ rsp = { } ;
2009-12-04 21:22:07 +00:00
while ( <CMD> )
{
2009-11-25 16:29:21 +00:00
my $ output = $ _ ;
chomp ( $ output ) ;
$ output =~ s/\\cM// ;
if ( $ output =~ /returned from postscript/ )
{
2009-12-04 21:22:07 +00:00
$ output =~
s/returned from postscript/Running of postscripts has completed./ ;
2009-11-25 16:29:21 +00:00
}
2010-03-21 13:11:47 +00:00
if ( $ request - > { rerunps4security } && $ request - > { rerunps4security } - > [ 0 ] eq "yes" ) {
if ( $ output =~ /Running of postscripts has completed/ ) {
$ output =~ s/Running of postscripts has completed/Redeliver certificates has completed/ ;
push @ { $ rsp - > { data } } , $ output ;
} elsif ( $ output !~ /Running postscript|Error loading module/ ) {
push @ { $ rsp - > { data } } , $ output ;
}
} else {
push @ { $ rsp - > { data } } , "$output" ;
}
2009-12-04 21:22:07 +00:00
}
close ( CMD ) ;
2010-03-21 13:11:47 +00:00
$ callback - > ( $ rsp ) ;
2009-11-25 16:29:21 +00:00
}
2009-12-04 21:22:07 +00:00
}
2009-11-12 20:13:34 +00:00
}
2010-03-21 13:11:47 +00:00
if ( $ request - > { rerunps4security } && $ request - > { rerunps4security } - > [ 0 ] eq "yes" ) {
# clean the know_hosts
xCAT::Utils - > runxcmd ( {
command = > [ 'makeknownhosts' ] ,
node = > \ @$ nodes ,
arg = > [ '-r' ] ,
} , $ subreq , 0 , 1 ) ;
}
2009-11-12 20:13:34 +00:00
}
2010-03-21 13:11:47 +00:00
2009-11-12 20:13:34 +00:00
return 0 ;
}
sub updatenodestat
{
my $ request = shift ;
my $ callback = shift ;
my @ nodes = ( ) ;
my @ args = ( ) ;
if ( ref ( $ request - > { node } ) )
{
@ nodes = @ { $ request - > { node } } ;
}
else
{
if ( $ request - > { node } ) { @ nodes = ( $ request - > { node } ) ; }
}
if ( ref ( $ request - > { arg } ) )
{
@ args = @ { $ request - > { arg } } ;
}
else
{
@ args = ( $ request - > { arg } ) ;
}
if ( ( @ nodes > 0 ) && ( @ args > 0 ) )
{
my % node_status = ( ) ;
my $ stat = $ args [ 0 ] ;
$ node_status { $ stat } = [] ;
foreach my $ node ( @ nodes )
{
my $ pa = $ node_status { $ stat } ;
push ( @$ pa , $ node ) ;
}
xCAT_monitoring::monitorctrl:: setNodeStatusAttributes ( \ % node_status , 1 ) ;
}
return 0 ;
2008-09-08 18:54:30 +00:00
}
2009-11-12 20:13:34 +00:00
#-------------------------------------------------------------------------------
= head3 doAIXcopy
Copy software update files to SNs - if needed .
Arguments:
Returns:
errors:
0 - OK
1 - error
hash refs:
- osimage definitions
- node update information
Example
my ( $ rc , $ imagedef , $ updateinfo ) = & doAIXcopy ( $ callback , \ % attrvals ,
$ nodes , $ subreq ) ;
Comments:
- running on MN
= cut
#------------------------------------------------------------------------------
sub doAIXcopy
{
my $ callback = shift ;
my $ av = shift ;
my $ nodes = shift ;
my $ subreq = shift ;
my @ nodelist ; # node list
my % attrvals ; # cmd line attr=val pairs
if ( $ nodes )
{
@ nodelist = @$ nodes ;
}
if ( $ av )
{
% attrvals = % { $ av } ;
}
# get the NIM primary server name
my $ nimprime = xCAT::InstUtils - > getnimprime ( ) ;
chomp $ nimprime ;
my % nodeupdateinfo ;
#
# do we have to copy files to any SNs????
#
# get a list of service nodes for this node list
my $ sn = xCAT::Utils - > get_ServiceNode ( \ @ nodelist , "xcat" , "MN" ) ;
if ( $ ::ERROR_RC )
{
my $ rsp ;
push @ { $ rsp - > { data } } , "Could not get list of xCAT service nodes." ;
xCAT::MsgUtils - > message ( "E" , $ rsp , $ callback ) ;
return 1 ;
}
# want list of remote service nodes - to copy files to
# get the servicenode ip
my $ ip = inet_ntoa ( inet_aton ( $ nimprime ) ) ;
chomp $ ip ;
my ( $ p1 , $ p2 , $ p3 , $ p4 ) = split /\./ , $ ip ;
my @ SNlist ;
foreach my $ snkey ( keys %$ sn )
{
my $ ip = inet_ntoa ( inet_aton ( $ snkey ) ) ;
chomp $ ip ;
my ( $ s1 , $ s2 , $ s3 , $ s4 ) = split /\./ , $ ip ;
if ( ( $ s1 == $ p1 ) && ( $ s2 == $ p2 ) && ( $ s3 == $ p3 ) && ( $ s4 == $ p4 ) )
{
next ;
}
else
{
if ( ! grep ( /^$snkey$/ , @ SNlist ) )
{
push ( @ SNlist , $ snkey ) ;
}
}
}
# get a list of osimage names needed for the nodes
my $ nodetab = xCAT::Table - > new ( 'nodetype' ) ;
my $ images =
$ nodetab - > getNodesAttribs ( \ @ nodelist , [ 'node' , 'provmethod' , 'profile' ] ) ;
my @ imagenames ;
foreach my $ node ( @ nodelist )
{
my $ imgname ;
if ( $ images - > { $ node } - > [ 0 ] - > { provmethod } )
{
$ imgname = $ images - > { $ node } - > [ 0 ] - > { provmethod } ;
}
elsif ( $ images - > { $ node } - > [ 0 ] - > { profile } )
{
$ imgname = $ images - > { $ node } - > [ 0 ] - > { profile } ;
}
if ( ! grep ( /^$imgname$/ , @ imagenames ) )
{
push @ imagenames , $ imgname ;
}
$ nodeupdateinfo { $ node } { imagename } = $ imgname ;
}
$ nodetab - > close ;
my $ osimageonly = 0 ;
if ( ( ! $ attrvals { installp_bundle } && ! $ attrvals { otherpkgs } ) && ! $ ::CMDLINE )
{
# if nothing is provided on the cmd line and we don't set CMDLINE
# then we just use
# the osimage def - used for permanent updates - saved
# in the osimage def
$ osimageonly = 1 ;
}
#
# get the osimage defs
#
my % imagedef ;
my @ pkglist ; # list of all software to go to SNs
my % bndloc ;
foreach $ img ( @ imagenames )
{
my % objtype ;
$ objtype { $ img } = 'osimage' ;
% imagedef = xCAT::DBobjUtils - > getobjdefs ( \ % objtype , $ callback ) ;
if ( ! defined ( % imagedef ) )
{
my $ rsp ;
push @ { $ rsp - > { data } } ,
"Could not get the xCAT osimage definition for \'$img\'.\n" ;
xCAT::MsgUtils - > message ( "E" , $ rsp , $ callback ) ;
return 1 ;
}
#
# if this is not a "standalone" type image then this is an error
#
if ( $ imagedef { $ img } { nimtype } ne "standalone" )
{
my $ rsp ;
push @ { $ rsp - > { data } } ,
2009-11-18 06:51:59 +00:00
"The osimage \'$img\' is not a standalone type. \nThe software maintenance function of updatenode command can only be used for standalone (diskfull) type nodes. \nUse the mknimimage comamand to update diskless osimages." ;
2009-11-12 20:13:34 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ callback ) ;
return 1 ;
}
if ( $ osimageonly != 1 )
{
# get packages from cmd line
if ( $ attrvals { installp_bundle } )
{
$ imagedef { $ img } { installp_bundle } = $ attrvals { installp_bundle } ;
}
else
{
$ imagedef { $ img } { installp_bundle } = "" ;
}
if ( $ attrvals { otherpkgs } )
{
$ imagedef { $ img } { otherpkgs } = $ attrvals { otherpkgs } ;
}
else
{
$ imagedef { $ img } { otherpkgs } = "" ;
}
}
if ( $ attrvals { installp_flags } )
{
$ imagedef { $ img } { installp_flags } = $ attrvals { installp_flags } ;
}
if ( $ attrvals { rpm_flags } )
{
$ imagedef { $ img } { rpm_flags } = $ attrvals { rpm_flags } ;
}
# get loc of lpp for node
$ imagedef { $ img } { lpp_loc } =
xCAT::InstUtils - > get_nim_attr_val ( $ imagedef { $ img } { lpp_source } ,
'location' , $ callback , $ nimprime , $ subreq ) ;
# keep a list of packages from otherpkgs and bndls
if ( $ imagedef { $ img } { otherpkgs } )
{
foreach $ pkg ( split ( /,/ , $ imagedef { $ img } { otherpkgs } ) )
{
if ( ! grep ( /^$&pkg$/ , @ pkglist ) )
{
push ( @ pkglist , $ pkg ) ;
}
}
}
if ( $ imagedef { $ img } { installp_bundle } )
{
my @ bndlist = split ( /,/ , $ imagedef { $ img } { installp_bundle } ) ;
foreach my $ bnd ( @ bndlist )
{
my ( $ rc , $ list , $ loc ) =
xCAT::InstUtils - > readBNDfile ( $ callback , $ bnd , $ nimprime ,
$ subreq ) ;
foreach my $ pkg ( @$ list )
{
chomp $ pkg ;
if ( ! grep ( /^$&pkg$/ , @ pkglist ) )
{
push ( @ pkglist , $ pkg ) ;
}
}
$ bndloc { $ bnd } = $ loc ;
}
}
# put array in string to pass along to SN
$ imagedef { $ img } { pkglist } = join ( ',' , @ pkglist ) ;
}
# if there are no SNs to update then return
if ( scalar ( @ SNlist ) == 0 )
{
return ( 0 , \ % imagedef , \ % nodeupdateinfo ) ;
}
# copy otherpkgs from lpp location on nim prime to same loc on SN
foreach my $ snkey ( @ SNlist )
{
# copy files to SN from nimprime!!
# TODO - need to handle xdsh to nimprime to do xdcp to SN?????
# for now - assume nimprime is management node
foreach my $ img ( @ imagenames )
{
2008-09-08 18:54:30 +00:00
2009-11-12 20:13:34 +00:00
# if lpp_source is not defined on SN then next
2010-01-27 10:23:03 +00:00
my $ scmd =
qq~/usr/sbin/lsnim -l $imagedef{$img}{lpp_source} 2>/dev/null~ ;
my $ out =
xCAT::InstUtils - > xcmd ( $ callback , $ subreq , "xdsh" , $ snkey , $ scmd ,
0 ) ;
2009-11-12 20:13:34 +00:00
if ( $ ::RUNCMD_RC != 0 )
{
next ;
}
my $ rpm_srcdir = "$imagedef{$img}{lpp_loc}/RPMS/ppc" ;
my $ instp_srcdir = "$imagedef{$img}{lpp_loc}/installp/ppc" ;
# copy all the packages
foreach my $ pkg ( @ pkglist )
{
2010-02-03 08:47:00 +00:00
my $ rcpargs ;
2009-11-12 20:13:34 +00:00
my $ srcfile ;
if ( ( $ pkg =~ /R:/ ) )
{
my ( $ junk , $ pname ) = split ( /:/ , $ pkg ) ;
# use rpm location
2010-02-03 08:47:00 +00:00
$ rcpargs = [ "$rpm_srcdir/$pname" , "$rpm_srcdir" ] ;
2009-11-12 20:13:34 +00:00
}
else
{
my $ pname ;
my $ junk ;
if ( $ pkg =~ /:/ )
{
( $ junk , $ pname ) = split ( /:/ , $ pkg ) ;
}
else
{
$ pname = $ pkg ;
}
# use installp loc
2010-02-03 08:47:00 +00:00
my @ allfiles = glob "$instp_srcdir/$pname*" ;
my $ sourcefiles = "" ;
foreach my $ file ( @ allfiles ) {
$ sourcefiles . = "$file " ;
}
$ rcpargs = [ $ sourcefiles , "$instp_srcdir" ] ;
2009-11-12 20:13:34 +00:00
}
2010-02-03 08:47:00 +00:00
my $ output = xCAT::Utils - > runxcmd ( { command = > [ "xdcp" ] ,
node = > [ $ snkey ] , arg = > $ rcpargs } , $ subreq , - 1 , 0 ) ;
2009-11-12 20:13:34 +00:00
if ( $ ::RUNCMD_RC != 0 )
{
my $ rsp ;
push @ { $ rsp - > { data } } , "Could not copy $pkg to $snkey.\n" ;
xCAT::MsgUtils - > message ( "E" , $ rsp , $ callback ) ;
}
}
}
} # end - for each service node
return ( 0 , \ % imagedef , \ % nodeupdateinfo ) ;
2008-09-25 03:04:56 +00:00
}
2009-11-12 20:13:34 +00:00
#-------------------------------------------------------------------------------
= head3 updateAIXsoftware
Update the software on an xCAT AIX cluster node .
2008-09-25 03:04:56 +00:00
2009-11-12 20:13:34 +00:00
Arguments:
Returns:
0 - OK
1 - error
Example
if ( & updateAIXsoftware ( $ callback , \ % attrres , \ % updates , $ nodes , $ subreq ) != 0 )
Comments:
- running on MN or SNs
= cut
#-------------------------------------------------------------------------------
sub updateAIXsoftware
{
my $ callback = shift ;
my $ imgdefs = shift ;
my $ updates = shift ;
my $ nodes = shift ;
my $ subreq = shift ;
2008-09-08 18:54:30 +00:00
2009-11-12 20:13:34 +00:00
my @ noderange = @$ nodes ;
my % attrvals ; # cmd line attr=val pairs
my @ pkglist ; # list of ALL software to install
2008-09-08 18:54:30 +00:00
2009-11-12 20:13:34 +00:00
# att=val - bndls, otherpakgs, flags
if ( $ attrs )
{
% attrvals = % { $ attrs } ;
}
if ( $ imgdefs )
{
% imagedefs = % { $ imgdefs } ;
}
if ( $ updates )
{
% nodeupdateinfo = % { $ updates } ;
}
my % bndloc ;
#
# get the server name for each node - as known by node
#
my $ noderestab = xCAT::Table - > new ( 'noderes' ) ;
my $ xcatmasters =
$ noderestab - > getNodesAttribs ( \ @ noderange , [ 'node' , 'xcatmaster' ] ) ;
# get the NIM primary server name
my $ nimprime = xCAT::InstUtils - > getnimprime ( ) ;
chomp $ nimprime ;
# if it's not the xcatmaster then default to the NIM primary
my % server ;
my @ servers ;
foreach my $ node ( @ noderange )
{
if ( $ xcatmasters - > { $ node } - > [ 0 ] - > { xcatmaster } )
{
$ server { $ node } = $ xcatmasters - > { $ node } - > [ 0 ] - > { xcatmaster } ;
}
else
{
$ server { $ node } = $ nimprime ;
}
if ( ! grep ( $ server { $ node } , @ servers ) )
{
push ( @ servers , $ server { $ node } ) ;
}
}
$ noderestab - > close ;
# sort nodes by image name so we can do bunch at a time
my % nodeoslist ;
foreach my $ node ( @ noderange )
{
foreach my $ serv ( @ servers )
{
push ( @ { $ nodeoslist { $ nodeupdateinfo { $ node } { imagename } } } , $ node ) ;
}
}
my $ error = 0 ;
my @ installp_files ; # list of tmp installp files created
foreach my $ img ( keys % imagedefs )
{
2009-11-17 18:53:10 +00:00
my $ noinstallp = 0 ;
2009-11-12 20:13:34 +00:00
chomp $ img ;
if ( $ img )
{
my @ nodes = @ { $ nodeoslist { $ img } } ;
2008-09-08 18:54:30 +00:00
2009-11-12 20:13:34 +00:00
# process the package list
# - split into rpm and installp
# - remove leading prefix - if any
my @ rpm_pkgs ;
my @ installp_pkgs ;
my @ pkglist = split ( /,/ , $ imagedefs { $ img } { pkglist } ) ;
if ( scalar ( @ pkglist ) )
{
foreach my $ p ( @ pkglist )
{
if ( ( $ p =~ /R:/ ) )
{
my ( $ junk , $ pname ) = split ( /:/ , $ p ) ;
push @ rpm_pkgs , $ pname ;
}
else
{
my $ pname ;
my $ junk ;
if ( $ p =~ /:/ )
{
( $ junk , $ pname ) = split ( /:/ , $ p ) ;
}
else
{
$ pname = $ p ;
}
push @ installp_pkgs , $ pname ;
}
}
}
#
# create tmp file for installp
#
my $ thisdate = `date +%s` ;
my $ installp_file_name = "installp_file-" . $ thisdate ;
chomp $ installp_file_name ;
if ( scalar ( @ installp_pkgs ) )
{
unless ( open ( INSTPFILE , ">/tmp/$installp_file_name" ) )
{
my $ rsp ;
push @ { $ rsp - > { data } } ,
"Could not open $installp_file_name.\n" ;
xCAT::MsgUtils - > message ( "E" , $ rsp , $ callback ) ;
return 1 ;
}
}
foreach ( @ installp_pkgs )
{
print INSTPFILE $ _ . "\n" ;
}
close ( INSTPFILE ) ;
# add new file to list so it can be removed later
push @ installp_files , $ installp_file_name ;
#
# copy file to each lpp_source, make sure it's all readable
# and export the lpp_source dir
#
if ( ( - e "/tmp/$installp_file_name" ) )
{
my $ icmd =
qq~cp /tmp/$installp_file_name $imagedefs{$img}{lpp_loc}~ ;
my $ output = xCAT::Utils - > runcmd ( "$icmd" , - 1 ) ;
if ( $ ::RUNCMD_RC != 0 )
{
my $ rsp ;
push @ { $ rsp - > { data } } ,
"Could not copy /tmp/$installp_file_name.\n" ;
push @ { $ rsp - > { data } } , "$output\n" ;
xCAT::MsgUtils - > message ( "E" , $ rsp , $ callback ) ;
return 1 ;
}
}
my $ chcmd = qq~cd $imagedefs{$img}{lpp_loc}; chmod -R +r *~ ;
my $ output = xCAT::Utils - > runcmd ( "$chcmd" , - 1 ) ;
if ( $ ::RUNCMD_RC != 0 )
{
my $ rsp ;
push @ { $ rsp - > { data } } , "Could not chmod $lpp.\n" ;
push @ { $ rsp - > { data } } , "$output\n" ;
xCAT::MsgUtils - > message ( "E" , $ rsp , $ callback ) ;
return 1 ;
}
my $ ecmd = qq~exportfs -i $imagedefs{$img}{lpp_loc}~ ;
my $ output = xCAT::Utils - > runcmd ( "$ecmd" , - 1 ) ;
if ( $ ::RUNCMD_RC != 0 )
{
my $ rsp ;
push @ { $ rsp - > { data } } , "Could not export $lpp.\n" ;
push @ { $ rsp - > { data } } , "$output\n" ;
xCAT::MsgUtils - > message ( "E" , $ rsp , $ callback ) ;
return 1 ;
}
#
# install sw on nodes
#
2009-12-01 18:21:30 +00:00
# $serv is the name of the nodes server as known by the node
2009-11-12 20:13:34 +00:00
foreach my $ serv ( @ servers )
{
# mount lpp dir to node
my $ mcmd = qq~mount $serv:$imagedefs{$img}{lpp_loc} /mnt~ ;
my $ output =
xCAT::InstUtils - > xcmd ( $ callback , $ subreq , "xdsh" , \ @ nodes ,
$ mcmd , 0 ) ;
if ( $ ::RUNCMD_RC != 0 )
{
my $ rsp ;
push @ { $ rsp - > { data } } ,
"Could not mount $imagedefs{$img}{lpp_loc} on nodes.\n" ;
push @ { $ rsp - > { data } } , "$output\n" ;
xCAT::MsgUtils - > message ( "E" , $ rsp , $ callback ) ;
$ error + + ;
next ;
}
}
# do installp first
# if we have installp filesets or other installp flags
2009-11-13 14:55:25 +00:00
# we may just get flags!
2009-11-12 20:13:34 +00:00
if ( ( scalar ( @ installp_pkgs ) )
2009-11-13 14:55:25 +00:00
|| ( $ imagedefs { $ img } { installp_flags } ) )
2009-11-12 20:13:34 +00:00
{
# - use installp with file
# set flags
my $ flags ;
if ( $ imagedefs { $ img } { installp_flags } )
{
$ flags = " " . $ imagedefs { $ img } { installp_flags } ;
}
else
{
$ flags = " -agQX " ;
}
# put together the installp command
my $ inpcmd = qq~/usr/sbin/installp ~ ;
# these installp flags can be used with -d
if ( $ flags =~ /l|L|i|A|a/ )
{
$ inpcmd . = qq~-d /mnt ~ ;
}
$ inpcmd . = qq~$flags ~ ;
# don't provide a list of filesets with these flags
if ( $ flags !~ /C|L|l/ )
{
2009-11-18 14:30:47 +00:00
if ( scalar ( @ installp_pkgs ) == 0 ) {
2009-11-17 18:53:10 +00:00
$ noinstallp = 1 ;
} else {
$ inpcmd . = qq~-f /mnt/$installp_file_name~ ;
}
2009-11-12 20:13:34 +00:00
}
2009-11-17 18:53:10 +00:00
# - could just have installp flags by mistake -ugh!
# - but don't have fileset to install - so don't run
# installp - UNLESS the flags don't need filesets
if ( $ noinstallp == 0 ) {
2009-11-12 20:13:34 +00:00
2009-11-17 18:53:10 +00:00
if ( $ ::VERBOSE )
{
my $ rsp ;
push @ { $ rsp - > { data } } , "Running: \'$inpcmd\'.\n" ;
xCAT::MsgUtils - > message ( "I" , $ rsp , $ callback ) ;
}
my @ output =
xCAT::InstUtils - > xcmd ( $ callback , $ subreq , "xdsh" , \ @ nodes ,
2009-11-12 20:13:34 +00:00
$ inpcmd , 1 ) ;
2009-11-17 18:53:10 +00:00
if ( $ ::RUNCMD_RC != 0 )
{
my $ rsp ;
push @ { $ rsp - > { data } } , "Could not run installp command.\n" ;
foreach my $ o ( @ output )
{
push @ { $ rsp - > { data } } , "$o" ;
}
xCAT::MsgUtils - > message ( "I" , $ rsp , $ callback ) ;
$ error + + ;
next ;
}
if ( $ ::VERBOSE )
{
my $ rsp ;
foreach my $ o ( @ output )
{
push @ { $ rsp - > { data } } , "$o" ;
}
xCAT::MsgUtils - > message ( "I" , $ rsp , $ callback ) ;
}
}
2009-11-12 20:13:34 +00:00
}
# - run updtvpkg to make sure installp software
# is registered with rpm
my $ ucmd = qq~/usr/sbin/updtvpkg~ ;
my $ output =
xCAT::InstUtils - > xcmd ( $ callback , $ subreq , "xdsh" , \ @ nodes , $ ucmd ,
0 ) ;
if ( $ ::RUNCMD_RC != 0 )
{
my $ rsp ;
2010-02-12 18:28:49 +00:00
push @ { $ rsp - > { data } } , "Could not run updtvpkg.\n" ;
2009-11-12 20:13:34 +00:00
push @ { $ rsp - > { data } } , "$output\n" ;
xCAT::MsgUtils - > message ( "E" , $ rsp , $ callback ) ;
next ;
}
2009-11-13 14:55:25 +00:00
# we may just get rpm flags!
if ( scalar ( @ rpm_pkgs ) || ( $ imagedefs { $ img } { rpm_flags } ) )
2009-11-12 20:13:34 +00:00
{
# don't do rpms if these installp flags were specified
if ( $ imagedefs { $ img } { installp_flags } !~ /C|L|l/ )
{
# set flags
my $ flags ;
if ( $ imagedefs { $ img } { rpm_flags } )
{
$ flags = " " . $ imagedefs { $ img } { rpm_flags } ;
}
else
{
$ flags = " -Uvh --replacepkgs " ;
}
my $ pkg_string = "" ;
foreach my $ pkg ( @ rpm_pkgs )
{
$ pkg_string . = " /mnt/RPMS/ppc/$pkg" ;
}
2009-11-19 18:44:04 +00:00
my $ rcmd ;
2010-02-12 18:28:49 +00:00
$ rcmd = qq~rpm $flags $pkg_string~ ;
2009-11-12 20:13:34 +00:00
if ( $ ::VERBOSE )
{
my $ rsp ;
push @ { $ rsp - > { data } } , "Running: \'$rcmd\'.\n" ;
xCAT::MsgUtils - > message ( "I" , $ rsp , $ callback ) ;
}
my @ output =
xCAT::InstUtils - > xcmd ( $ callback , $ subreq , "xdsh" , \ @ nodes ,
$ rcmd , 1 ) ;
if ( $ ::RUNCMD_RC != 0 )
{
my $ rsp ;
push @ { $ rsp - > { data } } , "Could not install RPMs.\n" ;
foreach my $ o ( @ output )
{
push @ { $ rsp - > { data } } , "$o" ;
}
xCAT::MsgUtils - > message ( "I" , $ rsp , $ callback ) ;
$ error + + ;
next ;
}
if ( $ ::VERBOSE )
{
my $ rsp ;
foreach my $ o ( @ output )
{
push @ { $ rsp - > { data } } , "$o" ;
}
xCAT::MsgUtils - > message ( "I" , $ rsp , $ callback ) ;
}
}
}
# unmount the lpp dir -
my $ ucmd = qq~umount -f /mnt~ ;
my $ output =
xCAT::InstUtils - > xcmd ( $ callback , $ subreq , "xdsh" , \ @ nodes , $ ucmd ,
0 ) ;
if ( $ ::RUNCMD_RC != 0 )
{
my $ rsp ;
push @ { $ rsp - > { data } } , "Could not umount.\n" ;
if ( $ ::VERBOSE )
{
push @ { $ rsp - > { data } } , "$output\n" ;
}
xCAT::MsgUtils - > message ( "E" , $ rsp , $ callback ) ;
next ;
}
}
}
# clean up files copied to lpp_source locations and
# unexport the lpp locations
foreach my $ img ( keys % imagedefs )
{
chomp $ img ;
foreach $ file ( @ installp_files )
{
2010-02-12 18:28:49 +00:00
my $ rcmd ;
if ( $ file =~ /installp_file/ ) {
$ rcmd = qq~rm -f /tmp/$file~ ;
} else {
$ rcmd = qq~rm -f $imagedefs{$img}{lpp_loc}/$file; rm -f /tmp/$file~ ;
}
2009-11-12 20:13:34 +00:00
my $ output = xCAT::Utils - > runcmd ( "$rcmd" , - 1 ) ;
if ( $ ::RUNCMD_RC != 0 )
{
my $ rsp ;
push @ { $ rsp - > { data } } ,
"Could not remove $imagedefs{$img}{lpp_loc}/$file.\n" ;
if ( $ ::VERBOSE )
{
push @ { $ rsp - > { data } } , "$output\n" ;
}
xCAT::MsgUtils - > message ( "E" , $ rsp , $ callback ) ;
next ;
}
}
# unexport lpp dirs????
my $ ucmd = qq~exportfs -u -F $imagedefs{$img}{lpp_loc}~ ;
my $ output = xCAT::Utils - > runcmd ( "$ucmd" , - 1 ) ;
if ( $ ::RUNCMD_RC != 0 )
{
my $ rsp ;
push @ { $ rsp - > { data } } ,
"Could not unexport $imagedefs{$img}{lpp_loc}.\n" ;
if ( $ ::VERBOSE )
{
push @ { $ rsp - > { data } } , "$output\n" ;
}
xCAT::MsgUtils - > message ( "E" , $ rsp , $ callback ) ;
next ;
}
}
if ( $ error )
{
my $ rsp ;
push @ { $ rsp - > { data } } ,
"One or more errors occured while updating node software.\n" ;
xCAT::MsgUtils - > message ( "E" , $ rsp , $ callback ) ;
return 1 ;
}
else
{
my $ rsp ;
push @ { $ rsp - > { data } } ,
"Cluster node software update commands have completed successfully.\n" ;
xCAT::MsgUtils - > message ( "I" , $ rsp , $ callback ) ;
}
return 0 ;
}
2009-12-01 18:21:30 +00:00