Skip to content
This repository has been archived by the owner on Jan 8, 2024. It is now read-only.

Commit

Permalink
Merge 73f3e8f into 1508f4b
Browse files Browse the repository at this point in the history
  • Loading branch information
xgess committed Jan 20, 2020
2 parents 1508f4b + 73f3e8f commit cb067db
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 9 deletions.
88 changes: 86 additions & 2 deletions keybase/platform_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"unsafe"

"github.com/kardianos/osext"
"github.com/keybase/go-ps"
"github.com/keybase/go-updater"
"github.com/keybase/go-updater/command"
"github.com/keybase/go-updater/process"
Expand Down Expand Up @@ -303,7 +304,7 @@ func (c *ComponentsChecker) checkRegistryComponents() (result bool) {
type KeybaseCommand string

const (
KeybaseCommandStart KeybaseCommand = "watchdog2"
KeybaseCommandStart KeybaseCommand = "watchdog"
KeybaseCommandStop KeybaseCommand = "stop"
)

Expand Down Expand Up @@ -418,6 +419,83 @@ func (c context) IsCheckCommand() bool {
return c.isCheckCommand
}

// findMyParent takes a slice of processes which includes the currently
// running process and returns which of these (if there is one)
// is the parent by pid of the currently running process
func findMyParent(processes []ps.Process) (parent ps.Process, found bool) {
myPid := os.Getpid()

var pidLookup map[int]ps.Process
for _, p := range processes {
pidLookup[p.Pid()] = p
}
myProcess, ok := pidLookup[myPid]
if !ok {
// my process is not in the slice of processes, so cannot find parent
return nil, false
}
parent, ok = pidLookup[myProcess.PPid()]
return parent, ok
}

// stopTheWatchdog looks for a keybase process which is the parent of this
// running process. if such a process exists, it might kill this process during
// updating (the watchdog, which does this), so stop it first.
func (c context) stopTheWatchdog() error {
c.log.Infof("looking for the watchdog process to stop it")

fetchKeybaseProcesses := func() ([]ps.Process, error) {
path, err := Dir("Keybase")
if err != nil {
return nil, err
}
keybaseBinPath := filepath.Join(path, "keybase.exe")
matcher := process.NewMatcher(keybaseBinPath, process.PathEqual, c.log)
return process.FindProcesses(matcher, time.Second, 200*time.Millisecond, c.log)
}

kbProcesses, err := fetchKeybaseProcesses()
if err != nil {
return err
}
parentProcess, found := findMyParent(kbProcesses)
if !found {
c.log.Warningf("the updater appears to be running without the watchdog which is unexpected but should be fine")
return nil
}
watchdogPid := parentProcess.Pid()
c.log.Infof("found the updater's watchdog process at pid %d, terminating it...", watchdogPid)
err = process.TerminatePID(watchdogPid, 0*time.Second /*unused on windows*/, c.log)
if err != nil {
c.log.Warningf("error terminating the watchdog: %f", err.Error())
return err
}
time.Sleep(5 * time.Second)
return nil
// timeOut := time.NewTimer(5 * time.Second)
// checkInterval := time.NewTicker(300 * time.Millisecond)
// watchdogCheckLoop:
// for {
// select {
// case <-timeOut.C:
// return fmt.Errorf("timed out trying to kill the updater's watchdog")
// case <-checkInterval.C:
// c.log.Infof("checking to see if the watchdog is dead yet")
// kbProcesses, err := fetchKeybaseProcesses()
// if err != nil {
// return err
// }
// for _, proc := range kbProcesses {
// if proc.Pid() == parentProcess.Pid() {
// // the parent process is not dead yet
// continue watchdogCheckLoop
// }
// }
// return nil
// }
// }
}

// copied from watchdog
func (c context) stopKeybaseProcesses() error {
path, err := Dir("Keybase")
Expand All @@ -426,6 +504,12 @@ func (c context) stopKeybaseProcesses() error {
return err
}

c.log.Infof("attempting to stop the watchdog")
err = c.stopTheWatchdog()
if err != nil {
c.log.Infof("Error stopping the watchdog: %s", err.Error())
}
c.log.Infof("watchdog is down, time to take down everything but the updater")
c.runKeybase(KeybaseCommandStop)
time.Sleep(time.Second)

Expand All @@ -443,7 +527,7 @@ func (c context) stopKeybaseProcesses() error {
exes = append(exes, guiExes...)
}

c.log.Infof("Terminating any existing programs we will be updating")
c.log.Infof("Terminating any existing programs we will be updating %+v", exes)
for _, program := range exes {
matcher := process.NewMatcher(program, process.PathEqual, c.log)
matcher.ExceptPID(ospid)
Expand Down
21 changes: 14 additions & 7 deletions watchdog/watchdog.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,25 @@ type Log interface {
// Watch monitors programs and restarts them if they aren't running
func Watch(programs []Program, restartDelay time.Duration, log Log) error {
// Terminate any existing programs that we are supposed to monitor
log.Infof("Terminating any existing programs we will be monitoring")
terminateExisting(programs, log)

// any program can terminate everything if it's ExitAllOnSuccess
exitAll := func() {
log.Infof("Terminating any other programs we are monitoring")
terminateExisting(programs, log)
os.Exit(0)
}
// Start monitoring all the programs
watchPrograms(programs, restartDelay, log)
watchPrograms(programs, restartDelay, log, exitAll)

return nil
}

func terminateExisting(programs []Program, log Log) {
// Terminate any monitored processes
// this logic also exists in the updater, so if you want to change it, look there too.
ospid := os.Getpid()
log.Infof("Terminating any existing programs we will be monitoring")
for _, program := range programs {
matcher := process.NewMatcher(program.Path, process.PathEqual, log)
matcher.ExceptPID(ospid)
Expand All @@ -61,15 +69,15 @@ func terminateExisting(programs []Program, log Log) {
}
}

func watchPrograms(programs []Program, delay time.Duration, log Log) {
func watchPrograms(programs []Program, delay time.Duration, log Log, exitAll func()) {
for _, program := range programs {
go watchProgram(program, delay, log)
go watchProgram(program, delay, log, exitAll)
}
}

// watchProgram will monitor a program and restart it if it exits.
// This method will run forever.
func watchProgram(program Program, restartDelay time.Duration, log Log) {
func watchProgram(program Program, restartDelay time.Duration, log Log, exitAll func()) {
for {
start := time.Now()
log.Infof("Starting %#v", program)
Expand All @@ -84,8 +92,7 @@ func watchProgram(program Program, restartDelay time.Duration, log Log) {
break
} else if program.ExitOn == ExitAllOnSuccess {
log.Infof("Program configured to exit on success, exiting")
// presumably the other watches are sleeping anyway
os.Exit(0)
exitAll()
}
}
log.Infof("Program ran for %s", time.Since(start))
Expand Down

0 comments on commit cb067db

Please sign in to comment.