Make run behave in the same way as up

Signed-off-by: Eric Hripko <ehripko@bloomberg.net>
This commit is contained in:
Eric Hripko 2020-05-15 14:32:18 +01:00
parent 52d2fcc274
commit 06462cd604
6 changed files with 112 additions and 35 deletions

View file

@ -1298,31 +1298,28 @@ def build_one_off_container_options(options, detach, command):
def run_one_off_container(container_options, project, service, options, toplevel_options,
toplevel_environment):
if not options['--no-deps']:
deps = service.get_dependency_names()
if deps:
project.up(
service_names=deps,
start_deps=True,
strategy=ConvergenceStrategy.never,
rescale=False
)
project.initialize()
container = service.create_container(
quiet=True,
detach = options.get('--detach')
use_network_aliases = options.get('--use-aliases')
containers = project.up(
service_names=[service.name],
start_deps=not options['--no-deps'],
strategy=ConvergenceStrategy.never,
detached=detach,
rescale=False,
one_off=True,
**container_options)
override_options=container_options,
)
try:
container = next(c for c in containers if c.service == service.name)
except StopIteration:
raise OperationFailedError('Could not bring up the requested service')
use_network_aliases = options['--use-aliases']
if options.get('--detach'):
if detach:
service.start_container(container, use_network_aliases)
print(container.name)
return
def remove_container(force=False):
def remove_container():
if options['--rm']:
project.client.remove_container(container.id, force=True, v=True)
@ -1355,7 +1352,7 @@ def run_one_off_container(container_options, project, service, options, toplevel
exit_code = 1
except (signals.ShutdownException, signals.HangUpException):
project.client.kill(container.id)
remove_container(force=True)
remove_container()
sys.exit(2)
remove_container()

View file

@ -565,6 +565,8 @@ class Project(object):
renew_anonymous_volumes=False,
silent=False,
cli=False,
one_off=False,
override_options=None,
):
if cli:
@ -584,7 +586,11 @@ class Project(object):
for svc in services:
svc.ensure_image_exists(do_build=do_build, silent=silent, cli=cli)
plans = self._get_convergence_plans(
services, strategy, always_recreate_deps=always_recreate_deps)
services,
strategy,
always_recreate_deps=always_recreate_deps,
one_off=service_names if one_off else [],
)
def do(service):
@ -597,6 +603,7 @@ class Project(object):
start=start,
reset_container_image=reset_container_image,
renew_anonymous_volumes=renew_anonymous_volumes,
override_options=override_options,
)
def get_deps(service):
@ -628,7 +635,7 @@ class Project(object):
self.networks.initialize()
self.volumes.initialize()
def _get_convergence_plans(self, services, strategy, always_recreate_deps=False):
def _get_convergence_plans(self, services, strategy, always_recreate_deps=False, one_off=None):
plans = {}
for service in services:
@ -638,6 +645,7 @@ class Project(object):
if name in plans and
plans[name].action in ('recreate', 'create')
]
is_one_off = one_off and service.name in one_off
if updated_dependencies and strategy.allows_recreate:
log.debug('%s has upstream changes (%s)',
@ -649,11 +657,11 @@ class Project(object):
container_has_links = any(c.get('HostConfig.Links') for c in service.containers())
should_recreate_for_links = service_has_links ^ container_has_links
if always_recreate_deps or containers_stopped or should_recreate_for_links:
plan = service.convergence_plan(ConvergenceStrategy.always)
plan = service.convergence_plan(ConvergenceStrategy.always, is_one_off)
else:
plan = service.convergence_plan(strategy)
plan = service.convergence_plan(strategy, is_one_off)
else:
plan = service.convergence_plan(strategy)
plan = service.convergence_plan(strategy, is_one_off)
plans[service.name] = plan

View file

@ -388,9 +388,12 @@ class Service(object):
platform = self.default_platform
return platform
def convergence_plan(self, strategy=ConvergenceStrategy.changed):
def convergence_plan(self, strategy=ConvergenceStrategy.changed, one_off=False):
containers = self.containers(stopped=True)
if one_off:
return ConvergencePlan('one_off', [])
if not containers:
return ConvergencePlan('create', [])
@ -439,25 +442,37 @@ class Service(object):
return has_diverged
def _execute_convergence_create(self, scale, detached, start):
def _execute_convergence_create(self, scale, detached, start, one_off=False, override_options=None):
i = self._next_container_number()
def create_and_start(service, n):
container = service.create_container(number=n, quiet=True)
if one_off:
container = service.create_container(one_off=True, quiet=True, **override_options)
else:
container = service.create_container(number=n, quiet=True)
if not detached:
container.attach_log_stream()
if start:
if start and not one_off:
self.start_container(container)
return container
def get_name(service_name):
if one_off:
return "_".join([
service_name.project,
service_name.service,
"run",
])
return self.get_container_name(service_name.service, service_name.number)
containers, errors = parallel_execute(
[
ServiceName(self.project, self.name, index)
for index in range(i, i + scale)
],
lambda service_name: create_and_start(self, service_name.number),
lambda service_name: self.get_container_name(service_name.service, service_name.number),
get_name,
"Creating"
)
for error in errors.values():
@ -528,16 +543,20 @@ class Service(object):
def execute_convergence_plan(self, plan, timeout=None, detached=False,
start=True, scale_override=None,
rescale=True, reset_container_image=False,
renew_anonymous_volumes=False):
renew_anonymous_volumes=False, override_options=None):
(action, containers) = plan
scale = scale_override if scale_override is not None else self.scale_num
containers = sorted(containers, key=attrgetter('number'))
self.show_scale_warnings(scale)
if action == 'create':
if action in ['create', 'one_off']:
return self._execute_convergence_create(
scale, detached, start
scale,
detached,
start,
one_off=(action == 'one_off'),
override_options=override_options
)
# The create action needs always needs an initial scale, but otherwise,