pvmetrics.go 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. package metrics
  2. import (
  3. "github.com/opencost/opencost/core/pkg/clustercache"
  4. "github.com/prometheus/client_golang/prometheus"
  5. dto "github.com/prometheus/client_model/go"
  6. v1 "k8s.io/api/core/v1"
  7. )
  8. //--------------------------------------------------------------------------
  9. // KubePVCollector
  10. //--------------------------------------------------------------------------
  11. // KubePVCollector is a prometheus collector that generates PV metrics
  12. type KubePVCollector struct {
  13. KubeClusterCache clustercache.ClusterCache
  14. metricsConfig MetricsConfig
  15. }
  16. // Describe sends the super-set of all possible descriptors of metrics
  17. // collected by this Collector.
  18. func (kpvcb KubePVCollector) Describe(ch chan<- *prometheus.Desc) {
  19. disabledMetrics := kpvcb.metricsConfig.GetDisabledMetricsMap()
  20. if _, disabled := disabledMetrics["kube_persistentvolume_capacity_bytes"]; !disabled {
  21. ch <- prometheus.NewDesc("kube_persistentvolume_capacity_bytes", "The pv storage capacity in bytes", []string{}, nil)
  22. }
  23. if _, disabled := disabledMetrics["kube_persistentvolume_status_phase"]; !disabled {
  24. ch <- prometheus.NewDesc("kube_persistentvolume_status_phase", "The phase indicates if a volume is available, bound to a claim, or released by a claim.", []string{}, nil)
  25. }
  26. if _, disabled := disabledMetrics["kubecost_pv_info"]; !disabled {
  27. ch <- prometheus.NewDesc("kubecost_pv_info", "The pv information", []string{}, nil)
  28. }
  29. }
  30. // Collect is called by the Prometheus registry when collecting metrics.
  31. func (kpvcb KubePVCollector) Collect(ch chan<- prometheus.Metric) {
  32. pvs := kpvcb.KubeClusterCache.GetAllPersistentVolumes()
  33. disabledMetrics := kpvcb.metricsConfig.GetDisabledMetricsMap()
  34. for _, pv := range pvs {
  35. pvUID := string(pv.UID)
  36. if _, disabled := disabledMetrics["kube_persistentvolume_status_phase"]; !disabled {
  37. phase := pv.Status.Phase
  38. if phase != "" {
  39. phases := []struct {
  40. v bool
  41. n string
  42. }{
  43. {phase == v1.VolumePending, string(v1.VolumePending)},
  44. {phase == v1.VolumeAvailable, string(v1.VolumeAvailable)},
  45. {phase == v1.VolumeBound, string(v1.VolumeBound)},
  46. {phase == v1.VolumeReleased, string(v1.VolumeReleased)},
  47. {phase == v1.VolumeFailed, string(v1.VolumeFailed)},
  48. }
  49. for _, p := range phases {
  50. ch <- newKubePVStatusPhaseMetric("kube_persistentvolume_status_phase", pv.Name, pvUID, p.n, boolFloat64(p.v))
  51. }
  52. }
  53. }
  54. if _, disabled := disabledMetrics["kube_persistentvolume_capacity_bytes"]; !disabled {
  55. storage := pv.Spec.Capacity[v1.ResourceStorage]
  56. m := newKubePVCapacityBytesMetric("kube_persistentvolume_capacity_bytes", pv.Name, pvUID, float64(storage.Value()))
  57. ch <- m
  58. }
  59. if _, disabled := disabledMetrics["kubecost_pv_info"]; !disabled {
  60. storageClass := pv.Spec.StorageClassName
  61. providerID := pv.Name
  62. var csiVolumeHandle string
  63. // if a more accurate provider ID is available, use that
  64. if pv.Spec.CSI != nil && pv.Spec.CSI.VolumeHandle != "" {
  65. providerID = pv.Spec.CSI.VolumeHandle
  66. csiVolumeHandle = pv.Spec.CSI.VolumeHandle
  67. }
  68. m := newKubecostPVInfoMetric("kubecost_pv_info", pv.Name, pvUID, storageClass, providerID, csiVolumeHandle, float64(1))
  69. ch <- m
  70. }
  71. }
  72. }
  73. //--------------------------------------------------------------------------
  74. // KubePVCapacityBytesMetric
  75. //--------------------------------------------------------------------------
  76. // KubePVCapacityBytesMetric is a prometheus.Metric
  77. type KubePVCapacityBytesMetric struct {
  78. fqName string
  79. help string
  80. pv string
  81. value float64
  82. uid string
  83. }
  84. // Creates a new KubePVCapacityBytesMetric, implementation of prometheus.Metric
  85. func newKubePVCapacityBytesMetric(fqname, pv, uid string, value float64) KubePVCapacityBytesMetric {
  86. return KubePVCapacityBytesMetric{
  87. fqName: fqname,
  88. help: "kube_persistentvolume_capacity_bytes pv storage capacity in bytes",
  89. pv: pv,
  90. value: value,
  91. uid: uid,
  92. }
  93. }
  94. // Desc returns the descriptor for the Metric. This method idempotently
  95. // returns the same descriptor throughout the lifetime of the Metric.
  96. func (kpcrr KubePVCapacityBytesMetric) Desc() *prometheus.Desc {
  97. l := prometheus.Labels{
  98. "persistentvolume": kpcrr.pv,
  99. "uid": kpcrr.uid,
  100. }
  101. return prometheus.NewDesc(kpcrr.fqName, kpcrr.help, []string{}, l)
  102. }
  103. // Write encodes the Metric into a "Metric" Protocol Buffer data
  104. // transmission object.
  105. func (kpcrr KubePVCapacityBytesMetric) Write(m *dto.Metric) error {
  106. m.Gauge = &dto.Gauge{
  107. Value: &kpcrr.value,
  108. }
  109. m.Label = []*dto.LabelPair{
  110. {
  111. Name: toStringPtr("persistentvolume"),
  112. Value: &kpcrr.pv,
  113. },
  114. {
  115. Name: toStringPtr("uid"),
  116. Value: &kpcrr.uid,
  117. },
  118. }
  119. return nil
  120. }
  121. //--------------------------------------------------------------------------
  122. // KubePVStatusPhaseMetric
  123. //--------------------------------------------------------------------------
  124. // KubePVStatusPhaseMetric is a prometheus.Metric
  125. type KubePVStatusPhaseMetric struct {
  126. fqName string
  127. help string
  128. pv string
  129. phase string
  130. value float64
  131. uid string
  132. }
  133. // Creates a new KubePVStatusPhaseMetric, implementation of prometheus.Metric
  134. func newKubePVStatusPhaseMetric(fqname, pv, uid, phase string, value float64) KubePVStatusPhaseMetric {
  135. return KubePVStatusPhaseMetric{
  136. fqName: fqname,
  137. help: "kube_persistentvolume_status_phase pv status phase",
  138. pv: pv,
  139. phase: phase,
  140. value: value,
  141. uid: uid,
  142. }
  143. }
  144. // Desc returns the descriptor for the Metric. This method idempotently
  145. // returns the same descriptor throughout the lifetime of the Metric.
  146. func (kpcrr KubePVStatusPhaseMetric) Desc() *prometheus.Desc {
  147. l := prometheus.Labels{
  148. "persistentvolume": kpcrr.pv,
  149. "phase": kpcrr.phase,
  150. "uid": kpcrr.uid,
  151. }
  152. return prometheus.NewDesc(kpcrr.fqName, kpcrr.help, []string{}, l)
  153. }
  154. // Write encodes the Metric into a "Metric" Protocol Buffer data
  155. // transmission object.
  156. func (kpcrr KubePVStatusPhaseMetric) Write(m *dto.Metric) error {
  157. m.Gauge = &dto.Gauge{
  158. Value: &kpcrr.value,
  159. }
  160. m.Label = []*dto.LabelPair{
  161. {
  162. Name: toStringPtr("persistentvolume"),
  163. Value: &kpcrr.pv,
  164. },
  165. {
  166. Name: toStringPtr("phase"),
  167. Value: &kpcrr.phase,
  168. },
  169. {
  170. Name: toStringPtr("uid"),
  171. Value: &kpcrr.uid,
  172. },
  173. }
  174. return nil
  175. }
  176. // --------------------------------------------------------------------------
  177. //
  178. // KubecostPVInfoMetric
  179. //
  180. // --------------------------------------------------------------------------
  181. // KubecostPVInfoMetric is a prometheus.Metric
  182. type KubecostPVInfoMetric struct {
  183. fqName string
  184. help string
  185. pv string
  186. storageClass string
  187. value float64
  188. providerId string
  189. uid string
  190. csiVolumeHandle string
  191. }
  192. // Creates a new newKubecostPVInfoMetric, implementation of prometheus.Metric
  193. func newKubecostPVInfoMetric(fqname, pv, uid, storageClass, providerID, csiVolumeHandle string, value float64) KubecostPVInfoMetric {
  194. return KubecostPVInfoMetric{
  195. fqName: fqname,
  196. help: "kubecost_pv_info pv info",
  197. pv: pv,
  198. storageClass: storageClass,
  199. value: value,
  200. providerId: providerID,
  201. uid: uid,
  202. csiVolumeHandle: csiVolumeHandle,
  203. }
  204. }
  205. // Desc returns the descriptor for the Metric. This method idempotently
  206. // returns the same descriptor throughout the lifetime of the Metric.
  207. func (kpvim KubecostPVInfoMetric) Desc() *prometheus.Desc {
  208. l := prometheus.Labels{
  209. "persistentvolume": kpvim.pv,
  210. "storageclass": kpvim.storageClass,
  211. "provider_id": kpvim.providerId,
  212. "uid": kpvim.uid,
  213. "csi_volume_handle": kpvim.csiVolumeHandle,
  214. }
  215. return prometheus.NewDesc(kpvim.fqName, kpvim.help, []string{}, l)
  216. }
  217. // Write encodes the Metric into a "Metric" Protocol Buffer data
  218. // transmission object.
  219. func (kpvim KubecostPVInfoMetric) Write(m *dto.Metric) error {
  220. m.Gauge = &dto.Gauge{
  221. Value: &kpvim.value,
  222. }
  223. m.Label = []*dto.LabelPair{
  224. {
  225. Name: toStringPtr("persistentvolume"),
  226. Value: &kpvim.pv,
  227. },
  228. {
  229. Name: toStringPtr("storageclass"),
  230. Value: &kpvim.storageClass,
  231. },
  232. {
  233. Name: toStringPtr("provider_id"),
  234. Value: &kpvim.providerId,
  235. },
  236. {
  237. Name: toStringPtr("uid"),
  238. Value: &kpvim.uid,
  239. },
  240. {
  241. Name: toStringPtr("csi_volume_handle"),
  242. Value: &kpvim.csiVolumeHandle,
  243. },
  244. }
  245. return nil
  246. }