package tech.powerjob.server.web.controller; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.time.DateFormatUtils; import org.springframework.beans.BeanUtils; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import tech.powerjob.common.OmsConstant; import tech.powerjob.common.response.ResultDTO; import tech.powerjob.server.auth.Permission; import tech.powerjob.server.auth.RoleScope; import tech.powerjob.server.auth.interceptor.ApiPermission; import tech.powerjob.server.common.constants.ContainerSourceType; import tech.powerjob.common.enums.SwitchableStatus; import tech.powerjob.server.common.utils.OmsFileUtils; import tech.powerjob.server.core.container.ContainerService; import tech.powerjob.server.core.container.ContainerTemplateGenerator; import tech.powerjob.server.persistence.remote.model.AppInfoDO; import tech.powerjob.server.persistence.remote.model.ContainerInfoDO; import tech.powerjob.server.persistence.remote.repository.AppInfoRepository; import tech.powerjob.server.persistence.remote.repository.ContainerInfoRepository; import tech.powerjob.server.web.request.GenerateContainerTemplateRequest; import tech.powerjob.server.web.request.SaveContainerInfoRequest; import tech.powerjob.server.web.response.ContainerInfoVO; import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.IOException; import java.util.List; import java.util.stream.Collectors; /** * 容器信息控制层 * * @author tjq * @since 2020/5/15 */ @Slf4j @RestController @RequestMapping("/container") public class ContainerController { private final ContainerService containerService; private final AppInfoRepository appInfoRepository; private final ContainerInfoRepository containerInfoRepository; public ContainerController(ContainerService containerService, AppInfoRepository appInfoRepository, ContainerInfoRepository containerInfoRepository) { this.containerService = containerService; this.appInfoRepository = appInfoRepository; this.containerInfoRepository = containerInfoRepository; } /** * 暴露给 worker 的下载端口,制品本身 version 不可枚举,不单独鉴权 * 如果对此有安全性需求,可自行实现加密鉴权逻辑,或者干脆走自己的下载通道下载制品 * @param version 容器版本 * @param response 响应 * @throws IOException 异常 */ @GetMapping("/downloadJar") public void downloadJar(String version, HttpServletResponse response) throws IOException { File file = containerService.fetchContainerJarFile(version); if (file.exists()) { OmsFileUtils.file2HttpResponse(file, response); } else { log.error("[Container] can't find container by version[{}], please deploy first!", version); } } @PostMapping("/downloadContainerTemplate") @ApiPermission(name = "Container-DownloadContainerTemplate", roleScope = RoleScope.APP, requiredPermission = Permission.READ) public void downloadContainerTemplate(@RequestBody GenerateContainerTemplateRequest req, HttpServletResponse response) throws IOException { File zipFile = ContainerTemplateGenerator.generate(req.getGroup(), req.getArtifact(), req.getName(), req.getPackageName(), req.getJavaVersion()); OmsFileUtils.file2HttpResponse(zipFile, response); } @PostMapping("/jarUpload") @ApiPermission(name = "Container-JarUpload", roleScope = RoleScope.APP, requiredPermission = Permission.OPS) public ResultDTO fileUpload(@RequestParam("file") MultipartFile file) throws Exception { if (file == null || file.isEmpty()) { return ResultDTO.failed("empty file"); } return ResultDTO.success(containerService.uploadContainerJarFile(file)); } @PostMapping("/save") @ApiPermission(name = "Container-Save", roleScope = RoleScope.APP, requiredPermission = Permission.OPS) public ResultDTO saveContainer(@RequestBody SaveContainerInfoRequest request) { request.valid(); ContainerInfoDO container = new ContainerInfoDO(); BeanUtils.copyProperties(request, container); container.setSourceType(request.getSourceType().getV()); container.setStatus(request.getStatus().getV()); containerService.save(container); return ResultDTO.success(null); } @GetMapping("/delete") @ApiPermission(name = "Container-Delete", roleScope = RoleScope.APP, requiredPermission = Permission.OPS) public ResultDTO deleteContainer(Long appId, Long containerId) { containerService.delete(appId, containerId); return ResultDTO.success(null); } @GetMapping("/list") @ApiPermission(name = "Container-List", roleScope = RoleScope.APP, requiredPermission = Permission.READ) public ResultDTO> listContainers(Long appId) { List res = containerInfoRepository.findByAppIdAndStatusNot(appId, SwitchableStatus.DELETED.getV()) .stream().map(ContainerController::convert).collect(Collectors.toList()); return ResultDTO.success(res); } @GetMapping("/listDeployedWorker") @ApiPermission(name = "Container-ListDeployedWorker", roleScope = RoleScope.APP, requiredPermission = Permission.READ) public ResultDTO listDeployedWorker(Long appId, Long containerId, HttpServletResponse response) { AppInfoDO appInfoDO = appInfoRepository.findById(appId).orElseThrow(() -> new IllegalArgumentException("can't find app by id:" + appId)); String targetServer = appInfoDO.getCurrentServer(); if (StringUtils.isEmpty(targetServer)) { return ResultDTO.failed("No workers have even registered!"); } return ResultDTO.success(containerService.fetchDeployedInfo(appId, containerId)); } private static ContainerInfoVO convert(ContainerInfoDO containerInfoDO) { ContainerInfoVO vo = new ContainerInfoVO(); BeanUtils.copyProperties(containerInfoDO, vo); if (containerInfoDO.getLastDeployTime() == null) { vo.setLastDeployTime("N/A"); }else { vo.setLastDeployTime(DateFormatUtils.format(containerInfoDO.getLastDeployTime(), OmsConstant.TIME_PATTERN)); } SwitchableStatus status = SwitchableStatus.of(containerInfoDO.getStatus()); vo.setStatus(status.name()); ContainerSourceType sourceType = ContainerSourceType.of(containerInfoDO.getSourceType()); vo.setSourceType(sourceType.name()); return vo; } }