Browse Source
* service code * [Feature][UI] Add front-end for cluster manage * fix e2e * remove comment on cluster controller * doc * img * setting e2e.yaml * test * rerun e2e * fix bug from comment * Update index.tsx use Nspace instead of css. * Update index.tsx Remove the style. * Delete index.module.scss Remove the useless file. Co-authored-by: qianl4 <qianl4@cicso.com> Co-authored-by: William Tong <weitong@cisco.com> Co-authored-by: Amy0104 <97265214+Amy0104@users.noreply.github.com>3.1.0-release
qianli2022
2 years ago
committed by
GitHub
39 changed files with 3178 additions and 35 deletions
After Width: | Height: | Size: 627 KiB |
@ -0,0 +1,236 @@
|
||||
/* |
||||
* 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_CLUSTER_ERROR; |
||||
import static org.apache.dolphinscheduler.api.enums.Status.DELETE_CLUSTER_ERROR; |
||||
import static org.apache.dolphinscheduler.api.enums.Status.QUERY_CLUSTER_BY_CODE_ERROR; |
||||
import static org.apache.dolphinscheduler.api.enums.Status.QUERY_CLUSTER_ERROR; |
||||
import static org.apache.dolphinscheduler.api.enums.Status.UPDATE_CLUSTER_ERROR; |
||||
import static org.apache.dolphinscheduler.api.enums.Status.VERIFY_CLUSTER_ERROR; |
||||
|
||||
import org.apache.dolphinscheduler.api.aspect.AccessLogAnnotation; |
||||
import org.apache.dolphinscheduler.api.exceptions.ApiException; |
||||
import org.apache.dolphinscheduler.api.service.ClusterService; |
||||
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.PostMapping; |
||||
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; |
||||
|
||||
/** |
||||
* cluster controller |
||||
*/ |
||||
@Api(tags = "CLUSTER_TAG") |
||||
@RestController |
||||
@RequestMapping("cluster") |
||||
public class ClusterController extends BaseController { |
||||
|
||||
@Autowired |
||||
private ClusterService clusterService; |
||||
|
||||
/** |
||||
* create cluster |
||||
* |
||||
* @param loginUser login user |
||||
* @param name cluster name |
||||
* @param config config |
||||
* @param description description |
||||
* @return returns an error if it exists |
||||
*/ |
||||
@ApiOperation(value = "createCluster", notes = "CREATE_CLUSTER_NOTES") |
||||
@ApiImplicitParams({ |
||||
@ApiImplicitParam(name = "name", value = "CLUSTER_NAME", required = true, dataType = "String"), |
||||
@ApiImplicitParam(name = "config", value = "CONFIG", required = true, dataType = "String"), |
||||
@ApiImplicitParam(name = "description", value = "CLUSTER_DESC", dataType = "String") |
||||
}) |
||||
@PostMapping(value = "/create") |
||||
@ResponseStatus(HttpStatus.CREATED) |
||||
@ApiException(CREATE_CLUSTER_ERROR) |
||||
@AccessLogAnnotation(ignoreRequestArgs = "loginUser") |
||||
public Result createProject(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser, |
||||
@RequestParam("name") String name, |
||||
@RequestParam("config") String config, |
||||
@RequestParam(value = "description", required = false) String description) { |
||||
|
||||
Map<String, Object> result = clusterService.createCluster(loginUser, name, config, description); |
||||
return returnDataList(result); |
||||
} |
||||
|
||||
/** |
||||
* update cluster |
||||
* |
||||
* @param loginUser login user |
||||
* @param code cluster code |
||||
* @param name cluster name |
||||
* @param config cluster config |
||||
* @param description description |
||||
* @return update result code |
||||
*/ |
||||
@ApiOperation(value = "updateCluster", notes = "UPDATE_CLUSTER_NOTES") |
||||
@ApiImplicitParams({ |
||||
@ApiImplicitParam(name = "code", value = "CLUSTER_CODE", required = true, dataType = "Long", example = "100"), |
||||
@ApiImplicitParam(name = "name", value = "CLUSTER_NAME", required = true, dataType = "String"), |
||||
@ApiImplicitParam(name = "config", value = "CLUSTER_CONFIG", required = true, dataType = "String"), |
||||
@ApiImplicitParam(name = "description", value = "CLUSTER_DESC", dataType = "String"), |
||||
}) |
||||
@PostMapping(value = "/update") |
||||
@ResponseStatus(HttpStatus.OK) |
||||
@ApiException(UPDATE_CLUSTER_ERROR) |
||||
@AccessLogAnnotation(ignoreRequestArgs = "loginUser") |
||||
public Result updateCluster(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser, |
||||
@RequestParam("code") Long code, |
||||
@RequestParam("name") String name, |
||||
@RequestParam("config") String config, |
||||
@RequestParam(value = "description", required = false) String description) { |
||||
Map<String, Object> result = clusterService.updateClusterByCode(loginUser, code, name, config, description); |
||||
return returnDataList(result); |
||||
} |
||||
|
||||
/** |
||||
* query cluster details by code |
||||
* |
||||
* @param clusterCode cluster code |
||||
* @return cluster detail information |
||||
*/ |
||||
@ApiOperation(value = "queryClusterByCode", notes = "QUERY_CLUSTER_BY_CODE_NOTES") |
||||
@ApiImplicitParams({ |
||||
@ApiImplicitParam(name = "clusterCode", value = "CLUSTER_CODE", required = true, dataType = "Long", example = "100") |
||||
}) |
||||
@GetMapping(value = "/query-by-code") |
||||
@ResponseStatus(HttpStatus.OK) |
||||
@ApiException(QUERY_CLUSTER_BY_CODE_ERROR) |
||||
@AccessLogAnnotation(ignoreRequestArgs = "loginUser") |
||||
public Result queryClusterByCode(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser, |
||||
@RequestParam("clusterCode") Long clusterCode) { |
||||
|
||||
Map<String, Object> result = clusterService.queryClusterByCode(clusterCode); |
||||
return returnDataList(result); |
||||
} |
||||
|
||||
/** |
||||
* query cluster list paging |
||||
* |
||||
* @param searchVal search value |
||||
* @param pageSize page size |
||||
* @param pageNo page number |
||||
* @return cluster list which the login user have permission to see |
||||
*/ |
||||
@ApiOperation(value = "queryClusterListPaging", notes = "QUERY_CLUSTER_LIST_PAGING_NOTES") |
||||
@ApiImplicitParams({ |
||||
@ApiImplicitParam(name = "searchVal", value = "SEARCH_VAL", dataType = "String"), |
||||
@ApiImplicitParam(name = "pageSize", value = "PAGE_SIZE", required = true, dataType = "Int", example = "20"), |
||||
@ApiImplicitParam(name = "pageNo", value = "PAGE_NO", required = true, dataType = "Int", example = "1") |
||||
}) |
||||
@GetMapping(value = "/list-paging") |
||||
@ResponseStatus(HttpStatus.OK) |
||||
@ApiException(QUERY_CLUSTER_ERROR) |
||||
@AccessLogAnnotation(ignoreRequestArgs = "loginUser") |
||||
public Result queryClusterListPaging(@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 = clusterService.queryClusterListPaging(pageNo, pageSize, searchVal); |
||||
return result; |
||||
} |
||||
|
||||
/** |
||||
* delete cluster by code |
||||
* |
||||
* @param loginUser login user |
||||
* @param clusterCode cluster code |
||||
* @return delete result code |
||||
*/ |
||||
@ApiOperation(value = "deleteClusterByCode", notes = "DELETE_CLUSTER_BY_CODE_NOTES") |
||||
@ApiImplicitParams({ |
||||
@ApiImplicitParam(name = "clusterCode", value = "CLUSTER_CODE", required = true, dataType = "Long", example = "100") |
||||
}) |
||||
@PostMapping(value = "/delete") |
||||
@ResponseStatus(HttpStatus.OK) |
||||
@ApiException(DELETE_CLUSTER_ERROR) |
||||
@AccessLogAnnotation(ignoreRequestArgs = "loginUser") |
||||
public Result deleteCluster(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser, |
||||
@RequestParam("clusterCode") Long clusterCode |
||||
) { |
||||
|
||||
Map<String, Object> result = clusterService.deleteClusterByCode(loginUser, clusterCode); |
||||
return returnDataList(result); |
||||
} |
||||
|
||||
/** |
||||
* query all cluster list |
||||
* |
||||
* @param loginUser login user |
||||
* @return all cluster list |
||||
*/ |
||||
@ApiOperation(value = "queryAllClusterList", notes = "QUERY_ALL_CLUSTER_LIST_NOTES") |
||||
@GetMapping(value = "/query-cluster-list") |
||||
@ResponseStatus(HttpStatus.OK) |
||||
@ApiException(QUERY_CLUSTER_ERROR) |
||||
@AccessLogAnnotation(ignoreRequestArgs = "loginUser") |
||||
public Result queryAllClusterList(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser) { |
||||
Map<String, Object> result = clusterService.queryAllClusterList(); |
||||
return returnDataList(result); |
||||
} |
||||
|
||||
/** |
||||
* verify cluster and cluster name |
||||
* |
||||
* @param loginUser login user |
||||
* @param clusterName cluster name |
||||
* @return true if the cluster name not exists, otherwise return false |
||||
*/ |
||||
@ApiOperation(value = "verifyCluster", notes = "VERIFY_CLUSTER_NOTES") |
||||
@ApiImplicitParams({ |
||||
@ApiImplicitParam(name = "clusterName", value = "CLUSTER_NAME", required = true, dataType = "String") |
||||
}) |
||||
@PostMapping(value = "/verify-cluster") |
||||
@ResponseStatus(HttpStatus.OK) |
||||
@ApiException(VERIFY_CLUSTER_ERROR) |
||||
@AccessLogAnnotation(ignoreRequestArgs = "loginUser") |
||||
public Result verifyCluster(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser, |
||||
@RequestParam(value = "clusterName") String clusterName |
||||
) { |
||||
Map<String, Object> result = clusterService.verifyCluster(clusterName); |
||||
return returnDataList(result); |
||||
} |
||||
} |
@ -0,0 +1,129 @@
|
||||
/* |
||||
* 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.dto; |
||||
|
||||
import java.util.Date; |
||||
import java.util.List; |
||||
|
||||
/** |
||||
* ClusterDto |
||||
*/ |
||||
public class ClusterDto { |
||||
|
||||
private int id; |
||||
|
||||
/** |
||||
* clluster code |
||||
*/ |
||||
private Long code; |
||||
|
||||
/** |
||||
* clluster name |
||||
*/ |
||||
private String name; |
||||
|
||||
/** |
||||
* config content |
||||
*/ |
||||
private String config; |
||||
|
||||
private String description; |
||||
|
||||
private List<String> processDefinitions; |
||||
|
||||
/** |
||||
* operator user id |
||||
*/ |
||||
private Integer operator; |
||||
|
||||
private Date createTime; |
||||
|
||||
private Date updateTime; |
||||
|
||||
public int getId() { |
||||
return id; |
||||
} |
||||
|
||||
public void setId(int id) { |
||||
this.id = id; |
||||
} |
||||
|
||||
public String getName() { |
||||
return name; |
||||
} |
||||
|
||||
public void setName(String name) { |
||||
this.name = name; |
||||
} |
||||
|
||||
public Long getCode() { |
||||
return this.code; |
||||
} |
||||
|
||||
public void setCode(Long code) { |
||||
this.code = code; |
||||
} |
||||
|
||||
public String getConfig() { |
||||
return this.config; |
||||
} |
||||
|
||||
public void setConfig(String config) { |
||||
this.config = config; |
||||
} |
||||
|
||||
public String getDescription() { |
||||
return this.description; |
||||
} |
||||
|
||||
public void setDescription(String description) { |
||||
this.description = description; |
||||
} |
||||
|
||||
public Integer getOperator() { |
||||
return this.operator; |
||||
} |
||||
|
||||
public void setOperator(Integer operator) { |
||||
this.operator = operator; |
||||
} |
||||
|
||||
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 List<String> getProcessDefinitions() { |
||||
return processDefinitions; |
||||
} |
||||
|
||||
public void setProcessDefinitions(List<String> processDefinitions) { |
||||
this.processDefinitions = processDefinitions; |
||||
} |
||||
} |
@ -0,0 +1,99 @@
|
||||
/* |
||||
* 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; |
||||
|
||||
/** |
||||
* cluster service |
||||
*/ |
||||
public interface ClusterService { |
||||
|
||||
/** |
||||
* create cluster |
||||
* |
||||
* @param loginUser login user |
||||
* @param name cluster name |
||||
* @param config cluster config |
||||
* @param desc cluster desc |
||||
*/ |
||||
Map<String, Object> createCluster(User loginUser, String name, String config, String desc); |
||||
|
||||
/** |
||||
* query cluster |
||||
* |
||||
* @param name cluster name |
||||
*/ |
||||
Map<String, Object> queryClusterByName(String name); |
||||
|
||||
/** |
||||
* query cluster |
||||
* |
||||
* @param code cluster code |
||||
*/ |
||||
Map<String, Object> queryClusterByCode(Long code); |
||||
|
||||
/** |
||||
* delete cluster |
||||
* |
||||
* @param loginUser login user |
||||
* @param code cluster code |
||||
*/ |
||||
Map<String, Object> deleteClusterByCode(User loginUser, Long code); |
||||
|
||||
/** |
||||
* update cluster |
||||
* |
||||
* @param loginUser login user |
||||
* @param code cluster code |
||||
* @param name cluster name |
||||
* @param config cluster config |
||||
* @param desc cluster desc |
||||
*/ |
||||
Map<String, Object> updateClusterByCode(User loginUser, Long code, String name, String config, String desc); |
||||
|
||||
/** |
||||
* query cluster paging |
||||
* |
||||
* @param pageNo page number |
||||
* @param searchVal search value |
||||
* @param pageSize page size |
||||
* @return cluster list page |
||||
*/ |
||||
Result queryClusterListPaging(Integer pageNo, Integer pageSize, String searchVal); |
||||
|
||||
/** |
||||
* query all cluster |
||||
* |
||||
* @return all cluster list |
||||
*/ |
||||
Map<String, Object> queryAllClusterList(); |
||||
|
||||
/** |
||||
* verify cluster name |
||||
* |
||||
* @param clusterName cluster name |
||||
* @return true if the cluster name not exists, otherwise return false |
||||
*/ |
||||
Map<String, Object> verifyCluster(String clusterName); |
||||
|
||||
} |
||||
|
@ -0,0 +1,335 @@
|
||||
/* |
||||
* 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.dto.ClusterDto; |
||||
import org.apache.dolphinscheduler.api.enums.Status; |
||||
import org.apache.dolphinscheduler.api.service.ClusterService; |
||||
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.utils.CodeGenerateUtils; |
||||
import org.apache.dolphinscheduler.common.utils.CodeGenerateUtils.CodeGenerateException; |
||||
import org.apache.dolphinscheduler.dao.entity.Cluster; |
||||
import org.apache.dolphinscheduler.dao.entity.User; |
||||
import org.apache.dolphinscheduler.dao.mapper.ClusterMapper; |
||||
|
||||
import org.apache.commons.collections.CollectionUtils; |
||||
import org.apache.commons.lang.StringUtils; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.Date; |
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
import java.util.stream.Collectors; |
||||
|
||||
import org.slf4j.Logger; |
||||
import org.slf4j.LoggerFactory; |
||||
import org.springframework.beans.BeanUtils; |
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.stereotype.Service; |
||||
import org.springframework.transaction.annotation.Transactional; |
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage; |
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
||||
|
||||
/** |
||||
* cluster definition service impl |
||||
*/ |
||||
@Service |
||||
public class ClusterServiceImpl extends BaseServiceImpl implements ClusterService { |
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ClusterServiceImpl.class); |
||||
|
||||
@Autowired |
||||
private ClusterMapper clusterMapper; |
||||
|
||||
/** |
||||
* create cluster |
||||
* |
||||
* @param loginUser login user |
||||
* @param name cluster name |
||||
* @param config cluster config |
||||
* @param desc cluster desc |
||||
*/ |
||||
@Transactional(rollbackFor = RuntimeException.class) |
||||
@Override |
||||
public Map<String, Object> createCluster(User loginUser, String name, String config, String desc) { |
||||
Map<String, Object> result = new HashMap<>(); |
||||
if (isNotAdmin(loginUser, result)) { |
||||
return result; |
||||
} |
||||
|
||||
Map<String, Object> checkResult = checkParams(name, config); |
||||
if (checkResult.get(Constants.STATUS) != Status.SUCCESS) { |
||||
return checkResult; |
||||
} |
||||
|
||||
Cluster clusterExistByName = clusterMapper.queryByClusterName(name); |
||||
if (clusterExistByName != null) { |
||||
putMsg(result, Status.CLUSTER_NAME_EXISTS, name); |
||||
return result; |
||||
} |
||||
|
||||
Cluster cluster = new Cluster(); |
||||
cluster.setName(name); |
||||
cluster.setConfig(config); |
||||
cluster.setDescription(desc); |
||||
cluster.setOperator(loginUser.getId()); |
||||
cluster.setCreateTime(new Date()); |
||||
cluster.setUpdateTime(new Date()); |
||||
long code = 0L; |
||||
try { |
||||
code = CodeGenerateUtils.getInstance().genCode(); |
||||
cluster.setCode(code); |
||||
} catch (CodeGenerateException e) { |
||||
logger.error("Cluster code get error, ", e); |
||||
} |
||||
if (code == 0L) { |
||||
putMsg(result, Status.INTERNAL_SERVER_ERROR_ARGS, "Error generating cluster code"); |
||||
return result; |
||||
} |
||||
|
||||
if (clusterMapper.insert(cluster) > 0) { |
||||
result.put(Constants.DATA_LIST, cluster.getCode()); |
||||
putMsg(result, Status.SUCCESS); |
||||
} else { |
||||
putMsg(result, Status.CREATE_CLUSTER_ERROR); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
/** |
||||
* query cluster paging |
||||
* |
||||
* @param pageNo page number |
||||
* @param searchVal search value |
||||
* @param pageSize page size |
||||
* @return cluster list page |
||||
*/ |
||||
@Override |
||||
public Result queryClusterListPaging(Integer pageNo, Integer pageSize, String searchVal) { |
||||
Result result = new Result(); |
||||
|
||||
Page<Cluster> page = new Page<>(pageNo, pageSize); |
||||
|
||||
IPage<Cluster> clusterIPage = clusterMapper.queryClusterListPaging(page, searchVal); |
||||
|
||||
PageInfo<ClusterDto> pageInfo = new PageInfo<>(pageNo, pageSize); |
||||
pageInfo.setTotal((int) clusterIPage.getTotal()); |
||||
|
||||
if (CollectionUtils.isNotEmpty(clusterIPage.getRecords())) { |
||||
|
||||
List<ClusterDto> dtoList = clusterIPage.getRecords().stream().map(cluster -> { |
||||
ClusterDto dto = new ClusterDto(); |
||||
BeanUtils.copyProperties(cluster, dto); |
||||
return dto; |
||||
}).collect(Collectors.toList()); |
||||
|
||||
pageInfo.setTotalList(dtoList); |
||||
} else { |
||||
pageInfo.setTotalList(new ArrayList<>()); |
||||
} |
||||
|
||||
result.setData(pageInfo); |
||||
putMsg(result, Status.SUCCESS); |
||||
return result; |
||||
} |
||||
|
||||
/** |
||||
* query all cluster |
||||
* |
||||
* @return all cluster list |
||||
*/ |
||||
@Override |
||||
public Map<String, Object> queryAllClusterList() { |
||||
Map<String, Object> result = new HashMap<>(); |
||||
List<Cluster> clusterList = clusterMapper.queryAllClusterList(); |
||||
|
||||
if (CollectionUtils.isNotEmpty(clusterList)) { |
||||
|
||||
List<ClusterDto> dtoList = clusterList.stream().map(cluster -> { |
||||
ClusterDto dto = new ClusterDto(); |
||||
BeanUtils.copyProperties(cluster, dto); |
||||
return dto; |
||||
}).collect(Collectors.toList()); |
||||
result.put(Constants.DATA_LIST, dtoList); |
||||
} else { |
||||
result.put(Constants.DATA_LIST, new ArrayList<>()); |
||||
} |
||||
|
||||
putMsg(result, Status.SUCCESS); |
||||
return result; |
||||
} |
||||
|
||||
/** |
||||
* query cluster |
||||
* |
||||
* @param code cluster code |
||||
*/ |
||||
@Override |
||||
public Map<String, Object> queryClusterByCode(Long code) { |
||||
Map<String, Object> result = new HashMap<>(); |
||||
|
||||
Cluster cluster = clusterMapper.queryByClusterCode(code); |
||||
|
||||
if (cluster == null) { |
||||
putMsg(result, Status.QUERY_CLUSTER_BY_CODE_ERROR, code); |
||||
} else { |
||||
|
||||
ClusterDto dto = new ClusterDto(); |
||||
BeanUtils.copyProperties(cluster, dto); |
||||
result.put(Constants.DATA_LIST, dto); |
||||
putMsg(result, Status.SUCCESS); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
/** |
||||
* query cluster |
||||
* |
||||
* @param name cluster name |
||||
*/ |
||||
@Override |
||||
public Map<String, Object> queryClusterByName(String name) { |
||||
Map<String, Object> result = new HashMap<>(); |
||||
|
||||
Cluster cluster = clusterMapper.queryByClusterName(name); |
||||
if (cluster == null) { |
||||
putMsg(result, Status.QUERY_CLUSTER_BY_NAME_ERROR, name); |
||||
} else { |
||||
|
||||
ClusterDto dto = new ClusterDto(); |
||||
BeanUtils.copyProperties(cluster, dto); |
||||
result.put(Constants.DATA_LIST, dto); |
||||
putMsg(result, Status.SUCCESS); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
/** |
||||
* delete cluster |
||||
* |
||||
* @param loginUser login user |
||||
* @param code cluster code |
||||
*/ |
||||
@Transactional(rollbackFor = RuntimeException.class) |
||||
@Override |
||||
public Map<String, Object> deleteClusterByCode(User loginUser, Long code) { |
||||
Map<String, Object> result = new HashMap<>(); |
||||
if (isNotAdmin(loginUser, result)) { |
||||
return result; |
||||
} |
||||
|
||||
int delete = clusterMapper.deleteByCode(code); |
||||
if (delete > 0) { |
||||
putMsg(result, Status.SUCCESS); |
||||
} else { |
||||
putMsg(result, Status.DELETE_CLUSTER_ERROR); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* update cluster |
||||
* |
||||
* @param loginUser login user |
||||
* @param code cluster code |
||||
* @param name cluster name |
||||
* @param config cluster config |
||||
* @param desc cluster desc |
||||
*/ |
||||
@Transactional(rollbackFor = RuntimeException.class) |
||||
@Override |
||||
public Map<String, Object> updateClusterByCode(User loginUser, Long code, String name, String config, String desc) { |
||||
Map<String, Object> result = new HashMap<>(); |
||||
if (isNotAdmin(loginUser, result)) { |
||||
return result; |
||||
} |
||||
|
||||
Map<String, Object> checkResult = checkParams(name, config); |
||||
if (checkResult.get(Constants.STATUS) != Status.SUCCESS) { |
||||
return checkResult; |
||||
} |
||||
|
||||
Cluster clusterExistByName = clusterMapper.queryByClusterName(name); |
||||
if (clusterExistByName != null && !clusterExistByName.getCode().equals(code)) { |
||||
putMsg(result, Status.CLUSTER_NAME_EXISTS, name); |
||||
return result; |
||||
} |
||||
|
||||
Cluster clusterExist = clusterMapper.queryByClusterCode(code); |
||||
if (clusterExist == null) { |
||||
putMsg(result, Status.CLUSTER_NOT_EXISTS, name); |
||||
return result; |
||||
} |
||||
|
||||
//update cluster
|
||||
clusterExist.setConfig(config); |
||||
clusterExist.setName(name); |
||||
clusterExist.setDescription(desc); |
||||
clusterMapper.updateById(clusterExist); |
||||
//need not update relation
|
||||
|
||||
putMsg(result, Status.SUCCESS); |
||||
return result; |
||||
} |
||||
|
||||
/** |
||||
* verify cluster name |
||||
* |
||||
* @param clusterName cluster name |
||||
* @return true if the cluster name not exists, otherwise return false |
||||
*/ |
||||
@Override |
||||
public Map<String, Object> verifyCluster(String clusterName) { |
||||
Map<String, Object> result = new HashMap<>(); |
||||
|
||||
if (StringUtils.isEmpty(clusterName)) { |
||||
putMsg(result, Status.CLUSTER_NAME_IS_NULL); |
||||
return result; |
||||
} |
||||
|
||||
Cluster cluster = clusterMapper.queryByClusterName(clusterName); |
||||
if (cluster != null) { |
||||
putMsg(result, Status.CLUSTER_NAME_EXISTS, clusterName); |
||||
return result; |
||||
} |
||||
|
||||
result.put(Constants.STATUS, Status.SUCCESS); |
||||
return result; |
||||
} |
||||
|
||||
public Map<String, Object> checkParams(String name, String config) { |
||||
Map<String, Object> result = new HashMap<>(); |
||||
if (StringUtils.isEmpty(name)) { |
||||
putMsg(result, Status.CLUSTER_NAME_IS_NULL); |
||||
return result; |
||||
} |
||||
if (StringUtils.isEmpty(config)) { |
||||
putMsg(result, Status.CLUSTER_CONFIG_IS_NULL); |
||||
return result; |
||||
} |
||||
result.put(Constants.STATUS, Status.SUCCESS); |
||||
return result; |
||||
} |
||||
|
||||
} |
||||
|
@ -0,0 +1,202 @@
|
||||
/* |
||||
* 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.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.junit.After; |
||||
import org.junit.Assert; |
||||
import org.junit.Before; |
||||
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; |
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference; |
||||
import com.google.common.base.Preconditions; |
||||
|
||||
public class ClusterControllerTest extends AbstractControllerTest { |
||||
public static final String clusterName = "Cluster1"; |
||||
public static final String config = "this is config content"; |
||||
public static final String desc = "this is cluster description"; |
||||
private static final Logger logger = LoggerFactory.getLogger(ClusterControllerTest.class); |
||||
private String clusterCode; |
||||
|
||||
@Before |
||||
public void before() throws Exception { |
||||
testCreateCluster(); |
||||
} |
||||
|
||||
@Override |
||||
@After |
||||
public void after() throws Exception { |
||||
testDeleteCluster(); |
||||
} |
||||
|
||||
public void testCreateCluster() throws Exception { |
||||
|
||||
MultiValueMap<String, String> paramsMap = new LinkedMultiValueMap<>(); |
||||
paramsMap.add("name", clusterName); |
||||
paramsMap.add("config", config); |
||||
paramsMap.add("description", desc); |
||||
|
||||
MvcResult mvcResult = mockMvc.perform(post("/cluster/create") |
||||
.header(SESSION_ID, sessionId) |
||||
.params(paramsMap)) |
||||
.andExpect(status().isCreated()) |
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON)) |
||||
.andReturn(); |
||||
|
||||
Result result = JSONUtils.parseObject(mvcResult.getResponse().getContentAsString(), new TypeReference<Result<String>>() { |
||||
}); |
||||
logger.info(result.toString()); |
||||
Assert.assertTrue(result != null && result.isSuccess()); |
||||
Assert.assertNotNull(result.getData()); |
||||
logger.info("create cluster return result:{}", mvcResult.getResponse().getContentAsString()); |
||||
|
||||
clusterCode = (String) result.getData(); |
||||
} |
||||
|
||||
@Test |
||||
public void testUpdateCluster() throws Exception { |
||||
MultiValueMap<String, String> paramsMap = new LinkedMultiValueMap<>(); |
||||
paramsMap.add("code", clusterCode); |
||||
paramsMap.add("name", "cluster_test_update"); |
||||
paramsMap.add("config", "{\"k8s\":\"apiVersion: v1\"}"); |
||||
paramsMap.add("desc", "the test cluster update"); |
||||
|
||||
MvcResult mvcResult = mockMvc.perform(post("/cluster/update") |
||||
.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); |
||||
logger.info(result.toString()); |
||||
Assert.assertTrue(result != null && result.isSuccess()); |
||||
logger.info("update cluster return result:{}", mvcResult.getResponse().getContentAsString()); |
||||
|
||||
} |
||||
|
||||
@Test |
||||
public void testQueryClusterByCode() throws Exception { |
||||
MultiValueMap<String, String> paramsMap = new LinkedMultiValueMap<>(); |
||||
paramsMap.add("clusterCode", clusterCode); |
||||
|
||||
MvcResult mvcResult = mockMvc.perform(get("/cluster/query-by-code") |
||||
.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); |
||||
logger.info(result.toString()); |
||||
Assert.assertTrue(result != null && result.isSuccess()); |
||||
logger.info(mvcResult.getResponse().getContentAsString()); |
||||
logger.info("query cluster by id :{}, return result:{}", clusterCode, mvcResult.getResponse().getContentAsString()); |
||||
|
||||
} |
||||
|
||||
@Test |
||||
public void testQueryClusterListPaging() throws Exception { |
||||
MultiValueMap<String, String> paramsMap = new LinkedMultiValueMap<>(); |
||||
paramsMap.add("searchVal", "test"); |
||||
paramsMap.add("pageSize", "2"); |
||||
paramsMap.add("pageNo", "2"); |
||||
|
||||
MvcResult mvcResult = mockMvc.perform(get("/cluster/list-paging") |
||||
.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); |
||||
logger.info(result.toString()); |
||||
Assert.assertTrue(result != null && result.isSuccess()); |
||||
logger.info("query list-paging cluster return result:{}", mvcResult.getResponse().getContentAsString()); |
||||
} |
||||
|
||||
@Test |
||||
public void testQueryAllClusterList() throws Exception { |
||||
MultiValueMap<String, String> paramsMap = new LinkedMultiValueMap<>(); |
||||
|
||||
MvcResult mvcResult = mockMvc.perform(get("/cluster/query-cluster-list") |
||||
.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); |
||||
logger.info(result.toString()); |
||||
Assert.assertTrue(result != null && result.isSuccess()); |
||||
logger.info("query all cluster return result:{}", mvcResult.getResponse().getContentAsString()); |
||||
|
||||
} |
||||
|
||||
@Test |
||||
public void testVerifyCluster() throws Exception { |
||||
MultiValueMap<String, String> paramsMap = new LinkedMultiValueMap<>(); |
||||
paramsMap.add("clusterName", clusterName); |
||||
|
||||
MvcResult mvcResult = mockMvc.perform(post("/cluster/verify-cluster") |
||||
.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); |
||||
logger.info(result.toString()); |
||||
Assert.assertTrue(result.isStatus(Status.CLUSTER_NAME_EXISTS)); |
||||
logger.info("verify cluster return result:{}", mvcResult.getResponse().getContentAsString()); |
||||
|
||||
} |
||||
|
||||
private void testDeleteCluster() throws Exception { |
||||
Preconditions.checkNotNull(clusterCode); |
||||
|
||||
MultiValueMap<String, String> paramsMap = new LinkedMultiValueMap<>(); |
||||
paramsMap.add("clusterCode", clusterCode); |
||||
|
||||
MvcResult mvcResult = mockMvc.perform(post("/cluster/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); |
||||
logger.info(result.toString()); |
||||
Assert.assertTrue(result != null && result.isSuccess()); |
||||
logger.info("delete cluster return result:{}", mvcResult.getResponse().getContentAsString()); |
||||
} |
||||
} |
@ -0,0 +1,290 @@
|
||||
/* |
||||
* 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.k8s.K8sManager; |
||||
import org.apache.dolphinscheduler.api.service.impl.ClusterServiceImpl; |
||||
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.Cluster; |
||||
import org.apache.dolphinscheduler.dao.entity.User; |
||||
import org.apache.dolphinscheduler.dao.mapper.ClusterMapper; |
||||
import org.apache.dolphinscheduler.dao.mapper.K8sNamespaceMapper; |
||||
import org.apache.dolphinscheduler.remote.exceptions.RemotingException; |
||||
|
||||
import org.apache.commons.collections.CollectionUtils; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
import org.assertj.core.util.Lists; |
||||
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 org.springframework.boot.configurationprocessor.json.JSONException; |
||||
import org.springframework.boot.configurationprocessor.json.JSONObject; |
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
||||
import com.baomidou.mybatisplus.core.metadata.IPage; |
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
||||
|
||||
/** |
||||
* cluster service test |
||||
*/ |
||||
@RunWith(MockitoJUnitRunner.class) |
||||
public class ClusterServiceTest { |
||||
|
||||
public static final Logger logger = LoggerFactory.getLogger(ClusterServiceTest.class); |
||||
|
||||
@InjectMocks |
||||
private ClusterServiceImpl clusterService; |
||||
|
||||
@Mock |
||||
private ClusterMapper clusterMapper; |
||||
|
||||
@Mock |
||||
private K8sNamespaceMapper k8sNamespaceMapper; |
||||
|
||||
@Mock |
||||
private K8sManager k8sManager; |
||||
|
||||
|
||||
public static final String testUserName = "clusterServerTest"; |
||||
|
||||
public static final String clusterName = "Env1"; |
||||
|
||||
@Before |
||||
public void setUp(){ |
||||
} |
||||
|
||||
@After |
||||
public void after(){ |
||||
} |
||||
|
||||
@Test |
||||
public void testCreateCluster() { |
||||
User loginUser = getGeneralUser(); |
||||
Map<String, Object> result = clusterService.createCluster(loginUser,clusterName,getConfig(),getDesc()); |
||||
logger.info(result.toString()); |
||||
Assert.assertEquals(Status.USER_NO_OPERATION_PERM, result.get(Constants.STATUS)); |
||||
|
||||
loginUser = getAdminUser(); |
||||
result = clusterService.createCluster(loginUser,clusterName,"",getDesc()); |
||||
logger.info(result.toString()); |
||||
Assert.assertEquals(Status.CLUSTER_CONFIG_IS_NULL, result.get(Constants.STATUS)); |
||||
|
||||
result = clusterService.createCluster(loginUser,"",getConfig(),getDesc()); |
||||
logger.info(result.toString()); |
||||
Assert.assertEquals(Status.CLUSTER_NAME_IS_NULL, result.get(Constants.STATUS)); |
||||
|
||||
Mockito.when(clusterMapper.queryByClusterName(clusterName)).thenReturn(getCluster()); |
||||
result = clusterService.createCluster(loginUser,clusterName,getConfig(),getDesc()); |
||||
logger.info(result.toString()); |
||||
Assert.assertEquals(Status.CLUSTER_NAME_EXISTS, result.get(Constants.STATUS)); |
||||
|
||||
Mockito.when(clusterMapper.insert(Mockito.any(Cluster.class))).thenReturn(1); |
||||
result = clusterService.createCluster(loginUser,"testName","testConfig","testDesc"); |
||||
logger.info(result.toString()); |
||||
Assert.assertEquals(Status.SUCCESS, result.get(Constants.STATUS)); |
||||
} |
||||
|
||||
@Test |
||||
public void testCheckParams() { |
||||
Map<String, Object> result = clusterService.checkParams(clusterName,getConfig()); |
||||
Assert.assertEquals(Status.SUCCESS, result.get(Constants.STATUS)); |
||||
result = clusterService.checkParams("",getConfig()); |
||||
Assert.assertEquals(Status.CLUSTER_NAME_IS_NULL, result.get(Constants.STATUS)); |
||||
result = clusterService.checkParams(clusterName,""); |
||||
Assert.assertEquals(Status.CLUSTER_CONFIG_IS_NULL, result.get(Constants.STATUS)); |
||||
} |
||||
|
||||
@Test |
||||
public void testUpdateClusterByCode() throws RemotingException { |
||||
User loginUser = getGeneralUser(); |
||||
Map<String, Object> result = clusterService.updateClusterByCode(loginUser,1L,clusterName,getConfig(),getDesc()); |
||||
logger.info(result.toString()); |
||||
Assert.assertEquals(Status.USER_NO_OPERATION_PERM, result.get(Constants.STATUS)); |
||||
|
||||
loginUser = getAdminUser(); |
||||
result = clusterService.updateClusterByCode(loginUser,1L,clusterName,"",getDesc()); |
||||
logger.info(result.toString()); |
||||
Assert.assertEquals(Status.CLUSTER_CONFIG_IS_NULL, result.get(Constants.STATUS)); |
||||
|
||||
result = clusterService.updateClusterByCode(loginUser,1L,"",getConfig(),getDesc()); |
||||
logger.info(result.toString()); |
||||
Assert.assertEquals(Status.CLUSTER_NAME_IS_NULL, result.get(Constants.STATUS)); |
||||
|
||||
result = clusterService.updateClusterByCode(loginUser,2L,clusterName,getConfig(),getDesc()); |
||||
logger.info(result.toString()); |
||||
Assert.assertEquals(Status.CLUSTER_NOT_EXISTS, result.get(Constants.STATUS)); |
||||
|
||||
Mockito.when(clusterMapper.queryByClusterName(clusterName)).thenReturn(getCluster()); |
||||
result = clusterService.updateClusterByCode(loginUser,2L,clusterName,getConfig(),getDesc()); |
||||
logger.info(result.toString()); |
||||
Assert.assertEquals(Status.CLUSTER_NAME_EXISTS, result.get(Constants.STATUS)); |
||||
|
||||
Mockito.when(clusterMapper.updateById(Mockito.any(Cluster.class))).thenReturn(1); |
||||
Mockito.when(clusterMapper.queryByClusterCode(1L)).thenReturn(getCluster()); |
||||
|
||||
result = clusterService.updateClusterByCode(loginUser,1L,"testName",getConfig(),"test"); |
||||
logger.info(result.toString()); |
||||
Assert.assertEquals(Status.SUCCESS, result.get(Constants.STATUS)); |
||||
|
||||
} |
||||
|
||||
@Test |
||||
public void testQueryAllClusterList() { |
||||
Mockito.when(clusterMapper.queryAllClusterList()).thenReturn(Lists.newArrayList(getCluster())); |
||||
Map<String, Object> result = clusterService.queryAllClusterList(); |
||||
logger.info(result.toString()); |
||||
Assert.assertEquals(Status.SUCCESS,result.get(Constants.STATUS)); |
||||
|
||||
List<Cluster> list = (List<Cluster>)(result.get(Constants.DATA_LIST)); |
||||
Assert.assertEquals(1,list.size()); |
||||
} |
||||
|
||||
@Test |
||||
public void testQueryClusterListPaging() { |
||||
IPage<Cluster> page = new Page<>(1, 10); |
||||
page.setRecords(getList()); |
||||
page.setTotal(1L); |
||||
Mockito.when(clusterMapper.queryClusterListPaging(Mockito.any(Page.class), Mockito.eq(clusterName))).thenReturn(page); |
||||
|
||||
Result result = clusterService.queryClusterListPaging(1, 10, clusterName); |
||||
logger.info(result.toString()); |
||||
PageInfo<Cluster> pageInfo = (PageInfo<Cluster>) result.getData(); |
||||
Assert.assertTrue(CollectionUtils.isNotEmpty(pageInfo.getTotalList())); |
||||
} |
||||
|
||||
@Test |
||||
public void testQueryClusterByName() { |
||||
Mockito.when(clusterMapper.queryByClusterName(clusterName)).thenReturn(null); |
||||
Map<String, Object> result = clusterService.queryClusterByName(clusterName); |
||||
logger.info(result.toString()); |
||||
Assert.assertEquals(Status.QUERY_CLUSTER_BY_NAME_ERROR,result.get(Constants.STATUS)); |
||||
|
||||
Mockito.when(clusterMapper.queryByClusterName(clusterName)).thenReturn(getCluster()); |
||||
result = clusterService.queryClusterByName(clusterName); |
||||
logger.info(result.toString()); |
||||
Assert.assertEquals(Status.SUCCESS,result.get(Constants.STATUS)); |
||||
} |
||||
|
||||
@Test |
||||
public void testQueryClusterByCode() { |
||||
Mockito.when(clusterMapper.queryByClusterCode(1L)).thenReturn(null); |
||||
Map<String, Object> result = clusterService.queryClusterByCode(1L); |
||||
logger.info(result.toString()); |
||||
Assert.assertEquals(Status.QUERY_CLUSTER_BY_CODE_ERROR,result.get(Constants.STATUS)); |
||||
|
||||
Mockito.when(clusterMapper.queryByClusterCode(1L)).thenReturn(getCluster()); |
||||
result = clusterService.queryClusterByCode(1L); |
||||
logger.info(result.toString()); |
||||
Assert.assertEquals(Status.SUCCESS,result.get(Constants.STATUS)); |
||||
} |
||||
|
||||
@Test |
||||
public void testDeleteClusterByCode() { |
||||
User loginUser = getGeneralUser(); |
||||
Map<String, Object> result = clusterService.deleteClusterByCode(loginUser,1L); |
||||
logger.info(result.toString()); |
||||
Assert.assertEquals(Status.USER_NO_OPERATION_PERM, result.get(Constants.STATUS)); |
||||
|
||||
loginUser = getAdminUser(); |
||||
Mockito.when(clusterMapper.deleteByCode(1L)).thenReturn(1); |
||||
result = clusterService.deleteClusterByCode(loginUser,1L); |
||||
logger.info(result.toString()); |
||||
Assert.assertEquals(Status.SUCCESS, result.get(Constants.STATUS)); |
||||
} |
||||
|
||||
@Test |
||||
public void testVerifyCluster() { |
||||
Map<String, Object> result = clusterService.verifyCluster(""); |
||||
logger.info(result.toString()); |
||||
Assert.assertEquals(Status.CLUSTER_NAME_IS_NULL, result.get(Constants.STATUS)); |
||||
|
||||
Mockito.when(clusterMapper.queryByClusterName(clusterName)).thenReturn(getCluster()); |
||||
result = clusterService.verifyCluster(clusterName); |
||||
logger.info(result.toString()); |
||||
Assert.assertEquals(Status.CLUSTER_NAME_EXISTS, result.get(Constants.STATUS)); |
||||
} |
||||
|
||||
private Cluster getCluster() { |
||||
Cluster cluster = new Cluster(); |
||||
cluster.setId(1); |
||||
cluster.setCode(1L); |
||||
cluster.setName(clusterName); |
||||
cluster.setConfig(getConfig()); |
||||
cluster.setDescription(getDesc()); |
||||
cluster.setOperator(1); |
||||
return cluster; |
||||
} |
||||
|
||||
/** |
||||
* create an cluster description |
||||
*/ |
||||
private String getDesc() { |
||||
return "create an cluster to test "; |
||||
} |
||||
|
||||
/** |
||||
* create an cluster config |
||||
*/ |
||||
private String getConfig() { |
||||
return "{\"k8s\":\"apiVersion: v1\\nclusters:\\n- cluster:\\n certificate-authority-data: LS0tLS1CRUdJTiBDRJUSUZJQ0FURS0tLS0tCg==\\n server: https:\\/\\/127.0.0.1:6443\\n name: kubernetes\\ncontexts:\\n- context:\\n cluster: kubernetes\\n user: kubernetes-admin\\n name: kubernetes-admin@kubernetes\\ncurrent-context: kubernetes-admin@kubernetes\\nkind: Config\\npreferences: {}\\nusers:\\n- name: kubernetes-admin\\n user:\\n client-certificate-data: LS0tLS1CRUdJTiBDRVJJ0cEhYYnBLRVktLS0tLQo=\"}\n"; |
||||
} |
||||
|
||||
/** |
||||
* create general user |
||||
*/ |
||||
private User getGeneralUser() { |
||||
User loginUser = new User(); |
||||
loginUser.setUserType(UserType.GENERAL_USER); |
||||
loginUser.setUserName(testUserName); |
||||
loginUser.setId(1); |
||||
return loginUser; |
||||
} |
||||
|
||||
/** |
||||
* create admin user |
||||
*/ |
||||
private User getAdminUser() { |
||||
User loginUser = new User(); |
||||
loginUser.setUserType(UserType.ADMIN_USER); |
||||
loginUser.setUserName(testUserName); |
||||
loginUser.setId(1); |
||||
return loginUser; |
||||
} |
||||
|
||||
private List<Cluster> getList() { |
||||
List<Cluster> list = new ArrayList<>(); |
||||
list.add(getCluster()); |
||||
return list; |
||||
} |
||||
} |
@ -0,0 +1,48 @@
|
||||
/* |
||||
* 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.common.utils; |
||||
|
||||
import org.apache.dolphinscheduler.spi.utils.StringUtils; |
||||
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode; |
||||
|
||||
/** |
||||
* cluster conf will include all env type, but only k8s config now |
||||
*/ |
||||
public class ClusterConfUtils { |
||||
|
||||
private static final String K8S_CONFIG = "k8s"; |
||||
|
||||
/** |
||||
* get k8s |
||||
* |
||||
* @param config cluster config in db |
||||
* @return |
||||
*/ |
||||
public static String getK8sConfig(String config) { |
||||
if (StringUtils.isEmpty(config)) { |
||||
return null; |
||||
} |
||||
ObjectNode conf = JSONUtils.parseObject(config); |
||||
if (conf == null) { |
||||
return null; |
||||
} |
||||
return conf.get(K8S_CONFIG).asText(); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,139 @@
|
||||
/* |
||||
* 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.TableId; |
||||
import com.baomidou.mybatisplus.annotation.TableName; |
||||
|
||||
/** |
||||
* Cluster |
||||
*/ |
||||
@TableName("t_ds_cluster") |
||||
public class Cluster { |
||||
|
||||
@TableId(value = "id", type = IdType.AUTO) |
||||
private int id; |
||||
|
||||
/** |
||||
* cluster code |
||||
*/ |
||||
private Long code; |
||||
|
||||
/** |
||||
* cluster name |
||||
*/ |
||||
private String name; |
||||
|
||||
/** |
||||
* config content |
||||
*/ |
||||
private String config; |
||||
|
||||
private String description; |
||||
|
||||
/** |
||||
* operator user id |
||||
*/ |
||||
private Integer operator; |
||||
|
||||
private Date createTime; |
||||
|
||||
private Date updateTime; |
||||
|
||||
public int getId() { |
||||
return id; |
||||
} |
||||
|
||||
public void setId(int id) { |
||||
this.id = id; |
||||
} |
||||
|
||||
public String getName() { |
||||
return name; |
||||
} |
||||
|
||||
public void setName(String name) { |
||||
this.name = name; |
||||
} |
||||
|
||||
public Long getCode() { |
||||
return this.code; |
||||
} |
||||
|
||||
public void setCode(Long code) { |
||||
this.code = code; |
||||
} |
||||
|
||||
public String getConfig() { |
||||
return this.config; |
||||
} |
||||
|
||||
public void setConfig(String config) { |
||||
this.config = config; |
||||
} |
||||
|
||||
public String getDescription() { |
||||
return this.description; |
||||
} |
||||
|
||||
public void setDescription(String description) { |
||||
this.description = description; |
||||
} |
||||
|
||||
public Integer getOperator() { |
||||
return this.operator; |
||||
} |
||||
|
||||
public void setOperator(Integer operator) { |
||||
this.operator = operator; |
||||
} |
||||
|
||||
public Date getCreateTime() { |
||||
return createTime; |
||||
} |
||||
|
||||
public void setCreateTime(Date createTime) { |
||||
this.createTime = createTime; |
||||
} |
||||
|
||||
public Date getUpdateTime() { |
||||
return updateTime; |
||||
} |
||||
|
||||
public void setUpdateTime(Date updateTime) { |
||||
this.updateTime = updateTime; |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return "Cluster{" |
||||
+ "id= " + id |
||||
+ ", code= " + code |
||||
+ ", name= " + name |
||||
+ ", config= " + config |
||||
+ ", description= " + description |
||||
+ ", operator= " + operator |
||||
+ ", createTime= " + createTime |
||||
+ ", updateTime= " + updateTime |
||||
+ "}"; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,71 @@
|
||||
/* |
||||
* 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.Cluster; |
||||
|
||||
import org.apache.ibatis.annotations.Param; |
||||
|
||||
import java.util.List; |
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
||||
import com.baomidou.mybatisplus.core.metadata.IPage; |
||||
|
||||
/** |
||||
* cluster mapper interface
|
||||
*/ |
||||
public interface ClusterMapper extends BaseMapper<Cluster> { |
||||
|
||||
/** |
||||
* query cluster by name |
||||
* |
||||
* @param name name |
||||
* @return cluster |
||||
*/ |
||||
Cluster queryByClusterName(@Param("clusterName") String name); |
||||
|
||||
/** |
||||
* query cluster by code |
||||
* |
||||
* @param clusterCode clusterCode |
||||
* @return cluster |
||||
*/ |
||||
Cluster queryByClusterCode(@Param("clusterCode") Long clusterCode); |
||||
|
||||
/** |
||||
* query all cluster list |
||||
* @return cluster list |
||||
*/ |
||||
List<Cluster> queryAllClusterList(); |
||||
|
||||
/** |
||||
* cluster page |
||||
* @param page page |
||||
* @param searchName searchName |
||||
* @return cluster IPage |
||||
*/ |
||||
IPage<Cluster> queryClusterListPaging(IPage<Cluster> page, @Param("searchName") String searchName); |
||||
|
||||
/** |
||||
* delete cluster by code |
||||
* |
||||
* @param code code |
||||
* @return int |
||||
*/ |
||||
int deleteByCode(@Param("code") Long code); |
||||
} |
@ -0,0 +1,55 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?> |
||||
<!-- |
||||
~ Licensed to the Apache Software Foundation (ASF) under one or more |
||||
~ contributor license agreements. See the NOTICE file distributed with |
||||
~ this work for additional information regarding copyright ownership. |
||||
~ The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
~ (the "License"); you may not use this file except in compliance with |
||||
~ the License. You may obtain a copy of the License at |
||||
~ |
||||
~ http://www.apache.org/licenses/LICENSE-2.0 |
||||
~ |
||||
~ Unless required by applicable law or agreed to in writing, software |
||||
~ distributed under the License is distributed on an "AS IS" BASIS, |
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
~ See the License for the specific language governing permissions and |
||||
~ limitations under the License. |
||||
--> |
||||
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > |
||||
<mapper namespace="org.apache.dolphinscheduler.dao.mapper.ClusterMapper"> |
||||
<sql id="baseSql"> |
||||
id, code, name, config, description, operator, create_time, update_time |
||||
</sql> |
||||
<select id="queryByClusterName" resultType="org.apache.dolphinscheduler.dao.entity.Cluster"> |
||||
select |
||||
<include refid="baseSql"/> |
||||
from t_ds_cluster |
||||
WHERE name = #{clusterName} |
||||
</select> |
||||
<select id="queryAllClusterList" resultType="org.apache.dolphinscheduler.dao.entity.Cluster"> |
||||
select |
||||
<include refid="baseSql"/> |
||||
from t_ds_cluster |
||||
order by create_time desc |
||||
</select> |
||||
<select id="queryClusterListPaging" resultType="org.apache.dolphinscheduler.dao.entity.Cluster"> |
||||
select |
||||
<include refid="baseSql"/> |
||||
from t_ds_cluster |
||||
where 1=1 |
||||
<if test="searchName!=null and searchName != ''"> |
||||
and name like concat('%', #{searchName}, '%') |
||||
</if> |
||||
order by create_time desc |
||||
</select> |
||||
<select id="queryByClusterCode" resultType="org.apache.dolphinscheduler.dao.entity.Cluster"> |
||||
select |
||||
<include refid="baseSql"/> |
||||
from t_ds_cluster |
||||
where code = #{clusterCode} |
||||
</select> |
||||
<delete id="deleteByCode"> |
||||
delete from t_ds_cluster where code = #{code} |
||||
</delete> |
||||
</mapper> |
@ -0,0 +1,191 @@
|
||||
/* |
||||
* 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.BaseDaoTest; |
||||
import org.apache.dolphinscheduler.dao.entity.Cluster; |
||||
|
||||
import java.util.Date; |
||||
import java.util.List; |
||||
|
||||
import org.junit.After; |
||||
import org.junit.Assert; |
||||
import org.junit.Before; |
||||
import org.junit.Test; |
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage; |
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
||||
|
||||
public class ClusterMapperTest extends BaseDaoTest { |
||||
|
||||
@Autowired |
||||
ClusterMapper clusterMapper; |
||||
|
||||
/** |
||||
* insert |
||||
* |
||||
* @return Cluster |
||||
*/ |
||||
private Cluster insertOne() { |
||||
//insertOne
|
||||
Cluster cluster = new Cluster(); |
||||
cluster.setName("testCluster"); |
||||
cluster.setCode(1L); |
||||
cluster.setOperator(1); |
||||
cluster.setConfig(getConfig()); |
||||
cluster.setDescription(getDesc()); |
||||
cluster.setCreateTime(new Date()); |
||||
cluster.setUpdateTime(new Date()); |
||||
clusterMapper.insert(cluster); |
||||
return cluster; |
||||
} |
||||
|
||||
@Before |
||||
public void setUp() { |
||||
clearTestData(); |
||||
} |
||||
|
||||
@After |
||||
public void after() { |
||||
clearTestData(); |
||||
} |
||||
|
||||
public void clearTestData() { |
||||
clusterMapper.queryAllClusterList().stream().forEach(cluster -> { |
||||
clusterMapper.deleteByCode(cluster.getCode()); |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* test update |
||||
*/ |
||||
@Test |
||||
public void testUpdate() { |
||||
//insertOne
|
||||
Cluster cluster = insertOne(); |
||||
cluster.setDescription("new description info"); |
||||
//update
|
||||
int update = clusterMapper.updateById(cluster); |
||||
Assert.assertEquals(update, 1); |
||||
} |
||||
|
||||
/** |
||||
* test delete |
||||
*/ |
||||
@Test |
||||
public void testDelete() { |
||||
Cluster cluster = insertOne(); |
||||
int delete = clusterMapper.deleteById(cluster.getId()); |
||||
Assert.assertEquals(delete, 1); |
||||
} |
||||
|
||||
/** |
||||
* test query |
||||
*/ |
||||
@Test |
||||
public void testQuery() { |
||||
insertOne(); |
||||
//query
|
||||
List<Cluster> clusters = clusterMapper.selectList(null); |
||||
Assert.assertEquals(clusters.size(), 1); |
||||
} |
||||
|
||||
/** |
||||
* test query cluster by name |
||||
*/ |
||||
@Test |
||||
public void testQueryByClusterName() { |
||||
Cluster entity = insertOne(); |
||||
Cluster cluster = clusterMapper.queryByClusterName(entity.getName()); |
||||
Assert.assertEquals(entity.toString(),cluster.toString()); |
||||
} |
||||
|
||||
/** |
||||
* test query cluster by code |
||||
*/ |
||||
@Test |
||||
public void testQueryByClusterCode() { |
||||
Cluster entity = insertOne(); |
||||
Cluster cluster = clusterMapper.queryByClusterCode(entity.getCode()); |
||||
Assert.assertEquals(entity.toString(),cluster.toString()); |
||||
} |
||||
|
||||
/** |
||||
* test query all clusters |
||||
*/ |
||||
@Test |
||||
public void testQueryAllClusterList() { |
||||
Cluster entity = insertOne(); |
||||
List<Cluster> clusters = clusterMapper.queryAllClusterList(); |
||||
Assert.assertEquals(clusters.size(), 1); |
||||
Assert.assertEquals(entity.toString(),clusters.get(0).toString()); |
||||
} |
||||
|
||||
/** |
||||
* test query cluster list paging |
||||
*/ |
||||
@Test |
||||
public void testQueryClusterListPaging() { |
||||
Cluster entity = insertOne(); |
||||
Page<Cluster> page = new Page<>(1, 10); |
||||
IPage<Cluster> clusterIPage = clusterMapper.queryClusterListPaging(page,""); |
||||
List<Cluster> clusterList = clusterIPage.getRecords(); |
||||
Assert.assertEquals(clusterList.size(), 1); |
||||
|
||||
clusterIPage = clusterMapper.queryClusterListPaging(page,"abc"); |
||||
clusterList = clusterIPage.getRecords(); |
||||
Assert.assertEquals(clusterList.size(), 0); |
||||
} |
||||
|
||||
/** |
||||
* test query all clusters |
||||
*/ |
||||
@Test |
||||
public void testDeleteByCode() { |
||||
Cluster entity = insertOne(); |
||||
int delete = clusterMapper.deleteByCode(entity.getCode()); |
||||
Assert.assertEquals(delete, 1); |
||||
} |
||||
|
||||
private String getDesc() { |
||||
return "create an cluster to test "; |
||||
} |
||||
|
||||
/** |
||||
* create an cluster config |
||||
*/ |
||||
private String getConfig() { |
||||
return "export HADOOP_HOME=/opt/hadoop-2.6.5\n" |
||||
+ "export HADOOP_CONF_DIR=/etc/hadoop/conf\n" |
||||
+ "export SPARK_HOME1=/opt/soft/spark1\n" |
||||
+ "export SPARK_HOME2=/opt/soft/spark2\n" |
||||
+ "export PYTHON_HOME=/opt/soft/python\n" |
||||
+ "export JAVA_HOME=/opt/java/jdk1.8.0_181-amd64\n" |
||||
+ "export HIVE_HOME=/opt/soft/hive\n" |
||||
+ "export FLINK_HOME=/opt/soft/flink\n" |
||||
+ "export DATAX_HOME=/opt/soft/datax\n" |
||||
+ "export YARN_CONF_DIR=\"/etc/hadoop/conf\"\n" |
||||
+ "\n" |
||||
+ "export PATH=$HADOOP_HOME/bin:$SPARK_HOME1/bin:$SPARK_HOME2/bin:$PYTHON_HOME/bin:$JAVA_HOME/bin:$HIVE_HOME/bin:$FLINK_HOME/bin:$DATAX_HOME/bin:$PATH\n" |
||||
+ "\n" |
||||
+ "export HADOOP_CLASSPATH=`hadoop classpath`\n" |
||||
+ "\n" |
||||
+ "#echo \"HADOOP_CLASSPATH=\"$HADOOP_CLASSPATH"; |
||||
} |
||||
} |
@ -0,0 +1,123 @@
|
||||
/* |
||||
* 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.cases; |
||||
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.awaitility.Awaitility.await; |
||||
|
||||
import org.apache.dolphinscheduler.e2e.core.DolphinScheduler; |
||||
import org.apache.dolphinscheduler.e2e.pages.LoginPage; |
||||
import org.apache.dolphinscheduler.e2e.pages.security.ClusterPage; |
||||
import org.apache.dolphinscheduler.e2e.pages.security.SecurityPage; |
||||
|
||||
import org.junit.jupiter.api.BeforeAll; |
||||
import org.junit.jupiter.api.Order; |
||||
import org.junit.jupiter.api.Test; |
||||
import org.openqa.selenium.By; |
||||
import org.openqa.selenium.WebElement; |
||||
import org.openqa.selenium.remote.RemoteWebDriver; |
||||
|
||||
@DolphinScheduler(composeFiles = "docker/basic/docker-compose.yaml") |
||||
class ClusterE2ETest { |
||||
|
||||
private static final String clusterName = "test_cluster_name"; |
||||
private static final String clusterConfig = "test_cluster_config"; |
||||
private static final String clusterDesc = "test_cluster_desc"; |
||||
|
||||
private static final String editClusterName = "edit_cluster_name"; |
||||
private static final String editClusterConfig = "edit_cluster_config"; |
||||
private static final String editClusterDesc = "edit_cluster_desc"; |
||||
|
||||
private static RemoteWebDriver browser; |
||||
|
||||
@BeforeAll |
||||
public static void setup() { |
||||
new LoginPage(browser) |
||||
.login("admin", "dolphinscheduler123") |
||||
.goToNav(SecurityPage.class) |
||||
.goToTab(ClusterPage.class) |
||||
; |
||||
} |
||||
|
||||
@Test |
||||
@Order(10) |
||||
void testCreateCluster() { |
||||
final ClusterPage page = new ClusterPage(browser); |
||||
page.create(clusterName, clusterConfig, clusterDesc); |
||||
|
||||
await().untilAsserted(() -> { |
||||
browser.navigate().refresh(); |
||||
assertThat(page.clusterList()) |
||||
.as("Cluster list should contain newly-created cluster") |
||||
.extracting(WebElement::getText) |
||||
.anyMatch(it -> it.contains(clusterName)); |
||||
}); |
||||
} |
||||
|
||||
@Test |
||||
@Order(20) |
||||
void testCreateDuplicateCluster() { |
||||
final ClusterPage page = new ClusterPage(browser); |
||||
page.create(clusterName, clusterConfig, clusterDesc); |
||||
|
||||
await().untilAsserted(() -> |
||||
assertThat(browser.findElement(By.tagName("body")).getText()) |
||||
.contains("already exists") |
||||
); |
||||
|
||||
page.createClusterForm().buttonCancel().click(); |
||||
} |
||||
|
||||
@Test |
||||
@Order(30) |
||||
void testEditCluster() { |
||||
final ClusterPage page = new ClusterPage(browser); |
||||
page.update(clusterName, editClusterName, editClusterConfig, editClusterDesc); |
||||
|
||||
await().untilAsserted(() -> { |
||||
browser.navigate().refresh(); |
||||
assertThat(page.clusterList()) |
||||
.as("Cluster list should contain newly-modified cluster") |
||||
.extracting(WebElement::getText) |
||||
.anyMatch(it -> it.contains(editClusterName)); |
||||
}); |
||||
} |
||||
|
||||
@Test |
||||
@Order(40) |
||||
void testDeleteCluster() { |
||||
final ClusterPage page = new ClusterPage(browser); |
||||
|
||||
page.delete(editClusterName); |
||||
|
||||
await().untilAsserted(() -> { |
||||
browser.navigate().refresh(); |
||||
|
||||
assertThat( |
||||
page.clusterList() |
||||
) |
||||
.as("Cluster list should not contain deleted cluster") |
||||
.noneMatch( |
||||
it -> it.getText().contains(clusterName) || it.getText().contains(editClusterName) |
||||
); |
||||
}); |
||||
} |
||||
} |
@ -0,0 +1,151 @@
|
||||
/* |
||||
* 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.JavascriptExecutor; |
||||
import org.openqa.selenium.Keys; |
||||
import org.openqa.selenium.WebElement; |
||||
import org.openqa.selenium.remote.RemoteWebDriver; |
||||
import org.openqa.selenium.support.FindBy; |
||||
import org.openqa.selenium.support.FindBys; |
||||
import org.openqa.selenium.support.PageFactory; |
||||
import org.openqa.selenium.support.ui.ExpectedConditions; |
||||
import org.openqa.selenium.support.ui.WebDriverWait; |
||||
|
||||
import lombok.Getter; |
||||
|
||||
@Getter |
||||
public final class ClusterPage extends NavBarPage implements SecurityPage.Tab { |
||||
@FindBy(className = "btn-create-cluster") |
||||
private WebElement buttonCreateCluster; |
||||
|
||||
@FindBy(className = "items") |
||||
private List<WebElement> clusterList; |
||||
|
||||
@FindBys({ |
||||
@FindBy(className = "n-popconfirm__action"), |
||||
@FindBy(className = "n-button--primary-type"), |
||||
}) |
||||
private WebElement buttonConfirm; |
||||
|
||||
private final ClusterForm createClusterForm; |
||||
private final ClusterForm editClusterForm; |
||||
|
||||
public ClusterPage(RemoteWebDriver driver) { |
||||
super(driver); |
||||
createClusterForm = new ClusterForm(); |
||||
editClusterForm = new ClusterForm(); |
||||
} |
||||
|
||||
public ClusterPage create(String name, String config, String desc) { |
||||
buttonCreateCluster().click(); |
||||
createClusterForm().inputClusterName().sendKeys(name); |
||||
createClusterForm().inputClusterConfig().sendKeys(config); |
||||
createClusterForm().inputClusterDesc().sendKeys(desc); |
||||
|
||||
createClusterForm().buttonSubmit().click(); |
||||
return this; |
||||
} |
||||
|
||||
public ClusterPage update(String oldName, String name, String config, String desc) { |
||||
clusterList() |
||||
.stream() |
||||
.filter(it -> it.findElement(By.className("cluster-name")).getAttribute("innerHTML").contains(oldName)) |
||||
.flatMap(it -> it.findElements(By.className("edit")).stream()) |
||||
.filter(WebElement::isDisplayed) |
||||
.findFirst() |
||||
.orElseThrow(() -> new RuntimeException("No edit button in cluster list")) |
||||
.click(); |
||||
|
||||
|
||||
editClusterForm().inputClusterName().sendKeys(Keys.CONTROL + "a"); |
||||
editClusterForm().inputClusterName().sendKeys(Keys.BACK_SPACE); |
||||
editClusterForm().inputClusterName().sendKeys(name); |
||||
|
||||
editClusterForm().inputClusterConfig().sendKeys(Keys.CONTROL + "a"); |
||||
editClusterForm().inputClusterConfig().sendKeys(Keys.BACK_SPACE); |
||||
editClusterForm().inputClusterConfig().sendKeys(config); |
||||
|
||||
editClusterForm().inputClusterDesc().sendKeys(Keys.CONTROL + "a"); |
||||
editClusterForm().inputClusterDesc().sendKeys(Keys.BACK_SPACE); |
||||
editClusterForm().inputClusterDesc().sendKeys(desc); |
||||
|
||||
editClusterForm().buttonSubmit().click(); |
||||
|
||||
return this; |
||||
} |
||||
|
||||
public ClusterPage delete(String name) { |
||||
clusterList() |
||||
.stream() |
||||
.filter(it -> it.getText().contains(name)) |
||||
.flatMap(it -> it.findElements(By.className("delete")).stream()) |
||||
.filter(WebElement::isDisplayed) |
||||
.findFirst() |
||||
.orElseThrow(() -> new RuntimeException("No delete button in cluster list")) |
||||
.click(); |
||||
|
||||
((JavascriptExecutor) driver).executeScript("arguments[0].click();", buttonConfirm()); |
||||
|
||||
return this; |
||||
} |
||||
|
||||
@Getter |
||||
public class ClusterForm { |
||||
ClusterForm() { |
||||
PageFactory.initElements(driver, this); |
||||
} |
||||
|
||||
@FindBys({ |
||||
@FindBy(className = "input-cluster-name"), |
||||
@FindBy(tagName = "input"), |
||||
}) |
||||
private WebElement inputClusterName; |
||||
|
||||
@FindBys({ |
||||
@FindBy(className = "input-cluster-config"), |
||||
@FindBy(tagName = "textarea"), |
||||
}) |
||||
private WebElement inputClusterConfig; |
||||
|
||||
@FindBys({ |
||||
@FindBy(className = "input-cluster-desc"), |
||||
@FindBy(tagName = "input"), |
||||
}) |
||||
private WebElement inputClusterDesc; |
||||
|
||||
@FindBys({ |
||||
@FindBy(className = "n-base-selection-tags"), |
||||
@FindBy(className = "n-tag__content"), |
||||
}) |
||||
private WebElement selectedWorkerGroup; |
||||
|
||||
@FindBy(className = "btn-submit") |
||||
private WebElement buttonSubmit; |
||||
|
||||
@FindBy(className = "btn-cancel") |
||||
private WebElement buttonCancel; |
||||
} |
||||
} |
@ -0,0 +1,80 @@
|
||||
/* |
||||
* 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. |
||||
*/ |
||||
|
||||
import { axios } from '@/service/service' |
||||
import { |
||||
ClusterReq, |
||||
ClusterCodeReq, |
||||
ClusterNameReq, |
||||
ListReq, |
||||
CodeReq |
||||
} from './types' |
||||
|
||||
export function createCluster(data: ClusterReq): any { |
||||
return axios({ |
||||
url: '/cluster/create', |
||||
method: 'post', |
||||
data |
||||
}) |
||||
} |
||||
|
||||
export function deleteClusterByCode(data: ClusterCodeReq): any { |
||||
return axios({ |
||||
url: '/cluster/delete', |
||||
method: 'post', |
||||
data |
||||
}) |
||||
} |
||||
|
||||
export function queryClusterListPaging(params: ListReq): any { |
||||
return axios({ |
||||
url: '/cluster/list-paging', |
||||
method: 'get', |
||||
params |
||||
}) |
||||
} |
||||
|
||||
export function queryClusterByCode(params: ClusterCodeReq): any { |
||||
return axios({ |
||||
url: '/cluster/query-by-code', |
||||
method: 'get', |
||||
params |
||||
}) |
||||
} |
||||
|
||||
export function queryAllClusterList(): any { |
||||
return axios({ |
||||
url: '/cluster/query-cluster-list', |
||||
method: 'get' |
||||
}) |
||||
} |
||||
|
||||
export function updateCluster(data: ClusterReq & CodeReq): any { |
||||
return axios({ |
||||
url: '/cluster/update', |
||||
method: 'post', |
||||
data |
||||
}) |
||||
} |
||||
|
||||
export function verifyCluster(data: ClusterNameReq): any { |
||||
return axios({ |
||||
url: '/cluster/verify-cluster', |
||||
method: 'post', |
||||
data |
||||
}) |
||||
} |
@ -0,0 +1,72 @@
|
||||
/* |
||||
* 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. |
||||
*/ |
||||
|
||||
interface ClusterReq { |
||||
config: string |
||||
name: string |
||||
description?: string |
||||
workerGroups?: string |
||||
} |
||||
|
||||
interface ClusterCodeReq { |
||||
clusterCode: number |
||||
} |
||||
|
||||
interface ClusterNameReq { |
||||
clusterName: string |
||||
} |
||||
|
||||
interface ListReq { |
||||
pageNo: number |
||||
pageSize: number |
||||
searchVal?: string |
||||
} |
||||
|
||||
interface CodeReq { |
||||
code: number |
||||
} |
||||
|
||||
interface ClusterItem { |
||||
id: number |
||||
code: any |
||||
name: string |
||||
config: string |
||||
description: string |
||||
workerGroups: string[] |
||||
operator: number |
||||
createTime: string |
||||
updateTime: string |
||||
} |
||||
|
||||
interface ClusterRes { |
||||
totalList: ClusterItem[] |
||||
total: number |
||||
totalPage: number |
||||
pageSize: number |
||||
currentPage: number |
||||
start: number |
||||
} |
||||
|
||||
export { |
||||
ClusterReq, |
||||
ClusterCodeReq, |
||||
ClusterNameReq, |
||||
ListReq, |
||||
CodeReq, |
||||
ClusterItem, |
||||
ClusterRes |
||||
} |
@ -0,0 +1,191 @@
|
||||
/* |
||||
* 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. |
||||
*/ |
||||
|
||||
import { defineComponent, PropType, toRefs, watch } from 'vue' |
||||
import Modal from '@/components/modal' |
||||
import { NForm, NFormItem, NInput } from 'naive-ui' |
||||
import { useModal } from './use-modal' |
||||
import { useI18n } from 'vue-i18n' |
||||
|
||||
const envK8sConfigPlaceholder = `apiVersion: v1
|
||||
clusters: |
||||
- cluster: |
||||
certificate-authority-data: LS0tLS1CZJQ0FURS0tLS0tCg== |
||||
server: https://127.0.0.1:6443
|
||||
name: kubernetes |
||||
contexts: |
||||
- context: |
||||
cluster: kubernetes |
||||
user: kubernetes-admin |
||||
name: kubernetes-admin@kubernetes |
||||
current-context: kubernetes-admin@kubernetes |
||||
kind: Config |
||||
preferences: {} |
||||
users: |
||||
- name: kubernetes-admin |
||||
user: |
||||
client-certificate-data: LS0tLS1CZJQ0FURS0tLS0tCg=
|
||||
` |
||||
|
||||
const envYarnConfigPlaceholder = 'In development...' |
||||
|
||||
const ClusterModal = defineComponent({ |
||||
name: 'ClusterModal', |
||||
props: { |
||||
showModalRef: { |
||||
type: Boolean as PropType<boolean>, |
||||
default: false |
||||
}, |
||||
statusRef: { |
||||
type: Number as PropType<number>, |
||||
default: 0 |
||||
}, |
||||
row: { |
||||
type: Object as PropType<any>, |
||||
default: {} |
||||
} |
||||
}, |
||||
emits: ['cancelModal', 'confirmModal'], |
||||
setup(props, ctx) { |
||||
const { variables, handleValidate } = useModal(props, ctx) |
||||
const { t } = useI18n() |
||||
|
||||
const cancelModal = () => { |
||||
if (props.statusRef === 0) { |
||||
variables.model.name = '' |
||||
variables.model.k8s_config = '' |
||||
variables.model.yarn_config = '' |
||||
variables.model.description = '' |
||||
} |
||||
ctx.emit('cancelModal', props.showModalRef) |
||||
} |
||||
|
||||
const confirmModal = () => { |
||||
handleValidate(props.statusRef) |
||||
} |
||||
|
||||
const setModal = (row: any) => { |
||||
variables.model.code = row.code |
||||
variables.model.name = row.name |
||||
if (row.config) { |
||||
const config = JSON.parse(row.config) |
||||
variables.model.k8s_config = config.k8s || '' |
||||
variables.model.yarn_config = config.yarn || '' |
||||
} else { |
||||
variables.model.k8s_config = '' |
||||
variables.model.yarn_config = '' |
||||
} |
||||
variables.model.description = row.description |
||||
} |
||||
|
||||
watch( |
||||
() => props.statusRef, |
||||
() => { |
||||
if (props.statusRef === 0) { |
||||
variables.model.name = '' |
||||
variables.model.k8s_config = '' |
||||
variables.model.yarn_config = '' |
||||
variables.model.description = '' |
||||
} else { |
||||
setModal(props.row) |
||||
} |
||||
} |
||||
) |
||||
|
||||
watch( |
||||
() => props.row, |
||||
() => { |
||||
setModal(props.row) |
||||
} |
||||
) |
||||
|
||||
return { t, ...toRefs(variables), cancelModal, confirmModal } |
||||
}, |
||||
render() { |
||||
const { t } = this |
||||
return ( |
||||
<div> |
||||
<Modal |
||||
title={ |
||||
this.statusRef === 0 |
||||
? t('security.cluster.create_cluster') |
||||
: t('security.cluster.edit_cluster') |
||||
} |
||||
show={this.showModalRef} |
||||
onCancel={this.cancelModal} |
||||
onConfirm={this.confirmModal} |
||||
confirmDisabled={!this.model.name || !this.model.description} |
||||
confirmClassName='btn-submit' |
||||
cancelClassName='btn-cancel' |
||||
confirmLoading={this.saving} |
||||
> |
||||
{{ |
||||
default: () => ( |
||||
<NForm model={this.model} rules={this.rules} ref='clusterFormRef'> |
||||
<NFormItem |
||||
label={t('security.cluster.cluster_name')} |
||||
path='name' |
||||
> |
||||
<NInput |
||||
class='input-cluster-name' |
||||
placeholder={t('security.cluster.cluster_name_tips')} |
||||
v-model={[this.model.name, 'value']} |
||||
/> |
||||
</NFormItem> |
||||
<NFormItem |
||||
label={t('security.cluster.kubernetes_config')} |
||||
path='k8s_config' |
||||
> |
||||
<NInput |
||||
class='input-cluster-config' |
||||
placeholder={envK8sConfigPlaceholder} |
||||
type='textarea' |
||||
autosize={{ minRows: 16 }} |
||||
v-model={[this.model.k8s_config, 'value']} |
||||
/> |
||||
</NFormItem> |
||||
<NFormItem |
||||
label={t('security.cluster.yarn_config')} |
||||
path='yarn_config' |
||||
> |
||||
<NInput |
||||
class='input-yarn-config' |
||||
placeholder={envYarnConfigPlaceholder} |
||||
disabled={true} |
||||
v-model={[this.model.yarn_config, 'value']} |
||||
/> |
||||
</NFormItem> |
||||
<NFormItem |
||||
label={t('security.cluster.cluster_desc')} |
||||
path='description' |
||||
> |
||||
<NInput |
||||
class='input-cluster-desc' |
||||
placeholder={t('security.cluster.cluster_description_tips')} |
||||
v-model={[this.model.description, 'value']} |
||||
/> |
||||
</NFormItem> |
||||
</NForm> |
||||
) |
||||
}} |
||||
</Modal> |
||||
</div> |
||||
) |
||||
} |
||||
}) |
||||
|
||||
export default ClusterModal |
@ -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. |
||||
*/ |
||||
|
||||
import { reactive, ref, SetupContext } from 'vue' |
||||
import { useI18n } from 'vue-i18n' |
||||
import { |
||||
verifyCluster, |
||||
createCluster, |
||||
updateCluster |
||||
} from '@/service/modules/cluster' |
||||
|
||||
export function useModal( |
||||
props: any, |
||||
ctx: SetupContext<('cancelModal' | 'confirmModal')[]> |
||||
) { |
||||
const { t } = useI18n() |
||||
|
||||
const variables = reactive({ |
||||
clusterFormRef: ref(), |
||||
model: { |
||||
code: ref<number>(-1), |
||||
name: ref(''), |
||||
k8s_config: ref(''), |
||||
yarn_config: ref(''), |
||||
description: ref('') |
||||
}, |
||||
saving: false, |
||||
rules: { |
||||
name: { |
||||
required: true, |
||||
trigger: ['input', 'blur'], |
||||
validator() { |
||||
if (variables.model.name === '') { |
||||
return new Error(t('security.cluster.cluster_name_tips')) |
||||
} |
||||
} |
||||
}, |
||||
description: { |
||||
required: true, |
||||
trigger: ['input', 'blur'], |
||||
validator() { |
||||
if (variables.model.description === '') { |
||||
return new Error(t('security.cluster.cluster_description_tips')) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
}) |
||||
|
||||
const handleValidate = async (statusRef: number) => { |
||||
await variables.clusterFormRef.validate() |
||||
|
||||
if (variables.saving) return |
||||
variables.saving = true |
||||
|
||||
try { |
||||
statusRef === 0 ? await submitClusterModal() : await updateClusterModal() |
||||
} finally { |
||||
variables.saving = false |
||||
} |
||||
} |
||||
|
||||
const submitClusterModal = () => { |
||||
verifyCluster({ clusterName: variables.model.name }).then(() => { |
||||
const data = { |
||||
name: variables.model.name, |
||||
config: JSON.stringify({ |
||||
k8s: variables.model.k8s_config, |
||||
yarn: variables.model.yarn_config |
||||
}), |
||||
description: variables.model.description |
||||
} |
||||
|
||||
createCluster(data).then(() => { |
||||
variables.model.name = '' |
||||
variables.model.k8s_config = '' |
||||
variables.model.yarn_config = '' |
||||
variables.model.description = '' |
||||
ctx.emit('confirmModal', props.showModalRef) |
||||
}) |
||||
}) |
||||
} |
||||
|
||||
const updateClusterModal = () => { |
||||
const data = { |
||||
code: variables.model.code, |
||||
name: variables.model.name, |
||||
config: JSON.stringify({ |
||||
k8s: variables.model.k8s_config, |
||||
yarn: variables.model.yarn_config |
||||
}), |
||||
description: variables.model.description |
||||
} |
||||
|
||||
updateCluster(data).then(() => { |
||||
ctx.emit('confirmModal', props.showModalRef) |
||||
}) |
||||
} |
||||
|
||||
return { |
||||
variables, |
||||
handleValidate |
||||
} |
||||
} |
@ -0,0 +1,170 @@
|
||||
/* |
||||
* 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. |
||||
*/ |
||||
|
||||
import { defineComponent, onMounted, toRefs, watch } from 'vue' |
||||
import { |
||||
NButton, |
||||
NCard, |
||||
NDataTable, |
||||
NIcon, |
||||
NInput, |
||||
NPagination, |
||||
NSpace |
||||
} from 'naive-ui' |
||||
import { SearchOutlined } from '@vicons/antd' |
||||
import { useI18n } from 'vue-i18n' |
||||
import { useTable } from './use-table' |
||||
import Card from '@/components/card' |
||||
import ClusterModal from './components/cluster-modal' |
||||
|
||||
const clusterManage = defineComponent({ |
||||
name: 'cluster-manage', |
||||
setup() { |
||||
const { t } = useI18n() |
||||
const { variables, getTableData, createColumns } = useTable() |
||||
|
||||
const requestData = () => { |
||||
getTableData({ |
||||
pageSize: variables.pageSize, |
||||
pageNo: variables.page, |
||||
searchVal: variables.searchVal |
||||
}) |
||||
} |
||||
|
||||
const onUpdatePageSize = () => { |
||||
variables.page = 1 |
||||
requestData() |
||||
} |
||||
|
||||
const onSearch = () => { |
||||
variables.page = 1 |
||||
requestData() |
||||
} |
||||
|
||||
const handleModalChange = () => { |
||||
variables.showModalRef = true |
||||
variables.statusRef = 0 |
||||
} |
||||
|
||||
const onCancelModal = () => { |
||||
variables.showModalRef = false |
||||
} |
||||
|
||||
const onConfirmModal = () => { |
||||
variables.showModalRef = false |
||||
requestData() |
||||
} |
||||
|
||||
onMounted(() => { |
||||
createColumns(variables) |
||||
requestData() |
||||
}) |
||||
|
||||
watch(useI18n().locale, () => { |
||||
createColumns(variables) |
||||
}) |
||||
|
||||
return { |
||||
t, |
||||
...toRefs(variables), |
||||
requestData, |
||||
onCancelModal, |
||||
onConfirmModal, |
||||
onUpdatePageSize, |
||||
handleModalChange, |
||||
onSearch |
||||
} |
||||
}, |
||||
render() { |
||||
const { |
||||
t, |
||||
requestData, |
||||
onUpdatePageSize, |
||||
onCancelModal, |
||||
onConfirmModal, |
||||
handleModalChange, |
||||
onSearch, |
||||
loadingRef |
||||
} = this |
||||
|
||||
return ( |
||||
<NSpace vertical> |
||||
<NCard> |
||||
<NSpace justify='space-between'> |
||||
<NButton |
||||
size='small' |
||||
type='primary' |
||||
onClick={handleModalChange} |
||||
class='btn-create-cluster' |
||||
> |
||||
{t('security.cluster.create_cluster')} |
||||
</NButton> |
||||
<NSpace> |
||||
<NInput |
||||
size='small' |
||||
clearable |
||||
v-model={[this.searchVal, 'value']} |
||||
placeholder={t('security.cluster.search_tips')} |
||||
/> |
||||
<NButton size='small' type='primary' onClick={onSearch}> |
||||
{{ |
||||
icon: () => ( |
||||
<NIcon> |
||||
<SearchOutlined /> |
||||
</NIcon> |
||||
) |
||||
}} |
||||
</NButton> |
||||
</NSpace> |
||||
</NSpace> |
||||
</NCard> |
||||
<Card> |
||||
<NSpace vertical> |
||||
<NDataTable |
||||
loading={loadingRef} |
||||
row-class-name='items' |
||||
columns={this.columns} |
||||
data={this.tableData} |
||||
scrollX={this.tableWidth} |
||||
/> |
||||
<NSpace justify='center'> |
||||
<NPagination |
||||
v-model:page={this.page} |
||||
v-model:page-size={this.pageSize} |
||||
page-count={this.totalPage} |
||||
show-size-picker |
||||
page-sizes={[10, 30, 50]} |
||||
show-quick-jumper |
||||
onUpdatePage={requestData} |
||||
onUpdatePageSize={onUpdatePageSize} |
||||
/> |
||||
</NSpace> |
||||
</NSpace> |
||||
</Card> |
||||
<ClusterModal |
||||
showModalRef={this.showModalRef} |
||||
statusRef={this.statusRef} |
||||
row={this.row} |
||||
onCancelModal={onCancelModal} |
||||
onConfirmModal={onConfirmModal} |
||||
/> |
||||
</NSpace> |
||||
) |
||||
} |
||||
}) |
||||
|
||||
export default clusterManage |
@ -0,0 +1,236 @@
|
||||
/* |
||||
* 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. |
||||
*/ |
||||
|
||||
import { useAsyncState } from '@vueuse/core' |
||||
import { reactive, h, ref } from 'vue' |
||||
import { format } from 'date-fns' |
||||
import { NButton, NPopconfirm, NSpace, NTooltip, NTag, NIcon } from 'naive-ui' |
||||
import { useI18n } from 'vue-i18n' |
||||
import { |
||||
queryClusterListPaging, |
||||
deleteClusterByCode |
||||
} from '@/service/modules/cluster' |
||||
import { DeleteOutlined, EditOutlined } from '@vicons/antd' |
||||
import type { ClusterRes, ClusterItem } from '@/service/modules/cluster/types' |
||||
import { parseTime } from '@/common/common' |
||||
import { |
||||
COLUMN_WIDTH_CONFIG, |
||||
calculateTableWidth, |
||||
DefaultTableWidth |
||||
} from '@/common/column-width-config' |
||||
|
||||
export function useTable() { |
||||
const { t } = useI18n() |
||||
|
||||
const handleEdit = (row: any) => { |
||||
variables.showModalRef = true |
||||
variables.statusRef = 1 |
||||
variables.row = row |
||||
} |
||||
|
||||
const createColumns = (variables: any) => { |
||||
variables.columns = [ |
||||
{ |
||||
title: '#', |
||||
key: 'index', |
||||
render: (row: any, index: number) => index + 1, |
||||
...COLUMN_WIDTH_CONFIG['index'] |
||||
}, |
||||
{ |
||||
title: t('security.cluster.cluster_name'), |
||||
key: 'name', |
||||
className: 'cluster-name', |
||||
...COLUMN_WIDTH_CONFIG['name'] |
||||
}, |
||||
{ |
||||
title: t('security.cluster.cluster_components'), |
||||
key: 'config', |
||||
...COLUMN_WIDTH_CONFIG['tag'], |
||||
render: (row: ClusterItem) => |
||||
h(NSpace, null, { |
||||
default: () => { |
||||
const components = [] |
||||
if (row.config) { |
||||
const config = JSON.parse(row.config) |
||||
if (config.yarn) { |
||||
components.push('yarn') |
||||
} |
||||
if (config.k8s) { |
||||
components.push('kubernetes') |
||||
} |
||||
} |
||||
return components.map((item: any) => |
||||
h( |
||||
NTag, |
||||
{ type: 'success', size: 'small' }, |
||||
{ default: () => item } |
||||
) |
||||
) |
||||
} |
||||
}) |
||||
}, |
||||
{ |
||||
title: t('security.cluster.cluster_desc'), |
||||
key: 'description', |
||||
...COLUMN_WIDTH_CONFIG['note'] |
||||
}, |
||||
{ |
||||
title: t('security.cluster.create_time'), |
||||
key: 'createTime', |
||||
...COLUMN_WIDTH_CONFIG['time'] |
||||
}, |
||||
{ |
||||
title: t('security.cluster.update_time'), |
||||
key: 'updateTime', |
||||
...COLUMN_WIDTH_CONFIG['time'] |
||||
}, |
||||
{ |
||||
title: t('security.cluster.operation'), |
||||
key: 'operation', |
||||
...COLUMN_WIDTH_CONFIG['operation'](2), |
||||
render(row: any) { |
||||
return h(NSpace, null, { |
||||
default: () => [ |
||||
h( |
||||
NTooltip, |
||||
{}, |
||||
{ |
||||
trigger: () => |
||||
h( |
||||
NButton, |
||||
{ |
||||
circle: true, |
||||
type: 'info', |
||||
size: 'small', |
||||
class: 'edit', |
||||
onClick: () => { |
||||
handleEdit(row) |
||||
} |
||||
}, |
||||
{ |
||||
icon: () => |
||||
h(NIcon, null, { default: () => h(EditOutlined) }) |
||||
} |
||||
), |
||||
default: () => t('security.cluster.edit') |
||||
} |
||||
), |
||||
h( |
||||
NPopconfirm, |
||||
{ |
||||
onPositiveClick: () => { |
||||
handleDelete(row) |
||||
} |
||||
}, |
||||
{ |
||||
trigger: () => |
||||
h( |
||||
NTooltip, |
||||
{}, |
||||
{ |
||||
trigger: () => |
||||
h( |
||||
NButton, |
||||
{ |
||||
circle: true, |
||||
type: 'error', |
||||
size: 'small', |
||||
class: 'delete' |
||||
}, |
||||
{ |
||||
icon: () => |
||||
h(NIcon, null, { |
||||
default: () => h(DeleteOutlined) |
||||
}) |
||||
} |
||||
), |
||||
default: () => t('security.cluster.delete') |
||||
} |
||||
), |
||||
default: () => t('security.cluster.delete_confirm') |
||||
} |
||||
) |
||||
] |
||||
}) |
||||
} |
||||
} |
||||
] |
||||
if (variables.tableWidth) { |
||||
variables.tableWidth = calculateTableWidth(variables.columns) |
||||
} |
||||
} |
||||
|
||||
const variables = reactive({ |
||||
columns: [], |
||||
tableWidth: DefaultTableWidth, |
||||
tableData: [], |
||||
page: ref(1), |
||||
pageSize: ref(10), |
||||
searchVal: ref(null), |
||||
totalPage: ref(1), |
||||
showModalRef: ref(false), |
||||
statusRef: ref(0), |
||||
row: {}, |
||||
loadingRef: ref(false) |
||||
}) |
||||
|
||||
const handleDelete = (row: any) => { |
||||
deleteClusterByCode({ clusterCode: row.code }).then(() => { |
||||
getTableData({ |
||||
pageSize: variables.pageSize, |
||||
pageNo: |
||||
variables.tableData.length === 1 && variables.page > 1 |
||||
? variables.page - 1 |
||||
: variables.page, |
||||
searchVal: variables.searchVal |
||||
}) |
||||
}) |
||||
} |
||||
|
||||
const getTableData = (params: any) => { |
||||
if (variables.loadingRef) return |
||||
variables.loadingRef = true |
||||
const { state } = useAsyncState( |
||||
queryClusterListPaging({ ...params }).then((res: ClusterRes) => { |
||||
variables.tableData = res.totalList.map((item, unused) => { |
||||
item.createTime = format( |
||||
parseTime(item.createTime), |
||||
'yyyy-MM-dd HH:mm:ss' |
||||
) |
||||
item.updateTime = format( |
||||
parseTime(item.updateTime), |
||||
'yyyy-MM-dd HH:mm:ss' |
||||
) |
||||
return { |
||||
...item |
||||
} |
||||
}) as any |
||||
variables.totalPage = res.totalPage |
||||
variables.loadingRef = false |
||||
}), |
||||
{} |
||||
) |
||||
|
||||
return state |
||||
} |
||||
|
||||
return { |
||||
variables, |
||||
getTableData, |
||||
createColumns |
||||
} |
||||
} |
Loading…
Reference in new issue