Be more explicit about why SSH arguments are added

This adds vvvvv log messages that spell out in detail where each SSH
command-line argument is obtained from.

Unfortunately, we can't be sure if, say, self._play_context.remote_user
is obtained from ANSIBLE_REMOTE_USER in the environment, remote_user in
ansible.cfg, -u on the command line, or an ansible_ssh_user setting in
the inventory or on a task or play. In some cases, e.g. timeout, we
can't even be sure if it was set by the user or just a default.

Nevertheless, on the theory that at five v's you can use all the hints
available, I've mentioned the possible sources in the log messages.

Note that this caveat applies only to the arguments that ssh.py adds by
itself. In the case of ssh_args and ssh_extra_args, we know where they
are from, and say so, though we can't say WHERE in the inventory they
may be set (e.g. in host_vars or group_vars etc.).
This commit is contained in:
Abhijit Menon-Sen 2015-08-13 11:16:42 +05:30
parent b605c285ba
commit 119d032389

View file

@ -73,6 +73,22 @@ class Connection(ConnectionBase):
''' used to identify this connection object from other classes '''
return 'ssh'
def _split_args(self, argstring):
"""
Takes a string like '-o Foo=1 -o Bar="foo bar"' and returns a
list ['-o', 'Foo=1', '-o', 'Bar=foo bar'] that can be added to
the argument list. The list will not contain any empty elements.
"""
return [x.strip() for x in shlex.split(argstring) if x.strip()]
def add_args(self, explanation, args):
"""
Adds the given args to _common_args and displays a
caller-supplied explanation of why they were added.
"""
self._common_args += args
self._display.vvvvv('SSH: ' + explanation + ': (%s)' % ')('.join(args), host=self._play_context.remote_addr)
def _connect(self):
''' connect to the remote host '''
@ -81,16 +97,25 @@ class Connection(ConnectionBase):
if self._connected:
return self
ssh_args = self.ssh_args or C.ANSIBLE_SSH_ARGS
if ssh_args is not None:
# make sure there is no empty string added as this can produce weird errors
self._common_args += [x.strip() for x in shlex.split(ssh_args) if x.strip()]
# We start with ansible_ssh_args from the inventory if it's set,
# or [ssh_connection]ssh_args from ansible.cfg, or the default
# Control* settings.
if self.ssh_args:
args = self._split_args(self.ssh_args)
self.add_args("inventory set ansible_ssh_args", args)
elif C.ANSIBLE_SSH_ARGS:
args = self._split_args(C.ANSIBLE_SSH_ARGS)
self.add_args("ansible.cfg set ssh_args", args)
else:
self._common_args += (
args = (
"-o", "ControlMaster=auto",
"-o", "ControlPersist=60s",
"-o", "ControlPath=\"{0}\"".format(C.ANSIBLE_SSH_CONTROL_PATH % dict(directory=self._cp_dir)),
"-o", "ControlPersist=60s"
)
self.add_args("default arguments", args)
# If any of the above have set ControlPersist but not a
# ControlPath, add one ourselves.
cp_in_use = False
cp_path_set = False
@ -101,34 +126,68 @@ class Connection(ConnectionBase):
cp_path_set = True
if cp_in_use and not cp_path_set:
self._common_args += ("-o", "ControlPath=\"{0}\"".format(
args = ("-o", "ControlPath=\"{0}\"".format(
C.ANSIBLE_SSH_CONTROL_PATH % dict(directory=self._cp_dir))
)
self.add_args("found only ControlPersist; added ControlPath", args)
if not C.HOST_KEY_CHECKING:
self._common_args += ("-o", "StrictHostKeyChecking=no")
self.add_args(
"ANSIBLE_HOST_KEY_CHECKING/host_key_checking disabled",
("-o", "StrictHostKeyChecking=no")
)
if self._play_context.port is not None:
self._common_args += ("-o", "Port={0}".format(self._play_context.port))
if self._play_context.private_key_file is not None:
self._common_args += ("-o", "IdentityFile=\"{0}\"".format(os.path.expanduser(self._play_context.private_key_file)))
self.add_args(
"ANSIBLE_REMOTE_PORT/remote_port/ansible_ssh_port set",
("-o", "Port={0}".format(self._play_context.port))
)
key = self._play_context.private_key_file
if key:
self.add_args(
"ANSIBLE_PRIVATE_KEY_FILE/private_key_file/ansible_ssh_private_key_file set",
("-o", "IdentityFile=\"{0}\"".format(os.path.expanduser(key)))
)
if self._play_context.password:
self._common_args += ("-o", "GSSAPIAuthentication=no",
"-o", "PubkeyAuthentication=no")
self.add_args(
"ansible_password/ansible_ssh_pass set", (
"-o", "GSSAPIAuthentication=no",
"-o", "PubkeyAuthentication=no"
)
)
else:
self._common_args += ("-o", "KbdInteractiveAuthentication=no",
"-o", "PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey",
"-o", "PasswordAuthentication=no")
if self._play_context.remote_user is not None and self._play_context.remote_user != pwd.getpwuid(os.geteuid())[0]:
self._common_args += ("-o", "User={0}".format(self._play_context.remote_user))
self._common_args += ("-o", "ConnectTimeout={0}".format(self._play_context.timeout))
self.add_args(
"ansible_password/ansible_ssh_pass not set", (
"-o", "KbdInteractiveAuthentication=no",
"-o", "PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey",
"-o", "PasswordAuthentication=no"
)
)
user = self._play_context.remote_user
if user and user != pwd.getpwuid(os.geteuid())[0]:
self.add_args(
"ANSIBLE_REMOTE_USER/remote_user/ansible_ssh_user/user/-u set",
("-o", "User={0}".format(self._play_context.remote_user))
)
self.add_args(
"ANSIBLE_TIMEOUT/timeout set",
("-o", "ConnectTimeout={0}".format(self._play_context.timeout))
)
# If any extra SSH arguments are specified in the inventory for
# this host, or specified as an override on the command line,
# add them in.
extra_args = self._play_context.ssh_extra_args or self.ssh_extra_args
if extra_args is not None:
self._common_args += [x.strip() for x in shlex.split(extra_args) if x.strip()]
if self._play_context.ssh_extra_args:
args = self._split_args(self._play_context.ssh_extra_args)
self.add_args("command-line added --ssh-extra-args", args)
elif self.ssh_extra_args:
args = self._split_args(self.ssh_extra_args)
self.add_args("inventory added ansible_ssh_extra_args", args)
self._connected = True