Move sudo command making to one common function

pull/1865/merge
Daniel Hokka Zakrisson 12 years ago
parent c339434e57
commit 7ecab22302

@ -21,6 +21,7 @@ import pipes
import shutil import shutil
import subprocess import subprocess
from ansible import errors from ansible import errors
from ansible import utils
from ansible.callbacks import vvv from ansible.callbacks import vvv
class Connection(object): 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 # 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 # 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") 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, prompt = utils.make_sudo_cmd(sudo_user, executable, cmd)
local_cmd = ['/bin/sh', '-c', sudocmd]
vvv("EXEC %s" % local_cmd, host=self.host) 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=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = p.communicate() stdout, stderr = p.communicate()
return (p.returncode, '', stdout, stderr) return (p.returncode, '', stdout, stderr)

@ -22,6 +22,7 @@ import socket
import random import random
from ansible.callbacks import vvv from ansible.callbacks import vvv
from ansible import errors from ansible import errors
from ansible import utils
# prevent paramiko warning noise -- see http://stackoverflow.com/questions/3920502/ # prevent paramiko warning noise -- see http://stackoverflow.com/questions/3920502/
HAVE_PARAMIKO=False HAVE_PARAMIKO=False
@ -117,22 +118,7 @@ class Connection(object):
vvv("EXEC %s" % quoted_command, host=self.host) vvv("EXEC %s" % quoted_command, host=self.host)
chan.exec_command(quoted_command) chan.exec_command(quoted_command)
else: else:
# Rather than detect if sudo wants a password this time, -k makes shcmd, prompt = utils.make_sudo_cmd(sudo_user, executable, cmd)
# 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)
vvv("EXEC %s" % shcmd, host=self.host) vvv("EXEC %s" % shcmd, host=self.host)
sudo_output = '' sudo_output = ''
try: try:

@ -26,6 +26,7 @@ import fcntl
import ansible.constants as C import ansible.constants as C
from ansible.callbacks import vvv from ansible.callbacks import vvv
from ansible import errors from ansible import errors
from ansible import utils
class Connection(object): class Connection(object):
''' ssh based connections ''' ''' ssh based connections '''
@ -93,22 +94,8 @@ class Connection(object):
else: else:
ssh_cmd.append(cmd) ssh_cmd.append(cmd)
else: else:
# Rather than detect if sudo wants a password this time, -k makes sudocmd, prompt = utils.make_sudo_cmd(sudo_user, executable, cmd)
# sudo always ask for a password if one is required. ssh_cmd.append(sudocmd)
# 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))
vvv("EXEC %s" % ssh_cmd, host=self.host) vvv("EXEC %s" % ssh_cmd, host=self.host)
try: try:

@ -31,6 +31,8 @@ import StringIO
import stat import stat
import termios import termios
import tty import tty
import pipes
import random
VERBOSITY=0 VERBOSITY=0
@ -529,3 +531,19 @@ def compile_when_to_only_if(expression):
else: else:
raise errors.AnsibleError("invalid usage of when_ operator: %s" % expression) 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)

Loading…
Cancel
Save