fix: 验收修正
This commit is contained in:
@@ -241,6 +241,10 @@ func CreateTrapShield(ctx *gin.Context) {
|
||||
infra.Response.Error(ctx, err)
|
||||
return
|
||||
}
|
||||
if err := validateTrapShield(&row); err != nil {
|
||||
infra.Response.Error(ctx, err)
|
||||
return
|
||||
}
|
||||
row.ID = 0
|
||||
if err := impl.DBService.Create(&row).Error; err != nil {
|
||||
infra.Response.Error(ctx, err)
|
||||
@@ -266,6 +270,10 @@ func UpdateTrapShield(ctx *gin.Context) {
|
||||
return
|
||||
}
|
||||
row.ID = id
|
||||
if err := validateTrapShield(&row); err != nil {
|
||||
infra.Response.Error(ctx, err)
|
||||
return
|
||||
}
|
||||
if err := impl.DBService.Save(&row).Error; err != nil {
|
||||
infra.Response.Error(ctx, err)
|
||||
return
|
||||
|
||||
@@ -3,12 +3,16 @@ package controllers
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"git.apinb.com/ops/logs/internal/ingest"
|
||||
"git.apinb.com/ops/logs/internal/models"
|
||||
)
|
||||
|
||||
var trapOIDPattern = regexp.MustCompile(`^\d+(?:\.\d+)*$`)
|
||||
|
||||
func validateSyslogRule(rule *models.SyslogRule) error {
|
||||
regexFields := []struct {
|
||||
name string
|
||||
@@ -71,6 +75,55 @@ func validateTrapRule(rule *models.TrapRule) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateTrapShield(shield *models.TrapShield) error {
|
||||
shield.Name = strings.TrimSpace(shield.Name)
|
||||
shield.SourceIPCIDR = strings.TrimSpace(shield.SourceIPCIDR)
|
||||
shield.InterfaceHint = strings.TrimSpace(shield.InterfaceHint)
|
||||
shield.TimeWindowsJSON = strings.TrimSpace(shield.TimeWindowsJSON)
|
||||
if shield.Name == "" {
|
||||
return fmt.Errorf("Trap 屏蔽规则名称不能为空")
|
||||
}
|
||||
if shield.SourceIPCIDR != "" {
|
||||
if strings.Contains(shield.SourceIPCIDR, "/") {
|
||||
if _, _, err := net.ParseCIDR(shield.SourceIPCIDR); err != nil {
|
||||
return fmt.Errorf("源 IP / CIDR 格式无效:%v", err)
|
||||
}
|
||||
} else if net.ParseIP(shield.SourceIPCIDR) == nil {
|
||||
return fmt.Errorf("源 IP / CIDR 格式无效")
|
||||
}
|
||||
}
|
||||
|
||||
normalizedPrefixes := make([]string, 0, len(shield.OIDPrefixes))
|
||||
seenPrefixes := make(map[string]struct{}, len(shield.OIDPrefixes))
|
||||
for _, raw := range shield.OIDPrefixes {
|
||||
prefix := normalizeTrapOIDInput(raw)
|
||||
if prefix == "" {
|
||||
continue
|
||||
}
|
||||
if !trapOIDPattern.MatchString(prefix) {
|
||||
return fmt.Errorf("Trap OID %q 格式无效", raw)
|
||||
}
|
||||
if _, exists := seenPrefixes[prefix]; exists {
|
||||
continue
|
||||
}
|
||||
seenPrefixes[prefix] = struct{}{}
|
||||
normalizedPrefixes = append(normalizedPrefixes, prefix)
|
||||
}
|
||||
shield.OIDPrefixes = normalizedPrefixes
|
||||
|
||||
if shield.SourceIPCIDR == "" && len(shield.OIDPrefixes) == 0 && shield.InterfaceHint == "" {
|
||||
return fmt.Errorf("Trap 屏蔽范围不能为空;请至少设置源 IP / CIDR、Trap 类型或接口提示中的一项")
|
||||
}
|
||||
if err := ingest.ValidateTimeWindowsJSON(shield.TimeWindowsJSON); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func normalizeTrapOIDInput(value string) string {
|
||||
return strings.Trim(strings.TrimSpace(value), ".")
|
||||
}
|
||||
|
||||
func validateOptionalRegex(field, pattern string) error {
|
||||
pattern = strings.TrimSpace(pattern)
|
||||
if pattern == "" {
|
||||
|
||||
82
internal/logic/controllers/trap_shield_options.go
Normal file
82
internal/logic/controllers/trap_shield_options.go
Normal file
@@ -0,0 +1,82 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"git.apinb.com/bsm-sdk/core/infra"
|
||||
"git.apinb.com/ops/logs/internal/impl"
|
||||
"git.apinb.com/ops/logs/internal/models"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type trapShieldOption struct {
|
||||
OIDPrefix string `json:"oid_prefix"`
|
||||
Name string `json:"name"`
|
||||
Vendor string `json:"vendor"`
|
||||
Source string `json:"source"`
|
||||
}
|
||||
|
||||
// ListTrapShieldOptions 返回 Trap 字典和已接收 Trap 中可用于屏蔽配置的类型。
|
||||
func ListTrapShieldOptions(ctx *gin.Context) {
|
||||
var dictionary []models.TrapDictionaryEntry
|
||||
if err := impl.DBService.Order("vendor asc, name asc, id asc").Find(&dictionary).Error; err != nil {
|
||||
infra.Response.Error(ctx, err)
|
||||
return
|
||||
}
|
||||
|
||||
options := make([]trapShieldOption, 0, len(dictionary))
|
||||
seen := make(map[string]struct{}, len(dictionary))
|
||||
for _, entry := range dictionary {
|
||||
oid := normalizeTrapOIDInput(entry.OID)
|
||||
if oid == "" {
|
||||
oid = normalizeTrapOIDInput(entry.OIDPrefix)
|
||||
}
|
||||
if oid == "" {
|
||||
continue
|
||||
}
|
||||
if _, exists := seen[oid]; exists {
|
||||
continue
|
||||
}
|
||||
seen[oid] = struct{}{}
|
||||
name := strings.TrimSpace(entry.Name)
|
||||
if name == "" {
|
||||
name = strings.TrimSpace(entry.Title)
|
||||
}
|
||||
if name == "" {
|
||||
name = oid
|
||||
}
|
||||
options = append(options, trapShieldOption{
|
||||
OIDPrefix: oid,
|
||||
Name: name,
|
||||
Vendor: strings.TrimSpace(entry.Vendor),
|
||||
Source: "dictionary",
|
||||
})
|
||||
}
|
||||
|
||||
var receivedOIDs []string
|
||||
if err := impl.DBService.Model(&models.LogEvent{}).
|
||||
Where("source_kind = ? AND trap_o_id <> ?", "snmp_trap", "").
|
||||
Distinct("trap_o_id").
|
||||
Order("trap_o_id asc").
|
||||
Pluck("trap_o_id", &receivedOIDs).Error; err != nil {
|
||||
infra.Response.Error(ctx, err)
|
||||
return
|
||||
}
|
||||
for _, rawOID := range receivedOIDs {
|
||||
oid := normalizeTrapOIDInput(rawOID)
|
||||
if oid == "" {
|
||||
continue
|
||||
}
|
||||
if _, exists := seen[oid]; exists {
|
||||
continue
|
||||
}
|
||||
seen[oid] = struct{}{}
|
||||
options = append(options, trapShieldOption{
|
||||
OIDPrefix: oid,
|
||||
Name: "已接收 Trap",
|
||||
Source: "received",
|
||||
})
|
||||
}
|
||||
|
||||
infra.Response.Success(ctx, gin.H{"items": options})
|
||||
}
|
||||
Reference in New Issue
Block a user