feat(virtual-machines): 添加虚拟机操作相关接口和功能

- 新增了虚拟机启动、关闭、强制关闭、重启等操作的接口和实现
- 增加了克隆虚拟机到桌面镜像的功能
- 更新了虚拟机删除逻辑,支持删除存储的镜像文件
- 重构了部分代码,优化了虚拟机相关数据的处理
master
chenhao 2025-09-02 09:56:51 +08:00
parent 4b7772b38d
commit 0292dcb065
9 changed files with 332 additions and 26 deletions

View File

@ -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) {

View File

@ -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);
} }
} }

View File

@ -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;
}
} }

View File

@ -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);
} }

View File

@ -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);
} }

View File

@ -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://")) {

View File

@ -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")));

View File

@ -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();
}
} }

View File

@ -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: