fleet/orbit/pkg/osservice/osservice_windows.go
Marcos Oviedo ec3f49881f
8009 fleet desktop icon duplication (#8017)
* Adding a new synchronization mechanism between fleet-desktop app and Orbit service. Improved windows service teardown to ensure that fleet-desktop does not get force killed without getting signaled. Improved windows process enumeration to avoid unnecessary delays during windows service start and windows service teardown. Updating windows service to reflect service teardown extra time due to synchronization.
2022-10-13 10:58:37 -03:00

87 lines
2.2 KiB
Go

//go:build windows
// +build windows
package osservice
import (
"os"
"github.com/rs/zerolog/log"
"golang.org/x/sys/windows"
"golang.org/x/sys/windows/svc"
)
type windowsService struct {
interruptCh chan struct{}
appDoneCh chan struct{}
}
func (m *windowsService) Execute(args []string, requests <-chan svc.ChangeRequest, changes chan<- svc.Status) (ssec bool, errno uint32) {
// Accepted service operations
const cmdsAccepted = svc.AcceptStop | svc.AcceptShutdown
// Expected service status update during initialization
changes <- svc.Status{State: svc.StartPending}
changes <- svc.Status{State: svc.Running, Accepts: cmdsAccepted}
// The listening loop below will keep listening for new SCM requests
for req := range requests {
switch req.Cmd {
case svc.Interrogate:
log.Info().Msg("Service Interrogate Requested")
changes <- req.CurrentStatus
case svc.Stop, svc.Shutdown:
log.Info().Msg("Service Stop Requested")
// Updating the service state to indicate stop
changes <- svc.Status{State: svc.Stopped, Win32ExitCode: 0}
// Best effort graceful tear down
// Runner group's will be interrupted after signaling them
close(m.interruptCh)
// Wait for runners group to finish
<-m.appDoneCh
// Drastic teardown
os.Exit(windows.NO_ERROR)
default:
log.Info().Msg("Unknown service request")
return false, uint32(windows.ERROR_INVALID_SERVICE_CONTROL)
}
}
return false, 0
}
// SetupServiceManagement implements the dispatcher and notification logic to
// interact with the Windows Service Control Manager (SCM)
func SetupServiceManagement(serviceName string, interruptCh chan struct{}, doneCh chan struct{}) {
if serviceName == "" {
log.Error().Msg(" service name should not be empty")
return
}
// Ensuring that we are only calling the SCM if running as a service
isWindowsService, err := svc.IsWindowsService()
if err != nil {
log.Error().Err(err).Msg("couldn't determine if running as a service")
return
}
if isWindowsService {
srvData := windowsService{
interruptCh: interruptCh,
appDoneCh: doneCh,
}
// Registering our service into the SCM
err := svc.Run(serviceName, &srvData)
if err != nil {
log.Info().Err(err).Msg("SCM registration failed")
}
}
}