communicators/ssh: cleanup PTY code for GH-4408]
This commit is contained in:
parent
a9be7ce224
commit
138aa5aad3
|
@ -45,6 +45,8 @@ BUG FIXES:
|
||||||
- commands/rsync-auto: Destroyed machines won't raise exceptions. [GH-4031]
|
- commands/rsync-auto: Destroyed machines won't raise exceptions. [GH-4031]
|
||||||
- communicators/ssh: Nicer error if remote unexpectedly disconects. [GH-4038]
|
- communicators/ssh: Nicer error if remote unexpectedly disconects. [GH-4038]
|
||||||
- communicators/ssh: Clean error when max sessions is hit. [GH-4044]
|
- communicators/ssh: Clean error when max sessions is hit. [GH-4044]
|
||||||
|
- communicators/ssh: Fix many issues around PTY-enabled output parsing.
|
||||||
|
[GH-4408]
|
||||||
- communicators/winrm: Support `mkdir` [GH-4271]
|
- communicators/winrm: Support `mkdir` [GH-4271]
|
||||||
- communicators/winrm: Properly escape double quotes. [GH-4309]
|
- communicators/winrm: Properly escape double quotes. [GH-4309]
|
||||||
- guests/centos: Fix issues when NFS client is installed by restarting
|
- guests/centos: Fix issues when NFS client is installed by restarting
|
||||||
|
|
|
@ -19,6 +19,9 @@ module VagrantPlugins
|
||||||
module CommunicatorSSH
|
module CommunicatorSSH
|
||||||
# This class provides communication with the VM via SSH.
|
# This class provides communication with the VM via SSH.
|
||||||
class Communicator < Vagrant.plugin("2", :communicator)
|
class Communicator < Vagrant.plugin("2", :communicator)
|
||||||
|
PTY_DELIM_START = "bccbb768c119429488cfd109aacea6b5-pty"
|
||||||
|
PTY_DELIM_END = "bccbb768c119429488cfd109aacea6b5-pty"
|
||||||
|
|
||||||
include Vagrant::Util::ANSIEscapeCodeRemover
|
include Vagrant::Util::ANSIEscapeCodeRemover
|
||||||
include Vagrant::Util::Retryable
|
include Vagrant::Util::Retryable
|
||||||
|
|
||||||
|
@ -401,9 +404,6 @@ module VagrantPlugins
|
||||||
return yield connection if block_given?
|
return yield connection if block_given?
|
||||||
end
|
end
|
||||||
|
|
||||||
DELIM_START = 'UniqueStartStringPTY'
|
|
||||||
DELIM_END = 'UniqueEndStringPTY'
|
|
||||||
|
|
||||||
# Executes the command on an SSH connection within a login shell.
|
# Executes the command on an SSH connection within a login shell.
|
||||||
def shell_execute(connection, command, **opts)
|
def shell_execute(connection, command, **opts)
|
||||||
opts = {
|
opts = {
|
||||||
|
@ -424,14 +424,16 @@ module VagrantPlugins
|
||||||
shell_cmd = shell if shell
|
shell_cmd = shell if shell
|
||||||
shell_cmd = "sudo -E -H #{shell_cmd}" if sudo
|
shell_cmd = "sudo -E -H #{shell_cmd}" if sudo
|
||||||
|
|
||||||
use_tty = false
|
# These variables are used to scrub PTY output if we're in a PTY
|
||||||
stdout = ''
|
pty = false
|
||||||
|
pty_stdout = ""
|
||||||
|
|
||||||
# Open the channel so we can execute or command
|
# Open the channel so we can execute or command
|
||||||
channel = connection.open_channel do |ch|
|
channel = connection.open_channel do |ch|
|
||||||
if @machine.config.ssh.pty
|
if @machine.config.ssh.pty
|
||||||
ch.request_pty do |ch2, success|
|
ch.request_pty do |ch2, success|
|
||||||
use_tty = success and command != ''
|
pty = success && command != ""
|
||||||
|
|
||||||
if success
|
if success
|
||||||
@logger.debug("pty obtained for connection")
|
@logger.debug("pty obtained for connection")
|
||||||
else
|
else
|
||||||
|
@ -446,8 +448,8 @@ module VagrantPlugins
|
||||||
# Filter out the clear screen command
|
# Filter out the clear screen command
|
||||||
data = remove_ansi_escape_codes(data)
|
data = remove_ansi_escape_codes(data)
|
||||||
@logger.debug("stdout: #{data}")
|
@logger.debug("stdout: #{data}")
|
||||||
if use_tty
|
if pty
|
||||||
stdout << data
|
pty_stdout << data
|
||||||
else
|
else
|
||||||
yield :stdout, data if block_given?
|
yield :stdout, data if block_given?
|
||||||
end
|
end
|
||||||
|
@ -497,21 +499,21 @@ module VagrantPlugins
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Output the command
|
# Output the command. If we're using a pty we have to do
|
||||||
if use_tty
|
# a little dance to make sure we get all the output properly
|
||||||
ch2.send_data "stty raw -echo\n"
|
# without the cruft added from pty mode.
|
||||||
ch2.send_data "export PS1=\n"
|
if pty
|
||||||
ch2.send_data "export PS2=\n"
|
data = "stty raw -echo\n"
|
||||||
ch2.send_data "export PROMPT_COMMAND=\n"
|
data += "export PS1=\n"
|
||||||
sleep(0.1)
|
data += "export PS2=\n"
|
||||||
data = "printf #{DELIM_START}\n"
|
data += "export PROMPT_COMMAND=\n"
|
||||||
|
data += "printf #{PTY_DELIM_START}\n"
|
||||||
data += "#{command}\n"
|
data += "#{command}\n"
|
||||||
data += "exitcode=$?\n"
|
data += "exitcode=$?\n"
|
||||||
data += "printf #{DELIM_END}\n"
|
data += "printf #{PTY_DELIM_END}\n"
|
||||||
|
data += "exit $exitcode\n"
|
||||||
data = data.force_encoding('ASCII-8BIT')
|
data = data.force_encoding('ASCII-8BIT')
|
||||||
ch2.send_data data
|
ch2.send_data data
|
||||||
# Remember to exit or this channel will hang open
|
|
||||||
ch2.send_data "exit $exitcode\n"
|
|
||||||
else
|
else
|
||||||
ch2.send_data "#{command}\n".force_encoding('ASCII-8BIT')
|
ch2.send_data "#{command}\n".force_encoding('ASCII-8BIT')
|
||||||
# Remember to exit or this channel will hang open
|
# Remember to exit or this channel will hang open
|
||||||
|
@ -520,9 +522,7 @@ module VagrantPlugins
|
||||||
|
|
||||||
# Send eof to let server know we're done
|
# Send eof to let server know we're done
|
||||||
ch2.eof!
|
ch2.eof!
|
||||||
ch2.wait
|
|
||||||
end
|
end
|
||||||
ch.wait
|
|
||||||
end
|
end
|
||||||
|
|
||||||
begin
|
begin
|
||||||
|
@ -548,7 +548,7 @@ module VagrantPlugins
|
||||||
@logger.info(
|
@logger.info(
|
||||||
"SSH connection unexpected closed. Assuming reboot or something.")
|
"SSH connection unexpected closed. Assuming reboot or something.")
|
||||||
exit_status = 0
|
exit_status = 0
|
||||||
use_tty = false
|
pty = false
|
||||||
rescue Net::SSH::ChannelOpenFailed
|
rescue Net::SSH::ChannelOpenFailed
|
||||||
raise Vagrant::Errors::SSHChannelOpenFail
|
raise Vagrant::Errors::SSHChannelOpenFail
|
||||||
rescue Net::SSH::Disconnect
|
rescue Net::SSH::Disconnect
|
||||||
|
@ -559,14 +559,16 @@ module VagrantPlugins
|
||||||
keep_alive.kill if keep_alive
|
keep_alive.kill if keep_alive
|
||||||
end
|
end
|
||||||
|
|
||||||
if use_tty
|
# If we're in a PTY, we now finally parse the output
|
||||||
@logger.debug("stdout: #{stdout}")
|
if pty
|
||||||
if not stdout.include? DELIM_START or not stdout.include? DELIM_END
|
@logger.debug("PTY stdout: #{pty_stdout}")
|
||||||
@logger.error("Error parsing TTY output")
|
if !pty_stdout.include?(PTY_DELIM_START) || !pty_stdout.include?(PTY_DELIM_END)
|
||||||
|
@logger.error("PTY stdout doesn't include delims")
|
||||||
raise Vagrant::Errors::SSHInvalidShell.new
|
raise Vagrant::Errors::SSHInvalidShell.new
|
||||||
end
|
end
|
||||||
data = stdout[/.*#{DELIM_START}(.*?)#{DELIM_END}/m, 1]
|
|
||||||
@logger.debug("selected stdout: #{data}")
|
data = stdout[/.*#{PTY_DELIM_START}(.*?)#{PTY_DELIM_END}/m, 1]
|
||||||
|
@logger.debug("PTY stdout parsed: #{data}")
|
||||||
yield :stdout, data if block_given?
|
yield :stdout, data if block_given?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue