2007-10-26 22:44:33 +00:00
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
#-------------------------------------------------------
2008-02-18 15:57:25 +00:00
= head1
2007-10-26 22:44:33 +00:00
xCAT plugin package to handle xdsh
Supported command:
xdsh - > dsh
xdcp - > dcp
= cut
#-------------------------------------------------------
package xCAT_plugin::xdsh ;
2008-07-18 12:04:28 +00:00
use strict ;
2009-07-07 11:38:53 +00:00
use Storable qw( dclone ) ;
2009-09-21 13:09:26 +00:00
use File::Basename ;
use File::Path ;
2008-04-07 19:25:44 +00:00
require xCAT::Table ;
2007-10-26 22:44:33 +00:00
2008-04-07 19:25:44 +00:00
require xCAT::Utils ;
2007-10-26 22:44:33 +00:00
2008-04-07 19:25:44 +00:00
require xCAT::MsgUtils ;
2007-12-12 13:24:36 +00:00
use Getopt::Long ;
require xCAT::DSHCLI ;
2007-10-26 22:44:33 +00:00
1 ;
#-------------------------------------------------------
2008-02-18 15:57:25 +00:00
= head3 handled_commands
2007-10-26 22:44:33 +00:00
Return list of commands handled by this plugin
= cut
#-------------------------------------------------------
sub handled_commands
{
return {
xdsh = > "xdsh" ,
xdcp = > "xdsh"
} ;
}
2008-03-10 18:25:22 +00:00
#-------------------------------------------------------
= head3 preprocess_request
Check and setup for hierarchy
= cut
#-------------------------------------------------------
2008-03-31 18:17:00 +00:00
sub preprocess_request
{
2009-12-04 14:48:50 +00:00
my $ req = shift ;
my $ cb = shift ;
my $ sub_req = shift ;
2008-03-31 18:17:00 +00:00
my % sn ;
2008-07-18 12:04:28 +00:00
my $ sn ;
2009-12-04 14:48:50 +00:00
my $ rc = 0 ;
2009-07-22 13:36:13 +00:00
2009-03-16 13:24:16 +00:00
#if already preprocessed, go straight to request
2009-12-04 14:48:50 +00:00
if ( ( defined ( $ req - > { _xcatpreprocessed } ) )
&& ( $ req - > { _xcatpreprocessed } - > [ 0 ] == 1 ) )
{
return [ $ req ] ;
}
my $ command = $ req - > { command } - > [ 0 ] ; # xdsh vs xdcp
2008-10-17 16:04:13 +00:00
my $ nodes = $ req - > { node } ;
my $ service = "xcat" ;
2008-07-18 12:04:28 +00:00
my @ requests ;
2009-12-04 14:48:50 +00:00
$ ::tmpsyncsnfile = "/tmp/xcatrf.tmp" ;
$ ::RUNCMD_RC = 0 ;
@ ::good_SN ;
@ ::bad_SN ;
my $ syncsn = 0 ; # sync service node only if 1
2009-06-25 18:17:53 +00:00
# read the environment variables for rsync setup
2009-05-19 14:59:17 +00:00
foreach my $ envar ( @ { $ req - > { env } } )
{
my ( $ var , $ value ) = split ( /=/ , $ envar , 2 ) ;
2009-07-22 13:36:13 +00:00
if ( $ var eq "RSYNCSNONLY" )
2009-06-04 12:21:10 +00:00
{ # syncing SN, will change noderange to list of SN
2009-07-22 13:36:13 +00:00
# we are only syncing the service node ( -s flag)
2009-06-04 12:21:10 +00:00
$ syncsn = 1 ;
2009-05-25 12:27:48 +00:00
}
2009-06-04 12:21:10 +00:00
if ( $ var eq "DSH_RSYNC_FILE" ) # from -F flag
{ # if hierarchy,need to copy file to the SN
2009-12-04 14:48:50 +00:00
$ ::syncsnfile = $ value ; # in the new /tmp/xcatrf.tmp
2009-05-19 14:59:17 +00:00
}
2009-12-04 14:48:50 +00:00
if ( $ var eq "DCP_PULL" ) # from -P flag
{
$ ::dcppull = 1 ; # TBD handle pull hierarchy
2009-09-23 11:44:08 +00:00
}
2009-05-19 14:59:17 +00:00
}
2008-03-31 18:17:00 +00:00
2009-12-04 14:48:50 +00:00
# there are nodes in the xdsh command, not xdsh to an image
2008-10-17 16:04:13 +00:00
if ( $ nodes )
{
2009-12-04 14:48:50 +00:00
# find service nodes for requested nodes
# build an individual request for each service node
# find out the names for the Management Node
my @ MNnodeinfo = xCAT::Utils - > determinehostname ;
my $ MNnodename = pop @ MNnodeinfo ; # hostname
my @ MNnodeipaddr = @ MNnodeinfo ; # ipaddresses
$ ::mnname = $ MNnodeipaddr [ 0 ] ;
$ ::SNpath ; # syncfile path on the service node
2008-10-17 16:04:13 +00:00
$ sn = xCAT::Utils - > get_ServiceNode ( $ nodes , $ service , "MN" ) ;
2009-09-21 13:09:26 +00:00
my @ snodes ;
my @ snoderange ;
2009-06-25 18:17:53 +00:00
2009-09-21 13:09:26 +00:00
# check to see if service nodes and not just the MN
2009-12-04 14:48:50 +00:00
# if just MN, then no hierarchy to deal with
2009-09-21 13:09:26 +00:00
if ( $ sn )
2009-06-25 18:17:53 +00:00
{
2009-09-21 13:09:26 +00:00
foreach my $ snkey ( keys %$ sn )
{
if ( ! grep ( /$snkey/ , @ MNnodeipaddr ) )
2009-12-04 14:48:50 +00:00
{ # if not the MN
2009-09-21 13:09:26 +00:00
push @ snodes , $ snkey ;
$ snoderange [ 0 ] . = "$snkey," ;
2009-12-04 14:48:50 +00:00
chop $ snoderange [ 0 ] ;
2009-09-21 13:09:26 +00:00
}
}
2009-12-04 14:48:50 +00:00
}
2009-06-25 18:17:53 +00:00
2009-12-04 14:48:50 +00:00
# if servicenodes and if xdcp and not pull function
# send command to service nodes first and process errors
# return an array of good service nodes
#
if ( @ snodes ) # service nodes
{
# if xdcp and not pull function
if ( ( $ command eq "xdcp" ) && ( $ ::dcppull == 0 ) )
2009-05-25 12:27:48 +00:00
{
2009-12-04 14:48:50 +00:00
my $ synfiledir ;
2009-05-25 12:27:48 +00:00
2009-09-21 13:09:26 +00:00
# get the directory on the servicenode to put the files in
my @ syndir = xCAT::Utils - > get_site_attribute ( "SNsyncfiledir" ) ;
if ( $ syndir [ 0 ] )
{
$ synfiledir = $ syndir [ 0 ] ;
2009-06-25 18:17:53 +00:00
}
2009-09-21 13:09:26 +00:00
else
{
2009-12-04 14:48:50 +00:00
$ synfiledir = "/var/xcat/syncfiles" ; # default
}
2009-09-21 13:09:26 +00:00
2009-12-04 14:48:50 +00:00
# setup the service node with the files to xdcp to the
# compute nodes
$ rc =
& process_servicenodes ( $ req , $ cb , $ sub_req , \ @ snodes ,
\ @ snoderange , $ synfiledir ) ;
2009-09-21 13:09:26 +00:00
2009-12-04 14:48:50 +00:00
# fatal error need to stop
if ( $ rc != 0 )
{
return ;
2009-09-21 13:09:26 +00:00
}
2009-05-25 12:27:48 +00:00
}
2009-12-04 14:48:50 +00:00
else
{ # command is xdsh or xdcp pull
@ ::good_SN = @ snodes ; # all good service nodes for now
}
2009-06-04 12:21:10 +00:00
2009-12-04 14:48:50 +00:00
}
else
{ # no servicenodes, no hierarchy
# process here on the MN
& process_request ( $ req , $ cb , $ sub_req ) ;
return ;
}
# if hierarchical work still to do
# Note there may still be a mix of nodes that are service from
# the MN and nodes that are serviced from the SN, for example
# a dsh to a list of servicenodes and nodes in the noderange.
if ( $ syncsn == 0 ) # not just syncing (-s) the service nodes
# taken care of in process_servicenodes
{
2009-07-22 13:36:13 +00:00
foreach my $ snkey ( keys %$ sn )
{
2009-06-04 12:21:10 +00:00
2009-12-04 14:48:50 +00:00
# if it is not being service by the MN
2009-07-22 13:36:13 +00:00
if ( ! grep ( /$snkey/ , @ MNnodeipaddr ) )
2009-12-04 14:48:50 +00:00
{
# if it is a good SN, one ready to service the nodes
if ( grep ( /$snkey/ , @ ::good_SN ) )
2009-06-04 12:21:10 +00:00
{
2009-12-04 14:48:50 +00:00
my $ noderequests = & process_nodes ( $ req , $ sn , $ snkey ) ;
push @ requests , $ noderequests ; # build request queue
2009-09-21 13:09:26 +00:00
}
2009-06-04 12:21:10 +00:00
}
2009-12-04 14:48:50 +00:00
else # serviced by the MN, then
{ # just run normal dsh dcp
2009-07-22 13:36:13 +00:00
my $ reqcopy = { %$ req } ;
$ reqcopy - > { node } = $ sn - > { $ snkey } ;
$ reqcopy - > { '_xcatdest' } = $ snkey ;
$ reqcopy - > { _xcatpreprocessed } - > [ 0 ] = 1 ;
push @ requests , $ reqcopy ;
}
} # end foreach
2009-12-04 14:48:50 +00:00
} # end syncing nodes
2008-10-17 16:04:13 +00:00
}
2009-12-04 14:48:50 +00:00
else # no nodes on the command
{ # running on local image
2008-10-17 16:04:13 +00:00
return [ $ req ] ;
2008-03-31 18:17:00 +00:00
}
return \ @ requests ;
}
2008-03-10 18:25:22 +00:00
2007-10-26 22:44:33 +00:00
#-------------------------------------------------------
2009-12-04 14:48:50 +00:00
= head3 process_servicenodes
Build the xdcp command to send to the service nodes first
Return an array of servicenodes that do not have errors
Returns error code:
if = 0 , good return continue to process the
nodes .
if = 1 , global error need to quit
= cut
#-------------------------------------------------------
sub process_servicenodes
{
my $ req = shift ;
my $ callback = shift ;
my $ sub_req = shift ;
my $ sn = shift ;
my $ snrange = shift ;
my $ synfiledir = shift ;
my @ snodes = @$ sn ;
my @ snoderange = @$ snrange ;
my $ args ;
$ ::RUNCMD_RC = 0 ;
my $ cmd = $ req - > { command } - > [ 0 ] ;
# if xdcp -F command (input $syncsnfile) and service nodes first need
# to be rsync to the
# $synfiledir directory
if ( $ ::syncsnfile )
{
if ( ! - f $ ::syncsnfile )
{ # syncfile does not exist, quit
my $ rsp = { } ;
$ rsp - > { data } - > [ 0 ] = "File:$::syncsnfile does not exist." ;
xCAT::MsgUtils - > message ( "E" , $ rsp , $ callback , 1 ) ;
return ( 1 ) ; # process no service nodes
}
# xdcp sync to the service node first
#change noderange to the service nodes
# sync each one and check for error
# if error do not add to good_SN array, add to bad_SN
foreach my $ node ( @ snodes )
{
# run the command to each servicenode
# xdcp <sn> -s -F <syncfile>
my @ sn = ( ) ;
push @ sn , $ node ;
# don't use runxcmd, because can go straight to process_request,
# these are all service nodes. Also servicenode is taken from
# the noderes table and may not be the same name as in the nodelist
# table, for example may be an ip address.
# here on the MN
my $ addreq ;
$ addreq - > { '_xcatdest' } = $ ::mnname ;
$ addreq - > { node } = \ @ sn ;
$ addreq - > { noderange } = \ @ sn ;
$ addreq - > { arg } - > [ 0 ] = "-s" ;
$ addreq - > { arg } - > [ 1 ] = "-F" ;
$ addreq - > { arg } - > [ 2 ] = $ ::syncsnfile ;
$ addreq - > { command } - > [ 0 ] = $ cmd ;
$ addreq - > { cwd } - > [ 0 ] = $ req - > { cwd } - > [ 0 ] ;
$ addreq - > { env } = $ req - > { env } ;
& process_request ( $ addreq , $ callback , $ sub_req ) ;
if ( $ ::FAILED_NODES == 0 )
{
push @ ::good_SN , $ node ;
}
else
{
push @ ::bad_SN , $ node ;
}
} # end foreach good servicenode
# for all the service nodes that are still good
# need to xdcp rsync file( -F input)
# to the service node to the /tmp/xcatrf.tmp file
my @ good_SN2 = @ ::good_SN ;
@ ::good_SN = ( ) ;
foreach my $ node ( @ good_SN2 )
{
my @ sn = ( ) ;
push @ sn , $ node ;
# run the command to each good servicenode
# xdcp <sn> <syncfile> <tmp/xcatrf.tmp>
my $ addreq ;
$ addreq - > { '_xcatdest' } = $ ::mnname ;
$ addreq - > { node } = \ @ sn ;
$ addreq - > { noderange } = \ @ sn ;
$ addreq - > { arg } - > [ 0 ] = "$::syncsnfile" ;
$ addreq - > { arg } - > [ 1 ] = "$::tmpsyncsnfile" ;
$ addreq - > { command } - > [ 0 ] = $ cmd ;
$ addreq - > { cwd } - > [ 0 ] = $ req - > { cwd } - > [ 0 ] ;
$ addreq - > { env } = $ req - > { env } ;
& process_request ( $ addreq , $ callback , $ sub_req ) ;
if ( $ ::FAILED_NODES == 0 )
{
push @ ::good_SN , $ node ;
}
else
{
push @ ::bad_SN , $ node ;
}
} # end foreach good service node
} # end xdcp -F
else
{
# if other xdcp commands, and not pull function
# mk the directory on the SN to hold the files
# to be sent to the SN.
# build a command to update the service nodes
# change the destination to the tmp location on
# the service node
# hierarchical support for pull (TBD)
#make the needed directory on the service node
# create new directory for path on Service Node
# xdsh <sn> mkdir -p $SNdir
my $ frompath = $ req - > { arg } - > [ - 2 ] ;
$ ::SNpath = $ synfiledir ;
$ ::SNpath . = $ frompath ;
my $ SNdir ;
$ SNdir = dirname ( $ ::SNpath ) ; # get directory
foreach my $ node ( @ snodes )
{
my @ sn = ( ) ;
push @ sn , $ node ;
# run the command to each servicenode
# to make the directory under the temporary
# SNsyncfiledir to hold the files that will be
# sent to the service nodes
# xdsh <sn> mkdir -p <SNsyncfiledir>/$::SNpath
my $ addreq ;
$ addreq - > { '_xcatdest' } = $ ::mnname ;
$ addreq - > { node } = \ @ sn ;
$ addreq - > { noderange } = \ @ sn ;
$ addreq - > { arg } - > [ 0 ] = "mkdir " ;
$ addreq - > { arg } - > [ 1 ] = "-p " ;
$ addreq - > { arg } - > [ 2 ] = $ SNdir ;
$ addreq - > { command } - > [ 0 ] = 'xdsh' ;
$ addreq - > { cwd } - > [ 0 ] = $ req - > { cwd } - > [ 0 ] ;
$ addreq - > { env } = $ req - > { env } ;
& process_request ( $ addreq , $ callback , $ sub_req ) ;
if ( $ ::FAILED_NODES == 0 )
{
push @ ::good_SN , $ node ;
}
else
{
push @ ::bad_SN , $ node ;
}
} # end foreach good servicenode
# now xdcp file to the service node to the new
# tmp path
# for all the service nodes that are still good
my @ good_SN2 = @ ::good_SN ;
@ ::good_SN = ( ) ;
foreach my $ node ( @ good_SN2 )
{
my @ sn ;
push @ sn , $ node ;
# copy the file to each good servicenode
# xdcp <sn> <file> <SNsyncfiledir/../file>
my $ addreq = dclone ( $ req ) ; # get original request
$ addreq - > { arg } - > [ - 1 ] = $ SNdir ; # change to tmppath on servicenode
$ addreq - > { '_xcatdest' } = $ ::mnname ;
$ addreq - > { node } = \ @ sn ;
$ addreq - > { noderange } = \ @ sn ;
& process_request ( $ addreq , $ callback , $ sub_req ) ;
if ( $ ::FAILED_NODES == 0 )
{
push @ ::good_SN , $ node ;
}
else
{
push @ ::bad_SN , $ node ;
}
} # end foreach good service node
}
# report bad service nodes]
if ( @ ::bad_SN )
{
my $ rsp = { } ;
my $ badnodes ;
foreach my $ badnode ( @ ::bad_SN )
{
$ badnodes . = $ badnode ;
$ badnodes . = ", " ;
}
chop $ badnodes ;
my $ msg =
"\nThe following servicenodes: $badnodes have errors and cannot be updated\n Until the error is fixed, xdcp will not work to nodes serviced by these service nodes. Run xdsh <servicenode,...> -c , to clean up the xdcp servicenode directory, and run the command again." ;
$ rsp - > { data } - > [ 0 ] = $ msg ;
xCAT::MsgUtils - > message ( "D" , $ rsp , $ callback ) ;
}
return ( 0 ) ;
}
#-------------------------------------------------------
= head3 process_nodes
Build the request to send to the nodes , serviced by SN
Return the request
= cut
#-------------------------------------------------------
sub process_nodes
{
my $ req = shift ;
my $ sn = shift ;
my $ snkey = shift ;
my $ command = $ req - > { command } - > [ 0 ] ;
my @ requests ;
# if the -F option to sync the nodes
# then for a Node
# change the command to use the -F /tmp/xcatrf.tmp
# because that is where the file was put on the SN
#
my $ newSNreq = dclone ( $ req ) ;
if ( $ ::syncsnfile ) # -F option
{
my $ args = $ newSNreq - > { arg } ;
my $ i = 0 ;
foreach my $ argument ( @$ args )
{
# find the -F and change the name of the
# file in the next array entry to the tmp file
if ( $ argument eq "-F" )
{
$ i + + ;
$ newSNreq - > { arg } - > [ $ i ] = $ ::tmpsyncsnfile ;
last ;
}
$ i + + ;
}
}
else
{ # if other dcp command, change from directory
# to be the site.SNsyncfiledir
# directory on the service node
# if not pull (-P) pullfunction
# xdsh and xdcp pull just use the input request
if ( ( $ command eq "xdcp" ) && ( $ ::dcppull == 0 ) )
{
$ newSNreq - > { arg } - > [ - 2 ] = $ ::SNpath ;
}
}
$ newSNreq - > { node } = $ sn - > { $ snkey } ;
$ newSNreq - > { '_xcatdest' } = $ snkey ;
$ newSNreq - > { _xcatpreprocessed } - > [ 0 ] = 1 ;
#push @requests, $newSNreq;
return $ newSNreq ;
}
#-------------------------------------------------------
2008-02-18 15:57:25 +00:00
= head3 process_request
2007-10-26 22:44:33 +00:00
Process the command
= cut
#-------------------------------------------------------
sub process_request
{
my $ request = shift ;
my $ callback = shift ;
2009-12-04 14:48:50 +00:00
my $ sub_req = shift ;
my $ nodes = $ request - > { node } ;
my $ command = $ request - > { command } - > [ 0 ] ;
my $ args = $ request - > { arg } ;
my $ envs = $ request - > { env } ;
my $ rsp = { } ;
2008-02-18 15:57:25 +00:00
# get the Environment Variables and set them in the current environment
2008-03-31 18:17:00 +00:00
foreach my $ envar ( @ { $ request - > { env } } )
{
my ( $ var , $ value ) = split ( /=/ , $ envar , 2 ) ;
$ ENV { $ var } = $ value ;
2007-12-12 13:24:36 +00:00
}
if ( $ command eq "xdsh" )
{
xdsh ( $ nodes , $ args , $ callback , $ command , $ request - > { noderange } - > [ 0 ] ) ;
2007-10-26 22:44:33 +00:00
}
else
{
2007-12-12 13:24:36 +00:00
if ( $ command eq "xdcp" )
2007-10-26 22:44:33 +00:00
{
2007-12-12 13:24:36 +00:00
xdcp ( $ nodes , $ args , $ callback , $ command ,
$ request - > { noderange } - > [ 0 ] ) ;
2007-10-26 22:44:33 +00:00
}
else
2007-12-12 13:24:36 +00:00
{
2008-10-17 16:04:13 +00:00
my $ rsp = { } ;
2007-10-26 22:44:33 +00:00
$ rsp - > { data } - > [ 0 ] =
2008-02-18 15:57:25 +00:00
"Unknown command $command. Cannot process the command." ;
xCAT::MsgUtils - > message ( "E" , $ rsp , $ callback , 1 ) ;
return ;
2007-10-26 22:44:33 +00:00
}
}
}
#-------------------------------------------------------
2008-02-18 15:57:25 +00:00
= head3 xdsh
2007-10-26 22:44:33 +00:00
2008-02-18 15:57:25 +00:00
Parses Builds and runs the dsh
2007-10-26 22:44:33 +00:00
= cut
#-------------------------------------------------------
sub xdsh
{
2007-12-12 13:24:36 +00:00
my ( $ nodes , $ args , $ callback , $ command , $ noderange ) = @ _ ;
2008-03-31 18:17:00 +00:00
2009-12-04 14:48:50 +00:00
$ ::FAILED_NODES = 0 ;
2009-11-10 15:57:05 +00:00
# parse dsh input, will return $::NUMBER_NODES_FAILED
2008-07-18 12:04:28 +00:00
my @ local_results =
2007-12-12 13:24:36 +00:00
xCAT::DSHCLI - > parse_and_run_dsh ( $ nodes , $ args , $ callback ,
$ command , $ noderange ) ;
2009-12-04 14:48:50 +00:00
my $ maxlines = 10000 ;
my $ arraylen = @ local_results ;
my $ rsp = { } ;
my $ i = 0 ;
2009-10-22 13:53:49 +00:00
my $ j ;
2009-12-04 14:48:50 +00:00
while ( $ i < $ arraylen )
{
for ( $ j = 0 ; $ j < $ maxlines ; $ j + + )
{
if ( $ i > $ arraylen )
{
last ;
}
else
{
$ rsp - > { data } - > [ $ j ] = $ local_results [ $ i ] ; # send max lines
}
$ i + + ;
}
xCAT::MsgUtils - > message ( "D" , $ rsp , $ callback ) ;
2009-10-22 13:53:49 +00:00
}
2009-12-04 14:48:50 +00:00
2009-11-10 15:57:05 +00:00
# set return code
$ rsp = { } ;
2009-12-04 14:48:50 +00:00
$ rsp - > { errorcode } = $ ::FAILED_NODES ;
2009-11-10 15:57:05 +00:00
$ callback - > ( $ rsp ) ;
2009-12-04 14:48:50 +00:00
return ;
2007-12-12 13:24:36 +00:00
}
#-------------------------------------------------------
2008-02-18 15:57:25 +00:00
= head3 xdcp
2007-12-12 13:24:36 +00:00
2008-02-18 15:57:25 +00:00
Parses , Builds and runs the dcp command
2007-12-12 13:24:36 +00:00
= cut
#-------------------------------------------------------
sub xdcp
{
my ( $ nodes , $ args , $ callback , $ command , $ noderange ) = @ _ ;
2008-03-31 18:17:00 +00:00
2009-12-04 14:48:50 +00:00
$ ::FAILED_NODES = 0 ;
2008-03-10 18:25:22 +00:00
#`touch /tmp/lissadebug`;
2007-12-12 13:24:36 +00:00
# parse dcp input
2008-07-18 12:04:28 +00:00
my @ local_results =
2007-12-12 13:24:36 +00:00
xCAT::DSHCLI - > parse_and_run_dcp ( $ nodes , $ args , $ callback ,
$ command , $ noderange ) ;
2008-10-17 16:04:13 +00:00
my $ rsp = { } ;
my $ i = 0 ;
2007-12-12 13:24:36 +00:00
## process return data
2009-12-04 14:48:50 +00:00
if ( @ local_results )
2007-10-26 22:44:33 +00:00
{
2009-12-04 14:48:50 +00:00
foreach my $ line ( @ local_results )
{
$ rsp - > { data } - > [ $ i ] = $ line ;
$ i + + ;
}
2007-10-26 22:44:33 +00:00
2009-12-04 14:48:50 +00:00
xCAT::MsgUtils - > message ( "D" , $ rsp , $ callback ) ;
}
2009-06-25 18:17:53 +00:00
if ( - e "/tmp/xcatrf.tmp" )
{ # used tmp file for -F option
#`rm /tmp/xcatrf.tmp`;
2009-06-04 12:21:10 +00:00
}
2009-12-04 14:48:50 +00:00
# set return code
$ rsp = { } ;
$ rsp - > { errorcode } = $ ::FAILED_NODES ;
$ callback - > ( $ rsp ) ;
2008-02-18 15:57:25 +00:00
return ;
2007-10-26 22:44:33 +00:00
}