Browse Source

[Feature][Task] K8s namespace auth manager (#9303)

* k8s auth

* remove log

* fix test

* use constants

* use constants K8S_LOCAL_TEST_CLUSTER

* simple auth get

* change test

* add namespace authorize in user page

* prettier code

* change test data

Co-authored-by: qianl4 <qianl4@cicso.com>
Co-authored-by: William Tong <weitong@cisco.com>
3.0.0/version-upgrade
qianli2022 2 years ago committed by GitHub
parent
commit
165d7aa51f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 91
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/K8sNamespaceController.java
  2. 26
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/UsersController.java
  3. 6
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/enums/Status.java
  4. 39
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/K8sNamespaceService.java
  5. 11
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/UsersService.java
  6. 155
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/K8SNamespaceServiceImpl.java
  7. 53
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/UsersServiceImpl.java
  8. 45
      dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/K8sNamespaceControllerTest.java
  9. 80
      dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/K8SNamespaceServiceTest.java
  10. 21
      dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/UsersServiceTest.java
  11. 1
      dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/Constants.java
  12. 92
      dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/K8sNamespace.java
  13. 164
      dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/K8sNamespaceUser.java
  14. 26
      dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/K8sNamespaceMapper.java
  15. 50
      dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/K8sNamespaceUserMapper.java
  16. 33
      dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/K8sNamespaceMapper.xml
  17. 40
      dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/K8sNamespaceUserMapper.xml
  18. 31
      dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_h2.sql
  19. 17
      dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_mysql.sql
  20. 19
      dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_postgresql.sql
  21. 19
      dolphinscheduler-dao/src/main/resources/sql/upgrade/2.1.0_schema/mysql/dolphinscheduler_ddl.sql
  22. 16
      dolphinscheduler-dao/src/main/resources/sql/upgrade/2.1.0_schema/postgresql/dolphinscheduler_ddl.sql
  23. 2
      dolphinscheduler-ui-next/src/locales/modules/en_US.ts
  24. 2
      dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts
  25. 17
      dolphinscheduler-ui-next/src/service/modules/k8s-namespace/index.ts
  26. 9
      dolphinscheduler-ui-next/src/service/modules/users/index.ts
  27. 5
      dolphinscheduler-ui-next/src/service/modules/users/types.ts
  28. 9
      dolphinscheduler-ui-next/src/views/security/user-manage/components/authorize-modal.tsx
  29. 37
      dolphinscheduler-ui-next/src/views/security/user-manage/components/use-authorize.ts
  30. 1
      dolphinscheduler-ui-next/src/views/security/user-manage/types.ts
  31. 6
      dolphinscheduler-ui-next/src/views/security/user-manage/use-columns.ts
  32. 23
      dolphinscheduler-ui/src/js/conf/home/pages/security/pages/namespace/_source/createNamespace.vue
  33. 2
      dolphinscheduler-ui/src/js/conf/home/pages/security/pages/namespace/_source/list.vue
  34. 52
      dolphinscheduler-ui/src/js/conf/home/pages/security/pages/users/_source/list.vue
  35. 2
      dolphinscheduler-ui/src/js/module/components/transfer/transfer.vue
  36. 7
      dolphinscheduler-ui/src/js/module/i18n/locale/en_US.js
  37. 3
      dolphinscheduler-ui/src/js/module/i18n/locale/zh_CN.js

91
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/K8sNamespaceController.java

@ -19,18 +19,23 @@ package org.apache.dolphinscheduler.api.controller;
import static org.apache.dolphinscheduler.api.enums.Status.CREATE_K8S_NAMESPACE_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.DELETE_K8S_NAMESPACE_BY_ID_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.QUERY_AUTHORIZED_NAMESPACE_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.QUERY_CAN_USE_K8S_CLUSTER_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.QUERY_K8S_NAMESPACE_LIST_PAGING_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.QUERY_UNAUTHORIZED_NAMESPACE_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.UPDATE_K8S_NAMESPACE_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.VERIFY_K8S_NAMESPACE_ERROR;
import org.apache.dolphinscheduler.api.aspect.AccessLogAnnotation;
import org.apache.dolphinscheduler.api.exceptions.ApiException;
import org.apache.dolphinscheduler.api.service.K8sNameSpaceService;
import org.apache.dolphinscheduler.api.service.K8sNamespaceService;
import org.apache.dolphinscheduler.api.utils.Result;
import org.apache.dolphinscheduler.common.Constants;
import org.apache.dolphinscheduler.common.utils.ParameterUtils;
import org.apache.dolphinscheduler.dao.entity.K8sNamespace;
import org.apache.dolphinscheduler.dao.entity.User;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
@ -60,7 +65,7 @@ import springfox.documentation.annotations.ApiIgnore;
public class K8sNamespaceController extends BaseController {
@Autowired
private K8sNameSpaceService k8sNameSpaceService;
private K8sNamespaceService k8sNamespaceService;
/**
* query namespace list paging
@ -92,7 +97,7 @@ public class K8sNamespaceController extends BaseController {
return result;
}
searchVal = ParameterUtils.handleEscapes(searchVal);
result = k8sNameSpaceService.queryListPaging(loginUser, searchVal, pageNo, pageSize);
result = k8sNamespaceService.queryListPaging(loginUser, searchVal, pageNo, pageSize);
return result;
}
@ -102,8 +107,6 @@ public class K8sNamespaceController extends BaseController {
*
* @param loginUser
* @param namespace k8s namespace
* @param owner owner
* @param tag Which type of job is available, can be empty, all available
* @param k8s k8s name
* @param limitsCpu max cpu
* @param limitsMemory max memory
@ -112,8 +115,6 @@ public class K8sNamespaceController extends BaseController {
@ApiOperation(value = "createK8sNamespace", notes = "CREATE_NAMESPACE_NOTES")
@ApiImplicitParams({
@ApiImplicitParam(name = "namespace", value = "NAMESPACE", required = true, dataType = "String"),
@ApiImplicitParam(name = "owner", value = "OWNER", required = false, dataType = "String"),
@ApiImplicitParam(name = "tag", value = "TAG", required = false, dataType = "String"),
@ApiImplicitParam(name = "k8s", value = "K8S", required = true, dataType = "String"),
@ApiImplicitParam(name = "limits_cpu", value = "LIMITS_CPU", required = false, dataType = "Double"),
@ApiImplicitParam(name = "limits_memory", value = "LIMITS_MEMORY", required = false, dataType = "Integer")
@ -125,12 +126,10 @@ public class K8sNamespaceController extends BaseController {
public Result createNamespace(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
@RequestParam(value = "namespace") String namespace,
@RequestParam(value = "k8s") String k8s,
@RequestParam(value = "owner", required = false) String owner,
@RequestParam(value = "tag", required = false) String tag,
@RequestParam(value = "limitsCpu", required = false) Double limitsCpu,
@RequestParam(value = "limitsMemory", required = false) Integer limitsMemory
) {
Map<String, Object> result = k8sNameSpaceService.createK8sNamespace(loginUser, namespace, k8s, owner, tag, limitsCpu, limitsMemory);
Map<String, Object> result = k8sNamespaceService.createK8sNamespace(loginUser, namespace, k8s, limitsCpu, limitsMemory);
return returnDataList(result);
}
@ -138,8 +137,7 @@ public class K8sNamespaceController extends BaseController {
* update namespace,namespace and k8s not allowed update, because may create on k8s,can delete and create new instead
*
* @param loginUser
* @param owner owner
* @param tag Which type of job is available,such as flink,means only flink job can use, can be empty, all available
* @param userName owner
* @param limitsCpu max cpu
* @param limitsMemory max memory
* @return
@ -147,8 +145,7 @@ public class K8sNamespaceController extends BaseController {
@ApiOperation(value = "updateK8sNamespace", notes = "UPDATE_NAMESPACE_NOTES")
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "K8S_NAMESPACE_ID", required = true, dataType = "Int", example = "100"),
@ApiImplicitParam(name = "owner", value = "OWNER", required = false, dataType = "String"),
@ApiImplicitParam(name = "tag", value = "TAG", required = false, dataType = "String"),
@ApiImplicitParam(name = "userName", value = "OWNER", required = false, dataType = "String"),
@ApiImplicitParam(name = "limitsCpu", value = "LIMITS_CPU", required = false, dataType = "Double"),
@ApiImplicitParam(name = "limitsMemory", value = "LIMITS_MEMORY", required = false, dataType = "Integer")})
@PutMapping(value = "/{id}")
@ -157,11 +154,11 @@ public class K8sNamespaceController extends BaseController {
@AccessLogAnnotation(ignoreRequestArgs = "loginUser")
public Result updateNamespace(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
@PathVariable(value = "id") int id,
@RequestParam(value = "owner", required = false) String owner,
@RequestParam(value = "userName", required = false) String userName,
@RequestParam(value = "tag", required = false) String tag,
@RequestParam(value = "limitsCpu", required = false) Double limitsCpu,
@RequestParam(value = "limitsMemory", required = false) Integer limitsMemory) {
Map<String, Object> result = k8sNameSpaceService.updateK8sNamespace(loginUser, id, owner, tag, limitsCpu, limitsMemory);
Map<String, Object> result = k8sNamespaceService.updateK8sNamespace(loginUser, id, userName, limitsCpu, limitsMemory);
return returnDataList(result);
}
@ -187,7 +184,7 @@ public class K8sNamespaceController extends BaseController {
@RequestParam(value = "k8s") String k8s
) {
return k8sNameSpaceService.verifyNamespaceK8s(namespace, k8s);
return k8sNamespaceService.verifyNamespaceK8s(namespace, k8s);
}
@ -208,7 +205,65 @@ public class K8sNamespaceController extends BaseController {
@AccessLogAnnotation
public Result delNamespaceById(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
@RequestParam(value = "id") int id) {
Map<String, Object> result = k8sNameSpaceService.deleteNamespaceById(loginUser, id);
Map<String, Object> result = k8sNamespaceService.deleteNamespaceById(loginUser, id);
return returnDataList(result);
}
/**
* query unauthorized namespace
*
* @param loginUser login user
* @param userId user id
* @return the namespaces which user have not permission to see
*/
@ApiOperation(value = "queryUnauthorizedNamespace", notes = "QUERY_UNAUTHORIZED_NAMESPACE_NOTES")
@ApiImplicitParams({
@ApiImplicitParam(name = "userId", value = "USER_ID", dataType = "Int", example = "100")
})
@GetMapping(value = "/unauth-namespace")
@ResponseStatus(HttpStatus.OK)
@ApiException(QUERY_UNAUTHORIZED_NAMESPACE_ERROR)
@AccessLogAnnotation(ignoreRequestArgs = "loginUser")
public Result queryUnauthorizedNamespace(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
@RequestParam("userId") Integer userId) {
Map<String, Object> result = k8sNamespaceService.queryUnauthorizedNamespace(loginUser, userId);
return returnDataList(result);
}
/**
* query unauthorized namespace
*
* @param loginUser login user
* @param userId user id
* @return namespaces which the user have permission to see
*/
@ApiOperation(value = "queryAuthorizedNamespace", notes = "QUERY_AUTHORIZED_NAMESPACE_NOTES")
@ApiImplicitParams({
@ApiImplicitParam(name = "userId", value = "USER_ID", dataType = "Int", example = "100")
})
@GetMapping(value = "/authed-namespace")
@ResponseStatus(HttpStatus.OK)
@ApiException(QUERY_AUTHORIZED_NAMESPACE_ERROR)
@AccessLogAnnotation(ignoreRequestArgs = "loginUser")
public Result queryAuthorizedNamespace(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
@RequestParam("userId") Integer userId) {
Map<String, Object> result = k8sNamespaceService.queryAuthorizedNamespace(loginUser, userId);
return returnDataList(result);
}
/**
* query namespace available
*
* @param loginUser login user
* @return namespace list
*/
@ApiOperation(value = "queryAvailableNamespaceList", notes = "QUERY_AVAILABLE_NAMESPACE_LIST_NOTES")
@GetMapping(value = "/available-list")
@ResponseStatus(HttpStatus.OK)
@ApiException(QUERY_CAN_USE_K8S_CLUSTER_ERROR)
@AccessLogAnnotation(ignoreRequestArgs = "loginUser")
public Result queryAvailableNamespaceList(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser) {
List<K8sNamespace> result = k8sNamespaceService.queryNamespaceAvailable(loginUser);
return success(result);
}
}

26
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/UsersController.java

@ -22,6 +22,7 @@ import static org.apache.dolphinscheduler.api.enums.Status.CREATE_USER_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.DELETE_USER_BY_ID_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.GET_USER_INFO_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.GRANT_DATASOURCE_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.GRANT_K8S_NAMESPACE_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.GRANT_PROJECT_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.GRANT_RESOURCE_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.GRANT_UDF_FUNCTION_ERROR;
@ -334,6 +335,31 @@ public class UsersController extends BaseController {
}
/**
* grant namespace
*
* @param loginUser login user
* @param userId user id
* @param namespaceIds namespace id array
* @return grant result code
*/
@ApiOperation(value = "grantNamespace", notes = "GRANT_NAMESPACE_NOTES")
@ApiImplicitParams({
@ApiImplicitParam(name = "userId", value = "USER_ID", required = true, dataType = "Int", example = "100"),
@ApiImplicitParam(name = "namespaceIds", value = "NAMESPACE_IDS", required = true, type = "String")
})
@PostMapping(value = "/grant-namespace")
@ResponseStatus(HttpStatus.OK)
@ApiException(GRANT_K8S_NAMESPACE_ERROR)
@AccessLogAnnotation
public Result grantNamespace(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
@RequestParam(value = "userId") int userId,
@RequestParam(value = "namespaceIds") String namespaceIds) {
Map<String, Object> result = usersService.grantNamespaces(loginUser, userId, namespaceIds);
return returnDataList(result);
}
/**
* grant datasource
*

6
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/enums/Status.java

@ -394,7 +394,11 @@ public enum Status {
VERIFY_K8S_NAMESPACE_ERROR(1300007, "verify k8s and namespace error", "验证k8s命名空间信息错误"),
DELETE_K8S_NAMESPACE_BY_ID_ERROR(1300008, "delete k8s namespace by id error", "删除命名空间错误"),
VERIFY_PARAMETER_NAME_FAILED(1300009, "The file name verify failed", "文件命名校验失败"),
STORE_OPERATE_CREATE_ERROR(1300010, "create the resource failed", "存储操作失败");
STORE_OPERATE_CREATE_ERROR(1300010, "create the resource failed", "存储操作失败"),
GRANT_K8S_NAMESPACE_ERROR(1300011, "grant namespace error", "授权资源错误"),
QUERY_UNAUTHORIZED_NAMESPACE_ERROR(1300012, "query unauthorized namespace error", "查询未授权命名空间错误"),
QUERY_AUTHORIZED_NAMESPACE_ERROR(1300013, "query authorized namespace error", "查询授权命名空间错误"),
QUERY_CAN_USE_K8S_CLUSTER_ERROR(1300014, "login user query can used k8s cluster list error", "查询可用k8s集群错误");
private final int code;
private final String enMsg;

39
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/K8sNameSpaceService.java → dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/K8sNamespaceService.java

@ -18,14 +18,16 @@
package org.apache.dolphinscheduler.api.service;
import org.apache.dolphinscheduler.api.utils.Result;
import org.apache.dolphinscheduler.dao.entity.K8sNamespace;
import org.apache.dolphinscheduler.dao.entity.User;
import java.util.List;
import java.util.Map;
/**
* k8s namespace service impl
*/
public interface K8sNameSpaceService {
public interface K8sNamespaceService {
/**
* query namespace list paging
*
@ -44,26 +46,23 @@ public interface K8sNameSpaceService {
* @param loginUser login user
* @param namespace namespace
* @param k8s k8s not null
* @param owner owner can null
* @param tag can null,if set means just used for one type job,such as flink,spark
* @param limitsCpu limits cpu, can null means not limit
* @param limitsMemory limits memory, can null means not limit
* @return
*/
Map<String, Object> createK8sNamespace(User loginUser, String namespace, String k8s, String owner, String tag, Double limitsCpu, Integer limitsMemory);
Map<String, Object> createK8sNamespace(User loginUser, String namespace, String k8s, Double limitsCpu, Integer limitsMemory);
/**
* update K8s Namespace tag and resource limit
*
* @param loginUser login user
* @param owner owner
* @param tag Which type of job is available,such as flink,means only flink job can use, can be empty, all available
* @param userName owner
* @param limitsCpu max cpu
* @param limitsMemory max memory
* @return
*/
Map<String, Object> updateK8sNamespace(User loginUser, int id, String owner, String tag, Double limitsCpu, Integer limitsMemory);
Map<String, Object> updateK8sNamespace(User loginUser, int id, String userName, Double limitsCpu, Integer limitsMemory);
/**
* verify namespace and k8s
@ -82,4 +81,30 @@ public interface K8sNameSpaceService {
* @return
*/
Map<String, Object> deleteNamespaceById(User loginUser, int id);
/**
* query unauthorized namespace
*
* @param loginUser login user
* @param userId user id
* @return the namespaces which user have not permission to see
*/
Map<String, Object> queryUnauthorizedNamespace(User loginUser, Integer userId);
/**
* query unauthorized namespace
*
* @param loginUser login user
* @param userId user id
* @return namespaces which the user have permission to see
*/
Map<String, Object> queryAuthorizedNamespace(User loginUser, Integer userId);
/**
* query namespace can use
*
* @param loginUser login user
* @return namespace list
*/
List<K8sNamespace> queryNamespaceAvailable(User loginUser);
}

11
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/UsersService.java

@ -194,6 +194,17 @@ public interface UsersService {
Map<String, Object> grantUDFFunction(User loginUser, int userId, String udfIds);
/**
* grant namespace
*
* @param loginUser login user
* @param userId user id
* @param namespaceIds namespace id array
* @return grant result code
*/
Map<String, Object> grantNamespaces(User loginUser, int userId, String namespaceIds);
/**
* grant datasource
*

155
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/K8sNameSpaceServiceImpl.java → dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/K8SNamespaceServiceImpl.java

@ -18,7 +18,7 @@
package org.apache.dolphinscheduler.api.service.impl;
import org.apache.dolphinscheduler.api.enums.Status;
import org.apache.dolphinscheduler.api.service.K8sNameSpaceService;
import org.apache.dolphinscheduler.api.service.K8sNamespaceService;
import org.apache.dolphinscheduler.api.utils.PageInfo;
import org.apache.dolphinscheduler.api.utils.Result;
import org.apache.dolphinscheduler.common.Constants;
@ -29,15 +29,20 @@ import org.apache.dolphinscheduler.service.k8s.K8sClientService;
import org.apache.commons.lang.StringUtils;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@ -45,9 +50,9 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
* k8s namespace service impl
*/
@Service
public class K8sNameSpaceServiceImpl extends BaseServiceImpl implements K8sNameSpaceService {
public class K8SNamespaceServiceImpl extends BaseServiceImpl implements K8sNamespaceService {
private static final Logger logger = LoggerFactory.getLogger(K8sNameSpaceServiceImpl.class);
private static final Logger logger = LoggerFactory.getLogger(K8SNamespaceServiceImpl.class);
private static String resourceYaml = "apiVersion: v1\n"
+ "kind: ResourceQuota\n"
@ -100,14 +105,12 @@ public class K8sNameSpaceServiceImpl extends BaseServiceImpl implements K8sNameS
* @param loginUser login user
* @param namespace namespace
* @param k8s k8s not null
* @param owner owner can null
* @param tag can null,if set means just used for one type job,such as flink,spark
* @param limitsCpu limits cpu, can null means not limit
* @param limitsMemory limits memory, can null means not limit
* @return
*/
@Override
public Map<String, Object> createK8sNamespace(User loginUser, String namespace, String k8s, String owner, String tag, Double limitsCpu, Integer limitsMemory) {
public Map<String, Object> createK8sNamespace(User loginUser, String namespace, String k8s, Double limitsCpu, Integer limitsMemory) {
Map<String, Object> result = new HashMap<>();
if (isNotAdmin(loginUser, result)) {
return result;
@ -143,8 +146,7 @@ public class K8sNameSpaceServiceImpl extends BaseServiceImpl implements K8sNameS
k8sNamespaceObj.setNamespace(namespace);
k8sNamespaceObj.setK8s(k8s);
k8sNamespaceObj.setOwner(owner);
k8sNamespaceObj.setTag(tag);
k8sNamespaceObj.setUserId(loginUser.getId());
k8sNamespaceObj.setLimitsCpu(limitsCpu);
k8sNamespaceObj.setLimitsMemory(limitsMemory);
k8sNamespaceObj.setOnlineJobNum(0);
@ -154,13 +156,15 @@ public class K8sNameSpaceServiceImpl extends BaseServiceImpl implements K8sNameS
k8sNamespaceObj.setCreateTime(now);
k8sNamespaceObj.setUpdateTime(now);
try {
String yamlStr = genDefaultResourceYaml(k8sNamespaceObj);
k8sClientService.upsertNamespaceAndResourceToK8s(k8sNamespaceObj, yamlStr);
} catch (Exception e) {
logger.error("namespace create to k8s error", e);
putMsg(result, Status.K8S_CLIENT_OPS_ERROR, e.getMessage());
return result;
if (!Constants.K8S_LOCAL_TEST_CLUSTER.equals(k8sNamespaceObj.getK8s())) {
try {
String yamlStr = genDefaultResourceYaml(k8sNamespaceObj);
k8sClientService.upsertNamespaceAndResourceToK8s(k8sNamespaceObj, yamlStr);
} catch (Exception e) {
logger.error("namespace create to k8s error", e);
putMsg(result, Status.K8S_CLIENT_OPS_ERROR, e.getMessage());
return result;
}
}
k8sNamespaceMapper.insert(k8sNamespaceObj);
@ -173,14 +177,13 @@ public class K8sNameSpaceServiceImpl extends BaseServiceImpl implements K8sNameS
* update K8s Namespace tag and resource limit
*
* @param loginUser login user
* @param owner owner
* @param tag Which type of job is available,such as flink,means only flink job can use, can be empty, all available
* @param userName owner
* @param limitsCpu max cpu
* @param limitsMemory max memory
* @return
*/
@Override
public Map<String, Object> updateK8sNamespace(User loginUser, int id, String owner, String tag, Double limitsCpu, Integer limitsMemory) {
public Map<String, Object> updateK8sNamespace(User loginUser, int id, String userName, Double limitsCpu, Integer limitsMemory) {
Map<String, Object> result = new HashMap<>();
if (isNotAdmin(loginUser, result)) {
return result;
@ -203,18 +206,19 @@ public class K8sNameSpaceServiceImpl extends BaseServiceImpl implements K8sNameS
}
Date now = new Date();
k8sNamespaceObj.setTag(tag);
k8sNamespaceObj.setLimitsCpu(limitsCpu);
k8sNamespaceObj.setLimitsMemory(limitsMemory);
k8sNamespaceObj.setUpdateTime(now);
k8sNamespaceObj.setOwner(owner);
try {
String yamlStr = genDefaultResourceYaml(k8sNamespaceObj);
k8sClientService.upsertNamespaceAndResourceToK8s(k8sNamespaceObj, yamlStr);
} catch (Exception e) {
logger.error("namespace update to k8s error", e);
putMsg(result, Status.K8S_CLIENT_OPS_ERROR, e.getMessage());
return result;
if (!Constants.K8S_LOCAL_TEST_CLUSTER.equals(k8sNamespaceObj.getK8s())) {
try {
String yamlStr = genDefaultResourceYaml(k8sNamespaceObj);
k8sClientService.upsertNamespaceAndResourceToK8s(k8sNamespaceObj, yamlStr);
} catch (Exception e) {
logger.error("namespace update to k8s error", e);
putMsg(result, Status.K8S_CLIENT_OPS_ERROR, e.getMessage());
return result;
}
}
// update to db
k8sNamespaceMapper.updateById(k8sNamespaceObj);
@ -271,8 +275,9 @@ public class K8sNameSpaceServiceImpl extends BaseServiceImpl implements K8sNameS
putMsg(result, Status.K8S_NAMESPACE_NOT_EXIST, id);
return result;
}
k8sClientService.deleteNamespaceToK8s(k8sNamespaceObj.getNamespace(), k8sNamespaceObj.getK8s());
if (!Constants.K8S_LOCAL_TEST_CLUSTER.equals(k8sNamespaceObj.getK8s())) {
k8sClientService.deleteNamespaceToK8s(k8sNamespaceObj.getNamespace(), k8sNamespaceObj.getK8s());
}
k8sNamespaceMapper.deleteById(id);
putMsg(result, Status.SUCCESS);
return result;
@ -323,4 +328,96 @@ public class K8sNameSpaceServiceImpl extends BaseServiceImpl implements K8sNameS
}
return result;
}
/**
* query unauthorized namespace
*
* @param loginUser login user
* @param userId user id
* @return the namespaces which user have not permission to see
*/
@Override
public Map<String, Object> queryUnauthorizedNamespace(User loginUser, Integer userId) {
Map<String, Object> result = new HashMap<>();
if (loginUser.getId() != userId && isNotAdmin(loginUser, result)) {
return result;
}
// query all namespace list,this auth does not like project
List<K8sNamespace> namespaceList = k8sNamespaceMapper.selectList(null);
List<K8sNamespace> resultList = new ArrayList<>();
Set<K8sNamespace> namespaceSet;
if (namespaceList != null && !namespaceList.isEmpty()) {
namespaceSet = new HashSet<>(namespaceList);
List<K8sNamespace> authedProjectList = k8sNamespaceMapper.queryAuthedNamespaceListByUserId(userId);
resultList = getUnauthorizedNamespaces(namespaceSet, authedProjectList);
}
result.put(Constants.DATA_LIST, resultList);
putMsg(result, Status.SUCCESS);
return result;
}
/**
* query authorized namespace
*
* @param loginUser login user
* @param userId user id
* @return namespaces which the user have permission to see
*/
@Override
public Map<String, Object> queryAuthorizedNamespace(User loginUser, Integer userId) {
Map<String, Object> result = new HashMap<>();
if (loginUser.getId() != userId && isNotAdmin(loginUser, result)) {
return result;
}
List<K8sNamespace> namespaces = k8sNamespaceMapper.queryAuthedNamespaceListByUserId(userId);
result.put(Constants.DATA_LIST, namespaces);
putMsg(result, Status.SUCCESS);
return result;
}
/**
* query namespace can use
*
* @param loginUser login user
* @return namespace list
*/
@Override
public List<K8sNamespace> queryNamespaceAvailable(User loginUser) {
if (isAdmin(loginUser)) {
return k8sNamespaceMapper.selectList(null);
} else {
return k8sNamespaceMapper.queryNamespaceAvailable(loginUser.getId());
}
}
/**
* get unauthorized namespace
*
* @param namespaceSet namespace set
* @param authedNamespaceList authed namespace list
* @return namespace list that authorization
*/
private List<K8sNamespace> getUnauthorizedNamespaces(Set<K8sNamespace> namespaceSet, List<K8sNamespace> authedNamespaceList) {
List<K8sNamespace> resultList = new ArrayList<>();
for (K8sNamespace k8sNamespace : namespaceSet) {
boolean existAuth = false;
if (authedNamespaceList != null && !authedNamespaceList.isEmpty()) {
for (K8sNamespace k8sNamespaceAuth : authedNamespaceList) {
if (k8sNamespace.equals(k8sNamespaceAuth)) {
existAuth = true;
}
}
}
if (!existAuth) {
resultList.add(k8sNamespace);
}
}
return resultList;
}
}

53
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/UsersServiceImpl.java

@ -36,6 +36,7 @@ import org.apache.dolphinscheduler.common.utils.EncryptionUtils;
import org.apache.dolphinscheduler.common.utils.PropertyUtils;
import org.apache.dolphinscheduler.dao.entity.AlertGroup;
import org.apache.dolphinscheduler.dao.entity.DatasourceUser;
import org.apache.dolphinscheduler.dao.entity.K8sNamespaceUser;
import org.apache.dolphinscheduler.dao.entity.Project;
import org.apache.dolphinscheduler.dao.entity.ProjectUser;
import org.apache.dolphinscheduler.dao.entity.Resource;
@ -46,6 +47,7 @@ import org.apache.dolphinscheduler.dao.entity.User;
import org.apache.dolphinscheduler.dao.mapper.AccessTokenMapper;
import org.apache.dolphinscheduler.dao.mapper.AlertGroupMapper;
import org.apache.dolphinscheduler.dao.mapper.DataSourceUserMapper;
import org.apache.dolphinscheduler.dao.mapper.K8sNamespaceUserMapper;
import org.apache.dolphinscheduler.dao.mapper.ProcessDefinitionMapper;
import org.apache.dolphinscheduler.dao.mapper.ProjectMapper;
import org.apache.dolphinscheduler.dao.mapper.ProjectUserMapper;
@ -117,6 +119,9 @@ public class UsersServiceImpl extends BaseServiceImpl implements UsersService {
@Autowired(required = false)
private StorageOperate storageOperate;
@Autowired
private K8sNamespaceUserMapper k8sNamespaceUserMapper;
/**
* create user, only system admin have permission
*
@ -798,6 +803,54 @@ public class UsersServiceImpl extends BaseServiceImpl implements UsersService {
return result;
}
/**
* grant namespace
*
* @param loginUser login user
* @param userId user id
* @param namespaceIds namespace id array
* @return grant result code
*/
@Override
@Transactional(rollbackFor = RuntimeException.class)
public Map<String, Object> grantNamespaces(User loginUser, int userId, String namespaceIds) {
Map<String, Object> result = new HashMap<>();
result.put(Constants.STATUS, false);
//only admin can operate
if (check(result, !isAdmin(loginUser), Status.USER_NO_OPERATION_PERM)) {
return result;
}
//check exist
User tempUser = userMapper.selectById(userId);
if (tempUser == null) {
putMsg(result, Status.USER_NOT_EXIST, userId);
return result;
}
k8sNamespaceUserMapper.deleteNamespaceRelation(0, userId);
if (StringUtils.isNotEmpty(namespaceIds)) {
String[] namespaceIdArr = namespaceIds.split(",");
for (String namespaceId : namespaceIdArr) {
Date now = new Date();
K8sNamespaceUser namespaceUser = new K8sNamespaceUser();
namespaceUser.setUserId(userId);
namespaceUser.setNamespaceId(Integer.parseInt(namespaceId));
namespaceUser.setPerm(7);
namespaceUser.setCreateTime(now);
namespaceUser.setUpdateTime(now);
k8sNamespaceUserMapper.insert(namespaceUser);
}
}
putMsg(result, Status.SUCCESS);
return result;
}
/**
* grant datasource
*

45
dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/K8sNamespaceControllerTest.java

@ -28,8 +28,12 @@ import org.apache.dolphinscheduler.api.utils.Result;
import org.apache.dolphinscheduler.common.utils.JSONUtils;
import org.apache.dolphinscheduler.dao.entity.User;
import java.util.HashMap;
import java.util.Map;
import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mockito;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
@ -96,7 +100,7 @@ public class K8sNamespaceControllerTest extends AbstractControllerTest {
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andReturn();
Result result = JSONUtils.parseObject(mvcResult.getResponse().getContentAsString(), Result.class);
Assert.assertEquals(Status.K8S_CLIENT_OPS_ERROR.getCode(), result.getCode().intValue());
Assert.assertEquals(Status.SUCCESS.getCode(), result.getCode().intValue());
logger.info("update queue return result:{}", mvcResult.getResponse().getContentAsString());
}
@ -137,7 +141,7 @@ public class K8sNamespaceControllerTest extends AbstractControllerTest {
}
@Test
public void delNamespaceById() throws Exception {
public void deleteNamespaceById() throws Exception {
MultiValueMap<String, String> paramsMap = new LinkedMultiValueMap<>();
paramsMap.add("id", "1");
@ -149,7 +153,42 @@ public class K8sNamespaceControllerTest extends AbstractControllerTest {
.andReturn();
Result result = JSONUtils.parseObject(mvcResult.getResponse().getContentAsString(), Result.class);
Assert.assertEquals(Status.DELETE_K8S_NAMESPACE_BY_ID_ERROR.getCode(), result.getCode().intValue());//there is no k8s cluster in test env
Assert.assertEquals(Status.SUCCESS.getCode(), result.getCode().intValue());//there is no k8s cluster in test env
logger.info(mvcResult.getResponse().getContentAsString());
}
@Test
public void testQueryUnauthorizedNamespace() throws Exception {
MultiValueMap<String, String> paramsMap = new LinkedMultiValueMap<>();
paramsMap.add("userId", "1");
MvcResult mvcResult = mockMvc.perform(get("/k8s-namespace/unauth-namespace")
.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);
Assert.assertEquals(Status.SUCCESS.getCode(), result.getCode().intValue());
logger.info(mvcResult.getResponse().getContentAsString());
}
@Test
public void testQueryAuthorizedNamespace() throws Exception {
MultiValueMap<String, String> paramsMap = new LinkedMultiValueMap<>();
paramsMap.add("userId", "1");
MvcResult mvcResult = mockMvc.perform(get("/k8s-namespace/authed-namespace")
.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);
Assert.assertEquals(Status.SUCCESS.getCode(), result.getCode().intValue());
logger.info(mvcResult.getResponse().getContentAsString());
}
}

80
dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/K8sNameSpaceServiceTest.java → dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/K8SNamespaceServiceTest.java

@ -18,7 +18,7 @@
package org.apache.dolphinscheduler.api.service;
import org.apache.dolphinscheduler.api.enums.Status;
import org.apache.dolphinscheduler.api.service.impl.K8sNameSpaceServiceImpl;
import org.apache.dolphinscheduler.api.service.impl.K8SNamespaceServiceImpl;
import org.apache.dolphinscheduler.api.utils.PageInfo;
import org.apache.dolphinscheduler.api.utils.Result;
import org.apache.dolphinscheduler.common.Constants;
@ -51,12 +51,12 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@RunWith(MockitoJUnitRunner.class)
public class K8sNameSpaceServiceTest {
public class K8SNamespaceServiceTest {
private static final Logger logger = LoggerFactory.getLogger(K8sNameSpaceServiceTest.class);
private static final Logger logger = LoggerFactory.getLogger(K8SNamespaceServiceTest.class);
@InjectMocks
private K8sNameSpaceServiceImpl k8sNameSpaceService;
private K8SNamespaceServiceImpl k8sNamespaceService;
@Mock
private K8sNamespaceMapper k8sNamespaceMapper;
@ -86,7 +86,7 @@ public class K8sNameSpaceServiceTest {
page.setTotal(1L);
page.setRecords(getNamespaceList());
Mockito.when(k8sNamespaceMapper.queryK8sNamespacePaging(Mockito.any(Page.class), Mockito.eq(namespace))).thenReturn(page);
Result result = k8sNameSpaceService.queryListPaging(getLoginUser(), namespace, 1, 10);
Result result = k8sNamespaceService.queryListPaging(getLoginUser(), namespace, 1, 10);
logger.info(result.toString());
PageInfo<K8sNamespace> pageInfo = (PageInfo<K8sNamespace>) result.getData();
Assert.assertTrue(CollectionUtils.isNotEmpty(pageInfo.getTotalList()));
@ -95,19 +95,19 @@ public class K8sNameSpaceServiceTest {
@Test
public void createK8sNamespace() {
// namespace is null
Map<String, Object> result = k8sNameSpaceService.createK8sNamespace(getLoginUser(), null, k8s, null, "tag", 10.0, 100);
Map<String, Object> result = k8sNamespaceService.createK8sNamespace(getLoginUser(), null, k8s, 10.0, 100);
logger.info(result.toString());
Assert.assertEquals(Status.REQUEST_PARAMS_NOT_VALID_ERROR, result.get(Constants.STATUS));
// k8s is null
result = k8sNameSpaceService.createK8sNamespace(getLoginUser(), namespace, null, null, "tag", 10.0, 100);
result = k8sNamespaceService.createK8sNamespace(getLoginUser(), namespace, null, 10.0, 100);
logger.info(result.toString());
Assert.assertEquals(Status.REQUEST_PARAMS_NOT_VALID_ERROR, result.get(Constants.STATUS));
// correct
result = k8sNameSpaceService.createK8sNamespace(getLoginUser(), namespace, k8s, null, "tag", 10.0, 100);
result = k8sNamespaceService.createK8sNamespace(getLoginUser(), namespace, k8s, 10.0, 100);
logger.info(result.toString());
Assert.assertEquals(Status.SUCCESS, result.get(Constants.STATUS));
//null limit cpu and mem
result = k8sNameSpaceService.createK8sNamespace(getLoginUser(), namespace, k8s, null, "tag", null, null);
result = k8sNamespaceService.createK8sNamespace(getLoginUser(), namespace, k8s, null, null);
logger.info(result.toString());
Assert.assertEquals(Status.SUCCESS, result.get(Constants.STATUS));
}
@ -116,15 +116,15 @@ public class K8sNameSpaceServiceTest {
public void updateK8sNamespace() {
Mockito.when(k8sNamespaceMapper.selectById(1)).thenReturn(getNamespace());
Map<String, Object> result = k8sNameSpaceService.updateK8sNamespace(getLoginUser(), 1, null, "tag", null, null);
Map<String, Object> result = k8sNamespaceService.updateK8sNamespace(getLoginUser(), 1, null, null, null);
logger.info(result.toString());
Assert.assertEquals(Status.SUCCESS, result.get(Constants.STATUS));
result = k8sNameSpaceService.updateK8sNamespace(getLoginUser(), 1, null, "tag", -1.0, 100);
result = k8sNamespaceService.updateK8sNamespace(getLoginUser(), 1, null, -1.0, 100);
logger.info(result.toString());
Assert.assertEquals(Status.REQUEST_PARAMS_NOT_VALID_ERROR, result.get(Constants.STATUS));
result = k8sNameSpaceService.updateK8sNamespace(getLoginUser(), 1, null, "tag", 1.0, 100);
result = k8sNamespaceService.updateK8sNamespace(getLoginUser(), 1, null, 1.0, 100);
logger.info(result.toString());
Assert.assertEquals(Status.SUCCESS, result.get(Constants.STATUS));
}
@ -135,22 +135,22 @@ public class K8sNameSpaceServiceTest {
Mockito.when(k8sNamespaceMapper.existNamespace(namespace, k8s)).thenReturn(true);
//namespace null
Result result = k8sNameSpaceService.verifyNamespaceK8s(null, k8s);
Result result = k8sNamespaceService.verifyNamespaceK8s(null, k8s);
logger.info(result.toString());
Assert.assertEquals(result.getCode().intValue(), Status.REQUEST_PARAMS_NOT_VALID_ERROR.getCode());
//k8s null
result = k8sNameSpaceService.verifyNamespaceK8s(namespace, null);
result = k8sNamespaceService.verifyNamespaceK8s(namespace, null);
logger.info(result.toString());
Assert.assertEquals(result.getCode().intValue(), Status.REQUEST_PARAMS_NOT_VALID_ERROR.getCode());
//exist
result = k8sNameSpaceService.verifyNamespaceK8s(namespace, k8s);
result = k8sNamespaceService.verifyNamespaceK8s(namespace, k8s);
logger.info(result.toString());
Assert.assertEquals(result.getCode().intValue(), Status.K8S_NAMESPACE_EXIST.getCode());
//not exist
result = k8sNameSpaceService.verifyNamespaceK8s(namespace, "other k8s");
result = k8sNamespaceService.verifyNamespaceK8s(namespace, "other k8s");
logger.info(result.toString());
Assert.assertEquals(result.getCode().intValue(), Status.SUCCESS.getCode());
}
@ -160,11 +160,57 @@ public class K8sNameSpaceServiceTest {
Mockito.when(k8sNamespaceMapper.deleteById(Mockito.any())).thenReturn(1);
Mockito.when(k8sNamespaceMapper.selectById(1)).thenReturn(getNamespace());
Map<String, Object> result = k8sNameSpaceService.deleteNamespaceById(getLoginUser(), 1);
Map<String, Object> result = k8sNamespaceService.deleteNamespaceById(getLoginUser(), 1);
logger.info(result.toString());
Assert.assertEquals(Status.SUCCESS, result.get(Constants.STATUS));
}
@Test
public void testQueryAuthorizedNamespace() {
Mockito.when(k8sNamespaceMapper.queryAuthedNamespaceListByUserId(2)).thenReturn(getNamespaceList());
User loginUser = getLoginUser();
// test admin user
loginUser.setUserType(UserType.ADMIN_USER);
Map<String, Object> result = k8sNamespaceService.queryAuthorizedNamespace(loginUser, 2);
logger.info(result.toString());
List<K8sNamespace> namespaces = (List<K8sNamespace>) result.get(Constants.DATA_LIST);
Assert.assertTrue(CollectionUtils.isNotEmpty(namespaces));
// test non-admin user
loginUser.setUserType(UserType.GENERAL_USER);
loginUser.setId(3);
result = k8sNamespaceService.queryAuthorizedNamespace(loginUser, 2);
Assert.assertEquals(Status.USER_NO_OPERATION_PERM, result.get(Constants.STATUS));
namespaces = (List<K8sNamespace>) result.get(Constants.DATA_LIST);
Assert.assertTrue(CollectionUtils.isEmpty(namespaces));
}
@Test
public void testQueryUnAuthorizedNamespace() {
Mockito.when(k8sNamespaceMapper.queryAuthedNamespaceListByUserId(2)).thenReturn(new ArrayList<>());
Mockito.when(k8sNamespaceMapper.selectList(Mockito.any())).thenReturn(getNamespaceList());
// test admin user
User loginUser = new User();
loginUser.setUserType(UserType.ADMIN_USER);
Map<String, Object> result = k8sNamespaceService.queryUnauthorizedNamespace(loginUser, 2);
logger.info(result.toString());
List<K8sNamespace> namespaces = (List<K8sNamespace>) result.get(Constants.DATA_LIST);
Assert.assertTrue(CollectionUtils.isNotEmpty(namespaces));
// test non-admin user
loginUser.setId(2);
loginUser.setUserType(UserType.GENERAL_USER);
result = k8sNamespaceService.queryUnauthorizedNamespace(loginUser, 3);
logger.info(result.toString());
Assert.assertEquals(Status.USER_NO_OPERATION_PERM, result.get(Constants.STATUS));
namespaces = (List<K8sNamespace>) result.get(Constants.DATA_LIST);
Assert.assertTrue(CollectionUtils.isEmpty(namespaces));
}
private User getLoginUser() {
User loginUser = new User();

21
dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/UsersServiceTest.java

@ -90,6 +90,9 @@ public class UsersServiceTest {
@Mock
private UDFUserMapper udfUserMapper;
@Mock
private K8sNamespaceUserMapper k8sNamespaceUserMapper;
@Mock
private ProjectMapper projectMapper;
@ -434,6 +437,24 @@ public class UsersServiceTest {
Assert.assertEquals(Status.SUCCESS, result.get(Constants.STATUS));
}
@Test
public void testGrantNamespaces() {
String namespaceIds = "100000,120000";
when(userMapper.selectById(1)).thenReturn(getUser());
User loginUser = new User();
//user not exist
loginUser.setUserType(UserType.ADMIN_USER);
Map<String, Object> result = usersService.grantNamespaces(loginUser, 2, namespaceIds);
logger.info(result.toString());
Assert.assertEquals(Status.USER_NOT_EXIST, result.get(Constants.STATUS));
//success
when(k8sNamespaceUserMapper.deleteNamespaceRelation(0,1)).thenReturn(1);
result = usersService.grantNamespaces(loginUser, 1, namespaceIds);
logger.info(result.toString());
Assert.assertEquals(Status.SUCCESS, result.get(Constants.STATUS));
}
@Test
public void testGrantDataSource() {
String datasourceIds = "100000,120000";

1
dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/Constants.java

@ -816,4 +816,5 @@ public final class Constants {
public static final String K8S = "k8s";
public static final String LIMITS_CPU = "limitsCpu";
public static final String LIMITS_MEMORY = "limitsMemory";
public static final String K8S_LOCAL_TEST_CLUSTER = "ds_null_k8s";
}

92
dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/K8sNamespace.java

@ -37,54 +37,66 @@ public class K8sNamespace {
*/
@TableField(value = "namespace")
private String namespace;
/**
* total cpu limit
*/
@TableField(value = "limits_cpu")
private Double limitsCpu;
/**
* total memory limit,mi
*/
private Integer limitsMemory;
/**
* owner
*/
@TableField(value = "owner")
private String owner;
@TableField(value = "user_id")
private int userId;
/**
* user name
*/
@TableField(exist = false)
private String userName;
/**
* create_time
*/
@TableField("create_time")
private Date createTime;
/**
* update_time
*/
@TableField("update_time")
private Date updateTime;
/**
* tag use for set this namespace allow run which type
* 1.00 = 1 cpu
*/
@TableField("tag")
private String tag;
@TableField("pod_request_cpu")
private Double podRequestCpu = 0.0;
/**
* Mi
*/
@TableField("pod_request_memory")
private Integer podRequestMemory = 0;
/**
*
* replicas
*/
@TableField("pod_replicas")
private Integer podReplicas = 0;
/**
* online job
*/
@TableField("online_job_num")
private Integer onlineJobNum = 0;
/**
* k8s name
*/
@ -123,12 +135,12 @@ public class K8sNamespace {
this.limitsMemory = limitsMemory;
}
public String getOwner() {
return owner;
public int getUserId() {
return userId;
}
public void setOwner(String owner) {
this.owner = owner;
public void setUserId(int userId) {
this.userId = userId;
}
public Date getCreateTime() {
@ -147,14 +159,6 @@ public class K8sNamespace {
this.updateTime = updateTime;
}
public String getTag() {
return tag;
}
public void setTag(String tag) {
this.tag = tag;
}
public Integer getPodRequestMemory() {
return podRequestMemory;
}
@ -194,4 +198,54 @@ public class K8sNamespace {
public void setPodRequestCpu(Double podRequestCpu) {
this.podRequestCpu = podRequestCpu;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
@Override
public String toString() {
return "K8sNamespace{" +
"id=" + id +
", namespace=" + namespace +
", limitsCpu=" + limitsCpu +
", limitsMemory=" + limitsMemory +
", userId=" + userId +
", podRequestCpu=" + podRequestCpu +
", podRequestMemory=" + podRequestMemory +
", podReplicas=" + podReplicas +
", k8s=" + k8s +
", createTime=" + createTime +
", updateTime=" + updateTime +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
K8sNamespace k8sNamespace = (K8sNamespace) o;
if (id.equals(k8sNamespace.id)) {
return true;
}
return namespace.equals(k8sNamespace.namespace) && k8s.equals(k8sNamespace.k8s);
}
@Override
public int hashCode() {
int result = id;
result = 31 * result + (k8s+namespace).hashCode();
return result;
}
}

164
dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/K8sNamespaceUser.java

@ -0,0 +1,164 @@
/*
* 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.dao.entity;
import java.util.Date;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
/**
* k8s namespace and user relation
*/
@TableName("t_ds_relation_namespace_user")
public class K8sNamespaceUser {
/**
* id
*/
@TableId(value = "id", type = IdType.AUTO)
private int id;
/**
* user id
*/
@TableField("user_id")
private int userId;
/**
* namespace id
*/
@TableField("namespace_id")
private int namespaceId;
/**
* k8s cluster
*/
@TableField(exist = false)
private String k8s;
/**
* namespace name
*/
@TableField(exist = false)
private String namespaceName;
/**
* user name
*/
@TableField(exist = false)
private String userName;
/**
* permission
*/
private int perm;
@TableField("create_time")
private Date createTime;
@TableField("update_time")
private Date updateTime;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public int getNamespaceId() {
return namespaceId;
}
public void setNamespaceId(int namespaceId) {
this.namespaceId = namespaceId;
}
public String getK8s() {
return k8s;
}
public void setK8s(String k8s) {
this.k8s = k8s;
}
public String getNamespaceName() {
return namespaceName;
}
public void setNamespaceName(String namespaceName) {
this.namespaceName = namespaceName;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public int getPerm() {
return perm;
}
public void setPerm(int perm) {
this.perm = perm;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Date getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
@Override
public String toString() {
return "K8sNamespaceUser{" +
"id=" + id +
", userId=" + userId +
", namespaceId=" + namespaceId +
", k8s=" + k8s +
", namespaceName=" + namespaceName +
", perm=" + perm +
", createTime=" + createTime +
", updateTime=" + updateTime +
'}';
}
}

26
dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/K8sNamespaceMapper.java

@ -21,6 +21,8 @@ import org.apache.dolphinscheduler.dao.entity.K8sNamespace;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
@ -46,4 +48,28 @@ public interface K8sNamespaceMapper extends BaseMapper<K8sNamespace> {
* @return true if exist else return null
*/
Boolean existNamespace(@Param("namespace") String namespace, @Param("k8s") String k8s);
/**
* query namespace except userId
*
* @param userId userId
* @return namespace list
*/
List<K8sNamespace> queryNamespaceExceptUserId(@Param("userId") int userId);
/**
* query authed namespace list by userId
*
* @param userId userId
* @return namespace list
*/
List<K8sNamespace> queryAuthedNamespaceListByUserId(@Param("userId") int userId);
/**
* query namespace can use
*
* @param userId userId
* @return namespace list
*/
List<K8sNamespace> queryNamespaceAvailable(@Param("userId") Integer userId);
}

50
dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/K8sNamespaceUserMapper.java

@ -0,0 +1,50 @@
/*
* 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.dao.mapper;
import org.apache.dolphinscheduler.dao.entity.K8sNamespaceUser;
import org.apache.ibatis.annotations.Param;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* namespace user mapper interface
*/
public interface K8sNamespaceUserMapper extends BaseMapper<K8sNamespaceUser> {
/**
* delete namespace user relation
*
* @param namespaceId namespaceId
* @param userId userId
* @return delete result
*/
int deleteNamespaceRelation(@Param("namespaceId") int namespaceId,
@Param("userId") int userId);
/**
* query namespace relation
*
* @param namespaceId namespaceId
* @param userId userId
* @return namespace user relation
*/
K8sNamespaceUser queryNamespaceRelation(@Param("namespaceId") int namespaceId,
@Param("userId") int userId);
}

33
dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/K8sNamespaceMapper.xml

@ -20,8 +20,13 @@
<mapper namespace="org.apache.dolphinscheduler.dao.mapper.K8sNamespaceMapper">
<sql id="baseSql">
id, namespace, k8s, owner, tag, limits_memory, limits_cpu, online_job_num, pod_replicas, pod_request_cpu, pod_request_memory, create_time, update_time
id, namespace, k8s, user_id, limits_memory, limits_cpu, online_job_num, pod_replicas, pod_request_cpu, pod_request_memory, create_time, update_time
</sql>
<sql id="baseSqlV2">
${alias}.id, ${alias}.namespace, ${alias}.k8s, ${alias}.user_id, ${alias}.limits_memory, ${alias}.limits_cpu, ${alias}.online_job_num, ${alias}.pod_replicas, ${alias}.pod_request_cpu, ${alias}.pod_request_memory, ${alias}.create_time, ${alias}.update_time
</sql>
<select id="queryK8sNamespacePaging" resultType="org.apache.dolphinscheduler.dao.entity.K8sNamespace">
select
<include refid="baseSql"/>
@ -45,4 +50,30 @@
</if>
</select>
<select id="queryNamespaceExceptUserId" resultType="org.apache.dolphinscheduler.dao.entity.K8sNamespace">
select
<include refid="baseSql"/>
from t_ds_k8s_namespace
where user_id <![CDATA[ <> ]]> #{userId}
</select>
<select id="queryAuthedNamespaceListByUserId" resultType="org.apache.dolphinscheduler.dao.entity.K8sNamespace">
select
<include refid="baseSqlV2">
<property name="alias" value="p"/>
</include>
from t_ds_k8s_namespace p,t_ds_relation_namespace_user rel
where p.id = rel.namespace_id and rel.user_id= #{userId}
</select>
<select id="queryNamespaceAvailable" resultType="org.apache.dolphinscheduler.dao.entity.K8sNamespace">
select
<include refid="baseSqlV2">
<property name="alias" value="b"/>
</include>
from ( select namespace_id from t_ds_relation_namespace_user where user_id= #{userId} ) a
left join t_ds_k8s_namespace b
on b.id = a.namespace_id
where b.id is not null
</select>
</mapper>

40
dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/K8sNamespaceUserMapper.xml

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!--
~ 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.
-->
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="org.apache.dolphinscheduler.dao.mapper.K8sNamespaceUserMapper">
<sql id="baseSql">
id, user_id, namespace_id, perm, create_time, update_time
</sql>
<delete id="deleteNamespaceRelation">
delete from t_ds_relation_namespace_user
where 1=1
and user_id = #{userId}
<if test="namespaceId != 0 ">
and namespace_id = #{namespaceId}
</if>
</delete>
<select id="queryNamespaceRelation" resultType="org.apache.dolphinscheduler.dao.entity.K8sNamespaceUser">
select
<include refid="baseSql"/>
from t_ds_relation_namespace_user
where namespace_id = #{namespaceId}
and user_id = #{userId}
limit 1
</select>
</mapper>

31
dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_h2.sql

@ -1898,11 +1898,10 @@ CREATE TABLE t_ds_k8s_namespace (
limits_memory int(11) DEFAULT NULL,
namespace varchar(100) DEFAULT NULL,
online_job_num int(11) DEFAULT NULL,
owner varchar(100) DEFAULT NULL,
user_id int(11) DEFAULT NULL,
pod_replicas int(11) DEFAULT NULL,
pod_request_cpu decimal(14,3) DEFAULT NULL,
pod_request_memory int(11) DEFAULT NULL,
tag varchar(100) DEFAULT NULL,
limits_cpu decimal(14,3) DEFAULT NULL,
k8s varchar(100) DEFAULT NULL,
create_time datetime DEFAULT NULL ,
@ -1914,8 +1913,32 @@ CREATE TABLE t_ds_k8s_namespace (
-- ----------------------------
-- Records of t_ds_k8s_namespace
-- ----------------------------
INSERT INTO t_ds_k8s_namespace
VALUES (1, 10000, 'default', 99, 'owner',1,NULL,1,'test',NULL,'default',null,null);
INSERT INTO `t_ds_k8s_namespace`
(`id`,`limits_memory`,`namespace`,`online_job_num`,`user_id`,`pod_replicas`,`pod_request_cpu`,`pod_request_memory`,`limits_cpu`,`k8s`,`create_time`,`update_time`)
VALUES (1, 1000, 'flink_test', 99, 1, 1, 0.1, 1, NULL, 'ds_null_k8s', '2022-03-03 11:31:24.0', '2022-03-03 11:31:24.0');
INSERT INTO `t_ds_k8s_namespace`
(`id`,`limits_memory`,`namespace`,`online_job_num`,`user_id`,`pod_replicas`,`pod_request_cpu`,`pod_request_memory`,`limits_cpu`,`k8s`,`create_time`,`update_time`)
VALUES (2, 500, 'spark_test', 90, 2,1,10000,1, NULL, 'ds_null_k8s', '2021-03-03 11:31:24.0', '2021-03-03 11:31:24.0');
INSERT INTO `t_ds_k8s_namespace`
(`id`,`limits_memory`,`namespace`,`online_job_num`,`user_id`,`pod_replicas`,`pod_request_cpu`,`pod_request_memory`,`limits_cpu`,`k8s`,`create_time`,`update_time`)
VALUES (3, 200, 'auth_test', 68, 3,1,100,1, 10000, 'ds_null_k8s', '2020-03-03 11:31:24.0', '2020-03-03 11:31:24.0');
-- ----------------------------
-- Table structure for t_ds_relation_namespace_user
-- ----------------------------
DROP TABLE IF EXISTS t_ds_relation_namespace_user;
CREATE TABLE t_ds_relation_namespace_user (
id int(11) NOT NULL AUTO_INCREMENT ,
user_id int(11) NOT NULL ,
namespace_id int(11) NOT NULL ,
perm int(11) DEFAULT '1' ,
create_time datetime DEFAULT NULL ,
update_time datetime DEFAULT NULL ,
PRIMARY KEY (id) ,
UNIQUE KEY namespace_user_unique (user_id,namespace_id)
);
-- ----------------------------
-- Table structure for t_ds_alert_send_status

17
dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_mysql.sql

@ -1891,11 +1891,10 @@ CREATE TABLE `t_ds_k8s_namespace` (
`limits_memory` int(11) DEFAULT NULL,
`namespace` varchar(100) DEFAULT NULL,
`online_job_num` int(11) DEFAULT NULL,
`owner` varchar(100) DEFAULT NULL,
`user_id` int(11) DEFAULT NULL,
`pod_replicas` int(11) DEFAULT NULL,
`pod_request_cpu` decimal(14,3) DEFAULT NULL,
`pod_request_memory` int(11) DEFAULT NULL,
`tag` varchar(100) DEFAULT NULL,
`limits_cpu` decimal(14,3) DEFAULT NULL,
`k8s` varchar(100) DEFAULT NULL,
`create_time` datetime DEFAULT NULL COMMENT 'create time',
@ -1904,6 +1903,20 @@ CREATE TABLE `t_ds_k8s_namespace` (
UNIQUE KEY `k8s_namespace_unique` (`namespace`,`k8s`)
) ENGINE= INNODB AUTO_INCREMENT= 1 DEFAULT CHARSET= utf8;
-- ----------------------------
-- Table structure for t_ds_relation_namespace_user
-- ----------------------------
DROP TABLE IF EXISTS `t_ds_relation_namespace_user`;
CREATE TABLE `t_ds_relation_namespace_user` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'key',
`user_id` int(11) NOT NULL COMMENT 'user id',
`namespace_id` int(11) DEFAULT NULL COMMENT 'namespace id',
`perm` int(11) DEFAULT '1' COMMENT 'limits of authority',
`create_time` datetime DEFAULT NULL COMMENT 'create time',
`update_time` datetime DEFAULT NULL COMMENT 'update time',
PRIMARY KEY (`id`),
UNIQUE KEY `namespace_user_unique` (`user_id`,`namespace_id`)
) ENGINE=InnoDB AUTO_INCREMENT= 1 DEFAULT CHARSET= utf8;
-- ----------------------------
-- Table structure for t_ds_alert_send_status

19
dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_postgresql.sql

@ -1889,11 +1889,10 @@ CREATE TABLE t_ds_k8s_namespace (
limits_memory int DEFAULT NULL ,
namespace varchar(100) DEFAULT NULL ,
online_job_num int DEFAULT '0' ,
owner varchar(100) DEFAULT NULL,
user_id int DEFAULT NULL,
pod_replicas int DEFAULT NULL,
pod_request_cpu NUMERIC(13,4) NULL,
pod_request_memory int DEFAULT NULL,
tag varchar(100) DEFAULT NULL,
limits_cpu NUMERIC(13,4) NULL,
k8s varchar(100) DEFAULT NULL,
create_time timestamp DEFAULT NULL ,
@ -1902,6 +1901,22 @@ CREATE TABLE t_ds_k8s_namespace (
CONSTRAINT k8s_namespace_unique UNIQUE (namespace,k8s)
);
--
-- Table structure for table t_ds_relation_namespace_user
--
DROP TABLE IF EXISTS t_ds_relation_namespace_user;
CREATE TABLE t_ds_relation_namespace_user (
id serial NOT NULL,
user_id int DEFAULT NULL ,
namespace_id int DEFAULT NULL ,
perm int DEFAULT NULL ,
create_time timestamp DEFAULT NULL ,
update_time timestamp DEFAULT NULL ,
PRIMARY KEY (id) ,
CONSTRAINT namespace_user_unique UNIQUE (user_id,namespace_id)
);
-- ----------------------------
-- Table structure for t_ds_alert_send_status
-- ----------------------------

19
dolphinscheduler-dao/src/main/resources/sql/upgrade/2.1.0_schema/mysql/dolphinscheduler_ddl.sql

@ -199,11 +199,10 @@ CREATE TABLE `t_ds_k8s_namespace` (
`limits_memory` int(11) DEFAULT NULL,
`namespace` varchar(100) DEFAULT NULL,
`online_job_num` int(11) DEFAULT NULL,
`owner` varchar(100) DEFAULT NULL,
`user_id` int(11) DEFAULT NULL,
`pod_replicas` int(11) DEFAULT NULL,
`pod_request_cpu` decimal(14,3) DEFAULT NULL,
`pod_request_memory` int(11) DEFAULT NULL,
`tag` varchar(100) DEFAULT NULL,
`limits_cpu` decimal(14,3) DEFAULT NULL,
`k8s` varchar(100) DEFAULT NULL,
`create_time` datetime DEFAULT NULL COMMENT 'create time',
@ -211,3 +210,19 @@ CREATE TABLE `t_ds_k8s_namespace` (
PRIMARY KEY (`id`),
UNIQUE KEY `k8s_namespace_unique` (`namespace`,`k8s`)
) ENGINE= INNODB AUTO_INCREMENT= 1 DEFAULT CHARSET= utf8;
-- ----------------------------
-- Table structure for t_ds_relation_namespace_user
-- ----------------------------
DROP TABLE IF EXISTS `t_ds_relation_namespace_user`;
CREATE TABLE `t_ds_relation_namespace_user` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'key',
`user_id` int(11) NOT NULL COMMENT 'user id',
`namespace_id` int(11) DEFAULT NULL COMMENT 'namespace id',
`perm` int(11) DEFAULT '1' COMMENT 'limits of authority',
`create_time` datetime DEFAULT NULL COMMENT 'create time',
`update_time` datetime DEFAULT NULL COMMENT 'update time',
PRIMARY KEY (`id`),
KEY `user_id_index` (`user_id`),
UNIQUE KEY `namespace_user_unique` (`user_id`,`namespace_id`)
) ENGINE=InnoDB AUTO_INCREMENT= 1 DEFAULT CHARSET= utf8;

16
dolphinscheduler-dao/src/main/resources/sql/upgrade/2.1.0_schema/postgresql/dolphinscheduler_ddl.sql

@ -180,12 +180,11 @@ EXECUTE 'CREATE TABLE IF NOT EXISTS '|| quote_ident(v_schema) ||'."t_ds_k8s_name
id serial NOT NULL,
limits_memory int DEFAULT NULL ,
namespace varchar(100) DEFAULT NULL ,
online_job_num int DEFAULT ''0'' ,
owner varchar(100) DEFAULT NULL,
online_job_num int DEFAULT NULL,
user_id int DEFAULT NULL,
pod_replicas int DEFAULT NULL,
pod_request_cpu NUMERIC(13,4) NULL,
pod_request_memory int DEFAULT NULL,
tag varchar(100) DEFAULT NULL,
limits_cpu NUMERIC(13,4) NULL,
k8s varchar(100) DEFAULT NULL,
create_time timestamp DEFAULT NULL ,
@ -194,6 +193,17 @@ EXECUTE 'CREATE TABLE IF NOT EXISTS '|| quote_ident(v_schema) ||'."t_ds_k8s_name
CONSTRAINT k8s_namespace_unique UNIQUE (namespace,k8s)
)';
EXECUTE 'CREATE TABLE IF NOT EXISTS '|| quote_ident(v_schema) ||'."t_ds_relation_namespace_user" (
id serial NOT NULL,
user_id int DEFAULT NULL ,
namespace_id int DEFAULT NULL ,
perm int DEFAULT NULL ,
create_time timestamp DEFAULT NULL ,
update_time timestamp DEFAULT NULL ,
PRIMARY KEY (id) ,
CONSTRAINT namespace_user_unique UNIQUE (user_id,namespace_id)
)';
return 'Success!';
exception when others then
---Raise EXCEPTION '(%)',SQLERRM;

2
dolphinscheduler-ui-next/src/locales/modules/en_US.ts

@ -1045,8 +1045,10 @@ const security = {
udf_resource: 'UDF Resource',
datasource: 'Datasource',
udf: 'UDF Function',
namespace: 'Namespace',
authorize_project: 'Project Authorize',
authorize_resource: 'Resource Authorize',
authorize_namespace: 'Namespace Authorize',
authorize_datasource: 'Datasource Authorize',
authorize_udf: 'UDF Function Authorize',
username: 'Username',

2
dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts

@ -1032,8 +1032,10 @@ const security = {
udf_resource: 'UDF资源',
datasource: '数据源',
udf: 'UDF函数',
namespace: '命名空间',
authorize_project: '项目授权',
authorize_resource: '资源授权',
authorize_namespace: '命名空间授权',
authorize_datasource: '数据源授权',
authorize_udf: 'UDF函数授权',
username: '用户名',

17
dolphinscheduler-ui-next/src/service/modules/k8s-namespace/index.ts

@ -17,6 +17,7 @@
import { axios } from '@/service/service'
import { ListReq, K8SReq } from './types'
import { UserIdReq } from '@/service/modules/resources/types'
export function queryNamespaceListPaging(params: ListReq): any {
return axios({
@ -60,3 +61,19 @@ export function delNamespaceById(id: number): any {
params: { id }
})
}
export function authNamespaceFunc(params: UserIdReq): any {
return axios({
url: '/k8s-namespace/authed-namespace',
method: 'get',
params
})
}
export function unAuthNamespaceFunc(params: UserIdReq): any {
return axios({
url: '/k8s-namespace/unauth-namespace',
method: 'get',
params
})
}

9
dolphinscheduler-ui-next/src/service/modules/users/index.ts

@ -28,6 +28,7 @@ import {
GrantProject,
ProjectCodeReq,
GrantUDFReq,
GrantNamespaceReq,
ListAllReq,
ListReq,
RegisterUserReq
@ -120,6 +121,14 @@ export function grantUDFFunc(data: GrantUDFReq & UserIdReq) {
})
}
export function grantNamespaceFunc(data: GrantNamespaceReq & UserIdReq) {
return axios({
url: '/users/grant-namespace',
method: 'post',
data
})
}
export function listUser(): any {
return axios({
url: '/users/list',

5
dolphinscheduler-ui-next/src/service/modules/users/types.ts

@ -66,6 +66,10 @@ interface GrantUDFReq {
udfIds: string
}
interface GrantNamespaceReq {
namespaceIds: string
}
interface ListAllReq extends UserReq {
alertGroup?: string
createTime?: string
@ -127,6 +131,7 @@ export {
GrantProject,
ProjectCodeReq,
GrantUDFReq,
GrantNamespaceReq,
ListAllReq,
ListReq,
RegisterUserReq,

9
dolphinscheduler-ui-next/src/views/security/user-manage/components/authorize-modal.tsx

@ -151,6 +151,15 @@ export const AuthorizeModal = defineComponent({
/>
</NSpace>
)}
{type === 'authorize_namespace' && (
<NTransfer
virtualScroll
options={this.unauthorizedNamespaces}
filterable
v-model:value={this.authorizedNamespaces}
class={styles.transfer}
/>
)}
</Modal>
)
}

37
dolphinscheduler-ui-next/src/views/security/user-manage/components/use-authorize.ts

@ -29,11 +29,16 @@ import {
authUDFFunc,
unAuthUDFFunc
} from '@/service/modules/resources'
import {
authNamespaceFunc,
unAuthNamespaceFunc
} from '@/service/modules/k8s-namespace'
import {
grantProject,
grantResource,
grantDataSource,
grantUDFFunc
grantUDFFunc,
grantNamespaceFunc
} from '@/service/modules/users'
import { removeUselessChildren } from '@/utils/tree-format'
import type { TAuthType, IResourceOption, IOption } from '../types'
@ -48,6 +53,8 @@ export function useAuthorize() {
unauthorizedDatasources: [] as IOption[],
authorizedUdfs: [] as number[],
unauthorizedUdfs: [] as IOption[],
authorizedNamespaces: [] as number[],
unauthorizedNamespaces: [] as IOption[],
resourceType: 'file',
fileResources: [] as IResourceOption[],
udfResources: [] as IResourceOption[],
@ -139,6 +146,25 @@ export function useAuthorize() {
state.authorizedUdfResources = udfTargets
}
const getNamespaces = async (userId: number) => {
if (state.loading) return
state.loading = true
const namespaces = await Promise.all([
authNamespaceFunc({ userId }),
unAuthNamespaceFunc({ userId })
])
state.loading = false
state.authorizedNamespaces = namespaces[0].map(
(item: { id: number }) => item.id
)
state.unauthorizedNamespaces = [...namespaces[0], ...namespaces[1]].map(
(item: { namespace: string; id: number }) => ({
label: item.namespace,
value: item.id
})
)
}
const onInit = (type: TAuthType, userId: number) => {
if (type === 'authorize_project') {
getProjects(userId)
@ -152,6 +178,9 @@ export function useAuthorize() {
if (type === 'authorize_resource') {
getResources(userId)
}
if (type === 'authorize_namespace') {
getNamespaces(userId)
}
}
/*
@ -242,6 +271,12 @@ export function useAuthorize() {
resourceIds: allPathId.join(',')
})
}
if (type === 'authorize_namespace') {
await grantNamespaceFunc({
userId,
namespaceIds: state.authorizedNamespaces.join(',')
})
}
state.saving = false
return true
}

1
dolphinscheduler-ui-next/src/views/security/user-manage/types.ts

@ -27,6 +27,7 @@ type TAuthType =
| 'authorize_resource'
| 'authorize_datasource'
| 'authorize_udf'
| 'authorize_namespace'
interface IRecord {
id: number

6
dolphinscheduler-ui-next/src/views/security/user-manage/use-columns.ts

@ -137,7 +137,11 @@ export function useColumns(onCallback: Function) {
label: t('security.user.datasource'),
key: 'authorize_datasource'
},
{ label: t('security.user.udf'), key: 'authorize_udf' }
{ label: t('security.user.udf'), key: 'authorize_udf' },
{
label: t('security.user.namespace'),
key: 'authorize_namespace'
}
],
onSelect: (key) =>
void onCallback({ rowData, key }, 'authorize')

23
dolphinscheduler-ui/src/js/conf/home/pages/security/pages/namespace/_source/createNamespace.vue

@ -48,18 +48,6 @@
</el-input>
</template>
</m-list-box-f>
<m-list-box-f>
<template slot="name">{{$t('K8s Tag')}}</template>
<template slot="content">
<el-input
type="input"
v-model="tag"
maxlength="60"
size="mini"
:placeholder="$t('Please enter k8s cluster')">
</el-input>
</template>
</m-list-box-f>
<m-list-box-f>
<template slot="name">{{$t('Limits Cpu')}}</template>
@ -90,7 +78,7 @@
<template slot="content">
<el-input
type="input"
v-model="owner"
v-model="userName"
maxlength="60"
size="mini"
:placeholder="$t('Please enter owner')">
@ -116,8 +104,7 @@
store,
namespace: '',
k8s: '',
owner: '',
tag: '',
userName: '',
limitsCpu: '',
limitsMemory: ''
}
@ -134,8 +121,7 @@
let param = {
namespace: _.trim(this.namespace),
k8s: _.trim(this.k8s),
owner: _.trim(this.owner),
tag: _.trim(this.tag),
userName: _.trim(this.userName),
limitsCpu: _.trim(this.limitsCpu),
limitsMemory: _.trim(this.limitsMemory)
}
@ -205,8 +191,7 @@
if (this.item) {
this.namespace = this.item.namespace
this.k8s = this.item.k8s
this.owner = this.item.owner
this.tag = this.item.tag
this.userName = this.item.userName
this.limitsCpu = this.item.limitsCpu
this.limitsMemory = this.item.limitsMemory
}

2
dolphinscheduler-ui/src/js/conf/home/pages/security/pages/namespace/_source/list.vue

@ -21,8 +21,6 @@
<el-table-column type="index" :label="$t('#')" width="50"></el-table-column>
<el-table-column prop="namespace" :label="$t('K8s Namespace')"></el-table-column>
<el-table-column prop="k8s" :label="$t('K8s Cluster')"></el-table-column>
<el-table-column prop="owner" :label="$t('Namespace Owner')"></el-table-column>
<el-table-column prop="tag" :label="$t('K8s Tag')"></el-table-column>
<el-table-column prop="limitsCpu" :label="$t('Limits Cpu')"></el-table-column>
<el-table-column prop="limitsMemory" :label="$t('Limits Memory')"></el-table-column>

52
dolphinscheduler-ui/src/js/conf/home/pages/security/pages/users/_source/list.vue

@ -58,6 +58,7 @@
<el-dropdown-item @click.native="_authFile(scope.row,scope.$index)">{{$t('Resources')}}</el-dropdown-item>
<el-dropdown-item @click.native="_authDataSource(scope.row,scope.$index)">{{$t('Datasource')}}</el-dropdown-item>
<el-dropdown-item @click.native="_authUdfFunc(scope.row,scope.$index)">{{$t('UDF Function')}}</el-dropdown-item>
<el-dropdown-item @click.native="_authNamespace(scope.row,scope.$index)">{{$t('K8s Namespace')}}</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</el-tooltip>
@ -107,6 +108,13 @@
width="auto">
<m-resource :resourceData="resourceData" @onUpdateAuthResource="onUpdateAuthResource" @closeAuthResource="closeAuthResource"></m-resource>
</el-dialog>
<el-dialog
v-if="authNamespaceDialog"
:visible.sync="authNamespaceDialog"
width="auto">
<m-transfer :transferData="transferData" @onUpdateAuthNamespace="onUpdateAuthNamespace" @closeAuthNamespace="closeAuthNamespace"></m-transfer>
</el-dialog>
</div>
</template>
<script>
@ -141,7 +149,8 @@
name: ''
}
},
resourceDialog: false
resourceDialog: false,
authNamespaceDialog: false
}
},
props: {
@ -348,6 +357,35 @@
this.$message.error(e.msg || '')
})
},
_authNamespace (item, i) {
this.getAuthList({
id: item.id,
type: 'namespace',
category: 'k8s-namespace'
}).then(data => {
let sourceListPrs = _.map(data[0], v => {
return {
id: v.id,
name: v.namespace
}
})
let targetListPrs = _.map(data[1], v => {
return {
id: v.id,
name: v.namespace
}
})
this.item = item
this.transferData.sourceListPrs = sourceListPrs
this.transferData.targetListPrs = targetListPrs
this.transferData.type.name = i18n.$t('K8s Namespace')
this.authNamespaceDialog = true
}).catch(e => {
this.$message.error(e.msg || '')
})
},
onUpdateAuthUdfFunc (udfIds) {
this._grantAuthorization('users/grant-udf-func', {
userId: this.item.id,
@ -360,6 +398,18 @@
this.authUdfFuncDialog = false
},
onUpdateAuthNamespace (namespaceIds) {
this._grantAuthorization('users/grant-namespace', {
userId: this.item.id,
namespaceIds: namespaceIds
})
this.authNamespaceDialog = false
},
closeAuthNamespace () {
this.authNamespaceDialog = false
},
_grantAuthorization (api, param) {
this.grantAuthorization({
api: api,

2
dolphinscheduler-ui/src/js/module/components/transfer/transfer.vue

@ -81,6 +81,8 @@
this.$emit('onUpdateAuthDataSource', _.map(this.targetList, v => v.id).join(','))
} else if (this.transferData.type.name === `${i18n.$t('UDF Function')}`) {
this.$emit('onUpdateAuthUdfFunc', _.map(this.targetList, v => v.id).join(','))
} else if (this.transferData.type.name === `${i18n.$t('K8s Namespace')}`) {
this.$emit('onUpdateAuthNamespace', _.map(this.targetList, v => v.id).join(','))
}
}, 800)
},

7
dolphinscheduler-ui/src/js/module/i18n/locale/en_US.js

@ -906,14 +906,13 @@ export default {
'Create namespace': 'Create namespace',
'Edit namespace': 'Edit namespace',
'Namespace manage': 'K8s namespace manage',
'K8s Namespace': 'k8s Namespace',
'K8s Namespace': 'K8s Namespace',
'Limits Cpu': 'Limit Cpu',
'Limits Memory': 'Limit Memory',
'K8s Cluster': 'k8s',
'K8s Cluster': 'k8s Cluster',
'Namespace Owner': 'Owner',
'Please enter k8s cluster': 'Please enter k8s cluster',
'Please enter namespace': 'Please enter namespace',
'Please enter namespace tag': 'Please enter namespace tag can null',
'Please enter owner': 'Please enter owner can null',
'K8s Tag': 'tag'
'Please enter owner': 'Please enter owner can null'
}

3
dolphinscheduler-ui/src/js/module/i18n/locale/zh_CN.js

@ -914,6 +914,5 @@ export default {
'Please enter k8s cluster': '请输入k8s集群值',
'Please enter namespace': '请输入命名空间',
'Please enter namespace tag': '请输入命名空间标签可空',
'Please enter owner': '请输入owner可空',
'K8s Tag': '标签'
'Please enter owner': '请输入owner可空'
}

Loading…
Cancel
Save