소스 검색

docker-compose exec doesn't have -e option (fixes #4551)

Signed-off-by: Guillermo Arribas <[email protected]>
Guillermo Arribas 8 년 전
부모
커밋
b30cb77a7b
3개의 변경된 파일74개의 추가작업 그리고 21개의 파일을 삭제
  1. 38 21
      compose/cli/main.py
  2. 26 0
      tests/acceptance/cli_test.py
  3. 10 0
      tests/fixtures/environment-exec/docker-compose.yml

+ 38 - 21
compose/cli/main.py

@@ -14,6 +14,8 @@ from distutils.spawn import find_executable
 from inspect import getdoc
 from operator import attrgetter
 
+import docker
+
 from . import errors
 from . import signals
 from .. import __version__
@@ -402,7 +404,7 @@ class TopLevelCommand(object):
         """
         Execute a command in a running container
 
-        Usage: exec [options] SERVICE COMMAND [ARGS...]
+        Usage: exec [options] [-e KEY=VAL...] SERVICE COMMAND [ARGS...]
 
         Options:
             -d                Detached mode: Run command in the background.
@@ -412,11 +414,16 @@ class TopLevelCommand(object):
                               allocates a TTY.
             --index=index     index of the container if there are multiple
                               instances of a service [default: 1]
+            -e, --env KEY=VAL Set environment variables (can be used multiple times,
+                              not supported in API < 1.25)
         """
         index = int(options.get('--index'))
         service = self.project.get_service(options['SERVICE'])
         detach = options['-d']
 
+        if options['--env'] and docker.utils.version_lt(self.project.client.api_version, '1.25'):
+            raise UserError("Setting environment for exec is not supported in API < 1.25'")
+
         try:
             container = service.get_container(number=index)
         except ValueError as e:
@@ -425,26 +432,7 @@ class TopLevelCommand(object):
         tty = not options["-T"]
 
         if IS_WINDOWS_PLATFORM and not detach:
-            args = ["exec"]
-
-            if options["-d"]:
-                args += ["--detach"]
-            else:
-                args += ["--interactive"]
-
-            if not options["-T"]:
-                args += ["--tty"]
-
-            if options["--privileged"]:
-                args += ["--privileged"]
-
-            if options["--user"]:
-                args += ["--user", options["--user"]]
-
-            args += [container.id]
-            args += command
-
-            sys.exit(call_docker(args))
+            sys.exit(call_docker(build_exec_command(options, container.id, command)))
 
         create_exec_options = {
             "privileged": options["--privileged"],
@@ -453,6 +441,9 @@ class TopLevelCommand(object):
             "stdin": tty,
         }
 
+        if docker.utils.version_gte(self.project.client.api_version, '1.25'):
+            create_exec_options["environment"] = options["--env"]
+
         exec_id = container.create_exec(command, **create_exec_options)
 
         if detach:
@@ -1295,3 +1286,29 @@ def parse_scale_args(options):
             )
         res[service_name] = num
     return res
+
+
+def build_exec_command(options, container_id, command):
+    args = ["exec"]
+
+    if options["-d"]:
+        args += ["--detach"]
+    else:
+        args += ["--interactive"]
+
+    if not options["-T"]:
+        args += ["--tty"]
+
+    if options["--privileged"]:
+        args += ["--privileged"]
+
+    if options["--user"]:
+        args += ["--user", options["--user"]]
+
+    if options["--env"]:
+        for env_variable in options["--env"]:
+            args += ["--env", env_variable]
+
+    args += [container_id]
+    args += command
+    return args

+ 26 - 0
tests/acceptance/cli_test.py

@@ -33,6 +33,7 @@ from tests.integration.testcases import no_cluster
 from tests.integration.testcases import pull_busybox
 from tests.integration.testcases import SWARM_SKIP_RM_VOLUMES
 from tests.integration.testcases import v2_1_only
+from tests.integration.testcases import v2_2_only
 from tests.integration.testcases import v2_only
 from tests.integration.testcases import v3_only
 
@@ -1369,6 +1370,31 @@ class CLITestCase(DockerClientTestCase):
         self.assertEqual(stdout, "operator\n")
         self.assertEqual(stderr, "")
 
+    @v2_2_only()
+    def test_exec_service_with_environment_overridden(self):
+        name = 'service'
+        self.base_dir = 'tests/fixtures/environment-exec'
+        self.dispatch(['up', '-d'])
+        self.assertEqual(len(self.project.containers()), 1)
+
+        stdout, stderr = self.dispatch([
+            'exec',
+            '-T',
+            '-e', 'foo=notbar',
+            '--env', 'alpha=beta',
+            name,
+            'env',
+        ])
+
+        # env overridden
+        assert 'foo=notbar' in stdout
+        # keep environment from yaml
+        assert 'hello=world' in stdout
+        # added option from command line
+        assert 'alpha=beta' in stdout
+
+        self.assertEqual(stderr, '')
+
     def test_run_service_without_links(self):
         self.base_dir = 'tests/fixtures/links-composefile'
         self.dispatch(['run', 'console', '/bin/true'])

+ 10 - 0
tests/fixtures/environment-exec/docker-compose.yml

@@ -0,0 +1,10 @@
+version: "2.2"
+
+services:
+  service:
+    image: busybox:latest
+    command: top
+
+    environment:
+      foo: bar
+      hello: world