feat(inputs.win_wmi): Add support for remote queries (#14973)
This commit is contained in:
parent
60adc92014
commit
f8905b270a
|
|
@ -19,12 +19,27 @@ See the [CONFIGURATION.md][CONFIGURATION.md] for more details.
|
||||||
|
|
||||||
[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins
|
[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins
|
||||||
|
|
||||||
|
## Secret-store support
|
||||||
|
|
||||||
|
This plugin supports secrets from secret-stores for the `username` and
|
||||||
|
`password` option.
|
||||||
|
See the [secret-store documentation][SECRETSTORE] for more details on how
|
||||||
|
to use them.
|
||||||
|
|
||||||
|
[SECRETSTORE]: ../../../docs/CONFIGURATION.md#secret-store-secrets
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
```toml @sample.conf
|
```toml @sample.conf
|
||||||
# Input plugin to query Windows Management Instrumentation
|
# Input plugin to query Windows Management Instrumentation
|
||||||
# This plugin ONLY supports Windows
|
# This plugin ONLY supports Windows
|
||||||
[[inputs.win_wmi]]
|
[[inputs.win_wmi]]
|
||||||
|
## Hostname or IP for remote connections, by default the local machine is queried
|
||||||
|
# host = ""
|
||||||
|
## Credentials for the connection, by default no credentials are used
|
||||||
|
# username = ""
|
||||||
|
# password = ""
|
||||||
|
|
||||||
[[inputs.win_wmi.query]]
|
[[inputs.win_wmi.query]]
|
||||||
# a string representing the WMI namespace to be queried
|
# a string representing the WMI namespace to be queried
|
||||||
namespace = "root\\cimv2"
|
namespace = "root\\cimv2"
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,9 @@ import (
|
||||||
|
|
||||||
"github.com/go-ole/go-ole"
|
"github.com/go-ole/go-ole"
|
||||||
"github.com/go-ole/go-ole/oleutil"
|
"github.com/go-ole/go-ole/oleutil"
|
||||||
|
|
||||||
"github.com/influxdata/telegraf"
|
"github.com/influxdata/telegraf"
|
||||||
|
"github.com/influxdata/telegraf/config"
|
||||||
"github.com/influxdata/telegraf/filter"
|
"github.com/influxdata/telegraf/filter"
|
||||||
"github.com/influxdata/telegraf/internal"
|
"github.com/influxdata/telegraf/internal"
|
||||||
)
|
)
|
||||||
|
|
@ -23,11 +25,13 @@ type Query struct {
|
||||||
Filter string `toml:"filter"`
|
Filter string `toml:"filter"`
|
||||||
TagPropertiesInclude []string `toml:"tag_properties"`
|
TagPropertiesInclude []string `toml:"tag_properties"`
|
||||||
|
|
||||||
tagFilter filter.Filter
|
host string
|
||||||
query string
|
query string
|
||||||
|
connectionParams []interface{}
|
||||||
|
tagFilter filter.Filter
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Query) prepare() error {
|
func (q *Query) prepare(host string, username, password config.Secret) error {
|
||||||
// Compile the filter
|
// Compile the filter
|
||||||
f, err := filter.Compile(q.TagPropertiesInclude)
|
f, err := filter.Compile(q.TagPropertiesInclude)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -35,6 +39,30 @@ func (q *Query) prepare() error {
|
||||||
}
|
}
|
||||||
q.tagFilter = f
|
q.tagFilter = f
|
||||||
|
|
||||||
|
q.host = host
|
||||||
|
if q.host != "" {
|
||||||
|
q.connectionParams = append(q.connectionParams, q.host)
|
||||||
|
} else {
|
||||||
|
q.connectionParams = append(q.connectionParams, nil)
|
||||||
|
}
|
||||||
|
q.connectionParams = append(q.connectionParams, q.Namespace)
|
||||||
|
if !username.Empty() {
|
||||||
|
u, err := username.Get()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("getting username secret failed: %w", err)
|
||||||
|
}
|
||||||
|
q.connectionParams = append(q.connectionParams, u.String())
|
||||||
|
username.Destroy()
|
||||||
|
}
|
||||||
|
if !password.Empty() {
|
||||||
|
p, err := password.Get()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("getting password secret failed: %w", err)
|
||||||
|
}
|
||||||
|
q.connectionParams = append(q.connectionParams, p.String())
|
||||||
|
password.Destroy()
|
||||||
|
}
|
||||||
|
|
||||||
// Construct the overall query from the given parts
|
// Construct the overall query from the given parts
|
||||||
wql := fmt.Sprintf("SELECT %s FROM %s", strings.Join(q.Properties, ", "), q.ClassName)
|
wql := fmt.Sprintf("SELECT %s FROM %s", strings.Join(q.Properties, ", "), q.ClassName)
|
||||||
if len(q.Filter) > 0 {
|
if len(q.Filter) > 0 {
|
||||||
|
|
@ -78,7 +106,8 @@ func (q *Query) execute(acc telegraf.Accumulator) error {
|
||||||
defer wmi.Release()
|
defer wmi.Release()
|
||||||
|
|
||||||
// service is a SWbemServices
|
// service is a SWbemServices
|
||||||
serviceRaw, err := oleutil.CallMethod(wmi, "ConnectServer", nil, q.Namespace)
|
serviceRaw, err := oleutil.CallMethod(wmi, "ConnectServer", q.connectionParams...)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed calling method ConnectServer: %w", err)
|
return fmt.Errorf("failed calling method ConnectServer: %w", err)
|
||||||
}
|
}
|
||||||
|
|
@ -116,6 +145,10 @@ func (q *Query) execute(acc telegraf.Accumulator) error {
|
||||||
func (q *Query) extractProperties(acc telegraf.Accumulator, itemRaw *ole.VARIANT) error {
|
func (q *Query) extractProperties(acc telegraf.Accumulator, itemRaw *ole.VARIANT) error {
|
||||||
tags, fields := map[string]string{}, map[string]interface{}{}
|
tags, fields := map[string]string{}, map[string]interface{}{}
|
||||||
|
|
||||||
|
if q.host != "" {
|
||||||
|
tags["source"] = q.host
|
||||||
|
}
|
||||||
|
|
||||||
item := itemRaw.ToIDispatch()
|
item := itemRaw.ToIDispatch()
|
||||||
defer item.Release()
|
defer item.Release()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,12 @@
|
||||||
# Input plugin to query Windows Management Instrumentation
|
# Input plugin to query Windows Management Instrumentation
|
||||||
# This plugin ONLY supports Windows
|
# This plugin ONLY supports Windows
|
||||||
[[inputs.win_wmi]]
|
[[inputs.win_wmi]]
|
||||||
|
## Hostname or IP for remote connections, by default the local machine is queried
|
||||||
|
# host = ""
|
||||||
|
## Credentials for the connection, by default no credentials are used
|
||||||
|
# username = ""
|
||||||
|
# password = ""
|
||||||
|
|
||||||
[[inputs.win_wmi.query]]
|
[[inputs.win_wmi.query]]
|
||||||
# a string representing the WMI namespace to be queried
|
# a string representing the WMI namespace to be queried
|
||||||
namespace = "root\\cimv2"
|
namespace = "root\\cimv2"
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/influxdata/telegraf"
|
"github.com/influxdata/telegraf"
|
||||||
|
"github.com/influxdata/telegraf/config"
|
||||||
"github.com/influxdata/telegraf/plugins/inputs"
|
"github.com/influxdata/telegraf/plugins/inputs"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -17,8 +18,11 @@ var sampleConfig string
|
||||||
|
|
||||||
// Wmi struct
|
// Wmi struct
|
||||||
type Wmi struct {
|
type Wmi struct {
|
||||||
Queries []Query `toml:"query"`
|
Host string `toml:"host"`
|
||||||
Log telegraf.Logger `toml:"-"`
|
Username config.Secret `toml:"username"`
|
||||||
|
Password config.Secret `toml:"password"`
|
||||||
|
Queries []Query `toml:"query"`
|
||||||
|
Log telegraf.Logger `toml:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// S_FALSE is returned by CoInitializeEx if it was already called on this thread.
|
// S_FALSE is returned by CoInitializeEx if it was already called on this thread.
|
||||||
|
|
@ -28,7 +32,7 @@ const sFalse = 0x00000001
|
||||||
func (w *Wmi) Init() error {
|
func (w *Wmi) Init() error {
|
||||||
for i := range w.Queries {
|
for i := range w.Queries {
|
||||||
q := &w.Queries[i]
|
q := &w.Queries[i]
|
||||||
if err := q.prepare(); err != nil {
|
if err := q.prepare(w.Host, w.Username, w.Password); err != nil {
|
||||||
return fmt.Errorf("preparing query %q failed: %w", q.ClassName, err)
|
return fmt.Errorf("preparing query %q failed: %w", q.ClassName, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue