mirror of
https://github.com/containers/podman-compose.git
synced 2025-05-20 14:10:56 +02:00
Add --abort-on-container-failure
Signed-off-by: gtebbutt <5956226+gtebbutt@users.noreply.github.com>
This commit is contained in:
parent
d532e09d7d
commit
e1d938ffa6
1
newsfragments/abort-on-container-failure.feature
Normal file
1
newsfragments/abort-on-container-failure.feature
Normal file
@ -0,0 +1 @@
|
|||||||
|
- Added --abort-on-container-failure option, to match docker-compose
|
@ -2978,9 +2978,20 @@ async def compose_up(compose: PodmanCompose, args):
|
|||||||
|
|
||||||
exit_code = 0
|
exit_code = 0
|
||||||
exiting = False
|
exiting = False
|
||||||
|
first_failed_task = None
|
||||||
|
|
||||||
while tasks:
|
while tasks:
|
||||||
done, tasks = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)
|
done, tasks = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)
|
||||||
if args.abort_on_container_exit:
|
|
||||||
|
if args.abort_on_container_failure and first_failed_task is None:
|
||||||
|
# Generally a single returned item when using asyncio.FIRST_COMPLETED, but that's not
|
||||||
|
# guaranteed. If multiple tasks finish at the exact same time the choice of which
|
||||||
|
# finished "first" is arbitrary
|
||||||
|
for t in done:
|
||||||
|
if t.result() != 0:
|
||||||
|
first_failed_task = t
|
||||||
|
|
||||||
|
if args.abort_on_container_exit or first_failed_task:
|
||||||
if not exiting:
|
if not exiting:
|
||||||
# If 2 containers exit at the exact same time, the cancellation of the other ones
|
# If 2 containers exit at the exact same time, the cancellation of the other ones
|
||||||
# cause the status to overwrite. Sleeping for 1 seems to fix this and make it match
|
# cause the status to overwrite. Sleeping for 1 seems to fix this and make it match
|
||||||
@ -2991,9 +3002,14 @@ async def compose_up(compose: PodmanCompose, args):
|
|||||||
t.cancel()
|
t.cancel()
|
||||||
t: Task
|
t: Task
|
||||||
exiting = True
|
exiting = True
|
||||||
for t in done:
|
if first_failed_task:
|
||||||
if t.get_name() == exit_code_from:
|
# Matches docker-compose behaviour, where the exit code of the task that triggered
|
||||||
exit_code = t.result()
|
# the cancellation is always propagated when aborting on failure
|
||||||
|
exit_code = first_failed_task.result()
|
||||||
|
else:
|
||||||
|
for t in done:
|
||||||
|
if t.get_name() == exit_code_from:
|
||||||
|
exit_code = t.result()
|
||||||
|
|
||||||
return exit_code
|
return exit_code
|
||||||
|
|
||||||
@ -3481,7 +3497,7 @@ def compose_up_parse(parser):
|
|||||||
"--detach",
|
"--detach",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
help="Detached mode: Run container in the background, print new container name. \
|
help="Detached mode: Run container in the background, print new container name. \
|
||||||
Incompatible with --abort-on-container-exit.",
|
Incompatible with --abort-on-container-exit and --abort-on-container-failure.",
|
||||||
)
|
)
|
||||||
parser.add_argument("--no-color", action="store_true", help="Produce monochrome output.")
|
parser.add_argument("--no-color", action="store_true", help="Produce monochrome output.")
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
@ -3522,7 +3538,14 @@ def compose_up_parse(parser):
|
|||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--abort-on-container-exit",
|
"--abort-on-container-exit",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
help="Stops all containers if any container was stopped. Incompatible with -d.",
|
help="Stops all containers if any container was stopped. Incompatible with -d and "
|
||||||
|
"--abort-on-container-failure.",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--abort-on-container-failure",
|
||||||
|
action="store_true",
|
||||||
|
help="Stops all containers if any container stops with a non-zero exit code. Incompatible "
|
||||||
|
"with -d and --abort-on-container-exit.",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-t",
|
"-t",
|
||||||
|
0
tests/integration/abort/__init__.py
Normal file
0
tests/integration/abort/__init__.py
Normal file
11
tests/integration/abort/docker-compose-fail-first.yaml
Normal file
11
tests/integration/abort/docker-compose-fail-first.yaml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
sh1:
|
||||||
|
image: nopush/podman-compose-test
|
||||||
|
command: ["dumb-init", "/bin/busybox", "sh", "-c", "sleep 1; exit 1"]
|
||||||
|
sh2:
|
||||||
|
image: nopush/podman-compose-test
|
||||||
|
command: ["dumb-init", "/bin/busybox", "sh", "-c", "sleep 2; exit 0"]
|
||||||
|
sh3:
|
||||||
|
image: nopush/podman-compose-test
|
||||||
|
command: ["dumb-init", "/bin/busybox", "sh", "-c", "sleep 3; exit 0"]
|
11
tests/integration/abort/docker-compose-fail-none.yaml
Normal file
11
tests/integration/abort/docker-compose-fail-none.yaml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
sh1:
|
||||||
|
image: nopush/podman-compose-test
|
||||||
|
command: ["dumb-init", "/bin/busybox", "sh", "-c", "sleep 1; exit 0"]
|
||||||
|
sh2:
|
||||||
|
image: nopush/podman-compose-test
|
||||||
|
command: ["dumb-init", "/bin/busybox", "sh", "-c", "sleep 2; exit 0"]
|
||||||
|
sh3:
|
||||||
|
image: nopush/podman-compose-test
|
||||||
|
command: ["dumb-init", "/bin/busybox", "sh", "-c", "sleep 3; exit 0"]
|
11
tests/integration/abort/docker-compose-fail-second.yaml
Normal file
11
tests/integration/abort/docker-compose-fail-second.yaml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
sh1:
|
||||||
|
image: nopush/podman-compose-test
|
||||||
|
command: ["dumb-init", "/bin/busybox", "sh", "-c", "sleep 1; exit 0"]
|
||||||
|
sh2:
|
||||||
|
image: nopush/podman-compose-test
|
||||||
|
command: ["dumb-init", "/bin/busybox", "sh", "-c", "sleep 2; exit 1"]
|
||||||
|
sh3:
|
||||||
|
image: nopush/podman-compose-test
|
||||||
|
command: ["dumb-init", "/bin/busybox", "sh", "-c", "sleep 3; exit 0"]
|
@ -0,0 +1,11 @@
|
|||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
sh1:
|
||||||
|
image: nopush/podman-compose-test
|
||||||
|
command: ["dumb-init", "/bin/busybox", "sh", "-c", "sleep 1; exit 1"]
|
||||||
|
sh2:
|
||||||
|
image: nopush/podman-compose-test
|
||||||
|
command: ["dumb-init", "/bin/busybox", "sh", "-c", "sleep 1; exit 0"]
|
||||||
|
sh3:
|
||||||
|
image: nopush/podman-compose-test
|
||||||
|
command: ["dumb-init", "/bin/busybox", "sh", "-c", "sleep 2; exit 0"]
|
46
tests/integration/abort/test_podman_compose_abort.py
Normal file
46
tests/integration/abort/test_podman_compose_abort.py
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
import os
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from parameterized import parameterized
|
||||||
|
|
||||||
|
from tests.integration.test_utils import RunSubprocessMixin
|
||||||
|
from tests.integration.test_utils import podman_compose_path
|
||||||
|
from tests.integration.test_utils import test_path
|
||||||
|
|
||||||
|
|
||||||
|
def compose_yaml_path(failure_order):
|
||||||
|
return os.path.join(test_path(), "abort", f"docker-compose-fail-{failure_order}.yaml")
|
||||||
|
|
||||||
|
|
||||||
|
class TestComposeAbort(unittest.TestCase, RunSubprocessMixin):
|
||||||
|
@parameterized.expand([
|
||||||
|
("exit", "first", 0),
|
||||||
|
("failure", "first", 1),
|
||||||
|
("exit", "second", 0),
|
||||||
|
("failure", "second", 1),
|
||||||
|
("exit", "simultaneous", 0),
|
||||||
|
("failure", "simultaneous", 1),
|
||||||
|
("exit", "none", 0),
|
||||||
|
("failure", "none", 0),
|
||||||
|
])
|
||||||
|
def test_abort(self, abort_type, failure_order, expected_exit_code):
|
||||||
|
try:
|
||||||
|
self.run_subprocess_assert_returncode(
|
||||||
|
[
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
compose_yaml_path(failure_order),
|
||||||
|
"up",
|
||||||
|
f"--abort-on-container-{abort_type}",
|
||||||
|
],
|
||||||
|
expected_exit_code,
|
||||||
|
)
|
||||||
|
finally:
|
||||||
|
self.run_subprocess_assert_returncode([
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
compose_yaml_path(failure_order),
|
||||||
|
"down",
|
||||||
|
])
|
Loading…
Reference in New Issue
Block a user