Remote Execute Command using SSH from Rails Application - ruby-on-rails

I have a Rails Application from which I will call one Ruby Definition in the controller, like this.
ssh root#host "uptime" >> /tmp/output
When I doing this, only the /tmp/output is created but not the content.
When I running the same from simple Ruby script its working fine.
my controller definition
def chefclient1
`ssh root#host "uptime" >> /tmp/output`
#time = Time.now
end
my view
= link_to('Start uptime', host_chefclient1_path)

You can use net-ssh gem to access remote host via ssh fo a ruby app. Set your environment up to:
HOSTNAME = 'host'
USER = 'root'
PASS = 'password'
Add to your_helper.rb: something like:
def chefclient1
result = nil
Net::SSH.start( ENV[ 'HOSTNAME' ], ENV[ 'USER' ], :password => ENV[ 'PASS' ] ) do| ssh |
result = ssh.exec! 'uptime'
puts result
end
File.open( '/tmp/output', 'w' ) {| f | f.puts result }
end
And use the helper method as you with from a view.

Related

RSpec be_equal not working

I am writing some rspec examples for a plain old ruby class in my rails project and I am facing the following problem.
I have this constructor:
class Server
def initialize(host='localhost',options={:port => 443, :password => '', :vpncmd_bin_path => '/usr/local/bin/vpncmd', :timeout => 5})
#host = host
#port = options[:port].present? ? options[:port] : 443
#password = options[:password].present? ? options[:password] : ''
#vpncmd_bin_path = options[:vpncmd_bin_path].present? ? options[:vpncmd_bin_path] : '/usr/local/bin/vpncmd'
#timeout = options[:timeout].present? ? options[:timeout] : 5
#hubs = {}
#hub_cache_dirty = true
#hub_password_cache = {}
end
...
end
This test example:
it "should have a default constructor that takes no argument" do
s = SoftEther::Server.new()
expect(s.host).to be_equal('localhost')
expect(s.port).to be_equal('443')
expect(s.timeout).to be_equal(5)
expect(s.vpncmd_bin_path).to be_equal('/usr/local/bin/vpncmd')
expect(s.password).to be_equal('')
end
And rspec gives me the following result with Rails 4.2.6, jruby-9.0.5.0 and 3.4.4:
1) SoftEtherSever should have a default constructor that takes no argument
Failure/Error: expect(s.host).to be_equal('localhost')
expected `"localhost".equal?("localhost")` to return true, got false
# ./spec/poro/softether_spec.rb:19:in `block in (root)'
What did I do wrong?
equal? checks whether two instances are the same. But it returns false when two strings contains the same value but refers to different objects:
"foo".equals?("foo")
# => false
What you should really use is eq()
expect(s.host).to eq('localhost')
Just to add an edge case to Simone's answer:
If you were to freeze the strings in question, you would get the result you expected:
irb(main):001:0> 'test'.equal? 'test'
=> false
irb(main):002:0> 'test'.freeze.equal? 'test'.freeze
=> true
In Ruby 2.3, this can be done by adding
# frozen_string_literal: true
to the top of the Ruby file.
With that said, Simone is right. You should use the eq matcher unless you truly want to test that you are using the same exact object instance. Then using equal is in order.

How to run the commands in Ruby as a root

I am using net/ssh gem in Ruby.
By the following code I can enter into the server from my local machine. But I want to execute the commands on the server by entering as a ROOT.
Normally, I enter into the server as a ROOT by the command
sudo su -
Following is my code.
require 'rubygems'
require 'net/ssh'
list_of_servers = "servers.csv"
username="XYZ"
IO.readlines(list_of_servers).each do |line|
line.chomp!
server = line.split(',')[0]
password = line.split(',')[1]
puts "---- " + server
Net::SSH.start(server, username, :password => password,:verbose => Logger::DEBUG) do |ssh|
result=ssh.exec!("sudo su -")
puts result
end
end
Output I get after entering into server.
D, [2015-11-21T21:48:26.005576 #56654] DEBUG -- io[3fce29cc9548]: received packet nr 15 type 97 len 12
I, [2015-11-21T21:48:26.005628 #56654] INFO -- net.ssh.connection.session[3fce29ce9834]: channel_close: 0
D, [2015-11-21T21:48:26.005796 #56654] DEBUG -- io[3fce29cc9548]: queueing packet nr 11 type 97 len 28
sudo: no tty present and no askpass program specified
Note:
I can successfully log into the server from my local machine but I cannot run the ROOT command (sudo su -).
You have to start tty for that
scenario = []
scenario << ""
scenario << "su"
#session = Net::SSH.start(ip , user,
:password => pass,
:auth_methods => ['password'],
:timeout => 10
)
#session.open_channel do |channel|
channel.request_pty do |ch, success|
ch.send_channel_request("shell") do |shell, success|
shell.on_data do |c, data|
#output << data
end
scenario.each do |s|
cmd = "#{s}\r\n"
shell.send_data(cmd)
end
end
end
end
According to man sudo, if you specify -S before the command, sudo takes the password from stdin.
I tried this both on a terminal and from ruby with success:
(insert your password, and the command you wish to run in the generic example below.)
echo "password" | sudo -S "command"
works for me.

Not setting arguments properly in rails tasks?

I am curious as to why my args variable is always coming back as {} in the following task:
desc "Create an Api Key assuming one doesn't exist."
task :create_api_key, [:name] => :environment do | t, args |
if !ApiKey.find_by_application_name(args[:name])
binding.pry
if ApiKey.new(:application_name => args[:name], :api_key => SecureRandom.hex(32)).save!
puts "Your key is: " + ApiKey.find_by_application_name(args[:name]).api_key
else
puts "Could not create the api key, you might be missing an argument: Application Name."
end
else
puts "This application already contains an api key."
end
end
The following is a run of the task (Note the binding.pry):
$ bin/rake create_api_key "xaaron_test"
From: /Users/Adam/Documents/Rails-Projects/BlackBird/lib/tasks/create_api_key.rake # line 4 :
1: desc "Create an Api Key assuming one doesn't exist."
2: task :create_api_key, [:name] => :environment do | t, args |
3: if !ApiKey.find_by_application_name(args[:name])
=> 4: binding.pry
5: if ApiKey.new(:application_name => args[:name], :api_key => SecureRandom.hex(32)).save!
6: puts "Your key is: " + ApiKey.find_by_application_name(args[:name]).api_key
7: else
8: puts "Could not create the api key, you might be missing an argument: Application Name."
9: end
[1] pry(main)> args
=> {}
Even if I do bin/rake create_api_key xaaron_test I get the same issue. What is going on? is there some small mistake some where I forgot about?
Update
I also spit out t to see what was in there:
pry(main)> t
=> <Rake::Task create_api_key => [environment]>
You pass arguments to a task by enclosing them in [] directly after the task name.
e.g.
rake create_api_key[xaaron_test]
If you use zsh, you need to escape the opening [
e.g.
rake create_api_key\[xaaron_test]

run the shell script from rails application after login to the remote system

I want to run a shell script from my Rails application. The script is started on the remote server via the net-ssh Gem. Here is my code:
Net::SSH.start('localhost', 'user', :password => '1234', :port => port) do |session|
session.exec!("#{Rails.root}/script/myscript")
end
I have checked that the script is present in my local application. Script is taking about 1 hour for completion. I have two questions:
Is this the right way for doing this?
How can I run the script in the background?
The sample doc says that the simple, and quite proper way to run the Net::SSH session is the following:
HOST = '192.168.1.113'
USER = 'username'
PASS = 'password'
Net::SSH.start( HOST, USER, :password => PASS ) do| ssh |
result = ssh.exec! 'ls'
puts result
end
I recomment to pass at least password argument via shell environment to don't store it in the script plainly. Also you could use micro-optparse gem to pass other argument via command line. So it could be as follows:
require 'micro-optparse'
options = Parser.new do |p|
p.banner = "This is a fancy script, for usage see below"
p.version = "fancy script 0.0 alpha"
p.option :host, "set host", :default => 'localhost'
p.option :host, "set user", :default => ''
end.parse!
Net::SSH.start( options[ :host ], options[ :user ], :password => ENV[ 'PASSWORD' ] ) do| ssh |
result = ssh.exec! 'ls'
puts result
end
And run from command line:
$ bundle exec ./1.rb --host=111.ru --user=user
{:host=>"111.ru", :user=>"user"}
Of course the support for :port argument can be added in the same manner.
Use nohup or screen utitilies to run a script as a service in linux:
result = ssh.exec! "nohup #{Rails.root}/script/myscript"
Why shouldn't it be the right way?
To run a shell script in the background, append & to the command
For example:
session.exec!("#{Rails.root}/script/myscript&")

ssh connection over ruby script

hy
i try to connect in the new server by ruby script
> 1.9.2p320 :038 > Net::SSH.start('192.168.10.80', 'root', :password => 'xxxxx')
> Net::SSH::AuthenticationFailed: root
> from /home/zyriuse/.rvm/gems/ruby-1.9.2-p320/gems/net-ssh-2.7.0/lib/net/ssh.rb:215:in > `start'
> from (irb):38
> from /home/zyriuse/.rvm/rubies/ruby-1.9.2-p320/bin/irb:16:in `<main>'
i dont understand why i get this error because when i try manually everything it's working
i try a lot of thing
require 'net/ssh'
require 'logger'
Net::SSH.start(
'localhost', 'zyriuse',
:keys => [ "~/.ssh/id_dsa.pub" ],
) do |session|
puts "hello "
end
~
zyriuse (Net::SSH::AuthenticationFailed)
Net::SSH.start( 'host',
:password=>'passord',
:port=>22,
:username=>'zyriuse',
... ) do |session|
puts "hello wordl"
end
`start': Net::SSH::AuthenticationFailed
i dont understand why i get all the time the same error
Make sure:
The account is correct
The password is correct
The IP is correct
that ssh root#192.168.10.80 works from your machine, typing the password
The error AuthenticationFailed means just that.

Resources