diff --git a/lib/portainer_cli.rb b/lib/portainer_cli.rb index 5290e4d..16aedc8 100644 --- a/lib/portainer_cli.rb +++ b/lib/portainer_cli.rb @@ -39,6 +39,7 @@ module PortainerCli HELP def self.run(argv) + debug = argv.delete('--debug') config = Config.load cmd = argv.shift&.downcase @@ -56,11 +57,11 @@ module PortainerCli when 'console' require_config!(config) client = Client.new(config) - Commands::Console.new(config, client).run(argv) + Commands::Console.new(config, client, debug: debug).run(argv) when 'exec', 'shell' require_config!(config) client = Client.new(config) - Commands::Exec.new(config, client).run(argv) + Commands::Exec.new(config, client, debug: debug).run(argv) when 'version', '--version', '-v' puts "portainer-cli #{PortainerCli::VERSION}" when 'help', '--help', '-h', nil diff --git a/lib/portainer_cli/commands/console.rb b/lib/portainer_cli/commands/console.rb index 0e68495..108a6ef 100644 --- a/lib/portainer_cli/commands/console.rb +++ b/lib/portainer_cli/commands/console.rb @@ -13,9 +13,10 @@ module PortainerCli class Console include Base - def initialize(config, client) + def initialize(config, client, debug: false) @config = config @client = client + @debug = debug end def run(args) @@ -42,7 +43,7 @@ module PortainerCli send_resize(endpoint_id, exec_id) if $stdout.tty? trap('SIGWINCH') { send_resize(endpoint_id, exec_id) } if $stdout.tty? - WebsocketExec.new(ws_url, @config.auth_header, ssl_verify: @config.ssl_verify).run + WebsocketExec.new(ws_url, @config.auth_header, ssl_verify: @config.ssl_verify, debug: @debug).run $stderr.puts dim("\r\nSession ended.") rescue PortainerCli::Client::ApiError => e diff --git a/lib/portainer_cli/commands/exec.rb b/lib/portainer_cli/commands/exec.rb index 3fdc554..a63de90 100644 --- a/lib/portainer_cli/commands/exec.rb +++ b/lib/portainer_cli/commands/exec.rb @@ -9,9 +9,10 @@ module PortainerCli class Exec include Base - def initialize(config, client) + def initialize(config, client, debug: false) @config = config @client = client + @debug = debug end # portainer-cli exec [-- cmd args...] @@ -36,7 +37,7 @@ module PortainerCli send_resize(endpoint_id, exec_id) if $stdout.tty? trap('SIGWINCH') { send_resize(endpoint_id, exec_id) } if $stdout.tty? - WebsocketExec.new(ws_url, @config.auth_header, ssl_verify: @config.ssl_verify).run + WebsocketExec.new(ws_url, @config.auth_header, ssl_verify: @config.ssl_verify, debug: @debug).run $stderr.puts dim("\r\nSession ended.") rescue PortainerCli::Client::ApiError => e diff --git a/lib/portainer_cli/websocket_exec.rb b/lib/portainer_cli/websocket_exec.rb index 6aea79d..82d8028 100644 --- a/lib/portainer_cli/websocket_exec.rb +++ b/lib/portainer_cli/websocket_exec.rb @@ -10,17 +10,23 @@ module PortainerCli class WebsocketExec READ_SIZE = 4096 - def initialize(url, auth_header, ssl_verify: true) + def initialize(url, auth_header, ssl_verify: true, debug: false) @url = URI.parse(url) @auth_header = auth_header @ssl_verify = ssl_verify + @debug = debug end def run + debug "WS URL: #{@url}" + debug "Auth headers: #{@auth_header.map { |k, v| "#{k}: #{v[0, 8]}..." }.join(', ')}" + socket = open_socket handshake = perform_handshake(socket) - raise "WebSocket handshake failed: #{handshake.error}" unless handshake.valid? + unless handshake.valid? + raise "WebSocket handshake failed: #{handshake.error}\nServer response:\n#{handshake.instance_variable_get(:@data)}" + end run_io_loop(socket) ensure @@ -50,18 +56,27 @@ module PortainerCli url: @url.to_s, headers: @auth_header ) + debug "Handshake request:\n#{handshake.to_s.chomp}" socket.write(handshake.to_s) + response = +'' loop do byte = socket.read(1) break if byte.nil? + response << byte handshake << byte break if handshake.finished? end + debug "Handshake response:\n#{response.chomp}" handshake end + def debug(msg) + return unless @debug + $stderr.puts "\e[2m[debug] #{msg}\e[0m" + end + def run_io_loop(socket) incoming = WebSocket::Frame::Incoming::Client.new