Repository: NetApp/harvest
Pull request #1763 (2023-02-22 10:11:52)

fix: handle min-max for network dashboard
- Removed from `NVMe/FC ports` as this table don't have column #C for `used%`


Patch:
diff --git a/grafana/dashboards/7mode/network7.json b/grafana/dashboards/7mode/network7.json
index a8de64b9..46b2383c 100644
--- a/grafana/dashboards/7mode/network7.json
+++ b/grafana/dashboards/7mode/network7.json
@@ -639,6 +639,14 @@
                         }
                       ]
                     }
+                  },
+                  {
+                    "id": "max",
+                    "value": 1
+                  },
+                  {
+                    "id": "min",
+                    "value": 0
                   }
                 ]
               },
@@ -697,18 +705,6 @@
                   }
                 ]
               },
-              {
-                "matcher": {
-                  "id": "byName",
-                  "options": "status"
-                },
-                "properties": [
-                  {
-                    "id": "custom.width",
-                    "value": 153
-                  }
-                ]
-              },
               {
                 "matcher": {
                   "id": "byName",
@@ -745,18 +741,6 @@
                   }
                 ]
               },
-              {
-                "matcher": {
-                  "id": "byName",
-                  "options": "used %"
-                },
-                "properties": [
-                  {
-                    "id": "custom.width",
-                    "value": 228
-                  }
-                ]
-              },
               {
                 "matcher": {
                   "id": "byName",
@@ -788,30 +772,6 @@
                     "value": "gradient-gauge"
                   }
                 ]
-              },
-              {
-                "matcher": {
-                  "id": "byName",
-                  "options": "send"
-                },
-                "properties": [
-                  {
-                    "id": "custom.width",
-                    "value": 360
-                  }
-                ]
-              },
-              {
-                "matcher": {
-                  "id": "byName",
-                  "options": "receive"
-                },
-                "properties": [
-                  {
-                    "id": "custom.width",
-                    "value": 398
-                  }
-                ]
               }
             ]
           },
@@ -1503,6 +1463,14 @@
                         }
                       ]
                     }
+                  },
+                  {
+                    "id": "max",
+                    "value": 1
+                  },
+                  {
+                    "id": "min",
+                    "value": 0
                   }
                 ]
               },
diff --git a/grafana/dashboards/cmode/network.json b/grafana/dashboards/cmode/network.json
index 6e45a16a..66419e5a 100644
--- a/grafana/dashboards/cmode/network.json
+++ b/grafana/dashboards/cmode/network.json
@@ -639,6 +639,14 @@
                         }
                       ]
                     }
+                  },
+                  {
+                    "id": "max",
+                    "value": 1
+                  },
+                  {
+                    "id": "min",
+                    "value": 0
                   }
                 ]
               },
@@ -697,18 +705,6 @@
                   }
                 ]
               },
-              {
-                "matcher": {
-                  "id": "byName",
-                  "options": "status"
-                },
-                "properties": [
-                  {
-                    "id": "custom.width",
-                    "value": 153
-                  }
-                ]
-              },
               {
                 "matcher": {
                   "id": "byName",
@@ -745,18 +741,6 @@
                   }
                 ]
               },
-              {
-                "matcher": {
-                  "id": "byName",
-                  "options": "used %"
-                },
-                "properties": [
-                  {
-                    "id": "custom.width",
-                    "value": 228
-                  }
-                ]
-              },
               {
                 "matcher": {
                   "id": "byName",
@@ -788,30 +772,6 @@
                     "value": "gradient-gauge"
                   }
                 ]
-              },
-              {
-                "matcher": {
-                  "id": "byName",
-                  "options": "send"
-                },
-                "properties": [
-                  {
-                    "id": "custom.width",
-                    "value": 360
-                  }
-                ]
-              },
-              {
-                "matcher": {
-                  "id": "byName",
-                  "options": "receive"
-                },
-                "properties": [
-                  {
-                    "id": "custom.width",
-                    "value": 398
-                  }
-                ]
               }
             ]
           },
@@ -1530,6 +1490,14 @@
                         }
                       ]
                     }
+                  },
+                  {
+                    "id": "max",
+                    "value": 1
+                  },
+                  {
+                    "id": "min",
+                    "value": 0
                   }
                 ]
               },
@@ -2535,54 +2503,6 @@
                   }
                 ]
               },
-              {
-                "matcher": {
-                  "id": "byName",
-                  "options": "Value #C"
-                },
-                "properties": [
-                  {
-                    "id": "unit",
-                    "value": "percentunit"
-                  },
-                  {
-                    "id": "custom.displayMode",
-                    "value": "gradient-gauge"
-                  },
-                  {
-                    "id": "displayName",
-                    "value": "used %"
-                  },
-                  {
-                    "id": "noValue",
-                    "value": "n/a"
-                  },
-                  {
-                    "id": "thresholds",
-                    "value": {
-                      "mode": "absolute",
-                      "steps": [
-                        {
-                          "color": "rgb(80, 220, 20)",
-                          "value": null
-                        },
-                        {
-                          "color": "light-yellow",
-                          "value": 50
-                        },
-                        {
-                          "color": "semi-dark-orange",
-                          "value": 75
-                        },
-                        {
-                          "color": "semi-dark-red",
-                          "value": 90
-                        }
-                      ]
-                    }
-                  }
-                ]
-              },
               {
                 "matcher": {
                   "id": "byName",
@@ -2693,7 +2613,6 @@
                     "node",
                     "port",
                     "speed",
-                    "Value #C",
                     "Value #A",
                     "Value #B"
                   ]


Test patch:
diff --git a/cmd/tools/grafana/dashboard_test.go b/cmd/tools/grafana/dashboard_test.go
index 6654bd3f..e810692c 100644
--- a/cmd/tools/grafana/dashboard_test.go
+++ b/cmd/tools/grafana/dashboard_test.go
@@ -54,7 +54,7 @@ func TestUnitsAndExprMatch(t *testing.T) {
 	mt := newMetricsTable()
 	visitDashboards([]string{"../../../grafana/dashboards/cmode", "../../../grafana/dashboards/storagegrid"},
 		func(path string, data []byte) {
-			checkUnits(path, mt, data)
+			checkUnits(t, path, mt, data)
 		})
 
 	// Exceptions are meant to reduce false negatives
@@ -161,12 +161,12 @@ func newMetricsTable() *metricsTable {
 	}
 }
 
-func checkUnits(dashboardPath string, mt *metricsTable, data []byte) {
+func checkUnits(t *testing.T, dashboardPath string, mt *metricsTable, data []byte) {
 	gjson.GetBytes(data, "panels").ForEach(func(key, value gjson.Result) bool {
-		doPanel("", key, value, mt, dashboardPath)
+		doPanel(t, "", key, value, mt, dashboardPath)
 		value.Get("panels").ForEach(func(key2, value2 gjson.Result) bool {
 			pathPrefix := fmt.Sprintf("panels[%d].", key.Int())
-			doPanel(pathPrefix, key2, value2, mt, dashboardPath)
+			doPanel(t, pathPrefix, key2, value2, mt, dashboardPath)
 			return true
 		})
 		return true
@@ -184,7 +184,7 @@ var metricDivideMetric2 = regexp.MustCompile(`(\w+)/.*?(\w+){`)
 // detects arrays
 var metricWithArray = regexp.MustCompile(`metric=~*"(.*?)"`)
 
-func doPanel(pathPrefix string, key gjson.Result, value gjson.Result, mt *metricsTable, dashboardPath string) bool {
+func doPanel(t *testing.T, pathPrefix string, key gjson.Result, value gjson.Result, mt *metricsTable, dashboardPath string) bool {
 	kind := value.Get("type").String()
 	if kind == "row" {
 		return true
@@ -197,17 +197,22 @@ func doPanel(pathPrefix string, key gjson.Result, value gjson.Result, mt *metric
 	title := value.Get("title").String()
 	sPath := shortPath(dashboardPath)
 
+	propertiesMap := make(map[string]map[string]string)
 	overrides := make([]override, 0, len(overridesSlice))
 	expressions := make([]expression, 0)
 	valueToName := make(map[string]string) // only used with panels[*].transformations[*].options.renameByName
 
 	for oi, overrideN := range overridesSlice {
 		matcherID := overrideN.Get("matcher.id")
+		// make sure that mapKey is unique for each override element
+		propertiesMapKey := matcherID.String() + strconv.Itoa(oi)
+		propertiesMap[propertiesMapKey] = make(map[string]string)
 		matcherOptions := overrideN.Get("matcher.options")
 		propertiesN := overrideN.Get("properties").Array()
 		for pi, propN := range propertiesN {
 			propID := propN.Get("id").String()
 			propVal := propN.Get("value").String()
+			propertiesMap[propertiesMapKey][propID] = propVal
 			if propID == "unit" {
 				o := override{
 					id:      matcherID.String(),
@@ -221,6 +226,19 @@ func doPanel(pathPrefix string, key gjson.Result, value gjson.Result, mt *metric
 		}
 	}
 
+	// In case of gradient-gauge and percent(0.0-1.0), we must override min and max value
+	for _, properties := range propertiesMap {
+		displayMode := properties["custom.displayMode"]
+		if properties["unit"] == "percentunit" && (displayMode == "gradient-gauge" || displayMode == "lcd-gauge" || displayMode == "basic") {
+			if maxVal, exist := properties["max"]; !exist || maxVal != "1" {
+				t.Errorf("dashboard=%s, title=%s should have max value 1", sPath, title)
+			}
+			if minVal, exist := properties["min"]; !exist || minVal != "0" {
+				t.Errorf("dashboard=%s, title=%s should have min value 0", sPath, title)
+			}
+		}
+	}
+
 	// Heatmap units are saved in a different place
 	if kind == "heatmap" && defaultUnit == "" {
 		defaultUnit = value.Get("yAxis.format").String()