Repository: NetApp/harvest
Pull request #1677 (2023-01-30 20:30:38)

feat: add StorageGRID overview dashboard
feat: add StorageGRID Prometheus collector


Patch:
diff --git a/cmd/collectors/rest/plugins/securityaccount/securityaccount.go b/cmd/collectors/rest/plugins/securityaccount/securityaccount.go
new file mode 100644
index 00000000..70f11721
--- /dev/null
+++ b/cmd/collectors/rest/plugins/securityaccount/securityaccount.go
@@ -0,0 +1,144 @@
+/*
+ * Copyright NetApp Inc, 2023 All rights reserved
+ */
+
+package securityaccount
+
+import (
+	"github.com/netapp/harvest/v2/cmd/collectors"
+	"github.com/netapp/harvest/v2/cmd/poller/plugin"
+	"github.com/netapp/harvest/v2/cmd/tools/rest"
+	"github.com/netapp/harvest/v2/pkg/conf"
+	"github.com/netapp/harvest/v2/pkg/errs"
+	"github.com/netapp/harvest/v2/pkg/matrix"
+	"github.com/netapp/harvest/v2/pkg/tree/node"
+	"github.com/tidwall/gjson"
+	"time"
+)
+
+type SecurityAccount struct {
+	*plugin.AbstractPlugin
+	data   *matrix.Matrix
+	client *rest.Client
+	query  string
+}
+
+func New(p *plugin.AbstractPlugin) plugin.Plugin {
+	return &SecurityAccount{AbstractPlugin: p}
+}
+
+func (s *SecurityAccount) Init() error {
+	var err error
+
+	if err = s.InitAbc(); err != nil {
+		return err
+	}
+
+	clientTimeout := s.ParentParams.GetChildContentS("client_timeout")
+	timeout, _ := time.ParseDuration(rest.DefaultTimeout)
+	duration, err := time.ParseDuration(clientTimeout)
+	if err == nil {
+		timeout = duration
+	} else {
+		s.Logger.Info().Str("timeout", timeout.String()).Msg("Using default timeout")
+	}
+	if s.client, err = rest.New(conf.ZapiPoller(s.ParentParams), timeout); err != nil {
+		s.Logger.Error().Stack().Err(err).Msg("connecting")
+		return err
+	}
+
+	if err = s.client.Init(5); err != nil {
+		return err
+	}
+
+	s.query = "api/security/accounts"
+	s.data = matrix.New(s.Parent+".SecurityAccount", "security_account", "security_account")
+
+	exportOptions := node.NewS("export_options")
+	instanceLabels := exportOptions.NewChildS("instance_labels", "")
+	instanceKeys := exportOptions.NewChildS("instance_keys", "")
+
+	if exportOption := s.ParentParams.GetChildS("export_options"); exportOption != nil {
+		if exportedLabels := exportOption.GetChildS("instance_labels"); exportedLabels != nil {
+			for _, label := range exportedLabels.GetAllChildContentS() {
+				instanceLabels.NewChildS("", label)
+			}
+		}
+		if exportedKeys := exportOption.GetChildS("instance_keys"); exportedKeys != nil {
+			for _, key := range exportedKeys.GetAllChildContentS() {
+				instanceKeys.NewChildS("", key)
+			}
+		}
+	}
+	s.data.SetExportOptions(exportOptions)
+	return nil
+}
+
+func (s *SecurityAccount) Run(data *matrix.Matrix) ([]*matrix.Matrix, error) {
+	var (
+		result                 []gjson.Result
+		err                    error
+		applicationToMethodMap map[string][]string
+	)
+
+	// Purge and reset data
+	s.data.PurgeInstances()
+	s.data.Reset()
+
+	// Set all global labels from Rest.go if already not exist
+	s.data.SetGlobalLabels(data.GetGlobalLabels())
+
+	href := rest.BuildHref("", "applications", nil, "", "", "", "", s.query)
+
+	if result, err = collectors.InvokeRestCall(s.client, href, s.Logger); err != nil {
+		return nil, err
+	}
+
+	for _, securityAccount := range result {
+		username := securityAccount.Get("name").String()
+		svm := securityAccount.Get("owner.name").String()
+
+		if !securityAccount.IsObject() {
+			s.Logger.Error().Str("type", securityAccount.Type.String()).Msg("Security Account is not an object, skipping")
+			return nil, errs.New(errs.ErrNoInstance, "security account is not an object")
+		}
+
+		// reset applicationToMethodMap map
+		applicationToMethodMap = make(map[string][]string)
+		// Parse application object and cache the details
+		if applications := securityAccount.Get("applications"); applications.Exists() {
+			for _, applicationDetail := range applications.Array() {
+				application := applicationDetail.Get("application").String()
+				if methodList := applicationDetail.Get("authentication_methods"); methodList.Exists() {
+					for _, method := range applicationDetail.Get("authentication_methods").Array() {
+						applicationToMethodMap[application] = append(applicationToMethodMap[application], method.String())
+					}
+				}
+			}
+		}
+
+		securityAccountKey := username + svm
+		if securityAccountInstance := data.GetInstance(securityAccountKey); securityAccountInstance != nil {
+			securityAccountInstance.SetExportable(false)
+
+			for application, methods := range applicationToMethodMap {
+				for _, method := range methods {
+					var securityAccountNewInstance *matrix.Instance
+					securityAccountNewKey := securityAccountKey + application + method
+					if securityAccountNewInstance, err = s.data.NewInstance(securityAccountNewKey); err != nil {
+						s.Logger.Error().Err(err).Str("add instance failed for instance key", securityAccountNewKey).Msg("")
+						return nil, err
+					}
+
+					for k, v := range securityAccountInstance.GetLabels().Map() {
+						securityAccountNewInstance.SetLabel(k, v)
+					}
+					securityAccountNewInstance.SetLabel("applications", application)
+					securityAccountNewInstance.SetLabel("methods", method)
+				}
+			}
+		}
+	}
+
+	return []*matrix.Matrix{s.data}, nil
+}
diff --git a/cmd/collectors/rest/rest.go b/cmd/collectors/rest/rest.go
index 9c2f8e1a..0cd453e3 100644
--- a/cmd/collectors/rest/rest.go
+++ b/cmd/collectors/rest/rest.go
@@ -5,6 +5,7 @@ import (
 	"github.com/netapp/harvest/v2/cmd/collectors/rest/plugins/certificate"
 	"github.com/netapp/harvest/v2/cmd/collectors/rest/plugins/disk"
 	"github.com/netapp/harvest/v2/cmd/collectors/rest/plugins/qtree"
+	"github.com/netapp/harvest/v2/cmd/collectors/rest/plugins/securityaccount"
 	"github.com/netapp/harvest/v2/cmd/collectors/rest/plugins/sensor"
 	"github.com/netapp/harvest/v2/cmd/collectors/rest/plugins/snapmirror"
 	"github.com/netapp/harvest/v2/cmd/collectors/rest/plugins/svm"
@@ -381,6 +382,8 @@ func (r *Rest) LoadPlugin(kind string, abc *plugin.AbstractPlugin) plugin.Plugin
 		return svm.New(abc)
 	case "Sensor":
 		return sensor.New(abc)
+	case "SecurityAccount":
+		return securityaccount.New(abc)
 	default:
 		r.Logger.Warn().Str("kind", kind).Msg("no rest plugin found ")
 	}
diff --git a/cmd/collectors/storagegrid/storagegrid.go b/cmd/collectors/storagegrid/storagegrid.go
index 1e1ceb00..28ce874c 100644
--- a/cmd/collectors/storagegrid/storagegrid.go
+++ b/cmd/collectors/storagegrid/storagegrid.go
@@ -1,9 +1,9 @@
 package storagegrid
 
 import (
+	"fmt"
 	"github.com/netapp/harvest/v2/cmd/collectors/rest"
 	"github.com/netapp/harvest/v2/cmd/collectors/storagegrid/plugins/bucket"
-	"github.com/netapp/harvest/v2/cmd/collectors/storagegrid/plugins/tenant"
 	srest "github.com/netapp/harvest/v2/cmd/collectors/storagegrid/rest"
 	"github.com/netapp/harvest/v2/cmd/poller/collector"
 	"github.com/netapp/harvest/v2/cmd/poller/plugin"
@@ -118,11 +118,9 @@ func (s *StorageGrid) InitCache() error {
 		return errs.New(errs.ErrMissingParam, "query")
 	}
 
-	// create metric cache
 	if counters = s.Params.GetChildS("counters"); counters == nil {
 		return errs.New(errs.ErrMissingParam, "counters")
 	}
-
 	s.ParseCounters(counters, s.Props)
 
 	s.Logger.Debug().
@@ -135,6 +133,120 @@ func (s *StorageGrid) InitCache() error {
 }
 
 func (s *StorageGrid) PollData() (map[string]*matrix.Matrix, error) {
+	if s.Props.Query == "prometheus" {
+		return s.pollPrometheusMetrics()
+	} else {
+		return s.pollRest()
+	}
+}
+
+func (s *StorageGrid) pollPrometheusMetrics() (map[string]*matrix.Matrix, error) {
+	var (
+		count      uint64
+		numRecords int
+		startTime  time.Time
+		apiD       time.Duration
+	)
+
+	metrics := make(map[string]*matrix.Matrix)
+	s.Logger.Debug().Msg("starting data poll")
+	s.Matrix[s.Object].Reset()
+	startTime = time.Now()
+
+	for _, metric := range s.Props.Metrics {
+		mat, err := s.GetMetric(metric.Name, metric.Label, nil)
+		if err != nil {
+			s.Logger.Error().Err(err).Str("metric", metric.Name).Msg("failed to get metric")
+			continue
+		}
+		metrics[metric.Name] = mat
+		numInstances := len(mat.GetInstances())
+		if numInstances == 0 {
+			s.Logger.Warn().Str("metric", metric.Name).Msg("no instances on storagegrid")
+			continue
+		}
+		count += uint64(numInstances)
+		numRecords += numInstances
+	}
+
+	apiD = time.Since(startTime)
+
+	_ = s.Metadata.LazySetValueInt64("api_time", "data", apiD.Microseconds())
+	_ = s.Metadata.LazySetValueInt64("parse_time", "data", 0)
+	_ = s.Metadata.LazySetValueUint64("metrics", "data", count)
+	_ = s.Metadata.LazySetValueInt64("instances", "data", int64(numRecords))
+	s.AddCollectCount(count)
+
+	return metrics, nil
+}
+
+func (s *StorageGrid) makePromMetrics(metricName string, result *[]gjson.Result, tenantNamesByID map[string]string) (*matrix.Matrix, error) {
+	var (
+		metric   *matrix.Metric
+		instance *matrix.Instance
+		err      error
+	)
+
+	mat := s.Matrix[s.Object].Clone(false, false, false)
+	mat.SetExportOptions(matrix.DefaultExportOptions())
+	mat.Object = s.Props.Object
+	mat.UUID += "." + metricName
+
+	r := (*result)[0]
+	resultType := r.Get("resultType").String()
+	if resultType != "vector" {
+		return nil, fmt.Errorf("unexpected resultType=[%s]", resultType)
+	}
+
+	results := r.Get("result").Array()
+	if len(results) == 0 {
+		return mat, nil
+	}
+
+	if metric, err = mat.NewMetricFloat64(metricName); err != nil {
+		return nil, fmt.Errorf("failed to create newMetric float64 metric=[%s]", metricName)
+	}
+
+	instances := r.Get("result").Array()
+	for i, rr := range instances {
+		if instance, err = mat.NewInstance(metricName + "-" + strconv.Itoa(i)); err != nil {
+			s.Logger.Error().Err(err).Str("instanceKey", metricName+"-"+strconv.Itoa(i)).Send()
+			continue
+		}
+		rr.Get("metric").ForEach(func(kk, vv gjson.Result) bool {
+			key := kk.String()
+			value := vv.String()
+
+			if key == "__name__" {
+				return true
+			}
+			if key == "instance" {
+				key = "node"
+			}
+			if tenantNamesByID != nil && key == "tenant_id" {
+				tenantName, ok := tenantNamesByID[value]
+				if ok {
+					instance.SetLabel("tenant", tenantName)
+				}
+			}
+			instance.SetLabel(key, value)
+			return true
+		})
+
+		// copy Prometheus metric value into new metric
+		valueArray := rr.Get("value").Array()
+		if len(valueArray) > 0 {
+			err = metric.SetValueFloat64(instance, valueArray[1].Float())
+			if err != nil {
+				s.Logger.Error().Err(err).Str("metric", metricName).Msg("Unable to set float key on metric")
+				continue
+			}
+		}
+	}
+	return mat, nil
+}
+
+func (s *StorageGrid) pollRest() (map[string]*matrix.Matrix, error) {
 	var (
 		count        uint64
 		apiD, parseD time.Duration
@@ -362,7 +474,7 @@ func (s *StorageGrid) LoadPlugin(kind string, abc *plugin.AbstractPlugin) plugin
 	case "Bucket":
 		return bucket.New(abc)
 	case "Tenant":
-		return tenant.New(abc)
+		return NewTenant(abc, s)
 	default:
 		s.Logger.Warn().Str("kind", kind).Msg("plugin not found")
 	}
@@ -475,6 +587,23 @@ func (s *StorageGrid) getNodeUuids() ([]collector.ID, error) {
 	return infos, nil
 }
 
+func (s *StorageGrid) GetMetric(metric string, display string, tenantNamesByID map[string]string) (*matrix.Matrix, error) {
+	var records []gjson.Result
+	err := s.client.GetMetricQuery(metric, &records)
+	if err != nil {
+		return nil, fmt.Errorf("failed to get metric=[%s] error: %w", metric, err)
+	}
+	if len(records) == 0 {
+		s.Logger.Debug().Str("metric", metric).Msg("no metrics on cluster")
+		return nil, nil
+	}
+	nameOfMetric := metric
+	if display != "" {
+		nameOfMetric = display
+	}
+	return s.makePromMetrics(nameOfMetric, &records, tenantNamesByID)
+}
+
 // Interface guards
 var (
 	_ collector.Collector = (*StorageGrid)(nil)
diff --git a/cmd/collectors/storagegrid/plugins/tenant/tenant.go b/cmd/collectors/storagegrid/tenant.go
similarity index 54%
rename from cmd/collectors/storagegrid/plugins/tenant/tenant.go
rename to cmd/collectors/storagegrid/tenant.go
index 0ce8eaae..c69d26f2 100644
--- a/cmd/collectors/storagegrid/plugins/tenant/tenant.go
+++ b/cmd/collectors/storagegrid/tenant.go
@@ -1,4 +1,4 @@
-package tenant
+package storagegrid
 
 import (
 	"github.com/netapp/harvest/v2/cmd/poller/plugin"
@@ -6,12 +6,17 @@ import (
 	"github.com/netapp/harvest/v2/pkg/matrix"
 )
 
+const (
+	lenOfPrefix = 12 // len("storagegrid_")
+)
+
 type Tenant struct {
 	*plugin.AbstractPlugin
+	sg *StorageGrid
 }
 
-func New(p *plugin.AbstractPlugin) plugin.Plugin {
-	return &Tenant{AbstractPlugin: p}
+func NewTenant(p *plugin.AbstractPlugin, s *StorageGrid) plugin.Plugin {
+	return &Tenant{AbstractPlugin: p, sg: s}
 }
 
 func (t *Tenant) Run(data *matrix.Matrix) ([]*matrix.Matrix, error) {
@@ -19,6 +24,7 @@ func (t *Tenant) Run(data *matrix.Matrix) ([]*matrix.Matrix, error) {
 	var (
 		used, quota, usedPercent *matrix.Metric
 		err                      error
+		tenantNamesByID          map[string]string
 	)
 
 	if used = data.GetMetric("dataBytes"); used == nil {
@@ -37,6 +43,7 @@ func (t *Tenant) Run(data *matrix.Matrix) ([]*matrix.Matrix, error) {
 		}
 	}
 
+	tenantNamesByID = make(map[string]string)
 	for _, instance := range data.GetInstances() {
 
 		var (
@@ -56,7 +63,37 @@ func (t *Tenant) Run(data *matrix.Matrix) ([]*matrix.Matrix, error) {
 				t.Logger.Error().Err(err).Float64("percentage", percentage).Msg("failed to set percentage")
 			}
 		}
+
+		id := instance.GetLabel("id")
+		name := instance.GetLabel("tenant")
+		if id != "" && name != "" {
+			tenantNamesByID[id] = name
+		}
 	}
 
-	return nil, nil
+	promMetrics := t.collectPromMetrics(tenantNamesByID)
+	return promMetrics, nil
+}
+
+func (t *Tenant) collectPromMetrics(tenantNamesByID map[string]string) []*matrix.Matrix {
+	metrics := make(map[string]*matrix.Matrix)
+	promMetrics := []string{
+		"storagegrid_tenant_usage_data_bytes",
+		"storagegrid_tenant_usage_quota_bytes",
+	}
+	for _, metric := range promMetrics {
+		mat, err := t.sg.GetMetric(metric, metric[lenOfPrefix:], tenantNamesByID)
+		if err != nil {
+			t.Logger.Error().Err(err).Str("metric", metric).Msg("Unable to get metric")
+			continue
+		}
+		mat.Object = "storagegrid"
+		metrics[metric] = mat
+	}
+
+	all := make([]*matrix.Matrix, 0, len(promMetrics))
+	for _, m := range metrics {
+		all = append(all, m)
+	}
+	return all
 }
diff --git a/cmd/poller/collector/collector.go b/cmd/poller/collector/collector.go
index 7a8556c1..7f80e5d5 100644
--- a/cmd/poller/collector/collector.go
+++ b/cmd/poller/collector/collector.go
@@ -122,7 +122,7 @@ func New(name, object string, options *options.Options, params *node.Node) *Abst
 
 // Init initializes a collector and does the trick of "inheritance",
 // hence a function and not a method.
-// A collector can to choose to call this function
+// A collector can choose to call this function
 // inside its Init method, or leave it to be called
 // by the poller during dynamic load.
 //
diff --git a/cmd/tools/grafana/metrics.go b/cmd/tools/grafana/metrics.go
index d6a37155..ce36edb2 100644
--- a/cmd/tools/grafana/metrics.go
+++ b/cmd/tools/grafana/metrics.go
@@ -25,7 +25,7 @@ var metricsCmd = &cobra.Command{
 func doMetrics(_ *cobra.Command, _ []string) {
 	adjustOptions()
 	validateImport()
-	visitDashboards(opts.dir, func(path string, data []byte) {
+	visitDashboards([]string{opts.dir}, func(path string, data []byte) {
 		visitExpressionsAndQueries(path, data)
 	})
 }
@@ -149,27 +149,29 @@ func doTarget(pathPrefix string, key gjson.Result, value gjson.Result,
 	}
 }
 
-func visitDashboards(dir string, eachDash func(path string, data []byte)) {
-	err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
-		if strings.Contains(path, "influxdb") {
-			return nil
-		}
-		if err != nil {
-			log.Fatal("failed to read directory:", err)
-		}
-		ext := filepath.Ext(path)
-		if ext != ".json" {
+func visitDashboards(dirs []string, eachDash func(path string, data []byte)) {
+	for _, dir := range dirs {
+		err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
+			if strings.Contains(path, "influxdb") {
+				return nil
+			}
+			if err != nil {
+				log.Fatal("failed to read directory:", err)
+			}
+			ext := filepath.Ext(path)
+			if ext != ".json" {
+				return nil
+			}
+			data, err := os.ReadFile(path)
+			if err != nil {
+				log.Fatalf("failed to read dashboards path=%s err=%v", path, err)
+			}
+			eachDash(path, data)
 			return nil
-		}
-		data, err := os.ReadFile(path)
+		})
 		if err != nil {
-			log.Fatalf("failed to read dashboards path=%s err=%v", path, err)
+			log.Fatal("failed to read dashboards:", err)
 		}
-		eachDash(path, data)
-		return nil
-	})
-	if err != nil {
-		log.Fatal("failed to read dashboards:", err)
 	}
 }
 
diff --git a/conf/rest/9.12.0/security_account.yaml b/conf/rest/9.12.0/security_account.yaml
index 6353d3cb..b3fd8eba 100644
--- a/conf/rest/9.12.0/security_account.yaml
+++ b/conf/rest/9.12.0/security_account.yaml
@@ -3,17 +3,19 @@ name:             SecurityAccount
 query:            api/security/accounts
 object:           security_account
 
+schedule:
+  - data: 1m
+
 counters:
   - ^^name                                      => user_name
   - ^^owner.name                                => svm
   - ^role.name                                  => role_name
   - ^password_hash_algorithm                    => hash_algorithm
   - ^locked                                     => locked
-  - ^applications.#.application                 => applications
-  - ^applications.#.authentication_methods.0    => methods
 
 
 plugins:
+  - SecurityAccount
   - LabelAgent:
       value_to_num_regex:
         - samluser methods .*saml.*$ .*saml.*$ `0`
@@ -26,9 +28,9 @@ export_options:
   instance_keys:
     - user_name
     - svm
+    - applications
+    - methods
   instance_labels:
     - role_name
     - hash_algorithm
     - locked
-    - applications
-    - methods
diff --git a/conf/storagegrid/11.6.0/storagegrid_metrics.yaml b/conf/storagegrid/11.6.0/storagegrid_metrics.yaml
new file mode 100644
index 00000000..1325a44d
--- /dev/null
+++ b/conf/storagegrid/11.6.0/storagegrid_metrics.yaml
@@ -0,0 +1,25 @@
+name:   Prometheus
+query:  prometheus
+object: storagegrid
+
+schedule:
+  - data: 3m
+
+counters:
+  - node_cpu_seconds_total
+  - storagegrid_ilm_awaiting_client_objects                   =>  ilm_awaiting_client_objects
+  - storagegrid_ilm_objects_processed                         =>  ilm_objects_processed
+  - storagegrid_network_received_bytes                        =>  network_received_bytes
+  - storagegrid_network_transmitted_bytes                     =>  network_transmitted_bytes
+  - storagegrid_private_ilm_awaiting_delete_objects           =>  private_ilm_awaiting_delete_objects
+  - storagegrid_private_load_balancer_storage_request_count   =>  private_load_balancer_storage_request_count
+  - storagegrid_private_load_balancer_storage_request_time    =>  private_load_balancer_storage_request_time
+  - storagegrid_private_s3_total_requests                     =>  private_s3_total_requests
+  - storagegrid_s3_operations_failed                          =>  s3_operations_failed
+  - storagegrid_s3_operations_successful                      =>  s3_operations_successful
+  - storagegrid_s3_operations_unauthorized                    =>  s3_operations_unauthorized
+  - storagegrid_storage_utilization_data_bytes                =>  storage_utilization_data_bytes
+  - storagegrid_storage_utilization_metadata_allowed_bytes    =>  storage_utilization_metadata_allowed_bytes
+  - storagegrid_storage_utilization_metadata_bytes            =>  storage_utilization_metadata_bytes
+  - storagegrid_storage_utilization_usable_space_bytes        =>  storage_utilization_usable_space_bytes
+  - storagegrid_node_cpu_utilization_percentage               =>  node_cpu_utilization_percentage
\ No newline at end of file
diff --git a/conf/storagegrid/default.yaml b/conf/storagegrid/default.yaml
index d86a3394..746fbf28 100644
--- a/conf/storagegrid/default.yaml
+++ b/conf/storagegrid/default.yaml
@@ -5,4 +5,5 @@ schedule:
   - data: 5m
 
 objects:
-  Tenant:          tenant.yaml
\ No newline at end of file
+  Tenant:          tenant.yaml
+  Prometheus:      storagegrid_metrics.yaml
\ No newline at end of file
diff --git a/grafana/dashboards/storagegrid/overview.json b/grafana/dashboards/storagegrid/overview.json
new file mode 100644
index 00000000..4268f7e0
--- /dev/null
+++ b/grafana/dashboards/storagegrid/overview.json
@@ -0,0 +1,1820 @@
+{
+  "__inputs": [
+    {
+      "name": "DS_PROMETHEUS",
+      "label": "Prometheus",
+      "description": "",
+      "type": "datasource",
+      "pluginId": "prometheus",
+      "pluginName": "Prometheus"
+    }
+  ],
+  "__requires": [
+    {
+      "type": "grafana",
+      "id": "grafana",
+      "name": "Grafana",
+      "version": "8.1.8"
+    },
+    {
+      "type": "datasource",
+      "id": "prometheus",
+      "name": "Prometheus",
+      "version": "1.0.0"
+    },
+    {
+      "type": "panel",
+      "id": "table",
+      "name": "Table",
+      "version": ""
+    },
+    {
+      "type": "panel",
+      "id": "timeseries",
+      "name": "Time series",
+      "version": ""
+    }
+  ],
+  "annotations": {
+    "list": [
+      {
+        "builtIn": 1,
+        "datasource": "-- Grafana --",
+        "enable": true,
+        "hide": true,
+        "iconColor": "rgba(0, 211, 255, 1)",
+        "name": "Annotations & Alerts",
+        "target": {
+          "limit": 100,
+          "matchAny": false,
+          "tags": [],
+          "type": "dashboard"
+        },
+        "type": "dashboard"
+      }
+    ]
+  },
+  "editable": true,
+  "gnetId": null,
+  "graphTooltip": 0,
+  "id": null,
+  "iteration": 1675087026731,
+  "links": [],
+  "panels": [
+    {
+      "collapsed": false,
+      "datasource": "${DS_PROMETHEUS}",
+      "gridPos": {
+        "h": 1,
+        "w": 24,
+        "x": 0,
+        "y": 0
+      },
+      "id": 6,
+      "panels": [],
+      "title": "Overview",
+      "type": "row"
+    },
+    {
+      "datasource": "${DS_PROMETHEUS}",
+      "description": "The percentage of the total usable space for object data that has been used for the site",
+      "fieldConfig": {
+        "defaults": {
+          "color": {
+            "mode": "thresholds"
+          },
+          "custom": {
+            "align": "auto",
+            "displayMode": "auto"
+          },
+          "mappings": [],
+          "thresholds": {
+            "mode": "absolute",
+            "steps": [
+              {
+                "color": "green",
+                "value": null
+              },
+              {
+                "color": "red",
+                "value": 80
+              }
+            ]
+          },
+          "unit": "decbytes"
+        },
+        "overrides": [
+          {
+            "matcher": {
+              "id": "byName",
+              "options": "Site"
+            },
+            "properties": [
+              {
+                "id": "custom.width",
+                "value": 118
+              }
+            ]
+          },
+          {
+            "matcher": {
+              "id": "byName",
+              "options": "Value #C"
+            },
+            "properties": [
+              {
+                "id": "unit",
+                "value": "percent"
+              },
+              {
+                "id": "decimals",
+                "value": 1
+              }
+            ]
+          }
+        ]
+      },
+      "gridPos": {
+        "h": 8,
+        "w": 12,
+        "x": 0,
+        "y": 1
+      },
+      "id": 37,
+      "options": {
+        "showHeader": true,
+        "sortBy": [
+          {
+            "desc": true,
+            "displayName": "Used space"
+          }
+        ]
+      },
+      "pluginVersion": "8.1.8",
+      "targets": [
+        {
+          "exemplar": true,
+          "expr": "sum by(site_name)(storagegrid_storage_utilization_data_bytes{datacenter=~\"$Datacenter\",cluster=~\"$Cluster\"})",
+          "format": "table",
+          "instant": true,
+          "interval": "",
+          "legendFormat": "",
+          "refId": "A"
+        },
+        {
+          "exemplar": true,
+          "expr": "sum by(site_name)(storagegrid_storage_utilization_usable_space_bytes{datacenter=~\"$Datacenter\",cluster=~\"$Cluster\"} + storagegrid_storage_utilization_data_bytes{datacenter=~\"$Datacenter\",cluster=~\"$Cluster\"})",
+          "format": "table",
+          "hide": false,
+          "instant": true,
+          "interval": "",
+          "legendFormat": "",
+          "refId": "B"
+        },
+        {
+          "exemplar": true,
+          "expr": "sum by(site_name)(storagegrid_storage_utilization_data_bytes{datacenter=~\"$Datacenter\",cluster=~\"$Cluster\"})/sum by(site_name)(storagegrid_storage_utilization_usable_space_bytes{datacenter=~\"$Datacenter\",cluster=~\"$Cluster\"} + storagegrid_storage_utilization_data_bytes{datacenter=~\"$Datacenter\",cluster=~\"$Cluster\"})",
+          "format": "table",
+          "hide": false,
+          "instant": true,
+          "interval": "",
+          "legendFormat": "",
+          "refId": "C"
+        }
+      ],
+      "title": "Data space usage breakdown",
+      "transformations": [
+        {
+          "id": "filterFieldsByName",
+          "options": {
+            "include": {
+              "names": [
+                "site_name",
+                "Value #A",
+                "Value #B",
+                "Value #C"
+              ]
+            }
+          }
+        },
+        {
+          "id": "merge",
+          "options": {}
+        },
+        {
+          "id": "organize",
+          "options": {
+            "excludeByName": {},
+            "indexByName": {
+              "Value #A": 2,
+              "Value #B": 3,
+              "Value #C": 1,
+              "site_name": 0
+            },
+            "renameByName": {
+              "Value": "Used space",
+              "Value #A": "Used space",
+              "Value #B": "Total space",
+              "Value #C": "Usage %",
+              "instance": "Node",
+              "service": "Service",
+              "site_name": "Site"
+            }
+          }
+        }
+      ],
+      "type": "table"
+    },
+    {
+      "datasource": "${DS_PROMETHEUS}",
+      "description": "The percentage of the total allowed space for object metadata that has been used for the site",
+      "fieldConfig": {
+        "defaults": {
+          "color": {
+            "mode": "thresholds"
+          },
+          "custom": {
+            "align": "auto",
+            "displayMode": "auto"
+          },
+          "mappings": [],
+          "thresholds": {
+            "mode": "absolute",
+            "steps": [
+              {
+                "color": "green",
+                "value": null
+              },
+              {
+                "color": "red",
+                "value": 80
+              }
+            ]
+          },
+          "unit": "decbytes"
+        },
+        "overrides": [
+          {
+            "matcher": {
+              "id": "byName",
+              "options": "Site"
+            },
+            "properties": [
+              {
+                "id": "custom.width",
+                "value": 118
+              }
+            ]
+          },
+          {
+            "matcher": {
+              "id": "byName",
+              "options": "Value #C"
+            },
+            "properties": [
+              {
+                "id": "unit",
+                "value": "percent"
+              },
+              {
+                "id": "decimals",
+                "value": 1
+              }
+            ]
+          }
+        ]
+      },
+      "gridPos": {
+        "h": 8,
+        "w": 12,
+        "x": 12,
+        "y": 1
+      },
+      "id": 38,
+      "options": {
+        "showHeader": true,
+        "sortBy": [
+          {
+            "desc": true,
+            "displayName": "Used space"
+          }
+        ]
+      },
+      "pluginVersion": "8.1.8",
+      "targets": [
+        {
+          "exemplar": true,
+          "expr": "sum by(site_name)(storagegrid_storage_utilization_metadata_bytes{datacenter=~\"$Datacenter\",cluster=~\"$Cluster\"})",
+          "format": "table",
+          "instant": true,
+          "interval": "",
+          "legendFormat": "",
+          "refId": "A"
+        },
+        {
+          "exemplar": true,
+          "expr": "sum by(site_name)(storagegrid_storage_utilization_metadata_allowed_bytes{datacenter=~\"$Datacenter\",cluster=~\"$Cluster\"})",
+          "format": "table",
+          "hide": false,
+          "instant": true,
+          "interval": "",
+          "legendFormat": "",
+          "refId": "B"
+        },
+        {
+          "exemplar": true,
+          "expr": "sum by(site_name)(storagegrid_storage_utilization_metadata_bytes{datacenter=~\"$Datacenter\",cluster=~\"$Cluster\"})/sum by(site_name)(storagegrid_storage_utilization_metadata_allowed_bytes{datacenter=~\"$Datacenter\",cluster=~\"$Cluster\"})",
+          "format": "table",
+          "hide": false,
+          "instant": true,
+          "interval": "",
+          "legendFormat": "",
+          "refId": "C"
+        }
+      ],
+      "title": "Metadata allowed space usage breakdown",
+      "transformations": [
+        {
+          "id": "filterFieldsByName",
+          "options": {
+            "include": {
+              "names": [
+                "site_name",
+                "Value #A",
+                "Value #B",
+                "Value #C"
+              ]
+            }
+          }
+        },
+        {
+          "id": "merge",
+          "options": {}
+        },
+        {
+          "id": "organize",
+          "options": {
+            "excludeByName": {},
+            "indexByName": {
+              "Value #A": 2,
+              "Value #B": 3,
+              "Value #C": 1,
+              "site_name": 0
+            },
+            "renameByName": {
+              "Value": "Used space",
+              "Value #A": "Used space",
+              "Value #B": "Allowed space",
+              "Value #C": "Usage %",
+              "instance": "Node",
+              "service": "Service",
+              "site_name": "Site"
+            }
+          }
+        }
+      ],
+      "type": "table"
+    },
+    {
+      "datasource": "${DS_PROMETHEUS}",
+      "description": "The amount of space used for user data during the selected time frame.",
+      "fieldConfig": {
+        "defaults": {
+          "color": {
+            "mode": "palette-classic"
+          },
+          "custom": {
+            "axisLabel": "",
+            "axisPlacement": "auto",
+            "barAlignment": 0,
+            "drawStyle": "line",
+            "fillOpacity": 0,
+            "gradientMode": "none",
+            "hideFrom": {
+              "legend": false,
+              "tooltip": false,
+              "viz": false
+            },
+            "lineInterpolation": "linear",
+            "lineWidth": 1,
+            "pointSize": 5,
+            "scaleDistribution": {
+              "type": "linear"
+            },
+            "showPoints": "auto",
+            "spanNulls": true,
+            "stacking": {
+              "group": "A",
+              "mode": "none"
+            },
+            "thresholdsStyle": {
+              "mode": "off"
+            }
+          },
+          "mappings": [],
+          "thresholds": {
+            "mode": "absolute",
+            "steps": [
+              {
+                "color": "green",
+                "value": null
+              },
+              {
+                "color": "red",
+                "value": 80
+              }
+            ]
+          },
+          "unit": "decbytes"
+        },
+        "overrides": []
+      },
+      "gridPos": {
+        "h": 11,
+        "w": 24,
+        "x": 0,
+        "y": 9
+      },
+      "id": 40,
+      "options": {
+        "legend": {
+          "calcs": [
+            "mean",
+            "lastNotNull",
+            "max"
+          ],
+          "displayMode": "table",
+          "placement": "bottom"
+        },
+        "tooltip": {
+          "mode": "single"
+        }
+      },
+      "targets": [
+        {
+          "exemplar": true,
+          "expr": "sum(storagegrid_storage_utilization_data_bytes{datacenter=~\"$Datacenter\",cluster=~\"$Cluster\"})",
+          "interval": "",
+          "legendFormat": "Spaced used",
+          "refId": "A"
+        }
+      ],
+      "title": "Data storage over time",
+      "type": "timeseries"
+    },
+    {
+      "collapsed": true,
+      "datasource": "${DS_PROMETHEUS}",
+      "gridPos": {
+        "h": 1,
+        "w": 24,
+        "x": 0,
+        "y": 20
+      },
+      "id": 4,
+      "panels": [
+        {
+          "datasource": "${DS_PROMETHEUS}",
+          "description": "The number of S3-specific operations performed. You can use this information to monitor your system's workloads and efficiencies.",
+          "fieldConfig": {
+            "defaults": {
+              "color": {
+                "mode": "palette-classic"
+              },
+              "custom": {
+                "axisLabel": "",
+                "axisPlacement": "auto",
+                "barAlignment": 0,
+                "drawStyle": "line",
+                "fillOpacity": 0,
+                "gradientMode": "none",
+                "hideFrom": {
+                  "legend": false,
+                  "tooltip": false,
+                  "viz": false
+                },
+                "lineInterpolation": "linear",
+                "lineWidth": 1,
+                "pointSize": 5,
+                "scaleDistribution": {
+                  "type": "linear"
+                },
+                "showPoints": "auto",
+                "spanNulls": true,
+                "stacking": {
+                  "group": "A",
+                  "mode": "none"
+                },
+                "thresholdsStyle": {
+                  "mode": "off"
+                }
+              },
+              "mappings": [],
+              "thresholds": {
+                "mode": "absolute",
+                "steps": [
+                  {
+                    "color": "green",
+                    "value": null
+                  },
+                  {
+                    "color": "red",
+                    "value": 80
+                  }
+                ]
+              },
+              "unit": "locale"
+            },
+            "overrides": []
+          },
+          "gridPos": {
+            "h": 9,
+            "w": 12,
+            "x": 0,
+            "y": 21
+          },
+          "id": 24,
+          "options": {
+            "legend": {
+              "calcs": [
+                "mean",
+                "lastNotNull",
+                "max"
+              ],
+              "displayMode": "table",
+              "placement": "bottom"
+            },
+            "tooltip": {
+              "mode": "single"
+            }
+          },
+          "targets": [
+            {
+              "exemplar": true,
+              "expr": "sum (increase(storagegrid_private_s3_total_requests{datacenter=~\"$Datacenter\",cluster=~\"$Cluster\",type=~\"put_.*\"}[2m]))",
+              "interval": "",
+              "legendFormat": "PUT",
+              "refId": "A"
+            },
+            {
+              "exemplar": true,
+              "expr": "sum (increase(storagegrid_private_s3_total_requests{datacenter=~\"$Datacenter\",cluster=~\"$Cluster\",type=~\"get_.*\"}[2m]))",
+              "hide": false,
+              "interval": "",
+              "legendFormat": "GET",
+              "refId": "B"
+            },
+            {
+              "exemplar": true,
+              "expr": "sum (increase(storagegrid_private_s3_total_requests{datacenter=~\"$Datacenter\",cluster=~\"$Cluster\",type=~\"delete_.*\"}[2m]))",
+              "hide": false,
+              "instant": false,
+              "interval": "",
+              "legendFormat": "DELETE",
+              "refId": "C"
+            },
+            {
+              "exemplar": true,
+              "expr": "sum (increase(storagegrid_private_s3_total_requests{datacenter=~\"$Datacenter\",cluster=~\"$Cluster\",type=~\"head_.*\"}[2m]))",
+              "hide": false,
+              "instant": false,
+              "interval": "",
+              "legendFormat": "HEAD",
+              "refId": "D"
+            },
+            {
+              "exemplar": true,
+              "expr": "sum (increase(storagegrid_private_s3_total_requests{datacenter=~\"$Datacenter\",cluster=~\"$Cluster\",type=~\"post_.*\"}[2m]))",
+              "hide": false,
+              "instant": false,
+              "interval": "",
+              "legendFormat": "POST",
+              "refId": "E"
+            }
+          ],
+          "title": "S3 operations",
+          "type": "timeseries"
+        },
+        {
+          "datasource": "${DS_PROMETHEUS}",
+          "description": "**Received**: The rate at which data is being received.\n\n**Transmitted**: The rate at which data is being sent.\n\nFor troubleshooting, these values can help establish a general baseline for network performance.",
+          "fieldConfig": {
+            "defaults": {
+              "color": {
+                "mode": "palette-classic"
+              },
+              "custom": {
+                "axisLabel": "",
+                "axisPlacement": "auto",
+                "barAlignment": 0,
+                "drawStyle": "line",
+                "fillOpacity": 0,
+                "gradientMode": "none",
+                "hideFrom": {
+                  "legend": false,
+                  "tooltip": false,
+                  "viz": false
+                },
+                "lineInterpolation": "linear",
+                "lineWidth": 1,
+                "pointSize": 5,
+                "scaleDistribution": {
+                  "type": "linear"
+                },
+                "showPoints": "auto",
+                "spanNulls": true,
+                "stacking": {
+                  "group": "A",
+                  "mode": "none"
+                },
+                "thresholdsStyle": {
+                  "mode": "off"
+                }
+              },
+              "mappings": [],
+              "thresholds": {
+                "mode": "absolute",
+                "steps": [
+                  {
+                    "color": "green",
+                    "value": null
+                  },
+                  {
+                    "color": "red",
+                    "value": 80
+                  }
+                ]
+              },
+              "unit": "Bps"
+            },
+            "overrides": []
+          },
+          "gridPos": {
+            "h": 9,
+            "w": 12,
+            "x": 12,
+            "y": 21
+          },
+          "id": 26,
+          "options": {
+            "legend": {
+              "calcs": [
+                "mean",
+                "lastNotNull",
+                "max"
+              ],
+              "displayMode": "table",
+              "placement": "bottom"
+            },
+            "tooltip": {
+              "mode": "single"
+            }
+          },
+          "targets": [
+            {
+              "exemplar": true,
+              "expr": "sum(rate(storagegrid_network_received_bytes{datacenter=~\"$Datacenter\",cluster=~\"$Cluster\"}[5m]))",
+              "interval": "",
+              "legendFormat": "Received",
+              "refId": "A"
+            },
+            {
+              "exemplar": true,
+              "expr": "sum(rate(storagegrid_network_transmitted_bytes{datacenter=~\"$Datacenter\",cluster=~\"$Cluster\"}[5m]))",
+              "hide": false,
+              "interval": "",
+              "legendFormat": "Transmitted",
+              "refId": "B"
+            }
+          ],
+          "title": "Network traffic",
+          "type": "timeseries"
+        },
+        {
+          "datasource": "${DS_PROMETHEUS}",
+          "description": "The number of S3 API requests received during the selected time frame.",
+          "fieldConfig": {
+            "defaults": {
+              "color": {
+                "mode": "palette-classic"
+              },
+              "custom": {
+                "axisLabel": "",
+                "axisPlacement": "auto",
+                "barAlignment": 0,
+                "drawStyle": "line",
+                "fillOpacity": 0,
+                "gradientMode": "none",
+                "hideFrom": {
+                  "legend": false,
+                  "tooltip": false,
+                  "viz": false
+                },
+                "lineInterpolation": "linear",
+                "lineWidth": 1,
+                "pointSize": 5,
+                "scaleDistribution": {
+                  "type": "linear"
+                },
+                "showPoints": "auto",
+                "spanNulls": true,
+                "stacking": {
+                  "group": "A",
+                  "mode": "none"
+                },
+                "thresholdsStyle": {
+                  "mode": "off"
+                }
+              },
+              "mappings": [],
+              "thresholds": {
+                "mode": "absolute",
+                "steps": [
+                  {
+                    "color": "green",
+                    "value": null
+                  },
+                  {
+                    "color": "red",
+                    "value": 80
+                  }
+                ]
+              },
+              "unit": "locale"
+            },
+            "overrides": []
+          },
+          "gridPos": {
+            "h": 9,
+            "w": 12,
+            "x": 0,
+            "y": 30
+          },
+          "id": 28,
+          "options": {
+            "legend": {
+              "calcs": [
+                "mean",
+                "lastNotNull",
+                "max"
+              ],
+              "displayMode": "table",
+              "placement": "bottom"
+            },
+            "tooltip": {
+              "mode": "single"
+            }
+          },
+          "targets": [
+            {
+              "exemplar": true,
+              "expr": "sum(storagegrid_s3_operations_successful{datacenter=~\"$Datacenter\",cluster=~\"$Cluster\"})",
+              "interval": "",
+              "legendFormat": "Successful",
+              "refId": "A"
+            },
+            {
+              "exemplar": true,
+              "expr": "sum(storagegrid_s3_operations_failed{datacenter=~\"$Datacenter\",cluster=~\"$Cluster\"})",
+              "hide": false,
+              "instant": false,
+              "interval": "",
+              "legendFormat": "Failed",
+              "refId": "B"
+            },
+            {
+              "exemplar": true,
+              "expr": "sum(storagegrid_s3_operations_unauthorized{datacenter=~\"$Datacenter\",cluster=~\"$Cluster\"})",
+              "hide": false,
+              "instant": false,
+              "interval": "",
+              "legendFormat": "Unauthorized",
+              "refId": "C"
+            }
+          ],
+          "title": "S3 API requests",
+          "type": "timeseries"
+        },
+        {
+          "datasource": "${DS_PROMETHEUS}",
+          "description": "- Bad request: 400\n- Forbidden: 403\n- Not found: 404\n\nYou can use these metrics to ensure platform services are working. Unexpected values might mean a platform service is incorrectly configured, or they might indicate an external problem such as a network issue. ",
+          "fieldConfig": {
+            "defaults": {
+              "color": {
+                "mode": "palette-classic"
+              },
+              "custom": {
+                "axisLabel": "",
+                "axisPlacement": "auto",
+                "barAlignment": 0,
+                "drawStyle": "line",
+                "fillOpacity": 0,
+                "gradientMode": "none",
+                "hideFrom": {
+                  "legend": false,
+                  "tooltip": false,
+                  "viz": false
+                },
+                "lineInterpolation": "linear",
+                "lineWidth": 1,
+                "pointSize": 5,
+                "scaleDistribution": {
+                  "type": "linear"
+                },
+                "showPoints": "auto",
+                "spanNulls": true,
+                "stacking": {
+                  "group": "A",
+                  "mode": "none"
+                },
+                "thresholdsStyle": {
+                  "mode": "off"
+                }
+              },
+              "mappings": [],
+              "thresholds": {
+                "mode": "absolute",
+                "steps": [
+                  {
+                    "color": "green",
+                    "value": null
+                  },
+                  {
+                    "color": "red",
+                    "value": 80
+                  }
+                ]
+              },
+              "unit": "locale"
+            },
+            "overrides": []
+          },
+          "gridPos": {
+            "h": 9,
+            "w": 12,
+            "x": 12,
+            "y": 30
+          },
+          "id": 30,
+          "options": {
+            "legend": {
+              "calcs": [
+                "mean",
+                "lastNotNull",
+                "max"
+              ],
+              "displayMode": "table",
+              "placement": "bottom"
+            },
+            "tooltip": {
+              "mode": "single"
+            }
+          },
+          "targets": [
+            {
+              "exemplar": true,
+              "expr": "sum (rate(storagegrid_private_load_balancer_storage_request_count{datacenter=~\"$Datacenter\",cluster=~\"$Cluster\",code=\"400\"}[3m]))",
+              "interval": "",
+              "legendFormat": "Bad request (400)",
+              "refId": "A"
+            },
+            {
+              "exemplar": true,
+              "expr": "sum (rate(storagegrid_private_load_balancer_storage_request_count{datacenter=~\"$Datacenter\",cluster=~\"$Cluster\",code=\"403\"}[3m]))",
+              "hide": false,
+              "instant": false,
+              "interval": "",
+              "legendFormat": "Forbidden (403)",
+              "refId": "B"
+            },
+            {
+              "exemplar": true,
+              "expr": "sum (rate(storagegrid_private_load_balancer_storage_request_count{datacenter=~\"$Datacenter\",cluster=~\"$Cluster\",code=\"404\"}[3m]))",
+              "hide": false,
+              "instant": false,
+              "interval": "",
+              "legendFormat": "Not found (404)",
+              "refId": "C"
+            }
+          ],
+          "title": "Error rate (requests/second)",
+          "type": "timeseries"
+        },
+        {
+          "datasource": "${DS_PROMETHEUS}",
+          "description": "Provides a 3-minute moving average of request durations, broken down by request type (GET, PUT, and DELETE). Each request duration starts when a request header is parsed by the Load Balancer service and ends when the complete response body is returned to the client.",
+          "fieldConfig": {
+            "defaults": {
+              "color": {
+                "mode": "palette-classic"
+              },
+              "custom": {
+                "axisLabel": "",
+                "axisPlacement": "auto",
+                "barAlignment": 0,
+                "drawStyle": "line",
+                "fillOpacity": 0,
+                "gradientMode": "none",
+                "hideFrom": {
+                  "legend": false,
+                  "tooltip": false,
+                  "viz": false
+                },
+                "lineInterpolation": "linear",
+                "lineWidth": 1,
+                "pointSize": 5,
+                "scaleDistribution": {
+                  "type": "linear"
+                },
+                "showPoints": "auto",
+                "spanNulls": true,
+                "stacking": {
+                  "group": "A",
+                  "mode": "none"
+                },
+                "thresholdsStyle": {
+                  "mode": "off"
+                }
+              },
+              "mappings": [],
+              "thresholds": {
+                "mode": "absolute",
+                "steps": [
+                  {
+                    "color": "green",
+                    "value": null
+                  },
+                  {
+                    "color": "red",
+                    "value": 80
+                  }
+                ]
+              },
+              "unit": "locale"
+            },
+            "overrides": []
+          },
+          "gridPos": {
+            "h": 9,
+            "w": 24,
+            "x": 0,
+            "y": 39
+          },
+          "id": 32,
+          "options": {
+            "legend": {
+              "calcs": [
+                "mean",
+                "lastNotNull",
+                "max"
+              ],
+              "displayMode": "table",
+              "placement": "bottom"
+            },
+            "tooltip": {
+              "mode": "single"
+            }
+          },
+          "targets": [
+            {
+              "exemplar": true,
+              "expr": "(sum (rate(storagegrid_private_load_balancer_storage_request_time{datacenter=~\"$Datacenter\",cluster=~\"$Cluster\",method=\"DELETE\"}[3m]))) /(sum (rate(storagegrid_private_load_balancer_storage_request_count{datacenter=~\"$Datacenter\",cluster=~\"$Cluster\",method=\"DELETE\"}[3m])))",
+              "interval": "",
+              "legendFormat": "DELETE",
+              "refId": "A"
+            },
+            {
+              "exemplar": true,
+              "expr": "(sum (rate(storagegrid_private_load_balancer_storage_request_time{datacenter=~\"$Datacenter\",cluster=~\"$Cluster\",method=\"GET\"}[3m]))) /(sum (rate(storagegrid_private_load_balancer_storage_request_count{datacenter=~\"$Datacenter\",cluster=~\"$Cluster\",method=\"GET\"}[3m])))",
+              "hide": false,
+              "interval": "",
+              "legendFormat": "GET",
+              "refId": "B"
+            },
+            {
+              "exemplar": true,
+              "expr": "(sum (rate(storagegrid_private_load_balancer_storage_request_time{datacenter=~\"$Datacenter\",cluster=~\"$Cluster\",method=\"PUT\"}[3m]))) /(sum (rate(storagegrid_private_load_balancer_storage_request_count{datacenter=~\"$Datacenter\",cluster=~\"$Cluster\",method=\"PUT\"}[3m])))",
+              "hide": false,
+              "interval": "",
+              "legendFormat": "PUT",
+              "refId": "C"
+            }
+          ],
+          "title": "Average request duration (non-error)",
+          "type": "timeseries"
+        }
+      ],
+      "title": "Performance",
+      "type": "row"
+    },
+    {
+      "collapsed": true,
+      "datasource": "${DS_PROMETHEUS}",
+      "gridPos": {
+        "h": 1,
+        "w": 24,
+        "x": 0,
+        "y": 21
+      },
+      "id": 2,
+      "panels": [
+        {
+          "datasource": "${DS_PROMETHEUS}",
+          "description": "",
+          "fieldConfig": {
+            "defaults": {
+              "color": {
+                "mode": "palette-classic"
+              },
+              "custom": {
+                "axisLabel": "",
+                "axisPlacement": "auto",
+                "barAlignment": 0,
+                "drawStyle": "line",
+                "fillOpacity": 0,
+                "gradientMode": "none",
+                "hideFrom": {
+                  "legend": false,
+                  "tooltip": false,
+                  "viz": false
+                },
+                "lineInterpolation": "linear",
+                "lineWidth": 1,
+                "pointSize": 5,
+                "scaleDistribution": {
+                  "type": "linear"
+                },
+                "showPoints": "auto",
+                "spanNulls": true,
+                "stacking": {
+                  "group": "A",
+                  "mode": "none"
+                },
+                "thresholdsStyle": {
+                  "mode": "off"
+                }
+              },
+              "mappings": [],
+              "thresholds": {
+                "mode": "absolute",
+                "steps": [
+                  {
+                    "color": "green",
+                    "value": null
+                  },
+                  {
+                    "color": "red",
+                    "value": 80
+                  }
+                ]
+              },
+              "unit": "decbytes"
+            },
+            "overrides": []
+          },
+          "gridPos": {
+            "h": 10,
+            "w": 12,
+            "x": 0,
+            "y": 22
+          },
+          "id": 12,
+          "options": {
+            "legend": {
+              "calcs": [
+                "mean",
+                "lastNotNull",
+                "max"
+              ],
+              "displayMode": "table",
+              "placement": "bottom"
+            },
+            "tooltip": {
+              "mode": "single"
+            }
+          },
+          "targets": [
+            {
+              "exemplar": true,
+              "expr": "topk($TopResources, avg by(tenant)(storagegrid_tenant_usage_data_bytes{datacenter=~\"$Datacenter\",cluster=~\"$Cluster\",tenant=~\"$TopTenantUsageBytes\"}))",
+              "format": "time_series",
+              "hide": false,
+              "interval": "",
+              "legendFormat": "{{tenant}}",
+              "refId": "A"
+            }
+          ],
+          "title": "Top $TopResources tenants by logical space used",
+          "type": "timeseries"
+        },
+        {
+          "datasource": "${DS_PROMETHEUS}",
+          "fieldConfig": {
+            "defaults": {
+              "color": {
+                "mode": "palette-classic"
+              },
+              "custom": {
+                "axisLabel": "",
+                "axisPlacement": "auto",
+                "barAlignment": 0,
+                "drawStyle": "line",
+                "fillOpacity": 0,
+                "gradientMode": "none",
+                "hideFrom": {
+                  "legend": false,
+                  "tooltip": false,
+                  "viz": false
+                },
+                "lineInterpolation": "linear",
+                "lineWidth": 1,
+                "pointSize": 5,
+                "scaleDistribution": {
+                  "type": "linear"
+                },
+                "showPoints": "auto",
+                "spanNulls": true,
+                "stacking": {
+                  "group": "A",
+                  "mode": "none"
+                },
+                "thresholdsStyle": {
+                  "mode": "off"
+                }
+              },
+              "mappings": [],
+              "thresholds": {
+                "mode": "absolute",
+                "steps": [
+                  {
+                    "color": "green",
+                    "value": null
+                  },
+                  {
+                    "color": "red",
+                    "value": 80
+                  }
+                ]
+              },
+              "unit": "decbytes"
+            },
+            "overrides": []
+          },
+          "gridPos": {
+            "h": 10,
+            "w": 12,
+            "x": 12,
+            "y": 22
+          },
+          "id": 14,
+          "options": {
+            "legend": {
+              "calcs": [
+                "mean",
+                "lastNotNull",
+                "max"
+              ],
+              "displayMode": "table",
+              "placement": "bottom"
+            },
+            "tooltip": {
+              "mode": "single"
+            }
+          },
+          "targets": [
+            {
+              "exemplar": true,
+              "expr": "topk($TopResources, avg by(tenant)(storagegrid_tenant_usage_data_bytes{datacenter=~\"$Datacenter\",cluster=~\"$Cluster\",tenant=~\"$TopTenantUsageBytes\"}/storagegrid_tenant_usage_quota_bytes{datacenter=~\"$Datacenter\",cluster=~\"$Cluster\",tenant=~\"$TopTenantUsageBytes\"}))",
+              "format": "time_series",
+              "interval": "",
+              "legendFormat": "{{tenant}}",
+              "refId": "A"
+            }
+          ],
+          "title": "Top $TopResources tenants by quota usage",
+          "type": "timeseries"
+        }
+      ],
+      "title": "Storage",
+      "type": "row"
+    },
+    {
+      "collapsed": true,
+      "datasource": "${DS_PROMETHEUS}",
+      "gridPos": {
+        "h": 1,
+        "w": 24,
+        "x": 0,
+        "y": 22
+      },
+      "id": 8,
+      "panels": [
+        {
+          "datasource": "${DS_PROMETHEUS}",
+          "description": "",
+          "fieldConfig": {
+            "defaults": {
+              "color": {
+                "mode": "palette-classic"
+              },
+              "custom": {
+                "axisLabel": "",
+                "axisPlacement": "auto",
+                "barAlignment": 0,
+                "drawStyle": "line",
+                "fillOpacity": 0,
+                "gradientMode": "none",
+                "hideFrom": {
+                  "legend": false,
+                  "tooltip": false,
+                  "viz": false
+                },
+                "lineInterpolation": "linear",
+                "lineWidth": 1,
+                "pointSize": 5,
+                "scaleDistribution": {
+                  "type": "linear"
+                },
+                "showPoints": "auto",
+                "spanNulls": true,
+                "stacking": {
+                  "group": "A",
+                  "mode": "none"
+                },
+                "thresholdsStyle": {
+                  "mode": "off"
+                }
+              },
+              "mappings": [],
+              "thresholds": {
+                "mode": "absolute",
+                "steps": [
+                  {
+                    "color": "green",
+                    "value": null
+                  },
+                  {
+                    "color": "red",
+                    "value": 80
+                  }
+                ]
+              },
+              "unit": "short"
+            },
+            "overrides": []
+          },
+          "gridPos": {
+            "h": 10,
+            "w": 12,
+            "x": 0,
+            "y": 23
+          },
+          "id": 16,
+          "options": {
+            "legend": {
+              "calcs": [
+                "mean",
+                "lastNotNull",
+                "max"
+              ],
+              "displayMode": "table",
+              "placement": "bottom"
+            },
+            "tooltip": {
+              "mode": "single"
+            }
+          },
+          "targets": [
+            {
+              "exemplar": true,
+              "expr": "sum(storagegrid_ilm_awaiting_client_objects{datacenter=~\"$Datacenter\",cluster=~\"$Cluster\"})",
+              "format": "time_series",
+              "interval": "",
+              "legendFormat": "To be scanned",
+              "refId": "A"
+            },
+            {
+              "exemplar": true,
+              "expr": "sum(storagegrid_private_ilm_awaiting_delete_objects{datacenter=~\"$Datacenter\",cluster=~\"$Cluster\"})",
+              "hide": false,
+              "interval": "",
+              "legendFormat": "To be deleted",
+              "refId": "B"
+            }
+          ],
+          "title": "ILM queue (Objects)",
+          "type": "timeseries"
+        },
+        {
+          "datasource": "${DS_PROMETHEUS}",
+          "description": "",
+          "fieldConfig": {
+            "defaults": {
+              "color": {
+                "mode": "palette-classic"
+              },
+              "custom": {
+                "axisLabel": "",
+                "axisPlacement": "auto",
+                "barAlignment": 0,
+                "drawStyle": "line",
+                "fillOpacity": 0,
+                "gradientMode": "none",
+                "hideFrom": {
+                  "legend": false,
+                  "tooltip": false,
+                  "viz": false
+                },
+                "lineInterpolation": "linear",
+                "lineWidth": 1,
+                "pointSize": 5,
+                "scaleDistribution": {
+                  "type": "linear"
+                },
+                "showPoints": "auto",
+                "spanNulls": true,
+                "stacking": {
+                  "group": "A",
+                  "mode": "none"
+                },
+                "thresholdsStyle": {
+                  "mode": "off"
+                }
+              },
+              "decimals": 1,
+              "mappings": [],
+              "thresholds": {
+                "mode": "absolute",
+                "steps": [
+                  {
+                    "color": "green",
+                    "value": null
+                  },
+                  {
+                    "color": "red",
+                    "value": 80
+                  }
+                ]
+              },
+              "unit": "objects/sec"
+            },
+            "overrides": []
+          },
+          "gridPos": {
+            "h": 10,
+            "w": 12,
+            "x": 12,
+            "y": 23
+          },
+          "id": 18,
+          "options": {
+            "legend": {
+              "calcs": [
+                "mean",
+                "lastNotNull",
+                "max"
+              ],
+              "displayMode": "table",
+              "placement": "bottom"
+            },
+            "tooltip": {
+              "mode": "single"
+            }
+          },
+          "targets": [
+            {
+              "exemplar": true,
+              "expr": "sum(rate(storagegrid_ilm_objects_processed{datacenter=~\"$Datacenter\",cluster=~\"$Cluster\"}[60m]))",
+              "format": "time_series",
+              "interval": "",
+              "legendFormat": "Scans",
+              "refId": "A"
+            }
+          ],
+          "title": "ILM evaluation rate (objects/second)",
+          "type": "timeseries"
+        }
+      ],
+      "title": "Information Lifecycle Management (ILM)",
+      "type": "row"
+    },
+    {
+      "collapsed": true,
+      "datasource": "${DS_PROMETHEUS}",
+      "gridPos": {
+        "h": 1,
+        "w": 24,
+        "x": 0,
+        "y": 23
+      },
+      "id": 10,
+      "panels": [
+        {
+          "datasource": "${DS_PROMETHEUS}",
+          "description": "",
+          "fieldConfig": {
+            "defaults": {
+              "color": {
+                "mode": "palette-classic"
+              },
+              "custom": {
+                "axisLabel": "",
+                "axisPlacement": "auto",
+                "barAlignment": 0,
+                "drawStyle": "line",
+                "fillOpacity": 0,
+                "gradientMode": "none",
+                "hideFrom": {
+                  "legend": false,
+                  "tooltip": false,
+                  "viz": false
+                },
+                "lineInterpolation": "linear",
+                "lineWidth": 1,
+                "pointSize": 5,
+                "scaleDistribution": {
+                  "type": "linear"
+                },
+                "showPoints": "auto",
+                "spanNulls": true,
+                "stacking": {
+                  "group": "A",
+                  "mode": "none"
+                },
+                "thresholdsStyle": {
+                  "mode": "off"
+                }
+              },
+              "mappings": [],
+              "thresholds": {
+                "mode": "absolute",
+                "steps": [
+                  {
+                    "color": "green",
+                    "value": null
+                  },
+                  {
+                    "color": "red",
+                    "value": 80
+                  }
+                ]
+              },
+              "unit": "percent"
+            },
+            "overrides": []
+          },
+          "gridPos": {
+            "h": 10,
+            "w": 12,
+            "x": 0,
+            "y": 24
+          },
+          "id": 20,
+          "options": {
+            "legend": {
+              "calcs": [
+                "mean",
+                "lastNotNull",
+                "max"
+              ],
+              "displayMode": "table",
+              "placement": "bottom"
+            },
+            "tooltip": {
+              "mode": "single"
+            }
+          },
+          "targets": [
+            {
+              "exemplar": true,
+              "expr": "topk($TopResources,(storagegrid_storage_utilization_data_bytes{datacenter=~\"$Datacenter\",cluster=~\"$Cluster\",node=~\"$TopNodesByDataUsage\"} / (storagegrid_storage_utilization_usable_space_bytes{datacenter=~\"$Datacenter\",cluster=~\"$Cluster\",node=~\"$TopNodesByDataUsage\"} + storagegrid_storage_utilization_data_bytes{datacenter=~\"$Datacenter\",cluster=~\"$Cluster\",node=~\"$TopNodesByDataUsage\"}) * 100))",
+              "format": "time_series",
+              "hide": false,
+              "interval": "",
+              "legendFormat": "{{node}}",
+              "refId": "A"
+            }
+          ],
+          "title": "Top $TopResources nodes by data usage",
+          "type": "timeseries"
+        },
+        {
+          "datasource": "${DS_PROMETHEUS}",
+          "description": "",
+          "fieldConfig": {
+            "defaults": {
+              "color": {
+                "mode": "palette-classic"
+              },
+              "custom": {
+                "axisLabel": "",
+                "axisPlacement": "auto",
+                "barAlignment": 0,
+                "drawStyle": "line",
+                "fillOpacity": 0,
+                "gradientMode": "none",
+                "hideFrom": {
+                  "legend": false,
+                  "tooltip": false,
+                  "viz": false
+                },
+                "lineInterpolation": "linear",
+                "lineWidth": 1,
+                "pointSize": 5,
+                "scaleDistribution": {
+                  "type": "linear"
+                },
+                "showPoints": "auto",
+                "spanNulls": true,
+                "stacking": {
+                  "group": "A",
+                  "mode": "none"
+                },
+                "thresholdsStyle": {
+                  "mode": "off"
+                }
+              },
+              "decimals": 1,
+              "mappings": [],
+              "thresholds": {
+                "mode": "absolute",
+                "steps": [
+                  {
+                    "color": "green",
+                    "value": null
+                  },
+                  {
+                    "color": "red",
+                    "value": 80
+                  }
+                ]
+              },
+              "unit": "percent"
+            },
+            "overrides": []
+          },
+          "gridPos": {
+            "h": 10,
+            "w": 12,
+            "x": 12,
+            "y": 24
+          },
+          "id": 22,
+          "options": {
+            "legend": {
+              "calcs": [
+                "mean",
+                "lastNotNull",
+                "max"
+              ],
+              "displayMode": "table",
+              "placement": "bottom"
+            },
+            "tooltip": {
+              "mode": "single"
+            }
+          },
+          "targets": [
+            {
+              "exemplar": true,
+              "expr": "topk($TopResources,storagegrid_node_cpu_utilization_percentage{datacenter=~\"$Datacenter\",cluster=~\"$Cluster\",node=~\"$TopNodeByCPU\"})\n",
+              "format": "time_series",
+              "interval": "",
+              "legendFormat": "{{node}}",
+              "refId": "A"
+            }
+          ],
+          "title": "Top $TopResources nodes by CPU usage",
+          "type": "timeseries"
+        }
+      ],
+      "title": "Nodes",
+      "type": "row"
+    }
+  ],
+  "schemaVersion": 30,
+  "style": "dark",
+  "tags": [
+    "harvest",
+    "storagegrid"
+  ],
+  "templating": {
+    "list": [
+      {
+        "allValue": null,
+        "current": {},
+        "datasource": "${DS_PROMETHEUS}",
+        "definition": "label_values(storagegrid_storage_utilization_data_bytes, datacenter)",
+        "description": null,
+        "error": null,
+        "hide": 0,
+        "includeAll": false,
+        "label": null,
+        "multi": true,
+        "name": "Datacenter",
+        "options": [],
+        "query": {
+          "query": "label_values(storagegrid_storage_utilization_data_bytes, datacenter)",
+          "refId": "StandardVariableQuery"
+        },
+        "refresh": 1,
+        "regex": "",
+        "skipUrlSync": false,
+        "sort": 1,
+        "type": "query"
+      },
+      {
+        "allValue": null,
+        "current": {},
+        "datasource": "${DS_PROMETHEUS}",
+        "definition": "label_values(storagegrid_storage_utilization_data_bytes{datacenter=~\"$Datacenter\"},cluster)",
+        "description": null,
+        "error": null,
+        "hide": 0,
+        "includeAll": false,
+        "label": null,
+        "multi": true,
+        "name": "Cluster",
+        "options": [],
+        "query": {
+          "query": "label_values(storagegrid_storage_utilization_data_bytes{datacenter=~\"$Datacenter\"},cluster)",
+          "refId": "StandardVariableQuery"
+        },
+        "refresh": 1,
+        "regex": "",
+        "skipUrlSync": false,
+        "sort": 1,
+        "type": "query"
+      },
+      {
+        "allValue": null,
+        "current": {
+          "selected": true,
+          "text": "5",
+          "value": "5"
+        },
+        "description": null,
+        "error": null,
+        "hide": 0,
+        "includeAll": false,
+        "label": null,
+        "multi": false,
+        "name": "TopResources",
+        "options": [
+          {
+            "selected": false,
+            "text": "1",
+            "value": "1"
+          },
+          {
+            "selected": false,
+            "text": "2",
+            "value": "2"
+          },
+          {
+            "selected": false,
+            "text": "3",
+            "value": "3"
+          },
+          {
+            "selected": false,
+            "text": "4",
+            "value": "4"
+          },
+          {
+            "selected": true,
+            "text": "5",
+            "value": "5"
+          },
+          {
+            "selected": false,
+            "text": "6",
+            "value": "6"
+          },
+          {
+            "selected": false,
+            "text": "8",
+            "value": "8"
+          },
+          {
+            "selected": false,
+            "text": "10",
+            "value": "10"
+          },
+          {
+            "selected": false,
+            "text": "15",
+            "value": "15"
+          },
+          {
+            "selected": false,
+            "text": "25",
+            "value": "25"
+          },
+          {
+            "selected": false,
+            "text": "50",
+            "value": "50"
+          },
+          {
+            "selected": false,
+            "text": "100",
+            "value": "100"
+          },
+          {
+            "selected": false,
+            "text": "250",
+            "value": "250"
+          },
+          {
+            "selected": false,
+            "text": "500",
+            "value": "500"
+          }
+        ],
+        "query": "1,2,3,4,5,6,8,10,15,25,50,100,250,500",
+        "queryValue": "",
+        "skipUrlSync": false,
+        "type": "custom"
+      },
+      {
+        "allValue": null,
+        "current": {},
+        "datasource": "${DS_PROMETHEUS}",
+        "definition": "query_result(topk($TopResources, avg by(tenant)(avg_over_time(storagegrid_tenant_usage_data_bytes[${__range}]))))",
+        "description": null,
+        "error": null,
+        "hide": 2,
+        "includeAll": true,
+        "label": null,
+        "multi": true,
+        "name": "TopTenantUsageBytes",
+        "options": [],
+        "query": {
+          "query": "query_result(topk($TopResources, avg by(tenant)(avg_over_time(storagegrid_tenant_usage_data_bytes[${__range}]))))",
+          "refId": "StandardVariableQuery"
+        },
+        "refresh": 1,
+        "regex": ".*tenant=\\\"(.*?)\\\".*",
+        "skipUrlSync": false,
+        "sort": 0,
+        "type": "query"
+      },
+      {
+        "allValue": null,
+        "current": {},
+        "datasource": "${DS_PROMETHEUS}",
+        "definition": "query_result(topk($TopResources,(avg_over_time(storagegrid_storage_utilization_data_bytes[${__range}]))))",
+        "description": null,
+        "error": null,
+        "hide": 2,
+        "includeAll": true,
+        "label": null,
+        "multi": true,
+        "name": "TopNodesByDataUsage",
+        "options": [],
+        "query": {
+          "query": "query_result(topk($TopResources,(avg_over_time(storagegrid_storage_utilization_data_bytes[${__range}]))))",
+          "refId": "StandardVariableQuery"
+        },
+        "refresh": 1,
+        "regex": "/.*node=\"(.*?)\".*/",
+        "skipUrlSync": false,
+        "sort": 0,
+        "type": "query"
+      },
+      {
+        "allValue": null,
+        "current": {},
+        "datasource": "${DS_PROMETHEUS}",
+        "definition": "query_result(topk($TopResources,(avg_over_time(storagegrid_node_cpu_utilization_percentage[${__range}]))))",
+        "description": null,
+        "error": null,
+        "hide": 2,
+        "includeAll": true,
+        "label": null,
+        "multi": true,
+        "name": "TopNodeByCPU",
+        "options": [],
+        "query": {
+          "query": "query_result(topk($TopResources,(avg_over_time(storagegrid_node_cpu_utilization_percentage[${__range}]))))",
+          "refId": "StandardVariableQuery"
+        },
+        "refresh": 1,
+        "regex": "/.*node=\"(.*?)\".*/",
+        "skipUrlSync": false,
+        "sort": 0,
+        "type": "query"
+      }
+    ]
+  },
+  "time": {
+    "from": "now-6h",
+    "to": "now"
+  },
+  "timepicker": {},
+  "timezone": "",
+  "title": "StorageGrid: Overview",
+  "uid": "",
+  "version": 1
+}
\ No newline at end of file
diff --git a/grafana/dashboards/storagegrid/tenant.json b/grafana/dashboards/storagegrid/tenant.json
index 02b426d5..5b2ee261 100644
--- a/grafana/dashboards/storagegrid/tenant.json
+++ b/grafana/dashboards/storagegrid/tenant.json
@@ -555,6 +555,6 @@
   "timepicker": {},
   "timezone": "",
   "title": "StorageGrid: Tenants",
-  "uid": "WZExvrV4z",
+  "uid": "",
   "version": 1
 }
\ No newline at end of file


Test patch:
diff --git a/cmd/tools/grafana/dashboard_test.go b/cmd/tools/grafana/dashboard_test.go
index 6b713d2a..6983f944 100644
--- a/cmd/tools/grafana/dashboard_test.go
+++ b/cmd/tools/grafana/dashboard_test.go
@@ -11,7 +11,7 @@ import (
 )
 
 func TestDatasource(t *testing.T) {
-	visitDashboards("../../../grafana/dashboards", func(path string, data []byte) {
+	visitDashboards([]string{"../../../grafana/dashboards"}, func(path string, data []byte) {
 		checkDashboardForDatasource(t, path, data)
 	})
 }
@@ -32,10 +32,10 @@ func checkDashboardForDatasource(t *testing.T, path string, data []byte) {
 
 func TestUnitsAndExprMatch(t *testing.T) {
 	mt := newMetricsTable()
-	dir := "../../../grafana/dashboards/cmode"
-	visitDashboards(dir, func(path string, data []byte) {
-		checkUnits(path, mt, data)
-	})
+	visitDashboards([]string{"../../../grafana/dashboards/cmode", "../../../grafana/dashboards/storagegrid"},
+		func(path string, data []byte) {
+			checkUnits(path, mt, data)
+		})
 
 	// Exceptions are meant to reduce false negatives
 	allowedSuffix := map[string][]string{
@@ -293,10 +293,10 @@ func unitForExpr(e expression, overrides []override, defaultUnit string,
 }
 
 func TestVariablesAreSorted(t *testing.T) {
-	dir := "../../../grafana/dashboards/cmode"
-	visitDashboards(dir, func(path string, data []byte) {
-		checkVariablesAreSorted(t, path, data)
-	})
+	visitDashboards([]string{"../../../grafana/dashboards/cmode", "../../../grafana/dashboards/storagegrid"},
+		func(path string, data []byte) {
+			checkVariablesAreSorted(t, path, data)
+		})
 }
 
 func checkVariablesAreSorted(t *testing.T, path string, data []byte) {
@@ -325,10 +325,11 @@ func checkVariablesAreSorted(t *testing.T, path string, data []byte) {
 }
 
 func TestNoUnusedVariables(t *testing.T) {
-	dir := "../../../grafana/dashboards/cmode"
-	visitDashboards(dir, func(path string, data []byte) {
-		checkUnusedVariables(t, path, data)
-	})
+	visitDashboards(
+		[]string{"../../../grafana/dashboards/cmode", "../../../grafana/dashboards/storagegrid"},
+		func(path string, data []byte) {
+			checkUnusedVariables(t, path, data)
+		})
 }
 
 func checkUnusedVariables(t *testing.T, path string, data []byte) {
@@ -395,10 +396,11 @@ func doExpr(pathPrefix string, key gjson.Result, value gjson.Result, exprFunc fu
 }
 
 func TestIDIsBlank(t *testing.T) {
-	dir := "../../../grafana/dashboards/cmode"
-	visitDashboards(dir, func(path string, data []byte) {
-		checkUIDIsBlank(t, path, data)
-	})
+	visitDashboards(
+		[]string{"../../../grafana/dashboards/cmode", "../../../grafana/dashboards/storagegrid"},
+		func(path string, data []byte) {
+			checkUIDIsBlank(t, path, data)
+		})
 }
 
 func checkUIDIsBlank(t *testing.T, path string, data []byte) {
@@ -409,10 +411,11 @@ func checkUIDIsBlank(t *testing.T, path string, data []byte) {
 }
 
 func TestUniquePanelIDs(t *testing.T) {
-	dir := "../../../grafana/dashboards/cmode"
-	visitDashboards(dir, func(path string, data []byte) {
-		checkUniquePanelIDs(t, path, data)
-	})
+	visitDashboards(
+		[]string{"../../../grafana/dashboards/cmode", "../../../grafana/dashboards/storagegrid"},
+		func(path string, data []byte) {
+			checkUniquePanelIDs(t, path, data)
+		})
 }
 
 func checkUniquePanelIDs(t *testing.T, path string, data []byte) {
@@ -450,10 +453,11 @@ func checkUniquePanelIDs(t *testing.T, path string, data []byte) {
 //   b) otherwise fail, printing the expression, path, dashboard
 
 func TestTopKRange(t *testing.T) {
-	dir := "../../../grafana/dashboards/cmode"
-	visitDashboards(dir, func(path string, data []byte) {
-		checkTopKRange(t, path, data)
-	})
+	visitDashboards(
+		[]string{"../../../grafana/dashboards/cmode", "../../../grafana/dashboards/storagegrid"},
+		func(path string, data []byte) {
+			checkTopKRange(t, path, data)
+		})
 }
 
 func checkTopKRange(t *testing.T, path string, data []byte) {
@@ -507,16 +511,16 @@ func checkTopKRange(t *testing.T, path string, data []byte) {
 }
 
 func TestOnlyHighlightsExpanded(t *testing.T) {
-	dir := "../../../grafana/dashboards/cmode"
-
 	exceptions := map[string]int{
 		"cmode/shelf.json":    2,
 		"cmode/security.json": 3,
 	}
 	// count number of expanded sections in dashboard and ensure num expanded = 1
-	visitDashboards(dir, func(path string, data []byte) {
-		checkExpansion(t, exceptions, path, data)
-	})
+	visitDashboards(
+		[]string{"../../../grafana/dashboards/cmode", "../../../grafana/dashboards/storagegrid"},
+		func(path string, data []byte) {
+			checkExpansion(t, exceptions, path, data)
+		})
 }
 
 func checkExpansion(t *testing.T, exceptions map[string]int, path string, data []byte) {
@@ -563,10 +567,11 @@ func visitAllPanels(data []byte, handle func(path string, key gjson.Result, valu
 }
 
 func TestLegends(t *testing.T) {
-	dir := "../../../grafana/dashboards/cmode"
-	visitDashboards(dir, func(path string, data []byte) {
-		checkLegends(t, path, data)
-	})
+	visitDashboards(
+		[]string{"../../../grafana/dashboards/cmode", "../../../grafana/dashboards/storagegrid"},
+		func(path string, data []byte) {
+			checkLegends(t, path, data)
+		})
 }
 
 func checkLegends(t *testing.T, path string, data []byte) {
@@ -631,10 +636,11 @@ func checkLegendCalculations(t *testing.T, gotLegendCalculations []string, dashP
 }
 
 func TestConnectNullValues(t *testing.T) {
-	dir := "../../../grafana/dashboards/cmode"
-	visitDashboards(dir, func(path string, data []byte) {
-		checkConnectNullValues(t, path, data)
-	})
+	visitDashboards(
+		[]string{"../../../grafana/dashboards/cmode", "../../../grafana/dashboards/storagegrid"},
+		func(path string, data []byte) {
+			checkConnectNullValues(t, path, data)
+		})
 }
 
 func checkConnectNullValues(t *testing.T, path string, data []byte) {
@@ -652,10 +658,11 @@ func checkConnectNullValues(t *testing.T, path string, data []byte) {
 }
 
 func TestPanelChildPanels(t *testing.T) {
-	dir := "../../../grafana/dashboards/cmode"
-	visitDashboards(dir, func(path string, data []byte) {
-		checkPanelChildPanels(t, shortPath(path), data)
-	})
+	visitDashboards(
+		[]string{"../../../grafana/dashboards/cmode", "../../../grafana/dashboards/storagegrid"},
+		func(path string, data []byte) {
+			checkPanelChildPanels(t, shortPath(path), data)
+		})
 }
 
 func checkPanelChildPanels(t *testing.T, path string, data []byte) {
diff --git a/cmd/tools/grafana/grafana_test.go b/cmd/tools/grafana/grafana_test.go
index 412f4af3..2c27b4d3 100644
--- a/cmd/tools/grafana/grafana_test.go
+++ b/cmd/tools/grafana/grafana_test.go
@@ -10,16 +10,25 @@ import (
 )
 
 func TestCheckVersion(t *testing.T) {
-
-	inputVersion := []string{"8.4.0-beta1", "7.2.3.4", "abc.1.3", "4.5.4", "7.1.0", "7.5.5"}
-	expectedOutPut := []bool{true, true, false, false, true, true}
-
-	for i, s := range inputVersion {
-		c := checkVersion(s)
-		if c != expectedOutPut[i] {
-			t.Errorf("Expected %t but got %t for input %s", expectedOutPut[i], c, inputVersion[i])
+	type vCheck struct {
+		version string
+		want    bool
+	}
+	checks := []vCheck{
+		{version: "8.4.0-beta1", want: true},
+		{version: "7.2.3.4", want: true},
+		{version: "abc.1.3", want: false},
+		{version: "4.5.4", want: false},
+		{version: "7.1.0", want: true},
+		{version: "7.5.5", want: true},
+	}
+	for _, check := range checks {
+		got := checkVersion(check.version)
+		if got != check.want {
+			t.Errorf("Expected %t but got %t for input %s", check.want, got, check.version)
 		}
 	}
+	t.Log("") // required so the test is not marked as terminated
 }
 
 func TestHttpsAddr(t *testing.T) {
@@ -63,33 +72,34 @@ func TestAddPrefixToMetricNames(t *testing.T) {
 	)
 
 	prefix := "xx_"
-	dir := "../../../grafana/dashboards/cmode"
-	visitDashboards(dir, func(path string, data []byte) {
-		oldExpressions = readExprs(data)
-		if err = json.Unmarshal(data, &dashboard); err != nil {
-			fmt.Printf("error parsing file [%s] %+v\n", path, err)
-			fmt.Println("-------------------------------")
-			fmt.Println(string(data))
-			fmt.Println("-------------------------------")
-			return
-		}
-		addGlobalPrefix(dashboard, prefix)
-
-		if updatedData, err = json.Marshal(dashboard); err != nil {
-			fmt.Printf("error parsing file [%s] %+v\n", path, err)
-			fmt.Println("-------------------------------")
-			fmt.Println(string(updatedData))
-			fmt.Println("-------------------------------")
-			return
-		}
-		newExpressions = readExprs(updatedData)
+	visitDashboards(
+		[]string{"../../../grafana/dashboards/cmode", "../../../grafana/dashboards/storagegrid"},
+		func(path string, data []byte) {
+			oldExpressions = readExprs(data)
+			if err = json.Unmarshal(data, &dashboard); err != nil {
+				fmt.Printf("error parsing file [%s] %+v\n", path, err)
+				fmt.Println("-------------------------------")
+				fmt.Println(string(data))
+				fmt.Println("-------------------------------")
+				return
+			}
+			addGlobalPrefix(dashboard, prefix)
+
+			if updatedData, err = json.Marshal(dashboard); err != nil {
+				fmt.Printf("error parsing file [%s] %+v\n", path, err)
+				fmt.Println("-------------------------------")
+				fmt.Println(string(updatedData))
+				fmt.Println("-------------------------------")
+				return
+			}
+			newExpressions = readExprs(updatedData)
 
-		for i := 0; i < len(newExpressions); i++ {
-			if newExpressions[i] != prefix+oldExpressions[i] {
-				t.Errorf("\nExpected: [%s]\n     Got: [%s]", prefix+oldExpressions[i], newExpressions[i])
+			for i := 0; i < len(newExpressions); i++ {
+				if newExpressions[i] != prefix+oldExpressions[i] {
+					t.Errorf("\nExpected: [%s]\n     Got: [%s]", prefix+oldExpressions[i], newExpressions[i])
+				}
 			}
-		}
-	})
+		})
 }
 
 func getExp(expr string, expressions *[]string) {
diff --git a/integration/test/dashboard_json_test.go b/integration/test/dashboard_json_test.go
index 7979f411..d561e7c2 100644
--- a/integration/test/dashboard_json_test.go
+++ b/integration/test/dashboard_json_test.go
@@ -199,7 +199,7 @@ func (suite *DashboardJsonTestSuite) TestJsonExpression() {
 
 func ShouldSkipDashboard(path string) bool {
 	// Ignore headroom dashboard from CI as it uses dynamic variables in query
-	skip := []string{"nfs4storePool", "headroom", "tenant", "fsa"}
+	skip := []string{"nfs4storePool", "headroom", "tenant", "fsa", "overview"}
 	for _, s := range skip {
 		if strings.Contains(path, s) {
 			return true