Skip to content

Return non-zero exit_code on failure when doing up -d #1181

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions newsfragments/handle-up-detach-exitcode.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Return non-zero exit_code on failure when `up -d`
26 changes: 20 additions & 6 deletions podman_compose.py
Original file line number Diff line number Diff line change
Expand Up @@ -2879,11 +2879,15 @@ def deps_from_container(args, cnt):
@cmd_run(podman_compose, "up", "Create and start the entire stack or some of its services")
async def compose_up(compose: PodmanCompose, args):
excluded = get_excluded(compose, args)

if not args.no_build:
# `podman build` does not cache, so don't always build
build_args = argparse.Namespace(if_not_exists=(not args.build), **args.__dict__)
if await compose.commands["build"](compose, build_args) != 0:
build_exit_code = await compose.commands["build"](compose, build_args)
if build_exit_code != 0:
log.error("Build command failed")
if not args.dry_run:
return build_exit_code

hashes = (
(
Expand Down Expand Up @@ -2911,19 +2915,29 @@ async def compose_up(compose: PodmanCompose, args):
# args.no_recreate disables check for changes (which is not implemented)

await create_pods(compose, args)
exit_code = 0
for cnt in compose.containers:
if cnt["_service"] in excluded:
log.debug("** skipping: %s", cnt["name"])
continue
podman_args = await container_to_args(compose, cnt, detached=False, no_deps=args.no_deps)
subproc = await compose.podman.run([], "create", podman_args)
if not args.no_start and args.detach and subproc is not None:
await run_container(
subproc_exit_code = await compose.podman.run([], "create", podman_args)
if subproc_exit_code is not None and subproc_exit_code != 0:
exit_code = subproc_exit_code

if not args.no_start and args.detach and subproc_exit_code is not None:
container_exit_code = await run_container(
compose, cnt["name"], deps_from_container(args, cnt), ([], "start", [cnt["name"]])
)

if args.no_start or args.detach or args.dry_run:
return
if container_exit_code is not None and container_exit_code != 0:
exit_code = container_exit_code

if args.dry_run:
return None
if args.no_start or args.detach:
return exit_code

# TODO: handle already existing
# TODO: if error creating do not enter loop
# TODO: colors if sys.stdout.isatty()
Expand Down
34 changes: 22 additions & 12 deletions tests/integration/in_pod/test_podman_compose_in_pod.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,16 @@ def podman_compose_path():
return os.path.join(base_path(), "podman_compose.py")


def is_root():
return os.geteuid() == 0


def failure_exitcode_when_rootful():
if is_root():
return 125
return 0


# If a compose file has userns_mode set, setting in_pod to True, results in error.
# Default in_pod setting is True, unless compose file provides otherwise.
# Compose file provides custom in_pod option, which can be overridden by command line in_pod option.
Expand Down Expand Up @@ -64,7 +74,7 @@ def test_x_podman_in_pod_false_command_line_in_pod_not_exists(self):
]

try:
self.run_subprocess_assert_returncode(command_up)
self.run_subprocess_assert_returncode(command_up, failure_exitcode_when_rootful())

finally:
self.run_subprocess_assert_returncode(down_cmd)
Expand Down Expand Up @@ -96,7 +106,7 @@ def test_x_podman_in_pod_false_command_line_in_pod_true(self):
]

try:
out, err = self.run_subprocess_assert_returncode(command_up)
out, err = self.run_subprocess_assert_returncode(command_up, 125)
self.assertEqual(b"Error: --userns and --pod cannot be set together" in err, True)

finally:
Expand Down Expand Up @@ -142,7 +152,7 @@ def test_x_podman_in_pod_false_command_line_in_pod_false(self):
]

try:
self.run_subprocess_assert_returncode(command_up)
self.run_subprocess_assert_returncode(command_up, failure_exitcode_when_rootful())

finally:
self.run_subprocess_assert_returncode(down_cmd)
Expand Down Expand Up @@ -188,7 +198,7 @@ def test_x_podman_in_pod_false_command_line_in_pod_empty_string(self):
]

try:
self.run_subprocess_assert_returncode(command_up)
self.run_subprocess_assert_returncode(command_up, failure_exitcode_when_rootful())

finally:
self.run_subprocess_assert_returncode(down_cmd)
Expand Down Expand Up @@ -221,7 +231,7 @@ def test_x_podman_in_pod_true_command_line_in_pod_not_exists(self):
]

try:
out, err = self.run_subprocess_assert_returncode(command_up)
out, err = self.run_subprocess_assert_returncode(command_up, 125)
self.assertEqual(b"Error: --userns and --pod cannot be set together" in err, True)

finally:
Expand Down Expand Up @@ -255,7 +265,7 @@ def test_x_podman_in_pod_true_command_line_in_pod_true(self):
]

try:
out, err = self.run_subprocess_assert_returncode(command_up)
out, err = self.run_subprocess_assert_returncode(command_up, 125)
self.assertEqual(b"Error: --userns and --pod cannot be set together" in err, True)

finally:
Expand Down Expand Up @@ -301,7 +311,7 @@ def test_x_podman_in_pod_true_command_line_in_pod_false(self):
]

try:
self.run_subprocess_assert_returncode(command_up)
self.run_subprocess_assert_returncode(command_up, failure_exitcode_when_rootful())

finally:
self.run_subprocess_assert_returncode(down_cmd)
Expand Down Expand Up @@ -334,7 +344,7 @@ def test_x_podman_in_pod_true_command_line_in_pod_empty_string(self):
]

try:
out, err = self.run_subprocess_assert_returncode(command_up)
out, err = self.run_subprocess_assert_returncode(command_up, 125)
self.assertEqual(b"Error: --userns and --pod cannot be set together" in err, True)

finally:
Expand Down Expand Up @@ -368,7 +378,7 @@ def test_x_podman_in_pod_not_exists_command_line_in_pod_not_exists(self):
]

try:
out, err = self.run_subprocess_assert_returncode(command_up)
out, err = self.run_subprocess_assert_returncode(command_up, 125)
self.assertEqual(b"Error: --userns and --pod cannot be set together" in err, True)

finally:
Expand Down Expand Up @@ -402,7 +412,7 @@ def test_x_podman_in_pod_not_exists_command_line_in_pod_true(self):
]

try:
out, err = self.run_subprocess_assert_returncode(command_up)
out, err = self.run_subprocess_assert_returncode(command_up, 125)
self.assertEqual(b"Error: --userns and --pod cannot be set together" in err, True)

finally:
Expand Down Expand Up @@ -448,7 +458,7 @@ def test_x_podman_in_pod_not_exists_command_line_in_pod_false(self):
]

try:
self.run_subprocess_assert_returncode(command_up)
self.run_subprocess_assert_returncode(command_up, failure_exitcode_when_rootful())

finally:
self.run_subprocess_assert_returncode(down_cmd)
Expand Down Expand Up @@ -482,7 +492,7 @@ def test_x_podman_in_pod_not_exists_command_line_in_pod_empty_string(self):
]

try:
out, err = self.run_subprocess_assert_returncode(command_up)
out, err = self.run_subprocess_assert_returncode(command_up, 125)
self.assertEqual(b"Error: --userns and --pod cannot be set together" in err, True)

finally:
Expand Down