diff --git a/management/server/migration/migration.go b/management/server/migration/migration.go index a14c24eea..9776418ad 100644 --- a/management/server/migration/migration.go +++ b/management/server/migration/migration.go @@ -1,6 +1,7 @@ package migration import ( + "database/sql" "encoding/gob" "encoding/json" "errors" @@ -121,7 +122,7 @@ func MigrateNetIPFieldFromBlobToJSON[T any](db *gorm.DB, fieldName string, index } tableName := stmt.Schema.Table - var item string + var item sql.NullString if err := db.Model(&model).Select(oldColumnName).First(&item).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { log.Printf("No records in table %s, no migration needed", tableName) @@ -130,12 +131,14 @@ func MigrateNetIPFieldFromBlobToJSON[T any](db *gorm.DB, fieldName string, index return fmt.Errorf("fetch first record: %w", err) } - var js json.RawMessage - var syntaxError *json.SyntaxError - err = json.Unmarshal([]byte(item), &js) - if err == nil || !errors.As(err, &syntaxError) { - log.Debugf("No migration needed for %s, %s", tableName, fieldName) - return nil + if item.Valid { + var js json.RawMessage + var syntaxError *json.SyntaxError + err = json.Unmarshal([]byte(item.String), &js) + if err == nil || !errors.As(err, &syntaxError) { + log.Debugf("No migration needed for %s, %s", tableName, fieldName) + return nil + } } if err := db.Transaction(func(tx *gorm.DB) error { @@ -153,12 +156,22 @@ func MigrateNetIPFieldFromBlobToJSON[T any](db *gorm.DB, fieldName string, index } for _, row := range rows { - blob, ok := row[oldColumnName].(string) - if !ok { - return fmt.Errorf("type assertion failed") + var blobValue string + if columnValue := row[oldColumnName]; columnValue != nil { + value, ok := columnValue.(string) + if !ok { + return fmt.Errorf("type assertion failed") + } + blobValue = value } - jsonValue, err := json.Marshal(net.IP(blob)) + columnIpValue := net.IP(blobValue) + if net.ParseIP(columnIpValue.String()) == nil { + log.Debugf("failed to parse %s as ip, fallback to ipv6 loopback", oldColumnName) + columnIpValue = net.IPv6loopback + } + + jsonValue, err := json.Marshal(columnIpValue) if err != nil { return fmt.Errorf("re-encode to JSON: %w", err) } diff --git a/management/server/sqlite_store.go b/management/server/sqlite_store.go index b02e4cdc3..36cb9b671 100644 --- a/management/server/sqlite_store.go +++ b/management/server/sqlite_store.go @@ -578,10 +578,10 @@ func getMigrations() []migrationFunc { return migration.MigrateFieldFromGobToJSON[route.Route, []string](db, "peer_groups") }, func(db *gorm.DB) error { - return migration.MigrateNetIPFieldFromBlobToJSON[nbpeer.Peer](db, "ip", "idx_peers_account_id_ip") + return migration.MigrateNetIPFieldFromBlobToJSON[nbpeer.Peer](db, "location_connection_ip", "") }, func(db *gorm.DB) error { - return migration.MigrateNetIPFieldFromBlobToJSON[nbpeer.Peer](db, "location_connection_ip", "") + return migration.MigrateNetIPFieldFromBlobToJSON[nbpeer.Peer](db, "ip", "idx_peers_account_id_ip") }, } }