Adding upstream version 1.34.4.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
e393c3af3f
commit
4978089aab
4963 changed files with 677545 additions and 0 deletions
248
plugins/inputs/win_services/win_services.go
Normal file
248
plugins/inputs/win_services/win_services.go
Normal file
|
@ -0,0 +1,248 @@
|
|||
//go:generate ../../../tools/readme_config_includer/generator
|
||||
//go:build windows
|
||||
|
||||
package win_services
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
"golang.org/x/sys/windows/svc"
|
||||
"golang.org/x/sys/windows/svc/mgr"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/filter"
|
||||
"github.com/influxdata/telegraf/plugins/inputs"
|
||||
)
|
||||
|
||||
//go:embed sample.conf
|
||||
var sampleConfig string
|
||||
|
||||
type WinServices struct {
|
||||
ServiceNames []string `toml:"service_names"`
|
||||
ServiceNamesExcluded []string `toml:"excluded_service_names"`
|
||||
|
||||
Log telegraf.Logger `toml:"-"`
|
||||
|
||||
mgrProvider managerProvider
|
||||
servicesFilter filter.Filter
|
||||
}
|
||||
|
||||
// winService provides interface for svc.Service
|
||||
type winService interface {
|
||||
Close() error
|
||||
Config() (mgr.Config, error)
|
||||
Query() (svc.Status, error)
|
||||
}
|
||||
|
||||
// managerProvider sets interface for acquiring manager instance, like mgr.Mgr
|
||||
type managerProvider interface {
|
||||
connect() (winServiceManager, error)
|
||||
}
|
||||
|
||||
// winServiceManager provides interface for mgr.Mgr
|
||||
type winServiceManager interface {
|
||||
disconnect() error
|
||||
openService(name string) (winService, error)
|
||||
listServices() ([]string, error)
|
||||
}
|
||||
|
||||
type serviceInfo struct {
|
||||
ServiceName string
|
||||
DisplayName string
|
||||
State int
|
||||
StartUpMode int
|
||||
}
|
||||
|
||||
func (*WinServices) SampleConfig() string {
|
||||
return sampleConfig
|
||||
}
|
||||
|
||||
func (m *WinServices) Init() error {
|
||||
// For case insensitive comparison (see issue #8796) we need to transform the services
|
||||
// to lowercase
|
||||
servicesInclude := make([]string, 0, len(m.ServiceNames))
|
||||
for _, s := range m.ServiceNames {
|
||||
servicesInclude = append(servicesInclude, strings.ToLower(s))
|
||||
}
|
||||
servicesExclude := make([]string, 0, len(m.ServiceNamesExcluded))
|
||||
for _, s := range m.ServiceNamesExcluded {
|
||||
servicesExclude = append(servicesExclude, strings.ToLower(s))
|
||||
}
|
||||
|
||||
f, err := filter.NewIncludeExcludeFilter(servicesInclude, servicesExclude)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m.servicesFilter = f
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *WinServices) Gather(acc telegraf.Accumulator) error {
|
||||
scmgr, err := m.mgrProvider.connect()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not open service manager: %w", err)
|
||||
}
|
||||
defer scmgr.disconnect()
|
||||
|
||||
serviceNames, err := m.listServices(scmgr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, srvName := range serviceNames {
|
||||
service, err := collectServiceInfo(scmgr, srvName)
|
||||
if err != nil {
|
||||
if isPermission(err) {
|
||||
m.Log.Debug(err.Error())
|
||||
} else {
|
||||
m.Log.Error(err.Error())
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
tags := map[string]string{
|
||||
"service_name": service.ServiceName,
|
||||
}
|
||||
// display name could be empty, but still valid service
|
||||
if len(service.DisplayName) > 0 {
|
||||
tags["display_name"] = service.DisplayName
|
||||
}
|
||||
|
||||
fields := map[string]interface{}{
|
||||
"state": service.State,
|
||||
"startup_mode": service.StartUpMode,
|
||||
}
|
||||
acc.AddFields("win_services", fields, tags)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// listServices returns a list of services to gather.
|
||||
func (m *WinServices) listServices(scmgr winServiceManager) ([]string, error) {
|
||||
names, err := scmgr.listServices()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not list services: %w", err)
|
||||
}
|
||||
|
||||
var services []string
|
||||
for _, name := range names {
|
||||
// Compare case-insensitive. Use lowercase as we already converted the filter to use it.
|
||||
n := strings.ToLower(name)
|
||||
if m.servicesFilter.Match(n) {
|
||||
services = append(services, name)
|
||||
}
|
||||
}
|
||||
|
||||
return services, nil
|
||||
}
|
||||
|
||||
func isPermission(err error) bool {
|
||||
var serviceErr *serviceError
|
||||
if errors.As(err, &serviceErr) {
|
||||
return errors.Is(serviceErr, fs.ErrPermission)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// collectServiceInfo gathers info about a service.
|
||||
func collectServiceInfo(scmgr winServiceManager, serviceName string) (*serviceInfo, error) {
|
||||
srv, err := scmgr.openService(serviceName)
|
||||
if err != nil {
|
||||
return nil, &serviceError{
|
||||
message: "could not open service",
|
||||
service: serviceName,
|
||||
err: err,
|
||||
}
|
||||
}
|
||||
defer srv.Close()
|
||||
|
||||
srvStatus, err := srv.Query()
|
||||
if err != nil {
|
||||
return nil, &serviceError{
|
||||
message: "could not query service",
|
||||
service: serviceName,
|
||||
err: err,
|
||||
}
|
||||
}
|
||||
|
||||
srvCfg, err := srv.Config()
|
||||
if err != nil {
|
||||
return nil, &serviceError{
|
||||
message: "could not get config of service",
|
||||
service: serviceName,
|
||||
err: err,
|
||||
}
|
||||
}
|
||||
|
||||
serviceInfo := &serviceInfo{
|
||||
ServiceName: serviceName,
|
||||
DisplayName: srvCfg.DisplayName,
|
||||
StartUpMode: int(srvCfg.StartType),
|
||||
State: int(srvStatus.State),
|
||||
}
|
||||
return serviceInfo, nil
|
||||
}
|
||||
|
||||
type serviceError struct {
|
||||
message string
|
||||
service string
|
||||
err error
|
||||
}
|
||||
|
||||
func (e *serviceError) Error() string {
|
||||
return fmt.Sprintf("%s: %q: %v", e.message, e.service, e.err)
|
||||
}
|
||||
|
||||
// winSvcMgr is wrapper for mgr.Mgr implementing winServiceManager interface
|
||||
type winSvcMgr struct {
|
||||
realMgr *mgr.Mgr
|
||||
}
|
||||
|
||||
func (m *winSvcMgr) disconnect() error {
|
||||
return m.realMgr.Disconnect()
|
||||
}
|
||||
|
||||
func (m *winSvcMgr) openService(name string) (winService, error) {
|
||||
serviceName, err := syscall.UTF16PtrFromString(name)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot convert service name %q: %w", name, err)
|
||||
}
|
||||
h, err := windows.OpenService(m.realMgr.Handle, serviceName, windows.GENERIC_READ)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mgr.Service{Name: name, Handle: h}, nil
|
||||
}
|
||||
|
||||
func (m *winSvcMgr) listServices() ([]string, error) {
|
||||
return m.realMgr.ListServices()
|
||||
}
|
||||
|
||||
// mgProvider is an implementation of WinServiceManagerProvider interface returning winSvcMgr
|
||||
type mgProvider struct {
|
||||
}
|
||||
|
||||
func (*mgProvider) connect() (winServiceManager, error) {
|
||||
h, err := windows.OpenSCManager(nil, nil, windows.GENERIC_READ)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
scmgr := &mgr.Mgr{Handle: h}
|
||||
return &winSvcMgr{scmgr}, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
inputs.Add("win_services", func() telegraf.Input {
|
||||
return &WinServices{
|
||||
mgrProvider: &mgProvider{},
|
||||
}
|
||||
})
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue