/
ssh_connection.rb
133 lines (120 loc) · 4.23 KB
/
ssh_connection.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
require 'net/http'
require 'net/ssh'
require 'stringio'
# TODO: Remove this class when this branch is merged,
# https://github.com/fusor/fusor/blob/deploy-cfme/server/app/lib/utils/fusor/command_utils.rb,
# and additional changes here have been applied.
module Utils
module Fusor
class SSHConnection
def initialize(host, user, password = nil, keyfile = nil)
@host = host
@user = user
@password = password
@keyfile = keyfile
end
def stringio_write(stringio, text)
$stdout.puts text if stringio.nil?
stringio.puts text unless stringio.nil?
end
def port_open?(port, stringio = nil, local_ip = "127.0.0.1", remote_ip = "192.0.2.1", seconds = 1)
t = Thread.new {
begin
keys = []
auth_methods = ["password"]
if @keyfile
keys << @keyfile
auth_methods << "publickey"
end
# :timeout => how long to wait for the initial connection to be made
Net::SSH.start(@host, @user, :password => @password, :timeout => seconds, :host_key => 'ssh_rsa',
:auth_methods => auth_methods, :keys => keys,
:number_of_password_prompts => 0) do |session|
puts "Forwarding #{port} #{remote_ip} #{port}"
session.forward.local(port, remote_ip, port)
session.loop { true }
end
rescue => e
stringio_write(stringio, e.message)
end
}
sleep 1
begin
url = "http://#{local_ip}:#{port}"
stringio_write(stringio, "Testing #{url}")
res = Net::HTTP.get_response(URI(url))
stringio_write(stringio, res.body)
stringio_write(stringio, "Port #{port} is open")
t.kill
true
rescue => e
stringio_write(stringio, e.message)
stringio_write(stringio, e.backtrace)
stringio_write(stringio, "Port #{port} is closed")
t.kill
false
end
end
def call_complete
@on_complete.call if @on_complete
end
def on_complete(hook)
@on_complete = hook
end
def call_failure
@on_failure.call if @on_failure
end
def on_failure(hook)
@on_failure = hook
end
def execute(commands, stringio = nil)
begin
keys = []
auth_methods = ["password"]
if @keyfile
keys << @keyfile
auth_methods << "publickey"
end
# :timeout => how long to wait for the initial connection to be made
Net::SSH.start(@host, @user, :password => @password, :timeout => 2, :host_key => 'ssh_rsa',
:auth_methods => auth_methods, :keys => keys,
:number_of_password_prompts => 0, :paranoid => false) do |ssh|
# open a new channel and configure a minimal set of callbacks, then run
# the event loop until the channel finishes (closes)
channel = ssh.open_channel do |ch|
ch.request_pty do |ch, success|
if !success
puts "Error: could not obtain pty"
call_failure
call_complete
end
end
ch.exec commands do |ch, success|
call_failure unless success
# "on_data" is called when the process writes something to stdout
ch.on_data do |c, data|
stringio_write(stringio, data)
end
# "on_extended_data" is called when the process writes something to stderr
ch.on_extended_data do |c, type, data|
$stderr.print data if stringio.nil?
stringio_write(stringio, data)
call_failure
end
ch.on_close { call_complete }
end
end
channel.wait
end
rescue Exception => e
puts e.message
puts e.backtrace.inspect
stringio_write(stringio, e.message)
call_failure
call_complete
e.message if stringio.nil?
end
end
end
end
end