mirror of
https://github.com/safing/portmaster
synced 2025-09-01 18:19:12 +00:00
[WIP] Add restart command to instance
This commit is contained in:
parent
c9631daa3e
commit
61babe2822
15 changed files with 81 additions and 98 deletions
|
@ -55,7 +55,10 @@ func initialize() *service.Instance {
|
||||||
|
|
||||||
// Create instance.
|
// Create instance.
|
||||||
var execCmdLine bool
|
var execCmdLine bool
|
||||||
instance, err := service.New(&service.ServiceConfig{})
|
instance, err := service.New(&service.ServiceConfig{
|
||||||
|
IsRunningAsService: isRunningAsService(),
|
||||||
|
DefaultRestartCommand: defaultRestartCommand,
|
||||||
|
})
|
||||||
switch {
|
switch {
|
||||||
case err == nil:
|
case err == nil:
|
||||||
// Continue
|
// Continue
|
||||||
|
|
|
@ -4,14 +4,19 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
processInfo "github.com/shirou/gopsutil/process"
|
||||||
|
|
||||||
"github.com/safing/portmaster/base/log"
|
"github.com/safing/portmaster/base/log"
|
||||||
"github.com/safing/portmaster/service"
|
"github.com/safing/portmaster/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var defaultRestartCommand = exec.Command("systemctl", "restart", "portmaster")
|
||||||
|
|
||||||
func run(instance *service.Instance) {
|
func run(instance *service.Instance) {
|
||||||
// Set default log level.
|
// Set default log level.
|
||||||
log.SetLogLevel(log.WarningLevel)
|
log.SetLogLevel(log.WarningLevel)
|
||||||
|
@ -98,3 +103,20 @@ func run(instance *service.Instance) {
|
||||||
|
|
||||||
os.Exit(instance.ExitCode())
|
os.Exit(instance.ExitCode())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isRunningAsService() bool {
|
||||||
|
// Get the current process ID
|
||||||
|
pid := os.Getpid()
|
||||||
|
|
||||||
|
currentProcess, err := processInfo.NewProcess(int32(pid))
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
ppid, err := currentProcess.Ppid()
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// Check if the parent process ID is 1 == init system
|
||||||
|
return ppid == 1
|
||||||
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
@ -24,6 +25,8 @@ var (
|
||||||
// wait groups
|
// wait groups
|
||||||
runWg sync.WaitGroup
|
runWg sync.WaitGroup
|
||||||
finishWg sync.WaitGroup
|
finishWg sync.WaitGroup
|
||||||
|
|
||||||
|
defaultRestartCommand = exec.Command("sc.exe", "restart", "PortmasterCore")
|
||||||
)
|
)
|
||||||
|
|
||||||
const serviceName = "PortmasterCore"
|
const serviceName = "PortmasterCore"
|
||||||
|
@ -168,3 +171,11 @@ func registerSignalHandler(instance *service.Instance) {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isRunningAsService() bool {
|
||||||
|
isService, err := svc.IsWindowsService()
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return isService
|
||||||
|
}
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
package service
|
package service
|
||||||
|
|
||||||
type ServiceConfig struct{}
|
import "os/exec"
|
||||||
|
|
||||||
|
type ServiceConfig struct {
|
||||||
|
IsRunningAsService bool
|
||||||
|
DefaultRestartCommand *exec.Cmd
|
||||||
|
}
|
||||||
|
|
|
@ -19,7 +19,6 @@ import (
|
||||||
"github.com/safing/portmaster/service/process"
|
"github.com/safing/portmaster/service/process"
|
||||||
"github.com/safing/portmaster/service/resolver"
|
"github.com/safing/portmaster/service/resolver"
|
||||||
"github.com/safing/portmaster/service/status"
|
"github.com/safing/portmaster/service/status"
|
||||||
"github.com/safing/portmaster/service/updates"
|
|
||||||
"github.com/safing/portmaster/spn/captain"
|
"github.com/safing/portmaster/spn/captain"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -149,8 +148,8 @@ func shutdown(_ *api.Request) (msg string, err error) {
|
||||||
func restart(_ *api.Request) (msg string, err error) {
|
func restart(_ *api.Request) (msg string, err error) {
|
||||||
log.Info("core: user requested restart via action")
|
log.Info("core: user requested restart via action")
|
||||||
|
|
||||||
// Let the updates module handle restarting.
|
// Trigger restart
|
||||||
updates.RestartNow()
|
module.instance.Restart()
|
||||||
|
|
||||||
return "restart initiated", nil
|
return "restart initiated", nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,6 +114,7 @@ func New(instance instance) (*Core, error) {
|
||||||
|
|
||||||
type instance interface {
|
type instance interface {
|
||||||
Shutdown()
|
Shutdown()
|
||||||
|
Restart()
|
||||||
AddWorkerInfoToDebugInfo(di *debug.Info)
|
AddWorkerInfoToDebugInfo(di *debug.Info)
|
||||||
BinaryUpdates() *updates.Updates
|
BinaryUpdates() *updates.Updates
|
||||||
IntelUpdates() *updates.Updates
|
IntelUpdates() *updates.Updates
|
||||||
|
|
|
@ -4,14 +4,17 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
go_runtime "runtime"
|
go_runtime "runtime"
|
||||||
|
"strings"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/safing/portmaster/base/api"
|
"github.com/safing/portmaster/base/api"
|
||||||
"github.com/safing/portmaster/base/config"
|
"github.com/safing/portmaster/base/config"
|
||||||
"github.com/safing/portmaster/base/database/dbmodule"
|
"github.com/safing/portmaster/base/database/dbmodule"
|
||||||
|
"github.com/safing/portmaster/base/log"
|
||||||
"github.com/safing/portmaster/base/metrics"
|
"github.com/safing/portmaster/base/metrics"
|
||||||
"github.com/safing/portmaster/base/notifications"
|
"github.com/safing/portmaster/base/notifications"
|
||||||
"github.com/safing/portmaster/base/rng"
|
"github.com/safing/portmaster/base/rng"
|
||||||
|
@ -101,7 +104,9 @@ type Instance struct {
|
||||||
sluice *sluice.SluiceModule
|
sluice *sluice.SluiceModule
|
||||||
terminal *terminal.TerminalModule
|
terminal *terminal.TerminalModule
|
||||||
|
|
||||||
CommandLineOperation func() error
|
CommandLineOperation func() error
|
||||||
|
isRunningAsService bool
|
||||||
|
defaultRestartCommand *exec.Cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func getCurrentBinaryFolder() (string, error) {
|
func getCurrentBinaryFolder() (string, error) {
|
||||||
|
@ -178,6 +183,8 @@ func New(svcCfg *ServiceConfig) (*Instance, error) { //nolint:maintidx
|
||||||
// Create instance to pass it to modules.
|
// Create instance to pass it to modules.
|
||||||
instance := &Instance{}
|
instance := &Instance{}
|
||||||
instance.ctx, instance.cancelCtx = context.WithCancel(context.Background())
|
instance.ctx, instance.cancelCtx = context.WithCancel(context.Background())
|
||||||
|
instance.isRunningAsService = svcCfg.IsRunningAsService
|
||||||
|
instance.defaultRestartCommand = svcCfg.DefaultRestartCommand
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
@ -671,7 +678,7 @@ func (i *Instance) Restart() {
|
||||||
i.core.EventRestart.Submit(struct{}{})
|
i.core.EventRestart.Submit(struct{}{})
|
||||||
time.Sleep(10 * time.Millisecond)
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
|
||||||
i.shutdown(RestartExitCode)
|
i.serviceRestart()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shutdown asynchronously stops the instance.
|
// Shutdown asynchronously stops the instance.
|
||||||
|
@ -700,6 +707,25 @@ func (i *Instance) shutdown(exitCode int) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *Instance) serviceRestart() {
|
||||||
|
if !i.isRunningAsService {
|
||||||
|
i.shutdown(RestartExitCode)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cmd := i.defaultRestartCommand
|
||||||
|
|
||||||
|
// Check if user defined custom command for restarting the service.
|
||||||
|
restartCommand, exists := os.LookupEnv("PORTMASTER_RESTART_COMMAND")
|
||||||
|
|
||||||
|
log.Debugf(`instance: running command "%s", %v`, restartCommand, exists)
|
||||||
|
if exists && restartCommand != "" {
|
||||||
|
commandSplit := strings.Split(restartCommand, " ")
|
||||||
|
cmd = exec.Command(commandSplit[0], commandSplit[1:]...)
|
||||||
|
}
|
||||||
|
log.Debugf("instance: running command %s", cmd.String())
|
||||||
|
_ = cmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
// Stopping returns whether the instance is shutting down.
|
// Stopping returns whether the instance is shutting down.
|
||||||
func (i *Instance) Stopping() bool {
|
func (i *Instance) Stopping() bool {
|
||||||
return i.ctx.Err() != nil
|
return i.ctx.Err() != nil
|
||||||
|
|
|
@ -16,6 +16,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
semver "github.com/hashicorp/go-version"
|
semver "github.com/hashicorp/go-version"
|
||||||
|
|
||||||
"github.com/safing/portmaster/base/log"
|
"github.com/safing/portmaster/base/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
package updates
|
|
|
@ -1 +0,0 @@
|
||||||
package updates
|
|
|
@ -150,7 +150,7 @@ func (u *Updates) applyUpdates(_ *mgr.WorkerCtx) error {
|
||||||
// Perform restart.
|
// Perform restart.
|
||||||
u.instance.Restart()
|
u.instance.Restart()
|
||||||
} else {
|
} else {
|
||||||
// Update completed and no restart was needed. Submit an event.
|
// Update completed and no restart is needed. Submit an event.
|
||||||
u.EventResourcesUpdated.Submit(struct{}{})
|
u.EventResourcesUpdated.Submit(struct{}{})
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
semver "github.com/hashicorp/go-version"
|
semver "github.com/hashicorp/go-version"
|
||||||
|
|
||||||
"github.com/safing/portmaster/base/log"
|
"github.com/safing/portmaster/base/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,85 +0,0 @@
|
||||||
package updates
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/tevino/abool"
|
|
||||||
|
|
||||||
"github.com/safing/portmaster/base/log"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// RebootOnRestart defines whether the whole system, not just the service,
|
|
||||||
// should be restarted automatically when triggering a restart internally.
|
|
||||||
RebootOnRestart bool
|
|
||||||
|
|
||||||
restartPending = abool.New()
|
|
||||||
restartTriggered = abool.New()
|
|
||||||
|
|
||||||
restartTime time.Time
|
|
||||||
restartTimeLock sync.Mutex
|
|
||||||
)
|
|
||||||
|
|
||||||
// IsRestarting returns whether a restart has been triggered.
|
|
||||||
func IsRestarting() bool {
|
|
||||||
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
|
|
||||||
// module system gracefully and returning with RestartExitCode. The restart
|
|
||||||
// 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.
|
|
||||||
func DelayedRestart(delay time.Duration) {
|
|
||||||
// Check if restart is already pending.
|
|
||||||
if !restartPending.SetToIf(false, true) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Schedule the restart task.
|
|
||||||
log.Warningf("updates: restart triggered, will execute in %s", delay)
|
|
||||||
restartAt := time.Now().Add(delay)
|
|
||||||
// module.restartWorkerMgr.Delay(delay)
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
// module.restartWorkerMgr.Delay(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TriggerRestartIfPending triggers an automatic restart, if one is pending.
|
|
||||||
// This can be used to prepone a scheduled restart if the conditions are preferable.
|
|
||||||
func TriggerRestartIfPending() {
|
|
||||||
// if restartPending.IsSet() {
|
|
||||||
// module.restartWorkerMgr.Go()
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
// RestartNow immediately executes a restart.
|
|
||||||
// This only works if the process is managed by portmaster-start.
|
|
||||||
func RestartNow() {
|
|
||||||
restartPending.Set()
|
|
||||||
// module.restartWorkerMgr.Go()
|
|
||||||
}
|
|
|
@ -1,7 +1,6 @@
|
||||||
package captain
|
package captain
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/safing/portmaster/service/updates"
|
|
||||||
"github.com/safing/portmaster/spn/conf"
|
"github.com/safing/portmaster/spn/conf"
|
||||||
"github.com/safing/portmaster/spn/docks"
|
"github.com/safing/portmaster/spn/docks"
|
||||||
)
|
)
|
||||||
|
@ -41,5 +40,7 @@ func updateConnectionStatus() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updates.TriggerRestartIfPending()
|
|
||||||
|
// TODO(vladimir): what was this needed for?
|
||||||
|
// updates.TriggerRestartIfPending()
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,7 @@ func updateSPNIntel(_ context.Context, _ interface{}) (err error) {
|
||||||
|
|
||||||
// Check if there is something to do.
|
// Check if there is something to do.
|
||||||
// TODO(vladimir): is update check needed
|
// TODO(vladimir): is update check needed
|
||||||
if intelResource != nil { //&& !intelResource.UpgradeAvailable() {
|
if intelResource != nil { // && !intelResource.UpgradeAvailable() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue