feat(scheduler): lifecycle 真实接线适配器(2/2) + 装配 BuildRealConfig
把 scheduler 的 stub lifecycle 换成 SQL 后端真实实现,并接入 server:
- SQLLifecycle:MySQL 后端,同时满足 detect.LifecycleService 与
orchestrate.LifecycleService(两个 thin adapter 包装共享核心)。
- TransitionStatus:乐观锁 UPDATE nodes SET status WHERE id AND status=from
→ rows affected(1=成功/0=冲突 no-op)+ 写 node_events(按状态映射 enum,
eventForStatus 纯函数已单测)+ bump directory_version,全在一个事务内。
- ListNodes/GetNode/SetWeight/BumpVersion/GetLoad(读 LoadCache)/WriteAuditLog。
- 已知限制:无历史 load 表 → GetLoadHistory 返回当前点(掉量规则安全降级);
destroy 的 cert 撤销留 TODO(provision 已拆 VM,撤销为纵深防御,待机群再接)。
- BuildRealConfig:用真实 lifecycle + provisionAdapter 装配三循环。
- main.go:SCHED_ENABLED 且有 DB 时走 BuildRealConfig(provision 无厂商凭证则
CreateNode 优雅失败、替换保持 pending),否则回退 stub。
- 全量 server 23 包测试通过;e2e(判封→drain→换机→置备)待机群+厂商凭证验证。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -34,6 +34,8 @@ import (
|
||||
"github.com/wangjia/pangolin/server/internal/mtls"
|
||||
"github.com/wangjia/pangolin/server/internal/nodes"
|
||||
agentv1 "github.com/wangjia/pangolin/server/internal/pb/agentv1"
|
||||
"github.com/wangjia/pangolin/server/internal/provision"
|
||||
"github.com/wangjia/pangolin/server/internal/provision/providers"
|
||||
"github.com/wangjia/pangolin/server/internal/redisutil"
|
||||
"github.com/wangjia/pangolin/server/internal/scheduler"
|
||||
"github.com/wangjia/pangolin/server/internal/scheduler/probe"
|
||||
@@ -164,9 +166,29 @@ func main() {
|
||||
if ps == nil {
|
||||
ps = probe.NewStore(schedRDB)
|
||||
}
|
||||
cfg := scheduler.BuildStubConfig(schedRDB, ps)
|
||||
// TODO(#5): replace stub lifecycle with real LifecycleService
|
||||
// TODO(#14): replace stub provision with real ProvisionService
|
||||
// Prefer real lifecycle (SQL) + provision (#14) wiring when a DB is
|
||||
// available; fall back to no-op stubs otherwise. Without vendor
|
||||
// credentials the provision service's CreateNode fails gracefully
|
||||
// (pending replacements stay pending) while lifecycle reads/transitions
|
||||
// still operate on real node rows.
|
||||
var cfg scheduler.Config
|
||||
if sqlDB != nil {
|
||||
provStore := provision.NewMySQLStore(sqlDB)
|
||||
provSvc, perr := provision.NewService(provision.Config{
|
||||
Store: provStore,
|
||||
Adapters: providers.NewRegistry(),
|
||||
})
|
||||
if perr != nil {
|
||||
log.Printf("scheduler: provision service init failed (%v) — using stub config", perr)
|
||||
cfg = scheduler.BuildStubConfig(schedRDB, ps)
|
||||
} else {
|
||||
cfg = scheduler.BuildRealConfig(schedRDB, ps, sqlDB,
|
||||
nodes.NewLoadCache(schedRDB), provSvc, provStore)
|
||||
log.Printf("scheduler: real lifecycle + provision wired")
|
||||
}
|
||||
} else {
|
||||
cfg = scheduler.BuildStubConfig(schedRDB, ps)
|
||||
}
|
||||
sched := scheduler.New(cfg)
|
||||
|
||||
// sigCtx cancels on SIGINT/SIGTERM, giving the scheduler up to
|
||||
@@ -179,7 +201,7 @@ func main() {
|
||||
slog.Error("scheduler: Start error", "error", err)
|
||||
}
|
||||
}()
|
||||
log.Printf("scheduler started (SCHED_ENABLED=true, stub lifecycle/provision)")
|
||||
log.Printf("scheduler started (SCHED_ENABLED=true)")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user