Merge pull request #1798 from dagwieers/raw-executable
Allow to change executable (shell/interpreter) when using raw
This commit is contained in:
commit
4955587d8c
8 changed files with 51 additions and 24 deletions
|
@ -438,11 +438,14 @@ class Runner(object):
|
|||
|
||||
# *****************************************************
|
||||
|
||||
def _low_level_exec_command(self, conn, cmd, tmp, sudoable=False):
|
||||
def _low_level_exec_command(self, conn, cmd, tmp, sudoable=False, executable=None):
|
||||
''' execute a command string over SSH, return the output '''
|
||||
|
||||
if not executable:
|
||||
executable = '/bin/sh'
|
||||
|
||||
sudo_user = self.sudo_user
|
||||
rc, stdin, stdout, stderr = conn.exec_command(cmd, tmp, sudo_user, sudoable=sudoable)
|
||||
rc, stdin, stdout, stderr = conn.exec_command(cmd, tmp, sudo_user, sudoable=sudoable, executable=executable)
|
||||
|
||||
if type(stdout) not in [ str, unicode ]:
|
||||
out = ''.join(stdout.readlines())
|
||||
|
|
|
@ -34,7 +34,15 @@ class ActionModule(object):
|
|||
self.runner = runner
|
||||
|
||||
def run(self, conn, tmp, module_name, module_args, inject):
|
||||
return ReturnData(conn=conn,
|
||||
result=self.runner._low_level_exec_command(conn, module_args.encode('utf-8'), tmp, sudoable=True)
|
||||
)
|
||||
executable = None
|
||||
args = []
|
||||
for arg in module_args.split(' '):
|
||||
if arg.startswith('executable='):
|
||||
executable = '='.join(arg.split('=')[1:])
|
||||
else:
|
||||
args.append(arg)
|
||||
module_args = ' '.join(args).encode('utf-8')
|
||||
|
||||
return ReturnData(conn=conn,
|
||||
result=self.runner._low_level_exec_command(conn, module_args, tmp, sudoable=True, executable=executable)
|
||||
)
|
||||
|
|
|
@ -67,7 +67,7 @@ class Connection(object):
|
|||
|
||||
return self
|
||||
|
||||
def exec_command(self, cmd, tmp_path, sudo_user, sudoable=False):
|
||||
def exec_command(self, cmd, tmp_path, sudo_user, sudoable=False, executable='/bin/sh'):
|
||||
''' run a command on the remote host '''
|
||||
|
||||
vvv("EXEC COMMAND %s" % cmd)
|
||||
|
@ -79,6 +79,7 @@ class Connection(object):
|
|||
mode='command',
|
||||
cmd=cmd,
|
||||
tmp_path=tmp_path,
|
||||
executable=executable,
|
||||
)
|
||||
data = utils.jsonify(data)
|
||||
data = utils.encrypt(self.key, data)
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
import traceback
|
||||
import os
|
||||
import pipes
|
||||
import shutil
|
||||
import subprocess
|
||||
from ansible import errors
|
||||
|
@ -36,20 +37,22 @@ class Connection(object):
|
|||
|
||||
return self
|
||||
|
||||
def exec_command(self, cmd, tmp_path, sudo_user, sudoable=False):
|
||||
def exec_command(self, cmd, tmp_path, sudo_user, sudoable=False, executable='/bin/sh'):
|
||||
''' run a command on the local host '''
|
||||
|
||||
if self.runner.sudo and sudoable:
|
||||
if not self.runner.sudo or not sudoable:
|
||||
local_cmd = [ executable, '-c', cmd]
|
||||
else:
|
||||
if self.runner.sudo_pass:
|
||||
# NOTE: if someone wants to add sudo w/ password to the local connection type, they are welcome
|
||||
# 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")
|
||||
cmd = "sudo -u {0} -s {1}".format(sudo_user, cmd)
|
||||
sudocmd = "sudo -u %s -s %s -c %s" % (sudo_user, executable, cmd)
|
||||
local_cmd = ['/bin/sh', '-c', sudocmd]
|
||||
|
||||
vvv("EXEC %s" % cmd, host=self.host)
|
||||
basedir = self.runner.basedir
|
||||
p = subprocess.Popen(cmd, cwd=basedir, shell=True, stdin=None,
|
||||
vvv("EXEC %s" % local_cmd, host=self.host)
|
||||
p = subprocess.Popen(local_cmd, cwd=self.runner.basedir, executable=executable,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
stdout, stderr = p.communicate()
|
||||
return (p.returncode, '', stdout, stderr)
|
||||
|
|
|
@ -96,7 +96,7 @@ class Connection(object):
|
|||
|
||||
return ssh
|
||||
|
||||
def exec_command(self, cmd, tmp_path, sudo_user, sudoable=False):
|
||||
def exec_command(self, cmd, tmp_path, sudo_user, sudoable=False, executable='/bin/sh'):
|
||||
''' run a command on the remote host '''
|
||||
|
||||
bufsize = 4096
|
||||
|
@ -110,7 +110,7 @@ class Connection(object):
|
|||
chan.get_pty()
|
||||
|
||||
if not self.runner.sudo or not sudoable:
|
||||
quoted_command = '/bin/sh -c ' + pipes.quote(cmd)
|
||||
quoted_command = executable + ' -c ' + pipes.quote(cmd)
|
||||
vvv("EXEC %s" % quoted_command, host=self.host)
|
||||
chan.exec_command(quoted_command)
|
||||
else:
|
||||
|
@ -123,8 +123,8 @@ class Connection(object):
|
|||
# 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 /bin/sh -c %s' % (
|
||||
prompt, sudo_user, pipes.quote(cmd))
|
||||
sudocmd = 'sudo -k && sudo -p "%s" -u %s %s -c %s' % (
|
||||
prompt, sudo_user, executable, pipes.quote(cmd))
|
||||
shcmd = '/bin/sh -c ' + pipes.quote(sudocmd)
|
||||
vvv("EXEC %s" % shcmd, host=self.host)
|
||||
sudo_output = ''
|
||||
|
|
|
@ -81,13 +81,15 @@ class Connection(object):
|
|||
os.write(self.wfd, "%s\n" % self.runner.remote_pass)
|
||||
os.close(self.wfd)
|
||||
|
||||
def exec_command(self, cmd, tmp_path, sudo_user,sudoable=False):
|
||||
def exec_command(self, cmd, tmp_path, sudo_user,sudoable=False, executable='/bin/sh'):
|
||||
''' run a command on the remote host '''
|
||||
|
||||
ssh_cmd = self._password_cmd()
|
||||
ssh_cmd += ["ssh", "-tt", "-q"] + self.common_args + [self.host]
|
||||
|
||||
if self.runner.sudo and sudoable:
|
||||
if not self.runner.sudo or not sudoable:
|
||||
ssh_cmd.append(executable + ' -c ' + pipes.quote(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)
|
||||
|
@ -97,10 +99,9 @@ class Connection(object):
|
|||
# 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 /bin/sh -c %s' % (
|
||||
prompt, sudo_user, pipes.quote(cmd))
|
||||
cmd = sudocmd
|
||||
ssh_cmd.append('/bin/sh -c ' + pipes.quote(cmd))
|
||||
sudocmd = 'sudo -k && sudo -p "%s" -u %s %s -c %s' % (
|
||||
prompt, sudo_user, executable, pipes.quote(cmd))
|
||||
ssh_cmd.append('/bin/sh -c ' + pipes.quote(sudocmd))
|
||||
|
||||
vvv("EXEC %s" % ssh_cmd, host=self.host)
|
||||
try:
|
||||
|
|
|
@ -149,9 +149,11 @@ def command(data):
|
|||
return dict(failed=True, msg='internal error: cmd is required')
|
||||
if 'tmp_path' not in data:
|
||||
return dict(failed=True, msg='internal error: tmp_path is required')
|
||||
if 'executable' not in data:
|
||||
return dict(failed=True, msg='internal error: executable is required')
|
||||
|
||||
log("executing: %s" % data['cmd'])
|
||||
p = subprocess.Popen(data['cmd'], shell=True, stdout=subprocess.PIPE, close_fds=True)
|
||||
p = subprocess.Popen(data['cmd'], executable=data['executable'], shell=True, stdout=subprocess.PIPE, close_fds=True)
|
||||
(stdout, stderr) = p.communicate()
|
||||
if stdout is None:
|
||||
stdout = ''
|
||||
|
|
11
library/raw
11
library/raw
|
@ -4,7 +4,16 @@ DOCUMENTATION = '''
|
|||
---
|
||||
module: raw
|
||||
short_description: Executes a low-down and dirty SSH command
|
||||
options: {}
|
||||
options:
|
||||
free_form:
|
||||
description:
|
||||
- the raw module takes a free form command to run
|
||||
required: true
|
||||
executable:
|
||||
description:
|
||||
- change the shell used to execute the command. Should be an absolute path to the executable.
|
||||
required: false
|
||||
version_added: "1.0"
|
||||
description:
|
||||
- Executes a low-down and dirty SSH command, not going through the module
|
||||
subsystem. This is useful and should only be done in two cases. The
|
||||
|
|
Loading…
Reference in a new issue