From a0d3719b52a55c7c1961b6692e53a4b3b6b4ca98 Mon Sep 17 00:00:00 2001 From: Leo Simons Date: Thu, 28 Aug 2014 18:02:27 +0200 Subject: [PATCH 1/2] Scrub SSH PTY output to filter out command echo-ing. --- plugins/communicators/ssh/communicator.rb | 41 +++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/plugins/communicators/ssh/communicator.rb b/plugins/communicators/ssh/communicator.rb index beab115e1..4921ce53e 100644 --- a/plugins/communicators/ssh/communicator.rb +++ b/plugins/communicators/ssh/communicator.rb @@ -401,6 +401,9 @@ module VagrantPlugins return yield connection if block_given? end + DELIM_START = 'UniqueStartStringPTY' + DELIM_END = 'UniqueEndStringPTY' + # Executes the command on an SSH connection within a login shell. def shell_execute(connection, command, **opts) opts = { @@ -421,10 +424,14 @@ module VagrantPlugins shell_cmd = shell if shell shell_cmd = "sudo -E -H #{shell_cmd}" if sudo + use_tty = false + stdout = '' + # Open the channel so we can execute or command channel = connection.open_channel do |ch| if @machine.config.ssh.pty ch.request_pty do |ch2, success| + use_tty = success and command != '' if success @logger.debug("pty obtained for connection") else @@ -439,7 +446,11 @@ module VagrantPlugins # Filter out the clear screen command data = remove_ansi_escape_codes(data) @logger.debug("stdout: #{data}") - yield :stdout, data if block_given? + if use_tty + stdout << data + else + yield :stdout, data if block_given? + end end ch2.on_extended_data do |ch3, type, data| @@ -487,14 +498,29 @@ module VagrantPlugins end # Output the command - ch2.send_data "#{command}\n".force_encoding('ASCII-8BIT') + if use_tty + ch2.send_data "stty raw -echo\n" + ch2.send_data "export PS1=\n" + ch2.send_data "export PS2=\n" + ch2.send_data "export PROMPT_COMMAND=\n" + sleep(0.1) + data = "printf #{DELIM_START}\n" + data += "#{command}\n" + data += "printf #{DELIM_END}\n" + data = data.force_encoding('ASCII-8BIT') + ch2.send_data data + else + ch2.send_data "#{command}\n".force_encoding('ASCII-8BIT') + end # Remember to exit or this channel will hang open ch2.send_data "exit\n" # Send eof to let server know we're done ch2.eof! + ch2.wait end + ch.wait end begin @@ -530,6 +556,17 @@ module VagrantPlugins keep_alive.kill if keep_alive end + if use_tty + @logger.debug("stdout: #{stdout}") + if not stdout.include? DELIM_START or not stdout.include? DELIM_END + @logger.error("Error parsing TTY output") + raise Vagrant::Errors::SSHInvalidShell.new + end + data = stdout[/.*#{DELIM_START}(.*?)#{DELIM_END}/m, 1] + @logger.debug("selected stdout: #{data}") + yield :stdout, data if block_given? + end + # Return the final exit status return exit_status end From 87fb5d11fe0fd342dbb2c581c4085295a1d3a950 Mon Sep 17 00:00:00 2001 From: Leo Simons Date: Fri, 29 Aug 2014 11:48:54 +0200 Subject: [PATCH 2/2] Preserve exit code while using pseudo-terminal hack. --- plugins/communicators/ssh/communicator.rb | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/plugins/communicators/ssh/communicator.rb b/plugins/communicators/ssh/communicator.rb index 4921ce53e..26c4b26e7 100644 --- a/plugins/communicators/ssh/communicator.rb +++ b/plugins/communicators/ssh/communicator.rb @@ -506,16 +506,18 @@ module VagrantPlugins sleep(0.1) data = "printf #{DELIM_START}\n" data += "#{command}\n" + data += "exitcode=$?\n" data += "printf #{DELIM_END}\n" data = data.force_encoding('ASCII-8BIT') ch2.send_data data + # Remember to exit or this channel will hang open + ch2.send_data "exit $exitcode\n" else ch2.send_data "#{command}\n".force_encoding('ASCII-8BIT') + # Remember to exit or this channel will hang open + ch2.send_data "exit\n" end - # Remember to exit or this channel will hang open - ch2.send_data "exit\n" - # Send eof to let server know we're done ch2.eof! ch2.wait @@ -546,6 +548,7 @@ module VagrantPlugins @logger.info( "SSH connection unexpected closed. Assuming reboot or something.") exit_status = 0 + use_tty = false rescue Net::SSH::ChannelOpenFailed raise Vagrant::Errors::SSHChannelOpenFail rescue Net::SSH::Disconnect