You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dolphinscheduler.apache.org by zi...@apache.org on 2023/07/26 03:53:03 UTC

[dolphinscheduler] branch dev updated: [Improvement-4375][api] cannot delete yarn queue (#13046)

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

zihaoxiang pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/dolphinscheduler.git


The following commit(s) were added to refs/heads/dev by this push:
     new 5ccc4cc889 [Improvement-4375][api] cannot delete yarn queue (#13046)
5ccc4cc889 is described below

commit 5ccc4cc889309ea2ae949b09cc7ecbb1d941ec67
Author: amao <56...@users.noreply.github.com>
AuthorDate: Wed Jul 26 11:52:57 2023 +0800

    [Improvement-4375][api] cannot delete yarn queue (#13046)
    
    * [Bug-12833][api]
    delete api
    
    * [Bug-12833][api]
    delete yarn queue
    
    * [Bug-12833][api]
    add Unit Test
    
    * Repair the failed CI
    
    * Repair the failed UT
    
    * Repair the failed Docs
    
    * Repair the failed Doc
    
    ---------
    
    Co-authored-by: amao <Gu...@Yumchina.com>
    Co-authored-by: xiangzihao <46...@qq.com>
---
 .../api/controller/QueueController.java            |  25 +++++
 .../apache/dolphinscheduler/api/enums/Status.java  |   7 +-
 .../dolphinscheduler/api/service/QueueService.java |  12 +++
 .../api/service/impl/QueueServiceImpl.java         |  56 +++++++++++
 .../api/controller/QueueControllerTest.java        |  18 ++++
 .../dolphinscheduler/dao/mapper/TenantMapper.java  |   7 ++
 .../dolphinscheduler/dao/mapper/TenantMapper.xml   |   7 ++
 dolphinscheduler-ui/src/locales/en_US/security.ts  |   2 +
 dolphinscheduler-ui/src/locales/zh_CN/security.ts  |   2 +
 .../src/service/modules/queues/index.ts            |   7 ++
 .../views/security/yarn-queue-manage/use-table.ts  | 102 ++++++++++++++++-----
 11 files changed, 220 insertions(+), 25 deletions(-)

diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/QueueController.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/QueueController.java
index e13e23a1df..0527ce77ae 100644
--- a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/QueueController.java
+++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/QueueController.java
@@ -18,6 +18,7 @@
 package org.apache.dolphinscheduler.api.controller;
 
 import static org.apache.dolphinscheduler.api.enums.Status.CREATE_QUEUE_ERROR;
+import static org.apache.dolphinscheduler.api.enums.Status.DELETE_QUEUE_BY_ID_ERROR;
 import static org.apache.dolphinscheduler.api.enums.Status.QUERY_QUEUE_LIST_ERROR;
 import static org.apache.dolphinscheduler.api.enums.Status.UPDATE_QUEUE_ERROR;
 import static org.apache.dolphinscheduler.api.enums.Status.VERIFY_QUEUE_ERROR;
@@ -30,8 +31,11 @@ import org.apache.dolphinscheduler.common.constants.Constants;
 import org.apache.dolphinscheduler.dao.entity.User;
 import org.apache.dolphinscheduler.plugin.task.api.utils.ParameterUtils;
 
+import java.util.Map;
+
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.DeleteMapping;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.PostMapping;
@@ -156,6 +160,27 @@ public class QueueController extends BaseController {
         return queueService.updateQueue(loginUser, id, queue, queueName);
     }
 
+    /**
+     *  delete queue by id
+     *
+     * @param loginUser login user
+     * @param id        queue id
+     * @return update result code
+     */
+    @Operation(summary = "deleteQueueById", description = "DELETE_QUEUE_NOTES")
+    @Parameters({
+            @Parameter(name = "id", description = "QUEUE_ID", required = true, schema = @Schema(implementation = int.class, example = "100"))
+    })
+    @DeleteMapping(value = "/{id}")
+    @ResponseStatus(HttpStatus.OK)
+    @ApiException(DELETE_QUEUE_BY_ID_ERROR)
+    @AccessLogAnnotation(ignoreRequestArgs = "loginUser")
+    public Result deleteQueueById(@Parameter(hidden = true) @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
+                                  @PathVariable(value = "id") int id) throws Exception {
+        Map<String, Object> result = queueService.deleteQueueById(loginUser, id);
+        return returnDataList(result);
+    }
+
     /**
      * verify queue and queue name
      *
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 8176a2ff89..f4622b5c9f 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
@@ -263,6 +263,12 @@ public enum Status {
     QUERY_TASK_INSTANCE_ERROR(10205, "query task instance error", "查询任务实例错误"),
     EXECUTE_NOT_DEFINE_TASK(10206, "please save and try again",
             "请先保存后再执行"),
+
+    DELETE_QUEUE_BY_ID_ERROR(10307, "delete queue by id error", "删除队列错误"),
+    DELETE_QUEUE_BY_ID_FAIL_USERS(10308, "delete queue by id fail, for there are {0} users using it",
+            "删除队列失败,有[{0}]个用户正在使用"),
+    DELETE_TENANT_BY_ID_FAIL_TENANTS(10309, "delete queue by id fail, for there are {0} tenants using it",
+            "删除队列失败,有[{0}]个租户正在使用"),
     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数据工厂列表错误"),
@@ -286,7 +292,6 @@ public enum Status {
     PROJECT_PARAMETER_NOT_EXISTS(10219, "project parameter {0} not exists", "项目参数[{0}]不存在"),
 
     PROJECT_PARAMETER_CODE_EMPTY(10220, "project parameter code empty", "项目参数code为空"),
-
     CREATE_PROJECT_PREFERENCE_ERROR(10300, "create project preference error", "创建项目偏好设置错误"),
 
     UPDATE_PROJECT_PREFERENCE_ERROR(10301, "update project preference error", "更新项目偏好设置错误"),
diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/QueueService.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/QueueService.java
index 0f62ea9028..69ed518445 100644
--- a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/QueueService.java
+++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/QueueService.java
@@ -21,6 +21,8 @@ import org.apache.dolphinscheduler.api.utils.Result;
 import org.apache.dolphinscheduler.dao.entity.Queue;
 import org.apache.dolphinscheduler.dao.entity.User;
 
+import java.util.Map;
+
 /**
  * queue service
  */
@@ -66,6 +68,16 @@ public interface QueueService {
      */
     Result updateQueue(User loginUser, int id, String queue, String queueName);
 
+    /**
+     * delete queue
+     *
+     * @param loginUser login user
+     * @param id queue id
+     * @return delete result code
+     * @throws Exception exception
+     */
+    Map<String, Object> deleteQueueById(User loginUser, int id) throws Exception;
+
     /**
      * verify queue and queueName
      *
diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/QueueServiceImpl.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/QueueServiceImpl.java
index ecdb3773ed..723c3010c5 100644
--- a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/QueueServiceImpl.java
+++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/QueueServiceImpl.java
@@ -17,6 +17,7 @@
 
 package org.apache.dolphinscheduler.api.service.impl;
 
+import static org.apache.dolphinscheduler.api.constants.ApiFuncIdentificationConstant.TENANT_DELETE;
 import static org.apache.dolphinscheduler.api.constants.ApiFuncIdentificationConstant.YARN_QUEUE_CREATE;
 import static org.apache.dolphinscheduler.api.constants.ApiFuncIdentificationConstant.YARN_QUEUE_UPDATE;
 
@@ -29,16 +30,21 @@ import org.apache.dolphinscheduler.common.constants.Constants;
 import org.apache.dolphinscheduler.common.enums.AuthorizationType;
 import org.apache.dolphinscheduler.common.enums.UserType;
 import org.apache.dolphinscheduler.dao.entity.Queue;
+import org.apache.dolphinscheduler.dao.entity.Tenant;
 import org.apache.dolphinscheduler.dao.entity.User;
 import org.apache.dolphinscheduler.dao.mapper.QueueMapper;
+import org.apache.dolphinscheduler.dao.mapper.TenantMapper;
 import org.apache.dolphinscheduler.dao.mapper.UserMapper;
 
+import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
 
@@ -64,6 +70,9 @@ public class QueueServiceImpl extends BaseServiceImpl implements QueueService {
     @Autowired
     private UserMapper userMapper;
 
+    @Autowired
+    private TenantMapper tenantMapper;
+
     /**
      * Check the queue new object valid or not
      *
@@ -223,6 +232,53 @@ public class QueueServiceImpl extends BaseServiceImpl implements QueueService {
         return result;
     }
 
+    /**
+     * delete queue
+     *
+     * @param loginUser login user
+     * @param id queue id
+     * @return delete result code
+     * @throws Exception exception
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Map<String, Object> deleteQueueById(User loginUser, int id) throws Exception {
+        Map<String, Object> result = new HashMap<>();
+
+        if (!canOperatorPermissions(loginUser, null, AuthorizationType.TENANT, TENANT_DELETE)) {
+            throw new ServiceException(Status.USER_NO_OPERATION_PERM);
+        }
+
+        Queue queue = queueMapper.selectById(id);
+        if (Objects.isNull(queue)) {
+            log.error("Queue does not exist");
+            throw new ServiceException(Status.QUEUE_NOT_EXIST);
+        }
+
+        List<Tenant> tenantList = tenantMapper.queryTenantListByQueueId(queue.getId());
+        if (CollectionUtils.isNotEmpty(tenantList)) {
+            log.warn("Delete queue failed, because there are {} tenants using it.", tenantList.size());
+            throw new ServiceException(Status.DELETE_TENANT_BY_ID_FAIL_TENANTS, tenantList.size());
+        }
+
+        List<User> userList = userMapper.queryUserListByQueue(queue.getQueueName());
+        if (CollectionUtils.isNotEmpty(userList)) {
+            log.warn("Delete queue failed, because there are {} users using it.", userList.size());
+            throw new ServiceException(Status.DELETE_QUEUE_BY_ID_FAIL_USERS, userList.size());
+        }
+
+        int delete = queueMapper.deleteById(id);
+        if (delete > 0) {
+            log.info("Queue is deleted and id is {}.", id);
+            putMsg(result, Status.SUCCESS);
+        } else {
+            log.error("Queue delete failed, queueId:{}.", id);
+            putMsg(result, Status.DELETE_QUEUE_BY_ID_ERROR);
+        }
+
+        return result;
+    }
+
     /**
      * verify queue and queueName
      *
diff --git a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/QueueControllerTest.java b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/QueueControllerTest.java
index e2311a25ae..0ddd7ad84b 100644
--- a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/QueueControllerTest.java
+++ b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/QueueControllerTest.java
@@ -17,6 +17,7 @@
 
 package org.apache.dolphinscheduler.api.controller;
 
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
@@ -177,4 +178,21 @@ public class QueueControllerTest extends AbstractControllerTest {
         logger.info(mvcResult.getResponse().getContentAsString());
         logger.info("verify queue return result:{}", mvcResult.getResponse().getContentAsString());
     }
+    @Test
+    public void testDeleteQueueById() throws Exception {
+        MultiValueMap<String, String> paramsMap = new LinkedMultiValueMap<>();
+        paramsMap.add("id", "64");
+
+        MvcResult mvcResult = mockMvc.perform(delete("/queues/{id}", 64)
+                .header(SESSION_ID, sessionId)
+                .params(paramsMap))
+                .andExpect(status().isOk())
+                .andExpect(content().contentType(MediaType.APPLICATION_JSON))
+                .andReturn();
+        Result result = JSONUtils.parseObject(mvcResult.getResponse().getContentAsString(), Result.class);
+
+        Assertions.assertNotNull(result);
+        Assertions.assertEquals(Status.QUEUE_NOT_EXIST.getCode(), result.getCode().intValue());
+        logger.info("delete queue return result:{}", mvcResult.getResponse().getContentAsString());
+    }
 }
diff --git a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/TenantMapper.java b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/TenantMapper.java
index 623c1f8a8d..90fee2ef5a 100644
--- a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/TenantMapper.java
+++ b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/TenantMapper.java
@@ -66,6 +66,13 @@ public interface TenantMapper extends BaseMapper<Tenant> {
      */
     Tenant queryByTenantCode(@Param("tenantCode") String tenantCode);
 
+    /**
+     * query tenants by queue id
+     *
+     * @param queueId queue id
+     * @return tenant list
+     */
+    List<Tenant> queryTenantListByQueueId(@Param("queueId") Integer queueId);
     /**
      * tenant page
      *
diff --git a/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/TenantMapper.xml b/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/TenantMapper.xml
index 60fe3a45ef..a941db420b 100644
--- a/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/TenantMapper.xml
+++ b/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/TenantMapper.xml
@@ -42,6 +42,13 @@
         where tenant_code = #{tenantCode}
     </select>
 
+    <select id="queryTenantListByQueueId" resultType="org.apache.dolphinscheduler.dao.entity.Tenant">
+        select
+        <include refid="baseSql"/>
+        from t_ds_tenant
+        where queue_id = #{queueId}
+    </select>
+
     <select id="queryAll" resultType="org.apache.dolphinscheduler.dao.entity.Tenant">
         select
         <include refid="baseSql"/>
diff --git a/dolphinscheduler-ui/src/locales/en_US/security.ts b/dolphinscheduler-ui/src/locales/en_US/security.ts
index 44536982b2..3b8e47586d 100644
--- a/dolphinscheduler-ui/src/locales/en_US/security.ts
+++ b/dolphinscheduler-ui/src/locales/en_US/security.ts
@@ -77,6 +77,8 @@ export default {
     update_time: 'Update Time',
     operation: 'Operation',
     edit: 'Edit',
+    delete: 'Delete',
+    delete_confirm: 'Delete?',
     queue_name_tips: 'Please enter your queue name',
     queue_value_tips: 'Please enter your queue value'
   },
diff --git a/dolphinscheduler-ui/src/locales/zh_CN/security.ts b/dolphinscheduler-ui/src/locales/zh_CN/security.ts
index ffe4f7dff8..d015730d8c 100644
--- a/dolphinscheduler-ui/src/locales/zh_CN/security.ts
+++ b/dolphinscheduler-ui/src/locales/zh_CN/security.ts
@@ -77,6 +77,8 @@ export default {
     update_time: '更新时间',
     operation: '操作',
     edit: '编辑',
+    delete: '删除',
+    delete_confirm: '确定删除吗?',
     queue_name_tips: '请输入队列名',
     queue_value_tips: '请输入队列值'
   },
diff --git a/dolphinscheduler-ui/src/service/modules/queues/index.ts b/dolphinscheduler-ui/src/service/modules/queues/index.ts
index ef93de6151..be7a8a8a8c 100644
--- a/dolphinscheduler-ui/src/service/modules/queues/index.ts
+++ b/dolphinscheduler-ui/src/service/modules/queues/index.ts
@@ -56,3 +56,10 @@ export function updateQueue(data: QueueReq, idReq: IdReq): any {
     data
   })
 }
+
+export function deleteQueueById(id: number): any {
+  return axios({
+    url: `/queues/${id}`,
+    method: 'delete'
+  })
+}
diff --git a/dolphinscheduler-ui/src/views/security/yarn-queue-manage/use-table.ts b/dolphinscheduler-ui/src/views/security/yarn-queue-manage/use-table.ts
index be5400020d..7008b8979d 100644
--- a/dolphinscheduler-ui/src/views/security/yarn-queue-manage/use-table.ts
+++ b/dolphinscheduler-ui/src/views/security/yarn-queue-manage/use-table.ts
@@ -17,10 +17,12 @@
 
 import { useAsyncState } from '@vueuse/core'
 import { reactive, h, ref } from 'vue'
-import { NButton, NIcon, NTooltip } from 'naive-ui'
+import {NButton, NIcon, NPopconfirm, NSpace, NTooltip} from 'naive-ui'
 import { useI18n } from 'vue-i18n'
-import { queryQueueListPaging } from '@/service/modules/queues'
-import { EditOutlined } from '@vicons/antd'
+import { queryQueueListPaging,
+  deleteQueueById
+} from '@/service/modules/queues'
+import {DeleteOutlined, EditOutlined} from '@vicons/antd'
 import type { QueueRes } from '@/service/modules/queues/types'
 
 export function useTable() {
@@ -32,6 +34,19 @@ export function useTable() {
     variables.row = row
   }
 
+  const handleDelete = (row: any) => {
+    deleteQueueById(row.id).then(() => {
+      getTableData({
+        pageSize: variables.pageSize,
+        pageNo:
+            variables.tableData.length === 1 && variables.page > 1
+                ? variables.page - 1
+                : variables.page,
+        searchVal: variables.searchVal
+      })
+    })
+  }
+
   const createColumns = (variables: any) => {
     variables.columns = [
       {
@@ -60,30 +75,69 @@ export function useTable() {
         title: t('security.yarn_queue.operation'),
         key: 'operation',
         render(row: any) {
-          return h(
-            NTooltip,
-            {},
-            {
-              trigger: () =>
+            return h(NSpace, null, {
+              default: () => [
                 h(
-                  NButton,
-                  {
-                    circle: true,
-                    type: 'info',
-                    size: 'small',
-                    class: 'edit',
-                    onClick: () => {
-                      handleEdit(row)
+                    NTooltip,
+                    {},
+                    {
+                      trigger: () =>
+                          h(
+                              NButton,
+                              {
+                                circle: true,
+                                type: 'info',
+                                size: 'small',
+                                class: 'edit',
+                                onClick: () => {
+                                  handleEdit(row)
+                                }
+                              },
+                              {
+                                icon: () =>
+                                    h(NIcon, null, { default: () => h(EditOutlined) })
+                              }
+                          ),
+                      default: () => t('security.yarn_queue.edit')
                     }
-                  },
-                  {
-                    icon: () =>
-                      h(NIcon, null, { default: () => h(EditOutlined) })
-                  }
                 ),
-              default: () => t('security.yarn_queue.edit')
-            }
-          )
+                h(
+                    NPopconfirm,
+                    {
+                      onPositiveClick: () => {
+                        handleDelete(row)
+                      }
+                    },
+                    {
+                      trigger: () =>
+                          h(
+                              NTooltip,
+                              {},
+                              {
+                                trigger: () =>
+                                    h(
+                                        NButton,
+                                        {
+                                          circle: true,
+                                          type: 'error',
+                                          size: 'small',
+                                          class: 'delete'
+                                        },
+                                        {
+                                          icon: () =>
+                                              h(NIcon, null, {
+                                                default: () => h(DeleteOutlined)
+                                              })
+                                        }
+                                    ),
+                                default: () => t('security.yarn_queue.delete')
+                              }
+                          ),
+                      default: () => t('security.yarn_queue.delete_confirm')
+                    }
+                )
+              ]
+            })
         }
       }
     ]