Fix Fleet Desktop bugs on Windows (#16402)

#15821

This PR is adding two improvements and fixing two Windows bugs in Fleet
Desktop:

## Improvement
- We are now capturing the stderr of Fleet Desktop. This helped me find
bug (1) below (otherwise the panic output below was hidden from us).
- To reduce complexity I'm removing the "Theme detection" routine
because we made the decision to use the colored icon for both themes...,
see here:
415d1f493b/orbit/cmd/desktop/desktop_windows.go (L21-L27)

## Bug fixes
1. Fleet Desktop icon not showing in the task bar. This was fixed by
updating to use the latest version of `fyne.io/systray`. (See
https://github.com/fyne-io/systray/issues/22#issuecomment-1173157898.)
2. Orbit now properly detects if Fleet Desktop isn't running on Windows.

Bug (1)'s panic output 
```
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x0 pc=0x72b14b]

goroutine 23 [running]:
fyne.io/systray.(*winTray).setTooltip(0x1eb5d40, {0x126923f?, 0x0?})
	/Users/luk/gopath/pkg/mod/fyne.io/systray@v1.10.0/systray_windows.go:260 +0xcb
fyne.io/systray.SetTooltip({0x126923f?, 0x125fc16?})
	/Users/luk/gopath/pkg/mod/fyne.io/systray@v1.10.0/systray_windows.go:961 +0x29
main.main.func1()
	/Users/luk/fleetdm/git/fleet/orbit/cmd/desktop/desktop.go:103 +0xba
fyne.io/systray.Register.func2()
	/Users/luk/gopath/pkg/mod/fyne.io/systray@v1.10.0/systray.go:98 +0x2f
created by fyne.io/systray.Register in goroutine 1
	/Users/luk/gopath/pkg/mod/fyne.io/systray@v1.10.0/systray.go:96 +0xb1
```

- [X] Changes file added for user-visible changes in `changes/` or
`orbit/changes/`.
See [Changes
files](https://fleetdm.com/docs/contributing/committing-changes#changes-files)
for more information.
- [X] Manual QA for all new/changed functionality
  - For Orbit and Fleet Desktop changes:
- [X] Manual QA must be performed in the three main OSs, macOS, Windows
and Linux.
- [x] Auto-update manual QA, from released version of component to new
version (see [tools/tuf/test](../tools/tuf/test/README.md)).
This commit is contained in:
Lucas Manuel Rodriguez 2024-01-29 18:52:55 -03:00 committed by GitHub
parent 3c5d52a5ff
commit ea25ce4e9e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 304 additions and 166 deletions

3
go.mod
View file

@ -4,7 +4,7 @@ go 1.21
require (
cloud.google.com/go/pubsub v1.33.0
fyne.io/systray v1.10.0
fyne.io/systray v1.10.1-0.20240111184411-11c585fff98d
github.com/AbGuthrie/goquery/v2 v2.0.1
github.com/DATA-DOG/go-sqlmock v1.5.0
github.com/Masterminds/semver v1.5.0
@ -289,7 +289,6 @@ require (
github.com/subosito/gotenv v1.2.0 // indirect
github.com/tchap/go-patricia/v2 v2.3.1 // indirect
github.com/technoweenie/multipartstreamer v1.0.1 // indirect
github.com/tevino/abool v1.2.0 // indirect
github.com/tklauser/go-sysconf v0.3.11 // indirect
github.com/tklauser/numcpus v0.6.0 // indirect
github.com/trivago/tgo v1.0.7 // indirect

6
go.sum
View file

@ -84,8 +84,8 @@ contrib.go.opencensus.io/integrations/ocsql v0.1.7/go.mod h1:8DsSdjz3F+APR+0z0Wk
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
fyne.io/systray v1.10.0 h1:Yr1D9Lxeiw3+vSuZWPlaHC8BMjIHZXJKkek706AfYQk=
fyne.io/systray v1.10.0/go.mod h1:oM2AQqGJ1AMo4nNqZFYU8xYygSBZkW2hmdJ7n4yjedE=
fyne.io/systray v1.10.1-0.20240111184411-11c585fff98d h1:NjHwOOuOgGswUOPzDlsEDJOqKdjOjwL8Vi1mj9qx9+o=
fyne.io/systray v1.10.1-0.20240111184411-11c585fff98d/go.mod h1:RVwqP9nYMo7h5zViCBHri2FgjXF7H2cub7MAq4NSoLs=
github.com/AbGuthrie/goquery/v2 v2.0.1 h1:h0tIhmeRroyqYjT9zxXPXOrheNp1xqNTV+XFWuDI+eA=
github.com/AbGuthrie/goquery/v2 v2.0.1/go.mod h1:xpDLF4kUr+TRFXogclRa7Zzc8bMAB/fYm1zG/XX1WOA=
github.com/AlekSi/pointer v1.2.0 h1:glcy/gc4h8HnG2Z3ZECSzZ1IX1x2JxRVuDzaJwQE0+w=
@ -1171,8 +1171,6 @@ github.com/tchap/go-patricia/v2 v2.3.1 h1:6rQp39lgIYZ+MHmdEq4xzuk1t7OdC35z/xm0BG
github.com/tchap/go-patricia/v2 v2.3.1/go.mod h1:VZRHKAb53DLaG+nA9EaYYiaEx6YztwDlLElMsnSHD4k=
github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM=
github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog=
github.com/tevino/abool v1.2.0 h1:heAkClL8H6w+mK5md9dzsuohKeXHUpY7Vw0ZCKW+huA=
github.com/tevino/abool v1.2.0/go.mod h1:qc66Pna1RiIsPa7O4Egxxs9OqkuxDX55zznh9K07Tzg=
github.com/theupdateframework/go-tuf v0.5.2 h1:habfDzTmpbzBLIFGWa2ZpVhYvFBoK0C1onC3a4zuPRA=
github.com/theupdateframework/go-tuf v0.5.2/go.mod h1:SyMV5kg5n4uEclsyxXJZI2UxPFJNDc4Y+r7wv+MlvTA=
github.com/throttled/throttled/v2 v2.8.0 h1:B5VfdM8BE+ClI2Ji238SbNOTWfYcocvuAhgT27lvwrE=

View file

@ -0,0 +1,2 @@
* Fixed bug on Windows where Fleet Desktop tray icon was not showing in the task bar.
* Fixed bug on Windows where Orbit was not bringing the Fleet Desktop process up (when it was detected as not running).

View file

@ -11,6 +11,7 @@ import (
"fyne.io/systray"
"github.com/fleetdm/fleet/v4/orbit/pkg/constant"
"github.com/fleetdm/fleet/v4/orbit/pkg/go-paniclog"
"github.com/fleetdm/fleet/v4/orbit/pkg/profiles"
"github.com/fleetdm/fleet/v4/orbit/pkg/token"
"github.com/fleetdm/fleet/v4/orbit/pkg/update"
@ -59,6 +60,7 @@ func setupRunners() {
func main() {
setupLogs()
setupStderr()
// Our TUF provided targets must support launching with "--help".
if len(os.Args) > 1 && os.Args[1] == "--help" {
@ -101,25 +103,11 @@ func main() {
log.Info().Msg("ready")
systray.SetTooltip("Fleet Desktop")
// Default to dark theme icon because this seems to be a better fit on Linux (Ubuntu at
// least). On macOS this is used as a template icon anyway.
systray.SetTemplateIcon(iconDark, iconDark)
// Theme detection is currently only on Windows. On macOS we use template icons (which
// automatically change), and on Linux we don't handle it yet (Ubuntu doesn't seem to change
// systray colors in the default configuration when toggling light/dark).
if runtime.GOOS == "windows" {
// Set the initial theme, and watch for theme changes.
theme, err := getSystemTheme()
if err != nil {
log.Error().Err(err).Msg("get system theme")
}
iconManager := newIconManager(theme)
go func() {
watchSystemTheme(iconManager)
}()
}
// Add a disabled menu item with the current version
versionItem := systray.AddMenuItem(fmt.Sprintf("Fleet Desktop v%s", version), "")
versionItem.Disable()
@ -438,14 +426,12 @@ func (m *mdmMigrationHandler) ShowInstructions() error {
return nil
}
// setupLogs configures our logging system to write logs to rolling files and
// stderr, if for some reason we can't write a log file the logs are still
// printed to stderr.
// setupLogs configures our logging system to write logs to rolling files, if for some
// reason we can't write a log file the logs are still printed to stderr.
func setupLogs() {
stderrOut := zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.RFC3339Nano, NoColor: true}
dir, err := logDir()
if err != nil {
stderrOut := zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.RFC3339Nano, NoColor: true}
log.Logger = log.Output(stderrOut)
log.Error().Err(err).Msg("find directory for logs")
return
@ -454,6 +440,7 @@ func setupLogs() {
dir = filepath.Join(dir, "Fleet")
if err := os.MkdirAll(dir, 0o755); err != nil {
stderrOut := zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.RFC3339Nano, NoColor: true}
log.Logger = log.Output(stderrOut)
log.Error().Err(err).Msg("make directories for log files")
return
@ -466,10 +453,40 @@ func setupLogs() {
MaxAge: 28, // days
}
log.Logger = log.Output(zerolog.MultiLevelWriter(
zerolog.ConsoleWriter{Out: logFile, TimeFormat: time.RFC3339Nano, NoColor: true},
stderrOut,
))
consoleWriter := zerolog.ConsoleWriter{Out: logFile, TimeFormat: time.RFC3339Nano, NoColor: true}
log.Logger = log.Output(consoleWriter)
}
// setupStderr redirects stderr output to a file.
func setupStderr() {
dir, err := logDir()
if err != nil {
log.Error().Err(err).Msg("find directory for stderr")
return
}
if err := os.MkdirAll(dir, 0o755); err != nil {
log.Error().Err(err).Msg("make directories for stderr")
return
}
stderrFile, err := os.OpenFile(filepath.Join(dir, "Fleet", "fleet-desktop.err"), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o666)
if err != nil {
log.Error().Err(err).Msg("create file to redirect stderr")
return
}
defer stderrFile.Close()
if _, err := stderrFile.Write([]byte(time.Now().UTC().Format("2006-01-02T15-04-05") + "\n")); err != nil {
log.Error().Err(err).Msg("write to stderr file")
}
// We need to use this method to properly capture golang's panic stderr output.
// Just setting os.Stderr to a file doesn't work (Go's runtime is probably using os.Stderr
// very early).
if _, err := paniclog.RedirectStderr(stderrFile); err != nil {
log.Error().Err(err).Msg("redirect stderr to file")
}
}
// logDir returns the default root directory to use for application-level logs.
@ -512,29 +529,3 @@ func logDir() (string, error) {
return dir, nil
}
type iconManager struct {
theme theme
}
func newIconManager(theme theme) *iconManager {
m := &iconManager{
theme: theme,
}
m.UpdateTheme(theme)
return m
}
func (m *iconManager) UpdateTheme(theme theme) {
m.theme = theme
switch theme {
case themeDark:
systray.SetIcon(iconDark)
case themeLight:
systray.SetIcon(iconLight)
case themeUnknown:
log.Debug().Msg("theme unknown, using dark theme")
default:
log.Error().Str("theme", string(theme)).Msg("tried to set invalid theme")
}
}

View file

@ -9,21 +9,9 @@ import (
"github.com/rs/zerolog/log"
)
//go:embed icon_light.png
var iconLight []byte
//go:embed icon_dark.png
var iconDark []byte
func getSystemTheme() (theme, error) {
log.Debug().Msg("get system theme not implemented for this platform")
return themeUnknown, nil
}
func watchSystemTheme(_ *iconManager) {
log.Debug().Msg("watch system theme not implemented for this platform")
}
func blockWaitForStopEvent(channelId string) error {
log.Debug().Msg("communication channel helpers are not implemented for this platform")
return nil

View file

@ -7,103 +7,25 @@ import (
_ "embed"
"errors"
"fmt"
"syscall"
"time"
"github.com/rs/zerolog/log"
"golang.org/x/sys/windows"
"golang.org/x/sys/windows/registry"
)
// For Windows we must use ico format for the icon,
// see https://github.com/getlantern/systray/blob/6065fda28be8c8d91aeb5e20de25e1600b8664a3/systray_windows.go#L850-L856.
// since watchSystemTheme is currently buggy, we are using the same icon for both themes
//
// In the past we implemented some logic to detect the Windows theme but it was buggy,
// so as a temporary fix we are using the same colored icon for both themes.
// Such theme detection logic was removed in this PR: https://github.com/fleetdm/fleet/pull/16402.
//go:embed windows_app.ico
var iconLight []byte
//go:embed windows_app.ico
var iconDark []byte
// Adapted from MIT licensed code in
// https://github.com/WireGuard/wireguard-go/commit/7e962a9932667f4a161b20aba5ff1c75ab8e578a
// and https://gist.github.com/jerblack/1d05bbcebb50ad55c312e4d7cf1bc909
// mkwinsyscall generates the Window syscall from the //sys comment below.
//go:generate go run golang.org/x/sys/windows/mkwinsyscall -output generated_syscall_windows.go desktop_windows.go
//sys regNotifyChangeKeyValue(key windows.Handle, watchSubtree bool, notifyFilter uint32, event windows.Handle, asynchronous bool) (regerrno error) = advapi32.RegNotifyChangeKeyValue
const (
// Registry path where theme value is stored.
registryPath = `Software\Microsoft\Windows\CurrentVersion\Themes\Personalize`
registryKey = "AppsUseLightTheme"
// REG_NOTIFY_CHANGE_LAST_SET notifies the caller of changes to a value of the key. This can include adding or deleting a value, or changing an existing value.
REG_NOTIFY_CHANGE_LAST_SET uint32 = 0x00000004
)
func getSystemTheme() (theme, error) {
// Adapted from https://stackoverflow.com/a/58494769/491710
key, err := registry.OpenKey(registry.CURRENT_USER, registryPath, registry.QUERY_VALUE)
if err != nil {
return themeDark, err
}
defer key.Close()
val, _, err := key.GetIntegerValue(registryKey)
if err != nil {
return themeDark, err
}
switch val {
case 0:
return themeDark, nil
case 1:
return themeLight, nil
default:
return themeUnknown, fmt.Errorf("unknown theme value %d", val)
}
}
// since this logic is currently buggy, we are currently using the same icon for both themes
func watchSystemTheme(iconManager *iconManager) {
for {
// Function call for proper defer semantics.
func() {
// Open the key within the loop, because "If the specified key is closed, the event is
// signaled. This means that an application should not depend on the key being open after
// returning from a wait operation on the event." -
// https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regnotifychangekeyvalue
key, err := registry.OpenKey(registry.CURRENT_USER, registryPath, syscall.KEY_NOTIFY)
if err != nil {
log.Error().Err(err).Msg("open registry key")
return
}
defer key.Close()
err = regNotifyChangeKeyValue(windows.Handle(key), false, REG_NOTIFY_CHANGE_LAST_SET, windows.Handle(0), false)
if err != nil {
log.Error().Err(err).Msg("change notification on registry value")
}
theme, err := getSystemTheme()
if err != nil {
log.Error().Err(err).Msg("get system theme")
return
}
log.Debug().Str("theme", string(theme)).Msg("got theme update")
// The systray library has a timeout issue trying to change the icon sometimes. As a
// cheap workaround, do this update a handful of times hoping one will work. Sadly the
// API doesn't return an error in these cases.
for i := 0; i < 10; i++ {
iconManager.UpdateTheme(theme)
time.Sleep(1 * time.Second)
}
}()
}
}
// blockWaitForStopEvent waits for the named event kernel object to be signalled
func blockWaitForStopEvent(channelId string) error {
if channelId == "" {

View file

@ -1,9 +0,0 @@
package main
type theme string
const (
themeDark theme = "dark"
themeLight = "light"
themeUnknown = "unknown"
)

View file

@ -0,0 +1,21 @@
Copyright (C) 2019 by Dustin Spicuzza (dustin@virtualroadside.com)
Copyright (C) 2012 by Nick Craig-Wood http://www.craig-wood.com/nick/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View file

@ -0,0 +1,34 @@
> This package was copied from https://github.com/virtuald/go-paniclog
go-paniclog
===========
By default, panics in golang are sent to stderr. Unfortunately, there isn't a
direct builtin global mechanism to capture/send the output of the panic to
a file or really do anything with it other than to write to stderr.
One possible solution is that you can redirect stderr to a file, and that's
all that this package does. Of course, once you redirect stderr to file,
anything else you write to stderr will also end up in that file. v2.0 now
includes a function you can use to undo the redirection if you wanted to do
that for some reason.
Reference: https://stackoverflow.com/questions/34772012/capturing-panic-in-golang
Alternatives
------------
* [panicwrap](https://github.com/mitchellh/panicwrap) may be a better solution
for many programs
Author
------
I can't claim any credit for this idea or the code, it is entirely taken from
the [rclone](https://github.com/ncw/rclone.git) program by Nick Craig-Wood.
License
-------
MIT License

View file

@ -0,0 +1,31 @@
package main
import (
"fmt"
"os"
"github.com/fleetdm/fleet/v4/orbit/pkg/go-paniclog"
)
func main() {
f, err := os.Create("test.log")
if err != nil {
fmt.Println("Error creating file:", err)
os.Exit(1)
}
undo, err := paniclog.RedirectStderr(f)
if err != nil {
fmt.Println("Error redirecting stderr:", err)
os.Exit(1)
}
f.Close()
if os.Getenv("UNDO_PANICLOG") != "" {
// demonstrates undoing the stderr redirect
undo() //nolint:errcheck
}
panic("this should end up in the file instead of the console")
}

View file

@ -0,0 +1,19 @@
package paniclog
import "os"
// UndoFunction will reverse the redirection
type UndoFunction func() error
// RedirectStderr to the file passed in, so that the output of any panics that
// occur will be sent to that file. The caller may close the file after
// this function returns.
//
// Of course, anything else written to stderr will also be sent to that file,
// so don't do that unless that's your intent.
//
// Returns a function that can be used to revert stderr back to the console,
// or an error if stderr could not be redirected
func RedirectStderr(f *os.File) (UndoFunction, error) {
return redirectStderr(f)
}

View file

@ -0,0 +1,15 @@
// Log the panic to the log file - for oses which can't do this
//go:build !windows && !darwin && !dragonfly && !freebsd && !linux && !nacl && !netbsd && !openbsd
// +build !windows,!darwin,!dragonfly,!freebsd,!linux,!nacl,!netbsd,!openbsd
package paniclog
import (
"errors"
"os"
)
func redirectStderr(f *os.File) (UndoFunction, error) {
return nil, errors.New("Can't redirect stderr to file")
}

View file

@ -0,0 +1,39 @@
// Log the panic under unix to the log file
//go:build !windows && !solaris && !plan9
// +build !windows,!solaris,!plan9
package paniclog
import (
"errors"
"os"
"golang.org/x/sys/unix"
)
func redirectStderr(f *os.File) (UndoFunction, error) {
stderrFd := int(os.Stderr.Fd())
oldfd, err := unix.Dup(stderrFd)
if err != nil {
return nil, errors.New("Failed to redirect stderr to file: " + err.Error())
}
err = unix.Dup2(int(f.Fd()), stderrFd)
if err != nil {
return nil, errors.New("Failed to redirect stderr to file: " + err.Error())
}
undo := func() error {
undoErr := unix.Dup2(oldfd, stderrFd)
unix.Close(oldfd)
if undoErr != nil {
return errors.New("Failed to reverse stderr redirection: " + err.Error())
}
return nil
}
return undo, nil
}

View file

@ -0,0 +1,84 @@
// Log the panic under windows to the log file
//
// Code from minix, via
//
// https://play.golang.org/p/kLtct7lSUg
//go:build windows
// +build windows
package paniclog
import (
"errors"
"os"
"syscall"
)
var (
kernel32 = syscall.MustLoadDLL("kernel32.dll")
procSetStdHandle = kernel32.MustFindProc("SetStdHandle")
procGetStdHandle = kernel32.MustFindProc("GetStdHandle")
)
func dupFD(fd uintptr) (syscall.Handle, error) {
// Cribbed from https://github.com/golang/go/blob/go1.8/src/syscall/exec_windows.go#L303.
p, err := syscall.GetCurrentProcess()
if err != nil {
return 0, err
}
var h syscall.Handle
return h, syscall.DuplicateHandle(p, syscall.Handle(fd), p, &h, 0, true, syscall.DUPLICATE_SAME_ACCESS)
}
func getStdHandle(stdHandle int32) (syscall.Handle, error) {
r0, _, e1 := syscall.Syscall(procGetStdHandle.Addr(), 2, uintptr(stdHandle), 0, 0)
rh0 := syscall.Handle(r0)
if rh0 == syscall.InvalidHandle {
if e1 != 0 {
return syscall.InvalidHandle, error(e1)
}
return syscall.InvalidHandle, syscall.EINVAL
}
return syscall.Handle(r0), nil
}
func setStdHandle(stdhandle int32, handle syscall.Handle) error {
r0, _, e1 := syscall.Syscall(procSetStdHandle.Addr(), 2, uintptr(stdhandle), uintptr(handle), 0)
if r0 == 0 {
if e1 != 0 {
return error(e1)
}
return syscall.EINVAL
}
return nil
}
func redirectStderr(f *os.File) (UndoFunction, error) {
stderrFd, err := getStdHandle(syscall.STD_ERROR_HANDLE)
if err != nil {
return nil, errors.New("Failed to redirect stderr to file: " + err.Error())
}
// duplicate the handle to match unix behavior
fHandle, err := dupFD(f.Fd())
if err != nil {
return nil, errors.New("Failed to duplicate file: " + err.Error())
}
err = setStdHandle(syscall.STD_ERROR_HANDLE, fHandle)
if err != nil {
return nil, errors.New("Failed to redirect stderr to file: " + err.Error())
}
undo := func() error {
err := setStdHandle(syscall.STD_ERROR_HANDLE, stderrFd)
if err != nil {
return errors.New("Failed to redirect stderr to file: " + err.Error())
}
syscall.CloseHandle(fHandle)
return nil
}
return undo, nil
}

View file

@ -54,7 +54,8 @@ func SignalProcessBeforeTerminate(processName string) error {
return nil
}
// GetProcessByName gets a single process object by its name
// GetProcessByName gets a single running process object by its name.
// Returns ErrProcessNotFound if the process was not found running.
func GetProcessByName(name string) (*gopsutil_process.Process, error) {
if name == "" {
return nil, errors.New("process name should not be empty")

View file

@ -136,16 +136,14 @@ func SignalProcessBeforeTerminate(processName string) error {
return fmt.Errorf("get process: %w", err)
}
isRunning, err := foundProcess.IsRunning()
if (err == nil) && (isRunning) {
if err := foundProcess.Kill(); err != nil {
return fmt.Errorf("kill process %d: %w", foundProcess.Pid, err)
}
if err := foundProcess.Kill(); err != nil {
return fmt.Errorf("kill process %d: %w", foundProcess.Pid, err)
}
return nil
}
// GetProcessByName gets a single process object by its name
// GetProcessByName gets a single running process object by its name.
// Returns ErrProcessNotFound if the process was not found running.
func GetProcessByName(name string) (*gopsutil_process.Process, error) {
if name == "" {
return nil, errors.New("process name should not be empty")
@ -198,6 +196,11 @@ func GetProcessByName(name string) (*gopsutil_process.Process, error) {
return nil, fmt.Errorf("NewProcess: %w", err)
}
isRunning, err := process.IsRunning()
if err != nil || !isRunning {
return nil, ErrProcessNotFound
}
return process, nil
}