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 0000000000..ddae560d67 --- /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 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 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 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 5bb6a2fd05..1f6add9b64 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 0000000000..c9156a38f3 --- /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 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 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 verifyNamespaceK8s(String namespace, String k8s); + + /** + * delete namespace by id + * + * @param loginUser login user + * @param id namespace id + * @return + */ + Map 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 0000000000..faa8a24cb3 --- /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 page = new Page<>(pageNo, pageSize); + + IPage k8sNamespaceList = k8sNamespaceMapper.queryK8sNamespacePaging(page, searchVal); + + Integer count = (int) k8sNamespaceList.getTotal(); + PageInfo 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 createK8sNamespace(User loginUser, String namespace, String k8s, String owner, String tag, Double limitsCpu, Integer limitsMemory) { + Map 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 updateK8sNamespace(User loginUser, int id, String owner, String tag, Double limitsCpu, Integer limitsMemory) { + Map 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 verifyNamespaceK8s(String namespace, String k8s) { + Result 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 deleteNamespaceById(User loginUser, int id) { + Map 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 0000000000..830943ba0d --- /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 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 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 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 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 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 0000000000..26735565d1 --- /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 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 pageInfo = (PageInfo) result.getData(); + Assert.assertTrue(CollectionUtils.isNotEmpty(pageInfo.getTotalList())); + } + + @Test + public void createK8sNamespace() { + // namespace is null + Map 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 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 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 getNamespaceList() { + List 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 7da88c4cc5..671af2bf26 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 0000000000..2cddf171e2 --- /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 0000000000..d22e7bd520 --- /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 0000000000..bcf617b988 --- /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 { + +} 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 0000000000..e804d55402 --- /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 { + /** + * k8s namespace page + * + * @param page page + * @param searchVal searchVal + * @return k8s namespace IPage + */ + IPage queryK8sNamespacePaging(IPage 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 0000000000..9099e0c411 --- /dev/null +++ b/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/K8sNamespaceMapper.xml @@ -0,0 +1,48 @@ + + + + + + + + id, namespace, k8s, owner, tag, limits_memory, limits_cpu, online_job_num, pod_replicas, pod_request_cpu, pod_request_memory, create_time, update_time + + + + + + diff --git a/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_h2.sql b/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_h2.sql index 45a452f643..3d4536dab7 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 ca3724b989..eed27f9287 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 1e371d728e..5d5ce6fcba 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 e12b696090..5f668880ff 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 3e35d60566..854b787204 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 6c4e13456d..642bee488b 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 0000000000..7253426123 --- /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 0000000000..0d10e345fe --- /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 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 2bbdd7bd2b..d2d78356e4 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 387f613308..8143cd7725 100644 --- a/dolphinscheduler-service/pom.xml +++ b/dolphinscheduler-service/pom.xml @@ -90,5 +90,9 @@ com.github.ben-manes.caffeine caffeine + + io.fabric8 + kubernetes-client + 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 0000000000..c921054f6b --- /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 deleteNamespaceToK8s(String name, String k8s) { + Optional 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 getNamespaceFromK8s(String name, String k8s) { + NamespaceList listNamespace = + k8sManager.getK8sClient(k8s).namespaces().list(); + + Optional list = + listNamespace.getItems().stream() + .filter((Namespace namespace) -> + namespace.getMetadata().getName().equals(name)) + .findFirst(); + + return list; + } + + private Namespace upsertNamespaceToK8s(String name, String k8s) { + Optional 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 0000000000..c86d0eca07 --- /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 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 nodeWrapper = new QueryWrapper<>(); + List 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 0000000000..2740b7d57f --- /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 getK8sList() { + List 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 0000000000..3d0903e85d --- /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. + */ + + 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 0000000000..73153b8851 --- /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. + */ + + 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 0000000000..b4c91c6c10 --- /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. + */ + + 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 4087460f19..cac6e4821f 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 b6b5a87382..07cc6c9643 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 62f627eb5c..96a812ca63 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 7b73389007..a42f195183 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 d0c28718e5..dd823bb1b2 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 9c7bcebac9..8d3fb24923 100644 --- a/pom.xml +++ b/pom.xml @@ -127,6 +127,7 @@ 2.5.1 3.0.0 3.1.6 + 5.8.0 apache ${project.name} @@ -902,6 +903,12 @@ error_prone_annotations ${error_prone_annotations.version} + + + io.fabric8 + kubernetes-client + ${kubernetes.version} + diff --git a/tools/dependencies/known-dependencies.txt b/tools/dependencies/known-dependencies.txt index 973f3cb1a4..6e9ecfbbf1 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