fluke/devops-service/lib/ssh/ssh_utils.rb

112 lines
4.2 KiB
Ruby
Raw Permalink Normal View History

2018-04-04 22:44:39 +03:00
require 'net/ssh'
require 'net/scp'
module Devops
module SSH
class Utils
class << self
# returns true if ssh available
def try_ssh host, remote_user, ssh_key_path
i = 1
begin
res = ""
Net::SSH.start( host, remote_user, :keys => [ssh_key_path], :timeout => 2, :keys_only=>true, :non_interactive => true ) do |ssh|
res = ssh.exec!('echo 1')
end
return res.strip == "1"
rescue Net::SSH::ConnectionTimeout, Errno::ECONNREFUSED
return false
rescue Net::SSH::AuthenticationFailed => e
if i < 3
i = i + 1
sleep(5)
retry
end
raise e
end
end
def run_command_out cmd, ip, remote_user, ssh_key_path, out
if remote_user != "root"
cmd = "sudo #{cmd}"
end
msg = "SSH: trying to run command '#{cmd}' on '#{ip}'"
DevopsLogger.logger.info(msg)
out.flush if out.respond_to?(:flush)
exit_code = nil
Net::SSH.start(ip, remote_user, :keys => [ssh_key_path], :keys_only=>true, :non_interactive => true) do |session|
session.open_channel do |channel|
channel.request_pty(:modes => { Net::SSH::Connection::Term::ECHO => 0 }) do |c, success|
raise "could not request pty" unless success
channel.exec cmd
channel.on_data do |ch, data|
out << data + "\n"
out.flush if out.respond_to?(:flush)
end
channel.on_request("exit-status") do |ch, data|
exit_code = data.read_long
end
end
end
session.loop
end
msg = "SSH: done with code '#{exit_code}'"
DevopsLogger.logger.info(msg)
exit_code
end
def run_script script_path, ip, remote_user, ssh_key_path, out
msg = "SSH: trying to run script '#{script_path}' on '#{ip}'"
DevopsLogger.logger.info(msg)
out << msg + "\n"
out.flush if out.respond_to?(:flush)
exit_code = nil
remote_path = "/tmp/script-#{Time.now.to_i}"
Net::SSH.start(ip, remote_user, :keys => [ssh_key_path], :keys_only=>true, :non_interactive => true) do |session|
session.scp.upload script_path, remote_path
session.open_channel do |channel|
channel.request_pty(:modes => { Net::SSH::Connection::Term::ECHO => 0 }) do |c, success|
raise "could not request pty" unless success
channel.exec "/bin/bash #{remote_path} && rm -f #{remote_path}"
channel.on_data do |ch, data|
out << data + "\n"
out.flush if out.respond_to?(:flush)
end
channel.on_request("exit-status") do |ch, data|
exit_code = data.read_long
end
end
end
session.loop
end
msg = "SSH: done with code '#{exit_code}'"
DevopsLogger.logger.info(msg)
out << msg + "\n"
out.flush if out.respond_to?(:flush)
exit_code
end
def upload_file data, ip, remote_user, ssh_key_path, remote_path
DevopsLogger.logger.info("SCP: trying to upload data to '#{remote_user}@#{ip}:#{remote_path}' with identity file #{ssh_key_path}")
Net::SSH.start(ip, remote_user, keys: [ssh_key_path], :keys_only => true, :non_interactive => true ) do |ssh|
res = ssh.scp.upload StringIO.new(data.to_s), remote_path
puts "UPLOAD RES: #{res}"
end
DevopsLogger.logger.info("SCP: done")
end
def copy_deploy_info data, ip, remote_user, ssh_key_path, out
upload_file(data, ip, remote_user, ssh_key_path, "/tmp/deploy_info.json")
cmd = "mv /tmp/deploy_info.json /etc/chef/"
cmd = "sudo " + cmd unless remote_user == "root"
run_command_out(cmd, ip, remote_user, ssh_key_path, out)
"/etc/chef/deploy_info.json"
end
end
end
end
end