line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# |
2
|
|
|
|
|
|
|
# (c) Jan Gehring |
3
|
|
|
|
|
|
|
# |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
package Rex::CLI; |
6
|
|
|
|
|
|
|
|
7
|
15
|
|
|
15
|
|
114605
|
use v5.12.5; |
|
15
|
|
|
|
|
74
|
|
8
|
15
|
|
|
15
|
|
76
|
use warnings; |
|
15
|
|
|
|
|
30
|
|
|
15
|
|
|
|
|
646
|
|
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
our $VERSION = '1.14.2.3'; # TRIAL VERSION |
11
|
|
|
|
|
|
|
|
12
|
15
|
|
|
15
|
|
691
|
use English qw(-no_match_vars); |
|
15
|
|
|
|
|
3915
|
|
|
15
|
|
|
|
|
117
|
|
13
|
15
|
|
|
15
|
|
6427
|
use FindBin; |
|
15
|
|
|
|
|
15557
|
|
|
15
|
|
|
|
|
716
|
|
14
|
15
|
|
|
15
|
|
102
|
use File::Basename qw(basename dirname); |
|
15
|
|
|
|
|
36
|
|
|
15
|
|
|
|
|
977
|
|
15
|
15
|
|
|
15
|
|
1140
|
use Time::HiRes qw(gettimeofday tv_interval); |
|
15
|
|
|
|
|
2830
|
|
|
15
|
|
|
|
|
77
|
|
16
|
15
|
|
|
15
|
|
1618
|
use Cwd qw(getcwd); |
|
15
|
|
|
|
|
28
|
|
|
15
|
|
|
|
|
580
|
|
17
|
15
|
|
|
15
|
|
66
|
use List::Util qw(max); |
|
15
|
|
|
|
|
27
|
|
|
15
|
|
|
|
|
1806
|
|
18
|
15
|
|
|
15
|
|
1274
|
use Text::Wrap; |
|
15
|
|
|
|
|
27365
|
|
|
15
|
|
|
|
|
805
|
|
19
|
15
|
|
|
15
|
|
1443
|
use Term::ANSIColor; |
|
15
|
|
|
|
|
17031
|
|
|
15
|
|
|
|
|
925
|
|
20
|
15
|
|
|
15
|
|
1113
|
use Term::ReadKey; |
|
15
|
|
|
|
|
30870
|
|
|
15
|
|
|
|
|
1369
|
|
21
|
15
|
|
|
15
|
|
1391
|
use Sort::Naturally; |
|
15
|
|
|
|
|
46586
|
|
|
15
|
|
|
|
|
1175
|
|
22
|
|
|
|
|
|
|
|
23
|
15
|
|
|
15
|
|
1286
|
use if $OSNAME eq 'MSWin32', 'Win32::Console::ANSI'; |
|
15
|
|
|
|
|
53
|
|
|
15
|
|
|
|
|
277
|
|
24
|
|
|
|
|
|
|
|
25
|
15
|
|
|
15
|
|
1715
|
use Rex; |
|
15
|
|
|
|
|
32
|
|
|
15
|
|
|
|
|
79
|
|
26
|
15
|
|
|
15
|
|
92
|
use Rex::Args; |
|
15
|
|
|
|
|
30
|
|
|
15
|
|
|
|
|
175
|
|
27
|
15
|
|
|
15
|
|
340
|
use Rex::Config; |
|
15
|
|
|
|
|
30
|
|
|
15
|
|
|
|
|
109
|
|
28
|
15
|
|
|
15
|
|
152
|
use Rex::Group; |
|
15
|
|
|
|
|
41
|
|
|
15
|
|
|
|
|
183
|
|
29
|
15
|
|
|
15
|
|
514
|
use Rex::Batch; |
|
15
|
|
|
|
|
31
|
|
|
15
|
|
|
|
|
158
|
|
30
|
15
|
|
|
15
|
|
448
|
use Rex::TaskList; |
|
15
|
|
|
|
|
31
|
|
|
15
|
|
|
|
|
47
|
|
31
|
15
|
|
|
15
|
|
293
|
use Rex::Logger; |
|
15
|
|
|
|
|
24
|
|
|
15
|
|
|
|
|
53
|
|
32
|
15
|
|
|
15
|
|
286
|
use YAML; |
|
15
|
|
|
|
|
20
|
|
|
15
|
|
|
|
|
888
|
|
33
|
|
|
|
|
|
|
|
34
|
15
|
|
|
15
|
|
87
|
use Data::Dumper; |
|
15
|
|
|
|
|
30
|
|
|
15
|
|
|
|
|
884
|
|
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
my $no_color = 0; |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
# preload some modules |
39
|
15
|
|
|
15
|
|
99
|
use Rex -base; |
|
15
|
|
|
|
|
34
|
|
|
15
|
|
|
|
|
101
|
|
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
$OUTPUT_AUTOFLUSH++; |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
my ( %opts, @help, @exit ); |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
if ( $#ARGV < 0 ) { |
46
|
|
|
|
|
|
|
@ARGV = qw(-h); |
47
|
|
|
|
|
|
|
} |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
sub new { |
50
|
0
|
|
|
0
|
0
|
0
|
my $that = shift; |
51
|
0
|
|
0
|
|
|
0
|
my $proto = ref($that) || $that; |
52
|
0
|
|
|
|
|
0
|
my $self = {@_}; |
53
|
|
|
|
|
|
|
|
54
|
0
|
|
|
|
|
0
|
bless( $self, $proto ); |
55
|
|
|
|
|
|
|
|
56
|
0
|
|
|
|
|
0
|
return $self; |
57
|
|
|
|
|
|
|
} |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
sub __run__ { |
60
|
0
|
|
|
0
|
|
0
|
my ( $self, %more_args ) = @_; |
61
|
|
|
|
|
|
|
|
62
|
0
|
|
|
|
|
0
|
Rex::Args->parse_rex_opts; |
63
|
0
|
|
|
|
|
0
|
%opts = Rex::Args->getopts; |
64
|
|
|
|
|
|
|
|
65
|
0
|
0
|
|
|
|
0
|
if ( $opts{'Q'} ) { |
66
|
0
|
|
|
|
|
0
|
my $stdout; |
67
|
0
|
|
|
|
|
0
|
open( my $newout, '>', \$stdout ); |
68
|
0
|
|
|
|
|
0
|
select $newout; |
69
|
0
|
|
|
|
|
0
|
close(STDERR); |
70
|
|
|
|
|
|
|
} |
71
|
|
|
|
|
|
|
|
72
|
0
|
0
|
|
|
|
0
|
if ( $opts{'m'} ) { |
73
|
0
|
|
|
|
|
0
|
$no_color = 1; |
74
|
0
|
|
|
|
|
0
|
$Rex::Logger::no_color = 1; |
75
|
|
|
|
|
|
|
} |
76
|
|
|
|
|
|
|
|
77
|
0
|
0
|
|
|
|
0
|
if ( $opts{'d'} ) { |
78
|
0
|
|
|
|
|
0
|
$Rex::Logger::debug = $opts{'d'}; |
79
|
0
|
|
|
|
|
0
|
$Rex::Logger::silent = 0; |
80
|
|
|
|
|
|
|
} |
81
|
|
|
|
|
|
|
|
82
|
0
|
|
|
|
|
0
|
Rex::Config->set_use_cache(1); |
83
|
0
|
0
|
|
|
|
0
|
if ( $opts{"c"} ) { |
|
|
0
|
|
|
|
|
|
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
# Rex::Config->set_use_cache(1); |
86
|
|
|
|
|
|
|
# since 0.46 just a pseudo option |
87
|
|
|
|
|
|
|
# cache is enabled by default |
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
elsif ( $opts{"C"} ) { |
90
|
0
|
|
|
|
|
0
|
Rex::Config->set_use_cache(0); |
91
|
|
|
|
|
|
|
} |
92
|
|
|
|
|
|
|
|
93
|
0
|
|
|
|
|
0
|
Rex::Logger::debug("This is Rex version: $Rex::VERSION"); |
94
|
0
|
|
|
|
|
0
|
Rex::Logger::debug("Command Line Parameters"); |
95
|
0
|
|
|
|
|
0
|
for my $param ( keys %opts ) { |
96
|
0
|
|
|
|
|
0
|
Rex::Logger::debug( "\t$param = " . $opts{$param} ); |
97
|
|
|
|
|
|
|
} |
98
|
|
|
|
|
|
|
|
99
|
0
|
0
|
0
|
|
|
0
|
if ( $opts{'h'} ) { |
|
|
0
|
|
|
|
|
|
100
|
0
|
|
|
|
|
0
|
$self->__help__; |
101
|
|
|
|
|
|
|
} |
102
|
|
|
|
|
|
|
elsif ( $opts{'v'} && !$opts{'T'} ) { |
103
|
0
|
|
|
|
|
0
|
$self->__version__; |
104
|
|
|
|
|
|
|
} |
105
|
|
|
|
|
|
|
|
106
|
0
|
0
|
|
|
|
0
|
if ( $opts{'q'} ) { |
107
|
0
|
|
|
|
|
0
|
$::QUIET = 1; |
108
|
0
|
0
|
|
|
|
0
|
if ( $opts{'w'} ) { |
109
|
0
|
|
|
|
|
0
|
$::QUIET = 2; |
110
|
|
|
|
|
|
|
} |
111
|
|
|
|
|
|
|
} |
112
|
|
|
|
|
|
|
|
113
|
0
|
|
|
|
|
0
|
$::rexfile = "Rexfile"; |
114
|
0
|
0
|
|
|
|
0
|
if ( $opts{'f'} ) { |
115
|
0
|
|
|
|
|
0
|
Rex::Logger::debug( "Using Rexfile: " . $opts{'f'} ); |
116
|
0
|
|
|
|
|
0
|
$::rexfile = $opts{'f'}; |
117
|
|
|
|
|
|
|
} |
118
|
|
|
|
|
|
|
else { |
119
|
0
|
0
|
0
|
|
|
0
|
if ( ( !-e $::rexfile ) && ( $ARGV[0] && $ARGV[0] =~ /:/ ) ) { |
|
|
|
0
|
|
|
|
|
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
#if there is no Rexfile, and the user asks for a longer path task, see if we can use it as the Rexfile |
122
|
|
|
|
|
|
|
#eg: rex -H $host Misc:Example:prepare --bar=baz |
123
|
0
|
|
|
|
|
0
|
$::rexfile = $ARGV[0]; |
124
|
0
|
|
|
|
|
0
|
$::rexfile =~ s/:[^:]*$//; |
125
|
0
|
|
|
|
|
0
|
$::rexfile =~ s{:}{/}g; |
126
|
0
|
|
|
|
|
0
|
$::rexfile = 'Rex/' . $::rexfile . '.pm'; |
127
|
|
|
|
|
|
|
} |
128
|
|
|
|
|
|
|
} |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
FORCE_SERVER: { |
131
|
|
|
|
|
|
|
|
132
|
0
|
0
|
|
|
|
0
|
if ( $opts{'H'} ) { |
|
0
|
|
|
|
|
0
|
|
133
|
0
|
0
|
|
|
|
0
|
if ( $opts{'H'} =~ m/^perl:(.*)/ ) { |
134
|
0
|
|
|
|
|
0
|
my $host_eval = eval($1); |
135
|
|
|
|
|
|
|
|
136
|
0
|
0
|
|
|
|
0
|
if ( ref($host_eval) eq "ARRAY" ) { |
137
|
0
|
|
|
|
|
0
|
$::FORCE_SERVER = join( " ", @{$host_eval} ); |
|
0
|
|
|
|
|
0
|
|
138
|
|
|
|
|
|
|
} |
139
|
|
|
|
|
|
|
else { |
140
|
0
|
|
|
|
|
0
|
die("Perl Code have to return an array reference."); |
141
|
|
|
|
|
|
|
} |
142
|
|
|
|
|
|
|
} |
143
|
|
|
|
|
|
|
else { |
144
|
0
|
|
|
|
|
0
|
$::FORCE_SERVER = $opts{'H'}; |
145
|
|
|
|
|
|
|
} |
146
|
|
|
|
|
|
|
} |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
} |
149
|
|
|
|
|
|
|
|
150
|
0
|
0
|
|
|
|
0
|
if ( $opts{'z'} ) { |
151
|
0
|
|
|
|
|
0
|
my $host_eval = eval { `$opts{'z'}`; }; |
|
0
|
|
|
|
|
0
|
|
152
|
0
|
0
|
|
|
|
0
|
if ( $host_eval =~ m/\S/xms ) { |
153
|
0
|
|
|
|
|
0
|
$::FORCE_SERVER = join( " ", split /\n|,|;/, $host_eval ); |
154
|
|
|
|
|
|
|
} |
155
|
|
|
|
|
|
|
else { |
156
|
0
|
|
|
|
|
0
|
$::FORCE_SERVER = $opts{'H'}; |
157
|
|
|
|
|
|
|
} |
158
|
|
|
|
|
|
|
} |
159
|
|
|
|
|
|
|
|
160
|
0
|
0
|
|
|
|
0
|
if ( $opts{'z'} ) { |
161
|
0
|
|
|
|
|
0
|
my $host_eval = eval { `$opts{'z'}`; }; |
|
0
|
|
|
|
|
0
|
|
162
|
0
|
0
|
|
|
|
0
|
if ( $host_eval =~ m/\S/xms ) { |
163
|
0
|
|
|
|
|
0
|
$::FORCE_SERVER = join( " ", split /\n|,|;/, $host_eval ); |
164
|
|
|
|
|
|
|
} |
165
|
|
|
|
|
|
|
else { |
166
|
0
|
|
|
|
|
0
|
Rex::Logger::info("You must give a valid command."); |
167
|
|
|
|
|
|
|
} |
168
|
|
|
|
|
|
|
} |
169
|
|
|
|
|
|
|
|
170
|
0
|
0
|
|
|
|
0
|
if ( $opts{'o'} ) { |
171
|
0
|
|
|
|
|
0
|
Rex::Output->require; |
172
|
0
|
|
|
|
|
0
|
Rex::Output->get( $opts{'o'} ); |
173
|
|
|
|
|
|
|
} |
174
|
|
|
|
|
|
|
|
175
|
0
|
|
|
|
|
0
|
handle_lock_file($::rexfile); |
176
|
|
|
|
|
|
|
|
177
|
0
|
0
|
|
|
|
0
|
Rex::Config->set_environment( $opts{"E"} ) if ( $opts{"E"} ); |
178
|
|
|
|
|
|
|
|
179
|
0
|
0
|
0
|
|
|
0
|
if ( $opts{'g'} || $opts{'G'} ) { |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
#$::FORCE_SERVER = "\0" . $opts{'g'}; |
182
|
0
|
|
0
|
|
|
0
|
$opts{'g'} ||= $opts{'G'}; |
183
|
|
|
|
|
|
|
|
184
|
0
|
0
|
|
|
|
0
|
if ( ref $opts{'g'} ne "ARRAY" ) { |
185
|
0
|
|
|
|
|
0
|
$::FORCE_SERVER = [ $opts{'g'} ]; |
186
|
|
|
|
|
|
|
} |
187
|
|
|
|
|
|
|
else { |
188
|
0
|
|
|
|
|
0
|
$::FORCE_SERVER = $opts{'g'}; |
189
|
|
|
|
|
|
|
} |
190
|
|
|
|
|
|
|
} |
191
|
|
|
|
|
|
|
|
192
|
0
|
|
|
|
|
0
|
load_server_ini_file($::rexfile); |
193
|
0
|
|
|
|
|
0
|
load_rexfile($::rexfile); |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
#### check if some parameters should be overwritten from the command line |
196
|
|
|
|
|
|
|
CHECK_OVERWRITE: { |
197
|
|
|
|
|
|
|
|
198
|
0
|
|
|
|
|
0
|
my $pass_auth = 0; |
|
0
|
|
|
|
|
0
|
|
199
|
|
|
|
|
|
|
|
200
|
0
|
0
|
|
|
|
0
|
if ( $opts{'u'} ) { |
201
|
0
|
|
|
|
|
0
|
Rex::Commands::user( $opts{'u'} ); |
202
|
0
|
|
|
|
|
0
|
for my $task ( Rex::TaskList->create()->get_tasks ) { |
203
|
0
|
|
|
|
|
0
|
Rex::TaskList->create()->get_task($task)->set_user( $opts{'u'} ); |
204
|
|
|
|
|
|
|
} |
205
|
|
|
|
|
|
|
} |
206
|
|
|
|
|
|
|
|
207
|
0
|
0
|
|
|
|
0
|
if ( $opts{'p'} ) { |
208
|
0
|
|
|
|
|
0
|
Rex::Commands::password( $opts{'p'} ); |
209
|
|
|
|
|
|
|
|
210
|
0
|
0
|
|
|
|
0
|
unless ( $opts{'P'} ) { |
211
|
0
|
|
|
|
|
0
|
$pass_auth = 1; |
212
|
|
|
|
|
|
|
} |
213
|
|
|
|
|
|
|
|
214
|
0
|
|
|
|
|
0
|
for my $task ( Rex::TaskList->create()->get_tasks ) { |
215
|
0
|
|
|
|
|
0
|
Rex::TaskList->create()->get_task($task)->set_password( $opts{'p'} ); |
216
|
|
|
|
|
|
|
} |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
} |
219
|
|
|
|
|
|
|
|
220
|
0
|
0
|
|
|
|
0
|
if ( $opts{'P'} ) { |
221
|
0
|
|
|
|
|
0
|
Rex::Commands::private_key( $opts{'P'} ); |
222
|
|
|
|
|
|
|
|
223
|
0
|
|
|
|
|
0
|
for my $task ( Rex::TaskList->create()->get_tasks ) { |
224
|
|
|
|
|
|
|
Rex::TaskList->create()->get_task($task) |
225
|
0
|
|
|
|
|
0
|
->set_auth( "private_key", $opts{'P'} ); |
226
|
|
|
|
|
|
|
} |
227
|
|
|
|
|
|
|
} |
228
|
|
|
|
|
|
|
|
229
|
0
|
0
|
|
|
|
0
|
if ( $opts{'K'} ) { |
230
|
0
|
|
|
|
|
0
|
Rex::Commands::public_key( $opts{'K'} ); |
231
|
|
|
|
|
|
|
|
232
|
0
|
|
|
|
|
0
|
for my $task ( Rex::TaskList->create()->get_tasks ) { |
233
|
|
|
|
|
|
|
Rex::TaskList->create()->get_task($task) |
234
|
0
|
|
|
|
|
0
|
->set_auth( "public_key", $opts{'K'} ); |
235
|
|
|
|
|
|
|
} |
236
|
|
|
|
|
|
|
} |
237
|
|
|
|
|
|
|
|
238
|
0
|
0
|
|
|
|
0
|
if ($pass_auth) { |
239
|
0
|
|
|
|
|
0
|
pass_auth; |
240
|
|
|
|
|
|
|
} |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
} |
243
|
|
|
|
|
|
|
|
244
|
0
|
|
|
|
|
0
|
Rex::Logger::debug("Initializing Logger from parameters found in $::rexfile"); |
245
|
|
|
|
|
|
|
|
246
|
0
|
0
|
0
|
|
|
0
|
if ( $opts{'T'} && $opts{'m'} ) { |
|
|
0
|
0
|
|
|
|
|
|
|
0
|
|
|
|
|
|
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
# create machine readable tasklist |
249
|
0
|
|
|
|
|
0
|
my @tasks = Rex::TaskList->create()->get_tasks; |
250
|
0
|
|
|
|
|
0
|
for my $task (@tasks) { |
251
|
0
|
|
|
|
|
0
|
my $desc = Rex::TaskList->create()->get_desc($task); |
252
|
0
|
|
|
|
|
0
|
$desc =~ s/'/\\'/gms; |
253
|
0
|
|
|
|
|
0
|
print "'$task'" . " = '$desc'\n"; |
254
|
|
|
|
|
|
|
} |
255
|
|
|
|
|
|
|
} |
256
|
|
|
|
|
|
|
elsif ( $opts{'T'} && $opts{'y'} ) { |
257
|
0
|
|
|
|
|
0
|
my @tasks = Rex::TaskList->create()->get_tasks; |
258
|
0
|
|
|
|
|
0
|
my @envs = Rex::Commands->get_environments(); |
259
|
0
|
|
|
|
|
0
|
my %groups = Rex::Group->get_groups; |
260
|
|
|
|
|
|
|
|
261
|
0
|
|
|
|
|
0
|
my %real_groups; |
262
|
|
|
|
|
|
|
|
263
|
0
|
|
|
|
|
0
|
for my $group ( keys %groups ) { |
264
|
0
|
|
|
|
|
0
|
my @servers = map { $_->get_servers } |
|
0
|
|
|
|
|
0
|
|
265
|
|
|
|
|
|
|
Rex::Group->get_group_object($group)->get_servers; |
266
|
0
|
|
|
|
|
0
|
$real_groups{$group} = \@servers; |
267
|
|
|
|
|
|
|
} |
268
|
|
|
|
|
|
|
|
269
|
0
|
|
|
|
|
0
|
print YAML::Dump( |
270
|
|
|
|
|
|
|
{ |
271
|
|
|
|
|
|
|
tasks => \@tasks, |
272
|
|
|
|
|
|
|
envs => \@envs, |
273
|
|
|
|
|
|
|
groups => \%real_groups, |
274
|
|
|
|
|
|
|
} |
275
|
|
|
|
|
|
|
); |
276
|
|
|
|
|
|
|
} |
277
|
|
|
|
|
|
|
elsif ( $opts{'T'} ) { |
278
|
0
|
|
|
|
|
0
|
_handle_T(%opts); |
279
|
|
|
|
|
|
|
|
280
|
0
|
|
|
|
|
0
|
Rex::global_sudo(0); |
281
|
0
|
0
|
|
|
|
0
|
Rex::Logger::debug("Removing lockfile") if ( !exists $opts{'F'} ); |
282
|
0
|
0
|
|
|
|
0
|
CORE::unlink("$::rexfile.lock") if ( !exists $opts{'F'} ); |
283
|
0
|
|
|
|
|
0
|
CORE::exit 0; |
284
|
|
|
|
|
|
|
} |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
# turn sudo on with cli option s is used |
287
|
0
|
0
|
|
|
|
0
|
if ( exists $opts{'s'} ) { |
288
|
0
|
|
|
|
|
0
|
sudo("on"); |
289
|
|
|
|
|
|
|
} |
290
|
0
|
0
|
|
|
|
0
|
if ( exists $opts{'S'} ) { |
291
|
0
|
|
|
|
|
0
|
sudo_password( $opts{'S'} ); |
292
|
|
|
|
|
|
|
} |
293
|
|
|
|
|
|
|
|
294
|
0
|
0
|
|
|
|
0
|
if ( exists $opts{'t'} ) { |
295
|
0
|
|
|
|
|
0
|
parallelism( $opts{'t'} ); |
296
|
|
|
|
|
|
|
} |
297
|
|
|
|
|
|
|
|
298
|
0
|
0
|
|
|
|
0
|
if ( $opts{'e'} ) { |
|
|
0
|
|
|
|
|
|
299
|
0
|
|
|
|
|
0
|
Rex::Logger::debug("Executing command line code"); |
300
|
0
|
|
|
|
|
0
|
Rex::Logger::debug( "\t" . $opts{'e'} ); |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
# execute the given code |
303
|
0
|
|
|
|
|
0
|
my $code = "sub { \n"; |
304
|
0
|
|
|
|
|
0
|
$code .= $opts{'e'} . "\n"; |
305
|
0
|
|
|
|
|
0
|
$code .= "}"; |
306
|
|
|
|
|
|
|
|
307
|
0
|
|
|
|
|
0
|
$code = eval($code); |
308
|
|
|
|
|
|
|
|
309
|
0
|
0
|
|
|
|
0
|
if ($EVAL_ERROR) { |
310
|
0
|
|
|
|
|
0
|
Rex::Logger::info( "Error in eval line: $EVAL_ERROR\n", "warn" ); |
311
|
0
|
|
|
|
|
0
|
exit 1; |
312
|
|
|
|
|
|
|
} |
313
|
|
|
|
|
|
|
|
314
|
0
|
0
|
|
|
|
0
|
if ( exists $opts{'t'} ) { |
315
|
0
|
|
|
|
|
0
|
parallelism( $opts{'t'} ); |
316
|
|
|
|
|
|
|
} |
317
|
|
|
|
|
|
|
|
318
|
0
|
|
|
|
|
0
|
my $pass_auth = 0; |
319
|
|
|
|
|
|
|
|
320
|
0
|
0
|
|
|
|
0
|
if ( $opts{'u'} ) { |
321
|
0
|
|
|
|
|
0
|
Rex::Commands::user( $opts{'u'} ); |
322
|
|
|
|
|
|
|
} |
323
|
|
|
|
|
|
|
|
324
|
0
|
0
|
|
|
|
0
|
if ( $opts{'p'} ) { |
325
|
0
|
|
|
|
|
0
|
Rex::Commands::password( $opts{'p'} ); |
326
|
|
|
|
|
|
|
|
327
|
0
|
0
|
|
|
|
0
|
unless ( $opts{'P'} ) { |
328
|
0
|
|
|
|
|
0
|
$pass_auth = 1; |
329
|
|
|
|
|
|
|
} |
330
|
|
|
|
|
|
|
} |
331
|
|
|
|
|
|
|
|
332
|
0
|
0
|
|
|
|
0
|
if ( $opts{'P'} ) { |
333
|
0
|
|
|
|
|
0
|
Rex::Commands::private_key( $opts{'P'} ); |
334
|
|
|
|
|
|
|
} |
335
|
|
|
|
|
|
|
|
336
|
0
|
0
|
|
|
|
0
|
if ( $opts{'K'} ) { |
337
|
0
|
|
|
|
|
0
|
Rex::Commands::public_key( $opts{'K'} ); |
338
|
|
|
|
|
|
|
} |
339
|
|
|
|
|
|
|
|
340
|
0
|
0
|
|
|
|
0
|
if ($pass_auth) { |
341
|
0
|
|
|
|
|
0
|
pass_auth; |
342
|
|
|
|
|
|
|
} |
343
|
|
|
|
|
|
|
|
344
|
0
|
|
|
|
|
0
|
my @params = (); |
345
|
0
|
0
|
|
|
|
0
|
if ( $opts{'H'} ) { |
346
|
0
|
|
|
|
|
0
|
push @params, split( /\s+/, $opts{'H'} ); |
347
|
|
|
|
|
|
|
} |
348
|
0
|
|
|
|
|
0
|
push @params, $code; |
349
|
0
|
|
|
|
|
0
|
push @params, "eval-line-desc"; |
350
|
0
|
|
|
|
|
0
|
push @params, {}; |
351
|
|
|
|
|
|
|
|
352
|
0
|
|
|
|
|
0
|
Rex::TaskList->create()->create_task( "eval-line", @params ); |
353
|
0
|
|
|
|
|
0
|
Rex::Commands::do_task("eval-line"); |
354
|
0
|
|
|
|
|
0
|
exit_rex(); |
355
|
|
|
|
|
|
|
} |
356
|
|
|
|
|
|
|
elsif ( $opts{'M'} ) { |
357
|
0
|
|
|
|
|
0
|
Rex::Logger::debug( "Loading Rex-Module: " . $opts{'M'} ); |
358
|
0
|
|
|
|
|
0
|
my $mod = $opts{'M'}; |
359
|
0
|
|
|
|
|
0
|
$mod =~ s{::}{/}g; |
360
|
0
|
|
|
|
|
0
|
$mod .= ".pm"; |
361
|
0
|
|
|
|
|
0
|
require $mod; |
362
|
|
|
|
|
|
|
} |
363
|
|
|
|
|
|
|
|
364
|
0
|
|
|
|
|
0
|
my $run_list = Rex::RunList->instance; |
365
|
|
|
|
|
|
|
|
366
|
0
|
0
|
|
|
|
0
|
if ( $opts{'b'} ) { |
367
|
0
|
|
|
|
|
0
|
my $batch = $opts{'b'}; |
368
|
0
|
|
|
|
|
0
|
Rex::Logger::debug("Running batch: $batch"); |
369
|
0
|
|
|
|
|
0
|
$run_list->add_task($_) for Rex::Batch->get_batch($batch); |
370
|
|
|
|
|
|
|
} |
371
|
|
|
|
|
|
|
|
372
|
0
|
|
|
|
|
0
|
$run_list->parse_opts(@ARGV); |
373
|
|
|
|
|
|
|
|
374
|
0
|
|
|
|
|
0
|
eval { $run_list->run_tasks }; |
|
0
|
|
|
|
|
0
|
|
375
|
0
|
0
|
|
|
|
0
|
if ($EVAL_ERROR) { |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
# this is always the child |
378
|
0
|
|
|
|
|
0
|
Rex::Logger::info( "Error running task/batch: $EVAL_ERROR", "warn" ); |
379
|
0
|
|
|
|
|
0
|
CORE::exit(0); |
380
|
|
|
|
|
|
|
} |
381
|
|
|
|
|
|
|
|
382
|
0
|
|
|
|
|
0
|
exit_rex(); |
383
|
|
|
|
|
|
|
} |
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
sub _print_color { |
386
|
0
|
|
|
0
|
|
0
|
my ( $msg, $color ) = @_; |
387
|
0
|
0
|
|
|
|
0
|
$color = 'green' if !defined($color); |
388
|
|
|
|
|
|
|
|
389
|
0
|
0
|
|
|
|
0
|
if ($no_color) { |
390
|
0
|
|
|
|
|
0
|
print $msg; |
391
|
|
|
|
|
|
|
} |
392
|
|
|
|
|
|
|
else { |
393
|
0
|
|
|
|
|
0
|
print colored( [$color], $msg ); |
394
|
|
|
|
|
|
|
} |
395
|
|
|
|
|
|
|
} |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
sub __help__ { |
398
|
|
|
|
|
|
|
|
399
|
0
|
|
|
0
|
|
0
|
my $fmt = " %-6s %s\n"; |
400
|
|
|
|
|
|
|
|
401
|
0
|
|
|
|
|
0
|
print "usage: \n"; |
402
|
0
|
|
|
|
|
0
|
print " rex [] [-H ] [-G ] []\n"; |
403
|
0
|
|
|
|
|
0
|
print " rex -T[m|y|v] []\n"; |
404
|
0
|
|
|
|
|
0
|
print "\n"; |
405
|
0
|
|
|
|
|
0
|
printf $fmt, "-b", "Run batch"; |
406
|
0
|
|
|
|
|
0
|
printf $fmt, "-e", "Run the given code fragment"; |
407
|
0
|
|
|
|
|
0
|
printf $fmt, "-E", "Execute a task on the given environment"; |
408
|
0
|
|
|
|
|
0
|
printf $fmt, "-G|-g", "Execute a task on the given server groups"; |
409
|
0
|
|
|
|
|
0
|
printf $fmt, "-H", "Execute a task on the given hosts (space delimited)"; |
410
|
0
|
|
|
|
|
0
|
printf $fmt, "-z", "Execute a task on hosts from this command's output"; |
411
|
0
|
|
|
|
|
0
|
print "\n"; |
412
|
0
|
|
|
|
|
0
|
printf $fmt, "-K", "Public key file for the ssh connection"; |
413
|
0
|
|
|
|
|
0
|
printf $fmt, "-P", "Private key file for the ssh connection"; |
414
|
0
|
|
|
|
|
0
|
printf $fmt, "-p", "Password for the ssh connection"; |
415
|
0
|
|
|
|
|
0
|
printf $fmt, "-u", "Username for the ssh connection"; |
416
|
0
|
|
|
|
|
0
|
print "\n"; |
417
|
0
|
|
|
|
|
0
|
printf $fmt, "-d", "Show debug output"; |
418
|
0
|
|
|
|
|
0
|
printf $fmt, "-ddd", "Show more debug output (includes profiling output)"; |
419
|
0
|
|
|
|
|
0
|
printf $fmt, "-m", "Monochrome output: no colors"; |
420
|
0
|
|
|
|
|
0
|
printf $fmt, "-o", "Output format"; |
421
|
0
|
|
|
|
|
0
|
printf $fmt, "-q", "Quiet mode: no log output"; |
422
|
0
|
|
|
|
|
0
|
printf $fmt, "-qw", "Quiet mode: only output warnings and errors"; |
423
|
0
|
|
|
|
|
0
|
printf $fmt, "-Q", "Really quiet: output nothing"; |
424
|
0
|
|
|
|
|
0
|
print "\n"; |
425
|
0
|
|
|
|
|
0
|
printf $fmt, "-T", "List tasks"; |
426
|
0
|
|
|
|
|
0
|
printf $fmt, "-Ta", "List all tasks, including hidden"; |
427
|
0
|
|
|
|
|
0
|
printf $fmt, "-Tm", "List tasks in machine-readable format"; |
428
|
0
|
|
|
|
|
0
|
printf $fmt, "-Tv", "List tasks verbosely"; |
429
|
0
|
|
|
|
|
0
|
printf $fmt, "-Ty", "List tasks in YAML format"; |
430
|
0
|
|
|
|
|
0
|
print "\n"; |
431
|
0
|
|
|
|
|
0
|
printf $fmt, "-c", "Turn cache ON"; |
432
|
0
|
|
|
|
|
0
|
printf $fmt, "-C", "Turn cache OFF"; |
433
|
0
|
|
|
|
|
0
|
printf $fmt, "-f", "Use this file instead of Rexfile"; |
434
|
0
|
|
|
|
|
0
|
printf $fmt, "-F", "Force: disregard lock file"; |
435
|
0
|
|
|
|
|
0
|
printf $fmt, "-h", "Display this help message"; |
436
|
0
|
|
|
|
|
0
|
printf $fmt, "-M", "Load this module instead of Rexfile"; |
437
|
0
|
|
|
|
|
0
|
printf $fmt, "-O", "Pass additional options, like CMDB path"; |
438
|
0
|
|
|
|
|
0
|
printf $fmt, "-s", "Use sudo for every command"; |
439
|
0
|
|
|
|
|
0
|
printf $fmt, "-S", "Password for sudo"; |
440
|
0
|
|
|
|
|
0
|
printf $fmt, "-t", "Number of threads to use (aka 'parallelism' param)"; |
441
|
0
|
|
|
|
|
0
|
printf $fmt, "-v", "Display (R)?ex version"; |
442
|
0
|
|
|
|
|
0
|
print "\n"; |
443
|
|
|
|
|
|
|
|
444
|
0
|
|
|
|
|
0
|
for my $code (@help) { |
445
|
0
|
|
|
|
|
0
|
&$code(); |
446
|
|
|
|
|
|
|
} |
447
|
|
|
|
|
|
|
|
448
|
0
|
|
|
|
|
0
|
CORE::exit 0; |
449
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
} |
451
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
sub add_help { |
453
|
0
|
|
|
0
|
0
|
0
|
my ( $self, $code ) = @_; |
454
|
0
|
|
|
|
|
0
|
push( @help, $code ); |
455
|
|
|
|
|
|
|
} |
456
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
sub add_exit { |
458
|
1
|
|
|
1
|
0
|
2
|
my ( $self, $code ) = @_; |
459
|
1
|
|
|
|
|
4
|
push( @exit, $code ); |
460
|
|
|
|
|
|
|
} |
461
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
sub __version__ { |
463
|
0
|
|
|
0
|
|
0
|
print "(R)?ex " . $Rex::VERSION . "\n"; |
464
|
0
|
|
|
|
|
0
|
CORE::exit 0; |
465
|
|
|
|
|
|
|
} |
466
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
sub _handle_T { |
468
|
0
|
|
|
0
|
|
0
|
my %opts = @_; |
469
|
|
|
|
|
|
|
|
470
|
0
|
|
|
|
|
0
|
my ($cols) = Term::ReadKey::GetTerminalSize(*STDOUT); |
471
|
0
|
|
0
|
|
|
0
|
$Text::Wrap::columns = $cols || 80; |
472
|
|
|
|
|
|
|
|
473
|
0
|
|
|
|
|
0
|
_list_tasks(); |
474
|
0
|
|
|
|
|
0
|
_list_batches(); |
475
|
0
|
|
|
|
|
0
|
_list_envs(); |
476
|
0
|
|
|
|
|
0
|
_list_groups(); |
477
|
|
|
|
|
|
|
} |
478
|
|
|
|
|
|
|
|
479
|
|
|
|
|
|
|
sub _list_tasks { |
480
|
0
|
|
|
0
|
|
0
|
Rex::Logger::debug("Listing Tasks"); |
481
|
|
|
|
|
|
|
|
482
|
0
|
|
|
|
|
0
|
my @tasks; |
483
|
0
|
0
|
|
|
|
0
|
if ( $opts{'a'} ) { |
484
|
0
|
|
|
|
|
0
|
@tasks = sort Rex::TaskList->create()->get_all_tasks(qr/.*/); |
485
|
|
|
|
|
|
|
} |
486
|
|
|
|
|
|
|
else { |
487
|
0
|
|
|
|
|
0
|
@tasks = Rex::TaskList->create()->get_tasks; |
488
|
|
|
|
|
|
|
} |
489
|
|
|
|
|
|
|
|
490
|
0
|
0
|
|
|
|
0
|
if ( defined $ARGV[0] ) { |
491
|
0
|
|
|
|
|
0
|
@tasks = grep { $_ =~ /^$ARGV[0]/ } @tasks; |
|
0
|
|
|
|
|
0
|
|
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
# Warn if the user passed args to '-T' and no matching task names were found |
494
|
0
|
0
|
|
|
|
0
|
Rex::Logger::info( "No tasks matching '$ARGV[0]' found.", "error" ) |
495
|
|
|
|
|
|
|
unless @tasks; |
496
|
|
|
|
|
|
|
} |
497
|
|
|
|
|
|
|
|
498
|
0
|
0
|
|
|
|
0
|
return unless @tasks; |
499
|
|
|
|
|
|
|
|
500
|
|
|
|
|
|
|
# fancy sorting of tasks -- put tasks from Rexfile first |
501
|
0
|
|
|
|
|
0
|
my @root_tasks = grep { !/:/ } @tasks; |
|
0
|
|
|
|
|
0
|
|
502
|
0
|
|
|
|
|
0
|
my @other_tasks = grep { /:/ } @tasks; |
|
0
|
|
|
|
|
0
|
|
503
|
0
|
|
|
|
|
0
|
@tasks = ( sort(@root_tasks), sort(@other_tasks) ); |
504
|
|
|
|
|
|
|
|
505
|
0
|
|
|
|
|
0
|
_print_color( "Tasks\n", "yellow" ); |
506
|
0
|
|
|
|
|
0
|
my $max_task_len = max map { length } @tasks; |
|
0
|
|
|
|
|
0
|
|
507
|
0
|
|
|
|
|
0
|
my $fmt = " %-" . $max_task_len . "s %s\n"; |
508
|
0
|
|
|
|
|
0
|
my $last_namespace = _namespace( $tasks[0] ); |
509
|
|
|
|
|
|
|
|
510
|
0
|
|
|
|
|
0
|
for my $task (@tasks) { |
511
|
0
|
0
|
|
|
|
0
|
print "\n" if $last_namespace ne _namespace($task); |
512
|
0
|
|
|
|
|
0
|
$last_namespace = _namespace($task); |
513
|
|
|
|
|
|
|
|
514
|
0
|
|
|
|
|
0
|
my $description = Rex::TaskList->create()->get_desc($task); |
515
|
0
|
|
|
|
|
0
|
my $output = sprintf $fmt, $task, $description; |
516
|
0
|
|
|
|
|
0
|
my $indent = " " x $max_task_len . " "; |
517
|
|
|
|
|
|
|
|
518
|
0
|
|
|
|
|
0
|
print wrap( "", $indent, $output ); |
519
|
|
|
|
|
|
|
|
520
|
0
|
0
|
|
|
|
0
|
if ( $opts{'v'} ) { |
521
|
0
|
|
|
|
|
0
|
my @servers = sort @{ Rex::TaskList->create()->get_task($task)->server }; |
|
0
|
|
|
|
|
0
|
|
522
|
0
|
|
|
|
|
0
|
_print_color( " Servers: " . join( ", ", @servers ) . "\n" ); |
523
|
|
|
|
|
|
|
} |
524
|
|
|
|
|
|
|
} |
525
|
|
|
|
|
|
|
} |
526
|
|
|
|
|
|
|
|
527
|
|
|
|
|
|
|
sub _namespace { |
528
|
0
|
|
|
0
|
|
0
|
my ($full_task_name) = @_; |
529
|
0
|
0
|
|
|
|
0
|
return "" unless $full_task_name =~ /:/; |
530
|
0
|
|
|
|
|
0
|
my ($namespace) = split /:/, $full_task_name; |
531
|
0
|
|
|
|
|
0
|
return $namespace; |
532
|
|
|
|
|
|
|
} |
533
|
|
|
|
|
|
|
|
534
|
|
|
|
|
|
|
sub _list_batches { |
535
|
0
|
|
|
0
|
|
0
|
Rex::Logger::debug("Listing Batches"); |
536
|
|
|
|
|
|
|
|
537
|
0
|
|
|
|
|
0
|
my @batchs = sort Rex::Batch->get_batchs; |
538
|
0
|
0
|
|
|
|
0
|
return unless Rex::Batch->get_batchs; |
539
|
|
|
|
|
|
|
|
540
|
0
|
|
|
|
|
0
|
_print_color( "Batches\n", 'yellow' ); |
541
|
0
|
|
|
|
|
0
|
my $max_batch_len = max map { length } @batchs; |
|
0
|
|
|
|
|
0
|
|
542
|
0
|
|
|
|
|
0
|
my $fmt = " %-" . $max_batch_len . "s %s\n"; |
543
|
|
|
|
|
|
|
|
544
|
0
|
|
|
|
|
0
|
for my $batch ( sort @batchs ) { |
545
|
0
|
|
|
|
|
0
|
my $description = Rex::Batch->get_desc($batch); |
546
|
0
|
|
|
|
|
0
|
my $output = sprintf $fmt, $batch, $description; |
547
|
0
|
|
|
|
|
0
|
my $indent = " " x $max_batch_len . " "; |
548
|
|
|
|
|
|
|
|
549
|
0
|
|
|
|
|
0
|
print wrap( "", $indent, $output ); |
550
|
|
|
|
|
|
|
|
551
|
0
|
0
|
|
|
|
0
|
if ( $opts{'v'} ) { |
552
|
0
|
|
|
|
|
0
|
my @tasks = Rex::Batch->get_batch($batch); |
553
|
0
|
|
|
|
|
0
|
_print_color( " " . join( " ", @tasks ) . "\n" ); |
554
|
|
|
|
|
|
|
} |
555
|
|
|
|
|
|
|
} |
556
|
|
|
|
|
|
|
} |
557
|
|
|
|
|
|
|
|
558
|
|
|
|
|
|
|
sub _list_envs { |
559
|
0
|
|
|
0
|
|
0
|
Rex::Logger::debug("Listing Envs"); |
560
|
|
|
|
|
|
|
|
561
|
|
|
|
|
|
|
my @envs = |
562
|
0
|
|
|
|
|
0
|
map { Rex::Commands->get_environment($_) } |
|
0
|
|
|
|
|
0
|
|
563
|
|
|
|
|
|
|
sort Rex::Commands->get_environments(); |
564
|
0
|
0
|
|
|
|
0
|
return unless @envs; |
565
|
|
|
|
|
|
|
|
566
|
0
|
0
|
|
|
|
0
|
_print_color( "Environments\n", "yellow" ) if scalar @envs; |
567
|
0
|
|
|
|
|
0
|
my $max_env_len = max map { length $_->{name} } @envs; |
|
0
|
|
|
|
|
0
|
|
568
|
0
|
|
|
|
|
0
|
my $fmt = " %-" . $max_env_len . "s %s\n"; |
569
|
|
|
|
|
|
|
|
570
|
0
|
|
|
|
|
0
|
for my $e ( sort @envs ) { |
571
|
0
|
|
|
|
|
0
|
my $output = sprintf $fmt, $e->{name}, $e->{description}; |
572
|
0
|
|
|
|
|
0
|
my $indent = " " x $max_env_len . " "; |
573
|
0
|
|
|
|
|
0
|
print wrap( "", $indent, $output ); |
574
|
|
|
|
|
|
|
} |
575
|
|
|
|
|
|
|
} |
576
|
|
|
|
|
|
|
|
577
|
|
|
|
|
|
|
sub _list_groups { |
578
|
0
|
|
|
0
|
|
0
|
Rex::Logger::debug("Listing Groups"); |
579
|
|
|
|
|
|
|
|
580
|
0
|
|
|
|
|
0
|
my %groups = Rex::Group->get_groups; |
581
|
0
|
|
|
|
|
0
|
my @group_names = sort keys %groups; |
582
|
|
|
|
|
|
|
|
583
|
0
|
0
|
|
|
|
0
|
return unless @group_names; |
584
|
|
|
|
|
|
|
|
585
|
0
|
|
|
|
|
0
|
_print_color( "Server Groups\n", "yellow" ); |
586
|
0
|
|
|
|
|
0
|
my $max_group_len = max map { length } @group_names; |
|
0
|
|
|
|
|
0
|
|
587
|
0
|
|
|
|
|
0
|
my $fmt = " %-" . $max_group_len . "s %s\n"; |
588
|
|
|
|
|
|
|
|
589
|
0
|
|
|
|
|
0
|
for my $group_name (@group_names) { |
590
|
0
|
|
|
|
|
0
|
my $hosts = join( ", ", sort @{ $groups{$group_name} } ); |
|
0
|
|
|
|
|
0
|
|
591
|
0
|
|
|
|
|
0
|
my $output = sprintf $fmt, $group_name, $hosts; |
592
|
0
|
|
|
|
|
0
|
my $indent = " " x $max_group_len . " "; |
593
|
0
|
|
|
|
|
0
|
print wrap( "", $indent, $output ); |
594
|
|
|
|
|
|
|
} |
595
|
|
|
|
|
|
|
} |
596
|
|
|
|
|
|
|
|
597
|
|
|
|
|
|
|
sub summarize { |
598
|
0
|
|
|
0
|
0
|
0
|
my ($signal) = @_; |
599
|
0
|
|
|
|
|
0
|
my %opts = Rex::Args->getopts; |
600
|
0
|
0
|
|
|
|
0
|
return if $opts{'T'}; |
601
|
|
|
|
|
|
|
|
602
|
0
|
|
|
|
|
0
|
my @summary = Rex::TaskList->create()->get_summary(); |
603
|
0
|
0
|
|
|
|
0
|
return unless @summary; # no tasks ran -- nothing to summarize |
604
|
|
|
|
|
|
|
|
605
|
0
|
|
|
|
|
0
|
my @failures = grep { $_->{exit_code} != 0 } @summary; |
|
0
|
|
|
|
|
0
|
|
606
|
|
|
|
|
|
|
|
607
|
0
|
0
|
|
|
|
0
|
if ( !@failures ) { |
608
|
0
|
|
|
|
|
0
|
Rex::Logger::info("All tasks successful on all hosts"); |
609
|
0
|
|
|
|
|
0
|
return; |
610
|
|
|
|
|
|
|
} |
611
|
|
|
|
|
|
|
|
612
|
0
|
|
|
|
|
0
|
Rex::Logger::info( @failures . " out of " . @summary . " task(s) failed:", |
613
|
|
|
|
|
|
|
"error" ); |
614
|
|
|
|
|
|
|
|
615
|
0
|
|
|
|
|
0
|
foreach ( |
616
|
|
|
|
|
|
|
sort { |
617
|
|
|
|
|
|
|
ncmp( $a->{task}, $b->{task} ) |
618
|
|
|
|
|
|
|
|| ncmp( $a->{server}, $b->{server} ) |
619
|
0
|
0
|
|
|
|
0
|
} @failures |
620
|
|
|
|
|
|
|
) |
621
|
|
|
|
|
|
|
{ |
622
|
0
|
|
|
|
|
0
|
Rex::Logger::info( "\t$_->{task} failed on $_->{server}", "error" ); |
623
|
0
|
0
|
|
|
|
0
|
if ( $_->{error_message} ) { |
624
|
0
|
|
|
|
|
0
|
for my $line ( split( $INPUT_RECORD_SEPARATOR, $_->{error_message} ) ) { |
625
|
0
|
|
|
|
|
0
|
Rex::Logger::info( "\t\t$line", "error" ); |
626
|
|
|
|
|
|
|
} |
627
|
|
|
|
|
|
|
} |
628
|
|
|
|
|
|
|
} |
629
|
|
|
|
|
|
|
} |
630
|
|
|
|
|
|
|
|
631
|
|
|
|
|
|
|
sub handle_lock_file { |
632
|
0
|
|
|
0
|
0
|
0
|
my $rexfile = shift; |
633
|
|
|
|
|
|
|
|
634
|
0
|
0
|
|
|
|
0
|
if ( $OSNAME !~ m/^MSWin/ ) { |
635
|
0
|
0
|
0
|
|
|
0
|
if ( -f "$rexfile.lock" && !exists $opts{'F'} ) { |
636
|
0
|
|
|
|
|
0
|
Rex::Logger::debug("Found $rexfile.lock"); |
637
|
0
|
|
|
|
|
0
|
my $pid = eval { |
638
|
0
|
|
|
|
|
0
|
local ( @ARGV, $INPUT_RECORD_SEPARATOR ) = ("$rexfile.lock"); |
639
|
0
|
|
|
|
|
0
|
<>; |
640
|
|
|
|
|
|
|
}; |
641
|
0
|
|
|
|
|
0
|
system( |
642
|
|
|
|
|
|
|
"ps aux | awk -F' ' ' { print \$2 } ' | grep $pid >/dev/null 2>&1"); |
643
|
0
|
0
|
|
|
|
0
|
if ( $CHILD_ERROR == 0 ) { |
644
|
0
|
|
|
|
|
0
|
Rex::Logger::info("Rexfile is in use by $pid."); |
645
|
0
|
|
|
|
|
0
|
CORE::exit 1; |
646
|
|
|
|
|
|
|
} |
647
|
|
|
|
|
|
|
else { |
648
|
0
|
|
|
|
|
0
|
Rex::Logger::debug("Found stale lock file. Removing it."); |
649
|
0
|
|
|
|
|
0
|
Rex::global_sudo(0); |
650
|
0
|
|
|
|
|
0
|
CORE::unlink("$rexfile.lock"); |
651
|
|
|
|
|
|
|
} |
652
|
|
|
|
|
|
|
} |
653
|
|
|
|
|
|
|
|
654
|
0
|
|
|
|
|
0
|
Rex::Logger::debug("Creating lock-file ($rexfile.lock)"); |
655
|
0
|
0
|
|
|
|
0
|
open( my $f, ">", "$rexfile.lock" ) or die($OS_ERROR); |
656
|
0
|
|
|
|
|
0
|
print $f $PID; |
657
|
0
|
|
|
|
|
0
|
close($f); |
658
|
|
|
|
|
|
|
} |
659
|
|
|
|
|
|
|
else { |
660
|
0
|
|
|
|
|
0
|
Rex::Logger::debug("Running on windows. Disabled lock file support."); |
661
|
|
|
|
|
|
|
} |
662
|
|
|
|
|
|
|
} |
663
|
|
|
|
|
|
|
|
664
|
|
|
|
|
|
|
sub load_server_ini_file { |
665
|
0
|
|
|
0
|
0
|
0
|
my $rexfile = shift; |
666
|
|
|
|
|
|
|
|
667
|
|
|
|
|
|
|
# load server ini file |
668
|
0
|
|
|
|
|
0
|
my $env = environment; |
669
|
0
|
|
|
|
|
0
|
my $ini_dir = dirname($rexfile); |
670
|
0
|
|
|
|
|
0
|
my $server_ini_file = "$ini_dir/server.$env.ini"; |
671
|
0
|
0
|
|
|
|
0
|
$server_ini_file = "$ini_dir/server.ini" unless -f $server_ini_file; |
672
|
|
|
|
|
|
|
|
673
|
0
|
0
|
0
|
|
|
0
|
if ( -f $server_ini_file && Rex::Group::Lookup::INI->is_loadable ) { |
674
|
0
|
|
|
|
|
0
|
Rex::Logger::debug("Loading $server_ini_file"); |
675
|
0
|
|
|
|
|
0
|
Rex::Group::Lookup::INI::groups_file($server_ini_file); |
676
|
|
|
|
|
|
|
} |
677
|
|
|
|
|
|
|
} |
678
|
|
|
|
|
|
|
|
679
|
|
|
|
|
|
|
sub load_rexfile { |
680
|
9
|
|
|
9
|
0
|
13491
|
my $rexfile = shift; |
681
|
9
|
|
|
|
|
46
|
Rex::Logger::debug("Loading $rexfile"); |
682
|
|
|
|
|
|
|
|
683
|
9
|
100
|
|
|
|
199
|
if ( !-f $rexfile ) { |
684
|
1
|
50
|
|
|
|
9
|
if ( !exists $opts{'e'} ) { |
685
|
1
|
|
|
|
|
8
|
Rex::Logger::info( "No Rexfile found.", "warn" ); |
686
|
1
|
|
|
|
|
4
|
Rex::Logger::info( "Create a file named 'Rexfile' in this directory,", |
687
|
|
|
|
|
|
|
"warn" ); |
688
|
1
|
|
|
|
|
16
|
Rex::Logger::info( "or specify the file you want to use with:", "warn" ); |
689
|
1
|
|
|
|
|
17
|
Rex::Logger::info( " rex -f file_to_use task_to_run", "warn" ); |
690
|
|
|
|
|
|
|
} |
691
|
1
|
|
|
|
|
8
|
return; |
692
|
|
|
|
|
|
|
} |
693
|
|
|
|
|
|
|
|
694
|
8
|
|
|
|
|
391
|
my $rexfile_dir = dirname $rexfile; |
695
|
8
|
|
|
|
|
43
|
my @new_inc = Rex::generate_inc($rexfile_dir); |
696
|
8
|
|
|
|
|
62
|
@INC = @new_inc; |
697
|
|
|
|
|
|
|
|
698
|
|
|
|
|
|
|
# load Rexfile |
699
|
8
|
|
|
|
|
21
|
eval { |
700
|
|
|
|
|
|
|
|
701
|
|
|
|
|
|
|
# add a true return value at the end of $rexfile. |
702
|
|
|
|
|
|
|
# we need to do this because perl want a "true" value |
703
|
|
|
|
|
|
|
# at the end of a file that is loaded. |
704
|
|
|
|
|
|
|
unshift @INC, sub { |
705
|
28
|
|
|
28
|
|
49179
|
my $load_file = $_[1]; |
706
|
28
|
100
|
|
|
|
183
|
if ( $load_file eq "__Rexfile__.pm" ) { |
707
|
7
|
50
|
|
|
|
284
|
open( my $fh, "<", $rexfile ) |
708
|
|
|
|
|
|
|
or die("Error can't open $rexfile: $OS_ERROR"); |
709
|
7
|
|
|
|
|
288
|
my @content = <$fh>; |
710
|
7
|
|
|
|
|
83
|
close($fh); |
711
|
7
|
|
|
|
|
28
|
chomp @content; |
712
|
|
|
|
|
|
|
|
713
|
7
|
|
|
|
|
21
|
my $i = 0; |
714
|
7
|
|
|
|
|
9
|
my $found_end = 0; |
715
|
|
|
|
|
|
|
|
716
|
|
|
|
|
|
|
# some rexfile has a __DATA__ or __END__ section |
717
|
|
|
|
|
|
|
# and we need to add the true value before those sections. |
718
|
7
|
|
|
|
|
14
|
for my $line (@content) { |
719
|
47
|
50
|
|
|
|
89
|
if ( $line =~ m/^__(DATA|END)__$/ ) { |
720
|
0
|
|
|
|
|
0
|
splice( @content, $i, 0, "42;" ); |
721
|
0
|
|
|
|
|
0
|
$found_end++; |
722
|
0
|
|
|
|
|
0
|
last; |
723
|
|
|
|
|
|
|
} |
724
|
47
|
|
|
|
|
58
|
$i++; |
725
|
|
|
|
|
|
|
} |
726
|
|
|
|
|
|
|
|
727
|
|
|
|
|
|
|
# we didn't found __DATA__ or __END__ so we just add |
728
|
|
|
|
|
|
|
# it at the end. |
729
|
7
|
50
|
|
|
|
16
|
if ( $found_end == 0 ) { |
730
|
7
|
|
|
|
|
19
|
push @content, "42;"; |
731
|
|
|
|
|
|
|
} |
732
|
|
|
|
|
|
|
|
733
|
|
|
|
|
|
|
# we can't remove this load from @INC because on perl 5.8 |
734
|
|
|
|
|
|
|
# this causes a crash |
735
|
|
|
|
|
|
|
#shift @INC; # remove this loader from @INC |
736
|
|
|
|
|
|
|
|
737
|
|
|
|
|
|
|
# we can't directly return a scalar reference because perl 5.8 |
738
|
|
|
|
|
|
|
# needs a filehandle. so we create a virtual filehandle... |
739
|
7
|
|
|
|
|
30
|
my $c = join( "\n", @content ); |
740
|
7
|
|
|
2
|
|
136
|
open( my $rex_fh, "<", \$c ); |
|
2
|
|
|
|
|
13
|
|
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
18
|
|
741
|
7
|
|
|
|
|
2122
|
return $rex_fh; |
742
|
|
|
|
|
|
|
} |
743
|
8
|
|
|
|
|
50
|
}; |
744
|
|
|
|
|
|
|
|
745
|
|
|
|
|
|
|
# we don't want to see the |
746
|
|
|
|
|
|
|
# normal perl warning message on the screen. Instead we print |
747
|
|
|
|
|
|
|
# the warning message in the catch-if below |
748
|
8
|
|
|
|
|
16
|
my @warnings; |
749
|
8
|
|
|
5
|
|
53
|
local $SIG{__WARN__} = sub { push @warnings, $_[0] }; |
|
5
|
|
|
|
|
288
|
|
750
|
|
|
|
|
|
|
|
751
|
|
|
|
|
|
|
# we can't use $rexfile here, because if the variable contains dots |
752
|
|
|
|
|
|
|
# the perl interpreter try to load the file directly without using @INC |
753
|
|
|
|
|
|
|
# so we just fake a module name. |
754
|
8
|
|
|
|
|
78
|
require __Rexfile__; |
755
|
|
|
|
|
|
|
|
756
|
|
|
|
|
|
|
# update %INC so that we can later use it to find the rexfile |
757
|
6
|
|
|
|
|
63
|
$INC{"__Rexfile__.pm"} = $rexfile; |
758
|
|
|
|
|
|
|
|
759
|
6
|
100
|
|
|
|
59
|
if (@warnings) { |
760
|
2
|
|
|
|
|
11
|
Rex::Logger::info( "You have some code warnings:", 'warn' ); |
761
|
2
|
|
|
|
|
8
|
for (@warnings) { |
762
|
4
|
|
|
|
|
12
|
chomp; |
763
|
|
|
|
|
|
|
|
764
|
4
|
|
|
|
|
11
|
my $message = _tidy_loading_message( $_, $rexfile ); |
765
|
|
|
|
|
|
|
|
766
|
4
|
|
|
|
|
14
|
Rex::Logger::info( "\t$message", 'warn' ); |
767
|
|
|
|
|
|
|
} |
768
|
|
|
|
|
|
|
} |
769
|
|
|
|
|
|
|
|
770
|
6
|
|
|
|
|
43
|
1; |
771
|
|
|
|
|
|
|
}; |
772
|
|
|
|
|
|
|
|
773
|
8
|
100
|
|
|
|
61
|
if ($EVAL_ERROR) { |
774
|
2
|
|
|
|
|
9
|
my $e = $EVAL_ERROR; |
775
|
2
|
|
|
|
|
5
|
chomp $e; |
776
|
|
|
|
|
|
|
|
777
|
2
|
|
|
|
|
7
|
$e = _tidy_loading_message( $e, $rexfile ); |
778
|
|
|
|
|
|
|
|
779
|
2
|
|
|
|
|
6
|
my ( @error_lines, @debug_lines ); |
780
|
|
|
|
|
|
|
|
781
|
2
|
|
|
|
|
36
|
for my $line ( split $INPUT_RECORD_SEPARATOR, $e ) { |
782
|
8
|
100
|
|
|
|
30
|
$line =~ m{CLI[.]pm[ ]line[ ]\d+}msx |
783
|
|
|
|
|
|
|
? push @debug_lines, $line |
784
|
|
|
|
|
|
|
: push @error_lines, $line; |
785
|
|
|
|
|
|
|
} |
786
|
|
|
|
|
|
|
|
787
|
2
|
|
|
|
|
11
|
Rex::Logger::info( "Compile time errors:", 'error' ); |
788
|
|
|
|
|
|
|
|
789
|
2
|
|
|
|
|
6
|
for my $error_line (@error_lines) { |
790
|
6
|
|
|
|
|
24
|
Rex::Logger::info( "\t$error_line", 'error' ); |
791
|
|
|
|
|
|
|
} |
792
|
|
|
|
|
|
|
|
793
|
2
|
|
|
|
|
9
|
for my $debug_line (@debug_lines) { |
794
|
2
|
|
|
|
|
9
|
Rex::Logger::debug("\t$debug_line"); |
795
|
|
|
|
|
|
|
} |
796
|
|
|
|
|
|
|
|
797
|
2
|
|
|
|
|
10
|
exit 1; |
798
|
|
|
|
|
|
|
} |
799
|
|
|
|
|
|
|
} |
800
|
|
|
|
|
|
|
|
801
|
|
|
|
|
|
|
sub _tidy_loading_message { |
802
|
6
|
|
|
6
|
|
15
|
my ( $message, $rexfile ) = @_; |
803
|
|
|
|
|
|
|
|
804
|
6
|
|
|
|
|
51
|
$message =~ s{/loader/[^/]+/__Rexfile__[.]pm}{$rexfile}gmsx; |
805
|
6
|
|
|
|
|
19
|
return $message; |
806
|
|
|
|
|
|
|
} |
807
|
|
|
|
|
|
|
|
808
|
|
|
|
|
|
|
sub exit_rex { |
809
|
0
|
|
|
0
|
0
|
0
|
my ( $exit_code_override, $signal ) = @_; |
810
|
|
|
|
|
|
|
|
811
|
0
|
0
|
|
|
|
0
|
summarize($signal) if !$signal; |
812
|
|
|
|
|
|
|
|
813
|
0
|
|
|
|
|
0
|
Rex::global_sudo(0); |
814
|
0
|
0
|
|
|
|
0
|
Rex::Logger::debug("Removing lockfile") if !exists $opts{'F'}; |
815
|
0
|
0
|
|
|
|
0
|
unlink("$::rexfile.lock") if !exists $opts{'F'}; |
816
|
|
|
|
|
|
|
|
817
|
0
|
|
|
|
|
0
|
select STDOUT; |
818
|
|
|
|
|
|
|
|
819
|
0
|
0
|
0
|
|
|
0
|
if ( !$signal && $opts{'o'} && defined( Rex::Output->get ) ) { |
|
|
|
0
|
|
|
|
|
820
|
0
|
|
|
|
|
0
|
Rex::Output->get->write(); |
821
|
0
|
|
|
|
|
0
|
IPC::Shareable->clean_up_all(); |
822
|
|
|
|
|
|
|
} |
823
|
|
|
|
|
|
|
|
824
|
0
|
|
|
|
|
0
|
for my $exit_hook (@exit) { |
825
|
0
|
|
|
|
|
0
|
$exit_hook->( $exit_code_override, $signal ); |
826
|
|
|
|
|
|
|
} |
827
|
|
|
|
|
|
|
|
828
|
0
|
0
|
|
|
|
0
|
if ($Rex::WITH_EXIT_STATUS) { |
829
|
0
|
0
|
|
|
|
0
|
CORE::exit($exit_code_override) if defined $exit_code_override; |
830
|
|
|
|
|
|
|
|
831
|
0
|
|
|
|
|
0
|
my @exit_codes = Rex::TaskList->create()->get_exit_codes(); |
832
|
0
|
|
|
|
|
0
|
for my $exit_code (@exit_codes) { |
833
|
0
|
0
|
|
|
|
0
|
$exit_code = $exit_code >> 8 if $exit_code > 255; |
834
|
0
|
0
|
|
|
|
0
|
CORE::exit($exit_code) if $exit_code != 0; |
835
|
|
|
|
|
|
|
} |
836
|
|
|
|
|
|
|
} |
837
|
|
|
|
|
|
|
|
838
|
0
|
|
|
|
|
0
|
CORE::exit(0); |
839
|
|
|
|
|
|
|
} |
840
|
|
|
|
|
|
|
|
841
|
|
|
|
|
|
|
# we capture CTRL+C so we can cleanup vars files |
842
|
|
|
|
|
|
|
# and give modules the chance to also do cleanup |
843
|
|
|
|
|
|
|
$SIG{INT} = sub { |
844
|
|
|
|
|
|
|
exit_rex( 1, "INT" ); |
845
|
|
|
|
|
|
|
}; |
846
|
|
|
|
|
|
|
|
847
|
|
|
|
|
|
|
1; |