技术驱动生活

routeros脚本:监测某一个网卡可用性,并且把结果提交到kuma中



经过和chatGPT多次友好耐心的沟通,终于把这个脚本写好了。

使用的是ChatGPT-o1-preview,还不能全信它,还是要看看代码的,否则它会一个问题里打转,永远出不来。


image.png


# 定义要监测的接口名称
:local interfaceName "wireguard1-usa5-ros2"
:log info "脚本开始执行,监测接口:$interfaceName"

# 定义 Kuma ID 变量
:local kumaID "3333333"

# 处理接口名称,移除文件名中不支持的字符(如空格、斜杠等)
:local sanitizedInterfaceName ""
:for i from=0 to=([:len $interfaceName] - 1) do={
    :local char [:pick $interfaceName $i]
    :if ($char ~ "[a-zA-Z0-9_-]") do={
        :set sanitizedInterfaceName ($sanitizedInterfaceName . $char)
    } else={
        :set sanitizedInterfaceName ($sanitizedInterfaceName . "_")
    }
}
:log info "处理后的接口名称:$sanitizedInterfaceName"

# 定义输出文件名,使用接口名称区分
:local outputFileName ("ping_output_" . $sanitizedInterfaceName . ".txt")

:local ipID [/ip address find interface=$interfaceName]
:if ($ipID != "") do={

    # 获取 IP 地址并去掉子网掩码部分
    :local ipAddress [/ip address get $ipID address]
    :set ipAddress [:pick $ipAddress 0 [:find $ipAddress "/"]]
    :log info "获取到 IP 地址:$ipAddress"

    # 解析 IP 地址的各个部分
    :local pos1 [:find $ipAddress "."]
    :local pos2 [:find $ipAddress "." ($pos1 + 1)]
    :local pos3 [:find $ipAddress "." ($pos2 + 1)]

    # 检查是否成功找到三个点的位置
    :if (($pos1 != "") && ($pos2 != "") && ($pos3 != "")) do={

        # 提取每个八位组
        :local octet1 [:pick $ipAddress 0 $pos1]
        :local octet2 [:pick $ipAddress ($pos1 + 1) $pos2]
        :local octet3 [:pick $ipAddress ($pos2 + 1) $pos3]
        # 将对端 IP 的最后一个八位组设置为 1
        :local octet4 "1"

        # 构建对端 IP 地址
        :local peerIP ($octet1 . "." . $octet2 . "." . $octet3 . "." . $octet4)
        :log info "构建对端 IP 地址:$peerIP"

        :log info "正在 Ping 对端 IP $peerIP"

        # 定义 Ping 参数
        :local pingCount 10
        :local maxLossPercent 50

        # 执行 Ping 命令并将输出保存到唯一的文件
        :log info "开始执行 Ping 命令,输出文件:$outputFileName"
        :execute "/ping $peerIP count=$pingCount" file=$outputFileName
        :log info "Ping 命令已启动"

        # 等待 Ping 命令完成
        :delay ($pingCount * 1s)
        :log info "等待 Ping 命令完成"

        # 检查是否生成了输出文件
        :if ([/file find name=$outputFileName] != "") do={
            :log info "成功生成 $outputFileName 文件"

            # 读取 Ping 输出文件的内容
            :local pingOutput [/file get [find name=$outputFileName] contents]
            :log info "读取 $outputFileName 文件内容"

            # 删除临时文件
            /file remove $outputFileName
            :log info "删除临时文件 $outputFileName"

            # 输出 pingOutput 内容到日志,供调试使用
            #:log info "Ping Output:\n$pingOutput"

            # 初始化变量
            :local sent ""
            :local received ""
            :local packetLoss ""
            :local avgRtt 0

            # 将 pingOutput 按行分割为数组
            :local lines [:toarray ""]
            :local line ""
            :local lineEnd 0
            :while ([:len $pingOutput] > 0) do={
                :set lineEnd [:find $pingOutput "\r\n"]
                :if ($lineEnd = -1) do={
                    :set line $pingOutput
                    :set pingOutput ""
                } else={
                    :set line [:pick $pingOutput 0 $lineEnd]
                    :set pingOutput [:pick $pingOutput ($lineEnd + 2) [:len $pingOutput]]
                }
                :if ([:len $line] > 0) do={
                    :set lines ($lines, $line)
                }
            }

            # 检查是否包含 "max-rtt"
            :local containsMaxRtt false
            :foreach l in=$lines do={
                :if ([:find $l "max-rtt="] != -1) do={
                    :set containsMaxRtt true
                }
            }
            :log info "Ping 输出是否包含 'max-rtt=':$containsMaxRtt"

            # 获取统计信息行
            :local summaryLine ""
            :if ($containsMaxRtt) do={
                # 取最后两行合并
                :local lineCount [:len $lines]
                :if ($lineCount >= 2) do={
                    :set summaryLine (($lines->($lineCount - 2)) . " " . ($lines->($lineCount - 1)))
                    :log info "合并最后两行为统计信息行:$summaryLine"
                } else={
                    :log error "Ping 输出行数不足,无法获取统计信息"
                }
            } else={
                # 取最后一行
                :local lineCount [:len $lines]
                :if ($lineCount >= 1) do={
                    :set summaryLine ($lines->($lineCount - 1))
                    :log info "使用最后一行为统计信息行:$summaryLine"
                } else={
                    :log error "Ping 输出行数不足,无法获取统计信息"
                }
            }

            # 检查是否获取到统计信息行
            :if ([:len $summaryLine] > 0) do={

                # 提取 sent
                :local sentPos [:find $summaryLine "sent="]
                :local sentEnd [:find $summaryLine " " ($sentPos + 5)]
                :if ($sentEnd = -1) do={
                    :set sentEnd [:len $summaryLine]
                }
                :local sentStr [:pick $summaryLine ($sentPos + 5) $sentEnd]
                :set sent [:tonum $sentStr]
                :log info "解析到 sent=$sent"

                # 提取 received
                :local recvPos [:find $summaryLine "received="]
                :local recvEnd [:find $summaryLine " " ($recvPos + 9)]
                :if ($recvEnd = -1) do={
                    :set recvEnd [:len $summaryLine]
                }
                :local recvStr [:pick $summaryLine ($recvPos + 9) $recvEnd]
                :set received [:tonum $recvStr]
                :log info "解析到 received=$received"

                # 提取 packet-loss
                :local lossPos [:find $summaryLine "packet-loss="]
                :local lossEnd [:find $summaryLine "%" ($lossPos + 12)]
                :if ($lossEnd = -1) do={
                    :set lossEnd [:len $summaryLine]
                }
                :local lossStr [:pick $summaryLine ($lossPos + 12) $lossEnd]
                :set packetLoss [:tonum $lossStr]
                :log info "解析到 packetLoss=$packetLoss"

                # 提取 avg-rtt
                :local avgPos [:find $summaryLine "avg-rtt="]
                :if ($avgPos != -1) do={
                    :local avgEnd [:find $summaryLine " " ($avgPos + 8)]
                    :if ($avgEnd = -1) do={
                        :set avgEnd [:len $summaryLine]
                    }
                    :local avgRttStr [:pick $summaryLine ($avgPos + 8) $avgEnd]
                    :log info "解析到 avgRttStr=$avgRttStr"

                    # 将 avgRttStr 转换为毫秒数
                    # 处理类似于 "166ms277us" 的字符串
                    :local msPos [:find $avgRttStr "ms"]
                    :local usPos [:find $avgRttStr "us"]
                    :local msValue 0
                    :local usValue 0
                    :if ($msPos != -1) do={
                        :set msValue [:tonum [:pick $avgRttStr 0 $msPos]]
                    }
                    :if ($usPos != -1) do={
                        :set usValue [:tonum [:pick $avgRttStr ($msPos + 2) $usPos]]
                    }
                    :set avgRtt ($msValue + ($usValue / 1000))
                    :log info "解析到 avgRtt=$avgRtt ms"
                } else={
                    :set avgRtt 0
                    :log warning "未能解析到 avg-rtt"
                }

                # 判断并提交到 Kuma
                :if ($packetLoss < $maxLossPercent) do={
                    :log info "Ping 成功,丢包率=$packetLoss%,平均 RTT: $avgRtt ms"
                    :local msg ("PingOK_Loss" . $packetLoss . "%")
                    :log info "提交结果到 Kuma:状态=up,消息=$msg,ping=$avgRtt"
                    /tool fetch url=("http://kuma2.ffffff.com:3001/api/push/" . $kumaID . "?status=up&msg=" . $msg . "&ping=" . $avgRtt) keep-result=no
                } else={
                    :log error "Ping 失败,丢包率=$packetLoss%"
                    :log info "状态为 down,不向 Kuma 提交结果"
                }

            } else={
                :log error "未获取到统计信息行,Ping 失败"
                :log info "状态为 down,不向 Kuma 提交结果"
            }

        } else={
            :log error "未生成 $outputFileName 文件,Ping 命令可能失败"
        }

    } else={
        :log error "无法解析 IP 地址 $ipAddress"
    }

} else={
    :log error "接口 $interfaceName 未分配 IP 地址"
}

:log info "脚本执行完毕"

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

Powered By Z-BlogPHP 1.7.3

2024 Copyright thesnowtop.com.All Rights Reserved.