Define byte strings versus text strings in docker connection

Fixes python3 string handling in the docker connection plugin

Fixes #24776

(cherry picked from commit 3277e6328b)
This commit is contained in:
Toshio Kuratomi 2017-09-09 19:07:10 -07:00
parent 5db6b61cf0
commit 305d5b4d5f

View file

@ -51,7 +51,7 @@ from distutils.version import LooseVersion
import ansible.constants as C
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
from ansible.module_utils._text import to_bytes, to_native, to_text
from ansible.plugins.connection import ConnectionBase, BUFSIZE
@ -89,7 +89,7 @@ class Connection(ConnectionBase):
raise AnsibleError("docker command not found in PATH")
docker_version = self._get_docker_version()
if LooseVersion(docker_version) < LooseVersion('1.3'):
if LooseVersion(docker_version) < LooseVersion(u'1.3'):
raise AnsibleError('docker connection type requires docker 1.3 or higher')
# The remote user we will request from docker (if supported)
@ -98,7 +98,7 @@ class Connection(ConnectionBase):
self.actual_user = None
if self._play_context.remote_user is not None:
if LooseVersion(docker_version) >= LooseVersion('1.7'):
if LooseVersion(docker_version) >= LooseVersion(u'1.7'):
# Support for specifying the exec user was added in docker 1.7
self.remote_user = self._play_context.remote_user
self.actual_user = self.remote_user
@ -106,8 +106,8 @@ class Connection(ConnectionBase):
self.actual_user = self._get_docker_remote_user()
if self.actual_user != self._play_context.remote_user:
display.warning('docker {0} does not support remote_user, using container default: {1}'
.format(docker_version, self.actual_user or '?'))
display.warning(u'docker {0} does not support remote_user, using container default: {1}'
.format(docker_version, self.actual_user or u'?'))
elif self._display.verbosity > 2:
# Since we're not setting the actual_user, look it up so we have it for logging later
# Only do this if display verbosity is high enough that we'll need the value
@ -116,7 +116,7 @@ class Connection(ConnectionBase):
@staticmethod
def _sanitize_version(version):
return re.sub('[^0-9a-zA-Z\.]', '', version)
return re.sub(u'[^0-9a-zA-Z\.]', u'', version)
def _old_docker_version(self):
cmd_args = []
@ -148,15 +148,15 @@ class Connection(ConnectionBase):
cmd, cmd_output, err, returncode = self._old_docker_version()
if returncode == 0:
for line in cmd_output.split('\n'):
if line.startswith('Server version:'): # old docker versions
for line in to_text(cmd_output, errors='surrogate_or_strict').split(u'\n'):
if line.startswith(u'Server version:'): # old docker versions
return self._sanitize_version(line.split()[2])
cmd, cmd_output, err, returncode = self._new_docker_version()
if returncode:
raise AnsibleError('Docker version check (%s) failed: %s' % (cmd, err))
raise AnsibleError('Docker version check (%s) failed: %s' % (to_native(cmd), to_native(err)))
return self._sanitize_version(cmd_output)
return self._sanitize_version(to_text(cmd_output, errors='surrogate_or_strict'))
def _get_docker_remote_user(self):
""" Get the default user configured in the docker container """
@ -164,13 +164,14 @@ class Connection(ConnectionBase):
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate()
out = to_text(out, errors='surrogate_or_strict')
if p.returncode != 0:
display.warning('unable to retrieve default user from docker container: %s' % out + err)
display.warning(u'unable to retrieve default user from docker container: %s %s' % (out, to_text(err)))
return None
# The default exec user is root, unless it was changed in the Dockerfile with USER
return out.strip() or 'root'
return out.strip() or u'root'
def _build_exec_cmd(self, cmd):
""" Build the local docker exec command to run cmd on remote_host
@ -184,13 +185,13 @@ class Connection(ConnectionBase):
if self._play_context.docker_extra_args:
local_cmd += self._play_context.docker_extra_args.split(' ')
local_cmd += ['exec']
local_cmd += [b'exec']
if self.remote_user is not None:
local_cmd += ['-u', self.remote_user]
local_cmd += [b'-u', self.remote_user]
# -i is needed to keep stdin open which allows pipelining to work
local_cmd += ['-i', self._play_context.remote_addr] + cmd
local_cmd += [b'-i', self._play_context.remote_addr] + cmd
return local_cmd
@ -199,7 +200,7 @@ class Connection(ConnectionBase):
super(Connection, self)._connect()
if not self._connected:
display.vvv(u"ESTABLISH DOCKER CONNECTION FOR USER: {0}".format(
self.actual_user or '?'), host=self._play_context.remote_addr
self.actual_user or u'?'), host=self._play_context.remote_addr
)
self._connected = True
@ -239,7 +240,7 @@ class Connection(ConnectionBase):
out_path = self._prefix_login_path(out_path)
if not os.path.exists(to_bytes(in_path, errors='surrogate_or_strict')):
raise AnsibleFileNotFound(
"file or module does not exist: %s" % in_path)
"file or module does not exist: %s" % to_native(in_path))
out_path = shlex_quote(out_path)
# Older docker doesn't have native support for copying files into
@ -257,7 +258,8 @@ class Connection(ConnectionBase):
stdout, stderr = p.communicate()
if p.returncode != 0:
raise AnsibleError("failed to transfer file %s to %s:\n%s\n%s" % (in_path, out_path, stdout, stderr))
raise AnsibleError("failed to transfer file %s to %s:\n%s\n%s" %
(to_native(in_path), to_native(out_path), to_native(stdout), to_native(stderr)))
def fetch_file(self, in_path, out_path):
""" Fetch a file from container to local. """