up, start, stop, kill and rm all accept a list of services

This commit is contained in:
Aanand Prasad 2013-12-20 18:30:23 +00:00
parent 81093627fe
commit d3346fa174
3 changed files with 97 additions and 34 deletions

View File

@ -5,6 +5,7 @@ import re
from inspect import getdoc
from .. import __version__
from ..project import NoSuchService
from .command import Command
from .formatter import Formatter
from .log_printer import LogPrinter
@ -37,6 +38,9 @@ def main():
except UserError, e:
log.error(e.msg)
exit(1)
except NoSuchService, e:
log.error(e.msg)
exit(1)
except NoSuchCommand, e:
log.error("No such command: %s", e.command)
log.error("")
@ -121,8 +125,6 @@ class TopLevelCommand(Command):
-d Detached mode: Run container in the background, print new container name
"""
service = self.project.get_service(options['SERVICE'])
if service is None:
raise UserError("No such service: %s" % options['SERVICE'])
container_options = {
'command': [options['COMMAND']] + options['ARGS'],
'tty': not options['-d'],
@ -146,17 +148,17 @@ class TopLevelCommand(Command):
"""
Create and start containers
Usage: up [options]
Usage: up [options] [SERVICE...]
Options:
-d Detached mode: Run containers in the background, print new container names
"""
detached = options['-d']
unstarted = self.project.create_containers()
unstarted = self.project.create_containers(service_names=options['SERVICE'])
if not detached:
to_attach = self.project.containers() + [c for (s, c) in unstarted]
to_attach = self.project.containers(service_names=options['SERVICE']) + [c for (s, c) in unstarted]
print "Attaching to", list_containers(to_attach)
log_printer = LogPrinter(to_attach, attach_params={'logs': True})
@ -176,33 +178,33 @@ class TopLevelCommand(Command):
"""
Start all services
Usage: start
Usage: start [SERVICE...]
"""
self.project.start()
self.project.start(service_names=options['SERVICE'])
def stop(self, options):
"""
Stop all services
Usage: stop
Usage: stop [SERVICE...]
"""
self.project.stop()
self.project.stop(service_names=options['SERVICE'])
def kill(self, options):
"""
Kill all containers
Usage: kill
Usage: kill [SERVICE...]
"""
self.project.kill()
self.project.kill(service_names=options['SERVICE'])
def rm(self, options):
"""
Remove all stopped containers
Usage: rm
Usage: rm [SERVICE...]
"""
self.project.remove_stopped()
self.project.remove_stopped(service_names=options['SERVICE'])
def logs(self, options):
"""

View File

@ -46,17 +46,40 @@ class Project(object):
return cls.from_dicts(name, dicts, client)
def get_service(self, name):
"""
Retrieve a service by name. Raises NoSuchService
if the named service does not exist.
"""
for service in self.services:
if service.name == name:
return service
def create_containers(self):
raise NoSuchService(name)
def get_services(self, service_names=None):
"""
Returns a list of this project's services filtered
by the provided list of names, or all services if
service_names is None or [].
Preserves the original order of self.services.
Raises NoSuchService if any of the named services
do not exist.
"""
if service_names is None or len(service_names) == 0:
return self.services
else:
unsorted = [self.get_service(name) for name in service_names]
return [s for s in self.services if s in unsorted]
def create_containers(self, service_names=None):
"""
Returns a list of (service, container) tuples,
one for each service with no running containers.
"""
containers = []
for service in self.services:
for service in self.get_services(service_names):
if len(service.containers()) == 0:
containers.append((service, service.create_container()))
return containers
@ -66,27 +89,34 @@ class Project(object):
container.kill()
container.remove()
def start(self, **options):
for service in self.services:
def start(self, service_names=None, **options):
for service in self.get_services(service_names):
service.start(**options)
def stop(self, **options):
for service in self.services:
def stop(self, service_names=None, **options):
for service in self.get_services(service_names):
service.stop(**options)
def kill(self, **options):
for service in self.services:
def kill(self, service_names=None, **options):
for service in self.get_services(service_names):
service.kill(**options)
def remove_stopped(self, **options):
for service in self.services:
def remove_stopped(self, service_names=None, **options):
for service in self.get_services(service_names):
service.remove_stopped(**options)
def containers(self, *args, **kwargs):
def containers(self, service_names=None, *args, **kwargs):
l = []
for service in self.services:
for service in self.get_services(service_names):
for container in service.containers(*args, **kwargs):
l.append(container)
return l
class NoSuchService(Exception):
def __init__(self, name):
self.name = name
self.msg = "No such service: %s" % self.name
def __str__(self):
return self.msg

View File

@ -42,11 +42,30 @@ class ProjectTest(DockerClientTestCase):
project = Project('test', [web], self.client)
self.assertEqual(project.get_service('web'), web)
def test_up(self):
def test_create_containers(self):
web = self.create_service('web')
db = self.create_service('db')
project = Project('test', [web, db], self.client)
unstarted = project.create_containers(service_names=['web'])
self.assertEqual(len(unstarted), 1)
self.assertEqual(unstarted[0][0], web)
self.assertEqual(len(web.containers(stopped=True)), 1)
self.assertEqual(len(db.containers(stopped=True)), 0)
unstarted = project.create_containers()
self.assertEqual(len(unstarted), 2)
self.assertEqual(unstarted[0][0], web)
self.assertEqual(unstarted[1][0], db)
self.assertEqual(len(web.containers(stopped=True)), 2)
self.assertEqual(len(db.containers(stopped=True)), 1)
def test_up(self):
web = self.create_service('web')
db = self.create_service('db')
other = self.create_service('other')
project = Project('test', [web, db, other], self.client)
web.create_container()
self.assertEqual(len(web.containers()), 0)
@ -54,7 +73,7 @@ class ProjectTest(DockerClientTestCase):
self.assertEqual(len(web.containers(stopped=True)), 1)
self.assertEqual(len(db.containers(stopped=True)), 0)
unstarted = project.create_containers()
unstarted = project.create_containers(service_names=['web', 'db'])
self.assertEqual(len(unstarted), 2)
self.assertEqual(unstarted[0][0], web)
self.assertEqual(unstarted[1][0], db)
@ -71,7 +90,7 @@ class ProjectTest(DockerClientTestCase):
self.assertEqual(len(web.containers(stopped=True)), 1)
self.assertEqual(len(db.containers(stopped=True)), 0)
def test_start_stop(self):
def test_start_stop_kill_remove(self):
web = self.create_service('web')
db = self.create_service('db')
project = Project('test', [web, db], self.client)
@ -81,13 +100,25 @@ class ProjectTest(DockerClientTestCase):
self.assertEqual(len(web.containers()), 0)
self.assertEqual(len(db.containers()), 0)
web.create_container()
web_container_1 = web.create_container()
web_container_2 = web.create_container()
db_container = db.create_container()
project.start(service_names=['web'])
self.assertEqual(set(c.name for c in project.containers()), set([web_container_1.name, web_container_2.name]))
project.start()
self.assertEqual(set(c.name for c in project.containers()), set([web_container_1.name, web_container_2.name, db_container.name]))
self.assertEqual(len(web.containers()), 1)
self.assertEqual(len(db.containers()), 0)
project.stop(service_names=['web'], timeout=1)
self.assertEqual(set(c.name for c in project.containers()), set([db_container.name]))
project.stop(timeout=1)
project.kill(service_names=['db'])
self.assertEqual(len(project.containers()), 0)
self.assertEqual(len(project.containers(stopped=True)), 3)
self.assertEqual(len(web.containers()), 0)
self.assertEqual(len(db.containers()), 0)
project.remove_stopped(service_names=['web'])
self.assertEqual(len(project.containers(stopped=True)), 1)
project.remove_stopped()
self.assertEqual(len(project.containers(stopped=True)), 0)