class Proxy::RemoteExecution::Cockpit::Session
Public Class Methods
new(env)
click to toggle source
# File lib/smart_proxy_remote_execution_ssh/cockpit.rb, line 114 def initialize(env) @env = env end
Public Instance Methods
hijack!()
click to toggle source
# File lib/smart_proxy_remote_execution_ssh/cockpit.rb, line 122 def hijack! @socket = nil if @env['ext.hijack!'] @socket = @env['ext.hijack!'].call elsif @env['rack.hijack?'] begin @env['rack.hijack'].call rescue NotImplementedError end @socket = @env['rack.hijack_io'] end raise 'Internal error: request hijacking not available' unless @socket ssh_on_socket end
valid?()
click to toggle source
# File lib/smart_proxy_remote_execution_ssh/cockpit.rb, line 118 def valid? @env["HTTP_CONNECTION"] == "upgrade" && @env["HTTP_UPGRADE"].to_s.split(',').any? { |part| part.strip == "raw" } end
Private Instance Methods
buf_socket()
click to toggle source
# File lib/smart_proxy_remote_execution_ssh/cockpit.rb, line 236 def buf_socket @buffered_socket ||= BufferedSocket.build(@socket) end
command()
click to toggle source
# File lib/smart_proxy_remote_execution_ssh/cockpit.rb, line 240 def command params["command"] end
host()
click to toggle source
# File lib/smart_proxy_remote_execution_ssh/cockpit.rb, line 248 def host params["hostname"] end
key_file()
click to toggle source
# File lib/smart_proxy_remote_execution_ssh/cockpit.rb, line 232 def key_file @key_file ||= Proxy::RemoteExecution::Ssh.private_key_file end
params()
click to toggle source
# File lib/smart_proxy_remote_execution_ssh/cockpit.rb, line 228 def params @params ||= MultiJson.load(@env["rack.input"].read) end
send_error(code, msg)
click to toggle source
# File lib/smart_proxy_remote_execution_ssh/cockpit.rb, line 221 def send_error(code, msg) buf_socket.enqueue("Status: #{code}\r\n") buf_socket.enqueue("Connection: close\r\n") buf_socket.enqueue("\r\n") buf_socket.enqueue(msg) end
send_start()
click to toggle source
# File lib/smart_proxy_remote_execution_ssh/cockpit.rb, line 211 def send_start unless @started @started = true buf_socket.enqueue("Status: 101\r\n") buf_socket.enqueue("Connection: upgrade\r\n") buf_socket.enqueue("Upgrade: raw\r\n") buf_socket.enqueue("\r\n") end end
ssh_on_socket()
click to toggle source
# File lib/smart_proxy_remote_execution_ssh/cockpit.rb, line 139 def ssh_on_socket with_error_handling { start_ssh_loop } end
ssh_options()
click to toggle source
# File lib/smart_proxy_remote_execution_ssh/cockpit.rb, line 252 def ssh_options auth_methods = %w[publickey] auth_methods.unshift('password') if params["ssh_password"] ret = {} ret[:port] = params["ssh_port"] if params["ssh_port"] ret[:keys] = [key_file] if key_file ret[:password] = params["ssh_password"] if params["ssh_password"] ret[:passphrase] = params[:ssh_key_passphrase] if params[:ssh_key_passphrase] ret[:keys_only] = true ret[:auth_methods] = auth_methods ret[:verify_host_key] = true ret[:number_of_password_prompts] = 1 ret end
ssh_user()
click to toggle source
# File lib/smart_proxy_remote_execution_ssh/cockpit.rb, line 244 def ssh_user params["ssh_user"] end
start_ssh_loop()
click to toggle source
# File lib/smart_proxy_remote_execution_ssh/cockpit.rb, line 164 def start_ssh_loop err_buf = "" Net::SSH.start(host, ssh_user, ssh_options) do |ssh| channel = ssh.open_channel do |ch| ch.exec(command) do |ch, success| raise "could not execute command" unless success ssh.listen_to(buf_socket) ch.on_process do if buf_socket.available.positive? ch.send_data(buf_socket.read_available) end if buf_socket.closed? ch.close end end ch.on_data do |ch2, data| send_start buf_socket.enqueue(data) end ch.on_request('exit-status') do |ch, data| code = data.read_long send_start if code.zero? err_buf += "Process exited with code #{code}.\r\n" ch.close end ch.on_request('exit-signal') do |ch, data| err_buf += "Process was terminated with signal #{data.read_string}.\r\n" ch.close end ch.on_extended_data do |ch2, type, data| err_buf += data end end end channel.wait send_error(400, err_buf) unless @started end end
with_error_handling() { || ... }
click to toggle source
# File lib/smart_proxy_remote_execution_ssh/cockpit.rb, line 143 def with_error_handling yield rescue Net::SSH::AuthenticationFailed => e send_error(401, e.message) rescue Errno::EHOSTUNREACH send_error(400, "No route to #{host}") rescue SystemCallError => e send_error(400, e.message) rescue SocketError => e send_error(400, e.message) rescue Exception => e logger.error e.message logger.debug e.backtrace.join("\n") send_error(500, "Internal error") unless @started ensure unless buf_socket.closed? buf_socket.wait_for_pending_sends buf_socket.close end end