# File lib/openshift-origin-node/utils/shell_exec.rb, line 49
  def self.shellCmd(cmd, pwd = ".", ignore_err = true, expected_rc = 0, timeout = 3600)
    out = err = rc = nil         
    begin
      # Using Open4 spawn with cwd isn't thread safe
      m_cmd = "cd #{pwd} && ( #{cmd} )"
      pid, stdin, stdout, stderr = Open4.popen4ext(true, m_cmd)
      begin
        stdin.close
        Timeout::timeout(timeout) do
          out = stdout.read
          err = stderr.read
        end
      rescue Timeout::Error
        pstree = Hash.new{|a,b| a[b]=[b]}
        pppids = Hash[*`ps -e -opid,ppid --no-headers`.map{|p| p.to_i}]
        pppids.each do |l_pid, l_ppid|
          pstree[l_ppid] << pstree[l_pid]
        end
        Process.kill("KILL", *(pstree[pid].flatten))
        raise OpenShift::Utils::ShellExecutionException.new("command timed out")
      ensure
        stdout.close
        stderr.close  
        rc = Process::waitpid2(pid)[1].exitstatus
      end
    rescue Exception => e
      raise OpenShift::Utils::ShellExecutionException.new(e.message
                                                    ) unless ignore_err
    end

    if !ignore_err and rc != expected_rc 
      raise OpenShift::Utils::ShellExecutionException.new(
        "Shell command '#{cmd}' returned an error. rc=#{rc}", rc)
    end
    return [out, err, rc]
  end