mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
Merge pull request #250 from jkleint/devel
Service module crashes if args has no "=".
This commit is contained in:
commit
5aa5a48f7f
2 changed files with 56 additions and 16 deletions
|
@ -26,6 +26,8 @@ import re
|
|||
import shutil
|
||||
import subprocess
|
||||
import pipes
|
||||
import socket
|
||||
import random
|
||||
|
||||
from ansible import errors
|
||||
# prevent paramiko warning noise
|
||||
|
@ -37,6 +39,7 @@ with warnings.catch_warnings():
|
|||
|
||||
################################################
|
||||
|
||||
RANDOM_PROMPT_LEN = 32 # 32 random chars in [a-z] gives > 128 bits of entropy
|
||||
|
||||
|
||||
class Connection(object):
|
||||
|
@ -142,19 +145,53 @@ class ParamikoConnection(object):
|
|||
quoted_command = '"$SHELL" -c ' + pipes.quote(cmd)
|
||||
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. The "--"
|
||||
# tells sudo that this is the end of sudo options and the command
|
||||
# follows. 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.
|
||||
sudocmd = 'sudo -k -- "$SHELL" -c ' + pipes.quote(cmd)
|
||||
chan.exec_command(sudocmd)
|
||||
if self.runner.sudo_pass:
|
||||
while not chan.recv_ready():
|
||||
time.sleep(0.25)
|
||||
sudo_output = chan.recv(bufsize) # Pull prompt, catch errors, eat sudo output
|
||||
chan.sendall(self.runner.sudo_pass + '\n')
|
||||
"""
|
||||
Sudo strategy:
|
||||
|
||||
First, if sudo doesn't need a password, it's easy: just run the
|
||||
command.
|
||||
|
||||
If we need a password, we want to read everything up to and
|
||||
including the prompt before sending the password. This is so sudo
|
||||
doesn't block sending the prompt, to catch any errors running sudo
|
||||
itself, and so sudo's output doesn't gunk up the command's output.
|
||||
Some systems have large login banners and slow networks, so the
|
||||
prompt isn't guaranteed to be in the first chunk we read. So, we
|
||||
have to keep reading until we find the password prompt, or timeout
|
||||
trying.
|
||||
|
||||
In order to detect the password prompt, we set it ourselves with
|
||||
the sudo -p switch. We use a random prompt so that a) it's
|
||||
exceedingly unlikely anyone's login material contains it and b) you
|
||||
can't forge it. This can fail if passprompt_override is set in
|
||||
/etc/sudoers.
|
||||
|
||||
Some systems are set to remember your sudo credentials for a set
|
||||
period across terminals and won't prompt for a password. We use
|
||||
sudo -k so it always asks for the password every time (if one is
|
||||
required) to avoid dealing with both cases.
|
||||
|
||||
The "--" tells sudo that this is the end of sudo options and the
|
||||
command follows.
|
||||
|
||||
We shell quote the command for safety, and since we can't run a quoted
|
||||
command directly with sudo (or sudo -s), we actually run the user's
|
||||
shell and pass the quoted command string to the shell's -c option.
|
||||
"""
|
||||
prompt = '[sudo via ansible, key=%s] password: ' % ''.join(chr(random.randint(ord('a'), ord('z'))) for _ in xrange(RANDOM_PROMPT_LEN))
|
||||
sudocmd = 'sudo -k -p "%s" -- "$SHELL" -c %s' % (prompt, pipes.quote(cmd))
|
||||
sudo_output = ''
|
||||
try:
|
||||
chan.exec_command(sudocmd)
|
||||
if self.runner.sudo_pass:
|
||||
while not sudo_output.endswith(prompt):
|
||||
chunk = chan.recv(bufsize)
|
||||
if not chunk:
|
||||
raise errors.AnsibleError('ssh connection closed waiting for sudo password prompt')
|
||||
sudo_output += chunk
|
||||
chan.sendall(self.runner.sudo_pass + '\n')
|
||||
except socket.timeout:
|
||||
raise errors.AnsibleError('ssh timed out waiting for sudo.\n' + sudo_output)
|
||||
|
||||
stdin = chan.makefile('wb', bufsize)
|
||||
stdout = chan.makefile('rb', bufsize)
|
||||
|
|
|
@ -37,9 +37,12 @@ if not len(items):
|
|||
sys.exit(1)
|
||||
|
||||
params = {}
|
||||
for x in items:
|
||||
(k, v) = x.split("=")
|
||||
params[k] = v
|
||||
for arg in items:
|
||||
if "=" not in arg:
|
||||
print json.dumps(dict(failed=True, msg='expected arguments of the form name=value'))
|
||||
sys.exit(1)
|
||||
(name, value) = arg.split("=")
|
||||
params[name] = value
|
||||
|
||||
name = params['name']
|
||||
state = params.get('state','unknown')
|
||||
|
|
Loading…
Reference in a new issue