mirror of
https://github.com/safing/portmaster
synced 2025-09-02 02:29:12 +00:00
Merge pull request #784 from safing/fix/abort-delayed-restart
Abort restarts if updated version is rolled back
This commit is contained in:
commit
6520e4d192
3 changed files with 75 additions and 26 deletions
|
@ -65,6 +65,8 @@ const (
|
||||||
|
|
||||||
updateFailed = "updates:failed"
|
updateFailed = "updates:failed"
|
||||||
updateSuccess = "updates:success"
|
updateSuccess = "updates:success"
|
||||||
|
|
||||||
|
updateTaskRepeatDuration = 1 * time.Hour
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -157,7 +159,7 @@ func start() error {
|
||||||
|
|
||||||
if !disableTaskSchedule {
|
if !disableTaskSchedule {
|
||||||
updateTask.
|
updateTask.
|
||||||
Repeat(1 * time.Hour).
|
Repeat(updateTaskRepeatDuration).
|
||||||
MaxDelay(30 * time.Minute)
|
MaxDelay(30 * time.Minute)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package updates
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/tevino/abool"
|
"github.com/tevino/abool"
|
||||||
|
@ -19,11 +20,26 @@ var (
|
||||||
restartTask *modules.Task
|
restartTask *modules.Task
|
||||||
restartPending = abool.New()
|
restartPending = abool.New()
|
||||||
restartTriggered = abool.New()
|
restartTriggered = abool.New()
|
||||||
|
|
||||||
|
restartTime time.Time
|
||||||
|
restartTimeLock sync.Mutex
|
||||||
)
|
)
|
||||||
|
|
||||||
// IsRestarting returns whether a restart is pending or currently in progress.
|
// IsRestarting returns whether a restart has been triggered.
|
||||||
func IsRestarting() bool {
|
func IsRestarting() bool {
|
||||||
return restartPending.IsSet()
|
return restartTriggered.IsSet()
|
||||||
|
}
|
||||||
|
|
||||||
|
// RestartIsPending returns whether a restart is pending.
|
||||||
|
func RestartIsPending() (pending bool, restartAt time.Time) {
|
||||||
|
if restartPending.IsNotSet() {
|
||||||
|
return false, time.Time{}
|
||||||
|
}
|
||||||
|
|
||||||
|
restartTimeLock.Lock()
|
||||||
|
defer restartTimeLock.Unlock()
|
||||||
|
|
||||||
|
return true, restartTime
|
||||||
}
|
}
|
||||||
|
|
||||||
// DelayedRestart triggers a restart of the application by shutting down the
|
// DelayedRestart triggers a restart of the application by shutting down the
|
||||||
|
@ -31,36 +47,57 @@ func IsRestarting() bool {
|
||||||
// may be further delayed by up to 10 minutes by the internal task scheduling
|
// may be further delayed by up to 10 minutes by the internal task scheduling
|
||||||
// system. This only works if the process is managed by portmaster-start.
|
// system. This only works if the process is managed by portmaster-start.
|
||||||
func DelayedRestart(delay time.Duration) {
|
func DelayedRestart(delay time.Duration) {
|
||||||
log.Warningf("updates: restart triggered, will execute in %s", delay)
|
// Check if restart is already pending.
|
||||||
|
if !restartPending.SetToIf(false, true) {
|
||||||
// This enables TriggerRestartIfPending.
|
return
|
||||||
// Subsequent calls to TriggerRestart should be able to set a new delay.
|
}
|
||||||
restartPending.Set()
|
|
||||||
|
|
||||||
// Schedule the restart task.
|
// Schedule the restart task.
|
||||||
restartTask.Schedule(time.Now().Add(delay))
|
log.Warningf("updates: restart triggered, will execute in %s", delay)
|
||||||
|
restartAt := time.Now().Add(delay)
|
||||||
|
restartTask.Schedule(restartAt)
|
||||||
|
|
||||||
|
// Set restartTime.
|
||||||
|
restartTimeLock.Lock()
|
||||||
|
defer restartTimeLock.Unlock()
|
||||||
|
restartTime = restartAt
|
||||||
|
}
|
||||||
|
|
||||||
|
// AbortRestart aborts a (delayed) restart.
|
||||||
|
func AbortRestart() {
|
||||||
|
if restartPending.SetToIf(true, false) {
|
||||||
|
log.Warningf("updates: restart aborted")
|
||||||
|
|
||||||
|
// Cancel schedule.
|
||||||
|
restartTask.Schedule(time.Time{})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TriggerRestartIfPending triggers an automatic restart, if one is pending.
|
// TriggerRestartIfPending triggers an automatic restart, if one is pending.
|
||||||
// This can be used to prepone a scheduled restart if the conditions are preferable.
|
// This can be used to prepone a scheduled restart if the conditions are preferable.
|
||||||
func TriggerRestartIfPending() {
|
func TriggerRestartIfPending() {
|
||||||
if restartPending.IsSet() {
|
if restartPending.IsSet() {
|
||||||
_ = automaticRestart(module.Ctx, nil)
|
restartTask.StartASAP()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RestartNow immediately executes a restart.
|
// RestartNow immediately executes a restart.
|
||||||
// This only works if the process is managed by portmaster-start.
|
// This only works if the process is managed by portmaster-start.
|
||||||
func RestartNow() {
|
func RestartNow() {
|
||||||
_ = automaticRestart(module.Ctx, nil)
|
restartPending.Set()
|
||||||
|
restartTask.StartASAP()
|
||||||
}
|
}
|
||||||
|
|
||||||
func automaticRestart(_ context.Context, _ *modules.Task) error {
|
func automaticRestart(_ context.Context, _ *modules.Task) error {
|
||||||
if restartTriggered.SetToIf(false, true) {
|
// Check if the restart is still scheduled.
|
||||||
log.Info("updates: initiating (automatic) restart")
|
if restartPending.IsNotSet() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trigger restart.
|
||||||
|
if restartTriggered.SetToIf(false, true) {
|
||||||
|
log.Warning("updates: initiating (automatic) restart")
|
||||||
|
|
||||||
// Set restart pending to ensure IsRestarting() returns true.
|
|
||||||
restartPending.Set()
|
|
||||||
// Set restart exit code.
|
// Set restart exit code.
|
||||||
modules.SetExitStatusCode(RestartExitCode)
|
modules.SetExitStatusCode(RestartExitCode)
|
||||||
// Do not use a worker, as this would block itself here.
|
// Do not use a worker, as this would block itself here.
|
||||||
|
|
|
@ -51,18 +51,19 @@ func initUpgrader() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func upgrader(_ context.Context, _ interface{}) error {
|
func upgrader(_ context.Context, _ interface{}) error {
|
||||||
// like a lock, but discard additional runs
|
// Lock runs, but discard additional runs.
|
||||||
if !upgraderActive.SetToIf(false, true) {
|
if !upgraderActive.SetToIf(false, true) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
defer upgraderActive.SetTo(false)
|
defer upgraderActive.SetTo(false)
|
||||||
|
|
||||||
// upgrade portmaster-start
|
// Upgrade portmaster-start.
|
||||||
err := upgradePortmasterStart()
|
err := upgradePortmasterStart()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warningf("updates: failed to upgrade portmaster-start: %s", err)
|
log.Warningf("updates: failed to upgrade portmaster-start: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Upgrade based on binary.
|
||||||
binBaseName := strings.Split(filepath.Base(os.Args[0]), "_")[0]
|
binBaseName := strings.Split(filepath.Base(os.Args[0]), "_")[0]
|
||||||
switch binBaseName {
|
switch binBaseName {
|
||||||
case "portmaster-core":
|
case "portmaster-core":
|
||||||
|
@ -149,36 +150,45 @@ func upgradeCoreNotifyActionHandler(_ context.Context, n *notifications.Notifica
|
||||||
}
|
}
|
||||||
|
|
||||||
func upgradeHub() error {
|
func upgradeHub() error {
|
||||||
if hubUpgradeStarted {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if spnHubUpdate != nil && !spnHubUpdate.UpgradeAvailable() {
|
if spnHubUpdate != nil && !spnHubUpdate.UpgradeAvailable() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// make identifier
|
// Make identifier for getting file from updater.
|
||||||
identifier := "hub/spn-hub" // identifier, use forward slash!
|
identifier := "hub/spn-hub" // identifier, use forward slash!
|
||||||
if onWindows {
|
if onWindows {
|
||||||
identifier += exeExt
|
identifier += exeExt
|
||||||
}
|
}
|
||||||
|
|
||||||
// get newest spn-hub
|
// Get newest spn-hub file.
|
||||||
newFile, err := GetPlatformFile(identifier)
|
newFile, err := GetPlatformFile(identifier)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
spnHubUpdate = newFile
|
spnHubUpdate = newFile
|
||||||
|
|
||||||
// check for new version
|
// Check if the new version is different.
|
||||||
if info.GetInfo().Version != spnHubUpdate.Version() {
|
if info.GetInfo().Version != spnHubUpdate.Version() {
|
||||||
// get random delay with up to three hours
|
// Get random delay with up to three hours.
|
||||||
delayMinutes, err := rng.Number(3 * 60)
|
delayMinutes, err := rng.Number(3 * 60)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
DelayedRestart(time.Duration(delayMinutes) * time.Minute)
|
// Delay restart for at least one hour for preparations.
|
||||||
hubUpgradeStarted = true
|
DelayedRestart(time.Duration(delayMinutes+60) * time.Minute)
|
||||||
|
|
||||||
|
// Increase update checks in order to detect aborts better.
|
||||||
|
if !disableTaskSchedule {
|
||||||
|
updateTask.Repeat(10 * time.Minute)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
AbortRestart()
|
||||||
|
|
||||||
|
// Set update task schedule back to normal.
|
||||||
|
if !disableTaskSchedule {
|
||||||
|
updateTask.Repeat(updateTaskRepeatDuration)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
Loading…
Add table
Reference in a new issue