13692: Make Python SDK error reporting more user friendly.
authorPeter Amstutz <pamstutz@veritasgenetics.com>
Thu, 5 Jul 2018 21:03:11 +0000 (17:03 -0400)
committerPeter Amstutz <pamstutz@veritasgenetics.com>
Thu, 5 Jul 2018 21:03:11 +0000 (17:03 -0400)
Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <pamstutz@veritasgenetics.com>

sdk/cwl/arvados_cwl/__init__.py
sdk/python/arvados/api.py
sdk/python/arvados/safeapi.py

index bf419dd9b649e23c19265cfd58db5008eff0caaf..062c7c2fa6fb58c6d385a016b87237c9c8e42f9f 100644 (file)
@@ -831,6 +831,8 @@ def main(args, stdout, stderr, api_client=None, keep_client=None,
         if api_client is None:
             api_client = arvados.safeapi.ThreadSafeApiCache(api_params={"model": OrderedJsonModel()}, keep_params={"num_retries": 4})
             keep_client = api_client.keep
+            # Make an API object now so errors are reported early.
+            api_client.users().current().execute()
         if keep_client is None:
             keep_client = arvados.keep.KeepClient(api_client=api_client, num_retries=4)
         runner = ArvCwlRunner(api_client, arvargs, keep_client=keep_client, num_retries=4)
index 4611a1aadf80043eb9afdeeaff727b27a09eecbc..b652db77d18a73214740672da6588f0fbaab3de3 100644 (file)
@@ -96,6 +96,10 @@ def _intercept_http_request(self, uri, method="GET", headers={}, **kwargs):
                           delay, exc_info=True)
             for conn in self.connections.values():
                 conn.close()
+        except httplib2.SSLHandshakeError as e:
+            # Intercept and re-raise with a better error message.
+            raise httplib2.SSLHandshakeError("Could not connect to %s\n%s\nPossible causes: remote SSL/TLS certificate expired, or was issued by an untrusted certificate authority." % (uri, e))
+
         time.sleep(delay)
         delay = delay * self._retry_delay_backoff
 
@@ -254,9 +258,12 @@ def api_from_config(version=None, apiconfig=None, **kwargs):
     if apiconfig is None:
         apiconfig = config.settings()
 
+    errors = []
     for x in ['ARVADOS_API_HOST', 'ARVADOS_API_TOKEN']:
         if x not in apiconfig:
-            raise ValueError("%s is not set. Aborting." % x)
+            errors.append(x)
+    if errors:
+        raise ValueError(" and ".join(errors)+" not set.\nPlease set in %s or export environment variable." % config.default_config_file)
     host = apiconfig.get('ARVADOS_API_HOST')
     token = apiconfig.get('ARVADOS_API_TOKEN')
     insecure = config.flag_is_true('ARVADOS_API_HOST_INSECURE', apiconfig)
index b12c121bf8d3f1dbd42f9e7ed0219d1e83583697..c6e17cae0b71a4ca0b580bbb6f8c056da8cb8988 100644 (file)
@@ -26,6 +26,12 @@ class ThreadSafeApiCache(object):
         self.apiconfig = copy.copy(apiconfig)
         self.api_params = api_params
         self.local = threading.local()
+
+        # Initialize an API object for this thread before creating
+        # KeepClient, this will report if ARVADOS_API_HOST or
+        # ARVADOS_API_TOKEN are missing.
+        self.localapi()
+
         self.keep = keep.KeepClient(api_client=self, **keep_params)
 
     def localapi(self):