@@ -0,0 +1,456 @@
package com.tongran.agent.client.service.impl ;
import cn.hutool.core.collection.CollectionUtil ;
import com.github.dockerjava.api.DockerClient ;
import com.github.dockerjava.api.model.Container ;
import com.github.dockerjava.core.DefaultDockerClientConfig ;
import com.github.dockerjava.core.DockerClientImpl ;
import com.github.dockerjava.httpclient5.ApacheDockerHttpClient ;
import com.github.dockerjava.transport.DockerHttpClient ;
import com.tongran.agent.client.core.config.GlobalConfig ;
import com.tongran.agent.client.core.eo.AlarmEO ;
import com.tongran.agent.client.core.eo.NativeNetworkInterfaceEO ;
import com.tongran.agent.client.core.vo.AlarmVO ;
import com.tongran.agent.client.service.AlarmService ;
import com.tongran.agent.client.utils.AgentDataUtil ;
import org.apache.commons.lang3.StringUtils ;
import org.springframework.stereotype.Service ;
import oshi.SystemInfo ;
import oshi.hardware.CentralProcessor ;
import oshi.hardware.HardwareAbstractionLayer ;
import oshi.hardware.NetworkIF ;
import oshi.software.os.OSFileStore ;
import oshi.software.os.OperatingSystem ;
import java.io.BufferedReader ;
import java.io.IOException ;
import java.io.InputStreamReader ;
import java.net.NetworkInterface ;
import java.net.SocketException ;
import java.time.Duration ;
import java.util.ArrayList ;
import java.util.Enumeration ;
import java.util.List ;
import java.util.Map ;
import java.util.concurrent.TimeUnit ;
import java.util.regex.Matcher ;
import java.util.regex.Pattern ;
import java.util.stream.Collectors ;
@Service
public class AlarmServiceImpl implements AlarmService {
@Override
public List < AlarmVO > alarmMonitor ( long timestamp ) {
List < AlarmVO > alarmVOList = new ArrayList < > ( ) ;
List < AlarmEO > list = GlobalConfig . ALARM_LIST . stream ( ) . filter ( a - > a . isCollect ( ) = = true ) . collect ( Collectors . toList ( ) ) ;
if ( CollectionUtil . isNotEmpty ( list ) ) {
for ( AlarmEO alarmEO : list ) {
String type = alarmEO . getType ( ) ;
String threshold = alarmEO . getThreshold ( ) ;
int compareType = alarmEO . getCompareType ( ) ;
AlarmVO alarmVO = AlarmVO . builder ( ) . type ( type ) . timestamp ( timestamp ) . build ( ) ;
switch ( type ) {
case " systemCpuUti " : //CPU使用率
alarmVO . setResult ( handleSystemCpuUti ( threshold , compareType ) ) ;
alarmVOList . add ( alarmVO ) ;
break ;
case " memoryUtilization " : //内存利用率
alarmVO . setResult ( handleMemoryUtilization ( threshold , compareType ) ) ;
alarmVOList . add ( alarmVO ) ;
break ;
case " systemSwapSizePercent " : //可用交换空间百分比
alarmVO . setResult ( handleSystemSwapSizePercent ( threshold , compareType ) ) ;
alarmVOList . add ( alarmVO ) ;
break ;
case " systemUsersNum " : //登录用户数
alarmVO . setResult ( handleSystemUsersNum ( threshold , compareType ) ) ;
alarmVOList . add ( alarmVO ) ;
break ;
case " vfsFsUtil " : //挂载点的空间利用率
alarmVO . setResult ( handleVfsFsUtil ( threshold , compareType ) ) ;
alarmVOList . add ( alarmVO ) ;
break ;
case " netUtil " : //网络带宽使用率
alarmVO . setResult ( handleNetUtil ( threshold , compareType ) ) ;
alarmVOList . add ( alarmVO ) ;
break ;
case " containerMemUtil " : //容器内存使用率
alarmVO . setResult ( handleContainerMemUtil ( threshold , compareType ) ) ;
alarmVOList . add ( alarmVO ) ;
break ;
case " netIfStatus " : //网络运行状态UP变down
alarmVO . setResult ( handleNetIfStatus ( ) ) ;
alarmVOList . add ( alarmVO ) ;
break ;
case " extraPorts " : //多余端口
alarmVO . setResult ( handleExtraPorts ( threshold ) ) ;
alarmVOList . add ( alarmVO ) ;
break ;
default : //其他
break ;
}
}
}
return alarmVOList ;
}
private String handleSystemCpuUti ( String threshold , int compareType ) {
try {
SystemInfo si = new SystemInfo ( ) ;
HardwareAbstractionLayer hal = si . getHardware ( ) ;
CentralProcessor processor = hal . getProcessor ( ) ;
long [ ] prevTicks = processor . getSystemCpuLoadTicks ( ) ;
try {
TimeUnit . SECONDS . sleep ( 1 ) ; // 等待1秒
} catch ( InterruptedException e ) {
e . printStackTrace ( ) ;
}
// 计算使用率
double cpuUsage = processor . getSystemCpuLoadBetweenTicks ( prevTicks ) * 100 ;
boolean isFalse = false ;
if ( StringUtils . isNotBlank ( threshold ) ) {
isFalse = compare ( cpuUsage , threshold , compareType ) ;
}
if ( isFalse ) {
return " 当前CPU使用率: " + cpuUsage + " % " ;
}
} catch ( Exception e ) {
e . printStackTrace ( ) ;
}
return " " ;
}
private String handleMemoryUtilization ( String threshold , int compareType ) {
try {
Map < String , Long > memInfo = AgentDataUtil . parseMemInfo ( ) ;
long total = memInfo . get ( " MemTotal " ) ;
long available = memInfo . getOrDefault ( " MemAvailable " ,
memInfo . get ( " MemFree " ) +
memInfo . getOrDefault ( " Buffers " , 0L ) +
memInfo . getOrDefault ( " Cached " , 0L ) +
memInfo . getOrDefault ( " SReclaimable " , 0L ) ) ;
// 总内存使用率
double totalUsage = ( double ) ( total - available ) / total * 100 ;
boolean isFalse = false ;
if ( StringUtils . isNotBlank ( threshold ) ) {
isFalse = compare ( totalUsage , threshold , compareType ) ;
}
if ( isFalse ) {
return " 当前内存利用率: " + totalUsage + " % " ;
}
} catch ( IOException e ) {
e . printStackTrace ( ) ;
}
return " " ;
}
private String handleSystemSwapSizePercent ( String threshold , int compareType ) {
try {
Map < String , Long > memInfo = AgentDataUtil . parseMemInfo ( ) ;
long swapTotal = memInfo . getOrDefault ( " SwapTotal " , 0L ) ;
long swapFree = memInfo . getOrDefault ( " SwapFree " , 0L ) ;
double swapSizePercent = ( double ) swapFree / swapTotal * 100 ; //可用交换空间百分比
boolean isFalse = false ;
if ( StringUtils . isNotBlank ( threshold ) ) {
isFalse = compare ( swapSizePercent , threshold , compareType ) ;
}
if ( isFalse ) {
return " 当前可用交换空间百分比: " + swapSizePercent + " % " ;
}
} catch ( IOException e ) {
e . printStackTrace ( ) ;
}
return " " ;
}
private String handleSystemUsersNum ( String threshold , int compareType ) {
SystemInfo si = new SystemInfo ( ) ;
OperatingSystem os = si . getOperatingSystem ( ) ;
int userNum = os . getSessions ( ) . size ( ) ;
boolean isFalse = false ;
if ( StringUtils . isNotBlank ( threshold ) ) {
isFalse = compare ( userNum , threshold , compareType ) ;
}
if ( isFalse ) {
return " 当前登录用户数: " + userNum ;
}
return " " ;
}
private String handleVfsFsUtil ( String threshold , int compareType ) {
String result = " " ;
SystemInfo si = new SystemInfo ( ) ;
for ( OSFileStore fs : si . getOperatingSystem ( ) . getFileSystem ( ) . getFileStores ( ) ) {
String mount = fs . getMount ( ) ;
long totalSpace = fs . getTotalSpace ( ) ;
long freeSpace = fs . getFreeSpace ( ) ;
double usagePercentage = totalSpace > 0 ?
( double ) ( totalSpace - freeSpace ) / totalSpace * 100 : 0 ;
if ( StringUtils . isNotBlank ( threshold ) ) {
boolean isFalse = compare ( usagePercentage , threshold , compareType ) ;
if ( isFalse ) {
result + = " 挂载点: " + mount + " ,当前空间利用率: " + usagePercentage + " %; " ;
}
}
}
return result ;
}
private String handleNetUtil ( String threshold , int compareType ) {
String result = " " ;
try {
SystemInfo si = new SystemInfo ( ) ;
HardwareAbstractionLayer hal = si . getHardware ( ) ;
// 获取所有网络接口
List < NetworkIF > networkIFs = hal . getNetworkIFs ( ) ;
// 第一次采样
for ( NetworkIF net : networkIFs ) {
net . updateAttributes ( ) ;
}
// 等待1秒
TimeUnit . SECONDS . sleep ( 1 ) ;
// 第二次采样并计算速率
for ( NetworkIF net : networkIFs ) {
// 只显示以太网接口
if ( net . getName ( ) . startsWith ( " eth " ) | |
net . getName ( ) . startsWith ( " en " ) | |
net . getDisplayName ( ) . toLowerCase ( ) . contains ( " ethernet " ) ) {
long prevBytesSent = net . getBytesSent ( ) ;
net . updateAttributes ( ) ;
long bytesSent = net . getBytesSent ( ) - prevBytesSent ;
// 获取最大带宽
double maxBandwidth = getInterfaceMaxBandwidth ( net ) ;
// 计算使用率百分比
double sentUsagePercentage = ( bytesToMbps ( bytesSent ) / maxBandwidth ) * 100 ;
boolean isFalse = false ;
if ( StringUtils . isNotBlank ( threshold ) ) {
isFalse = compare ( sentUsagePercentage , threshold , compareType ) ;
}
if ( isFalse ) {
result + = " 网络接口: " + net . getName ( ) + " ,当前发送流量带宽使用率: " + sentUsagePercentage + " %; " ;
}
}
}
} catch ( Exception e ) {
e . printStackTrace ( ) ;
}
return result ;
}
private String handleContainerMemUtil ( String threshold , int compareType ) {
// 配置Docker客户端
DefaultDockerClientConfig config = DefaultDockerClientConfig . createDefaultConfigBuilder ( )
. withDockerHost ( " unix:///var/run/docker.sock " )
. withDockerTlsVerify ( false ) // 根据你的配置调整
. build ( ) ;
DockerHttpClient httpClient = new ApacheDockerHttpClient . Builder ( )
. dockerHost ( config . getDockerHost ( ) )
. sslConfig ( config . getSSLConfig ( ) )
. maxConnections ( 100 )
. connectionTimeout ( Duration . ofSeconds ( 30 ) )
. responseTimeout ( Duration . ofSeconds ( 45 ) )
. build ( ) ;
DockerClient dockerClient = DockerClientImpl . getInstance ( config , httpClient ) ;
String result = " " ;
try {
// 获取正在运行的容器列表
List < Container > containers = dockerClient . listContainersCmd ( )
. withShowAll ( false ) // 只显示运行中的容器
. exec ( ) ;
// 打印容器信息
System . out . println ( " 运行中的Docker容器: " ) ;
System . out . println ( " 容器ID \ t \ t镜像 \ t \ t状态 \ t \ t名称 " ) ;
for ( Container container : containers ) {
String id = container . getId ( ) . substring ( 0 , 12 ) ; // 只显示短ID
String name = container . getNames ( ) [ 0 ] . replaceFirst ( " / " , " " ) ;
// 执行 docker stats 命令(--no-stream 表示只输出一次)
Process process = new ProcessBuilder (
" docker " , " stats " , " --no-stream " , id ,
" --format " , " 'table {{.ID}} \ t{{.Name}} \ t{{.CPUPerc}} \ t{{.MemPerc}} \ t{{.NetIO}} "
) . start ( ) ;
// 读取命令输出
BufferedReader reader = new BufferedReader (
new InputStreamReader ( process . getInputStream ( ) )
) ;
String line ;
while ( ( line = reader . readLine ( ) ) ! = null ) {
String [ ] parts = line . trim ( ) . split ( " \\ s+ " ) ;
String memUtil = parts [ 4 ] ; // 内存使用率
memUtil = memUtil . replace ( " % " , " " ) ;
if ( StringUtils . isNotBlank ( memUtil ) ) {
boolean isFalse = false ;
if ( StringUtils . isNotBlank ( threshold ) ) {
isFalse = compare ( Double . parseDouble ( memUtil ) , threshold , compareType ) ;
}
if ( isFalse ) {
result + = " 容器: " + name + " ,当前内存使用率 " + memUtil + " %; " ;
}
}
}
// 等待命令执行完成并获取退出码
int exitCode = process . waitFor ( ) ;
if ( exitCode ! = 0 ) {
System . err . println ( " 命令执行失败,退出码: " + exitCode ) ;
}
reader . close ( ) ;
}
} catch ( Exception e ) {
e . printStackTrace ( ) ;
} finally {
try {
dockerClient . close ( ) ;
} catch ( IOException e ) {
e . printStackTrace ( ) ;
}
}
return result ;
}
private String handleNetIfStatus ( ) {
String result = " " ;
try {
List < NativeNetworkInterfaceEO > list = getAllNetworkInterfaces ( ) ;
if ( CollectionUtil . isNotEmpty ( GlobalConfig . NET_LIST ) ) {
List < String > natList = list . stream ( ) . filter ( n - > n . isUp ( ) = = false ) . map ( NativeNetworkInterfaceEO : : getName ) . collect ( Collectors . toList ( ) ) ;
List < NativeNetworkInterfaceEO > temp = GlobalConfig . NET_LIST . stream ( ) . filter ( n - > n . isUp ( ) )
. collect ( Collectors . toList ( ) ) ;
for ( NativeNetworkInterfaceEO n : temp ) {
if ( natList . contains ( n . getName ( ) ) ) {
result + = " 网络接口: " + n . getName ( ) + " ,运行状态由UP转为DOWN; " ;
}
}
}
GlobalConfig . NET_LIST = list ;
} catch ( SocketException e ) {
System . err . println ( " 获取网络接口信息失败: " + e . getMessage ( ) ) ;
}
return result ;
}
private String handleExtraPorts ( String threshold ) {
String result = " " ;
try {
List < Integer > list = scanPortsUsingNmap ( ) ;
for ( Integer port : list ) {
boolean flag = verifyPort ( port , threshold ) ;
if ( ! flag ) {
result + = " 端口: " + port + " 已开放; " ;
}
}
} catch ( Exception e ) {
e . printStackTrace ( ) ;
}
return result ;
}
private boolean compare ( double value , String threshold , int compareType ) {
boolean isFalse = false ;
switch ( compareType ) {
case 1 : //大于且等于
if ( value > = Double . parseDouble ( threshold ) ) {
isFalse = true ;
}
break ;
case 2 : //小于
if ( value < Double . parseDouble ( threshold ) ) {
isFalse = true ;
}
break ;
case 3 : //小于且等于
if ( value < = Double . parseDouble ( threshold ) ) {
isFalse = true ;
}
break ;
default : //大于
if ( value > Double . parseDouble ( threshold ) ) {
isFalse = true ;
}
break ;
}
return isFalse ;
}
private static double bytesToMbps ( long bytes ) {
return bytes * 8 . 0 / 1_000_000 ; // bytes to megabits
}
/**
* 获取接口的理论最大带宽(Mbps)
*/
private double getInterfaceMaxBandwidth ( NetworkIF netIf ) {
String name = netIf . getName ( ) . toLowerCase ( ) ;
long speed = netIf . getSpeed ( ) ; // 获取接口速度(bps)
if ( speed > 0 ) {
return speed / 1_000_000 . 0 ; // 转换为Mbps
}
// 如果无法获取速度,根据常见接口类型估算
if ( name . contains ( " eth " ) | | name . contains ( " en " ) | | name . contains ( " gigabit " ) ) {
return 1000 . 0 ; // 千兆以太网
} else if ( name . contains ( " 10g " ) | | name . contains ( " 10000 " ) ) {
return 10000 . 0 ; // 万兆以太网
} else {
return 100 . 0 ; // 默认百兆以太网
}
}
/**
* 获取所有网络接口信息
*/
public List < NativeNetworkInterfaceEO > getAllNetworkInterfaces ( ) throws SocketException {
List < NativeNetworkInterfaceEO > interfaces = new ArrayList < > ( ) ;
Enumeration < NetworkInterface > networkInterfaces = NetworkInterface . getNetworkInterfaces ( ) ;
while ( networkInterfaces . hasMoreElements ( ) ) {
NetworkInterface ni = networkInterfaces . nextElement ( ) ;
NativeNetworkInterfaceEO interfaceInfo = NativeNetworkInterfaceEO . builder ( )
. name ( ni . getName ( ) )
. displayName ( ni . getDisplayName ( ) )
. up ( ni . isUp ( ) )
. build ( ) ;
interfaces . add ( interfaceInfo ) ;
}
return interfaces ;
}
/**
* 获取所有开放端口
*/
public List < Integer > scanPortsUsingNmap ( ) throws Exception {
List < Integer > openPorts = new ArrayList < > ( ) ;
Process process = Runtime . getRuntime ( ) . exec ( " nmap -p 1-65535 localhost " ) ;
BufferedReader reader = new BufferedReader ( new InputStreamReader ( process . getInputStream ( ) ) ) ;
String line ;
Pattern pattern = Pattern . compile ( " \\ d+/tcp open " ) ; // Adjust the regex based on nmap output format you expect
while ( ( line = reader . readLine ( ) ) ! = null ) {
Matcher matcher = pattern . matcher ( line ) ;
if ( matcher . find ( ) ) { // Assuming the output format is "port/protocol state" where state is "open" for open ports
String portStr = matcher . group ( 0 ) . split ( " / " ) [ 0 ] ; // Extract the port number part before "/tcp" or "/udp" etc.
openPorts . add ( Integer . parseInt ( portStr ) ) ; // Add the port number to the list of open ports
}
}
reader . close ( ) ;
return openPorts ;
}
public boolean verifyPort ( int port , String threshold ) {
String [ ] ports = threshold . split ( " ; " ) ;
for ( int i = 0 ; i < ports . length ; i + + ) {
String p = ports [ i ] ;
int start = 0 ;
int end = 0 ;
String [ ] arr = p . split ( " - " ) ;
start = Integer . parseInt ( arr [ 0 ] ) ;
if ( arr . length = = 2 ) {
end = Integer . parseInt ( arr [ 1 ] ) ;
}
if ( start < = port & & port < = end ) {
return true ;
}
}
return false ;
}
}