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 |