I've been trying to write a small library using Thor to help assist me in quick creating new projects and sites. I wrote this small method:
def ssh(cmd)
Net::SSH.start( server_ip, user, :port => port) do |session|
session.exec cmd
end
end
to just assist me in running quick commands on remote servers when needed.
The problem is when I need to run a command under sudo on the remote end, the script just seems to hang on me. For example when executing this...
ssh("sudo cp #{file_from_path} #{file_to_path}" )
The script will prompt me for a password
[sudo] password for user:
But then the whole thing hhangs after typing it in.
Would anyone happen to know why it hangs exactly, and what I can do to run sudo command on a remote server under Net::SSH (or some alternative)?
*note: Before suggested, I had originally started writing this library as a recipe under Capistrano, until I came upon Thor, and thought it would be a good chance to try it out. I'm not against having to switch the whole thing back to Capistrano if needed, but I'd just be really surprised if there isn't an easy way to run sudo commands on a remote server.
If your timestamp_timeout is zero, sudo always prompts for a password. This feature can be enabled only by the superuser, however. Ordinary users can achieve the same behavior with sudo -k, which forces sudo to prompt for a password on your next sudo command.
By default, sudo needs that a user authenticates using a password before running a command. Some times you may need to run a command with root privileges, but you do not want to type a password using sudo command. This is useful for scripting or any other purpose.
I hope this will help someone searching. I also needed to sudo
during deployment (restarting thin instances)
# deploy.rake
require 'net/ssh'
# INITIALIZE CONSTANTS HERE
HOST = 'yourwebsite.com'
USER = 'admin'
PASSWORD = 'your server password' # or use ENV variables?
# etc.
namespace :deploy do
namespace :staging do
task :restart do
commands = [
"cd #{PATH_TO_STAGING_APP} && git checkout master",
"git reset --hard HEAD",
"git pull origin master",
"bundle install --without test development",
"sudo thin restart -C /etc/thin/#{STAGING_APP}.yml"
]
Net::SSH.start(HOST, USER, :password => PASSWORD) do |ssh|
ssh.open_channel do |channel|
channel.request_pty do |ch, success|
if success
puts "Successfully obtained pty"
else
puts "Could not obtain pty"
end
end
channel.exec(commands.join(';')) do |ch, success|
abort "Could not execute commands!" unless success
channel.on_data do |ch, data|
puts "#{data}"
channel.send_data "#{PASSWORD}\n" if data =~ /password/
end
channel.on_extended_data do |ch, type, data|
puts "stderr: #{data}"
end
channel.on_close do |ch|
puts "Channel is closing!"
end
end
end
ssh.loop
end
end
end
end
Note that one channel can only execute one command. Hence I chained the commands together with commands.join(';')
Reference: Net::SSH::Connection::Channel
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With