diff --git a/docs/deployment/settings.md b/docs/deployment/settings.md index b006330f977..6fca5cd85e6 100644 --- a/docs/deployment/settings.md +++ b/docs/deployment/settings.md @@ -452,10 +452,14 @@ kyuubi.operation.status.polling.timeout|PT5S|Timeout(ms) for long polling asynch Key | Default | Meaning | Type | Since --- | --- | --- | --- | --- +kyuubi.server.batch.limit.connections.per.ipaddress|<undefined>|Maximum kyuubi server batch connections per ipaddress. Any user exceeding this limit will not be allowed to connect.|int|1.7.0 +kyuubi.server.batch.limit.connections.per.user|<undefined>|Maximum kyuubi server batch connections per user. Any user exceeding this limit will not be allowed to connect.|int|1.7.0 +kyuubi.server.batch.limit.connections.per.user.ipaddress|<undefined>|Maximum kyuubi server batch connections per user:ipaddress combination. Any user-ipaddress exceeding this limit will not be allowed to connect.|int|1.7.0 kyuubi.server.info.provider|ENGINE|The server information provider name, some clients may rely on this information to check the server compatibilities and functionalities.
  • SERVER: Return Kyuubi server information.
  • ENGINE: Return Kyuubi engine information.
  • |string|1.6.1 kyuubi.server.limit.connections.per.ipaddress|<undefined>|Maximum kyuubi server connections per ipaddress. Any user exceeding this limit will not be allowed to connect.|int|1.6.0 kyuubi.server.limit.connections.per.user|<undefined>|Maximum kyuubi server connections per user. Any user exceeding this limit will not be allowed to connect.|int|1.6.0 kyuubi.server.limit.connections.per.user.ipaddress|<undefined>|Maximum kyuubi server connections per user:ipaddress combination. Any user-ipaddress exceeding this limit will not be allowed to connect.|int|1.6.0 +kyuubi.server.limit.connections.user.white.list||The maximin connections of the user in the white list will not be limited.|seq|1.7.0 kyuubi.server.name|<undefined>|The name of Kyuubi Server.|string|1.5.0 kyuubi.server.redaction.regex|<undefined>|Regex to decide which Kyuubi contain sensitive information. When this regex matches a property key or value, the value is redacted from the various logs.||1.6.0 diff --git a/kyuubi-common/src/main/scala/org/apache/kyuubi/config/KyuubiConf.scala b/kyuubi-common/src/main/scala/org/apache/kyuubi/config/KyuubiConf.scala index d231d4a6fe7..e862f86494c 100644 --- a/kyuubi-common/src/main/scala/org/apache/kyuubi/config/KyuubiConf.scala +++ b/kyuubi-common/src/main/scala/org/apache/kyuubi/config/KyuubiConf.scala @@ -2132,6 +2132,15 @@ object KyuubiConf { .intConf .createOptional + val SERVER_LIMIT_CONNECTIONS_USER_WHITE_LIST: ConfigEntry[Seq[String]] = + buildConf("kyuubi.server.limit.connections.user.white.list") + .doc("The maximin connections of the user in the white list will not be limited.") + .version("1.7.0") + .serverOnly + .stringConf + .toSequence() + .createWithDefault(Nil) + val SERVER_LIMIT_BATCH_CONNECTIONS_PER_USER: OptionalConfigEntry[Int] = buildConf("kyuubi.server.batch.limit.connections.per.user") .doc("Maximum kyuubi server batch connections per user." + diff --git a/kyuubi-server/src/main/scala/org/apache/kyuubi/session/KyuubiSessionManager.scala b/kyuubi-server/src/main/scala/org/apache/kyuubi/session/KyuubiSessionManager.scala index 0d3a8fef6fd..fbcc88cc16f 100644 --- a/kyuubi-server/src/main/scala/org/apache/kyuubi/session/KyuubiSessionManager.scala +++ b/kyuubi-server/src/main/scala/org/apache/kyuubi/session/KyuubiSessionManager.scala @@ -280,20 +280,26 @@ class KyuubiSessionManager private (name: String) extends SessionManager(name) { val userLimit = conf.get(SERVER_LIMIT_CONNECTIONS_PER_USER).getOrElse(0) val ipAddressLimit = conf.get(SERVER_LIMIT_CONNECTIONS_PER_IPADDRESS).getOrElse(0) val userIpAddressLimit = conf.get(SERVER_LIMIT_CONNECTIONS_PER_USER_IPADDRESS).getOrElse(0) - limiter = applySessionLimiter(userLimit, ipAddressLimit, userIpAddressLimit) + val userWhiteList = conf.get(SERVER_LIMIT_CONNECTIONS_USER_WHITE_LIST) + limiter = applySessionLimiter(userLimit, ipAddressLimit, userIpAddressLimit, userWhiteList) val userBatchLimit = conf.get(SERVER_LIMIT_BATCH_CONNECTIONS_PER_USER).getOrElse(0) val ipAddressBatchLimit = conf.get(SERVER_LIMIT_BATCH_CONNECTIONS_PER_IPADDRESS).getOrElse(0) val userIpAddressBatchLimit = conf.get(SERVER_LIMIT_BATCH_CONNECTIONS_PER_USER_IPADDRESS).getOrElse(0) - batchLimiter = applySessionLimiter(userBatchLimit, ipAddressBatchLimit, userIpAddressBatchLimit) + batchLimiter = applySessionLimiter( + userBatchLimit, + ipAddressBatchLimit, + userIpAddressBatchLimit, + userWhiteList) } private def applySessionLimiter( userLimit: Int, ipAddressLimit: Int, - userIpAddressLimit: Int): Option[SessionLimiter] = { + userIpAddressLimit: Int, + userWhitelist: Seq[String]): Option[SessionLimiter] = { Seq(userLimit, ipAddressLimit, userIpAddressLimit).find(_ > 0).map(_ => - SessionLimiter(userLimit, ipAddressLimit, userIpAddressLimit)) + SessionLimiter(userLimit, ipAddressLimit, userIpAddressLimit, userWhitelist.toSet)) } } diff --git a/kyuubi-server/src/main/scala/org/apache/kyuubi/session/SessionLimiter.scala b/kyuubi-server/src/main/scala/org/apache/kyuubi/session/SessionLimiter.scala index d104b23c8c0..6c53a8e5e2f 100644 --- a/kyuubi-server/src/main/scala/org/apache/kyuubi/session/SessionLimiter.scala +++ b/kyuubi-server/src/main/scala/org/apache/kyuubi/session/SessionLimiter.scala @@ -101,10 +101,37 @@ class SessionLimiterImpl(userLimit: Int, ipAddressLimit: Int, userIpAddressLimit } } +class SessionLimiterWithUserWhitelistImpl( + userLimit: Int, + ipAddressLimit: Int, + userIpAddressLimit: Int, + userWhitelist: Set[String]) + extends SessionLimiterImpl(userLimit, ipAddressLimit, userIpAddressLimit) { + override def increment(userIpAddress: UserIpAddress): Unit = { + if (!userWhitelist.contains(userIpAddress.user)) { + super.increment(userIpAddress) + } + } + + override def decrement(userIpAddress: UserIpAddress): Unit = { + if (!userWhitelist.contains(userIpAddress.user)) { + super.decrement(userIpAddress) + } + } +} + object SessionLimiter { - def apply(userLimit: Int, ipAddressLimit: Int, userIpAddressLimit: Int): SessionLimiter = { - new SessionLimiterImpl(userLimit, ipAddressLimit, userIpAddressLimit) + def apply( + userLimit: Int, + ipAddressLimit: Int, + userIpAddressLimit: Int, + userWhiteList: Set[String] = Set.empty): SessionLimiter = { + new SessionLimiterWithUserWhitelistImpl( + userLimit, + ipAddressLimit, + userIpAddressLimit, + userWhiteList) } } diff --git a/kyuubi-server/src/test/scala/org/apache/kyuubi/session/SessionLimiterSuite.scala b/kyuubi-server/src/test/scala/org/apache/kyuubi/session/SessionLimiterSuite.scala index d2df573e185..4bafbecf919 100644 --- a/kyuubi-server/src/test/scala/org/apache/kyuubi/session/SessionLimiterSuite.scala +++ b/kyuubi-server/src/test/scala/org/apache/kyuubi/session/SessionLimiterSuite.scala @@ -96,4 +96,25 @@ class SessionLimiterSuite extends KyuubiFunSuite { limiter.asInstanceOf[SessionLimiterImpl].counters().asScala.values .foreach(c => assert(c.get() == 0)) } + + test("test session limiter with user white list") { + val user = "user001" + val ipAddress = "127.0.0.1" + val userLimit = 30 + val ipAddressLimit = 20 + val userIpAddressLimit = 10 + val limiter = SessionLimiter(userLimit, ipAddressLimit, userIpAddressLimit, Set(user)) + for (i <- 0 until 50) { + val userIpAddress = UserIpAddress(user, ipAddress) + limiter.increment(userIpAddress) + } + limiter.asInstanceOf[SessionLimiterImpl].counters().asScala.values + .foreach(c => assert(c.get() == 0)) + for (i <- 0 until 50) { + val userIpAddress = UserIpAddress(user, ipAddress) + limiter.decrement(userIpAddress) + } + limiter.asInstanceOf[SessionLimiterImpl].counters().asScala.values + .foreach(c => assert(c.get() == 0)) + } }