Parent

Methods

Class Index [+]

Quicksearch

MCollective::Shell

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
  timeout     - a timeout in seconds after which the subprocess is killed,
                the special value :on_thread_exit kills the subprocess
                when the invoking thread (typically the agent) has ended

Attributes

environment[R]

(Not documented)

command[R]

(Not documented)

status[R]

(Not documented)

stdout[R]

(Not documented)

stderr[R]

(Not documented)

stdin[R]

(Not documented)

cwd[R]

(Not documented)

timeout[R]

(Not documented)

Public Class Methods

new(command, options={}) click to toggle source

(Not documented)

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

Public Instance Methods

runcommand() click to toggle source

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

     # File lib/mcollective/shell.rb, line 69
 69:     def runcommand
 70:       opts = {"env"    => @environment,
 71:               "stdout" => @stdout,
 72:               "stderr" => @stderr,
 73:               "cwd"    => @cwd}
 74: 
 75:       opts["stdin"] = @stdin if @stdin
 76: 
 77: 
 78:       thread = Thread.current
 79:       # Start a double fork and exec with systemu which implies a guard thread.
 80:       # If a valid timeout is configured the guard thread will terminate the
 81:       # executing process and reap the pid.
 82:       # If no timeout is specified the process will run to completion with the
 83:       # guard thread reaping the pid on completion.
 84:       @status = systemu(@command, opts) do |cid|
 85:         begin
 86:           if timeout.is_a?(Fixnum)
 87:             # wait for the specified timeout
 88:             sleep timeout
 89:           else
 90:             # sleep while the agent thread is still alive
 91:             while(thread.alive?)
 92:               sleep 0.1
 93:             end
 94:           end
 95: 
 96:           # if the process is still running
 97:           if (Process.kill(0, cid))
 98:             # and a timeout was specified
 99:             if timeout
100:               if Util.windows?
101:                 Process.kill('KILL', cid)
102:               else
103:                 # Kill the process
104:                 Process.kill('TERM', cid)
105:                 sleep 2
106:                 Process.kill('KILL', cid) if (Process.kill(0, cid))
107:               end
108:             end
109:             # only wait if the parent thread is dead
110:             Process.waitpid(cid) unless thread.alive?
111:           end
112:         rescue SystemExit
113:         rescue Errno::ESRCH
114:         rescue Errno::ECHILD
115:           Log.warn("Could not reap process '#{cid}'.")
116:         rescue Exception => e
117:           Log.info("Unexpected exception received while waiting for child process: #{e.class}: #{e}")
118:         end
119:       end
120:       @status.thread.kill
121:       @status
122:     end

Disabled; run with --debug to generate this.

[Validate]

Generated with the Darkfish Rdoc Generator 1.1.6.