mscluster: merge multiple collector into one (Click here for more information) (#1585)

This commit is contained in:
Jan-Otto Kröpke
2024-08-29 22:03:05 +02:00
committed by GitHub
parent c99ac2c5aa
commit 3ce25ff1ef
19 changed files with 1473 additions and 1652 deletions

View File

@@ -0,0 +1,299 @@
package mscluster
import (
"errors"
"fmt"
"slices"
"strings"
"github.com/alecthomas/kingpin/v2"
"github.com/go-kit/log"
"github.com/prometheus-community/windows_exporter/pkg/types"
"github.com/prometheus/client_golang/prometheus"
)
const Name = "mscluster"
type Config struct {
CollectorsEnabled []string `yaml:"collectors_enabled"`
}
var ConfigDefaults = Config{
CollectorsEnabled: []string{
"cluster",
"network",
"node",
"resource",
"resourcegroup",
},
}
// A Collector is a Prometheus Collector for WMI MSCluster_Cluster metrics.
type Collector struct {
config Config
// cluster
clusterAddEvictDelay *prometheus.Desc
clusterAdminAccessPoint *prometheus.Desc
clusterAutoAssignNodeSite *prometheus.Desc
clusterAutoBalancerLevel *prometheus.Desc
clusterAutoBalancerMode *prometheus.Desc
clusterBackupInProgress *prometheus.Desc
clusterBlockCacheSize *prometheus.Desc
clusterClusSvcHangTimeout *prometheus.Desc
clusterClusSvcRegroupOpeningTimeout *prometheus.Desc
clusterClusSvcRegroupPruningTimeout *prometheus.Desc
clusterClusSvcRegroupStageTimeout *prometheus.Desc
clusterClusSvcRegroupTickInMilliseconds *prometheus.Desc
clusterClusterEnforcedAntiAffinity *prometheus.Desc
clusterClusterFunctionalLevel *prometheus.Desc
clusterClusterGroupWaitDelay *prometheus.Desc
clusterClusterLogLevel *prometheus.Desc
clusterClusterLogSize *prometheus.Desc
clusterClusterUpgradeVersion *prometheus.Desc
clusterCrossSiteDelay *prometheus.Desc
clusterCrossSiteThreshold *prometheus.Desc
clusterCrossSubnetDelay *prometheus.Desc
clusterCrossSubnetThreshold *prometheus.Desc
clusterCsvBalancer *prometheus.Desc
clusterDatabaseReadWriteMode *prometheus.Desc
clusterDefaultNetworkRole *prometheus.Desc
clusterDetectedCloudPlatform *prometheus.Desc
clusterDetectManagedEvents *prometheus.Desc
clusterDetectManagedEventsThreshold *prometheus.Desc
clusterDisableGroupPreferredOwnerRandomization *prometheus.Desc
clusterDrainOnShutdown *prometheus.Desc
clusterDynamicQuorumEnabled *prometheus.Desc
clusterEnableSharedVolumes *prometheus.Desc
clusterFixQuorum *prometheus.Desc
clusterGracePeriodEnabled *prometheus.Desc
clusterGracePeriodTimeout *prometheus.Desc
clusterGroupDependencyTimeout *prometheus.Desc
clusterHangRecoveryAction *prometheus.Desc
clusterIgnorePersistentStateOnStartup *prometheus.Desc
clusterLogResourceControls *prometheus.Desc
clusterLowerQuorumPriorityNodeId *prometheus.Desc
clusterMaxNumberOfNodes *prometheus.Desc
clusterMessageBufferLength *prometheus.Desc
clusterMinimumNeverPreemptPriority *prometheus.Desc
clusterMinimumPreemptorPriority *prometheus.Desc
clusterNetftIPSecEnabled *prometheus.Desc
clusterPlacementOptions *prometheus.Desc
clusterPlumbAllCrossSubnetRoutes *prometheus.Desc
clusterPreventQuorum *prometheus.Desc
clusterQuarantineDuration *prometheus.Desc
clusterQuarantineThreshold *prometheus.Desc
clusterQuorumArbitrationTimeMax *prometheus.Desc
clusterQuorumArbitrationTimeMin *prometheus.Desc
clusterQuorumLogFileSize *prometheus.Desc
clusterQuorumTypeValue *prometheus.Desc
clusterRequestReplyTimeout *prometheus.Desc
clusterResiliencyDefaultPeriod *prometheus.Desc
clusterResiliencyLevel *prometheus.Desc
clusterResourceDllDeadlockPeriod *prometheus.Desc
clusterRootMemoryReserved *prometheus.Desc
clusterRouteHistoryLength *prometheus.Desc
clusterS2DBusTypes *prometheus.Desc
clusterS2DCacheDesiredState *prometheus.Desc
clusterS2DCacheFlashReservePercent *prometheus.Desc
clusterS2DCachePageSizeKBytes *prometheus.Desc
clusterS2DEnabled *prometheus.Desc
clusterS2DIOLatencyThreshold *prometheus.Desc
clusterS2DOptimizations *prometheus.Desc
clusterSameSubnetDelay *prometheus.Desc
clusterSameSubnetThreshold *prometheus.Desc
clusterSecurityLevel *prometheus.Desc
clusterSecurityLevelForStorage *prometheus.Desc
clusterSharedVolumeVssWriterOperationTimeout *prometheus.Desc
clusterShutdownTimeoutInMinutes *prometheus.Desc
clusterUseClientAccessNetworksForSharedVolumes *prometheus.Desc
clusterWitnessDatabaseWriteTimeout *prometheus.Desc
clusterWitnessDynamicWeight *prometheus.Desc
clusterWitnessRestartInterval *prometheus.Desc
// network
networkCharacteristics *prometheus.Desc
networkFlags *prometheus.Desc
networkMetric *prometheus.Desc
networkRole *prometheus.Desc
networkState *prometheus.Desc
// node
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
resourceCharacteristics *prometheus.Desc
resourceDeadlockTimeout *prometheus.Desc
resourceEmbeddedFailureAction *prometheus.Desc
resourceFlags *prometheus.Desc
resourceIsAlivePollInterval *prometheus.Desc
resourceLooksAlivePollInterval *prometheus.Desc
resourceMonitorProcessId *prometheus.Desc
resourceOwnerNode *prometheus.Desc
resourcePendingTimeout *prometheus.Desc
resourceResourceClass *prometheus.Desc
resourceRestartAction *prometheus.Desc
resourceRestartDelay *prometheus.Desc
resourceRestartPeriod *prometheus.Desc
resourceRestartThreshold *prometheus.Desc
resourceRetryPeriodOnFailure *prometheus.Desc
resourceState *prometheus.Desc
resourceSubClass *prometheus.Desc
// ResourceGroup
resourceGroupAutoFailbackType *prometheus.Desc
resourceGroupCharacteristics *prometheus.Desc
resourceGroupColdStartSetting *prometheus.Desc
resourceGroupDefaultOwner *prometheus.Desc
resourceGroupFailbackWindowEnd *prometheus.Desc
resourceGroupFailbackWindowStart *prometheus.Desc
resourceGroupFailOverPeriod *prometheus.Desc
resourceGroupFailOverThreshold *prometheus.Desc
resourceGroupFlags *prometheus.Desc
resourceGroupGroupType *prometheus.Desc
resourceGroupOwnerNode *prometheus.Desc
resourceGroupPriority *prometheus.Desc
resourceGroupResiliencyPeriod *prometheus.Desc
resourceGroupState *prometheus.Desc
}
func New(config *Config) *Collector {
if config == nil {
config = &ConfigDefaults
}
if config.CollectorsEnabled == nil {
config.CollectorsEnabled = ConfigDefaults.CollectorsEnabled
}
c := &Collector{
config: *config,
}
return c
}
func NewWithFlags(app *kingpin.Application) *Collector {
c := &Collector{
config: ConfigDefaults,
}
c.config.CollectorsEnabled = make([]string, 0)
var collectorsEnabled string
app.Flag(
"collectors.mscluster.enabled",
"Comma-separated list of collectors to use.",
).Default(strings.Join(ConfigDefaults.CollectorsEnabled, ",")).StringVar(&collectorsEnabled)
app.Action(func(*kingpin.ParseContext) error {
c.config.CollectorsEnabled = strings.Split(collectorsEnabled, ",")
return nil
})
return c
}
func (c *Collector) GetName() string {
return Name
}
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
return []string{"Memory"}, nil
}
func (c *Collector) Close() error {
return nil
}
func (c *Collector) Build(_ log.Logger) error {
if len(c.config.CollectorsEnabled) == 0 {
return nil
}
if slices.Contains(c.config.CollectorsEnabled, "cluster") {
c.buildCluster()
}
if slices.Contains(c.config.CollectorsEnabled, "network") {
c.buildNetwork()
}
if slices.Contains(c.config.CollectorsEnabled, "node") {
c.buildNode()
}
if slices.Contains(c.config.CollectorsEnabled, "resource") {
c.buildResource()
}
if slices.Contains(c.config.CollectorsEnabled, "resourcegroup") {
c.buildResourceGroup()
}
return nil
}
// Collect sends the metric values for each metric
// to the provided prometheus Metric channel.
func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
logger = log.With(logger, "collector", Name)
if len(c.config.CollectorsEnabled) == 0 {
return nil
}
var (
err error
errs []error
nodeNames []string
)
if slices.Contains(c.config.CollectorsEnabled, "cluster") {
if err = c.collectCluster(logger, ch); err != nil {
errs = append(errs, fmt.Errorf("failed to collect cluster metrics: %w", err))
}
}
if slices.Contains(c.config.CollectorsEnabled, "network") {
if err = c.collectNetwork(logger, ch); err != nil {
errs = append(errs, fmt.Errorf("failed to collect network metrics: %w", err))
}
}
if slices.Contains(c.config.CollectorsEnabled, "node") {
if nodeNames, err = c.collectNode(logger, ch); err != nil {
errs = append(errs, fmt.Errorf("failed to collect node metrics: %w", err))
}
}
if slices.Contains(c.config.CollectorsEnabled, "resource") {
if err = c.collectResource(logger, ch, nodeNames); err != nil {
errs = append(errs, fmt.Errorf("failed to collect resource metrics: %w", err))
}
}
if slices.Contains(c.config.CollectorsEnabled, "resourcegroup") {
if err = c.collectResourceGroup(logger, ch, nodeNames); err != nil {
errs = append(errs, fmt.Errorf("failed to collect resource group metrics: %w", err))
}
}
if len(errs) > 0 {
return errors.Join(errs...)
}
return nil
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,105 @@
package mscluster
import (
"github.com/go-kit/log"
"github.com/prometheus-community/windows_exporter/pkg/types"
"github.com/prometheus-community/windows_exporter/pkg/wmi"
"github.com/prometheus/client_golang/prometheus"
)
const nameNetwork = Name + "_network"
// msClusterNetwork represents the MSCluster_Network WMI class
// - https://docs.microsoft.com/en-us/previous-versions/windows/desktop/cluswmi/mscluster-network
type msClusterNetwork struct {
Name string
Characteristics uint
Flags uint
Metric uint
Role uint
State uint
}
func (c *Collector) buildNetwork() {
c.networkCharacteristics = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, nameNetwork, "characteristics"),
"Provides the characteristics of the network.",
[]string{"name"},
nil,
)
c.networkFlags = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, nameNetwork, "flags"),
"Provides access to the flags set for the node. ",
[]string{"name"},
nil,
)
c.networkMetric = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, nameNetwork, "metric"),
"The metric of a cluster network (networks with lower values are used first). If this value is set, then the AutoMetric property is set to false.",
[]string{"name"},
nil,
)
c.networkRole = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, nameNetwork, "role"),
"Provides access to the network's Role property. The Role property describes the role of the network in the cluster. 0: None; 1: Cluster; 2: Client; 3: Both ",
[]string{"name"},
nil,
)
c.networkState = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, nameNetwork, "state"),
"Provides the current state of the network. 1-1: Unknown; 0: Unavailable; 1: Down; 2: Partitioned; 3: Up",
[]string{"name"},
nil,
)
}
// Collect sends the metric values for each metric
// to the provided prometheus metric channel.
func (c *Collector) collectNetwork(logger log.Logger, ch chan<- prometheus.Metric) error {
var dst []msClusterNetwork
q := wmi.QueryAllForClass(&dst, "MSCluster_Network", logger)
if err := wmi.QueryNamespace(q, &dst, "root/MSCluster"); err != nil {
return err
}
for _, v := range dst {
ch <- prometheus.MustNewConstMetric(
c.networkCharacteristics,
prometheus.GaugeValue,
float64(v.Characteristics),
v.Name,
)
ch <- prometheus.MustNewConstMetric(
c.networkFlags,
prometheus.GaugeValue,
float64(v.Flags),
v.Name,
)
ch <- prometheus.MustNewConstMetric(
c.networkMetric,
prometheus.GaugeValue,
float64(v.Metric),
v.Name,
)
ch <- prometheus.MustNewConstMetric(
c.networkRole,
prometheus.GaugeValue,
float64(v.Role),
v.Name,
)
ch <- prometheus.MustNewConstMetric(
c.networkState,
prometheus.GaugeValue,
float64(v.State),
v.Name,
)
}
return nil
}

View File

@@ -0,0 +1,235 @@
package mscluster
import (
"github.com/go-kit/log"
"github.com/prometheus-community/windows_exporter/pkg/types"
"github.com/prometheus-community/windows_exporter/pkg/wmi"
"github.com/prometheus/client_golang/prometheus"
)
const nameNode = Name + "_node"
// 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
BuildNumber uint
Characteristics uint
DetectedCloudPlatform uint
DynamicWeight uint
Flags uint
MajorVersion uint
MinorVersion uint
NeedsPreventQuorum uint
NodeDrainStatus uint
NodeHighestVersion uint
NodeLowestVersion uint
NodeWeight uint
State uint
StatusInformation uint
}
func (c *Collector) buildNode() {
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,
)
}
// Collect sends the metric values for each metric
// to the provided prometheus Metric channel.
func (c *Collector) collectNode(logger log.Logger, ch chan<- prometheus.Metric) ([]string, error) {
var dst []msClusterNode
q := wmi.QueryAllForClass(&dst, "MSCluster_Node", logger)
if err := wmi.QueryNamespace(q, &dst, "root/MSCluster"); err != nil {
return nil, 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
}

View File

@@ -0,0 +1,287 @@
package mscluster
import (
"github.com/go-kit/log"
"github.com/prometheus-community/windows_exporter/pkg/types"
"github.com/prometheus-community/windows_exporter/pkg/wmi"
"github.com/prometheus/client_golang/prometheus"
)
const nameResource = Name + "_resource"
// msClusterResource represents the MSCluster_Resource WMI class
// - https://docs.microsoft.com/en-us/previous-versions/windows/desktop/cluswmi/mscluster-resource
type msClusterResource struct {
Name string
Type string
OwnerGroup string
OwnerNode string
Characteristics uint
DeadlockTimeout uint
EmbeddedFailureAction uint
Flags uint
IsAlivePollInterval uint
LooksAlivePollInterval uint
MonitorProcessId uint
PendingTimeout uint
ResourceClass uint
RestartAction uint
RestartDelay uint
RestartPeriod uint
RestartThreshold uint
RetryPeriodOnFailure uint
State uint
Subclass uint
}
func (c *Collector) buildResource() {
c.resourceCharacteristics = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, nameResource, "characteristics"),
"Provides the characteristics of the object.",
[]string{"type", "owner_group", "name"},
nil,
)
c.resourceDeadlockTimeout = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, nameResource, "deadlock_timeout"),
"Indicates the length of time to wait, in milliseconds, before declaring a deadlock in any call into a resource.",
[]string{"type", "owner_group", "name"},
nil,
)
c.resourceEmbeddedFailureAction = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, nameResource, "embedded_failure_action"),
"The time, in milliseconds, that a resource should remain in a failed state before the Cluster service attempts to restart it.",
[]string{"type", "owner_group", "name"},
nil,
)
c.resourceFlags = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, nameResource, "flags"),
"Provides access to the flags set for the object.",
[]string{"type", "owner_group", "name"},
nil,
)
c.resourceIsAlivePollInterval = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, nameResource, "is_alive_poll_interval"),
"Provides access to the resource's IsAlivePollInterval property, which is the recommended interval in milliseconds at which the Cluster Service should poll the resource to determine whether it is operational. If the property is set to 0xFFFFFFFF, the Cluster Service uses the IsAlivePollInterval property for the resource type associated with the resource.",
[]string{"type", "owner_group", "name"},
nil,
)
c.resourceLooksAlivePollInterval = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, nameResource, "looks_alive_poll_interval"),
"Provides access to the resource's LooksAlivePollInterval property, which is the recommended interval in milliseconds at which the Cluster Service should poll the resource to determine whether it appears operational. If the property is set to 0xFFFFFFFF, the Cluster Service uses the LooksAlivePollInterval property for the resource type associated with the resource.",
[]string{"type", "owner_group", "name"},
nil,
)
c.resourceMonitorProcessId = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, nameResource, "monitor_process_id"),
"Provides the process ID of the resource host service that is currently hosting the resource.",
[]string{"type", "owner_group", "name"},
nil,
)
c.resourceOwnerNode = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, nameResource, "owner_node"),
"The node hosting the resource. 0: Not hosted; 1: Hosted",
[]string{"type", "owner_group", "node_name", "name"},
nil,
)
c.resourceOwnerNode = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, nameResource, "owner_node"),
"The node hosting the resource. 0: Not hosted; 1: Hosted",
[]string{"type", "owner_group", "node_name", "name"},
nil,
)
c.resourcePendingTimeout = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, nameResource, "pending_timeout"),
"Provides access to the resource's PendingTimeout property. If a resource cannot be brought online or taken offline in the number of milliseconds specified by the PendingTimeout property, the resource is forcibly terminated.",
[]string{"type", "owner_group", "name"},
nil,
)
c.resourceResourceClass = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, nameResource, "resource_class"),
"Gets or sets the resource class of a resource. 0: Unknown; 1: Storage; 2: Network; 32768: Unknown ",
[]string{"type", "owner_group", "name"},
nil,
)
c.resourceRestartAction = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, nameResource, "restart_action"),
"Provides access to the resource's RestartAction property, which is the action to be taken by the Cluster Service if the resource fails.",
[]string{"type", "owner_group", "name"},
nil,
)
c.resourceRestartDelay = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, nameResource, "restart_delay"),
"Indicates the time delay before a failed resource is restarted.",
[]string{"type", "owner_group", "name"},
nil,
)
c.resourceRestartPeriod = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, nameResource, "restart_period"),
"Provides access to the resource's RestartPeriod property, which is interval of time, in milliseconds, during which a specified number of restart attempts can be made on a nonresponsive resource.",
[]string{"type", "owner_group", "name"},
nil,
)
c.resourceRestartThreshold = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, nameResource, "restart_threshold"),
"Provides access to the resource's RestartThreshold property which is the maximum number of restart attempts that can be made on a resource within an interval defined by the RestartPeriod property before the Cluster Service initiates the action specified by the RestartAction property.",
[]string{"type", "owner_group", "name"},
nil,
)
c.resourceRetryPeriodOnFailure = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, nameResource, "retry_period_on_failure"),
"Provides access to the resource's RetryPeriodOnFailure property, which is the interval of time (in milliseconds) that a resource should remain in a failed state before the Cluster service attempts to restart it.",
[]string{"type", "owner_group", "name"},
nil,
)
c.resourceState = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, nameResource, "state"),
"The current state of the resource. -1: Unknown; 0: Inherited; 1: Initializing; 2: Online; 3: Offline; 4: Failed; 128: Pending; 129: Online Pending; 130: Offline Pending ",
[]string{"type", "owner_group", "name"},
nil,
)
c.resourceSubClass = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, nameResource, "subclass"),
"Provides the list of references to nodes that can be the owner of this resource.",
[]string{"type", "owner_group", "name"},
nil,
)
}
// Collect sends the metric values for each metric
// to the provided prometheus Metric channel.
func (c *Collector) collectResource(logger log.Logger, ch chan<- prometheus.Metric, nodeNames []string) error {
var dst []msClusterResource
q := wmi.QueryAllForClass(&dst, "MSCluster_Resource", logger)
if err := wmi.QueryNamespace(q, &dst, "root/MSCluster"); err != nil {
return err
}
for _, v := range dst {
ch <- prometheus.MustNewConstMetric(
c.resourceCharacteristics,
prometheus.GaugeValue,
float64(v.Characteristics),
v.Type, v.OwnerGroup, v.Name,
)
ch <- prometheus.MustNewConstMetric(
c.resourceDeadlockTimeout,
prometheus.GaugeValue,
float64(v.DeadlockTimeout),
v.Type, v.OwnerGroup, v.Name,
)
ch <- prometheus.MustNewConstMetric(
c.resourceEmbeddedFailureAction,
prometheus.GaugeValue,
float64(v.EmbeddedFailureAction),
v.Type, v.OwnerGroup, v.Name,
)
ch <- prometheus.MustNewConstMetric(
c.resourceFlags,
prometheus.GaugeValue,
float64(v.Flags),
v.Type, v.OwnerGroup, v.Name,
)
ch <- prometheus.MustNewConstMetric(
c.resourceIsAlivePollInterval,
prometheus.GaugeValue,
float64(v.IsAlivePollInterval),
v.Type, v.OwnerGroup, v.Name,
)
ch <- prometheus.MustNewConstMetric(
c.resourceLooksAlivePollInterval,
prometheus.GaugeValue,
float64(v.LooksAlivePollInterval),
v.Type, v.OwnerGroup, v.Name,
)
ch <- prometheus.MustNewConstMetric(
c.resourceMonitorProcessId,
prometheus.GaugeValue,
float64(v.MonitorProcessId),
v.Type, v.OwnerGroup, v.Name,
)
for _, nodeName := range nodeNames {
isCurrentState := 0.0
if v.OwnerNode == nodeName {
isCurrentState = 1.0
}
ch <- prometheus.MustNewConstMetric(
c.resourceOwnerNode,
prometheus.GaugeValue,
isCurrentState,
v.Type, v.OwnerGroup, nodeName, v.Name,
)
}
ch <- prometheus.MustNewConstMetric(
c.resourcePendingTimeout,
prometheus.GaugeValue,
float64(v.PendingTimeout),
v.Type, v.OwnerGroup, v.Name,
)
ch <- prometheus.MustNewConstMetric(
c.resourceResourceClass,
prometheus.GaugeValue,
float64(v.ResourceClass),
v.Type, v.OwnerGroup, v.Name,
)
ch <- prometheus.MustNewConstMetric(
c.resourceRestartAction,
prometheus.GaugeValue,
float64(v.RestartAction),
v.Type, v.OwnerGroup, v.Name,
)
ch <- prometheus.MustNewConstMetric(
c.resourceRestartDelay,
prometheus.GaugeValue,
float64(v.RestartDelay),
v.Type, v.OwnerGroup, v.Name,
)
ch <- prometheus.MustNewConstMetric(
c.resourceRestartPeriod,
prometheus.GaugeValue,
float64(v.RestartPeriod),
v.Type, v.OwnerGroup, v.Name,
)
ch <- prometheus.MustNewConstMetric(
c.resourceRestartThreshold,
prometheus.GaugeValue,
float64(v.RestartThreshold),
v.Type, v.OwnerGroup, v.Name,
)
ch <- prometheus.MustNewConstMetric(
c.resourceRetryPeriodOnFailure,
prometheus.GaugeValue,
float64(v.RetryPeriodOnFailure),
v.Type, v.OwnerGroup, v.Name,
)
ch <- prometheus.MustNewConstMetric(
c.resourceState,
prometheus.GaugeValue,
float64(v.State),
v.Type, v.OwnerGroup, v.Name,
)
ch <- prometheus.MustNewConstMetric(
c.resourceSubClass,
prometheus.GaugeValue,
float64(v.Subclass),
v.Type, v.OwnerGroup, v.Name,
)
}
return nil
}

View File

@@ -0,0 +1,243 @@
package mscluster
import (
"github.com/go-kit/log"
"github.com/prometheus-community/windows_exporter/pkg/types"
"github.com/prometheus-community/windows_exporter/pkg/wmi"
"github.com/prometheus/client_golang/prometheus"
)
const nameResourceGroup = Name + "_resourcegroup"
// msClusterResourceGroup represents the MSCluster_ResourceGroup WMI class
// - https://docs.microsoft.com/en-us/previous-versions/windows/desktop/cluswmi/mscluster-resourcegroup
type msClusterResourceGroup struct {
Name string
AutoFailbackType uint
Characteristics uint
ColdStartSetting uint
DefaultOwner uint
FailbackWindowEnd int
FailbackWindowStart int
FailoverPeriod uint
FailoverThreshold uint
Flags uint
GroupType uint
OwnerNode string
Priority uint
ResiliencyPeriod uint
State uint
}
func (c *Collector) buildResourceGroup() {
c.resourceGroupAutoFailbackType = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, nameResourceGroup, "auto_failback_type"),
"Provides access to the group's AutoFailbackType property.",
[]string{"name"},
nil,
)
c.resourceGroupCharacteristics = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, nameResourceGroup, "characteristics"),
"Provides the characteristics of the group.",
[]string{"name"},
nil,
)
c.resourceGroupColdStartSetting = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, nameResourceGroup, "cold_start_setting"),
"Indicates whether a group can start after a cluster cold start.",
[]string{"name"},
nil,
)
c.resourceGroupDefaultOwner = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, nameResourceGroup, "default_owner"),
"Number of the last node the resource group was activated on or explicitly moved to.",
[]string{"name"},
nil,
)
c.resourceGroupFailbackWindowEnd = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, nameResourceGroup, "failback_window_end"),
"The FailbackWindowEnd property provides the latest time that the group can be moved back to the node identified as its preferred node.",
[]string{"name"},
nil,
)
c.resourceGroupFailbackWindowStart = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, nameResourceGroup, "failback_window_start"),
"The FailbackWindowStart property provides the earliest time (that is, local time as kept by the cluster) that the group can be moved back to the node identified as its preferred node.",
[]string{"name"},
nil,
)
c.resourceGroupFailOverPeriod = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, nameResourceGroup, "failover_period"),
"The FailoverPeriod property specifies a number of hours during which a maximum number of failover attempts, specified by the FailoverThreshold property, can occur.",
[]string{"name"},
nil,
)
c.resourceGroupFailOverThreshold = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, nameResourceGroup, "failover_threshold"),
"The FailoverThreshold property specifies the maximum number of failover attempts.",
[]string{"name"},
nil,
)
c.resourceGroupFlags = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, nameResourceGroup, "flags"),
"Provides access to the flags set for the group. ",
[]string{"name"},
nil,
)
c.resourceGroupGroupType = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, nameResourceGroup, "group_type"),
"The Type of the resource group.",
[]string{"name"},
nil,
)
c.resourceGroupOwnerNode = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, nameResourceGroup, "owner_node"),
"The node hosting the resource group. 0: Not hosted; 1: Hosted",
[]string{"node_name", "name"},
nil,
)
c.resourceGroupOwnerNode = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, nameResourceGroup, "owner_node"),
"The node hosting the resource group. 0: Not hosted; 1: Hosted",
[]string{"node_name", "name"},
nil,
)
c.resourceGroupPriority = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, nameResourceGroup, "priority"),
"Priority value of the resource group",
[]string{"name"},
nil,
)
c.resourceGroupResiliencyPeriod = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, nameResourceGroup, "resiliency_period"),
"The resiliency period for this group, in seconds.",
[]string{"name"},
nil,
)
c.resourceGroupState = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, nameResourceGroup, "state"),
"The current state of the resource group. -1: Unknown; 0: Online; 1: Offline; 2: Failed; 3: Partial Online; 4: Pending",
[]string{"name"},
nil,
)
}
// Collect sends the metric values for each metric
// to the provided prometheus Metric channel.
func (c *Collector) collectResourceGroup(logger log.Logger, ch chan<- prometheus.Metric, nodeNames []string) error {
var dst []msClusterResourceGroup
q := wmi.QueryAllForClass(&dst, "MSCluster_ResourceGroup", logger)
if err := wmi.QueryNamespace(q, &dst, "root/MSCluster"); err != nil {
return err
}
for _, v := range dst {
ch <- prometheus.MustNewConstMetric(
c.resourceGroupAutoFailbackType,
prometheus.GaugeValue,
float64(v.AutoFailbackType),
v.Name,
)
ch <- prometheus.MustNewConstMetric(
c.resourceGroupCharacteristics,
prometheus.GaugeValue,
float64(v.Characteristics),
v.Name,
)
ch <- prometheus.MustNewConstMetric(
c.resourceGroupColdStartSetting,
prometheus.GaugeValue,
float64(v.ColdStartSetting),
v.Name,
)
ch <- prometheus.MustNewConstMetric(
c.resourceGroupDefaultOwner,
prometheus.GaugeValue,
float64(v.DefaultOwner),
v.Name,
)
ch <- prometheus.MustNewConstMetric(
c.resourceGroupFailbackWindowEnd,
prometheus.GaugeValue,
float64(v.FailbackWindowEnd),
v.Name,
)
ch <- prometheus.MustNewConstMetric(
c.resourceGroupFailbackWindowStart,
prometheus.GaugeValue,
float64(v.FailbackWindowStart),
v.Name,
)
ch <- prometheus.MustNewConstMetric(
c.resourceGroupFailOverPeriod,
prometheus.GaugeValue,
float64(v.FailoverPeriod),
v.Name,
)
ch <- prometheus.MustNewConstMetric(
c.resourceGroupFailOverThreshold,
prometheus.GaugeValue,
float64(v.FailoverThreshold),
v.Name,
)
ch <- prometheus.MustNewConstMetric(
c.resourceGroupFlags,
prometheus.GaugeValue,
float64(v.Flags),
v.Name,
)
ch <- prometheus.MustNewConstMetric(
c.resourceGroupGroupType,
prometheus.GaugeValue,
float64(v.GroupType),
v.Name,
)
for _, nodeName := range nodeNames {
isCurrentState := 0.0
if v.OwnerNode == nodeName {
isCurrentState = 1.0
}
ch <- prometheus.MustNewConstMetric(
c.resourceGroupOwnerNode,
prometheus.GaugeValue,
isCurrentState,
nodeName, v.Name,
)
}
ch <- prometheus.MustNewConstMetric(
c.resourceGroupPriority,
prometheus.GaugeValue,
float64(v.Priority),
v.Name,
)
ch <- prometheus.MustNewConstMetric(
c.resourceGroupResiliencyPeriod,
prometheus.GaugeValue,
float64(v.ResiliencyPeriod),
v.Name,
)
ch <- prometheus.MustNewConstMetric(
c.resourceGroupState,
prometheus.GaugeValue,
float64(v.State),
v.Name,
)
}
return nil
}