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
 | 
