Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] [2.8] connection/docker: add support for privilege escalation #56277

Merged
merged 2 commits into from May 21, 2019
Merged
Changes from 1 commit
Commits
File filter...
Filter file types
Jump to…
Jump to file or symbol
Failed to load files and symbols.

Always

Just for now

@@ -0,0 +1,4 @@
---
bugfixes:
- Fix privilege escalation support for the docker connection plugin when
credentials needs to be supplied (e.g. sudo with password).
@@ -39,6 +39,7 @@
"""

import distutils.spawn
import fcntl
import os
import os.path
import subprocess
@@ -47,6 +48,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
@@ -205,10 +207,55 @@ 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.become and self.become.expect_prompt() and sudoable:
display.debug("handling privilege escalation")
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.become.check_success(become_output) and not self.become.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()
break

This comment has been minimized.

Copy link
@felixfontein

felixfontein May 9, 2019

Author Contributor

I don't think this break should be there (and I guess I missed it in the original PR). It's not in local.py, either. @larsks where does it come from?

This comment has been minimized.

Copy link
@larsks

larsks May 9, 2019

Contributor

Huh, I haven't the foggiest idea. I didn't do any editing of that content that I recall. Funny that it works. I guess we submit a patch and fix it in the backports? Funny that everything still works. I wish this was all handled in one place...

This comment has been minimized.

Copy link
@felixfontein

felixfontein May 10, 2019

Author Contributor

I've created #56288 and will include it in this backport once it is merged.

Your stable-2.7 does not have this code included though...

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.become.check_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):
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.