1#
2# (c) Jan Gehring <jan.gehring@gmail.com>
3#
4# vim: set ts=2 sw=2 tw=0:
5# vim: set expandtab:
6
7package Rex::Helper::Run;
8
9use 5.010001;
10use strict;
11use warnings;
12
13our $VERSION = '1.13.4'; # VERSION
14
15require Exporter;
16use base qw(Exporter);
17use vars qw(@EXPORT);
18
19use Net::OpenSSH::ShellQuoter;
20use Rex::Interface::File;
21use Rex::Interface::Fs;
22use Rex::Helper::Path;
23use Carp;
24require Rex::Commands;
25require Rex::Config;
26
27@EXPORT = qw(upload_and_run i_run i_exec i_exec_nohup);
28
29sub upload_and_run {
30  my ( $template, %option ) = @_;
31
32  my $rnd_file = get_tmp_file;
33
34  my $fh = Rex::Interface::File->create;
35  $fh->open( ">", $rnd_file );
36  $fh->write($template);
37  $fh->close;
38
39  my $fs = Rex::Interface::Fs->create;
40  $fs->chmod( 755, $rnd_file );
41
42  my @argv;
43  my $command = $rnd_file;
44
45  if ( exists $option{with} ) {
46    $command = Rex::Config->get_executor_for( $option{with} ) . " $command";
47  }
48
49  if ( exists $option{args} ) {
50    $command .= join( " ", @{ $option{args} } );
51  }
52
53  return i_run("$command 2>&1");
54}
55
56# internal run command, doesn't get reported
57sub i_run {
58  my $cmd = shift;
59  my ( $code, $option );
60  $option = {};
61  if ( ref $_[0] eq "CODE" ) {
62    $code = shift;
63  }
64  if ( scalar @_ > 0 ) {
65    $option = {@_};
66  }
67
68  $option->{valid_retval} ||= [0];
69  $option->{fail_ok} //= 0;
70
71  if ( $option->{no_stderr} ) {
72    $cmd = "$cmd 2>/dev/null";
73  }
74
75  if ( $option->{stderr_to_stdout} ) {
76    $cmd = "$cmd 2>&1";
77  }
78
79  if ( ref $option->{valid_retval} ne "ARRAY" ) {
80    $option->{valid_retval} = [ $option->{valid_retval} ];
81  }
82
83  my $is_no_hup       = 0;
84  my $tmp_output_file = get_tmp_file();
85  if ( exists $option->{nohup} && $option->{nohup} ) {
86    $cmd = "nohup $cmd >$tmp_output_file";
87    delete $option->{nohup};
88    $is_no_hup = 1;
89  }
90
91  my $path;
92
93  if ( !Rex::Config->get_no_path_cleanup() ) {
94    $path = join( ":", Rex::Config->get_path() );
95  }
96
97  my $exec = Rex::Interface::Exec->create;
98  my ( $out, $err ) = $exec->exec( $cmd, $path, $option );
99  my $ret_val = $?;
100
101  chomp $out if $out;
102  chomp $err if $err;
103
104  $Rex::Commands::Run::LAST_OUTPUT = [ $out, $err ];
105
106  $out ||= "";
107  $err ||= "";
108
109  if ( scalar( grep { $_ == $ret_val } @{ $option->{valid_retval} } ) == 0 ) {
110    if ( !$option->{fail_ok} ) {
111      Rex::Logger::debug("Error executing `$cmd`: ");
112      Rex::Logger::debug("STDOUT:");
113      Rex::Logger::debug($out);
114      Rex::Logger::debug("STDERR:");
115      Rex::Logger::debug($err);
116
117      if ($is_no_hup) {
118        $out = $exec->exec("cat $tmp_output_file ; rm -f $tmp_output_file");
119        $Rex::Commands::Run::LAST_OUTPUT = [$out];
120        $?                               = $ret_val;
121      }
122
123      confess("Error during `i_run`");
124    }
125  }
126
127  if ($code) {
128    return &$code( $out, $err );
129  }
130
131  if (wantarray) {
132    return split( /\r?\n/, $out );
133  }
134
135  if ($is_no_hup) {
136    $out = $exec->exec("cat $tmp_output_file ; rm -f $tmp_output_file");
137    $Rex::Commands::Run::LAST_OUTPUT = [$out];
138    $?                               = $ret_val;
139  }
140
141  return $out;
142}
143
144sub i_exec {
145  my ( $cmd, @args ) = @_;
146
147  my $exec   = Rex::Interface::Exec->create;
148  my $quoter = Net::OpenSSH::ShellQuoter->quoter( $exec->shell->name );
149
150  my $_cmd_str = "$cmd " . join( " ", map { $quoter->quote($_) } @args );
151
152  i_run $_cmd_str;
153}
154
155sub i_exec_nohup {
156  my ( $cmd, @args ) = @_;
157
158  my $exec   = Rex::Interface::Exec->create;
159  my $quoter = Net::OpenSSH::ShellQuoter->quoter( $exec->shell->name );
160
161  my $_cmd_str = "$cmd " . join( " ", map { $quoter->quote($_) } @args );
162  i_run $_cmd_str, nohup => 1;
163}
164
1651;
166