mirror of
https://github.com/prometheus-community/windows_exporter.git
synced 2025-04-18 19:24:05 +03:00
295 lines
8.7 KiB
Go
295 lines
8.7 KiB
Go
// SPDX-License-Identifier: Apache-2.0
|
|
//
|
|
// Copyright 2025 The Prometheus Authors
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
//go:build windows
|
|
|
|
package mscluster
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/Microsoft/hcsshim/osversion"
|
|
"github.com/prometheus-community/windows_exporter/internal/mi"
|
|
"github.com/prometheus-community/windows_exporter/internal/types"
|
|
"github.com/prometheus/client_golang/prometheus"
|
|
)
|
|
|
|
const nameNode = Name + "_node"
|
|
|
|
type collectorNode struct {
|
|
nodeMIQuery mi.Query
|
|
|
|
nodeBuildNumber *prometheus.Desc
|
|
nodeCharacteristics *prometheus.Desc
|
|
nodeDetectedCloudPlatform *prometheus.Desc
|
|
nodeDynamicWeight *prometheus.Desc
|
|
nodeFlags *prometheus.Desc
|
|
nodeMajorVersion *prometheus.Desc
|
|
nodeMinorVersion *prometheus.Desc
|
|
nodeNeedsPreventQuorum *prometheus.Desc
|
|
nodeNodeDrainStatus *prometheus.Desc
|
|
nodeNodeHighestVersion *prometheus.Desc
|
|
nodeNodeLowestVersion *prometheus.Desc
|
|
nodeNodeWeight *prometheus.Desc
|
|
nodeState *prometheus.Desc
|
|
nodeStatusInformation *prometheus.Desc
|
|
}
|
|
|
|
// msClusterNode represents the MSCluster_Node WMI class
|
|
// - https://docs.microsoft.com/en-us/previous-versions/windows/desktop/cluswmi/mscluster-node
|
|
type msClusterNode struct {
|
|
Name string `mi:"Name"`
|
|
|
|
BuildNumber uint `mi:"BuildNumber"`
|
|
Characteristics uint `mi:"Characteristics"`
|
|
DetectedCloudPlatform uint `mi:"DetectedCloudPlatform"`
|
|
DynamicWeight uint `mi:"DynamicWeight"`
|
|
Flags uint `mi:"Flags"`
|
|
MajorVersion uint `mi:"MajorVersion"`
|
|
MinorVersion uint `mi:"MinorVersion"`
|
|
NeedsPreventQuorum uint `mi:"NeedsPreventQuorum"`
|
|
NodeDrainStatus uint `mi:"NodeDrainStatus"`
|
|
NodeHighestVersion uint `mi:"NodeHighestVersion"`
|
|
NodeLowestVersion uint `mi:"NodeLowestVersion"`
|
|
NodeWeight uint `mi:"NodeWeight"`
|
|
State uint `mi:"State"`
|
|
StatusInformation uint `mi:"StatusInformation"`
|
|
}
|
|
|
|
func (c *Collector) buildNode() error {
|
|
buildNumber := osversion.Build()
|
|
|
|
wmiSelect := "BuildNumber,Characteristics,DynamicWeight,Flags,MajorVersion,MinorVersion,NeedsPreventQuorum,NodeDrainStatus,NodeHighestVersion,NodeLowestVersion,NodeWeight,State,StatusInformation"
|
|
if buildNumber >= osversion.LTSC2022 {
|
|
wmiSelect += ",DetectedCloudPlatform"
|
|
}
|
|
|
|
nodeMIQuery, err := mi.NewQuery(fmt.Sprintf("SELECT %s FROM MSCluster_Node", wmiSelect))
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create WMI query: %w", err)
|
|
}
|
|
|
|
c.nodeMIQuery = nodeMIQuery
|
|
|
|
c.nodeBuildNumber = prometheus.NewDesc(
|
|
prometheus.BuildFQName(types.Namespace, nameNode, "build_number"),
|
|
"Provides access to the node's BuildNumber property.",
|
|
[]string{"name"},
|
|
nil,
|
|
)
|
|
c.nodeCharacteristics = prometheus.NewDesc(
|
|
prometheus.BuildFQName(types.Namespace, nameNode, "characteristics"),
|
|
"Provides access to the characteristics set for the node.",
|
|
[]string{"name"},
|
|
nil,
|
|
)
|
|
c.nodeDetectedCloudPlatform = prometheus.NewDesc(
|
|
prometheus.BuildFQName(types.Namespace, nameNode, "detected_cloud_platform"),
|
|
"(DetectedCloudPlatform)",
|
|
[]string{"name"},
|
|
nil,
|
|
)
|
|
c.nodeDynamicWeight = prometheus.NewDesc(
|
|
prometheus.BuildFQName(types.Namespace, nameNode, "dynamic_weight"),
|
|
"The dynamic vote weight of the node adjusted by dynamic quorum feature.",
|
|
[]string{"name"},
|
|
nil,
|
|
)
|
|
c.nodeFlags = prometheus.NewDesc(
|
|
prometheus.BuildFQName(types.Namespace, nameNode, "flags"),
|
|
"Provides access to the flags set for the node.",
|
|
[]string{"name"},
|
|
nil,
|
|
)
|
|
c.nodeMajorVersion = prometheus.NewDesc(
|
|
prometheus.BuildFQName(types.Namespace, nameNode, "major_version"),
|
|
"Provides access to the node's MajorVersion property, which specifies the major portion of the Windows version installed.",
|
|
[]string{"name"},
|
|
nil,
|
|
)
|
|
c.nodeMinorVersion = prometheus.NewDesc(
|
|
prometheus.BuildFQName(types.Namespace, nameNode, "minor_version"),
|
|
"Provides access to the node's MinorVersion property, which specifies the minor portion of the Windows version installed.",
|
|
[]string{"name"},
|
|
nil,
|
|
)
|
|
c.nodeNeedsPreventQuorum = prometheus.NewDesc(
|
|
prometheus.BuildFQName(types.Namespace, nameNode, "needs_prevent_quorum"),
|
|
"Whether the cluster service on that node should be started with prevent quorum flag.",
|
|
[]string{"name"},
|
|
nil,
|
|
)
|
|
c.nodeNodeDrainStatus = prometheus.NewDesc(
|
|
prometheus.BuildFQName(types.Namespace, nameNode, "node_drain_status"),
|
|
"The current node drain status of a node. 0: Not Initiated; 1: In Progress; 2: Completed; 3: Failed",
|
|
[]string{"name"},
|
|
nil,
|
|
)
|
|
c.nodeNodeHighestVersion = prometheus.NewDesc(
|
|
prometheus.BuildFQName(types.Namespace, nameNode, "node_highest_version"),
|
|
"Provides access to the node's NodeHighestVersion property, which specifies the highest possible version of the cluster service with which the node can join or communicate.",
|
|
[]string{"name"},
|
|
nil,
|
|
)
|
|
c.nodeNodeLowestVersion = prometheus.NewDesc(
|
|
prometheus.BuildFQName(types.Namespace, nameNode, "node_lowest_version"),
|
|
"Provides access to the node's NodeLowestVersion property, which specifies the lowest possible version of the cluster service with which the node can join or communicate.",
|
|
[]string{"name"},
|
|
nil,
|
|
)
|
|
c.nodeNodeWeight = prometheus.NewDesc(
|
|
prometheus.BuildFQName(types.Namespace, nameNode, "node_weight"),
|
|
"The vote weight of the node.",
|
|
[]string{"name"},
|
|
nil,
|
|
)
|
|
c.nodeState = prometheus.NewDesc(
|
|
prometheus.BuildFQName(types.Namespace, nameNode, "state"),
|
|
"Returns the current state of a node. -1: Unknown; 0: Up; 1: Down; 2: Paused; 3: Joining",
|
|
[]string{"name"},
|
|
nil,
|
|
)
|
|
c.nodeStatusInformation = prometheus.NewDesc(
|
|
prometheus.BuildFQName(types.Namespace, nameNode, "status_information"),
|
|
"The isolation or quarantine status of the node.",
|
|
[]string{"name"},
|
|
nil,
|
|
)
|
|
|
|
var dst []msClusterNode
|
|
|
|
if err := c.miSession.Query(&dst, mi.NamespaceRootMSCluster, c.nodeMIQuery); err != nil {
|
|
return fmt.Errorf("WMI query failed: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Collect sends the metric values for each metric
|
|
// to the provided prometheus Metric channel.
|
|
func (c *Collector) collectNode(ch chan<- prometheus.Metric) ([]string, error) {
|
|
var dst []msClusterNode
|
|
|
|
if err := c.miSession.Query(&dst, mi.NamespaceRootMSCluster, c.nodeMIQuery); err != nil {
|
|
return nil, fmt.Errorf("WMI query failed: %w", err)
|
|
}
|
|
|
|
nodeNames := make([]string, 0, len(dst))
|
|
|
|
for _, v := range dst {
|
|
ch <- prometheus.MustNewConstMetric(
|
|
c.nodeBuildNumber,
|
|
prometheus.GaugeValue,
|
|
float64(v.BuildNumber),
|
|
v.Name,
|
|
)
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
c.nodeCharacteristics,
|
|
prometheus.GaugeValue,
|
|
float64(v.Characteristics),
|
|
v.Name,
|
|
)
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
c.nodeDetectedCloudPlatform,
|
|
prometheus.GaugeValue,
|
|
float64(v.DetectedCloudPlatform),
|
|
v.Name,
|
|
)
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
c.nodeDynamicWeight,
|
|
prometheus.GaugeValue,
|
|
float64(v.DynamicWeight),
|
|
v.Name,
|
|
)
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
c.nodeFlags,
|
|
prometheus.GaugeValue,
|
|
float64(v.Flags),
|
|
v.Name,
|
|
)
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
c.nodeMajorVersion,
|
|
prometheus.GaugeValue,
|
|
float64(v.MajorVersion),
|
|
v.Name,
|
|
)
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
c.nodeMinorVersion,
|
|
prometheus.GaugeValue,
|
|
float64(v.MinorVersion),
|
|
v.Name,
|
|
)
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
c.nodeNeedsPreventQuorum,
|
|
prometheus.GaugeValue,
|
|
float64(v.NeedsPreventQuorum),
|
|
v.Name,
|
|
)
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
c.nodeNodeDrainStatus,
|
|
prometheus.GaugeValue,
|
|
float64(v.NodeDrainStatus),
|
|
v.Name,
|
|
)
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
c.nodeNodeHighestVersion,
|
|
prometheus.GaugeValue,
|
|
float64(v.NodeHighestVersion),
|
|
v.Name,
|
|
)
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
c.nodeNodeLowestVersion,
|
|
prometheus.GaugeValue,
|
|
float64(v.NodeLowestVersion),
|
|
v.Name,
|
|
)
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
c.nodeNodeWeight,
|
|
prometheus.GaugeValue,
|
|
float64(v.NodeWeight),
|
|
v.Name,
|
|
)
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
c.nodeState,
|
|
prometheus.GaugeValue,
|
|
float64(v.State),
|
|
v.Name,
|
|
)
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
c.nodeStatusInformation,
|
|
prometheus.GaugeValue,
|
|
float64(v.StatusInformation),
|
|
v.Name,
|
|
)
|
|
|
|
nodeNames = append(nodeNames, v.Name)
|
|
}
|
|
|
|
return nodeNames, nil
|
|
}
|