mirror of
https://github.com/Awuqing/BackupX.git
synced 2026-05-27 19:19:35 +08:00
节点池动态调度(企业集群核心需求): - model.Node 新增 Labels CSV;Node.HasLabel / LabelSet 辅助方法 - model.BackupTask 新增 NodePoolTag;与 NodeID 互斥(校验层拒绝同时设置) - BackupExecutionService.selectPoolNode:匹配标签的在线节点中选"运行中任务最少" 并列按 ID 升序稳定;空池返回 NODE_POOL_EMPTY 让用户立即感知 - 选中节点仅写 BackupRecord,不回写 task.NodeID —— 每次执行重选实现真轮转均衡 Grafana Dashboard(v2.1 指标的可视化闭环): - deploy/grafana/backupx-dashboard.json:11 个面板覆盖概览/时序/容量/集群 - deploy/grafana/README.md:Prometheus 抓取配置 + 告警建议 - release workflow 打包 grafana/ + nginx.conf 到 tar.gz 前端: - 节点列表:Agent 版本 vs Master 不一致时橙红 Tag + Tooltip 提示升级 - 节点列表新增"标签/节点池"列,支持 CSV 编辑 + 并发/带宽一起改 - 任务表单新增 NodePoolTag 输入框,与节点选择器互斥禁用 测试: - model/node_label_test.go:HasLabel / LabelSet / nil 安全 - service/node_pool_scheduler_test.go:负载最低优先 / 空池错误 / nil repo 降级 - go test ./... + npm run build 全绿
48 lines
1.1 KiB
Go
48 lines
1.1 KiB
Go
package model
|
|
|
|
import "testing"
|
|
|
|
func TestNodeHasLabel(t *testing.T) {
|
|
cases := []struct {
|
|
labels string
|
|
tag string
|
|
want bool
|
|
}{
|
|
{"prod,db,high-mem", "prod", true},
|
|
{"prod,db,high-mem", "db", true},
|
|
{"prod,db,high-mem", "backup", false},
|
|
{" prod , db ", "db", true}, // trim 空白
|
|
{"", "prod", false},
|
|
{"prod", "", false}, // 空 tag 不匹配
|
|
}
|
|
for _, c := range cases {
|
|
n := &Node{Labels: c.labels}
|
|
if got := n.HasLabel(c.tag); got != c.want {
|
|
t.Errorf("labels=%q tag=%q want %v got %v", c.labels, c.tag, c.want, got)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestNodeLabelSet(t *testing.T) {
|
|
n := &Node{Labels: "prod, db ,,high-mem,prod"}
|
|
set := n.LabelSet()
|
|
for _, want := range []string{"prod", "db", "high-mem"} {
|
|
if _, ok := set[want]; !ok {
|
|
t.Errorf("expected label %q in set", want)
|
|
}
|
|
}
|
|
if len(set) != 3 {
|
|
t.Errorf("duplicates not deduped, got %v", set)
|
|
}
|
|
}
|
|
|
|
func TestNilNodeHasLabelSafe(t *testing.T) {
|
|
var n *Node
|
|
if n.HasLabel("anything") {
|
|
t.Error("nil node should never match any label")
|
|
}
|
|
if s := n.LabelSet(); s != nil {
|
|
t.Errorf("nil node LabelSet should be nil, got %v", s)
|
|
}
|
|
}
|