feat: complete Kra admin backend migration

This commit is contained in:
2026-08-14 00:28:37 +08:00
parent c4bf7ee03b
commit acba9624d7
88 changed files with 1765 additions and 8623 deletions
+83 -2
View File
@@ -1,11 +1,14 @@
package data
import (
"context"
"encoding/json"
"fmt"
"os"
"path/filepath"
"kra/internal/conf"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/proto"
"gopkg.in/yaml.v3"
@@ -50,6 +53,10 @@ func setYAMLMapping(node *yaml.Node, key string, value any) error {
}
func (d *Data) persistConfig() error {
return d.persistConfigValues(d.config, d.admin)
}
func (d *Data) persistConfigValues(dataConfig *conf.Data, adminConfig *conf.AdminBackend) error {
if d.admin == nil || d.admin.ConfigPath == "" {
return nil
}
@@ -61,11 +68,11 @@ func (d *Data) persistConfig() error {
if err = yaml.Unmarshal(raw, &document); err != nil {
return err
}
dataValue, err := protoMap(d.config)
dataValue, err := protoMap(dataConfig)
if err != nil {
return err
}
adminValue, err := protoMap(d.admin)
adminValue, err := protoMap(adminConfig)
if err != nil {
return err
}
@@ -101,3 +108,77 @@ func (d *Data) persistConfig() error {
}
return os.Rename(tempName, d.admin.ConfigPath)
}
func (d *Data) reloadConfig(ctx context.Context) error {
if d.admin == nil || d.admin.ConfigPath == "" {
return fmt.Errorf("configuration path is not set")
}
raw, err := os.ReadFile(d.admin.ConfigPath)
if err != nil {
return err
}
var plain map[string]any
if err = yaml.Unmarshal(raw, &plain); err != nil {
return err
}
encoded, err := json.Marshal(plain)
if err != nil {
return err
}
var next conf.Bootstrap
if err = (protojson.UnmarshalOptions{DiscardUnknown: true}).Unmarshal(encoded, &next); err != nil {
return err
}
if next.Data == nil || next.Data.Database == nil || next.Admin == nil {
return fmt.Errorf("data.database and admin configuration are required")
}
next.Admin.ConfigPath = d.admin.ConfigPath
candidateDB, err := openDatabase(next.Data.Database, false, "")
if err != nil {
return fmt.Errorf("reload database: %w", err)
}
closeCandidate := true
defer func() {
if closeCandidate {
if sqlDB, closeErr := candidateDB.DB(); closeErr == nil {
_ = sqlDB.Close()
}
}
}()
if sqlDB, dbErr := candidateDB.DB(); dbErr != nil {
return dbErr
} else if err = sqlDB.PingContext(ctx); err != nil {
return fmt.Errorf("reload database: %w", err)
}
if err = migrateAll(candidateDB.WithContext(ctx)); err != nil {
return fmt.Errorf("reload database migrations: %w", err)
}
candidateStorage, err := buildFileStorage(next.Admin)
if err != nil {
return fmt.Errorf("reload storage: %w", err)
}
candidateRedis := openRedis(next.Data.Redis)
d.mu.Lock()
oldDB, oldRedis := d.gormDB, d.redis
d.gormDB, d.redis = candidateDB, candidateRedis
proto.Reset(d.config)
proto.Merge(d.config, next.Data)
proto.Reset(d.admin)
proto.Merge(d.admin, next.Admin)
d.database = d.config.Database
d.mu.Unlock()
if d.storage != nil {
d.storage.replace(candidateStorage)
}
closeCandidate = false
if oldDB != nil {
if sqlDB, closeErr := oldDB.DB(); closeErr == nil {
_ = sqlDB.Close()
}
}
if oldRedis != nil {
_ = oldRedis.Close()
}
return nil
}