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.
Related
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
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
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!
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.
an important part of my project is to log in into remote server with ssh and do something with files on it:
Net::SSH.start(#host, #username, :password => #password) do |ssh|
ssh.exec!(rename_files_on_remote_server)
end
How to test it?
I think I can have local ssh server on and check file names on it (maybe it could be in my test/spec directory).
Or maybe someone could point me better solution?
I think it's enough to test that you're sending the correct commands to the ssh server. You're application presumably doesn't implement the server - so you have to trust that the server is correctly working and tested.
If you do implement the server then you'd need to test that, but as far as the SSH stuff goes, i'd do some mocking like this (RSpec 2 syntax):
describe "SSH Access" do
let (:ssh_connection) { mock("SSH Connection") }
before (:each) do
Net::SSH.stub(:start) { ssh_connection }
end
it "should send rename commands to the connection" do
ssh_connection.should_receive(:exec!).ordered.with("expected command")
ssh_connection.should_receive(:exec!).ordered.with("next expected command")
SSHAccessClass.rename_files!
end
end
Your suggested solution is similar to how I've done it before:
Log into the local machine. For convenience you could use 'localhost' or '127.0.0.1', but for a better simulation of network activity you might want to use the full hostname. On Mac OS and Linux you can grab the host easily by using:
`hostname`
or
require 'socket'
hostname = Socket.gethostname
which should be universal.
From there create or touch a file on the local machine after logging in, so you can test for the change with your test code.