ruby net::ssh does not print stdout data on channel.on_data - ruby

I wanted to run a remote command with ruby's net::ssh and was hoping to print the output stdout but i don't see anything printed at the below code at channel.on_data
see test code:
Net::SSH.start('testhost', "root", :timeout => 10) do |ssh|
ssh.open_channel do |channel|
channel.exec('ls') do |_, success|
unless success
puts "NOT SUCCEESS:! "
end
channel.on_data do |_, data|
puts "DATAAAAAA:! " # ======> Why am i not getting to here?? <=======
end
channel.on_extended_data do |_, _, data|
puts "EXTENDED!!!"
end
channel.on_request("exit-status") do |_, data|
puts "EXIT!!!! "
end
channel.on_close do |ch|
puts "channel is closing!"
end
end
end
end
and the output is:
channel is closing!
why don't i get into the block on_data? I want to grab the stdout.
note that i know the client code is able to ssh to the remote server because when I asked the command to be ls > ls.log I saw that ls.log on target host.

Note that opening a channel is asynchronous, so you have to wait for the channel to do anything meaningful, otherwise you are closing the connection too soon.
Try this:
Net::SSH.start('test', "root", :timeout => 10) do |ssh|
ch = ssh.open_channel do |channel|
channel.exec('ls') do |_, success|
unless success
puts "Error"
end
channel.on_data do |_, data|
puts data
end
channel.on_extended_data do |_, _, data|
puts data
end
channel.on_request("exit-status") do |_, data|
puts "Exit"
end
channel.on_close do |ch|
puts "Closing!"
end
end
end
ch.wait
end

Related

Getting output from Ruby Net::SSH sessions

I've got a larger script that basically uses the same type of code below. The script runs and functions but I don't get output to the screen. How do I get the output of the script that is being executed remotely to show up on the screen I'm running the ruby script from?
#!/usr/bin/ruby
#
require 'rubygems'
require 'net/ssh'
require 'pty'
if ENV['USER'] == 'root'
raise "You can't run this as root"
end
Net::SSH.start(server01, testuser) do |ssh|
ssh.open_channel do |channel|
channel.on_request "exit-status" do |channel, data|
$exit_status = data.read_long
end
channel.on_data do |channel, data|
data
end
channel.request_pty do |channel, data|
channel.exec("sudo -s")
channel.send_data("/tmp/scripts/test.sh\n")
channel.send_data("exit\n")
end
end
end
puts "DONE"
change
channel.on_data do |channel, data|
data
end
to
channel.on_data do |channel, data|
puts data
end
the data mentioned is the response from the server
and add
channel.send_channel_request 'shell' do |ch, success|
if success
puts 'user shell started successfully'
else
puts 'could not start user shell'
end
end

Send messages on different channels using sinatra-websocket

Is there a way to send messages on different channels using the sinatra-websocket gem?
Basically I'm trying to replace Pusher with sinatra-websocket. Here's what I'm doing with Pusher:
Pusher["my_channel_A"].trigger('some_event_type', my_message)
Pusher["my_channel_B"].trigger('another_event_type', my_message)
What would be the equivalent of that syntax in this sinatra-websocket snippet?
request.websocket do |ws|
ws.onopen do
ws.send("Hello World!")
settings.sockets << ws
end
ws.onmessage do |msg|
EM.next_tick { settings.sockets.each{|s| s.send(msg) } }
end
ws.onclose do
warn("websocket closed")
settings.sockets.delete(ws)
end
end
Found an answer to this posted here:
get '/socket/live/game/:id' do
if !request.websocket?
puts "Not a websocket request"
else
request.websocket do |ws|
channel = params[:id]
#con = {channel: channel, socket: ws}
ws.onopen do
ws.send("Hello World!")
settings.sockets << #con
end
ws.onmessage do |msg|
return_array = []
settings.sockets.each do |hash|
#puts hash
#puts hash['channel']
if hash[:channel] == channel
#puts hash[:socket]
return_array << hash
puts "Same channel"
puts return_array
else
puts hash[:channel]
puts channel
puts "Not in same channel"
end
end
EM.next_tick { return_array.each{|s| s[:socket].send(msg) } }
end
ws.onclose do
warn("websocket closed")
settings.sockets.each do |hash|
if hash[:socket] == ws
settings.sockets.delete(hash)
puts "deleted"
else
puts "not deleted"
end
end
end
end
end
end
It's still quite verbose. I guess Pusher abstracts away all this through their API.

Implemeting amazon Simple nodification service in RUBY

Am trying to implement amazon SNS using ruby.
I want to create a topic,delete a topic,subscribe to a topic,publish to a topic.These are included in the following code.
#!/usr/bin/env ruby
require 'rubygems'
require 'aws-sdk'
AWS.config(:access_key_id => 'BT62W53Q', :secret_access_key => '0Edwg')
#sns=AWS::SNS.new
#D requirements
alpha = #sns.topics.create('CSC470Test-Alpha')
#sns.topics.create('CSC470Test-Beta')
temp=gets
#sns.topics.each do |topic|
puts topic.name
if(topic.name=='CSC470Test-Beta')
topic.delete
end
end
puts
puts 'Beta now deleted.'
puts
#sns.topics.each do |topic|
puts topic.name
end
puts
temp=gets
puts
#C requirements
#sns.topics.each do |topic|
if(topic.name=='CSC470Test-Alpha')
subbed1=false
subbed2=false
subbed3=false
topic.subscriptions.each do |sub|
if(sub.endpoint=='sn#aine.com')
subbed1=true;
end
if(sub.endpoint=='pran#aine.com')
subbed2=true;
end
if(sub.endpoint=='http://cloud.comtor.org/csc470logger/logger')
subbed3=true;
end
end
if(!subbed1)
puts 'Subscribed sika.'
topic.subscribe('sn#aine.com')
end
if(!subbed2)
puts 'Subscribed prka'
topic.subscribe('pran#aine.com', :json => true)
end
if(!subbed3)
puts 'Subscribed comtor site.'
topic.subscribe('http://cloud.comtor.org/csc470logger/logger')
end
end
end
temp=gets
puts 'Topics with info:'
#sns.topics.each do |topic|
puts
puts 'Arn'
puts topic.arn
puts 'Owner'
puts topic.owner
puts 'Policy'
puts topic.policy
puts 'Name'
puts topic.display_name
puts 'Confirmed Subscriptions:'
puts topic.subscriptions.
select{ |s| s.arn != 'PendingConfirmation' }.
map(&:endpoint)
# if(subs.confirmation_authenticated?)
# puts 'Arn: ' + subs.arn
# puts 'Endpoint: ' + subs.endpoint
# puts 'Protocol: ' + subs.protocol
# end
end
puts
temp=gets
#sns.subscriptions.each do |subs|
puts "SubscriptionARN: #{ subs.arn} "
puts "TopicARN: #{subs.topic_arn} "
puts "Owner: #{subs.owner_id} "
puts "Delivery Policy: #{ subs.delivery_policy_json} "
end
while running this code in rails console. iam getting this error
C:/ProgramData/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/aws-sdk-1.8.5/l
ib/aws/core/client.rb:339:in `return_or_raise': The request signature we calcula
ted does not match the signature you provided. Check your AWS Secret Access Key
and signing method. Consult the service documentation for details. (AWS::SNS::Er
rors::SignatureDoesNotMatch)
from C:/ProgramData/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/aw
s-sdk-1.8.5/lib/aws/core/client.rb:440:in `client_request'
from (eval):3:in `create_topic'
from C:/ProgramData/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/aw
s-sdk-1.8.5/lib/aws/sns/topic_collection.rb:24:in `create'

ruby shoes ssh connection

I am trying my hands on shoes but got stuck. I am trying to connect to a remote computer using ssh and issue a command, got it working in cli but it is a no go for me to get it working on shoes.
This might be a simple thing but new as I am I can't get past it.
Here is what my code looks like atm
Shoes.setup do
gem 'net-ssh'
end
require "rubygems"
require "net/ssh"
Shoes.app do
button "Connect" do
append Net::SSH.start( '192.168.100.127', 'fox', :password => "xxxxxx" ) do
|ssh_connection|
ssh_connection.open_channel do |channel|
channel.on_data do |ch, data|
puts data
channel.exec "ls -la" do |ch, success|
para success
if success then
alert "uploaded"
else
alert "Fail"
end
end
end
end
end
end
end
Your code is trying to receive data first which is not the case usually. Remove the on_data:
Shoes.app do
button "Connect" do
append Net::SSH.start( '192.168.100.127', 'fox', :password => "xxxxxx" ) do |ssh_connection|
ssh_connection.open_channel do |channel|
channel.exec "ls -la" do |ch, success|
para success
if success then
alert "uploaded"
else
alert "Fail"
end
end
end
end
end
end

How to get exit status with Ruby's Net::SSH library?

I have a snippet of code, simply trying to execute a script on a remote server, in the event that it fails, I'd like to make a follow-up call, imagine this:
require 'rubygems'
require 'net/ssh'
require 'etc'
server = 'localhost'
Net::SSH.start(server, Etc.getlogin) do |ssh|
puts (ssh.exec("true") ? 'Exit Success' : "Exit Failure")
puts (ssh.exec("false") ? 'Exit Success' : "Exit Failure")
end
I would expect (ignoring that stdout and stderr are printed in my contrived example) - but first line should exit with 0 which I would expect Ruby would interperate as false and display "Exit Failure" (sure, so the logic is wrong, the ternary needs to be flipped) - but the second line should exit with the opposite status, and it doesn't.
I can't even find anything in the documentation about how to do this, and I'm a little worried that I might be doing it wrong?!
I find the following way of running processes with Net::SSH much more useful. It provides you with distinct stdout and stderr, exit code and exit signal.
require 'rubygems'
require 'net/ssh'
require 'etc'
server = 'localhost'
def ssh_exec!(ssh, command)
stdout_data = ""
stderr_data = ""
exit_code = nil
exit_signal = nil
ssh.open_channel do |channel|
channel.exec(command) do |ch, success|
unless success
abort "FAILED: couldn't execute command (ssh.channel.exec)"
end
channel.on_data do |ch,data|
stdout_data+=data
end
channel.on_extended_data do |ch,type,data|
stderr_data+=data
end
channel.on_request("exit-status") do |ch,data|
exit_code = data.read_long
end
channel.on_request("exit-signal") do |ch, data|
exit_signal = data.read_long
end
end
end
ssh.loop
[stdout_data, stderr_data, exit_code, exit_signal]
end
Net::SSH.start(server, Etc.getlogin) do |ssh|
puts ssh_exec!(ssh, "true").inspect
# => ["", "", 0, nil]
puts ssh_exec!(ssh, "false").inspect
# => ["", "", 1, nil]
end
Hope this helps.
Building on the answer by flitzwald - I've monkey patched my version of this into Net::SSH (Ruby 1.9+)
class Net::SSH::Connection::Session
class CommandFailed < StandardError
end
class CommandExecutionFailed < StandardError
end
def exec_sc!(command)
stdout_data,stderr_data = "",""
exit_code,exit_signal = nil,nil
self.open_channel do |channel|
channel.exec(command) do |_, success|
raise CommandExecutionFailed, "Command \"#{command}\" was unable to execute" unless success
channel.on_data do |_,data|
stdout_data += data
end
channel.on_extended_data do |_,_,data|
stderr_data += data
end
channel.on_request("exit-status") do |_,data|
exit_code = data.read_long
end
channel.on_request("exit-signal") do |_, data|
exit_signal = data.read_long
end
end
end
self.loop
raise CommandFailed, "Command \"#{command}\" returned exit code #{exit_code}" unless exit_code == 0
{
stdout:stdout_data,
stderr:stderr_data,
exit_code:exit_code,
exit_signal:exit_signal
}
end
end
For newer versions of Net::SSH, you can just pass a status hash to Net::SSH::Connection::Session#exec:
status = {}
Net::SSH.start(hostname, user, options) do |ssh|
channel = ssh.exec(command, status: status)
channel.wait # wait for the command to actually be executed
end
puts status.inspect
# {:exit_code=>0}
By default, exec streams its output to $stdout and $stderr. You can pass a block to exec to do something different, a la:
ssh.exec(command, status: status) do |ch, stream, data|
if stream == :stdout
do_something_with_stdout(data)
else
do_something_with_stderr(data)
end
end
This works on 6.1.0 - not sure about availability for older versions. See http://net-ssh.github.io/net-ssh/Net/SSH/Connection/Session.html#method-i-exec for more details.

Resources