From b67b930ffcc8aeabdb6b3e75deae2e54933e0b8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Otto=20Kr=C3=B6pke?= Date: Sat, 28 Sep 2024 19:53:12 +0200 Subject: [PATCH] initiate: fix Cannot create another system semaphore error (#1653) --- exporter.go | 12 ++++++- pkg/initiate/initiate.go | 78 +++++++++++++++++++++++++--------------- 2 files changed, 60 insertions(+), 30 deletions(-) diff --git a/exporter.go b/exporter.go index 09906ffb..874321c2 100644 --- a/exporter.go +++ b/exporter.go @@ -39,7 +39,17 @@ import ( ) func main() { - os.Exit(run()) + exitCode := run() + + // If we are running as a service, we need to signal the service control manager that we are done. + if !initiate.IsService { + os.Exit(exitCode) + } + + initiate.ExitCodeCh <- exitCode + + // Wait for the service control manager to signal that we are done. + <-initiate.StopCh } func run() int { diff --git a/pkg/initiate/initiate.go b/pkg/initiate/initiate.go index ced9332e..cae05311 100644 --- a/pkg/initiate/initiate.go +++ b/pkg/initiate/initiate.go @@ -5,6 +5,7 @@ import ( "fmt" "os" + "golang.org/x/sys/windows" "golang.org/x/sys/windows/svc" "golang.org/x/sys/windows/svc/eventlog" ) @@ -15,61 +16,80 @@ const ( type windowsExporterService struct{} -var logger *eventlog.Log - -//nolint:nonamedreturns -func (s *windowsExporterService) Execute(_ []string, r <-chan svc.ChangeRequest, changes chan<- svc.Status) (ssec bool, errno uint32) { +func (s *windowsExporterService) Execute(_ []string, r <-chan svc.ChangeRequest, changes chan<- svc.Status) (bool, uint32) { const cmdsAccepted = svc.AcceptStop | svc.AcceptShutdown changes <- svc.Status{State: svc.StartPending} changes <- svc.Status{State: svc.Running, Accepts: cmdsAccepted} - for c := range r { - switch c.Cmd { - case svc.Interrogate: - changes <- c.CurrentStatus - case svc.Stop, svc.Shutdown: - _ = logger.Info(100, "Service Stop Received") + for { + select { + case exitCodeCh := <-ExitCodeCh: changes <- svc.Status{State: svc.StopPending} - return - default: - _ = logger.Error(102, fmt.Sprintf("unexpected control request #%d", c)) + return true, uint32(exitCodeCh) + case c := <-r: + switch c.Cmd { + case svc.Interrogate: + changes <- c.CurrentStatus + case svc.Stop, svc.Shutdown: + _ = logToEventToLog(windows.EVENTLOG_INFORMATION_TYPE, "service stop received") + + changes <- svc.Status{State: svc.StopPending} + + return false, 0 + default: + _ = logToEventToLog(windows.EVENTLOG_ERROR_TYPE, fmt.Sprintf("unexpected control request #%d", c)) + } } } - - return } -var StopCh = make(chan bool) +var ( + IsService bool + ExitCodeCh = make(chan int) + StopCh = make(chan struct{}) +) //nolint:gochecknoinits func init() { - isService, err := svc.IsWindowsService() + var err error + + IsService, err = svc.IsWindowsService() if err != nil { - logger, err = eventlog.Open("windows_exporter") + err = logToEventToLog(windows.EVENTLOG_ERROR_TYPE, fmt.Sprintf("Failed to detect service: %v", err)) if err != nil { os.Exit(2) } - _ = logger.Error(102, fmt.Sprintf("Failed to detect service: %v", err)) - os.Exit(1) } - if isService { - logger, err = eventlog.Open("windows_exporter") - if err != nil { - os.Exit(2) - } - - _ = logger.Info(100, "Attempting to start exporter service") + if IsService { + err = logToEventToLog(windows.EVENTLOG_INFORMATION_TYPE, "Attempting to start exporter service") go func() { err = svc.Run(serviceName, &windowsExporterService{}) if err != nil { - _ = logger.Error(102, fmt.Sprintf("Failed to start service: %v", err)) + _ = logToEventToLog(windows.EVENTLOG_ERROR_TYPE, fmt.Sprintf("Failed to start service: %v", err)) } - StopCh <- true + + StopCh <- struct{}{} }() } } + +func logToEventToLog(eType uint16, msg string) error { + eventLog, err := eventlog.Open("windows_exporter") + if err != nil { + return fmt.Errorf("failed to open event log: %w", err) + } + + p, err := windows.UTF16PtrFromString(msg) + if err != nil { + return fmt.Errorf("error convert string to UTF-16: %w", err) + } + + ss := []*uint16{p, nil, nil, nil, nil, nil, nil, nil, nil} + + return windows.ReportEvent(eventLog.Handle, eType, 0, 3299, 0, 9, 0, &ss[0], nil) +}