File Coverage

blib/lib/Rex.pm
Criterion Covered Total %
statement 264 440 60.0
branch 93 168 55.3
condition 47 77 61.0
subroutine 33 42 78.5
pod 6 22 27.2
total 443 749 59.1


line stmt bran cond sub pod time code
1             #
2             # (c) Jan Gehring
3             #
4              
5             =encoding UTF-8
6              
7             =head1 NAME
8              
9             Rex - the friendly automation framework
10              
11             =head1 DESCRIPTION
12              
13             Rex is an automation framework that is friendly to any combinations of local
14             and remote execution, push and pull style of management, or imperative and
15             declarative approach.
16              
17             Its flexibility makes it a great fit for many different use cases, but most
18             commonly Rex is used to automate application deployment and data center
19             infrastructure management tasks.
20              
21             See L for a starting point of available built-in commands.
22              
23             See L for more information about how to use rex on the command line.
24              
25             =head1 SYNOPSIS
26              
27             # In a Rexfile:
28             use Rex -feature => [qw/1.4/];
29              
30             user "root";
31             password "ch4ngem3";
32              
33             desc "Show system information";
34             task "sysinfo", sub {
35             say run "uname -a";
36             };
37              
38             1;
39              
40             # On the command line:
41             $ rex -H server[01..10] sysinfo
42              
43             =head1 CLASS METHODS
44              
45             =cut
46              
47             package Rex;
48              
49 102     102   731098 use v5.12.5;
  102         427  
50 102     102   532 use warnings;
  102         203  
  102         4729  
51              
52             our $VERSION = '1.14.3'; # VERSION
53              
54             BEGIN {
55 102     102   10264 use Rex::Logger;
  102         220  
  102         1632  
56 102     102   41640 use Rex::Interface::Cache;
  102         246  
  102         1771  
57 102     102   16548 use Data::Dumper;
  102         158695  
  102         4822  
58 102     102   39917 use Rex::Interface::Connection;
  102         244  
  102         1725  
59 102     102   2382 use Cwd qw(getcwd);
  102         181  
  102         5140  
60 102     102   15867 use Rex::Config;
  102         222  
  102         498  
61 102     102   40736 use Rex::Helper::Array;
  102         239  
  102         5473  
62 102     102   14494 use Rex::Report;
  102         234  
  102         743  
63 102     102   41073 use Rex::Notify;
  102         257  
  102         1133  
64 102     102   2836 use Rex::Require;
  102         211  
  102         496  
65 102     102   2267 use File::Basename;
  102         207  
  102         13569  
66 102     102   638 use File::Spec;
  102         169  
  102         1107  
67 102     102   2557 eval { Net::SSH2->require; };
  102         515  
68             }
69              
70             our ( @EXPORT, @CONNECTION_STACK, $GLOBAL_SUDO, $MODULE_PATHS,
71             $WITH_EXIT_STATUS, @FEATURE_FLAGS );
72              
73             $WITH_EXIT_STATUS = 1; # since 0.50 activated by default
74             @FEATURE_FLAGS = ();
75              
76             BEGIN {
77              
78             sub generate_inc {
79 110     110 0 286 my @additional = @_;
80              
81 110         256 my @rex_inc = ();
82              
83             # this must be the first, special handling for rex modules which uses Module.pm and not
84             # __module__.pm as their initial file. (rex pre 0.40 or something)
85             push @rex_inc, sub {
86 8707     8707   12192656 my $mod_to_load = $_[1];
87 8707         22313 return search_module_path( $mod_to_load, 1 );
88 110         642 };
89              
90             # this adds the current directory to the lib search path.
91             # this must come before all other paths, because custom libraries can be project dependant
92             # see: #1108
93 110         537 push @rex_inc, add_cwd_to_inc();
94 110         415 push @rex_inc, add_libstruct_to_inc($_) for @additional;
95              
96             # we have to add the Rexfile's path to @INC FIX: #1170
97 110         215 push @rex_inc, @additional;
98              
99             # add home directory/.rex/recipes to the search path, so that recipes can be managed
100             # at a central location.
101 110         321 my $home_dir = _home_dir();
102 110 50       1367 if ( -d "$home_dir/.rex/recipes" ) {
103 0         0 push( @INC, "$home_dir/.rex/recipes" );
104             }
105              
106             # add the default search locations
107 110         1001 push @rex_inc, @INC;
108              
109             # this must be the last entry, special handling to load rex modules.
110             push(
111             @rex_inc,
112             sub {
113 294     294   5308 my $mod_to_load = $_[1];
114 294         1323 return search_module_path( $mod_to_load, 0 );
115             }
116 110         684 );
117              
118 110         929 return @rex_inc;
119             }
120              
121             sub add_libstruct_to_inc {
122 118     118 0 294 my ($path) = @_;
123 118         237 my @ret = ();
124              
125 118 100       3689 if ( -d File::Spec->catdir( $path, "lib" ) ) {
126 110         1992 push( @ret, File::Spec->catdir( $path, "lib" ) );
127 110         835 push( @ret, File::Spec->catdir( $path, "lib", "perl", "lib", "perl5" ) );
128 110 50       627 if ( $^O eq "linux" ) {
129 110         794 push(
130             @ret,
131             File::Spec->catdir(
132             $path, "lib", "perl", "lib", "perl5", "x86_64-linux"
133             )
134             );
135             }
136 110 50       624 if ( $^O =~ m/^MSWin/ ) {
137 0         0 my ($special_win_path) = grep { m/\/MSWin32\-/ } @INC;
  0         0  
138 0 0       0 if ( defined $special_win_path ) {
139 0         0 my $mswin32_path = basename $special_win_path;
140 0         0 push(
141             @ret,
142             File::Spec->catdir(
143             $path, "lib", "perl", "lib", "perl5", $mswin32_path
144             )
145             );
146             }
147             }
148             }
149              
150 118         573 return @ret;
151             }
152              
153             sub add_cwd_to_inc {
154 110     110 0 1265 my $path = getcwd;
155 110         455 return add_libstruct_to_inc($path);
156             }
157              
158             sub _home_dir {
159 110 50   110   505 if ( $^O =~ m/^MSWin/ ) {
160 0         0 return $ENV{'USERPROFILE'};
161             }
162              
163 110   50     572 return $ENV{'HOME'} || "";
164             }
165              
166 102     102   5370 my @new_inc = generate_inc();
167 102         417636 @INC = @new_inc;
168              
169             }
170              
171             my $home = $ENV{'HOME'} || "/tmp";
172             if ( $^O =~ m/^MSWin/ ) {
173             $home = $ENV{'USERPROFILE'};
174             }
175              
176             push( @INC, "$home/.rex/recipes" );
177              
178             sub search_module_path {
179 9001     9001 0 24228 my ( $mod_to_load, $pre ) = @_;
180              
181 9001         40694 $mod_to_load =~ s/\.pm//g;
182              
183 9001         17576 my @search_in;
184 9001 100       19676 if ($pre) {
185 104235         240529 @search_in = map { ("$_/$mod_to_load.pm") }
186 8707         17739 grep { -d } @INC;
  147970         1576444  
187              
188             }
189             else {
190             @search_in =
191 3523         12461 map { ( "$_/$mod_to_load/__module__.pm", "$_/$mod_to_load/Module.pm" ) }
192 294         1228 grep { -d } @INC;
  5003         50475  
193             }
194              
195 9001         23005 for my $file (@search_in) {
196 46509         466048 my $o = -f $file;
197 46509         84526 my $fh_t;
198 46509 50 33     171122 if ( $^O =~ m/^MSWin/i && !$o ) {
199              
200             # this is a windows workaround for if(-f ) on symlinks
201 0         0 $o = open( my $fh_t, "<", $file );
202             }
203              
204 46509 100       145533 if ($o) {
205 8413 50       15522 close $fh_t if $fh_t;
206 8413         57951 my ($path) = ( $file =~ m/^(.*)\/.+?$/ );
207 8413 50       28199 if ( $path !~ m/\// ) {
208 0         0 $path = getcwd() . "/$path";
209             }
210              
211             # module found, register path
212 8413         47095 $MODULE_PATHS->{$mod_to_load} = { path => $path };
213 8413         15572 my $mod_package_name = $mod_to_load;
214 8413         29395 $mod_package_name =~ s/\//::/g;
215 8413         31717 $MODULE_PATHS->{$mod_package_name} = { path => $path };
216              
217 8413 50       18788 if ($pre) {
218 8413         4002648 return;
219             }
220              
221 0         0 open( my $fh, "<", $file );
222 0         0 return $fh;
223             }
224             }
225             }
226              
227             sub get_module_path {
228 6     6 0 12 my ($module) = @_;
229 6 50       25 if ( exists $MODULE_PATHS->{$module} ) {
230 0         0 return $MODULE_PATHS->{$module}->{path};
231             }
232             }
233              
234             sub push_connection {
235 103 100   103 0 679 if ( !ref $_[0]->{server} ) {
236 63         595 $_[0]->{server} = Rex::Group::Entry::Server->new( name => $_[0]->{server} );
237             }
238              
239 103         635 push @CONNECTION_STACK, $_[0];
240 103         295 return $_[0];
241             }
242              
243             sub pop_connection {
244 32     32 0 213 pop @CONNECTION_STACK;
245 32         4578 Rex::Logger::debug( "Connections in queue: " . scalar(@CONNECTION_STACK) );
246             }
247              
248             sub reconnect_lost_connections {
249 107 100   107 0 1067 if ( @CONNECTION_STACK > 0 ) {
250 1         8 Rex::Logger::debug("Need to reinitialize connections.");
251 1         9 for (@CONNECTION_STACK) {
252 2         27 $_->{conn}->reconnect;
253             }
254             }
255             }
256              
257             # ... no words
258             my @__modif_caller;
259              
260             sub unset_modified_caller {
261 0     0 0 0 @__modif_caller = ();
262             }
263              
264             sub modified_caller {
265 0     0 0 0 my (@caller) = @_;
266 0 0       0 if (@caller) {
267 0         0 @__modif_caller = @caller;
268             }
269             else {
270 0         0 return @__modif_caller;
271             }
272             }
273              
274             =head2 get_current_connection
275              
276             This function is deprecated since 0.28! See Rex::Commands::connection.
277              
278             Returns the current connection as a hashRef.
279              
280             =over 4
281              
282             =item server
283              
284             The server name
285              
286             =item ssh
287              
288             1 if it is a ssh connection, 0 if not.
289              
290             =back
291              
292             =cut
293              
294             sub get_current_connection {
295              
296             # if no connection available, use local connect
297 7382 100   7382 1 27621 unless (@CONNECTION_STACK) {
298 63         2084 my $conn = Rex::Interface::Connection->create("Local");
299              
300 63         444 Rex::push_connection(
301             {
302             conn => $conn,
303             ssh => $conn->get_connection_object,
304             cache => Rex::Interface::Cache->create(),
305             reporter => Rex::Report->create(),
306             notify => Rex::Notify->new(),
307             }
308             );
309             }
310              
311 7382         49399 $CONNECTION_STACK[-1];
312             }
313              
314             sub get_current_connection_object {
315 0     0 0 0 return Rex::get_current_connection()->{conn};
316             }
317              
318             =head2 is_ssh
319              
320             Returns 1 if the current connection is a ssh connection. 0 if not.
321              
322             =cut
323              
324             sub is_ssh {
325 1195 100   1195 1 3048 if ( $CONNECTION_STACK[-1] ) {
326 1189         5536 my $ref = ref( $CONNECTION_STACK[-1]->{"conn"} );
327 1189 50       10065 if ( $ref =~ m/SSH/ ) {
328 0         0 return $CONNECTION_STACK[-1]->{"conn"}->get_connection_object();
329             }
330             }
331              
332 1195         4916 return 0;
333             }
334              
335             =head2 is_local
336              
337             Returns 1 if the current connection is local. Otherwise 0.
338              
339             =cut
340              
341             sub is_local {
342 113 50   113 1 336 if ( $CONNECTION_STACK[-1] ) {
343 113         927 my $ref = ref( $CONNECTION_STACK[-1]->{"conn"} );
344 113 50       1670 if ( $ref =~ m/Local/ ) {
345 113         1225 return $CONNECTION_STACK[-1]->{"conn"}->get_connection_object();
346             }
347             }
348              
349 0         0 return 0;
350             }
351              
352             =head2 is_sudo
353              
354             Returns 1 if the current operation is executed within sudo.
355              
356             =cut
357              
358             sub is_sudo {
359              
360 3719 50 33 3719 1 20374 if ( exists $CONNECTION_STACK[-1]->{server}->{auth}->{sudo}
    50 33        
361             && $CONNECTION_STACK[-1]->{server}->{auth}->{sudo} == 1 )
362             {
363 0         0 return 1;
364             }
365             elsif ( exists $CONNECTION_STACK[-1]->{server}->{auth}->{sudo}
366             && $CONNECTION_STACK[-1]->{server}->{auth}->{sudo} == 0 )
367             {
368 0         0 return 0;
369             }
370              
371 3719 50       7205 if ($GLOBAL_SUDO) { return 1; }
  0         0  
372              
373 3719 50       8009 if ( $CONNECTION_STACK[-1] ) {
374 3719         22398 return $CONNECTION_STACK[-1]->{conn}->get_current_use_sudo;
375             }
376              
377 0         0 return 0;
378             }
379              
380             sub global_sudo {
381 0     0 0 0 my ($on) = @_;
382 0         0 $GLOBAL_SUDO = $on;
383              
384             # turn cache on
385 0         0 Rex::Config->set_use_cache(1);
386             }
387              
388             =head2 get_sftp
389              
390             Returns the sftp object for the current ssh connection.
391              
392             =cut
393              
394             sub get_sftp {
395 0 0   0 1 0 if ( $CONNECTION_STACK[-1] ) {
396 0         0 return $CONNECTION_STACK[-1]->{"conn"}->get_fs_connection_object();
397             }
398              
399 0         0 return 0;
400             }
401              
402             sub get_cache {
403 1897 100   1897 0 7531 if ( $CONNECTION_STACK[-1] ) {
404 1887         7615 return $CONNECTION_STACK[-1]->{"cache"};
405             }
406              
407 10         86 return Rex::Interface::Cache->create();
408             }
409              
410             =head2 connect
411              
412             Use this function to create a connection if you use Rex as a library.
413              
414             use Rex;
415             use Rex::Commands::Run;
416             use Rex::Commands::Fs;
417              
418             Rex::connect(
419             server => "remotehost",
420             user => "root",
421             password => "f00b4r",
422             private_key => "/path/to/private/key/file",
423             public_key => "/path/to/public/key/file",
424             );
425              
426             if(is_file("/foo/bar")) {
427             print "Do something...\n";
428             }
429              
430             my $output = run("uptime");
431              
432             =cut
433              
434             sub connect {
435              
436 0     0 1 0 my ($param) = {@_};
437              
438 0         0 my $server = $param->{server};
439 0   0     0 my $port = $param->{port} || 22;
440 0   0     0 my $timeout = $param->{timeout} || 5;
441 0         0 my $user = $param->{"user"};
442 0         0 my $pass = $param->{"password"};
443 0         0 my $cached_conn = $param->{"cached_connection"};
444              
445 0 0       0 if ( !$cached_conn ) {
446 0         0 my $conn =
447             Rex::Interface::Connection->create(Rex::Config::get_connection_type);
448              
449             $conn->connect(
450             user => $user,
451             password => $pass,
452             server => $server,
453             port => $port,
454             timeout => $timeout,
455 0         0 %{$param},
  0         0  
456             );
457              
458 0 0       0 unless ( $conn->is_connected ) {
459 0         0 die("Connection error or refused.");
460             }
461              
462             # push a remote connection
463 0         0 my $rex_conn = Rex::push_connection(
464             {
465             conn => $conn,
466             ssh => $conn->get_connection_object,
467             server => $server,
468             cache => Rex::Interface::Cache->create(),
469             reporter => Rex::Report->create( Rex::Config->get_report_type ),
470             notify => Rex::Notify->new(),
471             }
472             );
473              
474             # auth unsuccessfull
475 0 0       0 unless ( $conn->is_authenticated ) {
476 0         0 Rex::Logger::info( "Wrong username or password. Or wrong key.", "warn" );
477              
478             # after jobs
479              
480 0         0 die("Wrong username or password. Or wrong key.");
481             }
482              
483 0         0 return $rex_conn;
484             }
485             else {
486 0         0 Rex::push_connection($cached_conn);
487 0         0 return $cached_conn;
488             }
489              
490             }
491              
492             sub deprecated {
493 0     0 0 0 my ( $func, $version, @msg ) = @_;
494              
495 0 0       0 if ($func) {
496 0         0 Rex::Logger::info("The call to $func is deprecated.");
497             }
498              
499 0 0       0 if (@msg) {
500 0         0 for (@msg) {
501 0         0 Rex::Logger::info($_);
502             }
503             }
504              
505 0         0 Rex::Logger::info("");
506              
507 0         0 Rex::Logger::info(
508             "Please rewrite your code. This function will disappear in (R)?ex version $version."
509             );
510 0         0 Rex::Logger::info(
511             "If you need assistance, get in touch via one of our support channels!");
512              
513             }
514              
515             sub has_feature_version {
516 0     0 0 0 my ($version) = @_;
517              
518 0         0 my @version_flags = grep { m/^\d+\./ } @FEATURE_FLAGS;
  0         0  
519 0         0 for my $v (@version_flags) {
520 0 0       0 if ( $version <= $v ) {
521 0         0 return 1;
522             }
523             }
524              
525 0         0 return 0;
526             }
527              
528             sub has_feature_version_lower {
529 0     0 0 0 my ($version) = @_;
530              
531 0         0 my @version_flags = grep { m/^\d+\./ } @FEATURE_FLAGS;
  0         0  
532 0         0 for my $v (@version_flags) {
533 0 0       0 if ( $version > $v ) {
534 0         0 return 1;
535             }
536             }
537              
538 0         0 return 0;
539             }
540              
541             sub import {
542 685     685   26844 my ( $class, $what, $addition1 ) = @_;
543              
544 685         18910 srand();
545              
546 685 50 66     4691 if ( $addition1 && ref $addition1 eq "ARRAY" ) {
    100          
547 0         0 push @FEATURE_FLAGS, $what, @{$addition1};
  0         0  
548             }
549             elsif ($addition1) {
550 4         12 push @FEATURE_FLAGS, $what, $addition1;
551             }
552              
553 685   100     4378 $what ||= "";
554              
555 685         4033 my ( $register_to, $file, $line ) = caller;
556              
557             # use Net::OpenSSH if present (default without feature flag)
558 685         6547 Rex::Config->set_use_net_openssh_if_present(1);
559              
560 685 100       2330 if ( $what eq "-minimal" ) {
561 36         269 require Rex::Commands;
562 36         328 Rex::Commands->import( register_in => $register_to );
563              
564 36         247 require Rex::Helper::Rexfile::ParamLookup;
565 36         329 Rex::Helper::Rexfile::ParamLookup->import( register_in => $register_to );
566             }
567              
568 685 100 66     6986 if ( $what eq "-base" || $what eq "base" || $what eq "-feature" ) {
      100        
569 48         326 require Rex::Commands;
570 48         513 Rex::Commands->import( register_in => $register_to );
571              
572 48         397 require Rex::Commands::Run;
573 48         423 Rex::Commands::Run->import( register_in => $register_to );
574              
575 48         365 require Rex::Commands::Fs;
576 48         2400 Rex::Commands::Fs->import( register_in => $register_to );
577              
578 48         451 require Rex::Commands::File;
579 48         550 Rex::Commands::File->import( register_in => $register_to );
580              
581 48         397 require Rex::Commands::Cron;
582 48         629 Rex::Commands::Cron->import( register_in => $register_to );
583              
584 48         441 require Rex::Commands::Host;
585 48         477 Rex::Commands::Host->import( register_in => $register_to );
586              
587 48         445 require Rex::Commands::Download;
588 48         1136 Rex::Commands::Download->import( register_in => $register_to );
589              
590 48         439 require Rex::Commands::Upload;
591 48         686 Rex::Commands::Upload->import( register_in => $register_to );
592              
593 48         369 require Rex::Commands::Gather;
594 48         660 Rex::Commands::Gather->import( register_in => $register_to );
595              
596 48         961 require Rex::Commands::Kernel;
597 48         614 Rex::Commands::Kernel->import( register_in => $register_to );
598              
599 48         439 require Rex::Commands::Pkg;
600 48         495 Rex::Commands::Pkg->import( register_in => $register_to );
601              
602 48         461 require Rex::Commands::Service;
603 48         611 Rex::Commands::Service->import( register_in => $register_to );
604              
605 48         3864 require Rex::Commands::Sysctl;
606 48         483 Rex::Commands::Sysctl->import( register_in => $register_to );
607              
608 48         450 require Rex::Commands::Tail;
609 48         476 Rex::Commands::Tail->import( register_in => $register_to );
610              
611 48         461 require Rex::Commands::Process;
612 48         452 Rex::Commands::Process->import( register_in => $register_to );
613              
614 48         414 require Rex::Commands::Sync;
615 48         628 Rex::Commands::Sync->import( register_in => $register_to );
616              
617 48         467 require Rex::Commands::Notify;
618 48         556 Rex::Commands::Notify->import( register_in => $register_to );
619              
620 48         449 require Rex::Commands::User;
621 48         502 Rex::Commands::User->import( register_in => $register_to );
622              
623 48         415 require Rex::Helper::Rexfile::ParamLookup;
624 48         675 Rex::Helper::Rexfile::ParamLookup->import( register_in => $register_to );
625              
626 48         450 require Rex::Resource::firewall;
627 48         389 Rex::Resource::firewall->import( register_in => $register_to );
628             }
629              
630 685 100 66     3475 if ( $what eq "-feature" || $what eq "feature" ) {
631              
632 4 50       37 if ( !ref($addition1) ) {
633 4         49 $addition1 = [$addition1];
634             }
635 4         18 for my $add ( @{$addition1} ) {
  4         33  
636              
637 4         13 my $found_feature = 0;
638              
639 4 100       41 if ( $add =~ m/^(\d+\.\d+)$/ ) {
640 3         19 my $vers = $1;
641 3         39 my ( $major, $minor, $patch, $dev_release ) =
642             $Rex::VERSION =~ m/^(\d+)\.(\d+)\.(\d+)[_.]?(\d+)?$/;
643              
644 3         32 my ( $c_major, $c_minor ) = split( /\./, $vers );
645              
646 3 50 33     56 if ( defined $dev_release && $c_major == $major && $c_minor > $minor ) {
    50 33        
      33        
      33        
647 0         0 Rex::Logger::info(
648             "This is development release $Rex::VERSION of Rex. Enabling experimental feature flag for $vers.",
649             "warn"
650             );
651             }
652             elsif ( ( $c_major > $major )
653             || ( $c_major >= $major && $c_minor > $minor ) )
654             {
655 0         0 Rex::Logger::info(
656             "This Rexfile tries to enable features that are not supported with your version. Please update.",
657             "error"
658             );
659 0         0 exit 1;
660             }
661             }
662              
663 4 50 66     71 if ( $add =~ m/^\d+\.\d+$/ && $add >= 1.4 ) {
664 0         0 Rex::Logger::debug("Enabling task_chaining_cmdline_args feature");
665 0         0 Rex::Config->set_task_chaining_cmdline_args(1);
666 0         0 $found_feature = 1;
667             }
668              
669 4 50 66     56 if ( $add =~ m/^\d+\.\d+$/ && $add >= 1.3 ) {
670 0         0 Rex::Logger::debug("Activating new template engine.");
671 0         0 Rex::Config->set_use_template_ng(1);
672 0         0 $found_feature = 1;
673             }
674              
675 4 50 66     67 if ( $add =~ m/^\d+\.\d+$/ && $add >= 1.0 ) {
676 0         0 Rex::Logger::debug("Disabling usage of a tty");
677 0         0 Rex::Config->set_no_tty(1);
678 0         0 $found_feature = 1;
679             }
680              
681 4 50 66     57 if ( $add =~ m/^\d+\.\d+$/ && $add >= 0.56 ) {
682 0         0 Rex::Logger::debug("Activating autodie.");
683 0         0 Rex::Config->set_autodie(1);
684 0         0 $found_feature = 1;
685             }
686              
687 4 50 66     60 if ( $add =~ m/^\d+\.\d+$/ && $add >= 0.55 ) {
688 0         0 Rex::Logger::debug("Using Net::OpenSSH if present.");
689 0         0 Rex::Config->set_use_net_openssh_if_present(1);
690 0         0 $found_feature = 1;
691             }
692              
693 4 100 100     58 if ( $add =~ m/^\d+\.\d+$/ && $add >= 0.54 ) {
694 1         14 Rex::Logger::debug("Add service check.");
695 1         27 Rex::Config->set_check_service_exists(1);
696              
697 1         4 Rex::Logger::debug("Setting set() to not append data.");
698 1         9 Rex::Config->set_set_no_append(1);
699              
700 1         2 $found_feature = 1;
701             }
702              
703 4 100 100     57 if ( $add =~ m/^\d+\.\d+$/ && $add >= 0.53 ) {
704 1         7 Rex::Logger::debug("Registering CMDB as template variables.");
705 1         10 Rex::Config->set_register_cmdb_template(1);
706 1         2 $found_feature = 1;
707             }
708              
709 4 100 100     51 if ( $add =~ m/^\d+\.\d+$/ && $add >= 0.51 ) {
710 1         7 Rex::Logger::debug("activating featureset >= 0.51");
711 1         6 Rex::Config->set_task_call_by_method(1);
712              
713 1         6 require Rex::Constants;
714 1         5 Rex::Constants->import( register_in => $register_to );
715              
716 1         9 require Rex::CMDB;
717 1         21 Rex::CMDB->import( register_in => $register_to );
718              
719 1         24 Rex::Commands::set(
720             cmdb => {
721             type => "YAML",
722             path => [
723             "cmdb/{operatingsystem}/{hostname}.yml",
724             "cmdb/{operatingsystem}/default.yml",
725             "cmdb/{environment}/{hostname}.yml",
726             "cmdb/{environment}/default.yml",
727             "cmdb/{hostname}.yml",
728             "cmdb/default.yml",
729             ],
730             }
731             );
732              
733 1         4 $found_feature = 1;
734             }
735              
736 4 100 100     71 if ( $add =~ m/^\d+\.\d+$/ && $add >= 0.40 ) {
737 1         9 Rex::Logger::debug("activating featureset >= 0.40");
738 1         12 $Rex::Template::BE_LOCAL = 1;
739 1         5 $Rex::WITH_EXIT_STATUS = 1;
740 1         2 $found_feature = 1;
741             }
742              
743 4 100 100     37 if ( $add =~ m/^\d+\.\d+$/ && $add >= 0.35 ) {
744 1         5 Rex::Logger::debug("activating featureset >= 0.35");
745 1         2 $Rex::Commands::REGISTER_SUB_HASH_PARAMETER = 1;
746 1         2 $found_feature = 1;
747             }
748              
749             # remove default task auth
750 4 100 66     73 if ( $add =~ m/^\d+\.\d+$/ && $add >= 0.31 ) {
751 3         20 Rex::Logger::debug("activating featureset >= 0.31");
752 3         46 Rex::Config->set_default_auth(0);
753 3         8 $found_feature = 1;
754             }
755              
756 4 100       25 if ( $add eq 'autodie' ) {
757 1         5 Rex::Logger::debug('enabling autodie');
758 1         9 Rex::Config->set_autodie(1);
759 1         2 $found_feature = 1;
760             }
761              
762 4 50       13 if ( $add eq "no_autodie" ) {
763 0         0 Rex::Logger::debug("disabling autodie");
764 0         0 Rex::Config->set_autodie(0);
765 0         0 $found_feature = 1;
766             }
767              
768 4 50       15 if ( $add eq "rex_kvm_agent" ) {
769 0         0 Rex::Logger::debug(
770             "Activating experimental support for rex-kvm-agent.");
771 0         0 Rex::Config->set_use_rex_kvm_agent(1);
772 0         0 $found_feature = 1;
773             }
774              
775 4 50       22 if ( $add eq "template_ng" ) {
776 0         0 Rex::Logger::debug("Activating new template engine.");
777 0         0 Rex::Config->set_use_template_ng(1);
778 0         0 $found_feature = 1;
779             }
780              
781 4 50       26 if ( $add eq "no_template_ng" ) {
782 0         0 Rex::Logger::debug("Deactivating new template engine.");
783 0         0 Rex::Config->set_use_template_ng(0);
784 0         0 $found_feature = 1;
785             }
786              
787 4 50       24 if ( $add eq "register_cmdb_top_scope" ) {
788 0         0 Rex::Logger::debug("Registering CMDB as template variables.");
789 0         0 Rex::Config->set_register_cmdb_template(1);
790 0         0 $found_feature = 1;
791             }
792              
793 4 50       28 if ( $add eq "no_local_template_vars" ) {
794 0         0 Rex::Logger::debug("activating featureset no_local_template_vars");
795 0         0 $Rex::Template::BE_LOCAL = 0;
796 0         0 $found_feature = 1;
797             }
798              
799 4 50       25 if ( $add eq "exit_status" ) {
800 0         0 Rex::Logger::debug("activating featureset exit_status");
801 0         0 $Rex::WITH_EXIT_STATUS = 1;
802 0         0 $found_feature = 1;
803             }
804              
805 4 50       17 if ( $add eq "sudo_without_sh" ) {
806 0         0 Rex::Logger::debug(
807             "using sudo without sh. this might break some things.");
808 0         0 Rex::Config->set_sudo_without_sh(1);
809 0         0 $found_feature = 1;
810             }
811              
812 4 50       13 if ( $add eq "sudo_without_locales" ) {
813 0         0 Rex::Logger::debug(
814             "Using sudo without locales. this _will_ break things!");
815 0         0 Rex::Config->set_sudo_without_locales(1);
816 0         0 $found_feature = 1;
817             }
818              
819 4 50       14 if ( $add eq "tty" ) {
820 0         0 Rex::Logger::debug("Enabling pty usage for ssh");
821 0         0 Rex::Config->set_no_tty(0);
822 0         0 $found_feature = 1;
823             }
824              
825 4 50       13 if ( $add eq "no_tty" ) {
826 0         0 Rex::Logger::debug("Disabling pty usage for ssh");
827 0         0 Rex::Config->set_no_tty(1);
828 0         0 $found_feature = 1;
829             }
830              
831 4 50       15 if ( $add eq "empty_groups" ) {
832 0         0 Rex::Logger::debug("Enabling usage of empty groups");
833 0         0 Rex::Config->set_allow_empty_groups(1);
834 0         0 $found_feature = 1;
835             }
836              
837 4 50       20 if ( $add eq "use_server_auth" ) {
838 0         0 Rex::Logger::debug("Enabling use_server_auth");
839 0         0 Rex::Config->set_use_server_auth(1);
840 0         0 $found_feature = 1;
841             }
842              
843 4 50       17 if ( $add eq "exec_and_sleep" ) {
844 0         0 Rex::Logger::debug("Enabling exec_and_sleep");
845 0         0 Rex::Config->set_sleep_hack(1);
846 0         0 $found_feature = 1;
847             }
848              
849 4 50       22 if ( $add eq "disable_strict_host_key_checking" ) {
850 0         0 Rex::Logger::debug("Disabling strict host key checking for openssh");
851 0         0 Rex::Config->set_openssh_opt( StrictHostKeyChecking => "no" );
852 0         0 $found_feature = 1;
853             }
854              
855             #if($add eq "reporting" || $add eq "report" || exists $ENV{REX_REPORT_TYPE}) {
856             # Rex::Logger::debug("Enabling reporting");
857 4         59 Rex::Config->set_do_reporting(1);
858              
859             # $found_feature = 1;
860             #}
861              
862 4 50       23 if ( $add eq "source_profile" ) {
863 0         0 Rex::Logger::debug("Enabling source_profile");
864 0         0 Rex::Config->set_source_profile(1);
865 0         0 $found_feature = 1;
866             }
867              
868 4 50       20 if ( $add eq "source_global_profile" ) {
869 0         0 Rex::Logger::debug("Enabling source_global_profile");
870 0         0 Rex::Config->set_source_global_profile(1);
871 0         0 $found_feature = 1;
872             }
873              
874 4 50       34 if ( $add eq "no_path_cleanup" ) {
875 0         0 Rex::Logger::debug("Enabling no_path_cleanup");
876 0         0 Rex::Config->set_no_path_cleanup(1);
877 0         0 $found_feature = 1;
878             }
879              
880 4 50       23 if ( $add eq "exec_autodie" ) {
881 0         0 Rex::Logger::debug("Enabling exec_autodie");
882 0         0 Rex::Config->set_exec_autodie(1);
883 0         0 $found_feature = 1;
884             }
885              
886 4 50       17 if ( $add eq "no_cache" ) {
887 0         0 Rex::Logger::debug("disable caching");
888 0         0 Rex::Config->set_use_cache(0);
889 0         0 $found_feature = 1;
890             }
891              
892 4 50       20 if ( $add eq "verbose_run" ) {
893 0         0 Rex::Logger::debug("Enabling verbose_run feature");
894 0         0 Rex::Config->set_verbose_run(1);
895 0         0 $found_feature = 1;
896             }
897              
898 4 50       16 if ( $add eq "disable_taskname_warning" ) {
899 0         0 Rex::Logger::debug("Enabling disable_taskname_warning feature");
900 0         0 Rex::Config->set_disable_taskname_warning(1);
901 0         0 $found_feature = 1;
902             }
903              
904 4 50       25 if ( $add eq "no_task_chaining_cmdline_args" ) {
905 0         0 Rex::Logger::debug("Disabling task_chaining_cmdline_args feature");
906 0         0 Rex::Config->set_task_chaining_cmdline_args(0);
907 0         0 $found_feature = 1;
908             }
909              
910 4 50       19 if ( $add eq "task_chaining_cmdline_args" ) {
911 0         0 Rex::Logger::debug("Enabling task_chaining_cmdline_args feature");
912 0         0 Rex::Config->set_task_chaining_cmdline_args(1);
913 0         0 $found_feature = 1;
914             }
915              
916 4 50       20 if ( $add eq "write_utf8_files" ) {
917 0         0 Rex::Logger::debug("Enabling write_utf8_files feature");
918 0         0 Rex::Config->set_write_utf8_files(1);
919 0         0 $found_feature = 1;
920             }
921              
922 4 50       23 if ( $add eq "no_write_utf8_files" ) {
923 0         0 Rex::Logger::debug("Disabling write_utf8_files feature");
924 0         0 Rex::Config->set_write_utf8_files(0);
925 0         0 $found_feature = 1;
926             }
927              
928 4 50       19 if ( $found_feature == 0 ) {
929 0         0 Rex::Logger::info(
930             "You tried to load a feature ($add) that doesn't exists in your Rex version. Please update.",
931             "warn"
932             );
933 0         0 exit 1;
934             }
935              
936             }
937              
938             }
939              
940 685 50       2121 if ( exists $ENV{REX_REPORT_TYPE} ) {
941 0         0 Rex::Logger::debug("Enabling reporting");
942 0         0 Rex::Config->set_do_reporting(1);
943             }
944              
945 685 0 33     1823 if ( exists $ENV{REX_SUDO} && $ENV{REX_SUDO} ) {
946 0         0 Rex::global_sudo(1);
947             }
948              
949             # we are always strict
950 685         905772 strict->import;
951             }
952              
953             =head1 FEATURE FLAGS
954              
955             Everyone knows the pain if something gets deprecated and one has to
956             port his old (and stable) code to a new version of a library or a
957             framework. There is enough work to do instead of fixing code to work
958             with newer versions of them.
959              
960             So there is one promise new versions of Rex has to fulfill. They must
961             be backward compatible.
962              
963             I know this might be impossible in one way or another, but to minimize
964             this danger there is a thing called feature flags. If there is the need
965             to break backward compatibility in favor of a new feature there will be
966             a feature flag for this change. And only if this feature flag gets
967             enabled in the Rexfile it will break compatibility.
968              
969             So the default is always to remain compatible.
970              
971             If you have a problem that occurs after an update, it is considered as
972             a bug. Please report this bug in our issue tracker.
973              
974             Also see the L
975             section of the CONTRIBUTING guide.
976              
977             =head2 How to enable feature flags
978              
979             You can enable feature flags in your Rexfile with the following code:
980              
981             use Rex -feature => ['1.4'];
982              
983             or even multiple ones like this:
984              
985             use Rex -feature => [qw(1.4 exec_autodie)];
986              
987             =head2 List of feature flags
988              
989             =over 4
990              
991             =item 1.4
992              
993             Enable per-task argument parsing (L). Furthermore, all features from earlier versions are activated. Available since version 1.4.
994              
995             =item no_task_chaining_cmdline_args
996              
997             Disable per-task argument parsing. Available since version 1.4.
998              
999             =item task_chaining_cmdline_args
1000              
1001             Enable per-task argument parsing: C
1002             so task1 only gets C and task2 only gets C. Available since version 1.4.
1003              
1004             =item 1.3
1005              
1006             Activating the new template engine by default. Furthermore, all features from earlier versions are activated. Available since version 1.3.
1007              
1008             =item no_template_ng
1009              
1010             Disabling the new template engine. Available since version 1.3.
1011              
1012             =item 1.0
1013              
1014             Disabling usage of a tty. This increases compatibility for remote
1015             execution. Furthermore, all features from earlier versions are
1016             activated. Available since version 1.0.
1017              
1018             =item no_autodie
1019              
1020             Will disable autodie feature. Available since version 1.0.
1021              
1022             =item tty
1023              
1024             Enable pty usage for ssh connections. Available since version 1.0.
1025              
1026             =item template_ng
1027              
1028             Enabling the new template engine (better error reporting, etc.). Available since version 0.56.
1029              
1030             =item 0.56
1031              
1032             Will activate autodie feature. Furthermore, all features from earlier
1033             versions are activated. Available since version 0.56.
1034              
1035             =item autodie
1036              
1037             Will enable autodie feature: die on all failed L. Available since version 1.13.1.
1038              
1039             =item 0.55
1040              
1041             Will activate using L by default if present. Furthermore,
1042             all features from earlier versions are activated. Available since version 0.55.
1043              
1044             =item 0.54
1045              
1046             Will activate checking services for existence before trying to
1047             manipulate them, and C will overwrite already existing values
1048             (instead of concatenating). Furthermore, all features from earlier
1049             versions are activated. Available since version 0.54.
1050              
1051             =item 0.53
1052              
1053             Will activate register_cmdb_top_scope. And all things 0.51 and down
1054             activated. Available since version 0.53.
1055              
1056             =item register_cmdb_top_scope
1057              
1058             Will register all cmdb top scope variables automatically in the
1059             templates. Available since version 0.53.
1060              
1061             =item 0.51
1062              
1063             Will load L and the CMDB by default. And all things 0.47
1064             and down activated. Available since version 0.51.
1065              
1066             =item disable_taskname_warning
1067              
1068             Disable warning about invalid task names (they should match
1069             C). Available since version 0.47.
1070              
1071             =item verbose_run
1072              
1073             Explicitly output "Successfully executed" or "Error executing" messages
1074             for C commands. Available since version 0.47.
1075              
1076             =item no_cache
1077              
1078             Disable caching (like discovery results of remote OS, hardware, shell,
1079             etc.). Available since version 0.46.
1080              
1081             =item no_path_cleanup
1082              
1083             Controls whether Rex should use the default or explicitly configured C
1084             settings when executing commands or not. See also the L
1085             command and the L configuration option.
1086             Available since version 0.44.
1087              
1088             =item source_profile
1089              
1090             Source C<$HOME/.profile> before running a command. Available since version 0.44.
1091              
1092             =item source_global_profile
1093              
1094             Source C before running a command. Available since version 0.44.
1095              
1096             =item exec_autodie
1097              
1098             If you execute a command with C Rex will C if the command
1099             returns a C. Available since version 0.44.
1100              
1101             =item exec_and_sleep
1102              
1103             Sometimes some commands that fork away didn't keep running. With this
1104             flag rex will wait a few ms before exiting the shell. Available since version 0.43.
1105              
1106             =item disable_strict_host_key_checking
1107              
1108             Disabling strict host key checking for openssh connection mode. Available since version 0.43.
1109              
1110             =item reporting
1111              
1112             Enable reporting. Available since version 0.43.
1113              
1114             =item empty_groups
1115              
1116             Enable usage of empty groups. Available since version 0.42.
1117              
1118             =item use_server_auth
1119              
1120             Enable the usage of special authentication options for servers. Available since version 0.42.
1121              
1122             =item no_tty
1123              
1124             Disable pty usage for ssh connections. Available since version 0.41.
1125              
1126             =item no_local_template_vars
1127              
1128             Use global variables in templates. Available since version 0.40.
1129              
1130             =item sudo_without_sh
1131              
1132             Run sudo commands directly without the use of 'sh'. This might break
1133             things. Available since version 0.40.
1134              
1135             =item sudo_without_locales
1136              
1137             Run sudo commands without locales. This will break things if you don't
1138             use English locales. Available since version 0.40.
1139              
1140             =item exit_status
1141              
1142             This option tells Rex to return a non zero value on exit if a task
1143             fails. Available since version 0.39.
1144              
1145             =item 0.35
1146              
1147             This option enables the features of 0.31 and the possibility to call
1148             tasks as a functions without the need to use a hash reference for the
1149             parameters. Available since version 0.35.
1150              
1151             =item 0.31
1152              
1153             To enable special authentication options for a server group. This will
1154             overwrite the default authentication options for a task. Available since version 0.31.
1155              
1156             =back
1157              
1158             =head1 CONTRIBUTORS
1159              
1160             Many thanks to the contributors for their work. Please see L file for a complete list.
1161              
1162             =head1 LICENSE
1163              
1164             Rex is a free software, licensed under:
1165             The Apache License, Version 2.0, January 2004
1166              
1167             =cut
1168              
1169             1;