Kaydet (Commit) 0a94e5a9 authored tarafından Joffrey F's avatar Joffrey F

Merge branch 'TomasTomecek-add-env-support-to-exec'

...@@ -8,7 +8,8 @@ class ExecApiMixin(object): ...@@ -8,7 +8,8 @@ class ExecApiMixin(object):
@utils.minimum_version('1.15') @utils.minimum_version('1.15')
@utils.check_resource @utils.check_resource
def exec_create(self, container, cmd, stdout=True, stderr=True, def exec_create(self, container, cmd, stdout=True, stderr=True,
stdin=False, tty=False, privileged=False, user=''): stdin=False, tty=False, privileged=False, user='',
environment=None):
""" """
Sets up an exec instance in a running container. Sets up an exec instance in a running container.
...@@ -22,6 +23,9 @@ class ExecApiMixin(object): ...@@ -22,6 +23,9 @@ class ExecApiMixin(object):
tty (bool): Allocate a pseudo-TTY. Default: False tty (bool): Allocate a pseudo-TTY. Default: False
privileged (bool): Run as privileged. privileged (bool): Run as privileged.
user (str): User to execute command as. Default: root user (str): User to execute command as. Default: root
environment (dict or list): A dictionary or a list of strings in
the following format ``["PASSWORD=xxx"]`` or
``{"PASSWORD": "xxx"}``.
Returns: Returns:
(dict): A dictionary with an exec ``Id`` key. (dict): A dictionary with an exec ``Id`` key.
...@@ -31,17 +35,25 @@ class ExecApiMixin(object): ...@@ -31,17 +35,25 @@ class ExecApiMixin(object):
If the server returns an error. If the server returns an error.
""" """
if privileged and utils.compare_version('1.19', self._version) < 0: if privileged and utils.version_lt(self._version, '1.19'):
raise errors.InvalidVersion( raise errors.InvalidVersion(
'Privileged exec is not supported in API < 1.19' 'Privileged exec is not supported in API < 1.19'
) )
if user and utils.compare_version('1.19', self._version) < 0: if user and utils.version_lt(self._version, '1.19'):
raise errors.InvalidVersion( raise errors.InvalidVersion(
'User-specific exec is not supported in API < 1.19' 'User-specific exec is not supported in API < 1.19'
) )
if environment is not None and utils.version_lt(self._version, '1.25'):
raise errors.InvalidVersion(
'Setting environment for exec is not supported in API < 1.25'
)
if isinstance(cmd, six.string_types): if isinstance(cmd, six.string_types):
cmd = utils.split_command(cmd) cmd = utils.split_command(cmd)
if isinstance(environment, dict):
environment = utils.utils.format_environment(environment)
data = { data = {
'Container': container, 'Container': container,
'User': user, 'User': user,
...@@ -50,7 +62,8 @@ class ExecApiMixin(object): ...@@ -50,7 +62,8 @@ class ExecApiMixin(object):
'AttachStdin': stdin, 'AttachStdin': stdin,
'AttachStdout': stdout, 'AttachStdout': stdout,
'AttachStderr': stderr, 'AttachStderr': stderr,
'Cmd': cmd 'Cmd': cmd,
'Env': environment,
} }
url = self._url('/containers/{0}/exec', container) url = self._url('/containers/{0}/exec', container)
...@@ -97,6 +110,7 @@ class ExecApiMixin(object): ...@@ -97,6 +110,7 @@ class ExecApiMixin(object):
self._raise_for_status(res) self._raise_for_status(res)
@utils.minimum_version('1.15') @utils.minimum_version('1.15')
@utils.check_resource
def exec_start(self, exec_id, detach=False, tty=False, stream=False, def exec_start(self, exec_id, detach=False, tty=False, stream=False,
socket=False): socket=False):
""" """
...@@ -118,8 +132,6 @@ class ExecApiMixin(object): ...@@ -118,8 +132,6 @@ class ExecApiMixin(object):
If the server returns an error. If the server returns an error.
""" """
# we want opened socket if socket == True # we want opened socket if socket == True
if isinstance(exec_id, dict):
exec_id = exec_id.get('Id')
data = { data = {
'Tty': tty, 'Tty': tty,
......
...@@ -125,7 +125,7 @@ class Container(Model): ...@@ -125,7 +125,7 @@ class Container(Model):
def exec_run(self, cmd, stdout=True, stderr=True, stdin=False, tty=False, def exec_run(self, cmd, stdout=True, stderr=True, stdin=False, tty=False,
privileged=False, user='', detach=False, stream=False, privileged=False, user='', detach=False, stream=False,
socket=False): socket=False, environment=None):
""" """
Run a command inside this container. Similar to Run a command inside this container. Similar to
``docker exec``. ``docker exec``.
...@@ -141,6 +141,9 @@ class Container(Model): ...@@ -141,6 +141,9 @@ class Container(Model):
detach (bool): If true, detach from the exec command. detach (bool): If true, detach from the exec command.
Default: False Default: False
stream (bool): Stream response data. Default: False stream (bool): Stream response data. Default: False
environment (dict or list): A dictionary or a list of strings in
the following format ``["PASSWORD=xxx"]`` or
``{"PASSWORD": "xxx"}``.
Returns: Returns:
(generator or str): If ``stream=True``, a generator yielding (generator or str): If ``stream=True``, a generator yielding
...@@ -152,7 +155,7 @@ class Container(Model): ...@@ -152,7 +155,7 @@ class Container(Model):
""" """
resp = self.client.api.exec_create( resp = self.client.api.exec_create(
self.id, cmd, stdout=stdout, stderr=stderr, stdin=stdin, tty=tty, self.id, cmd, stdout=stdout, stderr=stderr, stdin=stdin, tty=tty,
privileged=privileged, user=user privileged=privileged, user=user, environment=environment
) )
return self.client.api.exec_start( return self.client.api.exec_start(
resp['Id'], detach=detach, tty=tty, stream=stream, socket=socket resp['Id'], detach=detach, tty=tty, stream=stream, socket=socket
......
...@@ -2,6 +2,7 @@ from docker.utils.socket import next_frame_size ...@@ -2,6 +2,7 @@ from docker.utils.socket import next_frame_size
from docker.utils.socket import read_exactly from docker.utils.socket import read_exactly
from .base import BaseAPIIntegrationTest, BUSYBOX from .base import BaseAPIIntegrationTest, BUSYBOX
from ..helpers import requires_api_version
class ExecTest(BaseAPIIntegrationTest): class ExecTest(BaseAPIIntegrationTest):
...@@ -121,3 +122,17 @@ class ExecTest(BaseAPIIntegrationTest): ...@@ -121,3 +122,17 @@ class ExecTest(BaseAPIIntegrationTest):
exec_info = self.client.exec_inspect(exec_id) exec_info = self.client.exec_inspect(exec_id)
self.assertIn('ExitCode', exec_info) self.assertIn('ExitCode', exec_info)
self.assertNotEqual(exec_info['ExitCode'], 0) self.assertNotEqual(exec_info['ExitCode'], 0)
@requires_api_version('1.25')
def test_exec_command_with_env(self):
container = self.client.create_container(BUSYBOX, 'cat',
detach=True, stdin_open=True)
id = container['Id']
self.client.start(id)
self.tmp_containers.append(id)
res = self.client.exec_create(id, 'env', environment=["X=Y"])
assert 'Id' in res
exec_log = self.client.exec_start(res)
assert b'X=Y\n' in exec_log
...@@ -366,7 +366,7 @@ class ContainerTest(unittest.TestCase): ...@@ -366,7 +366,7 @@ class ContainerTest(unittest.TestCase):
container.exec_run("echo hello world", privileged=True, stream=True) container.exec_run("echo hello world", privileged=True, stream=True)
client.api.exec_create.assert_called_with( client.api.exec_create.assert_called_with(
FAKE_CONTAINER_ID, "echo hello world", stdout=True, stderr=True, FAKE_CONTAINER_ID, "echo hello world", stdout=True, stderr=True,
stdin=False, tty=False, privileged=True, user='' stdin=False, tty=False, privileged=True, user='', environment=None
) )
client.api.exec_start.assert_called_with( client.api.exec_start.assert_called_with(
FAKE_EXEC_ID, detach=False, tty=False, stream=True, socket=False FAKE_EXEC_ID, detach=False, tty=False, stream=True, socket=False
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment