This is an automated email from the ASF dual-hosted git repository.

chengpan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/kyuubi.git


The following commit(s) were added to refs/heads/master by this push:
     new 7926cc66f [KYUUBI #5606][REST] Handle engine listing request properly 
for users who have not created engine
7926cc66f is described below

commit 7926cc66f66a082aac24d69c8b7e7f6f2394d8aa
Author: Cheng Pan <[email protected]>
AuthorDate: Fri Nov 3 21:44:12 2023 +0800

    [KYUUBI #5606][REST] Handle engine listing request properly for users who 
have not created engine
    
    ### _Why are the changes needed?_
    
    Close #5606
    
    ```
    2023-11-03 19:30:13.215 ERROR KyuubiRestFrontendService-57 
org.apache.kyuubi.server.api.v1.AdminResource: No such engine for user: 
anonymous, engine type: SPARK_SQL, share level: USER, subdomain: null
    org.apache.kyuubi.shaded.zookeeper.KeeperException$NoNodeException: 
KeeperErrorCode = NoNode for /kyuubi_1.8.1-SNAPSHOT_USER_SPARK_SQL/anonymous
            at 
org.apache.kyuubi.shaded.zookeeper.KeeperException.create(KeeperException.java:114)
            at 
org.apache.kyuubi.shaded.zookeeper.KeeperException.create(KeeperException.java:54)
            at 
org.apache.kyuubi.shaded.zookeeper.ZooKeeper.getChildren(ZooKeeper.java:1659)
            at 
org.apache.kyuubi.shaded.curator.framework.imps.GetChildrenBuilderImpl$3.call(GetChildrenBuilderImpl.java:230)
            at 
org.apache.kyuubi.shaded.curator.framework.imps.GetChildrenBuilderImpl$3.call(GetChildrenBuilderImpl.java:219)
            at 
org.apache.kyuubi.shaded.curator.RetryLoop.callWithRetry(RetryLoop.java:109)
            at 
org.apache.kyuubi.shaded.curator.framework.imps.GetChildrenBuilderImpl.pathInForeground(GetChildrenBuilderImpl.java:216)
            at 
org.apache.kyuubi.shaded.curator.framework.imps.GetChildrenBuilderImpl.forPath(GetChildrenBuilderImpl.java:207)
            at 
org.apache.kyuubi.shaded.curator.framework.imps.GetChildrenBuilderImpl.forPath(GetChildrenBuilderImpl.java:40)
            at 
org.apache.kyuubi.ha.client.zookeeper.ZookeeperDiscoveryClient.getChildren(ZookeeperDiscoveryClient.scala:82)
            at 
org.apache.kyuubi.server.api.v1.AdminResource.$anonfun$listEngines$5(AdminResource.scala:306)
            at 
org.apache.kyuubi.ha.client.DiscoveryClientProvider$.withDiscoveryClient(DiscoveryClientProvider.scala:36)
            at 
org.apache.kyuubi.server.api.v1.AdminResource.listEngines(AdminResource.scala:304)
    ```
    
    ### _How was this patch tested?_
    - [ ] Add some test cases that check the changes thoroughly including 
negative and positive cases if possible
    
    - [ ] Add screenshots for manual tests if appropriate
    
    - [x] [Run 
test](https://kyuubi.readthedocs.io/en/master/contributing/code/testing.html#running-tests)
 locally before make a pull request
    
    ### _Was this patch authored or co-authored using generative AI tooling?_
    
    No
    
    Closes #5619 from pan3793/list-engine.
    
    Closes #5606
    
    783894b3e [Cheng Pan] nit
    52eb538bb [Cheng Pan] nit
    8d8097fda [Cheng Pan] [KYUUBI #5606][REST] Handle engine listing request 
properly for users who have not created engine
    
    Authored-by: Cheng Pan <[email protected]>
    Signed-off-by: Cheng Pan <[email protected]>
---
 .../kyuubi/server/api/v1/AdminResource.scala       | 59 +++++++++-------------
 1 file changed, 24 insertions(+), 35 deletions(-)

diff --git 
a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/v1/AdminResource.scala
 
b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/v1/AdminResource.scala
index 75baba74f..0b017543e 100644
--- 
a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/v1/AdminResource.scala
+++ 
b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/v1/AdminResource.scala
@@ -40,7 +40,6 @@ import org.apache.kyuubi.operation.{KyuubiOperation, 
OperationHandle}
 import org.apache.kyuubi.server.KyuubiServer
 import org.apache.kyuubi.server.api.{ApiRequestContext, ApiUtils}
 import org.apache.kyuubi.session.{KyuubiSession, SessionHandle}
-import org.apache.kyuubi.shaded.zookeeper.KeeperException.NoNodeException
 
 @Tag(name = "Admin")
 @Produces(Array(MediaType.APPLICATION_JSON))
@@ -252,8 +251,8 @@ private[v1] class AdminResource extends ApiRequestContext 
with Logging {
     } else {
       fe.getSessionUser(hs2ProxyUser)
     }
-    val engine = getEngine(userName, engineType, shareLevel, subdomain, 
"default")
-    val engineSpace = getEngineSpace(engine)
+    val engine = normalizeEngineInfo(userName, engineType, shareLevel, 
subdomain, "default")
+    val engineSpace = calculateEngineSpace(engine)
 
     withDiscoveryClient(fe.getConf) { discoveryClient =>
       val engineNodes = discoveryClient.getChildren(engineSpace)
@@ -290,33 +289,24 @@ private[v1] class AdminResource extends ApiRequestContext 
with Logging {
     } else {
       fe.getSessionUser(hs2ProxyUser)
     }
-    val engine = getEngine(userName, engineType, shareLevel, subdomain, "")
-    val engineSpace = getEngineSpace(engine)
+    val engine = normalizeEngineInfo(userName, engineType, shareLevel, 
subdomain, "")
+    val engineSpace = calculateEngineSpace(engine)
 
     val engineNodes = ListBuffer[ServiceNodeInfo]()
-    Option(subdomain).filter(_.nonEmpty) match {
-      case Some(_) =>
-        withDiscoveryClient(fe.getConf) { discoveryClient =>
-          info(s"Listing engine nodes for $engineSpace")
+    withDiscoveryClient(fe.getConf) { discoveryClient =>
+      Option(subdomain).filter(_.nonEmpty) match {
+        case Some(_) =>
+          info(s"Listing engine nodes under $engineSpace")
           engineNodes ++= discoveryClient.getServiceNodesInfo(engineSpace)
-        }
-      case None =>
-        withDiscoveryClient(fe.getConf) { discoveryClient =>
-          try {
-            discoveryClient.getChildren(engineSpace).map { child =>
-              info(s"Listing engine nodes for $engineSpace/$child")
-              engineNodes ++= 
discoveryClient.getServiceNodesInfo(s"$engineSpace/$child")
-            }
-          } catch {
-            case nne: NoNodeException =>
-              error(
-                s"No such engine for user: $userName, " +
-                  s"engine type: $engineType, share level: $shareLevel, 
subdomain: $subdomain",
-                nne)
-              throw new NotFoundException(s"No such engine for user: 
$userName, " +
-                s"engine type: $engineType, share level: $shareLevel, 
subdomain: $subdomain")
+        case None if discoveryClient.pathNonExists(engineSpace) =>
+          warn(s"Path $engineSpace does not exist. user: $userName, engine 
type: $engineType, " +
+            s"share level: $shareLevel, subdomain: $subdomain")
+        case None =>
+          discoveryClient.getChildren(engineSpace).map { child =>
+            info(s"Listing engine nodes under $engineSpace/$child")
+            engineNodes ++= 
discoveryClient.getServiceNodesInfo(s"$engineSpace/$child")
           }
-        }
+      }
     }
     engineNodes.map(node =>
       new Engine(
@@ -360,7 +350,7 @@ private[v1] class AdminResource extends ApiRequestContext 
with Logging {
     servers.toSeq
   }
 
-  private def getEngine(
+  private def normalizeEngineInfo(
       userName: String,
       engineType: String,
       shareLevel: String,
@@ -373,6 +363,7 @@ private[v1] class AdminResource extends ApiRequestContext 
with Logging {
       .foreach(_ => clonedConf.set(ENGINE_SHARE_LEVEL_SUBDOMAIN, 
Option(subdomain)))
     
Option(shareLevel).filter(_.nonEmpty).foreach(clonedConf.set(ENGINE_SHARE_LEVEL,
 _))
 
+    val serverSpace = clonedConf.get(HA_NAMESPACE)
     val normalizedEngineType = clonedConf.get(ENGINE_TYPE)
     val engineSubdomain = 
clonedConf.get(ENGINE_SHARE_LEVEL_SUBDOMAIN).getOrElse(subdomainDefault)
     val engineShareLevel = clonedConf.get(ENGINE_SHARE_LEVEL)
@@ -384,22 +375,20 @@ private[v1] class AdminResource extends ApiRequestContext 
with Logging {
       engineShareLevel,
       engineSubdomain,
       null,
-      null,
+      serverSpace,
       Collections.emptyMap())
   }
 
-  private def getEngineSpace(engine: Engine): String = {
-    val serverSpace = fe.getConf.get(HA_NAMESPACE)
-    val appUser = engine.getSharelevel match {
+  private def calculateEngineSpace(engine: Engine): String = {
+    val userOrGroup = engine.getSharelevel match {
       case "GROUP" =>
         fe.sessionManager.groupProvider.primaryGroup(engine.getUser, 
fe.getConf.getAll.asJava)
       case _ => engine.getUser
     }
 
-    DiscoveryPaths.makePath(
-      
s"${serverSpace}_${engine.getVersion}_${engine.getSharelevel}_${engine.getEngineType}",
-      appUser,
-      engine.getSubdomain)
+    val engineSpace =
+      
s"${engine.getNamespace}_${engine.getVersion}_${engine.getSharelevel}_${engine.getEngineType}"
+    DiscoveryPaths.makePath(engineSpace, userOrGroup, engine.getSubdomain)
   }
 
   @ApiResponse(

Reply via email to