mirror of
https://gitee.com/dromara/Jpom.git
synced 2024-11-30 10:58:14 +08:00
新增机器资产管理
This commit is contained in:
parent
7f90ed0927
commit
80b73ea6b0
@ -1,5 +1,12 @@
|
||||
# 🚀 版本日志
|
||||
|
||||
1. 删除 node_info unLockType 字段
|
||||
2. 取消节点解绑功能
|
||||
3. 停止使用 NODE_STAT 表(暂时保留相关数据)
|
||||
4. MACHINE_NODE_STAT_LOG 表替代 SYSTEMMONITORLOG 表(并暂时保留 SYSTEMMONITORLOG 数据)
|
||||
5. 节点列表更名逻辑节点
|
||||
6. 新增机器资产管理
|
||||
|
||||
## 2.10.17 (2023-02-16)
|
||||
|
||||
1. 【server】新增 构建配置新增严格执行命令模式(判断命令执行状态码是否为0)
|
||||
|
@ -69,4 +69,11 @@ public interface INodeInfo {
|
||||
* @return proxy
|
||||
*/
|
||||
Proxy proxy();
|
||||
|
||||
/**
|
||||
* 超时时间
|
||||
*
|
||||
* @return 超时时间 单位秒
|
||||
*/
|
||||
Integer timeout();
|
||||
}
|
||||
|
@ -23,13 +23,16 @@
|
||||
package io.jpom.controller;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.system.SystemUtil;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import io.jpom.common.BaseAgentController;
|
||||
import io.jpom.common.JpomManifest;
|
||||
import io.jpom.common.JsonMessage;
|
||||
import io.jpom.common.RemoteVersion;
|
||||
import io.jpom.common.commander.AbstractProjectCommander;
|
||||
import io.jpom.common.commander.AbstractSystemCommander;
|
||||
import io.jpom.common.interceptor.NotAuthorize;
|
||||
import io.jpom.model.data.NodeProjectInfoModel;
|
||||
import io.jpom.model.data.NodeScriptModel;
|
||||
@ -37,12 +40,18 @@ import io.jpom.plugin.PluginFactory;
|
||||
import io.jpom.service.manage.ProjectInfoService;
|
||||
import io.jpom.service.script.NodeScriptServer;
|
||||
import io.jpom.util.JvmUtil;
|
||||
import io.jpom.util.OshiUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 首页
|
||||
@ -51,6 +60,7 @@ import java.util.List;
|
||||
* @since 2019/4/17
|
||||
*/
|
||||
@RestController
|
||||
@Slf4j
|
||||
public class IndexController extends BaseAgentController {
|
||||
|
||||
private final ProjectInfoService projectInfoService;
|
||||
@ -82,32 +92,73 @@ public class IndexController extends BaseAgentController {
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回节点项目状态信息
|
||||
* 获取节点统计信息
|
||||
*
|
||||
* @return array
|
||||
* @return json
|
||||
*/
|
||||
@RequestMapping(value = "status", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public JsonMessage<JSONObject> status() {
|
||||
@PostMapping(value = "get-stat-info", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public JsonMessage<JSONObject> getDirectTop() {
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
JSONObject topInfo = OshiUtils.getSimpleInfo();
|
||||
jsonObject.put("simpleStatus", topInfo);
|
||||
|
||||
JSONObject systemInfo = OshiUtils.getSystemInfo();
|
||||
jsonObject.put("systemInfo", systemInfo);
|
||||
|
||||
JSONObject jpomInfo = this.getJpomInfo();
|
||||
jsonObject.put("jpomInfo", jpomInfo);
|
||||
return JsonMessage.success("ok", jsonObject);
|
||||
}
|
||||
|
||||
private JSONObject getJpomInfo() {
|
||||
List<NodeProjectInfoModel> nodeProjectInfoModels = projectInfoService.list();
|
||||
List<NodeScriptModel> list = nodeScriptServer.list();
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("javaVirtualCount", JvmUtil.getJavaVirtualCount());
|
||||
JpomManifest instance = JpomManifest.getInstance();
|
||||
jsonObject.put("osName", instance.getOsName());
|
||||
jsonObject.put("jpomVersion", instance.getVersion());
|
||||
jsonObject.put("jpomManifest", instance);
|
||||
jsonObject.put("javaVersion", SystemUtil.getJavaRuntimeInfo().getVersion());
|
||||
// 获取JVM中内存总大小
|
||||
long totalMemory = SystemUtil.getTotalMemory();
|
||||
jsonObject.put("totalMemory", FileUtil.readableFileSize(totalMemory));
|
||||
jsonObject.put("totalMemory", SystemUtil.getTotalMemory());
|
||||
//
|
||||
long freeMemory = SystemUtil.getFreeMemory();
|
||||
jsonObject.put("freeMemory", FileUtil.readableFileSize(freeMemory));
|
||||
jsonObject.put("freeMemory", SystemUtil.getFreeMemory());
|
||||
//
|
||||
jsonObject.put("count", CollUtil.size(nodeProjectInfoModels));
|
||||
jsonObject.put("projectCount", CollUtil.size(nodeProjectInfoModels));
|
||||
jsonObject.put("scriptCount", CollUtil.size(list));
|
||||
// 运行时间
|
||||
jsonObject.put("runTime", instance.getUpTimeStr());
|
||||
jsonObject.put("runTimeLong", instance.getUpTime());
|
||||
return JsonMessage.success("", jsonObject);
|
||||
return jsonObject;
|
||||
}
|
||||
|
||||
|
||||
@RequestMapping(value = "processList", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public JsonMessage<List<JSONObject>> getProcessList(String processName, Integer count) {
|
||||
processName = StrUtil.emptyToDefault(processName, "java");
|
||||
List<JSONObject> processes = OshiUtils.getProcesses(processName, Convert.toInt(count, 20));
|
||||
processes = processes.stream()
|
||||
.peek(jsonObject -> {
|
||||
int processId = jsonObject.getIntValue("processId");
|
||||
String port = AbstractProjectCommander.getInstance().getMainPort(processId);
|
||||
jsonObject.put("port", port);
|
||||
//
|
||||
try {
|
||||
String jpomName = AbstractProjectCommander.getInstance().getJpomNameByPid(processId);
|
||||
jsonObject.put("jpomName", jpomName);
|
||||
} catch (IOException e) {
|
||||
log.error("解析进程失败", e);
|
||||
}
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
return JsonMessage.success("ok", processes);
|
||||
}
|
||||
|
||||
|
||||
@RequestMapping(value = "kill.json", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public JsonMessage<Object> kill(int pid) {
|
||||
long jpomAgentId = JpomManifest.getInstance().getPid();
|
||||
Assert.state(!StrUtil.equals(StrUtil.toString(jpomAgentId), StrUtil.toString(pid)), "不支持在线关闭 Agent 进程");
|
||||
String result = AbstractSystemCommander.getInstance().kill(null, pid);
|
||||
if (StrUtil.isEmpty(result)) {
|
||||
result = "成功kill";
|
||||
}
|
||||
return JsonMessage.success(result);
|
||||
}
|
||||
}
|
||||
|
@ -1,124 +0,0 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Code Technology Studio
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package io.jpom.controller;
|
||||
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import io.jpom.common.BaseAgentController;
|
||||
import io.jpom.common.JpomManifest;
|
||||
import io.jpom.common.JsonMessage;
|
||||
import io.jpom.common.commander.AbstractProjectCommander;
|
||||
import io.jpom.common.commander.AbstractSystemCommander;
|
||||
import io.jpom.util.OshiUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author jiangzeyin
|
||||
* @since 2019/4/16
|
||||
*/
|
||||
@RestController
|
||||
@Slf4j
|
||||
public class WelcomeController extends BaseAgentController {
|
||||
|
||||
@PostMapping(value = "getDirectTop", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public JsonMessage<JSONObject> getDirectTop() {
|
||||
JSONObject topInfo = OshiUtils.getSimpleInfo();
|
||||
return JsonMessage.success("ok", topInfo);
|
||||
}
|
||||
|
||||
// @RequestMapping(value = "getTop", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
// public JsonMessage<JSONObject> getTop(Long millis) {
|
||||
// Iterator<CacheObj<String, JSONObject>> cacheObjIterator = TopManager.get();
|
||||
// List<JSONObject> series = new ArrayList<>();
|
||||
// List<String> scale = new ArrayList<>();
|
||||
// int count = 60;
|
||||
// int minSize = 12;
|
||||
// while (cacheObjIterator.hasNext()) {
|
||||
// CacheObj<String, JSONObject> cacheObj = cacheObjIterator.next();
|
||||
// String key = cacheObj.getKey();
|
||||
// scale.add(key);
|
||||
// JSONObject value = cacheObj.getValue();
|
||||
// series.add(value);
|
||||
// }
|
||||
// //限定数组最大数量
|
||||
// if (series.size() > count) {
|
||||
// series = series.subList(series.size() - count, series.size());
|
||||
// scale = scale.subList(scale.size() - count, scale.size());
|
||||
// }
|
||||
// while (scale.size() <= minSize) {
|
||||
// if (scale.size() == 0) {
|
||||
// scale.add(DateUtil.formatTime(DateUtil.date()));
|
||||
// }
|
||||
// String time = scale.get(scale.size() - 1);
|
||||
// String newTime = StringUtil.getNextScaleTime(time, millis);
|
||||
// scale.add(newTime);
|
||||
// }
|
||||
// JSONObject object = new JSONObject();
|
||||
// object.put("scales", scale);
|
||||
// object.put("series", series);
|
||||
// return JsonMessage.success("", object);
|
||||
// }
|
||||
|
||||
|
||||
@RequestMapping(value = "processList", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public JsonMessage<List<JSONObject>> getProcessList(String processName, Integer count) {
|
||||
processName = StrUtil.emptyToDefault(processName, "java");
|
||||
List<JSONObject> processes = OshiUtils.getProcesses(processName, Convert.toInt(count, 20));
|
||||
processes = processes.stream().peek(jsonObject -> {
|
||||
int processId = jsonObject.getIntValue("processId");
|
||||
String port = AbstractProjectCommander.getInstance().getMainPort(processId);
|
||||
jsonObject.put("port", port);
|
||||
//
|
||||
try {
|
||||
String jpomName = AbstractProjectCommander.getInstance().getJpomNameByPid(processId);
|
||||
jsonObject.put("jpomName", jpomName);
|
||||
} catch (IOException e) {
|
||||
log.error("解析进程失败", e);
|
||||
}
|
||||
}).collect(Collectors.toList());
|
||||
return JsonMessage.success("ok", processes);
|
||||
}
|
||||
|
||||
|
||||
@RequestMapping(value = "kill.json", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public JsonMessage<Object> kill(int pid) {
|
||||
long jpomAgentId = JpomManifest.getInstance().getPid();
|
||||
Assert.state(!StrUtil.equals(StrUtil.toString(jpomAgentId), StrUtil.toString(pid)), "不支持在线关闭 Agent 进程");
|
||||
String result = AbstractSystemCommander.getInstance().kill(null, pid);
|
||||
if (StrUtil.isEmpty(result)) {
|
||||
result = "成功kill";
|
||||
}
|
||||
return JsonMessage.success(result);
|
||||
}
|
||||
}
|
@ -28,14 +28,20 @@ import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.system.oshi.CpuInfo;
|
||||
import cn.hutool.system.oshi.OshiUtil;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import oshi.hardware.GlobalMemory;
|
||||
import lombok.Data;
|
||||
import oshi.hardware.*;
|
||||
import oshi.software.os.FileSystem;
|
||||
import oshi.software.os.NetworkParams;
|
||||
import oshi.software.os.OSFileStore;
|
||||
import oshi.software.os.OperatingSystem;
|
||||
import oshi.util.GlobalConfig;
|
||||
import oshi.util.Util;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* @author bwcx_jzy
|
||||
@ -48,14 +54,58 @@ public class OshiUtils {
|
||||
GlobalConfig.set(GlobalConfig.OSHI_OS_WINDOWS_CPU_UTILITY, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统信息
|
||||
*
|
||||
* @return json
|
||||
*/
|
||||
public static JSONObject getSystemInfo() {
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
OperatingSystem os = OshiUtil.getOs();
|
||||
jsonObject.put("systemUptime", os.getSystemUptime());
|
||||
String manufacturer = os.getManufacturer();
|
||||
String family = os.getFamily();
|
||||
OperatingSystem.OSVersionInfo versionInfo = os.getVersionInfo();
|
||||
String versionStr = versionInfo.toString();
|
||||
jsonObject.put("osVersion", StrUtil.format("{} {} {}", manufacturer, family, versionStr));
|
||||
NetworkParams networkParams = os.getNetworkParams();
|
||||
String hostName = networkParams.getHostName();
|
||||
jsonObject.put("hostName", hostName);
|
||||
//
|
||||
HardwareAbstractionLayer hardware = OshiUtil.getHardware();
|
||||
ComputerSystem computerSystem = hardware.getComputerSystem();
|
||||
jsonObject.put("hardwareVersion", StrUtil.format("{} {}", computerSystem.getManufacturer(), computerSystem.getModel()));
|
||||
List<NetworkIF> networks = hardware.getNetworkIFs();
|
||||
List<String> collect = networks.stream()
|
||||
.flatMap((Function<NetworkIF, Stream<String>>) network -> Arrays.stream(network.getIPv4addr()))
|
||||
.collect(Collectors.toList());
|
||||
jsonObject.put("hostIpv4s", collect);
|
||||
//
|
||||
CentralProcessor processor = OshiUtil.getProcessor();
|
||||
CentralProcessor.ProcessorIdentifier identifier = processor.getProcessorIdentifier();
|
||||
jsonObject.put("osCpuIdentifierName", identifier.getName());
|
||||
jsonObject.put("osCpuCores", processor.getLogicalProcessorCount());
|
||||
GlobalMemory globalMemory = OshiUtil.getMemory();
|
||||
jsonObject.put("osMoneyTotal", globalMemory.getTotal());
|
||||
double[] systemLoadAverage = processor.getSystemLoadAverage(3);
|
||||
jsonObject.put("osLoadAverage", systemLoadAverage);
|
||||
FileSystem fileSystem = os.getFileSystem();
|
||||
List<OSFileStore> fileStores = fileSystem.getFileStores();
|
||||
long total = fileStores.stream().mapToLong(OSFileStore::getTotalSpace).sum();
|
||||
jsonObject.put("osFileStoreTotal", total);
|
||||
//
|
||||
return jsonObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取信息简单的基础状态信息
|
||||
*
|
||||
* @return json
|
||||
*/
|
||||
public static JSONObject getSimpleInfo() {
|
||||
CpuInfo cpuInfo = OshiUtil.getCpuInfo();
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("time", SystemClock.now());
|
||||
CpuInfo cpuInfo = OshiUtil.getCpuInfo();
|
||||
jsonObject.put("cpu", cpuInfo.getUsed());
|
||||
//
|
||||
GlobalMemory globalMemory = OshiUtil.getMemory();
|
||||
@ -69,10 +119,37 @@ public class OshiUtils {
|
||||
used += (fs.getTotalSpace() - fs.getUsableSpace());
|
||||
}
|
||||
jsonObject.put("disk", NumberUtil.div(used, total, 2) * 100);
|
||||
jsonObject.put("time", SystemClock.now());
|
||||
//
|
||||
NetIoInfo startNetInfo = getNetInfo();
|
||||
//暂停1秒
|
||||
Util.sleep(1000);
|
||||
NetIoInfo endNetInfo = getNetInfo();
|
||||
jsonObject.put("netTxBytes", endNetInfo.getTxbyt() - startNetInfo.getTxbyt());
|
||||
jsonObject.put("netRxBytes", endNetInfo.getRxbyt() - startNetInfo.getRxbyt());
|
||||
return jsonObject;
|
||||
}
|
||||
|
||||
private static NetIoInfo getNetInfo() {
|
||||
//
|
||||
long rxBytesBegin = 0;
|
||||
long txBytesBegin = 0;
|
||||
long rxPacketsBegin = 0;
|
||||
long txPacketsBegin = 0;
|
||||
List<NetworkIF> listBegin = OshiUtil.getNetworkIFs();
|
||||
for (NetworkIF net : listBegin) {
|
||||
rxBytesBegin += net.getBytesRecv();
|
||||
txBytesBegin += net.getBytesSent();
|
||||
rxPacketsBegin += net.getPacketsRecv();
|
||||
txPacketsBegin += net.getPacketsSent();
|
||||
}
|
||||
NetIoInfo netIoInfo = new NetIoInfo();
|
||||
netIoInfo.setRxbyt(rxBytesBegin);
|
||||
netIoInfo.setTxbyt(txBytesBegin);
|
||||
netIoInfo.setRxpck(rxPacketsBegin);
|
||||
netIoInfo.setTxpck(txPacketsBegin);
|
||||
return netIoInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询进程列表
|
||||
*
|
||||
@ -111,4 +188,28 @@ public class OshiUtils {
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Data
|
||||
private static class NetIoInfo {
|
||||
/**
|
||||
* 接收的数据包,rxpck/s
|
||||
*/
|
||||
private Long rxpck;
|
||||
|
||||
/**
|
||||
* 发送的数据包,txpck/s
|
||||
*/
|
||||
private Long txpck;
|
||||
|
||||
/**
|
||||
* 接收的KB数,rxkB/s
|
||||
*/
|
||||
private Long rxbyt;
|
||||
|
||||
/**
|
||||
* 发送的KB数,txkB/s
|
||||
*/
|
||||
private Long txbyt;
|
||||
|
||||
}
|
||||
}
|
||||
|
312
modules/agent/src/test/java/oshi/SystemInfoTest.java
Normal file
312
modules/agent/src/test/java/oshi/SystemInfoTest.java
Normal file
@ -0,0 +1,312 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Code Technology Studio
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package oshi;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import oshi.hardware.*;
|
||||
import oshi.software.os.FileSystem;
|
||||
import oshi.software.os.NetworkParams;
|
||||
import oshi.software.os.OSFileStore;
|
||||
import oshi.software.os.OperatingSystem;
|
||||
import oshi.util.FormatUtil;
|
||||
import oshi.util.Util;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author bwcx_jzy
|
||||
* @since 2023/2/18
|
||||
*/
|
||||
@Slf4j
|
||||
public class SystemInfoTest {
|
||||
|
||||
/**
|
||||
* The main method.
|
||||
*
|
||||
* @param args the arguments
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
// Options: ERROR > WARN > INFO > DEBUG > TRACE
|
||||
log.info("Initializing System...");
|
||||
SystemInfo si = new SystemInfo();
|
||||
|
||||
HardwareAbstractionLayer hal = si.getHardware();
|
||||
OperatingSystem os = si.getOperatingSystem();
|
||||
|
||||
System.out.println(os);
|
||||
|
||||
log.info("Checking computer system...");
|
||||
printComputerSystem(hal.getComputerSystem());
|
||||
|
||||
log.info("Checking Processor...");
|
||||
printProcessor(hal.getProcessor());
|
||||
|
||||
log.info("Checking Memory...");
|
||||
printMemory(hal.getMemory());
|
||||
|
||||
log.info("Checking CPU...");
|
||||
printCpu(hal.getProcessor());
|
||||
|
||||
log.info("Checking Processes...");
|
||||
printProcesses(os, hal.getMemory());
|
||||
|
||||
log.info("Checking Sensors...");
|
||||
printSensors(hal.getSensors());
|
||||
|
||||
log.info("Checking Power sources...");
|
||||
printPowerSources(hal.getPowerSources());
|
||||
|
||||
log.info("Checking Disks...");
|
||||
printDisks(hal.getDiskStores());
|
||||
|
||||
log.info("Checking File System...");
|
||||
printFileSystem(os.getFileSystem());
|
||||
|
||||
log.info("Checking Network interfaces...");
|
||||
printNetworkInterfaces(hal.getNetworkIFs());
|
||||
|
||||
log.info("Checking Network parameterss...");
|
||||
printNetworkParameters(os.getNetworkParams());
|
||||
|
||||
// hardware: displays
|
||||
log.info("Checking Displays...");
|
||||
printDisplays(hal.getDisplays());
|
||||
|
||||
// hardware: USB devices
|
||||
log.info("Checking USB Devices...");
|
||||
printUsbDevices(hal.getUsbDevices(true));
|
||||
}
|
||||
|
||||
private static void printComputerSystem(final ComputerSystem computerSystem) {
|
||||
|
||||
System.out.println("manufacturer: " + computerSystem.getManufacturer());
|
||||
System.out.println("model: " + computerSystem.getModel());
|
||||
System.out.println("serialnumber: " + computerSystem.getSerialNumber());
|
||||
final Firmware firmware = computerSystem.getFirmware();
|
||||
System.out.println("firmware:");
|
||||
System.out.println(" manufacturer: " + firmware.getManufacturer());
|
||||
System.out.println(" name: " + firmware.getName());
|
||||
System.out.println(" description: " + firmware.getDescription());
|
||||
System.out.println(" version: " + firmware.getVersion());
|
||||
System.out.println(" release date: " + (firmware.getReleaseDate() == null ? "unknown"
|
||||
: firmware.getReleaseDate() == null ? "unknown" : DateUtil.parse(firmware.getReleaseDate())));
|
||||
final Baseboard baseboard = computerSystem.getBaseboard();
|
||||
System.out.println("baseboard:");
|
||||
System.out.println(" manufacturer: " + baseboard.getManufacturer());
|
||||
System.out.println(" model: " + baseboard.getModel());
|
||||
System.out.println(" version: " + baseboard.getVersion());
|
||||
System.out.println(" serialnumber: " + baseboard.getSerialNumber());
|
||||
}
|
||||
|
||||
private static void printProcessor(CentralProcessor processor) {
|
||||
System.out.println(processor);
|
||||
System.out.println(" " + processor.getPhysicalPackageCount() + " physical CPU package(s)");
|
||||
System.out.println(" " + processor.getPhysicalProcessorCount() + " physical CPU core(s)");
|
||||
System.out.println(" " + processor.getLogicalProcessorCount() + " logical CPU(s)");
|
||||
|
||||
// System.out.println("Identifier: " + processor.getIdentifier());
|
||||
// System.out.println("ProcessorID: " + processor.getProcessorID());
|
||||
}
|
||||
|
||||
private static void printMemory(GlobalMemory memory) {
|
||||
// System.out.println("Memory: " + FormatUtil.formatBytes(memory.getAvailable()) + "/"
|
||||
// + FormatUtil.formatBytes(memory.getTotal()));
|
||||
// System.out.println("Swap used: " + FormatUtil.formatBytes(memory.getSwapUsed()) + "/"
|
||||
// + FormatUtil.formatBytes(memory.getSwapTotal()));
|
||||
}
|
||||
|
||||
private static void printCpu(CentralProcessor processor) {
|
||||
// System.out.println("Uptime: " + FormatUtil.formatElapsedSecs(processor.getSystemUptime()));
|
||||
System.out.println(
|
||||
"Context Switches/Interrupts: " + processor.getContextSwitches() + " / " + processor.getInterrupts());
|
||||
|
||||
long[] prevTicks = processor.getSystemCpuLoadTicks();
|
||||
System.out.println("CPU, IOWait, and IRQ ticks @ 0 sec:" + Arrays.toString(prevTicks));
|
||||
// Wait a second...
|
||||
Util.sleep(1000);
|
||||
long[] ticks = processor.getSystemCpuLoadTicks();
|
||||
System.out.println("CPU, IOWait, and IRQ ticks @ 1 sec:" + Arrays.toString(ticks));
|
||||
// long user = ticks[TickType.USER.getIndex()] - prevTicks[TickType.USER.getIndex()];
|
||||
// long nice = ticks[TickType.NICE.getIndex()] - prevTicks[TickType.NICE.getIndex()];
|
||||
// long sys = ticks[TickType.SYSTEM.getIndex()] - prevTicks[TickType.SYSTEM.getIndex()];
|
||||
// long idle = ticks[TickType.IDLE.getIndex()] - prevTicks[TickType.IDLE.getIndex()];
|
||||
// long iowait = ticks[TickType.IOWAIT.getIndex()] - prevTicks[TickType.IOWAIT.getIndex()];
|
||||
// long irq = ticks[TickType.IRQ.getIndex()] - prevTicks[TickType.IRQ.getIndex()];
|
||||
// long softirq = ticks[TickType.SOFTIRQ.getIndex()] - prevTicks[TickType.SOFTIRQ.getIndex()];
|
||||
// long steal = ticks[TickType.STEAL.getIndex()] - prevTicks[TickType.STEAL.getIndex()];
|
||||
// long totalCpu = user + nice + sys + idle + iowait + irq + softirq + steal;
|
||||
|
||||
// System.out.format(
|
||||
// "User: %.1f%% Nice: %.1f%% System: %.1f%% Idle: %.1f%% IOwait: %.1f%% IRQ: %.1f%% SoftIRQ: %.1f%% Steal: %.1f%%%n",
|
||||
// 100d * user / totalCpu, 100d * nice / totalCpu, 100d * sys / totalCpu, 100d * idle / totalCpu,
|
||||
// 100d * iowait / totalCpu, 100d * irq / totalCpu, 100d * softirq / totalCpu, 100d * steal / totalCpu);
|
||||
// System.out.format("CPU load: %.1f%% (counting ticks)%n", processor.getSystemCpuLoadBetweenTicks() * 100);
|
||||
// System.out.format("CPU load: %.1f%% (OS MXBean)%n", processor.getSystemCpuLoad() * 100);
|
||||
// double[] loadAverage = processor.getSystemLoadAverage(3);
|
||||
// System.out.println("CPU load averages:" + (loadAverage[0] < 0 ? " N/A" : String.format(" %.2f", loadAverage[0]))
|
||||
// + (loadAverage[1] < 0 ? " N/A" : String.format(" %.2f", loadAverage[1]))
|
||||
// + (loadAverage[2] < 0 ? " N/A" : String.format(" %.2f", loadAverage[2])));
|
||||
// // per core CPU
|
||||
// StringBuilder procCpu = new StringBuilder("CPU load per processor:");
|
||||
// double[] load = processor.getProcessorCpuLoadBetweenTicks();
|
||||
// for (double avg : load) {
|
||||
// procCpu.append(String.format(" %.1f%%", avg * 100));
|
||||
// }
|
||||
// System.out.println(procCpu.toString());
|
||||
}
|
||||
|
||||
private static void printProcesses(OperatingSystem os, GlobalMemory memory) {
|
||||
// System.out.println("Processes: " + os.getProcessCount() + ", Threads: " + os.getThreadCount());
|
||||
// // Sort by highest CPU
|
||||
// List<OSProcess> procs = Arrays.asList(os.getProcesses(5, ProcessSort.CPU));
|
||||
//
|
||||
// System.out.println(" PID %CPU %MEM VSZ RSS Name");
|
||||
// for (int i = 0; i < procs.size() && i < 5; i++) {
|
||||
// OSProcess p = procs.get(i);
|
||||
// System.out.format(" %5d %5.1f %4.1f %9s %9s %s%n", p.getProcessID(),
|
||||
// 100d * (p.getKernelTime() + p.getUserTime()) / p.getUpTime(),
|
||||
// 100d * p.getResidentSetSize() / memory.getTotal(), FormatUtil.formatBytes(p.getVirtualSize()),
|
||||
// FormatUtil.formatBytes(p.getResidentSetSize()), p.getName());
|
||||
// }
|
||||
}
|
||||
|
||||
private static void printSensors(Sensors sensors) {
|
||||
System.out.println("Sensors:");
|
||||
System.out.format(" CPU Temperature: %.1f°C%n", sensors.getCpuTemperature());
|
||||
System.out.println(" Fan Speeds: " + Arrays.toString(sensors.getFanSpeeds()));
|
||||
System.out.format(" CPU Voltage: %.1fV%n", sensors.getCpuVoltage());
|
||||
}
|
||||
|
||||
private static void printPowerSources(List<PowerSource> powerSources) {
|
||||
// StringBuilder sb = new StringBuilder("Power: ");
|
||||
// if (powerSources.length == 0) {
|
||||
// sb.append("Unknown");
|
||||
// } else {
|
||||
// double timeRemaining = powerSources[0].getTimeRemaining();
|
||||
// if (timeRemaining < -1d) {
|
||||
// sb.append("Charging");
|
||||
// } else if (timeRemaining < 0d) {
|
||||
// sb.append("Calculating time remaining");
|
||||
// } else {
|
||||
// sb.append(String.format("%d:%02d remaining", (int) (timeRemaining / 3600),
|
||||
// (int) (timeRemaining / 60) % 60));
|
||||
// }
|
||||
// }
|
||||
// for (PowerSource pSource : powerSources) {
|
||||
// sb.append(String.format("%n %s @ %.1f%%", pSource.getName(), pSource.getRemainingCapacity() * 100d));
|
||||
// }
|
||||
// System.out.println(sb.toString());
|
||||
}
|
||||
|
||||
private static void printDisks(List<HWDiskStore> diskStores) {
|
||||
System.out.println("Disks:");
|
||||
for (HWDiskStore disk : diskStores) {
|
||||
boolean readwrite = disk.getReads() > 0 || disk.getWrites() > 0;
|
||||
System.out.format(" %s: (model: %s - S/N: %s) size: %s, reads: %s (%s), writes: %s (%s), xfer: %s ms%n",
|
||||
disk.getName(), disk.getModel(), disk.getSerial(),
|
||||
disk.getSize() > 0 ? FormatUtil.formatBytesDecimal(disk.getSize()) : "?",
|
||||
readwrite ? disk.getReads() : "?", readwrite ? FormatUtil.formatBytes(disk.getReadBytes()) : "?",
|
||||
readwrite ? disk.getWrites() : "?", readwrite ? FormatUtil.formatBytes(disk.getWriteBytes()) : "?",
|
||||
readwrite ? disk.getTransferTime() : "?");
|
||||
List<HWPartition> partitions = disk.getPartitions();
|
||||
if (partitions == null) {
|
||||
// TODO Remove when all OS's implemented
|
||||
continue;
|
||||
}
|
||||
for (HWPartition part : partitions) {
|
||||
System.out.format(" |-- %s: %s (%s) Maj:Min=%d:%d, size: %s%s%n", part.getIdentification(),
|
||||
part.getName(), part.getType(), part.getMajor(), part.getMinor(),
|
||||
FormatUtil.formatBytesDecimal(part.getSize()),
|
||||
part.getMountPoint().isEmpty() ? "" : " @ " + part.getMountPoint());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void printFileSystem(FileSystem fileSystem) {
|
||||
System.out.println("File System:");
|
||||
|
||||
System.out.format(" File Descriptors: %d/%d%n", fileSystem.getOpenFileDescriptors(),
|
||||
fileSystem.getMaxFileDescriptors());
|
||||
|
||||
List<OSFileStore> fsArray = fileSystem.getFileStores();
|
||||
for (OSFileStore fs : fsArray) {
|
||||
long usable = fs.getUsableSpace();
|
||||
long total = fs.getTotalSpace();
|
||||
System.out.format(
|
||||
" %s (%s) [%s] %s of %s free (%.1f%%) is %s "
|
||||
+ (fs.getLogicalVolume() != null && fs.getLogicalVolume().length() > 0 ? "[%s]" : "%s")
|
||||
+ " and is mounted at %s%n",
|
||||
fs.getName(), fs.getDescription().isEmpty() ? "file system" : fs.getDescription(), fs.getType(),
|
||||
FormatUtil.formatBytes(usable), FormatUtil.formatBytes(fs.getTotalSpace()), 100d * usable / total,
|
||||
fs.getVolume(), fs.getLogicalVolume(), fs.getMount());
|
||||
}
|
||||
}
|
||||
|
||||
private static void printNetworkInterfaces(List<NetworkIF> networkIFs) {
|
||||
System.out.println("Network interfaces:");
|
||||
for (NetworkIF net : networkIFs) {
|
||||
System.out.format(" Name: %s (%s)%n", net.getName(), net.getDisplayName());
|
||||
System.out.format(" MAC Address: %s %n", net.getMacaddr());
|
||||
System.out.format(" MTU: %s, Speed: %s %n", net.getMTU(), FormatUtil.formatValue(net.getSpeed(), "bps"));
|
||||
System.out.format(" IPv4: %s %n", Arrays.toString(net.getIPv4addr()));
|
||||
System.out.format(" IPv6: %s %n", Arrays.toString(net.getIPv6addr()));
|
||||
boolean hasData = net.getBytesRecv() > 0 || net.getBytesSent() > 0 || net.getPacketsRecv() > 0
|
||||
|| net.getPacketsSent() > 0;
|
||||
System.out.format(" Traffic: received %s/%s%s; transmitted %s/%s%s %n",
|
||||
hasData ? net.getPacketsRecv() + " packets" : "?",
|
||||
hasData ? FormatUtil.formatBytes(net.getBytesRecv()) : "?",
|
||||
hasData ? " (" + net.getInErrors() + " err)" : "",
|
||||
hasData ? net.getPacketsSent() + " packets" : "?",
|
||||
hasData ? FormatUtil.formatBytes(net.getBytesSent()) : "?",
|
||||
hasData ? " (" + net.getOutErrors() + " err)" : "");
|
||||
}
|
||||
}
|
||||
|
||||
private static void printNetworkParameters(NetworkParams networkParams) {
|
||||
System.out.println("Network parameters:");
|
||||
System.out.format(" Host name: %s%n", networkParams.getHostName());
|
||||
System.out.format(" Domain name: %s%n", networkParams.getDomainName());
|
||||
System.out.format(" DNS servers: %s%n", Arrays.toString(networkParams.getDnsServers()));
|
||||
System.out.format(" IPv4 Gateway: %s%n", networkParams.getIpv4DefaultGateway());
|
||||
System.out.format(" IPv6 Gateway: %s%n", networkParams.getIpv6DefaultGateway());
|
||||
}
|
||||
|
||||
private static void printDisplays(List<Display> displays) {
|
||||
System.out.println("Displays:");
|
||||
int i = 0;
|
||||
for (Display display : displays) {
|
||||
System.out.println(" Display " + i + ":");
|
||||
System.out.println(display.toString());
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
private static void printUsbDevices(List<UsbDevice> usbDevices) {
|
||||
System.out.println("USB Devices:");
|
||||
for (UsbDevice usbDevice : usbDevices) {
|
||||
System.out.println(usbDevice.toString());
|
||||
}
|
||||
}
|
||||
}
|
42
modules/agent/src/test/java/oshi/TestInfo.java
Normal file
42
modules/agent/src/test/java/oshi/TestInfo.java
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Code Technology Studio
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package oshi;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import io.jpom.util.OshiUtils;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @author bwcx_jzy
|
||||
* @since 2023/2/18
|
||||
*/
|
||||
public class TestInfo {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
JSONObject systemInfo = OshiUtils.getSystemInfo();
|
||||
|
||||
//System.out.println(processor);
|
||||
System.out.println(systemInfo);
|
||||
}
|
||||
}
|
@ -40,6 +40,10 @@ public class Const {
|
||||
* 默认的工作空间
|
||||
*/
|
||||
public static final String WORKSPACE_DEFAULT_ID = "DEFAULT";
|
||||
/**
|
||||
* 默认的分组名
|
||||
*/
|
||||
public static final String DEFAULT_GROUP_NAME = "默认";
|
||||
// /**
|
||||
// * websocket 传输 agent 包 buffer size
|
||||
// */
|
||||
|
@ -22,6 +22,7 @@
|
||||
*/
|
||||
package io.jpom.common;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.lang.Opt;
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
@ -51,14 +52,15 @@ public class ReplaceStreamFilter implements Filter {
|
||||
ContentCachingRequestWrapper wrapper = new ContentCachingRequestWrapper((HttpServletRequest) request);
|
||||
chain.doFilter(wrapper, response);
|
||||
long endTime = System.currentTimeMillis();
|
||||
if (endTime - startTime > 1000 * 5) {
|
||||
long l = endTime - startTime;
|
||||
if (l > 1000 * 5) {
|
||||
byte[] contentAsByteArray = wrapper.getContentAsByteArray();
|
||||
String str = StrUtil.str(contentAsByteArray, CharsetUtil.CHARSET_UTF_8);
|
||||
String reqData = Opt.ofBlankAble(str)
|
||||
.map(s -> wrapper.getParameterMap())
|
||||
.map(JSONObject::toJSONString)
|
||||
.orElse(StrUtil.EMPTY);
|
||||
log.warn("[timeout] {} {}", wrapper.getRequestURI(), reqData);
|
||||
log.warn("[timeout] {} {} {}", wrapper.getRequestURI(), reqData, DateUtil.formatBetween(l));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Code Technology Studio
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package io.jpom.common.forward;
|
||||
|
||||
import cn.hutool.core.lang.Opt;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import io.jpom.common.Const;
|
||||
import io.jpom.system.ServerConfig;
|
||||
import top.jpom.transport.DataContentType;
|
||||
import top.jpom.transport.IUrlItem;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author bwcx_jzy
|
||||
* @since 2023/2/18
|
||||
*/
|
||||
public class DefaultUrlItem implements IUrlItem {
|
||||
private final NodeUrl nodeUrl;
|
||||
private final Integer timeout;
|
||||
private final String workspaceId;
|
||||
private final DataContentType dataContentType;
|
||||
|
||||
public DefaultUrlItem(NodeUrl nodeUrl, Integer timeout, String workspaceId, DataContentType dataContentType) {
|
||||
this.nodeUrl = nodeUrl;
|
||||
this.timeout = timeout;
|
||||
this.workspaceId = workspaceId;
|
||||
this.dataContentType = dataContentType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String path() {
|
||||
return nodeUrl.getUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer timeout() {
|
||||
if (nodeUrl.isFileTimeout()) {
|
||||
ServerConfig serverConfig = SpringUtil.getBean(ServerConfig.class);
|
||||
ServerConfig.NodeConfig configNode = serverConfig.getNode();
|
||||
return configNode.getUploadFileTimeout();
|
||||
} else {
|
||||
return Optional.of(nodeUrl.getTimeout())
|
||||
.flatMap(timeOut -> {
|
||||
if (timeOut == 0) {
|
||||
// 读取节点配置的超时时间
|
||||
return Optional.ofNullable(timeout);
|
||||
}
|
||||
// 值 < 0 url 指定不超时
|
||||
return timeOut > 0 ? Optional.of(timeOut) : Optional.empty();
|
||||
})
|
||||
.map(timeOut -> {
|
||||
if (timeOut <= 0) {
|
||||
return null;
|
||||
}
|
||||
// 超时时间不能小于 2 秒
|
||||
return Math.max(timeOut, 2);
|
||||
})
|
||||
.orElse(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String workspaceId() {
|
||||
return Opt.ofBlankAble(workspaceId).orElse(Const.WORKSPACE_DEFAULT_ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataContentType contentType() {
|
||||
return dataContentType;
|
||||
}
|
||||
}
|
@ -22,17 +22,16 @@
|
||||
*/
|
||||
package io.jpom.common.forward;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.io.IORuntimeException;
|
||||
import cn.hutool.core.io.resource.BytesResource;
|
||||
import cn.hutool.core.io.unit.DataSize;
|
||||
import cn.hutool.core.lang.Opt;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.net.url.UrlQuery;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.EnumUtil;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.core.util.URLUtil;
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
import cn.hutool.extra.servlet.ServletUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
@ -41,9 +40,9 @@ import com.alibaba.fastjson2.JSONObject;
|
||||
import com.alibaba.fastjson2.TypeReference;
|
||||
import io.jpom.common.Const;
|
||||
import io.jpom.common.JsonMessage;
|
||||
import io.jpom.func.assets.model.MachineNodeModel;
|
||||
import io.jpom.func.assets.server.MachineNodeServer;
|
||||
import io.jpom.model.data.NodeModel;
|
||||
import io.jpom.model.user.UserModel;
|
||||
import io.jpom.service.node.NodeService;
|
||||
import io.jpom.system.AgentException;
|
||||
import io.jpom.system.AuthorizeException;
|
||||
import io.jpom.system.ServerConfig;
|
||||
@ -61,6 +60,8 @@ import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Proxy;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.util.*;
|
||||
@ -68,6 +69,7 @@ import java.util.concurrent.ConcurrentLinkedDeque;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
@ -79,71 +81,119 @@ import java.util.function.Function;
|
||||
@Slf4j
|
||||
public class NodeForward {
|
||||
|
||||
/**
|
||||
* 创建代理
|
||||
*
|
||||
* @param type 代理类型
|
||||
* @param httpProxy 代理地址
|
||||
* @return proxy
|
||||
*/
|
||||
public static Proxy crateProxy(String type, String httpProxy) {
|
||||
if (StrUtil.isNotEmpty(httpProxy)) {
|
||||
List<String> split = StrUtil.splitTrim(httpProxy, StrUtil.COLON);
|
||||
String host = CollUtil.getFirst(split);
|
||||
int port = Convert.toInt(CollUtil.getLast(split), 0);
|
||||
Proxy.Type type1 = EnumUtil.fromString(Proxy.Type.class, type, Proxy.Type.HTTP);
|
||||
return new Proxy(type1, new InetSocketAddress(host, port));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static INodeInfo parseNodeInfo(NodeModel nodeModel) {
|
||||
Assert.hasText(nodeModel.getMachineId(), "节点信息不完整,缺少机器id");
|
||||
MachineNodeServer machineNodeServer = SpringUtil.getBean(MachineNodeServer.class);
|
||||
MachineNodeModel model = machineNodeServer.getByKey(nodeModel.getMachineId(), false);
|
||||
Assert.notNull(model, "对应的机器信息不存在");
|
||||
return model;
|
||||
}
|
||||
|
||||
public static INodeInfo coverNodeInfo(MachineNodeModel machineNodeModel) {
|
||||
if (StrUtil.isEmpty(machineNodeModel.getId())) {
|
||||
// 新增的情况
|
||||
return machineNodeModel;
|
||||
}
|
||||
MachineNodeServer machineNodeServer = SpringUtil.getBean(MachineNodeServer.class);
|
||||
MachineNodeModel model = machineNodeServer.getByKey(machineNodeModel.getId(), false);
|
||||
Optional.ofNullable(model)
|
||||
.ifPresent(exits -> {
|
||||
String password = Opt.ofBlankAble(machineNodeModel.getJpomPassword()).orElse(exits.getJpomPassword());
|
||||
machineNodeModel.setJpomPassword(password);
|
||||
});
|
||||
return machineNodeModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建节点 url
|
||||
*
|
||||
* @param iNodeInfo 节点信息
|
||||
* @param nodeUrl 节点功能 url
|
||||
* @param dataContentType 传输的数据类型
|
||||
*/
|
||||
public static IUrlItem parseUrlItem(INodeInfo iNodeInfo, String workspaceId, NodeUrl nodeUrl, DataContentType dataContentType) {
|
||||
//
|
||||
return new DefaultUrlItem(nodeUrl, iNodeInfo.timeout(), workspaceId, dataContentType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建节点 url
|
||||
*
|
||||
* @param iNodeInfo 节点信息
|
||||
* @param nodeUrl 节点功能 url
|
||||
*/
|
||||
public static IUrlItem parseUrlItem(INodeInfo iNodeInfo, String workspaceId, NodeUrl nodeUrl) {
|
||||
//
|
||||
return new DefaultUrlItem(nodeUrl, iNodeInfo.timeout(), workspaceId, DataContentType.FORM_URLENCODED);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建节点 url
|
||||
*
|
||||
* @param nodeModel 节点信息
|
||||
* @param nodeUrl 节点功能 url
|
||||
* @param dataContentType 传输的数据类型
|
||||
* @return item
|
||||
*/
|
||||
public static IUrlItem createUrlItem(NodeModel nodeModel, NodeUrl nodeUrl, DataContentType dataContentType) {
|
||||
// 修正节点密码
|
||||
if (StrUtil.isEmpty(nodeModel.getLoginPwd())) {
|
||||
NodeService nodeService = SpringUtil.getBean(NodeService.class);
|
||||
NodeModel model = nodeService.getByKey(nodeModel.getId(), false);
|
||||
nodeModel.setLoginPwd(model.getLoginPwd());
|
||||
nodeModel.setLoginName(model.getLoginName());
|
||||
}
|
||||
public static <T> T createUrlItem(NodeModel nodeModel, NodeUrl nodeUrl, DataContentType dataContentType, BiFunction<INodeInfo, IUrlItem, T> consumer) {
|
||||
INodeInfo parseNodeInfo = parseNodeInfo(nodeModel);
|
||||
//
|
||||
return new IUrlItem() {
|
||||
@Override
|
||||
public String path() {
|
||||
return nodeUrl.getUrl();
|
||||
IUrlItem iUrlItem = new DefaultUrlItem(nodeUrl, parseNodeInfo.timeout(), nodeModel.getWorkspaceId(), dataContentType);
|
||||
return consumer.apply(parseNodeInfo, iUrlItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer timeout() {
|
||||
if (nodeUrl.isFileTimeout()) {
|
||||
ServerConfig serverConfig = SpringUtil.getBean(ServerConfig.class);
|
||||
ServerConfig.NodeConfig configNode = serverConfig.getNode();
|
||||
return configNode.getUploadFileTimeout();
|
||||
} else {
|
||||
return Optional.of(nodeUrl.getTimeout())
|
||||
.flatMap(timeOut -> {
|
||||
if (timeOut == 0) {
|
||||
// 读取节点配置的超时时间
|
||||
return Optional.ofNullable(nodeModel.getTimeOut());
|
||||
}
|
||||
// 值 < 0 url 指定不超时
|
||||
return timeOut > 0 ? Optional.of(timeOut) : Optional.empty();
|
||||
})
|
||||
.map(timeOut -> {
|
||||
if (timeOut <= 0) {
|
||||
return null;
|
||||
}
|
||||
// 超时时间不能小于 2 秒
|
||||
return Math.max(timeOut, 2);
|
||||
})
|
||||
.orElse(null);
|
||||
}
|
||||
private static <T> T createUrlItem(NodeModel nodeModel, NodeUrl nodeUrl, BiFunction<INodeInfo, IUrlItem, T> consumer) {
|
||||
return createUrlItem(nodeModel, nodeUrl, DataContentType.FORM_URLENCODED, consumer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String workspaceId() {
|
||||
return Optional.ofNullable(nodeModel.getWorkspaceId()).orElse(Const.WORKSPACE_DEFAULT_ID);
|
||||
private static <T> T createUrlItem(INodeInfo nodeInfo, String workspaceId, NodeUrl nodeUrl, BiFunction<INodeInfo, IUrlItem, T> consumer) {
|
||||
return createUrlItem(nodeInfo, workspaceId, nodeUrl, DataContentType.FORM_URLENCODED, consumer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataContentType contentType() {
|
||||
return dataContentType;
|
||||
}
|
||||
};
|
||||
private static <T> T createUrlItem(INodeInfo nodeInfo, String workspaceId, NodeUrl nodeUrl, DataContentType dataContentType, BiFunction<INodeInfo, IUrlItem, T> consumer) {
|
||||
//
|
||||
IUrlItem iUrlItem = new DefaultUrlItem(nodeUrl, nodeInfo.timeout(), workspaceId, dataContentType);
|
||||
return consumer.apply(nodeInfo, iUrlItem);
|
||||
}
|
||||
|
||||
private static IUrlItem createUrlItem(NodeModel nodeModel, NodeUrl nodeUrl) {
|
||||
return createUrlItem(nodeModel, nodeUrl, DataContentType.FORM_URLENCODED);
|
||||
}
|
||||
// /**
|
||||
// * 普通消息转发
|
||||
// *
|
||||
// * @param nodeInfo 节点信息
|
||||
// * @param request 请求
|
||||
// * @param nodeUrl 节点的url
|
||||
// * @param <T> 泛型
|
||||
// * @return JSON
|
||||
// */
|
||||
// private static <T> JsonMessage<T> request(INodeInfo nodeInfo, HttpServletRequest request, NodeUrl nodeUrl, String... removeKeys) {
|
||||
// Map<String, String> map = Optional.ofNullable(request)
|
||||
// .map(ServletUtil::getParamMap)
|
||||
// .map(map1 -> MapUtil.removeAny(map1, removeKeys))
|
||||
// .orElse(null);
|
||||
// TypeReference<JsonMessage<T>> tTypeReference = new TypeReference<JsonMessage<T>>() {
|
||||
// };
|
||||
// return createUrlItem(nodeInfo, StrUtil.EMPTY, nodeUrl,
|
||||
// (nodeInfo1, urlItem) ->
|
||||
// TransportServerFactory.get().executeToType(nodeInfo1, urlItem, map, tTypeReference)
|
||||
// );
|
||||
// }
|
||||
|
||||
/**
|
||||
* 普通消息转发
|
||||
@ -159,9 +209,12 @@ public class NodeForward {
|
||||
.map(ServletUtil::getParamMap)
|
||||
.map(map1 -> MapUtil.removeAny(map1, removeKeys))
|
||||
.orElse(null);
|
||||
IUrlItem urlItem = createUrlItem(nodeModel, nodeUrl);
|
||||
return TransportServerFactory.get().executeToType(nodeModel, urlItem, map, new TypeReference<JsonMessage<T>>() {
|
||||
});
|
||||
TypeReference<JsonMessage<T>> tTypeReference = new TypeReference<JsonMessage<T>>() {
|
||||
};
|
||||
return createUrlItem(nodeModel, nodeUrl,
|
||||
(nodeInfo, urlItem) ->
|
||||
TransportServerFactory.get().executeToType(nodeInfo, urlItem, map, tTypeReference)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -173,11 +226,40 @@ public class NodeForward {
|
||||
* @return JSON
|
||||
*/
|
||||
public static <T> JsonMessage<T> request(NodeModel nodeModel, NodeUrl nodeUrl, JSONObject jsonObject) {
|
||||
IUrlItem urlItem = createUrlItem(nodeModel, nodeUrl);
|
||||
return TransportServerFactory.get().executeToType(nodeModel, urlItem, jsonObject, new TypeReference<JsonMessage<T>>() {
|
||||
});
|
||||
TypeReference<JsonMessage<T>> tTypeReference = new TypeReference<JsonMessage<T>>() {
|
||||
};
|
||||
return createUrlItem(nodeModel, nodeUrl, (nodeInfo, urlItem) -> TransportServerFactory.get().executeToType(nodeInfo, urlItem, jsonObject, tTypeReference));
|
||||
}
|
||||
|
||||
/**
|
||||
* 普通消息转发
|
||||
*
|
||||
* @param machineNodeModel 节点
|
||||
* @param nodeUrl 节点的url
|
||||
* @param jsonObject 数据
|
||||
* @return JSON
|
||||
*/
|
||||
public static <T> JsonMessage<T> request(MachineNodeModel machineNodeModel, NodeUrl nodeUrl, JSONObject jsonObject) {
|
||||
TypeReference<JsonMessage<T>> typeReference = new TypeReference<JsonMessage<T>>() {
|
||||
};
|
||||
INodeInfo nodeInfo = coverNodeInfo(machineNodeModel);
|
||||
return createUrlItem(nodeInfo, StrUtil.EMPTY, nodeUrl, (nodeInfo1, urlItem) -> TransportServerFactory.get().executeToType(nodeInfo1, urlItem, jsonObject, typeReference));
|
||||
}
|
||||
|
||||
// /**
|
||||
// * 普通消息转发
|
||||
// *
|
||||
// * @param nodeInfo 节点
|
||||
// * @param nodeUrl 节点的url
|
||||
// * @param jsonObject 数据
|
||||
// * @return JSON
|
||||
// */
|
||||
// private static <T> JsonMessage<T> request(INodeInfo nodeInfo, NodeUrl nodeUrl, JSONObject jsonObject) {
|
||||
// TypeReference<JsonMessage<T>> typeReference = new TypeReference<JsonMessage<T>>() {
|
||||
// };
|
||||
// return createUrlItem(nodeInfo, StrUtil.EMPTY, nodeUrl, (nodeInfo1, urlItem) -> TransportServerFactory.get().executeToType(nodeInfo1, urlItem, jsonObject, typeReference));
|
||||
// }
|
||||
|
||||
/**
|
||||
* 普通消息转发
|
||||
*
|
||||
@ -187,7 +269,35 @@ public class NodeForward {
|
||||
* @return JSON
|
||||
*/
|
||||
public static <T> JsonMessage<T> requestSharding(NodeModel nodeModel, NodeUrl nodeUrl, JSONObject jsonObject, File file, Function<JSONObject, JsonMessage<T>> doneCallback, BiConsumer<Long, Long> streamProgress) throws IOException {
|
||||
IUrlItem urlItem = createUrlItem(nodeModel, nodeUrl);
|
||||
INodeInfo nodeInfo = parseNodeInfo(nodeModel);
|
||||
return requestSharding(nodeInfo, nodeModel.getWorkspaceId(), nodeUrl, jsonObject, file, doneCallback, streamProgress);
|
||||
}
|
||||
|
||||
/**
|
||||
* 普通消息转发
|
||||
*
|
||||
* @param machineNodeModel 节点
|
||||
* @param nodeUrl 节点的url
|
||||
* @param jsonObject 数据
|
||||
* @return JSON
|
||||
*/
|
||||
public static <T> JsonMessage<T> requestSharding(MachineNodeModel machineNodeModel, NodeUrl nodeUrl, JSONObject jsonObject, File file, Function<JSONObject, JsonMessage<T>> doneCallback, BiConsumer<Long, Long> streamProgress) throws IOException {
|
||||
INodeInfo nodeInfo = coverNodeInfo(machineNodeModel);
|
||||
return requestSharding(nodeInfo, StrUtil.EMPTY, nodeUrl, jsonObject, file, doneCallback, streamProgress);
|
||||
}
|
||||
|
||||
/**
|
||||
* 普通消息转发
|
||||
*
|
||||
* @param nodeInfo 节点
|
||||
* @param workspaceId 工作空间id
|
||||
* @param streamProgress 进度回调
|
||||
* @param nodeUrl 节点的url
|
||||
* @param jsonObject 数据
|
||||
* @return JSON
|
||||
*/
|
||||
private static <T> JsonMessage<T> requestSharding(INodeInfo nodeInfo, String workspaceId, NodeUrl nodeUrl, JSONObject jsonObject, File file, Function<JSONObject, JsonMessage<T>> doneCallback, BiConsumer<Long, Long> streamProgress) throws IOException {
|
||||
IUrlItem urlItem = parseUrlItem(nodeInfo, workspaceId, nodeUrl, DataContentType.FORM_URLENCODED);
|
||||
ServerConfig serverConfig = SpringUtil.getBean(ServerConfig.class);
|
||||
ServerConfig.NodeConfig nodeConfig = serverConfig.getNode();
|
||||
long length = file.length();
|
||||
@ -242,7 +352,7 @@ public class NodeForward {
|
||||
}
|
||||
}
|
||||
// 上传
|
||||
JsonMessage<T> message = transportServer.executeToType(nodeModel, urlItem, uploadData, typeReference);
|
||||
JsonMessage<T> message = transportServer.executeToType(nodeInfo, urlItem, uploadData, typeReference);
|
||||
if (message.success()) {
|
||||
// 使用成功的个数计算
|
||||
success.add(currentChunk);
|
||||
@ -292,13 +402,49 @@ public class NodeForward {
|
||||
* @return JSON
|
||||
*/
|
||||
public static <T> JsonMessage<T> request(NodeModel nodeModel, NodeUrl nodeUrl, String pName, Object pVal, Object... parameters) {
|
||||
|
||||
INodeInfo parseNodeInfo = parseNodeInfo(nodeModel);
|
||||
return request(parseNodeInfo, nodeModel.getWorkspaceId(), nodeUrl, pName, pVal, parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* 普通消息转发
|
||||
*
|
||||
* @param machineNodeModel 节点
|
||||
* @param workspaceId 工作空间id
|
||||
* @param nodeUrl 节点的url
|
||||
* @param pName 主参数名
|
||||
* @param pVal 主参数值
|
||||
* @param parameters 其他参数
|
||||
* @return JSON
|
||||
*/
|
||||
public static <T> JsonMessage<T> request(MachineNodeModel machineNodeModel, String workspaceId, NodeUrl nodeUrl, String pName, Object pVal, Object... parameters) {
|
||||
Map<String, Object> parametersMap = MapUtil.of(pName, pVal);
|
||||
for (int i = 0; i < parameters.length; i += 2) {
|
||||
parametersMap.put(parameters[i].toString(), parameters[i + 1]);
|
||||
}
|
||||
IUrlItem urlItem = createUrlItem(nodeModel, nodeUrl);
|
||||
INodeInfo nodeInfo = coverNodeInfo(machineNodeModel);
|
||||
return request(nodeInfo, workspaceId, nodeUrl, pName, pVal, parameters);
|
||||
}
|
||||
|
||||
return TransportServerFactory.get().executeToType(nodeModel, urlItem, parametersMap, new TypeReference<JsonMessage<T>>() {
|
||||
/**
|
||||
* 普通消息转发
|
||||
*
|
||||
* @param nodeInfo 节点
|
||||
* @param workspaceId 工作空间id
|
||||
* @param nodeUrl 节点的url
|
||||
* @param pName 主参数名
|
||||
* @param pVal 主参数值
|
||||
* @param parameters 其他参数
|
||||
* @return JSON
|
||||
*/
|
||||
private static <T> JsonMessage<T> request(INodeInfo nodeInfo, String workspaceId, NodeUrl nodeUrl, String pName, Object pVal, Object... parameters) {
|
||||
Map<String, Object> parametersMap = MapUtil.of(pName, pVal);
|
||||
for (int i = 0; i < parameters.length; i += 2) {
|
||||
parametersMap.put(parameters[i].toString(), parameters[i + 1]);
|
||||
}
|
||||
IUrlItem iUrlItem = parseUrlItem(nodeInfo, workspaceId, nodeUrl);
|
||||
return TransportServerFactory.get().executeToType(nodeInfo, iUrlItem, parametersMap, new TypeReference<JsonMessage<T>>() {
|
||||
});
|
||||
}
|
||||
|
||||
@ -312,10 +458,11 @@ public class NodeForward {
|
||||
* @return JSON
|
||||
*/
|
||||
public static <T> JsonMessage<T> requestBody(NodeModel nodeModel, NodeUrl nodeUrl, JSONObject jsonData) {
|
||||
TypeReference<JsonMessage<T>> tTypeReference = new TypeReference<JsonMessage<T>>() {
|
||||
};
|
||||
return createUrlItem(nodeModel, nodeUrl, DataContentType.JSON,
|
||||
(nodeInfo, urlItem) -> TransportServerFactory.get().executeToType(nodeInfo, urlItem, jsonData, tTypeReference));
|
||||
|
||||
IUrlItem urlItem = createUrlItem(nodeModel, nodeUrl, DataContentType.JSON);
|
||||
return TransportServerFactory.get().executeToType(nodeModel, urlItem, jsonData, new TypeReference<JsonMessage<T>>() {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -357,10 +504,8 @@ public class NodeForward {
|
||||
*/
|
||||
public static <T> T requestData(NodeModel nodeModel, NodeUrl nodeUrl, HttpServletRequest request, Class<T> tClass) {
|
||||
Map<String, String> map = Optional.ofNullable(request).map(ServletUtil::getParamMap).orElse(null);
|
||||
IUrlItem urlItem = createUrlItem(nodeModel, nodeUrl);
|
||||
return TransportServerFactory.get().executeToTypeOnlyData(nodeModel, urlItem, map, tClass);
|
||||
// JsonMessage<T> jsonMessage = request(nodeModel, request, nodeUrl);
|
||||
// return jsonMessage.getData(tClass);
|
||||
return createUrlItem(nodeModel, nodeUrl, (nodeInfo, urlItem) -> TransportServerFactory.get().executeToTypeOnlyData(nodeInfo, urlItem, map, tClass));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -374,7 +519,7 @@ public class NodeForward {
|
||||
*/
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public static JsonMessage<String> requestMultipart(NodeModel nodeModel, MultipartHttpServletRequest request, NodeUrl nodeUrl) {
|
||||
IUrlItem urlItem = createUrlItem(nodeModel, nodeUrl);
|
||||
|
||||
//
|
||||
Map params = ServletUtil.getParamMap(request);
|
||||
//
|
||||
@ -387,8 +532,11 @@ public class NodeForward {
|
||||
throw Lombok.sneakyThrow(e);
|
||||
}
|
||||
});
|
||||
return TransportServerFactory.get().executeToType(nodeModel, urlItem, params, new TypeReference<JsonMessage<String>>() {
|
||||
});
|
||||
TypeReference<JsonMessage<String>> tTypeReference = new TypeReference<JsonMessage<String>>() {
|
||||
};
|
||||
return createUrlItem(nodeModel, nodeUrl,
|
||||
(nodeInfo, urlItem) -> TransportServerFactory.get().executeToType(nodeInfo, urlItem, params, tTypeReference));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -400,57 +548,55 @@ public class NodeForward {
|
||||
* @param nodeUrl 节点的url
|
||||
*/
|
||||
public static void requestDownload(NodeModel nodeModel, HttpServletRequest request, HttpServletResponse response, NodeUrl nodeUrl) {
|
||||
IUrlItem urlItem = createUrlItem(nodeModel, nodeUrl);
|
||||
//
|
||||
Map<String, String> params = ServletUtil.getParamMap(request);
|
||||
TransportServerFactory.get().download(nodeModel, urlItem, params, downloadCallback -> {
|
||||
createUrlItem(nodeModel, nodeUrl, (nodeInfo, urlItem) -> {
|
||||
TransportServerFactory.get().download(nodeInfo, urlItem, params, downloadCallback -> {
|
||||
Opt.ofBlankAble(downloadCallback.getContentDisposition())
|
||||
.ifPresent(s -> response.setHeader(HttpHeaders.CONTENT_DISPOSITION, s));
|
||||
response.setContentType(downloadCallback.getContentType());
|
||||
ServletUtil.write(response, downloadCallback.getInputStream());
|
||||
});
|
||||
return null;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取节点socket 信息
|
||||
*
|
||||
* @param nodeModel 节点信息
|
||||
* @param nodeUrl url
|
||||
* @return url
|
||||
*/
|
||||
public static String getSocketUrl(NodeModel nodeModel, NodeUrl nodeUrl, UserModel userInfo, Object... parameters) {
|
||||
String ws;
|
||||
if ("https".equalsIgnoreCase(nodeModel.getProtocol())) {
|
||||
ws = "wss";
|
||||
} else {
|
||||
ws = "ws";
|
||||
}
|
||||
if (StrUtil.isEmpty(nodeModel.getLoginPwd())) {
|
||||
NodeService nodeService = SpringUtil.getBean(NodeService.class);
|
||||
NodeModel model = nodeService.getByKey(nodeModel.getId(), false);
|
||||
nodeModel.setLoginPwd(model.getLoginPwd());
|
||||
nodeModel.setLoginName(model.getLoginName());
|
||||
}
|
||||
UrlQuery urlQuery = new UrlQuery();
|
||||
urlQuery.add(Const.JPOM_AGENT_AUTHORIZE, nodeModel.toAuthorize());
|
||||
//
|
||||
String optUser = userInfo.getId();
|
||||
optUser = URLUtil.encode(optUser);
|
||||
urlQuery.add("optUser", optUser);
|
||||
if (ArrayUtil.isNotEmpty(parameters)) {
|
||||
for (int i = 0; i < parameters.length; i += 2) {
|
||||
Object parameter = parameters[i + 1];
|
||||
String value = Convert.toStr(parameter, StrUtil.EMPTY);
|
||||
urlQuery.add(parameters[i].toString(), URLUtil.encode(value));
|
||||
}
|
||||
}
|
||||
// 兼容旧版本-节点升级 @author jzy
|
||||
//urlQuery.add("name", URLUtil.encode(nodeModel.getLoginName()));
|
||||
//urlQuery.add("password", URLUtil.encode(nodeModel.getLoginPwd()));
|
||||
String format = StrUtil.format("{}://{}{}?{}", ws, nodeModel.getUrl(), nodeUrl.getUrl(), urlQuery.toString());
|
||||
log.debug("web socket url:{}", format);
|
||||
return format;
|
||||
}
|
||||
// /**
|
||||
// * 获取节点socket 信息
|
||||
// *
|
||||
// * @param nodeModel 节点信息
|
||||
// * @param nodeUrl url
|
||||
// * @return url
|
||||
// */
|
||||
// public static String getSocketUrl(NodeModel nodeModel, NodeUrl nodeUrl, UserModel userInfo, Object... parameters) {
|
||||
// INodeInfo nodeInfo = parseNodeInfo(nodeModel);
|
||||
// String ws;
|
||||
// if ("https".equalsIgnoreCase(nodeInfo.scheme())) {
|
||||
// ws = "wss";
|
||||
// } else {
|
||||
// ws = "ws";
|
||||
// }
|
||||
// UrlQuery urlQuery = new UrlQuery();
|
||||
// urlQuery.add(Const.JPOM_AGENT_AUTHORIZE, nodeInfo.authorize());
|
||||
// //
|
||||
// String optUser = userInfo.getId();
|
||||
// optUser = URLUtil.encode(optUser);
|
||||
// urlQuery.add("optUser", optUser);
|
||||
// if (ArrayUtil.isNotEmpty(parameters)) {
|
||||
// for (int i = 0; i < parameters.length; i += 2) {
|
||||
// Object parameter = parameters[i + 1];
|
||||
// String value = Convert.toStr(parameter, StrUtil.EMPTY);
|
||||
// urlQuery.add(parameters[i].toString(), URLUtil.encode(value));
|
||||
// }
|
||||
// }
|
||||
// // 兼容旧版本-节点升级 @author jzy
|
||||
// //urlQuery.add("name", URLUtil.encode(nodeModel.getLoginName()));
|
||||
// //urlQuery.add("password", URLUtil.encode(nodeModel.getLoginPwd()));
|
||||
// String format = StrUtil.format("{}://{}{}?{}", ws, nodeInfo.url(), nodeUrl.getUrl(), urlQuery.toString());
|
||||
// log.debug("web socket url:{}", format);
|
||||
// return format;
|
||||
// }
|
||||
|
||||
public static <T> T toJsonMessage(String body, TypeReference<T> tTypeReference) {
|
||||
if (StrUtil.isEmpty(body)) {
|
||||
|
@ -40,8 +40,7 @@ public enum NodeUrl {
|
||||
*
|
||||
*/
|
||||
// GetTop("/getTop"),
|
||||
GetDirectTop("/getDirectTop"),
|
||||
Status("/status"),
|
||||
GetStatInfo("/get-stat-info"),
|
||||
exportTop("/exportTop"),
|
||||
Kill("/kill.json"),
|
||||
|
||||
|
@ -23,14 +23,11 @@
|
||||
package io.jpom.controller.node;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import io.jpom.common.BaseServerController;
|
||||
import io.jpom.common.JsonMessage;
|
||||
import io.jpom.common.ServerConst;
|
||||
import io.jpom.common.forward.NodeForward;
|
||||
import io.jpom.common.forward.NodeUrl;
|
||||
import io.jpom.common.validator.ValidatorItem;
|
||||
import io.jpom.func.assets.server.MachineNodeServer;
|
||||
import io.jpom.model.data.NodeModel;
|
||||
import io.jpom.model.node.ProjectInfoCacheModel;
|
||||
import io.jpom.model.node.ScriptCacheModel;
|
||||
@ -45,10 +42,12 @@ import io.jpom.service.node.script.NodeScriptExecuteLogServer;
|
||||
import io.jpom.service.node.script.NodeScriptServer;
|
||||
import io.jpom.service.outgiving.LogReadServer;
|
||||
import io.jpom.service.outgiving.OutGivingServer;
|
||||
import io.jpom.service.stat.NodeStatService;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import top.jpom.model.PageResultDto;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
@ -71,8 +70,8 @@ public class NodeEditController extends BaseServerController {
|
||||
private final LogReadServer logReadServer;
|
||||
private final ProjectInfoCacheService projectInfoCacheService;
|
||||
private final NodeScriptServer nodeScriptServer;
|
||||
private final NodeStatService nodeStatService;
|
||||
private final NodeScriptExecuteLogServer nodeScriptExecuteLogServer;
|
||||
private final MachineNodeServer machineNodeServer;
|
||||
|
||||
public NodeEditController(OutGivingServer outGivingServer,
|
||||
MonitorService monitorService,
|
||||
@ -80,23 +79,24 @@ public class NodeEditController extends BaseServerController {
|
||||
LogReadServer logReadServer,
|
||||
ProjectInfoCacheService projectInfoCacheService,
|
||||
NodeScriptServer nodeScriptServer,
|
||||
NodeStatService nodeStatService,
|
||||
NodeScriptExecuteLogServer nodeScriptExecuteLogServer) {
|
||||
NodeScriptExecuteLogServer nodeScriptExecuteLogServer,
|
||||
MachineNodeServer machineNodeServer) {
|
||||
this.outGivingServer = outGivingServer;
|
||||
this.monitorService = monitorService;
|
||||
this.buildService = buildService;
|
||||
this.logReadServer = logReadServer;
|
||||
this.projectInfoCacheService = projectInfoCacheService;
|
||||
this.nodeScriptServer = nodeScriptServer;
|
||||
this.nodeStatService = nodeStatService;
|
||||
this.nodeScriptExecuteLogServer = nodeScriptExecuteLogServer;
|
||||
this.machineNodeServer = machineNodeServer;
|
||||
}
|
||||
|
||||
|
||||
@PostMapping(value = "list_data.json", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Feature(method = MethodFeature.LIST)
|
||||
public JsonMessage<PageResultDto<NodeModel>> listJson() {
|
||||
PageResultDto<NodeModel> nodeModelPageResultDto = nodeService.listPage(getRequest());
|
||||
public JsonMessage<PageResultDto<NodeModel>> listJson(HttpServletRequest request) {
|
||||
PageResultDto<NodeModel> nodeModelPageResultDto = nodeService.listPage(request);
|
||||
nodeModelPageResultDto.each(nodeModel -> nodeModel.setMachineNodeData(machineNodeServer.getByKey(nodeModel.getMachineId())));
|
||||
return JsonMessage.success("", nodeModelPageResultDto);
|
||||
}
|
||||
|
||||
@ -131,24 +131,10 @@ public class NodeEditController extends BaseServerController {
|
||||
return JsonMessage.success("", listGroup);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "node_status", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Feature(method = MethodFeature.LIST)
|
||||
public JsonMessage<JSONArray> nodeStatus() {
|
||||
long timeMillis = System.currentTimeMillis();
|
||||
NodeModel node = getNode();
|
||||
JSONObject jsonObject = NodeForward.requestData(node, NodeUrl.Status, getRequest(), JSONObject.class);
|
||||
Assert.notNull(jsonObject, "获取信息失败");
|
||||
JSONArray jsonArray = new JSONArray();
|
||||
jsonObject.put("timeOut", System.currentTimeMillis() - timeMillis);
|
||||
jsonObject.put("nodeId", node.getId());
|
||||
jsonArray.add(jsonObject);
|
||||
return JsonMessage.success("", jsonArray);
|
||||
}
|
||||
|
||||
@PostMapping(value = "save.json", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Feature(method = MethodFeature.EDIT)
|
||||
public JsonMessage<String> save() {
|
||||
nodeService.update(getRequest());
|
||||
public JsonMessage<String> save(HttpServletRequest request) {
|
||||
nodeService.update(request);
|
||||
return JsonMessage.success("操作成功");
|
||||
}
|
||||
|
||||
@ -202,8 +188,6 @@ public class NodeEditController extends BaseServerController {
|
||||
//
|
||||
int i = nodeService.delByKey(id, request);
|
||||
if (i > 0) {
|
||||
// 删除节点统计数据
|
||||
nodeStatService.delByKey(id);
|
||||
//
|
||||
nodeScriptExecuteLogServer.delCache(id, request);
|
||||
}
|
||||
@ -227,21 +211,6 @@ public class NodeEditController extends BaseServerController {
|
||||
return JsonMessage.success("操作成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 解锁节点,通过插件端自动注册的节点默认未分配工作空间
|
||||
*
|
||||
* @param id 节点ID
|
||||
* @param toWorkspaceId 分配到到工作空间ID
|
||||
* @return msg
|
||||
*/
|
||||
@GetMapping(value = "un_lock_workspace", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Feature(method = MethodFeature.EDIT)
|
||||
@SystemPermission()
|
||||
public JsonMessage<String> unLockWorkspace(@ValidatorItem String id, @ValidatorItem String toWorkspaceId) {
|
||||
nodeService.checkUserWorkspace(toWorkspaceId);
|
||||
nodeService.unLock(id, toWorkspaceId);
|
||||
return JsonMessage.success("操作成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步到指定工作空间
|
||||
|
@ -20,75 +20,97 @@
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package io.jpom.controller.node;
|
||||
|
||||
import cn.hutool.core.collection.CollStreamUtil;
|
||||
import cn.hutool.db.Entity;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import io.jpom.common.BaseServerController;
|
||||
import io.jpom.common.JsonMessage;
|
||||
import io.jpom.model.stat.NodeStatModel;
|
||||
import io.jpom.permission.ClassFeature;
|
||||
import io.jpom.permission.Feature;
|
||||
import io.jpom.permission.MethodFeature;
|
||||
import io.jpom.service.stat.NodeStatService;
|
||||
import io.jpom.system.ServerConfig;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import top.jpom.model.PageResultDto;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author bwcx_jzy
|
||||
* @since 2022/1/22
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping(value = "/node/stat")
|
||||
@Feature(cls = ClassFeature.NODE_STAT)
|
||||
public class NodeStatController extends BaseServerController {
|
||||
|
||||
private final NodeStatService nodeStatService;
|
||||
private final ServerConfig.NodeConfig nodeConfig;
|
||||
|
||||
public NodeStatController(NodeStatService nodeStatService,
|
||||
ServerConfig serverConfig) {
|
||||
this.nodeStatService = nodeStatService;
|
||||
this.nodeConfig = serverConfig.getNode();
|
||||
}
|
||||
|
||||
@PostMapping(value = "list_data.json", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Feature(method = MethodFeature.LIST)
|
||||
public JsonMessage<PageResultDto<NodeStatModel>> listJson() {
|
||||
PageResultDto<NodeStatModel> nodeModelPageResultDto = nodeStatService.listPage(getRequest());
|
||||
return JsonMessage.success("", nodeModelPageResultDto);
|
||||
}
|
||||
|
||||
@GetMapping(value = "status_stat.json", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Feature(method = MethodFeature.LIST)
|
||||
public JsonMessage<JSONObject> statusStat() {
|
||||
String workspaceId = nodeStatService.getCheckUserWorkspace(getRequest());
|
||||
///*
|
||||
// * The MIT License (MIT)
|
||||
// *
|
||||
// * Copyright (c) 2019 Code Technology Studio
|
||||
// *
|
||||
// * Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// * this software and associated documentation files (the "Software"), to deal in
|
||||
// * the Software without restriction, including without limitation the rights to
|
||||
// * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// * the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// * subject to the following conditions:
|
||||
// *
|
||||
// * The above copyright notice and this permission notice shall be included in all
|
||||
// * copies or substantial portions of the Software.
|
||||
// *
|
||||
// * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// */
|
||||
//package io.jpom.controller.node;
|
||||
//
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("heartSecond", nodeConfig.getHeartSecond());
|
||||
{
|
||||
// 节点状态
|
||||
String sql = "select `status`,count(1) as cunt from " + nodeStatService.getTableName() + " where workspaceId=? group by `status`";
|
||||
List<Entity> list = nodeStatService.query(sql, workspaceId);
|
||||
Map<String, Integer> map = CollStreamUtil.toMap(list, entity -> entity.getStr("status"), entity -> entity.getInt("cunt"));
|
||||
jsonObject.put("status", map);
|
||||
}
|
||||
// {
|
||||
// // 启用状态
|
||||
// String sql = "select `openStatus`,count(1) as cunt from " + nodeService.getTableName() + " where workspaceId=? group by `openStatus`";
|
||||
// List<Entity> list = nodeStatService.query(sql, workspaceId);
|
||||
// Map<String, Integer> map = CollStreamUtil.toMap(list, entity -> entity.getStr("openStatus"), entity -> entity.getInt("cunt"));
|
||||
// jsonObject.put("openStatus", map);
|
||||
//import cn.hutool.core.collection.CollStreamUtil;
|
||||
//import cn.hutool.db.Entity;
|
||||
//import com.alibaba.fastjson2.JSONObject;
|
||||
//import io.jpom.common.BaseServerController;
|
||||
//import io.jpom.common.JsonMessage;
|
||||
//import io.jpom.model.stat.NodeStatModel;
|
||||
//import io.jpom.permission.ClassFeature;
|
||||
//import io.jpom.permission.Feature;
|
||||
//import io.jpom.permission.MethodFeature;
|
||||
//import io.jpom.service.stat.NodeStatService;
|
||||
//import io.jpom.system.ServerConfig;
|
||||
//import org.springframework.http.MediaType;
|
||||
//import org.springframework.web.bind.annotation.GetMapping;
|
||||
//import org.springframework.web.bind.annotation.PostMapping;
|
||||
//import org.springframework.web.bind.annotation.RequestMapping;
|
||||
//import org.springframework.web.bind.annotation.RestController;
|
||||
//import top.jpom.model.PageResultDto;
|
||||
//
|
||||
//import java.util.List;
|
||||
//import java.util.Map;
|
||||
//
|
||||
///**
|
||||
// * @author bwcx_jzy
|
||||
// * @since 2022/1/22
|
||||
// */
|
||||
//@RestController
|
||||
//@RequestMapping(value = "/node/stat")
|
||||
//@Feature(cls = ClassFeature.NODE_STAT)
|
||||
//public class NodeStatController extends BaseServerController {
|
||||
//
|
||||
// private final NodeStatService nodeStatService;
|
||||
// private final ServerConfig.NodeConfig nodeConfig;
|
||||
//
|
||||
// public NodeStatController(NodeStatService nodeStatService,
|
||||
// ServerConfig serverConfig) {
|
||||
// this.nodeStatService = nodeStatService;
|
||||
// this.nodeConfig = serverConfig.getNode();
|
||||
// }
|
||||
//
|
||||
// @PostMapping(value = "list_data.json", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
// @Feature(method = MethodFeature.LIST)
|
||||
// public JsonMessage<PageResultDto<NodeStatModel>> listJson() {
|
||||
// PageResultDto<NodeStatModel> nodeModelPageResultDto = nodeStatService.listPage(getRequest());
|
||||
// return JsonMessage.success("", nodeModelPageResultDto);
|
||||
// }
|
||||
//
|
||||
// @GetMapping(value = "status_stat.json", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
// @Feature(method = MethodFeature.LIST)
|
||||
// public JsonMessage<JSONObject> statusStat() {
|
||||
// String workspaceId = nodeStatService.getCheckUserWorkspace(getRequest());
|
||||
// //
|
||||
// JSONObject jsonObject = new JSONObject();
|
||||
// jsonObject.put("heartSecond", nodeConfig.getHeartSecond());
|
||||
// {
|
||||
// // 节点状态
|
||||
// String sql = "select `status`,count(1) as cunt from " + nodeStatService.getTableName() + " where workspaceId=? group by `status`";
|
||||
// List<Entity> list = nodeStatService.query(sql, workspaceId);
|
||||
// Map<String, Integer> map = CollStreamUtil.toMap(list, entity -> entity.getStr("status"), entity -> entity.getInt("cunt"));
|
||||
// jsonObject.put("status", map);
|
||||
// }
|
||||
//// {
|
||||
//// // 启用状态
|
||||
//// String sql = "select `openStatus`,count(1) as cunt from " + nodeService.getTableName() + " where workspaceId=? group by `openStatus`";
|
||||
//// List<Entity> list = nodeStatService.query(sql, workspaceId);
|
||||
//// Map<String, Integer> map = CollStreamUtil.toMap(list, entity -> entity.getStr("openStatus"), entity -> entity.getInt("cunt"));
|
||||
//// jsonObject.put("openStatus", map);
|
||||
//// }
|
||||
// return JsonMessage.success("", jsonObject);
|
||||
// }
|
||||
//}
|
||||
return JsonMessage.success("", jsonObject);
|
||||
}
|
||||
}
|
||||
|
@ -32,8 +32,9 @@ import com.alibaba.fastjson2.JSONObject;
|
||||
import io.jpom.common.*;
|
||||
import io.jpom.common.validator.ValidatorItem;
|
||||
import io.jpom.controller.openapi.NodeInfoController;
|
||||
import io.jpom.func.assets.model.MachineNodeModel;
|
||||
import io.jpom.func.assets.server.MachineNodeServer;
|
||||
import io.jpom.model.AgentFileModel;
|
||||
import io.jpom.model.data.NodeModel;
|
||||
import io.jpom.permission.ClassFeature;
|
||||
import io.jpom.permission.Feature;
|
||||
import io.jpom.permission.MethodFeature;
|
||||
@ -71,11 +72,14 @@ public class NodeUpdateController extends BaseServerController {
|
||||
|
||||
private final SystemParametersServer systemParametersServer;
|
||||
private final ServerConfig serverConfig;
|
||||
private final MachineNodeServer machineNodeServer;
|
||||
|
||||
public NodeUpdateController(SystemParametersServer systemParametersServer,
|
||||
ServerConfig serverConfig) {
|
||||
ServerConfig serverConfig,
|
||||
MachineNodeServer machineNodeServer) {
|
||||
this.systemParametersServer = systemParametersServer;
|
||||
this.serverConfig = serverConfig;
|
||||
this.machineNodeServer = machineNodeServer;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -220,25 +224,26 @@ public class NodeUpdateController extends BaseServerController {
|
||||
Assert.notNull(receiveCache, "没有对应的缓存信息");
|
||||
JSONArray jsonArray = receiveCache.getJSONArray("canUseNode");
|
||||
Assert.notEmpty(jsonArray, "没有对应的缓存信息:-1");
|
||||
Optional<NodeModel> any = jsonArray.stream().map(o -> {
|
||||
if (o instanceof NodeModel) {
|
||||
return (NodeModel) o;
|
||||
Optional<MachineNodeModel> any = jsonArray.stream().map(o -> {
|
||||
if (o instanceof MachineNodeModel) {
|
||||
return (MachineNodeModel) o;
|
||||
}
|
||||
JSONObject jsonObject = (JSONObject) o;
|
||||
return jsonObject.toJavaObject(NodeModel.class);
|
||||
}).filter(nodeModel -> StrUtil.equals(nodeModel.getUrl(), StrUtil.format("{}:{}", ip, port))).findAny();
|
||||
return jsonObject.toJavaObject(MachineNodeModel.class);
|
||||
}).filter(nodeModel -> StrUtil.equals(nodeModel.getJpomUrl(), StrUtil.format("{}:{}", ip, port))).findAny();
|
||||
Assert.state(any.isPresent(), "ip 地址信息不正确");
|
||||
NodeModel nodeModel = any.get();
|
||||
MachineNodeModel machineNodeModel = any.get();
|
||||
try {
|
||||
nodeService.testNode(nodeModel);
|
||||
machineNodeServer.testNode(machineNodeModel);
|
||||
} catch (Exception e) {
|
||||
log.warn("测试结果:{} {}", nodeModel.getUrl(), e.getMessage());
|
||||
log.warn("测试结果:{} {}", machineNodeModel.getJpomUrl(), e.getMessage());
|
||||
return new JsonMessage<>(500, "节点连接失败:" + e.getMessage());
|
||||
}
|
||||
// 插入
|
||||
boolean exists = nodeService.existsByUrl(nodeModel.getUrl(), nodeModel.getWorkspaceId(), null);
|
||||
Assert.state(!exists, "对应的节点已经存在拉:" + nodeModel.getUrl());
|
||||
nodeService.insert(nodeModel);
|
||||
boolean exists = machineNodeServer.existsByUrl(machineNodeModel.getJpomUrl(), null);
|
||||
Assert.state(!exists, "对应的节点已经存在拉:" + machineNodeModel.getJpomUrl());
|
||||
String workspaceId = nodeService.getCheckUserWorkspace(getRequest());
|
||||
machineNodeServer.insertAndNode(machineNodeModel, workspaceId);
|
||||
// 更新结果
|
||||
receiveCache.put("type", "success");
|
||||
return JsonMessage.success("安装成功", NodeInfoController.listReceiveCache(null));
|
||||
|
@ -33,10 +33,10 @@ import io.jpom.common.BaseServerController;
|
||||
import io.jpom.common.JsonMessage;
|
||||
import io.jpom.common.forward.NodeForward;
|
||||
import io.jpom.common.forward.NodeUrl;
|
||||
import io.jpom.func.assets.model.MachineNodeStatLogModel;
|
||||
import io.jpom.func.assets.server.MachineNodeStatLogServer;
|
||||
import io.jpom.model.data.NodeModel;
|
||||
import io.jpom.model.log.SystemMonitorLog;
|
||||
import io.jpom.permission.SystemPermission;
|
||||
import io.jpom.service.dblog.DbSystemMonitorLogService;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
@ -47,35 +47,36 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 欢迎页
|
||||
* 节点统计信息
|
||||
*
|
||||
* @author Administrator
|
||||
* @author bwcx_jzy
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping(value = "/node")
|
||||
public class NodeWelcomeController extends BaseServerController {
|
||||
|
||||
private final DbSystemMonitorLogService dbSystemMonitorLogService;
|
||||
private final MachineNodeStatLogServer machineNodeStatLogServer;
|
||||
|
||||
public NodeWelcomeController(DbSystemMonitorLogService dbSystemMonitorLogService) {
|
||||
this.dbSystemMonitorLogService = dbSystemMonitorLogService;
|
||||
public NodeWelcomeController(MachineNodeStatLogServer machineNodeStatLogServer) {
|
||||
this.machineNodeStatLogServer = machineNodeStatLogServer;
|
||||
}
|
||||
|
||||
@PostMapping(value = "node_monitor_data.json", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public JsonMessage<List<SystemMonitorLog>> nodeMonitorJson() {
|
||||
List<SystemMonitorLog> list = this.getList();
|
||||
public JsonMessage<List<MachineNodeStatLogModel>> nodeMonitorJson() {
|
||||
List<MachineNodeStatLogModel> list = this.getList();
|
||||
Assert.notEmpty(list, "没有查询到任何数据");
|
||||
return JsonMessage.success("ok", list);
|
||||
}
|
||||
|
||||
private List<SystemMonitorLog> getList() {
|
||||
private List<MachineNodeStatLogModel> getList() {
|
||||
NodeModel node = getNode();
|
||||
String machineId = node.getMachineId();
|
||||
String startDateStr = getParameter("time[0]");
|
||||
String endDateStr = getParameter("time[1]");
|
||||
if (StrUtil.hasEmpty(startDateStr, endDateStr)) {
|
||||
SystemMonitorLog systemMonitorLog = new SystemMonitorLog();
|
||||
systemMonitorLog.setNodeId(node.getId());
|
||||
return dbSystemMonitorLogService.queryList(systemMonitorLog, 500, new Order("monitorTime", Direction.DESC));
|
||||
MachineNodeStatLogModel systemMonitorLog = new MachineNodeStatLogModel();
|
||||
systemMonitorLog.setMachineId(machineId);
|
||||
return machineNodeStatLogServer.queryList(systemMonitorLog, 500, new Order("monitorTime", Direction.DESC));
|
||||
}
|
||||
// 处理时间
|
||||
DateTime startDate = DateUtil.parse(startDateStr);
|
||||
@ -86,69 +87,16 @@ public class NodeWelcomeController extends BaseServerController {
|
||||
endDate = DateUtil.endOfDay(endDate);
|
||||
}
|
||||
long endTime = endDate.getTime();
|
||||
|
||||
// 开启了节点信息采集
|
||||
Page pageObj = new Page(1, 5000);
|
||||
pageObj.addOrder(new Order("monitorTime", Direction.DESC));
|
||||
Entity entity = Entity.create();
|
||||
entity.set("nodeId", node.getId());
|
||||
entity.set("machineId", machineId);
|
||||
entity.set(" MONITORTIME", ">= " + startTime);
|
||||
entity.set("MONITORTIME", "<= " + endTime);
|
||||
return dbSystemMonitorLogService.listPageOnlyResult(entity, pageObj);
|
||||
return machineNodeStatLogServer.listPageOnlyResult(entity, pageObj);
|
||||
}
|
||||
|
||||
// private JSONObject getData() {
|
||||
// List<SystemMonitorLog> list = getList();
|
||||
// Assert.notEmpty(list, "没有查询到任何数据");
|
||||
// List<JSONObject> series = new ArrayList<>();
|
||||
// List<String> scale = new ArrayList<>();
|
||||
// for (int i = list.size() - 1; i >= 0; i--) {
|
||||
// SystemMonitorLog systemMonitorLog = list.get(i);
|
||||
// scale.add(new DateTime(systemMonitorLog.getMonitorTime()).toString(DatePattern.NORM_DATETIME_PATTERN));
|
||||
// JSONObject jsonObject = new JSONObject();
|
||||
// jsonObject.put("cpu", systemMonitorLog.getOccupyCpu());
|
||||
// jsonObject.put("memory", systemMonitorLog.getOccupyMemory());
|
||||
// jsonObject.put("memoryUsed", systemMonitorLog.getOccupyMemoryUsed());
|
||||
// jsonObject.put("disk", systemMonitorLog.getOccupyDisk());
|
||||
// series.add(jsonObject);
|
||||
// }
|
||||
//
|
||||
// JSONObject object = new JSONObject();
|
||||
// object.put("scales", scale);
|
||||
// object.put("series", series);
|
||||
// return object;
|
||||
// }
|
||||
//
|
||||
// @PostMapping(value = "getTop", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
// public String getTop() {
|
||||
// JSONObject object = getData();
|
||||
// return JsonMessage.success( "ok", object);
|
||||
// }
|
||||
|
||||
// @RequestMapping(value = "exportTop")
|
||||
// public void exportTop(String time) throws UnsupportedEncodingException {
|
||||
// List<SystemMonitorLog> result = getList();
|
||||
// if (CollUtil.isEmpty(result)) {
|
||||
// // NodeForward.requestDownload(node, getRequest(), getResponse(), NodeUrl.exportTop);
|
||||
// } else {
|
||||
// NodeModel node = getNode();
|
||||
// StringBuilder buf = new StringBuilder();
|
||||
// buf.append("监控时间").append(",占用cpu").append(",占用内存").append(",占用磁盘").append("\r\n");
|
||||
// for (SystemMonitorLog log : result) {
|
||||
// long monitorTime = log.getMonitorTime();
|
||||
// buf.append(DateUtil.date(monitorTime)).append(StrUtil.COMMA)
|
||||
// .append(log.getOccupyCpu()).append("%").append(StrUtil.COMMA)
|
||||
// .append(log.getOccupyMemory()).append("%").append(StrUtil.COMMA)
|
||||
// .append(log.getOccupyDisk()).append("%").append("\r\n");
|
||||
// }
|
||||
// String fileName = URLEncoder.encode("Jpom系统监控-" + node.getId(), "UTF-8");
|
||||
// HttpServletResponse response = getResponse();
|
||||
// response.setHeader("Content-Disposition", "attachment;filename=" + new String(fileName.getBytes(StandardCharsets.UTF_8), "GBK") + ".csv");
|
||||
// response.setContentType("text/csv;charset=utf-8");
|
||||
// ServletUtil.write(getResponse(), buf.toString(), CharsetUtil.UTF_8);
|
||||
// }
|
||||
// }
|
||||
|
||||
@RequestMapping(value = "processList", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public String getProcessList() {
|
||||
return NodeForward.request(getNode(), getRequest(), NodeUrl.ProcessList).toString();
|
||||
|
@ -35,8 +35,10 @@ import io.jpom.common.ServerOpenApi;
|
||||
import io.jpom.common.interceptor.NotLogin;
|
||||
import io.jpom.common.validator.ValidatorItem;
|
||||
import io.jpom.common.validator.ValidatorRule;
|
||||
import io.jpom.model.data.NodeModel;
|
||||
import io.jpom.func.assets.model.MachineNodeModel;
|
||||
import io.jpom.func.assets.server.MachineNodeServer;
|
||||
import io.jpom.model.data.WorkspaceModel;
|
||||
import io.jpom.model.user.UserModel;
|
||||
import io.jpom.service.node.NodeService;
|
||||
import io.jpom.service.system.WorkspaceService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -63,11 +65,14 @@ public class NodeInfoController extends BaseServerController {
|
||||
|
||||
private final NodeService nodeService;
|
||||
private final WorkspaceService workspaceService;
|
||||
private final MachineNodeServer machineNodeServer;
|
||||
|
||||
public NodeInfoController(NodeService nodeService,
|
||||
WorkspaceService workspaceService) {
|
||||
WorkspaceService workspaceService,
|
||||
MachineNodeServer machineNodeServer) {
|
||||
this.nodeService = nodeService;
|
||||
this.workspaceService = workspaceService;
|
||||
this.machineNodeServer = machineNodeServer;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -98,18 +103,18 @@ public class NodeInfoController extends BaseServerController {
|
||||
ipsList.add(clientIp);
|
||||
}
|
||||
List<String> canUseIps = ipsList.stream().filter(s -> this.testIpPort(s, ping)).collect(Collectors.toList());
|
||||
List<NodeModel> canUseNode = canUseIps.stream().map(s -> {
|
||||
NodeModel model = NodeInfoController.this.createModel(s, loginName, loginPwd, port, workspaceId);
|
||||
List<MachineNodeModel> canUseNode = canUseIps.stream().map(s -> {
|
||||
MachineNodeModel model = NodeInfoController.this.createMachineNodeModel(s, loginName, loginPwd, port);
|
||||
try {
|
||||
nodeService.testNode(model);
|
||||
machineNodeServer.testNode(model);
|
||||
} catch (Exception e) {
|
||||
log.warn("测试结果:{} {}", model.getUrl(), e.getMessage());
|
||||
log.warn("测试结果:{} {}", model.getJpomUrl(), e.getMessage());
|
||||
return null;
|
||||
}
|
||||
return model;
|
||||
}).filter(Objects::nonNull).collect(Collectors.toList());
|
||||
// 只返回能通的 IP
|
||||
canUseIps = canUseNode.stream().map(NodeModel::getName).collect(Collectors.toList());
|
||||
canUseIps = canUseNode.stream().map(MachineNodeModel::getName).collect(Collectors.toList());
|
||||
int size1 = CollUtil.size(canUseNode);
|
||||
//
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
@ -120,8 +125,8 @@ public class NodeInfoController extends BaseServerController {
|
||||
jsonObject.put("canUseNode", canUseNode);
|
||||
//
|
||||
exists = false;
|
||||
for (NodeModel nodeModel : canUseNode) {
|
||||
if (nodeService.existsByUrl(nodeModel.getUrl(), nodeModel.getWorkspaceId(), null)) {
|
||||
for (MachineNodeModel nodeModel : canUseNode) {
|
||||
if (machineNodeServer.existsByUrl(nodeModel.getJpomUrl(), null)) {
|
||||
// 存在
|
||||
jsonObject.put("type", "exists");
|
||||
exists = true;
|
||||
@ -130,10 +135,10 @@ public class NodeInfoController extends BaseServerController {
|
||||
}
|
||||
if (!exists) {
|
||||
if (size1 == 1) {
|
||||
// 只有一个 ip 可以使用
|
||||
// 添加插件端
|
||||
NodeModel first = CollUtil.getFirst(canUseNode);
|
||||
nodeService.insertNotFill(first);
|
||||
// 只有一个 ip 可以使用,添加插件端
|
||||
BaseServerController.resetInfo(UserModel.EMPTY);
|
||||
MachineNodeModel first = CollUtil.getFirst(canUseNode);
|
||||
machineNodeServer.insertAndNode(first, workspaceId);
|
||||
jsonObject.put("type", "success");
|
||||
} else {
|
||||
jsonObject.put("type", size1 == 0 ? "canUseIpEmpty" : "multiIp");
|
||||
@ -174,15 +179,14 @@ public class NodeInfoController extends BaseServerController {
|
||||
return NetUtil.ping(ip, pingTime * 1000);
|
||||
}
|
||||
|
||||
private NodeModel createModel(String ip, String loginName, String loginPwd, int port, String workspaceId) {
|
||||
NodeModel nodeModel = new NodeModel();
|
||||
nodeModel.setWorkspaceId(workspaceId);
|
||||
nodeModel.setName(ip);
|
||||
nodeModel.setOpenStatus(1);
|
||||
nodeModel.setLoginName(loginName);
|
||||
nodeModel.setLoginPwd(loginPwd);
|
||||
nodeModel.setUrl(ip + StrUtil.COLON + port);
|
||||
nodeModel.setProtocol("http");
|
||||
return nodeModel;
|
||||
private MachineNodeModel createMachineNodeModel(String ip, String loginName, String loginPwd, int port) {
|
||||
MachineNodeModel machineNodeModel = new MachineNodeModel();
|
||||
machineNodeModel.setName(ip);
|
||||
machineNodeModel.setStatus(1);
|
||||
machineNodeModel.setJpomUsername(loginName);
|
||||
machineNodeModel.setJpomPassword(loginPwd);
|
||||
machineNodeModel.setJpomUrl(ip + StrUtil.COLON + port);
|
||||
machineNodeModel.setJpomProtocol("http");
|
||||
return machineNodeModel;
|
||||
}
|
||||
}
|
||||
|
@ -45,6 +45,7 @@ import io.jpom.common.JsonMessage;
|
||||
import io.jpom.common.forward.NodeForward;
|
||||
import io.jpom.common.forward.NodeUrl;
|
||||
import io.jpom.common.validator.ValidatorItem;
|
||||
import io.jpom.func.assets.server.MachineNodeServer;
|
||||
import io.jpom.model.data.NodeModel;
|
||||
import io.jpom.model.data.SystemIpConfigModel;
|
||||
import io.jpom.model.node.NodeAgentWhitelist;
|
||||
@ -55,7 +56,6 @@ import io.jpom.permission.SystemPermission;
|
||||
import io.jpom.service.node.NodeService;
|
||||
import io.jpom.service.system.SystemParametersServer;
|
||||
import io.jpom.system.ExtConfigBean;
|
||||
import io.jpom.system.db.InitDb;
|
||||
import io.jpom.system.init.ProxySelectorConfig;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.config.YamlMapFactoryBean;
|
||||
@ -92,21 +92,21 @@ import java.util.Map;
|
||||
public class SystemConfigController extends BaseServerController {
|
||||
|
||||
private final SystemParametersServer systemParametersServer;
|
||||
private final InitDb initDb;
|
||||
private final NodeService nodeService;
|
||||
private final ProxySelectorConfig proxySelectorConfig;
|
||||
private final DbExtConfig dbExtConfig;
|
||||
private final MachineNodeServer machineNodeServer;
|
||||
|
||||
public SystemConfigController(SystemParametersServer systemParametersServer,
|
||||
InitDb initDb,
|
||||
NodeService nodeService,
|
||||
ProxySelectorConfig proxySelectorConfig,
|
||||
DbExtConfig dbExtConfig) {
|
||||
DbExtConfig dbExtConfig,
|
||||
MachineNodeServer machineNodeServer) {
|
||||
this.systemParametersServer = systemParametersServer;
|
||||
this.initDb = initDb;
|
||||
this.nodeService = nodeService;
|
||||
this.proxySelectorConfig = proxySelectorConfig;
|
||||
this.dbExtConfig = dbExtConfig;
|
||||
this.machineNodeServer = machineNodeServer;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -420,7 +420,7 @@ public class SystemConfigController extends BaseServerController {
|
||||
proxys = ObjectUtil.defaultIfNull(proxys, Collections.emptyList());
|
||||
for (ProxySelectorConfig.ProxyConfigItem proxy : proxys) {
|
||||
if (StrUtil.isNotEmpty(proxy.getProxyAddress())) {
|
||||
nodeService.testHttpProxy(proxy.getProxyAddress());
|
||||
machineNodeServer.testHttpProxy(proxy.getProxyAddress());
|
||||
}
|
||||
}
|
||||
systemParametersServer.upsert(ProxySelectorConfig.KEY, proxys, ProxySelectorConfig.KEY);
|
||||
|
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Code Technology Studio
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package io.jpom.func.assets.controller;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.db.Entity;
|
||||
import io.jpom.common.JsonMessage;
|
||||
import io.jpom.func.assets.model.MachineNodeModel;
|
||||
import io.jpom.func.assets.server.MachineNodeServer;
|
||||
import io.jpom.permission.ClassFeature;
|
||||
import io.jpom.permission.Feature;
|
||||
import io.jpom.permission.MethodFeature;
|
||||
import io.jpom.permission.SystemPermission;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import top.jpom.model.PageResultDto;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author bwcx_jzy
|
||||
* @since 2023/2/18
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping(value = "/system/assets/machine")
|
||||
@Feature(cls = ClassFeature.SYSTEM_ASSETS_MACHINE)
|
||||
@SystemPermission
|
||||
public class MachineNodeController {
|
||||
|
||||
private final MachineNodeServer machineNodeServer;
|
||||
|
||||
public MachineNodeController(MachineNodeServer machineNodeServer) {
|
||||
this.machineNodeServer = machineNodeServer;
|
||||
}
|
||||
|
||||
@PostMapping(value = "list-data", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Feature(method = MethodFeature.LIST)
|
||||
public JsonMessage<PageResultDto<MachineNodeModel>> listJson(HttpServletRequest request) {
|
||||
PageResultDto<MachineNodeModel> pageResultDto = machineNodeServer.listPage(request);
|
||||
return JsonMessage.success("", pageResultDto);
|
||||
}
|
||||
|
||||
@GetMapping(value = "list-group", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Feature(method = MethodFeature.LIST)
|
||||
public JsonMessage<List<String>> listGroup() {
|
||||
String sql = "select `groupName` from " + machineNodeServer.getTableName() + " group by `groupName`";
|
||||
List<Entity> list = machineNodeServer.query(sql);
|
||||
// 筛选字段
|
||||
List<String> collect = list.stream()
|
||||
.map(entity -> {
|
||||
Object obj = entity.get("groupName");
|
||||
return StrUtil.toStringOrNull(obj);
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
return JsonMessage.success("", collect);
|
||||
}
|
||||
|
||||
@PostMapping(value = "edit", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Feature(method = MethodFeature.EDIT)
|
||||
public JsonMessage<String> save(HttpServletRequest request) {
|
||||
machineNodeServer.update(request);
|
||||
return JsonMessage.success("操作成功");
|
||||
}
|
||||
}
|
@ -0,0 +1,242 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Code Technology Studio
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package io.jpom.func.assets.model;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.util.EnumUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
import io.jpom.model.BaseUserModifyDbModel;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import top.jpom.h2db.TableName;
|
||||
import top.jpom.transport.INodeInfo;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Proxy;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author bwcx_jzy
|
||||
* @since 2023/2/18
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName(value = "MACHINE_NODE_INFO", name = "机器节点信息")
|
||||
@Data
|
||||
public class MachineNodeModel extends BaseUserModifyDbModel implements INodeInfo {
|
||||
|
||||
/**
|
||||
* 机器名称
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* 分组名称
|
||||
*/
|
||||
private String groupName;
|
||||
/**
|
||||
* 机器主机名
|
||||
*/
|
||||
private String hostName;
|
||||
/**
|
||||
* 机器的 IP (多个)
|
||||
*/
|
||||
private String hostIpv4s;
|
||||
/**
|
||||
* 负载
|
||||
*/
|
||||
private String osLoadAverage;
|
||||
/**
|
||||
* 系统运行时间(自启动以来的时间)。
|
||||
* 自启动以来的秒数。
|
||||
*/
|
||||
private Long osSystemUptime;
|
||||
/**
|
||||
* 系统名称
|
||||
*/
|
||||
private String osName;
|
||||
/**
|
||||
* 系统版本
|
||||
*/
|
||||
private String osVersion;
|
||||
/**
|
||||
* 硬件版本
|
||||
*/
|
||||
private String osHardwareVersion;
|
||||
/**
|
||||
* CPU数
|
||||
*/
|
||||
private Integer osCpuCores;
|
||||
/**
|
||||
* 总内存
|
||||
*/
|
||||
private Long osMoneyTotal;
|
||||
/**
|
||||
* 硬盘总大小
|
||||
*/
|
||||
private Long osFileStoreTotal;
|
||||
/**
|
||||
* CPU 型号
|
||||
*/
|
||||
private String osCpuIdentifierName;
|
||||
/**
|
||||
* 占用cpu
|
||||
*/
|
||||
private Double osOccupyCpu;
|
||||
/**
|
||||
* 占用内存 (总共)
|
||||
*/
|
||||
private Double osOccupyMemory;
|
||||
/**
|
||||
* 占用磁盘
|
||||
*/
|
||||
private Double osOccupyDisk;
|
||||
/**
|
||||
* 节点连接状态
|
||||
* <p>
|
||||
* 状态{0,无法连接,1 正常, 2 授权信息错误, 3 状态码错误}
|
||||
*/
|
||||
private Integer status;
|
||||
/**
|
||||
* 状态消息
|
||||
*/
|
||||
private String statusMsg;
|
||||
/**
|
||||
* 传输方式。0 服务器拉取,1 节点机器推送
|
||||
*/
|
||||
private Integer transportMode;
|
||||
/**
|
||||
* jpom 通讯地址
|
||||
*/
|
||||
private String jpomUrl;
|
||||
/**
|
||||
* 节点协议
|
||||
*/
|
||||
private String jpomProtocol;
|
||||
/**
|
||||
* 通讯登录账号
|
||||
*/
|
||||
private String jpomUsername;
|
||||
/**
|
||||
* 通讯登录密码
|
||||
*/
|
||||
private String jpomPassword;
|
||||
/**
|
||||
* 超时时间
|
||||
*/
|
||||
private Integer jpomTimeout;
|
||||
/**
|
||||
* http 代理
|
||||
*/
|
||||
private String jpomHttpProxy;
|
||||
/**
|
||||
* http 代理 类型
|
||||
*/
|
||||
private String jpomHttpProxyType;
|
||||
/**
|
||||
* jpom 版本号
|
||||
*/
|
||||
private String jpomVersion;
|
||||
/**
|
||||
* jpom 启动时间
|
||||
*/
|
||||
private Long jpomUptime;
|
||||
/**
|
||||
* Jpom 打包时间
|
||||
*/
|
||||
private String jpomBuildTime;
|
||||
/**
|
||||
* 网络耗时(延迟)
|
||||
*/
|
||||
private Integer networkDelay;
|
||||
/**
|
||||
* jpom 项目数
|
||||
*/
|
||||
private Integer jpomProjectCount;
|
||||
/**
|
||||
* jpom 脚本数据
|
||||
*/
|
||||
private Integer jpomScriptCount;
|
||||
/**
|
||||
* java 版本
|
||||
*/
|
||||
private String javaVersion;
|
||||
/**
|
||||
* jvm 总内存
|
||||
*/
|
||||
private Long jvmTotalMemory;
|
||||
/**
|
||||
* jvm 剩余内存
|
||||
*/
|
||||
private Long jvmFreeMemory;
|
||||
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return this.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String url() {
|
||||
return this.getJpomUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String scheme() {
|
||||
return getJpomProtocol();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 授权的信息
|
||||
*
|
||||
* @return sha1
|
||||
*/
|
||||
@Override
|
||||
public String authorize() {
|
||||
return SecureUtil.sha1(this.jpomUsername + "@" + this.jpomPassword);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取节点的代理
|
||||
*
|
||||
* @return proxy
|
||||
*/
|
||||
@Override
|
||||
public Proxy proxy() {
|
||||
String httpProxy = this.getJpomHttpProxy();
|
||||
if (StrUtil.isNotEmpty(httpProxy)) {
|
||||
List<String> split = StrUtil.splitTrim(httpProxy, StrUtil.COLON);
|
||||
String host = CollUtil.getFirst(split);
|
||||
int port = Convert.toInt(CollUtil.getLast(split), 0);
|
||||
String type = this.getJpomHttpProxyType();
|
||||
Proxy.Type type1 = EnumUtil.fromString(Proxy.Type.class, type, Proxy.Type.HTTP);
|
||||
return new Proxy(type1, new InetSocketAddress(host, port));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer timeout() {
|
||||
return this.getJpomTimeout();
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Code Technology Studio
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package io.jpom.func.assets.model;
|
||||
|
||||
import io.jpom.model.log.SystemMonitorLog;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import top.jpom.h2db.TableName;
|
||||
import top.jpom.model.BaseDbModel;
|
||||
|
||||
/**
|
||||
* @author bwcx_jzy
|
||||
* @see SystemMonitorLog
|
||||
* @see io.jpom.model.data.NodeModel
|
||||
* @since 2023/02/18
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName(value = "MACHINE_NODE_STAT_LOG", name = "资产机器节点统计")
|
||||
@Data
|
||||
public class MachineNodeStatLogModel extends BaseDbModel {
|
||||
/**
|
||||
* 机器id
|
||||
*/
|
||||
private String machineId;
|
||||
/**
|
||||
* 占用cpu
|
||||
*/
|
||||
private Double occupyCpu;
|
||||
/**
|
||||
* 占用内存 (总共)
|
||||
*/
|
||||
private Double occupyMemory;
|
||||
/**
|
||||
* 占用磁盘
|
||||
*/
|
||||
private Double occupyDisk;
|
||||
/**
|
||||
* 监控时间
|
||||
* 插件端返回的时间
|
||||
*/
|
||||
private Long monitorTime;
|
||||
/**
|
||||
* 网络耗时(延迟)
|
||||
*/
|
||||
private Integer networkDelay;
|
||||
/**
|
||||
* 每秒发送的KB数,rxkB/s
|
||||
*/
|
||||
private Long netTxBytes;
|
||||
|
||||
/**
|
||||
* 每秒接收的KB数,rxkB/s
|
||||
*/
|
||||
private Long netRxBytes;
|
||||
}
|
@ -0,0 +1,402 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Code Technology Studio
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package io.jpom.func.assets.server;
|
||||
|
||||
import cn.hutool.core.collection.CollStreamUtil;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.date.SystemClock;
|
||||
import cn.hutool.core.net.NetUtil;
|
||||
import cn.hutool.core.thread.ThreadUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.db.Entity;
|
||||
import cn.hutool.extra.servlet.ServletUtil;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import io.jpom.common.*;
|
||||
import io.jpom.common.forward.NodeForward;
|
||||
import io.jpom.common.forward.NodeUrl;
|
||||
import io.jpom.cron.IAsyncLoad;
|
||||
import io.jpom.func.assets.model.MachineNodeModel;
|
||||
import io.jpom.func.assets.model.MachineNodeStatLogModel;
|
||||
import io.jpom.model.data.NodeModel;
|
||||
import io.jpom.model.user.UserModel;
|
||||
import io.jpom.service.h2db.BaseDbService;
|
||||
import io.jpom.service.node.NodeService;
|
||||
import io.jpom.system.AgentException;
|
||||
import io.jpom.system.AuthorizeException;
|
||||
import io.jpom.system.ServerConfig;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @author bwcx_jzy
|
||||
* @since 2023/2/18
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class MachineNodeServer extends BaseDbService<MachineNodeModel> implements ILoadEvent, IAsyncLoad, Runnable {
|
||||
|
||||
private final NodeService nodeService;
|
||||
private final ServerConfig.NodeConfig nodeConfig;
|
||||
private final MachineNodeStatLogServer machineNodeStatLogServer;
|
||||
|
||||
public MachineNodeServer(NodeService nodeService,
|
||||
ServerConfig serverConfig,
|
||||
MachineNodeStatLogServer machineNodeStatLogServer) {
|
||||
this.nodeService = nodeService;
|
||||
this.nodeConfig = serverConfig.getNode();
|
||||
this.machineNodeStatLogServer = machineNodeStatLogServer;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void fillSelectResult(MachineNodeModel data) {
|
||||
Optional.ofNullable(data).ifPresent(machineNodeModel -> machineNodeModel.setJpomPassword(null));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void fillInsert(MachineNodeModel machineNodeModel) {
|
||||
super.fillInsert(machineNodeModel);
|
||||
machineNodeModel.setGroupName(StrUtil.emptyToDefault(machineNodeModel.getGroupName(), Const.DEFAULT_GROUP_NAME));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet(ApplicationContext applicationContext) throws Exception {
|
||||
long count = this.count();
|
||||
if (count != 0) {
|
||||
log.debug("节点机器表已经存在 {} 条数据,不需要修复机器数据", count);
|
||||
return;
|
||||
}
|
||||
List<NodeModel> list = nodeService.list(false);
|
||||
if (CollUtil.isEmpty(list)) {
|
||||
log.debug("没有任何节点信息,不需要修复机器数据");
|
||||
return;
|
||||
}
|
||||
// delete from MACHINE_NODE_INFO;
|
||||
// drop table MACHINE_NODE_INFO;
|
||||
Map<String, List<NodeModel>> nodeUrlMap = CollStreamUtil.groupByKey(list, NodeModel::getUrl);
|
||||
List<MachineNodeModel> machineNodeModels = new ArrayList<>(nodeUrlMap.size());
|
||||
for (Map.Entry<String, List<NodeModel>> entry : nodeUrlMap.entrySet()) {
|
||||
List<NodeModel> value = entry.getValue();
|
||||
NodeModel first = CollUtil.getFirst(value);
|
||||
if (value.size() > 1) {
|
||||
log.warn("节点地址 {} 存在多个数据,将自动合并使用 {} 节点的配置信息", entry.getKey(), first.getName());
|
||||
}
|
||||
machineNodeModels.add(this.nodeInfoToMachineNode(first));
|
||||
}
|
||||
this.insert(machineNodeModels);
|
||||
log.info("成功修复 {} 条机器节点数据", machineNodeModels.size());
|
||||
// 更新节点的机器id
|
||||
for (MachineNodeModel value : machineNodeModels) {
|
||||
Entity entity = Entity.create();
|
||||
entity.set("machineId", value.getId());
|
||||
Entity where = Entity.create();
|
||||
where.set("url", value.getJpomUrl());
|
||||
nodeService.update(entity, where);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return HIGHEST_PRECEDENCE + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 节点对象转机器对象
|
||||
*
|
||||
* @param nodeModel 节点
|
||||
* @return 机器对象
|
||||
*/
|
||||
private MachineNodeModel nodeInfoToMachineNode(NodeModel nodeModel) {
|
||||
MachineNodeModel machineNodeModel = new MachineNodeModel();
|
||||
machineNodeModel.setName(nodeModel.getName());
|
||||
machineNodeModel.setGroupName(nodeModel.getGroup());
|
||||
machineNodeModel.setTransportMode(0);
|
||||
machineNodeModel.setStatus(0);
|
||||
machineNodeModel.setJpomTimeout(nodeModel.getTimeOut());
|
||||
machineNodeModel.setJpomUrl(nodeModel.getUrl());
|
||||
machineNodeModel.setJpomUsername(nodeModel.getLoginName());
|
||||
machineNodeModel.setJpomPassword(nodeModel.getLoginPwd());
|
||||
machineNodeModel.setJpomProtocol(nodeModel.getProtocol());
|
||||
machineNodeModel.setJpomHttpProxy(nodeModel.getHttpProxy());
|
||||
machineNodeModel.setJpomHttpProxyType(nodeModel.getHttpProxyType());
|
||||
machineNodeModel.setModifyUser(nodeModel.getModifyUser());
|
||||
machineNodeModel.setCreateTimeMillis(nodeModel.getCreateTimeMillis());
|
||||
machineNodeModel.setModifyTimeMillis(nodeModel.getModifyTimeMillis());
|
||||
return machineNodeModel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startLoad() {
|
||||
// 启动心跳检测
|
||||
int heartSecond = nodeConfig.getHeartSecond();
|
||||
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(runnable -> new Thread(runnable, "Jpom Node Monitor"));
|
||||
scheduler.scheduleAtFixedRate(this, 10, heartSecond, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
MachineNodeModel machineNodeModel = new MachineNodeModel();
|
||||
machineNodeModel.setTransportMode(0);
|
||||
List<MachineNodeModel> machineNodeModels = this.listByBean(machineNodeModel);
|
||||
this.checkList(machineNodeModels);
|
||||
}
|
||||
|
||||
|
||||
private void checkList(List<MachineNodeModel> machineNodeModels) {
|
||||
if (CollUtil.isEmpty(machineNodeModels)) {
|
||||
return;
|
||||
}
|
||||
machineNodeModels.forEach(machineNodeModel -> {
|
||||
// 超时时间统一,避免长时间无响应
|
||||
machineNodeModel.setJpomTimeout(10);
|
||||
//
|
||||
ThreadUtil.execute(() -> {
|
||||
try {
|
||||
BaseServerController.resetInfo(UserModel.EMPTY);
|
||||
long timeMillis = SystemClock.now();
|
||||
JsonMessage<JSONObject> message = NodeForward.request(machineNodeModel, NodeUrl.GetStatInfo, new JSONObject());
|
||||
int networkTime = (int) (System.currentTimeMillis() - timeMillis);
|
||||
JSONObject jsonObject;
|
||||
if (message.success()) {
|
||||
jsonObject = message.getData(JSONObject.class);
|
||||
} else {
|
||||
// 状态码错
|
||||
this.updateStatus(machineNodeModel, 3, message.toString());
|
||||
return;
|
||||
}
|
||||
jsonObject.put("networkDelay", networkTime);
|
||||
this.saveStatInfo(machineNodeModel, jsonObject);
|
||||
} catch (AuthorizeException agentException) {
|
||||
this.updateStatus(machineNodeModel, 2, agentException.getMessage());
|
||||
} catch (AgentException e) {
|
||||
this.updateStatus(machineNodeModel, 0, e.getMessage());
|
||||
} catch (Exception e) {
|
||||
this.updateStatus(machineNodeModel, 0, e.getMessage());
|
||||
log.error("获取节点监控信息失败", e);
|
||||
} finally {
|
||||
BaseServerController.removeEmpty();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新统计信息
|
||||
*
|
||||
* @param machineNode 机器数据
|
||||
* @param data 统计数据
|
||||
*/
|
||||
private void saveStatInfo(MachineNodeModel machineNode, JSONObject data) {
|
||||
MachineNodeModel machineNodeModel = new MachineNodeModel();
|
||||
machineNodeModel.setId(machineNode.getId());
|
||||
machineNodeModel.setStatus(1);
|
||||
machineNodeModel.setStatusMsg("ok");
|
||||
Integer networkDelay = data.getInteger("networkDelay");
|
||||
machineNodeModel.setNetworkDelay(networkDelay);
|
||||
// jpom 相关信息
|
||||
Optional.ofNullable(data.getJSONObject("jpomInfo")).ifPresent(jsonObject -> {
|
||||
JSONObject jpomManifest = jsonObject.getJSONObject("jpomManifest");
|
||||
Optional.ofNullable(jpomManifest)
|
||||
.ifPresent(jsonObject1 -> {
|
||||
machineNodeModel.setJpomVersion(jsonObject1.getString("version"));
|
||||
machineNodeModel.setJpomBuildTime(jsonObject1.getString("timeStamp"));
|
||||
machineNodeModel.setOsName(jsonObject1.getString("osName"));
|
||||
machineNodeModel.setJpomUptime(jsonObject1.getLong("upTime"));
|
||||
});
|
||||
machineNodeModel.setJpomProjectCount(jsonObject.getIntValue("projectCount"));
|
||||
machineNodeModel.setJpomScriptCount(jsonObject.getIntValue("scriptCount"));
|
||||
//
|
||||
machineNodeModel.setJvmFreeMemory(jsonObject.getLongValue("freeMemory"));
|
||||
machineNodeModel.setJvmTotalMemory(jsonObject.getLongValue("totalMemory"));
|
||||
machineNodeModel.setJavaVersion(jsonObject.getString("javaVersion"));
|
||||
});
|
||||
// 基础状态信息
|
||||
MachineNodeStatLogModel machineNodeStatLogModel = new MachineNodeStatLogModel();
|
||||
machineNodeStatLogModel.setMachineId(machineNodeModel.getId());
|
||||
machineNodeStatLogModel.setNetworkDelay(networkDelay);
|
||||
Optional.ofNullable(data.getJSONObject("simpleStatus")).ifPresent(jsonObject -> {
|
||||
machineNodeModel.setOsOccupyMemory(ObjectUtil.defaultIfNull(jsonObject.getDouble("memory"), -1D));
|
||||
machineNodeModel.setOsOccupyDisk(ObjectUtil.defaultIfNull(jsonObject.getDouble("disk"), -1D));
|
||||
machineNodeModel.setOsOccupyCpu(ObjectUtil.defaultIfNull(jsonObject.getDouble("cpu"), -1D));
|
||||
//
|
||||
machineNodeStatLogModel.setOccupyCpu(machineNodeModel.getOsOccupyCpu());
|
||||
machineNodeStatLogModel.setOccupyMemory(machineNodeModel.getOsOccupyMemory());
|
||||
machineNodeStatLogModel.setOccupyDisk(machineNodeModel.getOsOccupyDisk());
|
||||
machineNodeStatLogModel.setNetTxBytes(jsonObject.getLong("netTxBytes"));
|
||||
machineNodeStatLogModel.setNetRxBytes(jsonObject.getLong("netRxBytes"));
|
||||
machineNodeStatLogModel.setMonitorTime(jsonObject.getLongValue("time"));
|
||||
});
|
||||
// 系统信息
|
||||
Optional.ofNullable(data.getJSONObject("systemInfo")).ifPresent(jsonObject -> {
|
||||
machineNodeModel.setOsSystemUptime(jsonObject.getLong("systemUptime"));
|
||||
machineNodeModel.setOsVersion(jsonObject.getString("osVersion"));
|
||||
machineNodeModel.setHostName(jsonObject.getString("hostName"));
|
||||
machineNodeModel.setOsHardwareVersion(jsonObject.getString("hardwareVersion"));
|
||||
machineNodeModel.setHostIpv4s(CollUtil.join(jsonObject.getList("hostIpv4s", String.class), StrUtil.COMMA));
|
||||
machineNodeModel.setOsCpuIdentifierName(jsonObject.getString("osCpuIdentifierName"));
|
||||
machineNodeModel.setOsCpuCores(jsonObject.getInteger("osCpuCores"));
|
||||
machineNodeModel.setOsMoneyTotal(jsonObject.getLong("osMoneyTotal"));
|
||||
machineNodeModel.setOsLoadAverage(CollUtil.join(jsonObject.getList("osLoadAverage", Double.class), StrUtil.COMMA));
|
||||
machineNodeModel.setOsFileStoreTotal(jsonObject.getLong("osFileStoreTotal"));
|
||||
});
|
||||
this.updateById(machineNodeModel);
|
||||
machineNodeStatLogServer.insert(machineNodeStatLogModel);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新机器状态
|
||||
*
|
||||
* @param machineNode 机器信息
|
||||
* @param status 状态
|
||||
* @param msg 状态消息
|
||||
*/
|
||||
private void updateStatus(MachineNodeModel machineNode, int status, String msg) {
|
||||
MachineNodeModel machineNodeModel = new MachineNodeModel();
|
||||
machineNodeModel.setId(machineNode.getId());
|
||||
machineNodeModel.setStatus(status);
|
||||
machineNodeModel.setStatusMsg(msg);
|
||||
this.updateById(machineNodeModel);
|
||||
}
|
||||
|
||||
private MachineNodeModel resolveMachineData(HttpServletRequest request) {
|
||||
// 创建对象
|
||||
MachineNodeModel machineNodeModel = ServletUtil.toBean(request, MachineNodeModel.class, true);
|
||||
Assert.hasText(machineNodeModel.getName(), "请填写机器名称");
|
||||
Assert.hasText(machineNodeModel.getJpomUrl(), "请填写 节点地址");
|
||||
Assert.hasText(machineNodeModel.getJpomUsername(), "请填写节点密码");
|
||||
//
|
||||
MachineNodeModel update = new MachineNodeModel();
|
||||
update.setId(machineNodeModel.getId());
|
||||
update.setName(machineNodeModel.getName());
|
||||
update.setJpomHttpProxy(machineNodeModel.getJpomHttpProxy());
|
||||
update.setJpomHttpProxyType(machineNodeModel.getJpomHttpProxyType());
|
||||
update.setJpomUrl(machineNodeModel.getJpomUrl());
|
||||
update.setJpomProtocol(machineNodeModel.getJpomProtocol());
|
||||
update.setJpomUsername(machineNodeModel.getJpomUsername());
|
||||
update.setJpomPassword(machineNodeModel.getJpomPassword());
|
||||
update.setJpomTimeout(machineNodeModel.getJpomTimeout());
|
||||
return update;
|
||||
}
|
||||
|
||||
public boolean existsByUrl(String jpomUrl, String id) {
|
||||
Assert.hasText(jpomUrl, "节点地址不能为空");
|
||||
//
|
||||
Entity entity = Entity.create();
|
||||
entity.set("jpomUrl", jpomUrl);
|
||||
if (StrUtil.isNotEmpty(id)) {
|
||||
entity.set("id", StrUtil.format(" <> {}", id));
|
||||
}
|
||||
return this.exists(entity);
|
||||
}
|
||||
|
||||
public void update(HttpServletRequest request) {
|
||||
MachineNodeModel machineNodeModel = this.resolveMachineData(request);
|
||||
boolean exists = this.existsByUrl(machineNodeModel.getJpomUrl(), machineNodeModel.getId());
|
||||
Assert.state(!exists, "对应的节点已经存在啦");
|
||||
this.testNode(machineNodeModel);
|
||||
// 更新状态
|
||||
machineNodeModel.setStatus(1);
|
||||
//
|
||||
this.testHttpProxy(machineNodeModel.getJpomHttpProxy());
|
||||
//
|
||||
if (StrUtil.isNotEmpty(machineNodeModel.getId())) {
|
||||
this.updateById(machineNodeModel);
|
||||
} else {
|
||||
// 目前默认为此
|
||||
machineNodeModel.setTransportMode(0);
|
||||
this.insert(machineNodeModel);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试节点是否可以访问
|
||||
*
|
||||
* @param nodeModel 节点信息
|
||||
*/
|
||||
public void testNode(MachineNodeModel nodeModel) {
|
||||
//
|
||||
int timeout = ObjectUtil.defaultIfNull(nodeModel.getJpomTimeout(), 0);
|
||||
// 检查是否可用默认为5秒,避免太长时间无法连接一直等待
|
||||
nodeModel.setJpomTimeout(5);
|
||||
//
|
||||
JsonMessage<JpomManifest> objectJsonMessage = NodeForward.request(nodeModel, StrUtil.EMPTY, NodeUrl.Info, "nodeId", nodeModel.getId());
|
||||
try {
|
||||
JpomManifest jpomManifest = objectJsonMessage.getData(JpomManifest.class);
|
||||
Assert.notNull(jpomManifest, "节点连接失败,请检查节点是否在线");
|
||||
} catch (Exception e) {
|
||||
log.error("节点连接失败,请检查节点是否在线", e);
|
||||
throw new IllegalStateException("节点返回信息异常,请检查节点地址是否配置正确或者代理配置是否正确");
|
||||
}
|
||||
//
|
||||
nodeModel.setJpomTimeout(timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* 探测 http proxy 是否可用
|
||||
*
|
||||
* @param httpProxy http proxy
|
||||
*/
|
||||
public void testHttpProxy(String httpProxy) {
|
||||
if (StrUtil.isNotEmpty(httpProxy)) {
|
||||
List<String> split = StrUtil.splitTrim(httpProxy, StrUtil.COLON);
|
||||
Assert.isTrue(CollUtil.size(split) == 2, "HTTP代理地址格式不正确");
|
||||
String host = split.get(0);
|
||||
int port = Convert.toInt(split.get(1), 0);
|
||||
Assert.isTrue(StrUtil.isNotEmpty(host) && NetUtil.isValidPort(port), "HTTP代理地址格式不正确");
|
||||
//
|
||||
try {
|
||||
NetUtil.netCat(host, port, StrUtil.EMPTY.getBytes());
|
||||
} catch (Exception e) {
|
||||
log.warn("HTTP代理地址不可用:" + httpProxy, e);
|
||||
throw new IllegalArgumentException("HTTP代理地址不可用:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void insertAndNode(MachineNodeModel machineNodeModel, String workspaceId) {
|
||||
this.insert(machineNodeModel);
|
||||
NodeModel nodeModel = this.createModel(machineNodeModel, workspaceId);
|
||||
nodeService.insert(nodeModel);
|
||||
}
|
||||
|
||||
private NodeModel createModel(MachineNodeModel machineNodeModel, String workspaceId) {
|
||||
NodeModel nodeModel = new NodeModel();
|
||||
nodeModel.setWorkspaceId(workspaceId);
|
||||
nodeModel.setName(machineNodeModel.getName());
|
||||
nodeModel.setOpenStatus(1);
|
||||
nodeModel.setGroup(Const.DEFAULT_GROUP_NAME);
|
||||
return nodeModel;
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Code Technology Studio
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package io.jpom.func.assets.server;
|
||||
|
||||
import io.jpom.func.assets.model.MachineNodeStatLogModel;
|
||||
import io.jpom.service.h2db.BaseDbService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author bwcx_jzy
|
||||
* @since 2023/2/18
|
||||
*/
|
||||
@Service
|
||||
public class MachineNodeStatLogServer extends BaseDbService<MachineNodeStatLogModel> {
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Code Technology Studio
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package io.jpom.model;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* @author bwcx_jzy
|
||||
* @since 2023/2/18
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public abstract class BaseMachineModel extends BaseGroupModel {
|
||||
|
||||
/**
|
||||
* 机器id
|
||||
*/
|
||||
private String machineId;
|
||||
}
|
@ -22,22 +22,13 @@
|
||||
*/
|
||||
package io.jpom.model.data;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.util.EnumUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
import io.jpom.common.forward.NodeUrl;
|
||||
import io.jpom.model.BaseGroupModel;
|
||||
import cn.hutool.core.annotation.PropIgnore;
|
||||
import io.jpom.func.assets.model.MachineNodeModel;
|
||||
import io.jpom.model.BaseMachineModel;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import top.jpom.h2db.TableName;
|
||||
import top.jpom.transport.INodeInfo;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Proxy;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 节点实体
|
||||
@ -49,16 +40,20 @@ import java.util.List;
|
||||
@TableName(value = "NODE_INFO", name = "节点信息")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class NodeModel extends BaseGroupModel implements INodeInfo {
|
||||
public class NodeModel extends BaseMachineModel {
|
||||
|
||||
@Deprecated
|
||||
private String url;
|
||||
@Deprecated
|
||||
private String loginName;
|
||||
@Deprecated
|
||||
private String loginPwd;
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 节点协议
|
||||
*/
|
||||
@Deprecated
|
||||
private String protocol;
|
||||
/**
|
||||
* 开启状态,如果关闭状态就暂停使用节点 1 启用
|
||||
@ -67,29 +62,31 @@ public class NodeModel extends BaseGroupModel implements INodeInfo {
|
||||
/**
|
||||
* 节点超时时间
|
||||
*/
|
||||
@Deprecated
|
||||
private Integer timeOut;
|
||||
/**
|
||||
* 绑定的sshId
|
||||
*/
|
||||
private String sshId;
|
||||
/**
|
||||
* 锁定类型
|
||||
*/
|
||||
private String unLockType;
|
||||
|
||||
/**
|
||||
* http 代理
|
||||
*/
|
||||
@Deprecated
|
||||
private String httpProxy;
|
||||
/**
|
||||
* https 代理 类型
|
||||
*/
|
||||
@Deprecated
|
||||
private String httpProxyType;
|
||||
/**
|
||||
* 排序
|
||||
*/
|
||||
private Float sortValue;
|
||||
|
||||
@PropIgnore
|
||||
private MachineNodeModel machineNodeData;
|
||||
|
||||
public boolean isOpenStatus() {
|
||||
return openStatus != null && openStatus == 1;
|
||||
}
|
||||
@ -103,73 +100,8 @@ public class NodeModel extends BaseGroupModel implements INodeInfo {
|
||||
this.setWorkspaceId(workspaceId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 授权的信息
|
||||
*
|
||||
* @return sha1
|
||||
*/
|
||||
public String toAuthorize() {
|
||||
return SecureUtil.sha1(loginName + "@" + loginPwd);
|
||||
}
|
||||
// public String getRealUrl(NodeUrl nodeUrl) {
|
||||
// return StrUtil.format("{}://{}{}", getProtocol().toLowerCase(), getUrl(), nodeUrl.getUrl());
|
||||
// }
|
||||
|
||||
public String getRealUrl(NodeUrl nodeUrl) {
|
||||
return StrUtil.format("{}://{}{}", getProtocol().toLowerCase(), getUrl(), nodeUrl.getUrl());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return this.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String url() {
|
||||
return this.getUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String scheme() {
|
||||
return getProtocol();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String authorize() {
|
||||
return this.toAuthorize();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取节点的代理
|
||||
*
|
||||
* @return proxy
|
||||
*/
|
||||
@Override
|
||||
public Proxy proxy() {
|
||||
String httpProxy = this.getHttpProxy();
|
||||
if (StrUtil.isNotEmpty(httpProxy)) {
|
||||
List<String> split = StrUtil.splitTrim(httpProxy, StrUtil.COLON);
|
||||
String host = CollUtil.getFirst(split);
|
||||
int port = Convert.toInt(CollUtil.getLast(split), 0);
|
||||
String type = this.getHttpProxyType();
|
||||
Proxy.Type type1 = EnumUtil.fromString(Proxy.Type.class, type, Proxy.Type.HTTP);
|
||||
return new Proxy(type1, new InetSocketAddress(host, port));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建代理
|
||||
*
|
||||
* @param type 代理类型
|
||||
* @param httpProxy 代理地址
|
||||
* @return proxy
|
||||
*/
|
||||
public static Proxy crateProxy(String type, String httpProxy) {
|
||||
if (StrUtil.isNotEmpty(httpProxy)) {
|
||||
List<String> split = StrUtil.splitTrim(httpProxy, StrUtil.COLON);
|
||||
String host = CollUtil.getFirst(split);
|
||||
int port = Convert.toInt(CollUtil.getLast(split), 0);
|
||||
Proxy.Type type1 = EnumUtil.fromString(Proxy.Type.class, type, Proxy.Type.HTTP);
|
||||
return new Proxy(type1, new InetSocketAddress(host, port));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -89,6 +89,7 @@ public enum ClassFeature {
|
||||
SYSTEM_CACHE("系统缓存"),
|
||||
SYSTEM_LOG("系统日志"),
|
||||
SYSTEM_UPGRADE("在线升级"),
|
||||
SYSTEM_ASSETS_MACHINE("机器资产管理"),
|
||||
SYSTEM_CONFIG("服务端系统配置"),
|
||||
SYSTEM_EXT_CONFIG("系统配置目录"),
|
||||
SYSTEM_CONFIG_IP("系统配置IP白名单"),
|
||||
|
@ -31,6 +31,7 @@ import org.springframework.stereotype.Service;
|
||||
* @since 2019/9/13
|
||||
*/
|
||||
@Service
|
||||
@Deprecated
|
||||
public class DbSystemMonitorLogService extends BaseDbService<SystemMonitorLog> {
|
||||
|
||||
@Override
|
||||
|
@ -110,17 +110,17 @@ public abstract class BaseDbService<T extends BaseDbModel> extends BaseDbCommonS
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 不填充 插入
|
||||
*
|
||||
* @param t 数据
|
||||
*/
|
||||
public void insertNotFill(T t) {
|
||||
// def create time
|
||||
t.setCreateTimeMillis(ObjectUtil.defaultIfNull(t.getCreateTimeMillis(), SystemClock.now()));
|
||||
t.setId(ObjectUtil.defaultIfNull(t.getId(), IdUtil.fastSimpleUUID()));
|
||||
super.insert(t);
|
||||
}
|
||||
// /**
|
||||
// * 不填充 插入
|
||||
// *
|
||||
// * @param t 数据
|
||||
// */
|
||||
// public void insertNotFill(T t) {
|
||||
// // def create time
|
||||
// t.setCreateTimeMillis(ObjectUtil.defaultIfNull(t.getCreateTimeMillis(), SystemClock.now()));
|
||||
// t.setId(ObjectUtil.defaultIfNull(t.getId(), IdUtil.fastSimpleUUID()));
|
||||
// super.insert(t);
|
||||
// }
|
||||
|
||||
@Override
|
||||
public void insert(Collection<T> t) {
|
||||
@ -208,7 +208,11 @@ public abstract class BaseDbService<T extends BaseDbModel> extends BaseDbCommonS
|
||||
}
|
||||
|
||||
public List<T> list() {
|
||||
return super.listByBean(ReflectUtil.newInstance(this.tClass));
|
||||
return this.list(true);
|
||||
}
|
||||
|
||||
public List<T> list(boolean fill) {
|
||||
return this.listByBean(ReflectUtil.newInstance(this.tClass), fill);
|
||||
}
|
||||
|
||||
public long count() {
|
||||
|
@ -23,6 +23,7 @@
|
||||
package io.jpom.service.h2db;
|
||||
|
||||
import cn.hutool.db.Entity;
|
||||
import io.jpom.common.Const;
|
||||
import io.jpom.common.ServerConst;
|
||||
import io.jpom.model.BaseGroupModel;
|
||||
|
||||
@ -66,6 +67,6 @@ public abstract class BaseGroupService<T extends BaseGroupModel> extends BaseWor
|
||||
*/
|
||||
public void repairGroupFiled() {
|
||||
String sql = "update " + getTableName() + " set `GROUP`=? where `GROUP` is null or `GROUP`=''";
|
||||
super.execute(sql, "默认");
|
||||
super.execute(sql, Const.DEFAULT_GROUP_NAME);
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,7 @@
|
||||
package io.jpom.service.h2db;
|
||||
|
||||
import cn.hutool.db.Entity;
|
||||
import io.jpom.common.Const;
|
||||
import io.jpom.common.ServerConst;
|
||||
import io.jpom.model.BaseNodeGroupModel;
|
||||
import io.jpom.service.node.NodeService;
|
||||
@ -71,6 +72,6 @@ public abstract class BaseNodeGroupService<T extends BaseNodeGroupModel> extends
|
||||
*/
|
||||
public void repairGroupFiled() {
|
||||
String sql = "update " + getTableName() + " set `GROUP`=? where `GROUP` is null or `GROUP`=''";
|
||||
super.execute(sql, "默认");
|
||||
super.execute(sql, Const.DEFAULT_GROUP_NAME);
|
||||
}
|
||||
}
|
||||
|
@ -22,26 +22,16 @@
|
||||
*/
|
||||
package io.jpom.service.node;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.lang.Opt;
|
||||
import cn.hutool.core.lang.Validator;
|
||||
import cn.hutool.core.net.NetUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.db.Entity;
|
||||
import cn.hutool.extra.servlet.ServletUtil;
|
||||
import io.jpom.common.Const;
|
||||
import io.jpom.common.JpomManifest;
|
||||
import io.jpom.common.JsonMessage;
|
||||
import io.jpom.common.forward.NodeForward;
|
||||
import io.jpom.common.forward.NodeUrl;
|
||||
import io.jpom.model.data.NodeModel;
|
||||
import io.jpom.model.data.SshModel;
|
||||
import io.jpom.model.data.WorkspaceModel;
|
||||
import io.jpom.service.h2db.BaseGroupService;
|
||||
import io.jpom.service.node.ssh.SshService;
|
||||
import io.jpom.service.system.WorkspaceService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
@ -49,10 +39,7 @@ import org.springframework.util.Assert;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author bwcx_jzy
|
||||
@ -63,9 +50,6 @@ import java.util.stream.Collectors;
|
||||
public class NodeService extends BaseGroupService<NodeModel> {
|
||||
|
||||
private final SshService sshService;
|
||||
@Resource
|
||||
@Lazy
|
||||
private WorkspaceService workspaceService;
|
||||
|
||||
@Resource
|
||||
@Lazy
|
||||
@ -82,45 +66,53 @@ public class NodeService extends BaseGroupService<NodeModel> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试节点是否可以访问
|
||||
*
|
||||
* @param nodeModel 节点信息
|
||||
*/
|
||||
public void testNode(NodeModel nodeModel) {
|
||||
//
|
||||
int timeOut = ObjectUtil.defaultIfNull(nodeModel.getTimeOut(), 0);
|
||||
// 检查是否可用默认为5秒,避免太长时间无法连接一直等待
|
||||
nodeModel.setTimeOut(5);
|
||||
//
|
||||
JsonMessage<JpomManifest> objectJsonMessage = NodeForward.request(nodeModel, NodeUrl.Info, "nodeId", nodeModel.getId());
|
||||
try {
|
||||
JpomManifest jpomManifest = objectJsonMessage.getData(JpomManifest.class);
|
||||
Assert.notNull(jpomManifest, "节点连接失败,请检查节点是否在线");
|
||||
} catch (Exception e) {
|
||||
log.error("节点连接失败,请检查节点是否在线", e);
|
||||
throw new IllegalStateException("节点返回信息异常,请检查节点地址是否配置正确或者代理配置是否正确");
|
||||
}
|
||||
//
|
||||
nodeModel.setTimeOut(timeOut);
|
||||
}
|
||||
|
||||
public boolean existsByUrl(String url, String workspaceId, String id) {
|
||||
// Entity entity = Entity.create();
|
||||
// entity.set("url", nodeModel.getUrl());
|
||||
// entity.set("workspaceId", workspaceId);
|
||||
// if (StrUtil.isNotEmpty(id)) {
|
||||
// entity.set("id", StrUtil.format(" <> {}", id));
|
||||
// public boolean existsByUrl(String url, String workspaceId, String id) {
|
||||
//
|
||||
// // 可能出现错误
|
||||
// NodeModel nodeModel1 = new NodeModel();
|
||||
// nodeModel1.setUrl(url);
|
||||
// nodeModel1.setWorkspaceId(workspaceId);
|
||||
// List<NodeModel> nodeModels = ObjectUtil.defaultIfNull(super.listByBean(nodeModel1), Collections.EMPTY_LIST);
|
||||
// Optional<NodeModel> any = nodeModels.stream().filter(nodeModel2 -> !StrUtil.equals(id, nodeModel2.getId())).findAny();
|
||||
// return any.isPresent();
|
||||
// }
|
||||
// boolean exists = super.exists(entity);
|
||||
// Assert.state(!exists, "对应的节点已经存在啦");
|
||||
// 可能出现错误
|
||||
NodeModel nodeModel1 = new NodeModel();
|
||||
nodeModel1.setUrl(url);
|
||||
nodeModel1.setWorkspaceId(workspaceId);
|
||||
List<NodeModel> nodeModels = ObjectUtil.defaultIfNull(super.listByBean(nodeModel1), Collections.EMPTY_LIST);
|
||||
Optional<NodeModel> any = nodeModels.stream().filter(nodeModel2 -> !StrUtil.equals(id, nodeModel2.getId())).findAny();
|
||||
return any.isPresent();
|
||||
|
||||
private NodeModel resolveNode(HttpServletRequest request) {
|
||||
// 创建对象
|
||||
NodeModel nodeModel = ServletUtil.toBean(request, NodeModel.class, true);
|
||||
String id = nodeModel.getId();
|
||||
Assert.hasText(id, "没有节点id");
|
||||
Assert.hasText(nodeModel.getName(), "请填写节点名称");
|
||||
// 兼容就数据判断
|
||||
String checkId = StrUtil.replace(id, StrUtil.DASHED, StrUtil.UNDERLINE);
|
||||
Validator.validateGeneral(checkId, 2, Const.ID_MAX_LEN, "节点id不能为空并且2-50(英文字母 、数字和下划线)");
|
||||
|
||||
Assert.hasText(nodeModel.getName(), "节点名称 不能为空");
|
||||
String workspaceId = this.getCheckUserWorkspace(request);
|
||||
nodeModel.setWorkspaceId(workspaceId);
|
||||
|
||||
// 判断 ssh
|
||||
String sshId = nodeModel.getSshId();
|
||||
if (StrUtil.isNotEmpty(sshId)) {
|
||||
SshModel byKey = sshService.getByKey(sshId, request);
|
||||
Assert.notNull(byKey, "对应的 SSH 不存在");
|
||||
Entity entity = Entity.create();
|
||||
entity.set("sshId", sshId);
|
||||
entity.set("workspaceId", workspaceId);
|
||||
if (StrUtil.isNotEmpty(id)) {
|
||||
entity.set("id", StrUtil.format(" <> {}", id));
|
||||
}
|
||||
boolean exists = super.exists(entity);
|
||||
Assert.state(!exists, "对应的SSH已经被其他节点绑定啦");
|
||||
}
|
||||
NodeModel update = new NodeModel();
|
||||
update.setId(id);
|
||||
update.setName(nodeModel.getName());
|
||||
update.setGroup(nodeModel.getGroup());
|
||||
update.setSshId(nodeModel.getSshId());
|
||||
update.setOpenStatus(nodeModel.getOpenStatus());
|
||||
return update;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -129,95 +121,12 @@ public class NodeService extends BaseGroupService<NodeModel> {
|
||||
* @param request 请求对象
|
||||
*/
|
||||
public void update(HttpServletRequest request) {
|
||||
String type = request.getParameter("type");
|
||||
boolean create = "add".equalsIgnoreCase(type);
|
||||
// 创建对象
|
||||
NodeModel nodeModel = ServletUtil.toBean(request, NodeModel.class, true);
|
||||
String id = nodeModel.getId();
|
||||
if (StrUtil.isNotEmpty(id)) {
|
||||
String checkId = StrUtil.replace(id, StrUtil.DASHED, StrUtil.UNDERLINE);
|
||||
Validator.validateGeneral(checkId, 2, Const.ID_MAX_LEN, "节点id不能为空并且2-50(英文字母 、数字和下划线)");
|
||||
}
|
||||
Assert.hasText(nodeModel.getName(), "节点名称 不能为空");
|
||||
//
|
||||
this.testHttpProxy(nodeModel.getHttpProxy());
|
||||
NodeModel existsNode = super.getByKey(id);
|
||||
String workspaceId = this.getCheckUserWorkspace(request);
|
||||
nodeModel.setWorkspaceId(workspaceId);
|
||||
|
||||
//nodeModel.setProtocol(StrUtil.emptyToDefault(nodeModel.getProtocol(), "http"));
|
||||
{// 节点地址 重复
|
||||
boolean exists = this.existsByUrl(nodeModel.getUrl(), nodeModel.getWorkspaceId(), id);
|
||||
Assert.state(!exists, "对应的节点已经存在啦");
|
||||
}
|
||||
// 判断 ssh
|
||||
String sshId = nodeModel.getSshId();
|
||||
if (StrUtil.isNotEmpty(sshId)) {
|
||||
SshModel byKey = sshService.getByKey(sshId, request);
|
||||
Assert.notNull(byKey, "对应的 SSH 不存在");
|
||||
List<NodeModel> nodeBySshId = this.getNodeBySshId(sshId);
|
||||
nodeBySshId = ObjectUtil.defaultIfNull(nodeBySshId, Collections.emptyList());
|
||||
boolean anyMatch = nodeBySshId.stream().anyMatch(nodeModel2 -> !StrUtil.equals(id, nodeModel2.getId()));
|
||||
// Optional<NodeModel> any = anyMatch.findAny();
|
||||
Assert.state(!anyMatch, "对应的SSH已经被其他节点绑定啦");
|
||||
}
|
||||
if (nodeModel.isOpenStatus()) {
|
||||
//
|
||||
this.checkLockType(existsNode);
|
||||
this.testNode(nodeModel);
|
||||
}
|
||||
if (create) {
|
||||
|
||||
this.insert(nodeModel);
|
||||
NodeModel nodeModel = this.resolveNode(request);
|
||||
this.update(nodeModel);
|
||||
// 同步项目
|
||||
projectInfoCacheService.syncNode(nodeModel);
|
||||
} else {
|
||||
this.update(nodeModel);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 探测 http proxy 是否可用
|
||||
*
|
||||
* @param httpProxy http proxy
|
||||
*/
|
||||
public void testHttpProxy(String httpProxy) {
|
||||
if (StrUtil.isNotEmpty(httpProxy)) {
|
||||
List<String> split = StrUtil.splitTrim(httpProxy, StrUtil.COLON);
|
||||
Assert.isTrue(CollUtil.size(split) == 2, "HTTP代理地址格式不正确");
|
||||
String host = split.get(0);
|
||||
int port = Convert.toInt(split.get(1), 0);
|
||||
Assert.isTrue(StrUtil.isNotEmpty(host) && NetUtil.isValidPort(port), "HTTP代理地址格式不正确");
|
||||
//
|
||||
try {
|
||||
NetUtil.netCat(host, port, StrUtil.EMPTY.getBytes());
|
||||
} catch (Exception e) {
|
||||
log.warn("HTTP代理地址不可用:" + httpProxy, e);
|
||||
throw new IllegalArgumentException("HTTP代理地址不可用:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解锁分配工作空间
|
||||
*
|
||||
* @param id 节点ID
|
||||
* @param workspaceId 工作空间
|
||||
*/
|
||||
public void unLock(String id, String workspaceId) {
|
||||
NodeModel nodeModel = super.getByKey(id);
|
||||
Assert.notNull(nodeModel, "没有对应对节点");
|
||||
//
|
||||
WorkspaceModel workspaceModel = workspaceService.getByKey(workspaceId);
|
||||
Assert.notNull(workspaceModel, "没有对应对工作空间");
|
||||
|
||||
NodeModel nodeModel1 = new NodeModel();
|
||||
nodeModel1.setId(id);
|
||||
nodeModel1.setWorkspaceId(workspaceId);
|
||||
nodeModel1.setUnLockType(StrUtil.EMPTY);
|
||||
nodeModel1.setOpenStatus(1);
|
||||
super.update(nodeModel1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将节点信息同步到其他工作空间
|
||||
@ -228,144 +137,59 @@ public class NodeService extends BaseGroupService<NodeModel> {
|
||||
*/
|
||||
public void syncToWorkspace(String ids, String nowWorkspaceId, String workspaceId) {
|
||||
StrUtil.splitTrim(ids, StrUtil.COMMA).forEach(id -> {
|
||||
NodeModel data = super.getByKey(id, false, entity -> entity.set("workspaceId", nowWorkspaceId));
|
||||
NodeModel data = this.getByKey(id, false, entity -> entity.set("workspaceId", nowWorkspaceId));
|
||||
Assert.notNull(data, "没有对应到节点信息");
|
||||
//
|
||||
NodeModel where = new NodeModel();
|
||||
where.setWorkspaceId(workspaceId);
|
||||
where.setUrl(data.getUrl());
|
||||
NodeModel nodeModel = NodeService.super.queryByBean(where);
|
||||
if (nodeModel == null) {
|
||||
where.setMachineId(data.getMachineId());
|
||||
NodeModel nodeModel = this.queryByBean(where);
|
||||
Assert.isNull(nodeModel, () -> "对应工作空间已经存在改节点啦:" + nodeModel.getName());
|
||||
// 不存在则添加节点
|
||||
data.setId(null);
|
||||
data.setWorkspaceId(workspaceId);
|
||||
data.setCreateTimeMillis(null);
|
||||
data.setModifyTimeMillis(null);
|
||||
data.setModifyUser(null);
|
||||
data.setLoginName(null);
|
||||
data.setUrl(null);
|
||||
data.setLoginPwd(null);
|
||||
data.setProtocol(null);
|
||||
data.setHttpProxy(null);
|
||||
data.setHttpProxyType(null);
|
||||
// ssh 不同步
|
||||
data.setSshId(null);
|
||||
NodeService.super.insert(data);
|
||||
} else {
|
||||
// 修改信息
|
||||
NodeModel update = new NodeModel(nodeModel.getId());
|
||||
update.setLoginName(data.getLoginName());
|
||||
update.setLoginPwd(data.getLoginPwd());
|
||||
update.setProtocol(data.getProtocol());
|
||||
update.setHttpProxy(data.getHttpProxy());
|
||||
update.setHttpProxyType(data.getHttpProxyType());
|
||||
NodeService.super.updateById(update);
|
||||
}
|
||||
this.insert(data);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断节点是否锁定中
|
||||
*
|
||||
* @param nodeModel 节点
|
||||
*/
|
||||
private void checkLockType(NodeModel nodeModel) {
|
||||
if (nodeModel == null) {
|
||||
return;
|
||||
}
|
||||
// 判断锁定类型
|
||||
if (StrUtil.isNotEmpty(nodeModel.getUnLockType())) {
|
||||
//
|
||||
Assert.state(!StrUtil.equals(nodeModel.getUnLockType(), "unassignedWorkspace"), "当前节点还未分配工作空间,请分配");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insert(NodeModel nodeModel) {
|
||||
this.fillNodeInfo(nodeModel);
|
||||
super.insert(nodeModel);
|
||||
this.updateDuplicateNode(nodeModel);
|
||||
protected void fillInsert(NodeModel nodeModel) {
|
||||
super.fillInsert(nodeModel);
|
||||
// 表中字段不能为空,设置为空字符串
|
||||
nodeModel.setLoginName(StrUtil.EMPTY);
|
||||
nodeModel.setLoginPwd(StrUtil.EMPTY);
|
||||
nodeModel.setProtocol(StrUtil.EMPTY);
|
||||
nodeModel.setUrl(StrUtil.EMPTY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertNotFill(NodeModel nodeModel) {
|
||||
nodeModel.setWorkspaceId(StrUtil.emptyToDefault(nodeModel.getWorkspaceId(), Const.WORKSPACE_DEFAULT_ID));
|
||||
this.fillNodeInfo(nodeModel);
|
||||
super.insertNotFill(nodeModel);
|
||||
this.updateDuplicateNode(nodeModel);
|
||||
}
|
||||
|
||||
/**
|
||||
* 填充默认字段
|
||||
*
|
||||
* @param nodeModel 节点
|
||||
*/
|
||||
private void fillNodeInfo(NodeModel nodeModel) {
|
||||
nodeModel.setProtocol(StrUtil.emptyToDefault(nodeModel.getProtocol(), "http"));
|
||||
nodeModel.setOpenStatus(ObjectUtil.defaultIfNull(nodeModel.getOpenStatus(), 0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int delByKey(String keyValue) {
|
||||
return super.delByKey(keyValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int del(Entity where) {
|
||||
return super.del(where);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int updateById(NodeModel info) {
|
||||
int updateById = super.updateById(info);
|
||||
if (updateById > 0) {
|
||||
this.updateDuplicateNode(info);
|
||||
}
|
||||
return updateById;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新相同节点对 授权信息
|
||||
*
|
||||
* @param info 节点信息
|
||||
*/
|
||||
private void updateDuplicateNode(NodeModel info) {
|
||||
// if (StrUtil.hasEmpty(info.getUrl(), info.getLoginName(), info.getLoginPwd())) {
|
||||
// return;
|
||||
// @Override
|
||||
// public void insertNotFill(NodeModel nodeModel) {
|
||||
// nodeModel.setWorkspaceId(StrUtil.emptyToDefault(nodeModel.getWorkspaceId(), Const.WORKSPACE_DEFAULT_ID));
|
||||
// this.fillNodeInfo(nodeModel);
|
||||
// super.insertNotFill(nodeModel);
|
||||
// }
|
||||
// NodeModel update = new NodeModel();
|
||||
// update.setLoginName(info.getLoginName());
|
||||
// update.setLoginPwd(info.getLoginPwd());
|
||||
// //
|
||||
// NodeModel where = new NodeModel();
|
||||
// where.setUrl(info.getUrl());
|
||||
// int updateCount = super.update(super.dataBeanToEntity(update), super.dataBeanToEntity(where));
|
||||
// if (updateCount > 1) {
|
||||
// log.debug("update duplicate node {} {}", info.getUrl(), updateCount);
|
||||
|
||||
// /**
|
||||
// * 填充默认字段
|
||||
// *
|
||||
// * @param nodeModel 节点
|
||||
// */
|
||||
// private void fillNodeInfo(NodeModel nodeModel) {
|
||||
// nodeModel.setProtocol(StrUtil.emptyToDefault(nodeModel.getProtocol(), "http"));
|
||||
// nodeModel.setOpenStatus(ObjectUtil.defaultIfNull(nodeModel.getOpenStatus(), 0));
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 url 去重
|
||||
*
|
||||
* @return list
|
||||
*/
|
||||
public List<NodeModel> listDeDuplicationByUrl() {
|
||||
String sql = "select url,max(loginName) as loginName,max(loginPwd) as loginPwd,max(protocol) as protocol from " + super.getTableName() + " group by url";
|
||||
List<Entity> query = this.query(sql);
|
||||
if (query != null) {
|
||||
return query.stream().map((entity -> this.entityToBean(entity, this.tClass))).collect(Collectors.toList());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 url 去重
|
||||
*
|
||||
* @return list
|
||||
*/
|
||||
public List<String> getDeDuplicationByUrl() {
|
||||
String sql = "select url from " + super.getTableName() + " group by url";
|
||||
List<Entity> query = this.query(sql);
|
||||
if (query != null) {
|
||||
return query.stream().map((entity -> entity.getStr("url"))).collect(Collectors.toList());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<NodeModel> getNodeBySshId(String sshId) {
|
||||
NodeModel nodeModel = new NodeModel();
|
||||
|
@ -20,275 +20,280 @@
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package io.jpom.service.stat;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.date.SystemClock;
|
||||
import cn.hutool.core.thread.ThreadUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.db.Entity;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import io.jpom.common.BaseServerController;
|
||||
import io.jpom.common.JsonMessage;
|
||||
import io.jpom.common.forward.NodeForward;
|
||||
import io.jpom.common.forward.NodeUrl;
|
||||
import io.jpom.cron.IAsyncLoad;
|
||||
import io.jpom.model.data.NodeModel;
|
||||
import io.jpom.model.log.SystemMonitorLog;
|
||||
import io.jpom.model.stat.NodeStatModel;
|
||||
import io.jpom.model.user.UserModel;
|
||||
import io.jpom.service.dblog.DbSystemMonitorLogService;
|
||||
import io.jpom.service.h2db.BaseWorkspaceService;
|
||||
import io.jpom.service.node.NodeService;
|
||||
import io.jpom.system.AgentException;
|
||||
import io.jpom.system.AuthorizeException;
|
||||
import io.jpom.system.ServerConfig;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 节点统计 service
|
||||
*
|
||||
* @author bwcx_jzy
|
||||
* @since 2022/1/22
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class NodeStatService extends BaseWorkspaceService<NodeStatModel> implements IAsyncLoad, Runnable {
|
||||
|
||||
private final DbSystemMonitorLogService dbSystemMonitorLogService;
|
||||
private final NodeService nodeService;
|
||||
private final ServerConfig.NodeConfig nodeConfig;
|
||||
|
||||
public NodeStatService(DbSystemMonitorLogService dbSystemMonitorLogService,
|
||||
NodeService nodeService,
|
||||
ServerConfig serverConfig) {
|
||||
this.dbSystemMonitorLogService = dbSystemMonitorLogService;
|
||||
this.nodeService = nodeService;
|
||||
this.nodeConfig = serverConfig.getNode();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 url 去重
|
||||
*
|
||||
* @return list
|
||||
*/
|
||||
public List<String> getDeDuplicationByUrl() {
|
||||
String sql = "select url from " + super.getTableName() + " group by url";
|
||||
List<Entity> query = this.query(sql);
|
||||
if (query != null) {
|
||||
return query.stream().map((entity -> entity.getStr("url"))).collect(Collectors.toList());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startLoad() {
|
||||
// 启动心跳检测
|
||||
int heartSecond = nodeConfig.getHeartSecond();
|
||||
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(runnable -> new Thread(runnable, "Jpom Node Monitor"));
|
||||
scheduler.scheduleAtFixedRate(this, 10, heartSecond, TimeUnit.SECONDS);
|
||||
// 清理 错误的节点统计数据
|
||||
List<String> duplicationByUrl = nodeService.getDeDuplicationByUrl();
|
||||
List<String> statUrl = this.getDeDuplicationByUrl();
|
||||
Collection<String> subtract = CollUtil.subtract(statUrl, duplicationByUrl);
|
||||
///*
|
||||
// * The MIT License (MIT)
|
||||
// *
|
||||
// * Copyright (c) 2019 Code Technology Studio
|
||||
// *
|
||||
// * Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// * this software and associated documentation files (the "Software"), to deal in
|
||||
// * the Software without restriction, including without limitation the rights to
|
||||
// * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// * the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// * subject to the following conditions:
|
||||
// *
|
||||
// * The above copyright notice and this permission notice shall be included in all
|
||||
// * copies or substantial portions of the Software.
|
||||
// *
|
||||
// * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// */
|
||||
//package io.jpom.service.stat;
|
||||
//
|
||||
for (String s : subtract) {
|
||||
NodeStatModel statModel = new NodeStatModel();
|
||||
statModel.setUrl(s);
|
||||
this.del(this.dataBeanToEntity(statModel));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
List<NodeModel> nodeModels = nodeService.listDeDuplicationByUrl();
|
||||
//import cn.hutool.core.collection.CollUtil;
|
||||
//import cn.hutool.core.date.SystemClock;
|
||||
//import cn.hutool.core.thread.ThreadUtil;
|
||||
//import cn.hutool.core.util.ObjectUtil;
|
||||
//import cn.hutool.core.util.StrUtil;
|
||||
//import cn.hutool.db.Entity;
|
||||
//import com.alibaba.fastjson2.JSONObject;
|
||||
//import io.jpom.common.BaseServerController;
|
||||
//import io.jpom.common.JsonMessage;
|
||||
//import io.jpom.common.forward.NodeForward;
|
||||
//import io.jpom.common.forward.NodeUrl;
|
||||
//import io.jpom.cron.IAsyncLoad;
|
||||
//import io.jpom.model.data.NodeModel;
|
||||
//import io.jpom.model.log.SystemMonitorLog;
|
||||
//import io.jpom.model.stat.NodeStatModel;
|
||||
//import io.jpom.model.user.UserModel;
|
||||
//import io.jpom.service.dblog.DbSystemMonitorLogService;
|
||||
//import io.jpom.service.h2db.BaseWorkspaceService;
|
||||
//import io.jpom.service.node.NodeService;
|
||||
//import io.jpom.system.AgentException;
|
||||
//import io.jpom.system.AuthorizeException;
|
||||
//import io.jpom.system.ServerConfig;
|
||||
//import lombok.extern.slf4j.Slf4j;
|
||||
//import org.springframework.stereotype.Service;
|
||||
//
|
||||
this.checkList(nodeModels);
|
||||
}
|
||||
|
||||
|
||||
private List<NodeModel> getListByUrl(String url) {
|
||||
NodeModel nodeModel = new NodeModel();
|
||||
nodeModel.setUrl(url);
|
||||
return nodeService.listByBean(nodeModel);
|
||||
}
|
||||
|
||||
private void checkList(List<NodeModel> nodeModels) {
|
||||
if (CollUtil.isEmpty(nodeModels)) {
|
||||
return;
|
||||
}
|
||||
nodeModels.forEach(nodeModel -> {
|
||||
//import java.util.Collection;
|
||||
//import java.util.List;
|
||||
//import java.util.concurrent.Executors;
|
||||
//import java.util.concurrent.ScheduledExecutorService;
|
||||
//import java.util.concurrent.TimeUnit;
|
||||
//import java.util.stream.Collectors;
|
||||
//
|
||||
nodeModel.setName(nodeModel.getUrl());
|
||||
List<NodeModel> modelList = this.getListByUrl(nodeModel.getUrl());
|
||||
boolean match = modelList.stream().allMatch(NodeModel::isOpenStatus);
|
||||
if (!match) {
|
||||
// 节点都关闭
|
||||
try {
|
||||
BaseServerController.resetInfo(UserModel.EMPTY);
|
||||
this.save(modelList, 4, "节点禁用中");
|
||||
} finally {
|
||||
BaseServerController.removeEmpty();
|
||||
}
|
||||
return;
|
||||
}
|
||||
nodeModel.setOpenStatus(1);
|
||||
nodeModel.setTimeOut(5);
|
||||
///**
|
||||
// * 节点统计 service
|
||||
// *
|
||||
// * @author bwcx_jzy
|
||||
// * @since 2022/1/22
|
||||
// */
|
||||
//@Service
|
||||
//@Slf4j
|
||||
//public class NodeStatService extends BaseWorkspaceService<NodeStatModel> implements IAsyncLoad, Runnable {
|
||||
//
|
||||
ThreadUtil.execute(() -> {
|
||||
try {
|
||||
BaseServerController.resetInfo(UserModel.EMPTY);
|
||||
JSONObject nodeTopInfo = this.getNodeTopInfo(nodeModel);
|
||||
// private final DbSystemMonitorLogService dbSystemMonitorLogService;
|
||||
// private final NodeService nodeService;
|
||||
// private final ServerConfig.NodeConfig nodeConfig;
|
||||
//
|
||||
long timeMillis = SystemClock.now();
|
||||
JsonMessage<Object> jsonMessage = NodeForward.request(nodeModel, NodeUrl.Status, "nodeId", nodeModel.getId());
|
||||
int networkTime = (int) (System.currentTimeMillis() - timeMillis);
|
||||
JSONObject jsonObject;
|
||||
if (jsonMessage.success()) {
|
||||
jsonObject = jsonMessage.getData(JSONObject.class);
|
||||
} else {
|
||||
// 状态码错
|
||||
jsonObject = new JSONObject();
|
||||
jsonObject.put("status", 3);
|
||||
jsonObject.put("failureMsg", jsonMessage.toString());
|
||||
}
|
||||
jsonObject.put("networkTime", networkTime);
|
||||
if (nodeTopInfo != null) {
|
||||
nodeTopInfo.put("networkTime", networkTime);
|
||||
}
|
||||
this.save(modelList, nodeTopInfo, jsonObject);
|
||||
} catch (AuthorizeException agentException) {
|
||||
this.save(modelList, 2, agentException.getMessage());
|
||||
} catch (AgentException e) {
|
||||
this.save(modelList, 1, e.getMessage());
|
||||
} catch (Exception e) {
|
||||
this.save(modelList, 1, e.getMessage());
|
||||
log.error("获取节点监控信息失败", e);
|
||||
} finally {
|
||||
BaseServerController.removeEmpty();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private void saveSystemMonitor(List<NodeModel> modelList, JSONObject systemMonitor) {
|
||||
if (systemMonitor != null) {
|
||||
List<SystemMonitorLog> monitorLogs = modelList.stream().map(nodeModel -> {
|
||||
SystemMonitorLog log = new SystemMonitorLog();
|
||||
log.setOccupyMemory(systemMonitor.getDouble("memory"));
|
||||
log.setOccupyMemoryUsed(systemMonitor.getDouble("memoryUsed"));
|
||||
log.setOccupyDisk(systemMonitor.getDouble("disk"));
|
||||
log.setOccupyCpu(systemMonitor.getDouble("cpu"));
|
||||
log.setMonitorTime(systemMonitor.getLongValue("time"));
|
||||
log.setNetworkTime(systemMonitor.getIntValue("networkTime"));
|
||||
log.setNodeId(nodeModel.getId());
|
||||
return log;
|
||||
}).collect(Collectors.toList());
|
||||
// public NodeStatService(DbSystemMonitorLogService dbSystemMonitorLogService,
|
||||
// NodeService nodeService,
|
||||
// ServerConfig serverConfig) {
|
||||
// this.dbSystemMonitorLogService = dbSystemMonitorLogService;
|
||||
// this.nodeService = nodeService;
|
||||
// this.nodeConfig = serverConfig.getNode();
|
||||
// }
|
||||
//
|
||||
dbSystemMonitorLogService.insert(monitorLogs);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新状态 和错误信息
|
||||
*
|
||||
* @param modelList 节点
|
||||
* @param satus 状态
|
||||
* @param msg 错误消息
|
||||
*/
|
||||
private void save(List<NodeModel> modelList, int satus, String msg) {
|
||||
for (NodeModel nodeModel : modelList) {
|
||||
NodeStatModel nodeStatModel = this.create(nodeModel);
|
||||
nodeStatModel.setFailureMsg(msg);
|
||||
nodeStatModel.setStatus(satus);
|
||||
this.upsert(nodeStatModel);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 报错结果
|
||||
*
|
||||
* @param modelList 节点
|
||||
* @param systemMonitor 系统监控
|
||||
* @param statusData 状态数据
|
||||
*/
|
||||
private void save(List<NodeModel> modelList, JSONObject systemMonitor, JSONObject statusData) {
|
||||
this.saveSystemMonitor(modelList, systemMonitor);
|
||||
// /**
|
||||
// * 根据 url 去重
|
||||
// *
|
||||
// * @return list
|
||||
// */
|
||||
// public List<String> getDeDuplicationByUrl() {
|
||||
// String sql = "select url from " + super.getTableName() + " group by url";
|
||||
// List<Entity> query = this.query(sql);
|
||||
// if (query != null) {
|
||||
// return query.stream().map((entity -> entity.getStr("url"))).collect(Collectors.toList());
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
for (NodeModel nodeModel : modelList) {
|
||||
NodeStatModel nodeStatModel = this.create(nodeModel);
|
||||
if (nodeModel.isOpenStatus()) {
|
||||
if (systemMonitor != null) {
|
||||
nodeStatModel.setOccupyMemory(ObjectUtil.defaultIfNull(systemMonitor.getDouble("memory"), -1D));
|
||||
nodeStatModel.setOccupyMemoryUsed(ObjectUtil.defaultIfNull(systemMonitor.getDouble("memoryUsed"), -1D));
|
||||
nodeStatModel.setOccupyDisk(ObjectUtil.defaultIfNull(systemMonitor.getDouble("disk"), -1D));
|
||||
nodeStatModel.setOccupyCpu(ObjectUtil.defaultIfNull(systemMonitor.getDouble("cpu"), -1D));
|
||||
}
|
||||
// @Override
|
||||
// public void startLoad() {
|
||||
// // 启动心跳检测
|
||||
// int heartSecond = nodeConfig.getHeartSecond();
|
||||
// ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(runnable -> new Thread(runnable, "Jpom Node Monitor"));
|
||||
// scheduler.scheduleAtFixedRate(this, 10, heartSecond, TimeUnit.SECONDS);
|
||||
// // 清理 错误的节点统计数据
|
||||
// List<String> duplicationByUrl = nodeService.getDeDuplicationByUrl();
|
||||
// List<String> statUrl = this.getDeDuplicationByUrl();
|
||||
// Collection<String> subtract = CollUtil.subtract(statUrl, duplicationByUrl);
|
||||
// //
|
||||
// for (String s : subtract) {
|
||||
// NodeStatModel statModel = new NodeStatModel();
|
||||
// statModel.setUrl(s);
|
||||
// this.del(this.dataBeanToEntity(statModel));
|
||||
// }
|
||||
// }
|
||||
//
|
||||
nodeStatModel.setNetworkTime(statusData.getIntValue("networkTime"));
|
||||
nodeStatModel.setJpomVersion(statusData.getString("jpomVersion"));
|
||||
nodeStatModel.setOsName(statusData.getString("osName"));
|
||||
String runTime = statusData.getString("runTime");
|
||||
String runTimeLong = statusData.getString("runTimeLong");
|
||||
// 兼容数据
|
||||
nodeStatModel.setUpTimeStr(StrUtil.emptyToDefault(runTimeLong, runTime));
|
||||
nodeStatModel.setFailureMsg(StrUtil.emptyToDefault(statusData.getString("failureMsg"), StrUtil.EMPTY));
|
||||
// @Override
|
||||
// public void run() {
|
||||
// List<NodeModel> nodeModels = nodeService.listDeDuplicationByUrl();
|
||||
// //
|
||||
// this.checkList(nodeModels);
|
||||
// }
|
||||
//
|
||||
Integer statusInteger = statusData.getInteger("status");
|
||||
if (statusInteger != null) {
|
||||
nodeStatModel.setStatus(statusInteger);
|
||||
} else {
|
||||
nodeStatModel.setStatus(0);
|
||||
}
|
||||
} else {
|
||||
nodeStatModel.setStatus(4);
|
||||
nodeStatModel.setFailureMsg("节点禁用中");
|
||||
}
|
||||
this.upsert(nodeStatModel);
|
||||
}
|
||||
}
|
||||
|
||||
private NodeStatModel create(NodeModel model) {
|
||||
NodeStatModel nodeStatModel = new NodeStatModel();
|
||||
nodeStatModel.setId(model.getId());
|
||||
nodeStatModel.setWorkspaceId(model.getWorkspaceId());
|
||||
nodeStatModel.setName(model.getName());
|
||||
nodeStatModel.setUrl(model.getUrl());
|
||||
//
|
||||
nodeStatModel.setOccupyMemory(-1D);
|
||||
nodeStatModel.setOccupyMemoryUsed(-1D);
|
||||
nodeStatModel.setOccupyDisk(-1D);
|
||||
nodeStatModel.setOccupyCpu(-1D);
|
||||
nodeStatModel.setGroup(model.getGroup());
|
||||
nodeStatModel.setNetworkTime(-1);
|
||||
nodeStatModel.setUpTimeStr(StrUtil.EMPTY);
|
||||
return nodeStatModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取节点监控信息
|
||||
*
|
||||
* @param reqNode 真实节点
|
||||
*/
|
||||
private JSONObject getNodeTopInfo(NodeModel reqNode) {
|
||||
JsonMessage<?> message = NodeForward.request(reqNode, null, NodeUrl.GetDirectTop);
|
||||
Object data = message.getData();
|
||||
if (data == null) {
|
||||
return null;
|
||||
}
|
||||
if (data instanceof JSONObject) {
|
||||
return (JSONObject) data;
|
||||
}
|
||||
log.warn("{} node response msg:{}", reqNode.getName(), message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
// private List<NodeModel> getListByUrl(String url) {
|
||||
// NodeModel nodeModel = new NodeModel();
|
||||
// nodeModel.setUrl(url);
|
||||
// return nodeService.listByBean(nodeModel);
|
||||
// }
|
||||
//
|
||||
// private void checkList(List<NodeModel> nodeModels) {
|
||||
// if (CollUtil.isEmpty(nodeModels)) {
|
||||
// return;
|
||||
// }
|
||||
// nodeModels.forEach(nodeModel -> {
|
||||
// //
|
||||
// nodeModel.setName(nodeModel.getUrl());
|
||||
// List<NodeModel> modelList = this.getListByUrl(nodeModel.getUrl());
|
||||
// boolean match = modelList.stream().allMatch(NodeModel::isOpenStatus);
|
||||
// if (!match) {
|
||||
// // 节点都关闭
|
||||
// try {
|
||||
// BaseServerController.resetInfo(UserModel.EMPTY);
|
||||
// this.save(modelList, 4, "节点禁用中");
|
||||
// } finally {
|
||||
// BaseServerController.removeEmpty();
|
||||
// }
|
||||
// return;
|
||||
// }
|
||||
// nodeModel.setOpenStatus(1);
|
||||
// nodeModel.setTimeOut(5);
|
||||
// //
|
||||
// ThreadUtil.execute(() -> {
|
||||
// try {
|
||||
// BaseServerController.resetInfo(UserModel.EMPTY);
|
||||
// JsonMessage<JSONObject> message = NodeForward.request(reqNode, null, NodeUrl.GetDirectTop);
|
||||
// JSONObject nodeTopInfo = this.getNodeTopInfo(nodeModel);
|
||||
// //
|
||||
// long timeMillis = SystemClock.now();
|
||||
// JsonMessage<Object> jsonMessage = NodeForward.request(nodeModel, NodeUrl.Status, "nodeId", nodeModel.getId());
|
||||
// int networkTime = (int) (System.currentTimeMillis() - timeMillis);
|
||||
// JSONObject jsonObject;
|
||||
// if (jsonMessage.success()) {
|
||||
// jsonObject = jsonMessage.getData(JSONObject.class);
|
||||
// } else {
|
||||
// // 状态码错
|
||||
// jsonObject = new JSONObject();
|
||||
// jsonObject.put("status", 3);
|
||||
// jsonObject.put("failureMsg", jsonMessage.toString());
|
||||
// }
|
||||
// jsonObject.put("networkTime", networkTime);
|
||||
// if (nodeTopInfo != null) {
|
||||
// nodeTopInfo.put("networkTime", networkTime);
|
||||
// }
|
||||
// this.save(modelList, nodeTopInfo, jsonObject);
|
||||
// } catch (AuthorizeException agentException) {
|
||||
// this.save(modelList, 2, agentException.getMessage());
|
||||
// } catch (AgentException e) {
|
||||
// this.save(modelList, 1, e.getMessage());
|
||||
// } catch (Exception e) {
|
||||
// this.save(modelList, 1, e.getMessage());
|
||||
// log.error("获取节点监控信息失败", e);
|
||||
// } finally {
|
||||
// BaseServerController.removeEmpty();
|
||||
// }
|
||||
// });
|
||||
// });
|
||||
// }
|
||||
//
|
||||
// private void saveSystemMonitor(List<NodeModel> modelList, JSONObject systemMonitor) {
|
||||
// if (systemMonitor != null) {
|
||||
// List<SystemMonitorLog> monitorLogs = modelList.stream().map(nodeModel -> {
|
||||
// SystemMonitorLog log = new SystemMonitorLog();
|
||||
// log.setOccupyMemory(systemMonitor.getDouble("memory"));
|
||||
// log.setOccupyMemoryUsed(systemMonitor.getDouble("memoryUsed"));
|
||||
// log.setOccupyDisk(systemMonitor.getDouble("disk"));
|
||||
// log.setOccupyCpu(systemMonitor.getDouble("cpu"));
|
||||
// log.setMonitorTime(systemMonitor.getLongValue("time"));
|
||||
// log.setNetworkTime(systemMonitor.getIntValue("networkTime"));
|
||||
// log.setNodeId(nodeModel.getId());
|
||||
// return log;
|
||||
// }).collect(Collectors.toList());
|
||||
// //
|
||||
// dbSystemMonitorLogService.insert(monitorLogs);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 更新状态 和错误信息
|
||||
// *
|
||||
// * @param modelList 节点
|
||||
// * @param satus 状态
|
||||
// * @param msg 错误消息
|
||||
// */
|
||||
// private void save(List<NodeModel> modelList, int satus, String msg) {
|
||||
// for (NodeModel nodeModel : modelList) {
|
||||
// NodeStatModel nodeStatModel = this.create(nodeModel);
|
||||
// nodeStatModel.setFailureMsg(msg);
|
||||
// nodeStatModel.setStatus(satus);
|
||||
// this.upsert(nodeStatModel);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 报错结果
|
||||
// *
|
||||
// * @param modelList 节点
|
||||
// * @param systemMonitor 系统监控
|
||||
// * @param statusData 状态数据
|
||||
// */
|
||||
// private void save(List<NodeModel> modelList, JSONObject systemMonitor, JSONObject statusData) {
|
||||
// this.saveSystemMonitor(modelList, systemMonitor);
|
||||
// //
|
||||
// for (NodeModel nodeModel : modelList) {
|
||||
// NodeStatModel nodeStatModel = this.create(nodeModel);
|
||||
// if (nodeModel.isOpenStatus()) {
|
||||
// if (systemMonitor != null) {
|
||||
// nodeStatModel.setOccupyMemory(ObjectUtil.defaultIfNull(systemMonitor.getDouble("memory"), -1D));
|
||||
// nodeStatModel.setOccupyMemoryUsed(ObjectUtil.defaultIfNull(systemMonitor.getDouble("memoryUsed"), -1D));
|
||||
// nodeStatModel.setOccupyDisk(ObjectUtil.defaultIfNull(systemMonitor.getDouble("disk"), -1D));
|
||||
// nodeStatModel.setOccupyCpu(ObjectUtil.defaultIfNull(systemMonitor.getDouble("cpu"), -1D));
|
||||
// }
|
||||
// //
|
||||
// nodeStatModel.setNetworkTime(statusData.getIntValue("networkTime"));
|
||||
// nodeStatModel.setJpomVersion(statusData.getString("jpomVersion"));
|
||||
// nodeStatModel.setOsName(statusData.getString("osName"));
|
||||
// String runTime = statusData.getString("runTime");
|
||||
// String runTimeLong = statusData.getString("runTimeLong");
|
||||
// // 兼容数据
|
||||
// nodeStatModel.setUpTimeStr(StrUtil.emptyToDefault(runTimeLong, runTime));
|
||||
// nodeStatModel.setFailureMsg(StrUtil.emptyToDefault(statusData.getString("failureMsg"), StrUtil.EMPTY));
|
||||
// //
|
||||
// Integer statusInteger = statusData.getInteger("status");
|
||||
// if (statusInteger != null) {
|
||||
// nodeStatModel.setStatus(statusInteger);
|
||||
// } else {
|
||||
// nodeStatModel.setStatus(0);
|
||||
// }
|
||||
// } else {
|
||||
// nodeStatModel.setStatus(4);
|
||||
// nodeStatModel.setFailureMsg("节点禁用中");
|
||||
// }
|
||||
// this.upsert(nodeStatModel);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private NodeStatModel create(NodeModel model) {
|
||||
// NodeStatModel nodeStatModel = new NodeStatModel();
|
||||
// nodeStatModel.setId(model.getId());
|
||||
// nodeStatModel.setWorkspaceId(model.getWorkspaceId());
|
||||
// nodeStatModel.setName(model.getName());
|
||||
// nodeStatModel.setUrl(model.getUrl());
|
||||
// //
|
||||
// nodeStatModel.setOccupyMemory(-1D);
|
||||
// nodeStatModel.setOccupyMemoryUsed(-1D);
|
||||
// nodeStatModel.setOccupyDisk(-1D);
|
||||
// nodeStatModel.setOccupyCpu(-1D);
|
||||
// nodeStatModel.setGroup(model.getGroup());
|
||||
// nodeStatModel.setNetworkTime(-1);
|
||||
// nodeStatModel.setUpTimeStr(StrUtil.EMPTY);
|
||||
// return nodeStatModel;
|
||||
// }
|
||||
//}
|
||||
|
@ -52,7 +52,7 @@ public class WorkspaceService extends BaseDbService<WorkspaceModel> implements I
|
||||
if (workspaceModel == null) {
|
||||
WorkspaceModel defaultWorkspace = new WorkspaceModel();
|
||||
defaultWorkspace.setId(Const.WORKSPACE_DEFAULT_ID);
|
||||
defaultWorkspace.setName("默认");
|
||||
defaultWorkspace.setName(Const.DEFAULT_GROUP_NAME);
|
||||
defaultWorkspace.setDescription("系统默认的工作空间,不能删除");
|
||||
super.insert(defaultWorkspace);
|
||||
|
||||
|
@ -31,10 +31,7 @@ import io.jpom.util.SocketSessionUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.socket.TextMessage;
|
||||
import org.springframework.web.socket.WebSocketSession;
|
||||
import top.jpom.transport.DataContentType;
|
||||
import top.jpom.transport.IProxyWebSocket;
|
||||
import top.jpom.transport.IUrlItem;
|
||||
import top.jpom.transport.TransportServerFactory;
|
||||
import top.jpom.transport.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
@ -89,9 +86,10 @@ public abstract class BaseProxyHandler extends BaseHandler {
|
||||
if (nodeModel != null) {
|
||||
Object[] parameters = this.getParameters(attributes);
|
||||
// 连接节点
|
||||
IUrlItem urlItem = NodeForward.createUrlItem(nodeModel, this.nodeUrl, DataContentType.FORM_URLENCODED);
|
||||
INodeInfo nodeInfo = NodeForward.parseNodeInfo(nodeModel);
|
||||
IUrlItem urlItem = NodeForward.parseUrlItem(nodeInfo, nodeModel.getWorkspaceId(), this.nodeUrl, DataContentType.FORM_URLENCODED);
|
||||
|
||||
IProxyWebSocket proxySession = TransportServerFactory.get().websocket(nodeModel, urlItem, parameters);
|
||||
IProxyWebSocket proxySession = TransportServerFactory.get().websocket(nodeInfo, urlItem, parameters);
|
||||
proxySession.onMessage(s -> sendMsg(session, s));
|
||||
if (!proxySession.connectBlocking()) {
|
||||
this.sendMsg(session, "插件端连接失败");
|
||||
|
@ -22,7 +22,7 @@
|
||||
*/
|
||||
package io.jpom.socket;
|
||||
|
||||
import io.jpom.service.node.NodeService;
|
||||
import io.jpom.func.assets.server.MachineNodeServer;
|
||||
import io.jpom.service.system.SystemParametersServer;
|
||||
import io.jpom.socket.handler.*;
|
||||
import io.jpom.system.ServerConfig;
|
||||
@ -41,17 +41,17 @@ import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry
|
||||
public class ServerWebSocketConfig implements WebSocketConfigurer {
|
||||
private final ServerWebSocketInterceptor serverWebSocketInterceptor;
|
||||
private final SystemParametersServer systemParametersServer;
|
||||
private final NodeService nodeService;
|
||||
private final ServerConfig.NodeConfig nodeConfig;
|
||||
private final MachineNodeServer machineNodeServer;
|
||||
|
||||
public ServerWebSocketConfig(ServerWebSocketInterceptor serverWebSocketInterceptor,
|
||||
SystemParametersServer systemParametersServer,
|
||||
NodeService nodeService,
|
||||
ServerConfig serverConfig) {
|
||||
ServerConfig serverConfig,
|
||||
MachineNodeServer machineNodeServer) {
|
||||
this.serverWebSocketInterceptor = serverWebSocketInterceptor;
|
||||
this.systemParametersServer = systemParametersServer;
|
||||
this.nodeService = nodeService;
|
||||
this.nodeConfig = serverConfig.getNode();
|
||||
this.machineNodeServer = machineNodeServer;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -69,7 +69,7 @@ public class ServerWebSocketConfig implements WebSocketConfigurer {
|
||||
registry.addHandler(new SshHandler(), "/socket/ssh")
|
||||
.addInterceptors(serverWebSocketInterceptor).setAllowedOrigins("*");
|
||||
// 节点升级
|
||||
registry.addHandler(new NodeUpdateHandler(nodeService, systemParametersServer, nodeConfig), "/socket/node_update")
|
||||
registry.addHandler(new NodeUpdateHandler(machineNodeServer, systemParametersServer, nodeConfig), "/socket/node_update")
|
||||
.addInterceptors(serverWebSocketInterceptor).setAllowedOrigins("*");
|
||||
// 脚本模板
|
||||
registry.addHandler(new ServerScriptHandler(), "/socket/script_run")
|
||||
|
@ -36,25 +36,22 @@ import io.jpom.common.JsonMessage;
|
||||
import io.jpom.common.Type;
|
||||
import io.jpom.common.forward.NodeForward;
|
||||
import io.jpom.common.forward.NodeUrl;
|
||||
import io.jpom.func.assets.model.MachineNodeModel;
|
||||
import io.jpom.func.assets.server.MachineNodeServer;
|
||||
import io.jpom.model.AgentFileModel;
|
||||
import io.jpom.model.UploadFileModel;
|
||||
import io.jpom.model.WebSocketMessageModel;
|
||||
import io.jpom.model.data.NodeModel;
|
||||
import io.jpom.permission.ClassFeature;
|
||||
import io.jpom.permission.Feature;
|
||||
import io.jpom.permission.MethodFeature;
|
||||
import io.jpom.permission.SystemPermission;
|
||||
import io.jpom.service.node.NodeService;
|
||||
import io.jpom.service.system.SystemParametersServer;
|
||||
import io.jpom.socket.BaseProxyHandler;
|
||||
import io.jpom.socket.ConsoleCommandOp;
|
||||
import io.jpom.system.ServerConfig;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.socket.WebSocketSession;
|
||||
import top.jpom.transport.DataContentType;
|
||||
import top.jpom.transport.IProxyWebSocket;
|
||||
import top.jpom.transport.IUrlItem;
|
||||
import top.jpom.transport.TransportServerFactory;
|
||||
import top.jpom.transport.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
@ -85,14 +82,14 @@ public class NodeUpdateHandler extends BaseProxyHandler {
|
||||
private static final int INIT_WAIT = 10 * 1000;
|
||||
|
||||
private final SystemParametersServer systemParametersServer;
|
||||
private final NodeService nodeService;
|
||||
private final MachineNodeServer machineNodeServer;
|
||||
private final ServerConfig.NodeConfig nodeConfig;
|
||||
|
||||
public NodeUpdateHandler(NodeService nodeService,
|
||||
public NodeUpdateHandler(MachineNodeServer machineNodeServer,
|
||||
SystemParametersServer systemParametersServer,
|
||||
ServerConfig.NodeConfig nodeConfig) {
|
||||
super(null);
|
||||
this.nodeService = nodeService;
|
||||
this.machineNodeServer = machineNodeServer;
|
||||
this.systemParametersServer = systemParametersServer;
|
||||
this.nodeConfig = nodeConfig;
|
||||
//systemParametersServer = SpringUtil.getBean(SystemParametersServer.class);
|
||||
@ -117,16 +114,17 @@ public class NodeUpdateHandler extends BaseProxyHandler {
|
||||
|
||||
private void pullNodeList(WebSocketSession session, String ids) {
|
||||
List<String> split = StrUtil.split(ids, StrUtil.COMMA);
|
||||
List<NodeModel> nodeModelList = nodeService.listById(split);
|
||||
List<MachineNodeModel> nodeModelList = machineNodeServer.listById(split);
|
||||
if (nodeModelList == null) {
|
||||
this.onError(session, "没有查询到节点信息:" + ids);
|
||||
return;
|
||||
}
|
||||
for (NodeModel model : nodeModelList) {
|
||||
for (MachineNodeModel model : nodeModelList) {
|
||||
IProxyWebSocket nodeClient = clientMap.computeIfAbsent(model.getId(), s -> {
|
||||
IUrlItem urlItem = NodeForward.createUrlItem(model, NodeUrl.NodeUpdate, DataContentType.FORM_URLENCODED);
|
||||
INodeInfo nodeInfo = NodeForward.coverNodeInfo(model);
|
||||
IUrlItem urlItem = NodeForward.parseUrlItem(model, StrUtil.EMPTY, NodeUrl.NodeUpdate, DataContentType.FORM_URLENCODED);
|
||||
|
||||
IProxyWebSocket proxySession = TransportServerFactory.get().websocket(model, urlItem);
|
||||
IProxyWebSocket proxySession = TransportServerFactory.get().websocket(nodeInfo, urlItem);
|
||||
proxySession.onMessage(msg -> sendMsg(session, msg));
|
||||
return proxySession;
|
||||
});
|
||||
@ -241,7 +239,7 @@ public class NodeUpdateHandler extends BaseProxyHandler {
|
||||
}
|
||||
for (int i = 0; i < ids.size(); i++) {
|
||||
String id = ids.getString(i);
|
||||
NodeModel node = nodeService.getByKey(id);
|
||||
MachineNodeModel node = machineNodeServer.getByKey(id);
|
||||
if (node == null) {
|
||||
this.onError(session, "没有对应的节点:" + id);
|
||||
continue;
|
||||
@ -254,24 +252,24 @@ public class NodeUpdateHandler extends BaseProxyHandler {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean updateNodeItemHttp(NodeModel nodeModel, WebSocketSession session, AgentFileModel agentFileModel) throws IOException {
|
||||
private boolean updateNodeItemHttp(MachineNodeModel machineNodeModel, WebSocketSession session, AgentFileModel agentFileModel) throws IOException {
|
||||
File file = FileUtil.file(agentFileModel.getSavePath());
|
||||
|
||||
JsonMessage<String> message = NodeForward.requestSharding(nodeModel, NodeUrl.SystemUploadJar, new JSONObject(),
|
||||
JsonMessage<String> message = NodeForward.requestSharding(machineNodeModel, NodeUrl.SystemUploadJar, new JSONObject(),
|
||||
file,
|
||||
jsonObject -> NodeForward.request(nodeModel, NodeUrl.SystemUploadJarMerge, jsonObject),
|
||||
jsonObject -> NodeForward.request(machineNodeModel, NodeUrl.SystemUploadJarMerge, jsonObject),
|
||||
(total, progressSize) -> {
|
||||
UploadFileModel uploadFileModel = new UploadFileModel();
|
||||
uploadFileModel.setSize(total);
|
||||
uploadFileModel.setCompleteSize(progressSize);
|
||||
uploadFileModel.setId(nodeModel.getId());
|
||||
uploadFileModel.setId(machineNodeModel.getId());
|
||||
uploadFileModel.setVersion(agentFileModel.getVersion());
|
||||
// 更新进度
|
||||
WebSocketMessageModel model = new WebSocketMessageModel("updateNode", nodeModel.getId());
|
||||
WebSocketMessageModel model = new WebSocketMessageModel("updateNode", machineNodeModel.getId());
|
||||
model.setData(uploadFileModel);
|
||||
NodeUpdateHandler.this.sendMsg(model, session);
|
||||
});
|
||||
String id = nodeModel.getId();
|
||||
String id = machineNodeModel.getId();
|
||||
WebSocketMessageModel callbackRestartMessage = new WebSocketMessageModel("restart", id);
|
||||
callbackRestartMessage.setData(message.getMsg());
|
||||
this.sendMsg(callbackRestartMessage, session);
|
||||
@ -286,7 +284,7 @@ public class NodeUpdateHandler extends BaseProxyHandler {
|
||||
++retryCount;
|
||||
try {
|
||||
ThreadUtil.sleep(1000L);
|
||||
JsonMessage<Object> jsonMessage = NodeForward.request(nodeModel, NodeUrl.Info, "nodeId", id);
|
||||
JsonMessage<Object> jsonMessage = NodeForward.request(machineNodeModel, StrUtil.EMPTY, NodeUrl.Info, "nodeId", id);
|
||||
if (jsonMessage.success()) {
|
||||
this.sendMsg(callbackRestartMessage.setData("重启完成"), session);
|
||||
return true;
|
||||
@ -347,7 +345,7 @@ public class NodeUpdateHandler extends BaseProxyHandler {
|
||||
return false;
|
||||
}
|
||||
|
||||
private void updateNodeItem(String id, NodeModel node, WebSocketSession session, AgentFileModel agentFileModel, boolean http) {
|
||||
private void updateNodeItem(String id, MachineNodeModel node, WebSocketSession session, AgentFileModel agentFileModel, boolean http) {
|
||||
try {
|
||||
IProxyWebSocket client = clientMap.get(node.getId());
|
||||
if (client == null) {
|
||||
|
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Code Technology Studio
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package io.jpom.system.db;
|
||||
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import io.jpom.common.ILoadEvent;
|
||||
import io.jpom.service.h2db.BaseGroupService;
|
||||
import io.jpom.service.h2db.BaseNodeGroupService;
|
||||
import io.jpom.service.h2db.BaseNodeService;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 数据库初始化完成后
|
||||
*
|
||||
* @author bwcx_jzy
|
||||
* @since 2023/2/18
|
||||
*/
|
||||
public class DataInitEvent implements ILoadEvent {
|
||||
@Override
|
||||
public void afterPropertiesSet(ApplicationContext applicationContext) throws Exception {
|
||||
//
|
||||
Map<String, BaseGroupService> groupServiceMap = SpringUtil.getApplicationContext().getBeansOfType(BaseGroupService.class);
|
||||
for (BaseGroupService<?> value : groupServiceMap.values()) {
|
||||
value.repairGroupFiled();
|
||||
}
|
||||
//
|
||||
Map<String, BaseNodeGroupService> nodeGroupServiceMap = SpringUtil.getApplicationContext().getBeansOfType(BaseNodeGroupService.class);
|
||||
for (BaseNodeGroupService<?> value : nodeGroupServiceMap.values()) {
|
||||
value.repairGroupFiled();
|
||||
}
|
||||
// 同步项目
|
||||
Map<String, BaseNodeService> beansOfType = SpringUtil.getApplicationContext().getBeansOfType(BaseNodeService.class);
|
||||
for (BaseNodeService<?> value : beansOfType.values()) {
|
||||
value.syncAllNode();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return HIGHEST_PRECEDENCE + 2;
|
||||
}
|
||||
}
|
@ -32,14 +32,10 @@ import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
import cn.hutool.db.Db;
|
||||
import cn.hutool.db.ds.DSFactory;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import io.jpom.common.ILoadEvent;
|
||||
import io.jpom.common.JpomApplicationEvent;
|
||||
import io.jpom.model.data.BackupInfoModel;
|
||||
import io.jpom.service.dblog.BackupInfoService;
|
||||
import io.jpom.service.h2db.BaseGroupService;
|
||||
import io.jpom.service.h2db.BaseNodeGroupService;
|
||||
import io.jpom.service.h2db.BaseNodeService;
|
||||
import io.jpom.system.JpomRuntimeException;
|
||||
import lombok.Lombok;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -171,21 +167,6 @@ public class InitDb implements DisposableBean, ILoadEvent {
|
||||
throw Lombok.sneakyThrow(e);
|
||||
}
|
||||
log.info("{} db Successfully loaded, url is 【{}】", storageService.mode(), storageService.dbUrl());
|
||||
//
|
||||
Map<String, BaseGroupService> groupServiceMap = SpringUtil.getApplicationContext().getBeansOfType(BaseGroupService.class);
|
||||
for (BaseGroupService<?> value : groupServiceMap.values()) {
|
||||
value.repairGroupFiled();
|
||||
}
|
||||
//
|
||||
Map<String, BaseNodeGroupService> nodeGroupServiceMap = SpringUtil.getApplicationContext().getBeansOfType(BaseNodeGroupService.class);
|
||||
for (BaseNodeGroupService<?> value : nodeGroupServiceMap.values()) {
|
||||
value.repairGroupFiled();
|
||||
}
|
||||
// 同步项目
|
||||
Map<String, BaseNodeService> beansOfType = SpringUtil.getApplicationContext().getBeansOfType(BaseNodeService.class);
|
||||
for (BaseNodeService<?> value : beansOfType.values()) {
|
||||
value.syncAllNode();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -26,7 +26,7 @@ import cn.hutool.core.util.ReUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import io.jpom.common.ILoadEvent;
|
||||
import io.jpom.model.data.NodeModel;
|
||||
import io.jpom.common.forward.NodeForward;
|
||||
import io.jpom.service.system.SystemParametersServer;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -79,7 +79,7 @@ public class ProxySelectorConfig extends ProxySelector implements ILoadEvent {
|
||||
}
|
||||
return StrUtil.containsIgnoreCase(url, proxyConfigItem.getPattern());
|
||||
})
|
||||
.map(proxyConfigItem -> NodeModel.crateProxy(proxyConfigItem.getProxyType(), proxyConfigItem.getProxyAddress()))
|
||||
.map(proxyConfigItem -> NodeForward.crateProxy(proxyConfigItem.getProxyType(), proxyConfigItem.getProxyAddress()))
|
||||
.filter(Objects::nonNull)
|
||||
.findFirst()
|
||||
.map(Collections::singletonList)
|
||||
|
@ -5,7 +5,7 @@
|
||||
"id": "nodeManager",
|
||||
"childs": [
|
||||
{
|
||||
"title": "节点列表",
|
||||
"title": "逻辑节点",
|
||||
"id": "nodeList"
|
||||
},
|
||||
{
|
||||
|
@ -1,4 +1,16 @@
|
||||
[
|
||||
{
|
||||
"title": "资产管理",
|
||||
"icon_v3": "hdd",
|
||||
"id": "assets-manager",
|
||||
"childs": [
|
||||
{
|
||||
"id": "machine_node_info",
|
||||
"title": "机器管理",
|
||||
"role": "system"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "配置管理",
|
||||
"icon_v3": "save",
|
||||
|
@ -557,18 +557,34 @@ public abstract class BaseDbCommonService<T> {
|
||||
* @return data
|
||||
*/
|
||||
public List<T> listByBean(T data) {
|
||||
return this.listByBean(data, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询实体对象
|
||||
*
|
||||
* @param data 实体
|
||||
* @return data
|
||||
*/
|
||||
public List<T> listByBean(T data, boolean fill) {
|
||||
Entity where = this.dataBeanToEntity(data);
|
||||
List<Entity> entitys = this.queryList(where);
|
||||
return this.entityToBeanList(entitys);
|
||||
return this.entityToBeanList(entitys, fill);
|
||||
}
|
||||
|
||||
public List<T> entityToBeanList(List<Entity> entitys) {
|
||||
return this.entityToBeanList(entitys, true);
|
||||
}
|
||||
|
||||
public List<T> entityToBeanList(List<Entity> entitys, boolean fill) {
|
||||
if (entitys == null) {
|
||||
return null;
|
||||
}
|
||||
return entitys.stream().map((entity -> {
|
||||
T entityToBean = this.entityToBean(entity, this.tClass);
|
||||
if (fill) {
|
||||
this.fillSelectResult(entityToBean);
|
||||
}
|
||||
return entityToBean;
|
||||
})).collect(Collectors.toList());
|
||||
}
|
||||
|
@ -4,3 +4,5 @@ ADD,OUT_GIVING,group,String,50,,项目分组
|
||||
ADD,BUILD_INFO,buildEnvParameter,TEXT,,,构建环境变量
|
||||
ADD,BUILDHISTORYLOG,buildEnvCache,TEXT,,,构建环境变量
|
||||
ADD,OUT_GIVING,webhook,String,255,,webhook
|
||||
DROP,NODE_INFO,unLockType
|
||||
ADD,NODE_INFO,machineId,String,50,,机器id
|
||||
|
|
@ -0,0 +1,52 @@
|
||||
tableName,name,type,len,defaultValue,notNull,primaryKey,comment,tableComment
|
||||
MACHINE_NODE_INFO,id,String,50,,true,true,id,机器节点信息
|
||||
MACHINE_NODE_INFO,createTimeMillis,Long,,,false,false,数据创建时间,
|
||||
MACHINE_NODE_INFO,modifyTimeMillis,Long,,,false,false,数据修改时间,
|
||||
MACHINE_NODE_INFO,modifyUser,String,50,,false,false,修改人,
|
||||
MACHINE_NODE_INFO,strike,Integer,,0,false,false,逻辑删除{1,删除,0 未删除(默认)},
|
||||
MACHINE_NODE_INFO,name,String,50,,true,false,机器名称,
|
||||
MACHINE_NODE_INFO,groupName,String,50,,true,false,分组名称,
|
||||
MACHINE_NODE_INFO,hostName,String,255,,false,false,机器主机名,
|
||||
MACHINE_NODE_INFO,hostIpv4s,TEXT,,,false,false,机器所有 IP,
|
||||
MACHINE_NODE_INFO,osLoadAverage,String,100,,false,false,系统负载,
|
||||
MACHINE_NODE_INFO,osSystemUptime,Long,,,false,false,系统运行时间(自启动以来的时间),
|
||||
MACHINE_NODE_INFO,osVersion,String,255,,false,false,系统版本,
|
||||
MACHINE_NODE_INFO,osHardwareVersion,String,255,,false,false,硬件版本,
|
||||
MACHINE_NODE_INFO,osCpuCores,Integer,,,false,false,CPU数,
|
||||
MACHINE_NODE_INFO,osMoneyTotal,Long,,,false,false,总内存,
|
||||
MACHINE_NODE_INFO,osFileStoreTotal,Long,,,false,false,硬盘大小,
|
||||
MACHINE_NODE_INFO,osCpuIdentifierName,String,255,,false,false,CPU 型号,
|
||||
MACHINE_NODE_INFO,osName,String,50,,false,false,系统名称,
|
||||
MACHINE_NODE_INFO,status,TINYINT,,,true,false,节点连接状态:0 未连接,1 连接中,
|
||||
MACHINE_NODE_INFO,statusMsg,TEXT,,,false,false,状态消息,
|
||||
MACHINE_NODE_INFO,transportMode,TINYINT,,,true,false,传输方式。0 服务器拉取,1 节点机器推送,
|
||||
MACHINE_NODE_INFO,jpomUrl,String,100,,false,false,节点 url IP:PORT,
|
||||
MACHINE_NODE_INFO,jpomUsername,String,100,,false,false,节点登录名,
|
||||
MACHINE_NODE_INFO,jpomPassword,String,100,,false,false,节点密码,
|
||||
MACHINE_NODE_INFO,jpomProtocol,String,10,,false,false,协议 http https,
|
||||
MACHINE_NODE_INFO,jpomTimeout,Integer,,,false,false,节点超时时间,
|
||||
MACHINE_NODE_INFO,jpomHttpProxy,String,200,,false,false,http 代理,
|
||||
MACHINE_NODE_INFO,jpomHttpProxyType,String,20,,false,false,http 代理类型,
|
||||
MACHINE_NODE_INFO,jpomVersion,String,50,,false,false,jpom版本号,
|
||||
MACHINE_NODE_INFO,jpomUptime,Long,,,false,false,jpom运行时间,
|
||||
MACHINE_NODE_INFO,jpomBuildTime,String,50,,false,false,Jpom 打包时间,
|
||||
MACHINE_NODE_INFO,jpomProjectCount,Integer,,,false,false,jpom项目数,
|
||||
MACHINE_NODE_INFO,jpomScriptCount,Integer,,,false,false,jpom脚本数,
|
||||
MACHINE_NODE_INFO,networkDelay,Integer,,,false,false,网络耗时(延迟),
|
||||
MACHINE_NODE_INFO,javaVersion,String,50,,false,false,java版本,
|
||||
MACHINE_NODE_INFO,jvmTotalMemory,Long,,,false,false,jvm 总内存,
|
||||
MACHINE_NODE_INFO,jvmFreeMemory,Long,,,false,false,jvm 剩余内存,
|
||||
MACHINE_NODE_INFO,osOccupyCpu,Double,,,false,false,占用cpu,
|
||||
MACHINE_NODE_INFO,osOccupyMemory,Double,,,false,false,占用内存,
|
||||
MACHINE_NODE_INFO,osOccupyDisk,Double,,,false,false,占用磁盘,
|
||||
MACHINE_NODE_STAT_LOG,id,String,50,,true,true,id,资产机器节点统计
|
||||
MACHINE_NODE_STAT_LOG,createTimeMillis,Long,,,false,false,数据创建时间,
|
||||
MACHINE_NODE_STAT_LOG,modifyTimeMillis,Long,,,false,false,数据修改时间,
|
||||
MACHINE_NODE_STAT_LOG,machineId,String,50,,true,true,机器id,
|
||||
MACHINE_NODE_STAT_LOG,occupyCpu,Double,,,false,false,占用cpu,
|
||||
MACHINE_NODE_STAT_LOG,occupyMemory,Double,,,false,false,占用内存,
|
||||
MACHINE_NODE_STAT_LOG,occupyDisk,Double,,,false,false,占用磁盘,
|
||||
MACHINE_NODE_STAT_LOG,networkDelay,Integer,,0,false,false,网络耗时,
|
||||
MACHINE_NODE_STAT_LOG,monitorTime,Long,,,true,false,监控的时间,
|
||||
MACHINE_NODE_STAT_LOG,netTxBytes,Long,,,false,false,"每秒发送的KB数,rxkB/s",
|
||||
MACHINE_NODE_STAT_LOG,netRxBytes,Long,,,false,false,"每秒接收的KB数,rxkB/s",
|
|
@ -1,29 +1,29 @@
|
||||
import axios from "./config";
|
||||
// import axios from "./config";
|
||||
import { parseTime, formatPercent2 } from "@/utils/const";
|
||||
import echarts from "echarts";
|
||||
|
||||
// node 列表
|
||||
export function getStatist(params) {
|
||||
return axios({
|
||||
url: "/node/stat/list_data.json",
|
||||
method: "post",
|
||||
params: params,
|
||||
headers: {
|
||||
loading: "no",
|
||||
},
|
||||
});
|
||||
}
|
||||
// // node 列表
|
||||
// export function getStatist(params) {
|
||||
// return axios({
|
||||
// url: "/node/stat/list_data.json",
|
||||
// method: "post",
|
||||
// params: params,
|
||||
// headers: {
|
||||
// loading: "no",
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
|
||||
// node 列表
|
||||
export function statusStat() {
|
||||
return axios({
|
||||
url: "/node/stat/status_stat.json",
|
||||
method: "get",
|
||||
headers: {
|
||||
loading: "no",
|
||||
},
|
||||
});
|
||||
}
|
||||
// // node 列表
|
||||
// export function statusStat() {
|
||||
// return axios({
|
||||
// url: "/node/stat/status_stat.json",
|
||||
// method: "get",
|
||||
// headers: {
|
||||
// loading: "no",
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
|
||||
const defaultData = {
|
||||
title: {
|
||||
@ -163,7 +163,7 @@ export function generateNodeNetworkTimeChart(data) {
|
||||
const scales = [];
|
||||
for (var i = data.length - 1; i >= 0; i--) {
|
||||
const item = data[i];
|
||||
dataArray.data.push(parseFloat(item.networkTime));
|
||||
dataArray.data.push(parseFloat(item.networkDelay));
|
||||
scales.push(parseTime(item.monitorTime));
|
||||
}
|
||||
|
||||
@ -209,10 +209,10 @@ export function drawChart(data, domId, parseFn) {
|
||||
return historyChart;
|
||||
}
|
||||
|
||||
export const status = {
|
||||
1: "无法连接",
|
||||
0: "正常",
|
||||
2: "授权信息错误",
|
||||
3: "状态码错误",
|
||||
4: "关闭中",
|
||||
};
|
||||
// export const status = {
|
||||
// 1: "无法连接",
|
||||
// 0: "正常",
|
||||
// 2: "授权信息错误",
|
||||
// 3: "状态码错误",
|
||||
// 4: "关闭中",
|
||||
// };
|
||||
|
@ -43,14 +43,14 @@ export function getNodeListWithVersion(params) {
|
||||
});
|
||||
}
|
||||
|
||||
// node 状态
|
||||
export function getNodeStatus(nodeId) {
|
||||
return axios({
|
||||
url: "/node/node_status",
|
||||
method: "post",
|
||||
data: { nodeId },
|
||||
});
|
||||
}
|
||||
// // node 状态
|
||||
// export function getNodeStatus(nodeId) {
|
||||
// return axios({
|
||||
// url: "/node/node_status",
|
||||
// method: "post",
|
||||
// data: { nodeId },
|
||||
// });
|
||||
// }
|
||||
|
||||
// 节点 + 项目列表
|
||||
export function getNodeProjectList(params) {
|
||||
@ -88,14 +88,6 @@ export function syncProject(nodeId) {
|
||||
});
|
||||
}
|
||||
|
||||
export function unLockWorkspace(params) {
|
||||
return axios({
|
||||
url: "/node/un_lock_workspace",
|
||||
method: "get",
|
||||
params: params,
|
||||
});
|
||||
}
|
||||
|
||||
export function syncToWorkspace(params) {
|
||||
return axios({
|
||||
url: "/node/sync-to-workspace",
|
||||
|
34
web-vue/src/api/system/assets-machine.js
Normal file
34
web-vue/src/api/system/assets-machine.js
Normal file
@ -0,0 +1,34 @@
|
||||
import axios from "@/api/config";
|
||||
|
||||
// 机器 列表
|
||||
export function machineListData(params) {
|
||||
return axios({
|
||||
url: "/system/assets/machine/list-data",
|
||||
method: "post",
|
||||
params: params,
|
||||
});
|
||||
}
|
||||
|
||||
export function machineListGroup(params) {
|
||||
return axios({
|
||||
url: "/system/assets/machine/list-group",
|
||||
method: "get",
|
||||
params: params,
|
||||
});
|
||||
}
|
||||
|
||||
// 编辑机器
|
||||
export function machineEdit(params) {
|
||||
return axios({
|
||||
url: "/system/assets/machine/edit",
|
||||
method: "post",
|
||||
params: params,
|
||||
});
|
||||
}
|
||||
|
||||
export const statusMap = {
|
||||
0: "无法连接",
|
||||
1: "正常",
|
||||
2: "授权信息错误",
|
||||
3: "状态码错误",
|
||||
};
|
@ -1,20 +1,17 @@
|
||||
<template>
|
||||
<div class="full-content">
|
||||
<!-- <div ref="filter" class="filter"></div> -->
|
||||
<!-- 表格 :scroll="{ x: 1070, y: tableHeight -60 }" scroll 跟 expandedRowRender 不兼容,没法同时使用不然会多出一行数据-->
|
||||
<a-table :columns="columns" :data-source="list" bordered size="middle" rowKey="id" @expand="expand" :pagination="pagination" @change="changePage" :row-selection="rowSelection">
|
||||
<a-table :columns="columns" :data-source="list" bordered size="middle" rowKey="id" :pagination="pagination" @change="changePage" :row-selection="rowSelection">
|
||||
<template slot="title">
|
||||
<a-space>
|
||||
<a-input v-model="listQuery['%id%']" @pressEnter="loadData" placeholder="节点ID" />
|
||||
<a-input v-model="listQuery['%name%']" @pressEnter="loadData" placeholder="节点名称" />
|
||||
<a-input v-model="listQuery['%url%']" @pressEnter="loadData" placeholder="节点地址" />
|
||||
|
||||
<a-select show-search option-filter-prop="children" v-model="listQuery.group" allowClear placeholder="分组" class="search-input-item">
|
||||
<a-select-option v-for="item in groupList" :key="item">{{ item }}</a-select-option>
|
||||
</a-select>
|
||||
<a-tooltip title="按住 Ctr 或者 Alt/Option 键点击按钮快速回到第一页">
|
||||
<a-button :loading="loading" type="primary" @click="loadData">搜索</a-button>
|
||||
</a-tooltip>
|
||||
<a-button type="primary jpom-node-manage-add" @click="handleAdd">新增</a-button>
|
||||
|
||||
<a-dropdown>
|
||||
<a class="ant-dropdown-link" @click="(e) => e.preventDefault()"> 更多 <a-icon type="down" /> </a>
|
||||
<a-menu slot="overlay">
|
||||
@ -49,15 +46,13 @@
|
||||
</a-space>
|
||||
</template>
|
||||
<a-tooltip slot="url" slot-scope="text, record" placement="topLeft" :title="text">
|
||||
<span>{{ record.protocol }}://{{ text }}</span>
|
||||
<template v-if="record.machineNodeData">
|
||||
<span>{{ record.machineNodeData.jpomProtocol }}://{{ record.machineNodeData.jpomUrl }}</span>
|
||||
</template>
|
||||
<span v-else> - </span>
|
||||
</a-tooltip>
|
||||
<template slot="name" slot-scope="text, record">
|
||||
<template v-if="record.unLockType">
|
||||
<a-tooltip :title="`${text}`">
|
||||
<span>{{ text }}</span>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<template v-else-if="record.openStatus !== 1">
|
||||
<template v-if="record.openStatus !== 1">
|
||||
<a-tooltip :title="`${text}`">
|
||||
<span>{{ text }}</span>
|
||||
</a-tooltip>
|
||||
@ -79,15 +74,52 @@
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
<!-- <a-tooltip slot="cycle" slot-scope="text" placement="topLeft" :title="nodeMonitorCycle[text]">
|
||||
<span>{{ nodeMonitorCycle[text] }}</span>
|
||||
</a-tooltip> -->
|
||||
<a-tooltip slot="status" slot-scope="text, item" placement="topLeft" :title="statusMap[item.machineNodeData && item.machineNodeData.status] || '未知'">
|
||||
<!-- <span>{{ statusMap[item.machineNodeData && item.machineNodeData.status] || "未知" }}</span> -->
|
||||
|
||||
<a-tag :color="item.machineNodeData && item.machineNodeData.status === 1 ? 'green' : 'pink'" style="margin-right: 0px">
|
||||
{{ statusMap[item.machineNodeData && item.machineNodeData.status] || "未知" }}
|
||||
</a-tag>
|
||||
</a-tooltip>
|
||||
<a-tooltip slot="osName" slot-scope="text, item" placement="topLeft" :title="text">
|
||||
<span>{{ item.machineNodeData && item.machineNodeData.osName }}</span>
|
||||
</a-tooltip>
|
||||
<a-tooltip slot="javaVersion" slot-scope="text, item" placement="topLeft" :title="text">
|
||||
<span>{{ item.machineNodeData && item.machineNodeData.javaVersion }}</span>
|
||||
</a-tooltip>
|
||||
<a-tooltip slot="totalMemory" slot-scope="text, item" placement="topLeft" :title="renderSize(item.machineNodeData && item.machineNodeData.jvmTotalMemory)">
|
||||
<span>{{ renderSize(item.machineNodeData && item.machineNodeData.jvmTotalMemory) }}</span>
|
||||
</a-tooltip>
|
||||
<a-tooltip slot="freeMemory" slot-scope="text" placement="topLeft" :title="renderSize(text)">
|
||||
<span>{{ renderSize(text) }}</span>
|
||||
</a-tooltip>
|
||||
|
||||
<a-tooltip slot="runTime" slot-scope="text, item" placement="topLeft" :title="formatDuration(item.machineNodeData && item.machineNodeData.jpomUptime)">
|
||||
<span>{{ formatDuration(item.machineNodeData && item.machineNodeData.jpomUptime, "", 2) }}</span>
|
||||
</a-tooltip>
|
||||
<template slot="projectCount" slot-scope="text, item">
|
||||
<div v-if="item.machineNodeData" @click="syncNode(item)">
|
||||
<a-tooltip placement="topLeft" title="节点中的所有项目数量,点击重新同步节点项目信息">
|
||||
<a-tag>{{ item.machineNodeData.jpomProjectCount }} </a-tag>
|
||||
<a-icon type="sync" />
|
||||
</a-tooltip>
|
||||
</div>
|
||||
<span v-else>0</span>
|
||||
</template>
|
||||
<template slot="scriptCount" slot-scope="text, item">
|
||||
<div v-if="item.machineNodeData" @click="syncNodeScript(item)">
|
||||
<a-tooltip placement="topLeft" title="节点中的所有脚本模版数量,点击重新同步脚本模版信息">
|
||||
<a-tag>{{ item.machineNodeData.jpomScriptCount }} </a-tag>
|
||||
<a-icon type="sync" />
|
||||
</a-tooltip>
|
||||
</div>
|
||||
<span v-else>0</span>
|
||||
</template>
|
||||
|
||||
<template slot="operation" slot-scope="text, record, index">
|
||||
<a-tooltip title="我在这里" :visible="showOptVisible[record.id]">
|
||||
<a-space>
|
||||
<a-button size="small" v-if="record.unLockType" type="primary" @click="unlock(record)"><a-icon type="unlock" />解锁</a-button>
|
||||
|
||||
<a-tooltip v-else title="如果按钮不可用则表示当前节点已经关闭啦,需要去编辑中启用">
|
||||
<a-tooltip title="如果按钮不可用则表示当前节点已经关闭啦,需要去编辑中启用">
|
||||
<a-button size="small" class="jpom-node-manage-btn" type="primary" @click="handleNode(record)" :disabled="record.openStatus !== 1"><a-icon type="apartment" />管理</a-button>
|
||||
</a-tooltip>
|
||||
<a-tooltip title="需要到编辑中去为一个节点绑定一个 ssh信息才能启用该功能">
|
||||
@ -131,45 +163,11 @@
|
||||
</a-space>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<!-- 嵌套表格 -->
|
||||
<!-- <template slot="expandIcon" slot-scope="text" v-if="text.record.openStatus === 1"> <a-icon type="plus" /></template> -->
|
||||
<template slot="expandedRowRender" slot-scope="record">
|
||||
<a-table size="middle" :loading="childLoading" :columns="childColumns" :data-source="nodeStatusData[record.id]" :pagination="false" :rowKey="(record, index) => index">
|
||||
<a-tooltip slot="osName" slot-scope="text" placement="topLeft" :title="text">
|
||||
<span>{{ text }}</span>
|
||||
</a-tooltip>
|
||||
<a-tooltip slot="javaVersion" slot-scope="text" placement="topLeft" :title="text">
|
||||
<span>{{ text }}</span>
|
||||
</a-tooltip>
|
||||
<a-tooltip slot="runTime" slot-scope="text" placement="topLeft" :title="text">
|
||||
<span>{{ text }}</span>
|
||||
</a-tooltip>
|
||||
<template slot="projectCount" slot-scope="text, item">
|
||||
<div v-if="text" @click="syncNode(item)">
|
||||
<a-tooltip placement="topLeft" title="节点中的所有项目数量,点击重新同步节点项目信息">
|
||||
<a-tag>{{ text }} </a-tag>
|
||||
<a-icon type="sync" />
|
||||
</a-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
<template slot="scriptCount" slot-scope="text, item">
|
||||
<div v-if="text" @click="syncNodeScript(item)">
|
||||
<a-tooltip placement="topLeft" title="节点中的所有脚本模版数量,点击重新同步脚本模版信息">
|
||||
<a-tag>{{ text }} </a-tag>
|
||||
<a-icon type="sync" />
|
||||
</a-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
</a-table>
|
||||
</template>
|
||||
</a-table>
|
||||
|
||||
<!-- 编辑区 -->
|
||||
<a-modal destroyOnClose v-model="editNodeVisible" width="50%" title="编辑节点" @ok="handleEditNodeOk" :maskClosable="false">
|
||||
<a-form-model ref="editNodeForm" :rules="rules" :model="temp" :label-col="{ span: 4 }" :wrapper-col="{ span: 19 }">
|
||||
<!-- <a-form-model-item label="节点 ID" prop="id">
|
||||
<a-input v-model="temp.id" placeholder="创建之后不能修改" />
|
||||
</a-form-model-item> -->
|
||||
<a-form-model-item label="节点名称" prop="name">
|
||||
<a-input :maxLength="50" v-model="temp.name" placeholder="节点名称" />
|
||||
</a-form-model-item>
|
||||
@ -177,12 +175,6 @@
|
||||
<custom-select v-model="temp.group" :data="groupList" suffixIcon="" inputPlaceholder="添加分组" selectPlaceholder="选择分组名"> </custom-select>
|
||||
</a-form-model-item>
|
||||
|
||||
<!-- <a-form-model-item label="监控周期" prop="cycle">
|
||||
<a-select v-model="temp.cycle" defaultValue="0" placeholder="监控周期">
|
||||
<a-select-option v-for="(name, key) in nodeMonitorCycle" :key="parseInt(key)">{{ name }}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-model-item> -->
|
||||
|
||||
<a-form-model-item label="节点状态" prop="openStatus">
|
||||
<a-switch
|
||||
:checked="temp.openStatus == 1"
|
||||
@ -196,76 +188,12 @@
|
||||
default-checked
|
||||
/>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item prop="url">
|
||||
<template slot="label">
|
||||
节点地址
|
||||
<a-tooltip v-show="!temp.id">
|
||||
<template slot="title"
|
||||
>节点地址为插件端的 IP:PORT 插件端端口默认为:2123
|
||||
<ul>
|
||||
<li>节点地址建议使用内网地址</li>
|
||||
<li>如果插件端正常运行但是连接失败请检查端口是否开放,防火墙规则,云服务器的安全组入站规则</li>
|
||||
</ul>
|
||||
</template>
|
||||
<a-icon type="question-circle" theme="filled" />
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<a-input v-model="temp.url" placeholder="节点地址 (127.0.0.1:2123)">
|
||||
<a-select placeholder="选择协议类型" slot="addonBefore" v-model="temp.protocol" default-value="Http://" style="width: 80px">
|
||||
<a-select-option value="Http"> Http:// </a-select-option>
|
||||
<a-select-option value="Https"> Https:// </a-select-option>
|
||||
</a-select>
|
||||
<!-- <a-input v-model="temp.url" placeholder="节点地址 (127.0.0.1:2123)"/>-->
|
||||
</a-input>
|
||||
</a-form-model-item>
|
||||
<!-- <a-form-model-item label="节点协议" prop="protocol">-->
|
||||
<!-- <a-select v-model="temp.protocol" defaultValue="http" placeholder="节点协议">-->
|
||||
<!-- <a-select-option key="http">HTTP</a-select-option>-->
|
||||
<!-- <a-select-option key="htts">HTTPS</a-select-option>-->
|
||||
<!-- </a-select>-->
|
||||
<!-- </a-form-model-item>-->
|
||||
<!-- <a-form-model-item label="节点地址" prop="url">-->
|
||||
<!-- <a-input v-model="temp.url" placeholder="节点地址 (127.0.0.1:2123)"/>-->
|
||||
<!-- </a-form-model-item>-->
|
||||
<div class="node-config">
|
||||
<a-form-model-item label="节点账号" prop="loginName">
|
||||
<a-input v-model="temp.loginName" placeholder="节点账号,请查看节点启动输出的信息" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item :prop="`${temp.id ? 'loginPwd-update' : 'loginPwd'}`">
|
||||
<template slot="label">
|
||||
节点密码
|
||||
<a-tooltip v-show="!temp.id">
|
||||
<template slot="title"> 节点账号密码默认由系统生成:可以通过插件端数据目录下 agent_authorize.json 文件查看(如果自定义配置了账号密码将没有此文件) </template>
|
||||
<a-icon type="question-circle" theme="filled" />
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<a-input-password v-model="temp.loginPwd" placeholder="节点密码,请查看节点启动输出的信息" />
|
||||
</a-form-model-item>
|
||||
</div>
|
||||
<a-collapse>
|
||||
<a-collapse-panel key="1" header="其他配置">
|
||||
<a-form-model-item label="超时时间(s)" prop="timeOut">
|
||||
<a-input-number v-model="temp.timeOut" :min="0" placeholder="秒 (值太小可能会取不到节点状态)" style="width: 100%" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="绑定 SSH " prop="sshId">
|
||||
<a-select show-search option-filter-prop="children" v-model="temp.sshId" placeholder="请选择SSH">
|
||||
<a-select-option value="">不绑定</a-select-option>
|
||||
<a-select-option v-for="ssh in sshList" :key="ssh.id" :disabled="ssh.disabled">{{ ssh.name }}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-model-item>
|
||||
|
||||
<a-form-model-item label="代理" prop="httpProxy">
|
||||
<a-input v-model="temp.httpProxy" placeholder="代理地址 (127.0.0.1:8888)">
|
||||
<a-select slot="addonBefore" v-model="temp.httpProxyType" placeholder="选择代理类型" default-value="HTTP" style="width: 100px">
|
||||
<a-select-option value="HTTP">HTTP</a-select-option>
|
||||
<a-select-option value="SOCKS">SOCKS</a-select-option>
|
||||
<a-select-option value="DIRECT">DIRECT</a-select-option>
|
||||
</a-select>
|
||||
<!-- <a-input v-model="temp.url" placeholder="节点地址 (127.0.0.1:2123)"/>-->
|
||||
</a-input>
|
||||
</a-form-model-item>
|
||||
</a-collapse-panel>
|
||||
</a-collapse>
|
||||
</a-form-model>
|
||||
</a-modal>
|
||||
<!-- 管理节点 -->
|
||||
@ -289,16 +217,7 @@
|
||||
>
|
||||
<terminal v-if="terminalVisible" :sshId="temp.sshId" :nodeId="temp.id" />
|
||||
</a-modal>
|
||||
<!-- 解锁节点 -->
|
||||
<a-modal destroyOnClose v-model="unlockNode" title="解锁节点" @ok="handleUnLockNodeOk" :maskClosable="false">
|
||||
<a-form-model :model="temp" :label-col="{ span: 6 }" :wrapper-col="{ span: 14 }">
|
||||
<a-form-model-item label="绑定工作空间" prop="workspaceId">
|
||||
<a-select show-search option-filter-prop="children" v-model="temp.workspaceId" placeholder="请选择工作空间">
|
||||
<a-select-option v-for="item in workspaceList" :key="item.id">{{ item.name }}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-model-item>
|
||||
</a-form-model>
|
||||
</a-modal>
|
||||
|
||||
<!-- 快速安装插件端 -->
|
||||
<a-modal
|
||||
destroyOnClose
|
||||
@ -340,15 +259,16 @@
|
||||
</template>
|
||||
<script>
|
||||
import { mapGetters } from "vuex";
|
||||
import { deleteNode, editNode, getNodeGroupAll, getNodeList, getNodeStatus, syncProject, syncToWorkspace, unbind, unLockWorkspace, sortItem } from "@/api/node";
|
||||
import { deleteNode, editNode, getNodeGroupAll, getNodeList, syncProject, syncToWorkspace, unbind, sortItem } from "@/api/node";
|
||||
import { getSshListAll } from "@/api/ssh";
|
||||
import { syncScript } from "@/api/node-other";
|
||||
import NodeLayout from "./node-layout";
|
||||
import Terminal from "@/pages/ssh/terminal";
|
||||
import { CHANGE_PAGE, COMPUTED_PAGINATION, PAGE_DEFAULT_LIST_QUERY, parseTime } from "@/utils/const";
|
||||
import { CHANGE_PAGE, COMPUTED_PAGINATION, PAGE_DEFAULT_LIST_QUERY, formatDuration, renderSize } from "@/utils/const";
|
||||
import { getWorkSpaceListAll } from "@/api/workspace";
|
||||
import CustomSelect from "@/components/customSelect";
|
||||
import fastInstall from "./fast-install.vue";
|
||||
import { statusMap } from "@/api/system/assets-machine";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@ -360,12 +280,12 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
childLoading: false,
|
||||
|
||||
listQuery: Object.assign({}, PAGE_DEFAULT_LIST_QUERY),
|
||||
// nodeMonitorCycle: nodeMonitorCycle,
|
||||
statusMap,
|
||||
sshList: [],
|
||||
list: [],
|
||||
nodeStatusData: {},
|
||||
|
||||
groupList: [],
|
||||
showOptVisible: {},
|
||||
temp: {},
|
||||
@ -373,51 +293,29 @@ export default {
|
||||
editNodeVisible: false,
|
||||
drawerVisible: false,
|
||||
terminalVisible: false,
|
||||
unlockNode: false,
|
||||
|
||||
fastInstallNode: false,
|
||||
syncToWorkspaceVisible: false,
|
||||
drawerTitle: "",
|
||||
columns: [
|
||||
// { title: "节点 ID", dataIndex: "id", sorter: true, key: "id", ellipsis: true, scopedSlots: { customRender: "id" } },
|
||||
{ title: "节点名称", dataIndex: "name", sorter: true, key: "name", ellipsis: true, scopedSlots: { customRender: "name" } },
|
||||
|
||||
// { title: "节点协议", dataIndex: "protocol", sorter: true, key: "protocol", width: 100, ellipsis: true, scopedSlots: { customRender: "protocol" } },
|
||||
{ title: "节点地址", dataIndex: "url", sorter: true, key: "url", ellipsis: true, scopedSlots: { customRender: "url" } },
|
||||
{ title: "账号", dataIndex: "loginName", sorter: true, width: 150, key: "loginName", ellipsis: true, scopedSlots: { customRender: "loginName" } },
|
||||
// { title: "监控周期", dataIndex: "cycle", sorter: true, key: "cycle", ellipsis: true, scopedSlots: { customRender: "cycle" } },
|
||||
{ title: "超时时间", dataIndex: "timeOut", sorter: true, key: "timeOut", width: 100, ellipsis: true },
|
||||
{
|
||||
title: "修改时间",
|
||||
dataIndex: "modifyTimeMillis",
|
||||
ellipsis: true,
|
||||
sorter: true,
|
||||
customRender: (text) => {
|
||||
return parseTime(text);
|
||||
},
|
||||
width: 170,
|
||||
},
|
||||
{ title: "操作", dataIndex: "operation", key: "operation", width: 210, scopedSlots: { customRender: "operation" }, align: "center" },
|
||||
],
|
||||
childColumns: [
|
||||
{ title: "系统名", dataIndex: "osName", key: "osName", width: 100, ellipsis: true, scopedSlots: { customRender: "osName" } },
|
||||
{ title: "状态", dataIndex: "status", ellipsis: true, scopedSlots: { customRender: "status" } },
|
||||
{ title: "节点地址", dataIndex: "url", key: "url", width: "190px", ellipsis: true, scopedSlots: { customRender: "url" } },
|
||||
{ title: "系统名", dataIndex: "osName", key: "osName", width: "100px", ellipsis: true, scopedSlots: { customRender: "osName" } },
|
||||
{ title: "JDK 版本", dataIndex: "javaVersion", key: "javaVersion", ellipsis: true, scopedSlots: { customRender: "javaVersion" } },
|
||||
{ title: "JVM 总内存", dataIndex: "totalMemory", key: "totalMemory", width: 120 },
|
||||
{ title: "JVM 剩余内存", dataIndex: "freeMemory", key: "freeMemory", width: 140 },
|
||||
{ title: "版本", dataIndex: "jpomVersion", key: "jpomVersion", width: 120 },
|
||||
{ title: "Java 程序数", dataIndex: "javaVirtualCount", key: "javaVirtualCount", width: 120 },
|
||||
{ title: "JVM 总内存", dataIndex: "totalMemory", ellipsis: true, scopedSlots: { customRender: "totalMemory" } },
|
||||
{ title: "JVM 剩余内存", dataIndex: "machineNodeData.jvmFreeMemory", ellipsis: true, scopedSlots: { customRender: "freeMemory" } },
|
||||
|
||||
{ title: "项目数", dataIndex: "count", key: "count", width: 90, scopedSlots: { customRender: "projectCount" } },
|
||||
{ title: "脚本数", dataIndex: "scriptCount", key: "scriptCount", width: 90, scopedSlots: { customRender: "scriptCount" } },
|
||||
{ title: "响应时间", dataIndex: "timeOut", key: "timeOut", width: 120 },
|
||||
{ title: "已运行时间", dataIndex: "runTime", key: "runTime", width: 150, ellipsis: true, scopedSlots: { customRender: "runTime" } },
|
||||
{ title: "项目数", dataIndex: "count", key: "count", width: "90px", scopedSlots: { customRender: "projectCount" } },
|
||||
{ title: "脚本数", dataIndex: "scriptCount", key: "scriptCount", width: "90px", scopedSlots: { customRender: "scriptCount" } },
|
||||
|
||||
{ title: "已运行时间", dataIndex: "runTime", key: "runTime", ellipsis: true, scopedSlots: { customRender: "runTime" } },
|
||||
|
||||
{ title: "操作", dataIndex: "operation", key: "operation", width: "210px", scopedSlots: { customRender: "operation" }, align: "center" },
|
||||
],
|
||||
|
||||
rules: {
|
||||
id: [{ required: true, message: "Please input node id", trigger: "blur" }],
|
||||
name: [{ required: true, message: "Please input node name", trigger: "blur" }],
|
||||
url: [{ required: true, message: "Please input url", trigger: "blur" }],
|
||||
loginName: [{ required: true, message: "Please input login name", trigger: "blur" }],
|
||||
loginPwd: [{ required: true, message: "Please input login password", trigger: "blur" }],
|
||||
timeOut: [{ required: true, message: "Please input timeout", trigger: "blur" }],
|
||||
name: [{ required: true, message: "请输入节点名称", trigger: "blur" }],
|
||||
},
|
||||
workspaceList: [],
|
||||
tableSelections: [],
|
||||
@ -448,12 +346,10 @@ export default {
|
||||
});
|
||||
this.loadGroupList();
|
||||
},
|
||||
// destroyed() {
|
||||
// if (this.pullFastInstallResultTime) {
|
||||
// clearInterval(this.pullFastInstallResultTime);
|
||||
// }
|
||||
// },
|
||||
|
||||
methods: {
|
||||
formatDuration,
|
||||
renderSize,
|
||||
findTipNode() {
|
||||
if (this.$route.query.tipNodeId) {
|
||||
this.showOptVisible[this.$route.query.tipNodeId] = true;
|
||||
@ -492,11 +388,6 @@ export default {
|
||||
options: {
|
||||
hidePrev: true,
|
||||
steps: [
|
||||
{
|
||||
title: "导航助手",
|
||||
element: document.querySelector(".jpom-node-manage-add"),
|
||||
intro: "如果还没有节点 可以点击【新增】按钮新增节点",
|
||||
},
|
||||
{
|
||||
title: "导航助手",
|
||||
element: document.querySelector(".jpom-node-manage-btn"),
|
||||
@ -547,48 +438,7 @@ export default {
|
||||
});
|
||||
});
|
||||
},
|
||||
// 展开行
|
||||
expand(expanded, record) {
|
||||
if (expanded) {
|
||||
if (!record.openStatus) {
|
||||
this.$notification.error({
|
||||
message: "节点未启用",
|
||||
});
|
||||
return false;
|
||||
}
|
||||
// 请求节点状态数据
|
||||
this.childLoading = true;
|
||||
getNodeStatus(record.id).then((res) => {
|
||||
if (res.code === 200) {
|
||||
// bwcx_jzy 2022-05-11 单独使用对象,避免一级表格出现空白行
|
||||
this.nodeStatusData = {
|
||||
...this.nodeStatusData,
|
||||
[record.id]: [{ ...res.data[0], id: record.id + new Date().getTime() }],
|
||||
};
|
||||
}
|
||||
this.childLoading = false;
|
||||
});
|
||||
}
|
||||
},
|
||||
// 添加
|
||||
handleAdd() {
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
this.introGuide();
|
||||
}, 500);
|
||||
this.$refs["editNodeForm"] && this.$refs["editNodeForm"].resetFields();
|
||||
this.temp = {
|
||||
type: "add",
|
||||
cycle: 0,
|
||||
protocol: "http",
|
||||
openStatus: 1,
|
||||
timeOut: 0,
|
||||
loginName: "jpomAgent",
|
||||
};
|
||||
this.editNodeVisible = true;
|
||||
});
|
||||
this.loadSshList();
|
||||
},
|
||||
|
||||
// 进入终端
|
||||
handleTerminal(record) {
|
||||
this.temp = Object.assign({}, record);
|
||||
@ -729,44 +579,6 @@ export default {
|
||||
});
|
||||
},
|
||||
|
||||
unlock(record) {
|
||||
this.unlockNode = true;
|
||||
this.loadWorkSpaceListAll();
|
||||
|
||||
this.temp = Object.assign({}, record);
|
||||
this.temp.workspaceId = "";
|
||||
},
|
||||
handleUnLockNodeOk() {
|
||||
if (!this.temp.workspaceId) {
|
||||
this.$notification.warn({
|
||||
message: "请选择工作空间",
|
||||
});
|
||||
return false;
|
||||
}
|
||||
this.$confirm({
|
||||
title: "系统提示",
|
||||
content: "确定要将此节点绑定到这个工作空间吗?绑定后不可更改",
|
||||
okText: "确认",
|
||||
cancelText: "取消",
|
||||
onOk: () => {
|
||||
// 解锁
|
||||
unLockWorkspace({
|
||||
id: this.temp.id,
|
||||
toWorkspaceId: this.temp.workspaceId,
|
||||
}).then((res) => {
|
||||
if (res.code === 200) {
|
||||
this.$notification.success({
|
||||
message: res.msg,
|
||||
});
|
||||
this.unlockNode = false;
|
||||
this.loadData();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
// 同步到其他工作情况
|
||||
syncToWorkspaceShow() {
|
||||
this.syncToWorkspaceVisible = true;
|
||||
|
@ -61,7 +61,7 @@ export default {
|
||||
// 加载数据
|
||||
nodeMonitorData(params).then((res) => {
|
||||
if (res.code === 200) {
|
||||
if (this.type === "networkTime") {
|
||||
if (this.type === "networkDelay") {
|
||||
this.historyChart = drawChart(res.data, "historyChart", generateNodeNetworkTimeChart);
|
||||
} else {
|
||||
this.historyChart = drawChart(res.data, "historyChart", generateNodeTopChart);
|
||||
|
@ -1,41 +1,16 @@
|
||||
<template>
|
||||
<div class="full-content">
|
||||
<div>
|
||||
<a-card :bodyStyle="{ padding: '10px' }">
|
||||
<a-card>
|
||||
<template slot="title">
|
||||
<a-row style="text-align: center">
|
||||
<a-col :span="3">
|
||||
<a-statistic title="节点总数" :value="nodeCount"> </a-statistic>
|
||||
</a-col>
|
||||
<a-col :span="3" v-for="(desc, key) in statusMap" :key="key">
|
||||
<a-statistic :title="desc" :value="statusStatMap[key]">
|
||||
<template #suffix>
|
||||
<!-- <a-icon type="question-circle" /> -->
|
||||
</template>
|
||||
</a-statistic>
|
||||
</a-col>
|
||||
|
||||
<a-col :span="3"> <a-statistic-countdown format="s 秒" title="刷新倒计时" :value="deadline" @finish="onFinish" /> </a-col>
|
||||
</a-row>
|
||||
</template>
|
||||
<a-space direction="vertical">
|
||||
<div ref="filter" class="filter">
|
||||
<a-row>
|
||||
<a-space>
|
||||
<a-input v-model="listQuery['%name%']" @pressEnter="loadData" placeholder="节点名称" />
|
||||
<a-input v-model="listQuery['%url%']" @pressEnter="loadData" placeholder="节点地址" />
|
||||
<a-select v-model="listQuery.status" allowClear placeholder="请选择状态" class="search-input-item">
|
||||
<a-select-option v-for="(desc, key) in statusMap" :key="key">{{ desc }}</a-select-option>
|
||||
</a-select>
|
||||
|
||||
<a-select show-search option-filter-prop="children" v-model="listQuery.group" allowClear placeholder="分组" class="search-input-item">
|
||||
<a-select-option v-for="item in groupList" :key="item">{{ item }}</a-select-option>
|
||||
</a-select>
|
||||
<a-select v-model="listQuery['order_field']" allowClear placeholder="请选择排序字段" class="search-input-item">
|
||||
<a-select-option value="networkTime">网络延迟</a-select-option>
|
||||
<a-select-option value="occupyCpu">cpu</a-select-option>
|
||||
<a-select-option value="occupyDisk">硬盘</a-select-option>
|
||||
<a-select-option value="occupyMemoryUsed">内存Used</a-select-option>
|
||||
<a-select-option value="occupyMemory">内存</a-select-option>
|
||||
</a-select>
|
||||
|
||||
<a-tooltip title="按住 Ctr 或者 Alt/Option 键点击按钮快速回到第一页">
|
||||
<a-button :loading="loading" type="primary" @click="loadData">搜索</a-button>
|
||||
</a-tooltip>
|
||||
@ -55,9 +30,11 @@
|
||||
</template>
|
||||
<a-icon type="question-circle" theme="filled" />
|
||||
</a-tooltip>
|
||||
<a-col :span="3"> <a-statistic-countdown format="s 秒" title="" :value="deadline" @finish="onFinish" /> </a-col>
|
||||
</a-space>
|
||||
</div>
|
||||
</a-space>
|
||||
</a-row>
|
||||
</template>
|
||||
|
||||
<a-row :gutter="[16, 16]">
|
||||
<template v-if="list && list.length">
|
||||
<a-col v-for="item in list" :key="item.id" :span="6">
|
||||
@ -75,8 +52,14 @@
|
||||
</a-tooltip>
|
||||
</a-col>
|
||||
<a-col :span="7" style="text-align: right">
|
||||
<a-tooltip :title="`当前状态:${statusMap[item.status]} ${item.status === 0 ? '' : '异常描述:' + item.failureMsg} `">
|
||||
<a-tag :color="item.status === 0 ? 'green' : 'pink'" style="margin-right: 0px"> {{ statusMap[item.status] }}</a-tag>
|
||||
<a-tooltip>
|
||||
<template slot="title">
|
||||
<div>当前状态:{{ statusMap[item.machineNodeData && item.machineNodeData.status] }}</div>
|
||||
<div>状态描述:{{ (item.machineNodeData && item.machineNodeData.statusMsg) || "" }}</div>
|
||||
</template>
|
||||
<a-tag :color="item.machineNodeData && item.machineNodeData.status === 1 ? 'green' : 'pink'" style="margin-right: 0px">
|
||||
{{ statusMap[item.machineNodeData && item.machineNodeData.status] }}
|
||||
</a-tag>
|
||||
</a-tooltip>
|
||||
</a-col>
|
||||
</a-row>
|
||||
@ -84,7 +67,7 @@
|
||||
|
||||
<a-row :gutter="[8, 8]">
|
||||
<a-col :span="8">
|
||||
<a-tooltip @click="item.status === 4 ? null : handleHistory(item, 'nodeTop')" :title="`CPU 占用率:${item.occupyCpu}%`">
|
||||
<a-tooltip @click="handleHistory(item, 'nodeTop')" :title="`CPU 占用率:${item.occupyCpu}%`">
|
||||
<a-progress
|
||||
type="circle"
|
||||
:width="80"
|
||||
@ -100,7 +83,7 @@
|
||||
</a-tooltip>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
<a-tooltip @click="item.status === 4 ? null : handleHistory(item, 'nodeTop')" :title="`硬盘占用率:${item.occupyDisk}%`">
|
||||
<a-tooltip @click="handleHistory(item, 'nodeTop')" :title="`硬盘占用率:${item.occupyDisk}%`">
|
||||
<a-progress
|
||||
type="circle"
|
||||
:width="80"
|
||||
@ -116,10 +99,7 @@
|
||||
</a-tooltip>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
<a-tooltip
|
||||
@click="item.status === 4 ? null : handleHistory(item, 'nodeTop')"
|
||||
:title="`内存占用率:${item.occupyMemoryUsed && item.occupyMemoryUsed !== -1 ? item.occupyMemoryUsed : item.occupyMemory}%`"
|
||||
>
|
||||
<a-tooltip @click="handleHistory(item, 'nodeTop')" :title="`内存占用率:${item.occupyMemory}%`">
|
||||
<a-progress
|
||||
:width="80"
|
||||
type="circle"
|
||||
@ -130,7 +110,7 @@
|
||||
}"
|
||||
size="small"
|
||||
status="active"
|
||||
:percent="item.occupyMemoryUsed && item.occupyMemoryUsed !== -1 ? item.occupyMemoryUsed : item.occupyMemory"
|
||||
:percent="item.occupyMemory"
|
||||
/>
|
||||
</a-tooltip>
|
||||
</a-col>
|
||||
@ -138,40 +118,43 @@
|
||||
|
||||
<a-row :gutter="[8, 8]" style="text-align: center">
|
||||
<a-col :span="8">
|
||||
<a-tooltip @click="item.status === 4 ? null : handleHistory(item, 'networkTime')" :title="`${item.status === 4 ? '-' : '延迟' + item.networkTime + 'ms 点击查看历史趋势'}`">
|
||||
<a-tooltip
|
||||
@click="handleHistory(item, 'networkDelay')"
|
||||
:title="`${'延迟' + (formatDuration(item.machineNodeData && item.machineNodeData.networkDelay, '', 2) || '-') + ' 点击查看历史趋势'}`"
|
||||
>
|
||||
<a-statistic
|
||||
title="延迟"
|
||||
:value="item.networkTime"
|
||||
:value="item.machineNodeData && item.machineNodeData.networkDelay"
|
||||
valueStyle="font-size: 14px;overflow: hidden; text-overflow: ellipsis; white-space: nowrap"
|
||||
:formatter="
|
||||
(v) => {
|
||||
return item.networkTime === -1 ? '-' : item.networkTime + 'ms';
|
||||
return formatDuration(item.machineNodeData && item.machineNodeData.networkDelay, '', 2) || '-';
|
||||
}
|
||||
"
|
||||
/>
|
||||
</a-tooltip>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
<a-tooltip :title="formatDuration(item.upTimeStr) || '-'">
|
||||
<a-tooltip :title="formatDuration(item.machineNodeData && item.machineNodeData.jpomUptime, '', 1) || '-'">
|
||||
<a-statistic
|
||||
title="运行时间"
|
||||
valueStyle="font-size: 14px;overflow: hidden; text-overflow: ellipsis; white-space: nowrap"
|
||||
:formatter="
|
||||
(v) => {
|
||||
return formatDuration(item.upTimeStr, '', 1) || '-';
|
||||
return formatDuration(item.machineNodeData && item.machineNodeData.jpomUptime, '', 2) || '-';
|
||||
}
|
||||
"
|
||||
/>
|
||||
</a-tooltip>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
<a-tooltip :title="`${item.status === 4 ? '-' : parseTime(item.modifyTimeMillis)}`">
|
||||
<a-tooltip :title="`${parseTime(item.machineNodeData && item.machineNodeData.modifyTimeMillis)}`">
|
||||
<a-statistic
|
||||
title="更新时间"
|
||||
valueStyle="font-size: 14px;overflow: hidden; text-overflow: ellipsis; white-space: nowrap"
|
||||
:formatter="
|
||||
(v) => {
|
||||
return item.status === 4 ? '-' : parseTime(item.modifyTimeMillis, '{h}:{i}:{s}');
|
||||
return parseTime(item.machineNodeData && item.machineNodeData.modifyTimeMillis, '{h}:{i}:{s}');
|
||||
}
|
||||
"
|
||||
/>
|
||||
@ -221,25 +204,25 @@
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { getStatist, status, statusStat } from "@/api/node-stat";
|
||||
// import { getStatist, status, statusStat } from "@/api/node-stat";
|
||||
import {} from "@/api/node";
|
||||
import { PAGE_DEFAULT_LIST_QUERY, PAGE_DEFAULT_SHOW_TOTAL, formatDuration, parseTime, formatPercent2Number } from "@/utils/const";
|
||||
import NodeTop from "@/pages/node/node-layout/node-top";
|
||||
import { getNodeGroupAll } from "@/api/node";
|
||||
import { getNodeGroupAll, getNodeList } from "@/api/node";
|
||||
import { statusMap } from "@/api/system/assets-machine";
|
||||
|
||||
export default {
|
||||
components: { NodeTop },
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
statusMap: status,
|
||||
listQuery: Object.assign({ order: "descend", order_field: "networkTime" }, PAGE_DEFAULT_LIST_QUERY, {
|
||||
statusMap,
|
||||
listQuery: Object.assign({}, PAGE_DEFAULT_LIST_QUERY, {
|
||||
limit: 8,
|
||||
}),
|
||||
sizeOptions: ["8", "12", "16", "20", "24"],
|
||||
list: [],
|
||||
statusStatMap: {},
|
||||
// openStatusMap: {},
|
||||
nodeCount: 0,
|
||||
|
||||
monitorVisible: false,
|
||||
deadline: 0,
|
||||
temp: {},
|
||||
@ -253,11 +236,7 @@ export default {
|
||||
this.loadData();
|
||||
this.loadGroupList();
|
||||
},
|
||||
destroyed() {
|
||||
if (this.pullFastInstallResultTime) {
|
||||
clearInterval(this.pullFastInstallResultTime);
|
||||
}
|
||||
},
|
||||
destroyed() {},
|
||||
methods: {
|
||||
PAGE_DEFAULT_SHOW_TOTAL,
|
||||
parseTime,
|
||||
@ -267,37 +246,24 @@ export default {
|
||||
//this.list = [];
|
||||
this.listQuery.page = pointerEvent?.altKey || pointerEvent?.ctrlKey ? 1 : this.listQuery.page;
|
||||
this.loading = true;
|
||||
getStatist(this.listQuery).then((res) => {
|
||||
getNodeList(this.listQuery).then((res) => {
|
||||
if (res.code === 200) {
|
||||
this.list =
|
||||
res.data.result &&
|
||||
res.data.result.map((item) => {
|
||||
// console.log(item);
|
||||
item.occupyCpu = formatPercent2Number(item.occupyCpu);
|
||||
item.occupyMemoryUsed = formatPercent2Number(item.occupyMemoryUsed);
|
||||
item.occupyDisk = formatPercent2Number(item.occupyDisk);
|
||||
item.occupyMemory = formatPercent2Number(item.occupyMemory);
|
||||
item.occupyCpu = formatPercent2Number(item.machineNodeData?.osOccupyCpu);
|
||||
|
||||
item.occupyDisk = formatPercent2Number(item.machineNodeData?.osOccupyDisk);
|
||||
item.occupyMemory = formatPercent2Number(item.machineNodeData?.osOccupyMemory);
|
||||
return item;
|
||||
});
|
||||
this.listQuery.total = res.data.total;
|
||||
this.refreshInterval = 30;
|
||||
this.deadline = Date.now() + this.refreshInterval * 1000;
|
||||
}
|
||||
this.loading = false;
|
||||
});
|
||||
statusStat().then((res) => {
|
||||
if (res.data) {
|
||||
this.statusStatMap = res.data.status;
|
||||
let nodeCount2 = 0;
|
||||
// console.log(this.statusStatMap);
|
||||
Object.values(this.statusStatMap).forEach((element) => {
|
||||
nodeCount2 += element;
|
||||
});
|
||||
this.nodeCount = nodeCount2;
|
||||
this.refreshInterval = res.data.heartSecond;
|
||||
this.deadline = Date.now() + this.refreshInterval * 1000;
|
||||
//
|
||||
// this.openStatusMap = res.data.openStatus;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
onFinish() {
|
||||
@ -326,4 +292,13 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped></style>
|
||||
<style scoped>
|
||||
/* /deep/ .ant-statistic div {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/deep/ .ant-statistic-content-value,
|
||||
/deep/ .ant-statistic-content {
|
||||
font-size: 16px;
|
||||
} */
|
||||
</style>
|
||||
|
293
web-vue/src/pages/system/assets/machine/machine-list.vue
Normal file
293
web-vue/src/pages/system/assets/machine/machine-list.vue
Normal file
@ -0,0 +1,293 @@
|
||||
<template>
|
||||
<div>
|
||||
<a-card :bodyStyle="{ padding: '10px' }">
|
||||
<template slot="title">
|
||||
<a-space>
|
||||
<a-input class="search-input-item" @pressEnter="getMachineList" v-model="listQuery['%name%']" placeholder="机器名称" />
|
||||
<a-input class="search-input-item" @pressEnter="getMachineList" v-model="listQuery['%jpomUrl%']" placeholder="节点地址" />
|
||||
<a-select show-search option-filter-prop="children" v-model="listQuery.groupName" allowClear placeholder="分组" class="search-input-item">
|
||||
<a-select-option v-for="item in groupList" :key="item">{{ item }}</a-select-option>
|
||||
</a-select>
|
||||
<a-select v-model="listQuery['order_field']" allowClear placeholder="请选择排序字段" class="search-input-item">
|
||||
<a-select-option value="networkDelay">网络延迟</a-select-option>
|
||||
<a-select-option value="osOccupyCpu">cpu</a-select-option>
|
||||
<a-select-option value="osOccupyDisk">硬盘</a-select-option>
|
||||
<a-select-option value="osOccupyMemory">内存</a-select-option>
|
||||
<a-select-option value="osOccupyMemory">更新时间</a-select-option>
|
||||
<a-select-option value="osOccupyMemory">创建时间</a-select-option>
|
||||
</a-select>
|
||||
<a-button :loading="loading" type="primary" @click="getMachineList">搜索</a-button>
|
||||
</a-space>
|
||||
</template>
|
||||
<a-row :gutter="[16, 16]">
|
||||
<template v-if="list && list.length">
|
||||
<a-col v-for="item in list" :key="item.id" :span="6">
|
||||
<template>
|
||||
<a-card :headStyle="{ padding: '0 6px' }" :bodyStyle="{ padding: '10px' }">
|
||||
<template slot="title">
|
||||
<a-row :gutter="[4, 0]">
|
||||
<a-col :span="17" style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap">
|
||||
<a-tooltip>
|
||||
<template slot="title">
|
||||
<div>节点名称:{{ item.name }}</div>
|
||||
<div>节点地址:{{ item.jpomUrl }}</div>
|
||||
</template>
|
||||
|
||||
<a-button type="link" size="small" icon="edit" @click="handleEdit(item)">
|
||||
{{ item.name }}
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
</a-col>
|
||||
<a-col :span="7" style="text-align: right">
|
||||
<a-tooltip :title="`当前状态:${statusMap[item.status]} ${item.statusMsg ? '状态消息:' + item.statusMsg : ''} `">
|
||||
<a-tag :color="item.status === 1 ? 'green' : 'pink'" style="margin-right: 0px"> {{ statusMap[item.status] }}</a-tag>
|
||||
</a-tooltip>
|
||||
<a-button type="link" icon="fullscreen" size="small"> </a-button>
|
||||
<!-- <a-icon type="fullscreen" /> -->
|
||||
</a-col>
|
||||
</a-row>
|
||||
</template>
|
||||
|
||||
<!-- <a-row :gutter="[8, 8]"> -->
|
||||
<a-tooltip :title="item.osName">
|
||||
<div class="item-info">
|
||||
<div class="title">系统名称:</div>
|
||||
<div class="content">
|
||||
{{ item.osName }}
|
||||
</div>
|
||||
</div>
|
||||
</a-tooltip>
|
||||
<a-tooltip :title="item.osVersion">
|
||||
<div class="item-info">
|
||||
<div class="title">系统版本:</div>
|
||||
<div class="content">
|
||||
{{ item.osVersion }}
|
||||
</div>
|
||||
</div>
|
||||
</a-tooltip>
|
||||
<a-tooltip :title="item.osLoadAverage">
|
||||
<div class="item-info">
|
||||
<div class="title">系统负载:</div>
|
||||
<div class="content">
|
||||
{{ item.osLoadAverage }}
|
||||
</div>
|
||||
</div>
|
||||
</a-tooltip>
|
||||
<a-tooltip :title="item.jpomVersion">
|
||||
<div class="item-info">
|
||||
<div class="title">插件版本:</div>
|
||||
<div class="content">
|
||||
{{ item.jpomVersion }}
|
||||
</div>
|
||||
</div>
|
||||
</a-tooltip>
|
||||
<!-- <a-button type="link" :size="size"> 详情 </a-button> -->
|
||||
</a-card>
|
||||
</template>
|
||||
</a-col>
|
||||
</template>
|
||||
<a-col v-else :span="24">
|
||||
<a-empty description="没有任何节点" />
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row>
|
||||
<a-col>
|
||||
<a-pagination
|
||||
v-model="listQuery.page"
|
||||
v-if="listQuery.total / listQuery.limit > 1"
|
||||
:showTotal="
|
||||
(total) => {
|
||||
return PAGE_DEFAULT_SHOW_TOTAL(total, listQuery);
|
||||
}
|
||||
"
|
||||
:showSizeChanger="true"
|
||||
:pageSizeOptions="sizeOptions"
|
||||
:pageSize="listQuery.limit"
|
||||
:total="listQuery.total"
|
||||
@showSizeChange="
|
||||
(current, size) => {
|
||||
this.listQuery.limit = size;
|
||||
this.getMachineList();
|
||||
}
|
||||
"
|
||||
@change="this.getMachineList"
|
||||
show-less-items
|
||||
/>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-card>
|
||||
<!-- 编辑区 -->
|
||||
<a-modal destroyOnClose v-model="editVisible" width="50%" title="编辑机器" @ok="handleEditOk" :maskClosable="false">
|
||||
<a-form-model ref="editNodeForm" :rules="rules" :model="temp" :label-col="{ span: 4 }" :wrapper-col="{ span: 19 }">
|
||||
<a-form-model-item label="机器名称" prop="name">
|
||||
<a-input :maxLength="50" v-model="temp.name" placeholder="机器名称" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="机器分组" prop="group">
|
||||
<custom-select v-model="temp.groupName" :data="groupList" suffixIcon="" inputPlaceholder="添加分组" selectPlaceholder="选择分组名"> </custom-select>
|
||||
</a-form-model-item>
|
||||
|
||||
<a-form-model-item prop="jpomUrl">
|
||||
<template slot="label">
|
||||
节点地址
|
||||
<a-tooltip v-show="!temp.id">
|
||||
<template slot="title"
|
||||
>节点地址为插件端的 IP:PORT 插件端端口默认为:2123
|
||||
<ul>
|
||||
<li>节点地址建议使用内网地址</li>
|
||||
<li>如果插件端正常运行但是连接失败请检查端口是否开放,防火墙规则,云服务器的安全组入站规则</li>
|
||||
</ul>
|
||||
</template>
|
||||
<a-icon type="question-circle" theme="filled" />
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<a-input v-model="temp.jpomUrl" placeholder="节点地址 (127.0.0.1:2123)">
|
||||
<a-select placeholder="选择协议类型" slot="addonBefore" v-model="temp.jpomProtocol" default-value="Http://" style="width: 80px">
|
||||
<a-select-option value="Http"> Http:// </a-select-option>
|
||||
<a-select-option value="Https"> Https:// </a-select-option>
|
||||
</a-select>
|
||||
</a-input>
|
||||
</a-form-model-item>
|
||||
|
||||
<a-form-model-item label="节点账号" prop="loginName">
|
||||
<a-input v-model="temp.jpomUsername" placeholder="节点账号,请查看节点启动输出的信息" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item :prop="`${temp.id ? 'loginPwd-update' : 'loginPwd'}`">
|
||||
<template slot="label">
|
||||
节点密码
|
||||
<a-tooltip v-show="!temp.id">
|
||||
<template slot="title"> 节点账号密码默认由系统生成:可以通过插件端数据目录下 agent_authorize.json 文件查看(如果自定义配置了账号密码将没有此文件) </template>
|
||||
<a-icon type="question-circle" theme="filled" />
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<a-input-password v-model="temp.jpomPassword" placeholder="节点密码,请查看节点启动输出的信息" />
|
||||
</a-form-model-item>
|
||||
|
||||
<a-collapse>
|
||||
<a-collapse-panel key="1" header="其他配置">
|
||||
<a-form-model-item label="超时时间(s)" prop="timeOut">
|
||||
<a-input-number v-model="temp.jpomTimeout" :min="0" placeholder="秒 (值太小可能会取不到节点状态)" style="width: 100%" />
|
||||
</a-form-model-item>
|
||||
|
||||
<a-form-model-item label="代理" prop="jpomHttpProxy">
|
||||
<a-input v-model="temp.jpomHttpProxy" placeholder="代理地址 (127.0.0.1:8888)">
|
||||
<a-select slot="addonBefore" v-model="temp.jpomHttpProxyType" placeholder="选择代理类型" default-value="HTTP" style="width: 100px">
|
||||
<a-select-option value="HTTP">HTTP</a-select-option>
|
||||
<a-select-option value="SOCKS">SOCKS</a-select-option>
|
||||
<a-select-option value="DIRECT">DIRECT</a-select-option>
|
||||
</a-select>
|
||||
</a-input>
|
||||
</a-form-model-item>
|
||||
</a-collapse-panel>
|
||||
</a-collapse>
|
||||
</a-form-model>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { machineListData, machineListGroup, statusMap, machineEdit } from "@/api/system/assets-machine";
|
||||
import { CHANGE_PAGE, COMPUTED_PAGINATION, PAGE_DEFAULT_LIST_QUERY, PAGE_DEFAULT_SHOW_TOTAL, formatDuration, parseTime } from "@/utils/const";
|
||||
import CustomSelect from "@/components/customSelect";
|
||||
export default {
|
||||
components: {
|
||||
CustomSelect,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
statusMap,
|
||||
listQuery: Object.assign({ order: "descend", order_field: "networkDelay" }, PAGE_DEFAULT_LIST_QUERY, {}),
|
||||
sizeOptions: ["8", "12", "16", "20", "24"],
|
||||
list: [],
|
||||
groupList: [],
|
||||
loading: true,
|
||||
editVisible: false,
|
||||
temp: {},
|
||||
rules: {
|
||||
name: [{ required: true, message: "请输入机器的名称", trigger: "blur" }],
|
||||
},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
pagination() {
|
||||
return COMPUTED_PAGINATION(this.listQuery);
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.loadGroupList();
|
||||
this.getMachineList();
|
||||
},
|
||||
methods: {
|
||||
parseTime,
|
||||
formatDuration,
|
||||
PAGE_DEFAULT_SHOW_TOTAL,
|
||||
// 获取所有的分组
|
||||
loadGroupList() {
|
||||
machineListGroup().then((res) => {
|
||||
if (res.data) {
|
||||
this.groupList = res.data;
|
||||
}
|
||||
});
|
||||
},
|
||||
getMachineList(pointerEvent) {
|
||||
this.loading = true;
|
||||
this.listQuery.page = pointerEvent?.altKey || pointerEvent?.ctrlKey ? 1 : this.listQuery.page;
|
||||
machineListData(this.listQuery).then((res) => {
|
||||
if (res.code === 200) {
|
||||
this.list = res.data.result;
|
||||
this.listQuery.total = res.data.total;
|
||||
}
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
// 分页、排序、筛选变化时触发
|
||||
changePage(pagination, filters, sorter) {
|
||||
this.listQuery = CHANGE_PAGE(this.listQuery, { pagination, sorter });
|
||||
this.getMachineList();
|
||||
},
|
||||
// 修改
|
||||
handleEdit(record) {
|
||||
this.temp = Object.assign({}, record);
|
||||
delete this.temp.statusMsg;
|
||||
this.editVisible = true;
|
||||
},
|
||||
// 提交节点数据
|
||||
handleEditOk() {
|
||||
// 检验表单
|
||||
this.$refs["editNodeForm"].validate((valid) => {
|
||||
if (!valid) {
|
||||
return false;
|
||||
}
|
||||
// 提交数据
|
||||
machineEdit(this.temp).then((res) => {
|
||||
if (res.code === 200) {
|
||||
// 成功
|
||||
this.$notification.success({
|
||||
message: res.msg,
|
||||
});
|
||||
this.$refs["editNodeForm"].resetFields();
|
||||
this.editVisible = false;
|
||||
this.loadGroupList();
|
||||
this.getMachineList();
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.item-info {
|
||||
padding: 5px 0;
|
||||
}
|
||||
.item-info .title {
|
||||
display: inline;
|
||||
font-weight: bold;
|
||||
}
|
||||
.item-info .content {
|
||||
display: inline;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
</style>
|
@ -10,8 +10,8 @@
|
||||
</a-row>
|
||||
<a-space>
|
||||
<a-input class="search-input-item" @pressEnter="getNodeList" v-model="listQuery['%name%']" placeholder="节点名称" />
|
||||
<a-input class="search-input-item" @pressEnter="getNodeList" v-model="listQuery['%url%']" placeholder="节点地址" />
|
||||
<a-select show-search option-filter-prop="children" v-model="listQuery.group" allowClear placeholder="分组" class="search-input-item">
|
||||
<a-input class="search-input-item" @pressEnter="getNodeList" v-model="listQuery['%jpomUrl%']" placeholder="节点地址" />
|
||||
<a-select show-search option-filter-prop="children" v-model="listQuery.groupName" allowClear placeholder="分组" class="search-input-item">
|
||||
<a-select-option v-for="item in groupList" :key="item">{{ item }}</a-select-option>
|
||||
</a-select>
|
||||
<a-button :loading="loading" type="primary" @click="getNodeList">搜索</a-button>
|
||||
@ -66,7 +66,8 @@
|
||||
</template>
|
||||
<script>
|
||||
import upgrade from "@/components/upgrade";
|
||||
import { checkVersion, downloadRemote, getNodeGroupAll, getNodeList, uploadAgentFile, uploadAgentFileMerge } from "@/api/node";
|
||||
import { checkVersion, downloadRemote, uploadAgentFile, uploadAgentFileMerge } from "@/api/node";
|
||||
import { machineListData, machineListGroup, statusMap } from "@/api/system/assets-machine";
|
||||
import { mapGetters } from "vuex";
|
||||
import { CHANGE_PAGE, COMPUTED_PAGINATION, getWebSocketUrl, PAGE_DEFAULT_LIST_QUERY } from "@/utils/const";
|
||||
import { uploadPieces } from "@/utils/upload-pieces";
|
||||
@ -96,7 +97,7 @@ export default {
|
||||
columns: [
|
||||
// { title: "节点 ID", dataIndex: "id", ellipsis: true, scopedSlots: { customRender: "id" } },
|
||||
{ title: "节点名称", dataIndex: "name", ellipsis: true, scopedSlots: { customRender: "name" } },
|
||||
{ title: "节点地址", dataIndex: "url", sorter: true, key: "url", ellipsis: true, scopedSlots: { customRender: "url" } },
|
||||
{ title: "节点地址", dataIndex: "jpomUrl", sorter: true, key: "url", ellipsis: true, scopedSlots: { customRender: "url" } },
|
||||
{ title: "版本号", dataIndex: "version", width: "100px", ellipsis: true, scopedSlots: { customRender: "version" } },
|
||||
{ title: "打包时间", dataIndex: "timeStamp", width: "180px", ellipsis: true, scopedSlots: { customRender: "timeStamp" } },
|
||||
{ title: "运行时间", dataIndex: "upTimeStr", width: "180px", ellipsis: true, scopedSlots: { customRender: "upTimeStr" } },
|
||||
@ -110,6 +111,7 @@ export default {
|
||||
tableSelections: [],
|
||||
temp: {},
|
||||
percentage: 0,
|
||||
statusMap,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@ -159,7 +161,7 @@ export default {
|
||||
},
|
||||
// 获取所有的分组
|
||||
loadGroupList() {
|
||||
getNodeGroupAll().then((res) => {
|
||||
machineListGroup().then((res) => {
|
||||
if (res.data) {
|
||||
this.groupList = res.data;
|
||||
}
|
||||
@ -261,7 +263,7 @@ export default {
|
||||
},
|
||||
getNodeList() {
|
||||
this.loading = true;
|
||||
getNodeList(this.listQuery).then((res) => {
|
||||
machineListData(this.listQuery).then((res) => {
|
||||
if (res.code === 200) {
|
||||
this.list = res.data.result;
|
||||
this.listQuery.total = res.data.total;
|
||||
|
@ -122,6 +122,11 @@ const children = [
|
||||
];
|
||||
|
||||
const management = [
|
||||
{
|
||||
path: "/system/assets/machine-list",
|
||||
name: "system-machine-list",
|
||||
component: () => import("../pages/system/assets/machine/machine-list"),
|
||||
},
|
||||
{
|
||||
path: "/user/permission-group",
|
||||
name: "permission-group",
|
||||
|
@ -42,6 +42,7 @@ const routeMenuMap = {
|
||||
backup: "/system/backup",
|
||||
workspace: "/system/workspace",
|
||||
globalEnv: "/system/global-env",
|
||||
machine_node_info: "/system/assets/machine-list",
|
||||
};
|
||||
|
||||
export default routeMenuMap;
|
||||
|
Loading…
Reference in New Issue
Block a user