From 7ecab2230222d0eeffc0ff4c84981c126bc1e559 Mon Sep 17 00:00:00 2001 From: Daniel Hokka Zakrisson Date: Thu, 10 Jan 2013 06:50:56 +0100 Subject: [PATCH] Move sudo command making to one common function --- .../runner/connection_plugins/local.py | 7 ++++--- .../runner/connection_plugins/paramiko_ssh.py | 18 ++---------------- lib/ansible/runner/connection_plugins/ssh.py | 19 +++---------------- lib/ansible/utils/__init__.py | 18 ++++++++++++++++++ 4 files changed, 27 insertions(+), 35 deletions(-) diff --git a/lib/ansible/runner/connection_plugins/local.py b/lib/ansible/runner/connection_plugins/local.py index d1fae86114..4c6c8a070e 100644 --- a/lib/ansible/runner/connection_plugins/local.py +++ b/lib/ansible/runner/connection_plugins/local.py @@ -21,6 +21,7 @@ import pipes import shutil import subprocess from ansible import errors +from ansible import utils from ansible.callbacks import vvv class Connection(object): @@ -48,11 +49,11 @@ class Connection(object): # to do so. The primary usage of the local connection is for crontab and kickstart usage however # so this doesn't seem to be a huge priority raise errors.AnsibleError("sudo with password is presently only supported on the 'paramiko' (SSH) and native 'ssh' connection types") - sudocmd = "sudo -u %s -s %s -c %s" % (sudo_user, executable, cmd) - local_cmd = ['/bin/sh', '-c', sudocmd] + local_cmd, prompt = utils.make_sudo_cmd(sudo_user, executable, cmd) vvv("EXEC %s" % local_cmd, host=self.host) - p = subprocess.Popen(local_cmd, cwd=self.runner.basedir, executable=executable, + p = subprocess.Popen(local_cmd, shell=isinstance(local_cmd, basestring), + cwd=self.runner.basedir, executable=executable, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = p.communicate() return (p.returncode, '', stdout, stderr) diff --git a/lib/ansible/runner/connection_plugins/paramiko_ssh.py b/lib/ansible/runner/connection_plugins/paramiko_ssh.py index cc7b4c7f15..c532e8fd5a 100644 --- a/lib/ansible/runner/connection_plugins/paramiko_ssh.py +++ b/lib/ansible/runner/connection_plugins/paramiko_ssh.py @@ -22,6 +22,7 @@ import socket import random from ansible.callbacks import vvv from ansible import errors +from ansible import utils # prevent paramiko warning noise -- see http://stackoverflow.com/questions/3920502/ HAVE_PARAMIKO=False @@ -117,22 +118,7 @@ class Connection(object): vvv("EXEC %s" % quoted_command, host=self.host) chan.exec_command(quoted_command) else: - # Rather than detect if sudo wants a password this time, -k makes - # sudo always ask for a password if one is required. - # Passing a quoted compound command to sudo (or sudo -s) - # directly doesn't work, so we shellquote it with pipes.quote() - # and pass the quoted string to the user's shell. We loop reading - # output until we see the randomly-generated sudo prompt set with - # the -p option. - randbits = ''.join(chr(random.randint(ord('a'), ord('z'))) for x in xrange(32)) - prompt = '[sudo via ansible, key=%s] password: ' % randbits - sudocmd = 'sudo -k && sudo -p "%s" -u %s ' % ( - prompt, sudo_user) - if executable: - sudocmd += "%s -c %s" % (executable, pipes.quote(cmd)) - else: - sudocmd += cmd - shcmd = '/bin/sh -c ' + pipes.quote(sudocmd) + shcmd, prompt = utils.make_sudo_cmd(sudo_user, executable, cmd) vvv("EXEC %s" % shcmd, host=self.host) sudo_output = '' try: diff --git a/lib/ansible/runner/connection_plugins/ssh.py b/lib/ansible/runner/connection_plugins/ssh.py index a8ccc4de9c..66a7bcf504 100644 --- a/lib/ansible/runner/connection_plugins/ssh.py +++ b/lib/ansible/runner/connection_plugins/ssh.py @@ -26,6 +26,7 @@ import fcntl import ansible.constants as C from ansible.callbacks import vvv from ansible import errors +from ansible import utils class Connection(object): ''' ssh based connections ''' @@ -93,22 +94,8 @@ class Connection(object): else: ssh_cmd.append(cmd) else: - # Rather than detect if sudo wants a password this time, -k makes - # sudo always ask for a password if one is required. - # Passing a quoted compound command to sudo (or sudo -s) - # directly doesn't work, so we shellquote it with pipes.quote() - # and pass the quoted string to the user's shell. We loop reading - # output until we see the randomly-generated sudo prompt set with - # the -p option. - randbits = ''.join(chr(random.randint(ord('a'), ord('z'))) for x in xrange(32)) - prompt = '[sudo via ansible, key=%s] password: ' % randbits - sudocmd = 'sudo -k && sudo -p "%s" -u %s ' % ( - prompt, sudo_user) - if executable: - sudocmd += "%s -c %s" % (executable, pipes.quote(cmd)) - else: - sudocmd += cmd - ssh_cmd.append('/bin/sh -c ' + pipes.quote(sudocmd)) + sudocmd, prompt = utils.make_sudo_cmd(sudo_user, executable, cmd) + ssh_cmd.append(sudocmd) vvv("EXEC %s" % ssh_cmd, host=self.host) try: diff --git a/lib/ansible/utils/__init__.py b/lib/ansible/utils/__init__.py index a019e6d739..87637d40f0 100644 --- a/lib/ansible/utils/__init__.py +++ b/lib/ansible/utils/__init__.py @@ -31,6 +31,8 @@ import StringIO import stat import termios import tty +import pipes +import random VERBOSITY=0 @@ -529,3 +531,19 @@ def compile_when_to_only_if(expression): else: raise errors.AnsibleError("invalid usage of when_ operator: %s" % expression) +def make_sudo_cmd(sudo_user, executable, cmd): + """ + helper function for connection plugins to create sudo commands + """ + # Rather than detect if sudo wants a password this time, -k makes + # sudo always ask for a password if one is required. + # Passing a quoted compound command to sudo (or sudo -s) + # directly doesn't work, so we shellquote it with pipes.quote() + # and pass the quoted string to the user's shell. We loop reading + # output until we see the randomly-generated sudo prompt set with + # the -p option. + randbits = ''.join(chr(random.randint(ord('a'), ord('z'))) for x in xrange(32)) + prompt = '[sudo via ansible, key=%s] password: ' % randbits + sudocmd = 'sudo -k && sudo -S -p "%s" -u %s %s -c %s' % ( + prompt, sudo_user, executable or '$SHELL', pipes.quote(cmd)) + return ('/bin/sh -c ' + pipes.quote(sudocmd), prompt)