Use enum to represent 3 possible states of the one_off filter

Signed-off-by: Joffrey F <joffrey@docker.com>
This commit is contained in:
Joffrey F 2016-03-16 19:47:46 -07:00 committed by Aanand Prasad
parent 187ea4cd81
commit 5826a2147b
5 changed files with 53 additions and 34 deletions

View File

@ -22,6 +22,7 @@ from ..const import DEFAULT_TIMEOUT
from ..const import IS_WINDOWS_PLATFORM from ..const import IS_WINDOWS_PLATFORM
from ..progress_stream import StreamOutputError from ..progress_stream import StreamOutputError
from ..project import NoSuchService from ..project import NoSuchService
from ..project import OneOffFilter
from ..service import BuildAction from ..service import BuildAction
from ..service import BuildError from ..service import BuildError
from ..service import ConvergenceStrategy from ..service import ConvergenceStrategy
@ -437,7 +438,7 @@ class TopLevelCommand(object):
""" """
containers = sorted( containers = sorted(
self.project.containers(service_names=options['SERVICE'], stopped=True) + self.project.containers(service_names=options['SERVICE'], stopped=True) +
self.project.containers(service_names=options['SERVICE'], one_off=True), self.project.containers(service_names=options['SERVICE'], one_off=OneOffFilter.only),
key=attrgetter('name')) key=attrgetter('name'))
if options['-q']: if options['-q']:
@ -491,11 +492,13 @@ class TopLevelCommand(object):
Options: Options:
-f, --force Don't ask to confirm removal -f, --force Don't ask to confirm removal
-v Remove volumes associated with containers -v Remove volumes associated with containers
-a, --all Also remove one-off containers -a, --all Also remove one-off containers created by
docker-compose run
""" """
one_off = OneOffFilter.include if options.get('--all') else OneOffFilter.exclude
all_containers = self.project.containers( all_containers = self.project.containers(
service_names=options['SERVICE'], stopped=True, service_names=options['SERVICE'], stopped=True, one_off=one_off
one_off=(None if options.get('--all') else False)
) )
stopped_containers = [c for c in all_containers if not c.is_running] stopped_containers = [c for c in all_containers if not c.is_running]
@ -506,7 +509,7 @@ class TopLevelCommand(object):
self.project.remove_stopped( self.project.remove_stopped(
service_names=options['SERVICE'], service_names=options['SERVICE'],
v=options.get('-v', False), v=options.get('-v', False),
one_off=options.get('--all') one_off=one_off
) )
else: else:
print("No stopped containers") print("No stopped containers")

View File

@ -6,6 +6,7 @@ import logging
import operator import operator
from functools import reduce from functools import reduce
import enum
from docker.errors import APIError from docker.errors import APIError
from . import parallel from . import parallel
@ -35,6 +36,20 @@ from .volume import ProjectVolumes
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@enum.unique
class OneOffFilter(enum.Enum):
include = 0
exclude = 1
only = 2
@classmethod
def update_labels(cls, value, labels):
if value == cls.only:
labels.append('{0}={1}'.format(LABEL_ONE_OFF, "True"))
elif value == cls.exclude or value is False:
labels.append('{0}={1}'.format(LABEL_ONE_OFF, "False"))
class Project(object): class Project(object):
""" """
A collection of services. A collection of services.
@ -48,10 +63,8 @@ class Project(object):
def labels(self, one_off=False): def labels(self, one_off=False):
labels = ['{0}={1}'.format(LABEL_PROJECT, self.name)] labels = ['{0}={1}'.format(LABEL_PROJECT, self.name)]
if one_off is not None:
labels.append( OneOffFilter.update_labels(one_off, labels)
'{0}={1}'.format(LABEL_ONE_OFF, "True" if one_off else "False")
)
return labels return labels
@classmethod @classmethod
@ -253,7 +266,7 @@ class Project(object):
def remove_stopped(self, service_names=None, one_off=False, **options): def remove_stopped(self, service_names=None, one_off=False, **options):
parallel.parallel_remove(self.containers( parallel.parallel_remove(self.containers(
service_names, stopped=True, one_off=(None if one_off else False) service_names, stopped=True, one_off=one_off
), options) ), options)
def down(self, remove_image_type, include_volumes, remove_orphans=False): def down(self, remove_image_type, include_volumes, remove_orphans=False):

View File

@ -18,6 +18,7 @@ from docker import errors
from .. import mock from .. import mock
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 tests.integration.testcases import DockerClientTestCase from tests.integration.testcases import DockerClientTestCase
from tests.integration.testcases import get_links from tests.integration.testcases import get_links
from tests.integration.testcases import pull_busybox from tests.integration.testcases import pull_busybox
@ -105,7 +106,7 @@ class CLITestCase(DockerClientTestCase):
self.project.kill() self.project.kill()
self.project.remove_stopped() self.project.remove_stopped()
for container in self.project.containers(stopped=True, one_off=True): for container in self.project.containers(stopped=True, one_off=OneOffFilter.only):
container.remove(force=True) container.remove(force=True)
networks = self.client.networks() networks = self.client.networks()
@ -802,7 +803,7 @@ class CLITestCase(DockerClientTestCase):
self.assertEqual(len(self.project.containers()), 0) self.assertEqual(len(self.project.containers()), 0)
# Ensure stdin/out was open # Ensure stdin/out was open
container = self.project.containers(stopped=True, one_off=True)[0] container = self.project.containers(stopped=True, one_off=OneOffFilter.only)[0]
config = container.inspect()['Config'] config = container.inspect()['Config']
self.assertTrue(config['AttachStderr']) self.assertTrue(config['AttachStderr'])
self.assertTrue(config['AttachStdout']) self.assertTrue(config['AttachStdout'])
@ -852,7 +853,7 @@ class CLITestCase(DockerClientTestCase):
self.dispatch(['run', 'implicit']) self.dispatch(['run', 'implicit'])
service = self.project.get_service('implicit') service = self.project.get_service('implicit')
containers = service.containers(stopped=True, one_off=True) containers = service.containers(stopped=True, one_off=OneOffFilter.only)
self.assertEqual( self.assertEqual(
[c.human_readable_command for c in containers], [c.human_readable_command for c in containers],
[u'/bin/sh -c echo "success"'], [u'/bin/sh -c echo "success"'],
@ -860,7 +861,7 @@ class CLITestCase(DockerClientTestCase):
self.dispatch(['run', 'explicit']) self.dispatch(['run', 'explicit'])
service = self.project.get_service('explicit') service = self.project.get_service('explicit')
containers = service.containers(stopped=True, one_off=True) containers = service.containers(stopped=True, one_off=OneOffFilter.only)
self.assertEqual( self.assertEqual(
[c.human_readable_command for c in containers], [c.human_readable_command for c in containers],
[u'/bin/true'], [u'/bin/true'],
@ -871,7 +872,7 @@ class CLITestCase(DockerClientTestCase):
name = 'service' name = 'service'
self.dispatch(['run', '--entrypoint', '/bin/echo', name, 'helloworld']) self.dispatch(['run', '--entrypoint', '/bin/echo', name, 'helloworld'])
service = self.project.get_service(name) service = self.project.get_service(name)
container = service.containers(stopped=True, one_off=True)[0] container = service.containers(stopped=True, one_off=OneOffFilter.only)[0]
self.assertEqual( self.assertEqual(
shlex.split(container.human_readable_command), shlex.split(container.human_readable_command),
[u'/bin/echo', u'helloworld'], [u'/bin/echo', u'helloworld'],
@ -883,7 +884,7 @@ class CLITestCase(DockerClientTestCase):
user = 'sshd' user = 'sshd'
self.dispatch(['run', '--user={user}'.format(user=user), name], returncode=1) self.dispatch(['run', '--user={user}'.format(user=user), name], returncode=1)
service = self.project.get_service(name) service = self.project.get_service(name)
container = service.containers(stopped=True, one_off=True)[0] container = service.containers(stopped=True, one_off=OneOffFilter.only)[0]
self.assertEqual(user, container.get('Config.User')) self.assertEqual(user, container.get('Config.User'))
def test_run_service_with_user_overridden_short_form(self): def test_run_service_with_user_overridden_short_form(self):
@ -892,7 +893,7 @@ class CLITestCase(DockerClientTestCase):
user = 'sshd' user = 'sshd'
self.dispatch(['run', '-u', user, name], returncode=1) self.dispatch(['run', '-u', user, name], returncode=1)
service = self.project.get_service(name) service = self.project.get_service(name)
container = service.containers(stopped=True, one_off=True)[0] container = service.containers(stopped=True, one_off=OneOffFilter.only)[0]
self.assertEqual(user, container.get('Config.User')) self.assertEqual(user, container.get('Config.User'))
def test_run_service_with_environement_overridden(self): def test_run_service_with_environement_overridden(self):
@ -906,7 +907,7 @@ class CLITestCase(DockerClientTestCase):
'/bin/true', '/bin/true',
]) ])
service = self.project.get_service(name) service = self.project.get_service(name)
container = service.containers(stopped=True, one_off=True)[0] container = service.containers(stopped=True, one_off=OneOffFilter.only)[0]
# env overriden # env overriden
self.assertEqual('notbar', container.environment['foo']) self.assertEqual('notbar', container.environment['foo'])
# keep environement from yaml # keep environement from yaml
@ -920,7 +921,7 @@ class CLITestCase(DockerClientTestCase):
# create one off container # create one off container
self.base_dir = 'tests/fixtures/ports-composefile' self.base_dir = 'tests/fixtures/ports-composefile'
self.dispatch(['run', '-d', 'simple']) self.dispatch(['run', '-d', 'simple'])
container = self.project.get_service('simple').containers(one_off=True)[0] container = self.project.get_service('simple').containers(one_off=OneOffFilter.only)[0]
# get port information # get port information
port_random = container.get_local_port(3000) port_random = container.get_local_port(3000)
@ -937,7 +938,7 @@ class CLITestCase(DockerClientTestCase):
# create one off container # create one off container
self.base_dir = 'tests/fixtures/ports-composefile' self.base_dir = 'tests/fixtures/ports-composefile'
self.dispatch(['run', '-d', '--service-ports', 'simple']) self.dispatch(['run', '-d', '--service-ports', 'simple'])
container = self.project.get_service('simple').containers(one_off=True)[0] container = self.project.get_service('simple').containers(one_off=OneOffFilter.only)[0]
# get port information # get port information
port_random = container.get_local_port(3000) port_random = container.get_local_port(3000)
@ -958,7 +959,7 @@ class CLITestCase(DockerClientTestCase):
# create one off container # create one off container
self.base_dir = 'tests/fixtures/ports-composefile' self.base_dir = 'tests/fixtures/ports-composefile'
self.dispatch(['run', '-d', '-p', '30000:3000', '--publish', '30001:3001', 'simple']) self.dispatch(['run', '-d', '-p', '30000:3000', '--publish', '30001:3001', 'simple'])
container = self.project.get_service('simple').containers(one_off=True)[0] container = self.project.get_service('simple').containers(one_off=OneOffFilter.only)[0]
# get port information # get port information
port_short = container.get_local_port(3000) port_short = container.get_local_port(3000)
@ -980,7 +981,7 @@ class CLITestCase(DockerClientTestCase):
'--publish', '127.0.0.1:30001:3001', '--publish', '127.0.0.1:30001:3001',
'simple' 'simple'
]) ])
container = self.project.get_service('simple').containers(one_off=True)[0] container = self.project.get_service('simple').containers(one_off=OneOffFilter.only)[0]
# get port information # get port information
port_short = container.get_local_port(3000) port_short = container.get_local_port(3000)
@ -997,7 +998,7 @@ class CLITestCase(DockerClientTestCase):
# create one off container # create one off container
self.base_dir = 'tests/fixtures/expose-composefile' self.base_dir = 'tests/fixtures/expose-composefile'
self.dispatch(['run', '-d', '--service-ports', 'simple']) self.dispatch(['run', '-d', '--service-ports', 'simple'])
container = self.project.get_service('simple').containers(one_off=True)[0] container = self.project.get_service('simple').containers(one_off=OneOffFilter.only)[0]
ports = container.ports ports = container.ports
self.assertEqual(len(ports), 9) self.assertEqual(len(ports), 9)
@ -1021,7 +1022,7 @@ class CLITestCase(DockerClientTestCase):
self.dispatch(['run', '--name', name, 'service', '/bin/true']) self.dispatch(['run', '--name', name, 'service', '/bin/true'])
service = self.project.get_service('service') service = self.project.get_service('service')
container, = service.containers(stopped=True, one_off=True) container, = service.containers(stopped=True, one_off=OneOffFilter.only)
self.assertEqual(container.name, name) self.assertEqual(container.name, name)
def test_run_service_with_workdir_overridden(self): def test_run_service_with_workdir_overridden(self):
@ -1051,7 +1052,7 @@ class CLITestCase(DockerClientTestCase):
self.dispatch(['run', 'app', 'nslookup', 'db']) self.dispatch(['run', 'app', 'nslookup', 'db'])
containers = self.project.get_service('app').containers( containers = self.project.get_service('app').containers(
stopped=True, one_off=True) stopped=True, one_off=OneOffFilter.only)
assert len(containers) == 2 assert len(containers) == 2
for container in containers: for container in containers:
@ -1071,7 +1072,7 @@ class CLITestCase(DockerClientTestCase):
self.dispatch(['up', '-d']) self.dispatch(['up', '-d'])
self.dispatch(['run', '-d', 'app', 'top']) self.dispatch(['run', '-d', 'app', 'top'])
container = self.project.get_service('app').containers(one_off=True)[0] container = self.project.get_service('app').containers(one_off=OneOffFilter.only)[0]
networks = container.get('NetworkSettings.Networks') networks = container.get('NetworkSettings.Networks')
assert sorted(list(networks)) == [ assert sorted(list(networks)) == [
@ -1131,21 +1132,21 @@ class CLITestCase(DockerClientTestCase):
service.create_container(one_off=True) service.create_container(one_off=True)
kill_service(service) kill_service(service)
self.assertEqual(len(service.containers(stopped=True)), 1) self.assertEqual(len(service.containers(stopped=True)), 1)
self.assertEqual(len(service.containers(stopped=True, one_off=True)), 1) self.assertEqual(len(service.containers(stopped=True, one_off=OneOffFilter.only)), 1)
self.dispatch(['rm', '-f'], None) self.dispatch(['rm', '-f'], None)
self.assertEqual(len(service.containers(stopped=True)), 0) self.assertEqual(len(service.containers(stopped=True)), 0)
self.assertEqual(len(service.containers(stopped=True, one_off=True)), 1) self.assertEqual(len(service.containers(stopped=True, one_off=OneOffFilter.only)), 1)
self.dispatch(['rm', '-f', '-a'], None) self.dispatch(['rm', '-f', '-a'], None)
self.assertEqual(len(service.containers(stopped=True, one_off=True)), 0) self.assertEqual(len(service.containers(stopped=True, one_off=OneOffFilter.only)), 0)
service.create_container(one_off=False) service.create_container(one_off=False)
service.create_container(one_off=True) service.create_container(one_off=True)
kill_service(service) kill_service(service)
self.assertEqual(len(service.containers(stopped=True)), 1) self.assertEqual(len(service.containers(stopped=True)), 1)
self.assertEqual(len(service.containers(stopped=True, one_off=True)), 1) self.assertEqual(len(service.containers(stopped=True, one_off=OneOffFilter.only)), 1)
self.dispatch(['rm', '-f', '--all'], None) self.dispatch(['rm', '-f', '--all'], None)
self.assertEqual(len(service.containers(stopped=True)), 0) self.assertEqual(len(service.containers(stopped=True)), 0)
self.assertEqual(len(service.containers(stopped=True, one_off=True)), 0) self.assertEqual(len(service.containers(stopped=True, one_off=OneOffFilter.only)), 0)
def test_stop(self): def test_stop(self):
self.dispatch(['up', '-d'], None) self.dispatch(['up', '-d'], None)

View File

@ -24,6 +24,7 @@ from compose.const import LABEL_PROJECT
from compose.const import LABEL_SERVICE from compose.const import LABEL_SERVICE
from compose.const import LABEL_VERSION from compose.const import LABEL_VERSION
from compose.container import Container from compose.container import Container
from compose.project import OneOffFilter
from compose.service import ConvergencePlan from compose.service import ConvergencePlan
from compose.service import ConvergenceStrategy from compose.service import ConvergenceStrategy
from compose.service import NetworkMode from compose.service import NetworkMode
@ -60,7 +61,7 @@ class ServiceTest(DockerClientTestCase):
db = self.create_service('db') db = self.create_service('db')
container = db.create_container(one_off=True) container = db.create_container(one_off=True)
self.assertEqual(db.containers(stopped=True), []) self.assertEqual(db.containers(stopped=True), [])
self.assertEqual(db.containers(one_off=True, stopped=True), [container]) self.assertEqual(db.containers(one_off=OneOffFilter.only, stopped=True), [container])
def test_project_is_added_to_container_name(self): def test_project_is_added_to_container_name(self):
service = self.create_service('web') service = self.create_service('web')
@ -494,7 +495,7 @@ class ServiceTest(DockerClientTestCase):
create_and_start_container(db) create_and_start_container(db)
create_and_start_container(db) create_and_start_container(db)
c = create_and_start_container(db, one_off=True) c = create_and_start_container(db, one_off=OneOffFilter.only)
self.assertEqual( self.assertEqual(
set(get_links(c)), set(get_links(c)),

View File

@ -14,6 +14,7 @@ from compose.const import LABEL_ONE_OFF
from compose.const import LABEL_PROJECT from compose.const import LABEL_PROJECT
from compose.const import LABEL_SERVICE from compose.const import LABEL_SERVICE
from compose.container import Container from compose.container import Container
from compose.project import OneOffFilter
from compose.service import build_ulimits from compose.service import build_ulimits
from compose.service import build_volume_binding from compose.service import build_volume_binding
from compose.service import BuildAction from compose.service import BuildAction
@ -256,7 +257,7 @@ class ServiceTest(unittest.TestCase):
opts = service._get_container_create_options( opts = service._get_container_create_options(
{'name': name}, {'name': name},
1, 1,
one_off=True) one_off=OneOffFilter.only)
self.assertEqual(opts['name'], name) self.assertEqual(opts['name'], name)
def test_get_container_create_options_does_not_mutate_options(self): def test_get_container_create_options_does_not_mutate_options(self):