Class: Chef::ShellOut
- Defined in:
- lib/chef/shell_out.rb,
lib/chef/shell_out/unix.rb,
lib/chef/shell_out/windows.rb
Overview
Chef::ShellOut
Provides a simplified interface to shelling out yet still collecting both standard out and standard error and providing full control over environment, working directory, uid, gid, etc.
No means for passing input to the subprocess is provided, nor is there any way to inspect the output of the command as it is being read. If you need to do that, you have to use popen4 (in Chef::Mixin::Command)
Platform Support
Chef::ShellOut uses Kernel.fork() and is therefore unsuitable for Windows or jruby.
Defined Under Namespace
Constant Summary collapse
- READ_WAIT_TIME =
0.01
- READ_SIZE =
4096
- DEFAULT_READ_TIMEOUT =
600
- DEFAULT_ENVIRONMENT =
{'LC_ALL' => 'C'}
Instance Attribute Summary collapse
-
#command ⇒ Object
readonly
Returns the value of attribute command.
-
#command_log_level ⇒ Object
Returns the value of attribute command_log_level.
-
#command_log_prepend ⇒ Object
Returns the value of attribute command_log_prepend.
-
#cwd ⇒ Object
Returns the value of attribute cwd.
-
#environment ⇒ Object
readonly
Returns the value of attribute environment.
-
#execution_time ⇒ Object
readonly
Returns the value of attribute execution_time.
-
#group ⇒ Object
Returns the value of attribute group.
-
#live_stream ⇒ Object
Returns the value of attribute live_stream.
-
#process_status_pipe ⇒ Object
readonly
Returns the value of attribute process_status_pipe.
-
#status ⇒ Object
readonly
Returns the value of attribute status.
-
#stderr ⇒ Object
readonly
Returns the value of attribute stderr.
-
#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
Returns the value of attribute stdout.
-
#stdout_pipe ⇒ Object
readonly
Returns the value of attribute stdout_pipe.
- #timeout ⇒ Object
-
#umask ⇒ Object
Returns the value of attribute umask.
-
#user ⇒ Object
Returns the value of attribute user.
-
#valid_exit_codes ⇒ Object
Returns the value of attribute valid_exit_codes.
Instance Method Summary collapse
-
#error! ⇒ Object
Checks the
exitstatus
against the set ofvalid_exit_codes
. - #exitstatus ⇒ Object
-
#format_for_exception ⇒ Object
Creates a String showing the output of the command, including a banner showing the exact command executed.
- #gid ⇒ Object
-
#initialize(*command_args) ⇒ ShellOut
constructor
Arguments: Takes a single command, or a list of command fragments.
- #inspect ⇒ Object
-
#invalid!(msg = nil) ⇒ Object
Raises a Chef::Exceptions::ShellCommandFailed exception, appending the command’s stdout, stderr, and exitstatus to the exception message.
-
#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) * Chef::Exceptions::CommandTimeout when the command does not complete withintimeout
seconds (default: 60s). - #uid ⇒ Object
Methods included from Windows
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 commmand 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. By default, the environment will always be set to ‘LC_ALL’ => ‘C’ to prevent issues with multibyte characters in Ruby 1.8. To avoid this, use :environment => nil for no extra environment settings, or :environment => … to set other environment settings without changing the locale. -
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 60 seconds. Note: the stdlib Timeout library is not used.
Examples:
Invoke find(1) to search for .rb files:
find = Chef::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 = Chef::ShellOut.new("apachectl", "start", :user => 'www', :env => nil, :cwd => '/tmp')
cmd.run_command # etc.
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/chef/shell_out.rb', line 113 def initialize(*command_args) @stdout, @stderr = '', '' @live_stream = nil @command_log_level = :debug @command_log_prepend = nil @environment = DEFAULT_ENVIRONMENT @cwd = nil @valid_exit_codes = [0] 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)
Returns the value of attribute command.
62 63 64 |
# File 'lib/chef/shell_out.rb', line 62 def command @command end |
#command_log_level ⇒ Object
Returns the value of attribute command_log_level.
59 60 61 |
# File 'lib/chef/shell_out.rb', line 59 def command_log_level @command_log_level end |
#command_log_prepend ⇒ Object
Returns the value of attribute command_log_prepend.
60 61 62 |
# File 'lib/chef/shell_out.rb', line 60 def command_log_prepend @command_log_prepend end |
#cwd ⇒ Object
Returns the value of attribute cwd.
56 57 58 |
# File 'lib/chef/shell_out.rb', line 56 def cwd @cwd end |
#environment ⇒ Object (readonly)
Returns the value of attribute environment.
62 63 64 |
# File 'lib/chef/shell_out.rb', line 62 def environment @environment end |
#execution_time ⇒ Object (readonly)
Returns the value of attribute execution_time.
64 65 66 |
# File 'lib/chef/shell_out.rb', line 64 def execution_time @execution_time end |
#group ⇒ Object
Returns the value of attribute group.
55 56 57 |
# File 'lib/chef/shell_out.rb', line 55 def group @group end |
#live_stream ⇒ Object
Returns the value of attribute live_stream.
58 59 60 |
# File 'lib/chef/shell_out.rb', line 58 def live_stream @live_stream end |
#process_status_pipe ⇒ Object (readonly)
Returns the value of attribute process_status_pipe.
68 69 70 |
# File 'lib/chef/shell_out.rb', line 68 def process_status_pipe @process_status_pipe end |
#status ⇒ Object (readonly)
Returns the value of attribute status.
66 67 68 |
# File 'lib/chef/shell_out.rb', line 66 def status @status end |
#stderr ⇒ Object (readonly)
Returns the value of attribute stderr.
66 67 68 |
# File 'lib/chef/shell_out.rb', line 66 def stderr @stderr end |
#stderr_pipe ⇒ Object (readonly)
Returns the value of attribute stderr_pipe.
68 69 70 |
# File 'lib/chef/shell_out.rb', line 68 def stderr_pipe @stderr_pipe end |
#stdin_pipe ⇒ Object (readonly)
Returns the value of attribute stdin_pipe.
68 69 70 |
# File 'lib/chef/shell_out.rb', line 68 def stdin_pipe @stdin_pipe end |
#stdout ⇒ Object (readonly)
Returns the value of attribute stdout.
66 67 68 |
# File 'lib/chef/shell_out.rb', line 66 def stdout @stdout end |
#stdout_pipe ⇒ Object (readonly)
Returns the value of attribute stdout_pipe.
68 69 70 |
# File 'lib/chef/shell_out.rb', line 68 def stdout_pipe @stdout_pipe end |
#timeout ⇒ Object
143 144 145 |
# File 'lib/chef/shell_out.rb', line 143 def timeout @timeout || DEFAULT_READ_TIMEOUT end |
#umask ⇒ Object
Returns the value of attribute umask.
62 63 64 |
# File 'lib/chef/shell_out.rb', line 62 def umask @umask end |
#user ⇒ Object
Returns the value of attribute user.
54 55 56 |
# File 'lib/chef/shell_out.rb', line 54 def user @user end |
#valid_exit_codes ⇒ Object
Returns the value of attribute valid_exit_codes.
57 58 59 |
# File 'lib/chef/shell_out.rb', line 57 def valid_exit_codes @valid_exit_codes end |
Instance Method Details
#error! ⇒ Object
Checks the exitstatus
against the set of valid_exit_codes
. If exitstatus
is not in the list of valid_exit_codes
, calls invalid!
, which raises an Exception.
Returns
- nil:
-
always returns nil when it does not raise
Raises
- Chef::Exceptions::ShellCommandFailed:
-
via
invalid!
191 192 193 194 195 |
# File 'lib/chef/shell_out.rb', line 191 def error! unless Array(valid_exit_codes).include?(exitstatus) invalid!("Expected process to exit with #{valid_exit_codes.inspect}, but received '#{exitstatus}'") end end |
#exitstatus ⇒ Object
160 161 162 |
# File 'lib/chef/shell_out.rb', line 160 def exitstatus @status && @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.
150 151 152 153 154 155 156 157 158 |
# File 'lib/chef/shell_out.rb', line 150 def format_for_exception msg = "" 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
138 139 140 141 |
# File 'lib/chef/shell_out.rb', line 138 def gid return nil unless group group.kind_of?(Integer) ? group : Etc.getgrnam(group.to_s).gid end |
#inspect ⇒ Object
210 211 212 213 214 |
# File 'lib/chef/shell_out.rb', line 210 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 Chef::Exceptions::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
Chef::Exceptions::ShellCommandFailed always
205 206 207 208 |
# File 'lib/chef/shell_out.rb', line 205 def invalid!(msg=nil) msg ||= "Command produced unexpected results" raise Chef::Exceptions::ShellCommandFailed, msg + "\n" + format_for_exception 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)
-
Chef::Exceptions::CommandTimeout when the command does not complete within
timeout
seconds (default: 60s)
175 176 177 178 179 180 181 182 |
# File 'lib/chef/shell_out.rb', line 175 def run_command if command_log_prepend Chef::Log.send(command_log_level, "#{command_log_prepend} sh(#{@command})") else Chef::Log.send(command_log_level, "sh(#{@command})") end super end |
#uid ⇒ Object
133 134 135 136 |
# File 'lib/chef/shell_out.rb', line 133 def uid return nil unless user user.kind_of?(Integer) ? user : Etc.getpwnam(user.to_s).uid end |