重写复现方法
This commit is contained in:
@@ -1,20 +1,15 @@
|
|||||||
package com.mini.capi.job;
|
package com.mini.capi.job;
|
||||||
|
|
||||||
|
|
||||||
import com.mini.capi.biz.domain.*;
|
|
||||||
import com.mini.capi.biz.service.*;
|
|
||||||
import com.mini.capi.model.ApiResult;
|
import com.mini.capi.model.ApiResult;
|
||||||
|
import com.mini.capi.sys.service.DbService;
|
||||||
|
import com.mini.capi.sys.service.DockerService;
|
||||||
import com.mini.capi.utils.*;
|
import com.mini.capi.utils.*;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/Sys/jobs")
|
@RequestMapping("/Sys/jobs")
|
||||||
@@ -22,23 +17,10 @@ public class taskEnable {
|
|||||||
|
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private SshInfoService sshInfoService;
|
private DockerService dockerService;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private SshUserService sshUserService;
|
private DbService dbService;
|
||||||
|
|
||||||
@Resource
|
|
||||||
private DockerHostService dockerHostService;
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private DiskMountService diskMountService;
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private SysHostService sysHostService;
|
|
||||||
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private Executor hostExecutor;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -49,75 +31,20 @@ public class taskEnable {
|
|||||||
if (!vToken.isValidToken(token)) {
|
if (!vToken.isValidToken(token)) {
|
||||||
return ApiResult.error(401, "无效的访问令牌");
|
return ApiResult.error(401, "无效的访问令牌");
|
||||||
}
|
}
|
||||||
try {
|
return dockerService.jobHostDisk();
|
||||||
List<DockerHost> dockerHosts = dockerHostService.list();
|
|
||||||
List<String> errorList = Collections.synchronizedList(new ArrayList<>());
|
|
||||||
// 并行处理所有宿主机
|
|
||||||
CompletableFuture<?>[] futures = dockerHosts.stream()
|
|
||||||
.map(host -> CompletableFuture.runAsync(() -> handleSingleHost(host, errorList), hostExecutor))
|
|
||||||
.toArray(CompletableFuture[]::new);
|
|
||||||
// 等待全部完成
|
|
||||||
CompletableFuture.allOf(futures).join();
|
|
||||||
return errorList.isEmpty()
|
|
||||||
? ApiResult.success()
|
|
||||||
: ApiResult.error();
|
|
||||||
} catch (Exception e) {
|
|
||||||
return ApiResult.error(101, e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void handleSingleHost(DockerHost host, List<String> errorList) {
|
/**
|
||||||
try {
|
* 运行全部任务数据同步
|
||||||
SshUser sshUser = sshUserService.getById(host.getUserId());
|
*/
|
||||||
SshInfo sshInfo = sshInfoService.getById(host.getHostId());
|
@GetMapping("/getTaskSyncDbInfo")
|
||||||
/* 1. 采集实时数据 */
|
public ApiResult<?> jobSyncAllTask(String token) {
|
||||||
HostInfo.Result r = HostInfo.collect(
|
if (!vToken.isValidToken(token)) {
|
||||||
sshInfo.getHostIp(),
|
return ApiResult.error(401, "无效的访问令牌");
|
||||||
Integer.parseInt(sshInfo.getHostPort()),
|
|
||||||
sshUser.getCUsername(),
|
|
||||||
sshUser.getCPassword());
|
|
||||||
/* 2. 主机维度 saveOrUpdate */
|
|
||||||
SysHost sysHost = r.host;
|
|
||||||
sysHost.setSysHostId(host.getHostId());
|
|
||||||
sysHost.setUpdateTime(vDate.getNow());
|
|
||||||
sysHost.setDokerHostId(host.getDokerHostId());
|
|
||||||
sysHostService.saveOrUpdate(sysHost);
|
|
||||||
/* 3. 处理磁盘:先查库做索引,再比对 */
|
|
||||||
List<DiskMount> dbDisks = diskMountService.lambdaQuery()
|
|
||||||
.eq(DiskMount::getSysHostId, host.getHostId())
|
|
||||||
.list();
|
|
||||||
Map<String, DiskMount> dbDiskMap = dbDisks.stream()
|
|
||||||
.collect(Collectors.toMap(DiskMount::getMountPoint, Function.identity()));
|
|
||||||
|
|
||||||
List<DiskMount> toSaveOrUpdate = new ArrayList<>();
|
|
||||||
Set<String> liveMountPoint = new HashSet<>();
|
|
||||||
for (DiskMount d : r.disks) {
|
|
||||||
liveMountPoint.add(d.getMountPoint());
|
|
||||||
DiskMount exist = dbDiskMap.get(d.getMountPoint());
|
|
||||||
if (exist != null) {
|
|
||||||
d.setDiskMountId(exist.getDiskMountId());
|
|
||||||
} else {
|
|
||||||
d.setDiskMountId(vId.getUid());
|
|
||||||
}
|
|
||||||
d.setSysHostId(host.getHostId());
|
|
||||||
d.setUpdateTime(vDate.getNow());
|
|
||||||
toSaveOrUpdate.add(d);
|
|
||||||
}
|
|
||||||
/* 4. 批量保存/更新 */
|
|
||||||
diskMountService.saveOrUpdateBatch(toSaveOrUpdate);
|
|
||||||
/* 5. 删除实时已消失的盘 */
|
|
||||||
List<String> delIds = dbDisks.stream()
|
|
||||||
.filter(d -> !liveMountPoint.contains(d.getMountPoint()))
|
|
||||||
.map(DiskMount::getDiskMountId)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
if (!delIds.isEmpty()) {
|
|
||||||
diskMountService.removeByIds(delIds);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
// 仅记录异常,不中断其它任务
|
|
||||||
errorList.add(String.format("hostId=%s, error=%s", host.getHostId(), e.getMessage()));
|
|
||||||
}
|
}
|
||||||
|
return dbService.jobSyncAllTask();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,15 @@
|
|||||||
package com.mini.capi.sys.controller;
|
package com.mini.capi.sys.controller;
|
||||||
|
|
||||||
import com.mini.capi.biz.domain.DbConfig;
|
|
||||||
import com.mini.capi.biz.service.DbConfigService;
|
|
||||||
import com.mini.capi.config.DataSourceConfig;
|
|
||||||
import com.mini.capi.model.ApiResult;
|
import com.mini.capi.model.ApiResult;
|
||||||
import com.mini.capi.model.TabResult;
|
import com.mini.capi.model.TabResult;
|
||||||
|
import com.mini.capi.sys.service.DbService;
|
||||||
import com.mini.capi.utils.vToken;
|
import com.mini.capi.utils.vToken;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/Sys/dbs")
|
@RequestMapping("/Sys/dbs")
|
||||||
@@ -22,7 +17,7 @@ public class dbController {
|
|||||||
|
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private DbConfigService dbConfigService;
|
private DbService dbService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取MySQL的当前连接下的所有数据表
|
* 获取MySQL的当前连接下的所有数据表
|
||||||
@@ -33,45 +28,18 @@ public class dbController {
|
|||||||
if (!vToken.isValidToken(token)) {
|
if (!vToken.isValidToken(token)) {
|
||||||
return ApiResult.error(401, "无效的访问令牌");
|
return ApiResult.error(401, "无效的访问令牌");
|
||||||
}
|
}
|
||||||
|
return dbService.listSourceTables(dbId);
|
||||||
// 2. 校验dbId参数
|
|
||||||
if (dbId == null || dbId.trim().isEmpty()) {
|
|
||||||
return ApiResult.error(400, "数据库ID不能为空");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. 查询数据库配置并校验
|
|
||||||
DbConfig dbConfig = dbConfigService.getById(dbId);
|
|
||||||
if (dbConfig == null) {
|
|
||||||
return ApiResult.error(404, "未找到ID为[" + dbId + "]的数据库配置");
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
JdbcTemplate jdbcTemplate = DataSourceConfig.createJdbcTemplate(dbConfig);
|
|
||||||
// 补充参数传递
|
|
||||||
String querySql = "SELECT TABLE_NAME,TABLE_COMMENT FROM information_schema.tables WHERE TABLE_SCHEMA = ?";
|
|
||||||
List<Map<String, Object>> result = jdbcTemplate.queryForList(querySql, dbConfig.getDbName());
|
|
||||||
List<TabResult> data = result.stream()
|
|
||||||
.map(row -> {
|
|
||||||
String tableName = row.get("TABLE_NAME") != null ? row.get("TABLE_NAME").toString() : "";
|
|
||||||
String tableDesc = row.get("TABLE_COMMENT") != null ? row.get("TABLE_COMMENT").toString() : "";
|
|
||||||
return new TabResult(tableName, getComment(tableName, tableDesc));
|
|
||||||
})
|
|
||||||
.sorted(Comparator.comparing(TabResult::getTableName)) // 按表名排序
|
|
||||||
.toList();
|
|
||||||
return ApiResult.success(data);
|
|
||||||
} catch (Exception e) {
|
|
||||||
return ApiResult.error(101, e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private String getComment(String tableName, String tableDesc) {
|
/**
|
||||||
boolean hasTableDesc = tableDesc != null && !tableDesc.trim().isEmpty();
|
* 运行单个任务
|
||||||
// 根据表描述是否存在返回不同格式
|
*/
|
||||||
if (hasTableDesc) {
|
@GetMapping("/getTaskSyncDbByInfo")
|
||||||
return String.format("%s(%s)", tableDesc.trim(), tableName);
|
public ApiResult<?> jobSyncOneTask(String token, String taskId) {
|
||||||
} else {
|
if (!vToken.isValidToken(token)) {
|
||||||
return tableName;
|
return ApiResult.error(401, "无效的访问令牌");
|
||||||
}
|
}
|
||||||
|
return dbService.jobSyncOneTask(taskId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package com.mini.capi.sys.controller;
|
||||||
|
|
||||||
|
|
||||||
|
import com.mini.capi.model.ApiResult;
|
||||||
|
import com.mini.capi.sys.service.HostService;
|
||||||
|
import com.mini.capi.utils.vToken;
|
||||||
|
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/Sys/hosts")
|
||||||
|
public class hostController {
|
||||||
|
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private HostService hostService;
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("/getApiInfo")
|
||||||
|
public ApiResult<List<HostService.SnapshotDTO>> getApiInfo(String token) {
|
||||||
|
if (!vToken.isValidToken(token)) {
|
||||||
|
return ApiResult.error(401, "无效的访问令牌");
|
||||||
|
}
|
||||||
|
return hostService.getApiInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取容器列表
|
||||||
|
*/
|
||||||
|
@GetMapping("/getApiDockerInfo")
|
||||||
|
public ApiResult<?> getDockerInfo(String token) {
|
||||||
|
if (!vToken.isValidToken(token)) {
|
||||||
|
return ApiResult.error(401, "无效的访问令牌");
|
||||||
|
}
|
||||||
|
return hostService.getDockerInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启动容器
|
||||||
|
*/
|
||||||
|
@GetMapping("/getApiStartDockerInfo")
|
||||||
|
public ApiResult<?> startDockerInfo(String id, String token) {
|
||||||
|
if (!vToken.isValidToken(token)) {
|
||||||
|
return ApiResult.error(401, "无效的访问令牌");
|
||||||
|
}
|
||||||
|
return hostService.startDockerInfo(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 停止容器
|
||||||
|
*/
|
||||||
|
@GetMapping("/getApiStopDockerInfo")
|
||||||
|
public ApiResult<?> stopDockerInfo(String id, String token) {
|
||||||
|
if (!vToken.isValidToken(token)) {
|
||||||
|
return ApiResult.error(401, "无效的访问令牌");
|
||||||
|
}
|
||||||
|
return hostService.stopDockerInfo(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.mini.capi.job;
|
package com.mini.capi.sys.service;
|
||||||
|
|
||||||
import com.mini.capi.biz.domain.DbConfig;
|
import com.mini.capi.biz.domain.DbConfig;
|
||||||
import com.mini.capi.biz.domain.SyncTask;
|
import com.mini.capi.biz.domain.SyncTask;
|
||||||
@@ -8,28 +8,22 @@ import com.mini.capi.biz.service.SyncTaskLogService;
|
|||||||
import com.mini.capi.biz.service.SyncTaskService;
|
import com.mini.capi.biz.service.SyncTaskService;
|
||||||
import com.mini.capi.config.DataSourceConfig;
|
import com.mini.capi.config.DataSourceConfig;
|
||||||
import com.mini.capi.model.ApiResult;
|
import com.mini.capi.model.ApiResult;
|
||||||
import com.mini.capi.utils.vToken;
|
import com.mini.capi.model.TabResult;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
|
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
|
||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
|
|
||||||
import java.sql.*;
|
import java.sql.*;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
@RestController
|
@Service
|
||||||
@RequestMapping("/Sys/dbs")
|
public class DbService {
|
||||||
public class taskDbSync {
|
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private SyncTaskService syncTaskService;
|
private SyncTaskService syncTaskService;
|
||||||
@@ -43,17 +37,57 @@ public class taskDbSync {
|
|||||||
@Resource
|
@Resource
|
||||||
private Executor hostExecutor;
|
private Executor hostExecutor;
|
||||||
|
|
||||||
|
|
||||||
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");
|
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");
|
||||||
private static final String dsValue = LocalDate.now().format(DATE_FORMATTER);
|
private static final String dsValue = LocalDate.now().format(DATE_FORMATTER);
|
||||||
|
|
||||||
|
|
||||||
|
public ApiResult<List<TabResult>> listSourceTables(String dbId) {
|
||||||
|
// 1. 校验dbId参数
|
||||||
|
if (dbId == null || dbId.trim().isEmpty()) {
|
||||||
|
return ApiResult.error(400, "数据库ID不能为空");
|
||||||
|
}
|
||||||
|
// 2. 查询数据库配置并校验
|
||||||
|
DbConfig dbConfig = dbConfigService.getById(dbId);
|
||||||
|
if (dbConfig == null) {
|
||||||
|
return ApiResult.error(404, "未找到ID为[" + dbId + "]的数据库配置");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
JdbcTemplate jdbcTemplate = DataSourceConfig.createJdbcTemplate(dbConfig);
|
||||||
|
// 补充参数传递
|
||||||
|
String querySql = "SELECT TABLE_NAME,TABLE_COMMENT FROM information_schema.tables WHERE TABLE_SCHEMA = ?";
|
||||||
|
List<Map<String, Object>> result = jdbcTemplate.queryForList(querySql, dbConfig.getDbName());
|
||||||
|
List<TabResult> data = result.stream()
|
||||||
|
.map(row -> {
|
||||||
|
String tableName = row.get("TABLE_NAME") != null ? row.get("TABLE_NAME").toString() : "";
|
||||||
|
String tableDesc = row.get("TABLE_COMMENT") != null ? row.get("TABLE_COMMENT").toString() : "";
|
||||||
|
return new TabResult(tableName, getComment(tableName, tableDesc));
|
||||||
|
})
|
||||||
|
.sorted(Comparator.comparing(TabResult::getTableName)) // 按表名排序
|
||||||
|
.toList();
|
||||||
|
return ApiResult.success(data);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return ApiResult.error(101, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private String getComment(String tableName, String tableDesc) {
|
||||||
|
boolean hasTableDesc = tableDesc != null && !tableDesc.trim().isEmpty();
|
||||||
|
// 根据表描述是否存在返回不同格式
|
||||||
|
if (hasTableDesc) {
|
||||||
|
return String.format("%s(%s)", tableDesc.trim(), tableName);
|
||||||
|
} else {
|
||||||
|
return tableName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 运行全部任务
|
* 运行全部任务
|
||||||
*/
|
*/
|
||||||
@GetMapping("/getTaskSyncDbInfo")
|
public ApiResult<?> jobSyncAllTask() {
|
||||||
public ApiResult<?> jobSyncAllTask(String token) {
|
|
||||||
if (!vToken.isValidToken(token)) {
|
|
||||||
return ApiResult.error(401, "无效的访问令牌");
|
|
||||||
}
|
|
||||||
List<SyncTask> syncTasks = syncTaskService.list();
|
List<SyncTask> syncTasks = syncTaskService.list();
|
||||||
// 记录是否有任务失败(仅用于后台日志,不影响接口返回)
|
// 记录是否有任务失败(仅用于后台日志,不影响接口返回)
|
||||||
List<String> errorMessages = new ArrayList<>();
|
List<String> errorMessages = new ArrayList<>();
|
||||||
@@ -69,11 +103,7 @@ public class taskDbSync {
|
|||||||
/**
|
/**
|
||||||
* 运行单个任务
|
* 运行单个任务
|
||||||
*/
|
*/
|
||||||
@GetMapping("/getTaskSyncDbByInfo")
|
public ApiResult<?> jobSyncOneTask( String taskId) {
|
||||||
public ApiResult<?> jobSyncOneTask(String token, String taskId) {
|
|
||||||
if (!vToken.isValidToken(token)) {
|
|
||||||
return ApiResult.error(401, "无效的访问令牌");
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
SyncTask task = syncTaskService.getById(taskId);
|
SyncTask task = syncTaskService.getById(taskId);
|
||||||
// 记录是否有任务失败(仅用于后台日志,不影响接口返回)
|
// 记录是否有任务失败(仅用于后台日志,不影响接口返回)
|
||||||
117
src/main/java/com/mini/capi/sys/service/DockerService.java
Normal file
117
src/main/java/com/mini/capi/sys/service/DockerService.java
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
package com.mini.capi.sys.service;
|
||||||
|
|
||||||
|
import com.mini.capi.biz.domain.*;
|
||||||
|
import com.mini.capi.biz.service.*;
|
||||||
|
import com.mini.capi.model.ApiResult;
|
||||||
|
import com.mini.capi.utils.HostInfo;
|
||||||
|
import com.mini.capi.utils.vDate;
|
||||||
|
import com.mini.capi.utils.vId;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class DockerService {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SshInfoService sshInfoService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SshUserService sshUserService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private DockerHostService dockerHostService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private DiskMountService diskMountService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SysHostService sysHostService;
|
||||||
|
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private Executor hostExecutor;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取容器主机的磁盘使用情况
|
||||||
|
*/
|
||||||
|
public ApiResult<?> jobHostDisk() {
|
||||||
|
try {
|
||||||
|
List<DockerHost> dockerHosts = dockerHostService.list();
|
||||||
|
List<String> errorList = Collections.synchronizedList(new ArrayList<>());
|
||||||
|
// 并行处理所有宿主机
|
||||||
|
CompletableFuture<?>[] futures = dockerHosts.stream()
|
||||||
|
.map(host -> CompletableFuture.runAsync(() -> handleSingleHost(host, errorList), hostExecutor))
|
||||||
|
.toArray(CompletableFuture[]::new);
|
||||||
|
// 等待全部完成
|
||||||
|
CompletableFuture.allOf(futures).join();
|
||||||
|
return errorList.isEmpty()
|
||||||
|
? ApiResult.success()
|
||||||
|
: ApiResult.error();
|
||||||
|
} catch (Exception e) {
|
||||||
|
return ApiResult.error(101, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void handleSingleHost(DockerHost host, List<String> errorList) {
|
||||||
|
try {
|
||||||
|
SshUser sshUser = sshUserService.getById(host.getUserId());
|
||||||
|
SshInfo sshInfo = sshInfoService.getById(host.getHostId());
|
||||||
|
/* 1. 采集实时数据 */
|
||||||
|
HostInfo.Result r = HostInfo.collect(
|
||||||
|
sshInfo.getHostIp(),
|
||||||
|
Integer.parseInt(sshInfo.getHostPort()),
|
||||||
|
sshUser.getCUsername(),
|
||||||
|
sshUser.getCPassword());
|
||||||
|
/* 2. 主机维度 saveOrUpdate */
|
||||||
|
SysHost sysHost = r.host;
|
||||||
|
sysHost.setSysHostId(host.getHostId());
|
||||||
|
sysHost.setUpdateTime(vDate.getNow());
|
||||||
|
sysHost.setDokerHostId(host.getDokerHostId());
|
||||||
|
sysHostService.saveOrUpdate(sysHost);
|
||||||
|
/* 3. 处理磁盘:先查库做索引,再比对 */
|
||||||
|
List<DiskMount> dbDisks = diskMountService.lambdaQuery()
|
||||||
|
.eq(DiskMount::getSysHostId, host.getHostId())
|
||||||
|
.list();
|
||||||
|
Map<String, DiskMount> dbDiskMap = dbDisks.stream()
|
||||||
|
.collect(Collectors.toMap(DiskMount::getMountPoint, Function.identity()));
|
||||||
|
|
||||||
|
List<DiskMount> toSaveOrUpdate = new ArrayList<>();
|
||||||
|
Set<String> liveMountPoint = new HashSet<>();
|
||||||
|
for (DiskMount d : r.disks) {
|
||||||
|
liveMountPoint.add(d.getMountPoint());
|
||||||
|
DiskMount exist = dbDiskMap.get(d.getMountPoint());
|
||||||
|
if (exist != null) {
|
||||||
|
d.setDiskMountId(exist.getDiskMountId());
|
||||||
|
} else {
|
||||||
|
d.setDiskMountId(vId.getUid());
|
||||||
|
}
|
||||||
|
d.setSysHostId(host.getHostId());
|
||||||
|
d.setUpdateTime(vDate.getNow());
|
||||||
|
toSaveOrUpdate.add(d);
|
||||||
|
}
|
||||||
|
/* 4. 批量保存/更新 */
|
||||||
|
diskMountService.saveOrUpdateBatch(toSaveOrUpdate);
|
||||||
|
/* 5. 删除实时已消失的盘 */
|
||||||
|
List<String> delIds = dbDisks.stream()
|
||||||
|
.filter(d -> !liveMountPoint.contains(d.getMountPoint()))
|
||||||
|
.map(DiskMount::getDiskMountId)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
if (!delIds.isEmpty()) {
|
||||||
|
diskMountService.removeByIds(delIds);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 仅记录异常,不中断其它任务
|
||||||
|
errorList.add(String.format("hostId=%s, error=%s", host.getHostId(), e.getMessage()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.mini.capi.sys.controller;
|
package com.mini.capi.sys.service;
|
||||||
|
|
||||||
import com.mini.capi.biz.domain.DockerContainerInfo;
|
import com.mini.capi.biz.domain.DockerContainerInfo;
|
||||||
import com.mini.capi.biz.domain.DockerHost;
|
import com.mini.capi.biz.domain.DockerHost;
|
||||||
@@ -12,11 +12,8 @@ import com.mini.capi.model.ApiResult;
|
|||||||
import com.mini.capi.utils.HostRuntime;
|
import com.mini.capi.utils.HostRuntime;
|
||||||
import com.mini.capi.utils.docker;
|
import com.mini.capi.utils.docker;
|
||||||
import com.mini.capi.utils.vDate;
|
import com.mini.capi.utils.vDate;
|
||||||
import com.mini.capi.utils.vToken;
|
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
@@ -26,9 +23,8 @@ import java.util.concurrent.CompletableFuture;
|
|||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@RestController
|
@Service
|
||||||
@RequestMapping("/Sys/hosts")
|
public class HostService {
|
||||||
public class sysController {
|
|
||||||
|
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
@@ -57,7 +53,7 @@ public class sysController {
|
|||||||
public String memUsage;
|
public String memUsage;
|
||||||
public String swapTotal;
|
public String swapTotal;
|
||||||
public String swapUsed;
|
public String swapUsed;
|
||||||
public List<DiskDTO> disks;
|
public List<SnapshotDTO.DiskDTO> disks;
|
||||||
public String netRxBytes;
|
public String netRxBytes;
|
||||||
public String netTxBytes;
|
public String netTxBytes;
|
||||||
public double load1;
|
public double load1;
|
||||||
@@ -78,7 +74,7 @@ public class sysController {
|
|||||||
dto.swapTotal = humanBytes(s.swapTotal);
|
dto.swapTotal = humanBytes(s.swapTotal);
|
||||||
dto.swapUsed = humanBytes(s.swapUsed);
|
dto.swapUsed = humanBytes(s.swapUsed);
|
||||||
dto.disks = s.disks.stream()
|
dto.disks = s.disks.stream()
|
||||||
.map(d -> new DiskDTO(d.path,
|
.map(d -> new SnapshotDTO.DiskDTO(d.path,
|
||||||
humanBytes(d.total),
|
humanBytes(d.total),
|
||||||
humanBytes(d.free),
|
humanBytes(d.free),
|
||||||
humanBytes(d.used),
|
humanBytes(d.used),
|
||||||
@@ -253,12 +249,7 @@ public class sysController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@GetMapping("/getApiInfo")
|
public ApiResult<List<SnapshotDTO>> getApiInfo() {
|
||||||
public ApiResult<List<SnapshotDTO>> getApiInfo(String token) {
|
|
||||||
if (!vToken.isValidToken(token)) {
|
|
||||||
return ApiResult.error(401, "无效的访问令牌");
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 1. 新建一个一次性 List
|
// 1. 新建一个一次性 List
|
||||||
List<HostRuntime.Snapshot> snapshots =
|
List<HostRuntime.Snapshot> snapshots =
|
||||||
@@ -280,11 +271,7 @@ public class sysController {
|
|||||||
/**
|
/**
|
||||||
* 获取容器列表
|
* 获取容器列表
|
||||||
*/
|
*/
|
||||||
@GetMapping("/getApiDockerInfo")
|
public ApiResult<?> getDockerInfo() {
|
||||||
public ApiResult<?> getDockerInfo(String token) {
|
|
||||||
if (!vToken.isValidToken(token)) {
|
|
||||||
return ApiResult.error(401, "无效的访问令牌");
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
List<DockerHost> dockerHosts = dockerHostService.list();
|
List<DockerHost> dockerHosts = dockerHostService.list();
|
||||||
List<String> errorList = Collections.synchronizedList(new ArrayList<>());
|
List<String> errorList = Collections.synchronizedList(new ArrayList<>());
|
||||||
@@ -306,11 +293,7 @@ public class sysController {
|
|||||||
/**
|
/**
|
||||||
* 启动容器
|
* 启动容器
|
||||||
*/
|
*/
|
||||||
@GetMapping("/getApiStartDockerInfo")
|
public ApiResult<?> startDockerInfo(String id) {
|
||||||
public ApiResult<?> startDockerInfo(String id, String token) {
|
|
||||||
if (!vToken.isValidToken(token)) {
|
|
||||||
return ApiResult.error(401, "无效的访问令牌");
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
DockerContainerInfo cur = dockerInfoService.getById(id);
|
DockerContainerInfo cur = dockerInfoService.getById(id);
|
||||||
DockerHost host = dockerHostService.getById(cur.getDokerHostId());
|
DockerHost host = dockerHostService.getById(cur.getDokerHostId());
|
||||||
@@ -337,11 +320,7 @@ public class sysController {
|
|||||||
/**
|
/**
|
||||||
* 停止容器
|
* 停止容器
|
||||||
*/
|
*/
|
||||||
@GetMapping("/getApiStopDockerInfo")
|
public ApiResult<?> stopDockerInfo(String id) {
|
||||||
public ApiResult<?> stopDockerInfo(String id, String token) {
|
|
||||||
if (!vToken.isValidToken(token)) {
|
|
||||||
return ApiResult.error(401, "无效的访问令牌");
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
DockerContainerInfo cur = dockerInfoService.getById(id);
|
DockerContainerInfo cur = dockerInfoService.getById(id);
|
||||||
DockerHost host = dockerHostService.getById(cur.getDokerHostId());
|
DockerHost host = dockerHostService.getById(cur.getDokerHostId());
|
||||||
@@ -363,6 +342,4 @@ public class sysController {
|
|||||||
return ApiResult.error(101, e.getMessage());
|
return ApiResult.error(101, e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user