diff --git a/compose/cli/main.py b/compose/cli/main.py index 6f8cc47c8..4319d0ada 100644 --- a/compose/cli/main.py +++ b/compose/cli/main.py @@ -1256,6 +1256,7 @@ def run_one_off_container(container_options, project, service, options, project_ use_cli = not environment.get_boolean('COMPOSE_INTERACTIVE_NO_CLI') signals.set_signal_handler_to_shutdown() + signals.set_signal_handler_to_hang_up() try: try: if IS_WINDOWS_PLATFORM or use_cli: @@ -1273,10 +1274,10 @@ def run_one_off_container(container_options, project, service, options, project_ service.start_container(container) pty.start(sockets) exit_code = container.wait() - except signals.ShutdownException: + except (signals.ShutdownException): project.client.stop(container.id) exit_code = 1 - except signals.ShutdownException: + except (signals.ShutdownException, signals.HangUpException): project.client.kill(container.id) remove_container(force=True) sys.exit(2) diff --git a/compose/cli/signals.py b/compose/cli/signals.py index 9b360c44e..44def2ece 100644 --- a/compose/cli/signals.py +++ b/compose/cli/signals.py @@ -10,6 +10,10 @@ class ShutdownException(Exception): pass +class HangUpException(Exception): + pass + + def shutdown(signal, frame): raise ShutdownException() @@ -23,6 +27,16 @@ def set_signal_handler_to_shutdown(): set_signal_handler(shutdown) +def hang_up(signal, frame): + raise HangUpException() + + +def set_signal_handler_to_hang_up(): + # on Windows a ValueError will be raised if trying to set signal handler for SIGHUP + if not IS_WINDOWS_PLATFORM: + signal.signal(signal.SIGHUP, hang_up) + + def ignore_sigpipe(): # Restore default behavior for SIGPIPE instead of raising # an exception when encountered. diff --git a/tests/acceptance/cli_test.py b/tests/acceptance/cli_test.py index 8fb6dffec..9dd03b72f 100644 --- a/tests/acceptance/cli_test.py +++ b/tests/acceptance/cli_test.py @@ -1876,6 +1876,19 @@ class CLITestCase(DockerClientTestCase): 'simplecomposefile_simple_run_1', 'exited')) + def test_run_handles_sighup(self): + proc = start_process(self.base_dir, ['run', '-T', 'simple', 'top']) + wait_on_condition(ContainerStateCondition( + self.project.client, + 'simplecomposefile_simple_run_1', + 'running')) + + os.kill(proc.pid, signal.SIGHUP) + wait_on_condition(ContainerStateCondition( + self.project.client, + 'simplecomposefile_simple_run_1', + 'exited')) + @mock.patch.dict(os.environ) def test_run_unicode_env_values_from_system(self): value = 'ą, ć, ę, ł, ń, ó, ś, ź, ż'