This is an automated email from the ASF dual-hosted git repository.
caishunfeng pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/dolphinscheduler.git
The following commit(s) were added to refs/heads/dev by this push:
new 1511005 [Feature][api] Task can run on kubernetes - k8s client and
namespace #8247 (#8252)
1511005 is described below
commit 151100562f9e2751426ccca08aa71451a3f1614b
Author: qianli2022 <[email protected]>
AuthorDate: Tue Feb 15 10:21:15 2022 +0800
[Feature][api] Task can run on kubernetes - k8s client and namespace #8247
(#8252)
* add db operator for namespace
* add k8s client
* add k8s controller
* add namespace ui
* add licenses
* add kubernetes model known-dependencies
* add new licenses
* fix SonarCloud Code Analysis bug
* remove license for standard protocol
* fix variable MemoryStr to memoryStr
Co-authored-by: qianl4 <[email protected]>
---
.../api/controller/K8sNamespaceController.java | 214 ++++++++++++++
.../apache/dolphinscheduler/api/enums/Status.java | 9 +
.../api/service/K8sNameSpaceService.java | 85 ++++++
.../api/service/impl/K8sNameSpaceServiceImpl.java | 326 +++++++++++++++++++++
.../api/controller/K8sNamespaceControllerTest.java | 155 ++++++++++
.../api/service/K8sNameSpaceServiceTest.java | 189 ++++++++++++
.../apache/dolphinscheduler/common/Constants.java | 7 +
.../apache/dolphinscheduler/dao/entity/K8s.java | 103 +++++++
.../dolphinscheduler/dao/entity/K8sNamespace.java | 197 +++++++++++++
.../dolphinscheduler/dao/mapper/K8sMapper.java | 29 ++
.../dao/mapper/K8sNamespaceMapper.java | 49 ++++
.../dao/mapper/K8sNamespaceMapper.xml | 48 +++
.../src/main/resources/sql/dolphinscheduler_h2.sql | 39 ++-
.../main/resources/sql/dolphinscheduler_mysql.sql | 37 ++-
.../resources/sql/dolphinscheduler_postgresql.sql | 39 ++-
.../2.1.0_schema/mysql/dolphinscheduler_ddl.sql | 36 +++
.../postgresql/dolphinscheduler_ddl.sql | 26 ++
dolphinscheduler-dist/release-docs/LICENSE | 28 ++
.../release-docs/licenses/LICENSE-automaton.txt | 24 ++
.../e2e/pages/security/NamespacePage.java | 94 ++++++
.../e2e/pages/security/SecurityPage.java | 7 +
dolphinscheduler-service/pom.xml | 4 +
.../service/k8s/K8sClientService.java | 118 ++++++++
.../dolphinscheduler/service/k8s/K8sManager.java | 86 ++++++
.../service/k8s/K8sManagerTest.java | 78 +++++
.../pages/namespace/_source/createNamespace.vue | 219 ++++++++++++++
.../security/pages/namespace/_source/list.vue | 110 +++++++
.../home/pages/security/pages/namespace/index.vue | 160 ++++++++++
.../src/js/conf/home/router/module/security.js | 8 +
.../src/js/conf/home/store/security/actions.js | 63 ++++
.../components/secondaryMenu/_source/menu.js | 10 +
.../src/js/module/i18n/locale/en_US.js | 16 +-
.../src/js/module/i18n/locale/zh_CN.js | 16 +-
pom.xml | 7 +
tools/dependencies/known-dependencies.txt | 28 ++
35 files changed, 2659 insertions(+), 5 deletions(-)
diff --git
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/K8sNamespaceController.java
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/K8sNamespaceController.java
new file mode 100644
index 0000000..ddae560
--- /dev/null
+++
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/K8sNamespaceController.java
@@ -0,0 +1,214 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dolphinscheduler.api.controller;
+
+import static
org.apache.dolphinscheduler.api.enums.Status.CREATE_K8S_NAMESPACE_ERROR;
+import static
org.apache.dolphinscheduler.api.enums.Status.DELETE_K8S_NAMESPACE_BY_ID_ERROR;
+import static
org.apache.dolphinscheduler.api.enums.Status.QUERY_K8S_NAMESPACE_LIST_PAGING_ERROR;
+import static
org.apache.dolphinscheduler.api.enums.Status.UPDATE_K8S_NAMESPACE_ERROR;
+import static
org.apache.dolphinscheduler.api.enums.Status.VERIFY_K8S_NAMESPACE_ERROR;
+
+import org.apache.dolphinscheduler.api.aspect.AccessLogAnnotation;
+import org.apache.dolphinscheduler.api.exceptions.ApiException;
+import org.apache.dolphinscheduler.api.service.K8sNameSpaceService;
+import org.apache.dolphinscheduler.api.utils.Result;
+import org.apache.dolphinscheduler.common.Constants;
+import org.apache.dolphinscheduler.common.utils.ParameterUtils;
+import org.apache.dolphinscheduler.dao.entity.User;
+
+import java.util.Map;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestAttribute;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestController;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import springfox.documentation.annotations.ApiIgnore;
+
+/**
+ * k8s namespace controller
+ */
+@Api(tags = "K8S_NAMESPACE_TAG")
+@RestController
+@RequestMapping("/k8s-namespace")
+public class K8sNamespaceController extends BaseController {
+
+ @Autowired
+ private K8sNameSpaceService k8sNameSpaceService;
+
+ /**
+ * query namespace list paging
+ *
+ * @param loginUser login user
+ * @param searchVal search value
+ * @param pageSize page size
+ * @param pageNo page number
+ * @return namespace list which the login user have permission to see
+ */
+ @ApiOperation(value = "queryNamespaceListPaging", notes =
"QUERY_NAMESPACE_LIST_PAGING_NOTES")
+ @ApiImplicitParams({
+ @ApiImplicitParam(name = "searchVal", value = "SEARCH_VAL",
dataType = "String"),
+ @ApiImplicitParam(name = "pageSize", value = "PAGE_SIZE", required
= true, dataType = "Int", example = "10"),
+ @ApiImplicitParam(name = "pageNo", value = "PAGE_NO", required =
true, dataType = "Int", example = "1")
+ })
+ @GetMapping()
+ @ResponseStatus(HttpStatus.OK)
+ @ApiException(QUERY_K8S_NAMESPACE_LIST_PAGING_ERROR)
+ @AccessLogAnnotation(ignoreRequestArgs = "loginUser")
+ public Result queryProjectListPaging(@ApiIgnore @RequestAttribute(value =
Constants.SESSION_USER) User loginUser,
+ @RequestParam(value = "searchVal",
required = false) String searchVal,
+ @RequestParam("pageSize") Integer
pageSize,
+ @RequestParam("pageNo") Integer pageNo
+ ) {
+
+ Result result = checkPageParams(pageNo, pageSize);
+ if (!result.checkResult()) {
+ return result;
+ }
+ searchVal = ParameterUtils.handleEscapes(searchVal);
+ result = k8sNameSpaceService.queryListPaging(loginUser, searchVal,
pageNo, pageSize);
+ return result;
+ }
+
+
+ /**
+ * create namespace,if not exist on k8s,will create,if exist only register
in db
+ *
+ * @param loginUser
+ * @param namespace k8s namespace
+ * @param owner owner
+ * @param tag Which type of job is available, can be empty, all
available
+ * @param k8s k8s name
+ * @param limitsCpu max cpu
+ * @param limitsMemory max memory
+ * @return
+ */
+ @ApiOperation(value = "createK8sNamespace", notes =
"CREATE_NAMESPACE_NOTES")
+ @ApiImplicitParams({
+ @ApiImplicitParam(name = "namespace", value = "NAMESPACE",
required = true, dataType = "String"),
+ @ApiImplicitParam(name = "owner", value = "OWNER", required =
false, dataType = "String"),
+ @ApiImplicitParam(name = "tag", value = "TAG", required = false,
dataType = "String"),
+ @ApiImplicitParam(name = "k8s", value = "K8S", required = true,
dataType = "String"),
+ @ApiImplicitParam(name = "limits_cpu", value = "LIMITS_CPU",
required = false, dataType = "Double"),
+ @ApiImplicitParam(name = "limits_memory", value = "LIMITS_MEMORY",
required = false, dataType = "Integer")
+ })
+ @PostMapping()
+ @ResponseStatus(HttpStatus.CREATED)
+ @ApiException(CREATE_K8S_NAMESPACE_ERROR)
+ @AccessLogAnnotation(ignoreRequestArgs = "loginUser")
+ public Result createNamespace(@ApiIgnore @RequestAttribute(value =
Constants.SESSION_USER) User loginUser,
+ @RequestParam(value = "namespace") String
namespace,
+ @RequestParam(value = "k8s") String k8s,
+ @RequestParam(value = "owner", required =
false) String owner,
+ @RequestParam(value = "tag", required =
false) String tag,
+ @RequestParam(value = "limitsCpu", required
= false) Double limitsCpu,
+ @RequestParam(value = "limitsMemory",
required = false) Integer limitsMemory
+ ) {
+ Map<String, Object> result =
k8sNameSpaceService.createK8sNamespace(loginUser, namespace, k8s, owner, tag,
limitsCpu, limitsMemory);
+ return returnDataList(result);
+ }
+
+ /**
+ * update namespace,namespace and k8s not allowed update, because may
create on k8s,can delete and create new instead
+ *
+ * @param loginUser
+ * @param owner owner
+ * @param tag Which type of job is available,such as flink,means
only flink job can use, can be empty, all available
+ * @param limitsCpu max cpu
+ * @param limitsMemory max memory
+ * @return
+ */
+ @ApiOperation(value = "updateK8sNamespace", notes =
"UPDATE_NAMESPACE_NOTES")
+ @ApiImplicitParams({
+ @ApiImplicitParam(name = "id", value = "K8S_NAMESPACE_ID",
required = true, dataType = "Int", example = "100"),
+ @ApiImplicitParam(name = "owner", value = "OWNER", required =
false, dataType = "String"),
+ @ApiImplicitParam(name = "tag", value = "TAG", required = false,
dataType = "String"),
+ @ApiImplicitParam(name = "limitsCpu", value = "LIMITS_CPU",
required = false, dataType = "Double"),
+ @ApiImplicitParam(name = "limitsMemory", value = "LIMITS_MEMORY",
required = false, dataType = "Integer")})
+ @PutMapping(value = "/{id}")
+ @ResponseStatus(HttpStatus.CREATED)
+ @ApiException(UPDATE_K8S_NAMESPACE_ERROR)
+ @AccessLogAnnotation(ignoreRequestArgs = "loginUser")
+ public Result updateNamespace(@ApiIgnore @RequestAttribute(value =
Constants.SESSION_USER) User loginUser,
+ @PathVariable(value = "id") int id,
+ @RequestParam(value = "owner", required =
false) String owner,
+ @RequestParam(value = "tag", required =
false) String tag,
+ @RequestParam(value = "limitsCpu", required
= false) Double limitsCpu,
+ @RequestParam(value = "limitsMemory",
required = false) Integer limitsMemory) {
+ Map<String, Object> result =
k8sNameSpaceService.updateK8sNamespace(loginUser, id, owner, tag, limitsCpu,
limitsMemory);
+ return returnDataList(result);
+ }
+
+ /**
+ * verify namespace and k8s,one k8s namespace is unique
+ *
+ * @param loginUser login user
+ * @param namespace namespace
+ * @param k8s k8s
+ * @return true if the k8s and namespace not exists, otherwise return false
+ */
+ @ApiOperation(value = "verifyNamespaceK8s", notes =
"VERIFY_NAMESPACE_K8S_NOTES")
+ @ApiImplicitParams({
+ @ApiImplicitParam(name = "namespace", value = "NAMESPACE",
required = true, dataType = "String"),
+ @ApiImplicitParam(name = "k8s", value = "K8S", required = true,
dataType = "String")
+ })
+ @PostMapping(value = "/verify")
+ @ResponseStatus(HttpStatus.OK)
+ @ApiException(VERIFY_K8S_NAMESPACE_ERROR)
+ @AccessLogAnnotation(ignoreRequestArgs = "loginUser")
+ public Result verifyNamespace(@ApiIgnore @RequestAttribute(value =
Constants.SESSION_USER) User loginUser,
+ @RequestParam(value = "namespace") String
namespace,
+ @RequestParam(value = "k8s") String k8s
+ ) {
+
+ return k8sNameSpaceService.verifyNamespaceK8s(namespace, k8s);
+ }
+
+
+ /**
+ * delete namespace by id
+ *
+ * @param loginUser login user
+ * @param id namespace id
+ * @return delete result code
+ */
+ @ApiOperation(value = "delNamespaceById", notes =
"DELETE_NAMESPACE_BY_ID_NOTES")
+ @ApiImplicitParams({
+ @ApiImplicitParam(name = "id", value = "NAMESPACE_ID", required =
true, dataType = "Int", example = "100")
+ })
+ @PostMapping(value = "/delete")
+ @ResponseStatus(HttpStatus.OK)
+ @ApiException(DELETE_K8S_NAMESPACE_BY_ID_ERROR)
+ @AccessLogAnnotation
+ public Result delNamespaceById(@ApiIgnore @RequestAttribute(value =
Constants.SESSION_USER) User loginUser,
+ @RequestParam(value = "id") int id) {
+ Map<String, Object> result =
k8sNameSpaceService.deleteNamespaceById(loginUser, id);
+ return returnDataList(result);
+ }
+}
diff --git
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/enums/Status.java
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/enums/Status.java
index 5bb6a2f..1f6add9 100644
---
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/enums/Status.java
+++
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/enums/Status.java
@@ -380,6 +380,15 @@ public enum Status {
TASK_GROUP_STATUS_OPENED(130019,"The task group has been
opened.","任务组已经被开启"),
NOT_ALLOW_TO_DISABLE_OWN_ACCOUNT(130020, "Not allow to disable your own
account", "不能停用自己的账号"),
NOT_ALLOW_TO_DELETE_DEFAULT_ALARM_GROUP(130030, "Not allow to delete the
default alarm group ", "不能删除默认告警组"),
+
+ QUERY_K8S_NAMESPACE_LIST_PAGING_ERROR(1300001, "login user query k8s
namespace list paging error", "分页查询k8s名称空间列表错误"),
+ K8S_NAMESPACE_EXIST(1300002, "k8s namespace {0} already exists",
"k8s命名空间[{0}]已存在"),
+ CREATE_K8S_NAMESPACE_ERROR(1300003, "create k8s namespace error",
"创建k8s命名空间错误"),
+ UPDATE_K8S_NAMESPACE_ERROR(1300004, "update k8s namespace error",
"更新k8s命名空间信息错误"),
+ K8S_NAMESPACE_NOT_EXIST(1300005, "k8s namespace {0} not exists",
"命名空间ID[{0}]不存在"),
+ K8S_CLIENT_OPS_ERROR(1300006, "k8s error with exception {0}",
"k8s操作报错[{0}]"),
+ VERIFY_K8S_NAMESPACE_ERROR(1300007, "verify k8s and namespace error",
"验证k8s命名空间信息错误"),
+ DELETE_K8S_NAMESPACE_BY_ID_ERROR(1300008, "delete k8s namespace by id
error", "删除命名空间错误"),
;
private final int code;
diff --git
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/K8sNameSpaceService.java
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/K8sNameSpaceService.java
new file mode 100644
index 0000000..c9156a3
--- /dev/null
+++
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/K8sNameSpaceService.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dolphinscheduler.api.service;
+
+import org.apache.dolphinscheduler.api.utils.Result;
+import org.apache.dolphinscheduler.dao.entity.User;
+
+import java.util.Map;
+
+/**
+ * k8s namespace service impl
+ */
+public interface K8sNameSpaceService {
+ /**
+ * query namespace list paging
+ *
+ * @param loginUser login user
+ * @param pageNo page number
+ * @param searchVal search value
+ * @param pageSize page size
+ * @return k8s namespace list
+ */
+ 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
+ *
+ * @param loginUser login user
+ * @param namespace namespace
+ * @param k8s k8s not null
+ * @param owner owner can null
+ * @param tag can null,if set means just used for one type
job,such as flink,spark
+ * @param limitsCpu limits cpu, can null means not limit
+ * @param limitsMemory limits memory, can null means not limit
+ * @return
+ */
+ Map<String, Object> createK8sNamespace(User loginUser, String namespace,
String k8s, String owner, String tag, Double limitsCpu, Integer limitsMemory);
+
+
+ /**
+ * update K8s Namespace tag and resource limit
+ *
+ * @param loginUser login user
+ * @param owner owner
+ * @param tag Which type of job is available,such as flink,means
only flink job can use, can be empty, all available
+ * @param limitsCpu max cpu
+ * @param limitsMemory max memory
+ * @return
+ */
+ Map<String, Object> updateK8sNamespace(User loginUser, int id, String
owner, String tag, Double limitsCpu, Integer limitsMemory);
+
+ /**
+ * verify namespace and k8s
+ *
+ * @param namespace namespace
+ * @param k8s k8s
+ * @return true if the k8s and namespace not exists, otherwise return false
+ */
+ Result<Object> verifyNamespaceK8s(String namespace, String k8s);
+
+ /**
+ * delete namespace by id
+ *
+ * @param loginUser login user
+ * @param id namespace id
+ * @return
+ */
+ Map<String, Object> deleteNamespaceById(User loginUser, int id);
+}
diff --git
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/K8sNameSpaceServiceImpl.java
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/K8sNameSpaceServiceImpl.java
new file mode 100644
index 0000000..faa8a24
--- /dev/null
+++
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/K8sNameSpaceServiceImpl.java
@@ -0,0 +1,326 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dolphinscheduler.api.service.impl;
+
+import org.apache.dolphinscheduler.api.enums.Status;
+import org.apache.dolphinscheduler.api.service.K8sNameSpaceService;
+import org.apache.dolphinscheduler.api.utils.PageInfo;
+import org.apache.dolphinscheduler.api.utils.Result;
+import org.apache.dolphinscheduler.common.Constants;
+import org.apache.dolphinscheduler.dao.entity.K8sNamespace;
+import org.apache.dolphinscheduler.dao.entity.User;
+import org.apache.dolphinscheduler.dao.mapper.K8sNamespaceMapper;
+import org.apache.dolphinscheduler.service.k8s.K8sClientService;
+
+import org.apache.commons.lang.StringUtils;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+
+/**
+ * k8s namespace service impl
+ */
+@Service
+public class K8sNameSpaceServiceImpl extends BaseServiceImpl implements
K8sNameSpaceService {
+
+ private static final Logger logger =
LoggerFactory.getLogger(K8sNameSpaceServiceImpl.class);
+
+ private static String resourceYaml = "apiVersion: v1\n"
+ + "kind: ResourceQuota\n"
+ + "metadata:\n"
+ + " name: ${name}\n"
+ + " namespace: ${namespace}\n"
+ + "spec:\n"
+ + " hard:\n"
+ + " ${limitCpu}\n"
+ + " ${limitMemory}\n";
+ @Autowired
+ private K8sNamespaceMapper k8sNamespaceMapper;
+ @Autowired
+ private K8sClientService k8sClientService;
+
+ /**
+ * query namespace list paging
+ *
+ * @param loginUser login user
+ * @param pageNo page number
+ * @param searchVal search value
+ * @param pageSize page size
+ * @return k8s namespace list
+ */
+ @Override
+ public Result queryListPaging(User loginUser, String searchVal, Integer
pageNo, Integer pageSize) {
+ Result result = new Result();
+ if (!isAdmin(loginUser)) {
+ putMsg(result, Status.USER_NO_OPERATION_PERM);
+ return result;
+ }
+
+ Page<K8sNamespace> page = new Page<>(pageNo, pageSize);
+
+ IPage<K8sNamespace> k8sNamespaceList =
k8sNamespaceMapper.queryK8sNamespacePaging(page, searchVal);
+
+ Integer count = (int) k8sNamespaceList.getTotal();
+ PageInfo<K8sNamespace> pageInfo = new PageInfo<>(pageNo, pageSize);
+ pageInfo.setTotal(count);
+ pageInfo.setTotalList(k8sNamespaceList.getRecords());
+ result.setData(pageInfo);
+ putMsg(result, Status.SUCCESS);
+
+ return result;
+ }
+
+ /**
+ * create namespace,if not exist on k8s,will create,if exist only register
in db
+ *
+ * @param loginUser login user
+ * @param namespace namespace
+ * @param k8s k8s not null
+ * @param owner owner can null
+ * @param tag can null,if set means just used for one type
job,such as flink,spark
+ * @param limitsCpu limits cpu, can null means not limit
+ * @param limitsMemory limits memory, can null means not limit
+ * @return
+ */
+ @Override
+ public Map<String, Object> createK8sNamespace(User loginUser, String
namespace, String k8s, String owner, String tag, Double limitsCpu, Integer
limitsMemory) {
+ Map<String, Object> result = new HashMap<>();
+ if (isNotAdmin(loginUser, result)) {
+ return result;
+ }
+
+ if (StringUtils.isEmpty(namespace)) {
+ putMsg(result, Status.REQUEST_PARAMS_NOT_VALID_ERROR,
Constants.NAMESPACE);
+ return result;
+ }
+
+ if (StringUtils.isEmpty(k8s)) {
+ putMsg(result, Status.REQUEST_PARAMS_NOT_VALID_ERROR,
Constants.K8S);
+ return result;
+ }
+
+ if (limitsCpu != null && limitsCpu < 0.0) {
+ putMsg(result, Status.REQUEST_PARAMS_NOT_VALID_ERROR,
Constants.LIMITS_CPU);
+ return result;
+ }
+
+ if (limitsMemory != null && limitsMemory < 0) {
+ putMsg(result, Status.REQUEST_PARAMS_NOT_VALID_ERROR,
Constants.LIMITS_MEMORY);
+ return result;
+ }
+
+ if (checkNamespaceExistInDb(namespace, k8s)) {
+ putMsg(result, Status.K8S_NAMESPACE_EXIST, namespace, k8s);
+ return result;
+ }
+
+ K8sNamespace k8sNamespaceObj = new K8sNamespace();
+ Date now = new Date();
+
+ k8sNamespaceObj.setNamespace(namespace);
+ k8sNamespaceObj.setK8s(k8s);
+ k8sNamespaceObj.setOwner(owner);
+ k8sNamespaceObj.setTag(tag);
+ k8sNamespaceObj.setLimitsCpu(limitsCpu);
+ k8sNamespaceObj.setLimitsMemory(limitsMemory);
+ k8sNamespaceObj.setOnlineJobNum(0);
+ k8sNamespaceObj.setPodReplicas(0);
+ k8sNamespaceObj.setPodRequestCpu(0.0);
+ k8sNamespaceObj.setPodRequestMemory(0);
+ k8sNamespaceObj.setCreateTime(now);
+ k8sNamespaceObj.setUpdateTime(now);
+
+ try {
+ String yamlStr = genDefaultResourceYaml(k8sNamespaceObj);
+ k8sClientService.upsertNamespaceAndResourceToK8s(k8sNamespaceObj,
yamlStr);
+ } catch (Exception e) {
+ logger.error("namespace create to k8s error", e);
+ putMsg(result, Status.K8S_CLIENT_OPS_ERROR, e.getMessage());
+ return result;
+ }
+
+ k8sNamespaceMapper.insert(k8sNamespaceObj);
+ putMsg(result, Status.SUCCESS);
+
+ return result;
+ }
+
+ /**
+ * update K8s Namespace tag and resource limit
+ *
+ * @param loginUser login user
+ * @param owner owner
+ * @param tag Which type of job is available,such as flink,means
only flink job can use, can be empty, all available
+ * @param limitsCpu max cpu
+ * @param limitsMemory max memory
+ * @return
+ */
+ @Override
+ public Map<String, Object> updateK8sNamespace(User loginUser, int id,
String owner, String tag, Double limitsCpu, Integer limitsMemory) {
+ Map<String, Object> result = new HashMap<>();
+ if (isNotAdmin(loginUser, result)) {
+ return result;
+ }
+
+ if (limitsCpu != null && limitsCpu < 0.0) {
+ putMsg(result, Status.REQUEST_PARAMS_NOT_VALID_ERROR,
Constants.LIMITS_CPU);
+ return result;
+ }
+
+ if (limitsMemory != null && limitsMemory < 0) {
+ putMsg(result, Status.REQUEST_PARAMS_NOT_VALID_ERROR,
Constants.LIMITS_MEMORY);
+ return result;
+ }
+
+ K8sNamespace k8sNamespaceObj = k8sNamespaceMapper.selectById(id);
+ if (k8sNamespaceObj == null) {
+ putMsg(result, Status.K8S_NAMESPACE_NOT_EXIST, id);
+ return result;
+ }
+
+ Date now = new Date();
+ k8sNamespaceObj.setTag(tag);
+ k8sNamespaceObj.setLimitsCpu(limitsCpu);
+ k8sNamespaceObj.setLimitsMemory(limitsMemory);
+ k8sNamespaceObj.setUpdateTime(now);
+ k8sNamespaceObj.setOwner(owner);
+ try {
+ String yamlStr = genDefaultResourceYaml(k8sNamespaceObj);
+ k8sClientService.upsertNamespaceAndResourceToK8s(k8sNamespaceObj,
yamlStr);
+ } catch (Exception e) {
+ logger.error("namespace update to k8s error", e);
+ putMsg(result, Status.K8S_CLIENT_OPS_ERROR, e.getMessage());
+ return result;
+ }
+ // update to db
+ k8sNamespaceMapper.updateById(k8sNamespaceObj);
+
+ putMsg(result, Status.SUCCESS);
+ return result;
+ }
+
+ /**
+ * verify namespace and k8s
+ *
+ * @param namespace namespace
+ * @param k8s k8s
+ * @return true if the k8s and namespace not exists, otherwise return false
+ */
+ @Override
+ public Result<Object> verifyNamespaceK8s(String namespace, String k8s) {
+ Result<Object> result = new Result<>();
+ if (StringUtils.isEmpty(namespace)) {
+ putMsg(result, Status.REQUEST_PARAMS_NOT_VALID_ERROR,
Constants.NAMESPACE);
+ return result;
+ }
+
+ if (StringUtils.isEmpty(k8s)) {
+ putMsg(result, Status.REQUEST_PARAMS_NOT_VALID_ERROR,
Constants.K8S);
+ return result;
+ }
+
+ if (checkNamespaceExistInDb(namespace, k8s)) {
+ putMsg(result, Status.K8S_NAMESPACE_EXIST, namespace, k8s);
+ return result;
+ }
+
+ putMsg(result, Status.SUCCESS);
+ return result;
+ }
+
+ /**
+ * delete namespace by id
+ *
+ * @param loginUser login user
+ * @param id namespace id
+ * @return
+ */
+ @Override
+ public Map<String, Object> deleteNamespaceById(User loginUser, int id) {
+ Map<String, Object> result = new HashMap<>();
+ if (isNotAdmin(loginUser, result)) {
+ return result;
+ }
+
+ K8sNamespace k8sNamespaceObj = k8sNamespaceMapper.selectById(id);
+ if (k8sNamespaceObj == null) {
+ putMsg(result, Status.K8S_NAMESPACE_NOT_EXIST, id);
+ return result;
+ }
+
+ k8sClientService.deleteNamespaceToK8s(k8sNamespaceObj.getNamespace(),
k8sNamespaceObj.getK8s());
+ k8sNamespaceMapper.deleteById(id);
+ putMsg(result, Status.SUCCESS);
+ return result;
+ }
+
+ /**
+ * check namespace name exist
+ *
+ * @param namespace namespace
+ * @return true if the k8s and namespace not exists, otherwise return false
+ */
+ private boolean checkNamespaceExistInDb(String namespace, String k8s) {
+ return k8sNamespaceMapper.existNamespace(namespace, k8s) ==
Boolean.TRUE;
+ }
+
+ /**
+ * use cpu memory create yaml
+ *
+ * @param k8sNamespace
+ * @return yaml file
+ */
+ private String genDefaultResourceYaml(K8sNamespace k8sNamespace) {
+ //resource use same name with namespace
+ String name = k8sNamespace.getNamespace();
+ String namespace = k8sNamespace.getNamespace();
+ String cpuStr = null;
+ if (k8sNamespace.getLimitsCpu() != null) {
+ cpuStr = k8sNamespace.getLimitsCpu() + "";
+ }
+
+ String memoryStr = null;
+ if (k8sNamespace.getLimitsMemory() != null) {
+ memoryStr = k8sNamespace.getLimitsMemory() + "Gi";
+ }
+
+ String result = resourceYaml.replace("${name}", name)
+ .replace("${namespace}", namespace);
+ if (cpuStr == null) {
+ result = result.replace("${limitCpu}", "");
+ } else {
+ result = result.replace("${limitCpu}", "limits.cpu: '" + cpuStr +
"'");
+ }
+
+ if (memoryStr == null) {
+ result = result.replace("${limitMemory}", "");
+ } else {
+ result = result.replace("${limitMemory}", "limits.memory: " +
memoryStr);
+ }
+ return result;
+ }
+}
diff --git
a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/K8sNamespaceControllerTest.java
b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/K8sNamespaceControllerTest.java
new file mode 100644
index 0000000..830943b
--- /dev/null
+++
b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/K8sNamespaceControllerTest.java
@@ -0,0 +1,155 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dolphinscheduler.api.controller;
+
+import static
org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static
org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static
org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
+import static
org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
+import static
org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import org.apache.dolphinscheduler.api.enums.Status;
+import org.apache.dolphinscheduler.api.utils.Result;
+import org.apache.dolphinscheduler.common.utils.JSONUtils;
+import org.apache.dolphinscheduler.dao.entity.User;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.MediaType;
+import org.springframework.test.web.servlet.MvcResult;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+
+/**
+ * k8s namespace controller test
+ */
+public class K8sNamespaceControllerTest extends AbstractControllerTest {
+
+ private static final String NAMESPACE_CREATE_STRING = "namespace1";
+ private static final Logger logger =
LoggerFactory.getLogger(K8sNamespaceControllerTest.class);
+ protected User user;
+
+ @Test
+ public void queryProjectListPaging() throws Exception {
+ MultiValueMap<String, String> paramsMap = new LinkedMultiValueMap<>();
+ paramsMap.add("searchVal", "");
+ paramsMap.add("pageNo", "1");
+ paramsMap.add("pageSize", "20");
+
+ MvcResult mvcResult = mockMvc.perform(get("/k8s-namespace")
+ .header(SESSION_ID, sessionId)
+ .params(paramsMap))
+ .andExpect(status().isOk())
+ .andExpect(content().contentType(MediaType.APPLICATION_JSON))
+ .andReturn();
+ Result result =
JSONUtils.parseObject(mvcResult.getResponse().getContentAsString(),
Result.class);
+ Assert.assertEquals(Status.SUCCESS.getCode(),
result.getCode().intValue());
+ }
+
+ @Test
+ public void createNamespace() throws Exception {
+
+ MultiValueMap<String, String> paramsMap = new LinkedMultiValueMap<>();
+ paramsMap.add("namespace", NAMESPACE_CREATE_STRING);
+ paramsMap.add("k8s", "k8s");
+
+ MvcResult mvcResult = mockMvc.perform(post("/k8s-namespace")
+ .header(SESSION_ID, sessionId)
+ .params(paramsMap))
+ .andExpect(status().isCreated()) //it can
+ .andExpect(content().contentType(MediaType.APPLICATION_JSON))
+ .andReturn();
+
+ Result result =
JSONUtils.parseObject(mvcResult.getResponse().getContentAsString(),
Result.class);
+ Assert.assertEquals(Status.K8S_CLIENT_OPS_ERROR.getCode(),
result.getCode().intValue());//because we not have a k8s cluster in test env
+ logger.info("create queue return result:{}",
mvcResult.getResponse().getContentAsString());
+ }
+
+ @Test
+ public void updateNamespace() throws Exception {
+ MultiValueMap<String, String> paramsMap = new LinkedMultiValueMap<>();
+ paramsMap.add("id", "1");
+ paramsMap.add("owner", "owmer1");
+ paramsMap.add("tag", "flink");
+
+ MvcResult mvcResult = mockMvc.perform(put("/k8s-namespace/{id}", 1)
+ .header(SESSION_ID, sessionId)
+ .params(paramsMap))
+ .andExpect(status().isCreated())
+ .andExpect(content().contentType(MediaType.APPLICATION_JSON))
+ .andReturn();
+ Result result =
JSONUtils.parseObject(mvcResult.getResponse().getContentAsString(),
Result.class);
+ Assert.assertEquals(Status.K8S_CLIENT_OPS_ERROR.getCode(),
result.getCode().intValue());
+ logger.info("update queue return result:{}",
mvcResult.getResponse().getContentAsString());
+ }
+
+ @Test
+ public void verifyNamespace() throws Exception {
+ // queue value exist
+ MultiValueMap<String, String> paramsMap = new LinkedMultiValueMap<>();
+ paramsMap.add("namespace", NAMESPACE_CREATE_STRING);
+ paramsMap.add("k8s", "default");
+
+ // success
+
+ MvcResult mvcResult = mockMvc.perform(post("/k8s-namespace/verify")
+ .header(SESSION_ID, sessionId)
+ .params(paramsMap))
+ .andExpect(status().isOk())
+ .andExpect(content().contentType(MediaType.APPLICATION_JSON))
+ .andReturn();
+ Result result =
JSONUtils.parseObject(mvcResult.getResponse().getContentAsString(),
Result.class);
+ Assert.assertEquals(Status.SUCCESS.getCode(),
result.getCode().intValue());
+ logger.info(mvcResult.getResponse().getContentAsString());
+ logger.info("verify namespace return result:{}",
mvcResult.getResponse().getContentAsString());
+
+ //error
+ paramsMap.clear();
+ paramsMap.add("namespace", null);
+ paramsMap.add("k8s", "default");
+ mvcResult = mockMvc.perform(post("/k8s-namespace/verify")
+ .header(SESSION_ID, sessionId)
+ .params(paramsMap))
+ .andExpect(status().isOk())
+ .andExpect(content().contentType(MediaType.APPLICATION_JSON))
+ .andReturn();
+ result =
JSONUtils.parseObject(mvcResult.getResponse().getContentAsString(),
Result.class);
+ Assert.assertEquals(Status.VERIFY_K8S_NAMESPACE_ERROR.getCode(),
result.getCode().intValue());
+ logger.info(mvcResult.getResponse().getContentAsString());
+ logger.info("verify namespace return result:{}",
mvcResult.getResponse().getContentAsString());
+ }
+
+ @Test
+ public void delNamespaceById() throws Exception {
+ MultiValueMap<String, String> paramsMap = new LinkedMultiValueMap<>();
+ paramsMap.add("id", "1");
+
+ MvcResult mvcResult = mockMvc.perform(post("/k8s-namespace/delete")
+ .header(SESSION_ID, sessionId)
+ .params(paramsMap))
+ .andExpect(status().isOk())
+ .andExpect(content().contentType(MediaType.APPLICATION_JSON))
+ .andReturn();
+
+ Result result =
JSONUtils.parseObject(mvcResult.getResponse().getContentAsString(),
Result.class);
+ Assert.assertEquals(Status.DELETE_K8S_NAMESPACE_BY_ID_ERROR.getCode(),
result.getCode().intValue());//there is no k8s cluster in test env
+ logger.info(mvcResult.getResponse().getContentAsString());
+ }
+}
\ No newline at end of file
diff --git
a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/K8sNameSpaceServiceTest.java
b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/K8sNameSpaceServiceTest.java
new file mode 100644
index 0000000..2673556
--- /dev/null
+++
b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/K8sNameSpaceServiceTest.java
@@ -0,0 +1,189 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dolphinscheduler.api.service;
+
+import org.apache.dolphinscheduler.api.enums.Status;
+import org.apache.dolphinscheduler.api.service.impl.K8sNameSpaceServiceImpl;
+import org.apache.dolphinscheduler.api.utils.PageInfo;
+import org.apache.dolphinscheduler.api.utils.Result;
+import org.apache.dolphinscheduler.common.Constants;
+import org.apache.dolphinscheduler.common.enums.UserType;
+import org.apache.dolphinscheduler.dao.entity.K8sNamespace;
+import org.apache.dolphinscheduler.dao.entity.User;
+import org.apache.dolphinscheduler.dao.mapper.K8sNamespaceMapper;
+import org.apache.dolphinscheduler.dao.mapper.UserMapper;
+import org.apache.dolphinscheduler.service.k8s.K8sClientService;
+
+import org.apache.commons.collections.CollectionUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+
+@RunWith(MockitoJUnitRunner.class)
+public class K8sNameSpaceServiceTest {
+
+ private static final Logger logger =
LoggerFactory.getLogger(K8sNameSpaceServiceTest.class);
+
+ @InjectMocks
+ private K8sNameSpaceServiceImpl k8sNameSpaceService;
+
+ @Mock
+ private K8sNamespaceMapper k8sNamespaceMapper;
+
+ @Mock
+ private K8sClientService k8sClientService;
+
+ @Mock
+ private UserMapper userMapper;
+
+ private String namespace = "default";
+ private String k8s = "default";
+
+ @Before
+ public void setUp() throws Exception {
+
Mockito.when(k8sClientService.upsertNamespaceAndResourceToK8s(Mockito.any(K8sNamespace.class),
Mockito.anyString())).thenReturn(null);
+
Mockito.when(k8sClientService.deleteNamespaceToK8s(Mockito.anyString(),
Mockito.anyString())).thenReturn(null);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ }
+
+ @Test
+ public void queryListPaging() {
+ IPage<K8sNamespace> page = new Page<>(1, 10);
+ page.setTotal(1L);
+ page.setRecords(getNamespaceList());
+
Mockito.when(k8sNamespaceMapper.queryK8sNamespacePaging(Mockito.any(Page.class),
Mockito.eq(namespace))).thenReturn(page);
+ Result result = k8sNameSpaceService.queryListPaging(getLoginUser(),
namespace, 1, 10);
+ logger.info(result.toString());
+ PageInfo<K8sNamespace> pageInfo = (PageInfo<K8sNamespace>)
result.getData();
+ Assert.assertTrue(CollectionUtils.isNotEmpty(pageInfo.getTotalList()));
+ }
+
+ @Test
+ public void createK8sNamespace() {
+ // namespace is null
+ Map<String, Object> result =
k8sNameSpaceService.createK8sNamespace(getLoginUser(), null, k8s, null, "tag",
10.0, 100);
+ logger.info(result.toString());
+ Assert.assertEquals(Status.REQUEST_PARAMS_NOT_VALID_ERROR,
result.get(Constants.STATUS));
+ // k8s is null
+ result = k8sNameSpaceService.createK8sNamespace(getLoginUser(),
namespace, null, null, "tag", 10.0, 100);
+ logger.info(result.toString());
+ Assert.assertEquals(Status.REQUEST_PARAMS_NOT_VALID_ERROR,
result.get(Constants.STATUS));
+ // correct
+ result = k8sNameSpaceService.createK8sNamespace(getLoginUser(),
namespace, k8s, null, "tag", 10.0, 100);
+ logger.info(result.toString());
+ Assert.assertEquals(Status.SUCCESS, result.get(Constants.STATUS));
+ //null limit cpu and mem
+ result = k8sNameSpaceService.createK8sNamespace(getLoginUser(),
namespace, k8s, null, "tag", null, null);
+ logger.info(result.toString());
+ Assert.assertEquals(Status.SUCCESS, result.get(Constants.STATUS));
+ }
+
+ @Test
+ public void updateK8sNamespace() {
+
Mockito.when(k8sNamespaceMapper.selectById(1)).thenReturn(getNamespace());
+
+ Map<String, Object> result =
k8sNameSpaceService.updateK8sNamespace(getLoginUser(), 1, null, "tag", null,
null);
+ logger.info(result.toString());
+ Assert.assertEquals(Status.SUCCESS, result.get(Constants.STATUS));
+
+ result = k8sNameSpaceService.updateK8sNamespace(getLoginUser(), 1,
null, "tag", -1.0, 100);
+ logger.info(result.toString());
+ Assert.assertEquals(Status.REQUEST_PARAMS_NOT_VALID_ERROR,
result.get(Constants.STATUS));
+
+ result = k8sNameSpaceService.updateK8sNamespace(getLoginUser(), 1,
null, "tag", 1.0, 100);
+ logger.info(result.toString());
+ Assert.assertEquals(Status.SUCCESS, result.get(Constants.STATUS));
+ }
+
+ @Test
+ public void verifyNamespaceK8s() {
+
+ Mockito.when(k8sNamespaceMapper.existNamespace(namespace,
k8s)).thenReturn(true);
+
+ //namespace null
+ Result result = k8sNameSpaceService.verifyNamespaceK8s(null, k8s);
+ logger.info(result.toString());
+ Assert.assertEquals(result.getCode().intValue(),
Status.REQUEST_PARAMS_NOT_VALID_ERROR.getCode());
+
+ //k8s null
+ result = k8sNameSpaceService.verifyNamespaceK8s(namespace, null);
+ logger.info(result.toString());
+ Assert.assertEquals(result.getCode().intValue(),
Status.REQUEST_PARAMS_NOT_VALID_ERROR.getCode());
+
+ //exist
+ result = k8sNameSpaceService.verifyNamespaceK8s(namespace, k8s);
+ logger.info(result.toString());
+ Assert.assertEquals(result.getCode().intValue(),
Status.K8S_NAMESPACE_EXIST.getCode());
+
+ //not exist
+ result = k8sNameSpaceService.verifyNamespaceK8s(namespace, "other
k8s");
+ logger.info(result.toString());
+ Assert.assertEquals(result.getCode().intValue(),
Status.SUCCESS.getCode());
+ }
+
+ @Test
+ public void deleteNamespaceById() {
+
Mockito.when(k8sNamespaceMapper.deleteById(Mockito.any())).thenReturn(1);
+
Mockito.when(k8sNamespaceMapper.selectById(1)).thenReturn(getNamespace());
+
+ Map<String, Object> result =
k8sNameSpaceService.deleteNamespaceById(getLoginUser(), 1);
+ logger.info(result.toString());
+ Assert.assertEquals(Status.SUCCESS, result.get(Constants.STATUS));
+ }
+
+ private User getLoginUser() {
+
+ User loginUser = new User();
+ loginUser.setUserType(UserType.ADMIN_USER);
+ loginUser.setId(99999999);
+ return loginUser;
+ }
+
+ private K8sNamespace getNamespace() {
+ K8sNamespace k8sNamespace = new K8sNamespace();
+ k8sNamespace.setId(1);
+ k8sNamespace.setK8s(k8s);
+ k8sNamespace.setNamespace(namespace);
+ return k8sNamespace;
+ }
+
+ private List<K8sNamespace> getNamespaceList() {
+ List<K8sNamespace> k8sNamespaceList = new ArrayList<>();
+ k8sNamespaceList.add(getNamespace());
+ return k8sNamespaceList;
+ }
+}
\ No newline at end of file
diff --git
a/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/Constants.java
b/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/Constants.java
index 7da88c4..671af2b 100644
---
a/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/Constants.java
+++
b/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/Constants.java
@@ -809,4 +809,11 @@ public final class Constants {
public static final String CACHE_KEY_VALUE_ALL = "'all'";
+ /**
+ * use for k8s
+ */
+ public static final String NAMESPACE = "namespace";
+ public static final String K8S = "k8s";
+ public static final String LIMITS_CPU = "limitsCpu";
+ public static final String LIMITS_MEMORY = "limitsMemory";
}
diff --git
a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/K8s.java
b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/K8s.java
new file mode 100644
index 0000000..2cddf17
--- /dev/null
+++
b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/K8s.java
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dolphinscheduler.dao.entity;
+
+import java.util.Date;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+
+/**
+ * multi-data centre k8s temporary structure, waiting for new feature to
complete will switch
+ */
+@TableName("t_ds_k8s")
+public class K8s {
+ /**
+ * id
+ */
+ @TableId(value = "id", type = IdType.AUTO)
+ private int id;
+ /**
+ * k8s name
+ */
+ @TableField(value = "k8s_name")
+ private String k8sName;
+ /**
+ * k8s client config(yaml or json)
+ */
+ @TableField(value = "k8s_config")
+ private String k8sConfig;
+
+ /**
+ * create_time
+ */
+ @TableField("create_time")
+ private Date createTime;
+ /**
+ * update_time
+ */
+ @TableField("update_time")
+ private Date updateTime;
+
+
+ public K8s() {
+
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public String getK8sName() {
+ return k8sName;
+ }
+
+ public void setK8sName(String k8sName) {
+ this.k8sName = k8sName;
+ }
+
+ public String getK8sConfig() {
+ return k8sConfig;
+ }
+
+ public void setK8sConfig(String k8sConfig) {
+ this.k8sConfig = k8sConfig;
+ }
+
+ public Date getCreateTime() {
+ return createTime;
+ }
+
+ public void setCreateTime(Date createTime) {
+ this.createTime = createTime;
+ }
+
+ public Date getUpdateTime() {
+ return updateTime;
+ }
+
+ public void setUpdateTime(Date updateTime) {
+ this.updateTime = updateTime;
+ }
+}
diff --git
a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/K8sNamespace.java
b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/K8sNamespace.java
new file mode 100644
index 0000000..d22e7bd
--- /dev/null
+++
b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/K8sNamespace.java
@@ -0,0 +1,197 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dolphinscheduler.dao.entity;
+
+import java.util.Date;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+
+/**
+ * k8s namespace
+ */
+@TableName("t_ds_k8s_namespace")
+public class K8sNamespace {
+ @TableId(value = "id", type = IdType.AUTO)
+ private Integer id;
+
+ /**
+ * namespace name
+ */
+ @TableField(value = "namespace")
+ private String namespace;
+ /**
+ * total cpu limit
+ */
+ @TableField(value = "limits_cpu")
+ private Double limitsCpu;
+ /**
+ * total memory limit,mi
+ */
+ private Integer limitsMemory;
+ /**
+ * owner
+ */
+ @TableField(value = "owner")
+ private String owner;
+
+ /**
+ * create_time
+ */
+ @TableField("create_time")
+ private Date createTime;
+ /**
+ * update_time
+ */
+ @TableField("update_time")
+ private Date updateTime;
+ /**
+ * tag use for set this namespace allow run which type
+ */
+ @TableField("tag")
+ private String tag;
+
+ @TableField("pod_request_cpu")
+ private Double podRequestCpu = 0.0;
+ /**
+ * Mi
+ */
+ @TableField("pod_request_memory")
+ private Integer podRequestMemory = 0;
+ /**
+ *
+ */
+ @TableField("pod_replicas")
+ private Integer podReplicas = 0;
+ /**
+ * online job
+ */
+ @TableField("online_job_num")
+ private Integer onlineJobNum = 0;
+ /**
+ * k8s name
+ */
+ @TableField("k8s")
+ private String k8s;
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public String getNamespace() {
+ return namespace;
+ }
+
+ public void setNamespace(String namespace) {
+ this.namespace = namespace;
+ }
+
+ public Double getLimitsCpu() {
+ return limitsCpu;
+ }
+
+ public void setLimitsCpu(Double limitsCpu) {
+ this.limitsCpu = limitsCpu;
+ }
+
+ public Integer getLimitsMemory() {
+ return limitsMemory;
+ }
+
+ public void setLimitsMemory(Integer limitsMemory) {
+ this.limitsMemory = limitsMemory;
+ }
+
+ public String getOwner() {
+ return owner;
+ }
+
+ public void setOwner(String owner) {
+ this.owner = owner;
+ }
+
+ public Date getCreateTime() {
+ return createTime;
+ }
+
+ public void setCreateTime(Date createTime) {
+ this.createTime = createTime;
+ }
+
+ public Date getUpdateTime() {
+ return updateTime;
+ }
+
+ public void setUpdateTime(Date updateTime) {
+ this.updateTime = updateTime;
+ }
+
+ public String getTag() {
+ return tag;
+ }
+
+ public void setTag(String tag) {
+ this.tag = tag;
+ }
+
+ public Integer getPodRequestMemory() {
+ return podRequestMemory;
+ }
+
+ public void setPodRequestMemory(Integer podRequestMemory) {
+ this.podRequestMemory = podRequestMemory;
+ }
+
+ public Integer getPodReplicas() {
+ return podReplicas;
+ }
+
+ public void setPodReplicas(Integer podReplicas) {
+ this.podReplicas = podReplicas;
+ }
+
+ public Integer getOnlineJobNum() {
+ return onlineJobNum;
+ }
+
+ public void setOnlineJobNum(Integer onlineJobNum) {
+ this.onlineJobNum = onlineJobNum;
+ }
+
+ public String getK8s() {
+ return k8s;
+ }
+
+ public void setK8s(String k8s) {
+ this.k8s = k8s;
+ }
+
+ public Double getPodRequestCpu() {
+ return podRequestCpu;
+ }
+
+ public void setPodRequestCpu(Double podRequestCpu) {
+ this.podRequestCpu = podRequestCpu;
+ }
+}
diff --git
a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/K8sMapper.java
b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/K8sMapper.java
new file mode 100644
index 0000000..bcf617b
--- /dev/null
+++
b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/K8sMapper.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dolphinscheduler.dao.mapper;
+
+import org.apache.dolphinscheduler.dao.entity.K8s;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * k8s mapper interface
+ */
+public interface K8sMapper extends BaseMapper<K8s> {
+
+}
diff --git
a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/K8sNamespaceMapper.java
b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/K8sNamespaceMapper.java
new file mode 100644
index 0000000..e804d55
--- /dev/null
+++
b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/K8sNamespaceMapper.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dolphinscheduler.dao.mapper;
+
+import org.apache.dolphinscheduler.dao.entity.K8sNamespace;
+
+import org.apache.ibatis.annotations.Param;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+
+/**
+ * namespace interface
+ */
+public interface K8sNamespaceMapper extends BaseMapper<K8sNamespace> {
+ /**
+ * k8s namespace page
+ *
+ * @param page page
+ * @param searchVal searchVal
+ * @return k8s namespace IPage
+ */
+ IPage<K8sNamespace> queryK8sNamespacePaging(IPage<K8sNamespace> page,
+ @Param("searchVal") String
searchVal);
+
+ /**
+ * check the target namespace exist
+ *
+ * @param namespace namespace
+ * @param k8s k8s name
+ * @return true if exist else return null
+ */
+ Boolean existNamespace(@Param("namespace") String namespace, @Param("k8s")
String k8s);
+}
diff --git
a/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/K8sNamespaceMapper.xml
b/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/K8sNamespaceMapper.xml
new file mode 100644
index 0000000..9099e0c
--- /dev/null
+++
b/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/K8sNamespaceMapper.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one or more
+ ~ contributor license agreements. See the NOTICE file distributed with
+ ~ this work for additional information regarding copyright ownership.
+ ~ The ASF licenses this file to You under the Apache License, Version 2.0
+ ~ (the "License"); you may not use this file except in compliance with
+ ~ the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.apache.dolphinscheduler.dao.mapper.K8sNamespaceMapper">
+
+ <sql id="baseSql">
+ id, namespace, k8s, owner, tag, limits_memory, limits_cpu,
online_job_num, pod_replicas, pod_request_cpu, pod_request_memory, create_time,
update_time
+ </sql>
+ <select id="queryK8sNamespacePaging"
resultType="org.apache.dolphinscheduler.dao.entity.K8sNamespace">
+ select
+ <include refid="baseSql"/>
+ from t_ds_k8s_namespace
+ where 1= 1
+ <if test="searchVal != null and searchVal != ''">
+ and namespace like concat('%', #{searchVal}, '%')
+ </if>
+ order by update_time desc
+ </select>
+
+ <select id="existNamespace" resultType="java.lang.Boolean">
+ select 1 = 1
+ from t_ds_k8s_namespace
+ where 1 = 1
+ <if test="namespace != null and namespace != ''">
+ and namespace = #{namespace}
+ </if>
+ <if test="k8s != null and k8s != ''">
+ and k8s =#{k8s}
+ </if>
+ </select>
+
+</mapper>
diff --git
a/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_h2.sql
b/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_h2.sql
index 45a452f..3d4536d 100644
--- a/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_h2.sql
+++ b/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_h2.sql
@@ -1870,4 +1870,41 @@ CREATE TABLE t_ds_audit_log
time timestamp NULL DEFAULT CURRENT_TIMESTAMP,
resource_id int(11) NOT NULL,
PRIMARY KEY (id)
-);
\ No newline at end of file
+);
+
+
+DROP TABLE IF EXISTS t_ds_k8s;
+CREATE TABLE t_ds_k8s
+(
+ id int(11) NOT NULL AUTO_INCREMENT ,
+ k8s_name varchar(100) DEFAULT NULL ,
+ k8s_config text DEFAULT NULL,
+ create_time datetime DEFAULT NULL ,
+ update_time datetime DEFAULT NULL ,
+ PRIMARY KEY (id)
+);
+
+DROP TABLE IF EXISTS t_ds_k8s_namespace;
+CREATE TABLE t_ds_k8s_namespace (
+ id int(11) NOT NULL AUTO_INCREMENT ,
+ limits_memory int(11) DEFAULT NULL,
+ namespace varchar(100) DEFAULT NULL,
+ online_job_num int(11) DEFAULT NULL,
+ owner varchar(100) DEFAULT NULL,
+ pod_replicas int(11) DEFAULT NULL,
+ pod_request_cpu decimal(14,3) DEFAULT NULL,
+ pod_request_memory int(11) DEFAULT NULL,
+ tag varchar(100) DEFAULT NULL,
+ limits_cpu decimal(14,3) DEFAULT NULL,
+ k8s varchar(100) DEFAULT NULL,
+ create_time datetime DEFAULT NULL ,
+ update_time datetime DEFAULT NULL ,
+ PRIMARY KEY (id) ,
+ UNIQUE KEY k8s_namespace_unique (namespace,k8s)
+);
+
+-- ----------------------------
+-- Records of t_ds_k8s_namespace
+-- ----------------------------
+INSERT INTO t_ds_k8s_namespace
+VALUES (1, 10000, 'default', 99,
'owner',1,NULL,1,'test',NULL,'default',null,null);
\ No newline at end of file
diff --git
a/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_mysql.sql
b/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_mysql.sql
index ca3724b..eed27f9 100644
--- a/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_mysql.sql
+++ b/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_mysql.sql
@@ -1856,4 +1856,39 @@ CREATE TABLE `t_ds_audit_log` (
`time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT 'create time',
`resource_id` int(11) NULL DEFAULT NULL COMMENT 'resource id',
PRIMARY KEY (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT= 1 DEFAULT CHARSET=utf8;
\ No newline at end of file
+) ENGINE=InnoDB AUTO_INCREMENT= 1 DEFAULT CHARSET=utf8;
+
+-- ----------------------------
+-- Table structure for t_ds_k8s
+-- ----------------------------
+DROP TABLE IF EXISTS `t_ds_k8s`;
+CREATE TABLE `t_ds_k8s` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `k8s_name` varchar(100) DEFAULT NULL,
+ `k8s_config` text DEFAULT NULL,
+ `create_time` datetime DEFAULT NULL COMMENT 'create time',
+ `update_time` datetime DEFAULT NULL COMMENT 'update time',
+ PRIMARY KEY (`id`)
+) ENGINE= INNODB AUTO_INCREMENT= 1 DEFAULT CHARSET= utf8;
+
+-- ----------------------------
+-- Table structure for t_ds_k8s_namespace
+-- ----------------------------
+DROP TABLE IF EXISTS `t_ds_k8s_namespace`;
+CREATE TABLE `t_ds_k8s_namespace` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `limits_memory` int(11) DEFAULT NULL,
+ `namespace` varchar(100) DEFAULT NULL,
+ `online_job_num` int(11) DEFAULT NULL,
+ `owner` varchar(100) DEFAULT NULL,
+ `pod_replicas` int(11) DEFAULT NULL,
+ `pod_request_cpu` decimal(14,3) DEFAULT NULL,
+ `pod_request_memory` int(11) DEFAULT NULL,
+ `tag` varchar(100) DEFAULT NULL,
+ `limits_cpu` decimal(14,3) DEFAULT NULL,
+ `k8s` varchar(100) DEFAULT NULL,
+ `create_time` datetime DEFAULT NULL COMMENT 'create time',
+ `update_time` datetime DEFAULT NULL COMMENT 'update time',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `k8s_namespace_unique` (`namespace`,`k8s`)
+) ENGINE= INNODB AUTO_INCREMENT= 1 DEFAULT CHARSET= utf8;
diff --git
a/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_postgresql.sql
b/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_postgresql.sql
index 1e371d7..5d5ce6f 100644
---
a/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_postgresql.sql
+++
b/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_postgresql.sql
@@ -1850,4 +1850,41 @@ CREATE TABLE t_ds_audit_log (
time timestamp DEFAULT NULL ,
resource_id int NOT NULL,
PRIMARY KEY (id)
-);
\ No newline at end of file
+);
+
+--
+-- Table structure for table t_ds_k8s
+--
+
+DROP TABLE IF EXISTS t_ds_k8s;
+CREATE TABLE t_ds_k8s (
+ id serial NOT NULL,
+ k8s_name VARCHAR(100) DEFAULT NULL ,
+ k8s_config text ,
+ create_time timestamp DEFAULT NULL ,
+ update_time timestamp DEFAULT NULL ,
+ PRIMARY KEY (id)
+);
+
+--
+-- Table structure for table t_ds_k8s_namespace
+--
+
+DROP TABLE IF EXISTS t_ds_k8s_namespace;
+CREATE TABLE t_ds_k8s_namespace (
+ id serial NOT NULL,
+ limits_memory int DEFAULT NULL ,
+ namespace varchar(100) DEFAULT NULL ,
+ online_job_num int DEFAULT '0' ,
+ owner varchar(100) DEFAULT NULL,
+ pod_replicas int(11) DEFAULT NULL,
+ pod_request_cpu NUMERIC(13,4) NULL,
+ pod_request_memory int(11) DEFAULT NULL,
+ tag varchar(100) DEFAULT NULL,
+ limits_cpu NUMERIC(13,4) NULL,
+ k8s varchar(100) DEFAULT NULL,
+ create_time timestamp DEFAULT NULL ,
+ update_time timestamp DEFAULT NULL ,
+ PRIMARY KEY (id) ,
+ CONSTRAINT k8s_namespace_unique UNIQUE (namespace,k8s)
+);
diff --git
a/dolphinscheduler-dao/src/main/resources/sql/upgrade/2.1.0_schema/mysql/dolphinscheduler_ddl.sql
b/dolphinscheduler-dao/src/main/resources/sql/upgrade/2.1.0_schema/mysql/dolphinscheduler_ddl.sql
index e12b696..5f66888 100644
---
a/dolphinscheduler-dao/src/main/resources/sql/upgrade/2.1.0_schema/mysql/dolphinscheduler_ddl.sql
+++
b/dolphinscheduler-dao/src/main/resources/sql/upgrade/2.1.0_schema/mysql/dolphinscheduler_ddl.sql
@@ -168,3 +168,39 @@ CREATE TABLE `t_ds_relation_rule_input_entry` (
`update_time` datetime
DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+
+-- ----------------------------
+-- Table structure for t_ds_k8s
+-- ----------------------------
+DROP TABLE IF EXISTS `t_ds_k8s`;
+CREATE TABLE `t_ds_k8s` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `k8s_name` varchar(100) DEFAULT NULL,
+ `k8s_config` text DEFAULT NULL,
+ `create_time` datetime DEFAULT NULL COMMENT 'create time',
+ `update_time` datetime DEFAULT NULL COMMENT 'update time',
+ PRIMARY KEY (`id`)
+) ENGINE= INNODB AUTO_INCREMENT= 1 DEFAULT CHARSET= utf8;
+
+-- ----------------------------
+-- Table structure for t_ds_k8s_namespace
+-- ----------------------------
+DROP TABLE IF EXISTS `t_ds_k8s_namespace`;
+CREATE TABLE `t_ds_k8s_namespace` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `limits_memory` int(11) DEFAULT NULL,
+ `namespace` varchar(100) DEFAULT NULL,
+ `online_job_num` int(11) DEFAULT NULL,
+ `owner` varchar(100) DEFAULT NULL,
+ `pod_replicas` int(11) DEFAULT NULL,
+ `pod_request_cpu` decimal(14,3) DEFAULT NULL,
+ `pod_request_memory` int(11) DEFAULT NULL,
+ `tag` varchar(100) DEFAULT NULL,
+ `limits_cpu` decimal(14,3) DEFAULT NULL,
+ `k8s` varchar(100) DEFAULT NULL,
+ `create_time` datetime DEFAULT NULL COMMENT 'create time',
+ `update_time` datetime DEFAULT NULL COMMENT 'update time',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `k8s_namespace_unique` (`namespace`,`k8s`)
+) ENGINE= INNODB AUTO_INCREMENT= 1 DEFAULT CHARSET= utf8;
\ No newline at end of file
diff --git
a/dolphinscheduler-dao/src/main/resources/sql/upgrade/2.1.0_schema/postgresql/dolphinscheduler_ddl.sql
b/dolphinscheduler-dao/src/main/resources/sql/upgrade/2.1.0_schema/postgresql/dolphinscheduler_ddl.sql
index 3e35d60..854b787 100644
---
a/dolphinscheduler-dao/src/main/resources/sql/upgrade/2.1.0_schema/postgresql/dolphinscheduler_ddl.sql
+++
b/dolphinscheduler-dao/src/main/resources/sql/upgrade/2.1.0_schema/postgresql/dolphinscheduler_ddl.sql
@@ -154,6 +154,32 @@ EXECUTE 'CREATE INDEX IF NOT EXISTS
idx_task_definition_log_project_code ON ' ||
EXECUTE 'DROP INDEX IF EXISTS "idx_task_instance_code_version"';
EXECUTE 'CREATE INDEX IF NOT EXISTS idx_task_instance_code_version ON' ||
quote_ident(v_schema) ||'.t_ds_task_instance USING
Btree("task_code","task_definition_version")';
+EXECUTE 'CREATE TABLE IF NOT EXISTS '|| quote_ident(v_schema) ||'."t_ds_k8s" (
+ id serial NOT NULL,
+ k8s_name VARCHAR(100) DEFAULT NULL ,
+ k8s_config text ,
+ create_time timestamp DEFAULT NULL ,
+ update_time timestamp DEFAULT NULL ,
+ PRIMARY KEY (id)
+)';
+
+EXECUTE 'CREATE TABLE IF NOT EXISTS '|| quote_ident(v_schema)
||'."t_ds_k8s_namespace" (
+ id serial NOT NULL,
+ limits_memory int DEFAULT NULL ,
+ namespace varchar(100) DEFAULT NULL ,
+ online_job_num int DEFAULT ''0'' ,
+ owner varchar(100) DEFAULT NULL,
+ pod_replicas int(11) DEFAULT NULL,
+ pod_request_cpu NUMERIC(13,4) NULL,
+ pod_request_memory int(11) DEFAULT NULL,
+ tag varchar(100) DEFAULT NULL,
+ limits_cpu NUMERIC(13,4) NULL,
+ k8s varchar(100) DEFAULT NULL,
+ create_time timestamp DEFAULT NULL ,
+ update_time timestamp DEFAULT NULL ,
+ PRIMARY KEY (id) ,
+ CONSTRAINT k8s_namespace_unique UNIQUE (namespace,k8s)
+)';
return 'Success!';
exception when others then
diff --git a/dolphinscheduler-dist/release-docs/LICENSE
b/dolphinscheduler-dist/release-docs/LICENSE
index 6c4e134..642bee4 100644
--- a/dolphinscheduler-dist/release-docs/LICENSE
+++ b/dolphinscheduler-dist/release-docs/LICENSE
@@ -405,6 +405,33 @@ The text of each license is also included at
licenses/LICENSE-[project].txt.
protostuff-collectionschema 1.7.2:
https://github.com/protostuff/protostuff/protostuff-collectionschema Apache-2.0
prometheus client_java(simpleclient) 0.12.0:
https://github.com/prometheus/client_java, Apache 2.0
snowflake snowflake-2010:
https://github.com/twitter-archive/snowflake/tree/snowflake-2010, Apache 2.0
+ kubernetes-client 5.8.0:
https://mvnrepository.com/artifact/io.fabric8/kubernetes-client/5.8.0, Apache
2.0
+ kubernetes-model-admissionregistration 5.8.0:
https://mvnrepository.com/artifact/io.fabric8/kubernetes-model-admissionregistration/5.8.0,
Apache 2.0
+ kubernetes-model-apiextensions 5.8.0:
https://mvnrepository.com/artifact/io.fabric8/kubernetes-model-apiextensions/5.8.0,
Apache 2.0
+ kubernetes-model-apps 5.8.0:
https://mvnrepository.com/artifact/io.fabric8/kubernetes-model-apps/5.8.0,
Apache 2.0
+ kubernetes-model-autoscaling 5.8.0:
https://mvnrepository.com/artifact/io.fabric8/kubernetes-model-autoscaling/5.8.0,
Apache 2.0
+ kubernetes-model-batch 5.8.0:
https://mvnrepository.com/artifact/io.fabric8/kubernetes-model-autoscaling/5.8.0,
Apache 2.0
+ kubernetes-model-certificates 5.8.0:
https://mvnrepository.com/artifact/io.fabric8/kubernetes-model-certificates/5.8.0,
Apache 2.0
+ kubernetes-model-common 5.8.0:
https://mvnrepository.com/artifact/io.fabric8/kubernetes-model-common/5.8.0,
Apache 2.0
+ kubernetes-model-coordination 5.8.0:
https://mvnrepository.com/artifact/io.fabric8/kubernetes-model-coordination/5.8.0,
Apache 2.0
+ kubernetes-model-core 5.8.0:
https://mvnrepository.com/artifact/io.fabric8/kubernetes-model-core/5.8.0,
Apache 2.0
+ kubernetes-model-discovery 5.8.0:
https://mvnrepository.com/artifact/io.fabric8/kubernetes-model-discovery/5.8.0,
Apache 2.0
+ kubernetes-model-events 5.8.0:
https://mvnrepository.com/artifact/io.fabric8/kubernetes-model-events/5.8.0,
Apache 2.0
+ kubernetes-model-extensions 5.8.0:
https://mvnrepository.com/artifact/io.fabric8/kubernetes-model-extensions/5.8.0,
Apache 2.0
+ kubernetes-model-flowcontrol 5.8.0:
https://mvnrepository.com/artifact/io.fabric8/kubernetes-model-flowcontrol/5.8.0,
Apache 2.0
+ kubernetes-model-metrics 5.8.0:
https://mvnrepository.com/artifact/io.fabric8/kubernetes-model-metrics/5.8.0,
Apache 2.0
+ kubernetes-model-networking 5.8.0:
https://mvnrepository.com/artifact/io.fabric8/kubernetes-model-networking/5.8.0,
Apache 2.0
+ kubernetes-model-node 5.8.0:
https://mvnrepository.com/artifact/io.fabric8/kubernetes-model-node/5.8.0,
Apache 2.0
+ kubernetes-model-policy 5.8.0:
https://mvnrepository.com/artifact/io.fabric8/kubernetes-model-policy/5.8.0,
Apache 2.0
+ kubernetes-model-rbac 5.8.0:
https://mvnrepository.com/artifact/io.fabric8/kubernetes-model-rbac/5.8.0,
Apache 2.0
+ kubernetes-model-scheduling 5.8.0:
https://mvnrepository.com/artifact/io.fabric8/kubernetes-model-scheduling/5.8.0,
Apache 2.0
+ kubernetes-model-storageclass 5.8.0:
https://mvnrepository.com/artifact/io.fabric8/kubernetes-model-storageclass/5.8.0,
Apache 2.0
+ zjsonpatch 0.3.0
https://mvnrepository.com/artifact/io.fabric8/zjsonpatch/0.3.0, Apache 2.0
+ generex 1.0.2
https://mvnrepository.com/artifact/com.github.mifmif/generex/1.0.2, Apache 2.0
+ jackson-dataformat-yaml 2.12.5
https://mvnrepository.com/artifact/com.fasterxml.jackson.dataformat/jackson-dataformat-yaml/2.12.5,
Apache 2.0
+ logging-interceptor 3.14.9
https://mvnrepository.com/artifact/com.squareup.okhttp3/logging-interceptor/3.14.9,
Apache 2.0
+ okhttp 3.14.3
https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp/3.14.3, Apache
2.0
+ okio 1.17.2
https://mvnrepository.com/artifact/com.squareup.okio/okio/1.17.2, Apache 2.0
========================================================================
BSD licenses
@@ -428,6 +455,7 @@ The text of each license is also included at
licenses/LICENSE-[project].txt.
LatencyUtils 2.0.3: https://github.com/LatencyUtils/LatencyUtils,
BSD-2-Clause
janino 3.1.6:
https://mvnrepository.com/artifact/org.codehaus.janino/janino/3.1.6, BSD
3-clause
commons-compiler 3.1.6:
https://mvnrepository.com/artifact/org.codehaus.janino/janino/3.1.6, BSD
3-clause
+ automaton 1.11-8
https://mvnrepository.com/artifact/dk.brics.automaton/automaton/1.11-8, BSD
2-clause
========================================================================
CDDL licenses
diff --git a/dolphinscheduler-dist/release-docs/licenses/LICENSE-automaton.txt
b/dolphinscheduler-dist/release-docs/licenses/LICENSE-automaton.txt
new file mode 100644
index 0000000..7253426
--- /dev/null
+++ b/dolphinscheduler-dist/release-docs/licenses/LICENSE-automaton.txt
@@ -0,0 +1,24 @@
+Copyright (c) 2001-2022 Anders Moeller
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
diff --git
a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/NamespacePage.java
b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/NamespacePage.java
new file mode 100644
index 0000000..0d10e34
--- /dev/null
+++
b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/NamespacePage.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to Apache Software Foundation (ASF) under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Apache Software Foundation (ASF) licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.dolphinscheduler.e2e.pages.security;
+
+import org.apache.dolphinscheduler.e2e.pages.common.NavBarPage;
+
+import java.util.List;
+
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.remote.RemoteWebDriver;
+import org.openqa.selenium.support.FindBy;
+import org.openqa.selenium.support.PageFactory;
+
+import lombok.Getter;
+
+@Getter
+public final class NamespacePage extends NavBarPage implements
SecurityPage.Tab {
+ @FindBy(id = "btnCreateNamespace")
+ private WebElement buttonCreateNamespace;
+
+ @FindBy(className = "items")
+ private List<WebElement> namespaceList;
+
+ private final NamespaceForm createNamespaceForm;
+ private final NamespaceForm editNamespaceForm;
+
+ public NamespacePage(RemoteWebDriver driver) {
+ super(driver);
+ createNamespaceForm = new NamespaceForm();
+ editNamespaceForm = new NamespaceForm();
+ }
+
+ public NamespacePage create(String namespaceName, String namespaceValue) {
+ buttonCreateNamespace().click();
+ createNamespaceForm().inputNamespaceName().sendKeys(namespaceName);
+ createNamespaceForm().inputNamespaceValue().sendKeys(namespaceValue);
+ createNamespaceForm().buttonSubmit().click();
+ return this;
+ }
+
+ public NamespacePage update(String namespaceName, String
editNamespaceName, String editNamespaceValue) {
+ namespaceList()
+ .stream()
+ .filter(it ->
it.findElement(By.className("namespaceName")).getAttribute("innerHTML").contains(namespaceName))
+ .flatMap(it -> it.findElements(By.className("edit")).stream())
+ .filter(WebElement::isDisplayed)
+ .findFirst()
+ .orElseThrow(() -> new RuntimeException("No edit button in
namespace list"))
+ .click();
+
+ editNamespaceForm().inputNamespaceName().sendKeys(editNamespaceName);
+ editNamespaceForm().inputNamespaceValue().sendKeys(editNamespaceValue);
+ editNamespaceForm().buttonSubmit().click();
+
+ return this;
+ }
+
+ @Getter
+ public class NamespaceForm {
+ NamespaceForm() {
+ PageFactory.initElements(driver, this);
+ }
+
+ @FindBy(id = "inputNamespaceName")
+ private WebElement inputNamespaceName;
+
+ @FindBy(id = "inputNamespaceValue")
+ private WebElement inputNamespaceValue;
+
+ @FindBy(id = "btnSubmit")
+ private WebElement buttonSubmit;
+
+ @FindBy(id = "btnCancel")
+ private WebElement buttonCancel;
+ }
+}
diff --git
a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/SecurityPage.java
b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/SecurityPage.java
index 2bbdd7b..d2d7835 100644
---
a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/SecurityPage.java
+++
b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/SecurityPage.java
@@ -52,6 +52,9 @@ public class SecurityPage extends NavBarPage implements
NavBarItem {
@FindBy(className = "tab-token-manage")
private WebElement menuTokenManage;
+ @FindBy(className = "tab-namespace-manage")
+ private WebElement menuNamespaceManage;
+
public SecurityPage(RemoteWebDriver driver) {
super(driver);
}
@@ -88,6 +91,10 @@ public class SecurityPage extends NavBarPage implements
NavBarItem {
menuTokenManage().click();
return tab.cast(new TokenPage(driver));
}
+ if (tab == NamespacePage.class) {
+ menuNamespaceManage().click();
+ return tab.cast(new NamespacePage(driver));
+ }
throw new UnsupportedOperationException("Unknown tab: " +
tab.getName());
}
diff --git a/dolphinscheduler-service/pom.xml b/dolphinscheduler-service/pom.xml
index 387f613..8143cd7 100644
--- a/dolphinscheduler-service/pom.xml
+++ b/dolphinscheduler-service/pom.xml
@@ -90,5 +90,9 @@
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
+ <dependency>
+ <groupId>io.fabric8</groupId>
+ <artifactId>kubernetes-client</artifactId>
+ </dependency>
</dependencies>
</project>
diff --git
a/dolphinscheduler-service/src/main/java/org/apache/dolphinscheduler/service/k8s/K8sClientService.java
b/dolphinscheduler-service/src/main/java/org/apache/dolphinscheduler/service/k8s/K8sClientService.java
new file mode 100644
index 0000000..c921054
--- /dev/null
+++
b/dolphinscheduler-service/src/main/java/org/apache/dolphinscheduler/service/k8s/K8sClientService.java
@@ -0,0 +1,118 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dolphinscheduler.service.k8s;
+
+import org.apache.dolphinscheduler.dao.entity.K8sNamespace;
+
+import java.util.Optional;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.yaml.snakeyaml.Yaml;
+
+import io.fabric8.kubernetes.api.model.Namespace;
+import io.fabric8.kubernetes.api.model.NamespaceList;
+import io.fabric8.kubernetes.api.model.ObjectMeta;
+import io.fabric8.kubernetes.api.model.ResourceQuota;
+import io.fabric8.kubernetes.client.KubernetesClient;
+
+/**
+ * Encapsulates all client-related operations, not involving the db
+ */
+@Component
+public class K8sClientService {
+
+ private static Yaml yaml = new Yaml();
+ @Autowired
+ private K8sManager k8sManager;
+
+ public ResourceQuota upsertNamespaceAndResourceToK8s(K8sNamespace
k8sNamespace, String yamlStr) {
+ upsertNamespaceToK8s(k8sNamespace.getNamespace(),
k8sNamespace.getK8s());
+ return upsertNamespacedResourceToK8s(k8sNamespace, yamlStr);
+ }
+
+ public Optional<Namespace> deleteNamespaceToK8s(String name, String k8s) {
+ Optional<Namespace> result = getNamespaceFromK8s(name, k8s);
+ if (result.isPresent()) {
+ KubernetesClient client = k8sManager.getK8sClient(k8s);
+ Namespace body = new Namespace();
+ ObjectMeta meta = new ObjectMeta();
+ meta.setNamespace(name);
+ meta.setName(name);
+ body.setMetadata(meta);
+ client.namespaces().delete(body);
+ }
+ return getNamespaceFromK8s(name, k8s);
+ }
+
+ private ResourceQuota upsertNamespacedResourceToK8s(K8sNamespace
k8sNamespace, String yamlStr) {
+
+ KubernetesClient client =
k8sManager.getK8sClient(k8sNamespace.getK8s());
+
+ //创建资源
+ ResourceQuota queryExist = client.resourceQuotas()
+ .inNamespace(k8sNamespace.getNamespace())
+ .withName(k8sNamespace.getNamespace())
+ .get();
+
+
+ ResourceQuota body = yaml.loadAs(yamlStr, ResourceQuota.class);
+
+ if (queryExist != null) {
+ if (k8sNamespace.getLimitsCpu() == null &&
k8sNamespace.getLimitsMemory() == null) {
+
client.resourceQuotas().inNamespace(k8sNamespace.getNamespace())
+ .withName(k8sNamespace.getNamespace())
+ .delete();
+ return null;
+ }
+ }
+
+ return client.resourceQuotas().inNamespace(k8sNamespace.getNamespace())
+ .withName(k8sNamespace.getNamespace())
+ .createOrReplace(body);
+ }
+
+ private Optional<Namespace> getNamespaceFromK8s(String name, String k8s) {
+ NamespaceList listNamespace =
+ k8sManager.getK8sClient(k8s).namespaces().list();
+
+ Optional<Namespace> list =
+ listNamespace.getItems().stream()
+ .filter((Namespace namespace) ->
+ namespace.getMetadata().getName().equals(name))
+ .findFirst();
+
+ return list;
+ }
+
+ private Namespace upsertNamespaceToK8s(String name, String k8s) {
+ Optional<Namespace> result = getNamespaceFromK8s(name, k8s);
+ //if not exist create
+ if (!result.isPresent()) {
+ KubernetesClient client = k8sManager.getK8sClient(k8s);
+ Namespace body = new Namespace();
+ ObjectMeta meta = new ObjectMeta();
+ meta.setNamespace(name);
+ meta.setName(name);
+ body.setMetadata(meta);
+ return client.namespaces().create(body);
+ }
+ return result.get();
+ }
+
+}
diff --git
a/dolphinscheduler-service/src/main/java/org/apache/dolphinscheduler/service/k8s/K8sManager.java
b/dolphinscheduler-service/src/main/java/org/apache/dolphinscheduler/service/k8s/K8sManager.java
new file mode 100644
index 0000000..c86d0ec
--- /dev/null
+++
b/dolphinscheduler-service/src/main/java/org/apache/dolphinscheduler/service/k8s/K8sManager.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dolphinscheduler.service.k8s;
+
+import org.apache.dolphinscheduler.dao.entity.K8s;
+import org.apache.dolphinscheduler.dao.mapper.K8sMapper;
+import org.apache.dolphinscheduler.remote.exceptions.RemotingException;
+
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+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 com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+
+import io.fabric8.kubernetes.client.Config;
+import io.fabric8.kubernetes.client.DefaultKubernetesClient;
+import io.fabric8.kubernetes.client.KubernetesClient;
+
+/**
+ * A separate class, because then wait for multiple environment feature,
currently using db configuration, later unified
+ */
+@Component
+public class K8sManager {
+
+ private static final Logger logger =
LoggerFactory.getLogger(K8sManager.class);
+ /**
+ * cache k8s client
+ */
+ private static Map<String, KubernetesClient> clientMap = new Hashtable<>();
+
+ @Autowired
+ private K8sMapper k8sMapper;
+
+ public KubernetesClient getK8sClient(String k8sName) {
+ if (null == k8sName) {
+ return null;
+ }
+ return clientMap.get(k8sName);
+ }
+
+
+ @EventListener
+ public void buildApiClientAll(ApplicationReadyEvent readyEvent) throws
RemotingException {
+ QueryWrapper<K8s> nodeWrapper = new QueryWrapper<>();
+ List<K8s> k8sList = k8sMapper.selectList(nodeWrapper);
+
+ if (k8sList != null) {
+ for (K8s k8s : k8sList) {
+ DefaultKubernetesClient client = getClient(k8s.getK8sConfig());
+ clientMap.put(k8s.getK8sName(), client);
+ }
+ }
+ }
+
+ private DefaultKubernetesClient getClient(String configYaml) throws
RemotingException {
+ try {
+ Config config = Config.fromKubeconfig(configYaml);
+ return new DefaultKubernetesClient(config);
+ } catch (Exception e) {
+ logger.error("fail to get k8s ApiClient", e);
+ throw new RemotingException("fail to get k8s ApiClient:" +
e.getMessage());
+ }
+ }
+}
diff --git
a/dolphinscheduler-service/src/test/java/org/apache/dolphinscheduler/service/k8s/K8sManagerTest.java
b/dolphinscheduler-service/src/test/java/org/apache/dolphinscheduler/service/k8s/K8sManagerTest.java
new file mode 100644
index 0000000..2740b7d
--- /dev/null
+++
b/dolphinscheduler-service/src/test/java/org/apache/dolphinscheduler/service/k8s/K8sManagerTest.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dolphinscheduler.service.k8s;
+
+import org.apache.dolphinscheduler.dao.entity.K8s;
+import org.apache.dolphinscheduler.dao.mapper.K8sMapper;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import io.fabric8.kubernetes.client.KubernetesClient;
+
+@RunWith(MockitoJUnitRunner.Silent.class)
+public class K8sManagerTest {
+
+ @InjectMocks
+ private K8sManager k8sManager;
+
+ @Mock
+ private K8sMapper k8sMapper;
+
+ @Before
+ public void setUp() throws Exception {
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ }
+
+ @Test
+ public void getK8sClient() {
+
Mockito.when(k8sMapper.selectList(Mockito.any())).thenReturn(getK8sList());
+
+ KubernetesClient result = k8sManager.getK8sClient("must null");
+ Assert.assertNull(result);
+ result = k8sManager.getK8sClient(null);
+ Assert.assertNull(result);
+ }
+
+ private K8s getK8s() {
+ K8s k8s = new K8s();
+ k8s.setId(1);
+ k8s.setK8sName("default");
+ k8s.setK8sConfig("k8s config");
+ return k8s;
+ }
+
+ private List<K8s> getK8sList() {
+ List<K8s> k8sList = new ArrayList<>();
+ k8sList.add(getK8s());
+ return k8sList;
+ }
+}
\ No newline at end of file
diff --git
a/dolphinscheduler-ui/src/js/conf/home/pages/security/pages/namespace/_source/createNamespace.vue
b/dolphinscheduler-ui/src/js/conf/home/pages/security/pages/namespace/_source/createNamespace.vue
new file mode 100644
index 0000000..3d0903e
--- /dev/null
+++
b/dolphinscheduler-ui/src/js/conf/home/pages/security/pages/namespace/_source/createNamespace.vue
@@ -0,0 +1,219 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+<template>
+ <m-popover
+ ref="popover"
+ :ok-text="item ? $t('Edit') : $t('Submit')"
+ @ok="_ok"
+ @close="close">
+ <template slot="content">
+ <div class="create-tenement-model">
+ <m-list-box-f>
+ <template slot="name"><strong>*</strong>{{$t('Name')}}</template>
+ <template slot="content">
+ <el-input
+ type="input"
+ v-model="namespace"
+ maxlength="60"
+ size="mini"
+ :disabled="item ? true: false"
+ :placeholder="$t('Please enter name')">
+ </el-input>
+ </template>
+ </m-list-box-f>
+ <m-list-box-f>
+ <template slot="name"><strong>*</strong>{{$t('K8s
Cluster')}}</template>
+ <template slot="content">
+ <el-input
+ type="input"
+ v-model="k8s"
+ maxlength="60"
+ size="mini"
+ :disabled="item ? true: false"
+ :placeholder="$t('Please enter k8s cluster')">
+ </el-input>
+ </template>
+ </m-list-box-f>
+ <m-list-box-f>
+ <template slot="name">{{$t('K8s Tag')}}</template>
+ <template slot="content">
+ <el-input
+ type="input"
+ v-model="tag"
+ maxlength="60"
+ size="mini"
+ :placeholder="$t('Please enter k8s cluster')">
+ </el-input>
+ </template>
+ </m-list-box-f>
+
+ <m-list-box-f>
+ <template slot="name">{{$t('Limits Cpu')}}</template>
+ <template slot="content">
+ <el-input
+ v-model="limitsCpu"
+ size="small"
+ >
+ <template slot="append">Core</template>
+ </el-input>
+ </template>
+ </m-list-box-f>
+
+ <m-list-box-f>
+ <template slot="name">{{$t('Limits Memory')}}</template>
+ <template slot="content">
+ <el-input
+ v-model="limitsMemory"
+ size="small"
+ >
+ <template slot="append">GB</template>
+ </el-input>
+ </template>
+ </m-list-box-f>
+
+ <m-list-box-f>
+ <template slot="name">{{$t('Namespace Owner')}}</template>
+ <template slot="content">
+ <el-input
+ type="input"
+ v-model="owner"
+ maxlength="60"
+ size="mini"
+ :placeholder="$t('Please enter owner')">
+ </el-input>
+ </template>
+ </m-list-box-f>
+
+ </div>
+ </template>
+ </m-popover>
+</template>
+<script>
+ import _ from 'lodash'
+ import i18n from '@/module/i18n'
+ import store from '@/conf/home/store'
+ import mPopover from '@/module/components/popup/popover'
+ import mListBoxF from '@/module/components/listBoxF/listBoxF'
+
+ export default {
+ name: 'create-namespace',
+ data () {
+ return {
+ store,
+ namespace: '',
+ k8s: '',
+ owner: '',
+ tag: '',
+ limitsCpu: '',
+ limitsMemory: ''
+ }
+ },
+ props: {
+ item: Object
+ },
+ methods: {
+ _ok () {
+ if (!this._verification()) {
+ return
+ }
+
+ let param = {
+ namespace: _.trim(this.namespace),
+ k8s: _.trim(this.k8s),
+ owner: _.trim(this.owner),
+ tag: _.trim(this.tag),
+ limitsCpu: _.trim(this.limitsCpu),
+ limitsMemory: _.trim(this.limitsMemory)
+ }
+ // edit
+ if (this.item) {
+ param.id = this.item.id
+ }
+
+ let $then = (res) => {
+ this.$emit('onUpdate')
+ this.$message.success(res.msg)
+ this.$refs.popover.spinnerLoading = false
+ }
+
+ let $catch = (e) => {
+ this.$message.error(e.msg || '')
+ this.$refs.popover.spinnerLoading = false
+ }
+
+ if (this.item) {
+ this.$refs.popover.spinnerLoading = true
+ this.store.dispatch('security/updateNamespace', param).then(res => {
+ $then(res)
+ }).catch(e => {
+ $catch(e)
+ })
+ } else {
+ this._verifyName(param).then(() => {
+ this.$refs.popover.spinnerLoading = true
+ this.store.dispatch('security/createNamespace', param).then(res =>
{
+ $then(res)
+ }).catch(e => {
+ $catch(e)
+ })
+ }).catch(e => {
+ this.$message.error(e.msg || '')
+ })
+ }
+ },
+ _verification () {
+ if (!this.namespace.replace(/\s*/g, '')) {
+ this.$message.warning(`${i18n.$t('Please enter name')}`)
+ return false
+ }
+ if (!this.k8s.replace(/\s*/g, '')) {
+ this.$message.warning(`${i18n.$t('Please enter namespace')}`)
+ return false
+ }
+ return true
+ },
+ _verifyName (param) {
+ return new Promise((resolve, reject) => {
+ this.store.dispatch('security/verifyNamespaceK8s', param).then(res
=> {
+ resolve()
+ }).catch(e => {
+ reject(e)
+ })
+ })
+ },
+ close () {
+ this.$emit('close')
+ }
+ },
+ watch: {
+ },
+ created () {
+ if (this.item) {
+ this.namespace = this.item.namespace
+ this.k8s = this.item.k8s
+ this.owner = this.item.owner
+ this.tag = this.item.tag
+ this.limitsCpu = this.item.limitsCpu
+ this.limitsMemory = this.item.limitsMemory
+ }
+ },
+ mounted () {
+
+ },
+ components: { mPopover, mListBoxF }
+ }
+</script>
diff --git
a/dolphinscheduler-ui/src/js/conf/home/pages/security/pages/namespace/_source/list.vue
b/dolphinscheduler-ui/src/js/conf/home/pages/security/pages/namespace/_source/list.vue
new file mode 100644
index 0000000..73153b8
--- /dev/null
+++
b/dolphinscheduler-ui/src/js/conf/home/pages/security/pages/namespace/_source/list.vue
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+<template>
+ <div class="list-model">
+ <div class="table-box">
+ <el-table :data="list" size="mini" style="width: 100%">
+ <el-table-column type="index" :label="$t('#')"
width="50"></el-table-column>
+ <el-table-column prop="namespace" :label="$t('K8s
Namespace')"></el-table-column>
+ <el-table-column prop="k8s" :label="$t('K8s
Cluster')"></el-table-column>
+ <el-table-column prop="owner" :label="$t('Namespace
Owner')"></el-table-column>
+ <el-table-column prop="tag" :label="$t('K8s Tag')"></el-table-column>
+ <el-table-column prop="limitsCpu" :label="$t('Limits
Cpu')"></el-table-column>
+ <el-table-column prop="limitsMemory" :label="$t('Limits
Memory')"></el-table-column>
+
+ <el-table-column :label="$t('Create Time')" min-width="120">
+ <template slot-scope="scope">
+ <span>{{scope.row.createTime | formatDate}}</span>
+ </template>
+ </el-table-column>
+ <el-table-column :label="$t('Update Time')" min-width="120">
+ <template slot-scope="scope">
+ <span>{{scope.row.updateTime | formatDate}}</span>
+ </template>
+ </el-table-column>
+ <el-table-column :label="$t('Operation')" width="100">
+ <template slot-scope="scope">
+ <el-tooltip :content="$t('Edit')" placement="top">
+ <el-button type="primary" size="mini"
icon="el-icon-edit-outline" @click="_edit(scope.row)" circle></el-button>
+ </el-tooltip>
+ <el-tooltip :content="$t('Delete')" placement="top">
+ <el-popconfirm
+ :confirmButtonText="$t('Confirm')"
+ :cancelButtonText="$t('Cancel')"
+ icon="el-icon-info"
+ iconColor="red"
+ :title="$t('Delete?')"
+ @onConfirm="_delete(scope.row,scope.row.id)"
+ >
+ <el-button type="danger" size="mini" icon="el-icon-delete"
circle slot="reference"></el-button>
+ </el-popconfirm>
+ </el-tooltip>
+ </template>
+ </el-table-column>
+ </el-table>
+ </div>
+ </div>
+</template>
+<script>
+ import { mapActions } from 'vuex'
+
+ export default {
+ name: 'namespace-list',
+ data () {
+ return {
+ list: []
+ }
+ },
+ props: {
+ namespaceList: Array,
+ pageNo: Number,
+ pageSize: Number
+ },
+ methods: {
+ ...mapActions('security', ['deleteNamespace']),
+ _delete (item, i) {
+ this.deleteNamespace({
+ id: item.id
+ }).then(res => {
+ this.list.splice(i, 1)
+ this.$message.success(res.msg)
+ this.$emit('onUpdate')
+ }).catch(e => {
+ this.$message.error(e.msg || '')
+ })
+ },
+ _edit (item) {
+ this.$emit('on-edit', item)
+ }
+ },
+ watch: {
+ namespaceList (a) {
+ console.warn(a)
+ this.list = []
+ setTimeout(() => {
+ this.list = a
+ })
+ }
+ },
+ created () {
+ this.list = this.namespaceList
+ },
+ mounted () {
+ },
+ components: { }
+ }
+</script>
diff --git
a/dolphinscheduler-ui/src/js/conf/home/pages/security/pages/namespace/index.vue
b/dolphinscheduler-ui/src/js/conf/home/pages/security/pages/namespace/index.vue
new file mode 100644
index 0000000..b4c91c6
--- /dev/null
+++
b/dolphinscheduler-ui/src/js/conf/home/pages/security/pages/namespace/index.vue
@@ -0,0 +1,160 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+<template>
+ <m-list-construction :title="$t('Namespace manage')">
+ <template slot="conditions">
+ <m-conditions @on-conditions="_onConditions">
+ <template slot="button-group" v-if="isADMIN">
+ <el-button size="mini" @click="_create('')">{{$t('Create
namespace')}}</el-button>
+ <el-dialog
+ :title="item ? $t('Edit namespace') : $t('Create namespace')"
+ v-if="createNamespaceDialog"
+ :visible.sync="createNamespaceDialog"
+ width="auto">
+ <m-create-namespace :item="item" @onUpdate="onUpdate"
@close="close"></m-create-namespace>
+ </el-dialog>
+ </template>
+ </m-conditions>
+ </template>
+ <template slot="content">
+ <template v-if="namespaceList.length || total>0">
+ <m-list @on-edit="_onEdit"
+ @onUpdate="onUpdate"
+ :namespace-list="namespaceList"
+ :page-no="searchParams.pageNo"
+ :page-size="searchParams.pageSize">
+
+ </m-list>
+ <div class="page-box">
+ <el-pagination
+ background
+ @current-change="_page"
+ @size-change="_pageSize"
+ :page-size="searchParams.pageSize"
+ :current-page.sync="searchParams.pageNo"
+ :page-sizes="[10, 30, 50]"
+ layout="sizes, prev, pager, next, jumper"
+ :total="total">
+ </el-pagination>
+ </div>
+ </template>
+ <template v-if="!namespaceList.length && total<=0">
+ <m-no-data></m-no-data>
+ </template>
+ <m-spin :is-spin="isLoading" :is-left="isLeft"></m-spin>
+ </template>
+ </m-list-construction>
+</template>
+<script>
+ import _ from 'lodash'
+ import { mapActions } from 'vuex'
+ import mList from './_source/list'
+ import store from '@/conf/home/store'
+ import mSpin from '@/module/components/spin/spin'
+ import mCreateNamespace from './_source/createNamespace'
+ import mNoData from '@/module/components/noData/noData'
+ import listUrlParamHandle from '@/module/mixin/listUrlParamHandle'
+ import mConditions from '@/module/components/conditions/conditions'
+ import mListConstruction from
'@/module/components/listConstruction/listConstruction'
+
+ export default {
+ name: 'namespace-index',
+ data () {
+ return {
+ total: null,
+ isLoading: true,
+ namespaceList: [],
+ searchParams: {
+ pageSize: 10,
+ pageNo: 1,
+ searchVal: ''
+ },
+ isLeft: true,
+ isADMIN: store.state.user.userInfo.userType === 'ADMIN_USER',
+ item: {},
+ createNamespaceDialog: false
+
+ }
+ },
+ mixins: [listUrlParamHandle],
+ props: {},
+ methods: {
+ ...mapActions('security', ['getNamespaceListP']),
+ /**
+ * Query
+ */
+ _onConditions (o) {
+ this.searchParams = _.assign(this.searchParams, o)
+ this.searchParams.pageNo = 1
+ },
+ _page (val) {
+ this.searchParams.pageNo = val
+ },
+ _pageSize (val) {
+ this.searchParams.pageSize = val
+ },
+ _onEdit (item) {
+ this._create(item)
+ },
+ _create (item) {
+ this.item = item
+ this.createNamespaceDialog = true
+ },
+ onUpdate () {
+ this._debounceGET('false')
+ this.createNamespaceDialog = false
+ },
+ close () {
+ this.createNamespaceDialog = false
+ },
+ _getList (flag) {
+ if (sessionStorage.getItem('isLeft') === '0') {
+ this.isLeft = false
+ } else {
+ this.isLeft = true
+ }
+ this.isLoading = !flag
+ this.getNamespaceListP(this.searchParams).then(res => {
+ if (this.searchParams.pageNo > 1 && res.totalList.length === 0) {
+ this.searchParams.pageNo = this.searchParams.pageNo - 1
+ } else {
+ this.namespaceList = res.totalList
+ this.total = res.total
+ this.isLoading = false
+ }
+ }).catch(e => {
+ this.isLoading = false
+ })
+ }
+ },
+ watch: {
+ // router
+ '$route' (a) {
+ // url no params get instance list
+ this.searchParams.pageNo = _.isEmpty(a.query) ? 1 : a.query.pageNo
+ }
+ },
+ created () {
+ },
+ mounted () {
+ },
+ beforeDestroy () {
+ sessionStorage.setItem('isLeft', 1)
+ },
+ components: { mList, mListConstruction, mConditions, mSpin, mNoData,
mCreateNamespace }
+ }
+</script>
diff --git a/dolphinscheduler-ui/src/js/conf/home/router/module/security.js
b/dolphinscheduler-ui/src/js/conf/home/router/module/security.js
index 4087460..cac6e48 100644
--- a/dolphinscheduler-ui/src/js/conf/home/router/module/security.js
+++ b/dolphinscheduler-ui/src/js/conf/home/router/module/security.js
@@ -94,6 +94,14 @@ const security = [
meta: {
title: `${i18n.$t('Token manage')}`
}
+ },
+ {
+ path: '/security/namespace',
+ name: 'namespace',
+ component: resolve =>
require(['../../pages/security/pages/namespace'], resolve),
+ meta: {
+ title: `${i18n.$t('K8s Namespace')}`
+ }
}
]
}
diff --git a/dolphinscheduler-ui/src/js/conf/home/store/security/actions.js
b/dolphinscheduler-ui/src/js/conf/home/store/security/actions.js
index b6b5a87..07cc6c9 100644
--- a/dolphinscheduler-ui/src/js/conf/home/store/security/actions.js
+++ b/dolphinscheduler-ui/src/js/conf/home/store/security/actions.js
@@ -710,5 +710,68 @@ export default {
reject(e)
})
})
+ },
+
+ /**
+ * create namespace
+ */
+ createNamespace ({ state }, payload) {
+ return new Promise((resolve, reject) => {
+ io.post('k8s-namespace', payload, res => {
+ resolve(res)
+ }).catch(e => {
+ reject(e)
+ })
+ })
+ },
+ /**
+ * update namespace
+ */
+ updateNamespace ({ state }, payload) {
+ return new Promise((resolve, reject) => {
+ io.put(`k8s-namespace/${payload.id}`, payload, res => {
+ resolve(res)
+ }).catch(e => {
+ reject(e)
+ })
+ })
+ },
+ /**
+ * update namespace k8s
+ */
+ verifyNamespaceK8s ({ state }, payload) {
+ return new Promise((resolve, reject) => {
+ io.post('k8s-namespace/verify', payload, res => {
+ resolve(res)
+ }).catch(e => {
+ reject(e)
+ })
+ })
+ },
+
+ /**
+ * delete namespace
+ * @param "id":int
+ */
+ deleteNamespace ({ state }, payload) {
+ return new Promise((resolve, reject) => {
+ io.post('k8s-namespace/delete', payload, res => {
+ resolve(res)
+ }).catch(e => {
+ reject(e)
+ })
+ })
+ },
+ /**
+ * get namespace list pages
+ */
+ getNamespaceListP ({ state }, payload) {
+ return new Promise((resolve, reject) => {
+ io.get('k8s-namespace', payload, res => {
+ resolve(res.data)
+ }).catch(e => {
+ reject(e)
+ })
+ })
}
}
diff --git
a/dolphinscheduler-ui/src/js/module/components/secondaryMenu/_source/menu.js
b/dolphinscheduler-ui/src/js/module/components/secondaryMenu/_source/menu.js
index 62f627e..96a812c 100644
--- a/dolphinscheduler-ui/src/js/module/components/secondaryMenu/_source/menu.js
+++ b/dolphinscheduler-ui/src/js/module/components/secondaryMenu/_source/menu.js
@@ -187,6 +187,16 @@ const menu = {
icon: 'el-icon-document',
children: [],
classNames: 'tab-token-manage'
+ },
+ {
+ name: `${i18n.$t('K8s Namespace')}`,
+ id: 2,
+ path: 'namespace',
+ isOpen: true,
+ icon: 'el-icon-s-grid',
+ children: [],
+ enabled: true,
+ classNames: 'tab-namespace-manage'
}
],
resource: [
diff --git a/dolphinscheduler-ui/src/js/module/i18n/locale/en_US.js
b/dolphinscheduler-ui/src/js/module/i18n/locale/en_US.js
index 7b73389..a42f195 100755
--- a/dolphinscheduler-ui/src/js/module/i18n/locale/en_US.js
+++ b/dolphinscheduler-ui/src/js/module/i18n/locale/en_US.js
@@ -901,5 +901,19 @@ export default {
Last7DayFluctuation: 'Last7DayFluctuation',
Last30DayFluctuation: 'Last30DayFluctuation',
SrcTableTotalRows: 'SrcTableTotalRows',
- TargetTableTotalRows: 'TargetTableTotalRows'
+ TargetTableTotalRows: 'TargetTableTotalRows',
+ // k8s
+ 'Create namespace': 'Create namespace',
+ 'Edit namespace': 'Edit namespace',
+ 'Namespace manage': 'K8s namespace manage',
+ 'K8s Namespace': 'k8s Namespace',
+ 'Limits Cpu': 'Limit Cpu',
+ 'Limits Memory': 'Limit Memory',
+ 'K8s Cluster': 'k8s',
+ 'Namespace Owner': 'Owner',
+ 'Please enter k8s cluster': 'Please enter k8s cluster',
+ 'Please enter namespace': 'Please enter namespace',
+ 'Please enter namespace tag': 'Please enter namespace tag can null',
+ 'Please enter owner': 'Please enter owner can null',
+ 'K8s Tag': 'tag'
}
diff --git a/dolphinscheduler-ui/src/js/module/i18n/locale/zh_CN.js
b/dolphinscheduler-ui/src/js/module/i18n/locale/zh_CN.js
index d0c2871..dd823bb 100755
--- a/dolphinscheduler-ui/src/js/module/i18n/locale/zh_CN.js
+++ b/dolphinscheduler-ui/src/js/module/i18n/locale/zh_CN.js
@@ -901,5 +901,19 @@ export default {
Last7DayFluctuation: '最近7天波动',
Last30DayFluctuation: '最近30天波动',
SrcTableTotalRows: '源表总行数',
- TargetTableTotalRows: '目标表总行数'
+ TargetTableTotalRows: '目标表总行数',
+ // k8s
+ 'Create namespace': '创建命名空间',
+ 'Edit namespace': '编辑命名空间',
+ 'Namespace manage': 'k8s命名空间 管理',
+ 'K8s Namespace': 'k8s命名空间',
+ 'Limits Cpu': '最大Cpu',
+ 'Limits Memory': '最大内存',
+ 'K8s Cluster': 'k8s集群',
+ 'Namespace Owner': '负责人',
+ 'Please enter k8s cluster': '请输入k8s集群值',
+ 'Please enter namespace': '请输入命名空间',
+ 'Please enter namespace tag': '请输入命名空间标签可空',
+ 'Please enter owner': '请输入owner可空',
+ 'K8s Tag': '标签'
}
diff --git a/pom.xml b/pom.xml
index 9c7bceb..8d3fb24 100644
--- a/pom.xml
+++ b/pom.xml
@@ -127,6 +127,7 @@
<error_prone_annotations.version>2.5.1</error_prone_annotations.version>
<exec-maven-plugin.version>3.0.0</exec-maven-plugin.version>
<janino.version>3.1.6</janino.version>
+ <kubernetes.version>5.8.0</kubernetes.version>
<docker.hub>apache</docker.hub>
<docker.repo>${project.name}</docker.repo>
@@ -902,6 +903,12 @@
<artifactId>error_prone_annotations</artifactId>
<version>${error_prone_annotations.version}</version>
</dependency>
+
+ <dependency>
+ <groupId>io.fabric8</groupId>
+ <artifactId>kubernetes-client</artifactId>
+ <version>${kubernetes.version}</version>
+ </dependency>
</dependencies>
</dependencyManagement>
diff --git a/tools/dependencies/known-dependencies.txt
b/tools/dependencies/known-dependencies.txt
index 973f3cb..6e9ecfb 100755
--- a/tools/dependencies/known-dependencies.txt
+++ b/tools/dependencies/known-dependencies.txt
@@ -237,3 +237,31 @@ xmlbeans-3.1.0.jar
xmlenc-0.52.jar
zookeeper-3.4.14.jar
Java-WebSocket-1.5.1.jar
+kubernetes-client-5.8.0.jar
+kubernetes-model-admissionregistration-5.8.0.jar
+kubernetes-model-apiextensions-5.8.0.jar
+kubernetes-model-apps-5.8.0.jar
+kubernetes-model-autoscaling-5.8.0.jar
+kubernetes-model-batch-5.8.0.jar
+kubernetes-model-certificates-5.8.0.jar
+kubernetes-model-common-5.8.0.jar
+kubernetes-model-coordination-5.8.0.jar
+kubernetes-model-core-5.8.0.jar
+kubernetes-model-discovery-5.8.0.jar
+kubernetes-model-events-5.8.0.jar
+kubernetes-model-extensions-5.8.0.jar
+kubernetes-model-flowcontrol-5.8.0.jar
+kubernetes-model-metrics-5.8.0.jar
+kubernetes-model-networking-5.8.0.jar
+kubernetes-model-node-5.8.0.jar
+kubernetes-model-policy-5.8.0.jar
+kubernetes-model-rbac-5.8.0.jar
+kubernetes-model-scheduling-5.8.0.jar
+kubernetes-model-storageclass-5.8.0.jar
+zjsonpatch-0.3.0.jar
+automaton-1.11-8.jar
+generex-1.0.2.jar
+jackson-dataformat-yaml-2.12.5.jar
+logging-interceptor-3.14.9.jar
+okhttp-3.14.9.jar
+okio-1.17.2.jar
\ No newline at end of file