diff --git a/client/internal/engine.go b/client/internal/engine.go index 75f1d1012..80dfb10bf 100644 --- a/client/internal/engine.go +++ b/client/internal/engine.go @@ -76,6 +76,9 @@ const ( PeerConnectionTimeoutMax = 45000 // ms PeerConnectionTimeoutMin = 30000 // ms connInitLimit = 200 + // skipAutoUpdateVersion used as a placeholder for autoUpdateVersion in proto responses to indicate response contains no new updates + skipAutoUpdateVersion = "skip" + disableAutoUpdate = "disabled" ) var ErrResetConnection = fmt.Errorf("reset connection") @@ -704,15 +707,17 @@ func (e *Engine) handleSync(update *mgmProto.SyncResponse) error { e.syncMsgMux.Lock() defer e.syncMsgMux.Unlock() - if e.updateManager == nil && update.GetAutoUpdateVersion() != "disabled" { - e.updateManager = updatemanager.NewUpdateManager(e.statusRecorder) - e.updateManager.Start(e.ctx) - } else if e.updateManager != nil && update.GetAutoUpdateVersion() == "disabled" { - e.updateManager.Stop() - e.updateManager = nil - } - if e.updateManager != nil { - e.updateManager.SetVersion(update.GetAutoUpdateVersion()) + if update.GetAutoUpdateVersion() != skipAutoUpdateVersion { + if e.updateManager == nil && update.GetAutoUpdateVersion() != disableAutoUpdate { + e.updateManager = updatemanager.NewUpdateManager(e.statusRecorder) + e.updateManager.Start(e.ctx) + } else if e.updateManager != nil && update.GetAutoUpdateVersion() == disableAutoUpdate { + e.updateManager.Stop() + e.updateManager = nil + } + if e.updateManager != nil { + e.updateManager.SetVersion(update.GetAutoUpdateVersion()) + } } if update.GetNetbirdConfig() != nil { wCfg := update.GetNetbirdConfig() diff --git a/client/internal/updatemanager/manager.go b/client/internal/updatemanager/manager.go index b537f0df1..d82f79ebe 100644 --- a/client/internal/updatemanager/manager.go +++ b/client/internal/updatemanager/manager.go @@ -34,8 +34,9 @@ type UpdateManager struct { cancel context.CancelFunc update *version.Update - expectedVersion string - expectedVersionMutex sync.Mutex + expectedVersion *v.Version + updateToLatestVersion bool + expectedVersionMutex sync.Mutex } func NewUpdateManager(statusRecorder *peer.Status) *UpdateManager { @@ -69,7 +70,7 @@ func (u *UpdateManager) Start(ctx context.Context) { go u.updateLoop(ctx) } -func (u *UpdateManager) SetVersion(v string) { +func (u *UpdateManager) SetVersion(expectedVersion string) { if u.cancel == nil { log.Errorf("UpdateManager not started") return @@ -77,12 +78,22 @@ func (u *UpdateManager) SetVersion(v string) { u.expectedVersionMutex.Lock() defer u.expectedVersionMutex.Unlock() - if u.expectedVersion == v { - return + if expectedVersion == latestVersion { + u.updateToLatestVersion = true + u.expectedVersion = nil + } else { + expectedSemVer, err := v.NewVersion(expectedVersion) + if err != nil { + log.Errorf("Error parsing version: %v", err) + return + } + if u.expectedVersion.Equal(expectedSemVer) { + return + } + u.expectedVersion = expectedSemVer + u.updateToLatestVersion = false } - u.expectedVersion = v - select { case u.mgmUpdateChan <- struct{}{}: default: @@ -126,19 +137,17 @@ func (u *UpdateManager) handleUpdate(ctx context.Context) { u.expectedVersionMutex.Unlock() // Resolve "latest" to actual version - if expectedVersion == latestVersion { + if u.updateToLatestVersion { if !u.isVersionAvailable() { log.Tracef("Latest version not fetched yet") return } updateVersion = u.update.LatestVersion() + } else if u.expectedVersion != nil { + updateVersion = expectedVersion } else { - var err error - updateVersion, err = v.NewSemver(expectedVersion) - if err != nil { - log.Errorf("Failed to parse latest version: %v", err) - return - } + log.Debugf("No expected version information set") + return } if !u.shouldUpdate(updateVersion) { diff --git a/management/server/account.go b/management/server/account.go index a2a9e3b67..a8bdafa3d 100644 --- a/management/server/account.go +++ b/management/server/account.go @@ -52,6 +52,8 @@ const ( peerSchedulerRetryInterval = 3 * time.Second emptyUserID = "empty user ID in claims" errorGettingDomainAccIDFmt = "error getting account ID by private domain: %v" + // skipAutoUpdateVersion used as a placeholder for autoUpdateVersion in proto responses to indicate response contains no new updates + skipAutoUpdateVersion = "skip" ) type userLoggedInOnce bool diff --git a/management/server/http/handlers/accounts/accounts_handler.go b/management/server/http/handlers/accounts/accounts_handler.go index 23adc077f..634ff87e0 100644 --- a/management/server/http/handlers/accounts/accounts_handler.go +++ b/management/server/http/handlers/accounts/accounts_handler.go @@ -28,7 +28,9 @@ const ( // MinNetworkBits is the minimum prefix length for IPv4 network ranges (e.g., /29 gives 8 addresses, /28 gives 16) MinNetworkBitsIPv4 = 28 // MinNetworkBitsIPv6 is the minimum prefix length for IPv6 network ranges - MinNetworkBitsIPv6 = 120 + MinNetworkBitsIPv6 = 120 + disableAutoUpdate = "disabled" + autoUpdateLatestVersion = "latest" ) // handler is a handler that handles the server.Account HTTP endpoints @@ -206,8 +208,8 @@ func (h *handler) updateAccountRequestSettings(req api.PutApiAccountsAccountIdJS } if req.Settings.AutoUpdateVersion != nil { _, err := goversion.NewSemver(*req.Settings.AutoUpdateVersion) - if *req.Settings.AutoUpdateVersion == "latest" || - *req.Settings.AutoUpdateVersion == "disabled" || + if *req.Settings.AutoUpdateVersion == autoUpdateLatestVersion || + *req.Settings.AutoUpdateVersion == disableAutoUpdate || err == nil { returnSettings.AutoUpdateVersion = *req.Settings.AutoUpdateVersion } else if *req.Settings.AutoUpdateVersion != "" { diff --git a/management/server/token_mgr.go b/management/server/token_mgr.go index 7f5d26b39..5ff381d84 100644 --- a/management/server/token_mgr.go +++ b/management/server/token_mgr.go @@ -210,7 +210,7 @@ func (m *TimeBasedAuthSecretsManager) pushNewTURNAndRelayTokens(ctx context.Cont NetbirdConfig: &proto.NetbirdConfig{ Turns: turns, }, - AutoUpdateVersion: "skip", + AutoUpdateVersion: skipAutoUpdateVersion, } // workaround for the case when client is unable to handle turn and relay updates at different time @@ -247,7 +247,7 @@ func (m *TimeBasedAuthSecretsManager) pushNewRelayTokens(ctx context.Context, ac }, // omit Turns to avoid updates there }, - AutoUpdateVersion: "skip", + AutoUpdateVersion: skipAutoUpdateVersion, } m.extendNetbirdConfig(ctx, peerID, accountID, update)