| 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.exitcode
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
| command | [R] | |
| cwd | [R] | |
| environment | [R] | |
| status | [R] | |
| stderr | [R] | |
| stdin | [R] | |
| stdout | [R] |
# 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 = "/tmp"
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
Actually does the systemu call passing in the correct environment, stdout and stderr
# 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: # Running waitpid on the cid here will start a thread
71: # with the waitpid in it, this way even if the thread
72: # that started this process gets killed due to agent
73: # timeout or such there will still be a waitpid waiting
74: # for the child to exit and not leave zombies.
75: @status = systemu(@command, opts) do |cid|
76: begin
77: sleep 1
78: Process::waitpid(cid)
79: rescue SystemExit
80: rescue Errno::ECHILD
81: rescue Exception => e
82: Log.info("Unexpected exception received while waiting for child process: #{e.class}: #{e}")
83: end
84: end
85: end