diff --git a/pkg/kubelet/metrics/collectors/volume_stats.go b/pkg/kubelet/metrics/collectors/volume_stats.go index 8ff14a0b2ac..2fed2f3d0aa 100644 --- a/pkg/kubelet/metrics/collectors/volume_stats.go +++ b/pkg/kubelet/metrics/collectors/volume_stats.go @@ -61,6 +61,12 @@ var ( []string{"namespace", "persistentvolumeclaim"}, nil, metrics.ALPHA, "", ) + + volumeStatsHealthAbnormalDesc = metrics.NewDesc( + metrics.BuildFQName("", kubeletmetrics.KubeletSubsystem, kubeletmetrics.VolumeStatsHealthAbnormalKey), + "Volume health status. The count is either 1 or 0", + []string{"namespace", "persistentvolumeclaim"}, nil, + metrics.ALPHA, "") ) type volumeStatsCollector struct { @@ -85,6 +91,7 @@ func (collector *volumeStatsCollector) DescribeWithStability(ch chan<- *metrics. ch <- volumeStatsInodesDesc ch <- volumeStatsInodesFreeDesc ch <- volumeStatsInodesUsedDesc + ch <- volumeStatsHealthAbnormalDesc } // CollectWithStability implements the metrics.StableCollector interface. @@ -120,7 +127,16 @@ func (collector *volumeStatsCollector) CollectWithStability(ch chan<- metrics.Me addGauge(volumeStatsInodesDesc, pvcRef, float64(*volumeStat.Inodes)) addGauge(volumeStatsInodesFreeDesc, pvcRef, float64(*volumeStat.InodesFree)) addGauge(volumeStatsInodesUsedDesc, pvcRef, float64(*volumeStat.InodesUsed)) + addGauge(volumeStatsHealthAbnormalDesc, pvcRef, float64(convertBoolToFloat64(volumeStat.Abnormal))) allPVCs.Insert(pvcUniqStr) } } } + +func convertBoolToFloat64(boolVal bool) float64 { + if boolVal { + return 1 + } + + return 0 +} diff --git a/pkg/kubelet/metrics/collectors/volume_stats_test.go b/pkg/kubelet/metrics/collectors/volume_stats_test.go index 54f07178c6d..2cbeff4e37b 100644 --- a/pkg/kubelet/metrics/collectors/volume_stats_test.go +++ b/pkg/kubelet/metrics/collectors/volume_stats_test.go @@ -47,6 +47,8 @@ func TestVolumeStatsCollector(t *testing.T) { # TYPE kubelet_volume_stats_inodes_used gauge # HELP kubelet_volume_stats_used_bytes [ALPHA] Number of used bytes in the volume # TYPE kubelet_volume_stats_used_bytes gauge + # HELP kubelet_volume_stats_health_abnormal [ALPHA] Volume health status. The count is either 1 or 0 + # TYPE kubelet_volume_stats_health_abnormal gauge ` var ( @@ -83,6 +85,9 @@ func TestVolumeStatsCollector(t *testing.T) { Name: "testpvc", Namespace: "testns", }, + VolumeHealthStats: statsapi.VolumeHealthStats{ + Abnormal: true, + }, }, }, }, @@ -106,6 +111,9 @@ func TestVolumeStatsCollector(t *testing.T) { Name: "testpvc", Namespace: "testns", }, + VolumeHealthStats: statsapi.VolumeHealthStats{ + Abnormal: true, + }, }, }, }, @@ -118,6 +126,7 @@ func TestVolumeStatsCollector(t *testing.T) { kubelet_volume_stats_inodes_free{namespace="testns",persistentvolumeclaim="testpvc"} 655344 kubelet_volume_stats_inodes_used{namespace="testns",persistentvolumeclaim="testpvc"} 16 kubelet_volume_stats_used_bytes{namespace="testns",persistentvolumeclaim="testpvc"} 4.21789696e+09 + kubelet_volume_stats_health_abnormal{namespace="testns",persistentvolumeclaim="testpvc"} 1 ` metrics = []string{ @@ -127,6 +136,7 @@ func TestVolumeStatsCollector(t *testing.T) { "kubelet_volume_stats_inodes_free", "kubelet_volume_stats_inodes_used", "kubelet_volume_stats_used_bytes", + "kubelet_volume_stats_health_abnormal", } ) diff --git a/pkg/kubelet/metrics/metrics.go b/pkg/kubelet/metrics/metrics.go index 302db0de4da..7187e8d84d6 100644 --- a/pkg/kubelet/metrics/metrics.go +++ b/pkg/kubelet/metrics/metrics.go @@ -53,6 +53,7 @@ const ( VolumeStatsInodesKey = "volume_stats_inodes" VolumeStatsInodesFreeKey = "volume_stats_inodes_free" VolumeStatsInodesUsedKey = "volume_stats_inodes_used" + VolumeStatsHealthAbnormalKey = "volume_stats_health_abnormal" RunningPodsKey = "running_pods" RunningContainersKey = "running_containers" // Metrics keys of remote runtime operations diff --git a/pkg/kubelet/server/stats/volume_stat_calculator.go b/pkg/kubelet/server/stats/volume_stat_calculator.go index 63e9b1e7c39..b28b541dc72 100644 --- a/pkg/kubelet/server/stats/volume_stat_calculator.go +++ b/pkg/kubelet/server/stats/volume_stat_calculator.go @@ -200,6 +200,9 @@ func (s *volumeStatCalculator) parsePodVolumeStats(podName string, pvcRef *stats return stats.VolumeStats{ Name: podName, PVCRef: pvcRef, + VolumeHealthStats: stats.VolumeHealthStats{ + Abnormal: *metric.Abnormal, + }, FsStats: stats.FsStats{Time: metric.Time, AvailableBytes: &available, CapacityBytes: &capacity, UsedBytes: &used, Inodes: &inodes, InodesFree: &inodesFree, InodesUsed: &inodesUsed}, } diff --git a/pkg/kubelet/server/stats/volume_stat_calculator_test.go b/pkg/kubelet/server/stats/volume_stat_calculator_test.go index 1edd0c8d7df..a230d7a1dfe 100644 --- a/pkg/kubelet/server/stats/volume_stat_calculator_test.go +++ b/pkg/kubelet/server/stats/volume_stat_calculator_test.go @@ -283,6 +283,7 @@ func expectedBlockMetrics() *volume.Metrics { Available: resource.NewQuantity(available, resource.BinarySI), Capacity: resource.NewQuantity(capacity, resource.BinarySI), Used: resource.NewQuantity(available-capacity, resource.BinarySI), + Abnormal: &volumeCondition.Abnormal, } } diff --git a/staging/src/k8s.io/kubelet/pkg/apis/stats/v1alpha1/types.go b/staging/src/k8s.io/kubelet/pkg/apis/stats/v1alpha1/types.go index 50622f5170e..7efcc4dc269 100644 --- a/staging/src/k8s.io/kubelet/pkg/apis/stats/v1alpha1/types.go +++ b/staging/src/k8s.io/kubelet/pkg/apis/stats/v1alpha1/types.go @@ -269,6 +269,17 @@ type VolumeStats struct { // Reference to the PVC, if one exists // +optional PVCRef *PVCReference `json:"pvcRef,omitempty"` + + // VolumeHealthStats contains data about volume health + // +optional + VolumeHealthStats `json:"volumeHealthStats,omitempty"` +} + +// VolumeHealthStats contains data about volume health. +type VolumeHealthStats struct { + // Normal volumes are available for use and operating optimally. + // An abnormal volume does not meet these criteria. + Abnormal bool `json:"abnormal,omitempty"` } // PVCReference contains enough information to describe the referenced PVC.