From 9daced4c0433441bd36824b0af06ed0d31392158 Mon Sep 17 00:00:00 2001 From: Joffrey F Date: Fri, 12 May 2017 17:39:56 -0700 Subject: [PATCH] Prevent dependencies rescaling when executing `docker-compose run` Signed-off-by: Joffrey F --- compose/cli/main.py | 4 +++- compose/project.py | 6 ++++-- compose/service.py | 15 ++++++++++----- tests/acceptance/cli_test.py | 11 +++++++++++ 4 files changed, 28 insertions(+), 8 deletions(-) diff --git a/compose/cli/main.py b/compose/cli/main.py index 49800ba53..c91b8d898 100644 --- a/compose/cli/main.py +++ b/compose/cli/main.py @@ -1138,7 +1138,9 @@ def run_one_off_container(container_options, project, service, options): project.up( service_names=deps, start_deps=True, - strategy=ConvergenceStrategy.never) + strategy=ConvergenceStrategy.never, + rescale=False + ) project.initialize() diff --git a/compose/project.py b/compose/project.py index e80b10455..b282f718d 100644 --- a/compose/project.py +++ b/compose/project.py @@ -382,7 +382,8 @@ class Project(object): timeout=None, detached=False, remove_orphans=False, - scale_override=None): + scale_override=None, + rescale=True): warn_for_swarm_mode(self.client) @@ -405,7 +406,8 @@ class Project(object): plans[service.name], timeout=timeout, detached=detached, - scale_override=scale_override.get(service.name) + scale_override=scale_override.get(service.name), + rescale=rescale ) def get_deps(service): diff --git a/compose/service.py b/compose/service.py index 8699372ed..edd0a3764 100644 --- a/compose/service.py +++ b/compose/service.py @@ -390,7 +390,7 @@ class Service(object): return containers def _execute_convergence_recreate(self, containers, scale, timeout, detached, start): - if len(containers) > scale: + if scale is not None and len(containers) > scale: self._downscale(containers[scale:], timeout) containers = containers[:scale] @@ -408,14 +408,14 @@ class Service(object): for error in errors.values(): raise OperationFailedError(error) - if len(containers) < scale: + if scale is not None and len(containers) < scale: containers.extend(self._execute_convergence_create( scale - len(containers), detached, start )) return containers def _execute_convergence_start(self, containers, scale, timeout, detached, start): - if len(containers) > scale: + if scale is not None and len(containers) > scale: self._downscale(containers[scale:], timeout) containers = containers[:scale] if start: @@ -429,7 +429,7 @@ class Service(object): for error in errors.values(): raise OperationFailedError(error) - if len(containers) < scale: + if scale is not None and len(containers) < scale: containers.extend(self._execute_convergence_create( scale - len(containers), detached, start )) @@ -448,7 +448,7 @@ class Service(object): ) def execute_convergence_plan(self, plan, timeout=None, detached=False, - start=True, scale_override=None): + start=True, scale_override=None, rescale=True): (action, containers) = plan scale = scale_override if scale_override is not None else self.scale_num containers = sorted(containers, key=attrgetter('number')) @@ -460,6 +460,11 @@ class Service(object): scale, detached, start ) + # The create action needs always needs an initial scale, but otherwise, + # we set scale to none in no-rescale scenarios (`run` dependencies) + if not rescale: + scale = None + if action == 'recreate': return self._execute_convergence_recreate( containers, scale, timeout, detached, start diff --git a/tests/acceptance/cli_test.py b/tests/acceptance/cli_test.py index 75b15ae65..30eff1b6a 100644 --- a/tests/acceptance/cli_test.py +++ b/tests/acceptance/cli_test.py @@ -1211,6 +1211,17 @@ class CLITestCase(DockerClientTestCase): self.assertEqual(len(db.containers()), 1) self.assertEqual(len(console.containers()), 0) + def test_run_service_with_scaled_dependencies(self): + self.base_dir = 'tests/fixtures/v2-dependencies' + self.dispatch(['up', '-d', '--scale', 'db=2', '--scale', 'console=0']) + db = self.project.get_service('db') + console = self.project.get_service('console') + assert len(db.containers()) == 2 + assert len(console.containers()) == 0 + self.dispatch(['run', 'web', '/bin/true'], None) + assert len(db.containers()) == 2 + assert len(console.containers()) == 0 + def test_run_with_no_deps(self): self.base_dir = 'tests/fixtures/links-composefile' self.dispatch(['run', '--no-deps', 'web', '/bin/true'])