From 78ba71bdbd9aa8e64854fd9a758dfb9f22c3943f Mon Sep 17 00:00:00 2001 From: Tq Date: Mon, 30 Jan 2023 11:15:20 +0800 Subject: [PATCH] [Feature][task]add azure datafactory task type (#13417) * init data factory * add task-type-config.yaml * add data factory ui * submit doc * submit license --------- Co-authored-by: devosend --- docs/docs/en/guide/task/datafactory.md | 70 ++++++++ docs/docs/zh/guide/task/datafactory.md | 68 ++++++++ docs/img/tasks/demo/datafactory.png | Bin 0 -> 7174 bytes docs/img/tasks/demo/datafactory_auth1.png | Bin 0 -> 31893 bytes docs/img/tasks/demo/datafactory_auth2.png | Bin 0 -> 39440 bytes docs/img/tasks/icons/datafactory.png | Bin 0 -> 3707 bytes dolphinscheduler-api/pom.xml | 8 + .../api/controller/CloudController.java | 108 +++++++++++++ .../dolphinscheduler/api/enums/Status.java | 3 + .../api/service/CloudService.java | 31 ++++ .../api/service/impl/CloudServiceImpl.java | 88 ++++++++++ .../src/main/resources/task-type-config.yaml | 1 + dolphinscheduler-bom/pom.xml | 12 ++ .../src/main/resources/common.properties | 11 ++ dolphinscheduler-dist/release-docs/LICENSE | 44 ++++- .../LICENSE-azure-core-management.txt | 14 ++ ...ENSE-azure-resourcemanager-appplatform.txt | 14 ++ ...CENSE-azure-resourcemanager-appservice.txt | 14 ++ ...SE-azure-resourcemanager-authorization.txt | 14 ++ .../LICENSE-azure-resourcemanager-cdn.txt | 14 ++ .../LICENSE-azure-resourcemanager-compute.txt | 14 ++ ...zure-resourcemanager-containerinstance.txt | 14 ++ ...zure-resourcemanager-containerregistry.txt | 14 ++ ...azure-resourcemanager-containerservice.txt | 14 ++ .../LICENSE-azure-resourcemanager-cosmos.txt | 14 ++ ...ENSE-azure-resourcemanager-datafactory.txt | 14 ++ .../LICENSE-azure-resourcemanager-dns.txt | 14 ++ ...ICENSE-azure-resourcemanager-eventhubs.txt | 14 ++ ...LICENSE-azure-resourcemanager-keyvault.txt | 14 ++ .../LICENSE-azure-resourcemanager-monitor.txt | 14 ++ .../LICENSE-azure-resourcemanager-msi.txt | 14 ++ .../LICENSE-azure-resourcemanager-network.txt | 14 ++ ...CENSE-azure-resourcemanager-privatedns.txt | 14 ++ .../LICENSE-azure-resourcemanager-redis.txt | 14 ++ ...ICENSE-azure-resourcemanager-resources.txt | 14 ++ .../LICENSE-azure-resourcemanager-search.txt | 14 ++ ...CENSE-azure-resourcemanager-servicebus.txt | 14 ++ .../LICENSE-azure-resourcemanager-sql.txt | 14 ++ .../LICENSE-azure-resourcemanager-storage.txt | 14 ++ ...E-azure-resourcemanager-trafficmanager.txt | 14 ++ .../LICENSE-azure-resourcemanager.txt | 14 ++ .../LICENSE-azure-security-keyvault-keys.txt | 14 ++ ...ICENSE-azure-security-keyvault-secrets.txt | 14 ++ .../licenses/LICENSE-azure-storage-common.txt | 14 ++ .../LICENSE-azure-storage-file-share.txt | 14 ++ .../docker/file-manage/common.properties | 11 ++ .../dolphinscheduler-task-all/pom.xml | 5 + .../plugin/task/api/TaskConstants.java | 9 ++ .../dolphinscheduler-task-datafactory/pom.xml | 57 +++++++ .../task/datafactory/DatafactoryHook.java | 148 +++++++++++++++++ .../datafactory/DatafactoryParameters.java | 45 ++++++ .../task/datafactory/DatafactoryStatus.java | 38 +++++ .../task/datafactory/DatafactoryTask.java | 118 ++++++++++++++ .../datafactory/DatafactoryTaskChannel.java | 47 ++++++ .../DatafactoryTaskChannelFactory.java | 46 ++++++ .../task/datafactory/DatafactoryTaskTest.java | 120 ++++++++++++++ dolphinscheduler-task-plugin/pom.xml | 1 + .../public/images/task-icons/data_factory.png | Bin 0 -> 4950 bytes .../images/task-icons/data_factory_hover.png | Bin 0 -> 3707 bytes .../src/locales/en_US/project.ts | 21 ++- .../src/locales/zh_CN/project.ts | 8 +- .../src/service/modules/azure/index.ts | 41 +++++ .../src/service/modules/azure/types.ts | 23 +++ .../src/store/project/task-type.ts | 4 + .../src/store/project/types.ts | 1 + .../task/components/node/fields/index.ts | 1 + .../node/fields/use-data-factory.ts | 152 ++++++++++++++++++ .../task/components/node/format-data.ts | 8 +- .../task/components/node/tasks/index.ts | 4 +- .../components/node/tasks/use-data-factory.ts | 72 +++++++++ .../projects/task/components/node/types.ts | 3 + .../projects/task/constants/task-type.ts | 5 + .../workflow/components/dag/dag.module.scss | 6 + tools/dependencies/known-dependencies.txt | 32 ++++ 74 files changed, 1874 insertions(+), 16 deletions(-) create mode 100644 docs/docs/en/guide/task/datafactory.md create mode 100644 docs/docs/zh/guide/task/datafactory.md create mode 100644 docs/img/tasks/demo/datafactory.png create mode 100644 docs/img/tasks/demo/datafactory_auth1.png create mode 100644 docs/img/tasks/demo/datafactory_auth2.png create mode 100644 docs/img/tasks/icons/datafactory.png create mode 100644 dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/CloudController.java create mode 100644 dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/CloudService.java create mode 100644 dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/CloudServiceImpl.java create mode 100644 dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-core-management.txt create mode 100644 dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-appplatform.txt create mode 100644 dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-appservice.txt create mode 100644 dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-authorization.txt create mode 100644 dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-cdn.txt create mode 100644 dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-compute.txt create mode 100644 dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-containerinstance.txt create mode 100644 dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-containerregistry.txt create mode 100644 dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-containerservice.txt create mode 100644 dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-cosmos.txt create mode 100644 dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-datafactory.txt create mode 100644 dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-dns.txt create mode 100644 dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-eventhubs.txt create mode 100644 dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-keyvault.txt create mode 100644 dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-monitor.txt create mode 100644 dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-msi.txt create mode 100644 dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-network.txt create mode 100644 dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-privatedns.txt create mode 100644 dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-redis.txt create mode 100644 dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-resources.txt create mode 100644 dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-search.txt create mode 100644 dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-servicebus.txt create mode 100644 dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-sql.txt create mode 100644 dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-storage.txt create mode 100644 dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-trafficmanager.txt create mode 100644 dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager.txt create mode 100644 dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-security-keyvault-keys.txt create mode 100644 dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-security-keyvault-secrets.txt create mode 100644 dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-storage-common.txt create mode 100644 dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-storage-file-share.txt create mode 100644 dolphinscheduler-task-plugin/dolphinscheduler-task-datafactory/pom.xml create mode 100644 dolphinscheduler-task-plugin/dolphinscheduler-task-datafactory/src/main/java/org/apache/dolphinscheduler/plugin/task/datafactory/DatafactoryHook.java create mode 100644 dolphinscheduler-task-plugin/dolphinscheduler-task-datafactory/src/main/java/org/apache/dolphinscheduler/plugin/task/datafactory/DatafactoryParameters.java create mode 100644 dolphinscheduler-task-plugin/dolphinscheduler-task-datafactory/src/main/java/org/apache/dolphinscheduler/plugin/task/datafactory/DatafactoryStatus.java create mode 100644 dolphinscheduler-task-plugin/dolphinscheduler-task-datafactory/src/main/java/org/apache/dolphinscheduler/plugin/task/datafactory/DatafactoryTask.java create mode 100644 dolphinscheduler-task-plugin/dolphinscheduler-task-datafactory/src/main/java/org/apache/dolphinscheduler/plugin/task/datafactory/DatafactoryTaskChannel.java create mode 100644 dolphinscheduler-task-plugin/dolphinscheduler-task-datafactory/src/main/java/org/apache/dolphinscheduler/plugin/task/datafactory/DatafactoryTaskChannelFactory.java create mode 100644 dolphinscheduler-task-plugin/dolphinscheduler-task-datafactory/src/test/java/org/apache/dolphinscheduler/plugin/task/datafactory/DatafactoryTaskTest.java create mode 100644 dolphinscheduler-ui/public/images/task-icons/data_factory.png create mode 100644 dolphinscheduler-ui/public/images/task-icons/data_factory_hover.png create mode 100644 dolphinscheduler-ui/src/service/modules/azure/index.ts create mode 100644 dolphinscheduler-ui/src/service/modules/azure/types.ts create mode 100644 dolphinscheduler-ui/src/views/projects/task/components/node/fields/use-data-factory.ts create mode 100644 dolphinscheduler-ui/src/views/projects/task/components/node/tasks/use-data-factory.ts diff --git a/docs/docs/en/guide/task/datafactory.md b/docs/docs/en/guide/task/datafactory.md new file mode 100644 index 0000000000..1936db81f1 --- /dev/null +++ b/docs/docs/en/guide/task/datafactory.md @@ -0,0 +1,70 @@ +# Azure DataFactory Node + +## Overview + +In the world of big data, raw, unorganized data is often stored in relational, non-relational, and other storage systems.[Azure DataFactory](https://learn.microsoft.com/en-us/azure/data-factory/introduction) is a managed cloud service that's built for these complex hybrid extract-transform-load (ETL), extract-load-transform (ELT), and data integration projects. + +DolphinScheduler DataFactory functions: + +- Create Azure DataFactory task enable DolphinScheduler to schedule DataFactory pipelines, keep query pipeline execution status until finish the execution. + +## Prerequisite + +- **ResourceGroup**: Azure owns a resource group +- **DataFactory**: Azure owns a data factory under the resource group +- **Pipeline**: Azure owns pipelines under the assigned resource group and data factory +- **Application**: Azure owns an application has permission to visit data factory, enables using SDK to call data factory functions +- **ApplicationClientSecret**: To apply for client secret under Application `Certificates & secrets` +- **AZURE-CLI**: Install Azure auth application AZURE-CLI on machine, please refer to [Install the Azure CLI on Linux](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli-linux) + +### Application Permission Setting + +First, visit the `Subcription` page and choose `Access control (IAM)`, then click `Add role assignment` to the authorization page. +![Subcription-IAM](../../../../img/tasks/demo/datafactory_auth1.png) +After that, select `Contributor` role which satisfy functions calls in data factory. Then click `Members` page, and click `Select members`. +Search application name or application `Object ID` to assign `Contributor` role to application. +![Subcription-Role](../../../../img/tasks/demo/datafactory_auth2.png) + +## Configurations + +Config Azure configurations, modify `azure` related configurations in `common.properties` +- **resource.azure.client.id**: Azure Application Application (client) ID +- **resource.azure.client.secret**: Azure Application client secret under `Certificates & secrets` +- **resource.azure.subId**: Data factory subscription ID +- **resource.azure.tenant.id**: Azure Active Directory tenant ID + +```yaml +# The Azure client ID (Azure Application (client) ID) +resource.azure.client.id=minioadmin +# The Azure client secret in the Azure application +resource.azure.client.secret=minioadmin +# The Azure data factory subscription ID +resource.azure.subId=minioadmin +# The Azure tenant ID in the Azure Active Directory +resource.azure.tenant.id=minioadmin + +``` + +## Create Task + +- Click `Project -> Management-Project -> Name-Workflow Definition`, and click the "Create Workflow" button to enter the + DAG editing page. +- Drag from the toolbar task node to canvas. + +## Task Example + +[//]: # (TODO: use the commented anchor below once our website template supports this syntax) +[//]: # (- Please refer to [DolphinScheduler Task Parameters Appendix](appendix.md#default-task-parameters) `Default Task Parameters` section for default parameters.) + +- Please refer to [DolphinScheduler Task Parameters Appendix](appendix.md) `Default Task Parameters` section for default parameters. + +Here are some specific parameters for the DataFactory plugin: + +- **factoryName**: data factory name +- **resourceGroupName**: resource group name of the data factory +- **pipelineName**: pipeline name under the resource group and data factory + +The following shows the task plugin example: + +![data-factory](../../../../img/tasks/demo/datafactory.png) + diff --git a/docs/docs/zh/guide/task/datafactory.md b/docs/docs/zh/guide/task/datafactory.md new file mode 100644 index 0000000000..0fa3375bc1 --- /dev/null +++ b/docs/docs/zh/guide/task/datafactory.md @@ -0,0 +1,68 @@ +# Azure DataFactory 节点 + +## 综述 + +在大数据环境中,原始、散乱的数据通常存储在关系、非关系和其他存储系统中。[Azure DataFactory](https://learn.microsoft.com/en-us/azure/data-factory/introduction) 是为这些复杂的混合提取-转换-加载 (ETL)、提取-加载-转换 (ELT) 和数据集成项目而构建的托管云服务。 + +DolphinScheduler DataFactory 组件的功能: + +- 创建 Azure DataFactory 任务可以调度DataFactory中的pipeline,持续获取执行状态,直至任务执行完成。 + +## 前置条件 + +- **资源组**: 拥有一个资源组 +- **数据工厂**: 拥有一个资源组下的数据工厂 +- **Pipeline**: 拥有前两者对应的pipeline +- **应用**: 拥有一个有数据工厂访问权限的应用,才能赋予SDK调用数据工厂 +- **应用客户端密钥**: 在应用的`Certificates & secrets`申请客户端密钥 +- **AZURE-CLI**: 在机器上安装了AZURE的鉴权应用AZURE-CLI,请参考[在LINUX上安装AZURE-CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli-linux) + +### 应用权限设置 + +首先打开当前`Subcription`页面,点击`Access control (IAM)`,再点击`Add role assignment`进入授权页面。 +![Subcription-IAM](../../../../img/tasks/demo/datafactory_auth1.png) +首先选择`Contributor`角色足够满足调用数据工厂。然后选择`Members`页面,再选择`Select members`,检索APP名称或APP的`Object ID`并添加,从给指定APP添加权限. +![Subcription-Role](../../../../img/tasks/demo/datafactory_auth2.png) + +## 环境配置 + +需要进行Azure的一些配置,修改`common.properties`中的`azure`相关配置信息 +- **resource.azure.client.id**: Azure Application应用的Application (client) ID +- **resource.azure.client.secret**: Azure Application应用的`Certificates & secrets`下的客户端密钥 +- **resource.azure.subId**: 数据工厂的subscription ID +- **resource.azure.tenant.id**: Azure Active Directory下的tenant ID + +```yaml +# The Azure client ID (Azure Application (client) ID) +resource.azure.client.id=minioadmin +# The Azure client secret in the Azure application +resource.azure.client.secret=minioadmin +# The Azure data factory subscription ID +resource.azure.subId=minioadmin +# The Azure tenant ID in the Azure Active Directory +resource.azure.tenant.id=minioadmin + +``` + +## 创建任务 + +- 点击项目管理-项目名称-工作流定义,点击“创建工作流”按钮,进入 DAG 编辑页面; +- 拖动工具栏的 任务节点到画板中。 + +## 任务样例 + +[//]: # (TODO: use the commented anchor below once our website template supports this syntax) +[//]: # (- 默认参数说明请参考[DolphinScheduler任务参数附录](appendix.md#默认任务参数)`默认任务参数`一栏。) + +- 默认参数说明请参考[DolphinScheduler任务参数附录](appendix.md)`默认任务参数`一栏。 + +### 独有参数 + +- **factoryName**: 数据工厂名称 +- **resourceGroupName**: 与数据工厂相关的资源组名称 +- **pipelineName**: 选取数据工厂以及资源组下的对应pipeline名称 + +组件图示如下: + +![data-factory](../../../../img/tasks/demo/datafactory.png) + diff --git a/docs/img/tasks/demo/datafactory.png b/docs/img/tasks/demo/datafactory.png new file mode 100644 index 0000000000000000000000000000000000000000..711f8982ae5c31190527cf7ff2f75e6a046f9418 GIT binary patch literal 7174 zcmbuEcU)6gXjN+j8NM@ctXPmK8`z8VORYa11{vCH}Yok=2=XWAUw&pdQi^7xuzI!h5*+ z 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 XI{tWEOaT182hr6s(8OM|`{};`&1{uH literal 0 HcmV?d00001 diff --git a/docs/img/tasks/demo/datafactory_auth1.png b/docs/img/tasks/demo/datafactory_auth1.png new file mode 100644 index 0000000000000000000000000000000000000000..5e4bd71500b709a7ce9825a81e807b2a6468ff23 GIT binary patch literal 31893 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 BVPXIP literal 0 HcmV?d00001 diff --git a/docs/img/tasks/demo/datafactory_auth2.png b/docs/img/tasks/demo/datafactory_auth2.png new file mode 100644 index 0000000000000000000000000000000000000000..1a135191ce7ee1ae6af9e4daf59e7712915906a7 GIT binary patch literal 39440 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 z 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 literal 0 HcmV?d00001 diff --git a/docs/img/tasks/icons/datafactory.png b/docs/img/tasks/icons/datafactory.png new file mode 100644 index 0000000000000000000000000000000000000000..9cebaceee44bc2964c88f42489e50517413a3373 GIT binary patch literal 3707 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 literal 0 HcmV?d00001 diff --git a/dolphinscheduler-api/pom.xml b/dolphinscheduler-api/pom.xml index 8badbf4e74..9696ee7e2f 100644 --- a/dolphinscheduler-api/pom.xml +++ b/dolphinscheduler-api/pom.xml @@ -198,6 +198,14 @@ org.springdoc springdoc-openapi-ui + + com.azure.resourcemanager + azure-resourcemanager + + + com.azure.resourcemanager + azure-resourcemanager-datafactory + diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/CloudController.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/CloudController.java new file mode 100644 index 0000000000..a5d73748cb --- /dev/null +++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/CloudController.java @@ -0,0 +1,108 @@ +/* + * 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.api.controller; + +import static org.apache.dolphinscheduler.api.enums.Status.LIST_AZURE_DATA_FACTORY_ERROR; +import static org.apache.dolphinscheduler.api.enums.Status.LIST_AZURE_DATA_FACTORY_PIPELINE_ERROR; +import static org.apache.dolphinscheduler.api.enums.Status.LIST_AZURE_RESOURCE_GROUP_ERROR; + +import org.apache.dolphinscheduler.api.aspect.AccessLogAnnotation; +import org.apache.dolphinscheduler.api.enums.Status; +import org.apache.dolphinscheduler.api.exceptions.ApiException; +import org.apache.dolphinscheduler.api.service.CloudService; +import org.apache.dolphinscheduler.api.utils.Result; +import org.apache.dolphinscheduler.common.constants.Constants; +import org.apache.dolphinscheduler.dao.entity.User; + +import java.util.List; + +import javax.annotation.Resource; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; + +/** + * cloud controller + */ +@Tag(name = "CLOUD_TAG") +@RestController +@RequestMapping("/cloud") +public class CloudController extends BaseController { + + @Resource + private CloudService cloudService; + + /** + * get datafactory list + * + * @param loginUser login user + * @return datafactory name list + */ + @Operation(summary = "listDataFactory", description = "LIST_DATA_FACTORY") + @GetMapping(value = "/azure/datafactory/factories") + @ResponseStatus(HttpStatus.OK) + @ApiException(LIST_AZURE_DATA_FACTORY_ERROR) + @AccessLogAnnotation(ignoreRequestArgs = "loginUser") + public Result listDataFactory(@Parameter(hidden = true) @RequestAttribute(value = Constants.SESSION_USER) User loginUser) { + List factoryNames = cloudService.listDataFactory(loginUser); + return success(Status.SUCCESS.getMsg(), factoryNames); + } + + /** + * get resourceGroup list + * + * @param loginUser login user + * @return resourceGroup list + */ + @Operation(summary = "listResourceGroup", description = "LIST_RESOURCE_GROUP") + @GetMapping(value = "/azure/datafactory/resourceGroups") + @ResponseStatus(HttpStatus.OK) + @ApiException(LIST_AZURE_RESOURCE_GROUP_ERROR) + @AccessLogAnnotation(ignoreRequestArgs = "loginUser") + public Result listResourceGroup(@Parameter(hidden = true) @RequestAttribute(value = Constants.SESSION_USER) User loginUser) { + List resourceGroupNames = cloudService.listResourceGroup(loginUser); + return success(Status.SUCCESS.getMsg(), resourceGroupNames); + } + + /** + * get resourceGroup list + * + * @param loginUser login user + * @return resourceGroup list + */ + @Operation(summary = "listPipeline", description = "LIST_PIPELINE") + @GetMapping(value = "/azure/datafactory/pipelines") + @ResponseStatus(HttpStatus.OK) + @ApiException(LIST_AZURE_DATA_FACTORY_PIPELINE_ERROR) + @AccessLogAnnotation(ignoreRequestArgs = "loginUser") + public Result listPipeline(@Parameter(hidden = true) @RequestAttribute(value = Constants.SESSION_USER) User loginUser, + @RequestParam("factoryName") String factoryName, + @RequestParam("resourceGroupName") String resourceGroupName) { + List pipelineNames = cloudService.listPipeline(loginUser, factoryName, resourceGroupName); + return success(Status.SUCCESS.getMsg(), pipelineNames); + } +} diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/enums/Status.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/enums/Status.java index d60a867d77..97db8eb78f 100644 --- a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/enums/Status.java +++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/enums/Status.java @@ -265,6 +265,9 @@ public enum Status { "请先保存后再执行"), START_NODE_NOT_EXIST_IN_LAST_PROCESS(10207, "this node {0} does not exist in the latest process definition", "该节点 {0} 不存在于最新的流程定义中"), + LIST_AZURE_DATA_FACTORY_ERROR(10208, "list azure data factory error", "查询AZURE数据工厂列表错误"), + LIST_AZURE_RESOURCE_GROUP_ERROR(10209, "list azure resource group error", "查询AZURE资源组列表错误"), + LIST_AZURE_DATA_FACTORY_PIPELINE_ERROR(10210, "list azure data factory pipeline error", "查询AZURE数据工厂pipeline列表错误"), UDF_FUNCTION_NOT_EXIST(20001, "UDF function not found", "UDF函数不存在"), UDF_FUNCTION_EXISTS(20002, "UDF function already exists", "UDF函数已存在"), diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/CloudService.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/CloudService.java new file mode 100644 index 0000000000..057974bf11 --- /dev/null +++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/CloudService.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.api.service; + +import org.apache.dolphinscheduler.dao.entity.User; + +import java.util.List; + +public interface CloudService { + + List listDataFactory(User loginUser); + + List listResourceGroup(User loginUser); + + List listPipeline(User loginUser, String factoryName, String resourceGroupName); +} diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/CloudServiceImpl.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/CloudServiceImpl.java new file mode 100644 index 0000000000..38f7351ce8 --- /dev/null +++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/CloudServiceImpl.java @@ -0,0 +1,88 @@ +/* + * 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.api.service.impl; + +import org.apache.dolphinscheduler.api.service.CloudService; +import org.apache.dolphinscheduler.common.utils.PropertyUtils; +import org.apache.dolphinscheduler.dao.entity.User; +import org.apache.dolphinscheduler.plugin.task.api.TaskConstants; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.stereotype.Service; + +import com.azure.core.http.rest.PagedIterable; +import com.azure.core.management.AzureEnvironment; +import com.azure.core.management.profile.AzureProfile; +import com.azure.identity.ClientSecretCredential; +import com.azure.identity.ClientSecretCredentialBuilder; +import com.azure.resourcemanager.AzureResourceManager; +import com.azure.resourcemanager.datafactory.DataFactoryManager; +import com.azure.resourcemanager.datafactory.models.Factories; +import com.azure.resourcemanager.datafactory.models.PipelineResource; +import com.azure.resourcemanager.resources.models.ResourceGroups; + +@Service +public class CloudServiceImpl extends BaseServiceImpl implements CloudService { + + private static final String AZURE_CLIENT_ID = PropertyUtils.getString(TaskConstants.AZURE_CLIENT_ID); + private static final String AZURE_CLIENT_SECRET = PropertyUtils.getString(TaskConstants.AZURE_CLIENT_SECRET); + private static final String AZURE_ACCESS_SUB_ID = PropertyUtils.getString(TaskConstants.AZURE_ACCESS_SUB_ID); + private static final String AZURE_SECRET_TENANT_ID = PropertyUtils.getString(TaskConstants.AZURE_SECRET_TENANT_ID); + private static final AzureProfile profile = + new AzureProfile(AZURE_SECRET_TENANT_ID, AZURE_ACCESS_SUB_ID, AzureEnvironment.AZURE); + private static final ClientSecretCredential clientSecretCredential = new ClientSecretCredentialBuilder() + .clientId(AZURE_CLIENT_ID) + .clientSecret(AZURE_CLIENT_SECRET) + .tenantId(AZURE_SECRET_TENANT_ID) + .authorityHost(profile.getEnvironment().getActiveDirectoryEndpoint()) + .build(); + private static final DataFactoryManager manager; + private static final AzureResourceManager azure; + + static { + manager = DataFactoryManager.authenticate(clientSecretCredential, profile); + azure = AzureResourceManager.authenticate(clientSecretCredential, profile).withDefaultSubscription(); + } + + @Override + public List listDataFactory(User loginUser) { + Factories factories = manager.factories(); + List names = new ArrayList<>(); + factories.list().stream().forEach(e -> names.add(e.name())); + return names; + } + + @Override + public List listResourceGroup(User loginUser) { + ResourceGroups resourceGroups = azure.resourceGroups(); + List names = new ArrayList<>(); + resourceGroups.list().stream().forEach(e -> names.add(e.name())); + return names; + } + + @Override + public List listPipeline(User loginUser, String factoryName, String resourceGroupName) { + PagedIterable pipelineResources = + manager.pipelines().listByFactory(resourceGroupName, factoryName); + List names = new ArrayList<>(); + pipelineResources.stream().forEach(e -> names.add(e.name())); + return names; + } +} diff --git a/dolphinscheduler-api/src/main/resources/task-type-config.yaml b/dolphinscheduler-api/src/main/resources/task-type-config.yaml index c4f3c148dd..688f02930d 100644 --- a/dolphinscheduler-api/src/main/resources/task-type-config.yaml +++ b/dolphinscheduler-api/src/main/resources/task-type-config.yaml @@ -33,6 +33,7 @@ task: - 'EMR' - 'K8S' - 'DMS' + - 'DATA_FACTORY' logic: - 'SUB_PROCESS' - 'DEPENDENT' diff --git a/dolphinscheduler-bom/pom.xml b/dolphinscheduler-bom/pom.xml index a691d3f2cc..5ff6d57743 100644 --- a/dolphinscheduler-bom/pom.xml +++ b/dolphinscheduler-bom/pom.xml @@ -103,6 +103,8 @@ 1.7.1 2.1.0.9 1.12.300 + 2.21.0 + 1.0.0-beta.19 @@ -798,6 +800,16 @@ azure-identity ${azure-identity.version} + + com.azure.resourcemanager + azure-resourcemanager + ${azure-resourcemanager.version} + + + com.azure.resourcemanager + azure-resourcemanager-datafactory + ${azure-resourcemanager-datafactory.version} + com.amazon.redshift redshift-jdbc42 diff --git a/dolphinscheduler-common/src/main/resources/common.properties b/dolphinscheduler-common/src/main/resources/common.properties index 0ea630f412..b0a45b9cdd 100644 --- a/dolphinscheduler-common/src/main/resources/common.properties +++ b/dolphinscheduler-common/src/main/resources/common.properties @@ -26,6 +26,17 @@ resource.storage.type=NONE # resource store on HDFS/S3 path, resource file will store to this base path, self configuration, please make sure the directory exists on hdfs and have read write permissions. "/dolphinscheduler" is recommended resource.storage.upload.base.path=/dolphinscheduler +# The Azure client ID (Azure Application (client) ID) +resource.azure.client.id=minioadmin +# The Azure client secret in the Azure application +resource.azure.client.secret=minioadmin +# The Azure data factory subscription ID +resource.azure.subId=minioadmin +# The Azure tenant id in the Azure Active Directory +resource.azure.tenant.id=minioadmin +# The query interval +resource.query.interval=10000 + # The AWS access key. if resource.storage.type=S3 or use EMR-Task, This configuration is required resource.aws.access.key.id=minioadmin # The AWS secret access key. if resource.storage.type=S3 or use EMR-Task, This configuration is required diff --git a/dolphinscheduler-dist/release-docs/LICENSE b/dolphinscheduler-dist/release-docs/LICENSE index 2eb79349d3..8dc6103409 100644 --- a/dolphinscheduler-dist/release-docs/LICENSE +++ b/dolphinscheduler-dist/release-docs/LICENSE @@ -517,6 +517,8 @@ The text of each license is also included at licenses/LICENSE-[project].txt. reactor-netty-core 1.0.22: https://mvnrepository.com/artifact/io.projectreactor.netty/reactor-netty-core/1.0.22, Apache 2.0 reactor-netty-http 1.0.22: https://mvnrepository.com/artifact/io.projectreactor.netty/reactor-netty-http/1.0.22, Apache 2.0 DmJdbcDriver18 8.1.2.79: https://mvnrepository.com/artifact/com.dameng/DmJdbcDriver18/8.1.2.79, Apache 2.0 + nimbus-jose-jwt 9.22: https://mvnrepository.com/artifact/com.nimbusds/nimbus-jose-jwt/9.22, Apache 2.0 + woodstox-core 6.4.0: https://mvnrepository.com/artifact/com.fasterxml.woodstox/woodstox-core/6.4.0, Apache 2.0 jna-platform @@ -605,12 +607,42 @@ The text of each license is also included at licenses/LICENSE-[project].txt. bcpkix-jdk15on 1.68: https://mvnrepository.com/artifact/org.bouncycastle/bcpkix-jdk15on, MIT bcprov-jdk15on 1.68: https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on, MIT reactive-streams 1.0.4: https://mvnrepository.com/artifact/org.reactivestreams/reactive-streams/1.0.4, MIT - webjars-locator-core 0.50 https://mvnrepository.com/artifact/org.webjars/webjars-locator-core/0.50, MIT - azure-core 1.34.0 https://mvnrepository.com/artifact/com.azure/azure-core/1.34.0, MIT - azure-core-http-netty 1.12.7 https://mvnrepository.com/artifact/com.azure/azure-core-http-netty/1.12.7, MIT - azure-identity 1.7.1 https://mvnrepository.com/artifact/com.azure/azure-identity/1.7.1, MIT - msal4j 1.13.3 https://mvnrepository.com/artifact/com.microsoft.azure/msal4j/1.13.3, MIT - msal4j-persistence-extension 1.1.0 https://mvnrepository.com/artifact/com.microsoft.azure/msal4j-persistence-extension/1.1.0, MIT + webjars-locator-core 0.50: https://mvnrepository.com/artifact/org.webjars/webjars-locator-core/0.50, MIT + azure-core 1.34.0: https://mvnrepository.com/artifact/com.azure/azure-core/1.34.0, MIT + azure-core-http-netty 1.12.7: https://mvnrepository.com/artifact/com.azure/azure-core-http-netty/1.12.7, MIT + azure-identity 1.7.1: https://mvnrepository.com/artifact/com.azure/azure-identity/1.7.1, MIT + msal4j 1.13.3: https://mvnrepository.com/artifact/com.microsoft.azure/msal4j/1.13.3, MIT + msal4j-persistence-extension 1.1.0: https://mvnrepository.com/artifact/com.microsoft.azure/msal4j-persistence-extension/1.1.0, MIT + azure-resourcemanager 2.21.0: https://mvnrepository.com/artifact/com.azure.resourcemanager/azure-resourcemanager/2.21.0, MIT + azure-resourcemanager-appplatform 2.21.0: https://mvnrepository.com/artifact/com.azure.resourcemanager/azure-resourcemanager-appplatform/2.21.0, MIT + azure-resourcemanager-appservice 2.21.0: https://mvnrepository.com/artifact/com.azure.resourcemanager/azure-resourcemanager-appservice/2.21.0, MIT + azure-resourcemanager-authorization 2.21.0: https://mvnrepository.com/artifact/com.azure.resourcemanager/azure-resourcemanager-authorization/2.21.0, MIT + azure-resourcemanager-cdn 2.21.0: https://mvnrepository.com/artifact/com.azure.resourcemanager/azure-resourcemanager-cdn/2.21.0, MIT + azure-resourcemanager-compute 2.21.0: https://mvnrepository.com/artifact/com.azure.resourcemanager/azure-resourcemanager-compute/2.21.0, MIT + azure-resourcemanager-containerinstance 2.21.0: https://mvnrepository.com/artifact/com.azure.resourcemanager/azure-resourcemanager-containerinstance/2.21.0, MIT + azure-resourcemanager-containerregistry 2.21.0: https://mvnrepository.com/artifact/com.azure.resourcemanager/azure-resourcemanager-containerregistry/2.21.0, MIT + azure-resourcemanager-containerservice 2.21.0: https://mvnrepository.com/artifact/com.azure.resourcemanager/azure-resourcemanager-containerservice/2.21.0, MIT + azure-resourcemanager-cosmos 2.21.0: https://mvnrepository.com/artifact/com.azure.resourcemanager/azure-resourcemanager-cosmos/2.21.0, MIT + azure-resourcemanager-datafactory 1.0.0-beta.19 https://mvnrepository.com/artifact/com.azure.resourcemanager/azure-resourcemanager-datafactory/1.0.0-beta.19, MIT + azure-resourcemanager-dns 2.21.0: https://mvnrepository.com/artifact/com.azure.resourcemanager/azure-resourcemanager-dns/2.21.0, MIT + azure-resourcemanager-eventhubs 2.21.0: https://mvnrepository.com/artifact/com.azure.resourcemanager/azure-resourcemanager-eventhubs/2.21.0, MIT + azure-resourcemanager-keyvault 2.21.0: https://mvnrepository.com/artifact/com.azure.resourcemanager/azure-resourcemanager-keyvault/2.21.0, MIT + azure-resourcemanager-monitor 2.21.0: https://mvnrepository.com/artifact/com.azure.resourcemanager/azure-resourcemanager-monitor/2.21.0, MIT + azure-resourcemanager-msi 2.21.0: https://mvnrepository.com/artifact/com.azure.resourcemanager/azure-resourcemanager-msi/2.21.0, MIT + azure-resourcemanager-network 2.21.0: https://mvnrepository.com/artifact/com.azure.resourcemanager/azure-resourcemanager-network/2.21.0, MIT + azure-resourcemanager-privatedns 2.21.0: https://mvnrepository.com/artifact/com.azure.resourcemanager/azure-resourcemanager-privatedns/2.21.0, MIT + azure-resourcemanager-redis 2.21.0: https://mvnrepository.com/artifact/com.azure.resourcemanager/azure-resourcemanager-redis/2.21.0, MIT + azure-resourcemanager-resources 2.21.0: https://mvnrepository.com/artifact/com.azure.resourcemanager/azure-resourcemanager-resources/2.21.0, MIT + azure-resourcemanager-search 2.21.0: https://mvnrepository.com/artifact/com.azure.resourcemanager/azure-resourcemanager-search/2.21.0, MIT + azure-resourcemanager-servicebus 2.21.0: https://mvnrepository.com/artifact/com.azure.resourcemanager/azure-resourcemanager-servicebus/2.21.0, MIT + azure-resourcemanager-sql 2.21.0: https://mvnrepository.com/artifact/com.azure.resourcemanager/azure-resourcemanager-sql/2.21.0, MIT + azure-resourcemanager-storage 2.21.0: https://mvnrepository.com/artifact/com.azure.resourcemanager/azure-resourcemanager-storage/2.21.0, MIT + azure-resourcemanager-trafficmanager 2.21.0: https://mvnrepository.com/artifact/com.azure.resourcemanager/azure-resourcemanager-trafficmanager/2.21.0, MIT + azure-security-keyvault-keys 4.5.2: https://mvnrepository.com/artifact/com.azure/azure-security-keyvault-keys/4.5.2, MIT + azure-security-keyvault-secrets 4.5.2: https://mvnrepository.com/artifact/com.azure/azure-security-keyvault-secrets/4.5.2, MIT + azure-storage-common 12.19.1: https://mvnrepository.com/artifact/com.azure/azure-storage-common/12.19.1, MIT + azure-storage-file-share 12.16.1: https://mvnrepository.com/artifact/com.azure/azure-storage-file-share/12.16.1, MIT + azure-core-management 1.9.0: https://mvnrepository.com/artifact/com.azure/azure-core-management/1.9.0, MIT ======================================================================== MPL 1.1 licenses diff --git a/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-core-management.txt b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-core-management.txt new file mode 100644 index 0000000000..d332c60cd0 --- /dev/null +++ b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-core-management.txt @@ -0,0 +1,14 @@ +Copyright(c) 2016 Microsoft Corporation +All rights reserved. + +MIT License +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), +to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. \ No newline at end of file diff --git a/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-appplatform.txt b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-appplatform.txt new file mode 100644 index 0000000000..d332c60cd0 --- /dev/null +++ b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-appplatform.txt @@ -0,0 +1,14 @@ +Copyright(c) 2016 Microsoft Corporation +All rights reserved. + +MIT License +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), +to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. \ No newline at end of file diff --git a/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-appservice.txt b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-appservice.txt new file mode 100644 index 0000000000..d332c60cd0 --- /dev/null +++ b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-appservice.txt @@ -0,0 +1,14 @@ +Copyright(c) 2016 Microsoft Corporation +All rights reserved. + +MIT License +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), +to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. \ No newline at end of file diff --git a/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-authorization.txt b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-authorization.txt new file mode 100644 index 0000000000..d332c60cd0 --- /dev/null +++ b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-authorization.txt @@ -0,0 +1,14 @@ +Copyright(c) 2016 Microsoft Corporation +All rights reserved. + +MIT License +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), +to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. \ No newline at end of file diff --git a/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-cdn.txt b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-cdn.txt new file mode 100644 index 0000000000..d332c60cd0 --- /dev/null +++ b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-cdn.txt @@ -0,0 +1,14 @@ +Copyright(c) 2016 Microsoft Corporation +All rights reserved. + +MIT License +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), +to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. \ No newline at end of file diff --git a/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-compute.txt b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-compute.txt new file mode 100644 index 0000000000..d332c60cd0 --- /dev/null +++ b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-compute.txt @@ -0,0 +1,14 @@ +Copyright(c) 2016 Microsoft Corporation +All rights reserved. + +MIT License +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), +to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. \ No newline at end of file diff --git a/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-containerinstance.txt b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-containerinstance.txt new file mode 100644 index 0000000000..d332c60cd0 --- /dev/null +++ b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-containerinstance.txt @@ -0,0 +1,14 @@ +Copyright(c) 2016 Microsoft Corporation +All rights reserved. + +MIT License +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), +to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. \ No newline at end of file diff --git a/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-containerregistry.txt b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-containerregistry.txt new file mode 100644 index 0000000000..d332c60cd0 --- /dev/null +++ b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-containerregistry.txt @@ -0,0 +1,14 @@ +Copyright(c) 2016 Microsoft Corporation +All rights reserved. + +MIT License +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), +to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. \ No newline at end of file diff --git a/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-containerservice.txt b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-containerservice.txt new file mode 100644 index 0000000000..d332c60cd0 --- /dev/null +++ b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-containerservice.txt @@ -0,0 +1,14 @@ +Copyright(c) 2016 Microsoft Corporation +All rights reserved. + +MIT License +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), +to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. \ No newline at end of file diff --git a/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-cosmos.txt b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-cosmos.txt new file mode 100644 index 0000000000..d332c60cd0 --- /dev/null +++ b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-cosmos.txt @@ -0,0 +1,14 @@ +Copyright(c) 2016 Microsoft Corporation +All rights reserved. + +MIT License +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), +to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. \ No newline at end of file diff --git a/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-datafactory.txt b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-datafactory.txt new file mode 100644 index 0000000000..d332c60cd0 --- /dev/null +++ b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-datafactory.txt @@ -0,0 +1,14 @@ +Copyright(c) 2016 Microsoft Corporation +All rights reserved. + +MIT License +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), +to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. \ No newline at end of file diff --git a/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-dns.txt b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-dns.txt new file mode 100644 index 0000000000..d332c60cd0 --- /dev/null +++ b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-dns.txt @@ -0,0 +1,14 @@ +Copyright(c) 2016 Microsoft Corporation +All rights reserved. + +MIT License +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), +to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. \ No newline at end of file diff --git a/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-eventhubs.txt b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-eventhubs.txt new file mode 100644 index 0000000000..d332c60cd0 --- /dev/null +++ b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-eventhubs.txt @@ -0,0 +1,14 @@ +Copyright(c) 2016 Microsoft Corporation +All rights reserved. + +MIT License +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), +to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. \ No newline at end of file diff --git a/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-keyvault.txt b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-keyvault.txt new file mode 100644 index 0000000000..d332c60cd0 --- /dev/null +++ b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-keyvault.txt @@ -0,0 +1,14 @@ +Copyright(c) 2016 Microsoft Corporation +All rights reserved. + +MIT License +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), +to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. \ No newline at end of file diff --git a/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-monitor.txt b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-monitor.txt new file mode 100644 index 0000000000..d332c60cd0 --- /dev/null +++ b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-monitor.txt @@ -0,0 +1,14 @@ +Copyright(c) 2016 Microsoft Corporation +All rights reserved. + +MIT License +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), +to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. \ No newline at end of file diff --git a/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-msi.txt b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-msi.txt new file mode 100644 index 0000000000..d332c60cd0 --- /dev/null +++ b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-msi.txt @@ -0,0 +1,14 @@ +Copyright(c) 2016 Microsoft Corporation +All rights reserved. + +MIT License +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), +to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. \ No newline at end of file diff --git a/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-network.txt b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-network.txt new file mode 100644 index 0000000000..d332c60cd0 --- /dev/null +++ b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-network.txt @@ -0,0 +1,14 @@ +Copyright(c) 2016 Microsoft Corporation +All rights reserved. + +MIT License +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), +to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. \ No newline at end of file diff --git a/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-privatedns.txt b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-privatedns.txt new file mode 100644 index 0000000000..d332c60cd0 --- /dev/null +++ b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-privatedns.txt @@ -0,0 +1,14 @@ +Copyright(c) 2016 Microsoft Corporation +All rights reserved. + +MIT License +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), +to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. \ No newline at end of file diff --git a/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-redis.txt b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-redis.txt new file mode 100644 index 0000000000..d332c60cd0 --- /dev/null +++ b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-redis.txt @@ -0,0 +1,14 @@ +Copyright(c) 2016 Microsoft Corporation +All rights reserved. + +MIT License +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), +to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. \ No newline at end of file diff --git a/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-resources.txt b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-resources.txt new file mode 100644 index 0000000000..d332c60cd0 --- /dev/null +++ b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-resources.txt @@ -0,0 +1,14 @@ +Copyright(c) 2016 Microsoft Corporation +All rights reserved. + +MIT License +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), +to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. \ No newline at end of file diff --git a/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-search.txt b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-search.txt new file mode 100644 index 0000000000..d332c60cd0 --- /dev/null +++ b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-search.txt @@ -0,0 +1,14 @@ +Copyright(c) 2016 Microsoft Corporation +All rights reserved. + +MIT License +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), +to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. \ No newline at end of file diff --git a/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-servicebus.txt b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-servicebus.txt new file mode 100644 index 0000000000..d332c60cd0 --- /dev/null +++ b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-servicebus.txt @@ -0,0 +1,14 @@ +Copyright(c) 2016 Microsoft Corporation +All rights reserved. + +MIT License +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), +to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. \ No newline at end of file diff --git a/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-sql.txt b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-sql.txt new file mode 100644 index 0000000000..d332c60cd0 --- /dev/null +++ b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-sql.txt @@ -0,0 +1,14 @@ +Copyright(c) 2016 Microsoft Corporation +All rights reserved. + +MIT License +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), +to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. \ No newline at end of file diff --git a/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-storage.txt b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-storage.txt new file mode 100644 index 0000000000..d332c60cd0 --- /dev/null +++ b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-storage.txt @@ -0,0 +1,14 @@ +Copyright(c) 2016 Microsoft Corporation +All rights reserved. + +MIT License +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), +to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. \ No newline at end of file diff --git a/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-trafficmanager.txt b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-trafficmanager.txt new file mode 100644 index 0000000000..d332c60cd0 --- /dev/null +++ b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager-trafficmanager.txt @@ -0,0 +1,14 @@ +Copyright(c) 2016 Microsoft Corporation +All rights reserved. + +MIT License +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), +to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. \ No newline at end of file diff --git a/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager.txt b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager.txt new file mode 100644 index 0000000000..d332c60cd0 --- /dev/null +++ b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-resourcemanager.txt @@ -0,0 +1,14 @@ +Copyright(c) 2016 Microsoft Corporation +All rights reserved. + +MIT License +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), +to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. \ No newline at end of file diff --git a/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-security-keyvault-keys.txt b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-security-keyvault-keys.txt new file mode 100644 index 0000000000..d332c60cd0 --- /dev/null +++ b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-security-keyvault-keys.txt @@ -0,0 +1,14 @@ +Copyright(c) 2016 Microsoft Corporation +All rights reserved. + +MIT License +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), +to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. \ No newline at end of file diff --git a/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-security-keyvault-secrets.txt b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-security-keyvault-secrets.txt new file mode 100644 index 0000000000..d332c60cd0 --- /dev/null +++ b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-security-keyvault-secrets.txt @@ -0,0 +1,14 @@ +Copyright(c) 2016 Microsoft Corporation +All rights reserved. + +MIT License +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), +to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. \ No newline at end of file diff --git a/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-storage-common.txt b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-storage-common.txt new file mode 100644 index 0000000000..b5747801a6 --- /dev/null +++ b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-storage-common.txt @@ -0,0 +1,14 @@ +LICENSE-msal4j.txtCopyright(c) 2016 Microsoft Corporation +All rights reserved. + +MIT License +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), +to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. \ No newline at end of file diff --git a/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-storage-file-share.txt b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-storage-file-share.txt new file mode 100644 index 0000000000..d332c60cd0 --- /dev/null +++ b/dolphinscheduler-dist/release-docs/licenses/LICENSE-azure-storage-file-share.txt @@ -0,0 +1,14 @@ +Copyright(c) 2016 Microsoft Corporation +All rights reserved. + +MIT License +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), +to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. \ No newline at end of file diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/resources/docker/file-manage/common.properties b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/resources/docker/file-manage/common.properties index f4bba5438d..644b8825a9 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/resources/docker/file-manage/common.properties +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/resources/docker/file-manage/common.properties @@ -26,6 +26,17 @@ resource.storage.type=S3 # resource store on HDFS/S3 path, resource file will store to this base path, self configuration, please make sure the directory exists on hdfs and have read write permissions. "/dolphinscheduler" is recommended resource.storage.upload.base.path=/dolphinscheduler +# The Azure client ID (Azure Application (client) ID) +resource.azure.client.id=minioadmin +# The Azure client secret in the Azure application +resource.azure.client.secret=minioadmin +# The Azure data factory subscription ID +resource.azure.subId=minioadmin +# The Azure tenant id in the Azure Active Directory +resource.azure.tenant.id=minioadmin +# The query interval +resource.query.interval=10000 + # The AWS access key. if resource.storage.type=S3 or use EMR-Task, This configuration is required resource.aws.access.key.id=accessKey123 # The AWS secret access key. if resource.storage.type=S3 or use EMR-Task, This configuration is required diff --git a/dolphinscheduler-task-plugin/dolphinscheduler-task-all/pom.xml b/dolphinscheduler-task-plugin/dolphinscheduler-task-all/pom.xml index cd8a33b8a0..9d11d6fe58 100644 --- a/dolphinscheduler-task-plugin/dolphinscheduler-task-all/pom.xml +++ b/dolphinscheduler-task-plugin/dolphinscheduler-task-all/pom.xml @@ -212,6 +212,11 @@ dolphinscheduler-task-linkis ${project.version} + + org.apache.dolphinscheduler + dolphinscheduler-task-datafactory + ${project.version} + diff --git a/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/api/TaskConstants.java b/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/api/TaskConstants.java index d2514e349e..8337dc6f31 100644 --- a/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/api/TaskConstants.java +++ b/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/api/TaskConstants.java @@ -443,6 +443,15 @@ public class TaskConstants { public static final String TASK_TYPE_STREAM = "STREAM"; + /** + * azure config + */ + public static final String AZURE_CLIENT_ID = "resource.azure.client.id"; + public static final String AZURE_CLIENT_SECRET = "resource.azure.client.secret"; + public static final String AZURE_ACCESS_SUB_ID = "resource.azure.subId"; + public static final String AZURE_SECRET_TENANT_ID = "resource.azure.tenant.id"; + public static final String QUERY_INTERVAL = "resource.query.interval"; + /** * aws config */ diff --git a/dolphinscheduler-task-plugin/dolphinscheduler-task-datafactory/pom.xml b/dolphinscheduler-task-plugin/dolphinscheduler-task-datafactory/pom.xml new file mode 100644 index 0000000000..bbc1e59a1f --- /dev/null +++ b/dolphinscheduler-task-plugin/dolphinscheduler-task-datafactory/pom.xml @@ -0,0 +1,57 @@ + + + + 4.0.0 + + org.apache.dolphinscheduler + dolphinscheduler-task-plugin + dev-SNAPSHOT + + + dolphinscheduler-task-datafactory + jar + + + + org.apache.dolphinscheduler + dolphinscheduler-spi + provided + + + org.apache.dolphinscheduler + dolphinscheduler-task-api + provided + + + org.apache.dolphinscheduler + dolphinscheduler-common + provided + + + com.azure.resourcemanager + azure-resourcemanager-datafactory + 1.0.0-beta.19 + + + com.azure + azure-identity + + + + diff --git a/dolphinscheduler-task-plugin/dolphinscheduler-task-datafactory/src/main/java/org/apache/dolphinscheduler/plugin/task/datafactory/DatafactoryHook.java b/dolphinscheduler-task-plugin/dolphinscheduler-task-datafactory/src/main/java/org/apache/dolphinscheduler/plugin/task/datafactory/DatafactoryHook.java new file mode 100644 index 0000000000..763024169d --- /dev/null +++ b/dolphinscheduler-task-plugin/dolphinscheduler-task-datafactory/src/main/java/org/apache/dolphinscheduler/plugin/task/datafactory/DatafactoryHook.java @@ -0,0 +1,148 @@ +/* + * 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.task.datafactory; + +import org.apache.dolphinscheduler.common.utils.PropertyUtils; +import org.apache.dolphinscheduler.plugin.task.api.TaskConstants; + +import org.apache.commons.lang3.StringUtils; + +import java.util.Arrays; +import java.util.List; + +import lombok.Data; +import lombok.SneakyThrows; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.azure.core.management.AzureEnvironment; +import com.azure.core.management.profile.AzureProfile; +import com.azure.identity.ClientSecretCredential; +import com.azure.identity.ClientSecretCredentialBuilder; +import com.azure.resourcemanager.datafactory.DataFactoryManager; +import com.azure.resourcemanager.datafactory.models.CreateRunResponse; +import com.azure.resourcemanager.datafactory.models.PipelineResource; +import com.azure.resourcemanager.datafactory.models.PipelineRun; +import com.azure.resourcemanager.datafactory.models.PipelineRuns; + +@Data +public class DatafactoryHook { + + public static DatafactoryStatus[] taskFinishFlags = + {DatafactoryStatus.Failed, DatafactoryStatus.Succeeded, DatafactoryStatus.Cancelled}; + protected final Logger logger = + LoggerFactory.getLogger(String.format(TaskConstants.TASK_LOG_LOGGER_NAME_FORMAT, getClass())); + private final int QUERY_INTERVAL = PropertyUtils.getInt(TaskConstants.QUERY_INTERVAL, 10000); + private DataFactoryManager client; + private static AzureProfile profile; + private static ClientSecretCredential credential; + private String runId; + + public DatafactoryHook() { + logger.info("initDatafactoryClient ......"); + client = createClient(); + } + + protected static DataFactoryManager createClient() { + final String AZURE_ACCESS_SUB_ID = PropertyUtils.getString(TaskConstants.AZURE_ACCESS_SUB_ID); + final String AZURE_SECRET_TENANT_ID = PropertyUtils.getString(TaskConstants.AZURE_SECRET_TENANT_ID); + final String AZURE_CLIENT_ID = PropertyUtils.getString(TaskConstants.AZURE_CLIENT_ID); + final String AZURE_CLIENT_SECRET = PropertyUtils.getString(TaskConstants.AZURE_CLIENT_SECRET); + profile = + new AzureProfile(AZURE_SECRET_TENANT_ID, AZURE_ACCESS_SUB_ID, AzureEnvironment.AZURE); + credential = new ClientSecretCredentialBuilder() + .clientId(AZURE_CLIENT_ID) + .clientSecret(AZURE_CLIENT_SECRET) + .tenantId(AZURE_SECRET_TENANT_ID) + .authorityHost(profile.getEnvironment().getActiveDirectoryEndpoint()) + .build(); + return DataFactoryManager.authenticate(credential, profile); + } + + public Boolean startDatafactoryTask(DatafactoryParameters parameters) { + logger.info("initDatafactoryTask ......"); + PipelineResource pipelineResource = getPipelineResource(parameters); + if (pipelineResource == null) { + return false; + } + logger.info("startDatafactoryTask ......"); + CreateRunResponse run = pipelineResource.createRun(); + if (StringUtils.isEmpty(run.runId())) { + return false; + } + runId = run.runId(); + parameters.setRunId(runId); + return true; + } + + public Boolean cancelDatafactoryTask(DatafactoryParameters parameters) { + logger.info("cancelTask ......"); + PipelineRuns pipelineRuns = client.pipelineRuns(); + try { + pipelineRuns.cancel(parameters.getResourceGroupName(), parameters.getFactoryName(), runId); + } catch (RuntimeException e) { + logger.error("failed to cancel datafactory task: " + e.getMessage()); + return false; + } + return true; + } + + public DatafactoryStatus queryDatafactoryTaskStatus(DatafactoryParameters parameters) { + logger.info("queryDatafactoryTaskStatus ......"); + + PipelineRuns pipelineRuns = client.pipelineRuns(); + PipelineRun pipelineRun = + pipelineRuns.get(parameters.getResourceGroupName(), parameters.getFactoryName(), runId); + + if (pipelineRun != null) { + logger.info("queryDatafactoryTaskStatus ......{}", pipelineRun.status()); + return DatafactoryStatus.valueOf(pipelineRun.status()); + } + return null; + } + + private PipelineResource getPipelineResource(DatafactoryParameters parameters) { + return client.pipelines().get(parameters.getResourceGroupName(), parameters.getFactoryName(), + parameters.getPipelineName()); + } + + @SneakyThrows + public Boolean queryStatus(DatafactoryParameters parameters) { + List stopStatusSet = Arrays.asList(taskFinishFlags); + int maxRetry = 5; + while (maxRetry > 0) { + DatafactoryStatus status = queryDatafactoryTaskStatus(parameters); + + if (status == null) { + maxRetry--; + continue; + } + + if (stopStatusSet.contains(status)) { + if (status.equals(DatafactoryStatus.Succeeded)) { + return true; + } + return false; + } + logger.debug("wait {}ms to recheck finish status....", QUERY_INTERVAL); + Thread.sleep(QUERY_INTERVAL); + } + return false; + } +} diff --git a/dolphinscheduler-task-plugin/dolphinscheduler-task-datafactory/src/main/java/org/apache/dolphinscheduler/plugin/task/datafactory/DatafactoryParameters.java b/dolphinscheduler-task-plugin/dolphinscheduler-task-datafactory/src/main/java/org/apache/dolphinscheduler/plugin/task/datafactory/DatafactoryParameters.java new file mode 100644 index 0000000000..b0bbb75e8d --- /dev/null +++ b/dolphinscheduler-task-plugin/dolphinscheduler-task-datafactory/src/main/java/org/apache/dolphinscheduler/plugin/task/datafactory/DatafactoryParameters.java @@ -0,0 +1,45 @@ +/* + * 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.task.datafactory; + +import org.apache.dolphinscheduler.plugin.task.api.parameters.AbstractParameters; + +import org.apache.commons.lang3.StringUtils; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@Setter +@Getter +@NoArgsConstructor +@ToString +public class DatafactoryParameters extends AbstractParameters { + + private String factoryName; + private String resourceGroupName; + private String pipelineName; + private String runId; + + @Override + public boolean checkParameters() { + return StringUtils.isNotEmpty(factoryName) && StringUtils.isNotEmpty(resourceGroupName) + && StringUtils.isNotEmpty(pipelineName); + } +} diff --git a/dolphinscheduler-task-plugin/dolphinscheduler-task-datafactory/src/main/java/org/apache/dolphinscheduler/plugin/task/datafactory/DatafactoryStatus.java b/dolphinscheduler-task-plugin/dolphinscheduler-task-datafactory/src/main/java/org/apache/dolphinscheduler/plugin/task/datafactory/DatafactoryStatus.java new file mode 100644 index 0000000000..7f2af88877 --- /dev/null +++ b/dolphinscheduler-task-plugin/dolphinscheduler-task-datafactory/src/main/java/org/apache/dolphinscheduler/plugin/task/datafactory/DatafactoryStatus.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.task.datafactory; + +public enum DatafactoryStatus { + + Queued, + InProgress, + Succeeded, + Failed, + Canceling, + Cancelled, + ; + + /** + * Gets the status property: The status of a pipeline run. Possible values: Queued, InProgress, Succeeded, Failed, + * Canceling, Cancelled. + * + * @return the status value. + */ + DatafactoryStatus() { + } +} diff --git a/dolphinscheduler-task-plugin/dolphinscheduler-task-datafactory/src/main/java/org/apache/dolphinscheduler/plugin/task/datafactory/DatafactoryTask.java b/dolphinscheduler-task-plugin/dolphinscheduler-task-datafactory/src/main/java/org/apache/dolphinscheduler/plugin/task/datafactory/DatafactoryTask.java new file mode 100644 index 0000000000..b8a5db4371 --- /dev/null +++ b/dolphinscheduler-task-plugin/dolphinscheduler-task-datafactory/src/main/java/org/apache/dolphinscheduler/plugin/task/datafactory/DatafactoryTask.java @@ -0,0 +1,118 @@ +/* + * 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.task.datafactory; + +import org.apache.dolphinscheduler.common.utils.JSONUtils; +import org.apache.dolphinscheduler.plugin.task.api.AbstractRemoteTask; +import org.apache.dolphinscheduler.plugin.task.api.TaskConstants; +import org.apache.dolphinscheduler.plugin.task.api.TaskException; +import org.apache.dolphinscheduler.plugin.task.api.TaskExecutionContext; + +import org.apache.commons.lang3.StringUtils; + +import java.util.Collections; +import java.util.List; + +import lombok.Getter; +import lombok.Setter; + +@Setter +@Getter +public class DatafactoryTask extends AbstractRemoteTask { + + private final TaskExecutionContext taskExecutionContext; + private DatafactoryParameters parameters; + private DatafactoryHook hook; + + public DatafactoryTask(TaskExecutionContext taskExecutionContext) { + super(taskExecutionContext); + this.taskExecutionContext = taskExecutionContext; + } + + @Override + public List getApplicationIds() throws TaskException { + return Collections.emptyList(); + } + + @Override + public void init() { + parameters = JSONUtils.parseObject(taskExecutionContext.getTaskParams(), DatafactoryParameters.class); + logger.info("Initialize Datafactory task params {}", JSONUtils.toPrettyJsonString(parameters)); + hook = new DatafactoryHook(); + } + + @Override + public void submitApplication() throws TaskException { + try { + // start task + exitStatusCode = startDatafactoryTask(); + setExitStatusCode(exitStatusCode); + } catch (Exception e) { + setExitStatusCode(TaskConstants.EXIT_CODE_FAILURE); + throw new TaskException("data factory start task error", e); + } + // set runId to the appIds if start success + setAppIds(parameters.getRunId()); + } + + @Override + public void cancelApplication() throws TaskException { + checkApplicationId(); + hook.cancelDatafactoryTask(parameters); + exitStatusCode = TaskConstants.EXIT_CODE_KILL; + } + + @Override + public void trackApplicationStatus() throws TaskException { + checkApplicationId(); + Boolean isFinishedSuccessfully; + isFinishedSuccessfully = hook.queryStatus(parameters); + if (!isFinishedSuccessfully) { + exitStatusCode = TaskConstants.EXIT_CODE_FAILURE; + } else { + exitStatusCode = TaskConstants.EXIT_CODE_SUCCESS; + } + } + + /** + * check datafactory applicationId or get it from appId + */ + private void checkApplicationId() { + String taskExecArn = hook.getRunId(); + if (StringUtils.isEmpty(taskExecArn)) { + if (StringUtils.isEmpty(getAppIds())) { + throw new TaskException("datafactory runId is null, not created yet"); + } + hook.setRunId(getAppIds()); + } + } + + public int startDatafactoryTask() { + Boolean isStartSuccessfully = hook.startDatafactoryTask(parameters); + if (!isStartSuccessfully) { + return TaskConstants.EXIT_CODE_FAILURE; + } + return TaskConstants.EXIT_CODE_SUCCESS; + } + + @Override + public DatafactoryParameters getParameters() { + return parameters; + } + +} diff --git a/dolphinscheduler-task-plugin/dolphinscheduler-task-datafactory/src/main/java/org/apache/dolphinscheduler/plugin/task/datafactory/DatafactoryTaskChannel.java b/dolphinscheduler-task-plugin/dolphinscheduler-task-datafactory/src/main/java/org/apache/dolphinscheduler/plugin/task/datafactory/DatafactoryTaskChannel.java new file mode 100644 index 0000000000..d8c099bb09 --- /dev/null +++ b/dolphinscheduler-task-plugin/dolphinscheduler-task-datafactory/src/main/java/org/apache/dolphinscheduler/plugin/task/datafactory/DatafactoryTaskChannel.java @@ -0,0 +1,47 @@ +/* + * 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.task.datafactory; + +import org.apache.dolphinscheduler.common.utils.JSONUtils; +import org.apache.dolphinscheduler.plugin.task.api.TaskChannel; +import org.apache.dolphinscheduler.plugin.task.api.TaskExecutionContext; +import org.apache.dolphinscheduler.plugin.task.api.parameters.AbstractParameters; +import org.apache.dolphinscheduler.plugin.task.api.parameters.ParametersNode; +import org.apache.dolphinscheduler.plugin.task.api.parameters.resource.ResourceParametersHelper; + +public class DatafactoryTaskChannel implements TaskChannel { + + @Override + public void cancelApplication(boolean status) { + } + + @Override + public DatafactoryTask createTask(TaskExecutionContext taskRequest) { + return new DatafactoryTask(taskRequest); + } + + @Override + public AbstractParameters parseParameters(ParametersNode parametersNode) { + return JSONUtils.parseObject(parametersNode.getTaskParams(), DatafactoryParameters.class); + } + + @Override + public ResourceParametersHelper getResources(String parameters) { + return null; + } +} diff --git a/dolphinscheduler-task-plugin/dolphinscheduler-task-datafactory/src/main/java/org/apache/dolphinscheduler/plugin/task/datafactory/DatafactoryTaskChannelFactory.java b/dolphinscheduler-task-plugin/dolphinscheduler-task-datafactory/src/main/java/org/apache/dolphinscheduler/plugin/task/datafactory/DatafactoryTaskChannelFactory.java new file mode 100644 index 0000000000..e9dce1ac96 --- /dev/null +++ b/dolphinscheduler-task-plugin/dolphinscheduler-task-datafactory/src/main/java/org/apache/dolphinscheduler/plugin/task/datafactory/DatafactoryTaskChannelFactory.java @@ -0,0 +1,46 @@ +/* + * 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.task.datafactory; + +import org.apache.dolphinscheduler.plugin.task.api.TaskChannel; +import org.apache.dolphinscheduler.plugin.task.api.TaskChannelFactory; +import org.apache.dolphinscheduler.spi.params.base.PluginParams; + +import java.util.Collections; +import java.util.List; + +import com.google.auto.service.AutoService; + +@AutoService(TaskChannelFactory.class) +public class DatafactoryTaskChannelFactory implements TaskChannelFactory { + + @Override + public TaskChannel create() { + return new DatafactoryTaskChannel(); + } + + @Override + public String getName() { + return "DATA_FACTORY"; + } + + @Override + public List getParams() { + return Collections.emptyList(); + } +} diff --git a/dolphinscheduler-task-plugin/dolphinscheduler-task-datafactory/src/test/java/org/apache/dolphinscheduler/plugin/task/datafactory/DatafactoryTaskTest.java b/dolphinscheduler-task-plugin/dolphinscheduler-task-datafactory/src/test/java/org/apache/dolphinscheduler/plugin/task/datafactory/DatafactoryTaskTest.java new file mode 100644 index 0000000000..cf2c5a55ea --- /dev/null +++ b/dolphinscheduler-task-plugin/dolphinscheduler-task-datafactory/src/test/java/org/apache/dolphinscheduler/plugin/task/datafactory/DatafactoryTaskTest.java @@ -0,0 +1,120 @@ +/* + * 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.task.datafactory; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.when; + +import org.apache.dolphinscheduler.common.utils.JSONUtils; +import org.apache.dolphinscheduler.plugin.task.api.TaskConstants; +import org.apache.dolphinscheduler.plugin.task.api.TaskExecutionContext; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.azure.resourcemanager.datafactory.DataFactoryManager; +import com.azure.resourcemanager.datafactory.models.CreateRunResponse; +import com.azure.resourcemanager.datafactory.models.PipelineResource; +import com.azure.resourcemanager.datafactory.models.Pipelines; + +@ExtendWith(MockitoExtension.class) +public class DatafactoryTaskTest { + + private static final String mockRunId = + "3c7182f4-d107-43c7-af2a-8c7b3ed1d614"; + + DatafactoryTask datafactoryTask; + + @Mock + DataFactoryManager client; + MockedStatic datafactoryHookMockedStatic; + + @BeforeEach + public void before() throws IllegalAccessException { + client = mock(DataFactoryManager.class); + datafactoryHookMockedStatic = mockStatic(DatafactoryHook.class); + when(DatafactoryHook.createClient()).thenReturn(client); + + DatafactoryParameters datafactoryParameters = new DatafactoryParameters(); + datafactoryTask = initTask(datafactoryParameters); + } + + @Test + public void testConvertParam() { + DatafactoryParameters parameters = castParam(); + Assertions.assertEquals("whale1", parameters.getFactoryName()); + Assertions.assertEquals("factory1", parameters.getResourceGroupName()); + Assertions.assertEquals("CopyPipeline_ps8", parameters.getPipelineName()); + datafactoryHookMockedStatic.close(); + } + + @Test + public void testCheckCreateTask() { + DatafactoryHook hook = new DatafactoryHook(); + DataFactoryManager client1 = DatafactoryHook.createClient(); + hook.setClient(client1); + + PipelineResource pipelineResource = mock(PipelineResource.class); + Pipelines pipelines = mock(Pipelines.class); + when(client1.pipelines()).thenReturn(pipelines); + when(pipelines.get(any(), any(), any())).thenReturn(pipelineResource); + + CreateRunResponse response = mock(CreateRunResponse.class); + when(pipelineResource.createRun()).thenReturn(response); + when(response.runId()).thenReturn(mockRunId); + hook.startDatafactoryTask(castParam()); + Assertions.assertEquals(mockRunId, hook.getRunId()); + datafactoryHookMockedStatic.close(); + } + + @Test + public void testCancelTask() { + datafactoryTask.cancelApplication(); + Assertions.assertEquals(datafactoryTask.getExitStatusCode(), TaskConstants.EXIT_CODE_KILL); + datafactoryHookMockedStatic.close(); + } + + private DatafactoryParameters castParam() { + String input = + "{\"localParams\":[],\"resourceList\":[],\"factoryName\":\"whale1\",\"resourceGroupName\":\"factory1\",\"pipelineName\":\"CopyPipeline_ps8\"}"; + return JSONUtils.parseObject(input, DatafactoryParameters.class); + } + + private DatafactoryTask initTask(DatafactoryParameters DatasyncParameters) { + TaskExecutionContext taskExecutionContext = createContext(DatasyncParameters); + DatafactoryTask task = new DatafactoryTask(taskExecutionContext); + task.init(); + task.getHook().setRunId(mockRunId); + return task; + } + + public TaskExecutionContext createContext(DatafactoryParameters datafactoryParameters) { + String parameters = JSONUtils.toJsonString(datafactoryParameters); + TaskExecutionContext taskExecutionContext = Mockito.mock(TaskExecutionContext.class); + Mockito.when(taskExecutionContext.getTaskParams()).thenReturn(parameters); + return taskExecutionContext; + } +} diff --git a/dolphinscheduler-task-plugin/pom.xml b/dolphinscheduler-task-plugin/pom.xml index 6cd6c8a76a..27b741f06b 100644 --- a/dolphinscheduler-task-plugin/pom.xml +++ b/dolphinscheduler-task-plugin/pom.xml @@ -61,6 +61,7 @@ dolphinscheduler-task-datasync dolphinscheduler-task-kubeflow dolphinscheduler-task-linkis + dolphinscheduler-task-datafactory diff --git a/dolphinscheduler-ui/public/images/task-icons/data_factory.png b/dolphinscheduler-ui/public/images/task-icons/data_factory.png new file mode 100644 index 0000000000000000000000000000000000000000..fb3bbd33d51d4f85a09f0b3ce56ba08ec399201f GIT binary patch literal 4950 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 literal 0 HcmV?d00001 diff --git a/dolphinscheduler-ui/public/images/task-icons/data_factory_hover.png b/dolphinscheduler-ui/public/images/task-icons/data_factory_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..9cebaceee44bc2964c88f42489e50517413a3373 GIT binary patch literal 3707 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 literal 0 HcmV?d00001 diff --git a/dolphinscheduler-ui/src/locales/en_US/project.ts b/dolphinscheduler-ui/src/locales/en_US/project.ts index 5a42e12f53..3ee2cef106 100644 --- a/dolphinscheduler-ui/src/locales/en_US/project.ts +++ b/dolphinscheduler-ui/src/locales/en_US/project.ts @@ -37,10 +37,10 @@ export default { confirm: 'Confirm', cancel: 'Cancel', delete_confirm: 'Delete?', - authorize_level:'Authorize Level', + authorize_level: 'Authorize Level', no_permission: 'No Permission', read_permission: 'Read Permission', - all_permission: 'All Permission', + all_permission: 'All Permission' }, workflow: { on_line: 'Online', @@ -215,7 +215,7 @@ export default { workflow_relation_no_data_result_desc: 'There is not any workflows. Please create a workflow, and then visit this page again.', ready_to_block: 'Ready to block', - block: 'Block', + block: 'Block' }, task: { on_line: 'Online', @@ -329,7 +329,7 @@ export default { online: 'Online' }, node: { - is_cache: "Cache Execution", + is_cache: 'Cache Execution', jvm_args: 'Java VM Parameters', jvm_args_tips: 'Please enter virtual machine parameters', run_type: 'Run Type', @@ -377,7 +377,8 @@ export default { image: 'Image', image_tips: 'Please enter image', command: 'Command', - command_tips: 'Please enter the container execution command, for example: /bin/echo hello world', + command_tips: + 'Please enter the container execution command, for example: /bin/echo hello world', min_memory_tips: 'Please enter min memory', state: 'State', branch_flow: 'Branch flow', @@ -798,7 +799,13 @@ export default { pytorch_requirements: 'Requirement File', pytorch_conda_python_version: 'Python Version', pytorch_conda_python_version_tips: - 'Please enter the version number, such as 3.6, 3.7, 3.x' + 'Please enter the version number, such as 3.6, 3.7, 3.x', + factory_name: 'Factory Name', + resource_group_name: 'Resource Group Name', + pipeline_name: 'Pipeline Name', + factory_tips: 'Please select factory', + resource_group_tips: 'Please select resource group', + pipeline_tips: 'Please select pipeline' }, menu: { fav: 'Favorites', @@ -808,6 +815,6 @@ export default { di: 'Data Integration', dq: 'Data Quality', ml: 'Machine Learning', - other: 'Other', + other: 'Other' } } diff --git a/dolphinscheduler-ui/src/locales/zh_CN/project.ts b/dolphinscheduler-ui/src/locales/zh_CN/project.ts index 54c77d4633..1d5224022b 100644 --- a/dolphinscheduler-ui/src/locales/zh_CN/project.ts +++ b/dolphinscheduler-ui/src/locales/zh_CN/project.ts @@ -777,7 +777,13 @@ export default { pytorch_python_env_tool: 'python环境管理工具', pytorch_requirements: '依赖文件', pytorch_conda_python_version: 'python版本', - pytorch_conda_python_version_tips: '请输入版本号,如 3.6, 3.7, 3.x等' + pytorch_conda_python_version_tips: '请输入版本号,如 3.6, 3.7, 3.x等', + factory_name: '工厂名称', + resource_group_name: '资源组名称', + pipeline_name: 'pipeline名称', + factory_tips: '请选择工厂', + resource_group_tips: '请选择资源组', + pipeline_tips: '请选择pipeline' }, menu: { fav: '收藏组件', diff --git a/dolphinscheduler-ui/src/service/modules/azure/index.ts b/dolphinscheduler-ui/src/service/modules/azure/index.ts new file mode 100644 index 0000000000..28f83db45c --- /dev/null +++ b/dolphinscheduler-ui/src/service/modules/azure/index.ts @@ -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. + */ + +import { axios } from '@/service/service' +import { DataFactoryReq } from './types' + +export function queryDataFactoryFactories(): any { + return axios({ + url: '/cloud/azure/datafactory/factories', + method: 'get' + }) +} + +export function queryDataFactoryResourceGroups(): any { + return axios({ + url: '/cloud/azure/datafactory/resourceGroups', + method: 'get' + }) +} + +export function queryDataFactoryPipelines(params: DataFactoryReq): any { + return axios({ + url: '/cloud/azure/datafactory/pipelines', + method: 'get', + params + }) +} diff --git a/dolphinscheduler-ui/src/service/modules/azure/types.ts b/dolphinscheduler-ui/src/service/modules/azure/types.ts new file mode 100644 index 0000000000..5f59d70bde --- /dev/null +++ b/dolphinscheduler-ui/src/service/modules/azure/types.ts @@ -0,0 +1,23 @@ +/* + * 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. + */ + +interface DataFactoryReq { + factoryName: string + resourceGroupName: string +} + +export { DataFactoryReq } diff --git a/dolphinscheduler-ui/src/store/project/task-type.ts b/dolphinscheduler-ui/src/store/project/task-type.ts index b1f426bef8..24bc05614d 100644 --- a/dolphinscheduler-ui/src/store/project/task-type.ts +++ b/dolphinscheduler-ui/src/store/project/task-type.ts @@ -149,6 +149,10 @@ export const TASK_TYPES_MAP = { LINKIS: { alias: 'LINKIS', helperLinkDisable: true + }, + DATA_FACTORY: { + alias: 'DATA_FACTORY', + helperLinkDisable: true } } as { [key in TaskType]: { diff --git a/dolphinscheduler-ui/src/store/project/types.ts b/dolphinscheduler-ui/src/store/project/types.ts index e801f4a1eb..0df130e77b 100644 --- a/dolphinscheduler-ui/src/store/project/types.ts +++ b/dolphinscheduler-ui/src/store/project/types.ts @@ -56,6 +56,7 @@ type TaskType = | 'DATASYNC' | 'KUBEFLOW' | 'LINKIS' + | 'DATA_FACTORY' type ProgramType = 'JAVA' | 'SCALA' | 'PYTHON' diff --git a/dolphinscheduler-ui/src/views/projects/task/components/node/fields/index.ts b/dolphinscheduler-ui/src/views/projects/task/components/node/fields/index.ts index e7b4ab06f8..4510f47183 100644 --- a/dolphinscheduler-ui/src/views/projects/task/components/node/fields/index.ts +++ b/dolphinscheduler-ui/src/views/projects/task/components/node/fields/index.ts @@ -85,3 +85,4 @@ export { useDms } from './use-dms' export { useDatasync } from './use-datasync' export { useKubeflow } from './use-kubeflow' export { useLinkis } from './use-linkis' +export { useDataFactory } from './use-data-factory' diff --git a/dolphinscheduler-ui/src/views/projects/task/components/node/fields/use-data-factory.ts b/dolphinscheduler-ui/src/views/projects/task/components/node/fields/use-data-factory.ts new file mode 100644 index 0000000000..8dc6f5213c --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/task/components/node/fields/use-data-factory.ts @@ -0,0 +1,152 @@ +/* + * 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. + */ +import { + queryDataFactoryFactories, + queryDataFactoryPipelines, + queryDataFactoryResourceGroups +} from '@/service/modules/azure' +import { onMounted, ref, watch } from 'vue' +import { useI18n } from 'vue-i18n' +import { useCustomParams } from '.' +import type { IJsonItem } from '../types' + +export function useDataFactory(model: { [field: string]: any }): IJsonItem[] { + const { t } = useI18n() + + const factoryLoading = ref(false) + const resourceGroupLoading = ref(false) + const pipelineLoading = ref(false) + + const factoryOptions = ref([] as { label: string; value: number }[]) + const resourceGroupOptions = ref([] as { label: string; value: number }[]) + const pipelineOptions = ref([] as { label: string; value: number }[]) + + const getFactoryOptions = async () => { + if (factoryLoading.value) return + factoryLoading.value = true + const factories = await queryDataFactoryFactories() + factoryOptions.value = factories.map((factory: string) => ({ + label: factory, + value: factory + })) + factoryLoading.value = false + } + + const getResourceGroupName = async () => { + if (resourceGroupLoading.value) return + resourceGroupLoading.value = true + const groupNames = await queryDataFactoryResourceGroups() + resourceGroupOptions.value = groupNames.map((groupName: string) => ({ + label: groupName, + value: groupName + })) + resourceGroupLoading.value = false + } + + const getPipelineName = async ( + factoryName: string, + resourceGroupName: string + ) => { + if (pipelineLoading.value) return + pipelineLoading.value = true + const pipelineNames = await queryDataFactoryPipelines({ + factoryName, + resourceGroupName + }) + pipelineOptions.value = pipelineNames.map((pipelineName: string) => ({ + label: pipelineName, + value: pipelineName + })) + pipelineLoading.value = false + } + + const onChange = () => { + model['pipelineName'] = '' + if (model['factoryName'] && model['resourceGroupName']) { + getPipelineName(model['factoryName'], model['resourceGroupName']) + } + } + + watch( + () => model['pipelineName'], + () => { + if (model['pipelineName'] && pipelineOptions.value.length === 0) { + getPipelineName(model['factoryName'], model['resourceGroupName']) + } + } + ) + + onMounted(() => { + getFactoryOptions() + getResourceGroupName() + }) + + return [ + { + type: 'select', + field: 'factoryName', + span: 24, + name: t('project.node.factory_name'), + options: factoryOptions, + props: { + 'on-update:value': onChange, + loading: factoryLoading + }, + validate: { + trigger: ['input', 'trigger'], + required: true, + message: t('project.node.factory_tips') + } + }, + { + type: 'select', + field: 'resourceGroupName', + span: 24, + name: t('project.node.resource_group_name'), + options: resourceGroupOptions, + props: { + 'on-update:value': onChange, + loading: resourceGroupLoading + }, + validate: { + trigger: ['input', 'trigger'], + required: true, + message: t('project.node.resource_group_tips') + } + }, + { + type: 'select', + field: 'pipelineName', + span: 24, + name: t('project.node.pipeline_name'), + options: pipelineOptions, + props: { + loading: pipelineLoading + }, + validate: { + trigger: ['input', 'trigger'], + required: true, + message: t('project.node.pipeline_tips') + } + }, + ...useCustomParams({ + model, + field: 'localParams', + isSimple: true + }) + ] +} 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 ea804dc1d7..7d227db0e7 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 @@ -449,13 +449,19 @@ export function formatParams(data: INodeData): { taskParams.yamlContent = data.yamlContent taskParams.namespace = data.namespace } - + if (data.taskType === 'LINKIS') { taskParams.useCustom = data.useCustom taskParams.paramScript = data.paramScript taskParams.rawScript = data.rawScript } + if (data.taskType === 'DATA_FACTORY') { + taskParams.factoryName = data.factoryName + taskParams.resourceGroupName = data.resourceGroupName + taskParams.pipelineName = data.pipelineName + } + let timeoutNotifyStrategy = '' if (data.timeoutNotifyStrategy) { if (data.timeoutNotifyStrategy.length === 1) { diff --git a/dolphinscheduler-ui/src/views/projects/task/components/node/tasks/index.ts b/dolphinscheduler-ui/src/views/projects/task/components/node/tasks/index.ts index 1b6f998b4e..04a3518242 100644 --- a/dolphinscheduler-ui/src/views/projects/task/components/node/tasks/index.ts +++ b/dolphinscheduler-ui/src/views/projects/task/components/node/tasks/index.ts @@ -50,6 +50,7 @@ import { useDms } from './use-dms' import { useDatasync } from './use-datasync' import { useKubeflow } from './use-kubeflow' import { useLinkis } from './use-linkis' +import { useDataFactory } from './use-data-factory' export default { SHELL: useShell, @@ -86,5 +87,6 @@ export default { DMS: useDms, DATASYNC: useDatasync, KUBEFLOW: useKubeflow, - LINKIS: useLinkis + LINKIS: useLinkis, + DATA_FACTORY: useDataFactory } diff --git a/dolphinscheduler-ui/src/views/projects/task/components/node/tasks/use-data-factory.ts b/dolphinscheduler-ui/src/views/projects/task/components/node/tasks/use-data-factory.ts new file mode 100644 index 0000000000..c845fd0246 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/task/components/node/tasks/use-data-factory.ts @@ -0,0 +1,72 @@ +/* + * 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. + */ + +import { reactive } from 'vue' +import * as Fields from '../fields/index' +import type { IJsonItem, INodeData } from '../types' +import { ITaskData } from '../types' + +export function useDataFactory({ + projectCode, + from = 0, + readonly, + data +}: { + projectCode: number + from?: number + readonly?: boolean + data?: ITaskData +}) { + const model = reactive({ + name: '', + taskType: 'DATA_FACTORY', + flag: 'YES', + description: '', + timeoutFlag: false, + localParams: [], + environmentCode: null, + failRetryInterval: 1, + failRetryTimes: 0, + workerGroup: 'default', + delayTime: 0, + timeout: 30, + timeoutNotifyStrategy: ['WARN'], + factoryName: '', + resourceGroupName: '', + pipelineName: '' + } as INodeData) + + return { + json: [ + Fields.useName(from), + ...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }), + Fields.useRunFlag(), + Fields.useCache(), + Fields.useDescription(), + Fields.useTaskPriority(), + Fields.useWorkerGroup(), + Fields.useEnvironmentName(model, !data?.id), + ...Fields.useTaskGroup(model, projectCode), + ...Fields.useFailed(), + Fields.useDelayTime(model), + ...Fields.useTimeoutAlarm(model), + ...Fields.useDataFactory(model), + Fields.usePreTasks() + ] as IJsonItem[], + model + } +} diff --git a/dolphinscheduler-ui/src/views/projects/task/components/node/types.ts b/dolphinscheduler-ui/src/views/projects/task/components/node/types.ts index 282948345b..490503aafd 100644 --- a/dolphinscheduler-ui/src/views/projects/task/components/node/types.ts +++ b/dolphinscheduler-ui/src/views/projects/task/components/node/types.ts @@ -405,6 +405,9 @@ interface ITaskParams { cloudWatchLogGroupArn?: string yamlContent?: string paramScript?: ILocalParam[] + factoryName?: string + resourceGroupName?: string + pipelineName?: string } interface INodeData diff --git a/dolphinscheduler-ui/src/views/projects/task/constants/task-type.ts b/dolphinscheduler-ui/src/views/projects/task/constants/task-type.ts index 2606bea240..738892f68b 100644 --- a/dolphinscheduler-ui/src/views/projects/task/constants/task-type.ts +++ b/dolphinscheduler-ui/src/views/projects/task/constants/task-type.ts @@ -50,6 +50,7 @@ export type TaskType = | 'DATASYNC' | 'KUBEFLOW' | 'LINKIS' + | 'DATA_FACTORY' export type TaskExecuteType = 'STREAM' | 'BATCH' @@ -180,6 +181,10 @@ export const TASK_TYPES_MAP = { LINKIS: { alias: 'LINKIS', helperLinkDisable: true + }, + DATA_FACTORY: { + alias: 'DATA_FACTORY', + helperLinkDisable: true } } as { [key in TaskType]: { diff --git a/dolphinscheduler-ui/src/views/projects/workflow/components/dag/dag.module.scss b/dolphinscheduler-ui/src/views/projects/workflow/components/dag/dag.module.scss index 7aa0c9c709..65b7aa0067 100644 --- a/dolphinscheduler-ui/src/views/projects/workflow/components/dag/dag.module.scss +++ b/dolphinscheduler-ui/src/views/projects/workflow/components/dag/dag.module.scss @@ -204,6 +204,9 @@ $bgLight: #ffffff; &.icon-kubeflow { background-image: url('/images/task-icons/kubeflow.png'); } + &.icon-data_factory { + background-image: url('/images/task-icons/data_factory.png'); + } } &:hover { @@ -311,6 +314,9 @@ $bgLight: #ffffff; &.icon-kubeflow { background-image: url('/images/task-icons/kubeflow_hover.png'); } + &.icon-data_factory { + background-image: url('/images/task-icons/data_factory_hover.png'); + } } } diff --git a/tools/dependencies/known-dependencies.txt b/tools/dependencies/known-dependencies.txt index 5e7b64c525..eeb308e7bf 100644 --- a/tools/dependencies/known-dependencies.txt +++ b/tools/dependencies/known-dependencies.txt @@ -399,3 +399,35 @@ reactor-core-3.4.22.jar reactor-netty-core-1.0.22.jar reactor-netty-http-1.0.22.jar DmJdbcDriver18-8.1.2.79.jar +azure-resourcemanager-2.21.0.jar +azure-resourcemanager-appplatform-2.21.0.jar +azure-resourcemanager-appservice-2.21.0.jar +azure-resourcemanager-authorization-2.21.0.jar +azure-resourcemanager-cdn-2.21.0.jar +azure-resourcemanager-compute-2.21.0.jar +azure-resourcemanager-containerinstance-2.21.0.jar +azure-resourcemanager-containerregistry-2.21.0.jar +azure-resourcemanager-containerservice-2.21.0.jar +azure-resourcemanager-cosmos-2.21.0.jar +azure-resourcemanager-datafactory-1.0.0-beta.19.jar +azure-resourcemanager-dns-2.21.0.jar +azure-resourcemanager-eventhubs-2.21.0.jar +azure-resourcemanager-keyvault-2.21.0.jar +azure-resourcemanager-monitor-2.21.0.jar +azure-resourcemanager-msi-2.21.0.jar +azure-resourcemanager-network-2.21.0.jar +azure-resourcemanager-privatedns-2.21.0.jar +azure-resourcemanager-redis-2.21.0.jar +azure-resourcemanager-resources-2.21.0.jar +azure-resourcemanager-search-2.21.0.jar +azure-resourcemanager-servicebus-2.21.0.jar +azure-resourcemanager-sql-2.21.0.jar +azure-resourcemanager-storage-2.21.0.jar +azure-resourcemanager-trafficmanager-2.21.0.jar +azure-security-keyvault-keys-4.5.2.jar +azure-security-keyvault-secrets-4.5.2.jar +azure-storage-common-12.19.1.jar +azure-storage-file-share-12.16.1.jar +nimbus-jose-jwt-9.22.jar +woodstox-core-6.4.0.jar +azure-core-management-1.9.0.jar \ No newline at end of file