Skip to content

Commit

Permalink
feat(inputs.win_wmi): Add support for remote queries
Browse files Browse the repository at this point in the history
  • Loading branch information
srebhan committed Mar 12, 2024
1 parent 8183d47 commit 712d76b
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 7 deletions.
15 changes: 15 additions & 0 deletions plugins/inputs/win_wmi/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,27 @@ See the [CONFIGURATION.md][CONFIGURATION.md] for more details.

[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

```toml @sample.conf
# Input plugin to query Windows Management Instrumentation
# This plugin ONLY supports Windows
[[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]]
# a string representing the WMI namespace to be queried
namespace = "root\\cimv2"
Expand Down
41 changes: 37 additions & 4 deletions plugins/inputs/win_wmi/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ import (

"github.com/go-ole/go-ole"
"github.com/go-ole/go-ole/oleutil"

"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/config"
"github.com/influxdata/telegraf/filter"
"github.com/influxdata/telegraf/internal"
)
Expand All @@ -23,18 +25,44 @@ type Query struct {
Filter string `toml:"filter"`
TagPropertiesInclude []string `toml:"tag_properties"`

tagFilter filter.Filter
query string
host 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
f, err := filter.Compile(q.TagPropertiesInclude)
if err != nil {
return fmt.Errorf("compiling tag-filter failed: %w", err)
}
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
wql := fmt.Sprintf("SELECT %s FROM %s", strings.Join(q.Properties, ", "), q.ClassName)
if len(q.Filter) > 0 {
Expand Down Expand Up @@ -78,7 +106,8 @@ func (q *Query) execute(acc telegraf.Accumulator) error {
defer wmi.Release()

// service is a SWbemServices
serviceRaw, err := oleutil.CallMethod(wmi, "ConnectServer", nil, q.Namespace)
serviceRaw, err := oleutil.CallMethod(wmi, "ConnectServer", q.connectionParams...)

if err != nil {
return fmt.Errorf("failed calling method ConnectServer: %w", err)
}
Expand Down Expand Up @@ -116,6 +145,10 @@ func (q *Query) execute(acc telegraf.Accumulator) error {
func (q *Query) extractProperties(acc telegraf.Accumulator, itemRaw *ole.VARIANT) error {
tags, fields := map[string]string{}, map[string]interface{}{}

if q.host != "" {
tags["source"] = q.host
}

item := itemRaw.ToIDispatch()
defer item.Release()

Expand Down
6 changes: 6 additions & 0 deletions plugins/inputs/win_wmi/sample.conf
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
# Input plugin to query Windows Management Instrumentation
# This plugin ONLY supports Windows
[[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]]
# a string representing the WMI namespace to be queried
namespace = "root\\cimv2"
Expand Down
10 changes: 7 additions & 3 deletions plugins/inputs/win_wmi/win_wmi.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"sync"

"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/config"
"github.com/influxdata/telegraf/plugins/inputs"
)

Expand All @@ -17,8 +18,11 @@ var sampleConfig string

// Wmi struct
type Wmi struct {
Queries []Query `toml:"query"`
Log telegraf.Logger `toml:"-"`
Host string `toml:"host"`
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.
Expand All @@ -28,7 +32,7 @@ const sFalse = 0x00000001
func (w *Wmi) Init() error {
for i := range w.Queries {
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)
}
}
Expand Down

0 comments on commit 712d76b

Please sign in to comment.