mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-09-29 05:56:38 +08:00
migrate
This commit is contained in:
@@ -15,6 +15,7 @@ const (
|
||||
errNodeIDConflict = "节点标识生成冲突,请重试"
|
||||
errNodeNotFound = "节点不存在"
|
||||
errNodeForceSyncFailed = "节点不在线或通过 WebSocket 发送同步指令失败"
|
||||
errNoActiveConfigVersion = "当前没有激活版本"
|
||||
errAgentPreviewTagInvalid = "指定版本不是 preview 发布"
|
||||
errAgentStableTagInvalid = "正式版更新不能选择 preview 发布"
|
||||
)
|
||||
|
||||
@@ -12,7 +12,9 @@ import (
|
||||
|
||||
"github.com/Rain-kl/Wavelet/internal/apps/openflare/observability"
|
||||
"github.com/Rain-kl/Wavelet/internal/apps/openflare/option"
|
||||
ofws "github.com/Rain-kl/Wavelet/internal/apps/openflare/websocket"
|
||||
"github.com/Rain-kl/Wavelet/internal/model"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// Input is the create/update node payload.
|
||||
@@ -326,13 +328,23 @@ func RequestOpenrestyRestart(ctx context.Context, id uint) (*View, error) {
|
||||
return buildNodeView(node), nil
|
||||
}
|
||||
|
||||
// RequestForceSync requests a force sync via websocket (stub until T-AGENT).
|
||||
// RequestForceSync pushes force_sync_config to a connected agent websocket.
|
||||
func RequestForceSync(ctx context.Context, id uint) (*View, error) {
|
||||
node, err := model.GetOpenFlareNodeByID(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !sendAgentWSForceSyncConfig(node.NodeID) {
|
||||
activeConfig, err := model.GetActiveConfigVersion(ctx)
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, fmt.Errorf("无法获取当前激活的配置版本:%s", errNoActiveConfigVersion)
|
||||
}
|
||||
return nil, fmt.Errorf("无法获取当前激活的配置版本:%v", err)
|
||||
}
|
||||
if !ofws.SendForceSyncConfig(node.NodeID, forceSyncConfigPayload{
|
||||
Version: activeConfig.Version,
|
||||
Checksum: activeConfig.Checksum,
|
||||
}) {
|
||||
return nil, errors.New(errNodeForceSyncFailed)
|
||||
}
|
||||
return buildNodeView(node), nil
|
||||
@@ -371,9 +383,9 @@ func ensureGlobalDiscoveryToken(ctx context.Context) (string, error) {
|
||||
return token, nil
|
||||
}
|
||||
|
||||
func sendAgentWSForceSyncConfig(nodeID string) bool {
|
||||
_ = nodeID
|
||||
return false
|
||||
type forceSyncConfigPayload struct {
|
||||
Version string `json:"version"`
|
||||
Checksum string `json:"checksum"`
|
||||
}
|
||||
|
||||
// ValidateDiscoveryToken validates the global discovery token.
|
||||
|
||||
@@ -244,10 +244,26 @@ func TestRequestOpenrestyRestart(t *testing.T) {
|
||||
assert.True(t, updated.RestartOpenrestyRequested)
|
||||
}
|
||||
|
||||
func TestRequestForceSyncStub(t *testing.T) {
|
||||
func seedActiveConfigVersion(t *testing.T, ctx context.Context) {
|
||||
t.Helper()
|
||||
conn := db.DB(ctx)
|
||||
require.NotNil(t, conn)
|
||||
require.NoError(t, conn.AutoMigrate(&model.ConfigVersion{}))
|
||||
require.NoError(t, conn.Create(&model.ConfigVersion{
|
||||
Version: "20260618-001",
|
||||
SnapshotJSON: `{}`,
|
||||
RenderedConfig: `server {}`,
|
||||
Checksum: "abc123",
|
||||
IsActive: true,
|
||||
CreatedBy: "test",
|
||||
}).Error)
|
||||
}
|
||||
|
||||
func TestRequestForceSyncRequiresWebSocket(t *testing.T) {
|
||||
cleanup := setupNodeTestDB(t)
|
||||
defer cleanup()
|
||||
ctx := context.Background()
|
||||
seedActiveConfigVersion(t, ctx)
|
||||
|
||||
created, err := CreateNode(ctx, Input{Name: "edge-sync"})
|
||||
require.NoError(t, err)
|
||||
@@ -257,6 +273,22 @@ func TestRequestForceSyncStub(t *testing.T) {
|
||||
assert.Equal(t, errNodeForceSyncFailed, err.Error())
|
||||
}
|
||||
|
||||
func TestRequestForceSyncRequiresActiveConfig(t *testing.T) {
|
||||
cleanup := setupNodeTestDB(t)
|
||||
defer cleanup()
|
||||
ctx := context.Background()
|
||||
conn := db.DB(ctx)
|
||||
require.NotNil(t, conn)
|
||||
require.NoError(t, conn.AutoMigrate(&model.ConfigVersion{}))
|
||||
|
||||
created, err := CreateNode(ctx, Input{Name: "edge-sync-active"})
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = RequestForceSync(ctx, created.ID)
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), errNoActiveConfigVersion)
|
||||
}
|
||||
|
||||
func TestGetObservabilityStub(t *testing.T) {
|
||||
cleanup := setupNodeTestDB(t)
|
||||
defer cleanup()
|
||||
|
||||
@@ -37,6 +37,7 @@ sidebar: false
|
||||
- 新增 `internal/apps/openflare/tasks/` 集中承载 OpenFlare 定时/后台任务(主进程 cron,非 Asynq),含数据库可观测性自动清理、WAF IP 组周期同步、UptimeKuma 同步、ACME 证书自动续期。
|
||||
- 实装数据库可观测性手动/自动清理、WAF IP 组订阅/自动同步与测试接口、UptimeKuma 监控同步、TLS ACME 申请/续期(lego DNS-01)。
|
||||
- 修复 Wavelet Agent WebSocket 未处理 `status` 消息导致 WS 模式下 `last_seen_at` 停止更新、节点超时显示离线的问题;列表「最近心跳」恢复显示「WS 已连接」。
|
||||
- 修复节点「强制同步」仍为 stub 导致始终返回「节点不在线或通过 WebSocket 发送同步指令失败」的问题。
|
||||
|
||||
## [v2.3.4] - 2026-06-17
|
||||
|
||||
|
||||
Reference in New Issue
Block a user