Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

license collector #1524

Merged
merged 3 commits into from
Jul 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Name | Description | Enabled by default
[fsrmquota](docs/collector.fsrmquota.md) | Microsoft File Server Resource Manager (FSRM) Quotas collector |
[hyperv](docs/collector.hyperv.md) | Hyper-V hosts |
[iis](docs/collector.iis.md) | IIS sites and applications |
[license](docs/collector.license.md) | Windows license status |
[logical_disk](docs/collector.logical_disk.md) | Logical disks, disk I/O | ✓
[logon](docs/collector.logon.md) | User logon sessions |
[memory](docs/collector.memory.md) | Memory usage metrics |
Expand Down
53 changes: 53 additions & 0 deletions docs/collector.license.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# license collector

The license collector exposes metrics about the Windows license status.

|||
-|-
Metric name prefix | `license`
Data source | Win32
Enabled by default? | No

## Flags

None

## Metrics

| Name | Description | Type | Labels |
|--------------------------|----------------|-------|---------|
| `windows_license_status` | license status | gauge | `state` |

### Example metric

```
# HELP windows_license_status Status of windows license
# TYPE windows_license_status gauge
windows_license_status{state="genuine"} 1
windows_license_status{state="invalid_license"} 0
windows_license_status{state="last"} 0
windows_license_status{state="offline"} 0
windows_license_status{state="tampered"} 0
```


## Useful queries

Show if the license is genuine

```
windows_license_status{state="genuine"}
```

## Alerting examples
**prometheus.rules**
```yaml
- alert: "WindowsLicense"
expr: 'windows_license_status{state="genuine"} == 0'
for: "10m"
labels:
severity: "high"
annotations:
summary: "Windows system license is not genuine"
description: "The Windows system license is not genuine. Please check the license status."
```
3 changes: 3 additions & 0 deletions pkg/collector/collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"github.com/alecthomas/kingpin/v2"
"github.com/go-kit/log"

"github.com/prometheus-community/windows_exporter/pkg/collector/ad"
"github.com/prometheus-community/windows_exporter/pkg/collector/adcs"
"github.com/prometheus-community/windows_exporter/pkg/collector/adfs"
Expand All @@ -23,6 +24,7 @@ import (
"github.com/prometheus-community/windows_exporter/pkg/collector/exchange"
"github.com/prometheus-community/windows_exporter/pkg/collector/hyperv"
"github.com/prometheus-community/windows_exporter/pkg/collector/iis"
"github.com/prometheus-community/windows_exporter/pkg/collector/license"
"github.com/prometheus-community/windows_exporter/pkg/collector/logical_disk"
"github.com/prometheus-community/windows_exporter/pkg/collector/logon"
"github.com/prometheus-community/windows_exporter/pkg/collector/memory"
Expand Down Expand Up @@ -103,6 +105,7 @@ func NewWithConfig(logger log.Logger, config Config) Collectors {
collectors[exchange.Name] = exchange.New(logger, &config.Fsrmquota)
collectors[hyperv.Name] = hyperv.New(logger, &config.Hyperv)
collectors[iis.Name] = iis.New(logger, &config.Iis)
collectors[license.Name] = license.New(logger, &config.License)
collectors[logical_disk.Name] = logical_disk.New(logger, &config.LogicalDisk)
collectors[logon.Name] = logon.New(logger, &config.Logon)
collectors[memory.Name] = memory.New(logger, &config.Memory)
Expand Down
3 changes: 3 additions & 0 deletions pkg/collector/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/prometheus-community/windows_exporter/pkg/collector/exchange"
"github.com/prometheus-community/windows_exporter/pkg/collector/hyperv"
"github.com/prometheus-community/windows_exporter/pkg/collector/iis"
"github.com/prometheus-community/windows_exporter/pkg/collector/license"
"github.com/prometheus-community/windows_exporter/pkg/collector/logical_disk"
"github.com/prometheus-community/windows_exporter/pkg/collector/logon"
"github.com/prometheus-community/windows_exporter/pkg/collector/memory"
Expand Down Expand Up @@ -74,6 +75,7 @@ type Config struct {
Fsrmquota exchange.Config `yaml:"fsrmquota"`
Hyperv hyperv.Config `yaml:"hyperv"`
Iis iis.Config `yaml:"iis"`
License license.Config `yaml:"license"`
LogicalDisk logical_disk.Config `yaml:"logical_disk"`
Logon logon.Config `yaml:"logon"`
Memory memory.Config `yaml:"memory"`
Expand Down Expand Up @@ -133,6 +135,7 @@ var ConfigDefaults = Config{
Fsrmquota: exchange.ConfigDefaults,
Hyperv: hyperv.ConfigDefaults,
Iis: iis.ConfigDefaults,
License: license.ConfigDefaults,
LogicalDisk: logical_disk.ConfigDefaults,
Logon: logon.ConfigDefaults,
Memory: memory.ConfigDefaults,
Expand Down
95 changes: 95 additions & 0 deletions pkg/collector/license/license.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
//go:build windows

package license

import (
"github.com/alecthomas/kingpin/v2"
"github.com/go-kit/log"
"github.com/go-kit/log/level"
"github.com/prometheus/client_golang/prometheus"

"github.com/prometheus-community/windows_exporter/pkg/headers/slc"
"github.com/prometheus-community/windows_exporter/pkg/types"
)

const Name = "license"

var labelMap = map[slc.SL_GENUINE_STATE]string{
slc.SL_GEN_STATE_IS_GENUINE: "genuine",
slc.SL_GEN_STATE_INVALID_LICENSE: "invalid_license",
slc.SL_GEN_STATE_TAMPERED: "tampered",
slc.SL_GEN_STATE_OFFLINE: "offline",
slc.SL_GEN_STATE_LAST: "last",
}

type Config struct{}

var ConfigDefaults = Config{}

// A collector is a Prometheus collector for WMI Win32_PerfRawData_DNS_DNS metrics
type collector struct {
logger log.Logger

LicenseStatus *prometheus.Desc
}

func New(logger log.Logger, _ *Config) types.Collector {
c := &collector{}
c.SetLogger(logger)
return c
}

func NewWithFlags(_ *kingpin.Application) types.Collector {
return &collector{}
}

func (c *collector) GetName() string {
return Name
}

func (c *collector) SetLogger(logger log.Logger) {
c.logger = log.With(logger, "collector", Name)
}

func (c *collector) GetPerfCounter() ([]string, error) {
return []string{}, nil
}

func (c *collector) Build() error {
c.LicenseStatus = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "status"),
"Status of windows license",
[]string{"state"},
nil,
)

return nil
}

// Collect sends the metric values for each metric
// to the provided prometheus Metric channel.
func (c *collector) Collect(_ *types.ScrapeContext, ch chan<- prometheus.Metric) error {
if err := c.collect(ch); err != nil {
_ = level.Error(c.logger).Log("msg", "failed collecting license metrics", "err", err)
return err
}
return nil
}

func (c *collector) collect(ch chan<- prometheus.Metric) error {
status, err := slc.SLIsWindowsGenuineLocal()
if err != nil {
return err
}

for k, v := range labelMap {
val := 0.0
if status == k {
val = 1.0
}

ch <- prometheus.MustNewConstMetric(c.LicenseStatus, prometheus.GaugeValue, val, v)
}

return nil
}
12 changes: 12 additions & 0 deletions pkg/collector/license/license_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package license_test

import (
"testing"

"github.com/prometheus-community/windows_exporter/pkg/collector/license"
"github.com/prometheus-community/windows_exporter/pkg/testutils"
)

func BenchmarkCollector(b *testing.B) {
testutils.FuncBenchmarkCollector(b, license.Name, license.NewWithFlags)
}
2 changes: 2 additions & 0 deletions pkg/collector/map.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/prometheus-community/windows_exporter/pkg/collector/fsrmquota"
"github.com/prometheus-community/windows_exporter/pkg/collector/hyperv"
"github.com/prometheus-community/windows_exporter/pkg/collector/iis"
"github.com/prometheus-community/windows_exporter/pkg/collector/license"
"github.com/prometheus-community/windows_exporter/pkg/collector/logical_disk"
"github.com/prometheus-community/windows_exporter/pkg/collector/logon"
"github.com/prometheus-community/windows_exporter/pkg/collector/memory"
Expand Down Expand Up @@ -78,6 +79,7 @@ var Map = map[string]types.CollectorBuilderWithFlags{
fsrmquota.Name: fsrmquota.NewWithFlags,
hyperv.Name: hyperv.NewWithFlags,
iis.Name: iis.NewWithFlags,
license.Name: license.NewWithFlags,
logical_disk.Name: logical_disk.NewWithFlags,
logon.Name: logon.NewWithFlags,
memory.Name: memory.NewWithFlags,
Expand Down
40 changes: 40 additions & 0 deletions pkg/headers/slc/slc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package slc

import (
"errors"
"unsafe"

"golang.org/x/sys/windows"
)

var (
slc = windows.NewLazySystemDLL("slc.dll")
procSLIsWindowsGenuineLocal = slc.NewProc("SLIsWindowsGenuineLocal")
)

// Define SL_GENUINE_STATE enumeration
// https://learn.microsoft.com/en-us/windows/win32/api/slpublic/ne-slpublic-sl_genuine_state
type SL_GENUINE_STATE uint32

const (
SL_GEN_STATE_IS_GENUINE SL_GENUINE_STATE = iota
SL_GEN_STATE_INVALID_LICENSE
SL_GEN_STATE_TAMPERED
SL_GEN_STATE_OFFLINE
SL_GEN_STATE_LAST
)

// SLIsWindowsGenuineLocal function wrapper
func SLIsWindowsGenuineLocal() (SL_GENUINE_STATE, error) {
var genuineState SL_GENUINE_STATE

_, _, err := procSLIsWindowsGenuineLocal.Call(
uintptr(unsafe.Pointer(&genuineState)),
)

if !errors.Is(err, windows.NTE_OP_OK) {
return 0, err
}

return genuineState, nil
}