Module: Puppet::Util::Execution
- Included in:
- Provider::Exec, Diff
- Defined in:
- lib/puppet/util/execution.rb
Overview
This module defines methods for execution of system commands. It is intented for inclusion in classes that needs to execute system commands.
Defined Under Namespace
Classes: ProcessOutput
Constant Summary collapse
- NoOptionsSpecified =
Default empty options for execute
{}
Class Method Summary collapse
-
.execfail(command, exception) ⇒ Puppet::Util::Execution::ProcessOutput
Wraps execution of Execution.execute with mapping of exception to given exception (and output as argument).
-
.execpipe(command, failonfail = true) {|pipe| ... } ⇒ String
The command can be a simple string, which is executed as-is, or an Array, which is treated as a set of command arguments to pass through.
-
.execute(command, options = NoOptionsSpecified) ⇒ Puppet::Util::Execution::ProcessOutput
(also: util_execute)
Executes the desired command, and return the status and output.
-
.ruby_path ⇒ String
private
Returns the path to the ruby executable (available via Config object, even if it’s not in the PATH… so this is slightly safer than just using Puppet::Util.which).
Class Method Details
.execfail(command, exception) ⇒ Puppet::Util::Execution::ProcessOutput
Wraps execution of execute with mapping of exception to given exception (and output as argument).
101 102 103 104 105 106 |
# File 'lib/puppet/util/execution.rb', line 101 def self.execfail(command, exception) output = execute(command) return output rescue Puppet::ExecutionFailure raise exception, output, exception.backtrace end |
.execpipe(command, failonfail = true) {|pipe| ... } ⇒ String
The command can be a simple string, which is executed as-is, or an Array, which is treated as a set of command arguments to pass through.
In either case, the command is passed directly to the shell, STDOUT and STDERR are connected together, and STDOUT will be streamed to the yielded pipe.
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/puppet/util/execution.rb', line 58 def self.execpipe(command, failonfail = true) # Paste together an array with spaces. We used to paste directly # together, no spaces, which made for odd invocations; the user had to # include whitespace between arguments. # # Having two spaces is really not a big drama, since this passes to the # shell anyhow, while no spaces makes for a small developer cost every # time this is invoked. --daniel 2012-02-13 command_str = command.respond_to?(:join) ? command.join(' ') : command if respond_to? :debug debug "Executing '#{command_str}'" else Puppet.debug "Executing '#{command_str}'" end # force the run of the command with # the user/system locale to "C" (via environment variables LANG and LC_*) # it enables to have non localized output for some commands and therefore # a predictable output english_env = ENV.to_hash.merge( {'LANG' => 'C', 'LC_ALL' => 'C'} ) output = Puppet::Util.withenv(english_env) do open("| #{command_str} 2>&1") do |pipe| yield pipe end end if failonfail && exitstatus != 0 raise Puppet::ExecutionFailure, output end output end |
.execute(command, options = NoOptionsSpecified) ⇒ Puppet::Util::Execution::ProcessOutput Also known as: util_execute
Unfortunately, the default behavior for failonfail and combine (since 0.22.4 and 0.24.7, respectively) depend on whether options are specified or not. If specified, then failonfail and combine default to false (even when the options specified are neither failonfail nor combine). If no options are specified, then failonfail and combine default to true.
Executes the desired command, and return the status and output. def execute(command, options)
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 |
# File 'lib/puppet/util/execution.rb', line 144 def self.execute(command, = NoOptionsSpecified) # specifying these here rather than in the method signature to allow callers to pass in a partial # set of overrides without affecting the default values for options that they don't pass in = { :failonfail => NoOptionsSpecified.equal?(), :uid => nil, :gid => nil, :combine => NoOptionsSpecified.equal?(), :stdinfile => nil, :squelch => false, :override_locale => true, :custom_environment => {}, } = .merge() if command.is_a?(Array) command = command.flatten.map(&:to_s) str = command.join(" ") elsif command.is_a?(String) str = command end user_log_s = '' if [:uid] user_log_s << " uid=#{[:uid]}" end if [:gid] user_log_s << " gid=#{[:gid]}" end if user_log_s != '' user_log_s.prepend(' with') end if respond_to? :debug debug "Executing#{user_log_s}: '#{str}'" else Puppet.debug "Executing#{user_log_s}: '#{str}'" end null_file = Puppet.features.microsoft_windows? ? 'NUL' : '/dev/null' begin stdin = File.open([:stdinfile] || null_file, 'r') stdout = [:squelch] ? File.open(null_file, 'w') : Puppet::FileSystem::Uniquefile.new('puppet') stderr = [:combine] ? stdout : File.open(null_file, 'w') exec_args = [command, , stdin, stdout, stderr] if execution_stub = Puppet::Util::ExecutionStub.current_value return execution_stub.call(*exec_args) elsif Puppet.features.posix? child_pid = nil begin child_pid = execute_posix(*exec_args) exit_status = Process.waitpid2(child_pid).last.exitstatus child_pid = nil rescue Timeout::Error => e # NOTE: For Ruby 2.1+, an explicit Timeout::Error class has to be # passed to Timeout.timeout in order for there to be something for # this block to rescue. unless child_pid.nil? Process.kill(:TERM, child_pid) # Spawn a thread to reap the process if it dies. Thread.new { Process.waitpid(child_pid) } end raise e end elsif Puppet.features.microsoft_windows? process_info = execute_windows(*exec_args) begin exit_status = Puppet::Util::Windows::Process.wait_process(process_info.process_handle) ensure FFI::WIN32.CloseHandle(process_info.process_handle) FFI::WIN32.CloseHandle(process_info.thread_handle) end end [stdin, stdout, stderr].each {|io| io.close rescue nil} # read output in if required unless [:squelch] output = wait_for_output(stdout) Puppet.warning "Could not get output" unless output end if [:failonfail] and exit_status != 0 raise Puppet::ExecutionFailure, "Execution of '#{str}' returned #{exit_status}: #{output.strip}" end ensure if ![:squelch] && stdout # if we opened a temp file for stdout, we need to clean it up. stdout.close! end end Puppet::Util::Execution::ProcessOutput.new(output || '', exit_status) end |
.ruby_path ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns the path to the ruby executable (available via Config object, even if it’s not in the PATH… so this is slightly safer than just using Puppet::Util.which)
249 250 251 252 253 |
# File 'lib/puppet/util/execution.rb', line 249 def self.ruby_path() File.join(RbConfig::CONFIG['bindir'], RbConfig::CONFIG['ruby_install_name'] + RbConfig::CONFIG['EXEEXT']). sub(/.*\s.*/m, '"\&"') end |