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