2009-06-23 14:30:18 +00:00
#!/usr/bin/env perl
2007-12-12 13:38:48 +00:00
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
package xCAT::DSHCLI ;
2012-11-13 22:03:57 +00:00
BEGIN
{
$ ::XCATROOT = $ ENV { 'XCATROOT' } ? $ ENV { 'XCATROOT' } : '/opt/xcat' ;
}
use lib "$::XCATROOT/lib/perl" ;
2007-12-12 13:38:48 +00:00
use File::Basename ;
use locale ;
2008-07-24 14:36:56 +00:00
use strict ;
2007-12-12 13:38:48 +00:00
use File::Path ;
use POSIX ;
use Socket ;
use Getopt::Long ;
require xCAT::DSHCore ;
use xCAT::MsgUtils ;
use xCAT::Utils ;
2012-08-09 03:48:50 +00:00
use xCAT::TableUtils ;
2007-12-12 13:38:48 +00:00
use lib '/opt/xcat/xdsh' ;
our @ dsh_available_contexts = ( ) ;
our @ dsh_valid_contexts = ( ) ;
our $ dsh_exec_state = 0 ;
our $ dsh_forked_process = undef ;
our $ dsh_options = undef ;
our $ dsh_resolved_targets = undef ;
our $ dsh_unresolved_targets = undef ;
our % dsh_target_status = undef ;
our $ dsh_trace = undef ;
our % dsh_stats = ( ) ;
our $ signal_interrupt_flag = 0 ;
our $ dsh_cmd_background = 0 ;
$ ::CONTEXT_DIR = "/opt/xcat/xdsh/Context/" ;
$ ::__DCP_DELIM = 'Xcat,DELIMITER,Xcat' ;
our @ dsh_valid_env = (
2009-12-04 14:50:33 +00:00
'DCP_NODE_OPTS' , 'DCP_NODE_RCP' ,
'DSH_ENVIRONMENT' , 'DSH_FANOUT' ,
'DSH_LOG' , 'DSH_NODEGROUP_PATH' ,
'DSH_NODE_LIST' , 'DSH_NODE_OPTS' ,
'DSH_NODE_RCP' , 'DSH_NODE_RSH' ,
'DSH_OUTPUT' , 'DSH_PATH' ,
'DSH_SYNTAX' , 'DSH_TIMEOUT' ,
'DSH_REMOTE_PASSWORD' , 'DSH_TO_USERID' ,
'DSH_FROM_USERID' , 'DEVICETYPE' ,
'RSYNCSN' , 'DSH_RSYNC_FILE' ,
'RSYNCSNONLY' ,
2007-12-12 13:38:48 +00:00
) ;
select ( STDERR ) ;
$| = 1 ;
select ( STDOUT ) ;
$| = 1 ;
#----------------------------------------------------------------------------
= head3
execute_dcp
This is the main driver routine for an instance of the dcp command .
Given the options configured in the $ options hash table , the routine
configures the execution of the dcp instance , executes the remote copy
commands and processes the output from each target .
Arguments:
$ options - options hash table describing dcp configuration options
Returns:
The number of targets that failed to execute a remote copy command
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Globals:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Error:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Example:
Comments:
= cut
#----------------------------------------------------------------------------
sub execute_dcp
{
my ( $ class , $ options ) = @ _ ;
$ ::dsh_command = 'dcp' ;
2012-10-17 11:29:49 +00:00
my $ rsp = { } ;
$ rsp - > { data } - > [ 0 ] = "dsh> Dcp_process_id $$" ;
$$ options { 'monitor' } && xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
2007-12-12 13:38:48 +00:00
my $ result = xCAT::DSHCLI - > config_dcp ( $ options ) ;
$ result && ( return $ result ) ;
my % resolved_targets = ( ) ;
my % unresolved_targets = ( ) ;
my % context_targets = ( ) ;
xCAT::DSHCLI - > resolve_targets ( $ options , \ % resolved_targets ,
\ % unresolved_targets , \ % context_targets ) ;
if ( ! scalar ( % resolved_targets ) )
{
2008-10-17 16:04:13 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] = "No hosts in node list 1" ;
2008-02-18 15:57:25 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK , 1 ) ;
2007-12-12 13:38:48 +00:00
return + + $ result ;
}
$$ options { 'verify' }
&& xCAT::DSHCLI - > verify_targets ( $ options , \ % resolved_targets ) ;
#check if file descriptor number exceeds the max number in ulimit
#if (
# xCAT::DSHCLI->isFdNumExceed(
# 2, scalar(keys(%resolved_targets)),
# $$options{'fanout'}
# )
# )
#{
2008-07-18 12:02:22 +00:00
# my $rsp ={};
2012-06-07 13:00:05 +00:00
# $rsp->{error}->[0] = " The DSH fanout value has exceeded the system file descriptor upper limit. Please either reduce the fanout value, or increase max file descriptor number by running ulimit.";
2008-02-18 15:57:25 +00:00
# xCAT::MsgUtils->message("E", $rsp, $::CALLBACK, 1);
2007-12-12 13:38:48 +00:00
# return ++$result;
#}
my @ targets_waiting = ( sort keys ( % resolved_targets ) ) ;
my % targets_active = ( ) ;
my @ targets_finished = ( ) ;
my @ targets_failed = ( ) ;
my % targets_buffered = ( ) ;
my % output_buffers = ( ) ;
my % error_buffers = ( ) ;
my % pid_targets = ( ) ;
my % outfh_targets = ( ) ;
my % errfh_targets = ( ) ;
my % forked_process = ( ) ;
my @ output_files = ( ) ;
! $$ options { 'silent' } && push @ output_files , * STDOUT ;
my @ error_files = ( ) ;
! $$ options { 'silent' } && push @ error_files , * STDERR ;
xCAT::DSHCLI - > fork_fanout_dcp (
$ options , \ % resolved_targets ,
\ % forked_process , \ % pid_targets ,
\ % outfh_targets , \ % errfh_targets ,
\ @ targets_waiting , \ % targets_active
) ;
while ( keys ( % targets_active ) )
{
my $ rin = $ outfh_targets { 'bitmap' } | $ errfh_targets { 'bitmap' } ;
my $ fh_count =
select ( my $ rout = $ rin , undef , undef , $$ options { 'timeout' } ) ;
if ( $ fh_count == 0 )
{
my @ active_list = keys ( % targets_active ) ;
2008-10-17 16:04:13 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2008-02-18 15:57:25 +00:00
" Timed out waiting for response from child processes for the following nodes." ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 1 ] = " @active_list" ;
2008-02-18 15:57:25 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK , 1 ) ;
2007-12-12 13:38:48 +00:00
kill 'INT' , keys ( % pid_targets ) ;
$ result + + ;
last ;
}
my @ select_out_fhs =
xCAT::DSHCLI - > util_bit_indexes ( $ rout & $ outfh_targets { 'bitmap' } , 1 ) ;
( @ select_out_fhs )
&& xCAT::DSHCLI - > buffer_output (
$ options , \ % resolved_targets , \ % targets_active ,
\ @ targets_finished , \ @ targets_failed , \ % targets_buffered ,
\ % pid_targets , \ % forked_process , \ % outfh_targets ,
\ % output_buffers , \ % error_buffers , \ @ output_files ,
\ @ error_files , \ @ select_out_fhs
) ;
my @ select_err_fhs =
xCAT::DSHCLI - > util_bit_indexes ( $ rout & $ errfh_targets { 'bitmap' } , 1 ) ;
( @ select_err_fhs )
&& xCAT::DSHCLI - > buffer_error (
$ options , \ % resolved_targets ,
\ % targets_active , \ @ targets_finished ,
\ @ targets_failed , \ % targets_buffered ,
\ % pid_targets , \ % forked_process ,
\ % errfh_targets , \ % output_buffers ,
\ % error_buffers , \ @ output_files ,
\ @ error_files , \ @ select_err_fhs
) ;
my @ targets_buffered_keys = sort keys ( % targets_buffered ) ;
2008-07-18 12:02:22 +00:00
foreach my $ user_target ( @ targets_buffered_keys )
2007-12-12 13:38:48 +00:00
{
2008-07-24 14:36:56 +00:00
my $ target_properties = $ resolved_targets { $ user_target } ;
2007-12-12 13:38:48 +00:00
if ( ! $$ options { 'silent' } )
{
if ( $ ::DCP_API )
{
$ ::DCP_API_MESSAGE . =
join ( "" , @ { $ output_buffers { $ user_target } } )
. join ( "" , @ { $ error_buffers { $ user_target } } ) ;
if ( $$ options { 'display_output' } )
{
print STDOUT @ { $ output_buffers { $ user_target } } ;
print STDERR @ { $ error_buffers { $ user_target } } ;
}
}
else
{
print STDOUT @ { $ output_buffers { $ user_target } } ;
print STDERR @ { $ error_buffers { $ user_target } } ;
}
}
delete $ output_buffers { $ user_target } ;
delete $ error_buffers { $ user_target } ;
my $ exit_code = $ targets_buffered { $ user_target } { 'exit-code' } ;
2012-10-17 11:29:49 +00:00
2007-12-12 13:38:48 +00:00
if ( $ exit_code != 0 )
{
2012-10-19 13:07:10 +00:00
# report error status --nodestatus
2012-10-22 13:52:55 +00:00
# Note the message below for node status must
# not be NLS translated. Code depends on the English.
2012-10-19 13:07:10 +00:00
if ( $$ options { 'nodestatus' } ) {
my $ rsp = { } ;
$ rsp - > { data } - > [ 0 ] =
"$user_target: Remote_command_failed, error_code=$exit_code" ;
xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
}
2007-12-12 13:38:48 +00:00
push @ targets_failed , $ user_target ;
push @ { $ dsh_target_status { 'failed' } } , $ user_target ;
}
else
{
2012-10-22 13:52:55 +00:00
# Note the message below for node status must
# not be NLS translated. Code depends on the English.
2012-10-19 13:07:10 +00:00
if ( $$ options { 'nodestatus' } ) {
my $ rsp = { } ;
$ rsp - > { data } - > [ 0 ] =
"$user_target: Remote_command_successful" ;
xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
}
2007-12-12 13:38:48 +00:00
push @ targets_finished , $ user_target ;
}
2012-10-17 11:29:49 +00:00
2012-10-17 17:21:43 +00:00
# return list of badnodes and goodnodes
2012-10-17 11:29:49 +00:00
if ( $$ options { 'monitor' } ) {
foreach my $ badnode ( @ targets_failed ) {
my $ rsp = { } ;
$ rsp - > { data } - > [ 0 ] =
"dsh> Remote_command_failed $badnode" ;
xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
}
foreach my $ goodnode ( @ targets_finished ) {
my $ rsp = { } ;
$ rsp - > { data } - > [ 0 ] =
"dsh> Remote_command_successful $goodnode" ;
xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
}
}
2007-12-12 13:38:48 +00:00
delete $ targets_buffered { $ user_target } ;
}
( @ targets_waiting )
&& xCAT::DSHCLI - > fork_fanout_dcp (
$ options , \ % resolved_targets , \ % forked_process ,
\ % pid_targets , \ % outfh_targets , \ % errfh_targets ,
\ @ targets_waiting , \ % targets_active
) ;
}
2012-12-10 18:45:58 +00:00
if ( scalar ( @ targets_failed ) > 0 )
{
2012-12-24 14:19:53 +00:00
#$::DCP_NODES_FAILED = join ",", @targets_failed;
@ ::DCP_NODES_FAILED = @ targets_failed ;
2012-12-10 18:45:58 +00:00
}
2007-12-12 13:38:48 +00:00
return ( scalar ( @ targets_failed ) + scalar ( keys ( % unresolved_targets ) ) ) ;
}
#----------------------------------------------------------------------------
= head3
execute_dsh
This is the main driver routine for an instance of the dsh command .
Given the options configured in the $ options hash table , the routine
configures the execution of the dsh instance , executes the remote shell
commands and processes the output from each target .
Arguments:
$ options - options hash table describing dsh configuration options
Returns:
The number of targets that failed to execute a remote shell command
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Globals:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Error:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Example:
Comments:
= cut
#----------------------------------------------------------------------------
sub execute_dsh
{
my ( $ class , $ options ) = @ _ ;
$ ::dsh_command = 'dsh' ;
$ dsh_options = $ options ;
xCAT::DSHCLI - > config_signals_dsh ( $ options ) ;
2008-10-17 16:04:13 +00:00
my $ rsp = { } ;
2007-12-12 13:38:48 +00:00
$ rsp - > { data } - > [ 0 ] = "dsh> Dsh_process_id $$" ;
$$ options { 'monitor' } && xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
$ dsh_exec_state + + ;
my $ result = xCAT::DSHCLI - > config_dsh ( $ options ) ;
$ result && ( return $ result ) ;
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2007-12-12 13:38:48 +00:00
$ rsp - > { data } - > [ 0 ] = "dsh> Dsh_initialization_completed" ;
$$ options { 'monitor' } && xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
$ dsh_exec_state + + ;
my % resolved_targets = ( ) ;
$ dsh_resolved_targets = \ % resolved_targets ;
my % unresolved_targets = ( ) ;
$ dsh_unresolved_targets = \ % unresolved_targets ;
my % context_targets = ( ) ;
xCAT::DSHCLI - > resolve_targets ( $ options , \ % resolved_targets ,
\ % unresolved_targets , \ % context_targets ) ;
my @ canceled_targets = ( ) ;
$ dsh_target_status { 'canceled' } = \ @ canceled_targets ;
2008-10-17 16:04:13 +00:00
my $ rsp = { } ;
2007-12-12 13:38:48 +00:00
if ( scalar ( % unresolved_targets ) )
{
2008-07-18 12:02:22 +00:00
foreach my $ target ( sort keys ( % unresolved_targets ) )
2007-12-12 13:38:48 +00:00
{
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2007-12-12 13:38:48 +00:00
$ rsp - > { data } - > [ 0 ] = "dsh> Remote_command_cancelled $target" ;
$$ dsh_options { 'monitor' }
&& xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
}
}
if ( ! scalar ( % resolved_targets ) )
{
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] = " No hosts in node list 2" ;
2008-02-18 15:57:25 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK , 1 ) ;
2007-12-12 13:38:48 +00:00
return + + $ result ;
}
$ dsh_exec_state + + ;
if ( $$ options { 'verify' } )
{
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2007-12-12 13:38:48 +00:00
$ rsp - > { data } - > [ 0 ] = "dsh> Dsh_verifying_hosts" ;
$$ options { 'monitor' } && xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
xCAT::DSHCLI - > verify_targets ( $ options , \ % resolved_targets ) ;
}
#check if file descriptor number exceeds the max number in ulimit
#if (
# xCAT::DSHCLI->isFdNumExceed(
# 2, scalar(keys(%resolved_targets)),
# $$options{'fanout'}
# )
#)
#{
2008-02-18 15:57:25 +00:00
# $rsp->{data}->[0] = " The DSH fanout value has exceeded the system file descriptor upper limit. Please either reduce the fanout value, or increase max file descriptor number by running ulimit.";
# xCAT::MsgUtils->message("E", $rsp, $::CALLBACK, 1);
2007-12-12 13:38:48 +00:00
# return ++$result;
#}
my @ targets_failed = ( ) ;
$ dsh_target_status { 'failed' } = \ @ targets_failed ;
@ targets_failed =
xCAT::DSHCLI - > _execute_dsh ( $ options , \ % resolved_targets ,
\ % unresolved_targets , \ % context_targets ) ;
2012-12-10 18:45:58 +00:00
if ( scalar ( @ targets_failed ) > 0 )
2007-12-12 13:38:48 +00:00
{
2012-12-24 14:19:53 +00:00
# $::DSH_NODES_FAILED = join ",", @targets_failed;
@ ::DSH_NODES_FAILED = @ targets_failed ;
2007-12-12 13:38:48 +00:00
}
2012-12-10 18:45:58 +00:00
2007-12-12 13:38:48 +00:00
return ( scalar ( @ targets_failed ) + scalar ( keys ( % unresolved_targets ) ) ) ;
}
#----------------------------------------------------------------------------
= head3
_execute_dsh
2009-06-10 17:35:10 +00:00
Wrapper routine for execute_dsh
2007-12-12 13:38:48 +00:00
to execute actual dsh call
Arguments:
$ options - options hash table describing dsh configuration options
$ resolved_targets - hash table of resolved targets and target properties
$ unresolved_targets - hash table of unresolved targets and relevant properties
$ context_targets - hash table of targets grouped by context name
Returns:
@ targets_failed - a list of those targets that failed execution
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Globals:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Error:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Example:
Comments:
Internal Routine only
= cut
#----------------------------------------------------------------------------
sub _execute_dsh
{
my ( $ class , $ options , $ resolved_targets , $ unresolved_targets ,
2008-10-17 16:04:13 +00:00
$ context_targets )
= @ _ ;
2007-12-12 13:38:48 +00:00
my @ output_files = ( ) ;
! $$ options { 'silent' } && push @ output_files , * STDOUT ;
my @ error_files = ( ) ;
! $$ options { 'silent' } && push @ error_files , * STDERR ;
2008-07-18 12:02:22 +00:00
my @ targets_waiting = ( ) ;
@ targets_waiting = ( sort keys ( %$ resolved_targets ) ) ;
my @ dsh_target_status = ( ) ;
2007-12-12 13:38:48 +00:00
$ dsh_target_status { 'waiting' } = \ @ targets_waiting ;
my % targets_active = ( ) ;
$ dsh_target_status { 'active' } = \ % targets_active ;
my @ targets_finished = ( ) ;
$ dsh_target_status { 'finished' } = \ @ targets_finished ;
my @ targets_failed = ( ) ;
my % targets_buffered = ( ) ;
my % output_buffers = ( ) ;
my % error_buffers = ( ) ;
my % pid_targets = ( ) ;
my % outfh_targets = ( ) ;
my % errfh_targets = ( ) ;
my % forked_process = ( ) ;
$ dsh_forked_process = \ % forked_process ;
2008-10-17 16:04:13 +00:00
my $ rsp = { } ;
2008-07-18 12:02:22 +00:00
my $ result ;
2007-12-12 13:38:48 +00:00
$ rsp - > { data } - > [ 0 ] = "dsh> Dsh_remote_execution_started" ;
$$ options { 'monitor' } && xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
$ dsh_exec_state + + ;
xCAT::DSHCLI - > fork_fanout_dsh (
$ options , $ resolved_targets ,
\ % forked_process , \ % pid_targets ,
\ % outfh_targets , \ % errfh_targets ,
\ @ targets_waiting , \ % targets_active
) ;
while ( keys ( % targets_active ) )
{
my $ rin = $ outfh_targets { 'bitmap' } | $ errfh_targets { 'bitmap' } ;
my $ fh_count =
select ( my $ rout = $ rin , undef , undef , $$ options { 'timeout' } ) ;
if ( $ fh_count == 0 )
{
my @ active_list = keys ( % targets_active ) ;
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2009-06-18 18:52:35 +00:00
" Timed out waiting for response from child processes for the following nodes. Terminating the child processes. " ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 1 ] = " @active_list" ;
2012-12-06 19:37:17 +00:00
xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
2007-12-12 13:38:48 +00:00
@ targets_failed = keys ( % targets_active ) ;
2009-06-23 15:34:59 +00:00
& handle_signal_dsh ( 'INT' , 2 ) ;
2007-12-12 13:38:48 +00:00
$ result + + ;
2009-06-23 15:34:59 +00:00
#last;
2007-12-12 13:38:48 +00:00
}
my @ select_out_fhs =
xCAT::DSHCLI - > util_bit_indexes ( $ rout & $ outfh_targets { 'bitmap' } , 1 ) ;
if ( @ select_out_fhs )
{
if ( $$ options { 'streaming' } )
{
xCAT::DSHCLI - > stream_output (
$ options , $ resolved_targets , \ % targets_active ,
\ @ targets_finished , \ @ targets_failed , \ % pid_targets ,
\ % forked_process , \ % outfh_targets , \ % output_buffers ,
\ @ output_files , \ @ select_out_fhs
) ;
}
else
{
xCAT::DSHCLI - > buffer_output (
$ options , $ resolved_targets , \ % targets_active ,
\ @ targets_finished , \ @ targets_failed , \ % targets_buffered ,
\ % pid_targets , \ % forked_process , \ % outfh_targets ,
\ % output_buffers , \ % error_buffers , \ @ output_files ,
\ @ error_files , \ @ select_out_fhs
) ;
}
}
my @ select_err_fhs =
xCAT::DSHCLI - > util_bit_indexes ( $ rout & $ errfh_targets { 'bitmap' } , 1 ) ;
if ( @ select_err_fhs )
{
if ( $$ options { 'streaming' } )
{
xCAT::DSHCLI - > stream_error (
$ options , $ resolved_targets , \ % targets_active ,
\ @ targets_finished , \ @ targets_failed , \ % pid_targets ,
\ % forked_process , \ % errfh_targets , \ % error_buffers ,
\ @ error_files , \ @ select_err_fhs
) ;
}
else
{
xCAT::DSHCLI - > buffer_error (
$ options , $ resolved_targets , \ % targets_active ,
\ @ targets_finished , \ @ targets_failed , \ % targets_buffered ,
\ % pid_targets , \ % forked_process , \ % errfh_targets ,
\ % output_buffers , \ % error_buffers , \ @ output_files ,
\ @ error_files , \ @ select_err_fhs
) ;
}
}
2012-11-14 16:02:18 +00:00
# This is only if you are not streaming ( -s)
2007-12-12 13:38:48 +00:00
my @ targets_buffered_keys = sort keys ( % targets_buffered ) ;
2008-07-18 12:02:22 +00:00
foreach my $ user_target ( @ targets_buffered_keys )
2007-12-12 13:38:48 +00:00
{
my $ target_properties = $$ resolved_targets { $ user_target } ;
my $ output_file = undef ;
my $ output_filename = undef ;
my $ error_file = undef ;
my $ error_filename = undef ;
if ( ! $$ options { 'silent' } )
{
if ( $ ::DSH_API )
{
$ ::DSH_API_MESSAGE =
$ ::DSH_API_MESSAGE
. join ( "" , @ { $ output_buffers { $ user_target } } )
. join ( "" , @ { $ error_buffers { $ user_target } } ) ;
if ( $$ options { 'display_output' } )
{
2009-12-04 14:50:33 +00:00
# print STDOUT @{$output_buffers{$user_target}};
# print STDERR @{$error_buffers{$user_target}};
chomp ( @ { $ output_buffers { $ user_target } } ) ;
chomp ( @ { $ error_buffers { $ user_target } } ) ;
2009-11-09 19:08:40 +00:00
my $ rsp = { } ;
2009-12-04 14:50:33 +00:00
push @ { $ rsp - > { data } } , @ { $ output_buffers { $ user_target } } ;
xCAT::MsgUtils - > message ( "D" , $ rsp , $ ::CALLBACK ) ;
2009-11-09 19:08:40 +00:00
$ rsp = { } ;
2012-12-11 14:36:43 +00:00
push @ { $ rsp - > { error } } , @ { $ error_buffers { $ user_target } } ;
2013-02-28 20:35:42 +00:00
$ rsp - > { NoErrorPrefix } = 1 ;
2012-12-11 14:36:43 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK , 0 ) ;
2007-12-12 13:38:48 +00:00
}
}
else
{
2012-05-03 18:25:27 +00:00
# LKV: This is where the output shows up
2009-11-09 19:08:40 +00:00
#print STDOUT @{$output_buffers{$user_target}};
#print STDERR @{$error_buffers{$user_target}};
2009-12-04 14:50:33 +00:00
chomp ( @ { $ output_buffers { $ user_target } } ) ;
chomp ( @ { $ error_buffers { $ user_target } } ) ;
my $ rsp = { } ;
push @ { $ rsp - > { data } } , @ { $ output_buffers { $ user_target } } ;
xCAT::MsgUtils - > message ( "D" , $ rsp , $ ::CALLBACK ) ;
$ rsp = { } ;
2012-12-11 14:36:43 +00:00
push @ { $ rsp - > { error } } , @ { $ error_buffers { $ user_target } } ;
2013-02-28 20:35:42 +00:00
$ rsp - > { NoErrorPrefix } = 1 ;
2012-12-11 14:36:43 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK , 0 ) ;
2009-12-04 14:50:33 +00:00
2007-12-12 13:38:48 +00:00
}
}
delete $ output_buffers { $ user_target } ;
delete $ error_buffers { $ user_target } ;
my $ exit_code = $ targets_buffered { $ user_target } { 'exit-code' } ;
2009-11-10 15:55:59 +00:00
my $ target_rc = $ targets_buffered { $ user_target } { 'target-rc' } ;
2008-10-17 16:04:13 +00:00
my $ rsp = { } ;
2007-12-12 13:38:48 +00:00
if ( $ exit_code != 0 )
{
2012-10-22 13:52:55 +00:00
# Note the message below for node status must
# not be NLS translated. Code depends on the English.
2012-10-19 13:07:10 +00:00
# report error status --nodestatus
if ( $$ options { 'nodestatus' } ) {
my $ rsp = { } ;
$ rsp - > { data } - > [ 0 ] =
"$user_target: Remote_command_failed, error_code=$exit_code" ;
xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
}
# for monitoring -m
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] = "dsh> Remote_command_failed $user_target" ;
2007-12-12 13:38:48 +00:00
$$ options { 'monitor' }
2012-12-06 19:37:17 +00:00
&& xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
2009-07-06 16:26:18 +00:00
if ( ! grep ( /$user_target/ , @ targets_failed ) )
{ # not already in list
2009-07-10 11:56:19 +00:00
push @ targets_failed , $ user_target ;
2009-07-06 16:26:18 +00:00
}
2007-12-12 13:38:48 +00:00
push @ { $ dsh_target_status { 'failed' } } , $ user_target
if ! $ signal_interrupt_flag ;
}
else
{
if ( $ target_rc != 0 )
{
2012-10-22 13:52:55 +00:00
# Note the message below for node status must
# not be NLS translated. Code depends on the English.
2012-10-19 13:07:10 +00:00
# report error status --nodestatus
if ( $$ options { 'nodestatus' } ) {
my $ rsp = { } ;
$ rsp - > { data } - > [ 0 ] =
"$user_target: Remote_command_failed, error_code=$target_rc" ;
xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
}
# if monitoring
2012-06-15 15:42:45 +00:00
$ rsp = { } ;
2012-12-11 13:49:24 +00:00
$ rsp - > { data } - > [ 0 ] =
2007-12-12 13:38:48 +00:00
"dsh> Remote_command_failed $user_target" ;
$$ options { 'monitor' }
2012-12-06 19:37:17 +00:00
&& xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK , 1 ) ;
2007-12-12 13:38:48 +00:00
push @ targets_failed , $ user_target ;
push @ { $ dsh_target_status { 'failed' } } , $ user_target
if ! $ signal_interrupt_flag ;
}
2012-11-13 22:03:57 +00:00
elsif ( ! defined ( $ target_rc ) && ! $ dsh_cmd_background && ( $ ::DSH_MELLANOX_SWITCH == 0 ) && ( $$ options { 'devicetype' } !~ /EthSwitch/ ) )
2007-12-12 13:38:48 +00:00
{
2012-10-19 13:07:10 +00:00
# report error status --nodestatus
2012-10-22 13:52:55 +00:00
# Note the message below for node status must
# not be NLS translated. Code depends on the English.
2012-10-19 13:07:10 +00:00
if ( $$ options { 'nodestatus' } ) {
my $ rsp = { } ;
$ rsp - > { data } - > [ 0 ] =
"$user_target: Remote_command_failed, error_code=???" ;
xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
}
2012-06-15 15:42:45 +00:00
$ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2008-07-18 12:02:22 +00:00
" A return code for the command run on the host $user_target was not received." ;
2008-02-18 15:57:25 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK , 1 ) ;
2012-10-19 13:07:10 +00:00
2008-10-17 16:04:13 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2007-12-12 13:38:48 +00:00
"dsh> Remote_command_failed $user_target" ;
$$ options { 'monitor' }
2012-06-07 13:00:05 +00:00
&& xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK ) ;
2007-12-12 13:38:48 +00:00
push @ targets_failed , $ user_target ;
push @ { $ dsh_target_status { 'failed' } } , $ user_target
if ! $ signal_interrupt_flag ;
}
2012-10-19 13:07:10 +00:00
else # it worked
2007-12-12 13:38:48 +00:00
{
2012-10-22 13:52:55 +00:00
# Note the message below for node status must
# not be NLS translated. Code depends on the English.
2012-10-19 13:07:10 +00:00
if ( $$ options { 'nodestatus' } ) {
my $ rsp = { } ;
$ rsp - > { data } - > [ 0 ] =
"$user_target: Remote_command_successful" ;
xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
}
2012-06-15 15:42:45 +00:00
$ rsp = { } ;
2007-12-12 13:38:48 +00:00
$ rsp - > { data } - > [ 0 ] =
"dsh> Remote_command_successful $user_target" ;
$$ options { 'monitor' }
&& xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
push @ targets_finished , $ user_target ;
}
}
delete $ targets_buffered { $ user_target } ;
}
( @ targets_waiting )
&& xCAT::DSHCLI - > fork_fanout_dsh (
$ options , $ resolved_targets , \ % forked_process ,
\ % pid_targets , \ % outfh_targets , \ % errfh_targets ,
\ @ targets_waiting , \ % targets_active
) ;
}
$ dsh_exec_state + + ;
if ( $$ options { 'stats' } )
{
$ dsh_stats { 'end-time' } = localtime ( ) ;
scalar ( @ targets_finished )
&& ( $ dsh_stats { 'successful-targets' } = \ @ targets_finished ) ;
if ( scalar ( @ targets_failed ) )
{
2008-07-24 14:36:56 +00:00
if ( scalar ( @ { $ dsh_target_status { 'failed' } } ) )
2007-12-12 13:38:48 +00:00
{
$ dsh_stats { 'failed-targets' } = $ dsh_target_status { 'failed' } ;
}
else
{
$ dsh_stats { 'failed-targets' } = \ @ targets_failed ;
}
}
scalar ( @ { $ dsh_target_status { 'canceled' } } )
&& ( $ dsh_stats { 'canceled-targets' } = $ dsh_target_status { 'canceled' } ) ;
}
2008-10-17 16:04:13 +00:00
my $ rsp = { } ;
2007-12-12 13:38:48 +00:00
$ rsp - > { data } - > [ 0 ] = "dsh> Remote_command_execution_completed" ;
$$ options { 'monitor' } && xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
return @ targets_failed ;
}
#----------------------------------------------------------------------------
= head3
fork_fanout_dcp
Main process forking routine for an instance of the dcp command .
The routine creates forked processes of a remote copy command up to
the configured fanout value . Then output from each process is
processed . The number of currently forked processes is consistently
maintained up to the configured fanout value
Arguments:
$ options - options hash table describing dsh configuration options
$ resolved_targets - hash table of resolved targets and target properties
$ forked_process - hash table of process information keyed by target name
$ pid_targets - hash table of target names keyed by process ID
$ outfh_targets - hash table of STDOUT pipe handles keyed by target name
$ errfh_targets - hash table of STDERR pipe handles keyed by target name
$ targets_waiting - array of targets pending remote execution
$ targets_active - hash table of currently active targets with output possibly available
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Returns:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Globals:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Error:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Example:
Comments:
= cut
#----------------------------------------------------------------------------
sub fork_fanout_dcp
{
my (
$ class , $ options , $ resolved_targets ,
$ forked_process , $ pid_targets , $ outfh_targets ,
$ errfh_targets , $ targets_waiting , $ targets_active
)
= @ _ ;
while ( @$ targets_waiting
&& ( keys ( %$ targets_active ) < $$ options { 'fanout' } ) )
{
my $ user_target = shift @$ targets_waiting ;
my $ target_properties = $$ resolved_targets { $ user_target } ;
my @ dcp_command ;
2009-06-29 13:36:18 +00:00
my $ rsyncfile ;
2007-12-12 13:38:48 +00:00
2013-02-28 20:35:42 +00:00
if ( ! $$ target_properties { 'localhost' } ) # this is to a remote host
2007-12-12 13:38:48 +00:00
{
my $ target_type = $$ target_properties { 'type' } ;
my % rcp_config = ( ) ;
my $ remote_copy ;
my $ rsh_extension = 'RSH' ;
if ( $ target_type eq 'node' )
{
$ remote_copy =
$$ options { 'node-rcp' } { $$ target_properties { 'context' } }
|| $$ target_properties { 'remote-copy' } ;
( $ remote_copy =~ /\/scp$/ ) && ( $ rsh_extension = 'SSH' ) ;
( $ remote_copy =~ /\/rsync$/ ) && ( $ rsh_extension = 'RSYNC' ) ;
$ rcp_config { 'options' } =
$$ options { 'node-options' } { $$ target_properties { 'context' } } ;
}
$ rcp_config { 'preserve' } = $$ options { 'preserve' } ;
$ rcp_config { 'recursive' } = $$ options { 'recursive' } ;
2013-03-06 17:50:22 +00:00
$ rcp_config { 'sudo' } = $$ options { 'sudo' } ;
2007-12-12 13:38:48 +00:00
if ( $$ options { 'pull' } )
{
$ rcp_config { 'src-user' } = $$ target_properties { 'user' }
|| $$ options { 'user' } ;
$ rcp_config { 'src-host' } = $$ target_properties { 'hostname' } ;
$ rcp_config { 'src-file' } = $$ options { 'source' } ;
my @ target_file = split '/' , $$ options { 'source' } ;
$ rcp_config { 'dest-file' } =
"$$options{'target'}/$target_file[$#target_file]._$$target_properties{'hostname'}" ;
}
else
{
$ rcp_config { 'src-file' } = $$ options { 'source' } ;
$ rcp_config { 'dest-host' } = $$ target_properties { 'hostname' } ;
$ rcp_config { 'dest-file' } = $$ options { 'target' } ;
$ rcp_config { 'dest-user' } = $$ target_properties { 'user' }
|| $$ options { 'user' } ;
$ rcp_config { 'destDir_srcFile' } =
$$ options { 'destDir_srcFile' } { $ user_target } ;
}
#eval "require RemoteShell::$rsh_extension";
eval "require xCAT::$rsh_extension" ;
my $ remoteshell = "xCAT::$rsh_extension" ;
2012-07-02 12:55:37 +00:00
# HERE: Build the dcp command based on the arguments
2012-08-02 19:04:07 +00:00
my $ localhost = 0 ; # this is from the MN to another node
2007-12-12 13:38:48 +00:00
@ dcp_command =
$ remoteshell - > remote_copy_command ( \ % rcp_config , $ remote_copy ) ;
2013-02-28 20:35:42 +00:00
# add sudo for non-root users
if ( $$ options { 'sudo' } ) {
unshift ( @ dcp_command , 'sudo' ) ;
}
2007-12-12 13:38:48 +00:00
}
2012-08-02 16:23:08 +00:00
else # this is the local host ( running on the Management Node)
2007-12-12 13:38:48 +00:00
{
if ( $$ options { 'destDir_srcFile' } { $ user_target } )
{
2013-02-28 20:35:42 +00:00
my $ target_type = $$ target_properties { 'type' } ;
2009-07-10 11:56:19 +00:00
2013-02-28 20:35:42 +00:00
my % rcp_config = ( ) ;
2012-08-02 16:23:08 +00:00
2013-02-28 20:35:42 +00:00
my $ remote_copy ;
my $ rsh_extension = 'RSH' ;
2009-06-09 14:38:30 +00:00
2013-02-28 20:35:42 +00:00
if ( $ target_type eq 'node' )
{
2012-08-02 19:04:07 +00:00
$ remote_copy =
$$ options { 'node-rcp' } { $$ target_properties { 'context' } }
|| $$ target_properties { 'remote-copy' } ;
( $ remote_copy =~ /\/scp$/ ) && ( $ rsh_extension = 'SSH' ) ;
( $ remote_copy =~ /\/rsync$/ ) && ( $ rsh_extension = 'RSYNC' ) ;
$ rcp_config { 'options' } =
$$ options { 'node-options' } { $$ target_properties { 'context' } } ;
2013-02-28 20:35:42 +00:00
}
2012-08-02 19:04:07 +00:00
2013-02-28 20:35:42 +00:00
$ rcp_config { 'preserve' } = $$ options { 'preserve' } ;
$ rcp_config { 'recursive' } = $$ options { 'recursive' } ;
2012-08-02 19:04:07 +00:00
$ rcp_config { 'src-file' } = $$ options { 'source' } ;
$ rcp_config { 'dest-host' } = $$ target_properties { 'hostname' } ;
$ rcp_config { 'dest-file' } = $$ options { 'target' } ;
$ rcp_config { 'dest-user' } = $$ target_properties { 'user' }
|| $$ options { 'user' } ;
$ rcp_config { 'destDir_srcFile' } =
$$ options { 'destDir_srcFile' } { $ user_target } ;
2013-02-28 20:35:42 +00:00
eval "require xCAT::$rsh_extension" ;
my $ remoteshell = "xCAT::$rsh_extension" ;
# HERE: Build the dcp command based on the arguments
my $ localhost = 1 ; # this is on the MN to the MN
@ dcp_command =
2012-08-02 19:04:07 +00:00
$ remoteshell - > remote_copy_command ( \ % rcp_config , $ remote_copy , $ localhost ) ;
2013-02-28 20:35:42 +00:00
}
else # just a copy not a sync
{
2007-12-12 13:38:48 +00:00
@ dcp_command =
( '/bin/cp' , '-r' , $$ options { 'source' } , $$ options { 'target' } ) ;
2013-02-28 20:35:42 +00:00
}
2007-12-12 13:38:48 +00:00
}
2008-10-17 16:04:13 +00:00
my $ rsp = { } ;
2008-02-18 15:57:25 +00:00
$ rsp - > { data } - > [ 0 ] = " TRACE: Executing Command:@dcp_command" ;
2007-12-12 13:38:48 +00:00
$ dsh_trace
&& ( xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ) ;
my @ process_info =
xCAT::DSHCore - > fork_output ( $ user_target , @ dcp_command ) ;
vec ( $$ outfh_targets { 'bitmap' } , fileno ( $ process_info [ 1 ] ) , 1 ) = 1 ;
vec ( $$ errfh_targets { 'bitmap' } , fileno ( $ process_info [ 2 ] ) , 1 ) = 1 ;
$$ outfh_targets { fileno ( $ process_info [ 1 ] ) } = $ user_target ;
$$ errfh_targets { fileno ( $ process_info [ 2 ] ) } = $ user_target ;
$$ forked_process { $ user_target } = \ @ process_info ;
$$ targets_active { $ user_target } + + ;
$$ pid_targets { $ process_info [ 0 ] } = $ user_target ;
}
}
#----------------------------------------------------------------------------
= head3
fork_fanout_dsh
Main process forking routine for an instance of the dsh command .
The routine creates forked processes of a remote shell command up to
the configured fanout value . Then output from each process is
processed . The number of currently forked processes is consistently
maintained up to the configured fanout value
Arguments:
$ options - options hash table describing dsh configuration options
$ resolved_targets - hash table of resolved targets and target properties
$ forked_process - hash table of process information keyed by target name
$ pid_targets - hash table of target names keyed by process ID
$ outfh_targets - hash table of STDOUT pipe handles keyed by target name
$ errfh_targets - hash table of STDERR pipe handles keyed by target name
$ targets_waiting - array of targets pending remote execution
$ targets_active - hash table of currently active targets with output possibly available
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Returns:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Globals:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Error:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Example:
Comments:
= cut
#----------------------------------------------------------------------------
sub fork_fanout_dsh
{
my (
$ class , $ options , $ resolved_targets ,
$ forked_process , $ pid_targets , $ outfh_targets ,
$ errfh_targets , $ targets_waiting , $ targets_active
)
= @ _ ;
2012-11-13 22:03:57 +00:00
#get username and passeword for ether net switches (EthSwitch type)
if ( $$ options { 'devicetype' } =~ /EthSwitch/ ) {
if ( @$ targets_waiting > 0 ) {
if ( $ ENV { 'DSH_REMOTE_PASSWORD' } ) {
foreach my $ t ( keys ( %$ resolved_targets ) ) {
$ resolved_targets - > { $ t } - > { 'password' } = $ ENV { 'DSH_REMOTE_PASSWORD' } ;
$ resolved_targets - > { $ t } - > { 'user' } = $$ options { 'user' } ;
}
} else {
#get user name and password from the switches table
my $ switchestab = xCAT::Table - > new ( 'switches' , - create = > 0 ) ;
2012-12-06 21:11:29 +00:00
my $ switchents = $ switchestab - > getNodesAttribs ( $ targets_waiting , [ qw/switch sshusername sshpassword protocol/ ] ) ;
2012-11-13 22:03:57 +00:00
foreach my $ entry ( values %$ switchents ) {
my $ switch = $ entry - > [ 0 ] - > { switch } ;
if ( defined ( $ entry - > [ 0 ] - > { sshusername } ) ) {
$ resolved_targets - > { $ switch } - > { 'user' } = $ entry - > [ 0 ] - > { sshusername } ;
}
if ( defined ( $ entry - > [ 0 ] - > { sshpassword } ) ) {
$ resolved_targets - > { $ switch } - > { 'password' } = $ entry - > [ 0 ] - > { sshpassword } ;
}
2012-12-06 21:11:29 +00:00
if ( defined ( $ entry - > [ 0 ] - > { protocol } ) ) {
$ resolved_targets - > { $ switch } - > { 'remotecmdproto' } = $ entry - > [ 0 ] - > { protocol } ;
}
2012-11-13 22:03:57 +00:00
}
}
}
}
2013-05-13 12:14:03 +00:00
# save the original exports, we are going to add the unique node name below
2007-12-12 13:38:48 +00:00
while ( @$ targets_waiting
&& ( keys ( %$ targets_active ) < $$ options { 'fanout' } ) )
{
my $ user_target = shift @$ targets_waiting ;
2013-05-13 12:14:03 +00:00
# now add export NODE=nodename to the pre-command;
2013-06-05 16:25:31 +00:00
my $ exportnode = "export NODE=$user_target; " ;
2007-12-12 13:38:48 +00:00
my $ target_properties = $$ resolved_targets { $ user_target } ;
2012-12-13 05:27:24 +00:00
my @ commands ;
2007-12-12 13:38:48 +00:00
my $ localShell =
( $$ options { 'syntax' } eq 'csh' ) ? '/bin/csh' : '/bin/sh' ;
my @ dsh_command = ( $ localShell , '-c' ) ;
$$ options { 'command' } =~ s/\s*$// ;
$$ options { 'command' } =~ s/;$// ;
if ( $$ options { 'command' } =~ /\&$/ )
{
$$ options { 'post-command' } = "" ;
$ dsh_cmd_background = 1 ;
}
if ( $$ options { 'environment' } )
{
2013-02-28 20:35:42 +00:00
# if we are on a servicenode need to get the environment file
# from the SNsyncfiledir, not local
if ( xCAT::Utils - > isServiceNode ( ) ) {
my $ newenvfile ;
my $ synfiledir = "/var/xcat/syncfiles" ; #default
# get the directory on the servicenode to and add to filepath
my @ syndir = xCAT::TableUtils - > get_site_attribute ( "SNsyncfiledir" ) ;
if ( $ syndir [ 0 ] )
{
$ synfiledir = $ syndir [ 0 ] ;
}
$ newenvfile = $ synfiledir ;
$ newenvfile . = $$ options { 'environment' } ;
$$ options { 'environment' } = $ newenvfile ;
}
if ( ! ( - e $$ options { 'environment' } ) )
{
my $ rsp = { } ;
$ rsp - > { error } - > [ 0 ] = "File $$options{'environment'} does not exist" ;
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK ) ;
}
2013-06-05 16:25:31 +00:00
# build the xdsh command
2007-12-12 13:38:48 +00:00
push @ dsh_command ,
2013-06-05 16:25:31 +00:00
"$exportnode$$options{'pre-command'} . $$options{'environment'} ; $$options{'command'}$$options{'post-command'}" ;
2007-12-12 13:38:48 +00:00
}
else
{
push @ dsh_command ,
2013-06-05 16:25:31 +00:00
"$exportnode$$options{'pre-command'}$$options{'command'}$$options{'post-command'}" ;
2007-12-12 13:38:48 +00:00
}
if ( $$ target_properties { 'localhost' } )
{
if ( my $ specified_usr =
( $$ target_properties { 'user' } || $$ options { 'user' } ) )
{
2009-04-03 15:42:59 +00:00
my $ current_usr = getpwuid ( $> ) ;
2007-12-12 13:38:48 +00:00
if ( $ specified_usr ne $ current_usr )
{
delete $$ target_properties { 'localhost' } ;
}
}
}
if ( ! $$ target_properties { 'localhost' } )
{
@ dsh_command = ( ) ;
my $ target_type = $$ target_properties { 'type' } ;
my % rsh_config = ( ) ;
$ rsh_config { 'hostname' } = $$ target_properties { 'hostname' } ;
$ rsh_config { 'user' } = $$ target_properties { 'user' }
|| $$ options { 'user' } ;
my $ remote_shell ;
my $ rsh_extension = 'RSH' ;
if ( $ target_type eq 'node' )
{
my $ context = $$ target_properties { 'context' } ;
$ remote_shell = $$ options { 'node-rsh' } { $ context }
|| $$ options { 'node-rsh' } { 'none' }
|| $$ target_properties { 'remote-shell' }
|| $$ options { 'node-rsh-defaults' } { $ context } ;
( $ remote_shell =~ /\/ssh$/ ) && ( $ rsh_extension = 'SSH' ) ;
2009-11-12 15:50:13 +00:00
2012-11-13 22:03:57 +00:00
if ( $$ options { 'devicetype' } =~ /EthSwitch/ ) {
$ remote_shell = "$::XCATROOT/sbin/rshell_api" ;
$ rsh_extension = 'RShellAPI' ;
$ rsh_config { 'password' } = $$ target_properties { 'password' } ;
2013-01-09 18:15:27 +00:00
if ( $$ target_properties { 'remotecmdproto' } ) {
$ rsh_config { 'remotecmdproto' } = $$ target_properties { 'remotecmdproto' } ;
}
if ( $$ options { 'trace' } ) {
$ rsh_config { 'trace' } = 1 ;
}
2012-11-13 22:03:57 +00:00
}
2009-12-04 14:50:33 +00:00
# will not set -n for any command, causing problems
2009-11-17 13:28:55 +00:00
# with running xdsh to install rpms and start xcatd on AIX
2009-11-12 15:50:13 +00:00
# if IB switch device, do not set -n, causes no returncode
2009-11-17 13:28:55 +00:00
#if (($$options{'devicetype'})) {
2009-12-04 14:50:33 +00:00
$ rsh_config { 'options' } =
$$ options { 'node-options' } { $$ target_properties { 'context' } } ;
2009-11-17 13:28:55 +00:00
#} else { # not a device
2009-12-04 14:50:33 +00:00
# $rsh_config{'options'} = "-n "
#. $$options{'node-options'}{$$target_properties{'context'}};
2009-11-17 13:28:55 +00:00
#}
2007-12-12 13:38:48 +00:00
}
#eval "require RemoteShell::$rsh_extension";
eval "require xCAT::$rsh_extension" ;
2013-06-05 16:25:31 +00:00
$ rsh_config { 'command' } = "$exportnode$$options{'pre-command'}" ;
2007-12-12 13:38:48 +00:00
my $ tmp_env_file ;
2012-08-29 17:03:22 +00:00
# for the -E flag here we build and copy the -E env variable
# file to the nodes
2007-12-12 13:38:48 +00:00
if ( $$ options { 'environment' } )
{
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2008-02-18 15:57:25 +00:00
$ rsp - > { data } - > [ 0 ] = "TRACE: Environment option specified" ;
2007-12-12 13:38:48 +00:00
$ dsh_trace && ( xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ) ;
my % env_rcp_config = ( ) ;
$ tmp_env_file = POSIX:: tmpnam . '.dsh' ;
$ rsh_config { 'command' } . = ". $tmp_env_file ; " ;
$ env_rcp_config { 'src-file' } = $$ options { 'environment' } ;
$ env_rcp_config { 'dest-host' } = $$ target_properties { 'hostname' } ;
$ env_rcp_config { 'dest-file' } = $ tmp_env_file ;
$ env_rcp_config { 'dest-user' } = $$ target_properties { 'user' }
|| $$ options { 'user' } ;
my $ env_rcp_command = undef ;
my $ env_rcp_extension = $ rsh_extension ;
( $$ target_properties { 'type' } eq 'node' )
&& ( $ env_rcp_command = $ ENV { 'DSH_NODE_RCP' } ) ;
if ( $ env_rcp_command )
{
( $ env_rcp_command =~ /\/rcp$/ )
&& ( $ env_rcp_extension = 'RSH' ) ;
( $ env_rcp_command =~ /\/scp$/ )
&& ( $ env_rcp_extension = 'SSH' ) ;
}
#eval "require RemoteShell::$env_rcp_extension";
eval "require xCAT::$env_rcp_extension" ;
my $ rcp = "xCAT::$env_rcp_extension" ;
my @ env_rcp_command =
$ rcp - > remote_copy_command ( \ % env_rcp_config ) ;
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2007-12-12 13:38:48 +00:00
$ rsp - > { data } - > [ 0 ] =
2008-02-18 15:57:25 +00:00
"TRACE:Environment: Exporting File.@env_rcp_command " ;
2007-12-12 13:38:48 +00:00
$ dsh_trace && ( xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ) ;
2012-08-29 17:03:22 +00:00
# copy the Env Variable input file to the nodes
2013-01-18 03:37:00 +00:00
my @ env_rcp_process =
xCAT::DSHCore - > fork_no_output ( $ user_target , @ env_rcp_command ) ;
waitpid ( $ env_rcp_process [ 0 ] , undef ) ;
#push @commands, \@env_rcp_command;
2007-12-12 13:38:48 +00:00
}
my $ tmp_cmd_file ;
if ( $$ options { 'execute' } )
{
2013-01-09 18:15:27 +00:00
# first build the scp command to copy the file to execute
2013-02-28 20:35:42 +00:00
# down to the node into /tmp/*.dsh
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2008-02-18 15:57:25 +00:00
$ rsp - > { data } - > [ 0 ] = "TRACE: Execute option specified." ;
2007-12-12 13:38:48 +00:00
$ dsh_trace && ( xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ) ;
my % exe_rcp_config = ( ) ;
2013-02-28 20:35:42 +00:00
$ tmp_cmd_file = POSIX:: tmpnam . ".dsh" ;
2007-12-12 13:38:48 +00:00
my ( $ exe_cmd , @ args ) = @ { $$ options { 'execute' } } ;
my $ chmod_cmd = "" ;
2013-01-09 18:15:27 +00:00
# now build the xdsh of the file buffer
# add sudo for non-root users
if ( $$ options { 'sudo' } ) {
$ rsh_config { 'command' } . = "sudo " ;
$ rsh_config { 'sudo' } = "sudo " ;
}
2007-12-12 13:38:48 +00:00
$ rsh_config { 'command' } . =
"$chmod_cmd $tmp_cmd_file @args$$options{'post-command'}" ;
$ exe_rcp_config { 'src-file' } = $ exe_cmd ;
$ exe_rcp_config { 'dest-host' } = $$ target_properties { 'hostname' } ;
$ exe_rcp_config { 'dest-file' } = $ tmp_cmd_file ;
$ exe_rcp_config { 'dest-user' } = $$ target_properties { 'user' }
|| $$ options { 'user' } ;
my $ exe_rcp_command = undef ;
my $ exe_rcp_extension = $ rsh_extension ;
( $$ target_properties { 'type' } eq 'node' )
&& ( $ exe_rcp_command = $ ENV { 'DSH_NODE_RCP' } ) ;
if ( $ exe_rcp_command )
{
( $ exe_rcp_command =~ /\/rcp$/ )
&& ( $ exe_rcp_extension = 'RSH' ) ;
( $ exe_rcp_command =~ /\/scp$/ )
&& ( $ exe_rcp_extension = 'SSH' ) ;
}
#eval "require RemoteShell::$exe_rcp_extension";
eval "require xCAT::$exe_rcp_extension" ;
my $ rcp = "xCAT::$exe_rcp_extension" ;
my @ exe_rcp_command =
$ rcp - > remote_copy_command ( \ % exe_rcp_config ) ;
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2007-12-12 13:38:48 +00:00
$ rsp - > { data } - > [ 0 ] =
2008-02-18 15:57:25 +00:00
"TRACE:Execute: Exporting File:@exe_rcp_command" ;
2007-12-12 13:38:48 +00:00
$ dsh_trace && ( xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ) ;
2012-12-13 05:27:24 +00:00
#my @exe_rcp_process =
# xCAT::DSHCore->fork_no_output($user_target, @exe_rcp_command);
#waitpid($exe_rcp_process[0], undef);
push @ commands , \ @ exe_rcp_command ;
2007-12-12 13:38:48 +00:00
}
else
{
2013-01-09 18:15:27 +00:00
# add sudo for non-root users
2013-01-09 11:54:58 +00:00
if ( $$ options { 'sudo' } ) {
$ rsh_config { 'command' } . = "sudo " ;
$ rsh_config { 'sudo' } = "sudo " ;
}
2007-12-12 13:38:48 +00:00
$ rsh_config { 'command' } . =
"$$options{'command'}$$options{'post-command'}" ;
}
if ( $$ options { 'environment' } )
{
$ rsh_config { 'command' } . = ";rm $tmp_env_file" ;
}
if ( $$ options { 'execute' } )
{
2013-01-09 18:15:27 +00:00
$ rsh_config { 'command' } . = ";rm $tmp_cmd_file" ;
2007-12-12 13:38:48 +00:00
}
#eval "require RemoteShell::$rsh_extension";
eval "require xCAT::$rsh_extension" ;
my $ remoteshell = "xCAT::$rsh_extension" ;
push @ dsh_command ,
$ remoteshell - > remote_shell_command ( \ % rsh_config , $ remote_shell ) ;
}
my @ process_info ;
2008-10-17 16:04:13 +00:00
my $ rsp = { } ;
2008-02-18 15:57:25 +00:00
$ rsp - > { data } - > [ 0 ] = "Command name: @dsh_command" ;
2007-12-12 13:38:48 +00:00
$ dsh_trace && ( xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ) ;
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2007-12-12 13:38:48 +00:00
$ rsp - > { data } - > [ 0 ] = "dsh> Remote_command_started $user_target" ;
$$ options { 'monitor' } && xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
2012-08-29 17:11:57 +00:00
# execute and remove the /tmp file build which is a copy of the
# input -E file
2012-11-16 17:21:35 +00:00
#print "Command=@dsh_command\n";
2007-12-12 13:38:48 +00:00
2012-12-13 05:27:24 +00:00
#@process_info = xCAT::DSHCore->fork_output($user_target, @dsh_command);
push ( @ commands , \ @ dsh_command ) ; #print Dumper(\@commands);
@ process_info = xCAT::DSHCore - > fork_output_for_commands ( $ user_target , @ commands ) ;
2007-12-12 13:38:48 +00:00
if ( $ process_info [ 0 ] == - 2 )
{
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2008-02-18 15:57:25 +00:00
"$user_target could not execute this command $dsh_command[0] - $$options{'command'} , $! " ;
2007-12-12 13:38:48 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK ) ;
}
( $ process_info [ 0 ] == - 3 ) && ( & handle_signal_dsh ( 'INT' , 1 ) ) ;
if ( $ process_info [ 0 ] == - 4 )
{
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] = "Cannot redirect STDOUT, error= $!" ;
2007-12-12 13:38:48 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK ) ;
}
if ( $ process_info [ 0 ] == - 5 )
{
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] = "Cannot redirect STDERR, error= $!" ;
2007-12-12 13:38:48 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK ) ;
}
vec ( $$ outfh_targets { 'bitmap' } , fileno ( $ process_info [ 1 ] ) , 1 ) = 1 ;
vec ( $$ errfh_targets { 'bitmap' } , fileno ( $ process_info [ 2 ] ) , 1 ) = 1 ;
$$ outfh_targets { fileno ( $ process_info [ 1 ] ) } = $ user_target ;
$$ errfh_targets { fileno ( $ process_info [ 2 ] ) } = $ user_target ;
$$ forked_process { $ user_target } = \ @ process_info ;
$$ targets_active { $ user_target } + + ;
$$ pid_targets { $ process_info [ 0 ] } = $ user_target ;
}
}
#----------------------------------------------------------------------------
= head3
buffer_output
For a given list of targets with output available , this routine buffers
output from the targets STDOUT pipe handles into buffers grouped by
target name
Arguments:
$ options - options hash table describing dsh configuration options
$ resolved_targets - hash table of resolved targets and target properties
$ targets_active - hash table of currently active targets with output possibly available
$ targets_finished - list of targets with all output processed and have completed execution
$ targets_failed - list of targets that have unsuccessfully executed
$ targets_buffered - hash table of buffers with output from active targets
$ pid_targets - hash table of target names keyed by process ID
$ forked_process - hash table of process information keyed by target name
$ errfh_targets - hash table of STDERR pipe handles keyed by target name
$ output_buffers - hash table of STDOUT buffers keyed by target name
$ error_buffers - hash table of STDERR buffers keyed by target name
$ output_files - list of output file handles where output is to be written
$ error_files - list of error file handles where error output is to be written
$ select_err_fhs - list of currently available STDERR pipe handles
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Returns:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Globals:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Error:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Example:
Comments:
= cut
#----------------------------------------------------------------------------
sub buffer_output
{
my (
$ class , $ options , $ resolved_targets ,
$ targets_active , $ targets_finished , $ targets_failed ,
$ targets_buffered , $ pid_targets , $ forked_process ,
$ outfh_targets , $ output_buffers , $ error_buffers ,
$ output_files , $ error_files , $ select_out_fhs
)
= @ _ ;
2008-07-18 12:02:22 +00:00
foreach my $ select_out_fh ( @$ select_out_fhs )
2007-12-12 13:38:48 +00:00
{
my $ user_target = $$ outfh_targets { $ select_out_fh } ;
my $ output_fh = $$ forked_process { $ user_target } [ 1 ] ;
my $ error_fh = $$ forked_process { $ user_target } [ 2 ] ;
my $ target_properties = $$ resolved_targets { $ user_target } ;
if ( ! $$ output_buffers { $ user_target } )
{
my @ buffer = ( ) ;
$$ output_buffers { $ user_target } = \ @ buffer ;
}
if ( ! $$ output_buffers { "${user_target}_tmp" } )
{
my @ buffer_tmp = ( ) ;
$$ output_buffers { "${user_target}_tmp" } = \ @ buffer_tmp ;
}
my $ eof_output =
xCAT::DSHCore - > pipe_handler_buffer (
$ target_properties , $ output_fh , 4096 ,
"$user_target: " ,
$$ output_buffers { "${user_target}_tmp" } ,
$$ output_buffers { $ user_target }
) ;
if ( $ eof_output )
{
vec ( $$ outfh_targets { 'bitmap' } , fileno ( $ output_fh ) , 1 ) = 0 ;
delete $$ outfh_targets { $ user_target } ;
if ( + + $$ targets_active { $ user_target } == 3 )
2007-12-20 19:02:17 +00:00
{
2007-12-12 13:38:48 +00:00
my $ exit_code ;
2007-12-20 19:02:17 +00:00
my $ pid = waitpid ( $$ forked_process { $ user_target } [ 0 ] , 0 ) ;
if ( $ pid == - 1 )
{ # no child waiting ignore
2008-10-17 16:04:13 +00:00
my $ rsp = { } ;
2008-02-18 15:57:25 +00:00
$ rsp - > { data } - > [ 0 ] = "waitpid call PID=$pid. Ignore." ;
2007-12-20 19:02:17 +00:00
$$ options { 'monitor' }
&& xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
}
else
{ # check return code
$ exit_code = $? >> 8 ;
2007-12-12 13:38:48 +00:00
}
if ( scalar ( @ { $$ output_buffers { $ user_target } } ) == 1 )
{
( $$ output_buffers { $ user_target } [ 0 ] eq '' )
&& ( @ { $$ output_buffers { $ user_target } } = ( ) ) ;
}
if ( scalar ( @ { $$ error_buffers { $ user_target } } ) == 1 )
{
( $$ error_buffers { $ user_target } [ 0 ] eq '' )
&& ( @ { $$ error_buffers { $ user_target } } = ( ) ) ;
}
my % exit_status = (
'exit-code' = > $ exit_code ,
'target-rc' = > $$ target_properties { 'target-rc' }
) ;
$$ targets_buffered { $ user_target } = \ % exit_status ;
delete $$ targets_active { $ user_target } ;
2008-07-24 14:36:56 +00:00
delete $$ pid_targets { $$ forked_process { $ user_target } [ 0 ] } ;
2007-12-12 13:38:48 +00:00
close $ output_fh ;
close $ error_fh ;
}
}
}
}
#----------------------------------------------------------------------------
= head3
buffer_error
For a given list of targets with output available , this routine buffers
output from the targets STDERR pipe handles into buffers grouped by
target name
Arguments:
$ options - options hash table describing dsh configuration options
$ resolved_targets - hash table of resolved targets and target properties
$ targets_active - hash table of currently active targets with output possibly available
$ targets_finished - list of targets with all output processed and have completed execution
$ targets_failed - list of targets that have unsuccessfully executed
$ targets_buffered - hash table of buffers with output from active targets
$ pid_targets - hash table of target names keyed by process ID
$ forked_process - hash table of process information keyed by target name
$ errfh_targets - hash table of STDERR pipe handles keyed by target name
$ output_buffers - hash table of STDOUT buffers keyed by target name
$ error_buffers - hash table of STDERR buffers keyed by target name
$ output_files - list of output file handles where output is to be written
$ error_files - list of error file handles where error output is to be written
$ select_err_fhs - list of currently available STDERR pipe handles
Returns:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Globals:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Error:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Example:
Comments:
= cut
#----------------------------------------------------------------------------
sub buffer_error
{
my (
$ class , $ options , $ resolved_targets ,
$ targets_active , $ targets_finished , $ targets_failed ,
$ targets_buffered , $ pid_targets , $ forked_process ,
$ errfh_targets , $ output_buffers , $ error_buffers ,
$ output_files , $ error_files , $ select_err_fhs
)
= @ _ ;
2008-07-18 12:02:22 +00:00
foreach my $ select_err_fh ( @$ select_err_fhs )
2007-12-12 13:38:48 +00:00
{
my $ user_target = $$ errfh_targets { $ select_err_fh } ;
my $ output_fh = $$ forked_process { $ user_target } [ 1 ] ;
my $ error_fh = $$ forked_process { $ user_target } [ 2 ] ;
my $ target_properties = $$ resolved_targets { $ user_target } ;
if ( ! $$ error_buffers { $ user_target } )
{
my @ buffer = ( ) ;
$$ error_buffers { $ user_target } = \ @ buffer ;
}
if ( ! $$ error_buffers { "${user_target}_tmp" } )
{
my @ buffer_tmp = ( ) ;
$$ error_buffers { "${user_target}_tmp" } = \ @ buffer_tmp ;
}
my $ eof_error =
xCAT::DSHCore - > pipe_handler_buffer (
$ target_properties , $ error_fh , 4096 ,
"$user_target: " ,
$$ error_buffers { "${user_target}_tmp" } ,
$$ error_buffers { $ user_target }
) ;
if ( $ eof_error )
{
vec ( $$ errfh_targets { 'bitmap' } , fileno ( $ error_fh ) , 1 ) = 0 ;
delete $$ errfh_targets { $ user_target } ;
if ( + + $$ targets_active { $ user_target } == 3 )
{
my $ exit_code ;
2007-12-20 19:02:17 +00:00
my $ pid = waitpid ( $$ forked_process { $ user_target } [ 0 ] , 0 ) ;
if ( $ pid == - 1 )
{ # no child waiting
2008-10-17 16:04:13 +00:00
my $ rsp = { } ;
2008-02-18 15:57:25 +00:00
$ rsp - > { data } - > [ 0 ] = "waitpid call PID=$pid. Ignore." ;
2007-12-20 19:02:17 +00:00
$$ options { 'monitor' }
&& xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
}
else
{ # check return code
$ exit_code = $? >> 8 ;
2007-12-12 13:38:48 +00:00
}
if ( scalar ( @ { $$ output_buffers { $ user_target } } ) == 1 )
{
( $$ output_buffers { $ user_target } [ 0 ] eq '' )
&& ( @ { $$ output_buffers { $ user_target } } = ( ) ) ;
}
if ( scalar ( @ { $$ error_buffers { $ user_target } } ) == 1 )
{
( $$ error_buffers { $ user_target } [ 0 ] eq '' )
&& ( @ { $$ error_buffers { $ user_target } } = ( ) ) ;
}
my % exit_status = (
'exit-code' = > $ exit_code ,
'target-rc' = > $$ target_properties { 'target-rc' }
) ;
$$ targets_buffered { $ user_target } = \ % exit_status ;
delete $$ targets_active { $ user_target } ;
2008-07-24 14:36:56 +00:00
delete $$ pid_targets { $$ forked_process { $ user_target } [ 0 ] } ;
2007-12-12 13:38:48 +00:00
close $ output_fh ;
close $ error_fh ;
}
}
}
}
#----------------------------------------------------------------------------
= head3
2012-11-14 16:02:18 +00:00
stream_output - Running xdsh with the - s option
2007-12-12 13:38:48 +00:00
For a given list of targets with output available , this routine writes
output from the targets STDOUT pipe handles directly to STDOUT as soon
as it is available from the target
Arguments:
$ options - options hash table describing dsh configuration options
$ resolved_targets - hash table of resolved targets and target properties
$ targets_active - hash table of currently active targets with output possibly available
$ targets_finished - list of targets with all output processed and have completed execution
$ targets_failed - list of targets that have unsuccessfully executed
$ targets_buffered - hash table of buffers with output from active targets
$ pid_targets - hash table of target names keyed by process ID
$ forked_process - hash table of process information keyed by target name
$ outfh_targets - hash table of STDOUT pipe handles keyed by target name
$ output_buffers - hash table of STDOUT buffers keyed by target name
$ output_files - list of error file handles where error output is to be written
$ select_out_fhs - list of currently available STDOUT pipe handles
Returns:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Globals:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Error:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Example:
Comments:
= cut
#----------------------------------------------------------------------------
sub stream_output
{
my (
$ class , $ options , $ resolved_targets ,
$ targets_active , $ targets_finished , $ targets_failed ,
$ pid_targets , $ forked_process , $ outfh_targets ,
$ output_buffers , $ output_files , $ select_out_fhs
)
= @ _ ;
2008-07-18 12:02:22 +00:00
foreach my $ select_out_fh ( @$ select_out_fhs )
2007-12-12 13:38:48 +00:00
{
my $ user_target = $$ outfh_targets { $ select_out_fh } ;
my $ output_fh = $$ forked_process { $ user_target } [ 1 ] ;
my $ target_properties = $$ resolved_targets { $ user_target } ;
if ( ! $$ output_buffers { $ user_target } )
{
my @ buffer = ( ) ;
$$ output_buffers { $ user_target } = \ @ buffer ;
}
my $ eof_output =
xCAT::DSHCore - > pipe_handler (
$ options ,
$ target_properties ,
$ output_fh ,
4096 ,
"$user_target: " ,
$$ output_buffers { $ user_target } ,
@$ output_files
) ;
if ( $ eof_output )
{
vec ( $$ outfh_targets { 'bitmap' } , fileno ( $ output_fh ) , 1 ) = 0 ;
delete $$ outfh_targets { $ user_target } ;
if ( + + $$ targets_active { $ user_target } == 3 )
{
my $ exit_code ;
2007-12-20 19:02:17 +00:00
my $ pid = waitpid ( $$ forked_process { $ user_target } [ 0 ] , 0 ) ;
if ( $ pid == - 1 )
{ # no child waiting
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2008-02-18 15:57:25 +00:00
$ rsp - > { data } - > [ 0 ] = "waitpid call PID=$pid. Ignore." ;
2007-12-20 19:02:17 +00:00
$$ options { 'monitor' }
&& xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
}
else
{ # check return code
$ exit_code = $? >> 8 ;
2007-12-12 13:38:48 +00:00
}
my $ target_rc = $$ target_properties { 'target-rc' } ;
if ( $ exit_code != 0 )
{
2012-11-14 16:02:18 +00:00
# report error status --nodestatus
# Note the message below for node status must
# not be NLS translated. Code depends on the English.
if ( $$ options { 'nodestatus' } ) {
my $ rsp = { } ;
$ rsp - > { data } - > [ 0 ] =
"$user_target: Remote_command_failed, error_code=$exit_code" ;
xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
}
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2008-02-18 15:57:25 +00:00
"$user_target remote shell had error code: $exit_code" ;
2007-12-12 13:38:48 +00:00
! $$ options { 'silent' }
&& ( xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK ) ) ;
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2007-12-12 13:38:48 +00:00
$ rsp - > { data } - > [ 0 ] =
"dsh> Remote_command_failed $user_target" ;
$$ options { 'monitor' }
&& xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
push @$ targets_failed , $ user_target ;
push @ { $ dsh_target_status { 'failed' } } , $ user_target
if ! $ signal_interrupt_flag ;
}
else
{
if ( $ target_rc != 0 )
{
2012-11-14 16:02:18 +00:00
# report error status --nodestatus
# Note the message below for node status must
# not be NLS translated. Code depends on the English.
if ( $$ options { 'nodestatus' } ) {
my $ rsp = { } ;
$ rsp - > { data } - > [ 0 ] =
"$user_target: Remote_command_failed, error_code=$$target_properties{'target-rc'}" ;
xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
}
2007-12-12 13:38:48 +00:00
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2008-02-18 15:57:25 +00:00
" $user_target remote Command had return code: $$target_properties{'target-rc'} " ;
2007-12-12 13:38:48 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK ) ;
2008-10-17 16:04:13 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2007-12-12 13:38:48 +00:00
"dsh> Remote_command_failed $user_target" ;
$$ options { 'monitor' }
2012-06-07 13:00:05 +00:00
&& xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK ) ;
2007-12-12 13:38:48 +00:00
push @$ targets_failed , $ user_target ;
}
elsif ( ! defined ( $ target_rc ) )
{
2012-11-14 16:02:18 +00:00
# report error status --nodestatus
# Note the message below for node status must
# not be NLS translated. Code depends on the English.
if ( $$ options { 'nodestatus' } ) {
my $ rsp = { } ;
$ rsp - > { data } - > [ 0 ] =
"$user_target: Remote_command_failed, error_code=???" ;
xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
}
2007-12-12 13:38:48 +00:00
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2008-02-18 15:57:25 +00:00
" $user_target a return code run on this host was not received. " ;
2007-12-12 13:38:48 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK ) ;
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2007-12-12 13:38:48 +00:00
$ rsp - > { data } - > [ 0 ] =
"dsh> Remote_command_failed $user_target" ;
$$ options { 'monitor' }
&& xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
push @$ targets_failed , $ user_target ;
}
2012-11-14 16:02:18 +00:00
else # xdsh -s worked
2007-12-12 13:38:48 +00:00
{
2012-11-14 16:02:18 +00:00
# report error status --nodestatus
# Note the message below for node status must
# not be NLS translated. Code depends on the English.
if ( $$ options { 'nodestatus' } ) {
my $ rsp = { } ;
$ rsp - > { data } - > [ 0 ] =
"$user_target: Remote_command_successful" ;
xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
}
2007-12-12 13:38:48 +00:00
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2007-12-12 13:38:48 +00:00
$ rsp - > { data } - > [ 0 ] =
"dsh> Remote_command_successful $user_target" ;
$$ options { 'monitor' }
&& xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
push @$ targets_finished , $ user_target ;
}
}
delete $$ targets_active { $ user_target } ;
delete $$ pid_targets { $$ forked_process { $ user_target } [ 0 ] } ;
}
close $ output_fh ;
}
}
}
#----------------------------------------------------------------------------
= head3
stream_error
For a given list of targets with output available , this routine writes
output from the targets STDERR pipe handles directly to STDERR as soon
as it is available from the target
Arguments:
$ options - options hash table describing dsh configuration options
$ resolved_targets - hash table of resolved targets and target properties
$ targets_active - hash table of currently active targets with output possibly available
$ targets_finished - list of targets with all output processed and have completed execution
$ targets_failed - list of targets that have unsuccessfully executed
$ targets_buffered - hash table of buffers with output from active targets
$ pid_targets - hash table of target names keyed by process ID
$ forked_process - hash table of process information keyed by target name
$ errfh_targets - hash table of STDERR pipe handles keyed by target name
$ error_buffers - hash table of STDERR buffers keyed by target name
$ error_files - list of error file handles where error output is to be written
$ select_err_fhs - list of currently available STDERR pipe handles
Returns:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Globals:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Error:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Example:
Comments:
= cut
#----------------------------------------------------------------------------
sub stream_error
{
my (
$ class , $ options , $ resolved_targets ,
$ targets_active , $ targets_finished , $ targets_failed ,
$ pid_targets , $ forked_process , $ errfh_targets ,
$ error_buffers , $ error_files , $ select_err_fhs
)
= @ _ ;
2008-07-18 12:02:22 +00:00
foreach my $ select_err_fh ( @$ select_err_fhs )
2007-12-12 13:38:48 +00:00
{
my $ user_target = $$ errfh_targets { $ select_err_fh } ;
my $ error_fh = $$ forked_process { $ user_target } [ 2 ] ;
my $ target_properties = $$ resolved_targets { $ user_target } ;
if ( ! $$ error_buffers { $ user_target } )
{
my @ buffer = ( ) ;
$$ error_buffers { $ user_target } = \ @ buffer ;
}
my $ eof_error =
xCAT::DSHCore - > pipe_handler (
$ options ,
$ target_properties ,
$ error_fh ,
4096 ,
"$user_target: " ,
2008-07-24 14:36:56 +00:00
$$ error_buffers { $ user_target } ,
2007-12-12 13:38:48 +00:00
@$ error_files
) ;
if ( $ eof_error )
{
vec ( $$ errfh_targets { 'bitmap' } , fileno ( $ error_fh ) , 1 ) = 0 ;
delete $$ errfh_targets { $ user_target } ;
2008-10-17 16:04:13 +00:00
my $ rsp = { } ;
2007-12-12 13:38:48 +00:00
if ( + + $$ targets_active { $ user_target } == 3 )
{
my $ exit_code ;
2007-12-20 19:02:17 +00:00
my $ pid = waitpid ( $$ forked_process { $ user_target } [ 0 ] , 0 ) ;
if ( $ pid == - 1 )
{ # no child waiting
2008-02-18 15:57:25 +00:00
$ rsp - > { data } - > [ 0 ] = "waitpid call PID=$pid. Ignore." ;
2007-12-20 19:02:17 +00:00
$$ options { 'monitor' }
&& xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
}
else
{ # check return code
$ exit_code = $? >> 8 ;
2007-12-12 13:38:48 +00:00
}
my $ target_rc = $$ target_properties { 'target-rc' } ;
if ( $ exit_code != 0 )
{
2012-11-14 16:02:18 +00:00
# report error status --nodestatus
# Note the message below for node status must
# not be NLS translated. Code depends on the English.
if ( $$ options { 'nodestatus' } ) {
my $ rsp = { } ;
$ rsp - > { data } - > [ 0 ] =
"$user_target: Remote_command_failed, error_code=$exit_code" ;
xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
}
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2008-02-18 15:57:25 +00:00
" $user_target remote shell had exit code $exit_code." ;
2007-12-12 13:38:48 +00:00
! $$ options { 'silent' }
&& ( xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK ) ) ;
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2007-12-12 13:38:48 +00:00
"dsh> Remote_command_failed $user_target" ;
$$ options { 'monitor' }
2012-06-07 13:00:05 +00:00
&& xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK ) ;
2007-12-12 13:38:48 +00:00
push @$ targets_failed , $ user_target ;
push @ { $ dsh_target_status { 'failed' } } , $ user_target
if ! $ signal_interrupt_flag ;
}
else
{
if ( $ target_rc != 0 )
{
2012-11-14 16:02:18 +00:00
# report error status --nodestatus
# Note the message below for node status must
# not be NLS translated. Code depends on the English.
if ( $$ options { 'nodestatus' } ) {
my $ rsp = { } ;
$ rsp - > { data } - > [ 0 ] =
"$user_target: Remote_command_failed, error_code=$$target_properties{'target-rc'}" ;
xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
}
2007-12-12 13:38:48 +00:00
2012-11-16 17:21:35 +00:00
#my $rsp = {};
#$rsp->{error}->[0] =
# "$user_target remote command had return code $$target_properties{'target-rc'}";
#xCAT::MsgUtils->message("E", $rsp, $::CALLBACK);
2007-12-12 13:38:48 +00:00
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2007-12-12 13:38:48 +00:00
"dsh> Remote_command_failed $user_target" ;
$$ options { 'monitor' }
2012-06-07 13:00:05 +00:00
&& xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK ) ;
2007-12-12 13:38:48 +00:00
push @$ targets_failed , $ user_target ;
}
2011-10-11 16:37:51 +00:00
elsif ( ! defined ( $ target_rc ) && ( $ ::DSH_MELLANOX_SWITCH == 0 ) )
2007-12-12 13:38:48 +00:00
{
2012-11-14 16:02:18 +00:00
# report error status --nodestatus
# Note the message below for node status must
# not be NLS translated. Code depends on the English.
if ( $$ options { 'nodestatus' } ) {
my $ rsp = { } ;
$ rsp - > { data } - > [ 0 ] =
"$user_target: Remote_command_failed, error_code=???}" ;
xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
}
2007-12-12 13:38:48 +00:00
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-12-11 13:49:24 +00:00
$ rsp - > { data } - > [ 0 ] =
2008-02-18 15:57:25 +00:00
"A return code for the command run on $user_target was not received." ;
2012-12-06 19:37:17 +00:00
xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
2007-12-12 13:38:48 +00:00
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2007-12-12 13:38:48 +00:00
"dsh> Remote_command_failed $user_target" ;
$$ options { 'monitor' }
2012-06-07 13:00:05 +00:00
&& xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK ) ;
2007-12-12 13:38:48 +00:00
push @$ targets_failed , $ user_target ;
}
else
{
2012-11-14 16:02:18 +00:00
# report error status --nodestatus
# Note the message below for node status must
# not be NLS translated. Code depends on the English.
if ( $$ options { 'nodestatus' } ) {
my $ rsp = { } ;
$ rsp - > { data } - > [ 0 ] =
"$user_target: Remote_command_successful" ;
xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
}
2007-12-12 13:38:48 +00:00
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2007-12-12 13:38:48 +00:00
$ rsp - > { data } - > [ 0 ] =
"dsh> Remote_command_successful $user_target" ;
$$ options { 'monitor' }
&& xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
push @$ targets_finished , $ user_target ;
}
}
delete $$ targets_active { $ user_target } ;
delete $$ pid_targets { $$ forked_process { $ user_target } [ 0 ] } ;
}
close $ error_fh ;
}
}
}
#----------------------------------------------------------------------------
= head3
config_default_context
2009-12-04 14:50:33 +00:00
Return the name of the default context to the caller ( always XCAT )
2007-12-12 13:38:48 +00:00
Arguments:
$ options - options hash table describing dsh configuration options
Returns:
2009-12-04 14:50:33 +00:00
The name of the default context which is always XCAT
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Globals:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Error:
2009-12-04 14:50:33 +00:00
If context file not found
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Example:
Comments:
= cut
#----------------------------------------------------------------------------
sub config_default_context
{
my ( $ class , $ options ) = @ _ ;
2009-12-04 14:50:33 +00:00
my $ contextdir = $ ::CONTEXT_DIR ;
$ contextdir . = "XCAT.pm" ;
if ( - e "$contextdir" )
2007-12-12 13:38:48 +00:00
{
2009-12-04 14:50:33 +00:00
require Context::XCAT ;
( XCAT - > valid_context ) && ( $$ options { 'context' } = 'XCAT' ) ;
2007-12-12 13:38:48 +00:00
}
2009-12-04 14:50:33 +00:00
2007-12-12 13:38:48 +00:00
}
#----------------------------------------------------------------------------
= head3
config_dcp
This routine configures the command environment for an instance of the
dcp command based on the configuration of the DSH Utilities environment
defined in $ options .
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Arguments:
$ options - options hash table describing dsh configuration options
Returns:
Number of configuration errors
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Globals:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Error:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Example:
Comments:
= cut
#----------------------------------------------------------------------------
sub config_dcp
{
my ( $ class , $ options ) = @ _ ;
my $ result = 0 ;
$$ options { 'trace' } && $ dsh_trace + + ;
$ dsh_trace && xCAT::DSHCLI - > show_dsh_config ( $ options ) ;
xCAT::DSHCLI - > config_default_context ( $ options ) ;
if ( ! ( - e "$::CONTEXT_DIR$$options{'context'}.pm" ) )
{
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2012-12-08 11:56:05 +00:00
"Context file XCAT.pm does not exist." ;
2007-12-12 13:38:48 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK ) ;
return + + $ result ;
}
2008-10-17 16:04:13 +00:00
my $ rsp = { } ;
2008-02-18 15:57:25 +00:00
$ rsp - > { data } - > [ 0 ] = "TRACE:Default context is $$options{'context'}." ;
2007-12-12 13:38:48 +00:00
$ dsh_trace
&& xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
! $$ options { 'node-rcp' }
&& ( $$ options { 'node-rcp' } = $ ENV { 'DCP_NODE_RCP' }
|| $ ENV { 'DCP_COPY_CMD' }
|| undef ) ;
if ( $$ options { 'node-rcp' } )
{
my % node_rcp = ( ) ;
my @ remotecopy_list = split ',' , $$ options { 'node-rcp' } ;
2008-07-18 12:02:22 +00:00
foreach my $ context_remotecopy ( @ remotecopy_list )
2007-12-12 13:38:48 +00:00
{
my ( $ context , $ remotecopy ) = split ':' , $ context_remotecopy ;
if ( ! $ remotecopy )
{
$ remotecopy = $ context ;
scalar ( @ dsh_valid_contexts ) || xCAT::DSHCLI - > get_valid_contexts ;
2008-07-18 12:02:22 +00:00
foreach my $ context ( @ dsh_valid_contexts )
2007-12-12 13:38:48 +00:00
{
! $ node_rcp { $ context }
&& ( $ node_rcp { $ context } = $ remotecopy ) ;
}
}
else
{
$ node_rcp { $ context } = $ remotecopy ;
}
}
$$ options { 'node-rcp' } = \ % node_rcp ;
}
$$ options { 'fanout' } = $$ options { 'fanout' } || $ ENV { 'DSH_FANOUT' } || 64 ;
2008-10-17 16:04:13 +00:00
my $ rsp = { } ;
2008-02-18 15:57:25 +00:00
$ rsp - > { data } - > [ 0 ] = "TRACE:Fanout Value is $$options{'fanout'}." ;
2007-12-12 13:38:48 +00:00
$ dsh_trace
&& xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
$$ options { 'timeout' } = $$ options { 'timeout' } || $ ENV { 'DSH_TIMEOUT' } || undef ;
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2008-02-18 15:57:25 +00:00
$ rsp - > { data } - > [ 0 ] = "TRACE:Timeout Value is $$options{'timeout'}." ;
2007-12-12 13:38:48 +00:00
$ dsh_trace
&& xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
if ( ( ! $$ options { 'nodes' } )
&& ( $ ENV { 'DSH_NODE_LIST' } || $ ENV { 'DSH_LIST' } ) )
{
require Context::DSH ;
my $ node_list_file = $ ENV { 'DSH_NODE_LIST' }
|| $ ENV { 'DSH_LIST' }
|| $ ENV { 'WCOLL' } ;
my $ node_list = DSH - > read_target_file ( $ node_list_file ) ;
$$ options { 'nodes' } = join ',' , @$ node_list ;
}
elsif ( ! $$ options { 'nodes' } && $ ENV { 'DSH_NODE_LIST' } )
{
require Context::DSH ;
my $ node_list_file = $ ENV { 'DSH_NODE_LIST' } ;
my $ node_list = DSH - > read_target_file ( $ node_list_file ) ;
$$ options { 'nodes' } = join ',' , @$ node_list ;
}
$$ options { 'node-options' } = $$ options { 'node-options' }
|| $ ENV { 'DCP_NODE_OPTS' }
|| $ ENV { 'DSH_REMOTE_OPTS' } ;
if ( $$ options { 'node-options' } )
{
my % node_options = ( ) ;
my @ remoteopts_list = split ',' , $$ options { 'node-options' } ;
2008-07-18 12:02:22 +00:00
foreach my $ context_remoteopts ( @ remoteopts_list )
2007-12-12 13:38:48 +00:00
{
my ( $ context , $ remoteopts ) = split ':' , $ context_remoteopts ;
if ( ! $ remoteopts )
{
$ remoteopts = $ context ;
scalar ( @ dsh_valid_contexts ) || xCAT::DSHCLI - > get_valid_contexts ;
2008-07-18 12:02:22 +00:00
foreach my $ context ( @ dsh_valid_contexts )
2007-12-12 13:38:48 +00:00
{
! $ node_options { $ context }
&& ( $ node_options { $ context } = $ remoteopts ) ;
}
}
else
{
$ node_options { $ context } = $ remoteopts ;
}
}
$$ options { 'node-options' } = \ % node_options ;
}
if ( $$ options { 'pull' } && ! ( - d $$ options { 'target' } ) )
{
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2008-02-18 15:57:25 +00:00
"Cannot copy to target $$options{'target'}. Directory does not exist." ;
2007-12-12 13:38:48 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK ) ;
return + + $ result ;
}
return 0 ;
}
#----------------------------------------------------------------------------
= head3
config_dsh
This routine configures the command environment for an instance of the
dsh command based on the configuration of the DSH Utilities environment
defined in $ options .
Arguments:
$ options - options hash table describing dsh configuration options
Returns:
Number of configuration errors
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Globals:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Error:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Example:
Comments:
= cut
#----------------------------------------------------------------------------
sub config_dsh
{
my ( $ class , $ options ) = @ _ ;
my $ result = 0 ;
$$ options { 'stats' } = $$ options { 'monitor' } ;
if ( $$ options { 'stats' } )
{
$ dsh_stats { 'start-time' } = localtime ( ) ;
$ dsh_stats { 'user' } = $$ options { 'user' } || `whoami` ;
chomp ( $ dsh_stats { 'user' } ) ;
$ dsh_stats { 'successful-targets' } = ( ) ;
$ dsh_stats { 'failed-targets' } = ( ) ;
$ dsh_stats { 'report-status-messages' } = ( ) ;
$ dsh_stats { 'specified-targets' } = ( ) ;
scalar ( @ dsh_valid_contexts ) || xCAT::DSHCLI - > get_valid_contexts ;
push @ { $ dsh_stats { 'valid-contexts' } } , @ dsh_valid_contexts ;
2008-07-18 12:02:22 +00:00
foreach my $ context ( @ dsh_valid_contexts )
2007-12-12 13:38:48 +00:00
{
$ dsh_stats { 'specified-targets' } { $ context } = ( ) ;
$ dsh_stats { 'specified-targets' } { $ context } { 'nodes' } = ( ) ;
}
$$ options { 'command-name' } = $$ options { 'command-name' } || 'Unspecified' ;
$$ options { 'command-description' } = $$ options { 'command-description' }
|| '' ;
}
$$ options { 'trace' } && $ dsh_trace + + ;
$ dsh_trace && xCAT::DSHCLI - > show_dsh_config ;
xCAT::DSHCLI - > config_default_context ( $ options ) ;
my $ test = " $::CONTEXT_DIR$$options{'context'}.pm" ;
if ( ! ( - e "$::CONTEXT_DIR$$options{'context'}.pm" ) )
{
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2009-12-04 14:50:33 +00:00
"Context file $::CONTEXT_DIR$$options{'context'}.pm does not exist." ;
2007-12-12 13:38:48 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK ) ;
return + + $ result ;
}
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2008-02-18 15:57:25 +00:00
$ rsp - > { data } - > [ 0 ] = "TRACE:Default context is $$options{'context'}" ;
2007-12-12 13:38:48 +00:00
$ dsh_trace
&& xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
2011-10-11 16:16:27 +00:00
# Check devicetype attr and build command based on type
2009-02-04 17:18:44 +00:00
$$ options { 'devicetype' } = $$ options { 'devicetype' }
|| $ ENV { 'DEVICETYPE' }
|| undef ;
if ( $$ options { 'devicetype' } )
2009-01-08 12:57:02 +00:00
{
$ ENV { 'DEVICETYPE' } = $$ options { 'devicetype' } ;
2012-11-16 17:21:35 +00:00
my $ devicename = $$ options { 'devicetype' } ;
$ devicename =~ s/::/\//g ;
2009-02-04 17:18:44 +00:00
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-11-16 17:21:35 +00:00
$ rsp - > { data } - > [ 0 ] = "Processing $devicename device type" ;
2011-10-11 16:16:27 +00:00
$ dsh_trace && xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
2009-02-04 17:18:44 +00:00
2012-11-16 17:21:35 +00:00
# process the config file. check /var/opt/xcat/... first, if the config
# file is not found, goto /opt/xcat/share/devicetype
my $ devicepath = "/var/opt/xcat/" . $ devicename . "/config" ;
if ( ! - e $ devicepath ) {
$ devicepath = "$::XCATROOT/share/xcat/devicetype/" . $ devicename . "/config" ;
}
# Get configuration from $::XCATDEVCFGDIR
# used for QLogic and Mellanox
if ( - e $ devicepath )
{
my $ deviceconf = get_config ( $ devicepath ) ;
# Get all dsh section configuration
foreach my $ entry ( keys % { $$ deviceconf { 'xdsh' } } )
{
2009-01-08 12:57:02 +00:00
my $ value = $$ deviceconf { 'xdsh' } { $ entry } ;
if ( $ value )
{
$$ options { $ entry } = $ value ;
}
2012-11-16 17:21:35 +00:00
}
}
else
{
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] = "EMsgMISSING_DEV_CFG" ;
2009-01-08 12:57:02 +00:00
xCAT::MsgUtils - > message ( 'E' , $ rsp , $ ::CALLBACK ) ;
2012-11-16 17:21:35 +00:00
}
2009-01-08 12:57:02 +00:00
}
2007-12-12 13:38:48 +00:00
! $$ options { 'node-rsh' }
&& ( $$ options { 'node-rsh' } = $ ENV { 'DSH_NODE_RSH' }
|| $ ENV { 'DSH_REMOTE_CMD' }
|| undef ) ;
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2008-02-18 15:57:25 +00:00
$ rsp - > { data } - > [ 0 ] = "TRACE:Node RSH is $$options{'node-rsh'}" ;
2007-12-12 13:38:48 +00:00
$ dsh_trace
&& xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
my % node_rsh_defaults = ( ) ;
scalar ( @ dsh_valid_contexts ) || xCAT::DSHCLI - > get_valid_contexts ;
2008-07-18 12:02:22 +00:00
foreach my $ context ( @ dsh_valid_contexts )
2007-12-12 13:38:48 +00:00
{
eval "require Context::$context" ;
my $ defaults = $ context - > context_defaults ;
$ node_rsh_defaults { $ context } = $$ defaults { 'NodeRemoteShell' }
|| $$ defaults { 'RemoteShell' } ;
}
$$ options { 'node-rsh-defaults' } = \ % node_rsh_defaults ;
my % node_rsh = ( ) ;
if ( $$ options { 'node-rsh' } )
{
my @ remoteshell_list = split ',' , $$ options { 'node-rsh' } ;
2008-07-18 12:02:22 +00:00
foreach my $ context_remoteshell ( @ remoteshell_list )
2007-12-12 13:38:48 +00:00
{
my ( $ context , $ remoteshell ) = split ':' , $ context_remoteshell ;
if ( ! $ remoteshell )
{
$ remoteshell = $ context ;
! $ node_rsh { 'none' } && ( $ node_rsh { 'none' } = $ remoteshell ) ;
}
else
{
! $ node_rsh { $ context } && ( $ node_rsh { $ context } = $ remoteshell ) ;
}
}
}
$$ options { 'node-rsh' } = \ % node_rsh ;
$$ options { 'environment' } = $$ options { 'environment' }
|| $ ENV { 'DSH_ENVIRONMENT' }
|| undef ;
if ( $$ options { 'environment' } && ( - z $$ options { 'environment' } ) )
{
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-12-11 13:49:24 +00:00
$ rsp - > { data } - > [ 0 ] = "File: $$options{'environment'} is empty." ;
2012-12-06 19:37:17 +00:00
xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
2007-12-12 13:38:48 +00:00
$$ options { 'environment' } = undef ;
}
$$ options { 'fanout' } = $$ options { 'fanout' } || $ ENV { 'DSH_FANOUT' } || 64 ;
2012-06-15 15:42:45 +00:00
$ rsp = { } ;
2008-02-18 15:57:25 +00:00
$ rsp - > { data } - > [ 0 ] = "TRACE: Fanout value is $$options{'fanout'}." ;
2007-12-12 13:38:48 +00:00
$ dsh_trace
&& xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
$$ options { 'syntax' } = $$ options { 'syntax' } || $ ENV { 'DSH_SYNTAX' } || undef ;
if (
defined ( $$ options { 'syntax' } )
&& ( ( $$ options { 'syntax' } ne 'csh' )
&& ( $$ options { 'syntax' } ne 'ksh' ) )
)
{
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2008-02-18 15:57:25 +00:00
"Incorrect argument \"$$options{'syntax'}\" specified on -S flag. " ;
2007-12-12 13:38:48 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK ) ;
return + + $ result ;
}
my $ env_set = 'export' ;
my $ env_assign = '=' ;
if ( $$ options { 'syntax' } eq 'csh' )
{
$ env_set = 'setenv' ;
$ env_assign = ' ' ;
}
my $ path_set ;
$ ENV { 'DSH_PATH' }
&& ( $ path_set = "$env_set PATH$env_assign$ENV{'DSH_PATH'};" ) ;
$$ options { 'timeout' } = $$ options { 'timeout' } || $ ENV { 'DSH_TIMEOUT' } || undef ;
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2008-02-18 15:57:25 +00:00
$ rsp - > { data } - > [ 0 ] = "TRACE: Timeout value is $$options{'timeout'} " ;
2007-12-12 13:38:48 +00:00
$ dsh_trace
&& xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
2009-01-08 12:57:02 +00:00
# Check if $$options{'pre-command'} has been overwritten
2011-10-11 16:16:27 +00:00
# Mellanox uses pre-command = cli
2009-01-08 12:57:02 +00:00
if ( ! $$ options { 'pre-command' } )
2007-12-12 13:38:48 +00:00
{
2009-02-04 17:18:44 +00:00
2009-01-08 12:57:02 +00:00
# Set a default PATH
$$ options { 'pre-command' } = $ path_set ;
2007-12-12 13:38:48 +00:00
2009-01-08 12:57:02 +00:00
if ( ! $$ options { 'no-locale' } )
2007-12-12 13:38:48 +00:00
{
2009-01-08 12:57:02 +00:00
my @ output = `/usr/bin/locale` ;
chomp ( @ output ) ;
my @ settings = ( ) ;
! ( $$ options { 'syntax' } eq 'csh' ) && ( push @ settings , $ env_set ) ;
foreach my $ line ( @ output )
{
$ line =~ s/=/$env_assign/ ;
if ( $$ options { 'syntax' } eq 'csh' )
{
push @ settings , "$env_set $line;" ;
}
else
{
push @ settings , $ line ;
}
}
2007-12-12 13:38:48 +00:00
if ( $$ options { 'syntax' } eq 'csh' )
{
2009-01-08 12:57:02 +00:00
push @ settings , "$env_set PERL_BADLANG${env_assign}0;" ;
2007-12-12 13:38:48 +00:00
}
else
{
2009-01-08 12:57:02 +00:00
push @ settings , "PERL_BADLANG${env_assign}0" ;
2007-12-12 13:38:48 +00:00
}
2009-02-04 17:18:44 +00:00
2009-01-08 12:57:02 +00:00
my $ locale_settings = join ' ' , @ settings ;
! ( $$ options { 'syntax' } eq 'csh' ) && ( $ locale_settings . = ' ; ' ) ;
$$ options { 'pre-command' } . = $ locale_settings ;
2007-12-12 13:38:48 +00:00
}
2009-01-08 12:57:02 +00:00
}
else
{
2011-10-11 16:16:27 +00:00
# if entry NULL then remove
if ( $$ options { 'pre-command' } =~ /NULL/i ) {
$$ options { 'pre-command' } = '' ;
} else { #add space between pre-command and command
$$ options { 'pre-command' } . = " " ;
}
2009-01-08 12:57:02 +00:00
}
2007-12-12 13:38:48 +00:00
2009-01-08 12:57:02 +00:00
# Check if $$options{'post-command'} has been overwritten.
2009-02-04 17:18:44 +00:00
if ( ! $$ options { 'post-command' } )
2009-01-08 12:57:02 +00:00
{
2007-12-12 13:38:48 +00:00
if ( $$ options { 'syntax' } eq 'csh' )
{
2009-01-08 12:57:02 +00:00
$$ options { 'post-command' } =
"; $env_set DSH_TARGET_RC$env_assign\$status; echo \":DSH_TARGET_RC=\${DSH_TARGET_RC}:\"" ;
2007-12-12 13:38:48 +00:00
}
else
{
2009-01-08 12:57:02 +00:00
$$ options { 'post-command' } =
"; $env_set DSH_TARGET_RC$env_assign\$?; echo \":DSH_TARGET_RC=\${DSH_TARGET_RC}:\"" ;
2007-12-12 13:38:48 +00:00
}
2009-01-08 12:57:02 +00:00
$$ options { 'exit-status' }
&& ( $$ options { 'post-command' } . =
' ; echo "Remote_command_rc = $DSH_TARGET_RC"' ) ;
2007-12-12 13:38:48 +00:00
}
else
{
2009-02-04 17:18:44 +00:00
2009-01-08 12:57:02 +00:00
# post-command is overwritten by user , set env $::USER_POST_CMD
$ ::USER_POST_CMD = 1 ;
2011-10-11 16:16:27 +00:00
if ( $$ options { 'post-command' } =~ /NULL/i )
2009-01-08 12:57:02 +00:00
{
$$ options { 'post-command' } = '' ;
}
else
{
2011-10-11 16:16:27 +00:00
# Build the user post command, for example for QLogic
2009-01-08 12:57:02 +00:00
# $::DSH_EXIT_STATUS ony can be used in DSHCore::pipe_handler_buffer
# and DSHCore::pipe_handler
$$ options { 'exit-status' }
2009-02-04 17:18:44 +00:00
&& ( $ ::DSH_EXIT_STATUS = 1 ) ;
2009-01-08 12:57:02 +00:00
$$ options { 'post-command' } = ";$$options{'post-command'}" ;
2009-02-04 17:18:44 +00:00
2009-01-08 12:57:02 +00:00
# Append "DSH_RC" keyword to mark output
$$ options { 'post-command' } = "$$options{'post-command'};echo DSH_RC" ;
}
2007-12-12 13:38:48 +00:00
}
if (
! $$ options { 'nodes' }
&& ( $ ENV { 'DSH_NODE_LIST' }
|| $ ENV { 'DSH_LIST' } )
)
{
require Context::DSH ;
my $ node_list_file = $ ENV { 'DSH_NODE_LIST' }
|| $ ENV { 'DSH_LIST' }
|| $ ENV { 'WCOLL' } ;
my $ node_list = DSH - > read_target_file ( $ node_list_file ) ;
$$ options { 'nodes' } = join ',' , @$ node_list ;
}
elsif ( ! $$ options { 'nodes' } && $ ENV { 'DSH_NODE_LIST' } )
{
require Context::DSH ;
my $ node_list_file = $ ENV { 'DSH_NODE_LIST' } ;
my $ node_list = DSH - > read_target_file ( $ node_list_file ) ;
$$ options { 'nodes' } = join ',' , @$ node_list ;
}
$$ options { 'node-options' } = $$ options { 'node-options' }
|| $ ENV { 'DSH_NODE_OPTS' }
|| $ ENV { 'DSH_REMOTE_OPTS' } ;
if ( $$ options { 'node-options' } )
{
my % node_options = ( ) ;
my @ remoteopts_list = split ',' , $$ options { 'node-options' } ;
2008-07-18 12:02:22 +00:00
foreach my $ context_remoteopts ( @ remoteopts_list )
2007-12-12 13:38:48 +00:00
{
my ( $ context , $ remoteopts ) = split ':' , $ context_remoteopts ;
if ( ! $ remoteopts )
{
$ remoteopts = $ context ;
scalar ( @ dsh_valid_contexts ) || xCAT::DSHCLI - > get_valid_contexts ;
2008-07-18 12:02:22 +00:00
foreach my $ context ( @ dsh_valid_contexts )
2007-12-12 13:38:48 +00:00
{
! $ node_options { $ context }
&& ( $ node_options { $ context } = $ remoteopts ) ;
}
}
else
{
$ node_options { $ context } = $ remoteopts ;
}
}
$$ options { 'node-options' } = \ % node_options ;
}
if ( $$ options { 'execute' } )
{
my @ exe_command = split ' ' , $$ options { 'command' } ;
$$ options { 'execute' } = \ @ exe_command ;
if ( ! ( - e $ exe_command [ 0 ] ) )
{
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] = "File $exe_command[0] does not exist" ;
2007-12-12 13:38:48 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK ) ;
return + + $ result ;
}
if ( - z $ exe_command [ 0 ] )
{
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] = "File $exe_command[0] is empty." ;
2007-12-12 13:38:48 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK ) ;
return + + $ result ;
}
if ( ! ( - x $ exe_command [ 0 ] ) )
{
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] = "File $exe_command[0] is not executable." ;
2007-12-12 13:38:48 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK ) ;
return + + $ result ;
}
}
return 0 ;
}
#----------------------------------------------------------------------------
= head3
config_signals_dsh
Configures the signal handling routines for each system signal
and configures which signals should be restored as define in the
DSH environment options .
Arguments:
$ options - options hash table describing dsh configuration options
Returns:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Globals:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Error:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Example:
Comments:
= cut
#----------------------------------------------------------------------------
sub config_signals_dsh
{
my ( $ class , $ options ) = @ _ ;
$ SIG { 'STOP' } = 'DEFAULT' ;
$ SIG { 'CONT' } = 'DEFAULT' ;
$ SIG { 'TSTP' } = 'DEFAULT' ;
$ SIG { 'TERM' } = 'xCAT::DSHCLI::handle_signal_dsh' ;
$ SIG { 'QUIT' } = 'xCAT::DSHCLI::handle_signal_dsh' ;
$ SIG { 'INT' } = 'xCAT::DSHCLI::handle_signal_dsh' ;
$ SIG { 'ABRT' } = 'xCAT::DSHCLI::handle_signal_dsh' ;
$ SIG { 'ALRM' } = 'xCAT::DSHCLI::handle_signal_dsh' ;
$ SIG { 'FPE' } = 'xCAT::DSHCLI::handle_signal_dsh' ;
$ SIG { 'ILL' } = 'xCAT::DSHCLI::handle_signal_dsh' ;
$ SIG { 'PIPE' } = 'xCAT::DSHCLI::handle_signal_dsh' ;
$ SIG { 'SEGV' } = 'xCAT::DSHCLI::handle_signal_dsh' ;
$ SIG { 'USR1' } = 'xCAT::DSHCLI::handle_signal_dsh' ;
$ SIG { 'USR2' } = 'xCAT::DSHCLI::handle_signal_dsh' ;
$ SIG { 'TTIN' } = 'xCAT::DSHCLI::handle_signal_dsh' ;
$ SIG { 'TTOU' } = 'xCAT::DSHCLI::handle_signal_dsh' ;
$ SIG { 'BUS' } = 'xCAT::DSHCLI::handle_signal_dsh' ;
my @ ignore_signals = split /,/ , $$ options { 'ignore-signal' } ;
2008-07-18 12:02:22 +00:00
foreach my $ signal ( @ ignore_signals )
2007-12-12 13:38:48 +00:00
{
if ( ( $ signal ne 'STOP' )
&& ( $ signal ne 'CONT' )
&& ( $ signal ne 'TSTP' ) )
{
$ SIG { $ signal } = 'IGNORE' ;
}
}
}
#----------------------------------------------------------------------------
= head3
handle_signal_dsh
Signal handling routine for an instance of the dsh command . Depending
on the state of dsh execution and report configuraion , this routine
properly writes reports and output files if a termination signal is recieved
Arguments:
$ signal - termination signal to handle
$ fatal - 1 if signal is fatal , 0 otherwise
Returns:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Globals:
$ dsh_execution_state - current state of dsh execution
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Error:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Example:
Comments:
= cut
#----------------------------------------------------------------------------
sub handle_signal_dsh
{
my ( $ signal , $ fatal_error ) = @ _ ;
my $ DSH_STATE_BEGIN = 0 ;
my $ DSH_STATE_INIT_STARTED = 1 ;
my $ DSH_STATE_INIT_COMPLETE = 2 ;
my $ DSH_STATE_TARGET_RESOLVE_COMPLETE = 3 ;
my $ DSH_STATE_REMOTE_EXEC_STARTED = 4 ;
my $ DSH_STATE_REMOTE_EXEC_COMPLETE = 5 ;
if ( $ dsh_exec_state == $ DSH_STATE_BEGIN )
{
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2008-02-18 15:57:25 +00:00
"Command execution ended prematurely due to a previous error or stop request from the user." ;
2007-12-12 13:38:48 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK ) ;
2009-06-09 14:38:30 +00:00
exit ( 1 ) ;
2007-12-12 13:38:48 +00:00
}
elsif ( $ dsh_exec_state == $ DSH_STATE_INIT_STARTED )
{
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2008-02-18 15:57:25 +00:00
"Command execution ended prematurely due to a previous error or stop request from the user." ;
2007-12-12 13:38:48 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK ) ;
exit ( 1 ) ;
}
elsif ( $ dsh_exec_state == $ DSH_STATE_INIT_COMPLETE )
{
if ( $$ dsh_options { 'stats' } )
{
$ dsh_stats { 'exec-state' } = $ dsh_exec_state ;
$ dsh_stats { 'end-time' } = localtime ( ) ;
}
if ( @ { $ dsh_target_status { 'waiting' } } )
{
2008-07-18 12:02:22 +00:00
foreach my $ user_target ( @ { $ dsh_target_status { 'waiting' } } )
2007-12-12 13:38:48 +00:00
{
if ( $ fatal_error )
{
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2008-02-18 15:57:25 +00:00
"Running the command on $user_target has been cancelled due to unrecoverable error. The command was never sent to the host." ;
2007-12-12 13:38:48 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK ) ;
}
else
{
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2007-12-12 13:38:48 +00:00
$ rsp - > { data } - > [ 0 ] =
2008-11-07 16:37:05 +00:00
"xdsh> Remote_command_cancelled $user_target" ;
2007-12-12 13:38:48 +00:00
$$ dsh_options { 'monitor' }
&& xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
}
push @ { $ dsh_target_status { 'canceled' } } , $ user_target ;
}
}
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2008-07-24 14:36:56 +00:00
"Running commands have been cancelled due to unrecoverable error or stop request by user." ;
2007-12-12 13:38:48 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK ) ;
if ( $$ dsh_options { 'stats' } )
{
my @ empty_targets = ( ) ;
$ dsh_stats { 'successful-targets' } = \ @ empty_targets ;
$ dsh_stats { 'failed-targets' } = \ @ empty_targets ;
$ dsh_stats { 'canceled-targets' } = $ dsh_target_status { 'canceled' } ;
}
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2007-12-12 13:38:48 +00:00
$ rsp - > { data } - > [ 0 ] = "dsh> Dsh_remote_execution_completed." ;
$$ dsh_options { 'monitor' }
&& xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
exit ( 1 ) ;
}
elsif ( $ dsh_exec_state == $ DSH_STATE_TARGET_RESOLVE_COMPLETE )
{
if ( $$ dsh_options { 'stats' } )
{
$ dsh_stats { 'exec-state' } = $ dsh_exec_state ;
$ dsh_stats { 'end-time' } = localtime ( ) ;
}
if ( @ { $ dsh_target_status { 'waiting' } } )
{
2008-07-18 12:02:22 +00:00
foreach my $ user_target ( @ { $ dsh_target_status { 'waiting' } } )
2007-12-12 13:38:48 +00:00
{
if ( $ fatal_error )
{
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2008-02-18 15:57:25 +00:00
"$user_target: running of the command on this host has been cancelled due to unrecoverable error.\n The command was never sent to the host." ;
2012-06-07 13:00:05 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK ) ;
2007-12-12 13:38:48 +00:00
}
else
{
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2008-02-18 15:57:25 +00:00
"$user_target: running of the command on this host has been cancelled due to unrecoverable error or stop request by user.\n The command was never sent to the host." ;
2012-06-07 13:00:05 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK ) ;
2007-12-12 13:38:48 +00:00
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2008-11-07 16:37:05 +00:00
"xdsh> Remote_command_cancelled $user_target" ;
2007-12-12 13:38:48 +00:00
$$ dsh_options { 'monitor' }
2012-06-07 13:00:05 +00:00
&& xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK ) ;
2007-12-12 13:38:48 +00:00
}
push @ { $ dsh_target_status { 'canceled' } } , $ user_target ;
}
}
@ { $ dsh_target_status { 'waiting' } } = ( ) ;
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2007-12-12 13:38:48 +00:00
$ rsp - > { data } - > [ 0 ] =
2008-02-18 15:57:25 +00:00
"Command execution ended prematurely due to a previous unrecoverable error or stop by user.\n No commands were executed on any host." ;
2007-12-12 13:38:48 +00:00
if ( $$ dsh_options { 'stats' } )
{
my @ empty_targets = ( ) ;
$ dsh_stats { 'successful-targets' } = \ @ empty_targets ;
$ dsh_stats { 'failed-targets' } = \ @ empty_targets ;
$ dsh_stats { 'canceled-targets' } = $ dsh_target_status { 'canceled' } ;
}
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2008-11-07 16:37:05 +00:00
$ rsp - > { data } - > [ 0 ] = "xdsh> Dsh_remote_execution_completed" ;
2008-10-17 16:04:13 +00:00
$$ dsh_options { 'monitor' }
&& xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
2007-12-12 13:38:48 +00:00
exit ( 1 ) ;
}
elsif ( $ dsh_exec_state == $ DSH_STATE_REMOTE_EXEC_STARTED )
{
if ( $$ dsh_options { 'stats' } )
{
$ dsh_stats { 'exec-state' } = $ dsh_exec_state ;
$ dsh_stats { 'end-time' } = localtime ( ) ;
}
my $ targets_active = $ dsh_target_status { 'active' } ;
my @ targets_active_list = keys ( %$ targets_active ) ;
if ( @ targets_active_list )
{
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2008-02-18 15:57:25 +00:00
"Caught SIG$signal - terminating the child processes." ;
2007-12-12 13:38:48 +00:00
! $$ dsh_options { 'stats' }
&& xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK ) ;
my $ target_signal = $ signal ;
my $ last_error = $! ;
if ( $ signal ne 'QUIT' && $ signal ne 'INT' && $ signal ne 'TERM' )
{
$ target_signal = 'TERM' ;
$ SIG { 'TERM' } = 'IGNORE' ;
}
$ SIG { $ signal } = 'DEFAULT' ;
2008-07-18 12:02:22 +00:00
foreach my $ user_target ( @ targets_active_list )
2007-12-12 13:38:48 +00:00
{
if ( $$ dsh_options { 'stats' } )
{
if ( $ fatal_error )
{
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2008-02-18 15:57:25 +00:00
"Running the command on $user_target has been interrupted due to unrecoverable error. The command may not have completed successfully." ;
2012-06-07 13:00:05 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK ) ;
2007-12-12 13:38:48 +00:00
}
else
{
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2008-02-18 15:57:25 +00:00
"Running the command on $user_target has been interrupted due to unrecoverable error or stop request by the user. The command may not have completed successfully." ;
2012-06-07 13:00:05 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK ) ;
2007-12-12 13:38:48 +00:00
}
}
my $ target_pid = $$ dsh_forked_process { $ user_target } [ 0 ] ;
kill $ target_signal , $ target_pid ;
push @ { $ dsh_target_status { 'failed' } } , $ user_target ;
$ signal_interrupt_flag = 1 ;
}
$! = $ last_error ;
}
2009-06-23 15:34:59 +00:00
# if 2 input then this was a timeout on one process, we do
# not want to remove all the rest
if ( $ fatal_error != 2 )
{ # remove the waiting processes
if ( @ { $ dsh_target_status { 'waiting' } } )
2007-12-12 13:38:48 +00:00
{
2009-06-23 15:34:59 +00:00
foreach my $ user_target ( @ { $ dsh_target_status { 'waiting' } } )
2007-12-12 13:38:48 +00:00
{
2009-06-23 15:34:59 +00:00
if ( $ fatal_error )
{
2007-12-12 13:38:48 +00:00
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2009-06-23 15:34:59 +00:00
"Running the command on $user_target has been cancelled due to unrecoverable error. The command was never sent to the host." ;
2012-06-07 13:00:05 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK ) ;
2009-06-23 15:34:59 +00:00
}
2007-12-12 13:38:48 +00:00
2009-06-23 15:34:59 +00:00
else
{
2007-12-12 13:38:48 +00:00
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2009-06-23 15:34:59 +00:00
"Running the command on $user_target has been cancelled due to unrecoverable error or stop request by the user. The command was never sent to the host." ;
2012-06-07 13:00:05 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK ) ;
2007-12-12 13:38:48 +00:00
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2009-06-23 15:34:59 +00:00
"dsh> Remote_command_cancelled $user_target" ;
$$ dsh_options { 'monitor' }
2012-06-07 13:00:05 +00:00
&& xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK ) ;
2009-06-23 15:34:59 +00:00
}
2007-12-12 13:38:48 +00:00
2009-06-23 15:34:59 +00:00
push @ { $ dsh_target_status { 'canceled' } } , $ user_target ;
}
2007-12-12 13:38:48 +00:00
}
2009-06-23 15:34:59 +00:00
@ { $ dsh_target_status { 'waiting' } } = ( ) ;
2007-12-12 13:38:48 +00:00
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2009-06-23 15:34:59 +00:00
"Command execution ended prematurely due to a previous unrecoverable error or stop request by the user." ;
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK ) ;
} #end fatal_error != 2
2007-12-12 13:38:48 +00:00
if ( $$ dsh_options { 'stats' } )
{
my @ empty_targets = ( ) ;
$ dsh_stats { 'successful-targets' } = $ dsh_target_status { 'finished' } ;
$ dsh_stats { 'failed-targets' } = $ dsh_target_status { 'failed' } ;
$ dsh_stats { 'canceled-targets' } = $ dsh_target_status { 'canceled' } ;
}
return ;
}
elsif ( $ dsh_exec_state == $ DSH_STATE_REMOTE_EXEC_COMPLETE )
{
if ( $$ dsh_options { 'stats' } )
{
$ dsh_stats { 'exec-state' } = $ dsh_exec_state ;
$ dsh_stats { 'end-time' } = localtime ( ) ;
}
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2008-02-18 15:57:25 +00:00
"Running the command stopped due to unrecoverable error or stop request by the user." ;
2012-06-07 13:00:05 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK ) ;
2007-12-12 13:38:48 +00:00
return ;
}
else
{
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2008-02-18 15:57:25 +00:00
"Running the command stopped due to unrecoverable error or stop request by the user." ;
2012-06-07 13:00:05 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK ) ;
2007-12-12 13:38:48 +00:00
exit ( 1 ) ;
}
}
#----------------------------------------------------------------------------
= head3
resolve_targets
Main target resolution routine . This routine calls calls all appropriate
target resolution routines to resolve target information in the
dsh command environment . Currently the routine delegates resolution to
resolve_nodes .
Arguments:
$ options - options hash table describing dsh configuration options
$ resolved_targets - hash table of resolved targets and target properties
$ unresolved_targets - hash table of unresolved targets and target properties
$ context_targets - hash table of targets grouped by context name
Returns:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Globals:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Error:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Example:
Comments:
= cut
#----------------------------------------------------------------------------
sub resolve_targets
{
my ( $ class , $ options , $ resolved_targets , $ unresolved_targets ,
$ context_targets )
= @ _ ;
$$ options { 'nodes' }
&& xCAT::DSHCLI - > resolve_nodes ( $ options , $ resolved_targets ,
$ unresolved_targets , $ context_targets ) ;
}
#----------------------------------------------------------------------------
= head3
resolve_nodes
For a given list of contexts and node names , build a list of
nodes defined and augment the list with context node information .
Arguments:
$ options - options hash table describing dsh configuration options
$ resolved_targets - hash table of resolved targets and target properties
$ unresolved_targets - hash table of unresolved targets and target properties
$ context_targets - hash table of targets grouped by context name
Returns:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Globals:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Error:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Example:
Comments:
= cut
#----------------------------------------------------------------------------
sub resolve_nodes
{
my ( $ class , $ options , $ resolved_targets , $ unresolved_targets ,
$ context_targets )
= @ _ ;
2008-10-17 16:04:13 +00:00
2007-12-12 13:38:48 +00:00
my @ node_list = ( ) ;
2008-10-17 16:04:13 +00:00
@ node_list = split ',' , $$ options { 'nodes' } ;
2007-12-12 13:38:48 +00:00
2008-07-18 12:02:22 +00:00
foreach my $ context_node ( @ node_list )
2007-12-12 13:38:48 +00:00
{
my ( $ context , $ node ) = split ':' , $ context_node ;
! $ node
&& ( ( $ node = $ context ) && ( $ context = $$ options { 'context' } ) ) ;
push @ { $ dsh_stats { 'specified-targets' } { $ context } { 'nodes' } } , $ node ;
}
xCAT::DSHCLI - > _resolve_nodes ( $ options , $ resolved_targets ,
$ unresolved_targets , $ context_targets ,
@ node_list ) ;
}
#----------------------------------------------------------------------------
= head3
_resolve_nodes
Wrapper routine for resolve_all_nodes , resolve_nodes and
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Arguments:
$ options - options hash table describing dsh configuration options
$ resolved_targets - hash table of resolved targets and target properties
$ unresolved_targets - hash table of unresolved targets and relevant properties
$ context_targets - hash table of targets grouped by context name
@ nodes - a list of nodes to resolve
Returns:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Globals:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Error:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Example:
Comments:
= cut
#----------------------------------------------------------------------------
sub _resolve_nodes
{
my ( $ class , $ options , $ resolved_targets , $ unresolved_targets ,
$ context_targets , @ nodes )
= @ _ ;
my % resolved_nodes = ( ) ;
my % unresolved_nodes = ( ) ;
2009-07-10 11:56:19 +00:00
# this build the resolved nodes hash
# bypasses the old dsh resolution code
# unresolved nodes will be determined when the remote shell runs
xCAT::DSHCLI - > bld_resolve_nodes_hash ( $ options , \ % resolved_nodes , @ nodes ) ;
2008-07-18 12:02:22 +00:00
foreach my $ user_node ( keys ( % resolved_nodes ) )
2007-12-12 13:38:48 +00:00
{
my $ node_properties = $ resolved_nodes { $ user_node } ;
$$ node_properties { 'type' } = 'node' ;
eval "require Context::$$node_properties{'context'}" ;
my $ result =
$$ node_properties { 'context' } - > resolve_node ( $ node_properties ) ;
$ result && ( $$ resolved_targets { $ user_node } = $ node_properties ) ;
}
}
2009-07-10 11:56:19 +00:00
#---------------------------------------------------------------------------
= head3
resolve_nodes_hash
Builds the resolved nodes hash .
2012-05-02 11:54:31 +00:00
Does not do much anymore because we removed address resolution from
xdsh and just let ssh do it . Stayed to preserve the logic of the old
code .
Does check if the Management Node is part of the node range and sets
localhost if it is . The MN must be defined in nodelist and with
nodetype . nodetype = mn .
2009-07-10 11:56:19 +00:00
Arguments:
$ options - options hash table describing dsh configuration options
$ resolved_targets - hash table of resolved properties , keyed by target name
@ target_list - input list of target names to resolve
Returns:
None
Globals:
None
Error:
None
Example:
Comments:
= cut
#---------------------------------------------------------------------------
sub bld_resolve_nodes_hash
{
my ( $ class , $ options , $ resolved_targets , @ target_list ) = @ _ ;
2012-05-02 11:54:31 +00:00
# find out if we have an MN in the list, local cp and sh will be used
# not remote shell
2012-10-22 19:07:53 +00:00
my $ mname = xCAT::Utils - > noderangecontainsMn ( @ target_list ) ;
2009-07-10 11:56:19 +00:00
foreach my $ target ( @ target_list )
{
my $ hostname = $ target ;
my $ ip_address ;
my $ localhost ;
my $ user ;
my $ context = "XCAT" ;
2012-10-22 19:07:53 +00:00
# check to see if this node is the Management Node
if ( $ mname ) {
if ( $ mname eq $ target ) {
$ localhost = $ target ;
}
2012-05-02 11:54:31 +00:00
}
2009-07-10 11:56:19 +00:00
my % properties = (
'hostname' = > $ hostname ,
'ip-address' = > $ ip_address ,
'localhost' = > $ localhost ,
'user' = > $ user ,
'context' = > $ context ,
'unresolved' = > $ target
) ;
$$ resolved_targets { "$target" } = \ % properties ;
}
}
2007-12-12 13:38:48 +00:00
#----------------------------------------------------------------------------
= head3
verify_targets
Executes a verification test for all targets across all
available contexts . If a target cannot be verified it is removed
from the $ resolved_targets list
Arguments:
$ options - options hash table describing dsh configuration options
$ resolved_targets - hash table of resolved targets and target properties
Returns:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Globals:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Error:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Example:
Comments:
= cut
#----------------------------------------------------------------------------
sub verify_targets
{
my ( $ class , $ options , $ resolved_targets ) = @ _ ;
2008-07-18 12:02:22 +00:00
my @ ping_list ;
foreach my $ user_target ( keys ( %$ resolved_targets ) )
2007-12-12 13:38:48 +00:00
{
2009-07-10 11:56:19 +00:00
my $ hostname = $$ resolved_targets { $ user_target } { 'hostname' } ;
push @ ping_list , $ hostname ;
2007-12-12 13:38:48 +00:00
}
if ( @ ping_list )
{
my @ no_response = ( ) ;
2008-10-17 16:04:13 +00:00
my $ rsp = { } ;
2007-12-12 13:38:48 +00:00
$ rsp - > { data } - > [ 0 ] =
2008-02-18 15:57:25 +00:00
"TRACE:Verifying remaining targets with pping command." ;
2007-12-12 13:38:48 +00:00
$ dsh_trace && xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
2007-12-19 16:03:56 +00:00
@ no_response = xCAT::DSHCore - > pping_hostnames ( @ ping_list ) ;
2007-12-12 13:38:48 +00:00
2008-07-18 12:02:22 +00:00
foreach my $ hostname ( @ no_response )
2007-12-12 13:38:48 +00:00
{
my @ targets = grep /$hostname/ , keys ( %$ resolved_targets ) ;
2008-07-18 12:02:22 +00:00
foreach my $ user_target ( @ targets )
2007-12-12 13:38:48 +00:00
{
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2008-02-18 15:57:25 +00:00
"$user_target is not responding. No command will be issued to this host." ;
2007-12-12 13:38:48 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK ) ;
2012-12-05 14:00:48 +00:00
# report error status --nodestatus
# Note the message below for node status must
2012-12-06 19:37:17 +00:00
# not be NLS translated. Code depends on the English.
2012-12-05 14:00:48 +00:00
if ( $$ options { 'nodestatus' } ) {
my $ rsp = { } ;
$ rsp - > { data } - > [ 0 ] =
"$user_target: Remote_command_failed" ;
xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
}
2007-12-12 13:38:48 +00:00
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2007-12-12 13:38:48 +00:00
"dsh> Remote_command_cancelled $user_target" ;
$$ dsh_options { 'monitor' }
2012-06-07 13:00:05 +00:00
&& xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK ) ;
2007-12-12 13:38:48 +00:00
push @ { $ dsh_target_status { 'canceled' } } , $ user_target ;
$$ dsh_unresolved_targets { $ user_target } =
$$ resolved_targets { $ user_target } ;
delete $$ resolved_targets { $ user_target } ;
}
}
}
}
#----------------------------------------------------------------------------
= head3
get_available_contexts
Returns a list of available contexts in the DSH environment
Arguments:
None
Returns:
A list of available contexts in the DSH environment
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Globals:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Error:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Example:
Comments:
= cut
#----------------------------------------------------------------------------
sub get_available_contexts
{
opendir ( DIR , $ ::CONTEXT_DIR ) ;
my @ contexts =
grep { ( $ _ ne '.' ) && ( $ _ ne '..' ) && ( $ _ =~ /\.pm$/ ) } readdir DIR ;
closedir DIR ;
chomp ( @ contexts ) ;
2008-07-18 12:02:22 +00:00
foreach my $ context ( @ contexts )
2007-12-12 13:38:48 +00:00
{
$ context =~ s/\.pm$// ;
push @ dsh_available_contexts , $ context ;
}
}
#----------------------------------------------------------------------------
= head3
get_dsh_config
Get the initial DSH configuration for all available contexts
Arguments:
None
Returns:
A hash table of configuration properties grouped by context
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Globals:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Error:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Example:
Comments:
= cut
#----------------------------------------------------------------------------
sub get_dsh_config
{
scalar ( @ dsh_valid_contexts ) || xCAT::DSHCLI - > get_valid_contexts ;
my % dsh_config = ( ) ;
2008-07-18 12:02:22 +00:00
foreach my $ context ( @ dsh_valid_contexts )
2007-12-12 13:38:48 +00:00
{
$ dsh_config { $ context } = $ context - > context_properties ;
}
return \ % dsh_config ;
}
#----------------------------------------------------------------------------
= head3
get_dsh_defaults
Get the default properties for all available contexts
Arguments:
None
Returns:
A hash table of default properties for each context
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Globals:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Error:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Example:
Comments:
= cut
#----------------------------------------------------------------------------
sub get_dsh_defaults
{
scalar ( @ dsh_valid_contexts ) || xCAT::DSHCLI - > get_valid_contexts ;
my % dsh_defaults = ( ) ;
2008-07-18 12:02:22 +00:00
foreach my $ context ( @ dsh_valid_contexts )
2007-12-12 13:38:48 +00:00
{
$ dsh_defaults { $ context } = $ context - > context_defaults ;
}
return \ % dsh_defaults ;
}
#----------------------------------------------------------------------------
= head3
get_valid_contexts
Returns a list of valid contexts in the DSH environment .
A valid context is one that is available in the DSH environment
and whose valid_context routine returns 1
Arguments:
None
Returns:
A list of valid contexts
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Globals:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Error:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Example:
Comments:
= cut
#----------------------------------------------------------------------------
sub get_valid_contexts
{
scalar ( @ dsh_available_contexts ) || xCAT::DSHCLI - > get_available_contexts ;
@ dsh_valid_contexts = ( ) ;
2008-07-18 12:02:22 +00:00
foreach my $ context ( @ dsh_available_contexts )
2007-12-12 13:38:48 +00:00
{
eval "require Context::$context" ;
( $ context - > valid_context ) && ( push @ dsh_valid_contexts , $ context ) ;
}
}
#----------------------------------------------------------------------------
= head3
util_bit_indexes
Utility routine that converts a bit vector to a corresponding array
of 1 s and 0 s
Arguments:
None
Returns:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Globals:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Error:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Example:
Comments:
= cut
#----------------------------------------------------------------------------
sub util_bit_indexes
{
my ( $ class , $ vector , $ bit ) = @ _ ;
my @ bit_indexes = ( ) ;
my @ bits = split ( // , unpack ( "b*" , $ vector ) ) ;
my $ index = 0 ;
while ( @ bits )
{
( ( shift @ bits ) == $ bit ) && ( push @ bit_indexes , $ index ) ;
$ index + + ;
}
return @ bit_indexes ;
}
#-------------------------------------------------------------------------------
= head3
check_valid_options
Arguments:
1 - % options
Returns:
1 - there are invalid options
0 - options are all okay
Globals:
none
Error:
none
Comments:
none
= cut
#--------------------------------------------------------------------------------
sub check_valid_options
{
my ( $ pkg , $ options ) = @ _ ;
if ( scalar ( @$ options ) > 0 )
{
my @ invalid_opts ;
my @ valid_longnames = (
"continue" , "execute" ,
"fanout" , "help" ,
"user" , "monitor" ,
"nodes" , "node-options" ,
"node-rsh" , "stream" ,
"timeout" , "verify" ,
"exit-status" , "context" ,
"environment" , "ignore-sig" ,
"ignoresig" , "no-locale" ,
"nodegroups" , "silent" ,
"syntax" , "trace" ,
"version" , "command-name" ,
"commandName" , "command-description" ,
"commandDescription" , "noFileWriting" ,
"preserve" , "node-rcp" ,
"pull" , "recursive"
) ;
foreach my $ opt ( @$ options )
{
my $ tmp_opt = $ opt ;
# remove any leading dash first
$ tmp_opt =~ s/^-*// ;
# if this is a long keyword...
if ( grep /^\Q$tmp_opt\E$/ , @ valid_longnames )
{
# there should be two leading dashs
if ( $ opt !~ /^--\w+/ )
{
push @ invalid_opts , $ opt ;
}
}
}
if ( @ invalid_opts )
{
2008-10-17 16:04:13 +00:00
my $ rsp = { } ;
2007-12-12 13:38:48 +00:00
my $ badopts = join ( ',' , @ invalid_opts ) ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] = "Invalid options: $badopts" ;
2009-06-09 14:38:30 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK , 1 ) ;
2009-06-05 15:45:25 +00:00
return ;
2007-12-12 13:38:48 +00:00
}
}
return 0 ;
}
#-------------------------------------------------------------------------------
2008-02-18 15:57:25 +00:00
= head3
2007-12-12 13:38:48 +00:00
ignoreEnv
Remove dsh environment variable .
Arguments:
envList: indicates the env vars that seperated by comma
Returns:
None
Globals:
@ dsh_valie_env
Error:
none
Example:
if ( defined $ options { 'ignore_env' } ) { xCAT::DSHCLI - > ignoreEnv ( $ options { 'ignore_env' } ) ; }
Comments:
none
= cut
#--------------------------------------------------------------------------------
sub ignoreEnv
{
my ( $ class , $ envList ) = @ _ ;
my @ env_not_valid = ( ) ;
my @ env_to_save = split ',' , $ envList ;
2008-07-18 12:02:22 +00:00
my $ env ;
for $ env ( @ env_to_save )
2007-12-12 13:38:48 +00:00
{
if ( ! grep /$env/ , @ dsh_valid_env )
{
push @ env_not_valid , $ env ;
}
}
if ( scalar @ env_not_valid > 0 )
{
$ env = join "," , @ env_not_valid ;
2008-10-17 16:04:13 +00:00
my $ rsp = { } ;
2012-12-11 13:49:24 +00:00
$ rsp - > { data } - > [ 0 ] = "Invalid Environment Variable: $env" ;
2012-12-06 19:37:17 +00:00
xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
2009-06-05 15:45:25 +00:00
return ;
2007-12-12 13:38:48 +00:00
}
2008-07-18 12:02:22 +00:00
for $ env ( @ dsh_valid_env )
2007-12-12 13:38:48 +00:00
{
if ( ! grep /$env/ , @ env_to_save )
{
delete $ ENV { $ env } ;
}
}
}
#--------------------------------------------------------------------------------
2008-02-18 15:57:25 +00:00
= head3
2007-12-12 13:38:48 +00:00
isFdNumExceed
check if file descriptor number exceed the max number in ulimit
Arguments:
$ node_fd: indicates the file descriptor number required by each nodes
$ node_num: indicates the target nodes number
$ fanout: indicates the fanout value
$ remain_fd: indicates the file descriptor number remained by main processes
Returns:
0 : file descriptor number does not exceed the max number
1 : file descriptor number exceed the max number
Globals:
None
Error:
None
Example:
xCAT::DSHCLI - > check_fd_num ( 2 , scalar ( keys ( % resolved_targets ) ) , $$ options { 'fanout' } )
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Comments:
none
= cut
#--------------------------------------------------------------------------------
sub isFdNumExceed
{
my ( $ class , $ node_fs , $ node_num , $ fanout ) = @ _ ;
# Check the file descriptor number
my $ ulimit_cmd ;
my $ ls_cmd ;
if ( $^O =~ /^linux$/i )
{
$ ulimit_cmd =
"/bin/bash -c \'ulimit -n\'" ; #ulimit is embedded in bash on linux
$ ls_cmd = '/bin/ls' ;
}
else
{
$ ulimit_cmd = '/usr/bin/ulimit -n' ; #On AIX
$ ls_cmd = '/usr/bin/ls' ;
}
my $ fdnum = xCAT::Utils - > runcmd ( $ ulimit_cmd ) ;
return 0 if ( $ fdnum =~ /\s*unlimited\s*/ ) ;
if ( $ fdnum !~ /\s*\d+\s*/ ) #this should never happen
{
2008-10-17 16:04:13 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] = "Unsupport ulimit return code!" ;
2009-06-09 14:38:30 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK , 1 ) ;
2009-06-05 15:45:25 +00:00
return ;
2007-12-12 13:38:48 +00:00
}
my $ pid = getpid ;
# print "pid is $pid\n";
#there are some pid will be remained by dsh main process, such STDIN, STDOUT and others,
#it can be different on different system. So need to check them everytime
my @ remain_fds = xCAT::Utils - > runcmd ( $ ls_cmd . " /proc/$pid/fd" ) ;
my $ remain_fd_num = scalar ( @ remain_fds ) ;
# print "remain fd num is $remain_fd_num\n";
# sleep 1000;
$ node_num = ( $ node_num < $ fanout ) ? $ node_num : $ fanout ;
my $ max_fd_req = $ node_fs * $ node_num ; #the max fd number required by nodes
if ( ( $ max_fd_req + $ remain_fd_num ) > $ fdnum )
{
2009-06-05 15:45:25 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] = "Reached fdnum= $fdnum" ;
2009-06-09 14:38:30 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK , 1 ) ;
2009-06-05 15:45:25 +00:00
return ;
2007-12-12 13:38:48 +00:00
}
else
{
return 0 ;
}
}
#-------------------------------------------------------------------------------
= head3
2008-02-18 15:57:25 +00:00
usage_dsh
2007-12-12 13:38:48 +00:00
puts out dsh usage message
Arguments:
2008-02-18 15:57:25 +00:00
None
2007-12-12 13:38:48 +00:00
Returns:
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Globals:
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Error:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
= cut
#-------------------------------------------------------------------------------
sub usage_dsh
{
## usage message
2009-05-18 14:41:21 +00:00
my $ usagemsg1 = " xdsh -h \n xdsh -q \n xdsh -V \n" ;
2009-10-16 11:45:16 +00:00
my $ usagemsg1a = "xdsh <noderange> [-K] [-l logonuserid]\n" ;
2009-08-27 16:30:08 +00:00
my $ usagemsg2 = " [ - B bypass ] [ - c ] [ - e ] [ - E environment_file ]
2009-05-18 14:41:21 +00:00
[ - - devicetype type_of_device ] [ - f fanout ] \ n " ;
2009-02-04 17:18:44 +00:00
my $ usagemsg3 = " [-l user_ID] [-L] " ;
2012-05-02 10:36:05 +00:00
my $ usagemsg4 = " [ - m ] [ - o options ] [ - q] [-Q] [ - r remote_shell ]
2010-09-02 13:25:43 +00:00
[ - i image ] [ - s ] [ - S ksh | csh ] [ - t timeout ] \ n " ;
2013-01-09 11:54:58 +00:00
my $ usagemsg5 = " [-T] [-X environment variables] [-v] [-z] [--sudo]\n" ;
2009-10-16 11:45:16 +00:00
my $ usagemsg6 = " <command_list>" ;
2009-02-04 17:18:44 +00:00
my $ usagemsg . = $ usagemsg1 . = $ usagemsg1a . = $ usagemsg2 . = $ usagemsg3 . =
2009-05-18 14:41:21 +00:00
$ usagemsg4 . = $ usagemsg5 . = $ usagemsg6 ;
2007-12-12 13:38:48 +00:00
### end usage mesage
if ( $ ::CALLBACK )
{
2008-10-17 16:04:13 +00:00
my $ rsp = { } ;
2007-12-12 13:38:48 +00:00
$ rsp - > { data } - > [ 0 ] = $ usagemsg ;
xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
}
else
{
2008-02-18 15:57:25 +00:00
xCAT::MsgUtils - > message ( "I" , $ usagemsg . "\n" ) ;
2007-12-12 13:38:48 +00:00
}
return ;
}
#-------------------------------------------------------------------------------
= head3
parse_and_run_dsh
This parses the dsh input build the call to execute_dsh .
Arguments:
$ nodes , $ args , $ callback , $ command , $ noderange
2008-02-18 15:57:25 +00:00
These may exist , called from xdsh plugin
2007-12-12 13:38:48 +00:00
Returns:
2008-02-18 15:57:25 +00:00
Errors if invalid options or the executed dsh command
2007-12-12 13:38:48 +00:00
Globals:
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Error:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Example:
Comments:
= cut
#-------------------------------------------------------------------------------
sub parse_and_run_dsh
{
my ( $ class , $ nodes , $ args , $ callback , $ command , $ noderange ) = @ _ ;
$ ::CALLBACK = $ callback ;
2009-02-04 17:18:44 +00:00
if ( ! ( $ args ) )
{
2008-11-04 15:10:20 +00:00
usage_dsh ;
2009-06-05 15:45:25 +00:00
return ;
2008-11-04 15:10:20 +00:00
}
2009-02-04 17:18:44 +00:00
@ ARGV = @ { $ args } ; # get arguments
2007-12-20 19:02:17 +00:00
if ( $ ENV { 'XCATROOT' } )
{
2008-02-01 13:03:04 +00:00
$ ::XCATROOT = $ ENV { 'XCATROOT' } ; # setup xcatroot home directory
2007-12-20 19:02:17 +00:00
}
2008-02-01 13:03:04 +00:00
elsif ( - d '/opt/xcat' )
{
$ ::XCATROOT = "/opt/xcat" ;
}
else
{
$ ::XCATROOT = "/usr" ;
}
2007-12-12 13:38:48 +00:00
# parse the arguments
Getopt::Long:: Configure ( "posix_default" ) ;
Getopt::Long:: Configure ( "no_gnu_compat" ) ;
Getopt::Long:: Configure ( "bundling" ) ;
my % options = ( ) ;
# check for wrong long options
if ( xCAT::DSHCLI - > check_valid_options ( \ @ ARGV ) )
{
usage_dsh ;
2009-06-05 15:45:25 +00:00
return 1 ;
2007-12-12 13:38:48 +00:00
}
if (
! GetOptions (
2009-02-04 17:18:44 +00:00
'e|execute' = > \ $ options { 'execute' } ,
'f|fanout=i' = > \ $ options { 'fanout' } ,
'h|help' = > \ $ options { 'help' } ,
'l|user=s' = > \ $ options { 'user' } ,
'm|monitor' = > \ $ options { 'monitor' } ,
'o|node-options=s' = > \ $ options { 'node-options' } ,
'q|show-config' = > \ $ options { 'show-config' } ,
'r|node-rsh=s' = > \ $ options { 'node-rsh' } ,
'i|rootimg=s' = > \ $ options { 'rootimg' } ,
's|stream' = > \ $ options { 'streaming' } ,
't|timeout=i' = > \ $ options { 'timeout' } ,
'v|verify' = > \ $ options { 'verify' } ,
'z|exit-status' = > \ $ options { 'exit-status' } ,
2007-12-12 13:38:48 +00:00
'B|bypass' = > \ $ options { 'bypass' } ,
2009-12-04 15:00:26 +00:00
'c|cleanup' = > \ $ options { 'cleanup' } ,
2007-12-12 13:38:48 +00:00
'E|environment=s' = > \ $ options { 'environment' } ,
'I|ignore-sig|ignoresig=s' = > \ $ options { 'ignore-signal' } ,
2007-12-20 19:02:17 +00:00
'K|keysetup' = > \ $ options { 'ssh-setup' } ,
2007-12-12 13:38:48 +00:00
'L|no-locale' = > \ $ options { 'no-locale' } ,
'Q|silent' = > \ $ options { 'silent' } ,
'S|syntax=s' = > \ $ options { 'syntax' } ,
'T|trace' = > \ $ options { 'trace' } ,
'V|version' = > \ $ options { 'version' } ,
2009-02-04 17:18:44 +00:00
'devicetype|devicetype=s' = > \ $ options { 'devicetype' } ,
2012-10-17 17:21:43 +00:00
'nodestatus|nodestatus' = > \ $ options { 'nodestatus' } ,
2013-01-09 11:54:58 +00:00
'sudo|sudo' = > \ $ options { 'sudo' } ,
2007-12-12 13:38:48 +00:00
'command-name|commandName=s' = > \ $ options { 'command-name' } ,
'command-description|commandDescription=s' = >
\ $ options { 'command-description' } ,
'X:s' = > \ $ options { 'ignore_env' }
)
)
{
2008-10-17 16:04:13 +00:00
xCAT::DSHCLI - > usage_dsh ;
2008-10-28 15:32:58 +00:00
return 1 ;
2007-12-12 13:38:48 +00:00
}
if ( $ options { 'help' } )
{
2008-10-17 16:04:13 +00:00
xCAT::DSHCLI - > usage_dsh ;
2008-10-28 15:32:58 +00:00
return 0 ;
2007-12-12 13:38:48 +00:00
}
2012-05-01 15:54:17 +00:00
2007-12-12 13:38:48 +00:00
if ( $ options { 'show-config' } )
{
xCAT::DSHCLI - > show_dsh_config ;
2009-06-05 15:45:25 +00:00
return 0 ;
2007-12-12 13:38:48 +00:00
}
2009-05-18 14:41:21 +00:00
my $ remotecommand = $ options { 'node-rsh' } ;
2007-12-12 13:38:48 +00:00
if ( $ options { 'node-rsh' }
&& ( ! - f $ options { 'node-rsh' } || ! - x $ options { 'node-rsh' } ) )
{
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2009-05-18 14:41:21 +00:00
"Remote command: $remotecommand does not exist or is not executable." ;
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK ) ;
2009-06-05 15:45:25 +00:00
return ;
2009-05-18 14:41:21 +00:00
}
# put rsync on a dsh command
if ( $ options { 'node-rsh' }
&& ( grep /rsync/ , $ options { 'node-rsh' } ) )
{
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2009-05-18 14:41:21 +00:00
"Remote command: $remotecommand should be used with the dcp command. " ;
2007-12-12 13:38:48 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK ) ;
2009-06-05 15:45:25 +00:00
return ;
2007-12-12 13:38:48 +00:00
}
if ( defined $ options { 'ignore_env' } )
{
xCAT::DSHCLI - > ignoreEnv ( $ options { 'ignore_env' } ) ;
}
2009-04-03 15:42:59 +00:00
# this was determined in the xdsh client code, because non-root user
2009-04-20 13:08:25 +00:00
# actions must be taken there. For those calling xdsh plugin, default
# is root
2012-12-11 13:49:24 +00:00
if ( ! ( $ ENV { 'DSH_TO_USERID' } ) ) # env first
2009-04-03 15:42:59 +00:00
{
2012-12-11 13:49:24 +00:00
if ( ! ( $ options { 'user' } ) ) { # -l second
$ options { 'user' } = "root" ; # default
}
2009-04-03 15:42:59 +00:00
}
else
{
$ options { 'user' } = $ ENV { 'DSH_TO_USERID' } ;
}
2012-05-02 10:36:05 +00:00
if ( ( ! ( defined ( @$ nodes ) ) ) && ( ! ( defined ( $ options { 'rootimg' } ) ) ) )
{ # no nodes and not -i option, error
2009-05-18 14:41:21 +00:00
my $ rsp = ( ) ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] = "Unless using -i option, noderange is required." ;
2009-05-18 14:41:21 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK , 1 ) ;
return ;
}
2011-10-11 16:16:27 +00:00
# Determine switch type, processing Mellanox not the same as QLogic
my $ switchtype = $ options { 'devicetype' } ;
$ switchtype =~ s/::/\//g ;
2009-05-18 14:41:21 +00:00
2007-12-12 13:38:48 +00:00
#
# build list of nodes
2008-10-17 16:04:13 +00:00
my @ nodelist ;
my $ imagename ;
if ( defined ( $ options { 'rootimg' } ) )
{ # running against local host
# diskless image
2010-09-02 13:17:24 +00:00
# need directory for Linux, just osimage name for AIX
if ( xCAT::Utils - > isLinux ( ) ) {
if ( ! ( - e ( $ options { 'rootimg' } ) ) )
{ # directory does not exist
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2008-10-17 16:04:13 +00:00
"Input image directory $options{'rootimg'} does not exist." ;
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK , 1 ) ;
return ;
2010-09-02 13:17:24 +00:00
}
2008-10-17 16:04:13 +00:00
}
2007-12-12 13:38:48 +00:00
2008-10-17 16:04:13 +00:00
# since we have no input nodes for running xdsh against the image
2009-06-09 14:38:30 +00:00
# we will use the create the hostname from the directory
2008-10-17 16:04:13 +00:00
# for the hostname in the output
my $ path = $ options { 'rootimg' } ;
2009-02-04 17:18:44 +00:00
$ imagename = xCAT::Utils - > get_image_name ( $ path ) ;
if ( @$ nodes [ 0 ] eq "NO_NODE_RANGE" )
{ # from sinv, discard this name
2008-10-28 15:32:58 +00:00
undef @$ nodes ;
}
2008-10-17 16:04:13 +00:00
if ( defined ( @$ nodes ) )
{
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2008-10-28 15:32:58 +00:00
"Input noderange:@$nodes and any other xdsh flags or environment variables are not valid with -i flag." ;
2009-02-04 17:18:44 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK , 1 ) ;
2008-10-28 15:32:58 +00:00
return ;
2008-10-17 16:04:13 +00:00
}
}
else
{
@ nodelist = @$ nodes ;
$ options { 'nodes' } = join ( ',' , @ nodelist ) ;
}
#printf " node list is $options{'nodes'}";
2007-12-12 13:38:48 +00:00
# build arguments
2010-06-24 16:41:08 +00:00
2011-10-11 16:16:27 +00:00
# get the actual xdsh command from the argument list
2007-12-12 13:38:48 +00:00
$ options { 'command' } = join ' ' , @ ARGV ;
2011-10-11 16:16:27 +00:00
2007-12-12 13:38:48 +00:00
2011-10-11 16:16:27 +00:00
# if a Mellanox switch command we have to build
# the command xdsh will send special
# input will look something like this
# xdsh mswitch -l admin --devicetype IBSwitch::Mellanox
# enable;configure terminal;show ssh server host-keys
# We will build
# ssh admin@mswitch cli
2011-10-15 10:10:04 +00:00
# "enable" "configure terminal" "show ssh server host-keys"
2011-10-11 16:16:27 +00:00
my @ melcmds ;
if ( $ switchtype =~ /Mellanox/i ) {
2011-10-11 16:37:51 +00:00
$ ::DSH_MELLANOX_SWITCH = 1 ;
2011-10-11 16:16:27 +00:00
@ melcmds = split ( /;/ , $ options { 'command' } ) ;
my $ newcmd ;
foreach my $ cmd ( @ melcmds ) {
$ newcmd . = "\"" ;
$ newcmd . = $ cmd ;
$ newcmd . = "\" " ;
}
$ options { 'command' } = $ newcmd ;
2011-10-11 16:37:51 +00:00
} else {
$ ::DSH_MELLANOX_SWITCH = 0 ;
2011-10-11 16:16:27 +00:00
}
2009-04-03 15:42:59 +00:00
#
2007-12-20 19:02:17 +00:00
# -K option just sets up the ssh keys on the nodes and exits
2009-04-03 15:42:59 +00:00
#
2007-12-20 19:02:17 +00:00
if ( defined $ options { 'ssh-setup' } )
{
2012-06-26 14:39:56 +00:00
# check if any node in the noderange is the Management Node and exit
# with error, if the Management Node is in the Database and in the
# noderange
2012-08-07 14:57:31 +00:00
my $ mname = xCAT::Utils - > noderangecontainsMn ( @ nodelist ) ;
if ( $ mname ) { # MN in the nodelist
2012-06-26 14:39:56 +00:00
my $ rsp = { } ;
$ rsp - > { error } - > [ 0 ] =
"You must not run -K option against the Management Node:$mname." ;
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK , 1 ) ;
return ;
}
2011-10-11 16:16:27 +00:00
# if devicetype=Mellanox, xdsh does not setup ssh, rspconfig does
if ( $ switchtype =~ /Mellanox/i ) {
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2011-10-11 16:16:27 +00:00
"You do not use xdsh -K to setup the Mellanox switch ssh keys. Use rspconfig. See man page for rspconfig option sshcfg={enable|disable}." ;
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK , 1 ) ;
return ;
}
2008-10-17 16:04:13 +00:00
if ( defined $ options { 'rootimg' } )
{
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] = "Cannot use -R and -K flag together" ;
2008-10-17 16:04:13 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK , 1 ) ;
return ;
}
2009-02-04 17:18:44 +00:00
2009-04-05 12:18:17 +00:00
# IF using the xdsh -K -l option then we are setting up the
# --devicetype. xdsh -K -l is not allowed for users.
# This is checked for in the client code.
2009-02-04 17:18:44 +00:00
# DSH_REMOTE_PASSWORD env variable must be set to the correct
# password for the key update. This was setup in xdsh client
2011-10-17 13:19:25 +00:00
# frontend.
2009-02-04 17:18:44 +00:00
if ( ! ( $ ENV { 'DSH_REMOTE_PASSWORD' } ) )
{
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2010-09-28 02:47:19 +00:00
"User password for ssh key exchange has not been supplied.\n Cannot complete the -K command\n" ;
2009-02-04 17:18:44 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK , 1 ) ;
return ;
}
2009-02-06 12:52:36 +00:00
if ( ! ( $ ENV { 'DSH_FROM_USERID' } ) )
2009-02-04 17:18:44 +00:00
{
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2010-09-28 02:47:19 +00:00
"Current Userid has not been supplied.\n Cannot complete the -K command.\n" ;
2009-02-04 17:18:44 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK , 1 ) ;
return ;
}
2009-04-03 15:42:59 +00:00
if ( ! ( $ ENV { 'DSH_TO_USERID' } ) ) # id to logon to the node and update the
# keys
2009-02-04 17:18:44 +00:00
{
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2010-09-28 02:47:19 +00:00
"Logon Userid has not been supplied.\n Cannot complete the -K command.\n" ;
2009-02-06 12:52:36 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK , 1 ) ;
return ;
}
my $ current_userid = $ ENV { 'DSH_FROM_USERID' } ;
2009-04-03 15:42:59 +00:00
my $ to_userid = $ ENV { 'DSH_TO_USERID' } ;
2009-02-06 12:52:36 +00:00
# if current_userid ne touserid then current_userid
# must be root
if ( ( $ current_userid ne $ to_userid )
2009-04-03 15:42:59 +00:00
&& ( $ current_userid ne "root" ) )
2009-02-06 12:52:36 +00:00
{
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
"When touserid:$to_userid is not the same as the current user:$current_userid. The command must be run by root id." ;
2009-04-03 15:42:59 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK , 1 ) ;
return ;
2009-02-04 17:18:44 +00:00
}
# setting up IB switch ssh, different interface that ssh for
# userid on node. Must build special ssh command to be sent
# to the IB switch to setup ssh
if ( defined $ options { 'devicetype' } )
2008-10-17 16:04:13 +00:00
{
2009-02-04 17:18:44 +00:00
$ ENV { 'DEVICETYPE' } = $ options { 'devicetype' } ;
2012-11-16 17:21:35 +00:00
my $ devicename = $ options { 'devicetype' } ;
$ devicename =~ s/::/\//g ;
my $ devicepath = "/var/opt/xcat/" . $ devicename . "/config" ;
# go to backup directory if the config file
# cannot be found under /var/opt/xcat/...
if ( ! - e $ devicepath ) {
$ devicepath = "$::XCATROOT/share/xcat/devicetype/" . $ devicename . "/config" ;
}
if ( - e $ devicepath )
2009-01-08 12:57:02 +00:00
{
2009-02-04 17:18:44 +00:00
my $ deviceconf = get_config ( $ devicepath ) ;
# Get ssh-setup-command attribute from configuration
$ ENV { 'SSH_SETUP_COMMAND' } =
$$ deviceconf { 'main' } { 'ssh-setup-command' } ;
2009-01-08 12:57:02 +00:00
}
2008-10-17 16:04:13 +00:00
}
2009-02-04 17:18:44 +00:00
#
# setup ssh keys on the nodes or ib switch
#
2012-08-09 03:48:50 +00:00
my $ rc = xCAT::TableUtils - > setupSSH ( $ options { 'nodes' } ) ;
2009-02-04 17:18:44 +00:00
my @ results = "return code = $rc" ;
return ( @ results ) ;
2007-12-20 19:02:17 +00:00
}
2008-02-01 13:28:13 +00:00
if ( ! ( @ ARGV ) )
{ # no args , an error
2009-05-18 14:41:21 +00:00
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] = "No command argument provided" ;
2008-02-18 15:57:25 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK , 1 ) ;
2008-02-01 13:28:13 +00:00
return ;
}
2008-10-17 16:04:13 +00:00
my @ results ;
if ( defined $ options { 'rootimg' } )
{
@ results = xCAT::DSHCLI - > runlocal_on_rootimg ( \ % options , $ imagename ) ;
if ( $ ::RUNCMD_RC )
{ # error from dsh
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] = "Error from xdsh. Return Code = $::RUNCMD_RC" ;
2008-10-17 16:04:13 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK , 1 ) ;
2007-12-20 19:02:17 +00:00
2008-10-17 16:04:13 +00:00
}
}
2012-05-02 10:36:05 +00:00
else
2008-10-17 16:04:13 +00:00
{
2012-05-02 10:36:05 +00:00
#
# Execute the dsh api
#@results = xCAT::DSHCLI->runDsh_api(\%options, 0);
#if ($::RUNCMD_RC)
#{ # error from dsh
2012-06-07 13:00:05 +00:00
# $rsp->{error}->[0] = "Error from xdsh. Return Code = $::RUNCMD_RC";
2012-05-02 10:36:05 +00:00
# xCAT::MsgUtils->message("E", $rsp, $::CALLBACK, 1);
#}
# Execute the dsh command
2009-11-10 15:55:59 +00:00
# number of nodes failed becomes the xdsh return code
2012-05-02 10:36:05 +00:00
$ ::FAILED_NODES = xCAT::DSHCLI - > execute_dsh ( \ % options ) ;
2007-12-12 13:38:48 +00:00
}
return ( @ results ) ;
}
#-------------------------------------------------------------------------------
= head3
2008-02-18 15:57:25 +00:00
usage_dcp
2007-12-12 13:38:48 +00:00
puts out dcp usage message
Arguments:
2008-02-18 15:57:25 +00:00
None
2007-12-12 13:38:48 +00:00
Returns:
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Globals:
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Error:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
= cut
#-------------------------------------------------------------------------------
sub usage_dcp
{
### usage message
2009-10-16 11:45:16 +00:00
my $ usagemsg1 = " xdcp -h \n xdcp -q\n xdcp -V \n xdcp <noderange>\n" ;
2013-02-28 20:35:42 +00:00
my $ usagemsg2 = " [-B bypass] [-c] [-f fanout] [-l user_ID] [--sudo]\n" ;
2007-12-12 13:38:48 +00:00
my $ usagemsg3 =
2012-10-17 11:29:49 +00:00
" [-m] [-o options] [-p] [-P] [-q] [-Q] [-r node_remote_copy]\n" ;
2007-12-12 13:38:48 +00:00
my $ usagemsg4 =
" [-R] [-t timeout] [-T] [-X environment variables] [-v] \n" ;
2009-12-04 14:50:33 +00:00
my $ usagemsg5 = " source_file... target_path\n" ;
my $ usagemsg5a = " xdcp <noderange> [-s] -F <rsyncfile> " ;
my $ usagemsg5b = "[-f fanout] [-t timeout] [-o options] [-v]\n" ;
my $ usagemsg5c = " xdcp <-i imagepath> -F <rsyncfile> " ;
my $ usagemsg5d = "[-o options]" ;
2009-05-18 14:41:21 +00:00
2007-12-12 13:38:48 +00:00
my $ usagemsg . = $ usagemsg1 . = $ usagemsg2 . = $ usagemsg3 . = $ usagemsg4 . =
2009-12-04 14:50:33 +00:00
$ usagemsg5 . = $ usagemsg5a . = $ usagemsg5b . = $ usagemsg5c . = $ usagemsg5d ;
2007-12-12 13:38:48 +00:00
if ( $ ::CALLBACK )
{
2008-10-17 16:04:13 +00:00
my $ rsp = { } ;
2007-12-12 13:38:48 +00:00
$ rsp - > { data } - > [ 0 ] = $ usagemsg ;
xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
}
else
{
2008-02-18 15:57:25 +00:00
xCAT::MsgUtils - > message ( "I" , $ usagemsg . "\n" ) ;
2007-12-12 13:38:48 +00:00
}
return ;
}
#-------------------------------------------------------------------------------
= head3
parse_and_run_dcp
This parses the dcp input build the call to execute_dcp .
Arguments:
$ nodes , $ args , $ callback , $ command , $ noderange
2008-02-18 15:57:25 +00:00
These may exist , called from xdsh plugin
2007-12-12 13:38:48 +00:00
Returns:
2008-02-18 15:57:25 +00:00
Errors if invalid options or the executed dcp command
2007-12-12 13:38:48 +00:00
Globals:
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Error:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Example:
Comments:
= cut
#-------------------------------------------------------------------------------
sub parse_and_run_dcp
{
my ( $ class , $ nodes , $ args , $ callback , $ command , $ noderange ) = @ _ ;
$ ::CALLBACK = $ callback ;
2009-02-04 17:18:44 +00:00
if ( ! ( $ args ) )
{
2008-11-04 15:10:20 +00:00
usage_dcp ;
2009-06-05 15:45:25 +00:00
return 1 ;
2008-11-04 15:10:20 +00:00
}
2009-02-04 17:18:44 +00:00
@ ARGV = @ { $ args } ; # get arguments
2007-12-20 19:02:17 +00:00
if ( $ ENV { 'XCATROOT' } )
{
2008-02-01 13:03:04 +00:00
$ ::XCATROOT = $ ENV { 'XCATROOT' } ; # setup xcatroot home directory
}
else
{
$ ::XCATROOT = "/opt/xcat" ;
2007-12-20 19:02:17 +00:00
}
2008-02-01 13:03:04 +00:00
2007-12-12 13:38:48 +00:00
# parse the arguments
Getopt::Long:: Configure ( "posix_default" ) ;
Getopt::Long:: Configure ( "no_gnu_compat" ) ;
Getopt::Long:: Configure ( "bundling" ) ;
my % options = ( ) ;
# check for wrong long options
if ( xCAT::DSHCLI - > check_valid_options ( \ @ ARGV ) )
{
usage_dcp ;
2009-06-05 15:45:25 +00:00
return 1 ;
2007-12-12 13:38:48 +00:00
}
if (
! GetOptions (
'f|fanout=i' = > \ $ options { 'fanout' } ,
2009-05-18 14:41:21 +00:00
'F|File=s' = > \ $ options { 'File' } ,
2007-12-12 13:38:48 +00:00
'h|help' = > \ $ options { 'help' } ,
'l|user=s' = > \ $ options { 'user' } ,
2012-10-17 11:29:49 +00:00
'm|monitor' = > \ $ options { 'monitor' } ,
2007-12-12 13:38:48 +00:00
'o|node-options=s' = > \ $ options { 'node-options' } ,
'q|show-config' = > \ $ options { 'show-config' } ,
'p|preserve' = > \ $ options { 'preserve' } ,
'r|c|node-rcp=s' = > \ $ options { 'node-rcp' } ,
2009-05-18 14:41:21 +00:00
'i|rootimg=s' = > \ $ options { 'rootimg' } ,
's' = > \ $ options { 'rsyncSN' } ,
2007-12-12 13:38:48 +00:00
't|timeout=i' = > \ $ options { 'timeout' } ,
'v|verify' = > \ $ options { 'verify' } ,
'B|bypass' = > \ $ options { 'bypass' } ,
'Q|silent' = > \ $ options { 'silent' } ,
'P|pull' = > \ $ options { 'pull' } ,
'R|recursive' = > \ $ options { 'recursive' } ,
'T|trace' = > \ $ options { 'trace' } ,
'V|version' = > \ $ options { 'version' } ,
2009-01-08 12:57:02 +00:00
'devicetype=s' = > \ $ options { 'devicetype' } ,
2013-02-28 20:35:42 +00:00
'nodestatus|nodestatus' = > \ $ options { 'nodestatus' } ,
'sudo|sudo' = > \ $ options { 'sudo' } ,
2007-12-12 13:38:48 +00:00
'X:s' = > \ $ options { 'ignore_env' }
)
)
{
usage_dcp ;
2009-06-09 14:38:30 +00:00
return ( 1 ) ;
2007-12-12 13:38:48 +00:00
}
2008-10-17 16:04:13 +00:00
my $ rsp = { } ;
2007-12-12 13:38:48 +00:00
if ( $ options { 'help' } )
{
usage_dcp ;
2009-06-09 14:38:30 +00:00
return ( 0 ) ;
2007-12-12 13:38:48 +00:00
}
if ( $ options { 'show-config' } )
{
xCAT::DSHCLI - > show_dsh_config ;
2009-06-05 15:45:25 +00:00
return 0 ;
2007-12-12 13:38:48 +00:00
}
2009-07-22 13:34:55 +00:00
if ( defined ( $ options { 'rootimg' } ) )
{
if ( xCAT::Utils - > isAIX ( ) )
{
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] = "The -i option is not supported on AIX." ;
2009-07-22 13:34:55 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK , 1 ) ;
return ;
}
2009-07-10 14:18:46 +00:00
}
2012-05-02 10:36:05 +00:00
if ( ( ! ( defined ( @$ nodes ) ) ) && ( ! ( defined ( $ options { 'rootimg' } ) ) ) )
{ # no nodes and not -i option, error
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] = "Unless using -i option, noderange is required." ;
2009-05-18 14:41:21 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK , 1 ) ;
return ;
}
2007-12-12 13:38:48 +00:00
if ( $ options { 'version' } )
{
2008-07-07 19:04:37 +00:00
my $ version = xCAT::Utils - > Version ( ) ;
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2008-07-07 19:04:37 +00:00
$ rsp - > { data } - > [ 0 ] = "$version" ;
2007-12-12 13:38:48 +00:00
xCAT::MsgUtils - > message ( "I" , $ rsp , $ ::CALLBACK ) ;
2009-06-09 14:38:30 +00:00
return ( 0 ) ;
2007-12-12 13:38:48 +00:00
}
if ( defined $ options { 'ignore_env' } )
{
xCAT::DSHCLI - > ignoreEnv ( $ options { 'ignore_env' } ) ;
}
2009-05-18 14:41:21 +00:00
if ( defined ( $ options { 'rootimg' } ) )
{ # running against local host
# diskless image
2007-12-12 13:38:48 +00:00
2009-05-18 14:41:21 +00:00
if ( ! ( - e ( $ options { 'rootimg' } ) ) )
{ # directory does not exist
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2009-05-18 14:41:21 +00:00
"Input image directory $options{'rootimg'} does not exist." ;
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK , 1 ) ;
return ;
}
if ( ! ( $ options { 'File' } ) )
{ # File not given
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2009-05-18 14:41:21 +00:00
"If -i option is use, then the -F option must input the file list.\nThe file will contain the list of files to rsync to the image." ;
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK , 1 ) ;
return ;
}
}
# invalid to put the -F with the -r flag
if ( $ options { 'File' } && $ options { 'node-rcp' } )
{
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2009-05-18 14:41:21 +00:00
"If -F option is use, then -r is invalid. The command will always the rsync using ssh." ;
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK , 1 ) ;
return ;
}
# invalid to put the -s without the -F flag
if ( ! ( $ options { 'File' } ) && $ options { 'rsyncSN' } )
{
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2009-05-18 14:41:21 +00:00
"If -s option is use, then -F must point to the syncfile." ;
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK , 1 ) ;
return ;
}
2007-12-12 13:38:48 +00:00
2009-05-18 14:41:21 +00:00
# -s chosen or -F set rsync path
2009-06-23 15:34:59 +00:00
if ( $ options { 'rsyncSN' } || $ options { 'File' } )
{
if ( $^O eq 'aix' )
{
2009-07-10 11:56:19 +00:00
if ( - e ( "/usr/bin/rsync" ) )
{
$ options { 'node-rcp' } = '/usr/bin/rsync' ;
}
else
{
$ options { 'node-rcp' } = '/usr/local/bin/rsync' ;
2009-07-04 12:35:42 +00:00
}
2009-07-10 11:56:19 +00:00
2009-06-23 15:34:59 +00:00
}
elsif ( $^O eq 'linux' )
{
$ options { 'node-rcp' } = '/usr/bin/rsync' ;
}
2009-06-19 08:32:47 +00:00
}
2009-05-18 14:41:21 +00:00
my $ remotecopycommand = $ options { 'node-rcp' } ;
2007-12-12 13:38:48 +00:00
if ( $ options { 'node-rcp' }
&& ( ! - f $ options { 'node-rcp' } || ! - x $ options { 'node-rcp' } ) )
2012-06-15 15:42:45 +00:00
{
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] =
2009-05-18 14:41:21 +00:00
"Remote command: $remotecopycommand does not exist or is not executable." ;
2008-02-18 15:57:25 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK , 1 ) ;
2009-06-05 15:45:25 +00:00
return ;
2007-12-12 13:38:48 +00:00
}
2009-05-18 14:41:21 +00:00
#
# build list of nodes
my @ nodelist ;
if ( defined ( @$ nodes ) )
{ # there are nodes
@ nodelist = @$ nodes ;
$ options { 'nodes' } = join ( ',' , @ nodelist ) ;
2007-12-12 13:38:48 +00:00
}
else
2009-05-18 14:41:21 +00:00
{
2009-06-09 14:38:30 +00:00
if ( ! ( $ options { 'rootimg' } ) )
{
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] = "Noderange missing in command input." ;
2009-06-09 14:38:30 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK , 1 ) ;
return ;
}
2009-05-18 14:41:21 +00:00
}
#
# if -F flag then we are going to process the file and use
# rsync to distribute the files listed in the input file
# Format of the file lines are the following, follows the rsync syntax
# /.../file /..../file2 -> /..../directory
# /....file* /...../sample* -> /..../directory
#
my @ results ;
2009-06-29 13:36:18 +00:00
$ ::SYNCSN = 0 ;
2009-06-09 14:38:30 +00:00
# if updating an install image
# only going to run rsync locally
if ( ( $ options { 'File' } ) && ( $ options { 'rootimg' } ) )
{
my $ image = $ options { 'rootimg' } ;
my $ rc = & rsync_to_image ( $ options { 'File' } , $ image ) ;
if ( $ rc != 0 )
{ # error from dcp
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] = "Error running rsync to image:$image." ;
2009-06-09 14:38:30 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK , 1 ) ;
}
return ;
}
2011-01-18 15:40:18 +00:00
my $ synfiledir ;
2012-06-07 13:00:05 +00:00
my $ nodesyncfiledir ;
2012-06-19 17:30:35 +00:00
# set default sync dir on service node and node
# right now setting the nodes and sn syncfiledir the same, leaving
# the possibility that one day we may want them to be different
$ synfiledir = "/var/xcat/syncfiles" ;
$ nodesyncfiledir = "/var/xcat/node/syncfiles" ;
# get the directory on the servicenode to put the rsync files in
2012-08-09 03:48:50 +00:00
my @ syndir = xCAT::TableUtils - > get_site_attribute ( "SNsyncfiledir" ) ;
2012-06-19 17:30:35 +00:00
if ( $ syndir [ 0 ] )
{
$ synfiledir = $ syndir [ 0 ] ;
}
# get the directory on the node to put the rsync files in
2012-08-09 03:48:50 +00:00
my @ syndir = xCAT::TableUtils - > get_site_attribute ( "nodesyncfiledir" ) ;
2012-06-19 17:30:35 +00:00
if ( $ syndir [ 0 ] )
{
$ nodesyncfiledir = $ syndir [ 0 ] ;
}
my $ rc ;
2012-08-02 16:23:08 +00:00
my $ syncfile ;
if ( $ options { 'File' } ) {
$ syncfile = $ options { 'File' } ;
if ( ! - f $ options { 'File' } )
{
2012-08-01 13:29:12 +00:00
my $ rsp = ( ) ;
2012-12-11 13:49:24 +00:00
$ rsp - > { error } - > [ 0 ] = "File:$syncfile does not exist." ;
2012-08-01 13:29:12 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK , 1 ) ;
return ;
2012-08-02 16:23:08 +00:00
}
2012-08-01 13:29:12 +00:00
}
2009-06-25 18:17:19 +00:00
# if rsyncing the nodes or service nodes
2012-06-15 15:42:45 +00:00
2009-05-18 14:41:21 +00:00
if ( $ options { 'File' } )
{
2009-06-25 18:17:19 +00:00
# if syncing a service node
if ( $ options { 'rsyncSN' } )
{
2009-06-29 13:36:18 +00:00
$ ::SYNCSN = 1 ;
2009-06-25 18:17:19 +00:00
}
2011-01-18 15:40:18 +00:00
# the parsing of the file will fill in an array of postscripts
# need to be run if the associated file is updated
@ ::postscripts = ( ) ;
2012-04-27 11:26:51 +00:00
@ ::alwayspostscripts = ( ) ;
2012-06-15 15:42:45 +00:00
@ ::appendlines = ( ) ;
2012-07-27 18:20:08 +00:00
@ ::mergelines = ( ) ;
2009-06-25 18:17:19 +00:00
if ( xCAT::Utils - > isServiceNode ( ) )
{ # running on service node
$ rc =
& parse_rsync_input_file_on_SN ( \ @ nodelist , \ % options , $ syncfile ,
2012-06-07 13:00:05 +00:00
$ synfiledir , $ nodesyncfiledir ) ;
2009-06-25 18:17:19 +00:00
}
else
{ # running on MN
$ rc =
& parse_rsync_input_file_on_MN ( \ @ nodelist , \ % options , $ syncfile ,
2012-08-01 13:29:12 +00:00
$ ::SYNCSN , $ synfiledir , $ nodesyncfiledir ) ;
# build a temporary syncfile for the node's synclist
2012-08-02 16:23:08 +00:00
if ( $ ::SYNCSN == 1 ) { # syncing a servicenode
# we need to make sure the latest is on the servicenode
# for running of the syncfiles postscript, which only pulls
# from the service node
my $ tmpsyncfile = "/tmp/xdcpsynclist.$$" ;
my $ syncline = "$syncfile -> $syncfile" ;
open ( FILE , ">$tmpsyncfile" )
or die "cannot open file $tmpsyncfile\n" ;
print FILE " $syncline" ;
close FILE ;
# now put the original syncfile on the queue to sync to the SN's
$ rc =
2013-03-06 17:50:22 +00:00
& parse_rsync_input_file_on_MN ( \ @ nodelist , \ % options , $ tmpsyncfile ,
$ ::SYNCSN , $ synfiledir , $ nodesyncfiledir ) ;
2012-08-02 16:23:08 +00:00
# cleanup
my $ cmd = "rm $tmpsyncfile" ;
my @ output = xCAT::Utils - > runcmd ( $ cmd , 0 ) ;
if ( $ ::RUNCMD_RC != 0 )
{
2012-08-01 13:29:12 +00:00
my $ rsp = { } ;
2012-12-11 13:49:24 +00:00
$ rsp - > { error } - > [ 0 ] = "Command: $cmd failed." ;
2012-08-01 13:29:12 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK ) ;
2012-08-02 16:23:08 +00:00
}
2012-08-01 13:29:12 +00:00
}
2009-06-25 18:17:19 +00:00
}
2009-06-23 15:34:59 +00:00
if ( $ rc == 1 )
{
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] = "Error parsing the rsync file:$syncfile." ;
2009-06-10 17:35:10 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK , 1 ) ;
return ;
}
2009-05-18 14:41:21 +00:00
}
else # source and destination files are from command line
2007-12-12 13:38:48 +00:00
{
if ( @ ARGV < 1 )
{
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] = "Missing file arguments" ;
2008-07-18 12:02:22 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK , 1 ) ;
2009-06-05 15:45:25 +00:00
return ;
2007-12-12 13:38:48 +00:00
}
elsif ( @ ARGV == 1 )
{
if ( $ options { 'pull' } )
{
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] = "Missing target_path" ;
2008-07-18 12:02:22 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK , 1 ) ;
2009-06-09 14:38:30 +00:00
return ;
2007-12-12 13:38:48 +00:00
}
else
{
2012-07-02 12:55:37 +00:00
# HERE:only one line of input source and target in that line
# such as xdcp -R " /test/* /test"
my $ tmparg = pop @ ARGV ;
my ( $ src , $ tgt ) = split " " , $ tmparg ;
$ options { 'target' } = $ tgt ;
$ options { 'source' } = join $ ::__DCP_DELIM , $ src ;
2007-12-12 13:38:48 +00:00
}
}
elsif ( $ options { 'pull' } && ( @ ARGV > 2 ) )
{
2012-06-15 15:42:45 +00:00
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] = "Cannot pull more than one file from targets." ;
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK , 1 ) ;
2009-06-05 15:45:25 +00:00
return ;
2007-12-12 13:38:48 +00:00
}
else
{
2012-07-02 12:55:37 +00:00
# Get the source and the target
2007-12-12 13:38:48 +00:00
$ options { 'target' } = pop @ ARGV ;
$ options { 'source' } = join $ ::__DCP_DELIM , @ ARGV ;
}
2008-10-17 16:04:13 +00:00
}
2009-02-04 17:18:44 +00:00
2007-12-12 13:38:48 +00:00
# Execute the dcp api
2012-08-02 19:04:07 +00:00
# HERE: Run xdcp LKV
2009-05-18 14:41:21 +00:00
@ results = xCAT::DSHCLI - > runDcp_api ( \ % options , 0 ) ;
2010-06-24 16:41:08 +00:00
$ ::FAILED_NODES = $ ::RUNCMD_RC ;
2011-01-18 15:40:18 +00:00
# if not just syncing the service node SNsyncfiledir directory,
# @::postscripts should be empty in this case anyway
# if postscripts to run after rsync, process the output and
# create the xdsh command to run the ones needed
2012-04-27 11:26:51 +00:00
my @ results2 ;
my @ results3 ;
2012-06-15 15:42:45 +00:00
my @ results4 ;
2012-07-27 18:20:08 +00:00
my @ results5 ;
2012-06-18 16:39:35 +00:00
my $ ranpostscripts ;
my $ ranappendscripts ;
2012-07-27 18:20:08 +00:00
my $ ranmergescripts ;
2011-01-18 15:40:18 +00:00
if ( ( @ ::postscripts ) && ( $ ::SYNCSN == 0 ) ) {
2012-04-27 11:26:51 +00:00
@ results2 = & run_rsync_postscripts ( \ @ results , $ synfiledir ) ;
2012-06-18 16:39:35 +00:00
$ ranpostscripts = 1 ;
2012-04-27 11:26:51 +00:00
}
if ( ( @ ::alwayspostscripts ) && ( $ ::SYNCSN == 0 ) ) {
@ results3 = & run_always_rsync_postscripts ( \ @ nodelist , $ synfiledir ) ;
}
2012-06-19 17:30:35 +00:00
if ( ( $ ::appendscript ) && ( $ ::SYNCSN == 0 ) ) {
2012-06-15 15:42:45 +00:00
@ results4 = & bld_and_run_append ( \ @ nodelist , \ @ results , $ synfiledir , $ nodesyncfiledir ) ;
2012-06-18 16:39:35 +00:00
$ ranappendscripts = 1 ;
2012-06-15 15:42:45 +00:00
}
2012-07-27 18:20:08 +00:00
if ( ( $ ::mergescript ) && ( $ ::SYNCSN == 0 ) ) {
@ results5 = & bld_and_run_merge ( \ @ nodelist , \ @ results , $ synfiledir , $ nodesyncfiledir ) ;
$ ranmergescripts = 1 ;
}
2012-04-27 11:26:51 +00:00
my @ newresults ;
if ( @ results2 ) {
@ newresults = ( @ results2 ) ;
}
if ( @ results3 ) {
@ newresults = ( @ newresults , @ results3 ) ;
}
2012-06-15 15:42:45 +00:00
if ( @ results4 ) {
@ newresults = ( @ newresults , @ results3 , @ results4 ) ;
}
2012-07-27 18:20:08 +00:00
if ( @ results5 ) {
@ newresults = ( @ newresults , @ results3 , @ results4 , @ results5 ) ;
}
2012-04-27 11:26:51 +00:00
if ( @ newresults ) {
return ( @ newresults ) ;
2011-01-18 15:40:18 +00:00
} else {
2012-07-27 18:20:08 +00:00
# don't report results for postscripts,appendscripts,mergescripts because
2012-06-18 16:39:35 +00:00
# you get all the rsync returned lines
2012-07-27 18:20:08 +00:00
if ( ( $ ranpostscripts == 0 ) && ( $ ranappendscripts == 0 )
&& ( $ ranmergescripts == 0 ) ) {
2012-06-18 16:39:35 +00:00
return ( @ results ) ;
}
2012-04-27 11:26:51 +00:00
}
2007-12-12 13:38:48 +00:00
}
#-------------------------------------------------------------------------------
2009-06-09 14:38:30 +00:00
= head3
rsync_to_image
This parses the - F rsync input file . and runs rsync to the input
image for the files
2012-04-27 11:26:51 +00:00
Does not process the EXECUTE or EXECUTEALWAYS statement
2009-06-09 14:38:30 +00:00
File format :
/.../ file1 - > /.../ dir1 / filex
/.../ file1 - > /.../ dir1
/.../ file1 /..../ filex - > /...../ dir1
rsync command format
2011-08-23 16:25:28 +00:00
/usr/ bin /rsync -Lprgotz / etc /services $pathtoimage/ etc / services
/usr/ bin /rsync -Lprgotz / tmp /lissa/ file1 /tmp/ lissa /file $pathtoimage/ tmp / lissa
2009-06-09 14:38:30 +00:00
Arguments:
Input:
sync file
path to image
Returns:
Errors if invalid options or the executed dcp command
Globals:
Error:
None
Example:
Comments:
= cut
#-------------------------------------------------------------------------------
sub rsync_to_image
{
use File::Basename ;
my ( $ input_file , $ image ) = @ _ ;
my $ rc = 0 ;
open ( INPUTFILE , "< $input_file" ) || die "File $input_file does not exist\n" ;
while ( my $ line = <INPUTFILE> )
{
chomp $ line ;
2011-01-18 15:40:18 +00:00
if ( $ line =~ /^#/ ) # skip commments
{
next ;
}
# process no more lines, do not exec
2012-06-07 13:00:05 +00:00
# do not execute postscripts when syncing images
if ( ( $ line =~ /EXECUTE:/ ) || ( $ line =~ /EXECUTEALWAYS:/ )
2012-07-27 18:20:08 +00:00
|| ( $ line =~ /APPEND:/ ) || ( $ line =~ /MERGE:/ ) )
2012-04-27 11:26:51 +00:00
{ # process no more lines
2011-01-18 15:40:18 +00:00
last ;
}
2009-06-09 14:38:30 +00:00
if ( $ line =~ /(.+) -> (.+)/ )
{
my $ imageupdatedir = $ image ;
my $ imageupdatepath = $ image ;
my $ src_file = $ 1 ;
my $ dest_file = $ 2 ;
$ dest_file =~ s/[\s;]//g ;
my $ dest_dir ;
if ( - d $ dest_file ) # if a directory on the left side
{ # if a directory , just use
$ dest_dir = $ dest_file ;
$ dest_dir =~ s/\s*//g ; #remove blanks
$ imageupdatedir . = $ dest_dir ; # save the directory
$ imageupdatepath . = $ dest_dir ; # path is a directory
}
else # if a file on the left side
{ # strip off the file
$ dest_dir = dirname ( $ dest_file ) ;
$ dest_dir =~ s/\s*//g ; #remove blanks
$ imageupdatedir . = $ dest_dir ; # save directory
$ imageupdatepath . = $ dest_file ; # path to a file
}
my @ srcfiles = ( split ' ' , $ src_file ) ;
if ( ! ( - d $ imageupdatedir ) )
{ # if it does not exist, make it
2009-06-09 16:45:17 +00:00
my $ cmd = "mkdir -p $imageupdatedir" ;
2009-06-09 14:38:30 +00:00
my @ output = xCAT::Utils - > runcmd ( $ cmd , 0 ) ;
if ( $ ::RUNCMD_RC != 0 )
{
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] = "Command: $cmd failed." ;
2009-06-09 14:38:30 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK , 1 ) ;
return ;
}
}
# for each file on the line
my $ synccmd = "" ;
2009-06-23 15:34:59 +00:00
if ( $^O eq 'aix' )
{
2009-07-10 11:56:19 +00:00
if ( - e ( "/usr/bin/rsync" ) )
{
2011-08-23 16:25:28 +00:00
$ synccmd = "/usr/bin/rsync -Lprogtz " ;
2009-07-10 11:56:19 +00:00
}
else
{
2011-08-23 16:25:28 +00:00
$ synccmd = "/usr/local/bin/rsync -Lprogtz " ;
2009-07-10 11:56:19 +00:00
}
2009-06-23 15:34:59 +00:00
}
2009-07-10 11:56:19 +00:00
else # linux
2009-06-23 15:34:59 +00:00
{
2011-08-23 16:25:28 +00:00
$ synccmd = "/usr/bin/rsync -Lprogtz " ;
2009-06-19 08:32:47 +00:00
}
2009-06-09 14:38:30 +00:00
my $ syncopt = "" ;
foreach my $ srcfile ( @ srcfiles )
{
$ syncopt . = $ srcfile ;
$ syncopt . = " " ;
}
$ syncopt . = $ imageupdatepath ;
$ synccmd . = $ syncopt ;
2009-06-19 08:32:47 +00:00
xCAT::MsgUtils - > message ( "S" , "rsync2image: $synccmd\n" ) ;
2009-06-09 14:38:30 +00:00
my @ output = xCAT::Utils - > runcmd ( $ synccmd , 0 ) ;
if ( $ ::RUNCMD_RC != 0 )
{
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] = "Command: $synccmd failed." ;
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK ) ;
2009-06-09 14:38:30 +00:00
}
} # valid line
} # end reading file
close INPUTFILE ;
return $ rc ;
}
#-------------------------------------------------------------------------------
2007-12-12 13:38:48 +00:00
= head3
2009-06-25 18:17:19 +00:00
parse_rsync_input_file_on_MN
2007-12-12 13:38:48 +00:00
2009-06-25 18:17:19 +00:00
This parses the - F rsync input file on the Management node .
2009-05-18 14:41:21 +00:00
File format :
/.../ file1 - > /.../ dir1 / filex
/.../ file1 - > /.../ dir1
2010-06-24 16:41:08 +00:00
/.../ * - > /.../ dir1
2009-05-18 14:41:21 +00:00
/.../ file1 /..../ filex - > /...../ dir1
2012-04-27 11:26:51 +00:00
/tmp/ file2 - > /tmp/ file2
/tmp/ file2 . post - > /tmp/ file2 . post
EXECUTE:
/tmp/ file2 . post
EXECUTEALWAYS:
/tmp/m yscript1
/tmp/m yscript2
.
.
2009-05-18 14:41:21 +00:00
Arguments:
2009-06-25 18:17:19 +00:00
Input nodelist , options , pointer to the sync file , flag is
syncing the service node and
the directory to syn the files to on the service node
based on defaults or the site . SNsyncfiledir attribute ,
if syncing a service node for hierarchical support .
2009-05-18 14:41:21 +00:00
Returns:
Errors if invalid options or the executed dcp command
Globals:
2012-08-01 13:29:12 +00:00
$ ::SYNCSN indicates we are only syncing the files to the
service nodes xdcp - s flag
2009-05-18 14:41:21 +00:00
Error:
None
Example:
Comments:
2012-08-01 13:29:12 +00:00
We also add the original synclist file for the node to be sync ' d
to the service node
2009-05-18 14:41:21 +00:00
= cut
#-------------------------------------------------------------------------------
2009-06-25 18:17:19 +00:00
sub parse_rsync_input_file_on_MN
2009-05-18 14:41:21 +00:00
{
use File::Basename ;
2012-06-07 13:00:05 +00:00
my ( $ nodes , $ options , $ input_file , $ rsyncSN , $ syncdir , $ nodesyncfiledir ) = @ _ ;
2009-06-23 15:34:59 +00:00
my @ dest_host = @$ nodes ;
2012-06-12 12:36:54 +00:00
$ ::process_line = 0 ;
2010-06-24 16:41:08 +00:00
my $ destfileisdir ;
2012-06-07 13:00:05 +00:00
my $ clause = 0 ;
2012-06-15 15:42:45 +00:00
2009-05-18 14:41:21 +00:00
open ( INPUTFILE , "< $input_file" ) || die "File $input_file does not exist\n" ;
while ( my $ line = <INPUTFILE> )
{
chomp $ line ;
2012-04-27 11:26:51 +00:00
if ( ( $ line =~ /^#/ ) || ( $ line =~ /^\s*$/ ) )
# skip commments and blanks
2009-08-26 14:33:44 +00:00
{
2009-08-27 16:30:08 +00:00
next ;
2009-08-26 14:33:44 +00:00
}
2012-06-07 13:00:05 +00:00
# Determine if processing a clause or the synclist
if ( ( $ line =~ /EXECUTE:/ ) || ( $ line =~ /EXECUTEALWAYS:/ )
2012-07-27 18:20:08 +00:00
|| ( $ line =~ /APPEND:/ ) || ( $ line =~ /MERGE:/ ) ) {
2012-06-07 13:00:05 +00:00
$ clause = $ line ;
next ; # get the content of the clause
2012-04-27 11:26:51 +00:00
}
2012-06-07 13:00:05 +00:00
# processing a clause
if ( ( $ clause =~ /APPEND:/ ) || ( $ clause =~ /EXECUTEALWAYS:/ )
2012-07-27 18:20:08 +00:00
|| ( $ clause =~ /EXECUTE:/ ) || ( $ clause =~ /MERGE:/ ) ) {
2012-06-07 13:00:05 +00:00
if ( ( $ ::SYNCSN == 1 ) && ( ( $ clause =~ /EXECUTEALWAYS:/ ) ||
2012-06-19 17:30:35 +00:00
( $ clause =~ /EXECUTE:/ ) ) ) {
# for EXECUTE and EXECUTEALWAYS skip, if syncing SN only
2012-06-07 13:00:05 +00:00
next ;
} else { # process the clause
if ( $ clause =~ /EXECUTE:/ ) {
push @ ::postscripts , $ line ;
2012-04-27 11:26:51 +00:00
}
2012-06-07 13:00:05 +00:00
if ( $ clause =~ /EXECUTEALWAYS:/ ) {
push @ ::alwayspostscripts , $ line ;
}
if ( $ clause =~ /APPEND:/ ) {
2012-06-15 15:42:45 +00:00
# location of the base append script
2012-06-19 17:30:35 +00:00
# for APPEND we have to sync the appendscript and the
# append file to the SN
2012-06-12 12:36:54 +00:00
my $ onServiceNode = 0 ;
2012-06-18 16:39:35 +00:00
my $ syncappendscript = 0 ;
& build_append_rsync ( $ line , $ nodes , $ options , $ input_file , $ rsyncSN , $ syncdir , $ nodesyncfiledir , $ onServiceNode , $ syncappendscript ) ;
2012-06-19 17:30:35 +00:00
if ( $ ::SYNCSN == 0 ) {
# this triggers the running of the appendscript
$ ::appendscript = "/opt/xcat/share/xcat/scripts/xdcpappend.sh" ;
}
2012-06-15 15:42:45 +00:00
# add the append script to the sync
2012-06-19 17:30:35 +00:00
my $ appscript = "/opt/xcat/share/xcat/scripts/xdcpappend.sh" ;
my $ appendscriptline = "$appscript -> $appscript" ;
2012-06-18 16:39:35 +00:00
$ syncappendscript = 1 ; # syncing the xdcpappend.sh script
& build_append_rsync ( $ appendscriptline , $ nodes , $ options , $ input_file , $ rsyncSN , $ syncdir , $ nodesyncfiledir , $ onServiceNode , $ syncappendscript ) ;
2012-04-27 11:26:51 +00:00
}
2012-07-27 18:20:08 +00:00
if ( $ clause =~ /MERGE:/ ) {
# location of the base merge script
# for MERGE we have to sync the mergescript and the
# merge file to the SN
my $ onServiceNode = 0 ;
my $ syncmergescript = 0 ;
& build_merge_rsync ( $ line , $ nodes , $ options , $ input_file , $ rsyncSN , $ syncdir , $ nodesyncfiledir , $ onServiceNode , $ syncmergescript ) ;
if ( $ ::SYNCSN == 0 ) {
# this triggers the running of the mergescript
$ ::mergescript = "/opt/xcat/share/xcat/scripts/xdcpmerge.sh" ;
}
# add the merge script to the sync
my $ mergescript = "/opt/xcat/share/xcat/scripts/xdcpmerge.sh" ;
my $ mergescriptline = "$mergescript -> $mergescript" ;
$ syncmergescript = 1 ; # syncing the xdcpmerge.sh script
& build_merge_rsync ( $ mergescriptline , $ nodes , $ options , $ input_file , $ rsyncSN , $ syncdir , $ nodesyncfiledir , $ onServiceNode , $ syncmergescript ) ;
}
2011-01-18 15:40:18 +00:00
2012-06-07 13:00:05 +00:00
}
} else { # not processing EXECUTE, EXECUTEALWAYS or APPEND
# otherwise it is just the synclist
if ( $ line =~ /(.+) -> (.+)/ )
{
2009-08-27 16:30:08 +00:00
2012-06-12 12:36:54 +00:00
$ ::process_line = 1 ;
2009-05-18 14:41:21 +00:00
my $ src_file = $ 1 ;
my $ dest_file = $ 2 ;
$ dest_file =~ s/[\s;]//g ;
2009-06-29 13:36:18 +00:00
my @ srcfiles = ( split ' ' , $ src_file ) ;
my $ arraysize = scalar @ srcfiles ; # of source files on the line
2009-05-18 14:41:21 +00:00
my $ dest_dir ;
2010-06-24 16:41:08 +00:00
$ destfileisdir = 0 ;
if ( $ dest_file =~ /\/$/ )
{ # ends in /
$ destfileisdir = 1 ;
}
2009-06-29 13:36:18 +00:00
2009-08-27 16:30:08 +00:00
# if more than one file on the line then
2010-06-24 16:41:08 +00:00
# or the destination file ends in /
# /tmp/file1 -> /tmp/
2009-08-27 16:30:08 +00:00
# the destination is a directory
# else assume a file
2010-06-24 16:41:08 +00:00
if ( ( $ arraysize > 1 ) || ( $ destfileisdir == 1 ) )
2009-06-29 13:36:18 +00:00
{
2010-06-24 16:41:08 +00:00
$ dest_dir = $ dest_file ;
$ destfileisdir = 1 ;
2009-08-27 16:30:08 +00:00
}
2010-06-24 16:41:08 +00:00
else # get the directory name
2009-08-27 16:30:08 +00:00
{ # strip off the file
$ dest_dir = dirname ( $ dest_file ) ;
2009-05-18 14:41:21 +00:00
}
$ dest_dir =~ s/\s*//g ; #remove blanks
foreach my $ target_node ( @ dest_host )
{
2009-05-18 18:15:47 +00:00
$$ options { 'destDir_srcFile' } { $ target_node } || = { } ;
2009-05-18 14:41:21 +00:00
# for each file on the line
foreach my $ srcfile ( @ srcfiles )
{
2009-05-18 18:15:47 +00:00
# if syncing the Service Node, file goes to the same place
2010-04-21 18:49:24 +00:00
# where it was on the MN off the syncdir on the service
2009-06-25 18:17:19 +00:00
# node
2009-05-18 18:15:47 +00:00
if ( $ rsyncSN == 1 )
{ # syncing the SN
2009-06-25 18:17:19 +00:00
$ dest_dir = $ syncdir ; # the SN sync dir
$ dest_dir . = dirname ( $ srcfile ) ;
2009-05-18 18:15:47 +00:00
$ dest_dir =~ s/\s*//g ; #remove blanks
}
$$ options { 'destDir_srcFile' } { $ target_node } { $ dest_dir } || =
{ } ;
2009-05-18 14:41:21 +00:00
# can be full file name for destination or just the
# directory name
my $ src_basename = basename ( $ srcfile ) ; # get file name
my $ dest_basename ; # destination file name
2010-06-24 16:41:08 +00:00
# determine path to the file
if ( $ destfileisdir == 1 ) # if a directory
{
$ dest_basename = $ src_basename ;
2009-05-18 14:41:21 +00:00
}
else
2010-06-24 16:41:08 +00:00
{
$ dest_basename = basename ( $ dest_file ) ;
2009-05-18 14:41:21 +00:00
}
2009-06-09 14:38:30 +00:00
if ( $ rsyncSN == 1 ) # dest file will be the same as src
{ # syncing the SN
2009-06-03 14:38:12 +00:00
$ dest_basename = $ src_basename ;
}
$$ options { 'destDir_srcFile' } { $ target_node } { $ dest_dir } || =
2009-06-09 14:38:30 +00:00
$ dest_basename =~ s/[\s;]//g ;
2009-05-18 14:41:21 +00:00
# if the filename will be the same at the destination
if ( $ src_basename eq $ dest_basename )
{
$$ options { 'destDir_srcFile' } { $ target_node } { $ dest_dir }
{ 'same_dest_name' } || = [] ;
push @ { $$ options { 'destDir_srcFile' } { $ target_node }
{ $ dest_dir } { 'same_dest_name' } } , $ srcfile ;
}
else # changing file names
{
$$ options { 'destDir_srcFile' } { $ target_node } { $ dest_dir }
{ 'diff_dest_name' } || = { } ;
$$ options { 'destDir_srcFile' } { $ target_node } { $ dest_dir }
{ 'diff_dest_name' } { $ srcfile } = $ dest_basename ;
}
2012-06-07 13:00:05 +00:00
} # end of each srcfile
} # end of each node
} # if synclist line
} # end processing clauses EXECUTE, APPEND, etc
} #end while processing file
2009-05-18 14:41:21 +00:00
close INPUTFILE ;
2012-06-12 12:36:54 +00:00
if ( $ ::process_line == 0 )
2009-06-23 15:34:59 +00:00
{ # no valid lines in the file
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] = "Found no lines to process in $input_file." ;
2009-06-23 15:34:59 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK , 1 ) ;
return 1 ;
}
else
{
$$ options { 'nodes' } = join ',' , keys % { $$ options { 'destDir_srcFile' } } ;
2009-06-10 17:35:10 +00:00
}
return 0 ;
2009-05-18 14:41:21 +00:00
}
2012-06-07 13:00:05 +00:00
#-------------------------------------------------------------------------------
= head3
build_append_rsync
Handles the
APPEND: clause in the synclist
/tmp/ appendfile - > /tmp/ receivefile
2012-06-18 16:39:35 +00:00
Syncs the append file from the left side of the arrow
to the nodes into the site . nodesyncfiledir directory
After we find out which append file are actually changed , we
will sync and run and the append script
/opt/xc at /share/xc at /script/x dcpappend . sh
See build_append_script .
2012-06-07 13:00:05 +00:00
Returns:
Files do not exist , rsync errors .
Globals:
Error:
2012-06-12 12:36:54 +00:00
Files do not exist , rsync errors .
2012-06-07 13:00:05 +00:00
Example:
Comments:
= cut
2009-05-18 14:41:21 +00:00
#-------------------------------------------------------------------------------
2012-06-07 13:00:05 +00:00
sub build_append_rsync
{
use File::Basename ;
2012-06-18 16:39:35 +00:00
my ( $ line , $ nodes , $ options , $ input_file , $ rsyncSN , $ syncdir , $ nodesyncfiledir , $ onServiceNode , $ syncappendscript ) = @ _ ;
2012-06-12 12:36:54 +00:00
my @ dest_host = @$ nodes ;
my $ process_line = 0 ;
my $ destfileisdir ;
2012-06-15 15:42:45 +00:00
# add append directory to the base nodesyncfiledir
$ nodesyncfiledir . = "/append" ;
2012-06-12 12:36:54 +00:00
if ( $ line =~ /(.+) -> (.+)/ )
{
$ ::process_line = 1 ;
2012-06-18 16:39:35 +00:00
if ( $ syncappendscript == 0 ) { # don't add the xdcpappend.sh line
push @ ::appendlines , $ line ;
}
2012-06-12 12:36:54 +00:00
my $ src_file = $ 1 ; # append file left of arror
# it will be sync'd to $nodesyncfiledir/$append_file
my $ dest_file = $ nodesyncfiledir ;
$ dest_file . = $ src_file ;
$ dest_file =~ s/[\s;]//g ;
my $ dest_dir = dirname ( $ dest_file ) ;
$ dest_dir =~ s/\s*//g ; #remove blanks
foreach my $ target_node ( @ dest_host )
{
$$ options { 'destDir_srcFile' } { $ target_node } || = { } ;
# if syncing the Service Node, file goes to the same place
# where it was on the MN off the syncdir on the service
# node
if ( $ rsyncSN == 1 )
{ # syncing the SN
$ dest_dir = $ syncdir ; # the SN sync dir
$ dest_dir . = dirname ( $ src_file ) ;
$ dest_dir =~ s/\s*//g ; #remove blanks
}
$$ options { 'destDir_srcFile' } { $ target_node } { $ dest_dir } || =
{ } ;
my $ src_basename = basename ( $ src_file ) ; # get file name
# if this is syncing from the Service Node then we have
# to pick up files from /var/xcat/syncfiles...
if ( $ onServiceNode == 1 ) {
2012-06-18 16:39:35 +00:00
my $ newsrcfile = $ syncdir ; # add SN syndir on front
2012-06-12 12:36:54 +00:00
$ newsrcfile . = $ src_file ;
$ src_file = $ newsrcfile ;
}
# destination file name
my $ dest_basename = basename ( $ dest_file ) ;
if ( $ rsyncSN == 1 ) # dest file will be the same as src
{ # syncing the SN
$ dest_basename = $ src_basename ;
}
$$ options { 'destDir_srcFile' } { $ target_node } { $ dest_dir } || =
$ dest_basename =~ s/[\s;]//g ;
$$ options { 'destDir_srcFile' } { $ target_node } { $ dest_dir }
{ 'same_dest_name' } || = [] ;
push @ { $$ options { 'destDir_srcFile' } { $ target_node }
{ $ dest_dir } { 'same_dest_name' } } , $ src_file ;
2012-06-07 13:00:05 +00:00
2012-06-12 12:36:54 +00:00
} # end of each node
} # if synclist line
if ( $ ::process_line == 0 )
{ # no valid lines in the file
my $ rsp = { } ;
$ rsp - > { error } - > [ 0 ] = "Found no lines to process in $input_file APPEND Clause." ;
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK , 1 ) ;
return 1 ;
}
else
{
$$ options { 'nodes' } = join ',' , keys % { $$ options { 'destDir_srcFile' } } ;
}
2012-06-07 13:00:05 +00:00
return 0 ;
}
#-------------------------------------------------------------------------------
2012-07-27 18:20:08 +00:00
= head3
build_merge_rsync
Handles the
MERGE: clause in the synclist
/tmp/m ypasswd - > /etc/ passwd
/tmp/m ygroup - > /etc/g roup
/tmp/m yshadow - > /etc/s hadow
Merges the information from the files in mypasswd , mygroup ,
myshadow into /etc/ passwd , /etc/g roup , /etc/s hadow on the nodes .
These are the only files supported from MERGE and only on Linux
Returns:
Files do not exist , rsync errors .
Globals:
Error:
Files do not exist , rsync errors .
Example:
Comments:
= cut
#-------------------------------------------------------------------------------
sub build_merge_rsync
{
use File::Basename ;
my ( $ line , $ nodes , $ options , $ input_file , $ rsyncSN , $ syncdir , $ nodesyncfiledir , $ onServiceNode , $ syncmergescript ) = @ _ ;
my @ dest_host = @$ nodes ;
my $ process_line = 0 ;
my $ destfileisdir ;
# add merge directory to the base nodesyncfiledir
2012-07-30 19:49:02 +00:00
if ( $ syncmergescript == 1 ) { # syncing the xdcpmerge.sh
$ nodesyncfiledir . = "/merge" ;
} else { # all the other merge scripts
$ nodesyncfiledir . = "/merge/mergefiles" ;
}
2012-07-27 18:20:08 +00:00
if ( $ line =~ /(.+) -> (.+)/ )
{
$ ::process_line = 1 ;
if ( $ syncmergescript == 0 ) { # don't add the xdcpmerge.sh line
push @ ::mergelines , $ line ;
}
my $ src_file = $ 1 ; # merge file left of arror
# it will be sync'd to $nodesyncfiledir/$merge_file
my $ dest_file = $ nodesyncfiledir ;
$ dest_file . = $ src_file ;
$ dest_file =~ s/[\s;]//g ;
my $ dest_dir = dirname ( $ dest_file ) ;
$ dest_dir =~ s/\s*//g ; #remove blanks
foreach my $ target_node ( @ dest_host )
{
$$ options { 'destDir_srcFile' } { $ target_node } || = { } ;
# if syncing the Service Node, file goes to the same place
# where it was on the MN off the syncdir on the service
# node
if ( $ rsyncSN == 1 )
{ # syncing the SN
$ dest_dir = $ syncdir ; # the SN sync dir
$ dest_dir . = dirname ( $ src_file ) ;
$ dest_dir =~ s/\s*//g ; #remove blanks
}
$$ options { 'destDir_srcFile' } { $ target_node } { $ dest_dir } || =
{ } ;
my $ src_basename = basename ( $ src_file ) ; # get file name
# if this is syncing from the Service Node then we have
# to pick up files from /var/xcat/syncfiles...
if ( $ onServiceNode == 1 ) {
my $ newsrcfile = $ syncdir ; # add SN syndir on front
$ newsrcfile . = $ src_file ;
$ src_file = $ newsrcfile ;
}
# destination file name
my $ dest_basename = basename ( $ dest_file ) ;
if ( $ rsyncSN == 1 ) # dest file will be the same as src
{ # syncing the SN
$ dest_basename = $ src_basename ;
}
$$ options { 'destDir_srcFile' } { $ target_node } { $ dest_dir } || =
$ dest_basename =~ s/[\s;]//g ;
$$ options { 'destDir_srcFile' } { $ target_node } { $ dest_dir }
{ 'same_dest_name' } || = [] ;
push @ { $$ options { 'destDir_srcFile' } { $ target_node }
{ $ dest_dir } { 'same_dest_name' } } , $ src_file ;
} # end of each node
} # if synclist line
if ( $ ::process_line == 0 )
{ # no valid lines in the file
my $ rsp = { } ;
$ rsp - > { error } - > [ 0 ] = "Found no lines to process in $input_file APPEND Clause." ;
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK , 1 ) ;
return 1 ;
}
else
{
$$ options { 'nodes' } = join ',' , keys % { $$ options { 'destDir_srcFile' } } ;
}
return 0 ;
}
#-------------------------------------------------------------------------------
= head3
parse_rsync_input_file_on_SN
This parses the - F rsync input file on the Service node .
File format :
/.../ file1 - > /.../ dir1 / filex
/.../ file1 - > /.../ dir1
/.../ * - > /.../ dir1
/.../ file1 /..../ filex - > /...../ dir1
Arguments:
Input nodelist , options , pointer to the sync file and
the directory to syn the files from
based on defaults or the site . SNsyncfiledir attribute ,
Returns:
Errors if invalid options or the executed dcp command
Globals:
Error:
None
Example:
Comments:
#-------------------------------------------------------------------------------
2009-06-25 18:17:19 +00:00
= head3
parse_rsync_input_file_on_SN
This parses the - F rsync input file on the Service node .
File format :
/.../ file1 - > /.../ dir1 / filex
/.../ file1 - > /.../ dir1
2010-06-24 16:41:08 +00:00
/.../ * - > /.../ dir1
2009-06-25 18:17:19 +00:00
/.../ file1 /..../ filex - > /...../ dir1
Arguments:
Input nodelist , options , pointer to the sync file and
the directory to syn the files from
based on defaults or the site . SNsyncfiledir attribute ,
Returns:
Errors if invalid options or the executed dcp command
Globals:
Error:
None
Example:
Comments:
= cut
#-------------------------------------------------------------------------------
sub parse_rsync_input_file_on_SN
{
use File::Basename ;
2012-06-12 12:36:54 +00:00
my ( $ nodes , $ options , $ input_file , $ syncdir , $ nodesyncfiledir ) = @ _ ;
2009-06-25 18:17:19 +00:00
my @ dest_host = @$ nodes ;
my $ process_line = 0 ;
2010-06-24 16:41:08 +00:00
my $ destfileisdir ;
2012-06-12 12:36:54 +00:00
my $ rsyncSN ;
2012-06-07 13:00:05 +00:00
my $ clause = 0 ;
2009-06-25 18:17:19 +00:00
open ( INPUTFILE , "< $input_file" ) || die "File $input_file does not exist\n" ;
while ( my $ line = <INPUTFILE> )
{
chomp $ line ;
2012-04-27 11:26:51 +00:00
if ( ( $ line =~ /^#/ ) || ( $ line =~ /^\s*$/ ) )
# skip commments and blanks
2011-01-18 15:40:18 +00:00
{
next ;
}
2012-06-07 13:00:05 +00:00
# Determine if processing a clause or the synclist
if ( ( $ line =~ /EXECUTE:/ ) || ( $ line =~ /EXECUTEALWAYS:/ )
2012-07-27 18:20:08 +00:00
|| ( $ line =~ /APPEND:/ ) || ( $ line =~ /MERGE:/ ) ) {
2012-06-07 13:00:05 +00:00
$ clause = $ line ;
next ; # get the content of the clause
2011-01-18 15:40:18 +00:00
}
2012-06-07 13:00:05 +00:00
# processing a clause
2012-07-27 18:20:08 +00:00
if ( ( $ clause =~ /APPEND:/ ) || ( $ clause =~ /MERGE:/ )
|| ( $ clause =~ /EXECUTEALWAYS:/ )
2012-06-07 13:00:05 +00:00
|| ( $ clause =~ /EXECUTE:/ ) ) {
if ( ( $ ::SYNCSN == 1 ) && ( ( $ clause =~ /EXECUTEALWAYS:/ ) ||
( $ clause =~ /EXECUTE:/ ) ) ) { # skip, if syncing SN only
next ;
} else { # process the clause
if ( $ clause =~ /EXECUTE:/ ) {
push @ ::postscripts , $ line ;
2012-04-27 11:26:51 +00:00
}
2012-06-07 13:00:05 +00:00
if ( $ clause =~ /EXECUTEALWAYS:/ ) {
push @ ::alwayspostscripts , $ line ;
}
if ( $ clause =~ /APPEND:/ ) {
2012-06-12 12:36:54 +00:00
$ process_line = 1 ;
my $ onServiceNode = 1 ;
2012-06-18 16:39:35 +00:00
my $ syncappendscript = 0 ;
& build_append_rsync ( $ line , $ nodes , $ options , $ input_file , $ rsyncSN , $ syncdir , $ nodesyncfiledir , $ onServiceNode , $ syncappendscript ) ;
2012-06-19 17:30:35 +00:00
if ( $ ::SYNCSN == 0 ) {
# this triggers the running of the appendscript
$ ::appendscript = "/opt/xcat/share/xcat/scripts/xdcpappend.sh" ;
}
2012-06-18 16:39:35 +00:00
# add the append script to the sync
2012-06-19 17:30:35 +00:00
my $ appscript = "/opt/xcat/share/xcat/scripts/xdcpappend.sh" ;
my $ appendscriptline = "$appscript -> $appscript" ;
2012-06-18 16:39:35 +00:00
$ syncappendscript = 1 ; # syncing the xdcpappend.sh script
& build_append_rsync ( $ appendscriptline , $ nodes , $ options , $ input_file , $ rsyncSN , $ syncdir , $ nodesyncfiledir , $ onServiceNode , $ syncappendscript ) ;
2012-04-27 11:26:51 +00:00
}
2012-07-27 18:20:08 +00:00
if ( $ clause =~ /MERGE:/ ) {
$ process_line = 1 ;
my $ onServiceNode = 1 ;
my $ syncmergescript = 0 ;
& build_merge_rsync ( $ line , $ nodes , $ options , $ input_file , $ rsyncSN , $ syncdir , $ nodesyncfiledir , $ onServiceNode , $ syncmergescript ) ;
if ( $ ::SYNCSN == 0 ) {
# this triggers the running of the mergescript
$ ::mergescript = "/opt/xcat/share/xcat/scripts/xdcpmerge.sh" ;
}
# add the merge script to the sync
my $ appscript = "/opt/xcat/share/xcat/scripts/xdcpmerge.sh" ;
my $ mergescriptline = "$appscript -> $appscript" ;
$ syncmergescript = 1 ; # syncing the xdcpmerge.sh script
& build_merge_rsync ( $ mergescriptline , $ nodes , $ options , $ input_file , $ rsyncSN , $ syncdir , $ nodesyncfiledir , $ onServiceNode , $ syncmergescript ) ;
}
2012-04-27 11:26:51 +00:00
2012-06-07 13:00:05 +00:00
}
} else { # not processing EXECUTE, EXECUTEALWAYS or APPEND
# otherwise it is just the synclist
2009-06-25 18:17:19 +00:00
if ( $ line =~ /(.+) -> (.+)/ )
{
$ process_line = 1 ;
my $ src_file = $ 1 ;
my $ dest_file = $ 2 ;
2010-06-24 16:41:08 +00:00
$ dest_file =~ s/[\s;]//g ; # remove blanks
# see if destination is a directory
$ destfileisdir = 0 ;
if ( $ dest_file =~ /\/$/ )
{ # ends in /
$ destfileisdir = 1 ;
}
2009-06-29 13:36:18 +00:00
my @ srcfiles = ( split ' ' , $ src_file ) ;
my $ arraysize = scalar @ srcfiles ; # of source files on the line
2009-06-25 18:17:19 +00:00
my $ dest_dir ;
2009-06-29 13:36:18 +00:00
2010-06-24 16:41:08 +00:00
# if only more than one file on the line or ends in /
2009-08-27 16:30:08 +00:00
# then the destination is a directory
2009-12-04 14:50:33 +00:00
# else a file,
2010-06-24 16:41:08 +00:00
if ( ( $ arraysize > 1 ) || ( $ destfileisdir == 1 ) )
2009-08-27 16:30:08 +00:00
{
2010-06-24 16:41:08 +00:00
$ dest_dir = $ dest_file ;
$ destfileisdir = 1 ;
2009-06-25 18:17:19 +00:00
}
2009-12-04 14:50:33 +00:00
else # a file path
2009-08-27 16:30:08 +00:00
{
$ dest_dir = dirname ( $ dest_file ) ;
2009-06-25 18:17:19 +00:00
}
$ dest_dir =~ s/\s*//g ; #remove blanks
foreach my $ target_node ( @ dest_host )
{
$$ options { 'destDir_srcFile' } { $ target_node } || = { } ;
# for each file on the line
foreach my $ srcfile ( @ srcfiles )
{
2010-04-21 18:49:24 +00:00
my $ newsrcfile = $ syncdir ; # add syndir on front
$ newsrcfile . = $ srcfile ;
2009-06-25 18:17:19 +00:00
$$ options { 'destDir_srcFile' } { $ target_node } { $ dest_dir } || =
{ } ;
# can be full file name for destination or just the
# directory name. For source must be full path
2010-04-21 18:49:24 +00:00
my $ src_basename = basename ( $ newsrcfile ) ; # get file name
2009-06-25 18:17:19 +00:00
my $ dest_basename ; # destination file name
2010-06-24 16:41:08 +00:00
if ( $ destfileisdir == 1 ) # is a directory
{
$ dest_basename = $ src_basename ;
2009-06-25 18:17:19 +00:00
}
else
2010-06-24 16:41:08 +00:00
{
$ dest_basename = basename ( $ dest_file ) ;
2009-06-25 18:17:19 +00:00
}
$$ options { 'destDir_srcFile' } { $ target_node } { $ dest_dir } || =
$ dest_basename =~ s/[\s;]//g ;
# if the filename will be the same at the destination
if ( $ src_basename eq $ dest_basename )
{
$$ options { 'destDir_srcFile' } { $ target_node } { $ dest_dir }
{ 'same_dest_name' } || = [] ;
push @ { $$ options { 'destDir_srcFile' } { $ target_node }
2010-04-21 18:49:24 +00:00
{ $ dest_dir } { 'same_dest_name' } } , $ newsrcfile ;
2009-06-25 18:17:19 +00:00
}
else # changing file names
{
$$ options { 'destDir_srcFile' } { $ target_node } { $ dest_dir }
{ 'diff_dest_name' } || = { } ;
$$ options { 'destDir_srcFile' } { $ target_node } { $ dest_dir }
2010-04-21 18:49:24 +00:00
{ 'diff_dest_name' } { $ newsrcfile } = $ dest_basename ;
2009-06-25 18:17:19 +00:00
}
2012-06-07 13:00:05 +00:00
} # end of srcfile
} # end of each node
} # end of synclist
} # end processing clauses EXECUTE, APPEND, etc
} #end of processing file
2009-06-25 18:17:19 +00:00
close INPUTFILE ;
if ( $ process_line == 0 )
{ # no valid lines in the file
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] = "Found no lines to process in $input_file." ;
2009-06-25 18:17:19 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK , 1 ) ;
return 1 ;
}
else
{
$$ options { 'nodes' } = join ',' , keys % { $$ options { 'destDir_srcFile' } } ;
}
return 0 ;
}
2011-01-18 15:40:18 +00:00
#-------------------------------------------------------------------------------
= head3
run_rsync_postscripts
This executes the postscript file on the nodes where
the corresponding rsync file was updated
2012-04-27 11:26:51 +00:00
These are the scripts after EXECUTE: in the syncfile
2011-01-18 15:40:18 +00:00
rsync returns a list of files that have been updated
in the form hostname: < full file path >
For example: node1: tmp /test/ file1 ( yes it leaves the first / off )
This routine must match that list to the input list of postscripts .
If there is a match , for example
The postscript file is /tmp/ test /file1.post and tmp/ test / file1 was
updated , then it builds a xdsh command to the node to run
/tmp/ test / file1 . post .
On the service node , the file will be in $ syncdir /tmp/ test / file1 . post .
Also the routine must preserve all other messages returned from rsync ,
to return to the admin . It will remove the messages that the files
were updated , that is all of from hostname: < full file path > .
Input: the output from the xdcp rsync run
: @ ::postscripts to run
Comments:
Needs to remove the lines from rsync that are return to let
me know files were updated from the output to determine which
postscripts to run and leave any other messages
to return to the admin .
= cut
#-------------------------------------------------------------------------------
sub run_rsync_postscripts
{
my ( $ rsyncoutput , $ syncdir ) = @ _ ;
my @ rsync_output = @$ rsyncoutput ;
my @ newoutput = ( ) ;
my $ dshparms ;
my $ firstpass = 1 ;
foreach my $ postsfile ( @ ::postscripts ) {
my $ tmppostfile = $ postsfile ;
2011-01-18 19:04:44 +00:00
# if service node need to add the SNsyncfiledir to the path
if ( xCAT::Utils - > isServiceNode ( ) ) {
my $ tmpp = $ syncdir . $ tmppostfile ;
$ tmppostfile = $ tmpp ;
}
2012-04-27 11:26:51 +00:00
# remove first character for the compare, we have to do this because the
# return from rsync is tmp/file1 not /tmp/file1
2011-01-18 15:40:18 +00:00
substr ( $ tmppostfile , 0 , 1 ) = "" ;
# now remove .post from the postscript file for the compare
# with the returned file name
2012-08-23 13:56:05 +00:00
my ( $ tp , $ post ) = split ( /\.post/ , $ tmppostfile ) ;
2011-01-18 15:40:18 +00:00
$ tmppostfile = $ tp ;
foreach my $ line ( @ rsync_output ) {
my ( $ hostname , $ ps ) = split ( /: / , $ line ) ;
chomp $ ps ;
chomp $ hostname ;
if ( $ ps eq "rsync" ) { # this is a line that is not an update
# save output , if firstpass through output
if ( $ firstpass == 1 ) {
push @ newoutput , $ line ;
$ firstpass = 0 ;
}
next ;
}
if ( $ tmppostfile eq $ ps ) {
2011-01-18 19:35:32 +00:00
# build xdsh queue
2011-01-18 15:40:18 +00:00
# build host and all scripts to execute
push ( @ { $ dshparms - > { 'postscripts' } { $ postsfile } } , $ hostname ) ;
}
}
}
# now if we have postscripts to run, run xdsh
my $ out ;
2012-10-31 17:14:08 +00:00
# if we were called with runxcmd, like by updatenode
# need to save the runxcmd buffer
# $::xcmd_outref
my $ save_xcmd_outref ;
if ( $ ::xcmd_outref ) { # this means we were called with runxcmd
$ save_xcmd_outref = $ ::xcmd_outref ;
}
# my $ranaps=0; # did we run a postscript
2011-01-18 15:40:18 +00:00
foreach my $ ps ( keys % { $$ dshparms { 'postscripts' } } ) {
2011-01-18 19:35:32 +00:00
my @ nodes ;
push ( @ nodes , @ { $$ dshparms { 'postscripts' } { $ ps } } ) ;
# if on the service node need to add the $syncdir directory
# to the path
if ( xCAT::Utils - > isServiceNode ( ) ) {
my $ tmpp = $ syncdir . $ ps ;
$ ps = $ tmpp ;
}
2011-01-18 15:40:18 +00:00
$ out = xCAT::Utils - > runxcmd ( { command = > [ 'xdsh' ] ,
node = > \ @ nodes ,
arg = > [ "-e" , $ ps ]
2011-01-19 13:32:35 +00:00
} , $ ::SUBREQ , 0 , 1 ) ;
foreach my $ r ( @$ out ) {
push ( @ newoutput , $ r ) ;
}
2012-10-31 17:14:08 +00:00
# $ranaps=1;
}
# restore the runxcmd buffer
if ( $ save_xcmd_outref ) { # this means we were called with runxcmd
$ ::xcmd_outref = $ save_xcmd_outref ;
}
# TODO, will we ever need to merge
# if we ran a postscript and we were run
# using runxcmd, and there was previous output in the
# runxcmd buffer and we have output from the postscript
# then we have to merge the outputs
#if (($ranaps == 1) && ($save_xcmd_outref) && ($::xcmd_outref) ) {
# &mergeoutput($save_xcmd_outref);
#}
2011-01-18 15:40:18 +00:00
return @ newoutput ;
}
2012-06-15 15:42:45 +00:00
#-------------------------------------------------------------------------------
2009-06-25 18:17:19 +00:00
2012-06-15 15:42:45 +00:00
= head3
& bld_and_run_append
2012-07-27 18:20:08 +00:00
This builds the parm list and executes ( xdsh ) the append script file
2012-06-18 16:39:35 +00:00
on the nodes where
the corresponding append file was updated .
The append postscript has been previous sync ' d to the nodes .
2012-06-15 15:42:45 +00:00
These are the scripts after APPEND: in the syncfile
2012-06-18 16:39:35 +00:00
2012-06-15 15:42:45 +00:00
rsync returns a list of files that have been updated
in the form hostname: < full file path >
For example: node1: tmp /test/ file1 ( yes it leaves the first / off )
This routine must match that list to the input list of append files .
If there is a match , it will add the append function to
2012-07-27 18:20:08 +00:00
the append script
2012-06-15 15:42:45 +00:00
Input: the output from the xdcp rsync run
: @ ::appendlines to run
Comments:
Needs to remove the lines from rsync that are return to let
me know files were updated from the output to determine which
postscripts to run and leave any other messages
to return to the admin .
Runs xdsh with input to call /opt/xc at /share/xc at /scripts/x dcpappend . sh
2012-06-18 16:39:35 +00:00
which will perform the append function on the node .
Input is the nodesyncfiledir appendfile:orgfile appendfile2:orgfile2 ... .
2012-06-15 15:42:45 +00:00
= cut
#-------------------------------------------------------------------------------
sub bld_and_run_append
{
my ( $ hostnames , $ rsyncoutput , $ syncdir , $ nodesyncfiledir ) = @ _ ;
my @ hosts = @$ hostnames ;
my @ rsync_output = @$ rsyncoutput ;
my @ newoutput = ( ) ;
my $ dshparms ;
my $ firstpass = 1 ;
my $ headeradded = 0 ;
2012-07-27 18:20:08 +00:00
my $ processappend = 0 ;
2012-06-15 15:42:45 +00:00
2012-06-18 16:39:35 +00:00
$ ::xdcpappendparms = "$nodesyncfiledir " ;
2012-06-15 15:42:45 +00:00
# directory to save the original file to append
my $ nodesaveorgfiledir = $ nodesyncfiledir ;
$ nodesaveorgfiledir . = "/org" ;
# add append directory to the base nodesyncfiledir
$ nodesyncfiledir . = "/append" ;
2012-06-18 16:39:35 +00:00
# build the input appendfile:orgfile parsm
2012-06-15 15:42:45 +00:00
foreach my $ appendline ( @ ::appendlines ) {
if ( $ appendline =~ /(.+) -> (.+)/ )
{
my $ appendfile = $ 1 ; # append file left of arrow
my $ filetoappend = $ 2 ; # file to append right of arrow
my $ tmpappendfile = $ appendfile ;
# if service node need to add the syncdir to the path
# for the match
if ( xCAT::Utils - > isServiceNode ( ) ) {
my $ tmpp = $ syncdir . $ tmpappendfile ;
$ tmpappendfile = $ tmpp ;
}
# remove first char for the compare, we have to do this because the
# return from rsync is tmp/file1 not /tmp/file1
substr ( $ tmpappendfile , 0 , 1 ) = "" ;
# check to see if this file was rsync'd and to which hosts
foreach my $ line ( @ rsync_output ) {
my ( $ hostname , $ ps ) = split ( /: / , $ line ) ;
chomp $ ps ;
chomp $ hostname ;
if ( $ ps eq "rsync" ) { # this is a line that is not an update
# save output , if firstpass through output
if ( $ firstpass == 1 ) {
push @ newoutput , $ line ;
$ firstpass = 0 ;
}
next ;
}
# build the append script (xdcpappend.sh) parameter list,
# based on all the append files
# that were rsyn'd to at least one node
if ( $ tmpappendfile eq $ ps ) {
my $ parm = "$appendfile:$filetoappend " ;
$ ::xdcpappendparms . = $ parm ;
2012-07-27 18:20:08 +00:00
$ processappend = 1 ;
2012-06-15 15:42:45 +00:00
}
}
}
} # end for each append line
2012-06-19 17:30:35 +00:00
# add append script to each host to execute.
2012-07-27 18:20:08 +00:00
if ( $ ::appendscript && ( $ processappend == 1 ) ) {
2012-06-18 16:39:35 +00:00
# the append script has been sync'd to the site.nodesynfiledir
my $ nodeappendscript = $ nodesyncfiledir ;
$ nodeappendscript . = $ ::appendscript ;
2012-06-15 15:42:45 +00:00
foreach my $ host ( @ hosts ) {
2012-06-18 16:39:35 +00:00
push ( @ { $ dshparms - > { 'appendscripts' } { $ nodeappendscript } } , $ host ) ;
2012-06-15 15:42:45 +00:00
}
# now run xdsh
my $ out ;
foreach my $ ps ( keys % { $$ dshparms { 'appendscripts' } } ) {
my @ nodes ;
push ( @ nodes , @ { $$ dshparms { 'appendscripts' } { $ ps } } ) ;
$ out = xCAT::Utils - > runxcmd ( { command = > [ 'xdsh' ] ,
node = > \ @ nodes ,
arg = > [ $ ps , $ ::xdcpappendparms ]
} , $ ::SUBREQ , 0 , 1 ) ;
foreach my $ r ( @$ out ) {
push ( @ newoutput , $ r ) ;
}
}
}
return @ newoutput ;
}
2009-06-25 18:17:19 +00:00
#-------------------------------------------------------------------------------
2012-04-27 11:26:51 +00:00
2012-07-27 18:20:08 +00:00
= head3
& bld_and_run_merge
This builds the parm list and executes ( xdsh ) the merge script file
on the nodes where
the corresponding merge file was updated .
The merge script has been previous sync ' d to the nodes .
These are the scripts after MERGE: in the syncfile
rsync returns a list of files that have been updated
in the form hostname: < full file path >
For example: node1: tmp /test/ file1 ( yes it leaves the first / off )
This routine must match that list to the input list of merge files .
If there is a match , it will add the merge function to
the merge script
Input: the output from the xdcp rsync run
: @ ::mergelines to run
Comments:
Needs to remove the lines from rsync that are return to let
me know files were updated from the output to determine which
postscripts to run and leave any other messages
to return to the admin .
Runs xdsh with input to call /opt/xc at /share/xc at /scripts/x dcpmerge . sh
which will perform the merge function on the node .
Input is the nodesyncfiledir mergefile1:orgfile mergefile2:orgfile2 ... . ] Note: MERGE is only support on Linux and for /etc/ passwd , /etc/s hadow ,
and /etc/g roup
= cut
#-------------------------------------------------------------------------------
sub bld_and_run_merge
{
my ( $ hostnames , $ rsyncoutput , $ syncdir , $ nodesyncfiledir ) = @ _ ;
my @ hosts = @$ hostnames ;
my @ rsync_output = @$ rsyncoutput ;
my @ newoutput = ( ) ;
my $ dshparms ;
my $ firstpass = 1 ;
my $ headeradded = 0 ;
my $ processmerge = 0 ;
$ ::xdcpmergeparms = "$nodesyncfiledir " ;
# directory to save the original file to merge
my $ nodesaveorgfiledir = $ nodesyncfiledir ;
$ nodesaveorgfiledir . = "/org" ;
# add merge directory to the base nodesyncfiledir
$ nodesyncfiledir . = "/merge" ;
# build the input mergefile:orgfile parsm
foreach my $ mergeline ( @ ::mergelines ) {
if ( $ mergeline =~ /(.+) -> (.+)/ )
{
my $ mergefile = $ 1 ; # merge file left of arrow
my $ filetomerge = $ 2 ; # file to merge right of arrow
if ( ( $ filetomerge ne "/etc/passwd" )
&& ( $ filetomerge ne "/etc/group" )
&& ( $ filetomerge ne "/etc/shadow" ) ) {
my $ rsp = { } ;
$ rsp - > { error } - > [ 0 ] = "$filetomerge is not either /etc/passwd, /etc/group or /etc/shadow. Those are the only supported files for MERGE" ;
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK , 1 ) ;
return 1 ;
}
my $ tmpmergefile = $ mergefile ;
# if service node need to add the syncdir to the path
# for the match
if ( xCAT::Utils - > isServiceNode ( ) ) {
my $ tmpp = $ syncdir . $ tmpmergefile ;
$ tmpmergefile = $ tmpp ;
}
# remove first char for the compare, we have to do this because the
# return from rsync is tmp/file1 not /tmp/file1
substr ( $ tmpmergefile , 0 , 1 ) = "" ;
# check to see if this file was rsync'd and to which hosts
foreach my $ line ( @ rsync_output ) {
my ( $ hostname , $ ps ) = split ( /: / , $ line ) ;
chomp $ ps ;
chomp $ hostname ;
if ( $ ps eq "rsync" ) { # this is a line that is not an update
# save output , if firstpass through output
if ( $ firstpass == 1 ) {
push @ newoutput , $ line ;
$ firstpass = 0 ;
}
next ;
}
# build the merge script (xdcpmerge.sh) parameter list,
# based on all the merge files
# that were rsyn'd to at least one node
if ( $ tmpmergefile eq $ ps ) {
my $ parm = "$mergefile:$filetomerge " ;
$ ::xdcpmergeparms . = $ parm ;
$ processmerge = 1 ;
}
}
}
} # end for each merge line
# add merge script to each host to execute. If we need to run anything
if ( $ ::mergescript && ( $ processmerge == 1 ) ) {
# the merge script has been sync'd to the site.nodesynfiledir
my $ nodemergescript = $ nodesyncfiledir ;
$ nodemergescript . = $ ::mergescript ;
foreach my $ host ( @ hosts ) {
push ( @ { $ dshparms - > { 'mergescripts' } { $ nodemergescript } } , $ host ) ;
}
# now run xdsh
my $ out ;
foreach my $ ps ( keys % { $$ dshparms { 'mergescripts' } } ) {
my @ nodes ;
push ( @ nodes , @ { $$ dshparms { 'mergescripts' } { $ ps } } ) ;
$ out = xCAT::Utils - > runxcmd ( { command = > [ 'xdsh' ] ,
node = > \ @ nodes ,
arg = > [ $ ps , $ ::xdcpmergeparms ]
} , $ ::SUBREQ , 0 , 1 ) ;
foreach my $ r ( @$ out ) {
push ( @ newoutput , $ r ) ;
}
}
}
return @ newoutput ;
}
#-------------------------------------------------------------------------------
2012-04-27 11:26:51 +00:00
= head3
run_always_rsync_postscript
This subroutine runs the xdsh command for all the scripts listed in the
EXECUTEALWAYS: clause of the synclist file .
= cut
#-------------------------------------------------------------------------------
sub run_always_rsync_postscripts
{
my ( $ hostnames , $ syncdir ) = @ _ ;
my @ hosts = @$ hostnames ;
my @ newoutput = ( ) ;
my $ dshparms ;
foreach my $ postsfile ( @ ::alwayspostscripts ) {
my $ tmppostfile = $ postsfile ;
# if service node need to add the SNsyncfiledir to the path
if ( xCAT::Utils - > isServiceNode ( ) ) {
my $ tmpp = $ syncdir . $ tmppostfile ;
$ tmppostfile = $ tmpp ;
}
foreach my $ host ( @ hosts ) {
# build xdsh queue
# build host and all scripts to execute
push ( @ { $ dshparms - > { 'postscripts' } { $ postsfile } } , $ host ) ;
}
}
# now if we have postscripts to run, run xdsh
my $ out ;
2012-10-31 17:14:08 +00:00
# if we were called with runxcmd, like by updatenode
# need to save the runxcmd buffer
# $::xcmd_outref
my $ save_xcmd_outref ;
if ( $ ::xcmd_outref ) { # this means we were called with runxcmd
$ save_xcmd_outref = $ ::xcmd_outref ;
}
2012-04-27 11:26:51 +00:00
foreach my $ ps ( keys % { $$ dshparms { 'postscripts' } } ) {
my @ nodes ;
push ( @ nodes , @ { $$ dshparms { 'postscripts' } { $ ps } } ) ;
# if on the service node need to add the $syncdir directory
# to the path
if ( xCAT::Utils - > isServiceNode ( ) ) {
my $ tmpp = $ syncdir . $ ps ;
$ ps = $ tmpp ;
}
$ out = xCAT::Utils - > runxcmd ( { command = > [ 'xdsh' ] ,
node = > \ @ nodes ,
arg = > [ "-e" , $ ps ]
} , $ ::SUBREQ , 0 , 1 ) ;
foreach my $ r ( @$ out ) {
push ( @ newoutput , $ r ) ;
}
2012-10-31 17:14:08 +00:00
}
# restore the runxcmd buffer
if ( $ save_xcmd_outref ) { # this means we were called with runxcmd
$ ::xcmd_outref = $ save_xcmd_outref ;
2012-04-27 11:26:51 +00:00
}
return @ newoutput ;
}
#-------------------------------------------------------------------------------
2009-06-25 18:17:19 +00:00
2008-10-17 16:04:13 +00:00
= head3
runlocal_on_rootimg
This subroutine runs the xdsh command against the input image on the local
node .
Arguments:
$ optionRef:
2008-11-07 16:37:05 +00:00
Specifies a hash in which the xdsh options are provided
2008-10-17 16:04:13 +00:00
$ exitCode:
reference to an array for efficiency .
Example:
2012-05-02 10:36:05 +00:00
my @ outref = xCAT::DSHCLI - > runlocal_rootimg ( \ % options ) ;
2008-10-17 16:04:13 +00:00
= cut
#-------------------------------------------------------------------------------
sub runlocal_on_rootimg
{
my ( $ class , $ options , $ imagename ) = @ _ ;
2010-09-02 13:17:24 +00:00
my $ cmd ;
if ( xCAT::Utils - > isAIX ( ) ) { # use xcatchroot
$ cmd = "$::XCATROOT/bin/xcatchroot -i $$options{'rootimg'} \"$$options{'command'}\"" ;
} else {
$ cmd = "chroot $$options{'rootimg'} $$options{'command'}" ;
}
2008-10-17 16:04:13 +00:00
my @ output = xCAT::Utils - > runcmd ( $ cmd , 0 ) ;
if ( $ ::RUNCMD_RC != 0 )
{
my $ rsp = { } ;
2012-06-07 13:00:05 +00:00
$ rsp - > { error } - > [ 0 ] = "Command: $cmd failed, unable to process image." ;
2008-10-17 16:04:13 +00:00
xCAT::MsgUtils - > message ( "E" , $ rsp , $ ::CALLBACK , 1 ) ;
2009-06-05 15:45:25 +00:00
return ;
2008-10-17 16:04:13 +00:00
}
my @ newoutput ;
foreach my $ line ( @ output )
{
my $ newline . = $ imagename ;
$ newline . = ": " ;
$ newline . = $ line ;
$ newline . = "\n" ;
push @ newoutput , $ newline ;
}
$ ::DSH_API_MESSAGE = ( ) ;
$ ::DSH_API_MESSAGE = $ ::DSH_API_MESSAGE . join ( "" , @ newoutput ) ;
return $ ::DSH_API_MESSAGE ;
}
#-------------------------------------------------------------------------------
2007-12-12 13:38:48 +00:00
= head3
runDsh_api
This subroutine provides a concise interface to run remote command on multiple nodes .
Arguments:
2008-02-18 15:57:25 +00:00
$ optionRef:
Specifies a hash in which the dsh options are provided
2007-12-12 13:38:48 +00:00
$ exitCode:
2008-02-18 15:57:25 +00:00
Normally , if there is an error running the cmd ,
2007-12-12 13:38:48 +00:00
it will display the error msg
and exit with the cmds exit code , unless exitcode is given one of the
following values :
0 : display error msg , DO NOT exit on error , but set
$ ::RUNCMD_RC to the exit code .
- 1 : DO NOT display error msg and DO NOT exit on error , but set
$ ::RUNCMD_RC to the exit code .
- 2 : DO the default behavior ( display error msg and exit with cmds
exit code .
number > 0 : Display error msg and exit with the given code
$ refoutput:
2008-02-18 15:57:25 +00:00
if refoutput is true , then the output will be returned as a
2007-12-12 13:38:48 +00:00
reference to an array for efficiency .
Example:
my @ outref = xCAT::DSHCLI - > runDsh_api ( \ % options , - 2 ) ;
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
= cut
#-------------------------------------------------------------------------------
sub runDsh_api
{
shift ;
my ( $ optionsRef , $ exitCode , $ refoutput ) = @ _ ;
$ ::DSH_API = 1 ;
$ ::DSH_API_MESSAGE = "" ;
my $ verbose_old = $ ::VERBOSE ;
2008-10-17 16:04:13 +00:00
$ ::VERBOSE = 0 ;
2008-10-06 19:32:22 +00:00
#
# execute dsh
#
2008-10-17 16:04:13 +00:00
$ ::RUNCMD_RC = 0 ;
2007-12-12 13:38:48 +00:00
$ ::RUNCMD_RC = xCAT::DSHCLI - > execute_dsh ( $ optionsRef ) ;
2008-10-06 19:32:22 +00:00
2008-10-17 16:04:13 +00:00
$ ::DSH_API = 0 ;
$ ::VERBOSE = $ verbose_old ;
2007-12-12 13:38:48 +00:00
my $ returnCode ; #command will exit with this code
if ( $ ::RUNCMD_RC )
{
my $ dsh_api_displayerr = 1 ;
if ( defined ( $ exitCode ) && length ( $ exitCode ) && $ exitCode != - 2 )
{
if ( $ exitCode > 0 )
{
$ returnCode = $ exitCode ;
}
elsif ( $ exitCode <= 0 )
{
$ returnCode = '' ;
if ( $ exitCode < 0 )
{
$ dsh_api_displayerr = 0 ;
}
}
}
else
{
$ returnCode = $ ::RUNCMD_RC ;
}
if ( $ dsh_api_displayerr )
{
my $ errmsg = '' ;
if ( xCAT::Utils - > isLinux ( ) && $ ::RUNCMD_RC == 139 )
{
2008-10-17 16:04:13 +00:00
$ errmsg = "Return Code = 139 $errmsg" ;
2007-12-12 13:38:48 +00:00
}
else
{
$ errmsg = $ ::DSH_API_MESSAGE ;
}
2008-10-06 19:32:22 +00:00
if ( ( ! $ DSHCLI:: NO_MESSAGES ) && ( $ ::DSH_API_NODES_FAILED ) )
2007-12-12 13:38:48 +00:00
{
xCAT::MsgUtils - > message (
"E" ,
2008-11-07 16:37:05 +00:00
"xdsh command: $$optionsRef{'command'} failed on nodes:$::DSH_API_NODES_FAILED."
2007-12-12 13:38:48 +00:00
) ;
}
}
}
if ( $ refoutput )
{
my $ outputRef = [] ;
@$ outputRef = split "\n" , $ ::DSH_API_MESSAGE ;
chomp @$ outputRef ;
return $ outputRef ;
}
elsif ( wantarray )
{
my @ outputLines = split "\n" , $ ::DSH_API_MESSAGE ;
chomp @ outputLines ;
return @ outputLines ;
}
else
{
return $ ::DSH_API_MESSAGE ;
}
}
#-------------------------------------------------------------------------------
= head3
runDcp_api
2008-02-18 15:57:25 +00:00
This subroutine provides a concise interface to run remote command
2007-12-12 13:38:48 +00:00
on multiple nodes .
Arguments:
$ optionRef:
Specifies a hash in which the dsh options are provided
$ exitCode:
2008-02-18 15:57:25 +00:00
Normally , if there is an error running the cmd ,
2007-12-12 13:38:48 +00:00
it will display the error msg
2008-02-18 15:57:25 +00:00
and exit with the cmds exit code ,
2007-12-12 13:38:48 +00:00
unless exitcode is given one of the
following values :
0 : display error msg , DO NOT exit on error , but set
$ ::RUNCMD_RC to the exit code .
2008-02-18 15:57:25 +00:00
- 1 : DO NOT display error msg
2007-12-12 13:38:48 +00:00
and DO NOT exit on error , but set
$ ::RUNCMD_RC to the exit code .
2008-02-18 15:57:25 +00:00
- 2 : DO the default behavior
2007-12-12 13:38:48 +00:00
( display error msg and exit with cmds
exit code .
2008-02-18 15:57:25 +00:00
number > 0 : Display error msg and exit with the
2007-12-12 13:38:48 +00:00
given code
$ refoutput:
2008-02-18 15:57:25 +00:00
if refoutput is true , then the output
will be returned as a reference to
2007-12-12 13:38:48 +00:00
an array for efficiency .
Example:
my @ outref = xCAT::DSHCLI - > runDcp_api ( \ % options , - 2 ) ;
= cut
#-------------------------------------------------------------------------------
sub runDcp_api
{
shift ;
my ( $ optionsRef , $ exitCode , $ refoutput ) = @ _ ;
$ ::DCP_API = 1 ;
$ ::DCP_API_MESSAGE = "" ;
my $ verbose_old = $ ::VERBOSE ;
$ ::VERBOSE = 0 ;
if ( ! ref ( $ optionsRef - > { 'source' } ) )
{
$ optionsRef - > { 'source' } =~ s/\s/$::__DCP_DELIM/g ;
}
elsif ( ref ( $ optionsRef - > { 'source' } eq "ARRAY" ) )
{
$ optionsRef - > { 'source' } = join $ ::__DCP_DELIM ,
@ { $ optionsRef - > { 'source' } } ;
}
$ ::RUNCMD_RC = xCAT::DSHCLI - > execute_dcp ( $ optionsRef ) ;
$ ::DCP_API = 0 ;
$ ::VERBOSE = $ verbose_old ;
my $ returnCode ; #command will exit with this code
if ( $ ::RUNCMD_RC )
{
my $ dcp_api_displayerr = 1 ;
if ( defined ( $ exitCode ) && length ( $ exitCode ) && $ exitCode != - 2 )
{
if ( $ exitCode > 0 )
{
$ returnCode = $ exitCode ;
}
elsif ( $ exitCode <= 0 )
{
$ returnCode = '' ;
if ( $ exitCode < 0 )
{
$ dcp_api_displayerr = 0 ;
}
}
}
else
{
$ returnCode = $ ::RUNCMD_RC ;
}
if ( $ dcp_api_displayerr )
{
my $ errmsg = '' ;
if ( xCAT::Utils - > isLinux ( ) && $ ::RUNCMD_RC == 139 )
{
2008-10-17 16:04:13 +00:00
$ errmsg = "Return code=139 $errmsg" ;
2007-12-12 13:38:48 +00:00
}
else
{
$ errmsg = $ ::DCP_API_MESSAGE ;
}
if ( ! $ DSHCLI:: NO_MESSAGES )
{
xCAT::MsgUtils - > message ( "E" ,
2009-02-04 17:18:44 +00:00
"dcp command failed, Return code=$::RUNCMD_RC." ) ;
2007-12-12 13:38:48 +00:00
}
}
}
if ( $ refoutput )
{
my $ outputRef = [] ;
@$ outputRef = split "\n" , $ ::DCP_API_MESSAGE ;
chomp @$ outputRef ;
return $ outputRef ;
}
elsif ( wantarray )
{
my @ outputLines = split "\n" , $ ::DCP_API_MESSAGE ;
chomp @ outputLines ;
return @ outputLines ;
}
else
{
return $ ::DCP_API_MESSAGE ;
}
}
#-------------------------------------------------------------------------------
= head3
show_dsh_config
Displays the current configuration of the dsh command environment
and configuration information for each installed context
Arguments:
$ options - options hash table describing dsh configuration options
Returns:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Globals:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Error:
None
2008-02-18 15:57:25 +00:00
2007-12-12 13:38:48 +00:00
Example:
Comments:
= cut
#-------------------------------------------------------------------------------
sub show_dsh_config
{
my ( $ class , $ options ) = @ _ ;
xCAT::DSHCLI - > config_default_context ( $ options ) ;
my $ dsh_config = xCAT::DSHCLI - > get_dsh_config ;
foreach my $ context ( sort keys ( %$ dsh_config ) )
{
my $ context_properties = $$ dsh_config { $ context } ;
2008-07-24 14:36:56 +00:00
foreach my $ key ( sort keys ( %$ context_properties ) )
2007-12-12 13:38:48 +00:00
{
print STDOUT "$context:$key=$$context_properties{$key}\n" ;
}
}
}
2009-01-08 12:57:02 +00:00
#-------------------------------------------------------------------------------
2009-06-25 18:17:19 +00:00
= head3
get_config
2009-01-08 12:57:02 +00:00
Substitute specific keywords in hash
e . g . config file:
[ main ]
cachedir = /var/c ache / yum
keepcache = 1
[ base ]
name = Red Hat Linux $ releasever - $ basearch - Base
baseurl = http: //mi rror . dulug . duke . edu /pub/ yum - repository /redhat/ $ releasev
er /$basearch/
% config = {
main = > {
'cachedir' = > '/var/cache/yum' ,
'keepcache' = > '1'
} ,
bash = > {
'name' = > ' Red Hat Linux $ relea
sever - $ basearch - Base ' ,
'baseurl' = > ' http: //mi rror . dulug .
duke . edu /pub/ yum - repository /redhat/ $ releasever /$basearch/ '
}
}
Arguments:
$ configfile - config file
Returns:
$ config_ref - reference to config hash
Comments:
= cut
#-------------------------------------------------------------------------------
sub get_config
{
2009-02-04 17:18:44 +00:00
my $ configfile = shift ;
my @ content = readFile ( $ configfile ) ;
2009-01-08 12:57:02 +00:00
my $ current_section = "DEFAULT" ;
my % config ;
my $ xcat_use ;
$ xcat_use = 0 ;
foreach my $ line ( @ content )
{
my ( $ entry , $ value ) ;
chomp $ line ;
2009-02-04 17:18:44 +00:00
if ( $ line =~ /\QDO NOT ERASE THIS SECTION\E/ )
2009-01-08 12:57:02 +00:00
{
2009-02-04 17:18:44 +00:00
# reverse flag
$ xcat_use = ! $ xcat_use ;
2009-01-08 12:57:02 +00:00
}
if ( $ xcat_use )
{
2009-02-04 17:18:44 +00:00
# Remove leading "#". This line is used by xCAT
$ line =~ s/^#//g ;
2009-01-08 12:57:02 +00:00
}
else
{
2009-02-04 17:18:44 +00:00
# Remove comment line
$ line =~ s/#.*$//g ;
2009-01-08 12:57:02 +00:00
}
$ line =~ s/^\s+//g ;
$ line =~ s/\s+$//g ;
next unless $ line ;
2009-02-04 17:18:44 +00:00
if ( $ line =~ /^\s*\[([\w+-\.]+)\]\s*$/ )
{
2009-01-08 12:57:02 +00:00
$ current_section = $ 1 ;
2009-02-04 17:18:44 +00:00
}
else
{
2009-01-08 12:57:02 +00:00
# Ignore line doesn't key/value pair.
if ( $ line !~ /=/ )
{
next ;
}
$ line =~ /^\s*([^=]*)\s*=\s*(.*)\s*$/ ;
$ entry = $ 1 ;
$ value = $ 2 ;
$ entry =~ s/^#*//g ;
2009-02-04 17:18:44 +00:00
2009-01-08 12:57:02 +00:00
# Remove leading and trailing spaces
$ entry =~ s/^\s+//g ;
$ entry =~ s/\s+$//g ;
$ value =~ s/^\s+//g ;
$ value =~ s/\s+$//g ;
$ config { $ current_section } { "$entry" } = $ value ;
}
}
return \ % config ;
}
#-------------------------------------------------------------------------------
= head3 readFile
Read a file and return its content .
Arguments:
filename
Returns:
file contents or undef
Globals:
none
Error:
undef
Example:
my $ blah = readFile ( '/etc/redhat-release' ) ;
Comments:
none
= cut
#-------------------------------------------------------------------------------
sub readFile
{
my $ filename = shift ;
open ( FILE , "<$filename" ) ;
my @ contents = <FILE> ;
close ( FILE ) ;
return @ contents ;
}
2007-12-12 13:38:48 +00:00
1 ;