mirror of
https://github.com/Awuqing/BackupX.git
synced 2026-09-05 07:26:43 +08:00
功能: v2.1 可观测性与流控 (#47)
* 功能: v2.1 可观测性与流控 — Prometheus + 节点带宽 + 审计 Webhook 核心能力: - Prometheus /metrics 端点:11 类指标(任务/存储/节点/SLA/验证/恢复/复制) - 节点级带宽限速生效:model.Node.BandwidthLimit 覆盖全局默认 - 审计日志 Webhook 外输:HMAC-SHA256 签名,配合 SIEM 合规留档 实现: - server/internal/metrics/ 独立 Registry + 异步 Gauge Collector(30s) - backup/restore/verify/replication 服务注入 metrics 钩子,nil 安全 - resolveProviderForNode() 按 task.NodeID 解析 BandwidthLimit - AuditService.SetWebhook + 动态 settings 推送,无需重启 测试: - metrics/registry_test.go: 注册/采集/nil safety/HTTP handler - service/audit_service_webhook_test.go: 签名正确性/异步投递/禁用路径 - go test ./... 全部通过 * chore: 触发 CodeQL 扫描
This commit is contained in:
@@ -8,21 +8,55 @@ import (
|
||||
"backupx/server/internal/repository"
|
||||
)
|
||||
|
||||
// AuditWebhookConfigurer 抽象审计 webhook 配置接口,由 AuditService 实现。
|
||||
// 用接口解耦避免 settings_service 直接依赖 AuditService 具体类型。
|
||||
type AuditWebhookConfigurer interface {
|
||||
SetWebhook(url, secret string)
|
||||
}
|
||||
|
||||
type SettingsService struct {
|
||||
configs repository.SystemConfigRepository
|
||||
configs repository.SystemConfigRepository
|
||||
auditWebhook AuditWebhookConfigurer
|
||||
}
|
||||
|
||||
func NewSettingsService(configs repository.SystemConfigRepository) *SettingsService {
|
||||
return &SettingsService{configs: configs}
|
||||
}
|
||||
|
||||
// settingsKeys lists all user-editable setting keys.
|
||||
// SetAuditWebhookConfigurer 注入 audit webhook 配置接收方。
|
||||
// 启动时立即用当前 DB 中的设置调用一次,后续每次 Update 变更 webhook key 时同步推送。
|
||||
func (s *SettingsService) SetAuditWebhookConfigurer(ctx context.Context, configurer AuditWebhookConfigurer) {
|
||||
if s == nil || configurer == nil {
|
||||
return
|
||||
}
|
||||
s.auditWebhook = configurer
|
||||
// 启动时同步一次,保证重启后配置不丢失
|
||||
all, err := s.GetAll(ctx)
|
||||
if err == nil {
|
||||
configurer.SetWebhook(all[SettingKeyAuditWebhookURL], all[SettingKeyAuditWebhookSecret])
|
||||
}
|
||||
}
|
||||
|
||||
// 可被前端写入的系统设置键。新增键必须同步加入此清单,
|
||||
// 否则 Update 会忽略(安全原则:显式 allow-list)。
|
||||
const (
|
||||
SettingKeySiteName = "site_name"
|
||||
SettingKeyLanguage = "language"
|
||||
SettingKeyTimezone = "timezone"
|
||||
SettingKeyBackupNotificationEnabled = "backup_notification_enabled"
|
||||
SettingKeyBandwidthLimit = "bandwidth_limit"
|
||||
SettingKeyAuditWebhookURL = "audit_webhook_url"
|
||||
SettingKeyAuditWebhookSecret = "audit_webhook_secret"
|
||||
)
|
||||
|
||||
var settingsKeys = []string{
|
||||
"site_name",
|
||||
"language",
|
||||
"timezone",
|
||||
"backup_notification_enabled",
|
||||
"bandwidth_limit",
|
||||
SettingKeySiteName,
|
||||
SettingKeyLanguage,
|
||||
SettingKeyTimezone,
|
||||
SettingKeyBackupNotificationEnabled,
|
||||
SettingKeyBandwidthLimit,
|
||||
SettingKeyAuditWebhookURL,
|
||||
SettingKeyAuditWebhookSecret,
|
||||
}
|
||||
|
||||
func (s *SettingsService) GetAll(ctx context.Context) (map[string]string, error) {
|
||||
@@ -42,6 +76,7 @@ func (s *SettingsService) Update(ctx context.Context, settings map[string]string
|
||||
for _, key := range settingsKeys {
|
||||
allowed[key] = true
|
||||
}
|
||||
auditWebhookTouched := false
|
||||
for key, value := range settings {
|
||||
if !allowed[key] {
|
||||
continue
|
||||
@@ -50,6 +85,14 @@ func (s *SettingsService) Update(ctx context.Context, settings map[string]string
|
||||
if err := s.configs.Upsert(ctx, item); err != nil {
|
||||
return nil, apperror.Internal("SETTINGS_UPDATE_FAILED", "无法更新系统设置", err)
|
||||
}
|
||||
if key == SettingKeyAuditWebhookURL || key == SettingKeyAuditWebhookSecret {
|
||||
auditWebhookTouched = true
|
||||
}
|
||||
}
|
||||
// audit webhook 配置变化:立即同步到 AuditService,避免重启才生效
|
||||
if auditWebhookTouched && s.auditWebhook != nil {
|
||||
all, _ := s.GetAll(ctx)
|
||||
s.auditWebhook.SetWebhook(all[SettingKeyAuditWebhookURL], all[SettingKeyAuditWebhookSecret])
|
||||
}
|
||||
return s.GetAll(ctx)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user