From ec82f90a79ed6eb06f2efa86c00a6a4bc9690b28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Otto=20Kr=C3=B6pke?= Date: Sat, 10 Oct 2026 17:08:05 +0200 Subject: [PATCH] storage_spaces: add primordial label to pool info (#2650) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Claude Opus 5.5 Signed-off-by: Jan-Otto Kröpke --- docs/collector.storage_spaces.md | 41 +++++++++++++------ .../storage_spaces/storage_spaces_pool.go | 8 ++-- .../storage_spaces/storage_spaces_test.go | 16 +++++++- 3 files changed, 49 insertions(+), 16 deletions(-) diff --git a/docs/collector.storage_spaces.md b/docs/collector.storage_spaces.md index 5017f5bb..03505bcf 100644 --- a/docs/collector.storage_spaces.md +++ b/docs/collector.storage_spaces.md @@ -20,14 +20,19 @@ Matching is case-sensitive. ### Pool -| Name | Description | Type | Labels | -|------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------|-------|----------------------------------| -| `windows_storage_spaces_pool_info` | Storage pool information (value is always 1) | gauge | `name`, `unique_id` | -| `windows_storage_spaces_pool_health_status` | Health status of the storage pool. 0: Healthy, 1: Warning, 2: Unhealthy, 5: Unknown | gauge | `name`, `unique_id` | -| `windows_storage_spaces_pool_size_bytes` | Total size of the storage pool in bytes | gauge | `name`, `unique_id` | -| `windows_storage_spaces_pool_allocated_size_bytes` | Allocated size of the storage pool in bytes | gauge | `name`, `unique_id` | -| `windows_storage_spaces_pool_operational_status` | Operational status codes reported for the storage pool (one series per status value) | gauge | `name`, `unique_id`, `status` | -| `windows_storage_spaces_pool_thin_provisioning_alert_thresholds` | Thin provisioning alert thresholds configured for the storage pool, in percent (one series per configured threshold) | gauge | `name`, `unique_id`, `threshold` | +| Name | Description | Type | Labels | +|------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------|-------|-----------------------------------| +| `windows_storage_spaces_pool_info` | Storage pool information (value is always 1). `primordial` is `true` for the built-in primordial pool | gauge | `name`, `unique_id`, `primordial` | +| `windows_storage_spaces_pool_health_status` | Health status of the storage pool. 0: Healthy, 1: Warning, 2: Unhealthy, 5: Unknown | gauge | `name`, `unique_id` | +| `windows_storage_spaces_pool_size_bytes` | Total size of the storage pool in bytes | gauge | `name`, `unique_id` | +| `windows_storage_spaces_pool_allocated_size_bytes` | Allocated size of the storage pool in bytes | gauge | `name`, `unique_id` | +| `windows_storage_spaces_pool_operational_status` | Operational status codes reported for the storage pool (one series per status value) | gauge | `name`, `unique_id`, `status` | +| `windows_storage_spaces_pool_thin_provisioning_alert_thresholds` | Thin provisioning alert thresholds configured for the storage pool, in percent (one series per configured threshold) | gauge | `name`, `unique_id`, `threshold` | + +Windows always reports a built-in pool named `Primordial` next to the concrete pools. +It groups every local physical disk that can be pooled but is not yet part of a concrete pool, so its size is the sum of those disks and not usable pool capacity. +Only `windows_storage_spaces_pool_info` carries the `primordial` label. +Join on `unique_id` to restrict other pool metrics to concrete pools, as shown in the queries below. ### Virtual Disk @@ -42,13 +47,20 @@ Matching is case-sensitive. ### Example metric -`windows_storage_spaces_pool_size_bytes{name="Pool01",unique_id="{8f2c...}"} 1.0995116277760e+12` +``` +windows_storage_spaces_pool_info{name="Pool01",primordial="false",unique_id="{8f2c...}"} 1 +windows_storage_spaces_pool_size_bytes{name="Pool01",unique_id="{8f2c...}"} 1.0995116277760e+12 +``` ## Useful queries -Storage pool usage in percent +Storage pool usage in percent, excluding the primordial pool ``` -windows_storage_spaces_pool_allocated_size_bytes / windows_storage_spaces_pool_size_bytes * 100 +( + windows_storage_spaces_pool_allocated_size_bytes / windows_storage_spaces_pool_size_bytes * 100 +) +* on (instance, unique_id) group_left () + windows_storage_spaces_pool_info{primordial="false"} ``` Find virtual disks with low storage efficiency (over-provisioned) @@ -66,7 +78,12 @@ sum(windows_storage_spaces_virtual_disk_size_bytes) / sum(windows_storage_spaces #### Unhealthy storage pool ```yaml - alert: StoragePoolUnhealthy - expr: windows_storage_spaces_pool_health_status != 0 + expr: | + ( + windows_storage_spaces_pool_health_status != 0 + ) + * on (instance, unique_id) group_left () + windows_storage_spaces_pool_info{primordial="false"} for: 10m labels: severity: warning diff --git a/internal/collector/storage_spaces/storage_spaces_pool.go b/internal/collector/storage_spaces/storage_spaces_pool.go index 9e56fe5a..68d15765 100644 --- a/internal/collector/storage_spaces/storage_spaces_pool.go +++ b/internal/collector/storage_spaces/storage_spaces_pool.go @@ -44,6 +44,7 @@ type collectorStoragePool struct { type msftStoragePool struct { FriendlyName string `mi:"FriendlyName"` UniqueId string `mi:"UniqueId"` + IsPrimordial bool `mi:"IsPrimordial"` HealthStatus uint16 `mi:"HealthStatus"` Size uint64 `mi:"Size"` AllocatedSize uint64 `mi:"AllocatedSize"` @@ -53,7 +54,7 @@ type msftStoragePool struct { } func (c *Collector) buildStoragePool() error { - wmiSelect := "FriendlyName,UniqueId,HealthStatus,Size,AllocatedSize,OperationalStatus,ThinProvisioningAlertThresholds" + wmiSelect := "FriendlyName,UniqueId,IsPrimordial,HealthStatus,Size,AllocatedSize,OperationalStatus,ThinProvisioningAlertThresholds" storagePoolMIQuery, err := mi.NewQuery(fmt.Sprintf("SELECT %s FROM MSFT_StoragePool", wmiSelect)) if err != nil { @@ -64,8 +65,8 @@ func (c *Collector) buildStoragePool() error { c.storagePoolInfo = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, nameStoragePool, "info"), - "Storage pool information (value is always 1)", - []string{"name", "unique_id"}, + "Storage pool information (value is always 1). primordial is true for the built-in primordial pool", + []string{"name", "unique_id", "primordial"}, nil, ) @@ -127,6 +128,7 @@ func (c *Collector) collectStoragePool(ch chan<- prometheus.Metric, maxScrapeDur 1.0, pool.FriendlyName, pool.UniqueId, + strconv.FormatBool(pool.IsPrimordial), ) ch <- prometheus.MustNewConstMetric( diff --git a/internal/collector/storage_spaces/storage_spaces_test.go b/internal/collector/storage_spaces/storage_spaces_test.go index f669067e..e2fea55b 100644 --- a/internal/collector/storage_spaces/storage_spaces_test.go +++ b/internal/collector/storage_spaces/storage_spaces_test.go @@ -36,7 +36,7 @@ func TestCollector(t *testing.T) { pool := prometheus.Labels{"name": "GitHubActions"} virtualDisk := prometheus.Labels{"name": "CIVirtualDisk"} - testutils.RequireFixtureMetric(t, metrics, storage_spaces.Name, "windows_storage_spaces_pool_info", pool) + testutils.RequireFixtureMetric(t, metrics, storage_spaces.Name, "windows_storage_spaces_pool_info", prometheus.Labels{"name": "GitHubActions", "primordial": "false"}) testutils.RequireFixtureMetric(t, metrics, storage_spaces.Name, "windows_storage_spaces_virtual_disk_info", virtualDisk) for _, tc := range []struct { @@ -66,4 +66,18 @@ func TestCollector(t *testing.T) { require.Greater(t, value, 0.0) require.LessOrEqual(t, value, 100.0) } + + // Every pool, including the built-in primordial pool, must carry a boolean primordial label. + for _, metric := range metrics["windows_storage_spaces_pool_info"].GetMetric() { + var primordial []string + + for _, label := range metric.GetLabel() { + if label.GetName() == "primordial" { + primordial = append(primordial, label.GetValue()) + } + } + + require.Len(t, primordial, 1, "pool info metric %s", metric) + require.Contains(t, []string{"true", "false"}, primordial[0], "pool info metric %s", metric) + } }