From 7192eb30477f8987836c075eece6e530eb9b07f2 Mon Sep 17 00:00:00 2001 From: Dag Wieers Date: Fri, 23 Nov 2012 17:52:55 +0100 Subject: [PATCH] Use proper pseudo-tty's instead of pipes when using subprocess This change avoids the "tcgetattr: Invalid argument" error by making sure the ssh we start does have a proper pseudo-tty. We could also check whether our current terminal is a proper terminal (by doing a tcgetattr ourselves) but I don't think this adds anything. This closes #1662 (if all use-cases have been tested: sudo, passwd) --- lib/ansible/runner/connection_plugins/ssh.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/ansible/runner/connection_plugins/ssh.py b/lib/ansible/runner/connection_plugins/ssh.py index b10210d56e3..0d74053c33e 100644 --- a/lib/ansible/runner/connection_plugins/ssh.py +++ b/lib/ansible/runner/connection_plugins/ssh.py @@ -99,8 +99,17 @@ class Connection(object): ssh_cmd.append(cmd) vvv("EXEC %s" % ssh_cmd, host=self.host) - p = subprocess.Popen(ssh_cmd, stdin=subprocess.PIPE, - stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + try: + # Make sure stdin is a proper (pseudo) pty to avoid: tcgetattr errors + import pty + master, slave = pty.openpty() + p = subprocess.Popen(ssh_cmd, stdin=slave, + stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + stdin = os.fdopen(master, 'w', 0) + except: + p = subprocess.Popen(ssh_cmd, stdin=subprocess.PIPE, + stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + stdin = p.stdin self._send_password() @@ -118,7 +127,7 @@ class Connection(object): else: stdout = p.communicate() raise errors.AnsibleError('ssh connection error waiting for sudo password prompt') - p.stdin.write(self.runner.sudo_pass + '\n') + stdin.write(self.runner.sudo_pass + '\n') fcntl.fcntl(p.stdout, fcntl.F_SETFL, fcntl.fcntl(p.stdout, fcntl.F_GETFL) & ~os.O_NONBLOCK) # We can't use p.communicate here because the ControlMaster may have stdout open as well @@ -133,7 +142,7 @@ class Connection(object): break elif p.poll() is not None: break - p.stdin.close() # close stdin after we read from stdout (see also issue #848) + stdin.close() # close stdin after we read from stdout (see also issue #848) if p.returncode != 0 and stdout.find('Bad configuration option: ControlPersist') != -1: raise errors.AnsibleError('using -c ssh on certain older ssh versions may not support ControlPersist, set ANSIBLE_SSH_ARGS="" (or ansible_ssh_args in the config file) before running again')