mirror of
https://github.com/docker/compose.git
synced 2025-07-21 12:44:54 +02:00
Merge pull request #246 from d11wtq/feature/auto_start
Feature: `fig up` and `fig run` now start linked containers (closes #31).
This commit is contained in:
commit
95aa61cfe5
10
docs/cli.md
10
docs/cli.md
@ -45,7 +45,7 @@ For example:
|
|||||||
|
|
||||||
$ fig run web python manage.py shell
|
$ fig run web python manage.py shell
|
||||||
|
|
||||||
Note that this will not start any services that the command's service links to. So if, for example, your one-off command talks to your database, you will need to run `fig up -d db` first.
|
By default, linked services will be started, unless they are already running.
|
||||||
|
|
||||||
One-off commands are started in new containers with the same config as a normal container for that service, so volumes, links, etc will all be created as expected. The only thing different to a normal container is the command will be overridden with the one specified and no ports will be created in case they collide.
|
One-off commands are started in new containers with the same config as a normal container for that service, so volumes, links, etc will all be created as expected. The only thing different to a normal container is the command will be overridden with the one specified and no ports will be created in case they collide.
|
||||||
|
|
||||||
@ -53,6 +53,10 @@ Links are also created between one-off commands and the other containers for tha
|
|||||||
|
|
||||||
$ fig run db /bin/sh -c "psql -h \$DB_1_PORT_5432_TCP_ADDR -U docker"
|
$ fig run db /bin/sh -c "psql -h \$DB_1_PORT_5432_TCP_ADDR -U docker"
|
||||||
|
|
||||||
|
If you do not want linked containers to be started when running the one-off command, specify the `--no-deps` flag:
|
||||||
|
|
||||||
|
$ fig run --no-deps web python manage.py shell
|
||||||
|
|
||||||
## scale
|
## scale
|
||||||
|
|
||||||
Set number of containers to run for a service.
|
Set number of containers to run for a service.
|
||||||
@ -74,8 +78,10 @@ Stop running containers without removing them. They can be started again with `f
|
|||||||
|
|
||||||
Build, (re)create, start and attach to containers for a service.
|
Build, (re)create, start and attach to containers for a service.
|
||||||
|
|
||||||
|
Linked services will be started, unless they are already running.
|
||||||
|
|
||||||
By default, `fig up` will aggregate the output of each container, and when it exits, all containers will be stopped. If you run `fig up -d`, it'll start the containers in the background and leave them running.
|
By default, `fig up` will aggregate the output of each container, and when it exits, all containers will be stopped. If you run `fig up -d`, it'll start the containers in the background and leave them running.
|
||||||
|
|
||||||
If there are existing containers for a service, `fig up` will stop and recreate them (preserving mounted volumes with [volumes-from]), so that changes in `fig.yml` are picked up.
|
By default if there are existing containers for a service, `fig up` will stop and recreate them (preserving mounted volumes with [volumes-from]), so that changes in `fig.yml` are picked up. If you do no want containers to be stopped and recreated, use `fig up --no-recreate`. This will still start any stopped containers, if needed.
|
||||||
|
|
||||||
[volumes-from]: http://docs.docker.io/en/latest/use/working_with_volumes/
|
[volumes-from]: http://docs.docker.io/en/latest/use/working_with_volumes/
|
||||||
|
@ -202,21 +202,30 @@ class TopLevelCommand(Command):
|
|||||||
|
|
||||||
$ fig run web python manage.py shell
|
$ fig run web python manage.py shell
|
||||||
|
|
||||||
Note that this will not start any services that the command's service
|
By default, linked services will be started, unless they are already
|
||||||
links to. So if, for example, your one-off command talks to your
|
running. If you do not want to start linked services, use
|
||||||
database, you will need to run `fig up -d db` first.
|
`fig run --no-deps SERVICE COMMAND [ARGS...]`.
|
||||||
|
|
||||||
Usage: run [options] SERVICE COMMAND [ARGS...]
|
Usage: run [options] SERVICE COMMAND [ARGS...]
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
-d Detached mode: Run container in the background, print new
|
-d Detached mode: Run container in the background, print
|
||||||
container name
|
new container name.
|
||||||
-T Disable pseudo-tty allocation. By default `fig run`
|
-T Disable pseudo-tty allocation. By default `fig run`
|
||||||
allocates a TTY.
|
allocates a TTY.
|
||||||
--rm Remove container after run. Ignored in detached mode.
|
--rm Remove container after run. Ignored in detached mode.
|
||||||
|
--no-deps Don't start linked services.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
service = self.project.get_service(options['SERVICE'])
|
service = self.project.get_service(options['SERVICE'])
|
||||||
|
|
||||||
|
if not options['--no-deps']:
|
||||||
|
self.project.up(
|
||||||
|
service_names=service.get_linked_names(),
|
||||||
|
start_links=True,
|
||||||
|
recreate=False
|
||||||
|
)
|
||||||
|
|
||||||
tty = True
|
tty = True
|
||||||
if options['-d'] or options['-T'] or not sys.stdin.isatty():
|
if options['-d'] or options['-T'] or not sys.stdin.isatty():
|
||||||
tty = False
|
tty = False
|
||||||
@ -293,17 +302,29 @@ class TopLevelCommand(Command):
|
|||||||
|
|
||||||
If there are existing containers for a service, `fig up` will stop
|
If there are existing containers for a service, `fig up` will stop
|
||||||
and recreate them (preserving mounted volumes with volumes-from),
|
and recreate them (preserving mounted volumes with volumes-from),
|
||||||
so that changes in `fig.yml` are picked up.
|
so that changes in `fig.yml` are picked up. If you do not want existing
|
||||||
|
containers to be recreated, `fig up --no-recreate` will re-use existing
|
||||||
|
containers.
|
||||||
|
|
||||||
Usage: up [options] [SERVICE...]
|
Usage: up [options] [SERVICE...]
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
-d Detached mode: Run containers in the background, print new
|
-d Detached mode: Run containers in the background,
|
||||||
container names
|
print new container names.
|
||||||
|
--no-deps Don't start linked services.
|
||||||
|
--no-recreate If containers already exist, don't recreate them.
|
||||||
"""
|
"""
|
||||||
detached = options['-d']
|
detached = options['-d']
|
||||||
|
|
||||||
to_attach = self.project.up(service_names=options['SERVICE'])
|
start_links = not options['--no-deps']
|
||||||
|
recreate = not options['--no-recreate']
|
||||||
|
service_names = options['SERVICE']
|
||||||
|
|
||||||
|
to_attach = self.project.up(
|
||||||
|
service_names=service_names,
|
||||||
|
start_links=start_links,
|
||||||
|
recreate=recreate
|
||||||
|
)
|
||||||
|
|
||||||
if not detached:
|
if not detached:
|
||||||
print("Attaching to", list_containers(to_attach))
|
print("Attaching to", list_containers(to_attach))
|
||||||
@ -313,12 +334,12 @@ class TopLevelCommand(Command):
|
|||||||
log_printer.run()
|
log_printer.run()
|
||||||
finally:
|
finally:
|
||||||
def handler(signal, frame):
|
def handler(signal, frame):
|
||||||
self.project.kill(service_names=options['SERVICE'])
|
self.project.kill(service_names=service_names)
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
signal.signal(signal.SIGINT, handler)
|
signal.signal(signal.SIGINT, handler)
|
||||||
|
|
||||||
print("Gracefully stopping... (press Ctrl+C again to force)")
|
print("Gracefully stopping... (press Ctrl+C again to force)")
|
||||||
self.project.stop(service_names=options['SERVICE'])
|
self.project.stop(service_names=service_names)
|
||||||
|
|
||||||
def _attach_to_container(self, container_id, raw=False):
|
def _attach_to_container(self, container_id, raw=False):
|
||||||
socket_in = self.client.attach_socket(container_id, params={'stdin': 1, 'stream': 1})
|
socket_in = self.client.attach_socket(container_id, params={'stdin': 1, 'stream': 1})
|
||||||
|
@ -64,6 +64,7 @@ class Project(object):
|
|||||||
raise ConfigurationError('Service "%s" has a link to service "%s" which does not exist.' % (service_dict['name'], service_name))
|
raise ConfigurationError('Service "%s" has a link to service "%s" which does not exist.' % (service_dict['name'], service_name))
|
||||||
|
|
||||||
del service_dict['links']
|
del service_dict['links']
|
||||||
|
|
||||||
project.services.append(Service(client=client, project=name, links=links, **service_dict))
|
project.services.append(Service(client=client, project=name, links=links, **service_dict))
|
||||||
return project
|
return project
|
||||||
|
|
||||||
@ -88,22 +89,35 @@ class Project(object):
|
|||||||
|
|
||||||
raise NoSuchService(name)
|
raise NoSuchService(name)
|
||||||
|
|
||||||
def get_services(self, service_names=None):
|
def get_services(self, service_names=None, include_links=False):
|
||||||
"""
|
"""
|
||||||
Returns a list of this project's services filtered
|
Returns a list of this project's services filtered
|
||||||
by the provided list of names, or all services if
|
by the provided list of names, or all services if service_names is None
|
||||||
service_names is None or [].
|
or [].
|
||||||
|
|
||||||
Preserves the original order of self.services.
|
If include_links is specified, returns a list including the links for
|
||||||
|
service_names, in order of dependency.
|
||||||
|
|
||||||
Raises NoSuchService if any of the named services
|
Preserves the original order of self.services where possible,
|
||||||
do not exist.
|
reordering as needed to resolve links.
|
||||||
|
|
||||||
|
Raises NoSuchService if any of the named services do not exist.
|
||||||
"""
|
"""
|
||||||
if service_names is None or len(service_names) == 0:
|
if service_names is None or len(service_names) == 0:
|
||||||
return self.services
|
return self.get_services(
|
||||||
|
service_names=[s.name for s in self.services],
|
||||||
|
include_links=include_links
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
unsorted = [self.get_service(name) for name in service_names]
|
unsorted = [self.get_service(name) for name in service_names]
|
||||||
return [s for s in self.services if s in unsorted]
|
services = [s for s in self.services if s in unsorted]
|
||||||
|
|
||||||
|
if include_links:
|
||||||
|
services = reduce(self._inject_links, services, [])
|
||||||
|
|
||||||
|
uniques = []
|
||||||
|
[uniques.append(s) for s in services if s not in uniques]
|
||||||
|
return uniques
|
||||||
|
|
||||||
def start(self, service_names=None, **options):
|
def start(self, service_names=None, **options):
|
||||||
for service in self.get_services(service_names):
|
for service in self.get_services(service_names):
|
||||||
@ -124,14 +138,18 @@ class Project(object):
|
|||||||
else:
|
else:
|
||||||
log.info('%s uses an image, skipping' % service.name)
|
log.info('%s uses an image, skipping' % service.name)
|
||||||
|
|
||||||
def up(self, service_names=None):
|
def up(self, service_names=None, start_links=True, recreate=True):
|
||||||
new_containers = []
|
running_containers = []
|
||||||
|
|
||||||
for service in self.get_services(service_names):
|
for service in self.get_services(service_names, include_links=start_links):
|
||||||
for (_, new) in service.recreate_containers():
|
if recreate:
|
||||||
new_containers.append(new)
|
for (_, container) in service.recreate_containers():
|
||||||
|
running_containers.append(container)
|
||||||
|
else:
|
||||||
|
for container in service.start_or_create_containers():
|
||||||
|
running_containers.append(container)
|
||||||
|
|
||||||
return new_containers
|
return running_containers
|
||||||
|
|
||||||
def remove_stopped(self, service_names=None, **options):
|
def remove_stopped(self, service_names=None, **options):
|
||||||
for service in self.get_services(service_names):
|
for service in self.get_services(service_names):
|
||||||
@ -144,6 +162,20 @@ class Project(object):
|
|||||||
l.append(container)
|
l.append(container)
|
||||||
return l
|
return l
|
||||||
|
|
||||||
|
def _inject_links(self, acc, service):
|
||||||
|
linked_names = service.get_linked_names()
|
||||||
|
|
||||||
|
if len(linked_names) > 0:
|
||||||
|
linked_services = self.get_services(
|
||||||
|
service_names=linked_names,
|
||||||
|
include_links=True
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
linked_services = []
|
||||||
|
|
||||||
|
linked_services.append(service)
|
||||||
|
return acc + linked_services
|
||||||
|
|
||||||
|
|
||||||
class NoSuchService(Exception):
|
class NoSuchService(Exception):
|
||||||
def __init__(self, name):
|
def __init__(self, name):
|
||||||
|
@ -75,9 +75,7 @@ class Service(object):
|
|||||||
|
|
||||||
def start(self, **options):
|
def start(self, **options):
|
||||||
for c in self.containers(stopped=True):
|
for c in self.containers(stopped=True):
|
||||||
if not c.is_running:
|
self.start_container_if_stopped(c, **options)
|
||||||
log.info("Starting %s..." % c.name)
|
|
||||||
self.start_container(c, **options)
|
|
||||||
|
|
||||||
def stop(self, **options):
|
def stop(self, **options):
|
||||||
for c in self.containers():
|
for c in self.containers():
|
||||||
@ -200,6 +198,13 @@ class Service(object):
|
|||||||
|
|
||||||
return (intermediate_container, new_container)
|
return (intermediate_container, new_container)
|
||||||
|
|
||||||
|
def start_container_if_stopped(self, container, **options):
|
||||||
|
if container.is_running:
|
||||||
|
return container
|
||||||
|
else:
|
||||||
|
log.info("Starting %s..." % container.name)
|
||||||
|
return self.start_container(container, **options)
|
||||||
|
|
||||||
def start_container(self, container=None, volumes_from=None, **override_options):
|
def start_container(self, container=None, volumes_from=None, **override_options):
|
||||||
if container is None:
|
if container is None:
|
||||||
container = self.create_container(**override_options)
|
container = self.create_container(**override_options)
|
||||||
@ -243,6 +248,19 @@ class Service(object):
|
|||||||
)
|
)
|
||||||
return container
|
return container
|
||||||
|
|
||||||
|
def start_or_create_containers(self):
|
||||||
|
containers = self.containers(stopped=True)
|
||||||
|
|
||||||
|
if len(containers) == 0:
|
||||||
|
log.info("Creating %s..." % self.next_container_name())
|
||||||
|
new_container = self.create_container()
|
||||||
|
return [self.start_container(new_container)]
|
||||||
|
else:
|
||||||
|
return [self.start_container_if_stopped(c) for c in containers]
|
||||||
|
|
||||||
|
def get_linked_names(self):
|
||||||
|
return [s.name for (s, _) in self.links]
|
||||||
|
|
||||||
def next_container_name(self, one_off=False):
|
def next_container_name(self, one_off=False):
|
||||||
bits = [self.project, self.name]
|
bits = [self.project, self.name]
|
||||||
if one_off:
|
if one_off:
|
||||||
|
11
tests/fixtures/links-figfile/fig.yml
vendored
Normal file
11
tests/fixtures/links-figfile/fig.yml
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
db:
|
||||||
|
image: busybox:latest
|
||||||
|
command: /bin/sleep 300
|
||||||
|
web:
|
||||||
|
image: busybox:latest
|
||||||
|
command: /bin/sleep 300
|
||||||
|
links:
|
||||||
|
- db:db
|
||||||
|
console:
|
||||||
|
image: busybox:latest
|
||||||
|
command: /bin/sleep 300
|
@ -1,17 +1,20 @@
|
|||||||
from __future__ import unicode_literals
|
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
from .testcases import DockerClientTestCase
|
from .testcases import DockerClientTestCase
|
||||||
from mock import patch
|
from mock import patch
|
||||||
from fig.cli.main import TopLevelCommand
|
from fig.cli.main import TopLevelCommand
|
||||||
from fig.packages.six import StringIO
|
from fig.packages.six import StringIO
|
||||||
|
import sys
|
||||||
|
|
||||||
class CLITestCase(DockerClientTestCase):
|
class CLITestCase(DockerClientTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(CLITestCase, self).setUp()
|
super(CLITestCase, self).setUp()
|
||||||
|
self.old_sys_exit = sys.exit
|
||||||
|
sys.exit = lambda code=0: None
|
||||||
self.command = TopLevelCommand()
|
self.command = TopLevelCommand()
|
||||||
self.command.base_dir = 'tests/fixtures/simple-figfile'
|
self.command.base_dir = 'tests/fixtures/simple-figfile'
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
|
sys.exit = self.old_sys_exit
|
||||||
self.command.project.kill()
|
self.command.project.kill()
|
||||||
self.command.project.remove_stopped()
|
self.command.project.remove_stopped()
|
||||||
|
|
||||||
@ -43,6 +46,100 @@ class CLITestCase(DockerClientTestCase):
|
|||||||
self.assertNotIn('fig_another_1', output)
|
self.assertNotIn('fig_another_1', output)
|
||||||
self.assertIn('fig_yetanother_1', output)
|
self.assertIn('fig_yetanother_1', output)
|
||||||
|
|
||||||
|
def test_up(self):
|
||||||
|
self.command.dispatch(['up', '-d'], None)
|
||||||
|
service = self.command.project.get_service('simple')
|
||||||
|
another = self.command.project.get_service('another')
|
||||||
|
self.assertEqual(len(service.containers()), 1)
|
||||||
|
self.assertEqual(len(another.containers()), 1)
|
||||||
|
|
||||||
|
def test_up_with_links(self):
|
||||||
|
self.command.base_dir = 'tests/fixtures/links-figfile'
|
||||||
|
self.command.dispatch(['up', '-d', 'web'], None)
|
||||||
|
web = self.command.project.get_service('web')
|
||||||
|
db = self.command.project.get_service('db')
|
||||||
|
console = self.command.project.get_service('console')
|
||||||
|
self.assertEqual(len(web.containers()), 1)
|
||||||
|
self.assertEqual(len(db.containers()), 1)
|
||||||
|
self.assertEqual(len(console.containers()), 0)
|
||||||
|
|
||||||
|
def test_up_with_no_deps(self):
|
||||||
|
self.command.base_dir = 'tests/fixtures/links-figfile'
|
||||||
|
self.command.dispatch(['up', '-d', '--no-deps', 'web'], None)
|
||||||
|
web = self.command.project.get_service('web')
|
||||||
|
db = self.command.project.get_service('db')
|
||||||
|
console = self.command.project.get_service('console')
|
||||||
|
self.assertEqual(len(web.containers()), 1)
|
||||||
|
self.assertEqual(len(db.containers()), 0)
|
||||||
|
self.assertEqual(len(console.containers()), 0)
|
||||||
|
|
||||||
|
def test_up_with_recreate(self):
|
||||||
|
self.command.dispatch(['up', '-d'], None)
|
||||||
|
service = self.command.project.get_service('simple')
|
||||||
|
self.assertEqual(len(service.containers()), 1)
|
||||||
|
|
||||||
|
old_ids = [c.id for c in service.containers()]
|
||||||
|
|
||||||
|
self.command.dispatch(['up', '-d'], None)
|
||||||
|
self.assertEqual(len(service.containers()), 1)
|
||||||
|
|
||||||
|
new_ids = [c.id for c in service.containers()]
|
||||||
|
|
||||||
|
self.assertNotEqual(old_ids, new_ids)
|
||||||
|
|
||||||
|
def test_up_with_keep_old(self):
|
||||||
|
self.command.dispatch(['up', '-d'], None)
|
||||||
|
service = self.command.project.get_service('simple')
|
||||||
|
self.assertEqual(len(service.containers()), 1)
|
||||||
|
|
||||||
|
old_ids = [c.id for c in service.containers()]
|
||||||
|
|
||||||
|
self.command.dispatch(['up', '-d', '--no-recreate'], None)
|
||||||
|
self.assertEqual(len(service.containers()), 1)
|
||||||
|
|
||||||
|
new_ids = [c.id for c in service.containers()]
|
||||||
|
|
||||||
|
self.assertEqual(old_ids, new_ids)
|
||||||
|
|
||||||
|
|
||||||
|
@patch('sys.stdout', new_callable=StringIO)
|
||||||
|
def test_run_with_links(self, mock_stdout):
|
||||||
|
mock_stdout.fileno = lambda: 1
|
||||||
|
|
||||||
|
self.command.base_dir = 'tests/fixtures/links-figfile'
|
||||||
|
self.command.dispatch(['run', 'web', '/bin/true'], None)
|
||||||
|
db = self.command.project.get_service('db')
|
||||||
|
console = self.command.project.get_service('console')
|
||||||
|
self.assertEqual(len(db.containers()), 1)
|
||||||
|
self.assertEqual(len(console.containers()), 0)
|
||||||
|
|
||||||
|
@patch('sys.stdout', new_callable=StringIO)
|
||||||
|
def test_run_with_no_deps(self, mock_stdout):
|
||||||
|
mock_stdout.fileno = lambda: 1
|
||||||
|
|
||||||
|
self.command.base_dir = 'tests/fixtures/links-figfile'
|
||||||
|
self.command.dispatch(['run', '--no-deps', 'web', '/bin/true'], None)
|
||||||
|
db = self.command.project.get_service('db')
|
||||||
|
self.assertEqual(len(db.containers()), 0)
|
||||||
|
|
||||||
|
@patch('sys.stdout', new_callable=StringIO)
|
||||||
|
def test_run_does_not_recreate_linked_containers(self, mock_stdout):
|
||||||
|
mock_stdout.fileno = lambda: 1
|
||||||
|
|
||||||
|
self.command.base_dir = 'tests/fixtures/links-figfile'
|
||||||
|
self.command.dispatch(['up', '-d', 'db'], None)
|
||||||
|
db = self.command.project.get_service('db')
|
||||||
|
self.assertEqual(len(db.containers()), 1)
|
||||||
|
|
||||||
|
old_ids = [c.id for c in db.containers()]
|
||||||
|
|
||||||
|
self.command.dispatch(['run', 'web', '/bin/true'], None)
|
||||||
|
self.assertEqual(len(db.containers()), 1)
|
||||||
|
|
||||||
|
new_ids = [c.id for c in db.containers()]
|
||||||
|
|
||||||
|
self.assertEqual(old_ids, new_ids)
|
||||||
|
|
||||||
def test_rm(self):
|
def test_rm(self):
|
||||||
service = self.command.project.get_service('simple')
|
service = self.command.project.get_service('simple')
|
||||||
service.create_container()
|
service.create_container()
|
||||||
|
@ -44,6 +44,21 @@ class ProjectTest(DockerClientTestCase):
|
|||||||
project.start()
|
project.start()
|
||||||
self.assertEqual(len(project.containers()), 0)
|
self.assertEqual(len(project.containers()), 0)
|
||||||
|
|
||||||
|
project.up(['db'])
|
||||||
|
self.assertEqual(len(project.containers()), 1)
|
||||||
|
self.assertEqual(len(db.containers()), 1)
|
||||||
|
self.assertEqual(len(web.containers()), 0)
|
||||||
|
|
||||||
|
project.kill()
|
||||||
|
project.remove_stopped()
|
||||||
|
|
||||||
|
def test_project_up_recreates_containers(self):
|
||||||
|
web = self.create_service('web')
|
||||||
|
db = self.create_service('db', volumes=['/var/db'])
|
||||||
|
project = Project('figtest', [web, db], self.client)
|
||||||
|
project.start()
|
||||||
|
self.assertEqual(len(project.containers()), 0)
|
||||||
|
|
||||||
project.up(['db'])
|
project.up(['db'])
|
||||||
self.assertEqual(len(project.containers()), 1)
|
self.assertEqual(len(project.containers()), 1)
|
||||||
old_db_id = project.containers()[0].id
|
old_db_id = project.containers()[0].id
|
||||||
@ -59,6 +74,107 @@ class ProjectTest(DockerClientTestCase):
|
|||||||
project.kill()
|
project.kill()
|
||||||
project.remove_stopped()
|
project.remove_stopped()
|
||||||
|
|
||||||
|
def test_project_up_with_no_recreate_running(self):
|
||||||
|
web = self.create_service('web')
|
||||||
|
db = self.create_service('db', volumes=['/var/db'])
|
||||||
|
project = Project('figtest', [web, db], self.client)
|
||||||
|
project.start()
|
||||||
|
self.assertEqual(len(project.containers()), 0)
|
||||||
|
|
||||||
|
project.up(['db'])
|
||||||
|
self.assertEqual(len(project.containers()), 1)
|
||||||
|
old_db_id = project.containers()[0].id
|
||||||
|
db_volume_path = project.containers()[0].inspect()['Volumes']['/var/db']
|
||||||
|
|
||||||
|
project.up(recreate=False)
|
||||||
|
self.assertEqual(len(project.containers()), 2)
|
||||||
|
|
||||||
|
db_container = [c for c in project.containers() if 'db' in c.name][0]
|
||||||
|
self.assertEqual(c.id, old_db_id)
|
||||||
|
self.assertEqual(c.inspect()['Volumes']['/var/db'], db_volume_path)
|
||||||
|
|
||||||
|
project.kill()
|
||||||
|
project.remove_stopped()
|
||||||
|
|
||||||
|
def test_project_up_with_no_recreate_stopped(self):
|
||||||
|
web = self.create_service('web')
|
||||||
|
db = self.create_service('db', volumes=['/var/db'])
|
||||||
|
project = Project('figtest', [web, db], self.client)
|
||||||
|
project.start()
|
||||||
|
self.assertEqual(len(project.containers()), 0)
|
||||||
|
|
||||||
|
project.up(['db'])
|
||||||
|
project.stop()
|
||||||
|
|
||||||
|
old_containers = project.containers(stopped=True)
|
||||||
|
|
||||||
|
self.assertEqual(len(old_containers), 1)
|
||||||
|
old_db_id = old_containers[0].id
|
||||||
|
db_volume_path = old_containers[0].inspect()['Volumes']['/var/db']
|
||||||
|
|
||||||
|
project.up(recreate=False)
|
||||||
|
|
||||||
|
new_containers = project.containers(stopped=True)
|
||||||
|
self.assertEqual(len(new_containers), 2)
|
||||||
|
|
||||||
|
db_container = [c for c in new_containers if 'db' in c.name][0]
|
||||||
|
self.assertEqual(c.id, old_db_id)
|
||||||
|
self.assertEqual(c.inspect()['Volumes']['/var/db'], db_volume_path)
|
||||||
|
|
||||||
|
project.kill()
|
||||||
|
project.remove_stopped()
|
||||||
|
|
||||||
|
def test_project_up_without_all_services(self):
|
||||||
|
console = self.create_service('console')
|
||||||
|
db = self.create_service('db')
|
||||||
|
project = Project('figtest', [console, db], self.client)
|
||||||
|
project.start()
|
||||||
|
self.assertEqual(len(project.containers()), 0)
|
||||||
|
|
||||||
|
project.up()
|
||||||
|
self.assertEqual(len(project.containers()), 2)
|
||||||
|
self.assertEqual(len(db.containers()), 1)
|
||||||
|
self.assertEqual(len(console.containers()), 1)
|
||||||
|
|
||||||
|
project.kill()
|
||||||
|
project.remove_stopped()
|
||||||
|
|
||||||
|
def test_project_up_starts_links(self):
|
||||||
|
console = self.create_service('console')
|
||||||
|
db = self.create_service('db', volumes=['/var/db'])
|
||||||
|
web = self.create_service('web', links=[(db, 'db')])
|
||||||
|
|
||||||
|
project = Project('figtest', [web, db, console], self.client)
|
||||||
|
project.start()
|
||||||
|
self.assertEqual(len(project.containers()), 0)
|
||||||
|
|
||||||
|
project.up(['web'])
|
||||||
|
self.assertEqual(len(project.containers()), 2)
|
||||||
|
self.assertEqual(len(web.containers()), 1)
|
||||||
|
self.assertEqual(len(db.containers()), 1)
|
||||||
|
self.assertEqual(len(console.containers()), 0)
|
||||||
|
|
||||||
|
project.kill()
|
||||||
|
project.remove_stopped()
|
||||||
|
|
||||||
|
def test_project_up_with_no_deps(self):
|
||||||
|
console = self.create_service('console')
|
||||||
|
db = self.create_service('db', volumes=['/var/db'])
|
||||||
|
web = self.create_service('web', links=[(db, 'db')])
|
||||||
|
|
||||||
|
project = Project('figtest', [web, db, console], self.client)
|
||||||
|
project.start()
|
||||||
|
self.assertEqual(len(project.containers()), 0)
|
||||||
|
|
||||||
|
project.up(['web'], start_links=False)
|
||||||
|
self.assertEqual(len(project.containers()), 1)
|
||||||
|
self.assertEqual(len(web.containers()), 1)
|
||||||
|
self.assertEqual(len(db.containers()), 0)
|
||||||
|
self.assertEqual(len(console.containers()), 0)
|
||||||
|
|
||||||
|
project.kill()
|
||||||
|
project.remove_stopped()
|
||||||
|
|
||||||
def test_unscale_after_restart(self):
|
def test_unscale_after_restart(self):
|
||||||
web = self.create_service('web')
|
web = self.create_service('web')
|
||||||
project = Project('figtest', [web], self.client)
|
project = Project('figtest', [web], self.client)
|
||||||
|
@ -67,3 +67,68 @@ class ProjectTest(unittest.TestCase):
|
|||||||
)
|
)
|
||||||
project = Project('test', [web], None)
|
project = Project('test', [web], None)
|
||||||
self.assertEqual(project.get_service('web'), web)
|
self.assertEqual(project.get_service('web'), web)
|
||||||
|
|
||||||
|
def test_get_services_returns_all_services_without_args(self):
|
||||||
|
web = Service(
|
||||||
|
project='figtest',
|
||||||
|
name='web',
|
||||||
|
)
|
||||||
|
console = Service(
|
||||||
|
project='figtest',
|
||||||
|
name='console',
|
||||||
|
)
|
||||||
|
project = Project('test', [web, console], None)
|
||||||
|
self.assertEqual(project.get_services(), [web, console])
|
||||||
|
|
||||||
|
def test_get_services_returns_listed_services_with_args(self):
|
||||||
|
web = Service(
|
||||||
|
project='figtest',
|
||||||
|
name='web',
|
||||||
|
)
|
||||||
|
console = Service(
|
||||||
|
project='figtest',
|
||||||
|
name='console',
|
||||||
|
)
|
||||||
|
project = Project('test', [web, console], None)
|
||||||
|
self.assertEqual(project.get_services(['console']), [console])
|
||||||
|
|
||||||
|
def test_get_services_with_include_links(self):
|
||||||
|
db = Service(
|
||||||
|
project='figtest',
|
||||||
|
name='db',
|
||||||
|
)
|
||||||
|
web = Service(
|
||||||
|
project='figtest',
|
||||||
|
name='web',
|
||||||
|
links=[(db, 'database')]
|
||||||
|
)
|
||||||
|
cache = Service(
|
||||||
|
project='figtest',
|
||||||
|
name='cache'
|
||||||
|
)
|
||||||
|
console = Service(
|
||||||
|
project='figtest',
|
||||||
|
name='console',
|
||||||
|
links=[(web, 'web')]
|
||||||
|
)
|
||||||
|
project = Project('test', [web, db, cache, console], None)
|
||||||
|
self.assertEqual(
|
||||||
|
project.get_services(['console'], include_links=True),
|
||||||
|
[db, web, console]
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_get_services_removes_duplicates_following_links(self):
|
||||||
|
db = Service(
|
||||||
|
project='figtest',
|
||||||
|
name='db',
|
||||||
|
)
|
||||||
|
web = Service(
|
||||||
|
project='figtest',
|
||||||
|
name='web',
|
||||||
|
links=[(db, 'database')]
|
||||||
|
)
|
||||||
|
project = Project('test', [web, db], None)
|
||||||
|
self.assertEqual(
|
||||||
|
project.get_services(['web', 'db'], include_links=True),
|
||||||
|
[db, web]
|
||||||
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user