| 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; |