diff options
| author | shizhendong <[email protected]> | 2024-03-01 14:51:16 +0800 |
|---|---|---|
| committer | shizhendong <[email protected]> | 2024-03-01 14:51:16 +0800 |
| commit | 8036958d670a671a167fa7f6bcaedfdccac54fd7 (patch) | |
| tree | 8125173c84b79fe94363069e2b216f10473c120e | |
| parent | 5382c0e6f5071a52f5891830299f0bb0050bce0f (diff) | |
fix: NEZ-3413 通过执行 ssh 脚本获取设备基础信息rel-24.01.05
4 files changed, 59 insertions, 1483 deletions
diff --git a/nz-admin/src/main/java/com/nis/modules/asset/service/impl/AssetFeatureServiceImpl.java b/nz-admin/src/main/java/com/nis/modules/asset/service/impl/AssetFeatureServiceImpl.java index 851368c2..67bde24e 100644 --- a/nz-admin/src/main/java/com/nis/modules/asset/service/impl/AssetFeatureServiceImpl.java +++ b/nz-admin/src/main/java/com/nis/modules/asset/service/impl/AssetFeatureServiceImpl.java @@ -1,20 +1,15 @@ package com.nis.modules.asset.service.impl; -import cn.hutool.core.io.IoUtil; import cn.hutool.core.lang.Opt; import cn.hutool.core.lang.Validator; -import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; -import cn.hutool.extra.ssh.ChannelType; -import cn.hutool.extra.ssh.JschUtil; import cn.hutool.log.Log; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONPath; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.jcraft.jsch.ChannelExec; import com.jcraft.jsch.Session; import com.nis.common.smartvalidate.ValidateUtils; import com.nis.common.utils.RCode; @@ -30,20 +25,16 @@ import com.nis.modules.asset.service.AssetAssetService; import com.nis.modules.asset.service.AssetFeatureService; import com.nis.modules.asset.service.AssetTalonStatusService; import com.nis.modules.asset.service.TalonApiService; -import com.nis.modules.asset.util.LoacalLinuxCentralProcessor; -import com.nis.modules.asset.util.LocalLinuxNetworkIF; -import com.nis.modules.asset.util.LocalLinuxOperatingSystem; import org.apache.commons.lang3.time.StopWatch; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import oshi.hardware.CentralProcessor; -import oshi.software.os.OperatingSystem; -import oshi.util.ParseUtil; -import oshi.util.tuples.Pair; -import java.nio.charset.Charset; -import java.util.*; +import java.nio.charset.StandardCharsets; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.stream.Collectors; /** @@ -120,7 +111,7 @@ public class AssetFeatureServiceImpl extends ServiceImpl<AssetFeatureDao, AssetF log.debug("[collectAssetBasicInfo] [source=SSH] [asset: {}]", assetId); } source = "SSH"; - assetBasicInfoMap = this.collectAssetInfoWithSSH(assetId); + assetBasicInfoMap = this.collectAssetInfoWithSSH(assetId, typeConf.getSshCollectScript()); } // update @@ -169,7 +160,12 @@ public class AssetFeatureServiceImpl extends ServiceImpl<AssetFeatureDao, AssetF JSONArray diskInfoList = (JSONArray) JSONPath.eval(oshiInfo, "data.disk"); JSONArray networkIFInfoList = (JSONArray) JSONPath.eval(oshiInfo, "data.networkIF"); - Map<String, String> assetBasicInfoMap = Tool.MapUtil.builder("os", JSONObject.toJSONString(osInfo)).put("cpu", JSONObject.toJSONString(cpuInfo)).put("memory", JSONObject.toJSONString(memoryInfo)).put("disk", JSONObject.toJSONString(diskInfoList)).put("networkIF", JSONObject.toJSONString(networkIFInfoList)).build(); + Map<String, String> assetBasicInfoMap = Tool.MapUtil.builder("os", JSONObject.toJSONString(osInfo)) + .put("cpu", JSONObject.toJSONString(cpuInfo)) + .put("memory", JSONObject.toJSONString(memoryInfo)) + .put("disk", JSONObject.toJSONString(diskInfoList)) + .put("networkIF", JSONObject.toJSONString(networkIFInfoList)) + .build(); return assetBasicInfoMap; } } catch (Exception e) { @@ -200,7 +196,12 @@ public class AssetFeatureServiceImpl extends ServiceImpl<AssetFeatureDao, AssetF List<Map<String, Object>> diskInfoList = this.buildDiskInfoWithNode(assetId); List<Map<String, Object>> networkIFInfoList = this.buildNetworkIFInfoWithNode(assetId); - Map<String, String> assetBasicInfoMap = Tool.MapUtil.builder("os", JSONObject.toJSONString(osInfoMap)).put("cpu", JSONObject.toJSONString(cpuInfoMap)).put("memory", JSONObject.toJSONString(memoryInfoMap)).put("disk", JSONObject.toJSONString(diskInfoList)).put("networkIF", JSONObject.toJSONString(networkIFInfoList)).build(); + Map<String, String> assetBasicInfoMap = Tool.MapUtil.builder("os", JSONObject.toJSONString(osInfoMap)) + .put("cpu", JSONObject.toJSONString(cpuInfoMap)) + .put("memory", JSONObject.toJSONString(memoryInfoMap)) + .put("disk", JSONObject.toJSONString(diskInfoList)) + .put("networkIF", JSONObject.toJSONString(networkIFInfoList)) + .build(); return assetBasicInfoMap; } catch (Exception e) { log.error(e, "[collectAssetInfoWithNode] [error] [assetId: {}]", assetId); @@ -217,9 +218,10 @@ public class AssetFeatureServiceImpl extends ServiceImpl<AssetFeatureDao, AssetF * collect asset info with ssh * * @param assetId + * @param sshCollectScript * @return */ - public Map<String, String> collectAssetInfoWithSSH(Integer assetId) { + public Map<String, String> collectAssetInfoWithSSH(Integer assetId, String sshCollectScript) { StopWatch sw = new StopWatch(); sw.start(); Session session = null; @@ -227,14 +229,45 @@ public class AssetFeatureServiceImpl extends ServiceImpl<AssetFeatureDao, AssetF AssetAsset asset = assetService.getBaseMapper().selectById(assetId); session = SshUtil.getSshConnection(asset); - Map<String, Object> osInfoMap = this.buildOsInfoWithSSH(session, assetId); - Map<String, Object> cpuInfoMap = this.buildCpuInfoWithSSH(session, assetId); - Map<String, Object> memoryInfoMap = this.buildMemoryInfoWithSSH(session, assetId); - List<Map<String, Object>> diskInfoList = this.buildDiskInfoWithSSH(session, assetId); - List<Map<String, Object>> networkIFInfoList = this.buildNetworkIFInfoWithSSH(session, assetId); - - Map<String, String> assetBasicInfoMap = Tool.MapUtil.builder("os", JSONObject.toJSONString(osInfoMap)).put("cpu", JSONObject.toJSONString(cpuInfoMap)).put("memory", JSONObject.toJSONString(memoryInfoMap)).put("disk", JSONObject.toJSONString(diskInfoList)).put("networkIF", JSONObject.toJSONString(networkIFInfoList)).build(); - return assetBasicInfoMap; + if (StrUtil.isNotEmpty(sshCollectScript)) { + String cmd = """ + cat > /tmp/device_info_collector.sh << "EOF" + + """; + cmd += sshCollectScript; + String cmdEnd = """ + + EOF + """; + cmd += cmdEnd; + // 写入 + Tool.JschUtil.exec(session, cmd, StandardCharsets.UTF_8); + // 执行 + String result = Tool.JschUtil.exec(session, + "chmod +x /tmp/device_info_collector.sh && /tmp/device_info_collector.sh", + StandardCharsets.UTF_8); + result = StrUtil.nullToDefault(result, ""); + log.info("[collectAssetInfoWithSSH] [script execution result] [size: {}]", result.length()); + if (StrUtil.isNotEmpty(result)) { + JSONObject jsonObject = JSONObject.parseObject(result); + JSONObject osInfo = (JSONObject) JSONPath.eval(jsonObject, "os"); + JSONObject cpuInfo = (JSONObject) JSONPath.eval(jsonObject, "cpu"); + JSONObject memoryInfo = (JSONObject) JSONPath.eval(jsonObject, "memory"); + JSONArray diskInfoList = (JSONArray) JSONPath.eval(jsonObject, "disk"); + JSONArray networkIFInfoList = (JSONArray) JSONPath.eval(jsonObject, "networkIF"); + + Map<String, String> assetBasicInfoMap = Tool.MapUtil.builder("os", JSONObject.toJSONString(osInfo)) + .put("cpu", JSONObject.toJSONString(cpuInfo)) + .put("memory", JSONObject.toJSONString(memoryInfo)) + .put("disk", JSONObject.toJSONString(diskInfoList)) + .put("networkIF", JSONObject.toJSONString(networkIFInfoList)) + .build(); + return assetBasicInfoMap; + } + } else { + log.warn("[collectAssetInfoWithSSH] [ssh_collect_script is empty] [asset: {}]", assetId); + } + return Tool.MapUtil.empty(); } catch (Exception e) { log.error(e, "[collectAssetInfoWithSSH] [error] [asset: {}]", assetId); } finally { @@ -527,266 +560,4 @@ public class AssetFeatureServiceImpl extends ServiceImpl<AssetFeatureDao, AssetF } return Tool.ListUtil.empty(); } - - - /** - * build os info with SSH - * - * @param session - * @param assetId - * @return - */ - private Map<String, Object> buildOsInfoWithSSH(Session session, Integer assetId) { - try { - Map<String, Object> os = Tool.MapUtil.newHashMap(); - os.put("platform", "Linux"); - - String machine = JschUtil.exec(session, "uname -m", Charset.forName("UTF-8")); - os.put("bitness", StrUtil.contains(machine, "64") ? 64 : 32); - - String hostname = JschUtil.exec(session, "uname -n", Charset.forName("UTF-8")); - os.put("hostname", StrUtil.trim(hostname)); - - String manufacturer = JschUtil.exec(session, "uname -o", Charset.forName("UTF-8")); - os.put("manufacturer", StrUtil.trim(manufacturer)); - - LocalLinuxOperatingSystem localLinuxOperatingSystem = new LocalLinuxOperatingSystem(session); - Pair<String, OperatingSystem.OSVersionInfo> triplet = localLinuxOperatingSystem.queryFamilyVersionInfo(); - - String family = localLinuxOperatingSystem.getFamily(triplet); - os.put("family", StrUtil.trim(family)); - - OperatingSystem.OSVersionInfo versionInfo = localLinuxOperatingSystem.getVersionInfo(triplet); - os.put("versionInfo", versionInfo.toString()); - - LocalLinuxOperatingSystem.LocalLinuxNetworkParams localLinuxNetworkParams = new LocalLinuxOperatingSystem.LocalLinuxNetworkParams(); - String ipv4DefaultGateway = localLinuxNetworkParams.getIpv4DefaultGateway(); - String ipv6DefaultGateway = localLinuxNetworkParams.getIpv6DefaultGateway(); - os.put("ipv4DefaultGateway", ipv4DefaultGateway); - os.put("ipv6DefaultGateway", ipv6DefaultGateway); - return os; - } catch (Exception e) { - log.error(e, "[buildOsInfoWithSSH] [error] [assetId: {}]", assetId); - } - return Tool.MapUtil.empty(); - } - - - /** - * build cpu info with SSH - * - * @param session - * @param assetId - * @return - */ - private Map<String, Object> buildCpuInfoWithSSH(Session session, Integer assetId) { - try { - Map<String, Object> cpu = Tool.MapUtil.newHashMap(); - LoacalLinuxCentralProcessor processor = new LoacalLinuxCentralProcessor(session); - - cpu.put("physicalPackageCount", processor.getPhysicalPackageCount()); - cpu.put("physicalProcessorCount", processor.getPhysicalProcessorCount()); - cpu.put("logicalProcessorCount", processor.getLogicalProcessorCount()); - cpu.put("contextSwitches", processor.getContextSwitches()); - cpu.put("interrupts", processor.getInterrupts()); - - CentralProcessor.ProcessorIdentifier processorIdentifier = processor.queryProcessorId(); - cpu.put("family", processorIdentifier.getFamily()); - cpu.put("identifier", processorIdentifier.getIdentifier()); - cpu.put("microarchitecture", processorIdentifier.getMicroarchitecture()); - cpu.put("model", processorIdentifier.getModel()); - cpu.put("name", processorIdentifier.getName()); - cpu.put("vendor", processorIdentifier.getVendor()); - cpu.put("stepping", processorIdentifier.getStepping()); - cpu.put("cpu64bit", processorIdentifier.isCpu64bit()); - return cpu; - } catch (Exception e) { - log.error(e, "[buildCpuInfoWithSSH] [error] [assetId: {}]", assetId); - } - return Tool.MapUtil.empty(); - } - - /** - * build memory info with SSH - * - * @param session - * @param assetId - * @return - */ - private Map<String, Object> buildMemoryInfoWithSSH(Session session, Integer assetId) { - try { - Map<String, Object> memory = Tool.MapUtil.newHashMap(); - - List<String> procMemInfo = Tool.ListUtil.list(true); - ChannelExec channel = (ChannelExec) JschUtil.createChannel(session, ChannelType.EXEC); - channel.setCommand("cat /proc/meminfo"); - channel.connect(); - IoUtil.readLines(channel.getInputStream(), Charset.forName("UTF-8"), procMemInfo); - JschUtil.close(channel); - - for (String checkLine : procMemInfo) { - String[] memorySplit = ParseUtil.whitespaces.split(checkLine, 2); - if (memorySplit.length > 1) { - if (StrUtil.equals("MemTotal:", memorySplit[0])) { - long memTotal = ParseUtil.parseDecimalMemorySizeToBinary(memorySplit[1]); - memory.put("total", memTotal); - break; - } - } - } - for (String checkLine : procMemInfo) { - String[] memorySplit = ParseUtil.whitespaces.split(checkLine); - if (memorySplit.length > 1) { - if (StrUtil.equals("SwapTotal:", memorySplit[0])) { - long swapTotal = parseMeminfo(memorySplit); - memory.put("swapTotal", swapTotal); - } else if (StrUtil.equals("CommitLimit:", memorySplit[0])) { - long commitLimit = parseMeminfo(memorySplit); - memory.put("virtualMax", commitLimit); - } - } - } - return memory; - } catch (Exception e) { - log.error(e, "[buildMemoryInfoWithSSH] [error] [assetId: {}]", assetId); - } - return Tool.MapUtil.empty(); - } - - /** - * build disk info with SSH - * - * @param session - * @param assetId - * @return - */ - private List<Map<String, Object>> buildDiskInfoWithSSH(Session session, Integer assetId) { - try { - List<Map<String, Object>> disk = Tool.ListUtil.list(true); - - String sfdiskStr = JschUtil.exec(session, "sfdisk -s", Charset.forName("UTF-8")); - List<String> sfdiskList = StrUtil.split(StrUtil.emptyToDefault(StrUtil.trim(sfdiskStr), null), "\n"); - for (String item : sfdiskList) { - if (StrUtil.startWith(item, "/dev/sd")) { - Map<String, Object> tmap = Tool.MapUtil.newHashMap(); - - String[] split = item.split(":"); - String diskName = split[0]; - tmap.put("name", diskName); - - String deviceName = diskName.replaceAll("/dev/", ""); - - String sizeResult = JschUtil.exec(session, "lsblk -o NAME,SIZE -ab", Charset.forName("UTF-8")); - for (String item1 : StrUtil.split(sizeResult, "\n")) { - String[] lsblkFields = item1.split("\\s+"); - if (StrUtil.equals(deviceName, ArrayUtil.get(lsblkFields, 0))) { - tmap.put("size", ArrayUtil.get(lsblkFields, 1)); - break; - } - } - - String modelResult = JschUtil.exec(session, "lsblk -o NAME,MODEL -ab", Charset.forName("UTF-8")); - for (String item1 : StrUtil.split(modelResult, "\n")) { - String[] lsblkFields = item1.split("\\s+"); - if (StrUtil.equals(deviceName, ArrayUtil.get(lsblkFields, 0))) { - String result = Arrays.stream(lsblkFields, 1, lsblkFields.length).collect(Collectors.joining("_")); - tmap.put("model", result); - break; - } - } - - String serialResult = JschUtil.exec(session, "lsblk -o NAME,SERIAL -ab", Charset.forName("UTF-8")); - for (String item1 : StrUtil.split(serialResult, "\n")) { - String[] lsblkFields = item1.split("\\s+"); - if (StrUtil.equals(deviceName, ArrayUtil.get(lsblkFields, 0))) { - String result = Arrays.stream(lsblkFields, 1, lsblkFields.length).collect(Collectors.joining("_")); - tmap.put("serial", StrUtil.emptyToDefault(result, "unknown")); - break; - } - } - disk.add(tmap); - } - } - return disk; - } catch (Exception e) { - log.error(e, "[buildDiskInfoWithSSH] [error] [assetId: {}]", assetId); - } - return Tool.ListUtil.empty(); - } - - /** - * build NetworkIF info with SSH - * - * @param session - * @param assetId - * @return - */ - private List<Map<String, Object>> buildNetworkIFInfoWithSSH(Session session, Integer assetId) { - try { - List<Map<String, Object>> networkIFList = Tool.ListUtil.list(true); - - List<String> iFNameList = Tool.ListUtil.list(true); - ChannelExec channel = (ChannelExec) JschUtil.createChannel(session, ChannelType.EXEC); - channel.setCommand("ls /sys/class/net"); - channel.connect(); - IoUtil.readLines(channel.getInputStream(), Charset.forName("UTF-8"), iFNameList); - JschUtil.close(channel); - - for (String ifName : iFNameList) { - LocalLinuxNetworkIF networkIF = new LocalLinuxNetworkIF(session, ifName); - - Map<String, Object> networkData = Tool.MapUtil.newHashMap(); - networkData.put("index", networkIF.getIfIndex()); - networkData.put("name", networkIF.getName()); - networkData.put("ifAlias", networkIF.getIfAlias()); - networkData.put("ifType", networkIF.getIfType()); - networkData.put("speed", networkIF.getSpeed()); - networkData.put("mtu", networkIF.getMtu()); - networkData.put("ifOperStatus", StrUtil.equalsIgnoreCase("up", networkIF.getIfOperStatus()) ? 1 : 2); - networkData.put("macaddr", networkIF.getAddress()); - - String ipListStr = JschUtil.exec(session, "ifconfig " + ifName + " | grep \"inet\" | awk '{print $2}'", Charset.forName("UTF-8")); - if (StrUtil.isNotEmpty(StrUtil.trim(ipListStr))) { - List<String> ipAddressList = StrUtil.split(StrUtil.trim(ipListStr), "\n"); - Set<String> iPv4addrList = Tool.CollUtil.set(true); - Set<String> iPv6addrList = Tool.CollUtil.set(true); - - for (String address : ipAddressList) { - if (Validator.isIpv4(address)) { - iPv4addrList.add(address); - } else if (Validator.isIpv6(address)) { - iPv6addrList.add(address); - } - } - networkData.put("iPv4addr", iPv4addrList); - networkData.put("iPv6addr", iPv6addrList); - - // The Internet Protocol (IP) v4 subnet masks. - String subnetMasks = JschUtil.exec(session, "ip addr show " + ifName + " | grep \"inet\\b\" | awk '{print $2}' | cut -d '/' -f 2", Charset.forName("UTF-8")); - networkData.put("subnetMasks", StrUtil.split(StrUtil.emptyToDefault(StrUtil.trim(subnetMasks), null), "\n")); - } else { - networkData.put("iPv4addr", Tool.ListUtil.empty()); - networkData.put("iPv6addr", Tool.ListUtil.empty()); - networkData.put("subnetMasks", Tool.ListUtil.empty()); - } - networkIFList.add(networkData); - } - return networkIFList; - } catch (Exception e) { - log.error(e, "[buildNetworkIFInfoWithSSH] [error] [assetId: {}]", assetId); - } - return Tool.ListUtil.empty(); - } - - private static long parseMeminfo(String[] memorySplit) { - if (memorySplit.length < 2) { - return 0L; - } - long memory = ParseUtil.parseLongOrDefault(memorySplit[1], 0L); - if (memorySplit.length > 2 && "kB".equals(memorySplit[2])) { - memory *= 1024; - } - return memory; - } - } diff --git a/nz-admin/src/main/java/com/nis/modules/asset/util/LoacalLinuxCentralProcessor.java b/nz-admin/src/main/java/com/nis/modules/asset/util/LoacalLinuxCentralProcessor.java deleted file mode 100644 index dd9240a1..00000000 --- a/nz-admin/src/main/java/com/nis/modules/asset/util/LoacalLinuxCentralProcessor.java +++ /dev/null @@ -1,639 +0,0 @@ -/* - * Copyright 2016-2024 The OSHI Project Contributors - * SPDX-License-Identifier: MIT - */ -package com.nis.modules.asset.util; - -import cn.hutool.core.io.IoUtil; -import cn.hutool.extra.ssh.ChannelType; -import cn.hutool.extra.ssh.JschUtil; -import com.jcraft.jsch.ChannelExec; -import com.jcraft.jsch.JSchException; -import com.jcraft.jsch.Session; -import com.nis.common.utils.Tool; -import lombok.Data; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import oshi.annotation.concurrent.Immutable; -import oshi.annotation.concurrent.ThreadSafe; -import oshi.driver.linux.Lshw; -import oshi.hardware.CentralProcessor; -import oshi.util.ExecutingCommand; -import oshi.util.ParseUtil; -import oshi.util.Util; -import oshi.util.tuples.Triplet; - -import java.io.IOException; -import java.nio.charset.Charset; -import java.util.*; -import java.util.stream.Collectors; - -/** - * A CPU as defined in Linux /proc. - */ -@ThreadSafe -@Data -public class LoacalLinuxCentralProcessor { - - private static final Logger LOG = LoggerFactory.getLogger(LoacalLinuxCentralProcessor.class); - - public static final String MODEL = "/proc/device-tree/model"; - public static final String CPUINFO = "/proc/cpuinfo"; - public static final String STAT = "/proc/stat"; - - - private Session session; - - private int physicalPackageCount; - private int physicalProcessorCount; - private int logicalProcessorCount; - private List<CentralProcessor.LogicalProcessor> logicalProcessors; - private List<CentralProcessor.PhysicalProcessor> physicalProcessors; - - public LoacalLinuxCentralProcessor(Session session) { - this.session = session; - this.init(); - } - - public void init() { - Triplet<List<LogicalProcessor>, List<PhysicalProcessor>, List<ProcessorCache>> processorLists = this.initProcessorCounts(); - this.logicalProcessors = Collections.unmodifiableList((List) processorLists.getA()); - if (processorLists.getB() == null) { - Set<Integer> pkgCoreKeys = (Set) this.logicalProcessors.stream().map((p) -> { - return (p.getPhysicalPackageNumber() << 16) + p.getPhysicalProcessorNumber(); - }).collect(Collectors.toSet()); - List<CentralProcessor.PhysicalProcessor> physProcs = (List) pkgCoreKeys.stream().sorted().map((k) -> { - return new CentralProcessor.PhysicalProcessor(k >> 16, k & '\uffff'); - }).collect(Collectors.toList()); - this.physicalProcessors = Collections.unmodifiableList(physProcs); - } else { - this.physicalProcessors = Collections.unmodifiableList((List) processorLists.getB()); - } - - Set<Integer> physPkgs = new HashSet(); - Iterator var7 = this.logicalProcessors.iterator(); - - while (var7.hasNext()) { - LogicalProcessor logProc = (LogicalProcessor) var7.next(); - int pkg = logProc.getPhysicalPackageNumber(); - physPkgs.add(pkg); - } - - this.logicalProcessorCount = this.logicalProcessors.size(); - this.physicalProcessorCount = this.physicalProcessors.size(); - this.physicalPackageCount = physPkgs.size(); - } - - protected Triplet<List<LogicalProcessor>, List<PhysicalProcessor>, List<ProcessorCache>> initProcessorCounts() { - // Attempt to read from sysfs - Triplet<List<LogicalProcessor>, Map<Integer, Integer>, Map<Integer, String>> topology = readTopologyFromSysfs(); - // This sometimes fails so fall back to CPUID - if (topology.getA().isEmpty()) { - topology = this.readTopologyFromCpuinfo(); - } - List<LogicalProcessor> logProcs = topology.getA(); - Map<Integer, Integer> coreEfficiencyMap = topology.getB(); - Map<Integer, String> modAliasMap = topology.getC(); - // Failsafe - if (logProcs.isEmpty()) { - logProcs.add(new LogicalProcessor(0, 0, 0)); - } - if (coreEfficiencyMap.isEmpty()) { - coreEfficiencyMap.put(0, 0); - } - // Sort - logProcs.sort(Comparator.comparingInt(LogicalProcessor::getProcessorNumber)); - - List<PhysicalProcessor> physProcs = coreEfficiencyMap.entrySet().stream().sorted(Map.Entry.comparingByKey()) - .map(e -> { - int pkgId = e.getKey() >> 16; - int coreId = e.getKey() & 0xffff; - return new PhysicalProcessor(pkgId, coreId, e.getValue(), modAliasMap.getOrDefault(e.getKey(), "")); - }).collect(Collectors.toList()); - - return new Triplet<>(logProcs, physProcs, null); - } - - private Triplet<List<LogicalProcessor>, Map<Integer, Integer>, Map<Integer, String>> readTopologyFromSysfs() { - List<LogicalProcessor> logProcs = new ArrayList<>(); - Map<Integer, Integer> coreEfficiencyMap = new HashMap<>(); - Map<Integer, String> modAliasMap = new HashMap<>(); - String cpuPath = "/sys/devices/system/cpu/"; - try { - List<String> cpuFiles = this.runRemoteCommand("ls -d /sys/devices/system/cpu/cpu[0-9]*"); - cpuFiles.forEach(cpu -> { - String syspath = cpu.toString(); // /sys/devices/system/cpu/cpuX - Map<String, String> uevent = this.getKeyValueMapFromFile(syspath + "/uevent", "="); - String modAlias = uevent.get("MODALIAS"); - // updates caches as a side-effect - logProcs.add( - getLogicalProcessorFromSyspath(syspath, modAlias, coreEfficiencyMap, modAliasMap)); - }); - } catch (Exception e) { - e.printStackTrace(); - // No udev and no cpu info in sysfs? Bad. - LOG.warn("Unable to find CPU information in sysfs at path {}", cpuPath); - } - return new Triplet<>(logProcs, coreEfficiencyMap, modAliasMap); - } - - private LogicalProcessor getLogicalProcessorFromSyspath(String syspath, String modAlias, Map<Integer, Integer> coreEfficiencyMap, Map<Integer, String> modAliasMap) { - int processor = ParseUtil.getFirstIntValue(syspath); - int coreId = this.getIntFromFile(syspath + "/topology/core_id"); - int pkgId = this.getIntFromFile(syspath + "/topology/physical_package_id"); - int pkgCoreKey = (pkgId << 16) + coreId; - // The cpu_capacity value may not exist, this will just store 0 - coreEfficiencyMap.put(pkgCoreKey, this.getIntFromFile(syspath + "/cpu_capacity")); - if (!Util.isBlank(modAlias)) { - modAliasMap.put(pkgCoreKey, modAlias); - } - int nodeId = 0; - // final String nodePrefix = syspath + "/node"; - // try (Stream<Path> path = Files.list(Paths.get(syspath))) { - // Optional<Path> first = path.filter(p -> p.toString().startsWith(nodePrefix)).findFirst(); - // if (first.isPresent()) { - // nodeId = ParseUtil.getFirstIntValue(first.get().getFileName().toString()); - // } - // } catch (IOException e) { - // // ignore - // } - return new LogicalProcessor(processor, coreId, pkgId, nodeId); - } - - private Triplet<List<LogicalProcessor>, Map<Integer, Integer>, Map<Integer, String>> readTopologyFromCpuinfo() { - List<LogicalProcessor> logProcs = new ArrayList<>(); - Map<Integer, Integer> numaNodeMap = mapNumaNodesFromLscpu(); - Map<Integer, Integer> coreEfficiencyMap = new HashMap<>(); - - List<String> procCpu = this.readRemoteFile(CPUINFO); - int currentProcessor = 0; - int currentCore = 0; - int currentPackage = 0; - - boolean first = true; - for (String cpu : procCpu) { - // Count logical processors - if (cpu.startsWith("processor")) { - if (first) { - first = false; - } else { - // add from the previous iteration - logProcs.add(new LogicalProcessor(currentProcessor, currentCore, currentPackage, - numaNodeMap.getOrDefault(currentProcessor, 0))); - // Count unique combinations of core id and physical id. - coreEfficiencyMap.put((currentPackage << 16) + currentCore, 0); - } - // start creating for this iteration - currentProcessor = ParseUtil.parseLastInt(cpu, 0); - } else if (cpu.startsWith("core id") || cpu.startsWith("cpu number")) { - currentCore = ParseUtil.parseLastInt(cpu, 0); - } else if (cpu.startsWith("physical id")) { - currentPackage = ParseUtil.parseLastInt(cpu, 0); - } - } - logProcs.add(new LogicalProcessor(currentProcessor, currentCore, currentPackage, - numaNodeMap.getOrDefault(currentProcessor, 0))); - coreEfficiencyMap.put((currentPackage << 16) + currentCore, 0); - return new Triplet<>(logProcs, coreEfficiencyMap, Collections.emptyMap()); - } - - public long getContextSwitches() { - List<String> procStat = this.readRemoteFile(STAT); - Iterator var1 = procStat.iterator(); - - while (var1.hasNext()) { - String stat = (String) var1.next(); - if (stat.startsWith("ctxt ")) { - String[] ctxtArr = ParseUtil.whitespaces.split(stat); - if (ctxtArr.length == 2) { - return ParseUtil.parseLongOrDefault(ctxtArr[1], 0L); - } - } - } - return 0L; - } - - public long getInterrupts() { - List<String> procStat = this.readRemoteFile(STAT); - Iterator var1 = procStat.iterator(); - - while (var1.hasNext()) { - String stat = (String) var1.next(); - if (stat.startsWith("intr ")) { - String[] intrArr = ParseUtil.whitespaces.split(stat); - if (intrArr.length > 2) { - return ParseUtil.parseLongOrDefault(intrArr[1], 0L); - } - } - } - return 0L; - } - - public CentralProcessor.ProcessorIdentifier queryProcessorId() { - String cpuVendor = ""; - String cpuName = ""; - String cpuFamily = ""; - String cpuModel = ""; - String cpuStepping = ""; - long cpuFreq = 0L; - boolean cpu64bit = false; - StringBuilder armStepping = new StringBuilder(); - String[] flags = new String[0]; - List<String> cpuInfo = this.readRemoteFile(CPUINFO); - Iterator var13 = cpuInfo.iterator(); - - while (true) { - label111: - while (var13.hasNext()) { - String line = (String) var13.next(); - String[] splitLine = ParseUtil.whitespacesColonWhitespace.split(line); - if (splitLine.length < 2) { - if (line.startsWith("CPU architecture: ")) { - cpuFamily = line.replace("CPU architecture: ", "").trim(); - } - } else { - switch (splitLine[0]) { - case "vendor_id": - case "CPU implementer": - cpuVendor = splitLine[1]; - break; - case "model name": - case "Processor": - cpuName = splitLine[1]; - break; - case "flags": - flags = splitLine[1].toLowerCase().split(" "); - String[] var18 = flags; - int var19 = flags.length; - int var20 = 0; - - while (true) { - if (var20 >= var19) { - continue label111; - } - - String flag = var18[var20]; - if ("lm".equals(flag)) { - cpu64bit = true; - continue label111; - } - - ++var20; - } - case "stepping": - cpuStepping = splitLine[1]; - break; - case "CPU variant": - if (!armStepping.toString().startsWith("r")) { - armStepping.insert(0, "r" + splitLine[1]); - } - break; - case "CPU revision": - if (!armStepping.toString().contains("p")) { - armStepping.append('p').append(splitLine[1]); - } - break; - case "model": - case "CPU part": - cpuModel = splitLine[1]; - break; - case "cpu family": - cpuFamily = splitLine[1]; - break; - case "cpu MHz": - cpuFreq = ParseUtil.parseHertz(splitLine[1]); - } - } - } - - if (cpuName.contains("Hz")) { - cpuFreq = -1L; - } else { - long cpuCapacity = Lshw.queryCpuCapacity(); - if (cpuCapacity > cpuFreq) { - cpuFreq = cpuCapacity; - } - } - - if (cpuStepping.isEmpty()) { - cpuStepping = armStepping.toString(); - } - - String processorID = ""; -// if (cpuVendor.startsWith("0x")) { -// List<String> lscpu = ExecutingCommand.runNative("lscpu"); -// Iterator var24 = lscpu.iterator(); -// -// while(var24.hasNext()) { -// String line = (String)var24.next(); -// if (line.startsWith("Architecture:")) { -// cpuVendor = line.replace("Architecture:", "").trim(); -// } -// } -// } - return new CentralProcessor.ProcessorIdentifier(cpuVendor, cpuName, cpuFamily, cpuModel, cpuStepping, processorID, cpu64bit, cpuFreq); - } - } - - - private static Map<Integer, Integer> mapNumaNodesFromLscpu() { - Map<Integer, Integer> numaNodeMap = new HashMap<>(); - // Get numa node info from lscpu - List<String> lscpu = ExecutingCommand.runNative("lscpu -p=cpu,node"); - // Format: - // # comment lines starting with # - // # then comma-delimited cpu,node - // 0,0 - // 1,0 - for (String line : lscpu) { - if (!line.startsWith("#")) { - int pos = line.indexOf(','); - if (pos > 0 && pos < line.length()) { - numaNodeMap.put(ParseUtil.parseIntOrDefault(line.substring(0, pos), 0), - ParseUtil.parseIntOrDefault(line.substring(pos + 1), 0)); - } - } - } - return numaNodeMap; - } - - public int getIntFromFile(String filename) { - try { - List<String> read = this.readRemoteFile(filename); - if (!read.isEmpty()) { - return Integer.parseInt((String) read.get(0)); - } - } catch (NumberFormatException var2) { - } - return 0; - } - - public Map<String, String> getKeyValueMapFromFile(String filename, String separator) { - Map<String, String> map = new HashMap(); - - List<String> lines = this.readRemoteFile(filename); - Iterator var4 = lines.iterator(); - - while (var4.hasNext()) { - String line = (String) var4.next(); - String[] parts = line.split(separator); - if (parts.length == 2) { - map.put(parts[0], parts[1].trim()); - } - } - return map; - } - - public List<String> readRemoteFile(String filename) { - List<String> list = Tool.ListUtil.list(true); - try { - ChannelExec channel = (ChannelExec) JschUtil.createChannel(session, ChannelType.EXEC); - channel.setCommand("cat " + filename); - channel.connect(); - - IoUtil.readLines(channel.getInputStream(), Charset.forName("UTF-8"), list); - JschUtil.close(channel); - } catch (JSchException | IOException e) { - } - return list; - } - - public List<String> runRemoteCommand(String cmdToRun) { - List<String> list = Tool.ListUtil.list(true); - try { - ChannelExec channel = (ChannelExec) JschUtil.createChannel(session, ChannelType.EXEC); - channel.setCommand(cmdToRun); - channel.connect(); - - IoUtil.readLines(channel.getInputStream(), Charset.forName("UTF-8"), list); - JschUtil.close(channel); - } catch (JSchException | IOException e) { - } - return list; - } - - - @Immutable - class PhysicalProcessor { - private final int physicalPackageNumber; - private final int physicalProcessorNumber; - private final int efficiency; - private final String idString; - - public PhysicalProcessor(int physicalPackageNumber, int physicalProcessorNumber) { - this(physicalPackageNumber, physicalProcessorNumber, 0, ""); - } - - public PhysicalProcessor(int physicalPackageNumber, int physicalProcessorNumber, int efficiency, - String idString) { - this.physicalPackageNumber = physicalPackageNumber; - this.physicalProcessorNumber = physicalProcessorNumber; - this.efficiency = efficiency; - this.idString = idString; - } - - /** - * Gets a platform specific measure of processor performance vs. efficiency, useful for identifying cores in - * hybrid/System on Chip (SoC) processors such as ARM's big.LITTLE architecture, Apple's M1, and Intel's P-core - * and E-core hybrid technology. A core with a higher value for the efficiency class has intrinsically greater - * performance and less efficiency than a core with a lower value for the efficiency class. - * - * @return On Windows 10 and higher, returns the {@code EfficiencyClass} value from the - * {@code PROCESSOR_RELATIONSHIP} structure. - * <p> - * On macOS with Apple Silicon, emulates the same relative efficiency class values as Windows. - * <p> - * On Linux, returns the {@code cpu_capacity} value from sysfs. This is an optional cpu node property - * representing CPU capacity expressed in normalized DMIPS/MHz. - * <p> - * On OpenBSD, FreeBSD, and Solaris with ARM big.LITTLE processors, emulates the same relative - * efficiency class values as Windows. - * <p> - * For unimplemented operating systems or architectures, returns 0. - * @see <a href= - * "https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-processor_relationship">PROCESSOR_RELATIONSHIP</a> - * @see <a href= - * "https://www.kernel.org/doc/Documentation/devicetree/bindings/arm/cpu-capacity.txt">cpu-capacity</a> - */ - public int getEfficiency() { - return efficiency; - } - - /** - * Gets a platform specific identification string representing this core. This string requires user parsing to - * obtain meaningful information. As this is an experimental feature, users should not rely on the format. - * - * @return On Windows, returns the per-core Processor ID (CPUID). - * <p> - * On macOS, returns a compatibility string from the IO Registry identifying hybrid cores. - * <p> - * On Linux, returns the {@code MODALIAS} value for the core's driver. - * <p> - * On OpenBSD, FreeBSD, and Solaris, returns a per-core CPU identification string. - * <p> - * For unimplemented operating systems, returns an empty string. - */ - public String getIdString() { - return idString; - } - - @Override - public String toString() { - return "PhysicalProcessor [package/core=" + physicalPackageNumber + "/" + physicalProcessorNumber - + ", efficiency=" + efficiency + ", idString=" + idString + "]"; - } - } - - @Immutable - class ProcessorCache { - - /** - * The type of cache. - */ - public enum Type { - UNIFIED, INSTRUCTION, DATA, TRACE; - - @Override - public String toString() { - return name().substring(0, 1) + name().substring(1).toLowerCase(Locale.ROOT); - } - } - - private final byte level; - private final byte associativity; - private final short lineSize; - private final int cacheSize; - private final Type type; - - public ProcessorCache(byte level, byte associativity, short lineSize, int cacheSize, Type type) { - this.level = level; - this.associativity = associativity; - this.lineSize = lineSize; - this.cacheSize = cacheSize; - this.type = type; - } - - public ProcessorCache(int level, int associativity, int lineSize, long cacheSize, Type type) { - this((byte) level, (byte) associativity, (short) lineSize, (int) cacheSize, type); - } - - /** - * The cache level. This member can be 1 (L1), 2 (L2), 3 (L3), or 4 (L4). - * - * @return the level - */ - public byte getLevel() { - return level; - } - - /** - * The cache associativity. If this member is {@code 0xFF}, the cache is fully associative. - * - * @return the associativity - */ - public byte getAssociativity() { - return associativity; - } - - /** - * The cache line size, in bytes. - * - * @return the line size - */ - public short getLineSize() { - return lineSize; - } - - /** - * The cache size, in bytes. - * - * @return the cache size - */ - public int getCacheSize() { - return cacheSize; - } - - /** - * The cache type. - * - * @return the type - */ - public Type getType() { - return type; - } - - @Override - public String toString() { - return "ProcessorCache [L" + level + " " + type + ", cacheSize=" + cacheSize + ", " - + (associativity > 0 ? associativity + "-way" : "unknown") + " associativity, lineSize=" + lineSize - + "]"; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null || !(obj instanceof ProcessorCache)) { - return false; - } - ProcessorCache other = (ProcessorCache) obj; - return associativity == other.associativity && cacheSize == other.cacheSize && level == other.level - && lineSize == other.lineSize && type == other.type; - } - - @Override - public int hashCode() { - return Objects.hash(associativity, cacheSize, level, lineSize, type); - } - } - - - class LogicalProcessor { - private final int processorNumber; - private final int physicalProcessorNumber; - private final int physicalPackageNumber; - private final int numaNode; - private final int processorGroup; - - public LogicalProcessor(int processorNumber, int physicalProcessorNumber, int physicalPackageNumber) { - this(processorNumber, physicalProcessorNumber, physicalPackageNumber, 0, 0); - } - - public LogicalProcessor(int processorNumber, int physicalProcessorNumber, int physicalPackageNumber, int numaNode) { - this(processorNumber, physicalProcessorNumber, physicalPackageNumber, numaNode, 0); - } - - public LogicalProcessor(int processorNumber, int physicalProcessorNumber, int physicalPackageNumber, int numaNode, int processorGroup) { - this.processorNumber = processorNumber; - this.physicalProcessorNumber = physicalProcessorNumber; - this.physicalPackageNumber = physicalPackageNumber; - this.numaNode = numaNode; - this.processorGroup = processorGroup; - } - - public int getProcessorNumber() { - return this.processorNumber; - } - - public int getPhysicalProcessorNumber() { - return this.physicalProcessorNumber; - } - - public int getPhysicalPackageNumber() { - return this.physicalPackageNumber; - } - - public int getNumaNode() { - return this.numaNode; - } - - public int getProcessorGroup() { - return this.processorGroup; - } - - public String toString() { - return "LogicalProcessor [processorNumber=" + this.processorNumber + ", coreNumber=" + this.physicalProcessorNumber + ", packageNumber=" + this.physicalPackageNumber + ", numaNode=" + this.numaNode + ", processorGroup=" + this.processorGroup + "]"; - } - } -} diff --git a/nz-admin/src/main/java/com/nis/modules/asset/util/LocalLinuxNetworkIF.java b/nz-admin/src/main/java/com/nis/modules/asset/util/LocalLinuxNetworkIF.java deleted file mode 100644 index 531b6ace..00000000 --- a/nz-admin/src/main/java/com/nis/modules/asset/util/LocalLinuxNetworkIF.java +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright 2020-2023 The OSHI Project Contributors - * SPDX-License-Identifier: MIT - */ -package com.nis.modules.asset.util; - - -import cn.hutool.core.io.IoUtil; -import cn.hutool.extra.ssh.ChannelType; -import cn.hutool.extra.ssh.JschUtil; -import com.jcraft.jsch.ChannelExec; -import com.jcraft.jsch.JSchException; -import com.jcraft.jsch.Session; -import com.nis.common.utils.Tool; -import lombok.Data; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import oshi.annotation.concurrent.ThreadSafe; -import oshi.util.ParseUtil; -import oshi.util.Util; - -import java.io.IOException; -import java.nio.charset.Charset; -import java.util.*; - -/** - * LinuxNetworks class. - */ -@ThreadSafe -@Data -public final class LocalLinuxNetworkIF { - - private static final Logger LOG = LoggerFactory.getLogger(LocalLinuxNetworkIF.class); - - private String name; - private int ifType; - private int ifIndex; - private long mtu; - private long speed; - private String address; - private String ifAlias = ""; - private String ifOperStatus = "unknown"; - - private static Session session; - - public LocalLinuxNetworkIF(Session session, String ifName) { - this.session = session; - this.name = this.queryIfModelFromSysfs(ifName); - this.updateAttributes(); - } - - private String queryIfModelFromSysfs(String name) { - Map<String, String> uevent = this.getKeyValueMapFromFile("/sys/class/net/" + name + "/uevent", "="); - String devVendor = uevent.get("ID_VENDOR_FROM_DATABASE"); - String devModel = uevent.get("ID_MODEL_FROM_DATABASE"); - if (!Util.isBlank(devModel)) { - if (!Util.isBlank(devVendor)) { - return devVendor + " " + devModel; - } - return devModel; - } - return name; - } - - public boolean updateAttributes() { - String fileName = String.format(Locale.ROOT, "/sys/class/net/%s/statistics", getName()); - String ifDir = JschUtil.exec(session, "stat -c %F " + fileName, Charset.forName("UTF-8")); - if (!Tool.StrUtil.equalsAnyIgnoreCase("directory", Tool.StrUtil.trim(ifDir))) { - return false; - } - - String ifTypePath = String.format(Locale.ROOT, "/sys/class/net/%s/type", getName()); - String ifIndexPath = String.format(Locale.ROOT, "/sys/class/net/%s/ifindex", getName()); - String mtuPath = String.format(Locale.ROOT, "/sys/class/net/%s/mtu", getName()); - String addressPath = String.format(Locale.ROOT, "/sys/class/net/%s/address", getName()); - - String ifSpeed = String.format(Locale.ROOT, "/sys/class/net/%s/speed", getName()); - String ifAliasPath = String.format(Locale.ROOT, "/sys/class/net/%s/ifalias", getName()); - String ifOperStatusPath = String.format(Locale.ROOT, "/sys/class/net/%s/operstate", getName()); - - this.ifType = this.getIntFromFile(ifTypePath); - this.ifIndex = this.getIntFromFile(ifIndexPath); - this.mtu = this.getUnsignedLongFromFile(mtuPath); - long speedMiB = this.getUnsignedLongFromFile(ifSpeed); - // speed may be -1 from file. - this.speed = speedMiB < 0 ? 0 : speedMiB << 20; - this.address = this.getStringFromFile(addressPath); - this.ifAlias = this.getStringFromFile(ifAliasPath); - this.ifOperStatus = this.getStringFromFile(ifOperStatusPath); - return true; - } - - public int getIntFromFile(String filename) { - try { - List<String> read = this.readRemoteFile(filename); - if (!read.isEmpty()) { - return Integer.parseInt((String) read.get(0)); - } - } catch (NumberFormatException var2) { - } - return 0; - } - - public long getUnsignedLongFromFile(String filename) { - List<String> read = this.readRemoteFile(filename); - if (!read.isEmpty()) { - return ParseUtil.parseUnsignedLongOrDefault((String) read.get(0), 0L); - } else { - return 0L; - } - } - - public String getStringFromFile(String filename) { - List<String> read = this.readRemoteFile(filename); - if (!read.isEmpty()) { - return (String) read.get(0); - } else { - return ""; - } - } - - public Map<String, String> getKeyValueMapFromFile(String filename, String separator) { - Map<String, String> map = new HashMap(); - - List<String> lines = this.readRemoteFile(filename); - Iterator var4 = lines.iterator(); - - while (var4.hasNext()) { - String line = (String) var4.next(); - String[] parts = line.split(separator); - if (parts.length == 2) { - map.put(parts[0], parts[1].trim()); - } - } - return map; - } - - public List<String> readRemoteFile(String filename) { - List<String> list = Tool.ListUtil.list(true); - try { - ChannelExec channel = (ChannelExec) JschUtil.createChannel(session, ChannelType.EXEC); - channel.setCommand("cat " + filename); - channel.connect(); - - IoUtil.readLines(channel.getInputStream(), Charset.forName("UTF-8"), list); - JschUtil.close(channel); - } catch (JSchException | IOException e) { - } - return list; - } - - enum IfOperStatus { - /** - * Up and operational. Ready to pass packets. - */ - UP(1), - /** - * Down and not operational. Not ready to pass packets. - */ - DOWN(2), - /** - * In some test mode. - */ - TESTING(3), - /** - * The interface status is unknown. - */ - UNKNOWN(4), - /** - * The interface is not up, but is in a pending state, waiting for some external event. - */ - DORMANT(5), - /** - * Some component is missing - */ - NOT_PRESENT(6), - /** - * Down due to state of lower-layer interface(s). - */ - LOWER_LAYER_DOWN(7); - - private final int value; - - IfOperStatus(int value) { - this.value = value; - } - - /** - * @return the integer value specified in RFC 2863 for this operational status. - */ - public int getValue() { - return this.value; - } - } -} diff --git a/nz-admin/src/main/java/com/nis/modules/asset/util/LocalLinuxOperatingSystem.java b/nz-admin/src/main/java/com/nis/modules/asset/util/LocalLinuxOperatingSystem.java deleted file mode 100644 index 05619a09..00000000 --- a/nz-admin/src/main/java/com/nis/modules/asset/util/LocalLinuxOperatingSystem.java +++ /dev/null @@ -1,361 +0,0 @@ -// -// Source code recreated from a .class file by IntelliJ IDEA -// (powered by FernFlower decompiler) -// - -package com.nis.modules.asset.util; - -import cn.hutool.core.io.IoUtil; -import cn.hutool.extra.ssh.ChannelType; -import cn.hutool.extra.ssh.JschUtil; -import com.jcraft.jsch.ChannelExec; -import com.jcraft.jsch.JSchException; -import com.jcraft.jsch.Session; -import com.nis.common.utils.Tool; -import oshi.annotation.concurrent.ThreadSafe; -import oshi.software.common.AbstractOperatingSystem; -import oshi.software.os.FileSystem; -import oshi.software.os.InternetProtocolStats; -import oshi.software.os.NetworkParams; -import oshi.software.os.OSProcess; -import oshi.util.Constants; -import oshi.util.ParseUtil; -import oshi.util.tuples.Pair; -import oshi.util.tuples.Triplet; - -import java.io.IOException; -import java.nio.charset.Charset; -import java.util.List; - -@ThreadSafe -public class LocalLinuxOperatingSystem extends AbstractOperatingSystem { - - private static final String RELEASE_DELIM = " release "; - private static final String DOUBLE_QUOTES = "(?:^\")|(?:\"$)"; - - private static Session session; - - public LocalLinuxOperatingSystem(Session session) { - this.session = session; - } - - @Override - protected String queryManufacturer() { - return null; - } - - public String getFamily(Pair<String, OSVersionInfo> pair) { - return pair.getA(); - } - - public OSVersionInfo getVersionInfo(Pair<String, OSVersionInfo> pair) { - return pair.getB(); - } - - @Override - public Pair<String, OSVersionInfo> queryFamilyVersionInfo() { - Triplet<String, String, String> familyVersionCodename = queryFamilyVersionCodenameFromReleaseFiles(); - String buildNumber = null; - List<String> procVersion = this.readRemoteFile("/proc/version"); - - if (!procVersion.isEmpty()) { - String[] split = ParseUtil.whitespaces.split(procVersion.get(0)); - for (String s : split) { - if (!"Linux".equals(s) && !"version".equals(s)) { - buildNumber = s; - break; - } - } - } - OSVersionInfo versionInfo = new OSVersionInfo(familyVersionCodename.getB(), familyVersionCodename.getC(), - buildNumber); - return new Pair<>(familyVersionCodename.getA(), versionInfo); - } - - public Triplet<String, String, String> queryFamilyVersionCodenameFromReleaseFiles() { - Triplet<String, String, String> familyVersionCodename; - // There are two competing options for family/version information. - // Newer systems are adopting a standard /etc/os-release file: - // https://www.freedesktop.org/software/systemd/man/os-release.html - // - // Some systems are still using the lsb standard which parses a - // variety of /etc/*-release files and is most easily accessed via - // the commandline lsb_release -a, see here: - // https://linux.die.net/man/1/lsb_release - // In this case, the /etc/lsb-release file (if it exists) has - // optional overrides to the information in the /etc/distrib-release - // files, which show: "Distributor release x.x (Codename)" - - // Attempt to read /etc/system-release which has more details than - // os-release on (CentOS and Fedora) - if ((familyVersionCodename = readDistribRelease("/etc/system-release")) != null) { - // If successful, we're done. this.family has been set and - // possibly the versionID and codeName - return familyVersionCodename; - } - - // Attempt to read /etc/os-release file. - if ((familyVersionCodename = readOsRelease()) != null) { - // If successful, we're done. this.family has been set and - // possibly the versionID and codeName - return familyVersionCodename; - } - - - // The above two options should hopefully work on most - // distributions. If not, we keep having fun. - // Attempt to read /etc/lsb-release file - if ((familyVersionCodename = readLsbRelease()) != null) { - // If successful, we're done. this.family has been set and - // possibly the versionID and codeName - return familyVersionCodename; - } - - return new Triplet<>(Constants.UNKNOWN, Constants.UNKNOWN, Constants.UNKNOWN); - } - - private Triplet<String, String, String> readDistribRelease(String filename) { - List<String> osRelease = this.readRemoteFile(filename); - // Search for Distrib release x.x (Codename) - for (String line : osRelease) { - if (line.contains(RELEASE_DELIM)) { - // If this parses properly we're done - return parseRelease(line, RELEASE_DELIM); - } else if (line.contains(" VERSION ")) { - // If this parses properly we're done - return parseRelease(line, " VERSION "); - } - } - return null; - } - - private Triplet<String, String, String> readOsRelease() { - String family = null; - String versionId = Constants.UNKNOWN; - String codeName = Constants.UNKNOWN; - List<String> osRelease = this.readRemoteFile("/etc/os-release"); - // Search for NAME= - for (String line : osRelease) { - if (line.startsWith("VERSION=")) { - // remove beginning and ending '"' characters, etc from - // VERSION="14.04.4 LTS, Trusty Tahr" (Ubuntu style) - // or VERSION="17 (Beefy Miracle)" (os-release doc style) - line = line.replace("VERSION=", "").replaceAll(DOUBLE_QUOTES, "").trim(); - String[] split = line.split("[()]"); - if (split.length <= 1) { - // If no parentheses, check for Ubuntu's comma format - split = line.split(", "); - } - if (split.length > 0) { - versionId = split[0].trim(); - } - if (split.length > 1) { - codeName = split[1].trim(); - } - } else if (line.startsWith("NAME=") && family == null) { - // remove beginning and ending '"' characters, etc from - // NAME="Ubuntu" - family = line.replace("NAME=", "").replaceAll(DOUBLE_QUOTES, "").trim(); - } else if (line.startsWith("VERSION_ID=") && versionId.equals(Constants.UNKNOWN)) { - // remove beginning and ending '"' characters, etc from - // VERSION_ID="14.04" - versionId = line.replace("VERSION_ID=", "").replaceAll(DOUBLE_QUOTES, "").trim(); - } - } - return family == null ? null : new Triplet<>(family, versionId, codeName); - } - - private Triplet<String, String, String> readLsbRelease() { - String family = null; - String versionId = Constants.UNKNOWN; - String codeName = Constants.UNKNOWN; - List<String> osRelease = this.readRemoteFile("/etc/lsb-release"); - // Search for NAME= - for (String line : osRelease) { - if (line.startsWith("DISTRIB_DESCRIPTION=")) { - line = line.replace("DISTRIB_DESCRIPTION=", "").replaceAll(DOUBLE_QUOTES, "").trim(); - if (line.contains(RELEASE_DELIM)) { - Triplet<String, String, String> triplet = parseRelease(line, RELEASE_DELIM); - family = triplet.getA(); - if (versionId.equals(Constants.UNKNOWN)) { - versionId = triplet.getB(); - } - if (codeName.equals(Constants.UNKNOWN)) { - codeName = triplet.getC(); - } - } - } else if (line.startsWith("DISTRIB_ID=") && family == null) { - family = line.replace("DISTRIB_ID=", "").replaceAll(DOUBLE_QUOTES, "").trim(); - } else if (line.startsWith("DISTRIB_RELEASE=") && versionId.equals(Constants.UNKNOWN)) { - versionId = line.replace("DISTRIB_RELEASE=", "").replaceAll(DOUBLE_QUOTES, "").trim(); - } else if (line.startsWith("DISTRIB_CODENAME=") && codeName.equals(Constants.UNKNOWN)) { - codeName = line.replace("DISTRIB_CODENAME=", "").replaceAll(DOUBLE_QUOTES, "").trim(); - } - } - return family == null ? null : new Triplet<>(family, versionId, codeName); - } - - private Triplet<String, String, String> parseRelease(String line, String splitLine) { - String[] split = line.split(splitLine); - String family = split[0].trim(); - String versionId = Constants.UNKNOWN; - String codeName = Constants.UNKNOWN; - if (split.length > 1) { - split = split[1].split("[()]"); - if (split.length > 0) { - versionId = split[0].trim(); - } - if (split.length > 1) { - codeName = split[1].trim(); - } - } - return new Triplet<>(family, versionId, codeName); - } - - public List<String> readRemoteFile(String filename) { - List<String> list = Tool.ListUtil.list(true); - try { - ChannelExec channel = (ChannelExec) JschUtil.createChannel(session, ChannelType.EXEC); - channel.setCommand("cat " + filename); - channel.connect(); - - IoUtil.readLines(channel.getInputStream(), Charset.forName("UTF-8"), list); - JschUtil.close(channel); - } catch (JSchException | IOException e) { - } - return list; - } - - public static List<String> runRemoteCommand(String cmdToRun) { - List<String> list = Tool.ListUtil.list(true); - try { - ChannelExec channel = (ChannelExec) JschUtil.createChannel(session, ChannelType.EXEC); - channel.setCommand(cmdToRun); - channel.connect(); - - IoUtil.readLines(channel.getInputStream(), Charset.forName("UTF-8"), list); - JschUtil.close(channel); - } catch (JSchException | IOException e) { - } - return list; - } - - @Override - protected int queryBitness(int i) { - return 0; - } - - @Override - protected List<OSProcess> queryAllProcesses() { - return null; - } - - @Override - protected List<OSProcess> queryChildProcesses(int i) { - return null; - } - - @Override - protected List<OSProcess> queryDescendantProcesses(int i) { - return null; - } - - @Override - public FileSystem getFileSystem() { - return null; - } - - @Override - public InternetProtocolStats getInternetProtocolStats() { - return null; - } - - @Override - public OSProcess getProcess(int i) { - return null; - } - - @Override - public int getProcessId() { - return 0; - } - - @Override - public int getProcessCount() { - return 0; - } - - @Override - public int getThreadCount() { - return 0; - } - - @Override - public long getSystemUptime() { - return 0; - } - - @Override - public long getSystemBootTime() { - return 0; - } - - @Override - public NetworkParams getNetworkParams() { - return null; - } - - public static class LocalLinuxNetworkParams { - - public LocalLinuxNetworkParams() { - - } - - public String getIpv4DefaultGateway() { - List<String> routes = runRemoteCommand("route -A inet -n"); - if (routes.size() <= 2) { - return ""; - } else { - String gateway = ""; - int minMetric = Integer.MAX_VALUE; - - for (int i = 2; i < routes.size(); ++i) { - String[] fields = ParseUtil.whitespaces.split((CharSequence) routes.get(i)); - if (fields.length > 4 && fields[0].equals("0.0.0.0")) { - boolean isGateway = fields[3].indexOf(71) != -1; - int metric = ParseUtil.parseIntOrDefault(fields[4], Integer.MAX_VALUE); - if (isGateway && metric < minMetric) { - minMetric = metric; - gateway = fields[1]; - } - } - } - - return gateway; - } - } - - public String getIpv6DefaultGateway() { - List<String> routes = runRemoteCommand("route -A inet6 -n"); - if (routes.size() <= 2) { - return ""; - } else { - String gateway = ""; - int minMetric = Integer.MAX_VALUE; - - for (int i = 2; i < routes.size(); ++i) { - String[] fields = ParseUtil.whitespaces.split((CharSequence) routes.get(i)); - if (fields.length > 3 && fields[0].equals("::/0")) { - boolean isGateway = fields[2].indexOf(71) != -1; - int metric = ParseUtil.parseIntOrDefault(fields[3], Integer.MAX_VALUE); - if (isGateway && metric < minMetric) { - minMetric = metric; - gateway = fields[1]; - } - } - } - return gateway; - } - } - } -} |
