Browse Source

DWX-17085: added compute support for trino

With this change, trino compute can be discovered, saved to db and used
similar to hive and impala.
Amit Srivastava 1 year ago
parent
commit
41fd5de981

+ 19 - 9
apps/beeswax/src/beeswax/common.py

@@ -20,15 +20,15 @@ Common utils for beeswax.
 """
 """
 from __future__ import print_function
 from __future__ import print_function
 
 
-import numbers
 import re
 import re
 import time
 import time
+import numbers
 
 
 from django import forms
 from django import forms
 
 
-from beeswax.models import Namespace, Compute
+from beeswax.models import Compute, Namespace
 
 
-HIVE_IDENTIFER_REGEX = re.compile("(^[a-zA-Z0-9]\w*\.)?[a-zA-Z0-9]\w*$")
+HIVE_IDENTIFER_REGEX = re.compile(r"(^[a-zA-Z0-9]\w*\.)?[a-zA-Z0-9]\w*$")
 
 
 DL_FORMATS = ['csv', 'xls']
 DL_FORMATS = ['csv', 'xls']
 
 
@@ -44,7 +44,7 @@ RELATION_OPS_UNARY = ['IS NULL', 'IS NOT NULL', 'NOT']
 
 
 RELATION_OPS = ['=', '<>', '<', '<=', '>', '>='] + RELATION_OPS_UNARY
 RELATION_OPS = ['=', '<>', '<', '<=', '>', '>='] + RELATION_OPS_UNARY
 
 
-COMPUTE_TYPES = ['hive-compute', 'impala-compute']
+COMPUTE_TYPES = ['hive-compute', 'impala-compute', 'trino-compute']
 
 
 TERMINATORS = [
 TERMINATORS = [
   # (hive representation, description, ascii value)
   # (hive representation, description, ascii value)
@@ -56,12 +56,13 @@ TERMINATORS = [
   (' ', "Space", 32),
   (' ', "Space", 32),
 ]
 ]
 
 
+
 def timing(fn):
 def timing(fn):
   def decorator(*args, **kwargs):
   def decorator(*args, **kwargs):
     time1 = time.time()
     time1 = time.time()
     ret = fn(*args, **kwargs)
     ret = fn(*args, **kwargs)
     time2 = time.time()
     time2 = time.time()
-    print('%s elapsed time: %0.3f ms' % (fn.__name__, (time2-time1)*1000.0))
+    print('%s elapsed time: %0.3f ms' % (fn.__name__, (time2 - time1) * 1000.0))
     return ret
     return ret
   return decorator
   return decorator
 
 
@@ -79,7 +80,8 @@ def apply_natural_sort(collection, key=None):
   Applies a natural sort (http://rosettacode.org/wiki/Natural_sorting) to a list or dictionary
   Applies a natural sort (http://rosettacode.org/wiki/Natural_sorting) to a list or dictionary
   Dictionary types require a sort key to be specified
   Dictionary types require a sort key to be specified
   """
   """
-  to_digit = lambda i: int(i) if i.isdigit() else i
+  def to_digit(i):
+    return int(i) if i.isdigit() else i
 
 
   def tokenize_and_convert(item, key=None):
   def tokenize_and_convert(item, key=None):
     if key:
     if key:
@@ -94,7 +96,9 @@ def is_compute(cluster):
     return False
     return False
   connector = cluster.get('connector')
   connector = cluster.get('connector')
   compute = cluster.get('compute')
   compute = cluster.get('compute')
-  compute_check = lambda x: x and x.get('type') in COMPUTE_TYPES
+
+  def compute_check(x):
+    return x and x.get('type') in COMPUTE_TYPES
   return compute_check(cluster) or compute_check(connector) or compute_check(compute)
   return compute_check(cluster) or compute_check(connector) or compute_check(compute)
 
 
 
 
@@ -107,12 +111,16 @@ Following is the priority order
 3. Lookup namespace based on dialect from cluster or prpvided dialect
 3. Lookup namespace based on dialect from cluster or prpvided dialect
    and return the first compute filtered by user-access. Needs valid user
    and return the first compute filtered by user-access. Needs valid user
 '''
 '''
+
+
 def find_compute(cluster=None, user=None, dialect=None, namespace_id=None):
 def find_compute(cluster=None, user=None, dialect=None, namespace_id=None):
   if cluster:
   if cluster:
     # If we find a full/partial cluster object, we will attempt to load a compute
     # If we find a full/partial cluster object, we will attempt to load a compute
     connector = cluster.get('connector')
     connector = cluster.get('connector')
     compute = cluster.get('compute')
     compute = cluster.get('compute')
-    compute_check = lambda x: x and x.get('type') in COMPUTE_TYPES
+
+    def compute_check(x):
+      return x and x.get('type') in COMPUTE_TYPES
 
 
     # Pick the most probable compute object
     # Pick the most probable compute object
     selected_compute = (cluster if compute_check(cluster)
     selected_compute = (cluster if compute_check(cluster)
@@ -135,7 +143,9 @@ def find_compute(cluster=None, user=None, dialect=None, namespace_id=None):
       dialect = selected_compute['dialect'] if selected_compute.get('dialect') else dialect
       dialect = selected_compute['dialect'] if selected_compute.get('dialect') else dialect
       if not dialect and cluster.get('type'):
       if not dialect and cluster.get('type'):
         t = cluster['type']
         t = cluster['type']
-        dialect = 'hive' if t.startswith('hive') else 'impala' if t.startswith('impala') else None
+        dialect = 'hive' if t.startswith('hive') else\
+          'impala' if t.startswith('impala') else\
+            'trino' if t.startswith('trino') else None
 
 
   # We will attempt to find a default compute based on other criteria
   # We will attempt to find a default compute based on other criteria
   ns = None
   ns = None

+ 36 - 17
apps/beeswax/src/beeswax/conf.py

@@ -16,21 +16,22 @@
 # limitations under the License.
 # limitations under the License.
 
 
 from __future__ import division
 from __future__ import division
-from builtins import str
-import logging
+
+import sys
 import math
 import math
+import logging
 import os.path
 import os.path
-import sys
-
-from desktop.conf import default_ssl_cacerts, default_ssl_validate, AUTH_PASSWORD as DEFAULT_AUTH_PASSWORD,\
-  AUTH_USERNAME as DEFAULT_AUTH_USERNAME
-from desktop.lib.conf import ConfigSection, Config, coerce_bool, coerce_csv, coerce_password_from_script
+from builtins import str
 
 
-if sys.version_info[0] > 2:
-  from django.utils.translation import gettext_lazy as _t, gettext as _
-else:
-  from django.utils.translation import ugettext_lazy as _t, ugettext as _
+from django.utils.translation import gettext as _, gettext_lazy as _t
 
 
+from desktop.conf import (
+  AUTH_PASSWORD as DEFAULT_AUTH_PASSWORD,
+  AUTH_USERNAME as DEFAULT_AUTH_USERNAME,
+  default_ssl_cacerts,
+  default_ssl_validate,
+)
+from desktop.lib.conf import Config, ConfigSection, coerce_bool, coerce_csv, coerce_password_from_script
 
 
 LOG = logging.getLogger()
 LOG = logging.getLogger()
 
 
@@ -103,21 +104,25 @@ HIVE_SERVER_HOST = Config(
          "the fully-qualified domain name (FQDN) is required"),
          "the fully-qualified domain name (FQDN) is required"),
   default="localhost")
   default="localhost")
 
 
+
 def get_hive_thrift_binary_port():
 def get_hive_thrift_binary_port():
   """Devise port from core-site Thrift / execution mode & Http port"""
   """Devise port from core-site Thrift / execution mode & Http port"""
-  from beeswax.hive_site import hiveserver2_thrift_binary_port, get_hive_execution_mode   # Cyclic dependency
+  from beeswax.hive_site import get_hive_execution_mode, hiveserver2_thrift_binary_port  # Cyclic dependency
   return hiveserver2_thrift_binary_port() or (10500 if (get_hive_execution_mode() or '').lower() == 'llap' else 10000)
   return hiveserver2_thrift_binary_port() or (10500 if (get_hive_execution_mode() or '').lower() == 'llap' else 10000)
 
 
+
 HIVE_SERVER_PORT = Config(
 HIVE_SERVER_PORT = Config(
   key="hive_server_port",
   key="hive_server_port",
   help=_t("Configure the binary Thrift port for HiveServer2."),
   help=_t("Configure the binary Thrift port for HiveServer2."),
   dynamic_default=get_hive_thrift_binary_port,
   dynamic_default=get_hive_thrift_binary_port,
   type=int)
   type=int)
 
 
+
 def get_hive_thrift_http_port():
 def get_hive_thrift_http_port():
   """Devise port from core-site Thrift / execution mode & Http port"""
   """Devise port from core-site Thrift / execution mode & Http port"""
-  from beeswax.hive_site import hiveserver2_thrift_http_port, get_hive_execution_mode   # Cyclic dependency
-  return hiveserver2_thrift_http_port() or (10501 if (get_hive_execution_mode() or '').lower() == 'llap'  else 10001)
+  from beeswax.hive_site import get_hive_execution_mode, hiveserver2_thrift_http_port  # Cyclic dependency
+  return hiveserver2_thrift_http_port() or (10501 if (get_hive_execution_mode() or '').lower() == 'llap' else 10001)
+
 
 
 HIVE_HTTP_THRIFT_PORT = Config(
 HIVE_HTTP_THRIFT_PORT = Config(
   key="hive_server_http_port",
   key="hive_server_http_port",
@@ -165,7 +170,7 @@ ZOOKEEPER_CONN_TIMEOUT = Config(
   type=int,
   type=int,
   help=_t('Timeout in seconds for zookeeper connection.'))
   help=_t('Timeout in seconds for zookeeper connection.'))
 
 
-USE_GET_LOG_API = Config( # To remove in Hue 4
+USE_GET_LOG_API = Config(  # To remove in Hue 4
   key='use_get_log_api',
   key='use_get_log_api',
   default=False,
   default=False,
   type=coerce_bool,
   type=coerce_bool,
@@ -173,7 +178,7 @@ USE_GET_LOG_API = Config( # To remove in Hue 4
           'If false, use the FetchResults() Thrift call from Hive 1.0 or more instead.')
           'If false, use the FetchResults() Thrift call from Hive 1.0 or more instead.')
 )
 )
 
 
-BROWSE_PARTITIONED_TABLE_LIMIT = Config( # Deprecated, to remove in Hue 4
+BROWSE_PARTITIONED_TABLE_LIMIT = Config(  # Deprecated, to remove in Hue 4
   key='browse_partitioned_table_limit',
   key='browse_partitioned_table_limit',
   default=1000,
   default=1000,
   type=int,
   type=int,
@@ -187,10 +192,12 @@ QUERY_PARTITIONS_LIMIT = Config(
   type=int,
   type=int,
   help=_t('The maximum number of partitions that will be included in the SELECT * LIMIT sample query for partitioned tables.'))
   help=_t('The maximum number of partitions that will be included in the SELECT * LIMIT sample query for partitioned tables.'))
 
 
+
 def get_browse_partitioned_table_limit():
 def get_browse_partitioned_table_limit():
   """Get the old default"""
   """Get the old default"""
   return BROWSE_PARTITIONED_TABLE_LIMIT.get()
   return BROWSE_PARTITIONED_TABLE_LIMIT.get()
 
 
+
 LIST_PARTITIONS_LIMIT = Config(
 LIST_PARTITIONS_LIMIT = Config(
   key='list_partitions_limit',
   key='list_partitions_limit',
   dynamic_default=get_browse_partitioned_table_limit,
   dynamic_default=get_browse_partitioned_table_limit,
@@ -206,10 +213,12 @@ DOWNLOAD_CELL_LIMIT = Config(
           '(e.g. - 10K rows * 1K columns = 10M cells.) '
           '(e.g. - 10K rows * 1K columns = 10M cells.) '
           'A value of -1 means there will be no limit.'))
           'A value of -1 means there will be no limit.'))
 
 
+
 def get_deprecated_download_cell_limit():
 def get_deprecated_download_cell_limit():
   """Get the old default"""
   """Get the old default"""
   return math.floor(DOWNLOAD_CELL_LIMIT.get() / 100) if DOWNLOAD_CELL_LIMIT.get() > 0 else DOWNLOAD_CELL_LIMIT.get()
   return math.floor(DOWNLOAD_CELL_LIMIT.get() / 100) if DOWNLOAD_CELL_LIMIT.get() > 0 else DOWNLOAD_CELL_LIMIT.get()
 
 
+
 DOWNLOAD_ROW_LIMIT = Config(
 DOWNLOAD_ROW_LIMIT = Config(
   key='download_row_limit',
   key='download_row_limit',
   dynamic_default=get_deprecated_download_cell_limit,
   dynamic_default=get_deprecated_download_cell_limit,
@@ -297,15 +306,18 @@ SSL = ConfigSection(
   )
   )
 )
 )
 
 
+
 def get_auth_username():
 def get_auth_username():
   """Get from top level default from desktop"""
   """Get from top level default from desktop"""
   return DEFAULT_AUTH_USERNAME.get()
   return DEFAULT_AUTH_USERNAME.get()
 
 
+
 AUTH_USERNAME = Config(
 AUTH_USERNAME = Config(
   key="auth_username",
   key="auth_username",
   help=_t("Auth username of the hue user used for authentications."),
   help=_t("Auth username of the hue user used for authentications."),
   dynamic_default=get_auth_username)
   dynamic_default=get_auth_username)
 
 
+
 def get_auth_password():
 def get_auth_password():
   """Get from script or backward compatibility"""
   """Get from script or backward compatibility"""
   password = AUTH_PASSWORD_SCRIPT.get()
   password = AUTH_PASSWORD_SCRIPT.get()
@@ -314,6 +326,7 @@ def get_auth_password():
 
 
   return DEFAULT_AUTH_PASSWORD.get()
   return DEFAULT_AUTH_PASSWORD.get()
 
 
+
 AUTH_PASSWORD = Config(
 AUTH_PASSWORD = Config(
   key="auth_password",
   key="auth_password",
   help=_t("LDAP/PAM/.. password of the hue user used for authentications."),
   help=_t("LDAP/PAM/.. password of the hue user used for authentications."),
@@ -327,13 +340,15 @@ AUTH_PASSWORD_SCRIPT = Config(
   type=coerce_password_from_script,
   type=coerce_password_from_script,
   default=None)
   default=None)
 
 
+
 def get_use_sasl_default():
 def get_use_sasl_default():
   """Get from hive_site or backward compatibility"""
   """Get from hive_site or backward compatibility"""
   from beeswax.hive_site import get_hiveserver2_authentication, get_use_sasl  # Cyclic dependency
   from beeswax.hive_site import get_hiveserver2_authentication, get_use_sasl  # Cyclic dependency
   use_sasl = get_use_sasl()
   use_sasl = get_use_sasl()
   if use_sasl is not None:
   if use_sasl is not None:
     return use_sasl.upper() == 'TRUE'
     return use_sasl.upper() == 'TRUE'
-  return get_hiveserver2_authentication() in ('KERBEROS', 'NONE', 'LDAP', 'PAM') # list for backward compatibility
+  return get_hiveserver2_authentication() in ('KERBEROS', 'NONE', 'LDAP', 'PAM')  # list for backward compatibility
+
 
 
 USE_SASL = Config(
 USE_SASL = Config(
   key="use_sasl",
   key="use_sasl",
@@ -342,10 +357,12 @@ USE_SASL = Config(
   type=coerce_bool,
   type=coerce_bool,
   dynamic_default=get_use_sasl_default)
   dynamic_default=get_use_sasl_default)
 
 
+
 def has_multiple_sessions():
 def has_multiple_sessions():
   """When true will create multiple sessions for user queries"""
   """When true will create multiple sessions for user queries"""
   return MAX_NUMBER_OF_SESSIONS.get() != 1
   return MAX_NUMBER_OF_SESSIONS.get() != 1
 
 
+
 CLOSE_SESSIONS = Config(
 CLOSE_SESSIONS = Config(
   key="close_sessions",
   key="close_sessions",
   help=_t(
   help=_t(
@@ -356,9 +373,11 @@ CLOSE_SESSIONS = Config(
   dynamic_default=has_multiple_sessions
   dynamic_default=has_multiple_sessions
 )
 )
 
 
+
 def has_session_pool():
 def has_session_pool():
   return has_multiple_sessions() and not CLOSE_SESSIONS.get()
   return has_multiple_sessions() and not CLOSE_SESSIONS.get()
 
 
+
 MAX_CATALOG_SQL_ENTRIES = Config(
 MAX_CATALOG_SQL_ENTRIES = Config(
   key="max_catalog_sql_entries",
   key="max_catalog_sql_entries",
   help=_t(
   help=_t(

+ 6 - 0
desktop/core/src/desktop/conf.py

@@ -2258,6 +2258,12 @@ def has_connectors():
   return ENABLE_CONNECTORS.get()
   return ENABLE_CONNECTORS.get()
 
 
 
 
+def is_cdw_compute_enabled():
+  '''When the computes feature is turned on'''
+  clusters = CLUSTERS.get()
+  return bool(clusters and [c for c in clusters.values() if c.TYPE.get() == 'cdw'])
+
+
 CLUSTERS = UnspecifiedConfigSection(
 CLUSTERS = UnspecifiedConfigSection(
   "clusters",
   "clusters",
   help="One entry for each additional remote cluster Hue can interact with.",
   help="One entry for each additional remote cluster Hue can interact with.",

+ 52 - 2
desktop/core/src/desktop/management/commands/sync_warehouses.py

@@ -42,6 +42,7 @@ else:
 
 
 core_v1 = client.CoreV1Api()
 core_v1 = client.CoreV1Api()
 apps_v1 = client.AppsV1Api()
 apps_v1 = client.AppsV1Api()
+networking_v1 = client.NetworkingV1Api()
 
 
 SERVER_HELP = r"""
 SERVER_HELP = r"""
   Sync up the desktop_connectors with the available hive and impala warehouses
   Sync up the desktop_connectors with the available hive and impala warehouses
@@ -64,6 +65,7 @@ def sync_warehouses(args, options):
 
 
   hives = [c for c in computes if c['dialect'] == 'hive']
   hives = [c for c in computes if c['dialect'] == 'hive']
   impalas = [c for c in computes if c['dialect'] == 'impala']
   impalas = [c for c in computes if c['dialect'] == 'impala']
+  trinos = [c for c in computes if c['dialect'] == 'trino']
 
 
   (hive_warehouse, created) = models.Namespace.objects.get_or_create(
   (hive_warehouse, created) = models.Namespace.objects.get_or_create(
     external_id="CDW_HIVE_WAREHOUSE",
     external_id="CDW_HIVE_WAREHOUSE",
@@ -75,6 +77,11 @@ def sync_warehouses(args, options):
     defaults={'name': 'CDW Impala', 'description': 'CDW Impala Warehouse', 'dialect': 'impala', 'interface': 'hiveserver2'})
     defaults={'name': 'CDW Impala', 'description': 'CDW Impala Warehouse', 'dialect': 'impala', 'interface': 'hiveserver2'})
   add_computes_to_warehouse(impala_warehouse, impalas)
   add_computes_to_warehouse(impala_warehouse, impalas)
 
 
+  (trino_warehouse, created) = models.Namespace.objects.get_or_create(
+    external_id="CDW_TRINO_WAREHOUSE",
+    defaults={'name': 'CDW Trino', 'description': 'CDW Trino Warehouse', 'dialect': 'trino', 'interface': 'trino'})
+  add_computes_to_warehouse(trino_warehouse, trinos)
+
   LOG.info("Synced computes")
   LOG.info("Synced computes")
   LOG.debug("Current computes %s" % models.Compute.objects.all())
   LOG.debug("Current computes %s" % models.Compute.objects.all())
 
 
@@ -104,7 +111,7 @@ def get_computes_from_k8s():
       namespace = n.metadata.name
       namespace = n.metadata.name
       LOG.info('Getting details for ns: %s' % namespace)
       LOG.info('Getting details for ns: %s' % namespace)
       item = {
       item = {
-        'name': n.metadata.labels.get('displayname'),
+        'name': n.metadata.labels.get('displayname', namespace),
         'description': '%s (%s)' % (n.metadata.labels.get('displayname'), n.metadata.name),
         'description': '%s (%s)' % (n.metadata.labels.get('displayname'), n.metadata.name),
         'external_id': namespace,
         'external_id': namespace,
         # 'creation_timestamp': n.metadata.labels.get('creation_timestamp'),
         # 'creation_timestamp': n.metadata.labels.get('creation_timestamp'),
@@ -118,8 +125,11 @@ def get_computes_from_k8s():
       elif namespace.startswith('impala-'):
       elif namespace.startswith('impala-'):
         populate_impala(namespace, item)
         populate_impala(namespace, item)
         computes.append(item)
         computes.append(item)
+      elif namespace.startswith('trino-'):
+        update_trino_configs(namespace, item)
+        computes.append(item)
     except Exception as e:
     except Exception as e:
-      LOG.exception('Could not get details for ns: %s' % n)
+      LOG.exception('Could not get details for ns: %s' % (n.metadata.name if n.metadata is not None else n))
 
 
   return computes
   return computes
 
 
@@ -224,3 +234,43 @@ def update_impala_configs(namespace, impala, host):
     'ldap_groups': ldap_groups.split(",") if ldap_groups else None,
     'ldap_groups': ldap_groups.split(",") if ldap_groups else None,
     'settings': json.dumps(settings)
     'settings': json.dumps(settings)
   })
   })
+
+
+def update_trino_configs(namespace, trino):
+  deployments = apps_v1.list_namespaced_deployment(namespace).items
+  stfs = apps_v1.list_namespaced_stateful_set(namespace).items
+  ingresses = networking_v1.list_namespaced_ingress(namespace).items
+  trino_worker_dep = next((d for d in deployments
+                           if d.metadata.labels['app'] == 'trino' and d.metadata.labels['component'] == 'trino-worker'),
+                          None)
+  trino_coordinator_stfs = next((s for s in stfs if s.metadata.labels['app'] == 'trino-coordinator'), None)
+  trino_coordinator_ingress = next((i for i in ingresses if i.metadata.name == 'trino-coordinator-ingress'), None)
+
+  trino['is_ready'] = bool(trino_worker_dep and trino_worker_dep.status.ready_replicas
+                       and trino_coordinator_stfs and trino_coordinator_stfs.status.ready_replicas)
+
+  if not trino['is_ready']:
+    LOG.info("Trino %s not ready" % namespace)
+
+  coordinator_url = 'http://trino-coordinator.%s.svc.cluster.local:8080' % namespace
+  settings = []
+
+  trino_coordinator_configs = core_v1.read_namespaced_config_map('trino-coordinator-config', namespace)
+  core_site_data = confparse.ConfParse(trino_coordinator_configs.data['core-site.xml'])
+  ldap_bin_user = core_site_data.get('hadoop.security.group.mapping.ldap.bind.user')
+  if ldap_bin_user:
+    ldap_user_regex = '.*uid=([^,]+).*'
+    match = re.search(ldap_user_regex, ldap_bin_user)
+    ldap_user_id = match.group(1) if match and match.group(1) else None
+    settings.append({"name": "auth_username", "value": ldap_user_id})
+    settings.append({"name": "auth_password_script", "value": "/etc/hue/conf/altscript.sh hue.binduser.password"})
+    if trino_coordinator_ingress and trino_coordinator_ingress.spec.rules:
+      coordinator_url = 'https://%s:443' % trino_coordinator_ingress.spec.rules[0].host
+
+  settings.append({"name": "url", "value": coordinator_url})
+
+  trino.update({
+    'dialect': 'trino',
+    'interface': 'trino',
+    'settings': json.dumps(settings)
+  })

+ 1 - 1
desktop/core/src/desktop/models.py

@@ -1909,7 +1909,7 @@ class ClusterConfig(object):
           'optimizer': get_optimizer_mode(),
           'optimizer': get_optimizer_mode(),
           'page': '/editor/?type=%(type)s' % interpreter,
           'page': '/editor/?type=%(type)s' % interpreter,
           'is_sql': interpreter['is_sql'],
           'is_sql': interpreter['is_sql'],
-          'is_batchable': interpreter['dialect'] in ['hive', 'impala'] or interpreter['interface'] in ['oozie', 'sqlalchemy'],
+          'is_batchable': interpreter['dialect'] in ['hive', 'impala', 'trino'] or interpreter['interface'] in ['oozie', 'sqlalchemy'],
           'dialect': interpreter['dialect'],
           'dialect': interpreter['dialect'],
           'dialect_properties': interpreter.get('dialect_properties'),
           'dialect_properties': interpreter.get('dialect_properties'),
         })
         })

+ 1 - 1
desktop/libs/notebook/src/notebook/api.py

@@ -752,7 +752,7 @@ def autocomplete(request, server=None, database=None, table=None, column=None, n
   # Passed by check_document_access_permission but unused by APIs
   # Passed by check_document_access_permission but unused by APIs
   notebook = json.loads(request.POST.get('notebook', '{}'))
   notebook = json.loads(request.POST.get('notebook', '{}'))
   cluster = json.loads(request.POST.get('cluster', '{}'))
   cluster = json.loads(request.POST.get('cluster', '{}'))
-  if cluster and cluster.get('type') in ('hive-compute', 'impala-compute'):
+  if cluster and cluster.get('type') in ('hive-compute', 'impala-compute', 'trino-compute'):
     snippet = cluster
     snippet = cluster
   else:
   else:
     snippet = json.loads(request.POST.get('snippet', '{}'))
     snippet = json.loads(request.POST.get('snippet', '{}'))

+ 1 - 1
desktop/libs/notebook/src/notebook/conf.py

@@ -102,7 +102,7 @@ def get_ordered_interpreters(user=None):
     for interpreter in INTERPRETERS_CACHE:
     for interpreter in INTERPRETERS_CACHE:
       if check_has_missing_permission(user, interpreter, user_apps=user_apps):
       if check_has_missing_permission(user, interpreter, user_apps=user_apps):
         pass  # Not allowed
         pass  # Not allowed
-      elif has_computes and interpreter in ('hive', 'impala') and not computes_for_dialect(interpreter, user):
+      elif has_computes and interpreter in ('hive', 'impala', 'trino') and not computes_for_dialect(interpreter, user):
         pass  # No available computes for the dialect so skip
         pass  # No available computes for the dialect so skip
       else:
       else:
         user_interpreters.append(interpreter)
         user_interpreters.append(interpreter)

+ 3 - 3
desktop/libs/notebook/src/notebook/connectors/base.py

@@ -27,7 +27,7 @@ from django.utils.encoding import smart_str
 
 
 from beeswax.common import find_compute, is_compute
 from beeswax.common import find_compute, is_compute
 from desktop.auth.backend import is_admin
 from desktop.auth.backend import is_admin
-from desktop.conf import TASK_SERVER, has_connectors
+from desktop.conf import TASK_SERVER, has_connectors, is_cdw_compute_enabled
 from desktop.lib import export_csvxls
 from desktop.lib import export_csvxls
 from desktop.lib.exceptions_renderable import PopupException
 from desktop.lib.exceptions_renderable import PopupException
 from desktop.lib.i18n import smart_unicode
 from desktop.lib.i18n import smart_unicode
@@ -439,10 +439,10 @@ def get_api(request, snippet):
   if has_connectors() and snippet.get('type') == 'hello' and is_admin(request.user):
   if has_connectors() and snippet.get('type') == 'hello' and is_admin(request.user):
     LOG.debug('Using the interpreter from snippet')
     LOG.debug('Using the interpreter from snippet')
     interpreter = snippet.get('interpreter')
     interpreter = snippet.get('interpreter')
-  elif is_compute(snippet):
+  elif is_cdw_compute_enabled():
     LOG.debug("Finding the compute from db using snippet: %s" % snippet)
     LOG.debug("Finding the compute from db using snippet: %s" % snippet)
     interpreter = find_compute(cluster=snippet, user=request.user)
     interpreter = find_compute(cluster=snippet, user=request.user)
-  else:
+  if interpreter is None:
     LOG.debug("Picking up the connectors from the configs using connector_name: %s" % connector_name)
     LOG.debug("Picking up the connectors from the configs using connector_name: %s" % connector_name)
     interpreter = get_interpreter(connector_type=connector_name, user=request.user)
     interpreter = get_interpreter(connector_type=connector_name, user=request.user)
 
 

+ 1 - 1
desktop/libs/notebook/src/notebook/connectors/trino.py

@@ -57,7 +57,7 @@ class TrinoApi(Api):
   def __init__(self, user, interpreter=None):
   def __init__(self, user, interpreter=None):
     Api.__init__(self, user, interpreter=interpreter)
     Api.__init__(self, user, interpreter=interpreter)
     self.options = interpreter['options']
     self.options = interpreter['options']
-    self.server_host, self.server_port, self.http_scheme = self.parse_api_url(self.options['url'])
+    self.server_host, self.server_port, self.http_scheme = self.parse_api_url(self.options.get('url'))
     self.auth = None
     self.auth = None
 
 
     auth_username = self.options.get('auth_username', DEFAULT_AUTH_USERNAME.get())
     auth_username = self.options.get('auth_username', DEFAULT_AUTH_USERNAME.get())