Class MCollective::Shell
In: lib/mcollective/shell.rb
Parent: Object

Wrapper around systemu that handles executing of system commands in a way that makes stdout, stderr and status available. Supports timeouts and sets a default sane environment.

  s = Shell.new("date", opts)
  s.runcommand
  puts s.stdout
  puts s.stderr
  puts s.status.exitstatus

Options hash can have:

  cwd         - the working directory the command will be run from
  stdin       - a string that will be sent to stdin of the program
  stdout      - a variable that will receive stdout, must support <<
  stderr      - a variable that will receive stdin, must support <<
  environment - the shell environment, defaults to include LC_ALL=C
                set to nil to clear the environment even of LC_ALL

Methods

new   runcommand  

Attributes

command  [R] 
cwd  [R] 
environment  [R] 
status  [R] 
stderr  [R] 
stdin  [R] 
stdout  [R] 

Public Class methods

[Source]

    # File lib/mcollective/shell.rb, line 24
24:     def initialize(command, options={})
25:       @environment = {"LC_ALL" => "C"}
26:       @command = command
27:       @status = nil
28:       @stdout = ""
29:       @stderr = ""
30:       @stdin = nil
31:       @cwd = Dir.tmpdir
32: 
33:       options.each do |opt, val|
34:         case opt.to_s
35:           when "stdout"
36:             raise "stdout should support <<" unless val.respond_to?("<<")
37:             @stdout = val
38: 
39:           when "stderr"
40:             raise "stderr should support <<" unless val.respond_to?("<<")
41:             @stderr = val
42: 
43:           when "stdin"
44:             raise "stdin should be a String" unless val.is_a?(String)
45:             @stdin = val
46: 
47:           when "cwd"
48:             raise "Directory #{val} does not exist" unless File.directory?(val)
49:             @cwd = val
50: 
51:           when "environment"
52:             if val.nil?
53:               @environment = {}
54:             else
55:               @environment.merge!(val.dup)
56:             end
57:         end
58:       end
59:     end

Public Instance methods

Actually does the systemu call passing in the correct environment, stdout and stderr

[Source]

    # File lib/mcollective/shell.rb, line 62
62:     def runcommand
63:       opts = {"env"    => @environment,
64:               "stdout" => @stdout,
65:               "stderr" => @stderr,
66:               "cwd"    => @cwd}
67: 
68:       opts["stdin"] = @stdin if @stdin
69: 
70:       # Check if the parent thread is alive. If it should die,
71:       # and the process spawned by systemu is still alive,
72:       # fire off a blocking waitpid and wait for the process to
73:       # finish so that we can avoid zombies.
74:       thread = Thread.current
75:       @status = systemu(@command, opts) do |cid|
76:         begin
77:           while(thread.alive?)
78:             sleep 0.1
79:           end
80: 
81:           Process.waitpid(cid) if Process.getpgid(cid)
82:         rescue SystemExit
83:         rescue Errno::ESRCH
84:         rescue Errno::ECHILD
85:         rescue Exception => e
86:           Log.info("Unexpected exception received while waiting for child process: #{e.class}: #{e}")
87:         end
88:       end
89:     end

[Validate]