diff --git a/pkg/controller/volume/persistentvolume/metrics/BUILD b/pkg/controller/volume/persistentvolume/metrics/BUILD index 715e13fe8c9..7b589d2fb7b 100644 --- a/pkg/controller/volume/persistentvolume/metrics/BUILD +++ b/pkg/controller/volume/persistentvolume/metrics/BUILD @@ -6,6 +6,7 @@ go_library( importpath = "k8s.io/kubernetes/pkg/controller/volume/persistentvolume/metrics", visibility = ["//visibility:public"], deps = [ + "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/component-base/metrics:go_default_library", diff --git a/pkg/controller/volume/persistentvolume/metrics/metrics.go b/pkg/controller/volume/persistentvolume/metrics/metrics.go index b5e7bef4161..86ca21ff76e 100644 --- a/pkg/controller/volume/persistentvolume/metrics/metrics.go +++ b/pkg/controller/volume/persistentvolume/metrics/metrics.go @@ -23,6 +23,7 @@ import ( v1 "k8s.io/api/core/v1" "k8s.io/component-base/metrics" "k8s.io/component-base/metrics/legacyregistry" + "k8s.io/kubernetes/pkg/volume" metricutil "k8s.io/kubernetes/pkg/volume/util" ) @@ -31,6 +32,7 @@ const ( pvControllerSubsystem = "pv_collector" // Metric names. + totalPVKey = "total_pv_count" boundPVKey = "bound_pv_count" unboundPVKey = "unbound_pv_count" boundPVCKey = "bound_pvc_count" @@ -39,6 +41,11 @@ const ( // Label names. namespaceLabel = "namespace" storageClassLabel = "storage_class" + pluginNameLabel = "plugin_name" + volumeModeLabel = "volume_mode" + + // String to use when plugin name cannot be determined + pluginNameNotAvailable = "N/A" ) var registerMetrics sync.Once @@ -54,15 +61,15 @@ type PVCLister interface { } // Register all metrics for pv controller. -func Register(pvLister PVLister, pvcLister PVCLister) { +func Register(pvLister PVLister, pvcLister PVCLister, pluginMgr *volume.VolumePluginMgr) { registerMetrics.Do(func() { - legacyregistry.CustomMustRegister(newPVAndPVCCountCollector(pvLister, pvcLister)) + legacyregistry.CustomMustRegister(newPVAndPVCCountCollector(pvLister, pvcLister, pluginMgr)) legacyregistry.MustRegister(volumeOperationErrorsMetric) }) } -func newPVAndPVCCountCollector(pvLister PVLister, pvcLister PVCLister) *pvAndPVCCountCollector { - return &pvAndPVCCountCollector{pvLister: pvLister, pvcLister: pvcLister} +func newPVAndPVCCountCollector(pvLister PVLister, pvcLister PVCLister, pluginMgr *volume.VolumePluginMgr) *pvAndPVCCountCollector { + return &pvAndPVCCountCollector{pvLister: pvLister, pvcLister: pvcLister, pluginMgr: pluginMgr} } // Custom collector for current pod and container counts. @@ -73,12 +80,19 @@ type pvAndPVCCountCollector struct { pvLister PVLister // Cache for accessing information about PersistentVolumeClaims. pvcLister PVCLister + // Volume plugin manager + pluginMgr *volume.VolumePluginMgr } // Check if our collector implements necessary collector interface var _ metrics.StableCollector = &pvAndPVCCountCollector{} var ( + totalPVCountDesc = metrics.NewDesc( + metrics.BuildFQName("", pvControllerSubsystem, totalPVKey), + "Gauge measuring total number of persistent volumes", + []string{pluginNameLabel, volumeModeLabel}, nil, + metrics.ALPHA, "") boundPVCountDesc = metrics.NewDesc( metrics.BuildFQName("", pvControllerSubsystem, boundPVKey), "Gauge measuring number of persistent volume currently bound", @@ -110,7 +124,20 @@ var ( []string{"plugin_name", "operation_name"}) ) +// volumeCount counts by PluginName and VolumeMode. +type volumeCount map[string]map[string]int + +func (v volumeCount) add(pluginName string, volumeMode string) { + count, ok := v[pluginName] + if !ok { + count = map[string]int{} + } + count[volumeMode]++ + v[pluginName] = count +} + func (collector *pvAndPVCCountCollector) DescribeWithStability(ch chan<- *metrics.Desc) { + ch <- totalPVCountDesc ch <- boundPVCountDesc ch <- unboundPVCountDesc ch <- boundPVCCountDesc @@ -122,14 +149,26 @@ func (collector *pvAndPVCCountCollector) CollectWithStability(ch chan<- metrics. collector.pvcCollect(ch) } +func (collector *pvAndPVCCountCollector) getPVPluginName(pv *v1.PersistentVolume) string { + spec := volume.NewSpecFromPersistentVolume(pv, true) + fullPluginName := pluginNameNotAvailable + if plugin, err := collector.pluginMgr.FindPluginBySpec(spec); err == nil { + fullPluginName = metricutil.GetFullQualifiedPluginNameForVolume(plugin.GetPluginName(), spec) + } + return fullPluginName +} + func (collector *pvAndPVCCountCollector) pvCollect(ch chan<- metrics.Metric) { boundNumberByStorageClass := make(map[string]int) unboundNumberByStorageClass := make(map[string]int) + totalCount := make(volumeCount) for _, pvObj := range collector.pvLister.List() { pv, ok := pvObj.(*v1.PersistentVolume) if !ok { continue } + pluginName := collector.getPVPluginName(pv) + totalCount.add(pluginName, string(*pv.Spec.VolumeMode)) if pv.Status.Phase == v1.VolumeBound { boundNumberByStorageClass[pv.Spec.StorageClassName]++ } else { @@ -150,6 +189,16 @@ func (collector *pvAndPVCCountCollector) pvCollect(ch chan<- metrics.Metric) { float64(number), storageClassName) } + for pluginName, volumeModeCount := range totalCount { + for volumeMode, number := range volumeModeCount { + ch <- metrics.NewLazyConstMetric( + totalPVCountDesc, + metrics.GaugeValue, + float64(number), + pluginName, + volumeMode) + } + } } func (collector *pvAndPVCCountCollector) pvcCollect(ch chan<- metrics.Metric) { diff --git a/pkg/controller/volume/persistentvolume/pv_controller_base.go b/pkg/controller/volume/persistentvolume/pv_controller_base.go index 38e1d36e2bb..7b0f195a4de 100644 --- a/pkg/controller/volume/persistentvolume/pv_controller_base.go +++ b/pkg/controller/volume/persistentvolume/pv_controller_base.go @@ -317,7 +317,7 @@ func (ctrl *PersistentVolumeController) Run(stopCh <-chan struct{}) { go wait.Until(ctrl.volumeWorker, time.Second, stopCh) go wait.Until(ctrl.claimWorker, time.Second, stopCh) - metrics.Register(ctrl.volumes.store, ctrl.claims) + metrics.Register(ctrl.volumes.store, ctrl.claims, &ctrl.volumePluginMgr) <-stopCh }