Browse code

ANSIBLE_SSH_USETTY configuration option (#33148)

* Allow the user to circumvent adding -tt on ssh commands to help aid in
debugging ssh related problems.
* Move config to the plugin
* Set version_added
* Change yaml section to "connection"
* Fix ssh unit tests

jctanner authored on 2017/11/23 01:19:43
Showing 3 changed files
... ...
@@ -401,6 +401,10 @@
401 401
 # only be disabled if your sftp version has problems with batch mode
402 402
 #sftp_batch_mode = False
403 403
 
404
+# The -tt argument is passed to ssh when pipelining is not enabled because sudo 
405
+# requires a tty by default. 
406
+#use_tty = True
407
+
404 408
 [persistent_connection]
405 409
 
406 410
 # Configures the persistent connection timeout value in seconds.  This value is
... ...
@@ -185,6 +185,15 @@ DOCUMENTATION = '''
185 185
         env: [{name: ANSIBLE_SCP_IF_SSH}]
186 186
         ini:
187 187
         - {key: scp_if_ssh, section: ssh_connection}
188
+      use_tty:
189
+        version_added: '2.5'
190
+        default: True
191
+        description: add -tt to ssh commands to force tty allocation
192
+        env: [{name: ANSIBLE_SSH_USETTY}]
193
+        ini:
194
+        - {key: usetty, section: ssh_connection}
195
+        type: boolean
196
+        yaml: {key: connection.usetty}
188 197
 '''
189 198
 
190 199
 import errno
... ...
@@ -957,7 +966,11 @@ class Connection(ConnectionBase):
957 957
 
958 958
         ssh_executable = self._play_context.ssh_executable
959 959
 
960
-        if not in_data and sudoable:
960
+        # -tt can cause various issues in some environments so allow the user
961
+        # to disable it as a troubleshooting method.
962
+        use_tty = self.get_option('use_tty')
963
+
964
+        if not in_data and sudoable and use_tty:
961 965
             args = (ssh_executable, '-tt', self.host, cmd)
962 966
         else:
963 967
             args = (ssh_executable, self.host, cmd)
... ...
@@ -80,6 +80,8 @@ class TestConnectionBaseClass(unittest.TestCase):
80 80
         conn._build_command.return_value = 'ssh something something'
81 81
         conn._run = MagicMock()
82 82
         conn._run.return_value = (0, 'stdout', 'stderr')
83
+        conn.get_option = MagicMock()
84
+        conn.get_option.return_value = True
83 85
 
84 86
         res, stdout, stderr = conn.exec_command('ssh')
85 87
         res, stdout, stderr = conn.exec_command('ssh', 'this is some data')
... ...
@@ -538,6 +540,8 @@ class TestSSHConnectionRetries(object):
538 538
 
539 539
         self.conn._build_command = MagicMock()
540 540
         self.conn._build_command.return_value = 'ssh'
541
+        self.conn.get_option = MagicMock()
542
+        self.conn.get_option.return_value = True
541 543
 
542 544
         return_code, b_stdout, b_stderr = self.conn.exec_command('ssh', 'some data')
543 545
         assert return_code == 0
... ...
@@ -563,6 +567,8 @@ class TestSSHConnectionRetries(object):
563 563
 
564 564
         self.conn._build_command = MagicMock()
565 565
         self.conn._build_command.return_value = 'ssh'
566
+        self.conn.get_option = MagicMock()
567
+        self.conn.get_option.return_value = True
566 568
 
567 569
         pytest.raises(AnsibleConnectionFailure, self.conn.exec_command, 'ssh', 'some data')
568 570
         assert self.mock_popen.call_count == 10
... ...
@@ -575,6 +581,8 @@ class TestSSHConnectionRetries(object):
575 575
 
576 576
         self.conn._build_command = MagicMock()
577 577
         self.conn._build_command.return_value = 'ssh'
578
+        self.conn.get_option = MagicMock()
579
+        self.conn.get_option.return_value = True
578 580
 
579 581
         self.mock_popen.side_effect = [Exception('bad')] * 10
580 582
         pytest.raises(Exception, self.conn.exec_command, 'ssh', 'some data')