使用Ruby Net::SSH通过sudo读取远程文件

3
我需要读取一个我有权限(sudo)使用cat、less或tail命令读取的远程文件内容。我将使用Ruby编写程序,因此我应该使用Net::SSH来进行操作。这个文件是一个日志文件,所以它可能非常大。以下是我现在正在尝试的代码:
require 'rubygems'
require 'net/ssh'

cmd = "sudo cat /var/logs/httpd/ACCESS_log.2012.03.23"

Net::SSH.start( "SERVER" , "USER", :password => "PASSWORD") do |ssh|
  ssh.open_channel do |channel|
    channel.request_pty
     channel.exec(cmd);

     channel.on_close do
       puts "shell terminated"
     end
    channel.on_eof do |ch|
      puts "remote end is done sending data"
    end
    channel.on_extended_data do |ch, type, data|
      puts "got stderr: #{data.inspect}"
    end
    channel.on_data do |channel, data|
      if data =~ /^\[sudo\] password for USER:/
        puts "data works"
        channel.send_data 'PASSWORD'
      end
     channel.on_data do |ch,data|
        puts "in third"
        puts data.inspect
     end
    end
   channel.on_process do |ch|
     puts "in process"
   end
  ssh.loop
  end
end

当我运行它时,我会得到以下输出:
正在处理 正在处理 正在处理 数据有效 正在处理 正在处理 正在处理 第三个有效 "\r\n" 远程端已完成发送数据 shell 已终止
实际上,日志中目前有几千行数据,因为我可以使用putty从实际服务器读取它。
如何从 channel.on_data 中获取它?
谢谢。

我在自己的日志文件上运行了它,它可以正常工作...等等,那是以root用户身份运行的,卡在了实际用户上。 - DGM
在预览时,当我第一次发送密码之间,它会花费很长时间。 - user254694
您已经验证了该特定日志文件是否有内容?如果您直接使用ssh ssh USER@SERVER sudo cat /var/logs/httpd/ACCESS_log.2012.03.23,您会看到什么? - dbenhur
3个回答

2

我认为你需要在发送的密码中添加\n。这对我有用。请注意,我注释掉else子句的位置,你也可以从那里获取信息,但是只要在密码中添加\n,它就能正常工作。

require 'rubygems'
require 'net/ssh'
cmd = "sudo cat /var/log/mail.log" HOSTNAME = "myhost.example.com" USERNAME = "me" PASSWORD = "12345"
Net::SSH.start( HOSTNAME , USERNAME, :password => PASSWORD) do |ssh| ssh.open_channel do |channel| channel.request_pty channel.exec(cmd);
channel.on_close do puts "shell terminated" end channel.on_eof do |ch| puts "remote end is done sending data" end channel.on_extended_data do |ch, type, data| puts "got stderr: #{data.inspect}" end channel.on_data do |channel, data| if data =~ /^\[sudo\] password for #{USERNAME}:/ puts "data works" channel.send_data "#{PASSWORD}\n" else #puts "OUTPUT NOT MATCHED: #{data}" end channel.on_data do |ch,data| puts "in third" puts data.inspect end end channel.on_process do |ch| puts "in process" end ssh.loop end end

我同意@dbenhur的观点,多次调用on_data肯定会令人困惑,因为它会替换之前的代码块...最好将所有处理都放在一个数据块中。 - DGM
看起来 @DGM 解决了这个问题,密码需要一个 "\n"。在我的测试中起作用。 - dbenhur

0

在执行一个on_data回调时,您正在替换一个新的on_data回调。我没有深入研究Net::SSH的内部,但这可能会产生令人惊讶的行为。

尝试将您两个on_data回调中的代码更改为一个,并查看是否有所帮助。

channel.on_data do |channel, data|
  if data =~ /^\[sudo\] password for USER:/
    puts "data works"
    channel.send_data 'PASSWORD'
  else
    puts "in third"
    puts data.inspect
  if
end

作为一个附注,由于您需要sudo来读取日志,某些人认为他们和那个服务器值得保护。看起来您正在嵌入密码,这些密码可以在此Ruby程序中获得特权访问权限。这意味着任何能够阅读该程序的人都将获得相同的特权访问权限。您将采取什么措施来限制对此程序中密码的访问?

我现在正在嵌入密码,只是为了看看能否让某些东西正常工作。这种解决方案的结果是:处理中、处理中、处理中、数据有效、处理中、处理中、处理中,然后什么也没有发生。这是其他代码示例中的一件事情,促使我采用这种方式。它似乎应该是递归的。 - user254694

-1
require 'net/ssh'

Net::SSH.start('host', 'user', :password => "password") do |ssh|
  # capture all stderr and stdout output from a remote process
  output = ssh.exec!("hostname")
  puts output

  # capture only stdout matching a particular pattern
  stdout = ""
  ssh.exec!("ls -l /home/jamis") do |channel, stream, data|
    stdout << data if stream == :stdout
  end
  puts stdout

  # run multiple processes in parallel to completion
  ssh.exec "sed ..."
  ssh.exec "awk ..."
  ssh.exec "rm -rf ..."
  ssh.loop

  # open a new channel and configure a minimal set of callbacks, then run
  # the event loop until the channel finishes (closes)
  channel = ssh.open_channel do |ch|
    ch.exec "/usr/local/bin/ruby /path/to/file.rb" do |ch, success|
      raise "could not execute command" unless success

      # "on_data" is called when the process writes something to stdout
      ch.on_data do |c, data|
        $stdout.print data
      end

      # "on_extended_data" is called when the process writes something to stderr
      ch.on_extended_data do |c, type, data|
        $stderr.print data
      end

      ch.on_close { puts "done!" }
    end
  end

  channel.wait

  # forward connections on local port 1234 to port 80 of www.capify.org
  ssh.forward.local(1234, "www.capify.org", 80)
  ssh.loop { true }
end

最新文档 17.11.25


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接