summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael DeHaan <michael@ansibleworks.com>2013-07-04 16:03:17 -0400
committerMichael DeHaan <michael@ansibleworks.com>2013-07-04 21:31:14 -0400
commit8cc2f1c4a99d4a9967dac9e6d56e9548991946a1 (patch)
treee1a74a1217b08e40222514a841cd2e1ac895bbe7
parent9f9373ccb54c3bcc7e5ee4569c1d6a32ab6d9e05 (diff)
downloadansible-8cc2f1c4a99d4a9967dac9e6d56e9548991946a1.tar.gz
Lock around SSH connectivity to new hosts in host checking mode such that prompts for host approval
messages do not get interlaced.
-rw-r--r--lib/ansible/runner/connection_plugins/ssh.py32
1 files changed, 32 insertions, 0 deletions
diff --git a/lib/ansible/runner/connection_plugins/ssh.py b/lib/ansible/runner/connection_plugins/ssh.py
index 3a00e97b2f..ab65e0999a 100644
--- a/lib/ansible/runner/connection_plugins/ssh.py
+++ b/lib/ansible/runner/connection_plugins/ssh.py
@@ -93,6 +93,22 @@ class Connection(object):
os.write(self.wfd, "%s\n" % self.password)
os.close(self.wfd)
+ def not_in_host_file(self, host):
+ host_file = os.path.expanduser("~/.ssh/known_hosts")
+ if not os.path.exists(host_file):
+ print "previous known host file not found"
+ return True
+ host_fh = open(host_file)
+ data = host_fh.read()
+ host_fh.close()
+ for line in data.split("\n"):
+ if line is None or line.find(" ") == -1:
+ continue
+ tokens = line.split()
+ if host in tokens[0]:
+ return False
+ return True
+
def exec_command(self, cmd, tmp_path, sudo_user,sudoable=False, executable='/bin/sh'):
''' run a command on the remote host '''
@@ -109,6 +125,16 @@ class Connection(object):
ssh_cmd.append(sudocmd)
vvv("EXEC %s" % ssh_cmd, host=self.host)
+
+ not_in_host_file = self.not_in_host_file(self.host)
+
+ if C.HOST_KEY_CHECKING and not_in_host_file:
+ # lock around the initial SSH connectivity so the user prompt about whether to add
+ # the host to known hosts is not intermingled with multiprocess output.
+ KEY_LOCK = self.runner.lockfile
+ fcntl.lockf(KEY_LOCK, fcntl.LOCK_EX)
+
+
try:
# Make sure stdin is a proper (pseudo) pty to avoid: tcgetattr errors
import pty
@@ -161,6 +187,12 @@ class Connection(object):
elif p.poll() is not None:
break
stdin.close() # close stdin after we read from stdout (see also issue #848)
+
+ if C.HOST_KEY_CHECKING and not_in_host_file:
+ # lock around the initial SSH connectivity so the user prompt about whether to add
+ # the host to known hosts is not intermingled with multiprocess output.
+ KEY_LOCK = self.runner.lockfile
+ fcntl.lockf(KEY_LOCK, fcntl.LOCK_EX)
if p.returncode != 0 and stderr.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')