From a25da4af05f9e7f2b628bd3804540994f005d5b1 Mon Sep 17 00:00:00 2001 From: Bruno BAILLUET Date: Sat, 27 Sep 2014 17:39:49 +0200 Subject: [PATCH 1/2] Add a new inventory parameter (ansible_sudo_exe) to specify sudo command path. --- docsite/rst/intro_inventory.rst | 2 ++ lib/ansible/runner/__init__.py | 3 +++ lib/ansible/runner/connection_plugins/accelerate.py | 2 +- lib/ansible/runner/connection_plugins/local.py | 2 +- lib/ansible/runner/connection_plugins/paramiko_ssh.py | 2 +- lib/ansible/runner/connection_plugins/ssh.py | 2 +- lib/ansible/utils/__init__.py | 4 ++-- test/units/TestUtils.py | 2 +- 8 files changed, 12 insertions(+), 7 deletions(-) diff --git a/docsite/rst/intro_inventory.rst b/docsite/rst/intro_inventory.rst index a70f2b059ca..16360b1c91c 100644 --- a/docsite/rst/intro_inventory.rst +++ b/docsite/rst/intro_inventory.rst @@ -207,6 +207,8 @@ mentioned:: The ssh password to use (this is insecure, we strongly recommend using --ask-pass or SSH keys) ansible_sudo_pass The sudo password to use (this is insecure, we strongly recommend using --ask-sudo-pass) + ansible_sudo_exe + The sudo command path. ansible_connection Connection type of the host. Candidates are local, ssh or paramiko. The default is paramiko before Ansible 1.2, and 'smart' afterwards which detects whether usage of 'ssh' would be feasible based on whether ControlPersist is supported. ansible_ssh_private_key_file diff --git a/lib/ansible/runner/__init__.py b/lib/ansible/runner/__init__.py index a1133fdbada..944e574e6a7 100644 --- a/lib/ansible/runner/__init__.py +++ b/lib/ansible/runner/__init__.py @@ -154,6 +154,7 @@ class Runner(object): run_hosts=None, # an optional list of pre-calculated hosts to run on no_log=False, # option to enable/disable logging for a given task run_once=False, # option to enable/disable host bypass loop for a given task + sudo_exe=C.DEFAULT_SUDO_EXE, # ex: /usr/local/bin/sudo ): # used to lock multiprocess inputs and outputs at various levels @@ -212,6 +213,7 @@ class Runner(object): self.vault_pass = vault_pass self.no_log = no_log self.run_once = run_once + self.sudo_exe = sudo_exe if self.transport == 'smart': # if the transport is 'smart' see if SSH can support ControlPersist if not use paramiko @@ -810,6 +812,7 @@ class Runner(object): self.sudo_pass = inject.get('ansible_sudo_pass', self.sudo_pass) self.su = inject.get('ansible_su', self.su) self.su_pass = inject.get('ansible_su_pass', self.su_pass) + self.sudo_exe = inject.get('ansible_sudo_exe', self.sudo_exe) # select default root user in case self.sudo requested # but no user specified; happens e.g. in host vars when diff --git a/lib/ansible/runner/connection_plugins/accelerate.py b/lib/ansible/runner/connection_plugins/accelerate.py index 8277d805de2..a31124e119f 100644 --- a/lib/ansible/runner/connection_plugins/accelerate.py +++ b/lib/ansible/runner/connection_plugins/accelerate.py @@ -239,7 +239,7 @@ class Connection(object): executable = constants.DEFAULT_EXECUTABLE if self.runner.sudo and sudoable and sudo_user: - cmd, prompt, success_key = utils.make_sudo_cmd(sudo_user, executable, cmd) + cmd, prompt, success_key = utils.make_sudo_cmd(self.runner.sudo_exe, sudo_user, executable, cmd) vvv("EXEC COMMAND %s" % cmd) diff --git a/lib/ansible/runner/connection_plugins/local.py b/lib/ansible/runner/connection_plugins/local.py index ec57afcecf8..e282076ee1e 100644 --- a/lib/ansible/runner/connection_plugins/local.py +++ b/lib/ansible/runner/connection_plugins/local.py @@ -57,7 +57,7 @@ class Connection(object): else: local_cmd = cmd else: - local_cmd, prompt, success_key = utils.make_sudo_cmd(sudo_user, executable, cmd) + local_cmd, prompt, success_key = utils.make_sudo_cmd(self.runner.sudo_exe, sudo_user, executable, cmd) executable = executable.split()[0] if executable else None vvv("EXEC %s" % (local_cmd), host=self.host) diff --git a/lib/ansible/runner/connection_plugins/paramiko_ssh.py b/lib/ansible/runner/connection_plugins/paramiko_ssh.py index dc02b047f80..59932ebb7d2 100644 --- a/lib/ansible/runner/connection_plugins/paramiko_ssh.py +++ b/lib/ansible/runner/connection_plugins/paramiko_ssh.py @@ -225,7 +225,7 @@ class Connection(object): width=int(os.getenv('COLUMNS', 0)), height=int(os.getenv('LINES', 0))) if self.runner.sudo or sudoable: - shcmd, prompt, success_key = utils.make_sudo_cmd(sudo_user, executable, cmd) + shcmd, prompt, success_key = utils.make_sudo_cmd(self.runner.sudo_exe, sudo_user, executable, cmd) elif self.runner.su or su: shcmd, prompt, success_key = utils.make_su_cmd(su_user, executable, cmd) diff --git a/lib/ansible/runner/connection_plugins/ssh.py b/lib/ansible/runner/connection_plugins/ssh.py index cbba7659035..e8e431f401e 100644 --- a/lib/ansible/runner/connection_plugins/ssh.py +++ b/lib/ansible/runner/connection_plugins/ssh.py @@ -283,7 +283,7 @@ class Connection(object): else: ssh_cmd.append(cmd) else: - sudocmd, prompt, success_key = utils.make_sudo_cmd(sudo_user, executable, cmd) + sudocmd, prompt, success_key = utils.make_sudo_cmd(self.runner.sudo_exe, sudo_user, executable, cmd) ssh_cmd.append(sudocmd) vvv("EXEC %s" % ' '.join(ssh_cmd), host=self.host) diff --git a/lib/ansible/utils/__init__.py b/lib/ansible/utils/__init__.py index 9ad1254899d..f40a83eec03 100644 --- a/lib/ansible/utils/__init__.py +++ b/lib/ansible/utils/__init__.py @@ -1148,7 +1148,7 @@ def boolean(value): else: return False -def make_sudo_cmd(sudo_user, executable, cmd): +def make_sudo_cmd(sudo_exe, sudo_user, executable, cmd): """ helper function for connection plugins to create sudo commands """ @@ -1163,7 +1163,7 @@ def make_sudo_cmd(sudo_user, executable, cmd): prompt = '[sudo via ansible, key=%s] password: ' % randbits success_key = 'SUDO-SUCCESS-%s' % randbits sudocmd = '%s -k && %s %s -S -p "%s" -u %s %s -c %s' % ( - C.DEFAULT_SUDO_EXE, C.DEFAULT_SUDO_EXE, C.DEFAULT_SUDO_FLAGS, + sudo_exe, sudo_exe, C.DEFAULT_SUDO_FLAGS, prompt, sudo_user, executable or '$SHELL', pipes.quote('echo %s; %s' % (success_key, cmd))) return ('/bin/sh -c ' + pipes.quote(sudocmd), prompt, success_key) diff --git a/test/units/TestUtils.py b/test/units/TestUtils.py index 73ef9796743..79204238907 100644 --- a/test/units/TestUtils.py +++ b/test/units/TestUtils.py @@ -471,7 +471,7 @@ class TestUtils(unittest.TestCase): self.assertEqual(ansible.utils.boolean("foo"), False) def test_make_sudo_cmd(self): - cmd = ansible.utils.make_sudo_cmd('root', '/bin/sh', '/bin/ls') + cmd = ansible.utils.make_sudo_cmd(C.DEFAULT_SUDO_EXE, 'root', '/bin/sh', '/bin/ls') self.assertTrue(isinstance(cmd, tuple)) self.assertEqual(len(cmd), 3) self.assertTrue('-u root' in cmd[0]) From 4e5dc754fa45ff451bc57c499fee859ac769dbdc Mon Sep 17 00:00:00 2001 From: Bruno BAILLUET Date: Mon, 29 Sep 2014 19:46:41 +0200 Subject: [PATCH 2/2] Added a comment to mention that ansible_sudo_exe is available from version 1.8 and beyond --- docsite/rst/intro_inventory.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docsite/rst/intro_inventory.rst b/docsite/rst/intro_inventory.rst index 16360b1c91c..5b409e8e651 100644 --- a/docsite/rst/intro_inventory.rst +++ b/docsite/rst/intro_inventory.rst @@ -207,7 +207,7 @@ mentioned:: The ssh password to use (this is insecure, we strongly recommend using --ask-pass or SSH keys) ansible_sudo_pass The sudo password to use (this is insecure, we strongly recommend using --ask-sudo-pass) - ansible_sudo_exe + ansible_sudo_exe (new in version 1.8) The sudo command path. ansible_connection Connection type of the host. Candidates are local, ssh or paramiko. The default is paramiko before Ansible 1.2, and 'smart' afterwards which detects whether usage of 'ssh' would be feasible based on whether ControlPersist is supported.