Use ruby ββNet :: SSH to read remote file via sudo
I need to read the contents of a remote file to which I have permissions (sudo) using cat, less or tail.
I'm going to do this in Ruby, so I guess I should be using Net :: SSH to do this.
The file is a log file, so it can be quite large.
This is the code I'm trying now:
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
When I run I get the following output:
in process in process in process data work in process in process in process in third "\ r \ n" remote end completes sending data shell finished
Currently there are several thousand lines of data in the log because I can read it from a real server with putty.
How do I get this from channel.on_data?
thank
source to share
I think you need to add \n
to the password you are sending. This works for me. Note. At the place where I commented out the else clause, you can also get information from there, but it works the way you are, but with \n
in the password.
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
source to share
You are replacing the new callback on_data
when you execute the callback on_data
. I didn't do the internal processing of Net :: SSH, but it could cause surprising behavior.
Try changing the code in your two on_data callbacks to be the same and see if that helps.
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
As a side note, since you need sudo to read the logs, someone thinks they and this server deserve protection. It looks like you are embedding passwords that grant privileged access to the server in this ruby ββprogram. This means that anyone who can read the program gets the same privileged access. What will you do to restrict password access in this program?
source to share
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
source to share