mirror of https://github.com/docker/compose.git
Merge pull request #4555 from kbh2o/abort_abort
Return exit code when exiting with --abort-on-container-exit
This commit is contained in:
commit
b4f4ff1a6b
|
@ -87,6 +87,13 @@ class LogPrinter(object):
|
||||||
for line in consume_queue(queue, self.cascade_stop):
|
for line in consume_queue(queue, self.cascade_stop):
|
||||||
remove_stopped_threads(thread_map)
|
remove_stopped_threads(thread_map)
|
||||||
|
|
||||||
|
if self.cascade_stop:
|
||||||
|
matching_container = [cont.name for cont in self.containers if cont.name == line]
|
||||||
|
if line in matching_container:
|
||||||
|
# Returning the name of the container that started the
|
||||||
|
# the cascade_stop so we can return the correct exit code
|
||||||
|
return line
|
||||||
|
|
||||||
if not line:
|
if not line:
|
||||||
if not thread_map:
|
if not thread_map:
|
||||||
# There are no running containers left to tail, so exit
|
# There are no running containers left to tail, so exit
|
||||||
|
@ -132,8 +139,8 @@ class QueueItem(namedtuple('_QueueItem', 'item is_stop exc')):
|
||||||
return cls(None, None, exc)
|
return cls(None, None, exc)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def stop(cls):
|
def stop(cls, item=None):
|
||||||
return cls(None, True, None)
|
return cls(item, True, None)
|
||||||
|
|
||||||
|
|
||||||
def tail_container_logs(container, presenter, queue, log_args):
|
def tail_container_logs(container, presenter, queue, log_args):
|
||||||
|
@ -145,10 +152,9 @@ def tail_container_logs(container, presenter, queue, log_args):
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
queue.put(QueueItem.exception(e))
|
queue.put(QueueItem.exception(e))
|
||||||
return
|
return
|
||||||
|
|
||||||
if log_args.get('follow'):
|
if log_args.get('follow'):
|
||||||
queue.put(QueueItem.new(presenter.color_func(wait_on_exit(container))))
|
queue.put(QueueItem.new(presenter.color_func(wait_on_exit(container))))
|
||||||
queue.put(QueueItem.stop())
|
queue.put(QueueItem.stop(container.name))
|
||||||
|
|
||||||
|
|
||||||
def get_log_generator(container):
|
def get_log_generator(container):
|
||||||
|
@ -228,10 +234,7 @@ def consume_queue(queue, cascade_stop):
|
||||||
if item.exc:
|
if item.exc:
|
||||||
raise item.exc
|
raise item.exc
|
||||||
|
|
||||||
if item.is_stop:
|
if item.is_stop and not cascade_stop:
|
||||||
if cascade_stop:
|
continue
|
||||||
raise StopIteration
|
|
||||||
else:
|
|
||||||
continue
|
|
||||||
|
|
||||||
yield item.item
|
yield item.item
|
||||||
|
|
|
@ -890,11 +890,18 @@ class TopLevelCommand(object):
|
||||||
cascade_stop,
|
cascade_stop,
|
||||||
event_stream=self.project.events(service_names=service_names))
|
event_stream=self.project.events(service_names=service_names))
|
||||||
print("Attaching to", list_containers(log_printer.containers))
|
print("Attaching to", list_containers(log_printer.containers))
|
||||||
log_printer.run()
|
cascade_starter = log_printer.run()
|
||||||
|
|
||||||
if cascade_stop:
|
if cascade_stop:
|
||||||
print("Aborting on container exit...")
|
print("Aborting on container exit...")
|
||||||
|
exit_code = 0
|
||||||
|
for e in self.project.containers(service_names=options['SERVICE'], stopped=True):
|
||||||
|
if (not e.is_running and cascade_starter == e.name):
|
||||||
|
if not e.exit_code == 0:
|
||||||
|
exit_code = e.exit_code
|
||||||
|
break
|
||||||
self.project.stop(service_names=service_names, timeout=timeout)
|
self.project.stop(service_names=service_names, timeout=timeout)
|
||||||
|
sys.exit(exit_code)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def version(cls, options):
|
def version(cls, options):
|
||||||
|
|
|
@ -1085,10 +1085,18 @@ class CLITestCase(DockerClientTestCase):
|
||||||
wait_on_condition(ContainerCountCondition(self.project, 0))
|
wait_on_condition(ContainerCountCondition(self.project, 0))
|
||||||
|
|
||||||
def test_up_handles_abort_on_container_exit(self):
|
def test_up_handles_abort_on_container_exit(self):
|
||||||
start_process(self.base_dir, ['up', '--abort-on-container-exit'])
|
self.base_dir = 'tests/fixtures/abort-on-container-exit-0'
|
||||||
wait_on_condition(ContainerCountCondition(self.project, 2))
|
proc = start_process(self.base_dir, ['up', '--abort-on-container-exit'])
|
||||||
self.project.stop(['simple'])
|
|
||||||
wait_on_condition(ContainerCountCondition(self.project, 0))
|
wait_on_condition(ContainerCountCondition(self.project, 0))
|
||||||
|
proc.wait()
|
||||||
|
self.assertEqual(proc.returncode, 0)
|
||||||
|
|
||||||
|
def test_up_handles_abort_on_container_exit_code(self):
|
||||||
|
self.base_dir = 'tests/fixtures/abort-on-container-exit-1'
|
||||||
|
proc = start_process(self.base_dir, ['up', '--abort-on-container-exit'])
|
||||||
|
wait_on_condition(ContainerCountCondition(self.project, 0))
|
||||||
|
proc.wait()
|
||||||
|
self.assertEqual(proc.returncode, 1)
|
||||||
|
|
||||||
def test_exec_without_tty(self):
|
def test_exec_without_tty(self):
|
||||||
self.base_dir = 'tests/fixtures/links-composefile'
|
self.base_dir = 'tests/fixtures/links-composefile'
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
simple:
|
||||||
|
image: busybox:latest
|
||||||
|
command: top
|
||||||
|
another:
|
||||||
|
image: busybox:latest
|
||||||
|
command: ls .
|
|
@ -0,0 +1,6 @@
|
||||||
|
simple:
|
||||||
|
image: busybox:latest
|
||||||
|
command: top
|
||||||
|
another:
|
||||||
|
image: busybox:latest
|
||||||
|
command: ls /thecakeisalie
|
|
@ -187,11 +187,13 @@ class TestConsumeQueue(object):
|
||||||
assert next(generator) == 'b'
|
assert next(generator) == 'b'
|
||||||
|
|
||||||
def test_item_is_stop_with_cascade_stop(self):
|
def test_item_is_stop_with_cascade_stop(self):
|
||||||
|
"""Return the name of the container that caused the cascade_stop"""
|
||||||
queue = Queue()
|
queue = Queue()
|
||||||
for item in QueueItem.stop(), QueueItem.new('a'), QueueItem.new('b'):
|
for item in QueueItem.stop('foobar-1'), QueueItem.new('a'), QueueItem.new('b'):
|
||||||
queue.put(item)
|
queue.put(item)
|
||||||
|
|
||||||
assert list(consume_queue(queue, True)) == []
|
generator = consume_queue(queue, True)
|
||||||
|
assert next(generator) is 'foobar-1'
|
||||||
|
|
||||||
def test_item_is_none_when_timeout_is_hit(self):
|
def test_item_is_none_when_timeout_is_hit(self):
|
||||||
queue = Queue()
|
queue = Queue()
|
||||||
|
|
Loading…
Reference in New Issue