ruby net-ssh calling bash script with interactive prompts - ruby

I have a problem that I hope you can help me with
I’m trying to use ruby to ssh onto a machine and run a bash script, this part is fairly easy but the bash script requires me to entry a username and password interactively and this is where I’m stuck
So if I run the script manually I see:-
./run_file.sh
Enter username:
Enter password:
So at the enter Username prompt I have to enter the username etc
I’ve got a simple method I use to make the connection and my idea was to pass in an array made up of
[‘command to run’, ‘username’, ‘password’]
but I don’t know how to extend the Net::SSH call to respond to the prompts
# ssh conectivity method
def command_ssh(host, cmd)
require 'net/ssh'
user = LocalConfig::SSH_DETAILS[:user]
pass = LocalConfig::SSH_DETAILS[:pass]
Net::SSH.start(host, user, :password => pass, :paranoid => false, :auth_methods => ['password'], :timeout => 10 )do |ssh |
output = (ssh.exec!(cmd[0]))
return output
end
end
anyone got any ideas

managed to fix this by using the channel function, here's the method I use now
def connect(host,command)
require 'rubygems'
require 'net/ssh'
user = LocalConfig::SSH_DETAILS[:user]
pass = LocalConfig::SSH_DETAILS[:pass
o = ""
Net::SSH.start(host, user, :password => pass, :paranoid => false, :auth_methods => ['password'], :timeout => 30 )do |ssh |
channel = ssh.open_channel do |ch|
ch.exec(command) do |ch2, success|
ch2.send_data "myUserName\n"
ch2.send_data "mPassWord\n"
ch.on_data do |ch2, data|
o += data
end
end
end
channel.wait
return o.to_s
end
end

Related

How do I switch user in Linux using ruby and net/ssh?

Using below function I can connect to my Linux machine.
But few commands need root permission to execute and direct root login is disabled. Also, the user cannot sudo.
require 'net/ssh'
def sshutm(host,un,pwd,cmd)
Net::SSH.start( host, un, :password => pwd ) do|ssh|
result = ssh.exec!(cmd)
return result
end
end
I tried this but it dint work.
def sshutm(host,un,pwd,cmd)
Net::SSH.start( host, un, :password => pwd ) do|ssh|
ssh.exec!("su")
ssh.exec!("passowrd")
result = ssh.exec!(cmd)
return result
end
end
You could make your user a sudo user (e.g. http://www.linux.com/learn/tutorials/306766:linux-101-introduction-to-sudo), and execute the given command with sudo (e.g. sudo ls /root). Details vary on the used distribution.

Interactive Ruby script

I'm trying to write a ruby script that logs into a remote server, switches to another user, executes a script and answers questions to that script. Right now, I can log in but it hangs on the execution of the bash script. I'm not sure if I got the prompt part right but it's not getting to that point yet. It "hangs" on the running of the script or it just isn't printing the output of the script to the screen.
Here's what I got for now:
require 'rubygems'
require 'net/ssh'
require 'net/ssh/telnet'
s = Net::SSH::Telnet.new("Host" => "server1", "Username" => "dev", "Password" => "12345", "Prompt" => /[$%#>] \z/n)
puts s.cmd("sudo -s")
puts s.cmd("su - user1")
puts s.cmd("/opt/develop/develop-bin/start.sh")
puts s.waitfor(/Prompt/)
Here is the snippet that works for me. It is taken from the bigger library, so treat it as an example. Fill up the variables command, username, password, servername and sudoer and give a try
class AuthenticationError < StandardError; end
AUTH_METHODS = ['hostbased', 'password', 'keyboard-interactive']
MYPROMPT = SecureRandom.hex # or whatever you want
ret = ""
stderr_data = ""
Net::SSH.start(servername, username, :password => password, :auth_methods => AUTH_METHODS) do |ssh|
ssh.open_channel do |channel|
channel.on_data do |channel, data|
ret += data
raise AuthenticationError, "SUDO ACCESS DENIED" if data.inspect.include?('Sorry, try again.') || data.inspect.include?('not in sudoers')
channel.send_data(password+"\n") if data.inspect.include? MYPROMPT
sleep 0.1
end
channel.on_extended_data do |ch, type, data|
stderr_data+=data
end
channel.request_pty
channel.exec("sudo -p #{MYPROMPT} su - #{sudoer} -c '#{command}'")
channel.wait
end
end
puts ret.gsub(/^"/,'').gsub(/"$/,'')

How do I concatenate a method call?

I am calling a method so:
Net::SSH.start( value, USER, :password => PASS, :keys => ["/keys/id_rsa"] ) do|ssh|
mess = ssh.sudo "password", "apt-get upgrade"
end
The method is:
class Net::SSH::Connection::Session
def sudo password, command
exec %Q%echo "#{password}" | sudo -S #{command}% do |channel, stream, data|
stdout << data if stream == :stdout
end
return stdout
end
end
Later, I send an email with the mess variable and this works fine.
However, if I want to run through an array of hosts and try to append mess to a string like results << mess, all I get is an empty variable. I don't know why this is.

Ruby Net::SCP download asking for password then failing

I'm trying to download a file to an in-memory buffer from a unix box then upload the file to another unix box, but when I try to download the file it asks for my password then fails even if I put it in. I've tried both:
data = Net::SCP.download!("remote.host.com", "username", "/remote/path", :password => password)
and
data = Net::SCP::download!("remote.host.com", "username", "/remote/path", :password => password)
but I get:
Active Directory Password:
Then when I enter my password:
Net::SCP::Error: SCP did not finish successfully (1)
ruby 1.8.7 (2010-12-23 patchlevel 330) [i386-mingw32]
net-scp (1.0.4)
Try to use it like this:
require 'net/scp'
data = nil
Net::SCP.start("remote.host.com", "username", :password => "password") do |scp|
data = scp.download!("/remote/path")
end
puts data
EDIT: I only tried this on ruby ruby-1.9.3, sorry
Looks like Net::SFTP will be what I'm actually going to use, its not much more and is probably what I'd end up with anyway since I didn't realize I need to 'write' the #data before putting it on another server.
data = nil
Net::SFTP.start('remoteHost1', 'username', :password => 'password') do |sftp|
data = sftp.download!("filepath1")
end
Net::SFTP.start('remoteHost2', 'username', :password => 'password') do |sftp|
sftp.file.open("filePath2", "w") do |f|
f.puts data
end
end

How to get the result of executed command if Net::SSH library used?

I have a function
def run_through_ssh(command)
host = $edumate_server
user = 'user'
pass = '******'
output = Array.new
Net::SSH.start( host, user, :password => pass ) do|ssh|
output = ssh.exec(command)
#output = ssh.exec(command+" 2>&1")
end
return output
end
which executes the command I want correctly on the remote server but the output variable doesn't contain what the remotely executed command outputs to the screen. I use this function inside sinatra and strangely I can see the output on the screen where I run sinatra.
How can I capture the output of remotely executed command?
The output variable contains things like
#<Net::SSH::Connection::Channel:0x3fe40c0 #remote_maximum_window_size=2097152, #
eof=false, #on_open_failed=nil, #remote_window_size=2097152, #closing=true, #pro
perties={}, #local_maximum_packet_size=65536, #on_process=nil, #type="session",
#remote_id=0, #on_confirm_open=#<Proc:0x031f64a0#C:/Ruby187/lib/ruby/gems/1.8/ge
ms/net-ssh-2.2.1/lib/net/ssh/connection/session.rb:320>, #on_request={}, #local_
id=0, #on_extended_data=#<Proc:0x031f6560#C:/Ruby187/lib/ruby/gems/1.8/gems/net-
ssh-2.2.1/lib/net/ssh/connection/session.rb:332>, #local_maximum_window_size=131
072, #on_eof=nil, #connection=#<Net::SSH::Connection::Session:0x3fe42a0 #options
={:logger=>#<Logger:0x400cb90 #level=4, #progname=nil, #logdev=#<Logger::LogDevi
using
ruby 1.8.7 (2010-08-16 patchlevel 302) [i386-mingw32]
net-ssh (2.2.1)
Something like this should work:
Net::SSH.start( host, user, :password => pass ) do |ssh|
output = ssh.exec!(command)
end
output
The exec! method captures stdin/stdout if no block is given. See http://net-ssh.github.com/ssh/v2/api/classes/Net/SSH/Connection/Session.html#M000094

Resources