diff --git a/pkg/kubelet/metrics/collectors/volume_stats.go b/pkg/kubelet/metrics/collectors/volume_stats.go index e580bdb1516..3294150c2eb 100644 --- a/pkg/kubelet/metrics/collectors/volume_stats.go +++ b/pkg/kubelet/metrics/collectors/volume_stats.go @@ -65,7 +65,7 @@ var ( volumeStatsHealthAbnormalDesc = metrics.NewDesc( metrics.BuildFQName("", kubeletmetrics.KubeletSubsystem, kubeletmetrics.VolumeStatsHealthStatusKey), "Volume health status. The count is either 1 or 0", - []string{"namespace", "persistentvolumeclaim"}, nil, + []string{"namespace", "persistentvolumeclaim", "volume_health_status"}, nil, metrics.ALPHA, "") ) @@ -102,7 +102,6 @@ func (collector *volumeStatsCollector) CollectWithStability(ch chan<- metrics.Me } addGauge := func(desc *metrics.Desc, pvcRef *stats.PVCReference, v float64, lv ...string) { lv = append([]string{pvcRef.Namespace, pvcRef.Name}, lv...) - ch <- metrics.NewLazyConstMetric(desc, metrics.GaugeValue, v, lv...) } allPVCs := sets.String{} @@ -127,7 +126,7 @@ 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, convertBoolToFloat64(volumeStat.Abnormal)) + addGauge(volumeStatsHealthAbnormalDesc, pvcRef, convertBoolToFloat64(volumeStat.VolumeHealthStats.Abnormal), "abnormal") allPVCs.Insert(pvcUniqStr) } } diff --git a/pkg/kubelet/metrics/collectors/volume_stats_test.go b/pkg/kubelet/metrics/collectors/volume_stats_test.go index c9d9e1b89bb..032b69337e1 100644 --- a/pkg/kubelet/metrics/collectors/volume_stats_test.go +++ b/pkg/kubelet/metrics/collectors/volume_stats_test.go @@ -85,7 +85,7 @@ func TestVolumeStatsCollector(t *testing.T) { Name: "testpvc", Namespace: "testns", }, - VolumeHealthStats: statsapi.VolumeHealthStats{ + VolumeHealthStats: &statsapi.VolumeHealthStats{ Abnormal: true, }, }, @@ -111,7 +111,7 @@ func TestVolumeStatsCollector(t *testing.T) { Name: "testpvc", Namespace: "testns", }, - VolumeHealthStats: statsapi.VolumeHealthStats{ + VolumeHealthStats: &statsapi.VolumeHealthStats{ Abnormal: true, }, }, @@ -126,7 +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_status{namespace="testns",persistentvolumeclaim="testpvc"} 1 + kubelet_volume_stats_health_status{namespace="testns",persistentvolumeclaim="testpvc",volume_health_status="abnormal"} 1 ` metrics = []string{ diff --git a/pkg/kubelet/server/stats/volume_stat_calculator.go b/pkg/kubelet/server/stats/volume_stat_calculator.go index b28b541dc72..d429e867303 100644 --- a/pkg/kubelet/server/stats/volume_stat_calculator.go +++ b/pkg/kubelet/server/stats/volume_stat_calculator.go @@ -177,7 +177,11 @@ func (s *volumeStatCalculator) calcAndStoreStats() { // parsePodVolumeStats converts (internal) volume.Metrics to (external) stats.VolumeStats structures func (s *volumeStatCalculator) parsePodVolumeStats(podName string, pvcRef *stats.PVCReference, metric *volume.Metrics, volSpec v1.Volume) stats.VolumeStats { - var available, capacity, used, inodes, inodesFree, inodesUsed uint64 + var ( + available, capacity, used, inodes, inodesFree, inodesUsed uint64 + volumeStats stats.VolumeStats + ) + if metric.Available != nil { available = uint64(metric.Available.Value()) } @@ -197,13 +201,15 @@ func (s *volumeStatCalculator) parsePodVolumeStats(podName string, pvcRef *stats inodesUsed = uint64(metric.InodesUsed.Value()) } - return stats.VolumeStats{ - Name: podName, - PVCRef: pvcRef, - VolumeHealthStats: stats.VolumeHealthStats{ + volumeStats.FsStats = stats.FsStats{Time: metric.Time, AvailableBytes: &available, CapacityBytes: &capacity, + UsedBytes: &used, Inodes: &inodes, InodesFree: &inodesFree, InodesUsed: &inodesUsed} + volumeStats.Name = podName + volumeStats.PVCRef = pvcRef + if metric.Abnormal != nil { + volumeStats.VolumeHealthStats = &stats.VolumeHealthStats{ Abnormal: *metric.Abnormal, - }, - FsStats: stats.FsStats{Time: metric.Time, AvailableBytes: &available, CapacityBytes: &capacity, - UsedBytes: &used, Inodes: &inodes, InodesFree: &inodesFree, InodesUsed: &inodesUsed}, + } } + + return volumeStats } diff --git a/pkg/kubelet/server/stats/volume_stat_calculator_test.go b/pkg/kubelet/server/stats/volume_stat_calculator_test.go index a230d7a1dfe..ed29b39b4c7 100644 --- a/pkg/kubelet/server/stats/volume_stat_calculator_test.go +++ b/pkg/kubelet/server/stats/volume_stat_calculator_test.go @@ -128,8 +128,9 @@ func TestPVCRef(t *testing.T) { assert.Len(t, append(vs.EphemeralVolumes, vs.PersistentVolumes...), 4) // Verify 'vol0' doesn't have a PVC reference assert.Contains(t, append(vs.EphemeralVolumes, vs.PersistentVolumes...), kubestats.VolumeStats{ - Name: vol0, - FsStats: expectedFSStats(), + Name: vol0, + FsStats: expectedFSStats(), + VolumeHealthStats: expectedVolumeHealthStats(), }) // Verify 'vol1' has a PVC reference assert.Contains(t, append(vs.EphemeralVolumes, vs.PersistentVolumes...), kubestats.VolumeStats{ @@ -138,16 +139,18 @@ func TestPVCRef(t *testing.T) { Name: pvcClaimName0, Namespace: namespace0, }, - FsStats: expectedFSStats(), + FsStats: expectedFSStats(), + VolumeHealthStats: expectedVolumeHealthStats(), }) - // Verify 'vol2' has a PVC reference + // // Verify 'vol2' has a PVC reference assert.Contains(t, append(vs.EphemeralVolumes, vs.PersistentVolumes...), kubestats.VolumeStats{ Name: vol2, PVCRef: &kubestats.PVCReference{ Name: pvcClaimName1, Namespace: namespace0, }, - FsStats: expectedBlockStats(), + FsStats: expectedBlockStats(), + VolumeHealthStats: expectedVolumeHealthStats(), }) // Verify 'vol3' has a PVC reference assert.Contains(t, append(vs.EphemeralVolumes, vs.PersistentVolumes...), kubestats.VolumeStats{ @@ -263,6 +266,13 @@ func expectedFSStats() kubestats.FsStats { } } +func expectedVolumeHealthStats() *kubestats.VolumeHealthStats { + metric := expectedMetrics() + return &kubestats.VolumeHealthStats{ + Abnormal: *metric.Abnormal, + } +} + // Fake block-volume/metrics provider, block-devices have no inodes var _ volume.BlockVolume = &fakeBlockVolume{} 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 7efcc4dc269..cf7797d3d2e 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 @@ -272,14 +272,14 @@ type VolumeStats struct { // VolumeHealthStats contains data about volume health // +optional - VolumeHealthStats `json:"volumeHealthStats,omitempty"` + VolumeHealthStats *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"` + Abnormal bool `json:"abnormal"` } // PVCReference contains enough information to describe the referenced PVC. diff --git a/test/e2e_node/summary_test.go b/test/e2e_node/summary_test.go index cdb5302c38d..8e85b38b1b3 100644 --- a/test/e2e_node/summary_test.go +++ b/test/e2e_node/summary_test.go @@ -230,9 +230,11 @@ var _ = SIGDescribe("Summary API [NodeConformance]", func() { "test-empty-dir": gstruct.MatchAllFields(gstruct.Fields{ "Name": gomega.Equal("test-empty-dir"), "PVCRef": gomega.BeNil(), - "VolumeHealthStats": gstruct.MatchAllFields(gstruct.Fields{ - "Abnormal": gomega.BeTrue(), - }), + "VolumeHealthStats": gstruct.MatchAllFields( + gstruct.Fields{ + "Abnormal": gomega.BeFalse(), + }, + ), "FsStats": gstruct.MatchAllFields(gstruct.Fields{ "Time": recent(maxStatsAge), "AvailableBytes": fsCapacityBounds,