-
Notifications
You must be signed in to change notification settings - Fork 56
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix and improve Windows service handling (#321)
* Fix and improve Windows service handling This change addresses several issues how we handle windows services: - Change the DisplayName of the Sidecar itself so it does not conflict with old sidecars. - If a sidecar backend (aka collector) gets renamed, update the DisplayName to avoid a conflict with the existing service. - If backends get renamed, or deleted while the sidecar isn't running there was no way we could cleanup those. Therefore update golang/x/sys to a newer version that supports `ListServices()` so we can search for stale registered services and clean those. - Improve error handling in `ValidateBeforeStart()` which could lead to a panic if a service could not be created. Fixes #319 * Fix commandline parsing for Windows On Windows, use CommandLineToArgv() to run foreground processes. In the previous change I've only used it to run validation commands. With this change it is possible to run collectors without the need for services on Windows. Fixes #290 (2nd fix) * Fix intial Windows service startup `CreateService` would not create the service with command line arguments. Run an immediate `UpdateConfig` afterwards to fixup the `BinaryPathName`. Also remove the unecessarily verbose error message when we just probe whether a service is running. It's ok if it does not.
- Loading branch information
Showing
7 changed files
with
171 additions
and
78 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
// +build !windows | ||
|
||
package daemon | ||
|
||
import ( | ||
"github.com/Graylog2/collector-sidecar/backends" | ||
) | ||
|
||
// Dummy function. Only used on Windows | ||
func CleanOldServices(assignedBackends []*backends.Backend) { | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
package daemon | ||
|
||
import ( | ||
"fmt" | ||
"github.com/Graylog2/collector-sidecar/backends" | ||
"golang.org/x/sys/windows/svc" | ||
"golang.org/x/sys/windows/svc/eventlog" | ||
"golang.org/x/sys/windows/svc/mgr" | ||
"strings" | ||
"time" | ||
) | ||
|
||
func CleanOldServices(assignedBackends []*backends.Backend) { | ||
registeredServices, err := getRegisteredServices() | ||
if err != nil { | ||
log.Warn("Failed to get registered services. Skipping cleanup. ", err) | ||
return | ||
} | ||
for _, service := range registeredServices { | ||
if strings.Contains(service, ServiceNamePrefix) { | ||
log.Debugf("Found graylog service %s", service) | ||
if !serviceIsAssigned(assignedBackends, service) { | ||
log.Infof("Removing stale graylog service %s", service) | ||
uninstallService(service) | ||
} | ||
} | ||
} | ||
} | ||
|
||
func getRegisteredServices() ([]string, error) { | ||
m, err := mgr.Connect() | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer m.Disconnect() | ||
registeredServices, err := m.ListServices() | ||
if err != nil { | ||
return nil, err | ||
} | ||
return registeredServices, nil | ||
} | ||
|
||
func serviceIsAssigned(assignedBackends []*backends.Backend, serviceName string) bool { | ||
for _, backend := range assignedBackends { | ||
if backend.ServiceType == "svc" && ServiceNamePrefix+backend.Name == serviceName { | ||
return true | ||
} | ||
} | ||
return false | ||
} | ||
|
||
func uninstallService(name string) { | ||
log.Infof("Uninstalling service %s", name) | ||
stopService(name) | ||
|
||
m, err := mgr.Connect() | ||
if err != nil { | ||
log.Errorf("Failed to connect to service manager: %v", err) | ||
return | ||
} | ||
defer m.Disconnect() | ||
|
||
s, err := m.OpenService(name) | ||
// service exist so we try to uninstall it | ||
if err != nil { | ||
log.Debugf("Service %s doesn't exist, no uninstall action needed", name) | ||
return | ||
} | ||
|
||
defer s.Close() | ||
err = s.Delete() | ||
if err != nil { | ||
log.Errorf("Can't delete service %s: %v", name, err) | ||
} | ||
|
||
err = eventlog.Remove(s.Name) | ||
if err != nil { | ||
log.Errorf("RemoveEventLogSource() failed: %s", err) | ||
} | ||
return | ||
} | ||
|
||
func stopService(serviceName string) error { | ||
m, err := mgr.Connect() | ||
if err != nil { | ||
return fmt.Errorf("Failed to connect to service manager: %v", err) | ||
} | ||
defer m.Disconnect() | ||
|
||
ws, err := m.OpenService(serviceName) | ||
if err != nil { | ||
return fmt.Errorf("Could not access service %s: %v", serviceName, err) | ||
} | ||
defer ws.Close() | ||
|
||
status, err := ws.Control(svc.Stop) | ||
if err != nil { | ||
return fmt.Errorf("Could not send stop control: %v", err) | ||
} | ||
|
||
timeout := time.Now().Add(10 * time.Second) | ||
for status.State != svc.Stopped { | ||
if timeout.Before(time.Now()) { | ||
return fmt.Errorf("Timeout waiting for service to go to stopped state: %v", err) | ||
} | ||
time.Sleep(300 * time.Millisecond) | ||
status, err = ws.Query() | ||
if err != nil { | ||
return fmt.Errorf("Could not retrieve service status: %v", err) | ||
} | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters