Class: MCollective::Shell

Inherits:
Object
  • Object
show all
Defined in:
lib/mcollective/shell.rb

Overview

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

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(command, options = {}) ⇒ Shell

Returns a new instance of Shell.



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
# File 'lib/mcollective/shell.rb', line 24

def initialize(command, options={})
  @environment = {"LC_ALL" => "C"}
  @command = command
  @status = nil
  @stdout = ""
  @stderr = ""
  @stdin = nil
  @cwd = Dir.tmpdir

  options.each do |opt, val|
    case opt.to_s
      when "stdout"
        raise "stdout should support <<" unless val.respond_to?("<<")
        @stdout = val

      when "stderr"
        raise "stderr should support <<" unless val.respond_to?("<<")
        @stderr = val

      when "stdin"
        raise "stdin should be a String" unless val.is_a?(String)
        @stdin = val

      when "cwd"
        raise "Directory #{val} does not exist" unless File.directory?(val)
        @cwd = val

      when "environment"
        if val.nil?
          @environment = {}
        else
          @environment.merge!(val.dup)
        end
    end
  end
end

Instance Attribute Details

#commandObject (readonly)

Returns the value of attribute command.



22
23
24
# File 'lib/mcollective/shell.rb', line 22

def command
  @command
end

#cwdObject (readonly)

Returns the value of attribute cwd.



22
23
24
# File 'lib/mcollective/shell.rb', line 22

def cwd
  @cwd
end

#environmentObject (readonly)

Returns the value of attribute environment.



22
23
24
# File 'lib/mcollective/shell.rb', line 22

def environment
  @environment
end

#statusObject (readonly)

Returns the value of attribute status.



22
23
24
# File 'lib/mcollective/shell.rb', line 22

def status
  @status
end

#stderrObject (readonly)

Returns the value of attribute stderr.



22
23
24
# File 'lib/mcollective/shell.rb', line 22

def stderr
  @stderr
end

#stdinObject (readonly)

Returns the value of attribute stdin.



22
23
24
# File 'lib/mcollective/shell.rb', line 22

def stdin
  @stdin
end

#stdoutObject (readonly)

Returns the value of attribute stdout.



22
23
24
# File 'lib/mcollective/shell.rb', line 22

def stdout
  @stdout
end

Instance Method Details

#runcommandObject

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



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/mcollective/shell.rb', line 62

def runcommand
  opts = {"env"    => @environment,
          "stdout" => @stdout,
          "stderr" => @stderr,
          "cwd"    => @cwd}

  opts["stdin"] = @stdin if @stdin

  # Running waitpid on the cid here will start a thread
  # with the waitpid in it, this way even if the thread
  # that started this process gets killed due to agent
  # timeout or such there will still be a waitpid waiting
  # for the child to exit and not leave zombies.
  @status = systemu(@command, opts) do |cid|
    begin
      sleep 1
      Process::waitpid(cid)
    rescue SystemExit
    rescue Errno::ECHILD
    rescue Exception => e
      Log.info("Unexpected exception received while waiting for child process: #{e.class}: #{e}")
    end
  end
end