Module: Chef::ShellOut::Unix

Included in:
Chef::ShellOut
Defined in:
lib/chef/shell_out/unix.rb

Instance Method Summary collapse

Instance Method Details

#run_commandObject

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)



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/chef/shell_out/unix.rb', line 16

def run_command
  @child_pid = fork_subprocess

  configure_parent_process_file_descriptors
  propagate_pre_exec_failure

  @result = nil
  @execution_time = 0

  # Ruby 1.8.7 and 1.8.6 from mid 2009 try to allocate objects during GC
  # when calling IO.select and IO#read. Some OS Vendors are not interested
  # in updating their ruby packages (Apple, *cough*) and we *have to*
  # make it work. So I give you this epic hack:
  GC.disable
  until @status
    ready = IO.select(open_pipes, nil, nil, READ_WAIT_TIME)
    unless ready
      @execution_time += READ_WAIT_TIME
      if @execution_time >= timeout && !@result
        raise Chef::Exceptions::CommandTimeout, "command timed out:\n#{format_for_exception}"
      end
    end

    if ready && ready.first.include?(child_stdout)
      read_stdout_to_buffer
    end
    if ready && ready.first.include?(child_stderr)
      read_stderr_to_buffer
    end

    unless @status
      # make one more pass to get the last of the output after the
      # child process dies
      if results = Process.waitpid2(@child_pid, Process::WNOHANG)
        @status = results.last
        redo
      end
    end
  end
  self
rescue Exception
  # do our best to kill zombies
  Process.waitpid2(@child_pid, Process::WNOHANG) rescue nil
  raise
ensure
  # no matter what happens, turn the GC back on, and hope whatever busted
  # version of ruby we're on doesn't allocate some objects during the next
  # GC run.
  GC.enable
  close_all_pipes
end