Browse Source

[Feature-10629][Improvement] Support multi cluster environments - namespace use cluster (#10650)

* server code

* namespace ui

* fix dao test

* fix test

* fix

* docs and image update

Co-authored-by: qianl4 <qianl4@cicso.com>
3.1.0-release
qianli2022 2 years ago committed by GitHub
parent
commit
1e48bbc5c6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      docs/docs/en/guide/security.md
  2. 2
      docs/docs/zh/guide/security.md
  3. BIN
      docs/img/new_ui/dev/security/create-namespace.png
  4. 62
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/K8sNamespaceController.java
  5. 1
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/enums/Status.java
  6. 27
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/k8s/K8sClientService.java
  7. 88
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/k8s/K8sManager.java
  8. 13
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/K8sNamespaceService.java
  9. 29
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/ClusterServiceImpl.java
  10. 100
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/K8SNamespaceServiceImpl.java
  11. 2
      dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/ClusterControllerTest.java
  12. 14
      dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/K8sNamespaceControllerTest.java
  13. 34
      dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/k8s/K8sManagerTest.java
  14. 5
      dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/ClusterServiceTest.java
  15. 55
      dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/K8SNamespaceServiceTest.java
  16. 4
      dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/Constants.java
  17. 47
      dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/K8sNamespace.java
  18. 14
      dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/K8sNamespaceMapper.java
  19. 26
      dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/K8sNamespaceMapper.xml
  20. 21
      dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_h2.sql
  21. 6
      dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_mysql.sql
  22. 7
      dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_postgresql.sql
  23. 6
      dolphinscheduler-dao/src/main/resources/sql/upgrade/3.0.0_schema/mysql/dolphinscheduler_ddl.sql
  24. 6
      dolphinscheduler-dao/src/main/resources/sql/upgrade/3.0.0_schema/postgresql/dolphinscheduler_ddl.sql
  25. 6
      dolphinscheduler-dao/src/test/java/org/apache/dolphinscheduler/dao/mapper/K8sNamespaceMapperTest.java
  26. 2
      dolphinscheduler-ui/src/locales/en_US/security.ts
  27. 2
      dolphinscheduler-ui/src/locales/zh_CN/security.ts
  28. 2
      dolphinscheduler-ui/src/service/modules/k8s-namespace/types.ts
  29. 213
      dolphinscheduler-ui/src/views/security/k8s-namespace-manage/components/k8s-namespace-modal.tsx
  30. 54
      dolphinscheduler-ui/src/views/security/k8s-namespace-manage/components/use-modal.ts
  31. 145
      dolphinscheduler-ui/src/views/security/k8s-namespace-manage/use-table.ts

2
docs/docs/en/guide/security.md

@ -162,7 +162,7 @@ worker.groups=default,test
> Add or update k8s cluster > Add or update k8s cluster
- First enter the configuration of the k8s cluster connection into the table `t_ds_k8s` in the database, which will be configured later by the web page. - First enter the configuration of the k8s cluster connection into the table `t_ds_k8s` in the database for batch job and will removed later, the creation of the namespace now selects the cluster by drop-down options.
> Add or update namespace > Add or update namespace

2
docs/docs/zh/guide/security.md

@ -165,7 +165,7 @@ worker.groups=default,test
> 创建/更新 k8s集群 > 创建/更新 k8s集群
- 先把k8s集群连接的配置录入 database 的表 `t_ds_k8s`,后续会通过页面配置. - 先把k8s集群连接的配置录入 database 的表 `t_ds_k8s`给批次使用后续移除,namespace的创建现在通过下拉选择集群.
> 创建/更新 namespace > 创建/更新 namespace

BIN
docs/img/new_ui/dev/security/create-namespace.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 700 KiB

After

Width:  |  Height:  |  Size: 753 KiB

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

@ -20,7 +20,7 @@ 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.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.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_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_CAN_USE_K8S_NAMESPACE_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.QUERY_K8S_NAMESPACE_LIST_PAGING_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.QUERY_UNAUTHORIZED_NAMESPACE_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.UPDATE_K8S_NAMESPACE_ERROR; import static org.apache.dolphinscheduler.api.enums.Status.UPDATE_K8S_NAMESPACE_ERROR;
@ -78,18 +78,18 @@ public class K8sNamespaceController extends BaseController {
*/ */
@ApiOperation(value = "queryNamespaceListPaging", notes = "QUERY_NAMESPACE_LIST_PAGING_NOTES") @ApiOperation(value = "queryNamespaceListPaging", notes = "QUERY_NAMESPACE_LIST_PAGING_NOTES")
@ApiImplicitParams({ @ApiImplicitParams({
@ApiImplicitParam(name = "searchVal", value = "SEARCH_VAL", dataType = "String"), @ApiImplicitParam(name = "searchVal", value = "SEARCH_VAL", dataType = "String"),
@ApiImplicitParam(name = "pageSize", value = "PAGE_SIZE", required = true, dataType = "Int", example = "10"), @ApiImplicitParam(name = "pageSize", value = "PAGE_SIZE", required = true, dataType = "Int", example = "10"),
@ApiImplicitParam(name = "pageNo", value = "PAGE_NO", required = true, dataType = "Int", example = "1") @ApiImplicitParam(name = "pageNo", value = "PAGE_NO", required = true, dataType = "Int", example = "1")
}) })
@GetMapping() @GetMapping()
@ResponseStatus(HttpStatus.OK) @ResponseStatus(HttpStatus.OK)
@ApiException(QUERY_K8S_NAMESPACE_LIST_PAGING_ERROR) @ApiException(QUERY_K8S_NAMESPACE_LIST_PAGING_ERROR)
@AccessLogAnnotation(ignoreRequestArgs = "loginUser") @AccessLogAnnotation(ignoreRequestArgs = "loginUser")
public Result queryProjectListPaging(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser, public Result queryNamespaceListPaging(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
@RequestParam(value = "searchVal", required = false) String searchVal, @RequestParam(value = "searchVal", required = false) String searchVal,
@RequestParam("pageSize") Integer pageSize, @RequestParam("pageSize") Integer pageSize,
@RequestParam("pageNo") Integer pageNo @RequestParam("pageNo") Integer pageNo
) { ) {
Result result = checkPageParams(pageNo, pageSize); Result result = checkPageParams(pageNo, pageSize);
@ -107,17 +107,17 @@ public class K8sNamespaceController extends BaseController {
* *
* @param loginUser * @param loginUser
* @param namespace k8s namespace * @param namespace k8s namespace
* @param k8s k8s name * @param clusterCode clusterCode
* @param limitsCpu max cpu * @param limitsCpu max cpu
* @param limitsMemory max memory * @param limitsMemory max memory
* @return * @return
*/ */
@ApiOperation(value = "createK8sNamespace", notes = "CREATE_NAMESPACE_NOTES") @ApiOperation(value = "createK8sNamespace", notes = "CREATE_NAMESPACE_NOTES")
@ApiImplicitParams({ @ApiImplicitParams({
@ApiImplicitParam(name = "namespace", value = "NAMESPACE", required = true, dataType = "String"), @ApiImplicitParam(name = "namespace", value = "NAMESPACE", required = true, dataType = "String"),
@ApiImplicitParam(name = "k8s", value = "K8S", required = true, dataType = "String"), @ApiImplicitParam(name = "clusterCode", value = "CLUSTER_CODE", required = true, dataType = "Long"),
@ApiImplicitParam(name = "limits_cpu", value = "LIMITS_CPU", required = false, dataType = "Double"), @ApiImplicitParam(name = "limits_cpu", value = "LIMITS_CPU", required = false, dataType = "Double"),
@ApiImplicitParam(name = "limits_memory", value = "LIMITS_MEMORY", required = false, dataType = "Integer") @ApiImplicitParam(name = "limits_memory", value = "LIMITS_MEMORY", required = false, dataType = "Integer")
}) })
@PostMapping() @PostMapping()
@ResponseStatus(HttpStatus.CREATED) @ResponseStatus(HttpStatus.CREATED)
@ -125,11 +125,11 @@ public class K8sNamespaceController extends BaseController {
@AccessLogAnnotation(ignoreRequestArgs = "loginUser") @AccessLogAnnotation(ignoreRequestArgs = "loginUser")
public Result createNamespace(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser, public Result createNamespace(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
@RequestParam(value = "namespace") String namespace, @RequestParam(value = "namespace") String namespace,
@RequestParam(value = "k8s") String k8s, @RequestParam(value = "clusterCode") Long clusterCode,
@RequestParam(value = "limitsCpu", required = false) Double limitsCpu, @RequestParam(value = "limitsCpu", required = false) Double limitsCpu,
@RequestParam(value = "limitsMemory", required = false) Integer limitsMemory @RequestParam(value = "limitsMemory", required = false) Integer limitsMemory
) { ) {
Map<String, Object> result = k8sNamespaceService.createK8sNamespace(loginUser, namespace, k8s, limitsCpu, limitsMemory); Map<String, Object> result = k8sNamespaceService.createK8sNamespace(loginUser, namespace, clusterCode, limitsCpu, limitsMemory);
return returnDataList(result); return returnDataList(result);
} }
@ -137,17 +137,17 @@ public class K8sNamespaceController extends BaseController {
* update namespace,namespace and k8s not allowed update, because may create on k8s,can delete and create new instead * update namespace,namespace and k8s not allowed update, because may create on k8s,can delete and create new instead
* *
* @param loginUser * @param loginUser
* @param userName owner * @param userName owner
* @param limitsCpu max cpu * @param limitsCpu max cpu
* @param limitsMemory max memory * @param limitsMemory max memory
* @return * @return
*/ */
@ApiOperation(value = "updateK8sNamespace", notes = "UPDATE_NAMESPACE_NOTES") @ApiOperation(value = "updateK8sNamespace", notes = "UPDATE_NAMESPACE_NOTES")
@ApiImplicitParams({ @ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "K8S_NAMESPACE_ID", required = true, dataType = "Int", example = "100"), @ApiImplicitParam(name = "id", value = "K8S_NAMESPACE_ID", required = true, dataType = "Int", example = "100"),
@ApiImplicitParam(name = "userName", value = "OWNER", 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 = "limitsCpu", value = "LIMITS_CPU", required = false, dataType = "Double"),
@ApiImplicitParam(name = "limitsMemory", value = "LIMITS_MEMORY", required = false, dataType = "Integer")}) @ApiImplicitParam(name = "limitsMemory", value = "LIMITS_MEMORY", required = false, dataType = "Integer")})
@PutMapping(value = "/{id}") @PutMapping(value = "/{id}")
@ResponseStatus(HttpStatus.CREATED) @ResponseStatus(HttpStatus.CREATED)
@ApiException(UPDATE_K8S_NAMESPACE_ERROR) @ApiException(UPDATE_K8S_NAMESPACE_ERROR)
@ -165,15 +165,15 @@ public class K8sNamespaceController extends BaseController {
/** /**
* verify namespace and k8s,one k8s namespace is unique * verify namespace and k8s,one k8s namespace is unique
* *
* @param loginUser login user * @param loginUser login user
* @param namespace namespace * @param namespace namespace
* @param k8s k8s * @param clusterCode cluster code
* @return true if the k8s and namespace not exists, otherwise return false * @return true if the k8s and namespace not exists, otherwise return false
*/ */
@ApiOperation(value = "verifyNamespaceK8s", notes = "VERIFY_NAMESPACE_K8S_NOTES") @ApiOperation(value = "verifyNamespaceK8s", notes = "VERIFY_NAMESPACE_K8S_NOTES")
@ApiImplicitParams({ @ApiImplicitParams({
@ApiImplicitParam(name = "namespace", value = "NAMESPACE", required = true, dataType = "String"), @ApiImplicitParam(name = "namespace", value = "NAMESPACE", required = true, dataType = "String"),
@ApiImplicitParam(name = "k8s", value = "K8S", required = true, dataType = "String") @ApiImplicitParam(name = "clusterCode", value = "CLUSTER_CODE", required = true, dataType = "Long"),
}) })
@PostMapping(value = "/verify") @PostMapping(value = "/verify")
@ResponseStatus(HttpStatus.OK) @ResponseStatus(HttpStatus.OK)
@ -181,10 +181,10 @@ public class K8sNamespaceController extends BaseController {
@AccessLogAnnotation(ignoreRequestArgs = "loginUser") @AccessLogAnnotation(ignoreRequestArgs = "loginUser")
public Result verifyNamespace(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser, public Result verifyNamespace(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
@RequestParam(value = "namespace") String namespace, @RequestParam(value = "namespace") String namespace,
@RequestParam(value = "k8s") String k8s @RequestParam(value = "clusterCode") Long clusterCode
) { ) {
return k8sNamespaceService.verifyNamespaceK8s(namespace, k8s); return k8sNamespaceService.verifyNamespaceK8s(namespace, clusterCode);
} }
@ -197,7 +197,7 @@ public class K8sNamespaceController extends BaseController {
*/ */
@ApiOperation(value = "delNamespaceById", notes = "DELETE_NAMESPACE_BY_ID_NOTES") @ApiOperation(value = "delNamespaceById", notes = "DELETE_NAMESPACE_BY_ID_NOTES")
@ApiImplicitParams({ @ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "NAMESPACE_ID", required = true, dataType = "Int", example = "100") @ApiImplicitParam(name = "id", value = "NAMESPACE_ID", required = true, dataType = "Int", example = "100")
}) })
@PostMapping(value = "/delete") @PostMapping(value = "/delete")
@ResponseStatus(HttpStatus.OK) @ResponseStatus(HttpStatus.OK)
@ -213,7 +213,7 @@ public class K8sNamespaceController extends BaseController {
* query unauthorized namespace * query unauthorized namespace
* *
* @param loginUser login user * @param loginUser login user
* @param userId user id * @param userId user id
* @return the namespaces which user have not permission to see * @return the namespaces which user have not permission to see
*/ */
@ApiOperation(value = "queryUnauthorizedNamespace", notes = "QUERY_UNAUTHORIZED_NAMESPACE_NOTES") @ApiOperation(value = "queryUnauthorizedNamespace", notes = "QUERY_UNAUTHORIZED_NAMESPACE_NOTES")
@ -234,7 +234,7 @@ public class K8sNamespaceController extends BaseController {
* query unauthorized namespace * query unauthorized namespace
* *
* @param loginUser login user * @param loginUser login user
* @param userId user id * @param userId user id
* @return namespaces which the user have permission to see * @return namespaces which the user have permission to see
*/ */
@ApiOperation(value = "queryAuthorizedNamespace", notes = "QUERY_AUTHORIZED_NAMESPACE_NOTES") @ApiOperation(value = "queryAuthorizedNamespace", notes = "QUERY_AUTHORIZED_NAMESPACE_NOTES")
@ -260,7 +260,7 @@ public class K8sNamespaceController extends BaseController {
@ApiOperation(value = "queryAvailableNamespaceList", notes = "QUERY_AVAILABLE_NAMESPACE_LIST_NOTES") @ApiOperation(value = "queryAvailableNamespaceList", notes = "QUERY_AVAILABLE_NAMESPACE_LIST_NOTES")
@GetMapping(value = "/available-list") @GetMapping(value = "/available-list")
@ResponseStatus(HttpStatus.OK) @ResponseStatus(HttpStatus.OK)
@ApiException(QUERY_CAN_USE_K8S_CLUSTER_ERROR) @ApiException(QUERY_CAN_USE_K8S_NAMESPACE_ERROR)
@AccessLogAnnotation(ignoreRequestArgs = "loginUser") @AccessLogAnnotation(ignoreRequestArgs = "loginUser")
public Result queryAvailableNamespaceList(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser) { public Result queryAvailableNamespaceList(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser) {
List<K8sNamespace> result = k8sNamespaceService.queryNamespaceAvailable(loginUser); List<K8sNamespace> result = k8sNamespaceService.queryNamespaceAvailable(loginUser);

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

@ -423,6 +423,7 @@ public enum Status {
RESOURCE_FULL_NAME_TOO_LONG_ERROR(1300015, "resource's fullname is too long error", "资源文件名过长"), RESOURCE_FULL_NAME_TOO_LONG_ERROR(1300015, "resource's fullname is too long error", "资源文件名过长"),
TENANT_FULL_NAME_TOO_LONG_ERROR(1300016, "tenant's fullname is too long error", "租户名过长"), TENANT_FULL_NAME_TOO_LONG_ERROR(1300016, "tenant's fullname is too long error", "租户名过长"),
USER_PASSWORD_LENGTH_ERROR(1300017, "user's password length error", "用户密码长度错误"), USER_PASSWORD_LENGTH_ERROR(1300017, "user's password length error", "用户密码长度错误"),
QUERY_CAN_USE_K8S_NAMESPACE_ERROR(1300018, "login user query can used namespace list error", "查询可用命名空间错误"),
NO_CURRENT_OPERATING_PERMISSION(1400001, "The current user does not have this permission.", "当前用户无此权限"), NO_CURRENT_OPERATING_PERMISSION(1400001, "The current user does not have this permission.", "当前用户无此权限"),
FUNCTION_DISABLED(1400002, "The current feature is disabled.", "当前功能已被禁用"), FUNCTION_DISABLED(1400002, "The current feature is disabled.", "当前功能已被禁用"),

27
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/k8s/K8sClientService.java

@ -18,6 +18,7 @@
package org.apache.dolphinscheduler.api.k8s; package org.apache.dolphinscheduler.api.k8s;
import org.apache.dolphinscheduler.dao.entity.K8sNamespace; import org.apache.dolphinscheduler.dao.entity.K8sNamespace;
import org.apache.dolphinscheduler.remote.exceptions.RemotingException;
import java.util.Optional; import java.util.Optional;
@ -41,15 +42,15 @@ public class K8sClientService {
@Autowired @Autowired
private K8sManager k8sManager; private K8sManager k8sManager;
public ResourceQuota upsertNamespaceAndResourceToK8s(K8sNamespace k8sNamespace, String yamlStr) { public ResourceQuota upsertNamespaceAndResourceToK8s(K8sNamespace k8sNamespace, String yamlStr) throws RemotingException {
upsertNamespaceToK8s(k8sNamespace.getNamespace(), k8sNamespace.getK8s()); upsertNamespaceToK8s(k8sNamespace.getNamespace(), k8sNamespace.getClusterCode());
return upsertNamespacedResourceToK8s(k8sNamespace, yamlStr); return upsertNamespacedResourceToK8s(k8sNamespace, yamlStr);
} }
public Optional<Namespace> deleteNamespaceToK8s(String name, String k8s) { public Optional<Namespace> deleteNamespaceToK8s(String name, Long clusterCode) throws RemotingException {
Optional<Namespace> result = getNamespaceFromK8s(name, k8s); Optional<Namespace> result = getNamespaceFromK8s(name, clusterCode);
if (result.isPresent()) { if (result.isPresent()) {
KubernetesClient client = k8sManager.getK8sClient(k8s); KubernetesClient client = k8sManager.getK8sClient(clusterCode);
Namespace body = new Namespace(); Namespace body = new Namespace();
ObjectMeta meta = new ObjectMeta(); ObjectMeta meta = new ObjectMeta();
meta.setNamespace(name); meta.setNamespace(name);
@ -57,12 +58,12 @@ public class K8sClientService {
body.setMetadata(meta); body.setMetadata(meta);
client.namespaces().delete(body); client.namespaces().delete(body);
} }
return getNamespaceFromK8s(name, k8s); return getNamespaceFromK8s(name, clusterCode);
} }
private ResourceQuota upsertNamespacedResourceToK8s(K8sNamespace k8sNamespace, String yamlStr) { private ResourceQuota upsertNamespacedResourceToK8s(K8sNamespace k8sNamespace, String yamlStr) throws RemotingException {
KubernetesClient client = k8sManager.getK8sClient(k8sNamespace.getK8s()); KubernetesClient client = k8sManager.getK8sClient(k8sNamespace.getClusterCode());
//创建资源 //创建资源
ResourceQuota queryExist = client.resourceQuotas() ResourceQuota queryExist = client.resourceQuotas()
@ -86,9 +87,9 @@ public class K8sClientService {
.createOrReplace(body); .createOrReplace(body);
} }
private Optional<Namespace> getNamespaceFromK8s(String name, String k8s) { private Optional<Namespace> getNamespaceFromK8s(String name, Long clusterCode) throws RemotingException {
NamespaceList listNamespace = NamespaceList listNamespace =
k8sManager.getK8sClient(k8s).namespaces().list(); k8sManager.getK8sClient(clusterCode).namespaces().list();
Optional<Namespace> list = Optional<Namespace> list =
listNamespace.getItems().stream() listNamespace.getItems().stream()
@ -99,11 +100,11 @@ public class K8sClientService {
return list; return list;
} }
private Namespace upsertNamespaceToK8s(String name, String k8s) { private Namespace upsertNamespaceToK8s(String name, Long clusterCode) throws RemotingException {
Optional<Namespace> result = getNamespaceFromK8s(name, k8s); Optional<Namespace> result = getNamespaceFromK8s(name, clusterCode);
//if not exist create //if not exist create
if (!result.isPresent()) { if (!result.isPresent()) {
KubernetesClient client = k8sManager.getK8sClient(k8s); KubernetesClient client = k8sManager.getK8sClient(clusterCode);
Namespace body = new Namespace(); Namespace body = new Namespace();
ObjectMeta meta = new ObjectMeta(); ObjectMeta meta = new ObjectMeta();
meta.setNamespace(name); meta.setNamespace(name);

88
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/k8s/K8sManager.java

@ -17,29 +17,25 @@
package org.apache.dolphinscheduler.api.k8s; package org.apache.dolphinscheduler.api.k8s;
import org.apache.dolphinscheduler.dao.entity.K8s; import org.apache.dolphinscheduler.common.utils.ClusterConfUtils;
import org.apache.dolphinscheduler.dao.mapper.K8sMapper; import org.apache.dolphinscheduler.dao.entity.Cluster;
import org.apache.dolphinscheduler.dao.mapper.ClusterMapper;
import org.apache.dolphinscheduler.remote.exceptions.RemotingException; import org.apache.dolphinscheduler.remote.exceptions.RemotingException;
import java.util.Hashtable; import java.util.Hashtable;
import java.util.List;
import java.util.Map; import java.util.Map;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import io.fabric8.kubernetes.client.Config; import io.fabric8.kubernetes.client.Config;
import io.fabric8.kubernetes.client.DefaultKubernetesClient; import io.fabric8.kubernetes.client.DefaultKubernetesClient;
import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.client.KubernetesClient;
/** /**
* A separate class, because then wait for multiple environment feature, currently using db configuration, later unified * use multiple environment feature
*/ */
@Component @Component
public class K8sManager { public class K8sManager {
@ -48,27 +44,76 @@ public class K8sManager {
/** /**
* cache k8s client * cache k8s client
*/ */
private static Map<String, KubernetesClient> clientMap = new Hashtable<>(); private static Map<Long, KubernetesClient> clientMap = new Hashtable<>();
@Autowired @Autowired
private K8sMapper k8sMapper; private ClusterMapper clusterMapper;
public KubernetesClient getK8sClient(String k8sName) { /**
if (null == k8sName) { * get k8s client for api use
*
* @param clusterCode
* @return
*/
public synchronized KubernetesClient getK8sClient(Long clusterCode) throws RemotingException {
if (null == clusterCode) {
return null; return null;
} }
return clientMap.get(k8sName);
return getAndUpdateK8sClient(clusterCode, false);
}
/**
* @param clusterCode
* @return new client if need updated
*/
public synchronized KubernetesClient getAndUpdateK8sClient(Long clusterCode, boolean update) throws RemotingException {
if (null == clusterCode) {
return null;
}
if (update) {
deleteK8sClientInner(clusterCode);
}
if (clientMap.containsKey(clusterCode)) {
return clientMap.get(clusterCode);
} else {
createK8sClientInner(clusterCode);
}
return clientMap.get(clusterCode);
} }
@EventListener
public void buildApiClientAll(ApplicationReadyEvent readyEvent) throws RemotingException {
QueryWrapper<K8s> nodeWrapper = new QueryWrapper<>();
List<K8s> k8sList = k8sMapper.selectList(nodeWrapper);
if (k8sList != null) { private void deleteK8sClientInner(Long clusterCode) {
for (K8s k8s : k8sList) { if (clusterCode == null) {
DefaultKubernetesClient client = getClient(k8s.getK8sConfig()); return;
clientMap.put(k8s.getK8sName(), client); }
Cluster cluster = clusterMapper.queryByClusterCode(clusterCode);
if (cluster == null) {
return;
}
KubernetesClient client = clientMap.get(clusterCode);
if (client != null) {
client.close();
}
}
private void createK8sClientInner(Long clusterCode) throws RemotingException {
Cluster cluster = clusterMapper.queryByClusterCode(clusterCode);
if (cluster == null) {
return;
}
String k8sConfig = ClusterConfUtils.getK8sConfig(cluster.getConfig());
if (k8sConfig != null) {
DefaultKubernetesClient client = null;
try {
client = getClient(k8sConfig);
clientMap.put(clusterCode, client);
} catch (RemotingException e) {
logger.error("cluster code ={},fail to get k8s ApiClient: {}", clusterCode, e.getMessage());
throw new RemotingException("fail to get k8s ApiClient:" + e.getMessage());
} }
} }
} }
@ -82,4 +127,5 @@ public class K8sManager {
throw new RemotingException("fail to get k8s ApiClient:" + e.getMessage()); throw new RemotingException("fail to get k8s ApiClient:" + e.getMessage());
} }
} }
} }

13
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/K8sNamespaceService.java

@ -28,6 +28,7 @@ import java.util.Map;
* k8s namespace service impl * k8s namespace service impl
*/ */
public interface K8sNamespaceService { public interface K8sNamespaceService {
/** /**
* query namespace list paging * query namespace list paging
* *
@ -39,19 +40,17 @@ public interface K8sNamespaceService {
*/ */
Result queryListPaging(User loginUser, String searchVal, Integer pageNo, Integer pageSize); Result queryListPaging(User loginUser, String searchVal, Integer pageNo, Integer pageSize);
/** /**
* create namespace,if not exist on k8s,will create,if exist only register in db * create namespace,if not exist on k8s,will create,if exist only register in db
* *
* @param loginUser login user * @param loginUser login user
* @param namespace namespace * @param namespace namespace
* @param k8s k8s not null * @param clusterCode k8s not null
* @param limitsCpu limits cpu, can null means not limit * @param limitsCpu limits cpu, can null means not limit
* @param limitsMemory limits memory, can null means not limit * @param limitsMemory limits memory, can null means not limit
* @return * @return
*/ */
Map<String, Object> createK8sNamespace(User loginUser, String namespace, String k8s, Double limitsCpu, Integer limitsMemory); Map<String, Object> createK8sNamespace(User loginUser, String namespace, Long clusterCode, Double limitsCpu, Integer limitsMemory);
/** /**
* update K8s Namespace tag and resource limit * update K8s Namespace tag and resource limit
@ -67,11 +66,11 @@ public interface K8sNamespaceService {
/** /**
* verify namespace and k8s * verify namespace and k8s
* *
* @param namespace namespace * @param namespace namespace
* @param k8s k8s * @param clusterCode cluster code
* @return true if the k8s and namespace not exists, otherwise return false * @return true if the k8s and namespace not exists, otherwise return false
*/ */
Result<Object> verifyNamespaceK8s(String namespace, String k8s); Result<Object> verifyNamespaceK8s(String namespace, Long clusterCode);
/** /**
* delete namespace by id * delete namespace by id

29
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/ClusterServiceImpl.java

@ -19,15 +19,20 @@ package org.apache.dolphinscheduler.api.service.impl;
import org.apache.dolphinscheduler.api.dto.ClusterDto; import org.apache.dolphinscheduler.api.dto.ClusterDto;
import org.apache.dolphinscheduler.api.enums.Status; import org.apache.dolphinscheduler.api.enums.Status;
import org.apache.dolphinscheduler.api.k8s.K8sManager;
import org.apache.dolphinscheduler.api.service.ClusterService; import org.apache.dolphinscheduler.api.service.ClusterService;
import org.apache.dolphinscheduler.api.utils.PageInfo; import org.apache.dolphinscheduler.api.utils.PageInfo;
import org.apache.dolphinscheduler.api.utils.Result; import org.apache.dolphinscheduler.api.utils.Result;
import org.apache.dolphinscheduler.common.Constants; import org.apache.dolphinscheduler.common.Constants;
import org.apache.dolphinscheduler.common.utils.ClusterConfUtils;
import org.apache.dolphinscheduler.common.utils.CodeGenerateUtils; import org.apache.dolphinscheduler.common.utils.CodeGenerateUtils;
import org.apache.dolphinscheduler.common.utils.CodeGenerateUtils.CodeGenerateException; import org.apache.dolphinscheduler.common.utils.CodeGenerateUtils.CodeGenerateException;
import org.apache.dolphinscheduler.dao.entity.Cluster; import org.apache.dolphinscheduler.dao.entity.Cluster;
import org.apache.dolphinscheduler.dao.entity.K8sNamespace;
import org.apache.dolphinscheduler.dao.entity.User; import org.apache.dolphinscheduler.dao.entity.User;
import org.apache.dolphinscheduler.dao.mapper.ClusterMapper; import org.apache.dolphinscheduler.dao.mapper.ClusterMapper;
import org.apache.dolphinscheduler.dao.mapper.K8sNamespaceMapper;
import org.apache.dolphinscheduler.remote.exceptions.RemotingException;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
@ -46,6 +51,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@ -60,6 +66,11 @@ public class ClusterServiceImpl extends BaseServiceImpl implements ClusterServic
@Autowired @Autowired
private ClusterMapper clusterMapper; private ClusterMapper clusterMapper;
@Autowired
private K8sManager k8sManager;
@Autowired
private K8sNamespaceMapper k8sNamespaceMapper;
/** /**
* create cluster * create cluster
* *
@ -237,6 +248,14 @@ public class ClusterServiceImpl extends BaseServiceImpl implements ClusterServic
return result; return result;
} }
Integer relatedNamespaceNumber = k8sNamespaceMapper
.selectCount(new QueryWrapper<K8sNamespace>().lambda().eq(K8sNamespace::getClusterCode, code));
if (relatedNamespaceNumber > 0) {
putMsg(result, Status.DELETE_CLUSTER_RELATED_NAMESPACE_EXISTS);
return result;
}
int delete = clusterMapper.deleteByCode(code); int delete = clusterMapper.deleteByCode(code);
if (delete > 0) { if (delete > 0) {
putMsg(result, Status.SUCCESS); putMsg(result, Status.SUCCESS);
@ -281,6 +300,16 @@ public class ClusterServiceImpl extends BaseServiceImpl implements ClusterServic
return result; return result;
} }
if (!Constants.K8S_LOCAL_TEST_CLUSTER_CODE.equals(clusterExist.getCode())
&& !config.equals(ClusterConfUtils.getK8sConfig(clusterExist.getConfig()))) {
try {
k8sManager.getAndUpdateK8sClient(code, true);
} catch (RemotingException e) {
putMsg(result, Status.K8S_CLIENT_OPS_ERROR, name);
return result;
}
}
//update cluster //update cluster
clusterExist.setConfig(config); clusterExist.setConfig(config);
clusterExist.setName(name); clusterExist.setName(name);

100
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/K8SNamespaceServiceImpl.java

@ -22,13 +22,16 @@ import org.apache.dolphinscheduler.api.service.K8sNamespaceService;
import org.apache.dolphinscheduler.api.utils.PageInfo; import org.apache.dolphinscheduler.api.utils.PageInfo;
import org.apache.dolphinscheduler.api.utils.Result; import org.apache.dolphinscheduler.api.utils.Result;
import org.apache.dolphinscheduler.common.Constants; import org.apache.dolphinscheduler.common.Constants;
import org.apache.dolphinscheduler.common.enums.AuthorizationType; import org.apache.dolphinscheduler.common.utils.CodeGenerateUtils;
import org.apache.dolphinscheduler.dao.entity.Cluster;
import org.apache.dolphinscheduler.dao.entity.K8sNamespace; import org.apache.dolphinscheduler.dao.entity.K8sNamespace;
import org.apache.dolphinscheduler.dao.entity.User; import org.apache.dolphinscheduler.dao.entity.User;
import org.apache.dolphinscheduler.dao.mapper.ClusterMapper;
import org.apache.dolphinscheduler.dao.mapper.K8sNamespaceMapper; import org.apache.dolphinscheduler.dao.mapper.K8sNamespaceMapper;
import org.apache.dolphinscheduler.remote.exceptions.RemotingException;
import org.apache.dolphinscheduler.api.k8s.K8sClientService; import org.apache.dolphinscheduler.api.k8s.K8sClientService;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang.StringUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
@ -63,11 +66,16 @@ public class K8SNamespaceServiceImpl extends BaseServiceImpl implements K8sNames
+ " hard:\n" + " hard:\n"
+ " ${limitCpu}\n" + " ${limitCpu}\n"
+ " ${limitMemory}\n"; + " ${limitMemory}\n";
@Autowired @Autowired
private K8sNamespaceMapper k8sNamespaceMapper; private K8sNamespaceMapper k8sNamespaceMapper;
@Autowired @Autowired
private K8sClientService k8sClientService; private K8sClientService k8sClientService;
@Autowired
private ClusterMapper clusterMapper;
/** /**
* query namespace list paging * query namespace list paging
* *
@ -80,6 +88,11 @@ public class K8SNamespaceServiceImpl extends BaseServiceImpl implements K8sNames
@Override @Override
public Result queryListPaging(User loginUser, String searchVal, Integer pageNo, Integer pageSize) { public Result queryListPaging(User loginUser, String searchVal, Integer pageNo, Integer pageSize) {
Result result = new Result(); Result result = new Result();
if (!isAdmin(loginUser)) {
putMsg(result, Status.USER_NO_OPERATION_PERM);
return result;
}
Page<K8sNamespace> page = new Page<>(pageNo, pageSize); Page<K8sNamespace> page = new Page<>(pageNo, pageSize);
IPage<K8sNamespace> k8sNamespaceList = k8sNamespaceMapper.queryK8sNamespacePaging(page, searchVal); IPage<K8sNamespace> k8sNamespaceList = k8sNamespaceMapper.queryK8sNamespacePaging(page, searchVal);
@ -99,16 +112,15 @@ public class K8SNamespaceServiceImpl extends BaseServiceImpl implements K8sNames
* *
* @param loginUser login user * @param loginUser login user
* @param namespace namespace * @param namespace namespace
* @param k8s k8s not null * @param clusterCode k8s not null
* @param limitsCpu limits cpu, can null means not limit * @param limitsCpu limits cpu, can null means not limit
* @param limitsMemory limits memory, can null means not limit * @param limitsMemory limits memory, can null means not limit
* @return * @return
*/ */
@Override @Override
public Map<String, Object> createK8sNamespace(User loginUser, String namespace, String k8s, Double limitsCpu, Integer limitsMemory) { public Map<String, Object> createK8sNamespace(User loginUser, String namespace, Long clusterCode, Double limitsCpu, Integer limitsMemory) {
Map<String, Object> result = new HashMap<>(); Map<String, Object> result = new HashMap<>();
if (!canOperatorPermissions(loginUser, null,AuthorizationType.K8S_NAMESPACE,null)) { if (isNotAdmin(loginUser, result)) {
putMsg(result, Status.USER_NO_OPERATION_PERM);
return result; return result;
} }
@ -117,8 +129,8 @@ public class K8SNamespaceServiceImpl extends BaseServiceImpl implements K8sNames
return result; return result;
} }
if (StringUtils.isEmpty(k8s)) { if (clusterCode == null) {
putMsg(result, Status.REQUEST_PARAMS_NOT_VALID_ERROR, Constants.K8S); putMsg(result, Status.REQUEST_PARAMS_NOT_VALID_ERROR, Constants.CLUSTER);
return result; return result;
} }
@ -132,27 +144,45 @@ public class K8SNamespaceServiceImpl extends BaseServiceImpl implements K8sNames
return result; return result;
} }
if (checkNamespaceExistInDb(namespace, k8s)) { if (checkNamespaceExistInDb(namespace, clusterCode)) {
putMsg(result, Status.K8S_NAMESPACE_EXIST, namespace, k8s); putMsg(result, Status.K8S_NAMESPACE_EXIST, namespace, clusterCode);
return result;
}
Cluster cluster = clusterMapper.queryByClusterCode(clusterCode);
if (cluster == null) {
putMsg(result, Status.CLUSTER_NOT_EXISTS, namespace, clusterCode);
return result;
}
long code = 0L;
try {
code = CodeGenerateUtils.getInstance().genCode();
cluster.setCode(code);
} catch (CodeGenerateUtils.CodeGenerateException e) {
logger.error("Cluster code get error, ", e);
}
if (code == 0L) {
putMsg(result, Status.INTERNAL_SERVER_ERROR_ARGS, "Error generating cluster code");
return result; return result;
} }
K8sNamespace k8sNamespaceObj = new K8sNamespace(); K8sNamespace k8sNamespaceObj = new K8sNamespace();
Date now = new Date(); Date now = new Date();
k8sNamespaceObj.setCode(code);
k8sNamespaceObj.setNamespace(namespace); k8sNamespaceObj.setNamespace(namespace);
k8sNamespaceObj.setK8s(k8s); k8sNamespaceObj.setClusterCode(clusterCode);
k8sNamespaceObj.setUserId(loginUser.getId()); k8sNamespaceObj.setUserId(loginUser.getId());
k8sNamespaceObj.setLimitsCpu(limitsCpu); k8sNamespaceObj.setLimitsCpu(limitsCpu);
k8sNamespaceObj.setLimitsMemory(limitsMemory); k8sNamespaceObj.setLimitsMemory(limitsMemory);
k8sNamespaceObj.setOnlineJobNum(0);
k8sNamespaceObj.setPodReplicas(0); k8sNamespaceObj.setPodReplicas(0);
k8sNamespaceObj.setPodRequestCpu(0.0); k8sNamespaceObj.setPodRequestCpu(0.0);
k8sNamespaceObj.setPodRequestMemory(0); k8sNamespaceObj.setPodRequestMemory(0);
k8sNamespaceObj.setCreateTime(now); k8sNamespaceObj.setCreateTime(now);
k8sNamespaceObj.setUpdateTime(now); k8sNamespaceObj.setUpdateTime(now);
if (!Constants.K8S_LOCAL_TEST_CLUSTER.equals(k8sNamespaceObj.getK8s())) { if (!Constants.K8S_LOCAL_TEST_CLUSTER_CODE.equals(k8sNamespaceObj.getClusterCode())) {
try { try {
String yamlStr = genDefaultResourceYaml(k8sNamespaceObj); String yamlStr = genDefaultResourceYaml(k8sNamespaceObj);
k8sClientService.upsertNamespaceAndResourceToK8s(k8sNamespaceObj, yamlStr); k8sClientService.upsertNamespaceAndResourceToK8s(k8sNamespaceObj, yamlStr);
@ -181,8 +211,7 @@ public class K8SNamespaceServiceImpl extends BaseServiceImpl implements K8sNames
@Override @Override
public Map<String, Object> updateK8sNamespace(User loginUser, int id, String userName, 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<>(); Map<String, Object> result = new HashMap<>();
if (!canOperatorPermissions(loginUser, null,AuthorizationType.K8S_NAMESPACE,null)) { if (isNotAdmin(loginUser, result)) {
putMsg(result, Status.USER_NO_OPERATION_PERM);
return result; return result;
} }
@ -207,7 +236,7 @@ public class K8SNamespaceServiceImpl extends BaseServiceImpl implements K8sNames
k8sNamespaceObj.setLimitsMemory(limitsMemory); k8sNamespaceObj.setLimitsMemory(limitsMemory);
k8sNamespaceObj.setUpdateTime(now); k8sNamespaceObj.setUpdateTime(now);
if (!Constants.K8S_LOCAL_TEST_CLUSTER.equals(k8sNamespaceObj.getK8s())) { if (!Constants.K8S_LOCAL_TEST_CLUSTER_CODE.equals(k8sNamespaceObj.getClusterCode())) {
try { try {
String yamlStr = genDefaultResourceYaml(k8sNamespaceObj); String yamlStr = genDefaultResourceYaml(k8sNamespaceObj);
k8sClientService.upsertNamespaceAndResourceToK8s(k8sNamespaceObj, yamlStr); k8sClientService.upsertNamespaceAndResourceToK8s(k8sNamespaceObj, yamlStr);
@ -227,25 +256,25 @@ public class K8SNamespaceServiceImpl extends BaseServiceImpl implements K8sNames
/** /**
* verify namespace and k8s * verify namespace and k8s
* *
* @param namespace namespace * @param namespace namespace
* @param k8s k8s * @param clusterCode cluster code
* @return true if the k8s and namespace not exists, otherwise return false * @return true if the k8s and namespace not exists, otherwise return false
*/ */
@Override @Override
public Result<Object> verifyNamespaceK8s(String namespace, String k8s) { public Result<Object> verifyNamespaceK8s(String namespace, Long clusterCode) {
Result<Object> result = new Result<>(); Result<Object> result = new Result<>();
if (StringUtils.isEmpty(namespace)) { if (StringUtils.isEmpty(namespace)) {
putMsg(result, Status.REQUEST_PARAMS_NOT_VALID_ERROR, Constants.NAMESPACE); putMsg(result, Status.REQUEST_PARAMS_NOT_VALID_ERROR, Constants.NAMESPACE);
return result; return result;
} }
if (StringUtils.isEmpty(k8s)) { if (clusterCode == null) {
putMsg(result, Status.REQUEST_PARAMS_NOT_VALID_ERROR, Constants.K8S); putMsg(result, Status.REQUEST_PARAMS_NOT_VALID_ERROR, Constants.CLUSTER);
return result; return result;
} }
if (checkNamespaceExistInDb(namespace, k8s)) { if (checkNamespaceExistInDb(namespace, clusterCode)) {
putMsg(result, Status.K8S_NAMESPACE_EXIST, namespace, k8s); putMsg(result, Status.K8S_NAMESPACE_EXIST, namespace, clusterCode);
return result; return result;
} }
@ -263,8 +292,7 @@ public class K8SNamespaceServiceImpl extends BaseServiceImpl implements K8sNames
@Override @Override
public Map<String, Object> deleteNamespaceById(User loginUser, int id) { public Map<String, Object> deleteNamespaceById(User loginUser, int id) {
Map<String, Object> result = new HashMap<>(); Map<String, Object> result = new HashMap<>();
if (!canOperatorPermissions(loginUser, null,AuthorizationType.K8S_NAMESPACE,null)) { if (isNotAdmin(loginUser, result)) {
putMsg(result, Status.USER_NO_OPERATION_PERM);
return result; return result;
} }
@ -273,8 +301,13 @@ public class K8SNamespaceServiceImpl extends BaseServiceImpl implements K8sNames
putMsg(result, Status.K8S_NAMESPACE_NOT_EXIST, id); putMsg(result, Status.K8S_NAMESPACE_NOT_EXIST, id);
return result; return result;
} }
if (!Constants.K8S_LOCAL_TEST_CLUSTER.equals(k8sNamespaceObj.getK8s())) { if (!Constants.K8S_LOCAL_TEST_CLUSTER_CODE.equals(k8sNamespaceObj.getClusterCode())) {
k8sClientService.deleteNamespaceToK8s(k8sNamespaceObj.getNamespace(), k8sNamespaceObj.getK8s()); try {
k8sClientService.deleteNamespaceToK8s(k8sNamespaceObj.getNamespace(), k8sNamespaceObj.getClusterCode());
} catch (RemotingException e) {
putMsg(result, Status.K8S_CLIENT_OPS_ERROR, id);
return result;
}
} }
k8sNamespaceMapper.deleteById(id); k8sNamespaceMapper.deleteById(id);
putMsg(result, Status.SUCCESS); putMsg(result, Status.SUCCESS);
@ -287,8 +320,8 @@ public class K8SNamespaceServiceImpl extends BaseServiceImpl implements K8sNames
* @param namespace namespace * @param namespace namespace
* @return true if the k8s and namespace not exists, otherwise return false * @return true if the k8s and namespace not exists, otherwise return false
*/ */
private boolean checkNamespaceExistInDb(String namespace, String k8s) { private boolean checkNamespaceExistInDb(String namespace, Long clusterCode) {
return k8sNamespaceMapper.existNamespace(namespace, k8s) == Boolean.TRUE; return k8sNamespaceMapper.existNamespace(namespace, clusterCode) == Boolean.TRUE;
} }
/** /**
@ -338,8 +371,7 @@ public class K8SNamespaceServiceImpl extends BaseServiceImpl implements K8sNames
@Override @Override
public Map<String, Object> queryUnauthorizedNamespace(User loginUser, Integer userId) { public Map<String, Object> queryUnauthorizedNamespace(User loginUser, Integer userId) {
Map<String, Object> result = new HashMap<>(); Map<String, Object> result = new HashMap<>();
if (loginUser.getId() != userId && !canOperatorPermissions(loginUser, null,AuthorizationType.K8S_NAMESPACE,null)) { if (loginUser.getId() != userId && isNotAdmin(loginUser, result)) {
putMsg(result, Status.USER_NO_OPERATION_PERM);
return result; return result;
} }
// query all namespace list,this auth does not like project // query all namespace list,this auth does not like project
@ -367,8 +399,7 @@ public class K8SNamespaceServiceImpl extends BaseServiceImpl implements K8sNames
public Map<String, Object> queryAuthorizedNamespace(User loginUser, Integer userId) { public Map<String, Object> queryAuthorizedNamespace(User loginUser, Integer userId) {
Map<String, Object> result = new HashMap<>(); Map<String, Object> result = new HashMap<>();
if (loginUser.getId() != userId && !canOperatorPermissions(loginUser, null,AuthorizationType.K8S_NAMESPACE,null)) { if (loginUser.getId() != userId && isNotAdmin(loginUser, result)) {
putMsg(result, Status.USER_NO_OPERATION_PERM);
return result; return result;
} }
@ -387,7 +418,7 @@ public class K8SNamespaceServiceImpl extends BaseServiceImpl implements K8sNames
*/ */
@Override @Override
public List<K8sNamespace> queryNamespaceAvailable(User loginUser) { public List<K8sNamespace> queryNamespaceAvailable(User loginUser) {
if (canOperatorPermissions(loginUser,null,AuthorizationType.K8S_NAMESPACE,null)) { if (isAdmin(loginUser)) {
return k8sNamespaceMapper.selectList(null); return k8sNamespaceMapper.selectList(null);
} else { } else {
return k8sNamespaceMapper.queryNamespaceAvailable(loginUser.getId()); return k8sNamespaceMapper.queryNamespaceAvailable(loginUser.getId());
@ -419,5 +450,4 @@ public class K8SNamespaceServiceImpl extends BaseServiceImpl implements K8sNames
} }
return resultList; return resultList;
} }
} }

2
dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/ClusterControllerTest.java

@ -42,7 +42,7 @@ import com.google.common.base.Preconditions;
public class ClusterControllerTest extends AbstractControllerTest { public class ClusterControllerTest extends AbstractControllerTest {
public static final String clusterName = "Cluster1"; public static final String clusterName = "Cluster1";
public static final String config = "this is config content"; public static final String config = "{\"k8s\":\"apiVersion: v1\"}";
public static final String desc = "this is cluster description"; public static final String desc = "this is cluster description";
private static final Logger logger = LoggerFactory.getLogger(ClusterControllerTest.class); private static final Logger logger = LoggerFactory.getLogger(ClusterControllerTest.class);
private String clusterCode; private String clusterCode;

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

@ -28,12 +28,8 @@ import org.apache.dolphinscheduler.api.utils.Result;
import org.apache.dolphinscheduler.common.utils.JSONUtils; import org.apache.dolphinscheduler.common.utils.JSONUtils;
import org.apache.dolphinscheduler.dao.entity.User; import org.apache.dolphinscheduler.dao.entity.User;
import java.util.HashMap;
import java.util.Map;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.mockito.Mockito;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
@ -72,7 +68,7 @@ public class K8sNamespaceControllerTest extends AbstractControllerTest {
MultiValueMap<String, String> paramsMap = new LinkedMultiValueMap<>(); MultiValueMap<String, String> paramsMap = new LinkedMultiValueMap<>();
paramsMap.add("namespace", NAMESPACE_CREATE_STRING); paramsMap.add("namespace", NAMESPACE_CREATE_STRING);
paramsMap.add("k8s", "k8s"); paramsMap.add("clusterCode", "0");
MvcResult mvcResult = mockMvc.perform(post("/k8s-namespace") MvcResult mvcResult = mockMvc.perform(post("/k8s-namespace")
.header(SESSION_ID, sessionId) .header(SESSION_ID, sessionId)
@ -82,7 +78,7 @@ public class K8sNamespaceControllerTest extends AbstractControllerTest {
.andReturn(); .andReturn();
Result result = JSONUtils.parseObject(mvcResult.getResponse().getContentAsString(), Result.class); Result result = JSONUtils.parseObject(mvcResult.getResponse().getContentAsString(), Result.class);
Assert.assertEquals(Status.K8S_CLIENT_OPS_ERROR.getCode(), result.getCode().intValue());//because we not have a k8s cluster in test env Assert.assertEquals(Status.SUCCESS.getCode(), result.getCode().intValue());//because we not have a k8s cluster in test env
logger.info("create queue return result:{}", mvcResult.getResponse().getContentAsString()); logger.info("create queue return result:{}", mvcResult.getResponse().getContentAsString());
} }
@ -108,8 +104,8 @@ public class K8sNamespaceControllerTest extends AbstractControllerTest {
public void verifyNamespace() throws Exception { public void verifyNamespace() throws Exception {
// queue value exist // queue value exist
MultiValueMap<String, String> paramsMap = new LinkedMultiValueMap<>(); MultiValueMap<String, String> paramsMap = new LinkedMultiValueMap<>();
paramsMap.add("namespace", NAMESPACE_CREATE_STRING); paramsMap.add("namespace", "NAMESPACE_CREATE_STRING");
paramsMap.add("k8s", "default"); paramsMap.add("clusterCode", "100");
// success // success
@ -127,7 +123,7 @@ public class K8sNamespaceControllerTest extends AbstractControllerTest {
//error //error
paramsMap.clear(); paramsMap.clear();
paramsMap.add("namespace", null); paramsMap.add("namespace", null);
paramsMap.add("k8s", "default"); paramsMap.add("clusterCode", "100");
mvcResult = mockMvc.perform(post("/k8s-namespace/verify") mvcResult = mockMvc.perform(post("/k8s-namespace/verify")
.header(SESSION_ID, sessionId) .header(SESSION_ID, sessionId)
.params(paramsMap)) .params(paramsMap))

34
dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/k8s/K8sManagerTest.java

@ -17,8 +17,9 @@
package org.apache.dolphinscheduler.api.k8s; package org.apache.dolphinscheduler.api.k8s;
import org.apache.dolphinscheduler.dao.entity.K8s; import org.apache.dolphinscheduler.dao.entity.Cluster;
import org.apache.dolphinscheduler.dao.mapper.K8sMapper; import org.apache.dolphinscheduler.dao.mapper.ClusterMapper;
import org.apache.dolphinscheduler.remote.exceptions.RemotingException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -42,7 +43,7 @@ public class K8sManagerTest {
private K8sManager k8sManager; private K8sManager k8sManager;
@Mock @Mock
private K8sMapper k8sMapper; private ClusterMapper clusterMapper;
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
@ -53,26 +54,27 @@ public class K8sManagerTest {
} }
@Test @Test
public void getK8sClient() { public void getK8sClient() throws RemotingException {
Mockito.when(k8sMapper.selectList(Mockito.any())).thenReturn(getK8sList()); Mockito.when(clusterMapper.selectList(Mockito.any())).thenReturn(getClusterList());
KubernetesClient result = k8sManager.getK8sClient("must null"); KubernetesClient result = k8sManager.getK8sClient(1L);
Assert.assertNull(result); Assert.assertNull(result);
result = k8sManager.getK8sClient(null); result = k8sManager.getK8sClient(null);
Assert.assertNull(result); Assert.assertNull(result);
} }
private K8s getK8s() { private Cluster getCluster() {
K8s k8s = new K8s(); Cluster cluster = new Cluster();
k8s.setId(1); cluster.setId(1);
k8s.setK8sName("default"); cluster.setCode(1L);
k8s.setK8sConfig("k8s config"); cluster.setName("cluster");
return k8s; cluster.setConfig("{\"k8s\":\"k8s config yaml\"}");
return cluster;
} }
private List<K8s> getK8sList() { private List<Cluster> getClusterList() {
List<K8s> k8sList = new ArrayList<>(); List<Cluster> clusterList = new ArrayList<>();
k8sList.add(getK8s()); clusterList.add(getCluster());
return k8sList; return clusterList;
} }
} }

5
dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/ClusterServiceTest.java

@ -221,6 +221,11 @@ public class ClusterServiceTest {
result = clusterService.deleteClusterByCode(loginUser,1L); result = clusterService.deleteClusterByCode(loginUser,1L);
logger.info(result.toString()); logger.info(result.toString());
Assert.assertEquals(Status.SUCCESS, result.get(Constants.STATUS)); Assert.assertEquals(Status.SUCCESS, result.get(Constants.STATUS));
Mockito.when(k8sNamespaceMapper.selectCount(Mockito.any())).thenReturn(1);
result = clusterService.deleteClusterByCode(loginUser,1L);
logger.info(result.toString());
Assert.assertEquals(Status.DELETE_CLUSTER_RELATED_NAMESPACE_EXISTS, result.get(Constants.STATUS));
} }
@Test @Test

55
dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/K8SNamespaceServiceTest.java

@ -18,15 +18,15 @@
package org.apache.dolphinscheduler.api.service; package org.apache.dolphinscheduler.api.service;
import org.apache.dolphinscheduler.api.enums.Status; import org.apache.dolphinscheduler.api.enums.Status;
import org.apache.dolphinscheduler.api.service.impl.BaseServiceImpl;
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.PageInfo;
import org.apache.dolphinscheduler.api.utils.Result; import org.apache.dolphinscheduler.api.utils.Result;
import org.apache.dolphinscheduler.common.Constants; import org.apache.dolphinscheduler.common.Constants;
import org.apache.dolphinscheduler.common.enums.AuthorizationType;
import org.apache.dolphinscheduler.common.enums.UserType; import org.apache.dolphinscheduler.common.enums.UserType;
import org.apache.dolphinscheduler.dao.entity.Cluster;
import org.apache.dolphinscheduler.dao.entity.K8sNamespace; import org.apache.dolphinscheduler.dao.entity.K8sNamespace;
import org.apache.dolphinscheduler.dao.entity.User; import org.apache.dolphinscheduler.dao.entity.User;
import org.apache.dolphinscheduler.dao.mapper.ClusterMapper;
import org.apache.dolphinscheduler.dao.mapper.K8sNamespaceMapper; import org.apache.dolphinscheduler.dao.mapper.K8sNamespaceMapper;
import org.apache.dolphinscheduler.dao.mapper.UserMapper; import org.apache.dolphinscheduler.dao.mapper.UserMapper;
import org.apache.dolphinscheduler.api.k8s.K8sClientService; import org.apache.dolphinscheduler.api.k8s.K8sClientService;
@ -37,7 +37,6 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.apache.dolphinscheduler.api.permission.ResourcePermissionCheckService;
import org.junit.After; import org.junit.After;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
@ -57,7 +56,6 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
public class K8SNamespaceServiceTest { public class K8SNamespaceServiceTest {
private static final Logger logger = LoggerFactory.getLogger(K8SNamespaceServiceTest.class); private static final Logger logger = LoggerFactory.getLogger(K8SNamespaceServiceTest.class);
private static final Logger baseServiceLogger = LoggerFactory.getLogger(BaseServiceImpl.class);
@InjectMocks @InjectMocks
private K8SNamespaceServiceImpl k8sNamespaceService; private K8SNamespaceServiceImpl k8sNamespaceService;
@ -69,18 +67,18 @@ public class K8SNamespaceServiceTest {
private K8sClientService k8sClientService; private K8sClientService k8sClientService;
@Mock @Mock
private ResourcePermissionCheckService resourcePermissionCheckService; private UserMapper userMapper;
@Mock @Mock
private UserMapper userMapper; private ClusterMapper clusterMapper;
private String namespace = "default"; private String namespace = "default";
private String k8s = "default"; private Long clusterCode = 100L;
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
Mockito.when(k8sClientService.upsertNamespaceAndResourceToK8s(Mockito.any(K8sNamespace.class), Mockito.anyString())).thenReturn(null); Mockito.when(k8sClientService.upsertNamespaceAndResourceToK8s(Mockito.any(K8sNamespace.class), Mockito.anyString())).thenReturn(null);
Mockito.when(k8sClientService.deleteNamespaceToK8s(Mockito.anyString(), Mockito.anyString())).thenReturn(null); Mockito.when(k8sClientService.deleteNamespaceToK8s(Mockito.anyString(), Mockito.anyLong())).thenReturn(null);
} }
@After @After
@ -101,10 +99,8 @@ public class K8SNamespaceServiceTest {
@Test @Test
public void createK8sNamespace() { public void createK8sNamespace() {
Mockito.when(resourcePermissionCheckService.operationPermissionCheck(AuthorizationType.K8S_NAMESPACE, getLoginUser().getId(), null, baseServiceLogger)).thenReturn(true);
Mockito.when(resourcePermissionCheckService.resourcePermissionCheck(AuthorizationType.K8S_NAMESPACE, null, 0, baseServiceLogger)).thenReturn(true);
// namespace is null // namespace is null
Map<String, Object> result = k8sNamespaceService.createK8sNamespace(getLoginUser(), null, k8s, 10.0, 100); Map<String, Object> result = k8sNamespaceService.createK8sNamespace(getLoginUser(), null, clusterCode, 10.0, 100);
logger.info(result.toString()); logger.info(result.toString());
Assert.assertEquals(Status.REQUEST_PARAMS_NOT_VALID_ERROR, result.get(Constants.STATUS)); Assert.assertEquals(Status.REQUEST_PARAMS_NOT_VALID_ERROR, result.get(Constants.STATUS));
// k8s is null // k8s is null
@ -112,11 +108,12 @@ public class K8SNamespaceServiceTest {
logger.info(result.toString()); logger.info(result.toString());
Assert.assertEquals(Status.REQUEST_PARAMS_NOT_VALID_ERROR, result.get(Constants.STATUS)); Assert.assertEquals(Status.REQUEST_PARAMS_NOT_VALID_ERROR, result.get(Constants.STATUS));
// correct // correct
result = k8sNamespaceService.createK8sNamespace(getLoginUser(), namespace, k8s, 10.0, 100); Mockito.when(clusterMapper.queryByClusterCode(Mockito.anyLong())).thenReturn(getCluster());
result = k8sNamespaceService.createK8sNamespace(getLoginUser(), namespace, clusterCode, 10.0, 100);
logger.info(result.toString()); logger.info(result.toString());
Assert.assertEquals(Status.SUCCESS, result.get(Constants.STATUS)); Assert.assertEquals(Status.SUCCESS, result.get(Constants.STATUS));
//null limit cpu and mem //null limit cpu and mem
result = k8sNamespaceService.createK8sNamespace(getLoginUser(), namespace, k8s, null, null); result = k8sNamespaceService.createK8sNamespace(getLoginUser(), namespace, clusterCode, null, null);
logger.info(result.toString()); logger.info(result.toString());
Assert.assertEquals(Status.SUCCESS, result.get(Constants.STATUS)); Assert.assertEquals(Status.SUCCESS, result.get(Constants.STATUS));
} }
@ -124,8 +121,7 @@ public class K8SNamespaceServiceTest {
@Test @Test
public void updateK8sNamespace() { public void updateK8sNamespace() {
Mockito.when(k8sNamespaceMapper.selectById(1)).thenReturn(getNamespace()); Mockito.when(k8sNamespaceMapper.selectById(1)).thenReturn(getNamespace());
Mockito.when(resourcePermissionCheckService.operationPermissionCheck(AuthorizationType.K8S_NAMESPACE, getLoginUser().getId(), null, baseServiceLogger)).thenReturn(true);
Mockito.when(resourcePermissionCheckService.resourcePermissionCheck(AuthorizationType.K8S_NAMESPACE, null, 0, baseServiceLogger)).thenReturn(true);
Map<String, Object> result = k8sNamespaceService.updateK8sNamespace(getLoginUser(), 1, null, null, null); Map<String, Object> result = k8sNamespaceService.updateK8sNamespace(getLoginUser(), 1, null, null, null);
logger.info(result.toString()); logger.info(result.toString());
Assert.assertEquals(Status.SUCCESS, result.get(Constants.STATUS)); Assert.assertEquals(Status.SUCCESS, result.get(Constants.STATUS));
@ -142,10 +138,10 @@ public class K8SNamespaceServiceTest {
@Test @Test
public void verifyNamespaceK8s() { public void verifyNamespaceK8s() {
Mockito.when(k8sNamespaceMapper.existNamespace(namespace, k8s)).thenReturn(true); Mockito.when(k8sNamespaceMapper.existNamespace(namespace, clusterCode)).thenReturn(true);
//namespace null //namespace null
Result result = k8sNamespaceService.verifyNamespaceK8s(null, k8s); Result result = k8sNamespaceService.verifyNamespaceK8s(null, clusterCode);
logger.info(result.toString()); logger.info(result.toString());
Assert.assertEquals(result.getCode().intValue(), Status.REQUEST_PARAMS_NOT_VALID_ERROR.getCode()); Assert.assertEquals(result.getCode().intValue(), Status.REQUEST_PARAMS_NOT_VALID_ERROR.getCode());
@ -155,12 +151,12 @@ public class K8SNamespaceServiceTest {
Assert.assertEquals(result.getCode().intValue(), Status.REQUEST_PARAMS_NOT_VALID_ERROR.getCode()); Assert.assertEquals(result.getCode().intValue(), Status.REQUEST_PARAMS_NOT_VALID_ERROR.getCode());
//exist //exist
result = k8sNamespaceService.verifyNamespaceK8s(namespace, k8s); result = k8sNamespaceService.verifyNamespaceK8s(namespace, clusterCode);
logger.info(result.toString()); logger.info(result.toString());
Assert.assertEquals(result.getCode().intValue(), Status.K8S_NAMESPACE_EXIST.getCode()); Assert.assertEquals(result.getCode().intValue(), Status.K8S_NAMESPACE_EXIST.getCode());
//not exist //not exist
result = k8sNamespaceService.verifyNamespaceK8s(namespace, "other k8s"); result = k8sNamespaceService.verifyNamespaceK8s(namespace, 9999L);
logger.info(result.toString()); logger.info(result.toString());
Assert.assertEquals(result.getCode().intValue(), Status.SUCCESS.getCode()); Assert.assertEquals(result.getCode().intValue(), Status.SUCCESS.getCode());
} }
@ -169,8 +165,7 @@ public class K8SNamespaceServiceTest {
public void deleteNamespaceById() { public void deleteNamespaceById() {
Mockito.when(k8sNamespaceMapper.deleteById(Mockito.any())).thenReturn(1); Mockito.when(k8sNamespaceMapper.deleteById(Mockito.any())).thenReturn(1);
Mockito.when(k8sNamespaceMapper.selectById(1)).thenReturn(getNamespace()); Mockito.when(k8sNamespaceMapper.selectById(1)).thenReturn(getNamespace());
Mockito.when(resourcePermissionCheckService.operationPermissionCheck(AuthorizationType.K8S_NAMESPACE, getLoginUser().getId(), null, baseServiceLogger)).thenReturn(true);
Mockito.when(resourcePermissionCheckService.resourcePermissionCheck(AuthorizationType.K8S_NAMESPACE, null, 0, baseServiceLogger)).thenReturn(true);
Map<String, Object> result = k8sNamespaceService.deleteNamespaceById(getLoginUser(), 1); Map<String, Object> result = k8sNamespaceService.deleteNamespaceById(getLoginUser(), 1);
logger.info(result.toString()); logger.info(result.toString());
Assert.assertEquals(Status.SUCCESS, result.get(Constants.STATUS)); Assert.assertEquals(Status.SUCCESS, result.get(Constants.STATUS));
@ -179,8 +174,7 @@ public class K8SNamespaceServiceTest {
@Test @Test
public void testQueryAuthorizedNamespace() { public void testQueryAuthorizedNamespace() {
Mockito.when(k8sNamespaceMapper.queryAuthedNamespaceListByUserId(2)).thenReturn(getNamespaceList()); Mockito.when(k8sNamespaceMapper.queryAuthedNamespaceListByUserId(2)).thenReturn(getNamespaceList());
Mockito.when(resourcePermissionCheckService.operationPermissionCheck(AuthorizationType.K8S_NAMESPACE, getLoginUser().getId(), null, baseServiceLogger)).thenReturn(true);
Mockito.when(resourcePermissionCheckService.resourcePermissionCheck(AuthorizationType.K8S_NAMESPACE, null, 0, baseServiceLogger)).thenReturn(true);
User loginUser = getLoginUser(); User loginUser = getLoginUser();
// test admin user // test admin user
@ -203,8 +197,7 @@ public class K8SNamespaceServiceTest {
public void testQueryUnAuthorizedNamespace() { public void testQueryUnAuthorizedNamespace() {
Mockito.when(k8sNamespaceMapper.queryAuthedNamespaceListByUserId(2)).thenReturn(new ArrayList<>()); Mockito.when(k8sNamespaceMapper.queryAuthedNamespaceListByUserId(2)).thenReturn(new ArrayList<>());
Mockito.when(k8sNamespaceMapper.selectList(Mockito.any())).thenReturn(getNamespaceList()); Mockito.when(k8sNamespaceMapper.selectList(Mockito.any())).thenReturn(getNamespaceList());
Mockito.when(resourcePermissionCheckService.operationPermissionCheck(AuthorizationType.K8S_NAMESPACE, 0, null, baseServiceLogger)).thenReturn(true);
Mockito.when(resourcePermissionCheckService.resourcePermissionCheck(AuthorizationType.K8S_NAMESPACE, null, 0, baseServiceLogger)).thenReturn(true);
// test admin user // test admin user
User loginUser = new User(); User loginUser = new User();
loginUser.setUserType(UserType.ADMIN_USER); loginUser.setUserType(UserType.ADMIN_USER);
@ -235,7 +228,7 @@ public class K8SNamespaceServiceTest {
private K8sNamespace getNamespace() { private K8sNamespace getNamespace() {
K8sNamespace k8sNamespace = new K8sNamespace(); K8sNamespace k8sNamespace = new K8sNamespace();
k8sNamespace.setId(1); k8sNamespace.setId(1);
k8sNamespace.setK8s(k8s); k8sNamespace.setClusterCode(clusterCode);
k8sNamespace.setNamespace(namespace); k8sNamespace.setNamespace(namespace);
return k8sNamespace; return k8sNamespace;
} }
@ -245,4 +238,14 @@ public class K8SNamespaceServiceTest {
k8sNamespaceList.add(getNamespace()); k8sNamespaceList.add(getNamespace());
return k8sNamespaceList; return k8sNamespaceList;
} }
private Cluster getCluster() {
Cluster cluster = new Cluster();
cluster.setId(1);
cluster.setCode(1L);
cluster.setName("clusterName");
cluster.setConfig("{}");
cluster.setOperator(1);
return cluster;
}
} }

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

@ -804,10 +804,10 @@ public final class Constants {
* use for k8s * use for k8s
*/ */
public static final String NAMESPACE = "namespace"; public static final String NAMESPACE = "namespace";
public static final String K8S = "k8s"; public static final String CLUSTER = "cluster";
public static final String LIMITS_CPU = "limitsCpu"; public static final String LIMITS_CPU = "limitsCpu";
public static final String LIMITS_MEMORY = "limitsMemory"; public static final String LIMITS_MEMORY = "limitsMemory";
public static final String K8S_LOCAL_TEST_CLUSTER = "ds_null_k8s"; public static final Long K8S_LOCAL_TEST_CLUSTER_CODE = 0L;
/** /**
* schedule timezone * schedule timezone

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

@ -32,6 +32,11 @@ public class K8sNamespace {
@TableId(value = "id", type = IdType.AUTO) @TableId(value = "id", type = IdType.AUTO)
private Integer id; private Integer id;
/**
* cluster code
*/
private Long code;
/** /**
* namespace name * namespace name
*/ */
@ -92,16 +97,16 @@ public class K8sNamespace {
private Integer podReplicas = 0; private Integer podReplicas = 0;
/** /**
* online job * cluster code
*/ */
@TableField("online_job_num") @TableField("cluster_code")
private Integer onlineJobNum = 0; private Long clusterCode;
/** /**
* k8s name * k8s name
*/ */
@TableField("k8s") @TableField(exist = false)
private String k8s; private String clusterName;
public Integer getId() { public Integer getId() {
return id; return id;
@ -175,20 +180,20 @@ public class K8sNamespace {
this.podReplicas = podReplicas; this.podReplicas = podReplicas;
} }
public Integer getOnlineJobNum() { public Long getClusterCode() {
return onlineJobNum; return clusterCode;
} }
public void setOnlineJobNum(Integer onlineJobNum) { public void setClusterCode(Long clusterCode) {
this.onlineJobNum = onlineJobNum; this.clusterCode = clusterCode;
} }
public String getK8s() { public String getClusterName() {
return k8s; return clusterName;
} }
public void setK8s(String k8s) { public void setClusterName(String clusterName) {
this.k8s = k8s; this.clusterName = clusterName;
} }
public Double getPodRequestCpu() { public Double getPodRequestCpu() {
@ -211,14 +216,14 @@ public class K8sNamespace {
public String toString() { public String toString() {
return "K8sNamespace{" + return "K8sNamespace{" +
"id=" + id + "id=" + id +
"code=" + code +
", namespace=" + namespace + ", namespace=" + namespace +
", limitsCpu=" + limitsCpu + ", limitsCpu=" + limitsCpu +
", limitsMemory=" + limitsMemory + ", limitsMemory=" + limitsMemory +
", userId=" + userId +
", podRequestCpu=" + podRequestCpu + ", podRequestCpu=" + podRequestCpu +
", podRequestMemory=" + podRequestMemory + ", podRequestMemory=" + podRequestMemory +
", podReplicas=" + podReplicas + ", podReplicas=" + podReplicas +
", k8s=" + k8s + ", clusterCode=" + clusterCode +
", createTime=" + createTime + ", createTime=" + createTime +
", updateTime=" + updateTime + ", updateTime=" + updateTime +
'}'; '}';
@ -239,13 +244,21 @@ public class K8sNamespace {
return true; return true;
} }
return namespace.equals(k8sNamespace.namespace) && k8s.equals(k8sNamespace.k8s); return namespace.equals(k8sNamespace.namespace) && clusterName.equals(k8sNamespace.clusterName);
} }
@Override @Override
public int hashCode() { public int hashCode() {
int result = id; int result = id;
result = 31 * result + (k8s+namespace).hashCode(); result = 31 * result + (clusterName + namespace).hashCode();
return result; return result;
} }
public Long getCode() {
return code;
}
public void setCode(Long code) {
this.code = code;
}
} }

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

@ -43,11 +43,11 @@ public interface K8sNamespaceMapper extends BaseMapper<K8sNamespace> {
/** /**
* check the target namespace exist * check the target namespace exist
* *
* @param namespace namespace * @param namespace namespace
* @param k8s k8s name * @param clusterCode clusterCode
* @return true if exist else return null * @return true if exist else return null
*/ */
Boolean existNamespace(@Param("namespace") String namespace, @Param("k8s") String k8s); Boolean existNamespace(@Param("namespace") String namespace, @Param("clusterCode") Long clusterCode);
/** /**
* query namespace except userId * query namespace except userId
@ -72,4 +72,12 @@ public interface K8sNamespaceMapper extends BaseMapper<K8sNamespace> {
* @return namespace list * @return namespace list
*/ */
List<K8sNamespace> queryNamespaceAvailable(@Param("userId") Integer userId); List<K8sNamespace> queryNamespaceAvailable(@Param("userId") Integer userId);
/**
* check the target namespace
*
* @param namespaceCode namespaceCode
* @return true if exist else return null
*/
K8sNamespace queryByNamespaceCode(@Param("clusterCode") Long namespaceCode);
} }

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

@ -20,22 +20,26 @@
<mapper namespace="org.apache.dolphinscheduler.dao.mapper.K8sNamespaceMapper"> <mapper namespace="org.apache.dolphinscheduler.dao.mapper.K8sNamespaceMapper">
<sql id="baseSql"> <sql id="baseSql">
id, namespace, k8s, user_id, limits_memory, limits_cpu, online_job_num, pod_replicas, pod_request_cpu, pod_request_memory, create_time, update_time id, code, namespace, user_id, limits_memory, limits_cpu, pod_replicas, pod_request_cpu, pod_request_memory, cluster_code, create_time, update_time
</sql> </sql>
<sql id="baseSqlV2"> <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 ${alias}.id, ${alias}.code, ${alias}.namespace, ${alias}.user_id, ${alias}.limits_memory, ${alias}.limits_cpu, ${alias}.pod_replicas, ${alias}.pod_request_cpu, ${alias}.pod_request_memory, ${alias}.cluster_code, ${alias}.create_time, ${alias}.update_time
</sql> </sql>
<select id="queryK8sNamespacePaging" resultType="org.apache.dolphinscheduler.dao.entity.K8sNamespace"> <select id="queryK8sNamespacePaging" resultType="org.apache.dolphinscheduler.dao.entity.K8sNamespace">
select select
<include refid="baseSql"/> <include refid="baseSqlV2">
from t_ds_k8s_namespace <property name="alias" value="p"/>
</include>
,u.name as cluster_name
from t_ds_k8s_namespace p
left join t_ds_cluster u on u.code=p.cluster_code
where 1= 1 where 1= 1
<if test="searchVal != null and searchVal != ''"> <if test="searchVal != null and searchVal != ''">
and namespace like concat('%', #{searchVal}, '%') and p.namespace like concat('%', #{searchVal}, '%')
</if> </if>
order by update_time desc order by p.update_time desc
</select> </select>
<select id="existNamespace" resultType="java.lang.Boolean"> <select id="existNamespace" resultType="java.lang.Boolean">
@ -45,8 +49,8 @@
<if test="namespace != null and namespace != ''"> <if test="namespace != null and namespace != ''">
and namespace = #{namespace} and namespace = #{namespace}
</if> </if>
<if test="k8s != null and k8s != ''"> <if test="clusterCode != null and clusterCode != ''">
and k8s =#{k8s} and cluster_code =#{clusterCode}
</if> </if>
</select> </select>
@ -76,4 +80,10 @@
on b.id = a.namespace_id on b.id = a.namespace_id
where b.id is not null where b.id is not null
</select> </select>
<select id="queryByNamespaceCode" resultType="org.apache.dolphinscheduler.dao.entity.K8sNamespace">
select
<include refid="baseSql"/>
from t_ds_k8s_namespace
where code = #{namespaceCode}
</select>
</mapper> </mapper>

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

@ -1907,35 +1907,34 @@ CREATE TABLE t_ds_k8s
DROP TABLE IF EXISTS t_ds_k8s_namespace; DROP TABLE IF EXISTS t_ds_k8s_namespace;
CREATE TABLE t_ds_k8s_namespace ( CREATE TABLE t_ds_k8s_namespace (
id int(11) NOT NULL AUTO_INCREMENT , id int(11) NOT NULL AUTO_INCREMENT ,
code bigint(20) NOT NULL,
limits_memory int(11) DEFAULT NULL, limits_memory int(11) DEFAULT NULL,
namespace varchar(100) DEFAULT NULL, namespace varchar(100) DEFAULT NULL,
online_job_num int(11) DEFAULT NULL,
user_id int(11) DEFAULT NULL, user_id int(11) DEFAULT NULL,
pod_replicas int(11) DEFAULT NULL, pod_replicas int(11) DEFAULT NULL,
pod_request_cpu decimal(14,3) DEFAULT NULL, pod_request_cpu decimal(14,3) DEFAULT NULL,
pod_request_memory int(11) DEFAULT NULL, pod_request_memory int(11) DEFAULT NULL,
limits_cpu decimal(14,3) DEFAULT NULL, limits_cpu decimal(14,3) DEFAULT NULL,
k8s varchar(100) DEFAULT NULL, cluster_code bigint(20) NOT NULL,
create_time datetime DEFAULT NULL , create_time datetime DEFAULT NULL ,
update_time datetime DEFAULT NULL , update_time datetime DEFAULT NULL ,
PRIMARY KEY (id) , PRIMARY KEY (id) ,
UNIQUE KEY k8s_namespace_unique (namespace,k8s) UNIQUE KEY k8s_namespace_unique (namespace,cluster_code)
); );
-- ---------------------------- -- ----------------------------
-- Records of t_ds_k8s_namespace -- Records of t_ds_k8s_namespace
-- ---------------------------- -- ----------------------------
INSERT INTO `t_ds_k8s_namespace` 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`) (`id`,`code`,`limits_memory`,`namespace`,`user_id`,`pod_replicas`,`pod_request_cpu`,`pod_request_memory`,`limits_cpu`,`cluster_code`,`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'); VALUES (1, 990001, 1000, 'flink_test', 1, 1, 0.1, 1, 100, 0, '2022-03-03 11:31:24.0', '2022-03-03 11:31:24.0');
INSERT INTO `t_ds_k8s_namespace` 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`) (`id`,`code`,`limits_memory`,`namespace`,`user_id`,`pod_replicas`,`pod_request_cpu`,`pod_request_memory`,`limits_cpu`,`cluster_code`,`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'); VALUES (2, 990002, 500, 'spark_test', 2, 1, 10000, 1, 100, 0, '2021-03-03 11:31:24.0', '2021-03-03 11:31:24.0');
INSERT INTO `t_ds_k8s_namespace` 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`) (`id`,`code`,`limits_memory`,`namespace`,`user_id`,`pod_replicas`,`pod_request_cpu`,`pod_request_memory`,`limits_cpu`,`cluster_code`,`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'); VALUES (3, 990003, 200, 'auth_test', 3, 1, 100, 1, 10000, 0, '2020-03-03 11:31:24.0', '2020-03-03 11:31:24.0');
-- ---------------------------- -- ----------------------------
-- Table structure for t_ds_relation_namespace_user -- Table structure for t_ds_relation_namespace_user
@ -1990,4 +1989,4 @@ CREATE TABLE t_ds_cluster
INSERT INTO `t_ds_cluster` INSERT INTO `t_ds_cluster`
(`id`,`code`,`name`,`config`,`description`,`operator`,`create_time`,`update_time`) (`id`,`code`,`name`,`config`,`description`,`operator`,`create_time`,`update_time`)
VALUES (100, 100, 'ds_null_k8s', '{"k8s":"ds_null_k8s"}', 'test', 1, '2021-03-03 11:31:24.0', '2021-03-03 11:31:24.0'); VALUES (100, 0, 'ds_null_k8s', '{"k8s":"ds_null_k8s"}', 'test', 1, '2021-03-03 11:31:24.0', '2021-03-03 11:31:24.0');

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

@ -1901,19 +1901,19 @@ CREATE TABLE `t_ds_k8s` (
DROP TABLE IF EXISTS `t_ds_k8s_namespace`; DROP TABLE IF EXISTS `t_ds_k8s_namespace`;
CREATE TABLE `t_ds_k8s_namespace` ( CREATE TABLE `t_ds_k8s_namespace` (
`id` int(11) NOT NULL AUTO_INCREMENT, `id` int(11) NOT NULL AUTO_INCREMENT,
`code` bigint(20) NOT NULL DEFAULT '0',
`limits_memory` int(11) DEFAULT NULL, `limits_memory` int(11) DEFAULT NULL,
`namespace` varchar(100) DEFAULT NULL, `namespace` varchar(100) DEFAULT NULL,
`online_job_num` int(11) DEFAULT NULL,
`user_id` int(11) DEFAULT NULL, `user_id` int(11) DEFAULT NULL,
`pod_replicas` int(11) DEFAULT NULL, `pod_replicas` int(11) DEFAULT NULL,
`pod_request_cpu` decimal(14,3) DEFAULT NULL, `pod_request_cpu` decimal(14,3) DEFAULT NULL,
`pod_request_memory` int(11) DEFAULT NULL, `pod_request_memory` int(11) DEFAULT NULL,
`limits_cpu` decimal(14,3) DEFAULT NULL, `limits_cpu` decimal(14,3) DEFAULT NULL,
`k8s` varchar(100) DEFAULT NULL, `cluster_code` bigint(20) NOT NULL DEFAULT '0',
`create_time` datetime DEFAULT NULL COMMENT 'create time', `create_time` datetime DEFAULT NULL COMMENT 'create time',
`update_time` datetime DEFAULT NULL COMMENT 'update time', `update_time` datetime DEFAULT NULL COMMENT 'update time',
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
UNIQUE KEY `k8s_namespace_unique` (`namespace`,`k8s`) UNIQUE KEY `k8s_namespace_unique` (`namespace`,`cluster_code`)
) ENGINE= INNODB AUTO_INCREMENT= 1 DEFAULT CHARSET= utf8; ) ENGINE= INNODB AUTO_INCREMENT= 1 DEFAULT CHARSET= utf8;
-- ---------------------------- -- ----------------------------

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

@ -1900,21 +1900,22 @@ CREATE TABLE t_ds_k8s (
DROP TABLE IF EXISTS t_ds_k8s_namespace; DROP TABLE IF EXISTS t_ds_k8s_namespace;
CREATE TABLE t_ds_k8s_namespace ( CREATE TABLE t_ds_k8s_namespace (
id serial NOT NULL, id serial NOT NULL,
code bigint NOT NULL,
limits_memory int DEFAULT NULL , limits_memory int DEFAULT NULL ,
namespace varchar(100) DEFAULT NULL , namespace varchar(100) DEFAULT NULL ,
online_job_num int DEFAULT '0' ,
user_id int DEFAULT NULL, user_id int DEFAULT NULL,
pod_replicas int DEFAULT NULL, pod_replicas int DEFAULT NULL,
pod_request_cpu NUMERIC(13,4) NULL, pod_request_cpu NUMERIC(13,4) NULL,
pod_request_memory int DEFAULT NULL, pod_request_memory int DEFAULT NULL,
limits_cpu NUMERIC(13,4) NULL, limits_cpu NUMERIC(13,4) NULL,
k8s varchar(100) DEFAULT NULL, cluster_code bigint NOT NULL,
create_time timestamp DEFAULT NULL , create_time timestamp DEFAULT NULL ,
update_time timestamp DEFAULT NULL , update_time timestamp DEFAULT NULL ,
PRIMARY KEY (id) , PRIMARY KEY (id) ,
CONSTRAINT k8s_namespace_unique UNIQUE (namespace,k8s) CONSTRAINT k8s_namespace_unique UNIQUE (namespace,cluster_code)
); );
-- --
-- Table structure for table t_ds_relation_namespace_user -- Table structure for table t_ds_relation_namespace_user
-- --

6
dolphinscheduler-dao/src/main/resources/sql/upgrade/3.0.0_schema/mysql/dolphinscheduler_ddl.sql

@ -266,19 +266,19 @@ CREATE TABLE `t_ds_k8s` (
DROP TABLE IF EXISTS `t_ds_k8s_namespace`; DROP TABLE IF EXISTS `t_ds_k8s_namespace`;
CREATE TABLE `t_ds_k8s_namespace` ( CREATE TABLE `t_ds_k8s_namespace` (
`id` int(11) NOT NULL AUTO_INCREMENT, `id` int(11) NOT NULL AUTO_INCREMENT,
`code` bigint(20) NOT NULL DEFAULT '0',
`limits_memory` int(11) DEFAULT NULL, `limits_memory` int(11) DEFAULT NULL,
`namespace` varchar(100) DEFAULT NULL, `namespace` varchar(100) DEFAULT NULL,
`online_job_num` int(11) DEFAULT NULL,
`user_id` int(11) DEFAULT NULL, `user_id` int(11) DEFAULT NULL,
`pod_replicas` int(11) DEFAULT NULL, `pod_replicas` int(11) DEFAULT NULL,
`pod_request_cpu` decimal(14,3) DEFAULT NULL, `pod_request_cpu` decimal(14,3) DEFAULT NULL,
`pod_request_memory` int(11) DEFAULT NULL, `pod_request_memory` int(11) DEFAULT NULL,
`limits_cpu` decimal(14,3) DEFAULT NULL, `limits_cpu` decimal(14,3) DEFAULT NULL,
`k8s` varchar(100) DEFAULT NULL, `cluster_code` bigint(20) NOT NULL DEFAULT '0',
`create_time` datetime DEFAULT NULL COMMENT 'create time', `create_time` datetime DEFAULT NULL COMMENT 'create time',
`update_time` datetime DEFAULT NULL COMMENT 'update time', `update_time` datetime DEFAULT NULL COMMENT 'update time',
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
UNIQUE KEY `k8s_namespace_unique` (`namespace`,`k8s`) UNIQUE KEY `k8s_namespace_unique` (`namespace`,`cluster_code`)
) ENGINE= INNODB AUTO_INCREMENT= 1 DEFAULT CHARSET= utf8; ) ENGINE= INNODB AUTO_INCREMENT= 1 DEFAULT CHARSET= utf8;
-- ---------------------------- -- ----------------------------

6
dolphinscheduler-dao/src/main/resources/sql/upgrade/3.0.0_schema/postgresql/dolphinscheduler_ddl.sql

@ -242,19 +242,19 @@ EXECUTE 'CREATE TABLE IF NOT EXISTS '|| quote_ident(v_schema) ||'."t_ds_k8s" (
EXECUTE 'CREATE TABLE IF NOT EXISTS '|| quote_ident(v_schema) ||'."t_ds_k8s_namespace" ( EXECUTE 'CREATE TABLE IF NOT EXISTS '|| quote_ident(v_schema) ||'."t_ds_k8s_namespace" (
id serial NOT NULL, id serial NOT NULL,
code bigint NOT NULL,
limits_memory int DEFAULT NULL , limits_memory int DEFAULT NULL ,
namespace varchar(100) DEFAULT NULL , namespace varchar(100) DEFAULT NULL ,
online_job_num int DEFAULT NULL,
user_id int DEFAULT NULL, user_id int DEFAULT NULL,
pod_replicas int DEFAULT NULL, pod_replicas int DEFAULT NULL,
pod_request_cpu NUMERIC(13,4) NULL, pod_request_cpu NUMERIC(13,4) NULL,
pod_request_memory int DEFAULT NULL, pod_request_memory int DEFAULT NULL,
limits_cpu NUMERIC(13,4) NULL, limits_cpu NUMERIC(13,4) NULL,
k8s varchar(100) DEFAULT NULL, cluster_code bigint NOT NULL,
create_time timestamp DEFAULT NULL , create_time timestamp DEFAULT NULL ,
update_time timestamp DEFAULT NULL , update_time timestamp DEFAULT NULL ,
PRIMARY KEY (id) , PRIMARY KEY (id) ,
CONSTRAINT k8s_namespace_unique UNIQUE (namespace,k8s) CONSTRAINT k8s_namespace_unique UNIQUE (namespace,cluster_code)
)'; )';
EXECUTE 'CREATE TABLE IF NOT EXISTS '|| quote_ident(v_schema) ||'."t_ds_relation_namespace_user" ( EXECUTE 'CREATE TABLE IF NOT EXISTS '|| quote_ident(v_schema) ||'."t_ds_relation_namespace_user" (

6
dolphinscheduler-dao/src/test/java/org/apache/dolphinscheduler/dao/mapper/K8sNamespaceMapperTest.java

@ -23,7 +23,6 @@ import org.apache.dolphinscheduler.dao.entity.K8sNamespace;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import org.apache.dolphinscheduler.dao.entity.User;
import org.junit.After; import org.junit.After;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
@ -46,13 +45,14 @@ public class K8sNamespaceMapperTest extends BaseDaoTest {
private K8sNamespace insertOne() { private K8sNamespace insertOne() {
//insertOne //insertOne
K8sNamespace k8sNamespace = new K8sNamespace(); K8sNamespace k8sNamespace = new K8sNamespace();
k8sNamespace.setCode(999L);
k8sNamespace.setNamespace("testNamespace"); k8sNamespace.setNamespace("testNamespace");
k8sNamespace.setK8s("ds_null_k8s"); k8sNamespace.setClusterCode(100L);
k8sNamespace.setClusterName("ds_null_k8s");
k8sNamespace.setLimitsCpu(100.0); k8sNamespace.setLimitsCpu(100.0);
k8sNamespace.setLimitsMemory(100); k8sNamespace.setLimitsMemory(100);
k8sNamespace.setCreateTime(new Date()); k8sNamespace.setCreateTime(new Date());
k8sNamespace.setUpdateTime(new Date()); k8sNamespace.setUpdateTime(new Date());
k8sNamespace.setId(1);
k8sNamespaceMapper.insert(k8sNamespace); k8sNamespaceMapper.insert(k8sNamespace);
return k8sNamespace; return k8sNamespace;
} }

2
dolphinscheduler-ui/src/locales/en_US/security.ts

@ -269,8 +269,6 @@ export default {
k8s_namespace_tips: 'Please enter k8s namespace', k8s_namespace_tips: 'Please enter k8s namespace',
k8s_cluster: 'K8S Cluster', k8s_cluster: 'K8S Cluster',
k8s_cluster_tips: 'Please enter k8s cluster', k8s_cluster_tips: 'Please enter k8s cluster',
owner: 'Owner',
owner_tips: 'Please enter owner',
limit_cpu: 'Limit CPU', limit_cpu: 'Limit CPU',
limit_cpu_tips: 'Please enter limit CPU', limit_cpu_tips: 'Please enter limit CPU',
limit_memory: 'Limit Memory', limit_memory: 'Limit Memory',

2
dolphinscheduler-ui/src/locales/zh_CN/security.ts

@ -269,8 +269,6 @@ export default {
k8s_namespace_tips: '请输入k8s命名空间', k8s_namespace_tips: '请输入k8s命名空间',
k8s_cluster: 'K8S集群', k8s_cluster: 'K8S集群',
k8s_cluster_tips: '请输入k8s集群', k8s_cluster_tips: '请输入k8s集群',
owner: '负责人',
owner_tips: '请输入负责人',
limit_cpu: '最大CPU', limit_cpu: '最大CPU',
limit_cpu_tips: '请输入最大CPU', limit_cpu_tips: '请输入最大CPU',
limit_memory: '最大内存', limit_memory: '最大内存',

2
dolphinscheduler-ui/src/service/modules/k8s-namespace/types.ts

@ -23,7 +23,7 @@ interface ListReq {
interface K8SReq { interface K8SReq {
namespace: string namespace: string
k8s: string clusterCode: string
owner?: string owner?: string
tag?: string tag?: string
limitsCpu?: number | string limitsCpu?: number | string

213
dolphinscheduler-ui/src/views/security/k8s-namespace-manage/components/k8s-namespace-modal.tsx

@ -22,7 +22,8 @@ import {
NFormItem, NFormItem,
NInput, NInput,
NInputGroup, NInputGroup,
NInputGroupLabel NInputGroupLabel,
NSelect
} from 'naive-ui' } from 'naive-ui'
import { useModal } from './use-modal' import { useModal } from './use-modal'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
@ -45,13 +46,13 @@ const K8sNamespaceModal = defineComponent({
}, },
emits: ['cancelModal', 'confirmModal'], emits: ['cancelModal', 'confirmModal'],
setup(props, ctx) { setup(props, ctx) {
const { variables, handleValidate } = useModal(props, ctx) const { variables, handleValidate, getListData } = useModal(props, ctx)
const { t } = useI18n() const { t } = useI18n()
const cancelModal = () => { const cancelModal = () => {
if (props.statusRef === 0) { if (props.statusRef === 0) {
variables.model.namespace = '' variables.model.namespace = ''
variables.model.k8s = '' variables.model.clusterCode = ''
variables.model.limitsCpu = '' variables.model.limitsCpu = ''
variables.model.limitsMemory = '' variables.model.limitsMemory = ''
variables.model.userId = '' variables.model.userId = ''
@ -64,35 +65,42 @@ const K8sNamespaceModal = defineComponent({
} }
watch( watch(
() => props.statusRef, () => props.showModalRef,
() => { () => {
if (props.statusRef === 0) { props.showModalRef && getListData()
variables.model.namespace = '' }
variables.model.k8s = '' )
variables.model.limitsCpu = ''
variables.model.limitsMemory = '' watch(
variables.model.userId = '' () => props.statusRef,
} else { () => {
if (props.statusRef === 0) {
variables.model.namespace = ''
variables.model.clusterCode = ''
variables.model.limitsCpu = ''
variables.model.limitsMemory = ''
variables.model.userId = ''
} else {
variables.model.id = props.row.id
variables.model.namespace = props.row.namespace
variables.model.clusterCode = props.row.clusterCode
variables.model.limitsCpu = props.row.limitsCpu + ''
variables.model.limitsMemory = props.row.limitsMemory + ''
variables.model.userId = props.row.userId
}
}
)
watch(
() => props.row,
() => {
variables.model.id = props.row.id variables.model.id = props.row.id
variables.model.namespace = props.row.namespace variables.model.namespace = props.row.namespace
variables.model.k8s = props.row.k8s variables.model.clusterCode = props.row.clusterCode
variables.model.limitsCpu = props.row.limitsCpu + '' variables.model.limitsCpu = props.row.limitsCpu + ''
variables.model.limitsMemory = props.row.limitsMemory + '' variables.model.limitsMemory = props.row.limitsMemory + ''
variables.model.userId = props.row.userId variables.model.userId = props.row.userId
} }
}
)
watch(
() => props.row,
() => {
variables.model.id = props.row.id
variables.model.namespace = props.row.namespace
variables.model.k8s = props.row.k8s
variables.model.limitsCpu = props.row.limitsCpu + ''
variables.model.limitsMemory = props.row.limitsMemory + ''
variables.model.userId = props.row.userId
}
) )
return { t, ...toRefs(variables), cancelModal, confirmModal } return { t, ...toRefs(variables), cancelModal, confirmModal }
@ -100,87 +108,78 @@ const K8sNamespaceModal = defineComponent({
render() { render() {
const { t } = this const { t } = this
return ( return (
<div> <div>
<Modal <Modal
title={ title={
this.statusRef === 0 this.statusRef === 0
? t('security.k8s_namespace.create_namespace') ? t('security.k8s_namespace.create_namespace')
: t('security.k8s_namespace.edit_namespace') : t('security.k8s_namespace.edit_namespace')
} }
show={this.showModalRef} show={this.showModalRef}
onCancel={this.cancelModal} onCancel={this.cancelModal}
onConfirm={this.confirmModal} onConfirm={this.confirmModal}
confirmDisabled={!this.model.namespace || !this.model.k8s} confirmDisabled={!this.model.namespace || (this.model.clusterCode == null || this.model.clusterCode === '')}
confirmLoading={this.saving} confirmLoading={this.saving}
> >
{{ {{
default: () => ( default: () => (
<NForm <NForm
model={this.model} model={this.model}
rules={this.rules} rules={this.rules}
ref='k8sNamespaceFormRef' ref='k8sNamespaceFormRef'
> >
<NFormItem <NFormItem
label={t('security.k8s_namespace.k8s_namespace')} label={t('security.k8s_namespace.k8s_namespace')}
path='namespace' path='namespace'
> >
<NInput <NInput
placeholder={t('security.k8s_namespace.k8s_namespace_tips')} placeholder={t('security.k8s_namespace.k8s_namespace_tips')}
v-model={[this.model.namespace, 'value']} v-model={[this.model.namespace, 'value']}
disabled={this.statusRef !== 0} disabled={this.statusRef !== 0}
/> />
</NFormItem> </NFormItem>
<NFormItem <NFormItem
label={t('security.k8s_namespace.k8s_cluster')} label={t('security.k8s_namespace.k8s_cluster')}
path='k8s' path='clusterCode'
> >
<NInput <NSelect
placeholder={t('security.k8s_namespace.k8s_cluster_tips')} placeholder={t('security.k8s_namespace.k8s_cluster_tips')}
v-model={[this.model.k8s, 'value']} options={this.model.clusterOptions}
disabled={this.statusRef !== 0} v-model={[this.model.clusterCode, 'value']}
/> disabled={this.statusRef !== 0}
</NFormItem> />
<NFormItem </NFormItem>
label={t('security.k8s_namespace.limit_cpu')} <NFormItem
path='limitsCpu' label={t('security.k8s_namespace.limit_cpu')}
> path='limitsCpu'
<NInputGroup> >
<NInput <NInputGroup>
placeholder={t('security.k8s_namespace.limit_cpu_tips')} <NInput
v-model={[this.model.limitsCpu, 'value']} placeholder={t('security.k8s_namespace.limit_cpu_tips')}
/> v-model={[this.model.limitsCpu, 'value']}
<NInputGroupLabel>CORE</NInputGroupLabel> />
</NInputGroup> <NInputGroupLabel>CORE</NInputGroupLabel>
</NFormItem> </NInputGroup>
<NFormItem </NFormItem>
label={t('security.k8s_namespace.limit_memory')} <NFormItem
path='limitsMemory' label={t('security.k8s_namespace.limit_memory')}
> path='limitsMemory'
<NInputGroup> >
<NInput <NInputGroup>
placeholder={t( <NInput
'security.k8s_namespace.limit_memory_tips' placeholder={t(
)} 'security.k8s_namespace.limit_memory_tips'
v-model={[this.model.limitsMemory, 'value']} )}
/> v-model={[this.model.limitsMemory, 'value']}
<NInputGroupLabel>GB</NInputGroupLabel> />
</NInputGroup> <NInputGroupLabel>GB</NInputGroupLabel>
</NFormItem> </NInputGroup>
<NFormItem </NFormItem>
label={t('security.k8s_namespace.owner')} </NForm>
path='userId' )
> }}
<NInput </Modal>
placeholder={t('security.k8s_namespace.owner_tips')} </div>
v-model={[this.model.userId, 'value']}
disabled={this.statusRef !== 0}
/>
</NFormItem>
</NForm>
)
}}
</Modal>
</div>
) )
} }
}) })

54
dolphinscheduler-ui/src/views/security/k8s-namespace-manage/components/use-modal.ts

@ -22,10 +22,12 @@ import {
createK8sNamespace, createK8sNamespace,
updateK8sNamespace updateK8sNamespace
} from '@/service/modules/k8s-namespace' } from '@/service/modules/k8s-namespace'
import { queryAllClusterList } from '@/service/modules/cluster'
import { useAsyncState } from '@vueuse/core'
export function useModal( export function useModal(
props: any, props: any,
ctx: SetupContext<('cancelModal' | 'confirmModal')[]> ctx: SetupContext<('cancelModal' | 'confirmModal')[]>
) { ) {
const { t } = useI18n() const { t } = useI18n()
@ -34,10 +36,11 @@ export function useModal(
model: { model: {
id: ref<number>(-1), id: ref<number>(-1),
namespace: ref(''), namespace: ref(''),
k8s: ref(''), clusterCode: ref(''),
userId: ref(''), userId: ref(''),
limitsCpu: ref(''), limitsCpu: ref(''),
limitsMemory: ref('') limitsMemory: ref(''),
clusterOptions: []
}, },
saving: false, saving: false,
rules: { rules: {
@ -50,11 +53,11 @@ export function useModal(
} }
} }
}, },
k8s: { clusterCode: {
required: true, required: true,
trigger: ['input', 'blur'], trigger: ['input', 'blur'],
validator() { validator() {
if (variables.model.k8s === '') { if (variables.model.clusterCode === '') {
return new Error(t('security.k8s_namespace.k8s_cluster_tips')) return new Error(t('security.k8s_namespace.k8s_cluster_tips'))
} }
} }
@ -70,19 +73,43 @@ export function useModal(
try { try {
statusRef === 0 statusRef === 0
? await submitK8SNamespaceModal() ? await submitK8SNamespaceModal()
: await updateK8SNamespaceModal() : await updateK8SNamespaceModal()
variables.saving = false variables.saving = false
} catch (err) { } catch (err) {
variables.saving = false variables.saving = false
} }
} }
const getListData = () => {
const { state } = useAsyncState(
queryAllClusterList().then((res: any) => {
variables.model.clusterOptions = res
.filter((item: any) => {
if (item.config) {
const k8s = JSON.parse(item.config).k8s
return !!k8s
}
return false
})
.map((item: any) => {
return {
label: item.name,
value: item.code
}
})
}),
{}
)
return state
}
const submitK8SNamespaceModal = () => { const submitK8SNamespaceModal = () => {
verifyNamespaceK8s(variables.model).then(() => { verifyNamespaceK8s(variables.model).then(() => {
createK8sNamespace(variables.model).then(() => { createK8sNamespace(variables.model).then(() => {
variables.model.namespace = '' variables.model.namespace = ''
variables.model.k8s = '' variables.model.clusterCode = ''
variables.model.limitsCpu = '' variables.model.limitsCpu = ''
variables.model.limitsMemory = '' variables.model.limitsMemory = ''
variables.model.userId = '' variables.model.userId = ''
@ -93,14 +120,15 @@ export function useModal(
const updateK8SNamespaceModal = () => { const updateK8SNamespaceModal = () => {
updateK8sNamespace(variables.model, variables.model.id).then( updateK8sNamespace(variables.model, variables.model.id).then(
(ignored: any) => { (ignored: any) => {
ctx.emit('confirmModal', props.showModalRef) ctx.emit('confirmModal', props.showModalRef)
} }
) )
} }
return { return {
variables, variables,
handleValidate handleValidate,
getListData
} }
} }

145
dolphinscheduler-ui/src/views/security/k8s-namespace-manage/use-table.ts

@ -50,9 +50,9 @@ export function useTable() {
getTableData({ getTableData({
pageSize: variables.pageSize, pageSize: variables.pageSize,
pageNo: pageNo:
variables.tableData.length === 1 && variables.page > 1 variables.tableData.length === 1 && variables.page > 1
? variables.page - 1 ? variables.page - 1
: variables.page, : variables.page,
searchVal: variables.searchVal searchVal: variables.searchVal
}) })
}) })
@ -73,14 +73,9 @@ export function useTable() {
}, },
{ {
title: t('security.k8s_namespace.k8s_cluster'), title: t('security.k8s_namespace.k8s_cluster'),
key: 'k8s', key: 'clusterName',
...COLUMN_WIDTH_CONFIG['name'] ...COLUMN_WIDTH_CONFIG['name']
}, },
{
title: t('security.k8s_namespace.owner'),
key: 'userId',
...COLUMN_WIDTH_CONFIG['userName']
},
{ {
title: t('security.k8s_namespace.limit_cpu'), title: t('security.k8s_namespace.limit_cpu'),
key: 'limitsCpu', key: 'limitsCpu',
@ -109,61 +104,61 @@ export function useTable() {
return h(NSpace, null, { return h(NSpace, null, {
default: () => [ default: () => [
h( h(
NTooltip, NTooltip,
{}, {},
{ {
trigger: () => trigger: () =>
h( h(
NButton,
{
circle: true,
type: 'info',
size: 'small',
onClick: () => {
handleEdit(row)
}
},
{
icon: () =>
h(NIcon, null, { default: () => h(EditOutlined) })
}
),
default: () => t('security.k8s_namespace.edit')
}
),
h(
NPopconfirm,
{
onPositiveClick: () => {
handleDelete(row)
}
},
{
trigger: () =>
h(
NTooltip,
{},
{
trigger: () =>
h(
NButton, NButton,
{ {
circle: true, circle: true,
type: 'error', type: 'info',
size: 'small' size: 'small',
onClick: () => {
handleEdit(row)
}
}, },
{ {
icon: () => icon: () =>
h(NIcon, null, { h(NIcon, null, { default: () => h(EditOutlined) })
default: () => h(DeleteOutlined)
})
} }
), ),
default: () => t('security.k8s_namespace.delete') default: () => t('security.k8s_namespace.edit')
} }
), ),
default: () => t('security.k8s_namespace.delete_confirm') h(
} NPopconfirm,
{
onPositiveClick: () => {
handleDelete(row)
}
},
{
trigger: () =>
h(
NTooltip,
{},
{
trigger: () =>
h(
NButton,
{
circle: true,
type: 'error',
size: 'small'
},
{
icon: () =>
h(NIcon, null, {
default: () => h(DeleteOutlined)
})
}
),
default: () => t('security.k8s_namespace.delete')
}
),
default: () => t('security.k8s_namespace.delete_confirm')
}
) )
] ]
}) })
@ -193,24 +188,24 @@ export function useTable() {
if (variables.loadingRef) return if (variables.loadingRef) return
variables.loadingRef = true variables.loadingRef = true
const { state } = useAsyncState( const { state } = useAsyncState(
queryNamespaceListPaging({ ...params }).then((res: NamespaceListRes) => { queryNamespaceListPaging({ ...params }).then((res: NamespaceListRes) => {
variables.tableData = res.totalList.map((item, unused) => { variables.tableData = res.totalList.map((item, unused) => {
item.createTime = format( item.createTime = format(
parseTime(item.createTime), parseTime(item.createTime),
'yyyy-MM-dd HH:mm:ss' 'yyyy-MM-dd HH:mm:ss'
) )
item.updateTime = format( item.updateTime = format(
parseTime(item.updateTime), parseTime(item.updateTime),
'yyyy-MM-dd HH:mm:ss' 'yyyy-MM-dd HH:mm:ss'
) )
return { return {
...item ...item
} }
}) as any }) as any
variables.totalPage = res.totalPage variables.totalPage = res.totalPage
variables.loadingRef = false variables.loadingRef = false
}), }),
{} {}
) )
return state return state

Loading…
Cancel
Save