Ruby - checking ping status featback with ssh, backtick via ssh? - ruby

In my project I want to write a script to check if every device in my network is online/reachable. I have a method called pingtest and it works for now..
def pingtest(destination)
system("ping -n 2 #{destination}")
if $? == 0 #checking status of the backtick
puts "\n Ping was successful!"
else
close("Device is unreachable. Check the config.txt for the correct IPs.")
#close() is just print & exit..
end
end
Now I wanted to ping via a ssh session with an other device in my network:
#--------------------------------
require 'net/ssh'
Net::SSH.start(#ip, #user, :password => #password)
#--------------------------------
#ssh = Ssh.new(#config)
#ssh.cmd("ping -c 3 #{#IP}")
The ping works fine but how can I use my backtrack idea now to determine if it was succesful or not?
I thought about using a sftp connection..
"ping -c 3 #{#IP} => tmpfile.txt" => download => check/compare => delete
(or something like that) to check if it was correct, but im not statusfied with that. Is there a possibility to check the success status like I did before?
I also tried something like this..
result = #ssh.cmd("ping -c 3 #{#IP}")
if result.success? == 0 # and so on..
I startet learning ruby some days ago, so im a newbie looking forward for your ideas to help me with this problem.

You can use Net::SSH to run the command remotely, similarly to what you've already got there.
The result returned from running the command will be whatever is written to both stdout and stderr.
You can use the contents of that returned value to check if it was successful or not.
Net::SSH.start(#ip, #user. password: #password) do |ssh|
response = ssh.exec! "ping -c 3 #{#other_ip}"
if response.include? 'Destination Host Unreachable'
close("Host unreachable. Result was: #{result}")
else
puts "\n Ping was successful"
end
end

Related

create a background ssh tunnel in ruby

My oracle db is only accessable via a jumpoff server and is load balanced. As a result I run the following background tunnel command in bash:
ssh ${jumpoffUser}#${jumpoffIp} -L1521:ont-db01-vip:1521 -L1522:ont-db02-vip:1521 -fN
Before I run my commands on the db using sqlplus like so:
sqlplus #{#sqlUsername}/#{#sqlPassword}#'#{#sqlUrl}' #scripts/populateASDB.sql
This all works fine.
Now I want to rubisize this procedure.
In looking up the documentation on ruby I could not find how to put the tunnel in the background (which would be my preference) but I found documentation on local port forwarding which I thought would emulate the above tunnel and subsequent sqlplus command.
Here is my code:
Net::SSH.start( #jumpoffIp, #jumpoffUser ) do |session|
session.forward.local( 1521, 'ont-db01-vip', 1521 )
session.forward.local( 1522, 'ont-db02-vip', 1521 )
puts "About to populateDB"
res = %x[sqlplus #{#sqlUsername}/#{#sqlPassword}#'#{#sqlUrl}' #scripts/populateASDB.sql > output.txt]
puts "populateDb output #{res}"
session.loop
end
When I run the above I get the line "About to populateDB" but it hangs on the actual running of the sqlplus command. Is there something wrong with my port forwarding code or how do I put the following:
ssh ${jumpoffUser}#${jumpoffIp} -L1521:ont-db01-vip:1521 -L1522:ont-db02-vip:1521 -fN
into ruby code?
A
Try to use this gem: https://github.com/net-ssh/net-ssh-gateway/
require 'net/ssh/gateway'
gateway = Net::SSH::Gateway.new(#jumpoffIp, #jumpoffUser)
gateway.open('ont-db01-vip', 1521, 1521)
gateway.open('ont-db02-vip', 1521, 1521)
res = %x[sqlplus #{#sqlUsername}/#{#sqlPassword}#'#{#sqlUrl}' #scripts/populateASDB.sql > output.txt]
puts "populateDb output #{res}"
gateway.shutdown!
You have two problems.
1) You need to use 'session.loop { true }' so that the session actually loops
2) You don't start looping the session until your sqlplus command is done, but the sqlplus needs the session looping (the forwarding to be up).
So I suggest creating a background thread using Thread.new and then killing the thread once sqlplus is done.
Thanks to David's answer, I came up with the following:
Net::SSH.start(ip_addr, 'user') do |session|
session.forward.local( 9090, 'localhost', 9090 )
# Need to run the event loop in the background for SSH callbacks to work
t = Thread.new {
session.loop { true }
}
commands.each do | command |
command.call(9090)
end
Thread.kill(t)
end

How to get list of file names from a private remote ip

I am having access to ServerA and don't have access to ServerB.I want to get the list of file names from ServerB via serverA.
I am logging into ServerA using the following command and doing some functions.
Net::SSH.start(url, user, forward_agent: true) do |ssh|
ssh.exec('scp -r source dest')
end
But i want to get the list the file names from ServerB via ServerA. How can i do it ?
Eg: Dir["/path/*.txt"] or ls *.txt
OS: Linux
Language: ruby
You can use ssh to execute a remote command:
ssh username#hostname ls -l /foo/bar
If the ls command is not enough you can always use find or any other command.
EDIT
Here you have a full working script
require 'net/ssh'
Net::SSH.start('localhost', 'user', :password => "password") do |ssh|
stdout = ''
ssh.exec!("ls -l /tmp") do |channel, stream, data|
stdout << data if stream == :stdout
end
puts stdout
end
working with ruby 2.1.2p95
Also make sure you have ruby compiled with OpenSSL:
ruby -ropenssl -e 'puts OpenSSL::OPENSSL_VERSION'
EDIT 2
What you need is a tunnel, for more information check the official documentation.
require 'net/ssh/gateway'
gateway = Net::SSH::Gateway.new('host', 'user')
gateway.ssh("host.private", "user") do |ssh|
puts ssh.exec!("hostname")
end
gateway.open("host.private", 80) do |port|
Net::HTTP.get_print("127.0.0.1", "/path", port)
end
gateway.shutdown!

Net::SSH does not seem to connect to remote host

Following the syntax from http://net-ssh.github.io/net-ssh/
Net::SSH.start('remotehost', 'ava') do |ssh|
puts `hostname`
end
It prints the name of current hostname rather than remote hostname. What is wrong?
You should use as below :
Net::SSH.start('remotehost', 'ava') do |ssh|
puts ssh.host
end
As ssh is an instance of Net::SSH::Connection::Session class And if you browse the documentation,you will get the method #host,which will give you the desired result.

Unable to connect remote host through net/ssh

This is pretty weird. I have my public key added at host machine. I can simply run
ssh -p <port> -l <username> hostt.com
which simply opens the remote shell. I can even run my capistrano scripts for the deployments on the same machine. But when i was trying connect with this following simple ruby script
require 'rubygems'
require 'net/ssh'
Net::SSH.start("hostt.com",
:port => <port>,
:username => <username>
) do |session|
puts session.pwd
end
it refuses immediately with the following exception:
`initialize': Connection refused - connect(2) (Errno::ECONNREFUSED)
Is there anything I'm missing here?
Appreciate your help.
Okay, now after a few days when I look back to the problem, I got a quick success with the following tweak:
Net::SSH.start("<host>", "<user>", :port => "<port>") { |ssh|
puts "logged in"
puts ssh.exec!("ls -l")
} rescue puts "failed to connect."
So the difference with the previous one is the username, which in this case is passed as the second argument rather than like an option key.
you probably need to provide the location of your SSH key, or a password to use with the username you provide in the SSH.start parameters. for the keys, you need to pass the map value as an array :keys => ["path_to_key"]. I'm not sure why the api is set up that way, but it is.

Ruby Telnet Lib - Weird Response

I am trying to execute cmds on a remote CPU through telnet. While some commands sent (through Ruby's stdlib for telnet) are successful, others are giving me a weird response:
*===============================================================
Welcome to Microsoft Telnet Server.
*===============================================================
C:\Documents and Settings\UserJW>ls
Desktop
Favorites
My Documents
Start Menu
Sti_Trace.log
C:\Documents and Settings\UserJW>cd\
More?
Why is telnet giving me this "More?" response, as if expecting something?
In the code, I am simply connecting to remote CPU, logging in, and sending commands:
#connection = Net::Telnet.new(...)
#connection.login( user, pwd )
#connection.cmd(...)
Any help would be appreciated.
Thanks,
J
**EDIT:
#connection = Net::Telnet.new(
"Host" => machine,
"Prompt" => /[A-Za-z]:\\.*>\z/n,
"Timeout" => 3,
"Output_log" => output )
#connection.login( user, pwd )
#connection.cmd( 'ls' )
#connection.cmd( 'ls' )
output...
C:\Documents and Settings\UserJW>
ls
Desktop
Favorites
My Documents
Start Menu
Sti_Trace.log
C:\Documents and Settings\UserJW>
ls
More?
I can't even send more than one command, apparently. Is my Prompt regex wrong? I'm trying to allow..
C:[anything...]>
I meet a same problem with you ( ruby telnet to windows 2008 ,execute command error ).I solved it. the reason is ruby net/telnet library use error newline seperator. Must be EOL(CR+LF) but CR+NULL . But I don't know who make the bug,windows or ruby? I write a monkey patch as below:
class Net::Telnet
def print(string)
string = string.gsub(/#{IAC}/no, IAC + IAC) if #options["Telnetmode"]
if #options["Binmode"]
self.write(string)
else
if #telnet_option["BINARY"] and #telnet_option["SGA"]
self.write(string.gsub(/\n/n, CR))
elsif #telnet_option["SGA"]
self.write(string.gsub(/\n/n, EOL)) ### fix here. reaplce CR+NULL bY EOL
else
self.write(string.gsub(/\n/n, EOL))
end
end
end
end

Resources