[优化] 压缩脚本到 V16

This commit is contained in:
ryan
2026-06-01 19:36:52 +08:00
parent 581822d905
commit e00d67f2d9
10 changed files with 181 additions and 487 deletions
+114 -34
View File
@@ -1,23 +1,46 @@
// v16 is the first database migration after the V15 formal release baseline.
// It folds the previously drafted v16-v21 schema work into a single official
// upgrade: tunnel-relay fields, WAF IP groups, current node identity/version
// columns, and split node observation tables. The migration also backfills
// legacy node columns and removes obsolete pre-release tunnel metadata when
// present, so V15 deployments can upgrade directly to the new formal schema.
package migrate
import (
"fmt"
"log/slog"
"gorm.io/gorm"
)
type nodeV16 struct {
NodeType string `gorm:"column:node_type;not null;default:'edge_node'"`
RelayBindPort int `gorm:"column:relay_bind_port"`
func (nodeV16) TableName() string {
return "nodes"
}
type tunnelV16 struct {
ID uint `gorm:"primaryKey"`
func (tunnelV16) TableName() string {
return "tunnels"
}
type proxyRouteV16 struct {
UpstreamType string `gorm:"column:upstream_type;not null;default:'direct'"`
TunnelID *uint `gorm:"column:tunnel_id"`
func (proxyRouteV16) TableName() string {
return "proxy_routes"
}
type nodeV16 struct{}
type tunnelV16 struct{}
type proxyRouteV16 struct{}
type wafIPGroupV16 struct{}
type wafRuleGroupV16 struct{}
func (wafIPGroupV16) TableName() string {
return "waf_ip_groups"
}
func (wafRuleGroupV16) TableName() string {
return "waf_rule_groups"
}
func init() {
@@ -33,28 +56,50 @@ func V16() Migration {
}
}
func (nodeV16) TableName() string {
return "nodes"
}
func (tunnelV16) TableName() string {
return "tunnels"
}
func (proxyRouteV16) TableName() string {
return "proxy_routes"
}
func migrateV16(ctx Context, db *gorm.DB, backend string) error {
if err := db.AutoMigrate(&tunnelV16{}); err != nil {
return fmt.Errorf("auto migrate tunnelV16: %w", err)
if err := ctx.ApplyCurrentSchema(db, backend); err != nil {
return err
}
migrator := db.Migrator()
if migrator.HasColumn(&nodeV16{}, "agent_token") {
if err := db.Exec(`UPDATE nodes SET access_token = agent_token WHERE access_token IS NULL OR access_token = ''`).Error; err != nil {
return fmt.Errorf("backfill nodes.access_token from agent_token: %w", err)
}
}
if migrator.HasColumn(&nodeV16{}, "agent_version") {
if err := db.Exec(`UPDATE nodes SET version = agent_version WHERE version = '' OR version IS NULL`).Error; err != nil {
return fmt.Errorf("backfill nodes.version from agent_version: %w", err)
}
}
if migrator.HasColumn(&nodeV16{}, "nginx_version") {
if err := db.Exec(`UPDATE nodes SET ext_version = nginx_version WHERE ext_version IS NULL OR ext_version = ''`).Error; err != nil {
return fmt.Errorf("backfill nodes.ext_version from nginx_version: %w", err)
}
}
if err := db.Exec("UPDATE nodes SET node_type = 'edge_node' WHERE node_type = '' OR node_type IS NULL").Error; err != nil {
return fmt.Errorf("backfill nodes.node_type: %w", err)
}
if err := db.Exec("UPDATE proxy_routes SET upstream_type = 'direct' WHERE upstream_type = '' OR upstream_type IS NULL").Error; err != nil {
return fmt.Errorf("backfill proxy_routes.upstream_type: %w", err)
}
if migrator.HasColumn(&proxyRouteV16{}, "tunnel_id") {
if err := db.Model(&proxyRouteV16{}).Where("upstream_type = ?", "tunnel").Update("upstream_type", "direct").Error; err != nil {
return fmt.Errorf("reset pre-release tunnel proxy routes: %w", err)
}
if err := migrator.DropColumn(&proxyRouteV16{}, "tunnel_id"); err != nil {
return fmt.Errorf("drop pre-release proxy_routes.tunnel_id: %w", err)
}
}
if migrator.HasTable(&tunnelV16{}) {
if err := migrator.DropTable(&tunnelV16{}); err != nil {
return fmt.Errorf("drop pre-release tunnels table: %w", err)
}
slog.Info("dropped pre-release tunnels table during v16 migration")
}
return nil
}
@@ -62,22 +107,57 @@ func validateV16(ctx Context, db *gorm.DB, backend string) error {
if err := ctx.ValidateDatabaseSchemaVersion(db, backend, 15); err != nil {
return err
}
if !db.Migrator().HasColumn(&proxyRouteV16{}, "tunnel_node_id") {
if db == nil || !db.Migrator().HasTable(&tunnelV16{}) {
return fmt.Errorf("table tunnels is missing")
}
if !db.Migrator().HasColumn(&proxyRouteV16{}, "tunnel_id") {
return fmt.Errorf("column proxy_routes.tunnel_id is missing")
if db == nil {
return fmt.Errorf("database handle is nil")
}
migrator := db.Migrator()
for _, column := range []string{
"access_token",
"version",
"ext_version",
"node_type",
"relay_bind_port",
"relay_vhost_http_port",
"relay_auth_token",
"relay_agent_access_addr",
"relay_client_access_addr",
"relay_client_proxy_url",
"relay_status",
} {
if !migrator.HasColumn(&nodeV16{}, column) {
return fmt.Errorf("column nodes.%s is missing", column)
}
}
if !db.Migrator().HasColumn(&nodeV16{}, "node_type") {
return fmt.Errorf("column nodes.node_type is missing")
for _, column := range []string{
"upstream_type",
"tunnel_node_id",
"tunnel_target_addr",
"tunnel_target_protocol",
} {
if !migrator.HasColumn(&proxyRouteV16{}, column) {
return fmt.Errorf("column proxy_routes.%s is missing", column)
}
}
if !db.Migrator().HasColumn(&proxyRouteV16{}, "upstream_type") {
return fmt.Errorf("column proxy_routes.upstream_type is missing")
if migrator.HasColumn(&proxyRouteV16{}, "tunnel_id") {
return fmt.Errorf("column proxy_routes.tunnel_id should not exist in v16")
}
if !db.Migrator().HasColumn(&nodeV16{}, "relay_bind_port") {
return fmt.Errorf("column nodes.relay_bind_port is missing")
if migrator.HasTable(&tunnelV16{}) {
return fmt.Errorf("table tunnels should not exist in v16")
}
if !migrator.HasTable(&wafIPGroupV16{}) {
return fmt.Errorf("table waf_ip_groups is missing")
}
for _, column := range []string{
"ip_whitelist_groups",
"ip_blacklist_groups",
} {
if !migrator.HasColumn(&wafRuleGroupV16{}, column) {
return fmt.Errorf("column waf_rule_groups.%s is missing", column)
}
}
if !migrator.HasColumn(&wafIPGroupV16{}, "ext_ips") {
return fmt.Errorf("column waf_ip_groups.ext_ips is missing")
}
return nil
}