mirror of https://github.com/docker/compose.git
Add an acceptance test and docs for the down subcommand
Signed-off-by: Daniel Nephin <dnephin@docker.com>
This commit is contained in:
parent
c8ed156806
commit
c64af0a459
|
@ -247,7 +247,7 @@ class TopLevelCommand(DocoptCommand):
|
|||
def down(self, project, options):
|
||||
"""
|
||||
Stop containers and remove containers, networks, volumes, and images
|
||||
created by `up`.
|
||||
created by `up`. Only containers and networks are removed by default.
|
||||
|
||||
Usage: down [options]
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ def parallel_execute(objects, func, index_func, msg):
|
|||
object we give it.
|
||||
"""
|
||||
objects = list(objects)
|
||||
stream = get_output_stream(sys.stdout)
|
||||
stream = get_output_stream(sys.stderr)
|
||||
writer = ParallelStreamWriter(stream, msg)
|
||||
|
||||
for obj in objects:
|
||||
|
|
|
@ -272,7 +272,7 @@ class Project(object):
|
|||
|
||||
def down(self, remove_image_type, include_volumes):
|
||||
self.stop()
|
||||
self.remove_stopped()
|
||||
self.remove_stopped(v=include_volumes)
|
||||
self.remove_network()
|
||||
|
||||
if include_volumes:
|
||||
|
@ -441,6 +441,7 @@ class Project(object):
|
|||
return
|
||||
network = self.get_network()
|
||||
if network:
|
||||
log.info("Removing network %s", self.default_network_name)
|
||||
self.client.remove_network(network['Id'])
|
||||
|
||||
def uses_default_network(self):
|
||||
|
|
|
@ -686,6 +686,7 @@ class Service(object):
|
|||
if image_type == ImageType.local and self.options.get('image'):
|
||||
return False
|
||||
|
||||
log.info("Removing image %s", self.image_name)
|
||||
try:
|
||||
self.client.remove_image(self.image_name)
|
||||
return True
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
from __future__ import absolute_import
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import logging
|
||||
|
||||
from docker.errors import NotFound
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Volume(object):
|
||||
def __init__(self, client, project, name, driver=None, driver_opts=None,
|
||||
external_name=None):
|
||||
|
@ -20,6 +25,10 @@ class Volume(object):
|
|||
)
|
||||
|
||||
def remove(self):
|
||||
if self.external:
|
||||
log.info("Volume %s is external, skipping", self.full_name)
|
||||
return
|
||||
log.info("Removing volume %s", self.full_name)
|
||||
return self.client.remove_volume(self.full_name)
|
||||
|
||||
def inspect(self):
|
||||
|
|
|
@ -154,8 +154,7 @@ environments in just a few commands:
|
|||
|
||||
$ docker-compose up -d
|
||||
$ ./run_tests
|
||||
$ docker-compose stop
|
||||
$ docker-compose rm -f
|
||||
$ docker-compose down
|
||||
|
||||
### Single host deployments
|
||||
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
<!--[metadata]>
|
||||
+++
|
||||
title = "down"
|
||||
description = "down"
|
||||
keywords = ["fig, composition, compose, docker, orchestration, cli, down"]
|
||||
[menu.main]
|
||||
identifier="build.compose"
|
||||
parent = "smn_compose_cli"
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
# down
|
||||
|
||||
```
|
||||
Stop containers and remove containers, networks, volumes, and images
|
||||
created by `up`. Only containers and networks are removed by default.
|
||||
|
||||
Usage: down [options]
|
||||
|
||||
Options:
|
||||
--rmi type Remove images, type may be one of: 'all' to remove
|
||||
all images, or 'local' to remove only images that
|
||||
don't have an custom name set by the `image` field
|
||||
-v, --volumes Remove data volumes
|
||||
|
||||
```
|
|
@ -14,10 +14,14 @@ parent = "smn_compose_ref"
|
|||
The following pages describe the usage information for the [docker-compose](docker-compose.md) subcommands. You can also see this information by running `docker-compose [SUBCOMMAND] --help` from the command line.
|
||||
|
||||
* [build](build.md)
|
||||
* [config](config.md)
|
||||
* [create](create.md)
|
||||
* [down](down.md)
|
||||
* [events](events.md)
|
||||
* [help](help.md)
|
||||
* [kill](kill.md)
|
||||
* [logs](logs.md)
|
||||
* [pause](pause.md)
|
||||
* [port](port.md)
|
||||
* [ps](ps.md)
|
||||
* [pull](pull.md)
|
||||
|
@ -27,6 +31,7 @@ The following pages describe the usage information for the [docker-compose](dock
|
|||
* [scale](scale.md)
|
||||
* [start](start.md)
|
||||
* [stop](stop.md)
|
||||
* [unpause](unpause.md)
|
||||
* [up](up.md)
|
||||
|
||||
## Where to go next
|
||||
|
|
|
@ -319,8 +319,16 @@ class CLITestCase(DockerClientTestCase):
|
|||
assert '--rmi flag must be' in result.stderr
|
||||
|
||||
def test_down(self):
|
||||
result = self.dispatch(['down'])
|
||||
# TODO:
|
||||
self.base_dir = 'tests/fixtures/shutdown'
|
||||
self.dispatch(['up', '-d'])
|
||||
wait_on_condition(ContainerCountCondition(self.project, 1))
|
||||
|
||||
result = self.dispatch(['down', '--rmi=local', '--volumes'])
|
||||
assert 'Stopping shutdown_web_1' in result.stderr
|
||||
assert 'Removing shutdown_web_1' in result.stderr
|
||||
assert 'Removing volume shutdown_data' in result.stderr
|
||||
assert 'Removing image shutdown_web' in result.stderr
|
||||
assert 'Removing network shutdown_default' in result.stderr
|
||||
|
||||
def test_up_detached(self):
|
||||
self.dispatch(['up', '-d'])
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
FROM busybox:latest
|
||||
RUN echo something
|
||||
CMD top
|
|
@ -0,0 +1,10 @@
|
|||
|
||||
version: 2
|
||||
|
||||
volumes:
|
||||
data:
|
||||
driver: local
|
||||
|
||||
services:
|
||||
web:
|
||||
build: .
|
|
@ -616,13 +616,13 @@ class ServiceTest(DockerClientTestCase):
|
|||
service.create_container(number=next_number)
|
||||
service.create_container(number=next_number + 1)
|
||||
|
||||
with mock.patch('sys.stdout', new_callable=StringIO) as mock_stdout:
|
||||
with mock.patch('sys.stderr', new_callable=StringIO) as mock_stderr:
|
||||
service.scale(2)
|
||||
for container in service.containers():
|
||||
self.assertTrue(container.is_running)
|
||||
self.assertTrue(container.number in valid_numbers)
|
||||
|
||||
captured_output = mock_stdout.getvalue()
|
||||
captured_output = mock_stderr.getvalue()
|
||||
self.assertNotIn('Creating', captured_output)
|
||||
self.assertIn('Starting', captured_output)
|
||||
|
||||
|
@ -639,14 +639,14 @@ class ServiceTest(DockerClientTestCase):
|
|||
for container in service.containers():
|
||||
self.assertFalse(container.is_running)
|
||||
|
||||
with mock.patch('sys.stdout', new_callable=StringIO) as mock_stdout:
|
||||
with mock.patch('sys.stderr', new_callable=StringIO) as mock_stderr:
|
||||
service.scale(2)
|
||||
|
||||
self.assertEqual(len(service.containers()), 2)
|
||||
for container in service.containers():
|
||||
self.assertTrue(container.is_running)
|
||||
|
||||
captured_output = mock_stdout.getvalue()
|
||||
captured_output = mock_stderr.getvalue()
|
||||
self.assertIn('Creating', captured_output)
|
||||
self.assertIn('Starting', captured_output)
|
||||
|
||||
|
@ -665,12 +665,12 @@ class ServiceTest(DockerClientTestCase):
|
|||
response={},
|
||||
explanation="Boom")):
|
||||
|
||||
with mock.patch('sys.stdout', new_callable=StringIO) as mock_stdout:
|
||||
with mock.patch('sys.stderr', new_callable=StringIO) as mock_stderr:
|
||||
service.scale(3)
|
||||
|
||||
self.assertEqual(len(service.containers()), 1)
|
||||
self.assertTrue(service.containers()[0].is_running)
|
||||
self.assertIn("ERROR: for 2 Boom", mock_stdout.getvalue())
|
||||
self.assertIn("ERROR: for 2 Boom", mock_stderr.getvalue())
|
||||
|
||||
def test_scale_with_unexpected_exception(self):
|
||||
"""Test that when scaling if the API returns an error, that is not of type
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
from __future__ import absolute_import
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import docker
|
||||
import pytest
|
||||
|
||||
from compose import volume
|
||||
from tests import mock
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_client():
|
||||
return mock.create_autospec(docker.Client)
|
||||
|
||||
|
||||
class TestVolume(object):
|
||||
|
||||
def test_remove_local_volume(self, mock_client):
|
||||
vol = volume.Volume(mock_client, 'foo', 'project')
|
||||
vol.remove()
|
||||
mock_client.remove_volume.assert_called_once_with('foo_project')
|
||||
|
||||
def test_remove_external_volume(self, mock_client):
|
||||
vol = volume.Volume(mock_client, 'foo', 'project', external_name='data')
|
||||
vol.remove()
|
||||
assert not mock_client.remove_volume.called
|
Loading…
Reference in New Issue