mirror of https://github.com/docker/compose.git
Merge pull request #4566 from shin-/eddwardo-run-v
Add --volumes flag to docker-compose run
This commit is contained in:
commit
e344fe9a9f
|
@ -24,6 +24,7 @@ from ..config import ConfigurationError
|
||||||
from ..config import parse_environment
|
from ..config import parse_environment
|
||||||
from ..config.environment import Environment
|
from ..config.environment import Environment
|
||||||
from ..config.serialize import serialize_config
|
from ..config.serialize import serialize_config
|
||||||
|
from ..config.types import VolumeSpec
|
||||||
from ..const import IS_WINDOWS_PLATFORM
|
from ..const import IS_WINDOWS_PLATFORM
|
||||||
from ..errors import StreamParseError
|
from ..errors import StreamParseError
|
||||||
from ..progress_stream import StreamOutputError
|
from ..progress_stream import StreamOutputError
|
||||||
|
@ -729,7 +730,7 @@ class TopLevelCommand(object):
|
||||||
running. If you do not want to start linked services, use
|
running. If you do not want to start linked services, use
|
||||||
`docker-compose run --no-deps SERVICE COMMAND [ARGS...]`.
|
`docker-compose run --no-deps SERVICE COMMAND [ARGS...]`.
|
||||||
|
|
||||||
Usage: run [options] [-p PORT...] [-e KEY=VAL...] SERVICE [COMMAND] [ARGS...]
|
Usage: run [options] [-v VOLUME...] [-p PORT...] [-e KEY=VAL...] SERVICE [COMMAND] [ARGS...]
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
-d Detached mode: Run container in the background, print
|
-d Detached mode: Run container in the background, print
|
||||||
|
@ -743,6 +744,7 @@ class TopLevelCommand(object):
|
||||||
-p, --publish=[] Publish a container's port(s) to the host
|
-p, --publish=[] Publish a container's port(s) to the host
|
||||||
--service-ports Run command with the service's ports enabled and mapped
|
--service-ports Run command with the service's ports enabled and mapped
|
||||||
to the host.
|
to the host.
|
||||||
|
-v, --volume=[] Bind mount a volume (default [])
|
||||||
-T Disable pseudo-tty allocation. By default `docker-compose run`
|
-T Disable pseudo-tty allocation. By default `docker-compose run`
|
||||||
allocates a TTY.
|
allocates a TTY.
|
||||||
-w, --workdir="" Working directory inside the container
|
-w, --workdir="" Working directory inside the container
|
||||||
|
@ -1086,6 +1088,10 @@ def build_container_options(options, detach, command):
|
||||||
if options['--workdir']:
|
if options['--workdir']:
|
||||||
container_options['working_dir'] = options['--workdir']
|
container_options['working_dir'] = options['--workdir']
|
||||||
|
|
||||||
|
if options['--volume']:
|
||||||
|
volumes = [VolumeSpec.parse(i) for i in options['--volume']]
|
||||||
|
container_options['volumes'] = volumes
|
||||||
|
|
||||||
return container_options
|
return container_options
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ from __future__ import unicode_literals
|
||||||
import datetime
|
import datetime
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
import os.path
|
||||||
import signal
|
import signal
|
||||||
import subprocess
|
import subprocess
|
||||||
import time
|
import time
|
||||||
|
@ -18,6 +19,7 @@ import yaml
|
||||||
from docker import errors
|
from docker import errors
|
||||||
|
|
||||||
from .. import mock
|
from .. import mock
|
||||||
|
from ..helpers import create_host_file
|
||||||
from compose.cli.command import get_project
|
from compose.cli.command import get_project
|
||||||
from compose.container import Container
|
from compose.container import Container
|
||||||
from compose.project import OneOffFilter
|
from compose.project import OneOffFilter
|
||||||
|
@ -557,6 +559,45 @@ class CLITestCase(DockerClientTestCase):
|
||||||
|
|
||||||
self.assertEqual(old_ids, new_ids)
|
self.assertEqual(old_ids, new_ids)
|
||||||
|
|
||||||
|
def test_run_one_off_with_volume(self):
|
||||||
|
self.base_dir = 'tests/fixtures/simple-composefile-volume-ready'
|
||||||
|
volume_path = os.path.abspath(os.path.join(os.getcwd(), self.base_dir, 'files'))
|
||||||
|
create_host_file(self.client, os.path.join(volume_path, 'example.txt'))
|
||||||
|
|
||||||
|
self.dispatch([
|
||||||
|
'run',
|
||||||
|
'-v', '{}:/data'.format(volume_path),
|
||||||
|
'simple',
|
||||||
|
'test', '-f', '/data/example.txt'
|
||||||
|
], returncode=0)
|
||||||
|
# FIXME: does not work with Python 3
|
||||||
|
# assert cmd_result.stdout.strip() == 'FILE_CONTENT'
|
||||||
|
|
||||||
|
def test_run_one_off_with_multiple_volumes(self):
|
||||||
|
self.base_dir = 'tests/fixtures/simple-composefile-volume-ready'
|
||||||
|
volume_path = os.path.abspath(os.path.join(os.getcwd(), self.base_dir, 'files'))
|
||||||
|
create_host_file(self.client, os.path.join(volume_path, 'example.txt'))
|
||||||
|
|
||||||
|
self.dispatch([
|
||||||
|
'run',
|
||||||
|
'-v', '{}:/data'.format(volume_path),
|
||||||
|
'-v', '{}:/data1'.format(volume_path),
|
||||||
|
'simple',
|
||||||
|
'test', '-f', '/data/example.txt'
|
||||||
|
], returncode=0)
|
||||||
|
# FIXME: does not work with Python 3
|
||||||
|
# assert cmd_result.stdout.strip() == 'FILE_CONTENT'
|
||||||
|
|
||||||
|
self.dispatch([
|
||||||
|
'run',
|
||||||
|
'-v', '{}:/data'.format(volume_path),
|
||||||
|
'-v', '{}:/data1'.format(volume_path),
|
||||||
|
'simple',
|
||||||
|
'test', '-f' '/data1/example.txt'
|
||||||
|
], returncode=0)
|
||||||
|
# FIXME: does not work with Python 3
|
||||||
|
# assert cmd_result.stdout.strip() == 'FILE_CONTENT'
|
||||||
|
|
||||||
def test_create_with_force_recreate_and_no_recreate(self):
|
def test_create_with_force_recreate_and_no_recreate(self):
|
||||||
self.dispatch(
|
self.dispatch(
|
||||||
['create', '--force-recreate', '--no-recreate'],
|
['create', '--force-recreate', '--no-recreate'],
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
simple:
|
||||||
|
image: busybox:latest
|
|
@ -0,0 +1 @@
|
||||||
|
FILE_CONTENT
|
|
@ -1,6 +1,8 @@
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
from compose.config.config import ConfigDetails
|
from compose.config.config import ConfigDetails
|
||||||
from compose.config.config import ConfigFile
|
from compose.config.config import ConfigFile
|
||||||
from compose.config.config import load
|
from compose.config.config import load
|
||||||
|
@ -15,3 +17,30 @@ def build_config_details(contents, working_dir='working_dir', filename='filename
|
||||||
working_dir,
|
working_dir,
|
||||||
[ConfigFile(filename, contents)],
|
[ConfigFile(filename, contents)],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def create_host_file(client, filename):
|
||||||
|
dirname = os.path.dirname(filename)
|
||||||
|
|
||||||
|
with open(filename, 'r') as fh:
|
||||||
|
content = fh.read()
|
||||||
|
|
||||||
|
container = client.create_container(
|
||||||
|
'busybox:latest',
|
||||||
|
['sh', '-c', 'echo -n "{}" > {}'.format(content, filename)],
|
||||||
|
volumes={dirname: {}},
|
||||||
|
host_config=client.create_host_config(
|
||||||
|
binds={dirname: {'bind': dirname, 'ro': False}},
|
||||||
|
network_mode='none',
|
||||||
|
),
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
client.start(container)
|
||||||
|
exitcode = client.wait(container)
|
||||||
|
|
||||||
|
if exitcode != 0:
|
||||||
|
output = client.logs(container)
|
||||||
|
raise Exception(
|
||||||
|
"Container exited with code {}:\n{}".format(exitcode, output))
|
||||||
|
finally:
|
||||||
|
client.remove_container(container, force=True)
|
||||||
|
|
|
@ -10,6 +10,7 @@ from docker.errors import NotFound
|
||||||
|
|
||||||
from .. import mock
|
from .. import mock
|
||||||
from ..helpers import build_config as load_config
|
from ..helpers import build_config as load_config
|
||||||
|
from ..helpers import create_host_file
|
||||||
from .testcases import DockerClientTestCase
|
from .testcases import DockerClientTestCase
|
||||||
from compose.config import config
|
from compose.config import config
|
||||||
from compose.config import ConfigurationError
|
from compose.config import ConfigurationError
|
||||||
|
@ -1517,30 +1518,3 @@ class ProjectTest(DockerClientTestCase):
|
||||||
assert 'svc1' in svc2.get_dependency_names()
|
assert 'svc1' in svc2.get_dependency_names()
|
||||||
with pytest.raises(NoHealthCheckConfigured):
|
with pytest.raises(NoHealthCheckConfigured):
|
||||||
svc1.is_healthy()
|
svc1.is_healthy()
|
||||||
|
|
||||||
|
|
||||||
def create_host_file(client, filename):
|
|
||||||
dirname = os.path.dirname(filename)
|
|
||||||
|
|
||||||
with open(filename, 'r') as fh:
|
|
||||||
content = fh.read()
|
|
||||||
|
|
||||||
container = client.create_container(
|
|
||||||
'busybox:latest',
|
|
||||||
['sh', '-c', 'echo -n "{}" > {}'.format(content, filename)],
|
|
||||||
volumes={dirname: {}},
|
|
||||||
host_config=client.create_host_config(
|
|
||||||
binds={dirname: {'bind': dirname, 'ro': False}},
|
|
||||||
network_mode='none',
|
|
||||||
),
|
|
||||||
)
|
|
||||||
try:
|
|
||||||
client.start(container)
|
|
||||||
exitcode = client.wait(container)
|
|
||||||
|
|
||||||
if exitcode != 0:
|
|
||||||
output = client.logs(container)
|
|
||||||
raise Exception(
|
|
||||||
"Container exited with code {}:\n{}".format(exitcode, output))
|
|
||||||
finally:
|
|
||||||
client.remove_container(container, force=True)
|
|
||||||
|
|
|
@ -119,6 +119,7 @@ class CLITestCase(unittest.TestCase):
|
||||||
'--entrypoint': None,
|
'--entrypoint': None,
|
||||||
'--service-ports': None,
|
'--service-ports': None,
|
||||||
'--publish': [],
|
'--publish': [],
|
||||||
|
'--volume': [],
|
||||||
'--rm': None,
|
'--rm': None,
|
||||||
'--name': None,
|
'--name': None,
|
||||||
'--workdir': None,
|
'--workdir': None,
|
||||||
|
@ -153,6 +154,7 @@ class CLITestCase(unittest.TestCase):
|
||||||
'--entrypoint': None,
|
'--entrypoint': None,
|
||||||
'--service-ports': None,
|
'--service-ports': None,
|
||||||
'--publish': [],
|
'--publish': [],
|
||||||
|
'--volume': [],
|
||||||
'--rm': None,
|
'--rm': None,
|
||||||
'--name': None,
|
'--name': None,
|
||||||
'--workdir': None,
|
'--workdir': None,
|
||||||
|
@ -175,6 +177,7 @@ class CLITestCase(unittest.TestCase):
|
||||||
'--entrypoint': None,
|
'--entrypoint': None,
|
||||||
'--service-ports': None,
|
'--service-ports': None,
|
||||||
'--publish': [],
|
'--publish': [],
|
||||||
|
'--volume': [],
|
||||||
'--rm': True,
|
'--rm': True,
|
||||||
'--name': None,
|
'--name': None,
|
||||||
'--workdir': None,
|
'--workdir': None,
|
||||||
|
|
Loading…
Reference in New Issue