Skip to content

Commit

Permalink
BIGTOP-4321: Add API for cluster/host/service/component removal (#143)
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinw66 authored Jan 7, 2025
1 parent ae95023 commit 188afbe
Show file tree
Hide file tree
Showing 18 changed files with 133 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@
@Getter
public enum Command {
// Available for: Cluster, Host, Service, Component
// Remove is not a command because it won't create job, please refer to the related controller for remove action.
ADD("add", "Add"),
REMOVE("remove", "Remove"),
START("start", "Start"),
STOP("stop", "Stop"),
RESTART("restart", "Restart"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import org.apache.bigtop.manager.server.utils.ResponseEntity;

import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
Expand Down Expand Up @@ -65,4 +66,10 @@ public ResponseEntity<ClusterVO> update(@PathVariable Long id, @RequestBody @Val
ClusterDTO clusterDTO = ClusterConverter.INSTANCE.fromReq2DTO(clusterReq);
return ResponseEntity.success(clusterService.update(id, clusterDTO));
}

@Operation(summary = "remove", description = "Remove a cluster")
@DeleteMapping("/{id}")
public ResponseEntity<Boolean> remove(@PathVariable Long id) {
return ResponseEntity.success(clusterService.remove(id));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.apache.bigtop.manager.server.service.ComponentService;
import org.apache.bigtop.manager.server.utils.ResponseEntity;

import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
Expand Down Expand Up @@ -69,4 +70,10 @@ public ResponseEntity<PageVO<ComponentVO>> list(ComponentQuery query) {
public ResponseEntity<ComponentVO> get(@PathVariable Long clusterId, @PathVariable Long id) {
return ResponseEntity.success(componentService.get(id));
}

@Operation(summary = "remove", description = "Remove a component")
@DeleteMapping("/{id}")
public ResponseEntity<Boolean> remove(@PathVariable Long clusterId, @PathVariable Long id) {
return ResponseEntity.success(componentService.remove(id));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,10 @@ public ResponseEntity<HostVO> update(@PathVariable Long id, @RequestBody @Valida
return ResponseEntity.success(hostService.update(id, hostDTO));
}

@Operation(summary = "delete", description = "Delete a host")
@Operation(summary = "remove", description = "Remove a host")
@DeleteMapping("/{id}")
public ResponseEntity<Boolean> delete(@PathVariable Long id) {
return ResponseEntity.success(hostService.delete(id));
public ResponseEntity<Boolean> remove(@PathVariable Long id) {
return ResponseEntity.success(hostService.remove(id));
}

@Operation(summary = "Check connection", description = "Check connection for hosts")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,12 @@ public ResponseEntity<ServiceVO> get(@PathVariable Long clusterId, @PathVariable
return ResponseEntity.success(serviceService.get(id));
}

@Operation(summary = "remove", description = "Remove a service")
@DeleteMapping("/{id}")
public ResponseEntity<Boolean> remove(@PathVariable Long clusterId, @PathVariable Long id) {
return ResponseEntity.success(serviceService.remove(id));
}

@Operation(summary = "list service configs", description = "List service configs")
@GetMapping("/{id}/configs")
public ResponseEntity<List<ServiceConfigVO>> listConf(@PathVariable Long clusterId, @PathVariable Long id) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ public enum ApiExceptionEnum {
// Cluster Exceptions -- 11000 ~ 11999
CLUSTER_NOT_FOUND(11000, LocaleKeys.CLUSTER_NOT_FOUND),
CLUSTER_EXISTS(11001, LocaleKeys.CLUSTER_EXISTS),
CLUSTER_HAS_HOSTS(11002, LocaleKeys.CLUSTER_HAS_HOSTS),
CLUSTER_HAS_SERVICES(11003, LocaleKeys.CLUSTER_HAS_SERVICES),

// Host Exceptions -- 12000 ~ 12999
HOST_NOT_FOUND(12000, LocaleKeys.HOST_NOT_FOUND),
Expand All @@ -48,9 +50,11 @@ public enum ApiExceptionEnum {
// Service Exceptions -- 14000 ~ 14999
SERVICE_NOT_FOUND(14000, LocaleKeys.SERVICE_NOT_FOUND),
SERVICE_REQUIRED_NOT_FOUND(14001, LocaleKeys.SERVICE_REQUIRED_NOT_FOUND),
SERVICE_HAS_COMPONENTS(14002, LocaleKeys.SERVICE_HAS_COMPONENTS),

// Component Exceptions -- 15000 ~ 15999
COMPONENT_NOT_FOUND(15000, LocaleKeys.COMPONENT_NOT_FOUND),
COMPONENT_IS_RUNNING(15001, LocaleKeys.COMPONENT_IS_RUNNING),

// Job Exceptions -- 16000 ~ 16999
JOB_NOT_FOUND(16000, LocaleKeys.JOB_NOT_FOUND),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ public enum LocaleKeys {

CLUSTER_NOT_FOUND("cluster.not.found"),
CLUSTER_EXISTS("cluster.exists"),
CLUSTER_HAS_HOSTS("cluster.has.hosts"),
CLUSTER_HAS_SERVICES("cluster.has.services"),

HOST_NOT_FOUND("host.not.found"),
HOST_ASSIGNED("host.assigned"),
Expand All @@ -48,8 +50,10 @@ public enum LocaleKeys {

SERVICE_NOT_FOUND("service.not.found"),
SERVICE_REQUIRED_NOT_FOUND("service.required.not.found"),
SERVICE_HAS_COMPONENTS("service.has.components"),

COMPONENT_NOT_FOUND("component.not.found"),
COMPONENT_IS_RUNNING("component.is.running"),

JOB_NOT_FOUND("job.not.found"),
JOB_NOT_RETRYABLE("job.not.retryable"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,11 @@ public interface ClusterService {
* @return Cluster
*/
ClusterVO update(Long id, ClusterDTO clusterDTO);

/**
* Remove a cluster
*
* @return Cluster
*/
Boolean remove(Long id);
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,11 @@ public interface ComponentService {
* @return component
*/
ComponentVO get(Long id);

/**
* Remove a component.
*
* @return component
*/
Boolean remove(Long id);
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public interface HostService {
*
* @return Host
*/
Boolean delete(Long id);
Boolean remove(Long id);

/**
* Check hosts connection
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,13 @@ public interface ServiceService {
*/
ServiceVO get(Long id);

/**
* Remove a service.
*
* @return service
*/
Boolean remove(Long id);

List<ServiceConfigVO> listConf(Long clusterId, Long serviceId);

List<ServiceConfigVO> updateConf(Long clusterId, Long serviceId, List<ServiceConfigReq> reqs);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,20 @@
package org.apache.bigtop.manager.server.service.impl;

import org.apache.bigtop.manager.dao.po.ClusterPO;
import org.apache.bigtop.manager.dao.po.HostPO;
import org.apache.bigtop.manager.dao.po.ServicePO;
import org.apache.bigtop.manager.dao.repository.ClusterDao;
import org.apache.bigtop.manager.dao.repository.HostDao;
import org.apache.bigtop.manager.dao.repository.ServiceDao;
import org.apache.bigtop.manager.server.enums.ApiExceptionEnum;
import org.apache.bigtop.manager.server.exception.ApiException;
import org.apache.bigtop.manager.server.model.converter.ClusterConverter;
import org.apache.bigtop.manager.server.model.dto.ClusterDTO;
import org.apache.bigtop.manager.server.model.vo.ClusterVO;
import org.apache.bigtop.manager.server.service.ClusterService;

import org.apache.commons.collections4.CollectionUtils;

import org.springframework.stereotype.Service;

import lombok.extern.slf4j.Slf4j;
Expand All @@ -41,6 +47,12 @@ public class ClusterServiceImpl implements ClusterService {
@Resource
private ClusterDao clusterDao;

@Resource
private HostDao hostDao;

@Resource
private ServiceDao serviceDao;

@Override
public List<ClusterVO> list() {
List<ClusterPO> clusterPOList = clusterDao.findAll();
Expand All @@ -66,4 +78,19 @@ public ClusterVO update(Long id, ClusterDTO clusterDTO) {

return get(id);
}

@Override
public Boolean remove(Long id) {
List<HostPO> hostPOList = hostDao.findAllByClusterId(id);
if (CollectionUtils.isNotEmpty(hostPOList)) {
throw new ApiException(ApiExceptionEnum.CLUSTER_HAS_HOSTS);
}

List<ServicePO> servicePOList = serviceDao.findByClusterId(id);
if (CollectionUtils.isNotEmpty(servicePOList)) {
throw new ApiException(ApiExceptionEnum.CLUSTER_HAS_SERVICES);
}

return clusterDao.deleteById(id);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,15 @@
*/
package org.apache.bigtop.manager.server.service.impl;

import org.apache.bigtop.manager.common.constants.ComponentCategories;
import org.apache.bigtop.manager.dao.po.ComponentPO;
import org.apache.bigtop.manager.dao.po.ServiceConfigPO;
import org.apache.bigtop.manager.dao.query.ComponentQuery;
import org.apache.bigtop.manager.dao.repository.ComponentDao;
import org.apache.bigtop.manager.dao.repository.ServiceConfigDao;
import org.apache.bigtop.manager.server.enums.ApiExceptionEnum;
import org.apache.bigtop.manager.server.enums.HealthyStatusEnum;
import org.apache.bigtop.manager.server.exception.ApiException;
import org.apache.bigtop.manager.server.model.converter.ComponentConverter;
import org.apache.bigtop.manager.server.model.converter.ServiceConfigConverter;
import org.apache.bigtop.manager.server.model.dto.ComponentDTO;
Expand All @@ -47,6 +51,7 @@
import jakarta.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@Slf4j
@Service
Expand Down Expand Up @@ -86,6 +91,20 @@ public ComponentVO get(Long id) {
return componentVO;
}

@Override
public Boolean remove(Long id) {
ComponentPO componentPO = componentDao.findById(id);
ComponentDTO componentDTO = StackUtils.getComponentDTO(componentPO.getName());

// Only server component should be stopped before remove, client component can be removed directly.
if (componentDTO.getCategory().equals(ComponentCategories.SERVER)
&& Objects.equals(componentPO.getStatus(), HealthyStatusEnum.HEALTHY.getCode())) {
throw new ApiException(ApiExceptionEnum.COMPONENT_IS_RUNNING);
}

return componentDao.deleteById(id);
}

private QuickLinkVO getQuickLink(ComponentPO componentPO) {
ComponentDTO componentDTO = StackUtils.getComponentDTO(componentPO.getName());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,13 +143,12 @@ public HostVO update(Long id, HostDTO hostDTO) {
}

@Override
public Boolean delete(Long id) {
public Boolean remove(Long id) {
if (componentDao.countByHostId(id) > 0) {
throw new ApiException(ApiExceptionEnum.HOST_HAS_COMPONENTS);
}

hostDao.deleteById(id);
return true;
return hostDao.deleteById(id);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,18 @@
package org.apache.bigtop.manager.server.service.impl;

import org.apache.bigtop.manager.common.utils.JsonUtils;
import org.apache.bigtop.manager.dao.po.ComponentPO;
import org.apache.bigtop.manager.dao.po.ServiceConfigPO;
import org.apache.bigtop.manager.dao.po.ServiceConfigSnapshotPO;
import org.apache.bigtop.manager.dao.po.ServicePO;
import org.apache.bigtop.manager.dao.query.ComponentQuery;
import org.apache.bigtop.manager.dao.query.ServiceQuery;
import org.apache.bigtop.manager.dao.repository.ComponentDao;
import org.apache.bigtop.manager.dao.repository.ServiceConfigDao;
import org.apache.bigtop.manager.dao.repository.ServiceConfigSnapshotDao;
import org.apache.bigtop.manager.dao.repository.ServiceDao;
import org.apache.bigtop.manager.server.enums.ApiExceptionEnum;
import org.apache.bigtop.manager.server.exception.ApiException;
import org.apache.bigtop.manager.server.model.converter.ServiceConfigConverter;
import org.apache.bigtop.manager.server.model.converter.ServiceConfigSnapshotConverter;
import org.apache.bigtop.manager.server.model.converter.ServiceConverter;
Expand Down Expand Up @@ -67,6 +72,9 @@ public class ServiceServiceImpl implements ServiceService {
@Resource
private ServiceConfigSnapshotDao serviceConfigSnapshotDao;

@Resource
private ComponentDao componentDao;

@Override
public PageVO<ServiceVO> list(ServiceQuery query) {
PageQuery pageQuery = PageUtils.getPageQuery();
Expand All @@ -85,6 +93,17 @@ public ServiceVO get(Long id) {
return ServiceConverter.INSTANCE.fromPO2VO(serviceDao.findById(id));
}

@Override
public Boolean remove(Long id) {
ComponentQuery query = ComponentQuery.builder().serviceId(id).build();
List<ComponentPO> componentPOList = componentDao.findByQuery(query);
if (CollectionUtils.isNotEmpty(componentPOList)) {
throw new ApiException(ApiExceptionEnum.SERVICE_HAS_COMPONENTS);
}

return serviceDao.deleteById(id);
}

@Override
public List<ServiceConfigVO> listConf(Long clusterId, Long serviceId) {
List<ServiceConfigPO> list = serviceConfigDao.findByServiceId(serviceId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ login.account.disabled=User is disabled

cluster.not.found=Cluster not exist
cluster.exists=Cluster already exists
cluster.has.hosts=Cluster still has hosts, please remove them first
cluster.has.services=Cluster still has services, please remove them first

host.not.found=Host not exist
host.assigned=Hosts [{0}] already assigned to another cluster
Expand All @@ -42,8 +44,10 @@ stack.not.found=Stack not exist

service.not.found=Service not exist
service.required.not.found=Required Service [{0}] not exist
service.has.components=Service still has components, please remove them first

component.not.found=Component not exist
component.is.running=Component is running, please stop it first

job.not.found=Job not exist
job.not.retryable=Job is not retryable when it's not failed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ login.account.disabled=用户已被禁用

cluster.not.found=集群不存在
cluster.exists=集群已存在
cluster.has.hosts=集群上仍有主机,请先移除
cluster.has.services=集群上仍有服务,请先移除

host.not.found=主机不存在
host.assigned=主机 [{0}] 已属于其他集群
Expand All @@ -42,8 +44,10 @@ stack.not.found=组件栈不存在

service.not.found=服务不存在
service.required.not.found=依赖服务 [{0}] 不存在
service.has.components=服务上仍有组件,请先移除

component.not.found=组件不存在
component.is.running=组件正在运行,请先停止

job.not.found=任务不存在
job.not.retryable=任务非失败状态,无法重试
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,9 @@ void updateReturnsUpdatedHost() {
@Test
void deleteReturnsSuccess() {
Long hostId = 1L;
when(hostService.delete(hostId)).thenReturn(true);
when(hostService.remove(hostId)).thenReturn(true);

ResponseEntity<Boolean> response = hostController.delete(hostId);
ResponseEntity<Boolean> response = hostController.remove(hostId);

assertTrue(response.isSuccess());
assertTrue(response.getData());
Expand Down Expand Up @@ -163,9 +163,9 @@ void updateReturnsNullForInvalidHostId() {
@Test
void deleteReturnsFalseForInvalidHostId() {
Long hostId = 999L;
when(hostService.delete(hostId)).thenReturn(false);
when(hostService.remove(hostId)).thenReturn(false);

ResponseEntity<Boolean> response = hostController.delete(hostId);
ResponseEntity<Boolean> response = hostController.remove(hostId);

assertTrue(response.isSuccess());
assertFalse(response.getData());
Expand Down

0 comments on commit 188afbe

Please sign in to comment.