mirror of https://github.com/h44z/wg-portal.git
				
				
				
			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 { | ||||||
|  |  | ||||||
|  | @ -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