From 63f1673909e7aad4822a80ecdd243a8c6babb488 Mon Sep 17 00:00:00 2001 From: Matthew Hooker Date: Tue, 30 Jan 2018 23:09:12 -0800 Subject: [PATCH 1/2] ssh deadlines --- communicator/ssh/communicator.go | 7 +++++ communicator/ssh/connection.go | 30 +++++++++++++++++++ helper/communicator/config.go | 1 + helper/communicator/step_connect_ssh.go | 1 + .../docs/templates/communicator.html.md | 3 ++ 5 files changed, 42 insertions(+) create mode 100644 communicator/ssh/connection.go diff --git a/communicator/ssh/communicator.go b/communicator/ssh/communicator.go index eabf32aea..17d7cb6b8 100644 --- a/communicator/ssh/communicator.go +++ b/communicator/ssh/communicator.go @@ -59,6 +59,9 @@ type Config struct { // KeepAliveInterval sets how often we send a channel request to the // server. A value < 0 disables. KeepAliveInterval time.Duration + + // Timeout is how long to wait for a read or write to succeed. + Timeout time.Duration } // Creates a new packer.Communicator implementation over SSH. This takes @@ -291,6 +294,10 @@ func (c *comm) reconnect() (err error) { return } + if c.config.Timeout > 0 { + c.conn = &timeoutConn{c.conn, c.config.Timeout, c.config.Timeout} + } + log.Printf("handshaking with SSH") // Default timeout to 1 minute if it wasn't specified (zero value). For diff --git a/communicator/ssh/connection.go b/communicator/ssh/connection.go new file mode 100644 index 000000000..c3df04543 --- /dev/null +++ b/communicator/ssh/connection.go @@ -0,0 +1,30 @@ +package ssh + +import ( + "net" + "time" +) + +// timeoutConn wraps a net.Conn, and sets a deadline for every read +// and write operation. +type timeoutConn struct { + net.Conn + ReadTimeout time.Duration + WriteTimeout time.Duration +} + +func (c *timeoutConn) Read(b []byte) (int, error) { + err := c.Conn.SetReadDeadline(time.Now().Add(c.ReadTimeout)) + if err != nil { + return 0, err + } + return c.Conn.Read(b) +} + +func (c *timeoutConn) Write(b []byte) (int, error) { + err := c.Conn.SetWriteDeadline(time.Now().Add(c.WriteTimeout)) + if err != nil { + return 0, err + } + return c.Conn.Write(b) +} diff --git a/helper/communicator/config.go b/helper/communicator/config.go index 8fe1032cb..f2664b192 100644 --- a/helper/communicator/config.go +++ b/helper/communicator/config.go @@ -38,6 +38,7 @@ type Config struct { SSHProxyUsername string `mapstructure:"ssh_proxy_username"` SSHProxyPassword string `mapstructure:"ssh_proxy_password"` SSHKeepAliveInterval time.Duration `mapstructure:"ssh_keep_alive_interval"` + SSHReadWriteTimeout time.Duration `mapstructure:"ssh_read_write_timeout"` // WinRM WinRMUser string `mapstructure:"winrm_username"` diff --git a/helper/communicator/step_connect_ssh.go b/helper/communicator/step_connect_ssh.go index 192dba739..18fd699c7 100644 --- a/helper/communicator/step_connect_ssh.go +++ b/helper/communicator/step_connect_ssh.go @@ -183,6 +183,7 @@ func (s *StepConnectSSH) waitForSSH(state multistep.StateBag, cancel <-chan stru DisableAgentForwarding: s.Config.SSHDisableAgentForwarding, UseSftp: s.Config.SSHFileTransferMethod == "sftp", KeepAliveInterval: s.Config.SSHKeepAliveInterval, + Timeout: s.Config.SSHReadWriteTimeout, } log.Println("[INFO] Attempting SSH connection...") diff --git a/website/source/docs/templates/communicator.html.md b/website/source/docs/templates/communicator.html.md index 5fbb8a3d5..7b35370b4 100644 --- a/website/source/docs/templates/communicator.html.md +++ b/website/source/docs/templates/communicator.html.md @@ -106,6 +106,9 @@ The SSH communicator has the following options: - `ssh_pty` (boolean) - If true, a PTY will be requested for the SSH connection. This defaults to false. +* `ssh_read_write_timeout` (string) - The amount of time to wait for a remote + command to end. Example: "1h". Disabled by default. + - `ssh_timeout` (string) - The time to wait for SSH to become available. Packer uses this to determine when the machine has booted so this is usually quite long. Example value: "10m" From ff6425fb22a56c7d135b82a03ba8a2a195bfff63 Mon Sep 17 00:00:00 2001 From: Matthew Hooker Date: Wed, 31 Jan 2018 11:48:03 -0800 Subject: [PATCH 2/2] better documentation --- website/source/docs/templates/communicator.html.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/website/source/docs/templates/communicator.html.md b/website/source/docs/templates/communicator.html.md index 7b35370b4..0165ab5a1 100644 --- a/website/source/docs/templates/communicator.html.md +++ b/website/source/docs/templates/communicator.html.md @@ -107,7 +107,8 @@ The SSH communicator has the following options: connection. This defaults to false. * `ssh_read_write_timeout` (string) - The amount of time to wait for a remote - command to end. Example: "1h". Disabled by default. + command to end. This might be useful if, for example, packer hangs on + a connection after a reboot. Example: "5m". Disabled by default. - `ssh_timeout` (string) - The time to wait for SSH to become available. Packer uses this to determine when the machine has booted so this is