feat(virtual-machines): 添加虚拟机操作相关接口和功能
- 新增了虚拟机启动、关闭、强制关闭、重启等操作的接口和实现 - 增加了克隆虚拟机到桌面镜像的功能 - 更新了虚拟机删除逻辑,支持删除存储的镜像文件 - 重构了部分代码,优化了虚拟机相关数据的处理master
parent
4b7772b38d
commit
0292dcb065
|
|
@ -11,11 +11,17 @@ import com.unisinsight.project.service.ImageToolService;
|
||||||
import io.swagger.annotations.ApiImplicitParam;
|
import io.swagger.annotations.ApiImplicitParam;
|
||||||
import io.swagger.annotations.ApiImplicitParams;
|
import io.swagger.annotations.ApiImplicitParams;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.core.io.FileSystemResource;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.io.File;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|
@ -43,7 +49,7 @@ public class ImageToolController {
|
||||||
/**
|
/**
|
||||||
* 服务对象
|
* 服务对象
|
||||||
*/
|
*/
|
||||||
@Resource
|
@javax.annotation.Resource
|
||||||
private ImageToolService service;
|
private ImageToolService service;
|
||||||
@Autowired
|
@Autowired
|
||||||
private ChunkedUploadService chunkedUploadService;
|
private ChunkedUploadService chunkedUploadService;
|
||||||
|
|
@ -90,12 +96,12 @@ public class ImageToolController {
|
||||||
@RequestParam("shard_total") int totalChunks,
|
@RequestParam("shard_total") int totalChunks,
|
||||||
@RequestParam("file_name") String fileName,
|
@RequestParam("file_name") String fileName,
|
||||||
@RequestParam("file_size") long totalSize,
|
@RequestParam("file_size") long totalSize,
|
||||||
@RequestParam("file_version") String fileVersion,
|
@RequestParam(value = "file_version",required = false) String fileVersion,
|
||||||
@RequestParam(value = "description", required = false) String description
|
@RequestParam(value = "description", required = false) String description
|
||||||
) {
|
) {
|
||||||
|
|
||||||
return service.uploadChunk(chunk, chunkSize, chunkMd5, fileId, chunkNumber, totalChunks,
|
return service.uploadChunk(chunk, chunkSize, chunkMd5, fileId, chunkNumber, totalChunks,
|
||||||
fileName, totalSize,description);
|
fileName, totalSize,description,fileType,fileVersion);
|
||||||
}
|
}
|
||||||
@PostMapping("/cancel/upload")
|
@PostMapping("/cancel/upload")
|
||||||
@ApiOperation(value = "取消上传ImageTool文件")
|
@ApiOperation(value = "取消上传ImageTool文件")
|
||||||
|
|
@ -108,6 +114,42 @@ public class ImageToolController {
|
||||||
return Result.errorResultMessage(BaseErrorCode.HTTP_ERROR_CODE_500, "取消上传失败: " + e.getMessage());
|
return Result.errorResultMessage(BaseErrorCode.HTTP_ERROR_CODE_500, "取消上传失败: " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/download/{id}")
|
||||||
|
@ApiOperation(value = "下载ImageTool文件", notes = "通过文件ID下载对应的ImageTool文件")
|
||||||
|
public ResponseEntity<Resource> downloadFile(@PathVariable Integer id, HttpServletRequest request) {
|
||||||
|
try {
|
||||||
|
// 1. 查询文件信息
|
||||||
|
ImageTool imageTool = service.getById(id);
|
||||||
|
if (imageTool == null || imageTool.getStorePath() == null) {
|
||||||
|
return ResponseEntity.notFound().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 获取文件路径
|
||||||
|
String filePath = imageTool.getStorePath();
|
||||||
|
File file = new File(filePath);
|
||||||
|
|
||||||
|
if (!file.exists()) {
|
||||||
|
return ResponseEntity.notFound().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 构建响应
|
||||||
|
FileSystemResource resource = new FileSystemResource(file);
|
||||||
|
String contentType = request.getServletContext().getMimeType(file.getAbsolutePath());
|
||||||
|
if(contentType == null) {
|
||||||
|
contentType = "application/octet-stream";
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResponseEntity.ok()
|
||||||
|
.contentType(MediaType.parseMediaType(contentType))
|
||||||
|
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + imageTool.getFileName() + "\"")
|
||||||
|
.body(resource);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("下载文件失败,id:{},error:{}", id, e.getMessage(), e);
|
||||||
|
return ResponseEntity.internalServerError().build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ApiOperation(value = "修改")
|
@ApiOperation(value = "修改")
|
||||||
@PostMapping("/update")
|
@PostMapping("/update")
|
||||||
public Result<?> updateUser(@RequestBody ImageToolReq imageToolReq) {
|
public Result<?> updateUser(@RequestBody ImageToolReq imageToolReq) {
|
||||||
|
|
|
||||||
|
|
@ -106,8 +106,26 @@ public class ImageVirtualMachinesController {
|
||||||
return Result.errorResult(BaseErrorCode.PARAMS_CHK_ERROR);
|
return Result.errorResult(BaseErrorCode.PARAMS_CHK_ERROR);
|
||||||
}
|
}
|
||||||
log.info("终端启动请求参数为:{}", JSONUtil.toJsonStr(req));
|
log.info("终端启动请求参数为:{}", JSONUtil.toJsonStr(req));
|
||||||
return service.cloneTemplate(req);
|
return service.start(req);
|
||||||
}
|
}
|
||||||
|
@ApiOperation(value = "终端关闭")
|
||||||
|
@PostMapping("/shutdown")
|
||||||
|
public Result<?> shutdown(@RequestBody ImageVirtualMachinesReq req) {
|
||||||
|
if (Objects.isNull(req)) {
|
||||||
|
return Result.errorResult(BaseErrorCode.PARAMS_CHK_ERROR);
|
||||||
|
}
|
||||||
|
log.info("终端关闭请求参数为:{}", JSONUtil.toJsonStr(req));
|
||||||
|
return service.shutdown(req);
|
||||||
|
}
|
||||||
|
// @ApiOperation(value = "终端强制关闭")
|
||||||
|
// @PostMapping("/destroy")
|
||||||
|
// public Result<?> destroy(@RequestBody ImageVirtualMachinesReq req) {
|
||||||
|
// if (Objects.isNull(req)) {
|
||||||
|
// return Result.errorResult(BaseErrorCode.PARAMS_CHK_ERROR);
|
||||||
|
// }
|
||||||
|
// log.info("终端强制关闭请求参数为:{}", JSONUtil.toJsonStr(req));
|
||||||
|
// return service.destroy(req);
|
||||||
|
// }
|
||||||
@ApiOperation(value = "终端重启")
|
@ApiOperation(value = "终端重启")
|
||||||
@PostMapping("/reboot")
|
@PostMapping("/reboot")
|
||||||
public Result<?> reboot(@RequestBody ImageVirtualMachinesReq req) {
|
public Result<?> reboot(@RequestBody ImageVirtualMachinesReq req) {
|
||||||
|
|
@ -115,16 +133,7 @@ public class ImageVirtualMachinesController {
|
||||||
return Result.errorResult(BaseErrorCode.PARAMS_CHK_ERROR);
|
return Result.errorResult(BaseErrorCode.PARAMS_CHK_ERROR);
|
||||||
}
|
}
|
||||||
log.info("终端重启请求参数为:{}", JSONUtil.toJsonStr(req));
|
log.info("终端重启请求参数为:{}", JSONUtil.toJsonStr(req));
|
||||||
return service.cloneTemplate(req);
|
return service.reboot(req);
|
||||||
}
|
|
||||||
@ApiOperation(value = "终端快照")
|
|
||||||
@PostMapping("/snapshot")
|
|
||||||
public Result<?> snapshot(@RequestBody ImageVirtualMachinesReq req) {
|
|
||||||
if (Objects.isNull(req)) {
|
|
||||||
return Result.errorResult(BaseErrorCode.PARAMS_CHK_ERROR);
|
|
||||||
}
|
|
||||||
log.info("终端快照请求参数为:{}", JSONUtil.toJsonStr(req));
|
|
||||||
return service.cloneTemplate(req);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,19 @@ public class ImageConfigProperties {
|
||||||
private String updateUrl;
|
private String updateUrl;
|
||||||
@Getter(value=AccessLevel.NONE)
|
@Getter(value=AccessLevel.NONE)
|
||||||
private String startUrl;
|
private String startUrl;
|
||||||
|
@Getter(value=AccessLevel.NONE)
|
||||||
|
private String shutdownUrl;
|
||||||
|
@Getter(value=AccessLevel.NONE)
|
||||||
|
private String destroyUrl;
|
||||||
|
@Getter(value=AccessLevel.NONE)
|
||||||
|
private String rebootUrl;
|
||||||
|
@Getter(value=AccessLevel.NONE)
|
||||||
|
private String pauseUrl;
|
||||||
|
@Getter(value=AccessLevel.NONE)
|
||||||
|
private String resumeUrl;
|
||||||
|
@Getter(value=AccessLevel.NONE)
|
||||||
|
private String cloneToDesktopUrl;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -65,4 +78,29 @@ public class ImageConfigProperties {
|
||||||
public String getStartUrl() {
|
public String getStartUrl() {
|
||||||
return baseUrl+startUrl;
|
return baseUrl+startUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getShutdownUrl() {
|
||||||
|
return baseUrl+shutdownUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDestroyUrl() {
|
||||||
|
return baseUrl+destroyUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRebootUrl() {
|
||||||
|
return baseUrl+rebootUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPauseUrl() {
|
||||||
|
return baseUrl+pauseUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getResumeUrl() {
|
||||||
|
return baseUrl+resumeUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCloneToDesktopUrl() {
|
||||||
|
return baseUrl+cloneToDesktopUrl;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,10 @@ public interface ImageToolService extends IService<ImageTool> {
|
||||||
|
|
||||||
Result<?> delete(DeleteIdReq deleteIdReq);
|
Result<?> delete(DeleteIdReq deleteIdReq);
|
||||||
|
|
||||||
Result<?> uploadChunk(MultipartFile chunk, int chunkSize, String chunkMd5, String fileId, int chunkNumber, int totalChunks, String fileName, long totalSize, String description);
|
Result<?> uploadChunk(MultipartFile chunk, int chunkSize, String chunkMd5,
|
||||||
|
String fileId, int chunkNumber,
|
||||||
|
int totalChunks, String fileName,
|
||||||
|
long totalSize, String description
|
||||||
|
, String fileType,String fileVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,5 +27,35 @@ public interface ImageVirtualMachinesService extends IService<ImageVirtualMachin
|
||||||
Result<?> delete(DeleteIdReq deleteIdReq);
|
Result<?> delete(DeleteIdReq deleteIdReq);
|
||||||
|
|
||||||
Result<?> cloneTemplate(ImageVirtualMachinesReq req);
|
Result<?> cloneTemplate(ImageVirtualMachinesReq req);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启动虚拟机
|
||||||
|
* @param req
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
Result<?> start(ImageVirtualMachinesReq req);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭虚拟机
|
||||||
|
* @param req
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
Result<?> shutdown(ImageVirtualMachinesReq req);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 强制关闭虚拟机
|
||||||
|
* @param req
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
Result<?> destroy(ImageVirtualMachinesReq req);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重启虚拟机
|
||||||
|
* @param req
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
Result<?> reboot(ImageVirtualMachinesReq req);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,12 @@ import cn.hutool.json.JSONUtil;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.unisinsight.project.entity.dao.DeviceImageMapping;
|
import com.unisinsight.project.entity.dao.DeviceImageMapping;
|
||||||
import com.unisinsight.project.entity.dao.Image;
|
import com.unisinsight.project.entity.dao.Image;
|
||||||
|
import com.unisinsight.project.entity.dao.ImageDesktop;
|
||||||
|
import com.unisinsight.project.entity.res.ImageDesktopRes;
|
||||||
import com.unisinsight.project.entity.res.ImageRes;
|
import com.unisinsight.project.entity.res.ImageRes;
|
||||||
import com.unisinsight.project.exception.Result;
|
import com.unisinsight.project.exception.Result;
|
||||||
import com.unisinsight.project.mapper.DeviceImageMappingMapper;
|
import com.unisinsight.project.mapper.DeviceImageMappingMapper;
|
||||||
|
import com.unisinsight.project.mapper.ImageDesktopMapper;
|
||||||
import com.unisinsight.project.mapper.ImageMapper;
|
import com.unisinsight.project.mapper.ImageMapper;
|
||||||
import com.unisinsight.project.service.ClientService;
|
import com.unisinsight.project.service.ClientService;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
@ -33,7 +36,7 @@ import java.util.stream.Collectors;
|
||||||
public class ClientServiceImpl implements ClientService {
|
public class ClientServiceImpl implements ClientService {
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private ImageMapper imageMapper;
|
private ImageDesktopMapper imageDesktopMapper;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private DeviceImageMappingMapper deviceImageMappingMapper;
|
private DeviceImageMappingMapper deviceImageMappingMapper;
|
||||||
|
|
@ -44,6 +47,7 @@ public class ClientServiceImpl implements ClientService {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Result<?> getImageList(String deviceId, String token) {
|
public Result<?> getImageList(String deviceId, String token) {
|
||||||
|
// todo 改为桌面镜像 需验证
|
||||||
HashMap<String, Object> hashMap = new HashMap<>();
|
HashMap<String, Object> hashMap = new HashMap<>();
|
||||||
List<DeviceImageMapping> deviceImageMappings = deviceImageMappingMapper.selectList(new LambdaQueryWrapper<DeviceImageMapping>().eq(DeviceImageMapping::getDeviceId, deviceId));
|
List<DeviceImageMapping> deviceImageMappings = deviceImageMappingMapper.selectList(new LambdaQueryWrapper<DeviceImageMapping>().eq(DeviceImageMapping::getDeviceId, deviceId));
|
||||||
if (CollectionUtil.isEmpty(deviceImageMappings)) {
|
if (CollectionUtil.isEmpty(deviceImageMappings)) {
|
||||||
|
|
@ -52,13 +56,13 @@ public class ClientServiceImpl implements ClientService {
|
||||||
}
|
}
|
||||||
List<Long> imageIdList = deviceImageMappings.stream().map(DeviceImageMapping::getImageId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
|
List<Long> imageIdList = deviceImageMappings.stream().map(DeviceImageMapping::getImageId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
|
||||||
if (CollectionUtil.isNotEmpty(imageIdList)) {
|
if (CollectionUtil.isNotEmpty(imageIdList)) {
|
||||||
List<Image> images = imageMapper.selectList(new LambdaQueryWrapper<Image>().in(Image::getId, imageIdList));
|
List<ImageDesktop> images = imageDesktopMapper.selectList(new LambdaQueryWrapper<ImageDesktop>().in(ImageDesktop::getId, imageIdList));
|
||||||
log.info("用户登录查询镜像结果:{}", JSONUtil.toJsonStr(images));
|
log.info("用户登录查询镜像结果:{}", JSONUtil.toJsonStr(images));
|
||||||
List<ImageRes> imageRes = BeanUtil.copyToList(images, ImageRes.class);
|
List<ImageDesktopRes> imageRes = BeanUtil.copyToList(images, ImageDesktopRes.class);
|
||||||
List<HashMap<String, Object>> collect = imageRes.stream().distinct().map(e -> {
|
List<HashMap<String, Object>> collect = imageRes.stream().distinct().map(e -> {
|
||||||
HashMap<String, Object> map = new HashMap<>();
|
HashMap<String, Object> map = new HashMap<>();
|
||||||
if (StringUtils.isNotBlank(e.getImageFileName())) {
|
if (StringUtils.isNotBlank(e.getDesktopName())) {
|
||||||
map.put("name", e.getImageFileName());
|
map.put("name", e.getDesktopName());
|
||||||
}
|
}
|
||||||
if (StringUtils.isNotBlank(e.getBtPath())) {
|
if (StringUtils.isNotBlank(e.getBtPath())) {
|
||||||
if (e.getBtPath().contains("http://") || e.getBtPath().contains("https://")) {
|
if (e.getBtPath().contains("http://") || e.getBtPath().contains("https://")) {
|
||||||
|
|
|
||||||
|
|
@ -123,7 +123,9 @@ public class ImageToolServiceImpl extends ServiceImpl<ImageToolMapper, ImageTool
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Result<?> uploadChunk(MultipartFile chunk, int chunkSize, String chunkMd5, String fileId, int chunkNumber, int totalChunks, String fileName, long totalSize, String description) {
|
public Result<?> uploadChunk(MultipartFile chunk, int chunkSize, String chunkMd5, String fileId, int chunkNumber,
|
||||||
|
int totalChunks, String fileName, long totalSize, String description
|
||||||
|
, String fileType, String fileVersion) {
|
||||||
LambdaQueryWrapper<ImageTool> queryWrapper = new LambdaQueryWrapper<>();
|
LambdaQueryWrapper<ImageTool> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
queryWrapper.eq(ImageTool::getFileName, fileName);
|
queryWrapper.eq(ImageTool::getFileName, fileName);
|
||||||
ImageTool exists = mapper.selectOne(queryWrapper);
|
ImageTool exists = mapper.selectOne(queryWrapper);
|
||||||
|
|
@ -142,7 +144,8 @@ public class ImageToolServiceImpl extends ServiceImpl<ImageToolMapper, ImageTool
|
||||||
imageTool.setFileName(completion.getFileName());
|
imageTool.setFileName(completion.getFileName());
|
||||||
imageTool.setFileType(getFileType(completion.getFileName()));
|
imageTool.setFileType(getFileType(completion.getFileName()));
|
||||||
imageTool.setFileSize(completion.getFileSize());
|
imageTool.setFileSize(completion.getFileSize());
|
||||||
// imageTool.setFileVersion(fileVersion);
|
imageTool.setFileVersion(fileVersion);
|
||||||
|
imageTool.setFileType(fileType);
|
||||||
imageTool.setStorePath(completion.getFilePath());
|
imageTool.setStorePath(completion.getFilePath());
|
||||||
imageTool.setUploadTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
imageTool.setUploadTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
||||||
imageTool.setCreateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
imageTool.setCreateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,12 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
import com.unisinsight.project.entity.dao.Image;
|
import com.unisinsight.project.entity.dao.Image;
|
||||||
import com.unisinsight.project.entity.dao.ImageTool;
|
import com.unisinsight.project.entity.dao.ImageTool;
|
||||||
import com.unisinsight.project.entity.dao.ImageVirtualMachines;
|
import com.unisinsight.project.entity.dao.ImageVirtualMachines;
|
||||||
|
import com.unisinsight.project.entity.dao.ImageDesktop;
|
||||||
import com.unisinsight.project.entity.req.DeleteIdReq;
|
import com.unisinsight.project.entity.req.DeleteIdReq;
|
||||||
|
import com.unisinsight.project.entity.req.ImageCloneToDesktopReq;
|
||||||
import com.unisinsight.project.entity.req.ImageCreateReq;
|
import com.unisinsight.project.entity.req.ImageCreateReq;
|
||||||
|
import com.unisinsight.project.entity.req.ImageDeleteReq;
|
||||||
|
import com.unisinsight.project.entity.req.ImageOperationReq;
|
||||||
import com.unisinsight.project.entity.req.ImageUpdateReq;
|
import com.unisinsight.project.entity.req.ImageUpdateReq;
|
||||||
import com.unisinsight.project.entity.req.ImageVirtualMachinesReq;
|
import com.unisinsight.project.entity.req.ImageVirtualMachinesReq;
|
||||||
import com.unisinsight.project.entity.res.ImageStatusRes;
|
import com.unisinsight.project.entity.res.ImageStatusRes;
|
||||||
|
|
@ -22,6 +26,7 @@ import com.unisinsight.project.exception.BaseErrorCode;
|
||||||
import com.unisinsight.project.exception.Result;
|
import com.unisinsight.project.exception.Result;
|
||||||
import com.unisinsight.project.mapper.ImageVirtualMachinesMapper;
|
import com.unisinsight.project.mapper.ImageVirtualMachinesMapper;
|
||||||
import com.unisinsight.project.properties.ImageConfigProperties;
|
import com.unisinsight.project.properties.ImageConfigProperties;
|
||||||
|
import com.unisinsight.project.service.ImageDesktopService;
|
||||||
import com.unisinsight.project.service.ImageService;
|
import com.unisinsight.project.service.ImageService;
|
||||||
import com.unisinsight.project.service.ImageToolService;
|
import com.unisinsight.project.service.ImageToolService;
|
||||||
import com.unisinsight.project.service.ImageVirtualMachinesService;
|
import com.unisinsight.project.service.ImageVirtualMachinesService;
|
||||||
|
|
@ -58,6 +63,8 @@ public class ImageVirtualMachinesServiceImpl extends ServiceImpl<ImageVirtualMac
|
||||||
private ImageConfigProperties imageConfigProperties;
|
private ImageConfigProperties imageConfigProperties;
|
||||||
@Resource
|
@Resource
|
||||||
private ImageToolService imageToolService;
|
private ImageToolService imageToolService;
|
||||||
|
@Autowired
|
||||||
|
private ImageDesktopService imageDesktopService;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -159,7 +166,7 @@ public class ImageVirtualMachinesServiceImpl extends ServiceImpl<ImageVirtualMac
|
||||||
.networkName(imageVirtualMachinesReq.getNetworkModule())
|
.networkName(imageVirtualMachinesReq.getNetworkModule())
|
||||||
.isoPath(imageVirtualMachinesReq.getStoragePath())
|
.isoPath(imageVirtualMachinesReq.getStoragePath())
|
||||||
//驱动
|
//驱动
|
||||||
// .virtioWinPath(imageVirtualMachinesReq.getStoragePath())
|
.virtioWinPath(imageTool.getStorePath())
|
||||||
.description(imageVirtualMachinesReq.getDescription())
|
.description(imageVirtualMachinesReq.getDescription())
|
||||||
|
|
||||||
.build();
|
.build();
|
||||||
|
|
@ -232,6 +239,27 @@ public class ImageVirtualMachinesServiceImpl extends ServiceImpl<ImageVirtualMac
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Result<?> delete(DeleteIdReq deleteIdReq) {
|
public Result<?> delete(DeleteIdReq deleteIdReq) {
|
||||||
|
// 先查询要删除的虚拟机信息
|
||||||
|
ImageVirtualMachines imageVirtualMachines = machinesMapper.selectById(deleteIdReq.getId());
|
||||||
|
if (ObjectUtils.isEmpty(imageVirtualMachines)) {
|
||||||
|
log.info("查询镜像虚拟机返回为空");
|
||||||
|
return Result.errorResult(BaseErrorCode.HTTP_ERROR_CODE_500, "虚拟机不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用镜像删除服务
|
||||||
|
ImageDeleteReq deleteReq = ImageDeleteReq.builder()
|
||||||
|
.vmName(imageVirtualMachines.getImageName())
|
||||||
|
.deleteStorage(true)
|
||||||
|
.build();
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||||
|
HttpEntity<ImageDeleteReq> requestEntity = new HttpEntity<>(deleteReq, headers);
|
||||||
|
ResponseEntity<ImageStatusRes> exchange = restTemplate.exchange(imageConfigProperties.getDeleteUrl(), HttpMethod.POST, requestEntity, ImageStatusRes.class);
|
||||||
|
if (!exchange.getStatusCode().equals(HttpStatus.OK)) {
|
||||||
|
return Result.errorResult(BaseErrorCode.HTTP_REQUEST_FAILURE, "删除虚拟机失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除数据库记录
|
||||||
int deleted = machinesMapper.deleteById(deleteIdReq.getId());
|
int deleted = machinesMapper.deleteById(deleteIdReq.getId());
|
||||||
log.info("终端删除delete:{}", deleted);
|
log.info("终端删除delete:{}", deleted);
|
||||||
if (deleted == 1) {
|
if (deleted == 1) {
|
||||||
|
|
@ -243,8 +271,150 @@ public class ImageVirtualMachinesServiceImpl extends ServiceImpl<ImageVirtualMac
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Result<?> cloneTemplate(ImageVirtualMachinesReq req) {
|
public Result<?> cloneTemplate(ImageVirtualMachinesReq req) {
|
||||||
//todo 调用镜像生成服务 在生成完毕后生成桌面镜像数据 桌面镜像加BT
|
// 查询虚拟机信息
|
||||||
return null;
|
ImageVirtualMachines imageVirtualMachines = machinesMapper.selectById(req.getId());
|
||||||
}
|
if (ObjectUtils.isEmpty(imageVirtualMachines)) {
|
||||||
|
log.info("查询镜像虚拟机返回为空");
|
||||||
|
return Result.errorResult(BaseErrorCode.HTTP_ERROR_CODE_500, "虚拟机不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用克隆虚拟机到桌面镜像服务
|
||||||
|
ImageCloneToDesktopReq cloneReq = ImageCloneToDesktopReq.builder()
|
||||||
|
.vmName(imageVirtualMachines.getImageName())
|
||||||
|
.desktopName(req.getImageName() + "_desktop") // 使用虚拟机名称加desktop作为桌面镜像名称
|
||||||
|
.storagePath("/vms/iso") // 默认存储路径
|
||||||
|
.description("从虚拟机克隆的桌面镜像")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||||
|
HttpEntity<ImageCloneToDesktopReq> requestEntity = new HttpEntity<>(cloneReq, headers);
|
||||||
|
String cloneToDesktopUrl = imageConfigProperties.getCloneToDesktopUrl();
|
||||||
|
ResponseEntity<ImageStatusRes> exchange = restTemplate.exchange(cloneToDesktopUrl, HttpMethod.POST, requestEntity, ImageStatusRes.class);
|
||||||
|
if (!exchange.getStatusCode().equals(HttpStatus.OK)) {
|
||||||
|
return Result.errorResult(BaseErrorCode.HTTP_REQUEST_FAILURE, "克隆虚拟机到桌面镜像失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 克隆成功后生成桌面镜像数据
|
||||||
|
ImageDesktop imageDesktop = new ImageDesktop();
|
||||||
|
imageDesktop.setDesktopName(req.getImageName() + "_desktop");
|
||||||
|
imageDesktop.setImageVirtualId(Math.toIntExact(req.getId()));
|
||||||
|
imageDesktop.setOsVersion(imageVirtualMachines.getOsVersion());
|
||||||
|
// imageDesktop.setStoragePath("/vms/iso/" + req.getImageName() + "_desktop.qcow2"); // 假设是qcow2格式
|
||||||
|
// imageDesktop.setDesktopType(3); // QCOW2格式
|
||||||
|
// imageDesktop.setPublishStatus("unpublished"); // 默认未发布状态
|
||||||
|
imageDesktop.setCreateUser("admin");
|
||||||
|
imageDesktop.setUpdateUser("admin");
|
||||||
|
imageDesktop.setDescription("从虚拟机克隆的桌面镜像");
|
||||||
|
|
||||||
|
// 保存桌面镜像数据
|
||||||
|
boolean saved = imageDesktopService.save(imageDesktop);
|
||||||
|
if (!saved) {
|
||||||
|
log.error("保存桌面镜像数据失败");
|
||||||
|
return Result.errorResult(BaseErrorCode.HTTP_ERROR_CODE_500, "保存桌面镜像数据失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.successResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result<?> start(ImageVirtualMachinesReq req) {
|
||||||
|
// 查询虚拟机信息
|
||||||
|
ImageVirtualMachines imageVirtualMachines = machinesMapper.selectById(req.getId());
|
||||||
|
if (ObjectUtils.isEmpty(imageVirtualMachines)) {
|
||||||
|
log.info("查询镜像虚拟机返回为空");
|
||||||
|
return Result.errorResult(BaseErrorCode.HTTP_ERROR_CODE_500, "虚拟机不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用启动虚拟机服务
|
||||||
|
ImageOperationReq operationReq = ImageOperationReq.builder()
|
||||||
|
.vmName(imageVirtualMachines.getImageName())
|
||||||
|
.build();
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||||
|
HttpEntity<ImageOperationReq> requestEntity = new HttpEntity<>(operationReq, headers);
|
||||||
|
ResponseEntity<ImageStatusRes> exchange = restTemplate.exchange(imageConfigProperties.getStartUrl(), HttpMethod.POST, requestEntity, ImageStatusRes.class);
|
||||||
|
if (!exchange.getStatusCode().equals(HttpStatus.OK)) {
|
||||||
|
return Result.errorResult(BaseErrorCode.HTTP_REQUEST_FAILURE, "启动虚拟机失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.successResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result<?> shutdown(ImageVirtualMachinesReq req) {
|
||||||
|
// 查询虚拟机信息
|
||||||
|
ImageVirtualMachines imageVirtualMachines = machinesMapper.selectById(req.getId());
|
||||||
|
if (ObjectUtils.isEmpty(imageVirtualMachines)) {
|
||||||
|
log.info("查询镜像虚拟机返回为空");
|
||||||
|
return Result.errorResult(BaseErrorCode.HTTP_ERROR_CODE_500, "虚拟机不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用关闭虚拟机服务
|
||||||
|
ImageOperationReq operationReq = ImageOperationReq.builder()
|
||||||
|
.vmName(imageVirtualMachines.getImageName())
|
||||||
|
.build();
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||||
|
HttpEntity<ImageOperationReq> requestEntity = new HttpEntity<>(operationReq, headers);
|
||||||
|
String shutdownUrl = imageConfigProperties.getShutdownUrl();
|
||||||
|
ResponseEntity<ImageStatusRes> exchange = restTemplate.exchange(shutdownUrl, HttpMethod.POST, requestEntity, ImageStatusRes.class);
|
||||||
|
if (!exchange.getStatusCode().equals(HttpStatus.OK)) {
|
||||||
|
return Result.errorResult(BaseErrorCode.HTTP_REQUEST_FAILURE, "关闭虚拟机失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.successResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result<?> destroy(ImageVirtualMachinesReq req) {
|
||||||
|
// 查询虚拟机信息
|
||||||
|
ImageVirtualMachines imageVirtualMachines = machinesMapper.selectById(req.getId());
|
||||||
|
if (ObjectUtils.isEmpty(imageVirtualMachines)) {
|
||||||
|
log.info("查询镜像虚拟机返回为空");
|
||||||
|
return Result.errorResult(BaseErrorCode.HTTP_ERROR_CODE_500, "虚拟机不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用强制关闭虚拟机服务
|
||||||
|
ImageOperationReq operationReq = ImageOperationReq.builder()
|
||||||
|
.vmName(imageVirtualMachines.getImageName())
|
||||||
|
.build();
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||||
|
HttpEntity<ImageOperationReq> requestEntity = new HttpEntity<>(operationReq, headers);
|
||||||
|
String destroyUrl = imageConfigProperties.getDestroyUrl();
|
||||||
|
ResponseEntity<ImageStatusRes> exchange = restTemplate.exchange(destroyUrl, HttpMethod.POST, requestEntity, ImageStatusRes.class);
|
||||||
|
if (!exchange.getStatusCode().equals(HttpStatus.OK)) {
|
||||||
|
return Result.errorResult(BaseErrorCode.HTTP_REQUEST_FAILURE, "强制关闭虚拟机失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.successResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result<?> reboot(ImageVirtualMachinesReq req) {
|
||||||
|
// 查询虚拟机信息
|
||||||
|
ImageVirtualMachines imageVirtualMachines = machinesMapper.selectById(req.getId());
|
||||||
|
if (ObjectUtils.isEmpty(imageVirtualMachines)) {
|
||||||
|
log.info("查询镜像虚拟机返回为空");
|
||||||
|
return Result.errorResult(BaseErrorCode.HTTP_ERROR_CODE_500, "虚拟机不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用重启虚拟机服务
|
||||||
|
ImageOperationReq operationReq = ImageOperationReq.builder()
|
||||||
|
.vmName(imageVirtualMachines.getImageName())
|
||||||
|
.build();
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||||
|
HttpEntity<ImageOperationReq> requestEntity = new HttpEntity<>(operationReq, headers);
|
||||||
|
String rebootUrl = imageConfigProperties.getRebootUrl();
|
||||||
|
ResponseEntity<ImageStatusRes> exchange = restTemplate.exchange(rebootUrl, HttpMethod.POST, requestEntity, ImageStatusRes.class);
|
||||||
|
if (!exchange.getStatusCode().equals(HttpStatus.OK)) {
|
||||||
|
return Result.errorResult(BaseErrorCode.HTTP_REQUEST_FAILURE, "重启虚拟机失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.successResult();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,12 @@ image:
|
||||||
delete-url: /api/v1/vm/delete
|
delete-url: /api/v1/vm/delete
|
||||||
update-url: /api/v1/vm/update
|
update-url: /api/v1/vm/update
|
||||||
start-url: /api/v1/vm/start
|
start-url: /api/v1/vm/start
|
||||||
|
shutdown-url: /api/v1/vm/shutdown
|
||||||
|
destroy-url: /api/v1/vm/destroy
|
||||||
|
reboot-url: /api/v1/vm/reboot
|
||||||
|
pause-url: /api/v1/vm/pause
|
||||||
|
resume-url: /api/v1/vm/resume
|
||||||
|
clone-to-desktop-url: /api/v1/vm/clone-to-desktop
|
||||||
spring:
|
spring:
|
||||||
servlet:
|
servlet:
|
||||||
multipart:
|
multipart:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue