112 lines
4.2 KiB
Ruby
112 lines
4.2 KiB
Ruby
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
|