diff --git a/nex-be/src/main/java/com/unisinsight/project/controller/FileChunkController.java b/nex-be/src/main/java/com/unisinsight/project/controller/FileChunkController.java index 88b1b07..25b2bfa 100644 --- a/nex-be/src/main/java/com/unisinsight/project/controller/FileChunkController.java +++ b/nex-be/src/main/java/com/unisinsight/project/controller/FileChunkController.java @@ -177,35 +177,35 @@ public class FileChunkController { log.info("镜像新增insert:{}", save); if (save) { - // 异步执行创建和做种操作 - CompletableFuture.runAsync(() -> { - try { - String url = btUrl + "/vdi/start?sourceFile=%s&torrentFile=%s"; - url = String.format(url, finalFilePath, finalFilePath + ".torrent"); - log.info("请求bt创建接口参数: {}", url); - ResponseEntity responseEntity = restTemplate.exchange(url, HttpMethod.GET, null, Boolean.class); - log.info("请求bt创建接口返回: {}", JSONUtil.toJsonStr(responseEntity)); - HttpStatus statusCode = responseEntity.getStatusCode(); - if (statusCode == HttpStatus.OK) { - boolean result = Boolean.TRUE.equals(responseEntity.getBody()); - if (result) { - log.info("请求bt创建接口成功"); - LambdaQueryWrapper imageQueryWrapper = new LambdaQueryWrapper<>(); - imageQueryWrapper.eq(Image::getImageFileName, fileName); - Image imageBt = imageService.getOne(imageQueryWrapper); - if (ObjectUtils.isNotEmpty(imageBt)) { - imageBt.setBtPath(finalFilePath + ".torrent"); - boolean update = imageService.updateById(imageBt); - log.info("镜像bt更新insert:{}", update); - } else { - log.info("镜像bt更新查询失败:{}", fileName); - } - } - } - } catch (Exception e) { - log.error("请求bt创建接口失败: {}", e.getMessage(), e); - } - }); + //DEPRECATED bt种子移动到镜像虚拟机克隆 异步执行创建和做种操作 +// CompletableFuture.runAsync(() -> { +// try { +// String url = btUrl + "/vdi/start?sourceFile=%s&torrentFile=%s"; +// url = String.format(url, finalFilePath, finalFilePath + ".torrent"); +// log.info("请求bt创建接口参数: {}", url); +// ResponseEntity responseEntity = restTemplate.exchange(url, HttpMethod.GET, null, Boolean.class); +// log.info("请求bt创建接口返回: {}", JSONUtil.toJsonStr(responseEntity)); +// HttpStatus statusCode = responseEntity.getStatusCode(); +// if (statusCode == HttpStatus.OK) { +// boolean result = Boolean.TRUE.equals(responseEntity.getBody()); +// if (result) { +// log.info("请求bt创建接口成功"); +// LambdaQueryWrapper imageQueryWrapper = new LambdaQueryWrapper<>(); +// imageQueryWrapper.eq(Image::getImageFileName, fileName); +// Image imageBt = imageService.getOne(imageQueryWrapper); +// if (ObjectUtils.isNotEmpty(imageBt)) { +// imageBt.setBtPath(finalFilePath + ".torrent"); +// boolean update = imageService.updateById(imageBt); +// log.info("镜像bt更新insert:{}", update); +// } else { +// log.info("镜像bt更新查询失败:{}", fileName); +// } +// } +// } +// } catch (Exception e) { +// log.error("请求bt创建接口失败: {}", e.getMessage(), e); +// } +// }); response.put("status", "completed"); response.put("message", "文件上传并合并完成"); response.put("filePath", finalFilePath.toString()); diff --git a/nex-be/src/main/java/com/unisinsight/project/controller/ImageVirtualMachinesController.java b/nex-be/src/main/java/com/unisinsight/project/controller/ImageVirtualMachinesController.java new file mode 100644 index 0000000..2ae7150 --- /dev/null +++ b/nex-be/src/main/java/com/unisinsight/project/controller/ImageVirtualMachinesController.java @@ -0,0 +1,104 @@ +package com.unisinsight.project.controller; + + +import cn.hutool.json.JSONUtil; +import com.unisinsight.project.entity.req.DeleteIdReq; +import com.unisinsight.project.entity.req.ImageVirtualMachinesReq; +import com.unisinsight.project.entity.res.ImageVirtualMachinesRes; +import com.unisinsight.project.entity.res.PageResult; +import com.unisinsight.project.exception.BaseErrorCode; +import com.unisinsight.project.exception.Result; +import com.unisinsight.project.service.ImageVirtualMachinesService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.util.Objects; + +/** + * 镜像虚拟机(ImageVirtualMachines)表控制层 + * + * @author ch + * @since 2025-08-22 09:42:41 + */ +@RestController +@RequestMapping("/api/nex/v1/image/virtual/machines") +@Slf4j +@Api(tags = "镜像虚拟机类") +public class ImageVirtualMachinesController { + /** + * 服务对象 + */ + @Resource + private ImageVirtualMachinesService service; + + /** + * 分页查询所有数据 + * + * + * @param imageVirtualMachinesReq 查询实体 + * @return 所有数据 + */ + @ApiOperation(value = "分页查询镜像") + @PostMapping("/select/page") + public Result> selectPage(@RequestBody ImageVirtualMachinesReq imageVirtualMachinesReq) { + if (Objects.isNull(imageVirtualMachinesReq)) { + return Result.errorResult(BaseErrorCode.PARAMS_CHK_ERROR); + } + log.info("分页查询镜像请求参数为:{}", JSONUtil.toJsonStr(imageVirtualMachinesReq)); + return service.selectPage(imageVirtualMachinesReq); + } + @ApiOperation(value = "新增") + @PostMapping("/add") + public Result insertImageVirtualMachines(@RequestBody ImageVirtualMachinesReq imageVirtualMachinesReq) { + if (Objects.isNull(imageVirtualMachinesReq)) { + return Result.errorResult(BaseErrorCode.PARAMS_CHK_ERROR); + } + log.info("镜像虚拟机新增请求参数为:{}", JSONUtil.toJsonStr(imageVirtualMachinesReq)); + return service.insert(imageVirtualMachinesReq); + } + @ApiOperation(value = "镜像虚拟机修改") + @PostMapping("/update") + public Result updateUser(@RequestBody ImageVirtualMachinesReq imageVirtualMachinesReq) { + if (Objects.isNull(imageVirtualMachinesReq)) { + return Result.errorResult(BaseErrorCode.PARAMS_CHK_ERROR); + } + log.info("镜像虚拟机修改请求参数为:{}", JSONUtil.toJsonStr(imageVirtualMachinesReq)); + return service.update(imageVirtualMachinesReq); + } + @ApiOperation(value = "镜像虚拟机查询") + @PostMapping("/query") + public Result queryUser(@RequestBody ImageVirtualMachinesReq imageVirtualMachinesReq) { + if (Objects.isNull(imageVirtualMachinesReq)) { + return Result.errorResult(BaseErrorCode.PARAMS_CHK_ERROR); + } + log.info("镜像虚拟机查询请求参数为:{}", JSONUtil.toJsonStr(imageVirtualMachinesReq)); + return service.query(imageVirtualMachinesReq); + } + + @ApiOperation(value = "终端删除") + @PostMapping("/delete") + public Result delete(@RequestBody DeleteIdReq deleteIdReq) { + if (Objects.isNull(deleteIdReq)) { + return Result.errorResult(BaseErrorCode.PARAMS_CHK_ERROR); + } + log.info("镜像虚拟机删除请求参数为:{}", JSONUtil.toJsonStr(deleteIdReq)); + return service.delete(deleteIdReq); + } + @ApiOperation(value = "终端删除") + @PostMapping("/clone/template") + public Result cloneTemplate(@RequestBody ImageVirtualMachinesReq req) { + if (Objects.isNull(req)) { + return Result.errorResult(BaseErrorCode.PARAMS_CHK_ERROR); + } + log.info("镜像虚拟机克隆为模板请求参数为:{}", JSONUtil.toJsonStr(req)); + return service.cloneTemplate(req); + } + +} + diff --git a/nex-be/src/main/java/com/unisinsight/project/entity/dao/ImageVirtualMachines.java b/nex-be/src/main/java/com/unisinsight/project/entity/dao/ImageVirtualMachines.java new file mode 100644 index 0000000..e08fe3b --- /dev/null +++ b/nex-be/src/main/java/com/unisinsight/project/entity/dao/ImageVirtualMachines.java @@ -0,0 +1,126 @@ +package com.unisinsight.project.entity.dao; + + +import com.baomidou.mybatisplus.annotation.*; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + + +/** + * 镜像虚拟机(ImageVirtualMachines)表实体类 + * + * @author ch + * @since 2025-08-25 11:42:50 + */ +@TableName(value = "image_virtual_machines") +@Data +@ApiModel("镜像虚拟机") +public class ImageVirtualMachines extends Model { + /** + * ID + **/ + @TableId(value = "id", type = IdType.AUTO) + @ApiModelProperty("ID") + private Long id; + /** + * 镜像名称 + **/ + @TableField(value = "image_name") + @ApiModelProperty("镜像名称") + private String imageName; + /** + * 镜像状态: + **/ + @TableField(value = "image_status") + @ApiModelProperty("镜像状态") + private String imageStatus; + /** + * 系统镜像Id + **/ + @TableField(value = "image_system_id") + @ApiModelProperty("系统镜像Id") + private Long imageSystemId; + /** + * 操作系统 + **/ + @TableField(value = "os_version") + @ApiModelProperty("操作系统") + private String osVersion; + /** + * 镜像存储路径 + **/ + @TableField(value = "storage_path") + @ApiModelProperty("镜像存储路径") + private String storagePath; + /** + * 创建时间 + **/ + @TableField(value = "create_time", fill = FieldFill.INSERT) + @ApiModelProperty("创建时间") + private String createTime; + /** + * 创建人 + **/ + @TableField(value = "create_user") + @ApiModelProperty("创建人") + private String createUser; + /** + * 更新时间 + **/ + @TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE) + @ApiModelProperty("更新时间") + private String updateTime; + /** + * 更新人 + **/ + @TableField(value = "update_user") + @ApiModelProperty("更新人") + private String updateUser; + /** + * 是否删除:0-否,1-删除 + **/ + @TableLogic + @TableField(value = "deleted") + @ApiModelProperty("是否删除:0-否,1-删除") + private Integer deleted; + /** + * 描述 + **/ + @TableField(value = "description") + @ApiModelProperty("描述") + private String description; + /** + * cpu数量 + **/ + @TableField(value = "cpu_total") + @ApiModelProperty("cpu数量") + private Integer cpuTotal; + /** + * cpu核数量 + **/ + @TableField(value = "cpu_core_total") + @ApiModelProperty("cpu核数量") + private Integer cpuCoreTotal; + /** + * 内存大小(GB) + **/ + @TableField(value = "memory_total") + @ApiModelProperty("内存大小(GB)") + private Integer memoryTotal; + /** + * 系统盘大小(GB) + **/ + @TableField(value = "system_total") + @ApiModelProperty("系统盘大小(GB)") + private Integer systemTotal; + /** + * 网络模块 + **/ + @TableField(value = "network_module") + @ApiModelProperty("网络模块") + private String networkModule; + +} + diff --git a/nex-be/src/main/java/com/unisinsight/project/entity/req/ImageCreateReq.java b/nex-be/src/main/java/com/unisinsight/project/entity/req/ImageCreateReq.java new file mode 100644 index 0000000..7f03482 --- /dev/null +++ b/nex-be/src/main/java/com/unisinsight/project/entity/req/ImageCreateReq.java @@ -0,0 +1,54 @@ +package com.unisinsight.project.entity.req; + + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author : ch + * @version : 1.0 + * @ClassName : ImageCreateReq + * @Description : + * @DATE : Created in 15:49 2025/8/25 + *
       Copyright: Copyright(c) 2025     
+ *
       Company :   	紫光汇智信息技术有限公司		           
+ * Modification History: + * Date Author Version Discription + * -------------------------------------------------------------------------- + * 2025/08/25 ch 1.0 Why & What is modified: <修改原因描述> * + */ +@Data +@Builder +public class ImageCreateReq { + + @JsonProperty("name") + private String name; + @JsonProperty("os_type") + private String osType; + @JsonProperty("os_variant") + private String osVariant; + @JsonProperty("vcpus") + private Integer vcpus; + @JsonProperty("memory") + private Integer memory; + @JsonProperty("disk_size") + private Integer diskSize; + @JsonProperty("disk_format") + private String diskFormat; + @JsonProperty("storage_pool") + private String storagePool; + @JsonProperty("network_name") + private String networkName; + @JsonProperty("iso_path") + private String isoPath; + @JsonProperty("auto_mount_virtio") + private Boolean autoMountVirtio; + @JsonProperty("virtio_win_path") + private String virtioWinPath; + @JsonProperty("autostart") + private Boolean autostart; + @JsonProperty("description") + private String description; +} diff --git a/nex-be/src/main/java/com/unisinsight/project/entity/req/ImageUpdateReq.java b/nex-be/src/main/java/com/unisinsight/project/entity/req/ImageUpdateReq.java new file mode 100644 index 0000000..f997698 --- /dev/null +++ b/nex-be/src/main/java/com/unisinsight/project/entity/req/ImageUpdateReq.java @@ -0,0 +1,43 @@ +package com.unisinsight.project.entity.req; + + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author : ch + * @version : 1.0 + * @ClassName : ImageUpdateReq + * @Description : + * @DATE : Created in 16:14 2025/8/25 + *
       Copyright: Copyright(c) 2025     
+ *
       Company :   	紫光汇智信息技术有限公司		           
+ * Modification History: + * Date Author Version Discription + * -------------------------------------------------------------------------- + * 2025/08/25 ch 1.0 Why & What is modified: <修改原因描述> * + */ + +@Data +@Builder +public class ImageUpdateReq { + + @JsonProperty("vm_name") + private String vmName; + @JsonProperty("vcpus") + private Integer vcpus; + @JsonProperty("memory") + private Integer memory; + @JsonProperty("network_name") + private String networkName; + @JsonProperty("autostart") + private Boolean autostart; + @JsonProperty("auto_mount_virtio") + private Boolean autoMountVirtio; + @JsonProperty("virtio_win_path") + private String virtioWinPath; + @JsonProperty("description") + private String description; +} diff --git a/nex-be/src/main/java/com/unisinsight/project/entity/req/ImageVirtualMachinesReq.java b/nex-be/src/main/java/com/unisinsight/project/entity/req/ImageVirtualMachinesReq.java new file mode 100644 index 0000000..3afa0e9 --- /dev/null +++ b/nex-be/src/main/java/com/unisinsight/project/entity/req/ImageVirtualMachinesReq.java @@ -0,0 +1,135 @@ +package com.unisinsight.project.entity.req; + + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * 镜像虚拟机(ImageVirtualMachines)表实体类 + * + * @author ch + * @since 2025-08-25 11:42:52 + */ +@Data +@ApiModel("镜像虚拟机") +public class ImageVirtualMachinesReq { + /** + * ID + **/ + @JsonProperty("id") + @ApiModelProperty("ID") + private Long id; + /** + * 镜像名称 + **/ + @JsonProperty("image_name") + @ApiModelProperty("镜像名称") + private String imageName; + /** + * 镜像状态: 1-成功,2-失败 + **/ + @JsonProperty("image_status") + @ApiModelProperty("镜像状态") + private String imageStatus; + /** + * 系统镜像Id + **/ + @JsonProperty("image_system_id") + @ApiModelProperty("系统镜像Id") + private Long imageSystemId; + /** + * 操作系统 + **/ + @JsonProperty("os_version") + @ApiModelProperty("操作系统") + private String osVersion; + /** + * 镜像存储路径 + **/ + @JsonProperty("storage_path") + @ApiModelProperty("镜像存储路径") + private String storagePath; + /** + * 创建时间 + **/ + @JsonProperty("create_time") + @ApiModelProperty("创建时间") + private String createTime; + /** + * 创建人 + **/ + @JsonProperty("create_user") + @ApiModelProperty("创建人") + private String createUser; + /** + * 更新时间 + **/ + @JsonProperty("update_time") + @ApiModelProperty("更新时间") + private String updateTime; + /** + * 更新人 + **/ + @JsonProperty("update_user") + @ApiModelProperty("更新人") + private String updateUser; + /** + * 是否删除:0-否,1-删除 + **/ + @JsonProperty("deleted") + @ApiModelProperty("是否删除:0-否,1-删除") + private Integer deleted; + /** + * 描述 + **/ + @JsonProperty("description") + @ApiModelProperty("描述") + private String description; + /** + * cpu数量 + **/ + @JsonProperty("cpu_total") + @ApiModelProperty("cpu数量") + private Integer cpuTotal; + /** + * cpu核数量 + **/ + @JsonProperty("cpu_core_total") + @ApiModelProperty("cpu核数量") + private Integer cpuCoreTotal; + /** + * 内存大小(GB) + **/ + @JsonProperty("memory_total") + @ApiModelProperty("内存大小(GB)") + private Integer memoryTotal; + /** + * 系统盘大小(GB) + **/ + @JsonProperty("system_total") + @ApiModelProperty("系统盘大小(GB)") + private Integer systemTotal; + /** + * 网络模块 + **/ + @JsonProperty("network_module") + @ApiModelProperty("网络模块") + private String networkModule; + /** + * 查询页 + */ + @ApiModelProperty(value = "查询页", notes = "分页查询时再传") + @JsonProperty("page_num") + private Integer pageNum; + + + /** + * 每页数量 + */ + @ApiModelProperty(value = "每页数量", notes = "分页查询时再传") + @JsonProperty("page_size") + private Integer pageSize; +} + diff --git a/nex-be/src/main/java/com/unisinsight/project/entity/res/DeviceRes.java b/nex-be/src/main/java/com/unisinsight/project/entity/res/DeviceRes.java index aded557..96ebab6 100644 --- a/nex-be/src/main/java/com/unisinsight/project/entity/res/DeviceRes.java +++ b/nex-be/src/main/java/com/unisinsight/project/entity/res/DeviceRes.java @@ -1,6 +1,7 @@ package com.unisinsight.project.entity.res; +import com.baomidou.mybatisplus.annotation.TableField; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; @@ -84,4 +85,10 @@ public class DeviceRes implements Serializable { @ApiModelProperty("描述") @JsonProperty("description") private String description; + /** + * 设备状态 0:离线 1:在线 + */ + @ApiModelProperty("设备状态") + @JsonProperty("device_status") + private Integer deviceStatus; } diff --git a/nex-be/src/main/java/com/unisinsight/project/entity/res/ImageStatusRes.java b/nex-be/src/main/java/com/unisinsight/project/entity/res/ImageStatusRes.java new file mode 100644 index 0000000..4d0b108 --- /dev/null +++ b/nex-be/src/main/java/com/unisinsight/project/entity/res/ImageStatusRes.java @@ -0,0 +1,128 @@ +package com.unisinsight.project.entity.res; + + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * @author : ch + * @version : 1.0 + * @ClassName : ImageStatusRes + * @Description : + * @DATE : Created in 14:34 2025/8/25 + *
       Copyright: Copyright(c) 2025     
+ *
       Company :   	紫光汇智信息技术有限公司		           
+ * Modification History: + * Date Author Version Discription + * -------------------------------------------------------------------------- + * 2025/08/25 ch 1.0 Why & What is modified: <修改原因描述> * + */ +@NoArgsConstructor +@Data +public class ImageStatusRes { + + @JsonProperty("code") + private String code; + @JsonProperty("message") + private String message; + @JsonProperty("data") + private DataDTO data; + + @NoArgsConstructor + @Data + public static class DataDTO { + @JsonProperty("items") + private List items; + @JsonProperty("total") + private Integer total; + @JsonProperty("page") + private Integer page; + @JsonProperty("page_size") + private Integer pageSize; + @JsonProperty("total_pages") + private Integer totalPages; + @JsonProperty("not_found") + private List notFound; + + @NoArgsConstructor + @Data + public static class ItemsDTO { + @JsonProperty("name") + private String name; + @JsonProperty("uuid") + private String uuid; + @JsonProperty("id") + private Integer id; + @JsonProperty("state") + private String state; + @JsonProperty("vcpus") + private Integer vcpus; + @JsonProperty("memory") + private Integer memory; + @JsonProperty("memory_mb") + private Integer memoryMb; + @JsonProperty("autostart") + private Integer autostart; + @JsonProperty("persistent") + private Integer persistent; + @JsonProperty("os_type") + private String osType; + @JsonProperty("os_variant") + private String osVariant; + @JsonProperty("created_at") + private String createdAt; + @JsonProperty("disks") + private List disks; + @JsonProperty("disk_size") + private Double diskSize; + @JsonProperty("network_interfaces") + private List networkInterfaces; + @JsonProperty("vnc") + private VncDTO vnc; + @JsonProperty("auto_mount_virtio") + private Boolean autoMountVirtio; + @JsonProperty("virtio_win_path") + private String virtioWinPath; + @JsonProperty("iso_path") + private String isoPath; + @JsonProperty("interfaces") + private List interfaces; + @JsonProperty("ip_address") + private Object ipAddress; + + @NoArgsConstructor + @Data + public static class VncDTO { + @JsonProperty("port") + private String port; + @JsonProperty("autoport") + private Boolean autoport; + @JsonProperty("listen") + private String listen; + } + + @NoArgsConstructor + @Data + public static class DisksDTO { + @JsonProperty("device") + private String device; + @JsonProperty("file") + private String file; + @JsonProperty("bus") + private String bus; + } + + @NoArgsConstructor + @Data + public static class NetworkInterfacesDTO { + @JsonProperty("mac") + private String mac; + @JsonProperty("network") + private String network; + } + } + } +} diff --git a/nex-be/src/main/java/com/unisinsight/project/entity/res/ImageVirtualMachinesRes.java b/nex-be/src/main/java/com/unisinsight/project/entity/res/ImageVirtualMachinesRes.java new file mode 100644 index 0000000..60ab93e --- /dev/null +++ b/nex-be/src/main/java/com/unisinsight/project/entity/res/ImageVirtualMachinesRes.java @@ -0,0 +1,133 @@ +package com.unisinsight.project.entity.res; + + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; + +/** + * 镜像虚拟机(ImageVirtualMachines)表实体类 + * + * @author ch + * @since 2025-08-25 11:42:57 + */ +@Data +@ApiModel("镜像虚拟机") +public class ImageVirtualMachinesRes implements Serializable { + /** + * ID + **/ + @JsonProperty("id") + @ApiModelProperty("ID") + private Long id; + /** + * 镜像名称 + **/ + @JsonProperty("image_name") + @ApiModelProperty("镜像名称") + private String imageName; + /** + * 镜像状态: 根据接口返回 + **/ + @JsonProperty("image_status") + @ApiModelProperty("镜像状态: 根据接口返回") + private String imageStatus; + /** + * 系统镜像Id + **/ + @JsonProperty("image_system_id") + @ApiModelProperty("系统镜像Id") + private Long imageSystemId; + /** + * 系统镜像Id + **/ + @JsonProperty("image_system_name") + @ApiModelProperty("系统镜像名称") + private String imageSystemName; + /** + * 操作系统 + **/ + @JsonProperty("os_version") + @ApiModelProperty("操作系统") + private String osVersion; + /** + * 镜像存储路径 + **/ + @JsonProperty("storage_path") + @ApiModelProperty("镜像存储路径") + private String storagePath; + /** + * 创建时间 + **/ + @JsonProperty("create_time") + @ApiModelProperty("创建时间") + private String createTime; + /** + * 创建人 + **/ + @JsonProperty("create_user") + @ApiModelProperty("创建人") + private String createUser; + /** + * 更新时间 + **/ + @JsonProperty("update_time") + @ApiModelProperty("更新时间") + private String updateTime; + /** + * 更新人 + **/ + @JsonProperty("update_user") + @ApiModelProperty("更新人") + private String updateUser; + /** + * 是否删除:0-否,1-删除 + **/ + @JsonProperty("deleted") + @ApiModelProperty("是否删除:0-否,1-删除") + private Integer deleted; + /** + * 描述 + **/ + @JsonProperty("description") + @ApiModelProperty("描述") + private String description; + /** + * cpu数量 + **/ + @JsonProperty("cpu_total") + @ApiModelProperty("cpu数量") + private Integer cpuTotal; + /** + * cpu核数量 + **/ + @JsonProperty("cpu_core_total") + @ApiModelProperty("cpu核数量") + private Integer cpuCoreTotal; + /** + * 内存大小(GB) + **/ + @JsonProperty("memory_total") + @ApiModelProperty("内存大小(GB)") + private Integer memoryTotal; + /** + * 系统盘大小(GB) + **/ + @JsonProperty("system_total") + @ApiModelProperty("系统盘大小(GB)") + private Integer systemTotal; + /** + * 网络模块 + **/ + @JsonProperty("network_module") + @ApiModelProperty("网络模块") + private String networkModule; + @JsonProperty("vnc_data") + @ApiModelProperty("远程连接信息") + private ImageStatusRes.DataDTO.ItemsDTO.VncDTO vncData; + +} + diff --git a/nex-be/src/main/java/com/unisinsight/project/mapper/ImageVirtualMachinesMapper.java b/nex-be/src/main/java/com/unisinsight/project/mapper/ImageVirtualMachinesMapper.java new file mode 100644 index 0000000..bc0f144 --- /dev/null +++ b/nex-be/src/main/java/com/unisinsight/project/mapper/ImageVirtualMachinesMapper.java @@ -0,0 +1,18 @@ +package com.unisinsight.project.mapper; + +import java.util.List; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Param; +import com.unisinsight.project.entity.dao.ImageVirtualMachines; + +/** + * 镜像虚拟机(ImageVirtualMachines)表数据库访问层 + * + * @author ch + * @since 2025-08-25 11:42:53 + */ +public interface ImageVirtualMachinesMapper extends BaseMapper { + +} + diff --git a/nex-be/src/main/java/com/unisinsight/project/properties/ImageConfigProperties.java b/nex-be/src/main/java/com/unisinsight/project/properties/ImageConfigProperties.java new file mode 100644 index 0000000..5b5434b --- /dev/null +++ b/nex-be/src/main/java/com/unisinsight/project/properties/ImageConfigProperties.java @@ -0,0 +1,68 @@ +package com.unisinsight.project.properties; + +import lombok.AccessLevel; +import lombok.Data; +import lombok.Getter; +import lombok.Setter; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * @author : ch + * @version : 1.0 + * @ClassName : ImageConfigProperties + * @Description : 镜像服务配置属性类 + * @DATE : Created in 15:52 2025/8/25 + *
       Copyright: Copyright(c) 2025     
+ *
       Company :   	紫光汇智信息技术有限公司		           
+ * Modification History: + * Date Author Version Discription + * -------------------------------------------------------------------------- + * 2025/08/25 ch 1.0 Why & What is modified: <修改原因描述> * + */ +@Component +@ConfigurationProperties(prefix = "image") +@Data +public class ImageConfigProperties { + + /** + * 镜像服务基础URL + */ + private String baseUrl; + + /** + * 状态查询URL + */ + @Getter(value=AccessLevel.NONE) + private String statusUrl; + @Getter(value=AccessLevel.NONE) + private String createUrl; + @Getter(value=AccessLevel.NONE) + private String deleteUrl; + @Getter(value=AccessLevel.NONE) + private String updateUrl; + @Getter(value=AccessLevel.NONE) + private String startUrl; + + + + public String getStatusUrl() { + return baseUrl+statusUrl; + } + + public String getCreateUrl() { + return baseUrl+createUrl; + } + + public String getDeleteUrl() { + return baseUrl+deleteUrl; + } + + public String getUpdateUrl() { + return baseUrl+updateUrl; + } + + public String getStartUrl() { + return baseUrl+startUrl; + } +} diff --git a/nex-be/src/main/java/com/unisinsight/project/service/ImageVirtualMachinesService.java b/nex-be/src/main/java/com/unisinsight/project/service/ImageVirtualMachinesService.java new file mode 100644 index 0000000..a501160 --- /dev/null +++ b/nex-be/src/main/java/com/unisinsight/project/service/ImageVirtualMachinesService.java @@ -0,0 +1,31 @@ +package com.unisinsight.project.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.unisinsight.project.entity.dao.ImageVirtualMachines; +import com.unisinsight.project.entity.req.DeleteIdReq; +import com.unisinsight.project.entity.req.ImageVirtualMachinesReq; +import com.unisinsight.project.entity.res.ImageVirtualMachinesRes; +import com.unisinsight.project.entity.res.PageResult; +import com.unisinsight.project.exception.Result; + +/** + * 镜像虚拟机(ImageVirtualMachines)表服务接口 + * + * @author ch + * @since 2025-08-22 09:42:41 + */ +public interface ImageVirtualMachinesService extends IService { + + Result> selectPage(ImageVirtualMachinesReq imageVirtualMachinesReq); + + Result insert(ImageVirtualMachinesReq imageVirtualMachinesReq); + + Result update(ImageVirtualMachinesReq imageVirtualMachinesReq); + + Result query(ImageVirtualMachinesReq imageVirtualMachinesReq); + + Result delete(DeleteIdReq deleteIdReq); + + Result cloneTemplate(ImageVirtualMachinesReq req); +} + diff --git a/nex-be/src/main/java/com/unisinsight/project/service/impl/ImageVirtualMachinesServiceImpl.java b/nex-be/src/main/java/com/unisinsight/project/service/impl/ImageVirtualMachinesServiceImpl.java new file mode 100644 index 0000000..a844a52 --- /dev/null +++ b/nex-be/src/main/java/com/unisinsight/project/service/impl/ImageVirtualMachinesServiceImpl.java @@ -0,0 +1,237 @@ +package com.unisinsight.project.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.unisinsight.project.entity.dao.Image; +import com.unisinsight.project.entity.dao.ImageVirtualMachines; +import com.unisinsight.project.entity.req.DeleteIdReq; +import com.unisinsight.project.entity.req.ImageCreateReq; +import com.unisinsight.project.entity.req.ImageUpdateReq; +import com.unisinsight.project.entity.req.ImageVirtualMachinesReq; +import com.unisinsight.project.entity.res.ImageStatusRes; +import com.unisinsight.project.entity.res.ImageVirtualMachinesRes; +import com.unisinsight.project.entity.res.PageResult; +import com.unisinsight.project.exception.BaseErrorCode; +import com.unisinsight.project.exception.Result; +import com.unisinsight.project.mapper.ImageVirtualMachinesMapper; +import com.unisinsight.project.properties.ImageConfigProperties; +import com.unisinsight.project.service.ImageService; +import com.unisinsight.project.service.ImageVirtualMachinesService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.*; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +import javax.annotation.Resource; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 镜像虚拟机(ImageVirtualMachines)表服务实现类 + * + * @author ch + * @since 2025-08-22 09:42:41 + */ +@Service("imageVirtualMachinesService") +@Slf4j +public class ImageVirtualMachinesServiceImpl extends ServiceImpl implements ImageVirtualMachinesService { + @Resource + private ImageVirtualMachinesMapper machinesMapper; + @Autowired + private ImageService imageService; + @Resource + private RestTemplate restTemplate; + @Autowired + private ImageConfigProperties imageConfigProperties; + + + + @Override + public Result> selectPage(ImageVirtualMachinesReq imageVirtualMachinesReq) { + Page page = new Page<>(imageVirtualMachinesReq.getPageNum(), imageVirtualMachinesReq.getPageSize()); + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.like(StringUtils.isNotBlank(imageVirtualMachinesReq.getImageName()), ImageVirtualMachines::getImageName, imageVirtualMachinesReq.getImageName()); + queryWrapper.orderByAsc(ImageVirtualMachines::getId); + Page imageVirtualMachinesPage = machinesMapper.selectPage(page, queryWrapper); + log.info("分页查询镜像返回:{}", JSONUtil.toJsonStr(imageVirtualMachinesPage)); + if (CollectionUtil.isEmpty(imageVirtualMachinesPage.getRecords())) { + log.info("分页查询镜像返回为空"); + return Result.successResult(); + } else { + PageResult convert = PageResult.convertIPage(imageVirtualMachinesPage, ImageVirtualMachinesRes.class); + List data = convert.getData(); + List imageIdList = imageVirtualMachinesPage.getRecords().stream().map(ImageVirtualMachines::getImageSystemId).filter(Objects::nonNull).distinct().collect(Collectors.toList()); + Map imageMap = Collections.emptyMap(); + if (CollectionUtil.isNotEmpty(imageIdList)) { + LambdaQueryWrapper imageLambdaQueryWrapper = new LambdaQueryWrapper<>(); + imageLambdaQueryWrapper.in(Image::getId, imageIdList); + List imageList = imageService.list(imageLambdaQueryWrapper); + imageMap = imageList.stream().collect(Collectors.toMap(Image::getId, Image::getImageName)); + } + //查询虚拟机数据 + List nameList = data.stream().map(ImageVirtualMachinesRes::getImageName).filter(Objects::nonNull).distinct().collect(Collectors.toList()); + // 添加请求参数 + Map imageStatusData = getImageStatusData(nameList); + + for (ImageVirtualMachinesRes res : data) { + if (res.getImageSystemId() != null && StringUtils.isNotEmpty(imageMap.get(res.getImageSystemId()))) { + res.setImageSystemName(imageMap.get(res.getImageSystemId())); + } + if (imageStatusData.containsKey(res.getImageName())) { + ImageStatusRes.DataDTO.ItemsDTO itemsDTO = imageStatusData.get(res.getImageName()); + res.setImageStatus(itemsDTO.getState()); + res.setVncData(itemsDTO.getVnc()); + } + + + } + + return Result.successResult(convert); + } + } + + private Map getImageStatusData(List nameList) { + Map requestBody = new HashMap<>(); + requestBody.put("page", 1); + requestBody.put("page_size", 100); + requestBody.put("vm_names", nameList); + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + HttpEntity> requestEntity = new HttpEntity<>(requestBody, headers); + ResponseEntity exchange = restTemplate.exchange(imageConfigProperties.getStatusUrl(), HttpMethod.POST, requestEntity, ImageStatusRes.class); + if (exchange.getBody() != null && "200".equals(exchange.getBody().getCode()) && exchange.getBody().getData() != null) { + List items = exchange.getBody().getData().getItems(); + if (CollUtil.isNotEmpty(items)) { + return items.stream().collect(Collectors.toMap(ImageStatusRes.DataDTO.ItemsDTO::getName, Function.identity(), (k1, k2) -> k1)); + } + } + log.error("根据名称[{}]请求接口,返回数据为空:{}", nameList, exchange.getBody()); + return Collections.emptyMap(); + } + + + @Override + public Result insert(ImageVirtualMachinesReq imageVirtualMachinesReq) { + + // 调用镜像生成服务 + LambdaQueryWrapper imageLambdaQueryWrapper = new LambdaQueryWrapper<>(); + imageLambdaQueryWrapper.in(Image::getId, imageVirtualMachinesReq.getImageSystemId()); + Image systemImage = imageService.getOne(imageLambdaQueryWrapper); + ImageCreateReq createReq = ImageCreateReq.builder() + .name(imageVirtualMachinesReq.getImageName()) + .osType(imageVirtualMachinesReq.getOsVersion()) + .osVariant((systemImage!=null && StringUtils.isNotEmpty(systemImage.getImageVersion()))?systemImage.getImageVersion():"generic") + .vcpus(imageVirtualMachinesReq.getCpuTotal()) + .memory(imageVirtualMachinesReq.getMemoryTotal()) + .diskSize(imageVirtualMachinesReq.getSystemTotal()) + //存储池 +// .storagePool(imageVirtualMachinesReq.getStoragePath()) + .networkName(imageVirtualMachinesReq.getNetworkModule()) + .isoPath(imageVirtualMachinesReq.getStoragePath()) + //驱动 +// .virtioWinPath(imageVirtualMachinesReq.getStoragePath()) + .description(imageVirtualMachinesReq.getDescription()) + + .build(); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + HttpEntity requestEntity = new HttpEntity<>(createReq, headers); + ResponseEntity exchange = restTemplate.exchange(imageConfigProperties.getCreateUrl(), HttpMethod.POST, requestEntity, ImageStatusRes.class); + if (!exchange.getStatusCode().equals(HttpStatus.OK)){ + return Result.errorResult(BaseErrorCode.HTTP_REQUEST_FAILURE, "创建虚拟机失败"); + } + + ImageVirtualMachines imageVirtualMachines = BeanUtil.copyProperties(imageVirtualMachinesReq, ImageVirtualMachines.class); + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.lambda().eq(ImageVirtualMachines::getImageName, imageVirtualMachines.getImageName()); + ImageVirtualMachines selectOne = machinesMapper.selectOne(queryWrapper); + if (ObjectUtils.isNotEmpty(selectOne)) { + return new Result<>("200", "名称重复"); + } + imageVirtualMachines.setCreateUser("admin"); + imageVirtualMachines.setUpdateUser("admin"); + int insert = machinesMapper.insert(imageVirtualMachines); + log.info("终端新增insert:{}", insert); + if (insert == 1) { + return Result.successResult(); + } else { + return Result.errorResult(BaseErrorCode.HTTP_ERROR_CODE_500); + } + } + + @Override + public Result update(ImageVirtualMachinesReq imageVirtualMachinesReq) { + // todo 调用镜像修改服务 + ImageUpdateReq updateReq = ImageUpdateReq.builder() + .vmName(imageVirtualMachinesReq.getImageName()) + .vcpus(imageVirtualMachinesReq.getCpuTotal()) + .memory(imageVirtualMachinesReq.getMemoryTotal()) + + .networkName(imageVirtualMachinesReq.getNetworkModule()) + //驱动 +// .virtioWinPath(imageVirtualMachinesReq.getStoragePath()) + .description(imageVirtualMachinesReq.getDescription()) + .build(); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + HttpEntity requestEntity = new HttpEntity<>(updateReq, headers); + ResponseEntity exchange = restTemplate.exchange(imageConfigProperties.getUpdateUrl(), HttpMethod.POST, requestEntity, ImageStatusRes.class); + if (!exchange.getStatusCode().equals(HttpStatus.OK)){ + return Result.errorResult(BaseErrorCode.HTTP_REQUEST_FAILURE, "修改虚拟机失败"); + } + + + ImageVirtualMachines imageVirtualMachines = BeanUtil.copyProperties(imageVirtualMachinesReq, ImageVirtualMachines.class); + imageVirtualMachines.setUpdateUser("admin"); + int updated = machinesMapper.updateById(imageVirtualMachines); + log.info("镜像虚拟机修改updated:{}", updated); + if (updated == 1) { + return Result.successResult(); + } else { + return Result.errorResult(BaseErrorCode.HTTP_ERROR_CODE_500); + } + } + + @Override + public Result query(ImageVirtualMachinesReq imageVirtualMachinesReq) { + ImageVirtualMachines imageVirtualMachines = machinesMapper.selectById(imageVirtualMachinesReq.getId()); + + if (ObjectUtils.isEmpty(imageVirtualMachines)) { + log.info("查询镜像虚拟机返回为空"); + return Result.successResult(); + } + ImageVirtualMachinesRes res = BeanUtil.copyProperties(imageVirtualMachines, ImageVirtualMachinesRes.class); + log.info("查询镜像虚拟机返回:{}", JSONUtil.toJsonStr(res)); + return Result.successResult(res); + } + + @Override + public Result delete(DeleteIdReq deleteIdReq) { + int deleted = machinesMapper.deleteById(deleteIdReq.getId()); + log.info("终端删除insert:{}", deleted); + if (deleted == 1) { + return Result.successResult(); + } else { + return Result.errorResult(BaseErrorCode.HTTP_ERROR_CODE_500); + } + } + + @Override + public Result cloneTemplate(ImageVirtualMachinesReq req) { + //todo 调用镜像生成服务 在生成完毕后生成桌面镜像数据 + return null; + } +} + diff --git a/nex-be/src/main/resources/application.yml b/nex-be/src/main/resources/application.yml index 06e97cb..87a714f 100644 --- a/nex-be/src/main/resources/application.yml +++ b/nex-be/src/main/resources/application.yml @@ -6,7 +6,13 @@ file: temp-dir: /var/lib/vdi/tmp/chunked-uploads dir: /var/lib/vdi/test bt-url: http://10.100.51.86:8114 - +image: + base-url: http://10.100.51.118:5173 + status-url: /api/v1/vm/batch-status + create-url: /api/v1/vm/create + delete-url: /api/v1/vm/delete + update-url: /api/v1/vm/update + start-url: /api/v1/vm/start spring: servlet: multipart: @@ -47,4 +53,4 @@ mybatis-plus: grpc: server: # 指定Grpc暴露的端口,后续客户端通过这个端口访问 - port: 50051 \ No newline at end of file + port: 51051 \ No newline at end of file diff --git a/nex-be/src/main/resources/mappers/ImageVirtualMachinesMapper.xml b/nex-be/src/main/resources/mappers/ImageVirtualMachinesMapper.xml new file mode 100644 index 0000000..2c7a364 --- /dev/null +++ b/nex-be/src/main/resources/mappers/ImageVirtualMachinesMapper.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + id,image_name,image_file_name,image_status,image_version,os_version, + bt_path,storage_path,create_time,create_user,update_time, + update_user,deleted,description + +