|
|
@@ -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,
|