mirror of
https://github.com/DJSundog/wg-portal.git
synced 2024-11-23 07:03:50 -05:00
simple database migration versioning, todo: implement migrations
This commit is contained in:
parent
b4f3228bec
commit
8f21c12c3d
@ -74,3 +74,36 @@ func GetDatabaseForConfig(cfg *DatabaseConfig) (db *gorm.DB, err error) {
|
|||||||
db.Config.Logger = logger.New(logrus.StandardLogger(), logCfg)
|
db.Config.Logger = logger.New(logrus.StandardLogger(), logCfg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DatabaseMigrationInfo struct {
|
||||||
|
Version string `gorm:"primaryKey"`
|
||||||
|
Applied time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
func MigrateDatabase(db *gorm.DB, version string) error {
|
||||||
|
if err := db.AutoMigrate(&DatabaseMigrationInfo{}); err != nil {
|
||||||
|
return errors.Wrap(err, "failed to migrate version database")
|
||||||
|
}
|
||||||
|
|
||||||
|
newVersion := DatabaseMigrationInfo{
|
||||||
|
Version: version,
|
||||||
|
Applied: time.Now(),
|
||||||
|
}
|
||||||
|
|
||||||
|
existingMigration := DatabaseMigrationInfo{}
|
||||||
|
db.Where("version = ?", version).FirstOrInit(&existingMigration)
|
||||||
|
|
||||||
|
if existingMigration.Version == "" {
|
||||||
|
lastVersion := DatabaseMigrationInfo{}
|
||||||
|
db.Order("applied desc, version desc").FirstOrInit(&lastVersion)
|
||||||
|
|
||||||
|
// TODO: migrate database
|
||||||
|
|
||||||
|
res := db.Create(&newVersion)
|
||||||
|
if res.Error != nil {
|
||||||
|
return errors.Wrap(res.Error, "failed to write version to database")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -103,6 +103,10 @@ func (s *Server) Setup(ctx context.Context) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.WithMessage(err, "database setup failed")
|
return errors.WithMessage(err, "database setup failed")
|
||||||
}
|
}
|
||||||
|
err = common.MigrateDatabase(s.db, Version)
|
||||||
|
if err != nil {
|
||||||
|
return errors.WithMessage(err, "database migration failed")
|
||||||
|
}
|
||||||
|
|
||||||
// Setup http server
|
// Setup http server
|
||||||
gin.SetMode(gin.DebugMode)
|
gin.SetMode(gin.DebugMode)
|
||||||
@ -183,9 +187,6 @@ func (s *Server) Setup(ctx context.Context) error {
|
|||||||
if s.peers, err = wireguard.NewPeerManager(s.db, s.wg); err != nil {
|
if s.peers, err = wireguard.NewPeerManager(s.db, s.wg); err != nil {
|
||||||
return errors.WithMessage(err, "unable to setup peer manager")
|
return errors.WithMessage(err, "unable to setup peer manager")
|
||||||
}
|
}
|
||||||
if err = s.peers.InitFromPhysicalInterface(); err != nil {
|
|
||||||
return errors.WithMessagef(err, "unable to initialize peer manager")
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, deviceName := range s.wg.Cfg.DeviceNames {
|
for _, deviceName := range s.wg.Cfg.DeviceNames {
|
||||||
if err = s.RestoreWireGuardInterface(deviceName); err != nil {
|
if err = s.RestoreWireGuardInterface(deviceName); err != nil {
|
||||||
|
3
internal/server/version.go
Normal file
3
internal/server/version.go
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
var Version = "1.0.5"
|
@ -70,7 +70,7 @@ type Peer struct {
|
|||||||
|
|
||||||
UID string `form:"uid" binding:"required,alphanum"` // uid for html identification
|
UID string `form:"uid" binding:"required,alphanum"` // uid for html identification
|
||||||
DeviceName string `gorm:"index" form:"device" binding:"required"`
|
DeviceName string `gorm:"index" form:"device" binding:"required"`
|
||||||
DeviceType DeviceType `gorm:"-" form:"devicetype" binding:"required,oneof=client server custom"`
|
DeviceType DeviceType `gorm:"-" form:"devicetype" binding:"required,oneof=client server"`
|
||||||
Identifier string `form:"identifier" binding:"required,max=64"` // Identifier AND Email make a WireGuard peer unique
|
Identifier string `form:"identifier" binding:"required,max=64"` // Identifier AND Email make a WireGuard peer unique
|
||||||
Email string `gorm:"index" form:"mail" binding:"required,email"`
|
Email string `gorm:"index" form:"mail" binding:"required,email"`
|
||||||
IgnoreGlobalSettings bool `form:"ignoreglobalsettings"`
|
IgnoreGlobalSettings bool `form:"ignoreglobalsettings"`
|
||||||
@ -223,7 +223,7 @@ const (
|
|||||||
type Device struct {
|
type Device struct {
|
||||||
Interface *wgtypes.Device `gorm:"-"`
|
Interface *wgtypes.Device `gorm:"-"`
|
||||||
|
|
||||||
Type DeviceType `form:"devicetype" binding:"required,oneof=client server custom"`
|
Type DeviceType `form:"devicetype" binding:"required,oneof=client server"`
|
||||||
DeviceName string `form:"device" gorm:"primaryKey" binding:"required,alphanum"`
|
DeviceName string `form:"device" gorm:"primaryKey" binding:"required,alphanum"`
|
||||||
DisplayName string `form:"displayname" binding:"omitempty,max=200"`
|
DisplayName string `form:"displayname" binding:"omitempty,max=200"`
|
||||||
|
|
||||||
@ -344,10 +344,31 @@ type PeerManager struct {
|
|||||||
func NewPeerManager(db *gorm.DB, wg *Manager) (*PeerManager, error) {
|
func NewPeerManager(db *gorm.DB, wg *Manager) (*PeerManager, error) {
|
||||||
pm := &PeerManager{db: db, wg: wg}
|
pm := &PeerManager{db: db, wg: wg}
|
||||||
|
|
||||||
|
// check if old device table exists (from version <= 1.0.3), if so migrate it.
|
||||||
|
if db.Migrator().HasColumn(&Device{}, "endpoint") {
|
||||||
|
if err := db.Migrator().RenameColumn(&Device{}, "endpoint", "default_endpoint"); err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "failed to migrate old database structure for column endpoint")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if db.Migrator().HasColumn(&Device{}, "allowed_ips_str") {
|
||||||
|
if err := db.Migrator().RenameColumn(&Device{}, "allowed_ips_str", "default_allowed_ips_str"); err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "failed to migrate old database structure for column allowed_ips_str")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if db.Migrator().HasColumn(&Device{}, "persistent_keepalive") {
|
||||||
|
if err := db.Migrator().RenameColumn(&Device{}, "persistent_keepalive", "default_persistent_keepalive"); err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "failed to migrate old database structure for column persistent_keepalive")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err := pm.db.AutoMigrate(&Peer{}, &Device{}); err != nil {
|
if err := pm.db.AutoMigrate(&Peer{}, &Device{}); err != nil {
|
||||||
return nil, errors.WithMessage(err, "failed to migrate peer database")
|
return nil, errors.WithMessage(err, "failed to migrate peer database")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := pm.initFromPhysicalInterface(); err != nil {
|
||||||
|
return nil, errors.WithMessagef(err, "unable to initialize peer manager")
|
||||||
|
}
|
||||||
|
|
||||||
// check if peers without device name exist (from version <= 1.0.3), if so assign them to the default device.
|
// check if peers without device name exist (from version <= 1.0.3), if so assign them to the default device.
|
||||||
peers := make([]Peer, 0)
|
peers := make([]Peer, 0)
|
||||||
pm.db.Find(&peers)
|
pm.db.Find(&peers)
|
||||||
@ -361,7 +382,7 @@ func NewPeerManager(db *gorm.DB, wg *Manager) (*PeerManager, error) {
|
|||||||
// validate and update existing peers if needed
|
// validate and update existing peers if needed
|
||||||
for _, deviceName := range wg.Cfg.DeviceNames {
|
for _, deviceName := range wg.Cfg.DeviceNames {
|
||||||
dev := pm.GetDevice(deviceName)
|
dev := pm.GetDevice(deviceName)
|
||||||
peers = pm.GetAllPeers(deviceName)
|
peers := pm.GetAllPeers(deviceName)
|
||||||
for i := range peers {
|
for i := range peers {
|
||||||
if err := pm.fixPeerDefaultData(&peers[i], &dev); err != nil {
|
if err := pm.fixPeerDefaultData(&peers[i], &dev); err != nil {
|
||||||
return nil, errors.WithMessagef(err, "unable to fix peers for interface %s", deviceName)
|
return nil, errors.WithMessagef(err, "unable to fix peers for interface %s", deviceName)
|
||||||
@ -372,9 +393,9 @@ func NewPeerManager(db *gorm.DB, wg *Manager) (*PeerManager, error) {
|
|||||||
return pm, nil
|
return pm, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitFromPhysicalInterface read all WireGuard peers from the WireGuard interface configuration. If a peer does not
|
// initFromPhysicalInterface read all WireGuard peers from the WireGuard interface configuration. If a peer does not
|
||||||
// exist in the local database, it gets created.
|
// exist in the local database, it gets created.
|
||||||
func (m *PeerManager) InitFromPhysicalInterface() error {
|
func (m *PeerManager) initFromPhysicalInterface() error {
|
||||||
for _, deviceName := range m.wg.Cfg.DeviceNames {
|
for _, deviceName := range m.wg.Cfg.DeviceNames {
|
||||||
peers, err := m.wg.GetPeerList(deviceName)
|
peers, err := m.wg.GetPeerList(deviceName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -415,7 +436,7 @@ func (m *PeerManager) InitFromPhysicalInterface() error {
|
|||||||
// assumption: server mode is used
|
// assumption: server mode is used
|
||||||
func (m *PeerManager) validateOrCreatePeer(device string, wgPeer wgtypes.Peer) error {
|
func (m *PeerManager) validateOrCreatePeer(device string, wgPeer wgtypes.Peer) error {
|
||||||
peer := Peer{}
|
peer := Peer{}
|
||||||
m.db.Where("public_key = ? OR endpoint_public_key = ?", wgPeer.PublicKey.String(), wgPeer.PublicKey.String()).FirstOrInit(&peer)
|
m.db.Where("public_key = ?", wgPeer.PublicKey.String()).FirstOrInit(&peer)
|
||||||
|
|
||||||
dev := m.GetDevice(device)
|
dev := m.GetDevice(device)
|
||||||
|
|
||||||
@ -450,6 +471,14 @@ func (m *PeerManager) validateOrCreatePeer(device string, wgPeer wgtypes.Peer) e
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if peer.DeviceName == "" {
|
||||||
|
peer.DeviceName = device
|
||||||
|
res := m.db.Save(&peer)
|
||||||
|
if res.Error != nil {
|
||||||
|
return errors.Wrapf(res.Error, "failed to update autodetected peer %s", peer.PublicKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -479,6 +508,15 @@ func (m *PeerManager) validateOrCreateDevice(dev wgtypes.Device, ipAddresses []s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if device.Type == "" {
|
||||||
|
device.Type = DeviceTypeServer // from version <= 1.0.3, only server mode devices were supported
|
||||||
|
|
||||||
|
res := m.db.Save(&device)
|
||||||
|
if res.Error != nil {
|
||||||
|
return errors.Wrapf(res.Error, "failed to update autodetected device")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user