From c0126b7f30ff335aa1cfd62508b041084fb090d5 Mon Sep 17 00:00:00 2001 From: He Zhao <32693629+zhaohehuhu@users.noreply.github.com> Date: Tue, 18 Apr 2023 11:12:39 +0800 Subject: [PATCH] [Feature][plugin] Support Kyuubi datasource (#13642) --------- Co-authored-by: weitong Co-authored-by: Rick Cheng <38122586+rickchengx@users.noreply.github.com> --- docs/configs/docsdev.js | 8 + docs/docs/en/guide/datasource/kyuubi.md | 33 +++ docs/docs/zh/guide/datasource/kyuubi.md | 29 +++ docs/img/new_ui/dev/datasource/kyuubi.png | Bin 0 -> 144696 bytes dolphinscheduler-bom/pom.xml | 7 +- .../common/constants/DataSourceConstants.java | 4 + .../dolphinscheduler-datasource-all/pom.xml | 5 + .../pom.xml | 56 +++++ .../kyuubi/KyuubiDataSourceChannel.java | 31 +++ .../KyuubiDataSourceChannelFactory.java | 37 +++ .../kyuubi/KyuubiDataSourceClient.java | 75 ++++++ .../kyuubi/param/KyuubiConnectionParam.java | 38 +++ .../param/KyuubiDataSourceParamDTO.java | 41 ++++ .../param/KyuubiDataSourceProcessor.java | 147 ++++++++++++ .../KyuubiDataSourceChannelFactoryTest.java | 39 ++++ .../kyuubi/KyuubiDataSourceChannelTest.java | 40 ++++ .../kyuubi/KyuubiDataSourceClientTest.java | 73 ++++++ .../param/KyuubiDataSourceProcessorTest.java | 172 ++++++++++++++ .../KyuubiJDBCDataSourceProviderTest.java | 60 +++++ dolphinscheduler-datasource-plugin/pom.xml | 1 + .../licenses/LICENSE-kyuubi-hive-jdbc.txt | 218 ++++++++++++++++++ .../dolphinscheduler/spi/enums/DbType.java | 3 +- .../task/components/node/fields/use-udfs.ts | 9 +- .../task/components/node/format-data.ts | 4 + tools/dependencies/known-dependencies.txt | 1 + 25 files changed, 1126 insertions(+), 5 deletions(-) create mode 100644 docs/docs/en/guide/datasource/kyuubi.md create mode 100644 docs/docs/zh/guide/datasource/kyuubi.md create mode 100644 docs/img/new_ui/dev/datasource/kyuubi.png create mode 100644 dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/pom.xml create mode 100644 dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/src/main/java/org/apache/dolphinscheduler/plugin/datasource/kyuubi/KyuubiDataSourceChannel.java create mode 100644 dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/src/main/java/org/apache/dolphinscheduler/plugin/datasource/kyuubi/KyuubiDataSourceChannelFactory.java create mode 100644 dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/src/main/java/org/apache/dolphinscheduler/plugin/datasource/kyuubi/KyuubiDataSourceClient.java create mode 100644 dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/src/main/java/org/apache/dolphinscheduler/plugin/datasource/kyuubi/param/KyuubiConnectionParam.java create mode 100644 dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/src/main/java/org/apache/dolphinscheduler/plugin/datasource/kyuubi/param/KyuubiDataSourceParamDTO.java create mode 100644 dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/src/main/java/org/apache/dolphinscheduler/plugin/datasource/kyuubi/param/KyuubiDataSourceProcessor.java create mode 100644 dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/src/test/java/org/apache/dolphinscheduler/plugin/datasource/kyuubi/KyuubiDataSourceChannelFactoryTest.java create mode 100644 dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/src/test/java/org/apache/dolphinscheduler/plugin/datasource/kyuubi/KyuubiDataSourceChannelTest.java create mode 100644 dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/src/test/java/org/apache/dolphinscheduler/plugin/datasource/kyuubi/KyuubiDataSourceClientTest.java create mode 100644 dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/src/test/java/org/apache/dolphinscheduler/plugin/datasource/kyuubi/param/KyuubiDataSourceProcessorTest.java create mode 100644 dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/src/test/java/org/apache/dolphinscheduler/plugin/datasource/kyuubi/provider/KyuubiJDBCDataSourceProviderTest.java create mode 100644 dolphinscheduler-dist/release-docs/licenses/LICENSE-kyuubi-hive-jdbc.txt diff --git a/docs/configs/docsdev.js b/docs/configs/docsdev.js index 88e0850cc3..95f042b55c 100644 --- a/docs/configs/docsdev.js +++ b/docs/configs/docsdev.js @@ -271,6 +271,10 @@ export default { title: 'HIVE', link: '/en-us/docs/dev/user_doc/guide/datasource/hive.html', }, + { + title: 'KYUUBI', + link: '/en-us/docs/dev/user_doc/guide/datasource/kyuubi.html', + }, { title: 'Spark', link: '/en-us/docs/dev/user_doc/guide/datasource/spark.html', @@ -964,6 +968,10 @@ export default { title: 'HIVE', link: '/zh-cn/docs/dev/user_doc/guide/datasource/hive.html', }, + { + title: 'KYUUBI', + link: '/zh-cn/docs/dev/user_doc/guide/datasource/kyuubi.html', + }, { title: 'Spark', link: '/zh-cn/docs/dev/user_doc/guide/datasource/spark.html', diff --git a/docs/docs/en/guide/datasource/kyuubi.md b/docs/docs/en/guide/datasource/kyuubi.md new file mode 100644 index 0000000000..6fc5c020e6 --- /dev/null +++ b/docs/docs/en/guide/datasource/kyuubi.md @@ -0,0 +1,33 @@ +# KYUUBI + +## Use HiveServer2 + +![kyuubi](../../../../img/new_ui/dev/datasource/kyuubi.png) + +## Datasource Parameters + +| **Datasource** | **Description** | +|----------------------------|-----------------------------------------------------------| +| Datasource | Select KYUUBI. | +| Datasource name | Enter the name of the DataSource. | +| Description | Enter a description of the DataSource. | +| IP/Host Name | Enter the KYUUBI service IP. | +| Port | Enter the KYUUBI service port. | +| Username | Set the username for KYUUBI connection. | +| Password | Set the password for KYUUBI connection. | +| Database name | Enter the database name of the KYUUBI connection. | +| Jdbc connection parameters | Parameter settings for KYUUBI connection, in JSON format. | + +```Kerberos Authentication +just simply configure them in the connection parameters if kerberos authentication is required. + +clientKeytab: path of Kerberos keytab file for client authentication + +clientPrincipal: Kerberos principal for client authentication + +serverPrincipal: Kerberos principal configured by kyuubi.kinit.principal at the server side. +``` + +## Native Supported + +Yes, could use this datasource by default. diff --git a/docs/docs/zh/guide/datasource/kyuubi.md b/docs/docs/zh/guide/datasource/kyuubi.md new file mode 100644 index 0000000000..b880df6a32 --- /dev/null +++ b/docs/docs/zh/guide/datasource/kyuubi.md @@ -0,0 +1,29 @@ +# KYUUBI数据源 + +## 使用HiveServer2 + +![kyuubi](../../../../img/new_ui/dev/datasource/kyuubi.png) + +- 数据源:选择 KYUUBI +- 数据源名称:输入数据源的名称 +- 描述:输入数据源的描述 +- IP 主机名:输入连接 KYUUBI 的 IP +- 端口:输入连接 KYUUBI 的端口 +- 用户名:设置连接 KYUUBI 的用户名 +- 密码:设置连接 KYUUBI 的密码 +- 数据库名:输入连接 KYUUBI 的数据库名称 +- Jdbc 连接参数:用于 KYUUBI 连接的参数设置,以 JSON 形式填写 + +```Kerberos 验证 +如需Kerberos验证,请直接配置相应参数在jdbc连接参数中 + +clientKeytab: 用户客户端验证的keytab文件路径 + +clientPrincipal: 用户客户端验证的Kerberos principal + +serverPrincipal: 在服务端通过kyuubi.kinit.principal配置的Kerberos principal. +``` + +## 是否原生支持 + +是,数据源不需要任务附加操作即可使用。 diff --git a/docs/img/new_ui/dev/datasource/kyuubi.png b/docs/img/new_ui/dev/datasource/kyuubi.png new file mode 100644 index 0000000000000000000000000000000000000000..abdfdcb6df2f8c3861e634c58dedf6ca9b5e0081 GIT binary patch literal 144696 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.1-jre 42.4.1 2.3.9 + 1.7.0 2.11.0 6.1.1 0.3.2-patch11 @@ -537,7 +538,11 @@ - + + org.apache.kyuubi + kyuubi-hive-jdbc-shaded + ${kyuubi-jdbc.version} + commons-io commons-io diff --git a/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/constants/DataSourceConstants.java b/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/constants/DataSourceConstants.java index f2f580a8b8..16e66d515a 100644 --- a/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/constants/DataSourceConstants.java +++ b/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/constants/DataSourceConstants.java @@ -37,6 +37,7 @@ public class DataSourceConstants { public static final String COM_ATHENA_JDBC_DRIVER = "com.simba.athena.jdbc.Driver"; public static final String COM_TRINO_JDBC_DRIVER = "io.trino.jdbc.TrinoDriver"; public static final String COM_DAMENG_JDBC_DRIVER = "dm.jdbc.driver.DmDriver"; + public static final String ORG_APACHE_KYUUBI_JDBC_DRIVER = "org.apache.kyuubi.jdbc.KyuubiHiveDriver"; public static final String COM_OCEANBASE_JDBC_DRIVER = "com.oceanbase.jdbc.Driver"; /** @@ -55,12 +56,15 @@ public class DataSourceConstants { public static final String TRINO_VALIDATION_QUERY = "select 1"; public static final String DAMENG_VALIDATION_QUERY = "select 1"; + public static final String KYUUBI_VALIDATION_QUERY = "select 1"; + /** * jdbc url */ public static final String JDBC_MYSQL = "jdbc:mysql://"; public static final String JDBC_POSTGRESQL = "jdbc:postgresql://"; public static final String JDBC_HIVE_2 = "jdbc:hive2://"; + public static final String JDBC_KYUUBI = "jdbc:kyuubi://"; public static final String JDBC_CLICKHOUSE = "jdbc:clickhouse://"; public static final String JDBC_ORACLE_SID = "jdbc:oracle:thin:@"; public static final String JDBC_ORACLE_SERVICE_NAME = "jdbc:oracle:thin:@//"; diff --git a/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-all/pom.xml b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-all/pom.xml index 010343bde8..5eda89cc12 100644 --- a/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-all/pom.xml +++ b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-all/pom.xml @@ -112,5 +112,10 @@ dolphinscheduler-datasource-ssh ${project.version} + + org.apache.dolphinscheduler + dolphinscheduler-datasource-kyuubi + ${project.version} + diff --git a/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/pom.xml b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/pom.xml new file mode 100644 index 0000000000..86381d7aad --- /dev/null +++ b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/pom.xml @@ -0,0 +1,56 @@ + + + + 4.0.0 + + org.apache.dolphinscheduler + dolphinscheduler-datasource-plugin + dev-SNAPSHOT + + + dolphinscheduler-datasource-kyuubi + jar + ${project.artifactId} + + + + org.apache.dolphinscheduler + dolphinscheduler-spi + provided + + + + org.apache.dolphinscheduler + dolphinscheduler-datasource-api + ${project.version} + + + + org.apache.dolphinscheduler + dolphinscheduler-task-api + provided + + + + org.apache.kyuubi + kyuubi-hive-jdbc-shaded + + + + diff --git a/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/src/main/java/org/apache/dolphinscheduler/plugin/datasource/kyuubi/KyuubiDataSourceChannel.java b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/src/main/java/org/apache/dolphinscheduler/plugin/datasource/kyuubi/KyuubiDataSourceChannel.java new file mode 100644 index 0000000000..28c85c8a2c --- /dev/null +++ b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/src/main/java/org/apache/dolphinscheduler/plugin/datasource/kyuubi/KyuubiDataSourceChannel.java @@ -0,0 +1,31 @@ +/* + * 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.dolphinscheduler.plugin.datasource.kyuubi; + +import org.apache.dolphinscheduler.spi.datasource.BaseConnectionParam; +import org.apache.dolphinscheduler.spi.datasource.DataSourceChannel; +import org.apache.dolphinscheduler.spi.datasource.DataSourceClient; +import org.apache.dolphinscheduler.spi.enums.DbType; + +public class KyuubiDataSourceChannel implements DataSourceChannel { + + @Override + public DataSourceClient createDataSourceClient(BaseConnectionParam baseConnectionParam, DbType dbType) { + return new KyuubiDataSourceClient(baseConnectionParam, dbType); + } +} diff --git a/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/src/main/java/org/apache/dolphinscheduler/plugin/datasource/kyuubi/KyuubiDataSourceChannelFactory.java b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/src/main/java/org/apache/dolphinscheduler/plugin/datasource/kyuubi/KyuubiDataSourceChannelFactory.java new file mode 100644 index 0000000000..4c67a2098f --- /dev/null +++ b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/src/main/java/org/apache/dolphinscheduler/plugin/datasource/kyuubi/KyuubiDataSourceChannelFactory.java @@ -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. + */ + +package org.apache.dolphinscheduler.plugin.datasource.kyuubi; + +import org.apache.dolphinscheduler.spi.datasource.DataSourceChannel; +import org.apache.dolphinscheduler.spi.datasource.DataSourceChannelFactory; + +import com.google.auto.service.AutoService; + +@AutoService(DataSourceChannelFactory.class) +public class KyuubiDataSourceChannelFactory implements DataSourceChannelFactory { + + @Override + public String getName() { + return "kyuubi"; + } + + @Override + public DataSourceChannel create() { + return new KyuubiDataSourceChannel(); + } +} diff --git a/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/src/main/java/org/apache/dolphinscheduler/plugin/datasource/kyuubi/KyuubiDataSourceClient.java b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/src/main/java/org/apache/dolphinscheduler/plugin/datasource/kyuubi/KyuubiDataSourceClient.java new file mode 100644 index 0000000000..3e0af69577 --- /dev/null +++ b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/src/main/java/org/apache/dolphinscheduler/plugin/datasource/kyuubi/KyuubiDataSourceClient.java @@ -0,0 +1,75 @@ +/* + * 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.dolphinscheduler.plugin.datasource.kyuubi; + +import org.apache.dolphinscheduler.plugin.datasource.api.client.CommonDataSourceClient; +import org.apache.dolphinscheduler.plugin.datasource.api.provider.JDBCDataSourceProvider; +import org.apache.dolphinscheduler.spi.datasource.BaseConnectionParam; +import org.apache.dolphinscheduler.spi.enums.DbType; + +import java.sql.Connection; +import java.sql.SQLException; + +import lombok.extern.slf4j.Slf4j; + +import org.springframework.jdbc.core.JdbcTemplate; + +@Slf4j +public class KyuubiDataSourceClient extends CommonDataSourceClient { + + public KyuubiDataSourceClient(BaseConnectionParam baseConnectionParam, DbType dbType) { + super(baseConnectionParam, dbType); + } + + @Override + protected void preInit() { + log.info("PreInit in {}", getClass().getName()); + } + + @Override + protected void initClient(BaseConnectionParam baseConnectionParam, DbType dbType) { + + this.dataSource = JDBCDataSourceProvider.createOneSessionJdbcDataSource(baseConnectionParam, dbType); + this.jdbcTemplate = new JdbcTemplate(dataSource); + log.info("Init {} success.", getClass().getName()); + } + + @Override + protected void checkEnv(BaseConnectionParam baseConnectionParam) { + super.checkEnv(baseConnectionParam); + } + + @Override + public Connection getConnection() { + Connection connection = null; + while (connection == null) { + try { + connection = dataSource.getConnection(); + } catch (SQLException e) { + log.error("Failed to get Kyuubi Connection.", e); + } + } + return connection; + } + + @Override + public void close() { + super.close(); + log.info("Closed Kyuubi datasource client."); + } +} diff --git a/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/src/main/java/org/apache/dolphinscheduler/plugin/datasource/kyuubi/param/KyuubiConnectionParam.java b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/src/main/java/org/apache/dolphinscheduler/plugin/datasource/kyuubi/param/KyuubiConnectionParam.java new file mode 100644 index 0000000000..9c9097f897 --- /dev/null +++ b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/src/main/java/org/apache/dolphinscheduler/plugin/datasource/kyuubi/param/KyuubiConnectionParam.java @@ -0,0 +1,38 @@ +/* + * 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.dolphinscheduler.plugin.datasource.kyuubi.param; + +import org.apache.dolphinscheduler.spi.datasource.BaseConnectionParam; + +public class KyuubiConnectionParam extends BaseConnectionParam { + + @Override + public String toString() { + return "KyuubiConnectionParam{" + + "user='" + user + '\'' + + ", password='" + password + '\'' + + ", address='" + address + '\'' + + ", database='" + database + '\'' + + ", jdbcUrl='" + jdbcUrl + '\'' + + ", driverLocation='" + driverLocation + '\'' + + ", driverClassName='" + driverClassName + '\'' + + ", validationQuery='" + validationQuery + '\'' + + ", other='" + other + '\'' + + '}'; + } +} diff --git a/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/src/main/java/org/apache/dolphinscheduler/plugin/datasource/kyuubi/param/KyuubiDataSourceParamDTO.java b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/src/main/java/org/apache/dolphinscheduler/plugin/datasource/kyuubi/param/KyuubiDataSourceParamDTO.java new file mode 100644 index 0000000000..e81151fcfd --- /dev/null +++ b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/src/main/java/org/apache/dolphinscheduler/plugin/datasource/kyuubi/param/KyuubiDataSourceParamDTO.java @@ -0,0 +1,41 @@ +/* + * 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.dolphinscheduler.plugin.datasource.kyuubi.param; + +import org.apache.dolphinscheduler.plugin.datasource.api.datasource.BaseDataSourceParamDTO; +import org.apache.dolphinscheduler.spi.enums.DbType; + +public class KyuubiDataSourceParamDTO extends BaseDataSourceParamDTO { + + @Override + public String toString() { + return "KyuubiDataSourceParamDTO{" + + "host='" + host + '\'' + + ", port=" + port + + ", database='" + database + '\'' + + ", userName='" + userName + '\'' + + ", password='" + password + '\'' + + ", other='" + other + '\'' + + '}'; + } + + @Override + public DbType getType() { + return DbType.KYUUBI; + } +} diff --git a/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/src/main/java/org/apache/dolphinscheduler/plugin/datasource/kyuubi/param/KyuubiDataSourceProcessor.java b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/src/main/java/org/apache/dolphinscheduler/plugin/datasource/kyuubi/param/KyuubiDataSourceProcessor.java new file mode 100644 index 0000000000..37fa9ab929 --- /dev/null +++ b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/src/main/java/org/apache/dolphinscheduler/plugin/datasource/kyuubi/param/KyuubiDataSourceProcessor.java @@ -0,0 +1,147 @@ +/* + * 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.dolphinscheduler.plugin.datasource.kyuubi.param; + +import org.apache.dolphinscheduler.common.constants.Constants; +import org.apache.dolphinscheduler.common.constants.DataSourceConstants; +import org.apache.dolphinscheduler.common.utils.JSONUtils; +import org.apache.dolphinscheduler.plugin.datasource.api.datasource.AbstractDataSourceProcessor; +import org.apache.dolphinscheduler.plugin.datasource.api.datasource.BaseDataSourceParamDTO; +import org.apache.dolphinscheduler.plugin.datasource.api.datasource.DataSourceProcessor; +import org.apache.dolphinscheduler.plugin.datasource.api.utils.PasswordUtils; +import org.apache.dolphinscheduler.spi.datasource.BaseConnectionParam; +import org.apache.dolphinscheduler.spi.datasource.ConnectionParam; +import org.apache.dolphinscheduler.spi.enums.DbType; + +import org.apache.commons.collections4.MapUtils; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import com.google.auto.service.AutoService; + +@AutoService(DataSourceProcessor.class) +public class KyuubiDataSourceProcessor extends AbstractDataSourceProcessor { + + @Override + public BaseDataSourceParamDTO castDatasourceParamDTO(String paramJson) { + return JSONUtils.parseObject(paramJson, KyuubiDataSourceParamDTO.class); + } + + @Override + public BaseDataSourceParamDTO createDatasourceParamDTO(String connectionJson) { + KyuubiDataSourceParamDTO kyuubiDataSourceParamDTO = new KyuubiDataSourceParamDTO(); + KyuubiConnectionParam kyuubiConnectionParam = (KyuubiConnectionParam) createConnectionParams(connectionJson); + kyuubiDataSourceParamDTO.setDatabase(kyuubiConnectionParam.getDatabase()); + kyuubiDataSourceParamDTO.setUserName(kyuubiConnectionParam.getUser()); + kyuubiDataSourceParamDTO.setOther(kyuubiConnectionParam.getOther()); + + String[] tmpArray = kyuubiConnectionParam.getAddress().split(Constants.DOUBLE_SLASH); + StringBuilder hosts = new StringBuilder(); + String[] hostPortArray = tmpArray[tmpArray.length - 1].split(Constants.COMMA); + for (String hostPort : hostPortArray) { + hosts.append(hostPort.split(Constants.COLON)[0]).append(Constants.COMMA); + } + hosts.deleteCharAt(hosts.length() - 1); + kyuubiDataSourceParamDTO.setHost(hosts.toString()); + kyuubiDataSourceParamDTO.setPort(Integer.parseInt(hostPortArray[0].split(Constants.COLON)[1])); + + return kyuubiDataSourceParamDTO; + } + + @Override + public BaseConnectionParam createConnectionParams(BaseDataSourceParamDTO datasourceParam) { + KyuubiDataSourceParamDTO kyuubiParam = (KyuubiDataSourceParamDTO) datasourceParam; + StringBuilder address = new StringBuilder(); + address.append(DataSourceConstants.JDBC_KYUUBI); + for (String zkHost : kyuubiParam.getHost().split(",")) { + address.append(String.format("%s:%s,", zkHost, kyuubiParam.getPort())); + } + address.deleteCharAt(address.length() - 1); + String jdbcUrl = address + "/" + kyuubiParam.getDatabase(); + KyuubiConnectionParam kyuubiConnectionParam = new KyuubiConnectionParam(); + kyuubiConnectionParam.setDatabase(kyuubiParam.getDatabase()); + kyuubiConnectionParam.setAddress(address.toString()); + kyuubiConnectionParam.setJdbcUrl(jdbcUrl); + kyuubiConnectionParam.setUser(kyuubiParam.getUserName()); + kyuubiConnectionParam.setPassword(PasswordUtils.encodePassword(kyuubiParam.getPassword())); + kyuubiConnectionParam.setDriverClassName(getDatasourceDriver()); + kyuubiConnectionParam.setValidationQuery(getValidationQuery()); + kyuubiConnectionParam.setOther(kyuubiParam.getOther()); + return kyuubiConnectionParam; + } + + @Override + public ConnectionParam createConnectionParams(String connectionJson) { + return JSONUtils.parseObject(connectionJson, KyuubiConnectionParam.class); + + } + + @Override + public String getDatasourceDriver() { + return DataSourceConstants.ORG_APACHE_KYUUBI_JDBC_DRIVER; + } + + @Override + public String getValidationQuery() { + return DataSourceConstants.KYUUBI_VALIDATION_QUERY; + } + + @Override + public String getJdbcUrl(ConnectionParam connectionParam) { + KyuubiConnectionParam kyuubiConnectionParam = (KyuubiConnectionParam) connectionParam; + String jdbcUrl = kyuubiConnectionParam.getJdbcUrl(); + + if (MapUtils.isNotEmpty(kyuubiConnectionParam.getOther())) { + return jdbcUrl + "?" + transformOther(kyuubiConnectionParam.getOther()); + } + return jdbcUrl; + } + + @Override + public Connection getConnection(ConnectionParam connectionParam) throws ClassNotFoundException, SQLException { + KyuubiConnectionParam kyuubiConnectionParam = (KyuubiConnectionParam) connectionParam; + Class.forName(getDatasourceDriver()); + return DriverManager.getConnection(getJdbcUrl(connectionParam), + kyuubiConnectionParam.getUser(), PasswordUtils.decodePassword(kyuubiConnectionParam.getPassword())); + } + + @Override + public DbType getDbType() { + return DbType.KYUUBI; + } + + @Override + public DataSourceProcessor create() { + return new KyuubiDataSourceProcessor(); + } + + private String transformOther(Map otherMap) { + if (MapUtils.isEmpty(otherMap)) { + return null; + } + List otherList = new ArrayList<>(); + otherMap.forEach((key, value) -> otherList.add(String.format("%s=%s", key, value))); + return String.join(";", otherList); + } + +} diff --git a/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/src/test/java/org/apache/dolphinscheduler/plugin/datasource/kyuubi/KyuubiDataSourceChannelFactoryTest.java b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/src/test/java/org/apache/dolphinscheduler/plugin/datasource/kyuubi/KyuubiDataSourceChannelFactoryTest.java new file mode 100644 index 0000000000..bc837cbe43 --- /dev/null +++ b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/src/test/java/org/apache/dolphinscheduler/plugin/datasource/kyuubi/KyuubiDataSourceChannelFactoryTest.java @@ -0,0 +1,39 @@ +/* + * 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.dolphinscheduler.plugin.datasource.kyuubi; + +import org.apache.dolphinscheduler.spi.datasource.DataSourceChannel; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class KyuubiDataSourceChannelFactoryTest { + + @Test + public void testCreate() { + KyuubiDataSourceChannelFactory sourceChannelFactory = new KyuubiDataSourceChannelFactory(); + DataSourceChannel dataSourceChannel = sourceChannelFactory.create(); + Assertions.assertNotNull(dataSourceChannel); + } + + @Test + public void testGetName() { + KyuubiDataSourceChannelFactory sourceChannelFactory = new KyuubiDataSourceChannelFactory(); + Assertions.assertEquals("kyuubi", sourceChannelFactory.getName()); + } +} diff --git a/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/src/test/java/org/apache/dolphinscheduler/plugin/datasource/kyuubi/KyuubiDataSourceChannelTest.java b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/src/test/java/org/apache/dolphinscheduler/plugin/datasource/kyuubi/KyuubiDataSourceChannelTest.java new file mode 100644 index 0000000000..78e3a33d2b --- /dev/null +++ b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/src/test/java/org/apache/dolphinscheduler/plugin/datasource/kyuubi/KyuubiDataSourceChannelTest.java @@ -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. + */ + +package org.apache.dolphinscheduler.plugin.datasource.kyuubi; + +import org.apache.dolphinscheduler.plugin.datasource.kyuubi.param.KyuubiConnectionParam; +import org.apache.dolphinscheduler.spi.enums.DbType; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +public class KyuubiDataSourceChannelTest { + + @Test + public void testCreateDataSourceClient() { + KyuubiDataSourceChannel sourceChannel = Mockito.mock(KyuubiDataSourceChannel.class); + KyuubiDataSourceClient dataSourceClient = Mockito.mock(KyuubiDataSourceClient.class); + Mockito.when(sourceChannel.createDataSourceClient(Mockito.any(), Mockito.any())).thenReturn(dataSourceClient); + Assertions + .assertNotNull(sourceChannel.createDataSourceClient(new KyuubiConnectionParam(), DbType.KYUUBI)); + } +} diff --git a/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/src/test/java/org/apache/dolphinscheduler/plugin/datasource/kyuubi/KyuubiDataSourceClientTest.java b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/src/test/java/org/apache/dolphinscheduler/plugin/datasource/kyuubi/KyuubiDataSourceClientTest.java new file mode 100644 index 0000000000..041420cc48 --- /dev/null +++ b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/src/test/java/org/apache/dolphinscheduler/plugin/datasource/kyuubi/KyuubiDataSourceClientTest.java @@ -0,0 +1,73 @@ +/* + * 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.dolphinscheduler.plugin.datasource.kyuubi; + +import org.apache.dolphinscheduler.plugin.datasource.kyuubi.param.KyuubiConnectionParam; +import org.apache.dolphinscheduler.spi.enums.DbType; + +import java.sql.Connection; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +public class KyuubiDataSourceClientTest { + + @Mock + private KyuubiDataSourceClient kyuubiDataSourceClient; + + @Test + public void testPreInit() { + kyuubiDataSourceClient.preInit(); + Mockito.verify(kyuubiDataSourceClient).preInit(); + } + + @Test + public void testCheckEnv() { + + KyuubiConnectionParam kyuubiConnectionParam = new KyuubiConnectionParam(); + kyuubiDataSourceClient.checkEnv(kyuubiConnectionParam); + Mockito.verify(kyuubiDataSourceClient).checkEnv(kyuubiConnectionParam); + } + + @Test + public void testInitClient() { + KyuubiConnectionParam kyuubiConnectionParam = new KyuubiConnectionParam(); + kyuubiDataSourceClient.initClient(kyuubiConnectionParam, DbType.KYUUBI); + Mockito.verify(kyuubiDataSourceClient).initClient(kyuubiConnectionParam, DbType.KYUUBI); + } + + @Test + public void testCheckClient() { + kyuubiDataSourceClient.checkClient(); + Mockito.verify(kyuubiDataSourceClient).checkClient(); + } + + @Test + public void testGetConnection() { + Connection connection = Mockito.mock(Connection.class); + Mockito.when(kyuubiDataSourceClient.getConnection()).thenReturn(connection); + Assertions.assertNotNull(kyuubiDataSourceClient.getConnection()); + + } + +} diff --git a/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/src/test/java/org/apache/dolphinscheduler/plugin/datasource/kyuubi/param/KyuubiDataSourceProcessorTest.java b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/src/test/java/org/apache/dolphinscheduler/plugin/datasource/kyuubi/param/KyuubiDataSourceProcessorTest.java new file mode 100644 index 0000000000..865565c5dc --- /dev/null +++ b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/src/test/java/org/apache/dolphinscheduler/plugin/datasource/kyuubi/param/KyuubiDataSourceProcessorTest.java @@ -0,0 +1,172 @@ +/* + * 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.dolphinscheduler.plugin.datasource.kyuubi.param; + +import org.apache.dolphinscheduler.common.constants.DataSourceConstants; +import org.apache.dolphinscheduler.common.utils.JSONUtils; +import org.apache.dolphinscheduler.plugin.datasource.api.utils.CommonUtils; +import org.apache.dolphinscheduler.plugin.datasource.api.utils.DataSourceUtils; +import org.apache.dolphinscheduler.plugin.datasource.api.utils.PasswordUtils; +import org.apache.dolphinscheduler.spi.datasource.ConnectionParam; +import org.apache.dolphinscheduler.spi.enums.DbType; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +public class KyuubiDataSourceProcessorTest { + + private KyuubiDataSourceProcessor kyuubiDatasourceProcessor = new KyuubiDataSourceProcessor(); + @Test + public void testCheckDatasourceParam() { + KyuubiDataSourceParamDTO kyuubiDatasourceParamDTO = new KyuubiDataSourceParamDTO(); + kyuubiDatasourceParamDTO.setHost("localhost"); + kyuubiDatasourceParamDTO.setDatabase("default"); + Map other = new HashMap<>(); + other.put("serverTimezone", "Asia/Shanghai"); + kyuubiDatasourceParamDTO.setOther(other); + DataSourceUtils.checkDatasourceParam(kyuubiDatasourceParamDTO); + Assertions.assertTrue(true); + } + + @Test + public void testBuildConnectionParams() { + KyuubiDataSourceParamDTO kyuubiDataSourceParamDTO = new KyuubiDataSourceParamDTO(); + kyuubiDataSourceParamDTO.setHost("localhost"); + kyuubiDataSourceParamDTO.setDatabase("default"); + kyuubiDataSourceParamDTO.setUserName("root"); + kyuubiDataSourceParamDTO.setPort(3306); + kyuubiDataSourceParamDTO.setPassword("123456"); + + try ( + MockedStatic mockedStaticPasswordUtils = Mockito.mockStatic(PasswordUtils.class); + MockedStatic mockedStaticCommonUtils = Mockito.mockStatic(CommonUtils.class)) { + mockedStaticPasswordUtils.when(() -> PasswordUtils.encodePassword(Mockito.anyString())) + .thenReturn("123456"); + mockedStaticCommonUtils.when(CommonUtils::getKerberosStartupState).thenReturn(false); + ConnectionParam connectionParam = DataSourceUtils.buildConnectionParams(kyuubiDataSourceParamDTO); + Assertions.assertNotNull(connectionParam); + } + } + + @Test + public void testBuildConnectionParams2() { + KyuubiDataSourceParamDTO kyuubiDataSourceParamDTO = new KyuubiDataSourceParamDTO(); + kyuubiDataSourceParamDTO.setHost("localhost"); + kyuubiDataSourceParamDTO.setDatabase("default"); + kyuubiDataSourceParamDTO.setUserName("root"); + kyuubiDataSourceParamDTO.setPort(3306); + kyuubiDataSourceParamDTO.setPassword("123456"); + ConnectionParam connectionParam = + DataSourceUtils.buildConnectionParams(DbType.KYUUBI, JSONUtils.toJsonString(kyuubiDataSourceParamDTO)); + Assertions.assertNotNull(connectionParam); + } + @Test + public void testCreateConnectionParams() { + Map props = new HashMap<>(); + props.put("serverTimezone", "utc"); + KyuubiDataSourceParamDTO kyuubiDataSourceParamDTO = new KyuubiDataSourceParamDTO(); + kyuubiDataSourceParamDTO.setHost("localhost1,localhost2"); + kyuubiDataSourceParamDTO.setPort(5142); + kyuubiDataSourceParamDTO.setUserName("default"); + kyuubiDataSourceParamDTO.setDatabase("default"); + kyuubiDataSourceParamDTO.setOther(props); + + try ( + MockedStatic mockedStaticPasswordUtils = Mockito.mockStatic(PasswordUtils.class); + MockedStatic mockedStaticCommonUtils = Mockito.mockStatic(CommonUtils.class)) { + mockedStaticPasswordUtils.when(() -> PasswordUtils.encodePassword(Mockito.anyString())).thenReturn("test"); + KyuubiConnectionParam connectionParams = (KyuubiConnectionParam) kyuubiDatasourceProcessor + .createConnectionParams(kyuubiDataSourceParamDTO); + Assertions.assertNotNull(connectionParams); + Assertions.assertEquals("jdbc:kyuubi://localhost1:5142,localhost2:5142", connectionParams.getAddress()); + } + } + + @Test + public void testCreateConnectionParams2() { + String connectionParam = "{\"user\":\"default\",\"address\":\"jdbc:kyuubi://localhost1:5142,localhost2:5142\"" + + ",\"jdbcUrl\":\"jdbc:kyuubi://localhost1:5142,localhost2:5142/default\"}"; + KyuubiConnectionParam connectionParams = (KyuubiConnectionParam) kyuubiDatasourceProcessor + .createConnectionParams(connectionParam); + Assertions.assertNotNull(connectionParam); + Assertions.assertEquals("default", connectionParams.getUser()); + } + @Test + public void testCreateDatasourceParamDTO() { + String connectionParam = "{\"user\":\"default\",\"address\":\"jdbc:kyuubi://localhost1:5142,localhost2:5142\"" + + ",\"jdbcUrl\":\"jdbc:kyuubi://localhost1:5142,localhost2:5142/default\"}"; + KyuubiDataSourceParamDTO kyuubiDataSourceParamDTO = (KyuubiDataSourceParamDTO) kyuubiDatasourceProcessor + .createDatasourceParamDTO(connectionParam); + Assertions.assertEquals("default", kyuubiDataSourceParamDTO.getUserName()); + } + + @Test + public void testGetDatasourceDriver() { + Assertions.assertEquals(DataSourceConstants.ORG_APACHE_KYUUBI_JDBC_DRIVER, + kyuubiDatasourceProcessor.getDatasourceDriver()); + } + + @Test + public void testGetJdbcUrl() { + KyuubiConnectionParam connectionParam = new KyuubiConnectionParam(); + connectionParam.setJdbcUrl("jdbc:kyuubi://localhost1:5142,localhost2:5142/default"); + Map other = new HashMap<>(); + other.put("serverTimezone", "Asia/Shanghai"); + connectionParam.setOther(other); + Assertions.assertEquals("jdbc:kyuubi://localhost1:5142,localhost2:5142/default?serverTimezone=Asia/Shanghai", + kyuubiDatasourceProcessor.getJdbcUrl(connectionParam)); + } + + @Test + public void testDbType() { + Assertions.assertEquals(18, DbType.KYUUBI.getCode()); + Assertions.assertEquals("kyuubi", DbType.KYUUBI.getDescp()); + Assertions.assertEquals(DbType.KYUUBI, DbType.of(18)); + } + + @Test + public void testGetDbType() { + Assertions.assertEquals(DbType.KYUUBI, kyuubiDatasourceProcessor.getDbType()); + } + + @Test + public void testGetValidationQuery() { + Assertions.assertEquals(DataSourceConstants.KYUUBI_VALIDATION_QUERY, + kyuubiDatasourceProcessor.getValidationQuery()); + } + + @Test + public void testBuildString() { + KyuubiDataSourceParamDTO kyuubiDataSourceParamDTO = new KyuubiDataSourceParamDTO(); + kyuubiDataSourceParamDTO.setHost("localhost"); + kyuubiDataSourceParamDTO.setDatabase("default"); + kyuubiDataSourceParamDTO.setUserName("root"); + kyuubiDataSourceParamDTO.setPort(3306); + kyuubiDataSourceParamDTO.setPassword("123456"); + Assertions.assertNotNull(kyuubiDataSourceParamDTO.toString()); + } + +} diff --git a/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/src/test/java/org/apache/dolphinscheduler/plugin/datasource/kyuubi/provider/KyuubiJDBCDataSourceProviderTest.java b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/src/test/java/org/apache/dolphinscheduler/plugin/datasource/kyuubi/provider/KyuubiJDBCDataSourceProviderTest.java new file mode 100644 index 0000000000..5c135f5004 --- /dev/null +++ b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-kyuubi/src/test/java/org/apache/dolphinscheduler/plugin/datasource/kyuubi/provider/KyuubiJDBCDataSourceProviderTest.java @@ -0,0 +1,60 @@ +/* + * 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.dolphinscheduler.plugin.datasource.kyuubi.provider; + +import org.apache.dolphinscheduler.plugin.datasource.api.provider.JDBCDataSourceProvider; +import org.apache.dolphinscheduler.plugin.datasource.kyuubi.param.KyuubiConnectionParam; +import org.apache.dolphinscheduler.spi.enums.DbType; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +import com.zaxxer.hikari.HikariDataSource; + +public class KyuubiJDBCDataSourceProviderTest { + + @Test + public void testCreateJdbcDataSource() { + try ( + MockedStatic mockedJDBCDataSourceProvider = + Mockito.mockStatic(JDBCDataSourceProvider.class)) { + HikariDataSource dataSource = Mockito.mock(HikariDataSource.class); + mockedJDBCDataSourceProvider + .when(() -> JDBCDataSourceProvider.createJdbcDataSource(Mockito.any(), Mockito.any())) + .thenReturn(dataSource); + Assertions.assertNotNull( + JDBCDataSourceProvider.createJdbcDataSource(new KyuubiConnectionParam(), DbType.KYUUBI)); + } + } + + @Test + public void testCreateOneSessionJdbcDataSource() { + try ( + MockedStatic mockedJDBCDataSourceProvider = + Mockito.mockStatic(JDBCDataSourceProvider.class)) { + HikariDataSource dataSource = Mockito.mock(HikariDataSource.class); + mockedJDBCDataSourceProvider + .when(() -> JDBCDataSourceProvider.createOneSessionJdbcDataSource(Mockito.any(), Mockito.any())) + .thenReturn(dataSource); + Assertions.assertNotNull( + JDBCDataSourceProvider.createOneSessionJdbcDataSource(new KyuubiConnectionParam(), DbType.KYUUBI)); + } + } +} diff --git a/dolphinscheduler-datasource-plugin/pom.xml b/dolphinscheduler-datasource-plugin/pom.xml index 53bfa9e009..97ece76fa8 100644 --- a/dolphinscheduler-datasource-plugin/pom.xml +++ b/dolphinscheduler-datasource-plugin/pom.xml @@ -42,6 +42,7 @@ dolphinscheduler-datasource-all dolphinscheduler-datasource-redshift dolphinscheduler-datasource-athena + dolphinscheduler-datasource-kyuubi dolphinscheduler-datasource-trino dolphinscheduler-datasource-starrocks dolphinscheduler-datasource-azure-sql diff --git a/dolphinscheduler-dist/release-docs/licenses/LICENSE-kyuubi-hive-jdbc.txt b/dolphinscheduler-dist/release-docs/licenses/LICENSE-kyuubi-hive-jdbc.txt new file mode 100644 index 0000000000..837c400271 --- /dev/null +++ b/dolphinscheduler-dist/release-docs/licenses/LICENSE-kyuubi-hive-jdbc.txt @@ -0,0 +1,218 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. + +------------------------------------------------------------------------------------ +This product bundles various third-party components under other open source licenses. +This section summarizes those components and their licenses. See licenses/ +for text of these licenses. + +Apache License Version 2.0 +-------------------------- +kyuubi-server/src/main/resources/org/apache/kyuubi/ui/swagger/* + +MIT license +----------- +kyuubi-server/src/main/resources/org/apache/kyuubi/ui/static/assets/fonts/* +kyuubi-server/src/main/resources/org/apache/kyuubi/ui/static/icon.min.css +kyuubi-server/src/main/resources/org/apache/kyuubi/ui/static/semantic.min.css +kyuubi-server/src/main/resources/org/apache/kyuubi/ui/static/semantic.min.js +kyuubi-server/src/main/resources/org/apache/kyuubi/ui/static/jquery-3.6.0.min.js diff --git a/dolphinscheduler-spi/src/main/java/org/apache/dolphinscheduler/spi/enums/DbType.java b/dolphinscheduler-spi/src/main/java/org/apache/dolphinscheduler/spi/enums/DbType.java index 90d556feaf..3244f2b9ea 100644 --- a/dolphinscheduler-spi/src/main/java/org/apache/dolphinscheduler/spi/enums/DbType.java +++ b/dolphinscheduler-spi/src/main/java/org/apache/dolphinscheduler/spi/enums/DbType.java @@ -45,7 +45,8 @@ public enum DbType { AZURESQL(14, "azuresql"), DAMENG(15, "dameng"), OCEANBASE(16, "oceanbase"), - SSH(17, "ssh"); + SSH(17, "ssh"), + KYUUBI(18, "kyuubi"); private static final Map DB_TYPE_MAP = Arrays.stream(DbType.values()).collect(toMap(DbType::getCode, Functions.identity())); diff --git a/dolphinscheduler-ui/src/views/projects/task/components/node/fields/use-udfs.ts b/dolphinscheduler-ui/src/views/projects/task/components/node/fields/use-udfs.ts index 6ac9712718..3c2f444354 100644 --- a/dolphinscheduler-ui/src/views/projects/task/components/node/fields/use-udfs.ts +++ b/dolphinscheduler-ui/src/views/projects/task/components/node/fields/use-udfs.ts @@ -23,12 +23,15 @@ export function useUdfs(model: { [field: string]: any }): IJsonItem { const { t } = useI18n() const options = ref([]) const loading = ref(false) - const span = computed(() => (['HIVE', 'SPARK'].includes(model.type) ? 24 : 0)) + const span = computed(() => + ['HIVE', 'SPARK', 'KYUUBI'].includes(model.type) ? 24 : 0 + ) const getUdfs = async () => { if (loading.value) return loading.value = true - const res = await queryUdfFuncList({ type: model.type }) + const type = model.type === 'KYUUBI' ? 'HIVE' : model.type + const res = await queryUdfFuncList({ type }) options.value = res.map((udf: { id: number; funcName: string }) => ({ value: String(udf.id), label: udf.funcName @@ -39,7 +42,7 @@ export function useUdfs(model: { [field: string]: any }): IJsonItem { watch( () => model.type, (value) => { - if (['HIVE', 'SPARK'].includes(value)) { + if (['HIVE', 'SPARK', 'KYUUBI'].includes(value)) { getUdfs() } } diff --git a/dolphinscheduler-ui/src/views/projects/task/components/node/format-data.ts b/dolphinscheduler-ui/src/views/projects/task/components/node/format-data.ts index b4c346834a..8b54dc03e4 100644 --- a/dolphinscheduler-ui/src/views/projects/task/components/node/format-data.ts +++ b/dolphinscheduler-ui/src/views/projects/task/components/node/format-data.ts @@ -203,6 +203,10 @@ export function formatParams(data: INodeData): { if (data.udfs) taskParams.udfs = data.udfs.join(',') taskParams.connParams = data.connParams } + + if (data.type === 'KYUUBI') { + if (data.udfs) taskParams.udfs = data.udfs.join(',') + } } if (data.taskType === 'PROCEDURE') { diff --git a/tools/dependencies/known-dependencies.txt b/tools/dependencies/known-dependencies.txt index be7e550e7a..ed9e5e3bd2 100644 --- a/tools/dependencies/known-dependencies.txt +++ b/tools/dependencies/known-dependencies.txt @@ -474,3 +474,4 @@ sshd-sftp-2.8.0.jar sshd-common-2.8.0.jar sshd-core-2.8.0.jar jcl-over-slf4j-1.7.36.jar +kyuubi-hive-jdbc-shaded-1.7.0.jar \ No newline at end of file