13108: Don't try to install signal handler in background thread
authorPeter Amstutz <pamstutz@veritasgenetics.com>
Thu, 12 Apr 2018 20:22:52 +0000 (16:22 -0400)
committerPeter Amstutz <pamstutz@veritasgenetics.com>
Thu, 12 Apr 2018 20:22:52 +0000 (16:22 -0400)
Fix Docker image upload failure due to arv-put trying to install a
signal handler somewhere other than the main thread.

Also install toplevel signal handler to convert SIGTERM to
KeyboardInterrupt.

Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <pamstutz@veritasgenetics.com>

sdk/cwl/arvados_cwl/__init__.py
sdk/cwl/arvados_cwl/arvdocker.py
sdk/python/arvados/commands/keepdocker.py
sdk/python/arvados/commands/put.py

index c2f43fe368b47c1c75447195feb2ed96d27b39d6..2fa6da703464fcb74be35ccc9b42dbc5c65508fe 100644 (file)
@@ -19,6 +19,8 @@ from functools import partial
 import pkg_resources  # part of setuptools
 import Queue
 import time
+import signal
+import thread
 
 from cwltool.errors import WorkflowException
 import cwltool.main
@@ -564,7 +566,7 @@ class ArvCwlRunner(object):
             raise
         except:
             if sys.exc_info()[0] is KeyboardInterrupt:
-                logger.error("Interrupted, marking pipeline as failed")
+                logger.error("Interrupted, workflow will be cancelled")
             else:
                 logger.error("Execution failed: %s", sys.exc_info()[1], exc_info=(sys.exc_info()[1] if self.debug else False))
             if self.pipeline:
@@ -761,12 +763,16 @@ def add_arv_hints():
         "http://arvados.org/cwl#ReuseRequirement"
     ])
 
-def main(args, stdout, stderr, api_client=None, keep_client=None):
+def main(args, stdout, stderr, api_client=None, keep_client=None,
+         install_sig_handlers=True):
     parser = arg_parser()
 
     job_order_object = None
     arvargs = parser.parse_args(args)
 
+    if install_sig_handlers:
+        signal.signal(signal.SIGTERM, lambda x, y: thread.interrupt_main())
+
     if arvargs.update_workflow:
         if arvargs.update_workflow.find('-7fd4e-') == 5:
             want_api = 'containers'
index 5483ccbf52b59f2d2133bacd76ad7eaaa775a91f..68573aa48e1d84e8560dae509906cf3a6285ad7d 100644 (file)
@@ -57,7 +57,7 @@ def arv_docker_get_image(api_client, dockerRequirement, pull_image, project_uuid
             args.append(image_tag)
             logger.info("Uploading Docker image %s:%s", image_name, image_tag)
             try:
-                arvados.commands.keepdocker.main(args, stdout=sys.stderr)
+                arvados.commands.keepdocker.main(args, stdout=sys.stderr, install_sig_handlers=False)
             except SystemExit as e:
                 if e.code:
                     raise WorkflowException("keepdocker exited with code %s" % e.code)
index ff7201a75bdaf4aaf1b6086803fe8f1eaca83e30..16fefdb2fa978f6f1f808bf4187f9259f5108dd0 100644 (file)
@@ -345,7 +345,7 @@ def _uuid2pdh(api, uuid):
         select=['portable_data_hash'],
     ).execute()['items'][0]['portable_data_hash']
 
-def main(arguments=None, stdout=sys.stdout):
+def main(arguments=None, stdout=sys.stdout, install_sig_handlers=True):
     args = arg_parser.parse_args(arguments)
     api = arvados.api('v1')
 
@@ -490,7 +490,8 @@ def main(arguments=None, stdout=sys.stdout):
             put_args += ['--name', collection_name]
 
         coll_uuid = arv_put.main(
-            put_args + ['--filename', outfile_name, image_file.name], stdout=stdout).strip()
+            put_args + ['--filename', outfile_name, image_file.name], stdout=stdout,
+            install_sig_handlers=install_sig_handlers).strip()
 
         # Read the image metadata and make Arvados links from it.
         image_file.seek(0)
index 5dde8e53c933d05b2facbf8df284941635da3b42..af8e243b849f10458cfe0ff058c9890649e53888 100644 (file)
@@ -993,7 +993,8 @@ def desired_project_uuid(api_client, project_uuid, num_retries):
         raise ValueError("Not a valid project UUID: {}".format(project_uuid))
     return query.execute(num_retries=num_retries)['uuid']
 
-def main(arguments=None, stdout=sys.stdout, stderr=sys.stderr):
+def main(arguments=None, stdout=sys.stdout, stderr=sys.stderr,
+         install_sig_handlers=True):
     global api_client
 
     args = parse_arguments(arguments)
@@ -1014,8 +1015,10 @@ def main(arguments=None, stdout=sys.stdout, stderr=sys.stderr):
 
     # Install our signal handler for each code in CAUGHT_SIGNALS, and save
     # the originals.
-    orig_signal_handlers = {sigcode: signal.signal(sigcode, exit_signal_handler)
-                            for sigcode in CAUGHT_SIGNALS}
+    orig_signal_handlers = {}
+    if install_sig_handlers:
+        orig_signal_handlers = {sigcode: signal.signal(sigcode, exit_signal_handler)
+                                for sigcode in CAUGHT_SIGNALS}
 
     # Determine the name to use
     if args.name: