From 8b4ed0c1a8c5da8d1bd650698049491d702684d9 Mon Sep 17 00:00:00 2001 From: d11wtq Date: Sat, 7 Jun 2014 08:22:27 +0000 Subject: [PATCH 01/31] Spike: Add 'auto_start' option to fig.yml Signed-off-by: Chris Corbyn --- fig/project.py | 12 +++++++++--- fig/service.py | 5 +++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/fig/project.py b/fig/project.py index b271a810a..1f1571f08 100644 --- a/fig/project.py +++ b/fig/project.py @@ -64,7 +64,13 @@ class Project(object): raise ConfigurationError('Service "%s" has a link to service "%s" which does not exist.' % (service_dict['name'], service_name)) del service_dict['links'] - project.services.append(Service(client=client, project=name, links=links, **service_dict)) + + auto_start = True + if 'auto_start' in service_dict: + auto_start = service_dict.get('auto_start', True) + del service_dict['auto_start'] + + project.services.append(Service(auto_start=auto_start, client=client, project=name, links=links, **service_dict)) return project @classmethod @@ -88,7 +94,7 @@ class Project(object): raise NoSuchService(name) - def get_services(self, service_names=None): + def get_services(self, service_names=None, auto_start=True): """ Returns a list of this project's services filtered by the provided list of names, or all services if @@ -100,7 +106,7 @@ class Project(object): do not exist. """ if service_names is None or len(service_names) == 0: - return self.services + return filter(lambda srv: srv.auto_start == auto_start, self.services) else: unsorted = [self.get_service(name) for name in service_names] return [s for s in self.services if s in unsorted] diff --git a/fig/service.py b/fig/service.py index 21a3ea40d..a954dc4a3 100644 --- a/fig/service.py +++ b/fig/service.py @@ -37,7 +37,7 @@ class ConfigError(ValueError): class Service(object): - def __init__(self, name, client=None, project='default', links=[], **options): + def __init__(self, name, auto_start=True, client=None, project='default', links=[], **options): if not re.match('^[a-zA-Z0-9]+$', name): raise ConfigError('Invalid name: %s' % name) if not re.match('^[a-zA-Z0-9]+$', project): @@ -45,7 +45,7 @@ class Service(object): if 'image' in options and 'build' in options: raise ConfigError('Service %s has both an image and build path specified. A service can either be built to image or use an existing image, not both.' % name) - supported_options = DOCKER_CONFIG_KEYS + ['build', 'expose'] + supported_options = DOCKER_CONFIG_KEYS + ['auto_start', 'build', 'expose'] for k in options: if k not in supported_options: @@ -55,6 +55,7 @@ class Service(object): raise ConfigError(msg) self.name = name + self.auto_start = auto_start self.client = client self.project = project self.links = links or [] From edf6b560167f2ad0b63f17ff402de65d3760f5f9 Mon Sep 17 00:00:00 2001 From: d11wtq Date: Sat, 7 Jun 2014 08:22:54 +0000 Subject: [PATCH 02/31] Spike: Add --up option to `fig run` Signed-off-by: Chris Corbyn --- fig/cli/main.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/fig/cli/main.py b/fig/cli/main.py index f58986458..1e2ea90fc 100644 --- a/fig/cli/main.py +++ b/fig/cli/main.py @@ -202,9 +202,10 @@ class TopLevelCommand(Command): $ 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. + Note that by default 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 either run `fig up -d db` + first, or use `fig run --up SERVICE COMMAND [ARGS...]`. Usage: run [options] SERVICE COMMAND [ARGS...] @@ -214,7 +215,13 @@ class TopLevelCommand(Command): -T Disable pseudo-tty allocation. By default `fig run` allocates a TTY. --rm Remove container after run. Ignored in detached mode. + --up Also start services that the command's service links to """ + + if options['--up']: + # FIXME: I'm not sure if this is good python form + self.up({'-d': True, 'SERVICE': None}) + service = self.project.get_service(options['SERVICE']) tty = True From 0c12db06ec8bafd7a640e09bc0e374038c062b8c Mon Sep 17 00:00:00 2001 From: d11wtq Date: Sat, 7 Jun 2014 13:03:53 +0000 Subject: [PATCH 03/31] Move 'auto_start' option default to Service and add unit tests Signed-off-by: Chris Corbyn --- fig/project.py | 11 +++-------- fig/service.py | 6 ++++-- tests/unit/project_test.py | 2 +- tests/unit/service_test.py | 4 ++++ 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/fig/project.py b/fig/project.py index 1f1571f08..605e4c077 100644 --- a/fig/project.py +++ b/fig/project.py @@ -65,12 +65,7 @@ class Project(object): del service_dict['links'] - auto_start = True - if 'auto_start' in service_dict: - auto_start = service_dict.get('auto_start', True) - del service_dict['auto_start'] - - project.services.append(Service(auto_start=auto_start, client=client, project=name, links=links, **service_dict)) + project.services.append(Service(client=client, project=name, links=links, **service_dict)) return project @classmethod @@ -94,7 +89,7 @@ class Project(object): raise NoSuchService(name) - def get_services(self, service_names=None, auto_start=True): + 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 @@ -106,7 +101,7 @@ class Project(object): do not exist. """ if service_names is None or len(service_names) == 0: - return filter(lambda srv: srv.auto_start == auto_start, self.services) + return filter(lambda s: s.options['auto_start'], self.services) else: unsorted = [self.get_service(name) for name in service_names] return [s for s in self.services if s in unsorted] diff --git a/fig/service.py b/fig/service.py index a954dc4a3..7df3c46b9 100644 --- a/fig/service.py +++ b/fig/service.py @@ -37,7 +37,7 @@ class ConfigError(ValueError): class Service(object): - def __init__(self, name, auto_start=True, client=None, project='default', links=[], **options): + def __init__(self, name, client=None, project='default', links=[], **options): if not re.match('^[a-zA-Z0-9]+$', name): raise ConfigError('Invalid name: %s' % name) if not re.match('^[a-zA-Z0-9]+$', project): @@ -45,6 +45,9 @@ class Service(object): if 'image' in options and 'build' in options: raise ConfigError('Service %s has both an image and build path specified. A service can either be built to image or use an existing image, not both.' % name) + if 'auto_start' not in options: + options['auto_start'] = True + supported_options = DOCKER_CONFIG_KEYS + ['auto_start', 'build', 'expose'] for k in options: @@ -55,7 +58,6 @@ class Service(object): raise ConfigError(msg) self.name = name - self.auto_start = auto_start self.client = client self.project = project self.links = links or [] diff --git a/tests/unit/project_test.py b/tests/unit/project_test.py index 4a2ad1422..f5bacc654 100644 --- a/tests/unit/project_test.py +++ b/tests/unit/project_test.py @@ -13,7 +13,7 @@ class ProjectTest(unittest.TestCase): { 'name': 'db', 'image': 'ubuntu' - } + }, ], None) self.assertEqual(len(project.services), 2) self.assertEqual(project.get_service('web').name, 'web') diff --git a/tests/unit/service_test.py b/tests/unit/service_test.py index 490cb60d6..330e04114 100644 --- a/tests/unit/service_test.py +++ b/tests/unit/service_test.py @@ -20,6 +20,10 @@ class ServiceTest(unittest.TestCase): Service('a') Service('foo') + def test_auto_start_defaults_true(self): + service = Service(name='foo', project='bar') + self.assertEqual(service.options['auto_start'], True) + def test_project_validation(self): self.assertRaises(ConfigError, lambda: Service(name='foo', project='_')) Service(name='foo', project='bar') From dfc74e2a774f2ed09bc277614da8a92ed8ae452a Mon Sep 17 00:00:00 2001 From: d11wtq Date: Sat, 7 Jun 2014 13:19:28 +0000 Subject: [PATCH 04/31] Write integration test for 'auto_start' behaviour Signed-off-by: Chris Corbyn --- tests/integration/project_test.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/integration/project_test.py b/tests/integration/project_test.py index fa7e38586..28dab507a 100644 --- a/tests/integration/project_test.py +++ b/tests/integration/project_test.py @@ -59,6 +59,21 @@ class ProjectTest(DockerClientTestCase): project.kill() project.remove_stopped() + def test_project_up_without_auto_start(self): + console = self.create_service('console', auto_start=False) + 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()), 1) + self.assertEqual(len(db.containers()), 1) + self.assertEqual(len(console.containers()), 0) + + project.kill() + project.remove_stopped() + def test_unscale_after_restart(self): web = self.create_service('web') project = Project('figtest', [web], self.client) From 22c531dea7cf0e9e7de686907033bd1d07c3caef Mon Sep 17 00:00:00 2001 From: d11wtq Date: Sat, 7 Jun 2014 13:29:28 +0000 Subject: [PATCH 05/31] Add unit tests for Project.get_services() Signed-off-by: Chris Corbyn --- tests/unit/project_test.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/unit/project_test.py b/tests/unit/project_test.py index f5bacc654..7c0ee4cd9 100644 --- a/tests/unit/project_test.py +++ b/tests/unit/project_test.py @@ -67,3 +67,29 @@ class ProjectTest(unittest.TestCase): ) project = Project('test', [web], None) self.assertEqual(project.get_service('web'), web) + + def test_get_services_returns_all_auto_started_without_args(self): + web = Service( + project='figtest', + name='web', + ) + console = Service( + project='figtest', + name='console', + auto_start=False + ) + project = Project('test', [web, console], None) + self.assertEqual(project.get_services(), [web]) + + def test_get_services_returns_listed_services_with_args(self): + web = Service( + project='figtest', + name='web', + ) + console = Service( + project='figtest', + name='console', + auto_start=False + ) + project = Project('test', [web, console], None) + self.assertEqual(project.get_services(['console']), [console]) From 13a296049b1be6950a3b0c58581c39a037981b31 Mon Sep 17 00:00:00 2001 From: d11wtq Date: Sat, 7 Jun 2014 13:44:07 +0000 Subject: [PATCH 06/31] Update cli integration test for 'auto_start' behaviour Signed-off-by: Chris Corbyn --- tests/fixtures/simple-figfile/fig.yml | 1 + tests/integration/cli_test.py | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/tests/fixtures/simple-figfile/fig.yml b/tests/fixtures/simple-figfile/fig.yml index 225323755..26b5f439c 100644 --- a/tests/fixtures/simple-figfile/fig.yml +++ b/tests/fixtures/simple-figfile/fig.yml @@ -2,5 +2,6 @@ simple: image: ubuntu command: /bin/sleep 300 another: + auto_start: false image: ubuntu command: /bin/sleep 300 diff --git a/tests/integration/cli_test.py b/tests/integration/cli_test.py index 125b018ed..c94ac20c1 100644 --- a/tests/integration/cli_test.py +++ b/tests/integration/cli_test.py @@ -43,6 +43,13 @@ class CLITestCase(DockerClientTestCase): self.assertNotIn('fig_another_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()), 0) + def test_rm(self): service = self.command.project.get_service('simple') service.create_container() From b081077f2be2d4f2c81e1d513a25d46f5b9892e7 Mon Sep 17 00:00:00 2001 From: d11wtq Date: Sun, 8 Jun 2014 05:51:40 +0000 Subject: [PATCH 07/31] Remove FIXME, as there's nothing to fix :) Signed-off-by: Chris Corbyn --- fig/cli/main.py | 1 - 1 file changed, 1 deletion(-) diff --git a/fig/cli/main.py b/fig/cli/main.py index 1e2ea90fc..aa3b1428e 100644 --- a/fig/cli/main.py +++ b/fig/cli/main.py @@ -219,7 +219,6 @@ class TopLevelCommand(Command): """ if options['--up']: - # FIXME: I'm not sure if this is good python form self.up({'-d': True, 'SERVICE': None}) service = self.project.get_service(options['SERVICE']) From b672861ffdf4afeaad409f53f7db4256b4c03632 Mon Sep 17 00:00:00 2001 From: d11wtq Date: Sun, 8 Jun 2014 06:32:42 +0000 Subject: [PATCH 08/31] Spike: Start linked containers on `fig run` by default Signed-off-by: Chris Corbyn --- fig/cli/main.py | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/fig/cli/main.py b/fig/cli/main.py index aa3b1428e..127760051 100644 --- a/fig/cli/main.py +++ b/fig/cli/main.py @@ -202,27 +202,29 @@ class TopLevelCommand(Command): $ fig run web python manage.py shell - Note that by default 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 either run `fig up -d db` - first, or use `fig run --up SERVICE COMMAND [ARGS...]`. + By default, linked services will be started, unless they are already + running. If you do not want to start linked services, use + `fig run --no-links SERVICE COMMAND [ARGS...]`. Usage: run [options] SERVICE COMMAND [ARGS...] Options: - -d Detached mode: Run container in the background, print new - container name - -T Disable pseudo-tty allocation. By default `fig run` - allocates a TTY. - --rm Remove container after run. Ignored in detached mode. - --up Also start services that the command's service links to + -d Detached mode: Run container in the background, print + new container name. + -T Disable pseudo-tty allocation. By default `fig run` + allocates a TTY. + --rm Remove container after run. Ignored in detached mode. + --no-links Don't start linked services. """ - if options['--up']: - self.up({'-d': True, 'SERVICE': None}) - service = self.project.get_service(options['SERVICE']) + if not options['--no-links']: + self.up({ + '-d': True, + 'SERVICE': self._get_linked_service_names(service) + }) + tty = True if options['-d'] or options['-T'] or not sys.stdin.isatty(): tty = False @@ -338,5 +340,8 @@ class TopLevelCommand(Command): raw=raw, ) + def _get_linked_service_names(self, service): + return [s.name for (s, _) in service.links] + def list_containers(containers): return ", ".join(c.name for c in containers) From 6bfe5e049d4440054b460b92d254b5504b4890aa Mon Sep 17 00:00:00 2001 From: d11wtq Date: Sun, 8 Jun 2014 07:03:18 +0000 Subject: [PATCH 09/31] Spike: Implement --no-links for `fig up` Signed-off-by: Chris Corbyn --- fig/cli/main.py | 22 +++++++++++++--------- fig/project.py | 10 +++++++++- fig/service.py | 3 +++ 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/fig/cli/main.py b/fig/cli/main.py index 127760051..594a20aee 100644 --- a/fig/cli/main.py +++ b/fig/cli/main.py @@ -220,10 +220,10 @@ class TopLevelCommand(Command): service = self.project.get_service(options['SERVICE']) if not options['--no-links']: - self.up({ - '-d': True, - 'SERVICE': self._get_linked_service_names(service) - }) + self.project.up( + service_names=service.get_linked_names(), + start_links=True + ) tty = True if options['-d'] or options['-T'] or not sys.stdin.isatty(): @@ -306,12 +306,16 @@ class TopLevelCommand(Command): Usage: up [options] [SERVICE...] Options: - -d Detached mode: Run containers in the background, print new - container names + -d Detached mode: Run containers in the background, print + new container names. + --no-links Don't start linked services. """ detached = options['-d'] - to_attach = self.project.up(service_names=options['SERVICE']) + start_links = not options['--no-links'] + service_names = options['SERVICE'] + + to_attach = self.project.up(service_names=service_names, start_links=start_links) if not detached: print("Attaching to", list_containers(to_attach)) @@ -321,12 +325,12 @@ class TopLevelCommand(Command): log_printer.run() finally: def handler(signal, frame): - self.project.kill(service_names=options['SERVICE']) + self.project.kill(service_names=service_names) sys.exit(0) signal.signal(signal.SIGINT, handler) 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): socket_in = self.client.attach_socket(container_id, params={'stdin': 1, 'stream': 1}) diff --git a/fig/project.py b/fig/project.py index 605e4c077..5152c5d7d 100644 --- a/fig/project.py +++ b/fig/project.py @@ -125,10 +125,18 @@ class Project(object): else: log.info('%s uses an image, skipping' % service.name) - def up(self, service_names=None): + def up(self, service_names=None, start_links=True): new_containers = [] for service in self.get_services(service_names): + linked_services = service.get_linked_names() + + if start_links and len(linked_services) > 0: + new_containers.extend(self.up( + service_names=linked_services, + start_links=True + )) + for (_, new) in service.recreate_containers(): new_containers.append(new) diff --git a/fig/service.py b/fig/service.py index 7df3c46b9..748b13e02 100644 --- a/fig/service.py +++ b/fig/service.py @@ -242,6 +242,9 @@ class Service(object): ) return container + def get_linked_names(self): + return [s.name for (s, _) in self.links] + def next_container_name(self, one_off=False): bits = [self.project, self.name] if one_off: From 9dd53ecdaa6476d77c8877bfd907d22e0e5d8da1 Mon Sep 17 00:00:00 2001 From: d11wtq Date: Sun, 8 Jun 2014 08:51:09 +0000 Subject: [PATCH 10/31] Fix bug with duplicate service entries in `fig up` Signed-off-by: Chris Corbyn --- fig/project.py | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/fig/project.py b/fig/project.py index 5152c5d7d..15e25d542 100644 --- a/fig/project.py +++ b/fig/project.py @@ -89,22 +89,32 @@ class Project(object): 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 - by the provided list of names, or all services if + by the provided list of names, or all auto_start services if service_names is None or []. + If include_links is specified, returns a list prepended with the needed + links for service_names, in order of dependency. + 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 filter(lambda s: s.options['auto_start'], self.services) + return [s for s in self.services if s.options['auto_start']] else: 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._prepend_with_links, services, []) + + uniques = [] + [uniques.append(s) for s in services if s not in uniques] + return uniques def start(self, service_names=None, **options): for service in self.get_services(service_names): @@ -128,15 +138,7 @@ class Project(object): def up(self, service_names=None, start_links=True): new_containers = [] - for service in self.get_services(service_names): - linked_services = service.get_linked_names() - - if start_links and len(linked_services) > 0: - new_containers.extend(self.up( - service_names=linked_services, - start_links=True - )) - + for service in self.get_services(service_names, include_links=start_links): for (_, new) in service.recreate_containers(): new_containers.append(new) @@ -153,6 +155,14 @@ class Project(object): l.append(container) return l + def _prepend_with_links(self, acc, service): + linked_services = self.get_services( + service_names=service.get_linked_names(), + include_links=True + ) + linked_services.append(service) + return acc + linked_services + class NoSuchService(Exception): def __init__(self, name): From 14cbe40543cdc7526b2e5c8958d6a032cf2f2f0f Mon Sep 17 00:00:00 2001 From: d11wtq Date: Sun, 8 Jun 2014 08:55:14 +0000 Subject: [PATCH 11/31] Update doc string to reflect new behaviour. Signed-off-by: Chris Corbyn --- fig/project.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fig/project.py b/fig/project.py index 15e25d542..1703be688 100644 --- a/fig/project.py +++ b/fig/project.py @@ -95,13 +95,13 @@ class Project(object): by the provided list of names, or all auto_start services if service_names is None or []. - If include_links is specified, returns a list prepended with the needed - links for service_names, in order of dependency. + If include_links is specified, returns a list including the links for + service_names, in order of dependency. - Preserves the original order of self.services. + Preserves the original order of self.services where possible, + reordering as needed to resolve links. - Raises NoSuchService if any of the named services - do not exist. + Raises NoSuchService if any of the named services do not exist. """ if service_names is None or len(service_names) == 0: return [s for s in self.services if s.options['auto_start']] From 949df9772613f4f8ea7a57bf0725c02d9833388c Mon Sep 17 00:00:00 2001 From: d11wtq Date: Sun, 8 Jun 2014 09:09:57 +0000 Subject: [PATCH 12/31] Fix issue with infinite recursion when service_names is empty Signed-off-by: Chris Corbyn --- fig/project.py | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/fig/project.py b/fig/project.py index 1703be688..ac1477edc 100644 --- a/fig/project.py +++ b/fig/project.py @@ -104,7 +104,10 @@ class Project(object): Raises NoSuchService if any of the named services do not exist. """ if service_names is None or len(service_names) == 0: - return [s for s in self.services if s.options['auto_start']] + return self.get_services( + service_names=[s.name for s in self.services if s.options['auto_start']], + include_links=include_links + ) else: unsorted = [self.get_service(name) for name in service_names] services = [s for s in self.services if s in unsorted] @@ -156,10 +159,19 @@ class Project(object): return l def _prepend_with_links(self, acc, service): - linked_services = self.get_services( - service_names=service.get_linked_names(), - include_links=True - ) + if service in acc: + return acc + + 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 From 3d8ce448b861bdb67dc3379c236ca659b835c29e Mon Sep 17 00:00:00 2001 From: d11wtq Date: Sun, 8 Jun 2014 09:48:59 +0000 Subject: [PATCH 13/31] Spike: Re-use existing containers for `fig run` Signed-off-by: Chris Corbyn --- fig/cli/main.py | 15 ++++++++++++--- fig/project.py | 7 ++----- fig/service.py | 15 +++++++++++---- 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/fig/cli/main.py b/fig/cli/main.py index 594a20aee..a107a3fb0 100644 --- a/fig/cli/main.py +++ b/fig/cli/main.py @@ -222,7 +222,8 @@ class TopLevelCommand(Command): if not options['--no-links']: self.project.up( service_names=service.get_linked_names(), - start_links=True + start_links=True, + keep_old=True ) tty = True @@ -301,7 +302,9 @@ class TopLevelCommand(Command): 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. + so that changes in `fig.yml` are picked up. If you do not want existing + containers to be recreated, `fig up --keep-old` will re-use existing + containers. Usage: up [options] [SERVICE...] @@ -309,13 +312,19 @@ class TopLevelCommand(Command): -d Detached mode: Run containers in the background, print new container names. --no-links Don't start linked services. + --keep-old If containers already exist, don't recreate them. """ detached = options['-d'] start_links = not options['--no-links'] + keep_old = options['--keep-old'] service_names = options['SERVICE'] - to_attach = self.project.up(service_names=service_names, start_links=start_links) + to_attach = self.project.up( + service_names=service_names, + start_links=start_links, + keep_old=keep_old + ) if not detached: print("Attaching to", list_containers(to_attach)) diff --git a/fig/project.py b/fig/project.py index ac1477edc..51461cd37 100644 --- a/fig/project.py +++ b/fig/project.py @@ -138,11 +138,11 @@ class Project(object): else: log.info('%s uses an image, skipping' % service.name) - def up(self, service_names=None, start_links=True): + def up(self, service_names=None, start_links=True, keep_old=False): new_containers = [] for service in self.get_services(service_names, include_links=start_links): - for (_, new) in service.recreate_containers(): + for (_, new) in service.recreate_containers(keep_old): new_containers.append(new) return new_containers @@ -159,9 +159,6 @@ class Project(object): return l def _prepend_with_links(self, acc, service): - if service in acc: - return acc - linked_names = service.get_linked_names() if len(linked_names) > 0: diff --git a/fig/service.py b/fig/service.py index 748b13e02..cd9cbf832 100644 --- a/fig/service.py +++ b/fig/service.py @@ -76,9 +76,7 @@ class Service(object): def start(self, **options): for c in self.containers(stopped=True): - if not c.is_running: - log.info("Starting %s..." % c.name) - self.start_container(c, **options) + self.start_container_if_stopped(c, **options) def stop(self, **options): for c in self.containers(): @@ -156,7 +154,7 @@ class Service(object): return Container.create(self.client, **container_options) raise - def recreate_containers(self, **override_options): + def recreate_containers(self, keep_old=False, **override_options): """ If a container for this service doesn't exist, create and start one. If there are any, stop them, create+start new ones, and remove the old containers. @@ -168,6 +166,8 @@ class Service(object): container = self.create_container(**override_options) self.start_container(container) return [(None, container)] + elif keep_old: + return [(None, self.start_container_if_stopped(c)) for c in containers] else: tuples = [] @@ -201,6 +201,13 @@ class Service(object): 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): if container is None: container = self.create_container(**override_options) From ac541e208f1a03e733295a5634fb258b44e94510 Mon Sep 17 00:00:00 2001 From: d11wtq Date: Sun, 8 Jun 2014 10:04:39 +0000 Subject: [PATCH 14/31] Remove obsolete method _get_linked_service_names() Signed-off-by: Chris Corbyn --- fig/cli/main.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/fig/cli/main.py b/fig/cli/main.py index a107a3fb0..6c00cb493 100644 --- a/fig/cli/main.py +++ b/fig/cli/main.py @@ -353,8 +353,5 @@ class TopLevelCommand(Command): raw=raw, ) - def _get_linked_service_names(self, service): - return [s.name for (s, _) in service.links] - def list_containers(containers): return ", ".join(c.name for c in containers) From c0231bdb700e6e3823b9fcd54d49f0d149c97c7e Mon Sep 17 00:00:00 2001 From: d11wtq Date: Sun, 8 Jun 2014 10:08:40 +0000 Subject: [PATCH 15/31] Rename _prepend_with_links() -> _inject_links() Signed-off-by: Chris Corbyn --- fig/project.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fig/project.py b/fig/project.py index 51461cd37..4e74c3afe 100644 --- a/fig/project.py +++ b/fig/project.py @@ -113,7 +113,7 @@ class Project(object): services = [s for s in self.services if s in unsorted] if include_links: - services = reduce(self._prepend_with_links, services, []) + services = reduce(self._inject_links, services, []) uniques = [] [uniques.append(s) for s in services if s not in uniques] @@ -158,7 +158,7 @@ class Project(object): l.append(container) return l - def _prepend_with_links(self, acc, service): + def _inject_links(self, acc, service): linked_names = service.get_linked_names() if len(linked_names) > 0: From 5d92f12f8e33506c986efdf366371a372f3594bb Mon Sep 17 00:00:00 2001 From: d11wtq Date: Sun, 8 Jun 2014 10:58:13 +0000 Subject: [PATCH 16/31] Add unit tests for include_links in get_services() Signed-off-by: Chris Corbyn --- tests/unit/project_test.py | 41 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/tests/unit/project_test.py b/tests/unit/project_test.py index 7c0ee4cd9..0703ae782 100644 --- a/tests/unit/project_test.py +++ b/tests/unit/project_test.py @@ -93,3 +93,44 @@ class ProjectTest(unittest.TestCase): ) 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] + ) From a6c8319b5df7c353de12c87e0896087749159240 Mon Sep 17 00:00:00 2001 From: d11wtq Date: Sun, 8 Jun 2014 11:11:52 +0000 Subject: [PATCH 17/31] Add integration tests for Service.recreate_containers() with keep_old Signed-off-by: Chris Corbyn --- tests/integration/service_test.py | 46 +++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/tests/integration/service_test.py b/tests/integration/service_test.py index 78ddbd850..8f4d3f791 100644 --- a/tests/integration/service_test.py +++ b/tests/integration/service_test.py @@ -132,6 +132,52 @@ class ServiceTest(DockerClientTestCase): self.assertNotEqual(old_container.id, new_container.id) self.assertRaises(APIError, lambda: self.client.inspect_container(intermediate_container.id)) + def test_recreate_containers_with_keep_old_running(self): + service = self.create_service( + 'db', + environment={'FOO': '1'}, + volumes=['/var/db'], + entrypoint=['ps'], + command=['ax'] + ) + old_container = service.create_container() + service.start_container(old_container) + + num_containers_before = len(self.client.containers(all=True)) + + tuples = service.recreate_containers(keep_old=True) + self.assertEqual(len(tuples), 1) + + intermediate_container = tuples[0][0] + new_container = tuples[0][1] + + self.assertIsNone(intermediate_container) + self.assertEqual(len(self.client.containers(all=True)), num_containers_before) + self.assertEqual(old_container.id, new_container.id) + + def test_recreate_containers_with_keep_old_stopped(self): + service = self.create_service( + 'db', + environment={'FOO': '1'}, + volumes=['/var/db'], + entrypoint=['ps'], + command=['ax'] + ) + old_container = service.create_container() + old_container.stop() + + num_containers_before = len(self.client.containers(all=True)) + + tuples = service.recreate_containers(keep_old=True) + self.assertEqual(len(tuples), 1) + + intermediate_container = tuples[0][0] + new_container = tuples[0][1] + + self.assertIsNone(intermediate_container) + self.assertEqual(len(self.client.containers(all=True)), num_containers_before) + self.assertEqual(old_container.id, new_container.id) + def test_start_container_passes_through_options(self): db = self.create_service('db') db.start_container(environment={'FOO': 'BAR'}) From d8b0fa294ecc975093e8d8539ee52151a2136e76 Mon Sep 17 00:00:00 2001 From: d11wtq Date: Sun, 8 Jun 2014 11:32:16 +0000 Subject: [PATCH 18/31] Add integration tests for Project.up() w/ start_links and keep_old Signed-off-by: Chris Corbyn --- tests/integration/project_test.py | 73 +++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/tests/integration/project_test.py b/tests/integration/project_test.py index 28dab507a..f2b9075ef 100644 --- a/tests/integration/project_test.py +++ b/tests/integration/project_test.py @@ -44,6 +44,21 @@ class ProjectTest(DockerClientTestCase): project.start() 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']) self.assertEqual(len(project.containers()), 1) old_db_id = project.containers()[0].id @@ -59,6 +74,28 @@ class ProjectTest(DockerClientTestCase): project.kill() project.remove_stopped() + def test_project_up_with_keep_old(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(keep_old=True) + 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_without_auto_start(self): console = self.create_service('console', auto_start=False) db = self.create_service('db') @@ -74,6 +111,42 @@ class ProjectTest(DockerClientTestCase): 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_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'], 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): web = self.create_service('web') project = Project('figtest', [web], self.client) From 18728a64b9940bb2e29d04a2fc64356be5393efb Mon Sep 17 00:00:00 2001 From: d11wtq Date: Sun, 8 Jun 2014 12:33:08 +0000 Subject: [PATCH 19/31] Write tests for --no-links changes to `fig up` Signed-off-by: Chris Corbyn --- tests/integration/cli_test.py | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/tests/integration/cli_test.py b/tests/integration/cli_test.py index c94ac20c1..c9494fc9b 100644 --- a/tests/integration/cli_test.py +++ b/tests/integration/cli_test.py @@ -1,7 +1,7 @@ from __future__ import unicode_literals from __future__ import absolute_import from .testcases import DockerClientTestCase -from mock import patch +#from mock import patch from fig.cli.main import TopLevelCommand from fig.packages.six import StringIO @@ -50,6 +50,26 @@ class CLITestCase(DockerClientTestCase): self.assertEqual(len(service.containers()), 1) self.assertEqual(len(another.containers()), 0) + def test_up_with_links(self): + self.command.base_dir = 'tests/fixtures/links-figfile' + self.command.dispatch([str('up'), str('-d'), str('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_links(self): + self.command.base_dir = 'tests/fixtures/links-figfile' + self.command.dispatch([str('up'), str('-d'), str('--no-links'), str('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_rm(self): service = self.command.project.get_service('simple') service.create_container() From 94a31642481bf5f6d21e73c783561c05318e619e Mon Sep 17 00:00:00 2001 From: d11wtq Date: Sun, 8 Jun 2014 12:37:42 +0000 Subject: [PATCH 20/31] Re-add missing import for patch Signed-off-by: Chris Corbyn --- tests/integration/cli_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/cli_test.py b/tests/integration/cli_test.py index c9494fc9b..0380b2b8e 100644 --- a/tests/integration/cli_test.py +++ b/tests/integration/cli_test.py @@ -1,7 +1,7 @@ from __future__ import unicode_literals from __future__ import absolute_import from .testcases import DockerClientTestCase -#from mock import patch +from mock import patch from fig.cli.main import TopLevelCommand from fig.packages.six import StringIO From 655d347ea2b298fd9928718d9c0dfc66fe189205 Mon Sep 17 00:00:00 2001 From: d11wtq Date: Sun, 8 Jun 2014 13:03:58 +0000 Subject: [PATCH 21/31] Write integration tests on new `fig run` linking behaviour Signed-off-by: Chris Corbyn --- tests/integration/cli_test.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/integration/cli_test.py b/tests/integration/cli_test.py index 0380b2b8e..dbdd2a8aa 100644 --- a/tests/integration/cli_test.py +++ b/tests/integration/cli_test.py @@ -4,14 +4,18 @@ from .testcases import DockerClientTestCase from mock import patch from fig.cli.main import TopLevelCommand from fig.packages.six import StringIO +import sys class CLITestCase(DockerClientTestCase): def setUp(self): super(CLITestCase, self).setUp() + self.old_sys_exit = sys.exit + sys.exit = lambda code=0: None self.command = TopLevelCommand() self.command.base_dir = 'tests/fixtures/simple-figfile' def tearDown(self): + sys.exit = self.old_sys_exit self.command.project.kill() self.command.project.remove_stopped() @@ -70,6 +74,26 @@ class CLITestCase(DockerClientTestCase): self.assertEqual(len(db.containers()), 0) self.assertEqual(len(console.containers()), 0) + @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([str('run'), str('web'), str('/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_links(self, mock_stdout): + mock_stdout.fileno = lambda: 1 + + self.command.base_dir = 'tests/fixtures/links-figfile' + self.command.dispatch([str('run'), str('--no-links'), str('web'), str('/bin/true')], None) + db = self.command.project.get_service('db') + self.assertEqual(len(db.containers()), 0) + def test_rm(self): service = self.command.project.get_service('simple') service.create_container() From 6c4299039a1e6c13dea0b9c3eaa08a1bab345ceb Mon Sep 17 00:00:00 2001 From: d11wtq Date: Sun, 8 Jun 2014 13:16:14 +0000 Subject: [PATCH 22/31] Write integration tests for `--keep-old` in the CLI Signed-off-by: Chris Corbyn --- tests/integration/cli_test.py | 47 +++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/tests/integration/cli_test.py b/tests/integration/cli_test.py index dbdd2a8aa..c615b1676 100644 --- a/tests/integration/cli_test.py +++ b/tests/integration/cli_test.py @@ -74,6 +74,35 @@ class CLITestCase(DockerClientTestCase): 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([str('up'), str('-d'), str('--keep-old')], 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 @@ -94,6 +123,24 @@ class CLITestCase(DockerClientTestCase): 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([str('up'), str('-d'), str('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([str('run'), str('web'), str('/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): service = self.command.project.get_service('simple') service.create_container() From a04143e2a7aec2e61fe9e89ef2938c04ff018bbb Mon Sep 17 00:00:00 2001 From: d11wtq Date: Sun, 8 Jun 2014 13:16:59 +0000 Subject: [PATCH 23/31] Remove unused: from __future__ import unicode_literals. This is not being used and it confuses the Command class. Rather than try to fix the Command class, I've taken the pragmatic approach and removed the trigger that confuses it. Signed-off-by: Chris Corbyn --- tests/integration/cli_test.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/tests/integration/cli_test.py b/tests/integration/cli_test.py index c615b1676..1000e8dab 100644 --- a/tests/integration/cli_test.py +++ b/tests/integration/cli_test.py @@ -1,4 +1,3 @@ -from __future__ import unicode_literals from __future__ import absolute_import from .testcases import DockerClientTestCase from mock import patch @@ -56,7 +55,7 @@ class CLITestCase(DockerClientTestCase): def test_up_with_links(self): self.command.base_dir = 'tests/fixtures/links-figfile' - self.command.dispatch([str('up'), str('-d'), str('web')], None) + 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') @@ -66,7 +65,7 @@ class CLITestCase(DockerClientTestCase): def test_up_with_no_links(self): self.command.base_dir = 'tests/fixtures/links-figfile' - self.command.dispatch([str('up'), str('-d'), str('--no-links'), str('web')], None) + self.command.dispatch(['up', '-d', '--no-links', 'web'], None) web = self.command.project.get_service('web') db = self.command.project.get_service('db') console = self.command.project.get_service('console') @@ -95,7 +94,7 @@ class CLITestCase(DockerClientTestCase): old_ids = [c.id for c in service.containers()] - self.command.dispatch([str('up'), str('-d'), str('--keep-old')], None) + self.command.dispatch(['up', '-d', '--keep-old'], None) self.assertEqual(len(service.containers()), 1) new_ids = [c.id for c in service.containers()] @@ -108,7 +107,7 @@ class CLITestCase(DockerClientTestCase): mock_stdout.fileno = lambda: 1 self.command.base_dir = 'tests/fixtures/links-figfile' - self.command.dispatch([str('run'), str('web'), str('/bin/true')], None) + 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) @@ -119,7 +118,7 @@ class CLITestCase(DockerClientTestCase): mock_stdout.fileno = lambda: 1 self.command.base_dir = 'tests/fixtures/links-figfile' - self.command.dispatch([str('run'), str('--no-links'), str('web'), str('/bin/true')], None) + self.command.dispatch(['run', '--no-links', 'web', '/bin/true'], None) db = self.command.project.get_service('db') self.assertEqual(len(db.containers()), 0) @@ -128,13 +127,13 @@ class CLITestCase(DockerClientTestCase): mock_stdout.fileno = lambda: 1 self.command.base_dir = 'tests/fixtures/links-figfile' - self.command.dispatch([str('up'), str('-d'), str('db')], None) + 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([str('run'), str('web'), str('/bin/true')], None) + self.command.dispatch(['run', 'web', '/bin/true'], None) self.assertEqual(len(db.containers()), 1) new_ids = [c.id for c in db.containers()] From ab1fbc96c3cb1f4add960d55b5d3d7fcfa88a436 Mon Sep 17 00:00:00 2001 From: d11wtq Date: Sun, 8 Jun 2014 22:47:09 +0000 Subject: [PATCH 24/31] Move keep_old check up into Project Signed-off-by: Chris Corbyn --- fig/project.py | 12 +++++--- fig/service.py | 14 ++++++++-- tests/integration/project_test.py | 30 +++++++++++++++++++- tests/integration/service_test.py | 46 ------------------------------- 4 files changed, 48 insertions(+), 54 deletions(-) diff --git a/fig/project.py b/fig/project.py index 4e74c3afe..5c798d384 100644 --- a/fig/project.py +++ b/fig/project.py @@ -139,13 +139,17 @@ class Project(object): log.info('%s uses an image, skipping' % service.name) def up(self, service_names=None, start_links=True, keep_old=False): - new_containers = [] + running_containers = [] for service in self.get_services(service_names, include_links=start_links): - for (_, new) in service.recreate_containers(keep_old): - new_containers.append(new) + if keep_old: + for container in service.start_or_create_containers(): + running_containers.append(container) + else: + for (_, container) in service.recreate_containers(): + running_containers.append(container) - return new_containers + return running_containers def remove_stopped(self, service_names=None, **options): for service in self.get_services(service_names): diff --git a/fig/service.py b/fig/service.py index cd9cbf832..7de0ae7dc 100644 --- a/fig/service.py +++ b/fig/service.py @@ -154,7 +154,7 @@ class Service(object): return Container.create(self.client, **container_options) raise - def recreate_containers(self, keep_old=False, **override_options): + def recreate_containers(self, **override_options): """ If a container for this service doesn't exist, create and start one. If there are any, stop them, create+start new ones, and remove the old containers. @@ -166,8 +166,6 @@ class Service(object): container = self.create_container(**override_options) self.start_container(container) return [(None, container)] - elif keep_old: - return [(None, self.start_container_if_stopped(c)) for c in containers] else: tuples = [] @@ -249,6 +247,16 @@ class Service(object): ) 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] diff --git a/tests/integration/project_test.py b/tests/integration/project_test.py index f2b9075ef..0c5c1aa76 100644 --- a/tests/integration/project_test.py +++ b/tests/integration/project_test.py @@ -74,7 +74,7 @@ class ProjectTest(DockerClientTestCase): project.kill() project.remove_stopped() - def test_project_up_with_keep_old(self): + def test_project_up_with_keep_old_running(self): web = self.create_service('web') db = self.create_service('db', volumes=['/var/db']) project = Project('figtest', [web, db], self.client) @@ -96,6 +96,34 @@ class ProjectTest(DockerClientTestCase): project.kill() project.remove_stopped() + def test_project_up_with_keep_old_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(keep_old=True) + + 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_auto_start(self): console = self.create_service('console', auto_start=False) db = self.create_service('db') diff --git a/tests/integration/service_test.py b/tests/integration/service_test.py index 8f4d3f791..78ddbd850 100644 --- a/tests/integration/service_test.py +++ b/tests/integration/service_test.py @@ -132,52 +132,6 @@ class ServiceTest(DockerClientTestCase): self.assertNotEqual(old_container.id, new_container.id) self.assertRaises(APIError, lambda: self.client.inspect_container(intermediate_container.id)) - def test_recreate_containers_with_keep_old_running(self): - service = self.create_service( - 'db', - environment={'FOO': '1'}, - volumes=['/var/db'], - entrypoint=['ps'], - command=['ax'] - ) - old_container = service.create_container() - service.start_container(old_container) - - num_containers_before = len(self.client.containers(all=True)) - - tuples = service.recreate_containers(keep_old=True) - self.assertEqual(len(tuples), 1) - - intermediate_container = tuples[0][0] - new_container = tuples[0][1] - - self.assertIsNone(intermediate_container) - self.assertEqual(len(self.client.containers(all=True)), num_containers_before) - self.assertEqual(old_container.id, new_container.id) - - def test_recreate_containers_with_keep_old_stopped(self): - service = self.create_service( - 'db', - environment={'FOO': '1'}, - volumes=['/var/db'], - entrypoint=['ps'], - command=['ax'] - ) - old_container = service.create_container() - old_container.stop() - - num_containers_before = len(self.client.containers(all=True)) - - tuples = service.recreate_containers(keep_old=True) - self.assertEqual(len(tuples), 1) - - intermediate_container = tuples[0][0] - new_container = tuples[0][1] - - self.assertIsNone(intermediate_container) - self.assertEqual(len(self.client.containers(all=True)), num_containers_before) - self.assertEqual(old_container.id, new_container.id) - def test_start_container_passes_through_options(self): db = self.create_service('db') db.start_container(environment={'FOO': 'BAR'}) From 85b96197999d26da42d74a3768ec02833a7e2946 Mon Sep 17 00:00:00 2001 From: d11wtq Date: Sun, 8 Jun 2014 23:00:15 +0000 Subject: [PATCH 25/31] Document 'auto_start' in fig.yml Signed-off-by: Chris Corbyn --- docs/yml.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/yml.md b/docs/yml.md index 24484d4f6..8a69dffc7 100644 --- a/docs/yml.md +++ b/docs/yml.md @@ -54,6 +54,9 @@ expose: volumes: - cache/:/tmp/cache +-- Do not automatically run this service on `fig up` (default: true) +auto_start: false + -- Add environment variables. environment: RACK_ENV: development From 74e067c6e62818438fee0c88fcbce65db5929d1d Mon Sep 17 00:00:00 2001 From: d11wtq Date: Sun, 8 Jun 2014 23:05:54 +0000 Subject: [PATCH 26/31] Document --keep-old flag in CLI reference Signed-off-by: Chris Corbyn --- docs/cli.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/cli.md b/docs/cli.md index 9eb87f1f8..3d5871ad3 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -45,7 +45,7 @@ For example: $ 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. @@ -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" +If you do not want linked containers to be started when running the one-off command, specify the `--no-links` flag: + + $ fig run --no-links web python manage.py shell + ## scale 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. +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. -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 --keep-old`. This will still start any stopped containers, if needed. [volumes-from]: http://docs.docker.io/en/latest/use/working_with_volumes/ From 1d1e23611b4e8caf87d6d2601bc8ee1e81d7e5db Mon Sep 17 00:00:00 2001 From: d11wtq Date: Sun, 8 Jun 2014 23:20:51 +0000 Subject: [PATCH 27/31] Rename --keep-old to --no-recreate Signed-off-by: Chris Corbyn --- docs/cli.md | 2 +- fig/cli/main.py | 16 ++++++++-------- fig/project.py | 8 ++++---- tests/integration/cli_test.py | 2 +- tests/integration/project_test.py | 8 ++++---- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/docs/cli.md b/docs/cli.md index 3d5871ad3..5e99e8341 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -82,6 +82,6 @@ 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 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 --keep-old`. This will still start any stopped containers, if needed. +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/ diff --git a/fig/cli/main.py b/fig/cli/main.py index 6c00cb493..cfb6a7782 100644 --- a/fig/cli/main.py +++ b/fig/cli/main.py @@ -223,7 +223,7 @@ class TopLevelCommand(Command): self.project.up( service_names=service.get_linked_names(), start_links=True, - keep_old=True + recreate=False ) tty = True @@ -303,27 +303,27 @@ class TopLevelCommand(Command): 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 not want existing - containers to be recreated, `fig up --keep-old` will re-use existing + containers to be recreated, `fig up --no-recreate` will re-use existing containers. Usage: up [options] [SERVICE...] Options: - -d Detached mode: Run containers in the background, print - new container names. - --no-links Don't start linked services. - --keep-old If containers already exist, don't recreate them. + -d Detached mode: Run containers in the background, + print new container names. + --no-links Don't start linked services. + --no-recreate If containers already exist, don't recreate them. """ detached = options['-d'] start_links = not options['--no-links'] - keep_old = options['--keep-old'] + recreate = not options['--no-recreate'] service_names = options['SERVICE'] to_attach = self.project.up( service_names=service_names, start_links=start_links, - keep_old=keep_old + recreate=recreate ) if not detached: diff --git a/fig/project.py b/fig/project.py index 5c798d384..5e2b1fccb 100644 --- a/fig/project.py +++ b/fig/project.py @@ -138,15 +138,15 @@ class Project(object): else: log.info('%s uses an image, skipping' % service.name) - def up(self, service_names=None, start_links=True, keep_old=False): + def up(self, service_names=None, start_links=True, recreate=True): running_containers = [] for service in self.get_services(service_names, include_links=start_links): - if keep_old: - for container in service.start_or_create_containers(): + if recreate: + for (_, container) in service.recreate_containers(): running_containers.append(container) else: - for (_, container) in service.recreate_containers(): + for container in service.start_or_create_containers(): running_containers.append(container) return running_containers diff --git a/tests/integration/cli_test.py b/tests/integration/cli_test.py index 1000e8dab..ba309ef16 100644 --- a/tests/integration/cli_test.py +++ b/tests/integration/cli_test.py @@ -94,7 +94,7 @@ class CLITestCase(DockerClientTestCase): old_ids = [c.id for c in service.containers()] - self.command.dispatch(['up', '-d', '--keep-old'], None) + self.command.dispatch(['up', '-d', '--no-recreate'], None) self.assertEqual(len(service.containers()), 1) new_ids = [c.id for c in service.containers()] diff --git a/tests/integration/project_test.py b/tests/integration/project_test.py index 0c5c1aa76..dcca570b2 100644 --- a/tests/integration/project_test.py +++ b/tests/integration/project_test.py @@ -74,7 +74,7 @@ class ProjectTest(DockerClientTestCase): project.kill() project.remove_stopped() - def test_project_up_with_keep_old_running(self): + 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) @@ -86,7 +86,7 @@ class ProjectTest(DockerClientTestCase): old_db_id = project.containers()[0].id db_volume_path = project.containers()[0].inspect()['Volumes']['/var/db'] - project.up(keep_old=True) + project.up(recreate=False) self.assertEqual(len(project.containers()), 2) db_container = [c for c in project.containers() if 'db' in c.name][0] @@ -96,7 +96,7 @@ class ProjectTest(DockerClientTestCase): project.kill() project.remove_stopped() - def test_project_up_with_keep_old_stopped(self): + 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) @@ -112,7 +112,7 @@ class ProjectTest(DockerClientTestCase): old_db_id = old_containers[0].id db_volume_path = old_containers[0].inspect()['Volumes']['/var/db'] - project.up(keep_old=True) + project.up(recreate=False) new_containers = project.containers(stopped=True) self.assertEqual(len(new_containers), 2) From e71e82f8ac167ae840af1395bb474239c5d431a8 Mon Sep 17 00:00:00 2001 From: Chris Corbyn Date: Wed, 11 Jun 2014 10:09:54 +0000 Subject: [PATCH 28/31] Add missing fixture file Signed-off-by: Chris Corbyn --- tests/fixtures/links-figfile/fig.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tests/fixtures/links-figfile/fig.yml diff --git a/tests/fixtures/links-figfile/fig.yml b/tests/fixtures/links-figfile/fig.yml new file mode 100644 index 000000000..955436336 --- /dev/null +++ b/tests/fixtures/links-figfile/fig.yml @@ -0,0 +1,11 @@ +db: + image: ubuntu + command: /bin/sleep 300 +web: + image: ubuntu + command: /bin/sleep 300 + links: + - db:db +console: + image: ubuntu + command: /bin/sleep 300 From 6e485df0845618af78ee19869c5df924e1a3ce93 Mon Sep 17 00:00:00 2001 From: d11wtq Date: Wed, 11 Jun 2014 10:41:24 +0000 Subject: [PATCH 29/31] Rename --no-links to --only Signed-off-by: d11wtq --- docs/cli.md | 4 ++-- fig/cli/main.py | 24 ++++++++++++------------ tests/integration/cli_test.py | 4 ++-- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/docs/cli.md b/docs/cli.md index 5e99e8341..ac22feeee 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -53,9 +53,9 @@ 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" -If you do not want linked containers to be started when running the one-off command, specify the `--no-links` flag: +If you do not want linked containers to be started when running the one-off command, specify the `--only` flag: - $ fig run --no-links web python manage.py shell + $ fig run --only web python manage.py shell ## scale diff --git a/fig/cli/main.py b/fig/cli/main.py index cfb6a7782..3847e9821 100644 --- a/fig/cli/main.py +++ b/fig/cli/main.py @@ -204,22 +204,22 @@ class TopLevelCommand(Command): By default, linked services will be started, unless they are already running. If you do not want to start linked services, use - `fig run --no-links SERVICE COMMAND [ARGS...]`. + `fig run --only SERVICE COMMAND [ARGS...]`. Usage: run [options] SERVICE COMMAND [ARGS...] Options: - -d Detached mode: Run container in the background, print - new container name. - -T Disable pseudo-tty allocation. By default `fig run` - allocates a TTY. - --rm Remove container after run. Ignored in detached mode. - --no-links Don't start linked services. + -d Detached mode: Run container in the background, print new + container name. + -T Disable pseudo-tty allocation. By default `fig run` + allocates a TTY. + --rm Remove container after run. Ignored in detached mode. + --only Don't start linked services. """ service = self.project.get_service(options['SERVICE']) - if not options['--no-links']: + if not options['--only']: self.project.up( service_names=service.get_linked_names(), start_links=True, @@ -309,14 +309,14 @@ class TopLevelCommand(Command): Usage: up [options] [SERVICE...] Options: - -d Detached mode: Run containers in the background, - print new container names. - --no-links Don't start linked services. + -d Detached mode: Run containers in the background, + print new container names. + --only Don't start linked services. --no-recreate If containers already exist, don't recreate them. """ detached = options['-d'] - start_links = not options['--no-links'] + start_links = not options['--only'] recreate = not options['--no-recreate'] service_names = options['SERVICE'] diff --git a/tests/integration/cli_test.py b/tests/integration/cli_test.py index ba309ef16..00e1b79cb 100644 --- a/tests/integration/cli_test.py +++ b/tests/integration/cli_test.py @@ -65,7 +65,7 @@ class CLITestCase(DockerClientTestCase): def test_up_with_no_links(self): self.command.base_dir = 'tests/fixtures/links-figfile' - self.command.dispatch(['up', '-d', '--no-links', 'web'], None) + self.command.dispatch(['up', '-d', '--only', 'web'], None) web = self.command.project.get_service('web') db = self.command.project.get_service('db') console = self.command.project.get_service('console') @@ -118,7 +118,7 @@ class CLITestCase(DockerClientTestCase): mock_stdout.fileno = lambda: 1 self.command.base_dir = 'tests/fixtures/links-figfile' - self.command.dispatch(['run', '--no-links', 'web', '/bin/true'], None) + self.command.dispatch(['run', '--only', 'web', '/bin/true'], None) db = self.command.project.get_service('db') self.assertEqual(len(db.containers()), 0) From 0fc9cc65d135e509097677beeeef985567e2f47f Mon Sep 17 00:00:00 2001 From: Chris Corbyn Date: Sat, 21 Jun 2014 10:30:36 +0000 Subject: [PATCH 30/31] Rename '--only' => '--no-deps' Signed-off-by: Chris Corbyn --- docs/cli.md | 4 ++-- fig/cli/main.py | 24 ++++++++++++------------ tests/integration/cli_test.py | 10 +++++----- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/docs/cli.md b/docs/cli.md index ac22feeee..a697ab7ae 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -53,9 +53,9 @@ 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" -If you do not want linked containers to be started when running the one-off command, specify the `--only` flag: +If you do not want linked containers to be started when running the one-off command, specify the `--no-deps` flag: - $ fig run --only web python manage.py shell + $ fig run --no-deps web python manage.py shell ## scale diff --git a/fig/cli/main.py b/fig/cli/main.py index 3847e9821..9e4e46699 100644 --- a/fig/cli/main.py +++ b/fig/cli/main.py @@ -204,22 +204,22 @@ class TopLevelCommand(Command): By default, linked services will be started, unless they are already running. If you do not want to start linked services, use - `fig run --only SERVICE COMMAND [ARGS...]`. + `fig run --no-deps SERVICE COMMAND [ARGS...]`. Usage: run [options] SERVICE COMMAND [ARGS...] Options: - -d Detached mode: Run container in the background, print new - container name. - -T Disable pseudo-tty allocation. By default `fig run` - allocates a TTY. - --rm Remove container after run. Ignored in detached mode. - --only Don't start linked services. + -d Detached mode: Run container in the background, print + new container name. + -T Disable pseudo-tty allocation. By default `fig run` + allocates a TTY. + --rm Remove container after run. Ignored in detached mode. + --no-deps Don't start linked services. """ service = self.project.get_service(options['SERVICE']) - if not options['--only']: + if not options['--no-deps']: self.project.up( service_names=service.get_linked_names(), start_links=True, @@ -309,14 +309,14 @@ class TopLevelCommand(Command): Usage: up [options] [SERVICE...] Options: - -d Detached mode: Run containers in the background, - print new container names. - --only Don't start linked services. + -d Detached mode: Run containers in the background, + print new container names. + --no-deps Don't start linked services. --no-recreate If containers already exist, don't recreate them. """ detached = options['-d'] - start_links = not options['--only'] + start_links = not options['--no-deps'] recreate = not options['--no-recreate'] service_names = options['SERVICE'] diff --git a/tests/integration/cli_test.py b/tests/integration/cli_test.py index 00e1b79cb..87c9680ba 100644 --- a/tests/integration/cli_test.py +++ b/tests/integration/cli_test.py @@ -51,7 +51,7 @@ class CLITestCase(DockerClientTestCase): 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()), 0) + self.assertEqual(len(another.containers()), 1) def test_up_with_links(self): self.command.base_dir = 'tests/fixtures/links-figfile' @@ -63,9 +63,9 @@ class CLITestCase(DockerClientTestCase): self.assertEqual(len(db.containers()), 1) self.assertEqual(len(console.containers()), 0) - def test_up_with_no_links(self): + def test_up_with_no_deps(self): self.command.base_dir = 'tests/fixtures/links-figfile' - self.command.dispatch(['up', '-d', '--only', 'web'], None) + 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') @@ -114,11 +114,11 @@ class CLITestCase(DockerClientTestCase): self.assertEqual(len(console.containers()), 0) @patch('sys.stdout', new_callable=StringIO) - def test_run_with_no_links(self, mock_stdout): + 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', '--only', 'web', '/bin/true'], None) + self.command.dispatch(['run', '--no-deps', 'web', '/bin/true'], None) db = self.command.project.get_service('db') self.assertEqual(len(db.containers()), 0) From 247691ca4470e685e0f42fb6e455f0b88b04470b Mon Sep 17 00:00:00 2001 From: Chris Corbyn Date: Sat, 21 Jun 2014 10:39:36 +0000 Subject: [PATCH 31/31] Remove auto_start option from fig.yml. This option is redundant now that services can be started along with links. Signed-off-by: Chris Corbyn --- docs/yml.md | 3 --- fig/project.py | 6 +++--- fig/service.py | 5 +---- tests/fixtures/simple-figfile/fig.yml | 1 - tests/integration/project_test.py | 10 +++++----- tests/unit/project_test.py | 6 ++---- tests/unit/service_test.py | 4 ---- 7 files changed, 11 insertions(+), 24 deletions(-) diff --git a/docs/yml.md b/docs/yml.md index 8a69dffc7..24484d4f6 100644 --- a/docs/yml.md +++ b/docs/yml.md @@ -54,9 +54,6 @@ expose: volumes: - cache/:/tmp/cache --- Do not automatically run this service on `fig up` (default: true) -auto_start: false - -- Add environment variables. environment: RACK_ENV: development diff --git a/fig/project.py b/fig/project.py index 5e2b1fccb..a3b78f5d5 100644 --- a/fig/project.py +++ b/fig/project.py @@ -92,8 +92,8 @@ class Project(object): def get_services(self, service_names=None, include_links=False): """ Returns a list of this project's services filtered - by the provided list of names, or all auto_start services if - service_names is None or []. + by the provided list of names, or all services if service_names is None + or []. If include_links is specified, returns a list including the links for service_names, in order of dependency. @@ -105,7 +105,7 @@ class Project(object): """ if service_names is None or len(service_names) == 0: return self.get_services( - service_names=[s.name for s in self.services if s.options['auto_start']], + service_names=[s.name for s in self.services], include_links=include_links ) else: diff --git a/fig/service.py b/fig/service.py index 7de0ae7dc..c49f0fd80 100644 --- a/fig/service.py +++ b/fig/service.py @@ -45,10 +45,7 @@ class Service(object): if 'image' in options and 'build' in options: raise ConfigError('Service %s has both an image and build path specified. A service can either be built to image or use an existing image, not both.' % name) - if 'auto_start' not in options: - options['auto_start'] = True - - supported_options = DOCKER_CONFIG_KEYS + ['auto_start', 'build', 'expose'] + supported_options = DOCKER_CONFIG_KEYS + ['build', 'expose'] for k in options: if k not in supported_options: diff --git a/tests/fixtures/simple-figfile/fig.yml b/tests/fixtures/simple-figfile/fig.yml index e301dc622..3538ab097 100644 --- a/tests/fixtures/simple-figfile/fig.yml +++ b/tests/fixtures/simple-figfile/fig.yml @@ -2,6 +2,5 @@ simple: image: busybox:latest command: /bin/sleep 300 another: - auto_start: false image: busybox:latest command: /bin/sleep 300 diff --git a/tests/integration/project_test.py b/tests/integration/project_test.py index dcca570b2..f52476828 100644 --- a/tests/integration/project_test.py +++ b/tests/integration/project_test.py @@ -124,17 +124,17 @@ class ProjectTest(DockerClientTestCase): project.kill() project.remove_stopped() - def test_project_up_without_auto_start(self): - console = self.create_service('console', auto_start=False) + 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()), 1) + self.assertEqual(len(project.containers()), 2) self.assertEqual(len(db.containers()), 1) - self.assertEqual(len(console.containers()), 0) + self.assertEqual(len(console.containers()), 1) project.kill() project.remove_stopped() @@ -157,7 +157,7 @@ class ProjectTest(DockerClientTestCase): project.kill() project.remove_stopped() - def test_project_up_with_no_links(self): + 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')]) diff --git a/tests/unit/project_test.py b/tests/unit/project_test.py index 5acd2b4c8..ce80333f2 100644 --- a/tests/unit/project_test.py +++ b/tests/unit/project_test.py @@ -68,7 +68,7 @@ class ProjectTest(unittest.TestCase): project = Project('test', [web], None) self.assertEqual(project.get_service('web'), web) - def test_get_services_returns_all_auto_started_without_args(self): + def test_get_services_returns_all_services_without_args(self): web = Service( project='figtest', name='web', @@ -76,10 +76,9 @@ class ProjectTest(unittest.TestCase): console = Service( project='figtest', name='console', - auto_start=False ) project = Project('test', [web, console], None) - self.assertEqual(project.get_services(), [web]) + self.assertEqual(project.get_services(), [web, console]) def test_get_services_returns_listed_services_with_args(self): web = Service( @@ -89,7 +88,6 @@ class ProjectTest(unittest.TestCase): console = Service( project='figtest', name='console', - auto_start=False ) project = Project('test', [web, console], None) self.assertEqual(project.get_services(['console']), [console]) diff --git a/tests/unit/service_test.py b/tests/unit/service_test.py index 330e04114..490cb60d6 100644 --- a/tests/unit/service_test.py +++ b/tests/unit/service_test.py @@ -20,10 +20,6 @@ class ServiceTest(unittest.TestCase): Service('a') Service('foo') - def test_auto_start_defaults_true(self): - service = Service(name='foo', project='bar') - self.assertEqual(service.options['auto_start'], True) - def test_project_validation(self): self.assertRaises(ConfigError, lambda: Service(name='foo', project='_')) Service(name='foo', project='bar')