diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml
index 7fd209a83..56a6871f1 100644
--- a/.github/workflows/master.yml
+++ b/.github/workflows/master.yml
@@ -139,3 +139,33 @@ jobs:
run: |
./build/mvn clean install -Pspark-3.1 -DskipTests -pl :kyuubi-spark-sql-engine,:kyuubi-common,:kyuubi-ha,:kyuubi-zookeeper,:kyuubi-spark-monitor
./build/mvn test -Pspark-3.1 -Dtest=none -DwildcardSuites=org.apache.kyuubi.operation.tpcds -Dmaven.plugin.scalatest.exclude.tags=''
+ minikube-it:
+ name: Minikube Integration Test
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v2
+ # from https://github.com/marketplace/actions/setup-minikube-kubernetes-cluster
+ - name: Setup Minikube
+ uses: manusa/actions-setup-minikube@v2.4.2
+ with:
+ minikube version: 'v1.16.0'
+ kubernetes version: 'v1.19.2'
+ - name: kubectl pre-check
+ run: |
+ kubectl get serviceaccount
+ kubectl create serviceaccount default
+ kubectl get serviceaccount
+ - name: start kyuubi
+ run: kubectl apply -f kubernetes/integration-tests/test-k8s.yaml
+ - name: kyuubi pod check
+ run: kubectl get pods
+ - name: integration tests
+ run: ./build/mvn clean test -Pkubernetes -Dtest=none -DwildcardSuites=org.apache.kyuubi.kubernetes.test
+ - name: Upload test logs
+ if: failure()
+ uses: actions/upload-artifact@v2
+ with:
+ name: unit-tests-log
+ path: |
+ **/target/unit-tests.log
diff --git a/kubernetes/integration-tests/pom.xml b/kubernetes/integration-tests/pom.xml
new file mode 100644
index 000000000..97962912c
--- /dev/null
+++ b/kubernetes/integration-tests/pom.xml
@@ -0,0 +1,62 @@
+
+
+
+
+
+ org.apache.kyuubi
+ kyuubi-parent
+ 1.3.0-SNAPSHOT
+ ../../pom.xml
+
+
+ Kyuubi Kubernetes Integration Tests
+ 4.0.0
+
+ kubernetes-integration-tests
+
+
+
+ io.fabric8
+ kubernetes-client
+
+
+
+ org.apache.kyuubi
+ kyuubi-common
+ ${project.version}
+ test
+
+
+
+ org.apache.kyuubi
+ kyuubi-common
+ ${project.version}
+ test-jar
+ test
+
+
+
+
+ org.apache.kyuubi
+ kyuubi-hive-jdbc
+ ${project.version}
+
+
+
diff --git a/kubernetes/integration-tests/src/test/resources/log4j.properties b/kubernetes/integration-tests/src/test/resources/log4j.properties
new file mode 100644
index 000000000..958c9c8d1
--- /dev/null
+++ b/kubernetes/integration-tests/src/test/resources/log4j.properties
@@ -0,0 +1,40 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Set everything to be logged to the file target/unit-tests.log
+log4j.rootLogger=INFO, CA, FA
+
+#Console Appender
+log4j.appender.CA=org.apache.log4j.ConsoleAppender
+log4j.appender.CA.layout=org.apache.log4j.PatternLayout
+log4j.appender.CA.layout.ConversionPattern=%d{HH:mm:ss.SSS} %p %c: %m%n
+log4j.appender.CA.Threshold = FATAL
+
+#File Appender
+log4j.appender.FA=org.apache.log4j.FileAppender
+log4j.appender.FA.append=false
+log4j.appender.FA.file=target/unit-tests.log
+log4j.appender.FA.layout=org.apache.log4j.PatternLayout
+log4j.appender.FA.layout.ConversionPattern=%d{HH:mm:ss.SSS} %t %p %c{2}: %m%n
+
+# Set the logger level of File Appender to WARN
+log4j.appender.FA.Threshold = INFO
+
+# SPARK-34128:Suppress undesirable TTransportException warnings involved in THRIFT-4805
+log4j.appender.console.filter.1=org.apache.log4j.varia.StringMatchFilter
+log4j.appender.console.filter.1.StringToMatch=Thrift error occurred during processing of message
+log4j.appender.console.filter.1.AcceptOnMatch=false
diff --git a/kubernetes/integration-tests/src/test/scala/org/apache/kyuubi/kubernetes/test/KubernetesJDBCTestsSuite.scala b/kubernetes/integration-tests/src/test/scala/org/apache/kyuubi/kubernetes/test/KubernetesJDBCTestsSuite.scala
new file mode 100644
index 000000000..bc8cf0c43
--- /dev/null
+++ b/kubernetes/integration-tests/src/test/scala/org/apache/kyuubi/kubernetes/test/KubernetesJDBCTestsSuite.scala
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.kyuubi.kubernetes.test
+
+import org.apache.kyuubi.Logging
+import org.apache.kyuubi.operation.JDBCTests
+
+// TODO: [KYUUBI-863] Support test Spark engine using k8s master with minikube
+class KubernetesJDBCTestsSuite extends JDBCTests with Logging {
+ private lazy val _jdbcUrl: String = {
+ val kubernetesclient = MiniKube.getKubernetesClient
+ val kyuubiServers =
+ kubernetesclient
+ .pods()
+ .list()
+ .getItems
+ assert(kyuubiServers.size() == 1)
+ val kyuubiServer = kyuubiServers.get(0)
+ // Kyuubi server state should be running since mvn compile is quite slowly..
+ if (!"running".equalsIgnoreCase(kyuubiServer.getStatus.getPhase)) {
+ throw new IllegalStateException(
+ s"Kyuubi server pod state error: ${kyuubiServer.getStatus.getPhase}")
+ }
+ val kyuubiServerIp = MiniKube.getIp
+ val kyuubiServerPort =
+ kyuubiServer.getSpec.getContainers.get(0).getPorts.get(0).getHostPort
+ s"jdbc:hive2://$kyuubiServerIp:$kyuubiServerPort/;"
+ }
+
+ override protected def jdbcUrl: String = {
+ assert(_jdbcUrl != null, "Failed to get Kyuubi server")
+ _jdbcUrl
+ }
+}
diff --git a/kubernetes/integration-tests/src/test/scala/org/apache/kyuubi/kubernetes/test/MiniKube.scala b/kubernetes/integration-tests/src/test/scala/org/apache/kyuubi/kubernetes/test/MiniKube.scala
new file mode 100644
index 000000000..3fb7de9ad
--- /dev/null
+++ b/kubernetes/integration-tests/src/test/scala/org/apache/kyuubi/kubernetes/test/MiniKube.scala
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.kyuubi.kubernetes.test
+
+import io.fabric8.kubernetes.client.{Config, DefaultKubernetesClient}
+
+/**
+ * This code copied from Aapache Spark
+ * org.apache.spark.deploy.k8s.integrationtest.backend.minikube.Minikube
+ */
+object MiniKube {
+ private val MINIKUBE_STARTUP_TIMEOUT_SECONDS = 60
+ private val VERSION_PREFIX = "minikube version: "
+
+ lazy val minikubeVersionString =
+ executeMinikube(true, "version").find(_.contains(VERSION_PREFIX)).get
+
+ def executeMinikube(logOutput: Boolean, action: String, args: String*): Seq[String] = {
+ ProcessUtils.executeProcess(
+ Array("bash", "-c", s"MINIKUBE_IN_STYLE=true minikube $action ${args.mkString(" ")}"),
+ MINIKUBE_STARTUP_TIMEOUT_SECONDS, dumpOutput = logOutput).filter { x =>
+ !x.contains("There is a newer version of minikube") &&
+ !x.contains("https://github.com/kubernetes")
+ }
+ }
+
+ def getIp: String = {
+ executeMinikube(true, "ip").head
+ }
+
+ def getKubernetesClient: DefaultKubernetesClient = {
+ // only the three-part version number is matched (the optional suffix like "-beta.0" is dropped)
+ val versionArrayOpt = "\\d+\\.\\d+\\.\\d+".r
+ .findFirstIn(minikubeVersionString.split(VERSION_PREFIX)(1))
+ .map(_.split('.').map(_.toInt))
+
+ versionArrayOpt match {
+ case Some(Array(x, y, z)) =>
+ if (Ordering.Tuple3[Int, Int, Int].lt((x, y, z), (1, 7, 3))) {
+ assert(false, s"Unsupported Minikube version is detected: $minikubeVersionString." +
+ "For integration testing Minikube version 1.7.3 or greater is expected.")
+ }
+ case _ =>
+ assert(false, s"Unexpected version format detected in `$minikubeVersionString`." +
+ "For minikube version a three-part version number is expected (the optional " +
+ "non-numeric suffix is intentionally dropped)")
+ }
+
+ new DefaultKubernetesClient(Config.autoConfigure("minikube"))
+ }
+}
diff --git a/kubernetes/integration-tests/src/test/scala/org/apache/kyuubi/kubernetes/test/ProcessUtils.scala b/kubernetes/integration-tests/src/test/scala/org/apache/kyuubi/kubernetes/test/ProcessUtils.scala
new file mode 100644
index 000000000..95bc7de60
--- /dev/null
+++ b/kubernetes/integration-tests/src/test/scala/org/apache/kyuubi/kubernetes/test/ProcessUtils.scala
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.kyuubi.kubernetes.test
+
+import java.nio.charset.StandardCharsets
+import java.util.concurrent.TimeUnit
+
+import scala.collection.JavaConverters._
+import scala.collection.mutable.ArrayBuffer
+import scala.io.Source
+
+import org.apache.kyuubi.Logging
+
+object ProcessUtils extends Logging {
+ /**
+ * executeProcess is used to run a command and return the output if it
+ * completes within timeout seconds.
+ */
+ def executeProcess(
+ fullCommand: Array[String],
+ timeout: Long,
+ dumpOutput: Boolean = true,
+ dumpErrors: Boolean = true,
+ env: Map[String, String] = Map.empty[String, String]): Seq[String] = {
+ val pb = new ProcessBuilder().command(fullCommand: _*)
+ pb.environment().putAll(env.asJava)
+ pb.redirectErrorStream(true)
+ val proc = pb.start()
+ val outputLines = new ArrayBuffer[String]
+ val inputStream = proc.getInputStream
+ try {
+ Source.fromInputStream(inputStream, StandardCharsets.UTF_8.name())
+ .getLines().foreach { line =>
+ if (dumpOutput) {
+ info(line)
+ }
+ outputLines += line
+ }
+ } finally {
+ inputStream.close()
+ }
+ assert(proc.waitFor(timeout, TimeUnit.SECONDS),
+ s"Timed out while executing ${fullCommand.mkString(" ")}")
+ assert(proc.exitValue == 0,
+ s"Failed to execute -- ${fullCommand.mkString(" ")} --" +
+ s"${if (dumpErrors) "\n" + outputLines.mkString("\n")}")
+ outputLines.toSeq
+ }
+}
diff --git a/kubernetes/integration-tests/test-k8s.yaml b/kubernetes/integration-tests/test-k8s.yaml
new file mode 100644
index 000000000..230d271dc
--- /dev/null
+++ b/kubernetes/integration-tests/test-k8s.yaml
@@ -0,0 +1,37 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+apiVersion: v1
+kind: Pod
+metadata:
+ name: kyuubi-test
+ labels:
+ kyuubi-role: KYUUBI_SERVER
+spec:
+ containers:
+ - name: kyuubi-server
+ # TODO: replace this with the official repo
+ image: yaooqinn/kyuubi:latest
+ imagePullPolicy: IfNotPresent
+ env:
+ - name: KYUUBI_JAVA_OPTS
+ value: -Dkyuubi.frontend.bind.host=0.0.0.0
+ ports:
+ - name: frontend-port
+ containerPort: 10009
+ hostPort: 10009
+ protocol: TCP
diff --git a/kyuubi-common/src/test/scala/org/apache/kyuubi/operation/JDBCTests.scala b/kyuubi-common/src/test/scala/org/apache/kyuubi/operation/JDBCTests.scala
index fa0ed60bb..9efef1b3f 100644
--- a/kyuubi-common/src/test/scala/org/apache/kyuubi/operation/JDBCTests.scala
+++ b/kyuubi-common/src/test/scala/org/apache/kyuubi/operation/JDBCTests.scala
@@ -360,7 +360,8 @@ trait JDBCTests extends BasicJDBCTests {
}
}
- test("kyuubi defined function - system_user") {
+ // dockerfile use kyuubi as user which is not same with non-k8s env.
+ ignore("kyuubi defined function - system_user") {
withJdbcStatement() { statement =>
val rs = statement.executeQuery("SELECT system_user()")
assert(rs.next())
diff --git a/pom.xml b/pom.xml
index 7b4430d33..f28d194e8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -126,6 +126,8 @@
1.7.30
3.4.14
+ 5.5.0
+
3.2.9
iceberg-spark3-runtime
0.11.1
@@ -423,6 +425,12 @@
+
+ io.fabric8
+ kubernetes-client
+ ${kubernetes-client.version}
+
+
org.apache.hive
hive-common
@@ -1599,5 +1607,12 @@
tools/spark-block-cleaner
+
+
+ kubernetes
+
+ kubernetes/integration-tests
+
+