Skip to content
Permalink
Browse files

connection/docker: add privilege escalation support

As described in #53385 (and #31759), the docker connection driver did
not support privilege escalation. This commit is a shameless
cut-and-paste of the privilege escalation support from the `local`
connection plugin into the `docker` plugin.

This is a backport to stable-2.7 of #55816.
  • Loading branch information...
larsks authored and abadger committed Apr 26, 2019
1 parent 6bc671a commit a8e14cfe1f8c0845af5a63fbd7cf8598ca305c95
@@ -0,0 +1,4 @@
---
bugfixes:
- Fix privilege escalation support for the docker connection plugin when
credentials need to be supplied (e.g. sudo with password).
@@ -40,6 +40,7 @@
"""

import distutils.spawn
import fcntl
import os
import os.path
import subprocess
@@ -48,6 +49,7 @@
from distutils.version import LooseVersion

import ansible.constants as C
from ansible.compat import selectors
from ansible.errors import AnsibleError, AnsibleFileNotFound
from ansible.module_utils.six.moves import shlex_quote
from ansible.module_utils._text import to_bytes, to_native, to_text
@@ -211,10 +213,52 @@ def exec_command(self, cmd, in_data=None, sudoable=False):

display.vvv("EXEC %s" % (local_cmd,), host=self._play_context.remote_addr)
local_cmd = [to_bytes(i, errors='surrogate_or_strict') for i in local_cmd]
p = subprocess.Popen(local_cmd, shell=False, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)

p = subprocess.Popen(
local_cmd,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)

if self._play_context.prompt and sudoable:
fcntl.fcntl(p.stdout, fcntl.F_SETFL, fcntl.fcntl(p.stdout, fcntl.F_GETFL) | os.O_NONBLOCK)
fcntl.fcntl(p.stderr, fcntl.F_SETFL, fcntl.fcntl(p.stderr, fcntl.F_GETFL) | os.O_NONBLOCK)
selector = selectors.DefaultSelector()
selector.register(p.stdout, selectors.EVENT_READ)
selector.register(p.stderr, selectors.EVENT_READ)

become_output = b''
try:
while not self.check_become_success(become_output) and not self.check_password_prompt(become_output):
events = selector.select(self._play_context.timeout)
if not events:
stdout, stderr = p.communicate()
raise AnsibleError('timeout waiting for privilege escalation password prompt:\n' + to_native(become_output))

for key, event in events:
if key.fileobj == p.stdout:
chunk = p.stdout.read()
elif key.fileobj == p.stderr:
chunk = p.stderr.read()

if not chunk:
stdout, stderr = p.communicate()
raise AnsibleError('privilege output closed while waiting for password prompt:\n' + to_native(become_output))
become_output += chunk
finally:
selector.close()

if not self.check_become_success(become_output):
p.stdin.write(to_bytes(self._play_context.become_pass, errors='surrogate_or_strict') + b'\n')
fcntl.fcntl(p.stdout, fcntl.F_SETFL, fcntl.fcntl(p.stdout, fcntl.F_GETFL) & ~os.O_NONBLOCK)
fcntl.fcntl(p.stderr, fcntl.F_SETFL, fcntl.fcntl(p.stderr, fcntl.F_GETFL) & ~os.O_NONBLOCK)

display.debug("getting output with communicate()")
stdout, stderr = p.communicate(in_data)
display.debug("done communicating")

display.debug("done with docker.exec_command()")
return (p.returncode, stdout, stderr)

def _prefix_login_path(self, remote_path):

0 comments on commit a8e14cf

Please sign in to comment.
You can’t perform that action at this time.