Adding docker-compose down

Signed-off-by: Daniel Nephin <dnephin@docker.com>
This commit is contained in:
Daniel Nephin 2015-11-27 12:19:43 -05:00
commit c8ed156806
5 changed files with 110 additions and 0 deletions

View file

@ -25,6 +25,7 @@ from ..progress_stream import StreamOutputError
from ..project import NoSuchService
from ..service import BuildError
from ..service import ConvergenceStrategy
from ..service import ImageType
from ..service import NeedsBuildError
from .command import friendly_error_message
from .command import get_config_path_from_options
@ -129,6 +130,7 @@ class TopLevelCommand(DocoptCommand):
build Build or rebuild services
config Validate and view the compose file
create Create services
down Stop and remove containers, networks, images, and volumes
events Receive real time events from containers
help Get help on a command
kill Kill containers
@ -242,6 +244,22 @@ class TopLevelCommand(DocoptCommand):
do_build=not options['--no-build']
)
def down(self, project, options):
"""
Stop containers and remove containers, networks, volumes, and images
created by `up`.
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
"""
image_type = image_type_from_opt('--rmi', options['--rmi'])
project.down(image_type, options['--volumes'])
def events(self, project, options):
"""
Receive real time events from containers.
@ -660,6 +678,15 @@ def convergence_strategy_from_opts(options):
return ConvergenceStrategy.changed
def image_type_from_opt(flag, value):
if not value:
return ImageType.none
try:
return ImageType[value]
except KeyError:
raise UserError("%s flag must be one of: all, local" % flag)
def run_one_off_container(container_options, project, service, options):
if not options['--no-deps']:
deps = service.get_linked_service_names()

View file

@ -270,6 +270,24 @@ class Project(object):
)
)
def down(self, remove_image_type, include_volumes):
self.stop()
self.remove_stopped()
self.remove_network()
if include_volumes:
self.remove_volumes()
self.remove_images(remove_image_type)
def remove_images(self, remove_image_type):
for service in self.get_services():
service.remove_image(remove_image_type)
def remove_volumes(self):
for volume in self.volumes:
volume.remove()
def restart(self, service_names=None, **options):
containers = self.containers(service_names, stopped=True)
parallel.parallel_restart(containers, options)
@ -419,6 +437,8 @@ class Project(object):
self.client.create_network(self.default_network_name, driver=self.network_driver)
def remove_network(self):
if not self.use_networking:
return
network = self.get_network()
if network:
self.client.remove_network(network['Id'])

View file

@ -98,6 +98,14 @@ class ConvergenceStrategy(enum.Enum):
return self is not type(self).never
@enum.unique
class ImageType(enum.Enum):
"""Enumeration for the types of images known to compose."""
none = 0
local = 1
all = 2
class Service(object):
def __init__(
self,
@ -672,6 +680,19 @@ class Service(object):
def custom_container_name(self):
return self.options.get('container_name')
def remove_image(self, image_type):
if not image_type or image_type == ImageType.none:
return False
if image_type == ImageType.local and self.options.get('image'):
return False
try:
self.client.remove_image(self.image_name)
return True
except APIError as e:
log.error("Failed to remove image for service %s: %s", self.name, e)
return False
def specifies_host_port(self):
def has_host_port(binding):
_, external_bindings = split_port(binding)