Merge pull request #4555 from kbh2o/abort_abort

Return exit code when exiting with --abort-on-container-exit
This commit is contained in:
Joffrey F 2017-03-01 17:51:58 -08:00 committed by GitHub
commit b4f4ff1a6b
6 changed files with 47 additions and 15 deletions

View File

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

View File

@ -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):

View File

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

View File

@ -0,0 +1,6 @@
simple:
image: busybox:latest
command: top
another:
image: busybox:latest
command: ls .

View File

@ -0,0 +1,6 @@
simple:
image: busybox:latest
command: top
another:
image: busybox:latest
command: ls /thecakeisalie

View File

@ -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()