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   749011 use v5.12.5;
  102         437  
50 102     102   557 use warnings;
  102         249  
  102         5254  
51              
52             our $VERSION = '1.14.2.2'; # TRIAL VERSION
53              
54             BEGIN {
55 102     102   11227 use Rex::Logger;
  102         219  
  102         1811  
56 102     102   44730 use Rex::Interface::Cache;
  102         274  
  102         1777  
57 102     102   17579 use Data::Dumper;
  102         171725  
  102         5079  
58 102     102   42395 use Rex::Interface::Connection;
  102         252  
  102         1836  
59 102     102   2554 use Cwd qw(getcwd);
  102         189  
  102         4942  
60 102     102   16925 use Rex::Config;
  102         226  
  102         511  
61 102     102   43223 use Rex::Helper::Array;
  102         279  
  102         5649  
62 102     102   15765 use Rex::Report;
  102         219  
  102         758  
63 102     102   43629 use Rex::Notify;
  102         246  
  102         1201  
64 102     102   3060 use Rex::Require;
  102         206  
  102         497  
65 102     102   2227 use File::Basename;
  102         216  
  102         11343  
66 102     102   669 use File::Spec;
  102         193  
  102         1180  
67 102     102   2624 eval { Net::SSH2->require; };
  102         518  
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 315 my @additional = @_;
80              
81 110         245 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 8420     8420   12787391 my $mod_to_load = $_[1];
87 8420         22298 return search_module_path( $mod_to_load, 1 );
88 110         617 };
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         493 push @rex_inc, add_cwd_to_inc();
94 110         393 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         213 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         290 my $home_dir = _home_dir();
102 110 50       1541 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         1112 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 278     278   4472 my $mod_to_load = $_[1];
114 278         1274 return search_module_path( $mod_to_load, 0 );
115             }
116 110         766 );
117              
118 110         970 return @rex_inc;
119             }
120              
121             sub add_libstruct_to_inc {
122 118     118 0 309 my ($path) = @_;
123 118         292 my @ret = ();
124              
125 118 100       3872 if ( -d File::Spec->catdir( $path, "lib" ) ) {
126 110         2218 push( @ret, File::Spec->catdir( $path, "lib" ) );
127 110         737 push( @ret, File::Spec->catdir( $path, "lib", "perl", "lib", "perl5" ) );
128 110 50       741 if ( $^O eq "linux" ) {
129 110         854 push(
130             @ret,
131             File::Spec->catdir(
132             $path, "lib", "perl", "lib", "perl5", "x86_64-linux"
133             )
134             );
135             }
136 110 50       594 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         617 return @ret;
151             }
152              
153             sub add_cwd_to_inc {
154 110     110 0 1361 my $path = getcwd;
155 110         490 return add_libstruct_to_inc($path);
156             }
157              
158             sub _home_dir {
159 110 50   110   575 if ( $^O =~ m/^MSWin/ ) {
160 0         0 return $ENV{'USERPROFILE'};
161             }
162              
163 110   50     697 return $ENV{'HOME'} || "";
164             }
165              
166 102     102   5713 my @new_inc = generate_inc();
167 102         438848 @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 8698     8698 0 23943 my ( $mod_to_load, $pre ) = @_;
180              
181 8698         39860 $mod_to_load =~ s/\.pm//g;
182              
183 8698         17729 my @search_in;
184 8698 100       19909 if ($pre) {
185 100802         242311 @search_in = map { ("$_/$mod_to_load.pm") }
186 8420         17561 grep { -d } @INC;
  143102         1571293  
187              
188             }
189             else {
190             @search_in =
191 3331         12090 map { ( "$_/$mod_to_load/__module__.pm", "$_/$mod_to_load/Module.pm" ) }
192 278         1241 grep { -d } @INC;
  4731         48562  
193             }
194              
195 8698         23118 for my $file (@search_in) {
196 45672         474148 my $o = -f $file;
197 45672         90381 my $fh_t;
198 45672 50 33     172683 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 45672 100       147926 if ($o) {
205 8142 50       15064 close $fh_t if $fh_t;
206 8142         57480 my ($path) = ( $file =~ m/^(.*)\/.+?$/ );
207 8142 50       26907 if ( $path !~ m/\// ) {
208 0         0 $path = getcwd() . "/$path";
209             }
210              
211             # module found, register path
212 8142         49340 $MODULE_PATHS->{$mod_to_load} = { path => $path };
213 8142         15860 my $mod_package_name = $mod_to_load;
214 8142         29524 $mod_package_name =~ s/\//::/g;
215 8142         31241 $MODULE_PATHS->{$mod_package_name} = { path => $path };
216              
217 8142 50       18353 if ($pre) {
218 8142         3995987 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 14 my ($module) = @_;
229 6 50       29 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 726 if ( !ref $_[0]->{server} ) {
236 63         745 $_[0]->{server} = Rex::Group::Entry::Server->new( name => $_[0]->{server} );
237             }
238              
239 103         635 push @CONNECTION_STACK, $_[0];
240 103         353 return $_[0];
241             }
242              
243             sub pop_connection {
244 32     32 0 319 pop @CONNECTION_STACK;
245 32         4122 Rex::Logger::debug( "Connections in queue: " . scalar(@CONNECTION_STACK) );
246             }
247              
248             sub reconnect_lost_connections {
249 107 100   107 0 1333 if ( @CONNECTION_STACK > 0 ) {
250 1         5 Rex::Logger::debug("Need to reinitialize connections.");
251 1         12 for (@CONNECTION_STACK) {
252 2         31 $_->{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 7173 100   7173 1 31661 unless (@CONNECTION_STACK) {
298 63         2178 my $conn = Rex::Interface::Connection->create("Local");
299              
300 63         488 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 7173         57040 $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 1196 100   1196 1 3751 if ( $CONNECTION_STACK[-1] ) {
326 1190         8290 my $ref = ref( $CONNECTION_STACK[-1]->{"conn"} );
327 1190 50       12825 if ( $ref =~ m/SSH/ ) {
328 0         0 return $CONNECTION_STACK[-1]->{"conn"}->get_connection_object();
329             }
330             }
331              
332 1196         6119 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 114 50   114 1 436 if ( $CONNECTION_STACK[-1] ) {
343 114         1042 my $ref = ref( $CONNECTION_STACK[-1]->{"conn"} );
344 114 50       1870 if ( $ref =~ m/Local/ ) {
345 114         1290 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 3510 50 33 3510 1 23181 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 3510 50       7904 if ($GLOBAL_SUDO) { return 1; }
  0         0  
372              
373 3510 50       9121 if ( $CONNECTION_STACK[-1] ) {
374 3510         25076 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 1898 100   1898 0 7977 if ( $CONNECTION_STACK[-1] ) {
404 1888         9199 return $CONNECTION_STACK[-1]->{"cache"};
405             }
406              
407 10         102 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 669     669   25289 my ( $class, $what, $addition1 ) = @_;
543              
544 669         19084 srand();
545              
546 669 50 66     4636 if ( $addition1 && ref $addition1 eq "ARRAY" ) {
    100          
547 0         0 push @FEATURE_FLAGS, $what, @{$addition1};
  0         0  
548             }
549             elsif ($addition1) {
550 4         11 push @FEATURE_FLAGS, $what, $addition1;
551             }
552              
553 669   100     4698 $what ||= "";
554              
555 669         4246 my ( $register_to, $file, $line ) = caller;
556              
557             # use Net::OpenSSH if present (default without feature flag)
558 669         6541 Rex::Config->set_use_net_openssh_if_present(1);
559              
560 669 100       2411 if ( $what eq "-minimal" ) {
561 36         290 require Rex::Commands;
562 36         400 Rex::Commands->import( register_in => $register_to );
563              
564 36         275 require Rex::Helper::Rexfile::ParamLookup;
565 36         331 Rex::Helper::Rexfile::ParamLookup->import( register_in => $register_to );
566             }
567              
568 669 100 66     7813 if ( $what eq "-base" || $what eq "base" || $what eq "-feature" ) {
      100        
569 48         358 require Rex::Commands;
570 48         548 Rex::Commands->import( register_in => $register_to );
571              
572 48         419 require Rex::Commands::Run;
573 48         424 Rex::Commands::Run->import( register_in => $register_to );
574              
575 48         390 require Rex::Commands::Fs;
576 48         2420 Rex::Commands::Fs->import( register_in => $register_to );
577              
578 48         444 require Rex::Commands::File;
579 48         528 Rex::Commands::File->import( register_in => $register_to );
580              
581 48         465 require Rex::Commands::Cron;
582 48         617 Rex::Commands::Cron->import( register_in => $register_to );
583              
584 48         462 require Rex::Commands::Host;
585 48         464 Rex::Commands::Host->import( register_in => $register_to );
586              
587 48         390 require Rex::Commands::Download;
588 48         1137 Rex::Commands::Download->import( register_in => $register_to );
589              
590 48         349 require Rex::Commands::Upload;
591 48         727 Rex::Commands::Upload->import( register_in => $register_to );
592              
593 48         374 require Rex::Commands::Gather;
594 48         744 Rex::Commands::Gather->import( register_in => $register_to );
595              
596 48         1092 require Rex::Commands::Kernel;
597 48         603 Rex::Commands::Kernel->import( register_in => $register_to );
598              
599 48         593 require Rex::Commands::Pkg;
600 48         543 Rex::Commands::Pkg->import( register_in => $register_to );
601              
602 48         491 require Rex::Commands::Service;
603 48         666 Rex::Commands::Service->import( register_in => $register_to );
604              
605 48         4277 require Rex::Commands::Sysctl;
606 48         454 Rex::Commands::Sysctl->import( register_in => $register_to );
607              
608 48         497 require Rex::Commands::Tail;
609 48         528 Rex::Commands::Tail->import( register_in => $register_to );
610              
611 48         423 require Rex::Commands::Process;
612 48         531 Rex::Commands::Process->import( register_in => $register_to );
613              
614 48         512 require Rex::Commands::Sync;
615 48         565 Rex::Commands::Sync->import( register_in => $register_to );
616              
617 48         530 require Rex::Commands::Notify;
618 48         465 Rex::Commands::Notify->import( register_in => $register_to );
619              
620 48         399 require Rex::Commands::User;
621 48         483 Rex::Commands::User->import( register_in => $register_to );
622              
623 48         416 require Rex::Helper::Rexfile::ParamLookup;
624 48         559 Rex::Helper::Rexfile::ParamLookup->import( register_in => $register_to );
625              
626 48         448 require Rex::Resource::firewall;
627 48         454 Rex::Resource::firewall->import( register_in => $register_to );
628             }
629              
630 669 100 66     3695 if ( $what eq "-feature" || $what eq "feature" ) {
631              
632 4 50       29 if ( !ref($addition1) ) {
633 4         42 $addition1 = [$addition1];
634             }
635 4         18 for my $add ( @{$addition1} ) {
  4         27  
636              
637 4         12 my $found_feature = 0;
638              
639 4 100       39 if ( $add =~ m/^(\d+\.\d+)$/ ) {
640 3         14 my $vers = $1;
641 3         45 my ( $major, $minor, $patch, $dev_release ) =
642             $Rex::VERSION =~ m/^(\d+)\.(\d+)\.(\d+)[_.]?(\d+)?$/;
643              
644 3         19 my ( $c_major, $c_minor ) = split( /\./, $vers );
645              
646 3 50 33     117 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     73 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     62 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     50 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     58 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     54 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     59 if ( $add =~ m/^\d+\.\d+$/ && $add >= 0.54 ) {
694 1         6 Rex::Logger::debug("Add service check.");
695 1         28 Rex::Config->set_check_service_exists(1);
696              
697 1         3 Rex::Logger::debug("Setting set() to not append data.");
698 1         16 Rex::Config->set_set_no_append(1);
699              
700 1         3 $found_feature = 1;
701             }
702              
703 4 100 100     58 if ( $add =~ m/^\d+\.\d+$/ && $add >= 0.53 ) {
704 1         5 Rex::Logger::debug("Registering CMDB as template variables.");
705 1         6 Rex::Config->set_register_cmdb_template(1);
706 1         2 $found_feature = 1;
707             }
708              
709 4 100 100     44 if ( $add =~ m/^\d+\.\d+$/ && $add >= 0.51 ) {
710 1         5 Rex::Logger::debug("activating featureset >= 0.51");
711 1         4 Rex::Config->set_task_call_by_method(1);
712              
713 1         6 require Rex::Constants;
714 1         4 Rex::Constants->import( register_in => $register_to );
715              
716 1         6 require Rex::CMDB;
717 1         20 Rex::CMDB->import( register_in => $register_to );
718              
719 1         28 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     72 if ( $add =~ m/^\d+\.\d+$/ && $add >= 0.40 ) {
737 1         12 Rex::Logger::debug("activating featureset >= 0.40");
738 1         19 $Rex::Template::BE_LOCAL = 1;
739 1         9 $Rex::WITH_EXIT_STATUS = 1;
740 1         17 $found_feature = 1;
741             }
742              
743 4 100 100     77 if ( $add =~ m/^\d+\.\d+$/ && $add >= 0.35 ) {
744 1         7 Rex::Logger::debug("activating featureset >= 0.35");
745 1         4 $Rex::Commands::REGISTER_SUB_HASH_PARAMETER = 1;
746 1         3 $found_feature = 1;
747             }
748              
749             # remove default task auth
750 4 100 66     52 if ( $add =~ m/^\d+\.\d+$/ && $add >= 0.31 ) {
751 3         22 Rex::Logger::debug("activating featureset >= 0.31");
752 3         56 Rex::Config->set_default_auth(0);
753 3         7 $found_feature = 1;
754             }
755              
756 4 100       25 if ( $add eq 'autodie' ) {
757 1         6 Rex::Logger::debug('enabling autodie');
758 1         24 Rex::Config->set_autodie(1);
759 1         3 $found_feature = 1;
760             }
761              
762 4 50       14 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       14 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       15 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       24 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       22 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       19 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       35 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       26 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       24 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       27 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       16 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       14 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       12 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       14 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       26 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         72 Rex::Config->set_do_reporting(1);
858              
859             # $found_feature = 1;
860             #}
861              
862 4 50       16 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       26 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       22 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       14 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       20 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       31 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       28 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       21 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       16 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       53 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       18 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 669 50       2119 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 669 0 33     1818 if ( exists $ENV{REX_SUDO} && $ENV{REX_SUDO} ) {
946 0         0 Rex::global_sudo(1);
947             }
948              
949             # we are always strict
950 669         911279 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;