diff --git a/dashboards/persistentvolumesusage.libsonnet b/dashboards/persistentvolumesusage.libsonnet index d8416b8ce..5dad9bd68 100644 --- a/dashboards/persistentvolumesusage.libsonnet +++ b/dashboards/persistentvolumesusage.libsonnet @@ -1,173 +1,203 @@ -local grafana = import 'github.com/grafana/grafonnet-lib/grafonnet/grafana.libsonnet'; -local dashboard = grafana.dashboard; -local row = grafana.row; -local prometheus = grafana.prometheus; -local template = grafana.template; -local graphPanel = grafana.graphPanel; -local promgrafonnet = import '../lib/promgrafonnet/promgrafonnet.libsonnet'; -local gauge = promgrafonnet.gauge; +local g = import 'github.com/grafana/grafonnet/gen/grafonnet-latest/main.libsonnet'; +local prometheus = g.query.prometheus; +local gauge = g.panel.gauge; +local timeSeries = g.panel.timeSeries; +local var = g.dashboard.variable; { + local gaugePanel(title, unit, query) = + gauge.new(title) + + gauge.standardOptions.withUnit(unit) + + gauge.queryOptions.withInterval($._config.grafanaK8s.minimumTimeInterval) + + gauge.queryOptions.withTargets([ + prometheus.new('${datasource}', query) + + prometheus.withInstant(true), + ]), + + local tsPanel = + timeSeries { + new(title): + timeSeries.new(title) + + timeSeries.options.legend.withShowLegend() + + timeSeries.options.legend.withAsTable() + + timeSeries.options.legend.withDisplayMode('table') + + timeSeries.options.legend.withPlacement('right') + + timeSeries.options.legend.withCalcs(['lastNotNull']) + + timeSeries.options.tooltip.withMode('single') + + timeSeries.fieldConfig.defaults.custom.withShowPoints('never') + + timeSeries.fieldConfig.defaults.custom.withFillOpacity(10) + + timeSeries.fieldConfig.defaults.custom.withSpanNulls(true) + + timeSeries.queryOptions.withInterval($._config.grafanaK8s.minimumTimeInterval), + }, + grafanaDashboards+:: { 'persistentvolumesusage.json': - local sizeGraph = graphPanel.new( - 'Volume Space Usage', - datasource='$datasource', - format='bytes', - min=0, - span=9, - stack=true, - legend_show=true, - legend_values=true, - legend_min=true, - legend_max=true, - legend_current=true, - legend_total=false, - legend_avg=true, - legend_alignAsTable=true, - legend_rightSide=false, - ).addTarget(prometheus.target( - ||| - ( - sum without(instance, node) (topk(1, (kubelet_volume_stats_capacity_bytes{%(clusterLabel)s="$cluster", %(kubeletSelector)s, namespace="$namespace", persistentvolumeclaim="$volume"}))) - - - sum without(instance, node) (topk(1, (kubelet_volume_stats_available_bytes{%(clusterLabel)s="$cluster", %(kubeletSelector)s, namespace="$namespace", persistentvolumeclaim="$volume"}))) + local variables = { + datasource: + var.datasource.new('datasource', 'prometheus') + + var.datasource.withRegex($._config.datasourceFilterRegex) + + var.datasource.generalOptions.showOnDashboard.withLabelAndValue() + + var.datasource.generalOptions.withLabel('Data source') + + { + current: { + selected: true, + text: $._config.datasourceName, + value: $._config.datasourceName, + }, + }, + + cluster: + var.query.new('cluster') + + var.query.withDatasourceFromVariable(self.datasource) + + var.query.queryTypes.withLabelValues( + $._config.clusterLabel, + 'kubelet_volume_stats_capacity_bytes{%(kubeletSelector)s}' % $._config, + ) + + var.query.generalOptions.withLabel('cluster') + + var.query.refresh.onTime() + + ( + if $._config.showMultiCluster + then var.query.generalOptions.showOnDashboard.withLabelAndValue() + else var.query.generalOptions.showOnDashboard.withNothing() + ) + + var.query.withSort(type='alphabetical'), + + namespace: + var.query.new('namespace') + + var.query.withDatasourceFromVariable(self.datasource) + + var.query.queryTypes.withLabelValues( + 'namespace', + 'kubelet_volume_stats_capacity_bytes{%(clusterLabel)s="$cluster", %(kubeletSelector)s}' % $._config, ) - ||| % $._config, - legendFormat='Used Space', - intervalFactor=1, - )).addTarget(prometheus.target( - ||| - sum without(instance, node) (topk(1, (kubelet_volume_stats_available_bytes{%(clusterLabel)s="$cluster", %(kubeletSelector)s, namespace="$namespace", persistentvolumeclaim="$volume"}))) - ||| % $._config, - legendFormat='Free Space', - intervalFactor=1, - )); + + var.query.generalOptions.withLabel('Namespace') + + var.query.refresh.onTime() + + var.query.generalOptions.showOnDashboard.withLabelAndValue() + + var.query.withSort(type='alphabetical'), - local sizeGauge = gauge.new( - 'Volume Space Usage', - ||| - max without(instance,node) ( - ( - topk(1, kubelet_volume_stats_capacity_bytes{%(clusterLabel)s="$cluster", %(kubeletSelector)s, namespace="$namespace", persistentvolumeclaim="$volume"}) - - - topk(1, kubelet_volume_stats_available_bytes{%(clusterLabel)s="$cluster", %(kubeletSelector)s, namespace="$namespace", persistentvolumeclaim="$volume"}) + volume: + var.query.new('volume') + + var.query.withDatasourceFromVariable(self.datasource) + + var.query.queryTypes.withLabelValues( + 'persistentvolumeclaim', + 'kubelet_volume_stats_capacity_bytes{%(clusterLabel)s="$cluster", %(kubeletSelector)s, namespace="$namespace"}' % $._config, ) - / - topk(1, kubelet_volume_stats_capacity_bytes{%(clusterLabel)s="$cluster", %(kubeletSelector)s, namespace="$namespace", persistentvolumeclaim="$volume"}) - * 100) - ||| % $._config, - ).withLowerBeingBetter(); + + var.query.generalOptions.withLabel('PersistentVolumeClaim') + + var.query.refresh.onTime() + + var.query.generalOptions.showOnDashboard.withLabelAndValue() + + var.query.withSort(type='alphabetical'), + }; + local panels = { + tsUsage: + tsPanel.new('Volume Space Usage') + + tsPanel.standardOptions.withUnit('bytes') + + tsPanel.queryOptions.withTargets([ + prometheus.new('${datasource}', ||| + ( + sum without(instance, node) (topk(1, (kubelet_volume_stats_capacity_bytes{%(clusterLabel)s="$cluster", %(kubeletSelector)s, namespace="$namespace", persistentvolumeclaim="$volume"}))) + - + sum without(instance, node) (topk(1, (kubelet_volume_stats_available_bytes{%(clusterLabel)s="$cluster", %(kubeletSelector)s, namespace="$namespace", persistentvolumeclaim="$volume"}))) + ) + ||| % $._config) + + prometheus.withLegendFormat('Used Space'), - local inodesGraph = graphPanel.new( - 'Volume inodes Usage', - datasource='$datasource', - format='none', - min=0, - span=9, - stack=true, - legend_show=true, - legend_values=true, - legend_min=true, - legend_max=true, - legend_current=true, - legend_total=false, - legend_avg=true, - legend_alignAsTable=true, - legend_rightSide=false, - ).addTarget(prometheus.target( - ||| - sum without(instance, node) (topk(1, (kubelet_volume_stats_inodes_used{%(clusterLabel)s="$cluster", %(kubeletSelector)s, namespace="$namespace", persistentvolumeclaim="$volume"}))) - ||| % $._config, - legendFormat='Used inodes', - intervalFactor=1, - )).addTarget(prometheus.target( - ||| - ( - sum without(instance, node) (topk(1, (kubelet_volume_stats_inodes{%(clusterLabel)s="$cluster", %(kubeletSelector)s, namespace="$namespace", persistentvolumeclaim="$volume"}))) - - - sum without(instance, node) (topk(1, (kubelet_volume_stats_inodes_used{%(clusterLabel)s="$cluster", %(kubeletSelector)s, namespace="$namespace", persistentvolumeclaim="$volume"}))) + prometheus.new('${datasource}', ||| + sum without(instance, node) (topk(1, (kubelet_volume_stats_available_bytes{%(clusterLabel)s="$cluster", %(kubeletSelector)s, namespace="$namespace", persistentvolumeclaim="$volume"}))) + ||| % $._config) + + prometheus.withLegendFormat('Free Space'), + ]), + gaugeUsage: + gaugePanel( + 'Volume Space Usage', + 'percent', + ||| + max without(instance,node) ( + ( + topk(1, kubelet_volume_stats_capacity_bytes{%(clusterLabel)s="$cluster", %(kubeletSelector)s, namespace="$namespace", persistentvolumeclaim="$volume"}) + - + topk(1, kubelet_volume_stats_available_bytes{%(clusterLabel)s="$cluster", %(kubeletSelector)s, namespace="$namespace", persistentvolumeclaim="$volume"}) + ) + / + topk(1, kubelet_volume_stats_capacity_bytes{%(clusterLabel)s="$cluster", %(kubeletSelector)s, namespace="$namespace", persistentvolumeclaim="$volume"}) + * 100) + ||| % $._config ) - ||| % $._config, - legendFormat=' Free inodes', - intervalFactor=1, - )); + + gauge.standardOptions.withMin(0) + + gauge.standardOptions.withMax(100) + + gauge.standardOptions.color.withMode('thresholds') + + gauge.standardOptions.thresholds.withMode('absolute') + + gauge.standardOptions.thresholds.withSteps( + [ + gauge.thresholdStep.withColor('green') + + gauge.thresholdStep.withValue(0), - local inodeGauge = gauge.new( - 'Volume inodes Usage', - ||| - max without(instance,node) ( - topk(1, kubelet_volume_stats_inodes_used{%(clusterLabel)s="$cluster", %(kubeletSelector)s, namespace="$namespace", persistentvolumeclaim="$volume"}) - / - topk(1, kubelet_volume_stats_inodes{%(clusterLabel)s="$cluster", %(kubeletSelector)s, namespace="$namespace", persistentvolumeclaim="$volume"}) - * 100) - ||| % $._config, - ).withLowerBeingBetter(); + gauge.thresholdStep.withColor('orange') + + gauge.thresholdStep.withValue(80), + gauge.thresholdStep.withColor('red') + + gauge.thresholdStep.withValue(90), + ] + ), - dashboard.new( - '%(dashboardNamePrefix)sPersistent Volumes' % $._config.grafanaK8s, - time_from='now-7d', - uid=($._config.grafanaDashboardIDs['persistentvolumesusage.json']), - tags=($._config.grafanaK8s.dashboardTags), - ).addTemplate( - { - current: { - selected: true, - text: $._config.datasourceName, - value: $._config.datasourceName, - }, - hide: 0, - label: 'Data source', - name: 'datasource', - options: [], - query: 'prometheus', - refresh: 1, - regex: $._config.datasourceFilterRegex, - type: 'datasource', - }, - ) - .addTemplate( - template.new( - 'cluster', - '$datasource', - 'label_values(kubelet_volume_stats_capacity_bytes{%(kubeletSelector)s}, %(clusterLabel)s)' % $._config, - label='cluster', - refresh='time', - hide=if $._config.showMultiCluster then '' else 'variable', - sort=1, - ) - ) - .addTemplate( - template.new( - 'namespace', - '$datasource', - 'label_values(kubelet_volume_stats_capacity_bytes{%(clusterLabel)s="$cluster", %(kubeletSelector)s}, namespace)' % $._config, - label='Namespace', - refresh='time', - sort=1, - ) - ) - .addTemplate( - template.new( - 'volume', - '$datasource', - 'label_values(kubelet_volume_stats_capacity_bytes{%(clusterLabel)s="$cluster", %(kubeletSelector)s, namespace="$namespace"}, persistentvolumeclaim)' % $._config, - label='PersistentVolumeClaim', - refresh='time', - sort=1, - ) - ) - .addRow( - row.new() - .addPanel(sizeGraph) - .addPanel(sizeGauge) - ) - .addRow( - row.new() - .addPanel(inodesGraph) - .addPanel(inodeGauge) - ), + tsInodes: + tsPanel.new('Volume inodes Usage') + + tsPanel.standardOptions.withUnit('none') + + tsPanel.queryOptions.withTargets([ + prometheus.new('${datasource}', 'sum without(instance, node) (topk(1, (kubelet_volume_stats_inodes_used{%(clusterLabel)s="$cluster", %(kubeletSelector)s, namespace="$namespace", persistentvolumeclaim="$volume"})))' % $._config) + + prometheus.withLegendFormat('Used inodes'), + + prometheus.new('${datasource}', ||| + ( + sum without(instance, node) (topk(1, (kubelet_volume_stats_inodes{%(clusterLabel)s="$cluster", %(kubeletSelector)s, namespace="$namespace", persistentvolumeclaim="$volume"}))) + - + sum without(instance, node) (topk(1, (kubelet_volume_stats_inodes_used{%(clusterLabel)s="$cluster", %(kubeletSelector)s, namespace="$namespace", persistentvolumeclaim="$volume"}))) + ) + ||| % $._config) + + prometheus.withLegendFormat('Free inodes'), + ]), + gaugeInodes: + gaugePanel( + 'Volume inodes Usage', + 'percent', + ||| + max without(instance,node) ( + topk(1, kubelet_volume_stats_inodes_used{%(clusterLabel)s="$cluster", %(kubeletSelector)s, namespace="$namespace", persistentvolumeclaim="$volume"}) + / + topk(1, kubelet_volume_stats_inodes{%(clusterLabel)s="$cluster", %(kubeletSelector)s, namespace="$namespace", persistentvolumeclaim="$volume"}) + * 100) + ||| % $._config + ) + + gauge.standardOptions.withMin(0) + + gauge.standardOptions.withMax(100) + + gauge.standardOptions.color.withMode('thresholds') + + gauge.standardOptions.thresholds.withMode('absolute') + + gauge.standardOptions.thresholds.withSteps( + [ + gauge.thresholdStep.withColor('green') + + gauge.thresholdStep.withValue(0), + + gauge.thresholdStep.withColor('orange') + + gauge.thresholdStep.withValue(80), + + gauge.thresholdStep.withColor('red') + + gauge.thresholdStep.withValue(90), + ] + ), + }; + + g.dashboard.new('%(dashboardNamePrefix)sPersistent Volumes' % $._config.grafanaK8s) + + g.dashboard.withUid($._config.grafanaDashboardIDs['persistentvolumesusage.json']) + + g.dashboard.withTags($._config.grafanaK8s.dashboardTags) + + g.dashboard.withEditable(false) + + g.dashboard.time.withFrom('now-1h') + + g.dashboard.time.withTo('now') + + g.dashboard.withRefresh($._config.grafanaK8s.refresh) + + g.dashboard.withVariables([variables.datasource, variables.cluster, variables.namespace, variables.volume]) + + g.dashboard.withPanels([ + panels.tsUsage { gridPos+: { w: 18, h: 7, y: 0 } }, + panels.gaugeUsage { gridPos+: { w: 6, h: 7, x: 18, y: 0 } }, + panels.tsInodes { gridPos+: { w: 18, h: 7, y: 7 } }, + panels.gaugeInodes { gridPos+: { w: 6, h: 7, x: 18, y: 7 } }, + ]), }, }