Files
network-topology-discovery/internal/device/parser.go
T
Your Name c311a570da Fix: 添加命令间500毫秒延迟防止H3C设备速率限制
- 每个SSH命令执行后等待500毫秒
- 解决命令交替返回0字节的问题
2026-04-26 02:45:50 +08:00

110 lines
2.9 KiB
Go

package device
import (
"fmt"
"time"
"network-topology-discovery/pkg/models"
sshclient "network-topology-discovery/internal/ssh"
)
// Parser 设备解析器接口
type Parser interface {
// GetCommands 获取需要执行的命令列表
GetCommands() []string
// Parse 解析命令输出,填充设备信息
Parse(device *models.Device, outputs []string) error
// GetType 获取设备类型
GetType() models.DeviceType
}
// BaseParser 基础解析器
type BaseParser struct {
DeviceType models.DeviceType
}
// GetType 获取设备类型
func (b *BaseParser) GetType() models.DeviceType {
return b.DeviceType
}
// DiscoverDevice 发现并采集设备信息
func DiscoverDevice(ip string, deviceType models.DeviceType, username, password string) (*models.Device, error) {
device := &models.Device{
IP: ip,
Type: deviceType,
}
// 创建SSH客户端 - 默认启用不安全加密算法以兼容老旧设备,增加超时时间
client := sshclient.NewClient(sshclient.Config{
Host: ip,
Username: username,
Password: password,
Timeout: 30 * time.Second, // 增加到30秒,防止大输出超时
InsecureCiphers: true, // 启用旧版加密算法支持
})
// 连接
if err := client.Connect(); err != nil {
device.ScanStatus = "failed"
device.ErrorMessage = err.Error()
return device, err
}
defer client.Close()
// 获取对应的解析器
var parser Parser
switch deviceType {
case models.DeviceTypeCisco:
parser = &CiscoParser{}
case models.DeviceTypeHuawei:
parser = &HuaweiParser{}
case models.DeviceTypeH3C:
parser = &H3CParser{}
case models.DeviceTypeASA:
parser = &ASAParser{}
case models.DeviceTypeLinux:
parser = &LinuxParser{}
case models.DeviceTypeWindows:
parser = &WindowsParser{}
default:
device.ScanStatus = "failed"
device.ErrorMessage = "unsupported device type"
return device, nil
}
// 获取命令列表
commands := parser.GetCommands()
// 执行命令 - 允许部分命令失败,增加详细日志和延迟防止设备速率限制
outputs := make([]string, 0, len(commands))
for i, cmd := range commands {
// 每个命令之间等待500毫秒,防止设备速率限制导致返回空数据
if i > 0 {
time.Sleep(500 * time.Millisecond)
}
fmt.Printf("[PARSER] Executing command %d/%d: %s\n", i+1, len(commands), cmd)
output, err := client.ExecuteCommand(cmd)
if err != nil {
// 记录警告但继续执行其他命令
fmt.Printf("Warning: command '%s' failed: %v\n", cmd, err)
outputs = append(outputs, "")
} else {
fmt.Printf("[PARSER] Command '%s' returned %d bytes\n", cmd, len(output))
outputs = append(outputs, output)
}
}
// 解析输出
if err := parser.Parse(device, outputs); err != nil {
device.ScanStatus = "failed"
device.ErrorMessage = err.Error()
return device, err
}
device.ScanStatus = "success"
return device, nil
}