From 3ad9b4cba62707777c3a144677e12ccd913c79a8 Mon Sep 17 00:00:00 2001 From: Abhijit Menon-Sen Date: Fri, 2 Oct 2015 11:57:47 +0530 Subject: [PATCH 1/6] Rework additional ssh argument handling Now we have the following ways to set additional arguments: 1. [ssh_connection]ssh_args in ansible.cfg: global setting, prepended to every command line for ssh/scp/sftp. Overrides default ControlPersist settings. 2. ansible_ssh_common_args inventory variable. Appended to every command line for ssh/scp/sftp. Used in addition to ssh_args, if set above, or the default settings. 3. ansible_{sftp,scp,ssh}_extra_args inventory variables. Appended to every command line for the relevant binary only. Used in addition to #1 and #2, if set above, or the default settings. 3. Using the --ssh-common-args or --{sftp,scp,ssh}-extra-args command line options (which are overriden by #2 and #3 above). This preserves backwards compatibility (for ssh_args in ansible.cfg), but also permits global settings (e.g. ProxyCommand via _common_args) or ssh-specific options (e.g. -R via ssh_extra_args). Fixes #12576 --- docs/man/man1/ansible-playbook.1.asciidoc.in | 19 +++++-- docs/man/man1/ansible-pull.1.asciidoc.in | 19 +++++-- docs/man/man1/ansible.1.asciidoc.in | 19 +++++-- docsite/rst/intro_inventory.rst | 13 +++-- lib/ansible/cli/__init__.py | 8 ++- lib/ansible/playbook/play_context.py | 6 +++ lib/ansible/plugins/connection/ssh.py | 57 ++++++++++---------- 7 files changed, 100 insertions(+), 41 deletions(-) diff --git a/docs/man/man1/ansible-playbook.1.asciidoc.in b/docs/man/man1/ansible-playbook.1.asciidoc.in index 2a1a94c5cd..356ad545e6 100644 --- a/docs/man/man1/ansible-playbook.1.asciidoc.in +++ b/docs/man/man1/ansible-playbook.1.asciidoc.in @@ -151,10 +151,23 @@ run operations with su as this user (default=root) Run operations with sudo (nopasswd) (deprecated, use become) -*--ssh-extra-args=*''-o ProxyCommand="ssh -W %h:%p ..." ...'':: +*--ssh-common-args=*''-o ProxyCommand="ssh -W %h:%p ..." ...'':: -Add the specified arguments to any ssh command-line. Useful to set a -ProxyCommand to use a jump host, but any arguments may be specified. +Add the specified arguments to any sftp/scp/ssh command-line. Useful to +set a ProxyCommand to use a jump host, but any arguments that are +accepted by all three programs may be specified. + +*--sftp-extra-args=*''-f ...'':: + +Add the specified arguments to any sftp command-line. + +*--scp-extra-args=*''-l ...'':: + +Add the specified arguments to any scp command-line. + +*--ssh-extra-args=*''-R ...'':: + +Add the specified arguments to any ssh command-line. *-U*, 'SUDO_USER', *--sudo-user=*'SUDO_USER':: diff --git a/docs/man/man1/ansible-pull.1.asciidoc.in b/docs/man/man1/ansible-pull.1.asciidoc.in index 520a60bf21..c0a5ab9ed2 100644 --- a/docs/man/man1/ansible-pull.1.asciidoc.in +++ b/docs/man/man1/ansible-pull.1.asciidoc.in @@ -105,10 +105,23 @@ Purge the checkout after the playbook is run. Sleep for random interval (between 0 and SLEEP number of seconds) before starting. This is a useful way ot disperse git requests. -*--ssh-extra-args=*''-o ProxyCommand="ssh -W %h:%p ..." ...'':: +*--ssh-common-args=*''-o ProxyCommand="ssh -W %h:%p ..." ...'':: -Add the specified arguments to any ssh command-line. Useful to set a -ProxyCommand to use a jump host, but any arguments may be specified. +Add the specified arguments to any sftp/scp/ssh command-line. Useful to +set a ProxyCommand to use a jump host, but any arguments that are +accepted by all three programs may be specified. + +*--sftp-extra-args=*''-f ...'':: + +Add the specified arguments to any sftp command-line. + +*--scp-extra-args=*''-l ...'':: + +Add the specified arguments to any scp command-line. + +*--ssh-extra-args=*''-R ...'':: + +Add the specified arguments to any ssh command-line. *-t* 'TAGS', *--tags=*'TAGS':: diff --git a/docs/man/man1/ansible.1.asciidoc.in b/docs/man/man1/ansible.1.asciidoc.in index 7578e8f8be..07172ffd9b 100644 --- a/docs/man/man1/ansible.1.asciidoc.in +++ b/docs/man/man1/ansible.1.asciidoc.in @@ -143,10 +143,23 @@ Run operations with su as this user (default=root) Run the command as the user given by -u and sudo to root. -*--ssh-extra-args=*''-o ProxyCommand="ssh -W %h:%p ..." ...'':: +*--ssh-common-args=*''-o ProxyCommand="ssh -W %h:%p ..." ...'':: -Add the specified arguments to any ssh command-line. Useful to set a -ProxyCommand to use a jump host, but any arguments may be specified. +Add the specified arguments to any sftp/scp/ssh command-line. Useful to +set a ProxyCommand to use a jump host, but any arguments that are +accepted by all three programs may be specified. + +*--sftp-extra-args=*''-f ...'':: + +Add the specified arguments to any sftp command-line. + +*--scp-extra-args=*''-l ...'':: + +Add the specified arguments to any scp command-line. + +*--ssh-extra-args=*''-R ...'':: + +Add the specified arguments to any ssh command-line. *-U* 'SUDO_USERNAME', *--sudo-user=*'SUDO_USERNAME':: diff --git a/docsite/rst/intro_inventory.rst b/docsite/rst/intro_inventory.rst index 353aebe794..d3ac8cfa18 100644 --- a/docsite/rst/intro_inventory.rst +++ b/docsite/rst/intro_inventory.rst @@ -212,11 +212,16 @@ SSH connection:: The ssh password to use (this is insecure, we strongly recommend using --ask-pass or SSH keys) ansible_ssh_private_key_file Private key file used by ssh. Useful if using multiple keys and you don't want to use SSH agent. - ansible_ssh_args - This setting overrides any ``ssh_args`` configured in ``ansible.cfg``. + ansible_ssh_common_args + This setting is always appended to the default command line for + sftp, scp, and ssh. Useful to configure a ``ProxyCommand`` for a + certain host (or group). + ansible_sftp_extra_args + This setting is always appended to the default sftp command line. + ansible_scp_extra_args + This setting is always appended to the default scp command line. ansible_ssh_extra_args - Additional arguments for ssh. Useful to configure a ``ProxyCommand`` for a certain host (or group). - This is used in addition to any ``ssh_args`` configured in ``ansible.cfg`` or the inventory. + This setting is always appended to the default ssh command line. ansible_ssh_pipelining Determines whether or not to use SSH pipelining. This can override the ``pipelining`` setting in ``ansible.cfg``. diff --git a/lib/ansible/cli/__init__.py b/lib/ansible/cli/__init__.py index 5aeef380db..a3d128f911 100644 --- a/lib/ansible/cli/__init__.py +++ b/lib/ansible/cli/__init__.py @@ -314,8 +314,14 @@ class CLI(object): help="connection type to use (default=%s)" % C.DEFAULT_TRANSPORT) parser.add_option('-T', '--timeout', default=C.DEFAULT_TIMEOUT, type='int', dest='timeout', help="override the connection timeout in seconds (default=%s)" % C.DEFAULT_TIMEOUT) + parser.add_option('--ssh-common-args', default='', dest='ssh_common_args', + help="specify common arguments to pass to sftp/scp/ssh (e.g. ProxyCommand)") + parser.add_option('--sftp-extra-args', default='', dest='sftp_extra_args', + help="specify extra arguments to pass to sftp only (e.g. -f, -l)") + parser.add_option('--scp-extra-args', default='', dest='scp_extra_args', + help="specify extra arguments to pass to scp only (e.g. -l)") parser.add_option('--ssh-extra-args', default='', dest='ssh_extra_args', - help="specify extra arguments to pass to ssh (e.g. ProxyCommand)") + help="specify extra arguments to pass to ssh only (e.g. -R)") if async_opts: parser.add_option('-P', '--poll', default=C.DEFAULT_POLL_INTERVAL, type='int', dest='poll_interval', diff --git a/lib/ansible/playbook/play_context.py b/lib/ansible/playbook/play_context.py index dfccf7345b..9cadcf9a76 100644 --- a/lib/ansible/playbook/play_context.py +++ b/lib/ansible/playbook/play_context.py @@ -140,6 +140,9 @@ class PlayContext(Base): _private_key_file = FieldAttribute(isa='string', default=C.DEFAULT_PRIVATE_KEY_FILE) _timeout = FieldAttribute(isa='int', default=C.DEFAULT_TIMEOUT) _shell = FieldAttribute(isa='string') + _ssh_common_args = FieldAttribute(isa='string') + _sftp_extra_args = FieldAttribute(isa='string') + _scp_extra_args = FieldAttribute(isa='string') _ssh_extra_args = FieldAttribute(isa='string') _connection_lockfd= FieldAttribute(isa='int') _pipelining = FieldAttribute(isa='bool', default=C.ANSIBLE_SSH_PIPELINING) @@ -240,6 +243,9 @@ class PlayContext(Base): self.remote_user = options.remote_user self.private_key_file = options.private_key_file + self.ssh_common_args = options.ssh_common_args + self.sftp_extra_args = options.sftp_extra_args + self.scp_extra_args = options.scp_extra_args self.ssh_extra_args = options.ssh_extra_args # privilege escalation diff --git a/lib/ansible/plugins/connection/ssh.py b/lib/ansible/plugins/connection/ssh.py index fce231127a..293fa014fd 100644 --- a/lib/ansible/plugins/connection/ssh.py +++ b/lib/ansible/plugins/connection/ssh.py @@ -33,6 +33,7 @@ from ansible import constants as C from ansible.errors import AnsibleError, AnsibleConnectionFailure, AnsibleFileNotFound from ansible.plugins.connection import ConnectionBase from ansible.utils.path import unfrackpath, makedirs_safe +from ansible.utils.vars import combine_vars SSHPASS_AVAILABLE = None @@ -47,15 +48,21 @@ class Connection(ConnectionBase): super(Connection, self).__init__(*args, **kwargs) self.host = self._play_context.remote_addr - self.ssh_extra_args = '' - self.ssh_args = '' + for v in ['ssh_common_args', 'sftp_extra_args', 'scp_extra_args', 'ssh_extra_args']: + setattr(self, v, '') def set_host_overrides(self, host): - v = host.get_vars() - if 'ansible_ssh_extra_args' in v: - self.ssh_extra_args = v['ansible_ssh_extra_args'] - if 'ansible_ssh_args' in v: - self.ssh_args = v['ansible_ssh_args'] + # FIXME: The following can only use the variables set directly against + # the host ("hostname var=...") or the group ("[group:vars] ...") in the + # inventory file, but NOT those read from group_vars/host_vars files or + # any other source. That's clearly wrong, but we don't have access to a + # VariableManager here, so I don't know how to get at those settings. + + vars = combine_vars(host.get_group_vars(), host.get_vars()) + for v in ['ssh_common_args', 'sftp_extra_args', 'scp_extra_args', 'ssh_extra_args']: + name = 'ansible_%s' % v + if name in vars: + setattr(self, v, vars[name]) # The connection is created by running ssh/scp/sftp from the exec_command, # put_file, and fetch_file methods, so we don't need to do any connection @@ -151,8 +158,7 @@ class Connection(ConnectionBase): if binary == 'sftp' and C.DEFAULT_SFTP_BATCH_MODE: self._command += ['-b', '-'] - elif binary == 'ssh': - self._command += ['-C'] + self._command += ['-C'] if self._play_context.verbosity > 3: self._command += ['-vvv'] @@ -160,14 +166,10 @@ class Connection(ConnectionBase): # Older versions of ssh (e.g. in RHEL 6) don't accept sftp -q. self._command += ['-q'] - # Next, we add ansible_ssh_args from the inventory if it's set, or - # [ssh_connection]ssh_args from ansible.cfg, or the default Control* - # settings. + # Next, we add [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: + if C.ANSIBLE_SSH_ARGS: args = self._split_args(C.ANSIBLE_SSH_ARGS) self._add_args("ansible.cfg set ssh_args", args) else: @@ -189,7 +191,7 @@ class Connection(ConnectionBase): if self._play_context.port is not None: self._add_args( - "ANSIBLE_REMOTE_PORT/remote_port/ansible_ssh_port set", + "ANSIBLE_REMOTE_PORT/remote_port/ansible_port set", ("-o", "Port={0}".format(self._play_context.port)) ) @@ -212,7 +214,7 @@ class Connection(ConnectionBase): 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", + "ANSIBLE_REMOTE_USER/remote_user/ansible_user/user/-u set", ("-o", "User={0}".format(self._play_context.remote_user)) ) @@ -221,16 +223,17 @@ class Connection(ConnectionBase): ("-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. + # If the inventory specifies either common or binary-specific arguments + # applicable to this host, or they are specified as an override on the + # command line, add them in now. - 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) + for opt in ['ssh_common_args', binary + '_extra_args']: + if getattr(self._play_context, opt): + args = self._split_args(getattr(self._play_context, opt)) + self._add_args("command-line added --%s" % opt.replace('_', '-'), args) + elif getattr(self, opt): + args = self._split_args(getattr(self, opt)) + self._add_args("inventory added ansible_%s" % opt, args) # Check if ControlPersist is enabled (either by default, or using # ssh_args or ssh_extra_args) and add a ControlPath if one hasn't From 1981bf2b950053e05110fed7d87f7d5f42c1a700 Mon Sep 17 00:00:00 2001 From: Abhijit Menon-Sen Date: Fri, 2 Oct 2015 12:55:48 +0530 Subject: [PATCH 2/6] Aggregate ssh arguments in PlayContext instead of the connection plugin Using set_host_overrides() in the connection plugin to access the ssh argument variables from the inventory didn't see group_vars/host_vars settings, as noted earlier. Instead, we can set the correct values in the PlayContext, which has access to all command-line options, task settings, and variables. The only downside of doing so is that the source of the settings is no longer available in ssh.py, and therefore can't be logged. But the code is simpler, and it actually works. This change was suggested by @jimi-c in response to the FIXME in the earlier commit. --- lib/ansible/playbook/play_context.py | 5 ++++ lib/ansible/plugins/connection/ssh.py | 33 +++++---------------------- 2 files changed, 11 insertions(+), 27 deletions(-) diff --git a/lib/ansible/playbook/play_context.py b/lib/ansible/playbook/play_context.py index 9cadcf9a76..8c7b0f25d7 100644 --- a/lib/ansible/playbook/play_context.py +++ b/lib/ansible/playbook/play_context.py @@ -67,6 +67,10 @@ MAGIC_VARIABLE_MAPPING = dict( become_pass = ('ansible_become_password','ansible_become_pass'), become_exe = ('ansible_become_exe',), become_flags = ('ansible_become_flags',), + ssh_common_args = ('ansible_ssh_common_args',), + sftp_extra_args = ('ansible_sftp_extra_args',), + scp_extra_args = ('ansible_scp_extra_args',), + ssh_extra_args = ('ansible_ssh_extra_args',), sudo = ('ansible_sudo',), sudo_user = ('ansible_sudo_user',), sudo_pass = ('ansible_sudo_password', 'ansible_sudo_pass'), @@ -140,6 +144,7 @@ class PlayContext(Base): _private_key_file = FieldAttribute(isa='string', default=C.DEFAULT_PRIVATE_KEY_FILE) _timeout = FieldAttribute(isa='int', default=C.DEFAULT_TIMEOUT) _shell = FieldAttribute(isa='string') + _ssh_args = FieldAttribute(isa='string', default=C.ANSIBLE_SSH_ARGS) _ssh_common_args = FieldAttribute(isa='string') _sftp_extra_args = FieldAttribute(isa='string') _scp_extra_args = FieldAttribute(isa='string') diff --git a/lib/ansible/plugins/connection/ssh.py b/lib/ansible/plugins/connection/ssh.py index 293fa014fd..85eb22bbcd 100644 --- a/lib/ansible/plugins/connection/ssh.py +++ b/lib/ansible/plugins/connection/ssh.py @@ -33,7 +33,6 @@ from ansible import constants as C from ansible.errors import AnsibleError, AnsibleConnectionFailure, AnsibleFileNotFound from ansible.plugins.connection import ConnectionBase from ansible.utils.path import unfrackpath, makedirs_safe -from ansible.utils.vars import combine_vars SSHPASS_AVAILABLE = None @@ -48,21 +47,6 @@ class Connection(ConnectionBase): super(Connection, self).__init__(*args, **kwargs) self.host = self._play_context.remote_addr - for v in ['ssh_common_args', 'sftp_extra_args', 'scp_extra_args', 'ssh_extra_args']: - setattr(self, v, '') - - def set_host_overrides(self, host): - # FIXME: The following can only use the variables set directly against - # the host ("hostname var=...") or the group ("[group:vars] ...") in the - # inventory file, but NOT those read from group_vars/host_vars files or - # any other source. That's clearly wrong, but we don't have access to a - # VariableManager here, so I don't know how to get at those settings. - - vars = combine_vars(host.get_group_vars(), host.get_vars()) - for v in ['ssh_common_args', 'sftp_extra_args', 'scp_extra_args', 'ssh_extra_args']: - name = 'ansible_%s' % v - if name in vars: - setattr(self, v, vars[name]) # The connection is created by running ssh/scp/sftp from the exec_command, # put_file, and fetch_file methods, so we don't need to do any connection @@ -169,8 +153,8 @@ class Connection(ConnectionBase): # Next, we add [ssh_connection]ssh_args from ansible.cfg, or the default # Control* settings. - if C.ANSIBLE_SSH_ARGS: - args = self._split_args(C.ANSIBLE_SSH_ARGS) + if self._play_context.ssh_args: + args = self._split_args(self._play_context.ssh_args) self._add_args("ansible.cfg set ssh_args", args) else: args = ( @@ -223,20 +207,15 @@ class Connection(ConnectionBase): ("-o", "ConnectTimeout={0}".format(self._play_context.timeout)) ) - # If the inventory specifies either common or binary-specific arguments - # applicable to this host, or they are specified as an override on the - # command line, add them in now. + # Add in any common or binary-specific arguments from the PlayContext + # (i.e. inventory or task settings or overrides on the command line). for opt in ['ssh_common_args', binary + '_extra_args']: if getattr(self._play_context, opt): args = self._split_args(getattr(self._play_context, opt)) - self._add_args("command-line added --%s" % opt.replace('_', '-'), args) - elif getattr(self, opt): - args = self._split_args(getattr(self, opt)) - self._add_args("inventory added ansible_%s" % opt, args) + self._add_args("PlayContext set %s" % opt, args) - # Check if ControlPersist is enabled (either by default, or using - # ssh_args or ssh_extra_args) and add a ControlPath if one hasn't + # Check if ControlPersist is enabled and add a ControlPath if one hasn't # already been set. controlpersist, controlpath = self._persistence_controls(self._command) From 96c4dc273a3f5bc70f2111ce063b2a750825a5a6 Mon Sep 17 00:00:00 2001 From: Abhijit Menon-Sen Date: Fri, 2 Oct 2015 13:13:49 +0530 Subject: [PATCH 3/6] Set explicit default for ANSIBLE_SSH_ARGS The earlier code behaved exactly as though this default had been set, but it was actually handled as a(n unnecessary) special case inside the connection plugin, rather than set as an explicit default. If the default is overriden either in ansible.cfg or the environment, the new code will continue to work (in fact, it won't know or care, since it just uses the value set in the PlayContext). This is submitted as a separate commit for easier review to address backwards-compatibility concerns. --- lib/ansible/constants.py | 2 +- lib/ansible/plugins/connection/ssh.py | 9 +-------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/lib/ansible/constants.py b/lib/ansible/constants.py index 8ebc4d5742..3d985d0f3d 100644 --- a/lib/ansible/constants.py +++ b/lib/ansible/constants.py @@ -224,7 +224,7 @@ RETRY_FILES_SAVE_PATH = get_config(p, DEFAULTS, 'retry_files_save_path' DEFAULT_NULL_REPRESENTATION = get_config(p, DEFAULTS, 'null_representation', 'ANSIBLE_NULL_REPRESENTATION', None, isnone=True) # CONNECTION RELATED -ANSIBLE_SSH_ARGS = get_config(p, 'ssh_connection', 'ssh_args', 'ANSIBLE_SSH_ARGS', None) +ANSIBLE_SSH_ARGS = get_config(p, 'ssh_connection', 'ssh_args', 'ANSIBLE_SSH_ARGS', '-o ControlMaster=auto -o ControlPersist=60s') ANSIBLE_SSH_CONTROL_PATH = get_config(p, 'ssh_connection', 'control_path', 'ANSIBLE_SSH_CONTROL_PATH', "%(directory)s/ansible-ssh-%%h-%%p-%%r") ANSIBLE_SSH_PIPELINING = get_config(p, 'ssh_connection', 'pipelining', 'ANSIBLE_SSH_PIPELINING', False, boolean=True) ANSIBLE_SSH_RETRIES = get_config(p, 'ssh_connection', 'retries', 'ANSIBLE_SSH_RETRIES', 0, integer=True) diff --git a/lib/ansible/plugins/connection/ssh.py b/lib/ansible/plugins/connection/ssh.py index 85eb22bbcd..10e96ae039 100644 --- a/lib/ansible/plugins/connection/ssh.py +++ b/lib/ansible/plugins/connection/ssh.py @@ -150,18 +150,11 @@ class Connection(ConnectionBase): # Older versions of ssh (e.g. in RHEL 6) don't accept sftp -q. self._command += ['-q'] - # Next, we add [ssh_connection]ssh_args from ansible.cfg, or the default - # Control* settings. + # Next, we add [ssh_connection]ssh_args from ansible.cfg. if self._play_context.ssh_args: args = self._split_args(self._play_context.ssh_args) self._add_args("ansible.cfg set ssh_args", args) - else: - args = ( - "-o", "ControlMaster=auto", - "-o", "ControlPersist=60s" - ) - self._add_args("default arguments", args) # Now we add various arguments controlled by configuration file settings # (e.g. host_key_checking) or inventory variables (ansible_ssh_port) or From 478e234bc3fab8668a575aafc811797bd834b424 Mon Sep 17 00:00:00 2001 From: Abhijit Menon-Sen Date: Fri, 2 Oct 2015 12:11:27 +0530 Subject: [PATCH 4/6] Reword the jump host section in the FAQ It's just s/extra_args/common_args/, but I reworded some parts to make things a bit clearer too. Closes #12335 --- docsite/rst/faq.rst | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docsite/rst/faq.rst b/docsite/rst/faq.rst index f8bc6a84c3..5537376050 100644 --- a/docsite/rst/faq.rst +++ b/docsite/rst/faq.rst @@ -60,23 +60,23 @@ for new users. How do I configure a jump host to access servers that I have no direct access to? +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -With Ansible version 2, it's possible to set `ansible_ssh_extra_args` as -an inventory variable. Any arguments specified this way are added to the -ssh command line when connecting to the relevant host(s), so it's a good -way to set a `ProxyCommand`. Consider the following inventory group: +With Ansible 2, you can set a `ProxyCommand` in the +`ansible_ssh_common_args` inventory variable. Any arguments specified in +this variable are added to the sftp/scp/ssh command line when connecting +to the relevant host(s). Consider the following inventory group:: [gatewayed] foo ansible_host=192.0.2.1 bar ansible_host=192.0.2.2 -You can create `group_vars/gatewayed.yml` with the following contents: +You can create `group_vars/gatewayed.yml` with the following contents:: - ansible_ssh_extra_args: '-o ProxyCommand="ssh -W %h:%p -q user@gateway.example.com"' + ansible_ssh_common_args: '-o ProxyCommand="ssh -W %h:%p -q user@gateway.example.com"' -Ansible will then add these arguments when trying to connect to any host -in the group `gatewayed`. (These arguments are added to any `ssh_args` -that may be configured, so it isn't necessary to repeat the default -`ControlPath` settings in `ansible_ssh_extra_args`.) +Ansible will append these arguments to the command line when trying to +connect to any hosts in the group `gatewayed`. (These arguments are used +in addition to any `ssh_args` from `ansible.cfg`, so you do not need to +repeat global `ControlPersist` settings in `ansible_ssh_common_args`.) Note that `ssh -W` is available only with OpenSSH 5.4 or later. With older versions, it's necessary to execute `nc %h:%p` or some equivalent From b127221f503b43af4af5cf5e7eb8b9ec80ecf173 Mon Sep 17 00:00:00 2001 From: Abhijit Menon-Sen Date: Fri, 2 Oct 2015 20:04:01 +0530 Subject: [PATCH 5/6] Pass default None to getattr, remove repeated call --- lib/ansible/plugins/connection/ssh.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/ansible/plugins/connection/ssh.py b/lib/ansible/plugins/connection/ssh.py index 10e96ae039..29648b591a 100644 --- a/lib/ansible/plugins/connection/ssh.py +++ b/lib/ansible/plugins/connection/ssh.py @@ -204,8 +204,9 @@ class Connection(ConnectionBase): # (i.e. inventory or task settings or overrides on the command line). for opt in ['ssh_common_args', binary + '_extra_args']: - if getattr(self._play_context, opt): - args = self._split_args(getattr(self._play_context, opt)) + attr = getattr(self._play_context, opt, None) + if attr is not None: + args = self._split_args(attr) self._add_args("PlayContext set %s" % opt, args) # Check if ControlPersist is enabled and add a ControlPath if one hasn't From ba98c70bea7be68385c37e625a9edbc80edecde2 Mon Sep 17 00:00:00 2001 From: Abhijit Menon-Sen Date: Fri, 2 Oct 2015 21:52:12 +0530 Subject: [PATCH 6/6] Mention new ssh argument variable in the changelog --- CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 267ca2a0cc..a65765d071 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,7 +22,12 @@ Major Changes: They will retain the value of `None`. To go back to the old behaviour, you can override the `null_representation` setting to an empty string in your config file or by setting the `ANSIBLE_NULL_REPRESENTATION` environment variable. -* Use "pattern1,pattern2" to combine host matching patterns. The use of +* The `ansible_ssh_common_args` inventory variable now provides a + convenient way to configure a per-group or per-host ssh ProxyCommand + or set any other ssh options. Also, `ansible_ssh_extra_args` can be + used to set options that are accepted only by ssh (not sftp or scp, + which have their own analogous settings). +* Use `pattern1,pattern2` to combine host matching patterns. The use of ':' as a separator is deprecated (accepted with a warning) because it conflicts with IPv6 addresses. The undocumented use of ';' as a separator is no longer supported.