Class: Mixlib::ShellOut
- Inherits:
-
Object
- Object
- Mixlib::ShellOut
- Defined in:
- lib/mixlib/shellout.rb,
lib/mixlib/shellout/unix.rb,
lib/mixlib/shellout/helper.rb,
lib/mixlib/shellout/version.rb,
lib/mixlib/shellout/windows.rb,
lib/mixlib/shellout/exceptions.rb
Defined Under Namespace
Modules: Helper, Unix, Windows Classes: CommandTimeout, EmptyWindowsCommand, Error, InvalidCommandOption, ShellCommandFailed
Constant Summary collapse
- READ_WAIT_TIME =
0.01
- READ_SIZE =
4096
- DEFAULT_READ_TIMEOUT =
600
- VERSION =
"3.2.8".freeze
Constants included from Unix
Constants included from Windows
Constants included from Process::Constants
Process::Constants::ENVIRONMENT_BLOCK_ENDS, Process::Constants::ERROR_LOGON_TYPE_NOT_GRANTED, Process::Constants::ERROR_PRIVILEGE_NOT_HELD, Process::Constants::LOGON32_LOGON_BATCH, Process::Constants::LOGON32_LOGON_INTERACTIVE, Process::Constants::LOGON32_PROVIDER_DEFAULT, Process::Constants::UOI_NAME, Process::Constants::WAIT_ABANDONED, Process::Constants::WAIT_ABANDONED_0, Process::Constants::WAIT_FAILED, Process::Constants::WAIT_OBJECT_0, Process::Constants::WAIT_TIMEOUT, Process::Constants::WIN32_PROFILETYPE_LOCAL, Process::Constants::WIN32_PROFILETYPE_PT_MANDATORY, Process::Constants::WIN32_PROFILETYPE_PT_ROAMING, Process::Constants::WIN32_PROFILETYPE_PT_ROAMING_PREEXISTING, Process::Constants::WIN32_PROFILETYPE_PT_TEMPORARY
Instance Attribute Summary collapse
-
#command ⇒ Object
readonly
The command to be executed.
-
#cwd ⇒ Object
Working directory for the subprocess.
-
#domain ⇒ Object
Returns the value of attribute domain.
-
#elevated ⇒ Object
Runs windows process with elevated privileges.
-
#environment ⇒ Object
Environment variables that will be set for the subcommand.
-
#execution_time ⇒ Object
readonly
The amount of time the subcommand took to execute.
-
#group ⇒ Object
Group the command will run as.
-
#input ⇒ Object
ShellOut will push data from :input down the stdin of the subprocess.
-
#live_stderr ⇒ Object
When live_stderr is set, the stderr of the subprocess will be copied to it as the subprocess is running.
-
#live_stdout ⇒ Object
When live_stdout is set, the stdout of the subprocess will be copied to it as the subprocess is running.
-
#log_level ⇒ Object
The log level at which ShellOut should log.
-
#log_tag ⇒ Object
A string which will be prepended to the log message.
-
#logger ⇒ Object
If a logger is set, ShellOut will log a message before it executes the command.
-
#login ⇒ Object
Whether to simulate logon as the user.
-
#password ⇒ Object
Returns the value of attribute password.
-
#process_status_pipe ⇒ Object
readonly
Returns the value of attribute process_status_pipe.
-
#sensitive ⇒ Object
Returns the value of attribute sensitive.
-
#status ⇒ Object
readonly
A Process::Status (or ducktype) object collected when the subprocess is reaped.
-
#stderr ⇒ Object
readonly
Data written to stderr by the subprocess.
-
#stderr_pipe ⇒ Object
readonly
Returns the value of attribute stderr_pipe.
-
#stdin_pipe ⇒ Object
readonly
Returns the value of attribute stdin_pipe.
-
#stdout ⇒ Object
readonly
Data written to stdout by the subprocess.
-
#stdout_pipe ⇒ Object
readonly
Returns the value of attribute stdout_pipe.
- #timeout ⇒ Object
-
#umask ⇒ Object
The umask that will be set for the subcommand.
-
#user ⇒ Object
User the command will run as.
-
#valid_exit_codes ⇒ Object
An Array of acceptable exit codes.
-
#with_logon ⇒ Object
TODO remove.
Instance Method Summary collapse
-
#error! ⇒ Object
If #error? is true, calls
invalid!
, which raises an Exception. -
#error? ⇒ Boolean
Checks the
exitstatus
against the set ofvalid_exit_codes
. -
#exitstatus ⇒ Object
The exit status of the subprocess.
-
#format_for_exception ⇒ Object
Creates a String showing the output of the command, including a banner showing the exact command executed.
-
#gid ⇒ Object
The gid that the subprocess will switch to.
-
#initialize(*command_args) ⇒ ShellOut
constructor
Arguments: Takes a single command, or a list of command fragments.
- #inspect ⇒ Object
-
#invalid!(msg = nil) ⇒ Object
Raises a ShellCommandFailed exception, appending the command’s stdout, stderr, and exitstatus to the exception message.
-
#live_stream ⇒ Object
Returns the stream that both is being used by both live_stdout and live_stderr, or nil.
-
#live_stream=(stream) ⇒ Object
A shortcut for setting both live_stdout and live_stderr, so that both the stdout and stderr from the subprocess will be copied to the same stream as the subprocess is running.
-
#run_command ⇒ Object
Run the command, writing the command’s standard out and standard error to
stdout
andstderr
, and saving its exit status object tostatus
=== Returns returnsself
;stdout
,stderr
,status
, andexitstatus
will be populated with results of the command === Raises * Errno::EACCES when you are not privileged to execute the command * Errno::ENOENT when the command is not available on the system (or not in the current $PATH) * CommandTimeout when the command does not complete withintimeout
seconds (default: 600s). -
#uid ⇒ Object
The uid that the subprocess will switch to.
Methods included from Unix
#all_seconderies, #logon_environment, #process_environment, #sgids, #using_login?
Constructor Details
#initialize(*command_args) ⇒ ShellOut
Arguments:
Takes a single command, or a list of command fragments. These are used as arguments to Kernel.exec. See the Kernel.exec documentation for more explanation of how arguments are evaluated. The last argument can be an options Hash.
Options:
If the last argument is a Hash, it is removed from the list of args passed to exec and used as an options hash. The following options are available:
-
user
: the user the command should run as. if an integer is given, it is used as a uid. A string is treated as a username and resolved to a uid with Etc.getpwnam -
group
: the group the command should run as. works similarly touser
-
cwd
: the directory to chdir to before running the command -
umask
: a umask to set before running the command. If given as an Integer, be sure to use two leading zeros so it’s parsed as Octal. A string will be treated as an octal integer -
returns
: one or more Integer values to use as valid exit codes for the subprocess. This only has an effect if you callerror!
afterrun_command
. -
environment
: a Hash of environment variables to set before the command is run. -
timeout
: a Numeric value for the number of seconds to wait on the child process before raising an Exception. This is calculated as the total amount of time that ShellOut waited on the child process without receiving any output (i.e., IO.select returned nil). Default is 600 seconds. Note: the stdlib Timeout library is not used. -
input
: A String of data to be passed to the subcommand. This is written to the child process’ stdin stream before the process is launched. The child’s stdin stream will be a pipe, so the size of input data should not exceed the system’s default pipe capacity (4096 bytes is a safe value, though on newer Linux systems the capacity is 64k by default). -
live_stream
: An IO or Logger-like object (must respond to the append operator <<) that will receive data as ShellOut reads it from the child process. Generally this is used to copy data from the child to the parent’s stdout so that users may observe the progress of long-running commands. -
login
: Whether to simulate a login (set secondary groups, primary group, environment variables etc) as done by the OS in an actual login
Examples:
Invoke find(1) to search for .rb files:
find = Mixlib::ShellOut.new("find . -name '*.rb'")
find.run_command
# If all went well, the results are on +stdout+
puts find.stdout
# find(1) prints diagnostic info to STDERR:
puts "error messages" + find.stderr
# Raise an exception if it didn't exit with 0
find.error!
Run a command as the www
user with no extra ENV settings from /tmp
cmd = Mixlib::ShellOut.new("apachectl", "start", :user => 'www', :env => nil, :cwd => '/tmp')
cmd.run_command # etc.
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
# File 'lib/mixlib/shellout.rb', line 169 def initialize(*command_args) @stdout, @stderr, @process_status = "", "", "" @live_stdout = @live_stderr = nil @input = nil @log_level = :debug @log_tag = nil @environment = {} @cwd = nil @valid_exit_codes = [0] @terminate_reason = nil @timeout = nil @elevated = false @sensitive = false if command_args.last.is_a?(Hash) (command_args.pop) end @command = command_args.size == 1 ? command_args.first : command_args end |
Instance Attribute Details
#command ⇒ Object (readonly)
The command to be executed.
84 85 86 |
# File 'lib/mixlib/shellout.rb', line 84 def command @command end |
#cwd ⇒ Object
Working directory for the subprocess. Normally set via options to new
54 55 56 |
# File 'lib/mixlib/shellout.rb', line 54 def cwd @cwd end |
#domain ⇒ Object
Returns the value of attribute domain.
41 42 43 |
# File 'lib/mixlib/shellout.rb', line 41 def domain @domain end |
#elevated ⇒ Object
Runs windows process with elevated privileges. Required for Powershell commands which need elevated privileges
113 114 115 |
# File 'lib/mixlib/shellout.rb', line 113 def elevated @elevated end |
#environment ⇒ Object
Environment variables that will be set for the subcommand. Refer to the documentation of new to understand how ShellOut interprets this.
91 92 93 |
# File 'lib/mixlib/shellout.rb', line 91 def environment @environment end |
#execution_time ⇒ Object (readonly)
The amount of time the subcommand took to execute
98 99 100 |
# File 'lib/mixlib/shellout.rb', line 98 def execution_time @execution_time end |
#group ⇒ Object
Group the command will run as. Normally set via options passed to new
51 52 53 |
# File 'lib/mixlib/shellout.rb', line 51 def group @group end |
#input ⇒ Object
ShellOut will push data from :input down the stdin of the subprocess. Normally set via options passed to new. Default: nil
71 72 73 |
# File 'lib/mixlib/shellout.rb', line 71 def input @input end |
#live_stderr ⇒ Object
When live_stderr is set, the stderr of the subprocess will be copied to it as the subprocess is running.
66 67 68 |
# File 'lib/mixlib/shellout.rb', line 66 def live_stderr @live_stderr end |
#live_stdout ⇒ Object
When live_stdout is set, the stdout of the subprocess will be copied to it as the subprocess is running.
62 63 64 |
# File 'lib/mixlib/shellout.rb', line 62 def live_stdout @live_stdout end |
#log_level ⇒ Object
The log level at which ShellOut should log.
78 79 80 |
# File 'lib/mixlib/shellout.rb', line 78 def log_level @log_level end |
#log_tag ⇒ Object
A string which will be prepended to the log message.
81 82 83 |
# File 'lib/mixlib/shellout.rb', line 81 def log_tag @log_tag end |
#logger ⇒ Object
If a logger is set, ShellOut will log a message before it executes the command.
75 76 77 |
# File 'lib/mixlib/shellout.rb', line 75 def logger @logger end |
#login ⇒ Object
Whether to simulate logon as the user. Normally set via options passed to new Always enabled on windows
48 49 50 |
# File 'lib/mixlib/shellout.rb', line 48 def login @login end |
#password ⇒ Object
Returns the value of attribute password.
42 43 44 |
# File 'lib/mixlib/shellout.rb', line 42 def password @password end |
#process_status_pipe ⇒ Object (readonly)
Returns the value of attribute process_status_pipe.
110 111 112 |
# File 'lib/mixlib/shellout.rb', line 110 def process_status_pipe @process_status_pipe end |
#sensitive ⇒ Object
Returns the value of attribute sensitive.
115 116 117 |
# File 'lib/mixlib/shellout.rb', line 115 def sensitive @sensitive end |
#status ⇒ Object (readonly)
A Process::Status (or ducktype) object collected when the subprocess is reaped.
108 109 110 |
# File 'lib/mixlib/shellout.rb', line 108 def status @status end |
#stderr ⇒ Object (readonly)
Data written to stderr by the subprocess
104 105 106 |
# File 'lib/mixlib/shellout.rb', line 104 def stderr @stderr end |
#stderr_pipe ⇒ Object (readonly)
Returns the value of attribute stderr_pipe.
110 111 112 |
# File 'lib/mixlib/shellout.rb', line 110 def stderr_pipe @stderr_pipe end |
#stdin_pipe ⇒ Object (readonly)
Returns the value of attribute stdin_pipe.
110 111 112 |
# File 'lib/mixlib/shellout.rb', line 110 def stdin_pipe @stdin_pipe end |
#stdout ⇒ Object (readonly)
Data written to stdout by the subprocess
101 102 103 |
# File 'lib/mixlib/shellout.rb', line 101 def stdout @stdout end |
#stdout_pipe ⇒ Object (readonly)
Returns the value of attribute stdout_pipe.
110 111 112 |
# File 'lib/mixlib/shellout.rb', line 110 def stdout_pipe @stdout_pipe end |
#timeout ⇒ Object
227 228 229 |
# File 'lib/mixlib/shellout.rb', line 227 def timeout @timeout || DEFAULT_READ_TIMEOUT end |
#umask ⇒ Object
The umask that will be set for the subcommand.
87 88 89 |
# File 'lib/mixlib/shellout.rb', line 87 def umask @umask end |
#user ⇒ Object
User the command will run as. Normally set via options passed to new
40 41 42 |
# File 'lib/mixlib/shellout.rb', line 40 def user @user end |
#valid_exit_codes ⇒ Object
An Array of acceptable exit codes. #error? (and #error!) use this list to determine if the command was successful. Normally set via options to new
58 59 60 |
# File 'lib/mixlib/shellout.rb', line 58 def valid_exit_codes @valid_exit_codes end |
#with_logon ⇒ Object
TODO remove
44 45 46 |
# File 'lib/mixlib/shellout.rb', line 44 def with_logon @with_logon end |
Instance Method Details
#error! ⇒ Object
If #error? is true, calls invalid!
, which raises an Exception.
Returns
- nil:
-
always returns nil when it does not raise
Raises
- ::ShellCommandFailed:
-
via
invalid!
286 287 288 |
# File 'lib/mixlib/shellout.rb', line 286 def error! invalid!("Expected process to exit with #{valid_exit_codes.inspect}, but received '#{exitstatus}'") if error? end |
#error? ⇒ Boolean
Checks the exitstatus
against the set of valid_exit_codes
.
Returns
true
if exitstatus
is not in the list of valid_exit_codes
, false otherwise.
277 278 279 |
# File 'lib/mixlib/shellout.rb', line 277 def error? !Array(valid_exit_codes).include?(exitstatus) end |
#exitstatus ⇒ Object
The exit status of the subprocess. Will be nil if the command is still running or died without setting an exit status (e.g., terminated by ‘kill -9`).
250 251 252 |
# File 'lib/mixlib/shellout.rb', line 250 def exitstatus @status&.exitstatus end |
#format_for_exception ⇒ Object
Creates a String showing the output of the command, including a banner showing the exact command executed. Used by invalid!
to show command results when the command exited with an unexpected status.
234 235 236 237 238 239 240 241 242 243 244 245 |
# File 'lib/mixlib/shellout.rb', line 234 def format_for_exception return "Command execution failed. STDOUT/STDERR suppressed for sensitive resource" if sensitive msg = "" msg << "#{@terminate_reason}\n" if @terminate_reason msg << "---- Begin output of #{command} ----\n" msg << "STDOUT: #{stdout.strip}\n" msg << "STDERR: #{stderr.strip}\n" msg << "---- End output of #{command} ----\n" msg << "Ran #{command} returned #{status.exitstatus}" if status msg end |
#gid ⇒ Object
The gid that the subprocess will switch to. If the group attribute is given as a group name, it is converted to a gid by Etc.getgrnam TODO migrate to shellout/unix.rb
220 221 222 223 224 225 |
# File 'lib/mixlib/shellout.rb', line 220 def gid return group.is_a?(Integer) ? group : Etc.getgrnam(group.to_s).gid if group return Etc.getpwuid(uid).gid if using_login? nil end |
#inspect ⇒ Object
303 304 305 306 307 |
# File 'lib/mixlib/shellout.rb', line 303 def inspect "<#{self.class.name}##{object_id}: command: '#{@command}' process_status: #{@status.inspect} " + "stdout: '#{stdout.strip}' stderr: '#{stderr.strip}' child_pid: #{@child_pid.inspect} " + "environment: #{@environment.inspect} timeout: #{timeout} user: #{@user} group: #{@group} working_dir: #{@cwd} >" end |
#invalid!(msg = nil) ⇒ Object
Raises a ShellCommandFailed exception, appending the command’s stdout, stderr, and exitstatus to the exception message.
Arguments
msg
: A String to use as the basis of the exception message. The default explanation is very generic, providing a more informative message is highly encouraged.
Raises
ShellCommandFailed always
298 299 300 301 |
# File 'lib/mixlib/shellout.rb', line 298 def invalid!(msg = nil) msg ||= "Command produced unexpected results" raise ShellCommandFailed, msg + "\n" + format_for_exception end |
#live_stream ⇒ Object
Returns the stream that both is being used by both live_stdout and live_stderr, or nil
191 192 193 |
# File 'lib/mixlib/shellout.rb', line 191 def live_stream live_stdout == live_stderr ? live_stdout : nil end |
#live_stream=(stream) ⇒ Object
A shortcut for setting both live_stdout and live_stderr, so that both the stdout and stderr from the subprocess will be copied to the same stream as the subprocess is running.
198 199 200 |
# File 'lib/mixlib/shellout.rb', line 198 def live_stream=(stream) @live_stdout = @live_stderr = stream end |
#run_command ⇒ Object
Run the command, writing the command’s standard out and standard error to stdout
and stderr
, and saving its exit status object to status
Returns
returns self
; stdout
, stderr
, status
, and exitstatus
will be populated with results of the command
Raises
-
Errno::EACCES when you are not privileged to execute the command
-
Errno::ENOENT when the command is not available on the system (or not in the current $PATH)
-
CommandTimeout when the command does not complete within
timeout
seconds (default: 600s)
265 266 267 268 269 270 271 |
# File 'lib/mixlib/shellout.rb', line 265 def run_command if logger = (log_tag.nil? ? "" : "#{@log_tag} ") << "sh(#{@command})" logger.send(log_level, ) end super end |
#uid ⇒ Object
The uid that the subprocess will switch to. If the user attribute was given as a username, it is converted to a uid by Etc.getpwnam TODO migrate to shellout/unix.rb
211 212 213 214 215 |
# File 'lib/mixlib/shellout.rb', line 211 def uid return nil unless user user.is_a?(Integer) ? user : Etc.getpwnam(user.to_s).uid end |