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   740917 use v5.12.5;
  102         470  
50 102     102   565 use warnings;
  102         219  
  102         5263  
51              
52             our $VERSION = '1.14.2.3'; # TRIAL VERSION
53              
54             BEGIN {
55 102     102   11068 use Rex::Logger;
  102         203  
  102         1648  
56 102     102   43442 use Rex::Interface::Cache;
  102         247  
  102         1718  
57 102     102   18040 use Data::Dumper;
  102         171068  
  102         5126  
58 102     102   41919 use Rex::Interface::Connection;
  102         241  
  102         2005  
59 102     102   2525 use Cwd qw(getcwd);
  102         198  
  102         5098  
60 102     102   17570 use Rex::Config;
  102         214  
  102         583  
61 102     102   42955 use Rex::Helper::Array;
  102         295  
  102         5713  
62 102     102   15582 use Rex::Report;
  102         208  
  102         766  
63 102     102   43359 use Rex::Notify;
  102         269  
  102         1241  
64 102     102   3007 use Rex::Require;
  102         205  
  102         488  
65 102     102   2260 use File::Basename;
  102         210  
  102         10742  
66 102     102   671 use File::Spec;
  102         196  
  102         1175  
67 102     102   2612 eval { Net::SSH2->require; };
  102         594  
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 354 my @additional = @_;
80              
81 110         219 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 8713     8713   12529339 my $mod_to_load = $_[1];
87 8713         23334 return search_module_path( $mod_to_load, 1 );
88 110         645 };
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         413 push @rex_inc, add_cwd_to_inc();
94 110         355 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         249 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         312 my $home_dir = _home_dir();
102 110 50       1389 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         1067 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   4323 my $mod_to_load = $_[1];
114 294         1435 return search_module_path( $mod_to_load, 0 );
115             }
116 110         711 );
117              
118 110         1004 return @rex_inc;
119             }
120              
121             sub add_libstruct_to_inc {
122 118     118 0 304 my ($path) = @_;
123 118         259 my @ret = ();
124              
125 118 100       5128 if ( -d File::Spec->catdir( $path, "lib" ) ) {
126 110         1022 push( @ret, File::Spec->catdir( $path, "lib" ) );
127 110         833 push( @ret, File::Spec->catdir( $path, "lib", "perl", "lib", "perl5" ) );
128 110 50       691 if ( $^O eq "linux" ) {
129 110         878 push(
130             @ret,
131             File::Spec->catdir(
132             $path, "lib", "perl", "lib", "perl5", "x86_64-linux"
133             )
134             );
135             }
136 110 50       929 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         566 return @ret;
151             }
152              
153             sub add_cwd_to_inc {
154 110     110 0 1351 my $path = getcwd;
155 110         514 return add_libstruct_to_inc($path);
156             }
157              
158             sub _home_dir {
159 110 50   110   576 if ( $^O =~ m/^MSWin/ ) {
160 0         0 return $ENV{'USERPROFILE'};
161             }
162              
163 110   50     609 return $ENV{'HOME'} || "";
164             }
165              
166 102     102   5463 my @new_inc = generate_inc();
167 102         435778 @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 9007     9007 0 24660 my ( $mod_to_load, $pre ) = @_;
180              
181 9007         41487 $mod_to_load =~ s/\.pm//g;
182              
183 9007         18569 my @search_in;
184 9007 100       20526 if ($pre) {
185 104313         251225 @search_in = map { ("$_/$mod_to_load.pm") }
186 8713         18234 grep { -d } @INC;
  148078         1641443  
187              
188             }
189             else {
190             @search_in =
191 3523         12375 map { ( "$_/$mod_to_load/__module__.pm", "$_/$mod_to_load/Module.pm" ) }
192 294         1222 grep { -d } @INC;
  5003         51513  
193             }
194              
195 9007         23889 for my $file (@search_in) {
196 46525         482592 my $o = -f $file;
197 46525         87079 my $fh_t;
198 46525 50 33     179369 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 46525 100       150647 if ($o) {
205 8419 50       15578 close $fh_t if $fh_t;
206 8419         59251 my ($path) = ( $file =~ m/^(.*)\/.+?$/ );
207 8419 50       28426 if ( $path !~ m/\// ) {
208 0         0 $path = getcwd() . "/$path";
209             }
210              
211             # module found, register path
212 8419         51482 $MODULE_PATHS->{$mod_to_load} = { path => $path };
213 8419         16519 my $mod_package_name = $mod_to_load;
214 8419         34638 $mod_package_name =~ s/\//::/g;
215 8419         32450 $MODULE_PATHS->{$mod_package_name} = { path => $path };
216              
217 8419 50       19175 if ($pre) {
218 8419         4152095 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       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 694 if ( !ref $_[0]->{server} ) {
236 63         633 $_[0]->{server} = Rex::Group::Entry::Server->new( name => $_[0]->{server} );
237             }
238              
239 103         717 push @CONNECTION_STACK, $_[0];
240 103         306 return $_[0];
241             }
242              
243             sub pop_connection {
244 32     32 0 241 pop @CONNECTION_STACK;
245 32         4484 Rex::Logger::debug( "Connections in queue: " . scalar(@CONNECTION_STACK) );
246             }
247              
248             sub reconnect_lost_connections {
249 107 100   107 0 3356 if ( @CONNECTION_STACK > 0 ) {
250 1         5 Rex::Logger::debug("Need to reinitialize connections.");
251 1         10 for (@CONNECTION_STACK) {
252 2         46 $_->{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 33106 unless (@CONNECTION_STACK) {
298 63         2112 my $conn = Rex::Interface::Connection->create("Local");
299              
300 63         483 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         57798 $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 3400 if ( $CONNECTION_STACK[-1] ) {
326 1189         9019 my $ref = ref( $CONNECTION_STACK[-1]->{"conn"} );
327 1189 50       11795 if ( $ref =~ m/SSH/ ) {
328 0         0 return $CONNECTION_STACK[-1]->{"conn"}->get_connection_object();
329             }
330             }
331              
332 1195         5591 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 381 if ( $CONNECTION_STACK[-1] ) {
343 113         958 my $ref = ref( $CONNECTION_STACK[-1]->{"conn"} );
344 113 50       1672 if ( $ref =~ m/Local/ ) {
345 113         1680 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 25693 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       8833 if ($GLOBAL_SUDO) { return 1; }
  0         0  
372              
373 3719 50       9695 if ( $CONNECTION_STACK[-1] ) {
374 3719         25520 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 8137 if ( $CONNECTION_STACK[-1] ) {
404 1887         9415 return $CONNECTION_STACK[-1]->{"cache"};
405             }
406              
407 10         96 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   26209 my ( $class, $what, $addition1 ) = @_;
543              
544 685         20033 srand();
545              
546 685 50 66     4712 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     4683 $what ||= "";
554              
555 685         4261 my ( $register_to, $file, $line ) = caller;
556              
557             # use Net::OpenSSH if present (default without feature flag)
558 685         6873 Rex::Config->set_use_net_openssh_if_present(1);
559              
560 685 100       2370 if ( $what eq "-minimal" ) {
561 36         300 require Rex::Commands;
562 36         397 Rex::Commands->import( register_in => $register_to );
563              
564 36         258 require Rex::Helper::Rexfile::ParamLookup;
565 36         306 Rex::Helper::Rexfile::ParamLookup->import( register_in => $register_to );
566             }
567              
568 685 100 66     7951 if ( $what eq "-base" || $what eq "base" || $what eq "-feature" ) {
      100        
569 48         402 require Rex::Commands;
570 48         512 Rex::Commands->import( register_in => $register_to );
571              
572 48         421 require Rex::Commands::Run;
573 48         452 Rex::Commands::Run->import( register_in => $register_to );
574              
575 48         384 require Rex::Commands::Fs;
576 48         2513 Rex::Commands::Fs->import( register_in => $register_to );
577              
578 48         490 require Rex::Commands::File;
579 48         559 Rex::Commands::File->import( register_in => $register_to );
580              
581 48         447 require Rex::Commands::Cron;
582 48         630 Rex::Commands::Cron->import( register_in => $register_to );
583              
584 48         419 require Rex::Commands::Host;
585 48         510 Rex::Commands::Host->import( register_in => $register_to );
586              
587 48         404 require Rex::Commands::Download;
588 48         1172 Rex::Commands::Download->import( register_in => $register_to );
589              
590 48         353 require Rex::Commands::Upload;
591 48         1137 Rex::Commands::Upload->import( register_in => $register_to );
592              
593 48         418 require Rex::Commands::Gather;
594 48         660 Rex::Commands::Gather->import( register_in => $register_to );
595              
596 48         1128 require Rex::Commands::Kernel;
597 48         663 Rex::Commands::Kernel->import( register_in => $register_to );
598              
599 48         639 require Rex::Commands::Pkg;
600 48         599 Rex::Commands::Pkg->import( register_in => $register_to );
601              
602 48         527 require Rex::Commands::Service;
603 48         692 Rex::Commands::Service->import( register_in => $register_to );
604              
605 48         4215 require Rex::Commands::Sysctl;
606 48         492 Rex::Commands::Sysctl->import( register_in => $register_to );
607              
608 48         488 require Rex::Commands::Tail;
609 48         500 Rex::Commands::Tail->import( register_in => $register_to );
610              
611 48         430 require Rex::Commands::Process;
612 48         483 Rex::Commands::Process->import( register_in => $register_to );
613              
614 48         419 require Rex::Commands::Sync;
615 48         642 Rex::Commands::Sync->import( register_in => $register_to );
616              
617 48         460 require Rex::Commands::Notify;
618 48         535 Rex::Commands::Notify->import( register_in => $register_to );
619              
620 48         486 require Rex::Commands::User;
621 48         480 Rex::Commands::User->import( register_in => $register_to );
622              
623 48         407 require Rex::Helper::Rexfile::ParamLookup;
624 48         587 Rex::Helper::Rexfile::ParamLookup->import( register_in => $register_to );
625              
626 48         512 require Rex::Resource::firewall;
627 48         479 Rex::Resource::firewall->import( register_in => $register_to );
628             }
629              
630 685 100 66     3905 if ( $what eq "-feature" || $what eq "feature" ) {
631              
632 4 50       37 if ( !ref($addition1) ) {
633 4         38 $addition1 = [$addition1];
634             }
635 4         17 for my $add ( @{$addition1} ) {
  4         23  
636              
637 4         10 my $found_feature = 0;
638              
639 4 100       43 if ( $add =~ m/^(\d+\.\d+)$/ ) {
640 3         15 my $vers = $1;
641 3         47 my ( $major, $minor, $patch, $dev_release ) =
642             $Rex::VERSION =~ m/^(\d+)\.(\d+)\.(\d+)[_.]?(\d+)?$/;
643              
644 3         17 my ( $c_major, $c_minor ) = split( /\./, $vers );
645              
646 3 50 33     90 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     81 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     53 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     56 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     53 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     55 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     63 if ( $add =~ m/^\d+\.\d+$/ && $add >= 0.54 ) {
694 1         5 Rex::Logger::debug("Add service check.");
695 1         17 Rex::Config->set_check_service_exists(1);
696              
697 1         4 Rex::Logger::debug("Setting set() to not append data.");
698 1         8 Rex::Config->set_set_no_append(1);
699              
700 1         1 $found_feature = 1;
701             }
702              
703 4 100 100     64 if ( $add =~ m/^\d+\.\d+$/ && $add >= 0.53 ) {
704 1         6 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     54 if ( $add =~ m/^\d+\.\d+$/ && $add >= 0.51 ) {
710 1         4 Rex::Logger::debug("activating featureset >= 0.51");
711 1         5 Rex::Config->set_task_call_by_method(1);
712              
713 1         5 require Rex::Constants;
714 1         5 Rex::Constants->import( register_in => $register_to );
715              
716 1         5 require Rex::CMDB;
717 1         21 Rex::CMDB->import( register_in => $register_to );
718              
719 1         25 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         8 Rex::Logger::debug("activating featureset >= 0.40");
738 1         7 $Rex::Template::BE_LOCAL = 1;
739 1         5 $Rex::WITH_EXIT_STATUS = 1;
740 1         3 $found_feature = 1;
741             }
742              
743 4 100 100     70 if ( $add =~ m/^\d+\.\d+$/ && $add >= 0.35 ) {
744 1         12 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     392 if ( $add =~ m/^\d+\.\d+$/ && $add >= 0.31 ) {
751 3         28 Rex::Logger::debug("activating featureset >= 0.31");
752 3         55 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         14 Rex::Config->set_autodie(1);
759 1         1 $found_feature = 1;
760             }
761              
762 4 50       24 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       17 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       20 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       21 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       18 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       20 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       26 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       47 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       15 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       15 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       15 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       13 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       23 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       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         69 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       23 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       20 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       16 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       21 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       19 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       41 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       26 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       15 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       16 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       17 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       2349 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     1873 if ( exists $ENV{REX_SUDO} && $ENV{REX_SUDO} ) {
946 0         0 Rex::global_sudo(1);
947             }
948              
949             # we are always strict
950 685         894593 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;