I have a Ruby on Rails (Rails 3.2.14 and ruby 1.9.3) application that uploads 2 files to a remote SFTP server. The SFTP code is:
require 'net/sftp'
Rails.logger.info("Creating SFTP connection")
uri = URI.parse('sftp://'+ host)
Net::SFTP.start(uri.host,'user', :password=>'password',:port=>port) do |sftp|
Rails.logger.info("SFTP Connection created, uploading files.")
sftp.upload!("public/file1.txt", "./file1.txt")
Rails.logger.info("First file uploaded.")
sftp.upload!("file2.txt", "./file2.txt")
Rails.logger.info("Both files uploaded, terminating connection.")
end
Rails.logger.info("Connection terminated.")
Both files are uploading properly to the remote server, but the connection doesn't seem to close. I keep getting an error when I execute this function and on analyzing my console, I see that the "Both files uploaded, terminating connection." logger message is running, but nothing after that. I've tried using
sftp.close(:handle)
sftp.close!(:handle)
#and
sftp.close_connection()
but none of them are working. Any idea on why this is happening and how I can rectify it? I'm running this through a single instance Engine Yard cloud server.
EDIT These are the last few lines in my log: Creating SFTP connection SFTP Connection created, uploading files. First file uploaded. Both files uploaded, terminating connection.
After that, nothing. When viewing my log with the 'tail -f' command, the log goes up to that last line, and the app redirects to the internal server error page.
Make sure you log in to your server's IP ADDRESS (not your domain) with the SYSTEM USER used to create your app; attempting to connect to your domain directly is one of the most common causes of SFTP connection failures. Make sure you attempt to connect over SFTP. ServerPilot does not support unsecure FTP connections.
Net::SFTP.start('host', 'user', password: 'pass', port: 22) do |sftp|
# Do stuff
end
is equivalent to :
session = Net::SSH.start('host', 'user', password: 'pass', port: 22)
sftp = Net::SFTP::Session.new(session)
sftp.connect!
# Do stuff
sftp.close_channel unless sftp.nil?
session.close unless session.nil?
For people that couldn't find a way to actually close the connection, without using auto-closing blocks, here is how I you can achieve this :
require 'net/ssh'
require 'net/sftp'
begin
# Instance SSH/SFTP session :
session = Net::SSH.start('host', 'user', password: 'pass', port: 22)
sftp = Net::SFTP::Session.new(session)
# Always good to timeout :
Timeout.timeout(10) do
sftp.connect! # Establish connection
# Do stuff
end
rescue Timeout::Error => e
# Do some custom logging
puts e.message
ensure
# Close SSH/SFTP session
sftp.close_channel unless sftp.nil? # Close SFTP
session.close unless session.nil? # Then SSH
# If you really really really wanna make sure it's closed,
# and raise after 10 seconds delay
Timeout.timeout(10) do
sleep 1 until (sftp.nil? or sftp.closed?) and (session.nil? or session.closed?)
end
end
If you don't close the connection before performing some other task, you might sometimes experience errors like this in rails for instance :
IOError (not opened for reading) # Not closed when rendering controller action
ActionView::Template::Error (not opened for reading) # Not closed when rendering template
I don't know why, but rewriting the code to include 'net/ssh' and creating the sftp connection explicitly through SSH worked!
require 'net/ssh'
require 'net/sftp'
#upload a file or directory to the remote host
Rails.logger.info("Creating SFTP connection")
session=Net::SSH.start('host','user', :password=>'password',:port=>port)
sftp=Net::SFTP::Session.new(session).connect!
Rails.logger.info("SFTP Connection created, uploading files.")
sftp.upload!("file1.txt", "./file1.txt")
Rails.logger.info("First file uploaded.")
sftp.upload!("file2.txt", "./file2.txt")
Rails.logger.info("Both files uploaded, terminating connection.")
Rails.logger.info("Connection terminated.")
Perhaps someone can shed some light on why this one worked and the other didn't.
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