From 11b8c8d57f7ce7df28a6ee885dd2c33ad44879cf Mon Sep 17 00:00:00 2001 From: tenfyzhong Date: Wed, 8 Apr 2026 14:58:59 +0800 Subject: [PATCH 1/4] metrics: use datasource variable in TiCDC dashboard titles Signed-off-by: tenfyzhong --- metrics/grafana/ticdc_new_arch.json | 2 +- metrics/nextgengrafana/ticdc_new_arch_next_gen.json | 2 +- metrics/nextgengrafana/ticdc_new_arch_with_keyspace_name.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/metrics/grafana/ticdc_new_arch.json b/metrics/grafana/ticdc_new_arch.json index d2bf3084d9..bb07b42402 100644 --- a/metrics/grafana/ticdc_new_arch.json +++ b/metrics/grafana/ticdc_new_arch.json @@ -27296,7 +27296,7 @@ ] }, "timezone": "browser", - "title": "test-cluster-TiCDC-New-Arch", + "title": "${DS_TEST-CLUSTER}-cluster-TiCDC-New-Arch", "uid": "YiGL8hBZ0aac", "version": 40 } diff --git a/metrics/nextgengrafana/ticdc_new_arch_next_gen.json b/metrics/nextgengrafana/ticdc_new_arch_next_gen.json index 826a7987e8..0b448f6668 100644 --- a/metrics/nextgengrafana/ticdc_new_arch_next_gen.json +++ b/metrics/nextgengrafana/ticdc_new_arch_next_gen.json @@ -27296,7 +27296,7 @@ ] }, "timezone": "browser", - "title": "test-cluster-TiCDC-New-Arch", + "title": "${DS_TEST-CLUSTER}-cluster-TiCDC-New-Arch", "uid": "YiGL8hBZ0aac", "version": 40 } diff --git a/metrics/nextgengrafana/ticdc_new_arch_with_keyspace_name.json b/metrics/nextgengrafana/ticdc_new_arch_with_keyspace_name.json index a5d5fde2e1..525a4439b7 100644 --- a/metrics/nextgengrafana/ticdc_new_arch_with_keyspace_name.json +++ b/metrics/nextgengrafana/ticdc_new_arch_with_keyspace_name.json @@ -11488,7 +11488,7 @@ ] }, "timezone": "browser", - "title": "test-cluster-TiCDC-New-Arch", + "title": "${DS_TEST-CLUSTER}-cluster-TiCDC-New-Arch", "uid": "lGT5hED6vqTn", "version": 40 } From e84c81556937bf1d56bbe8d180196e76dd337e95 Mon Sep 17 00:00:00 2001 From: tenfyzhong Date: Wed, 8 Apr 2026 15:11:40 +0800 Subject: [PATCH 2/4] scripts: validate next gen metrics outputs Signed-off-by: tenfyzhong --- scripts/generate-next-gen-metrics.sh | 14 ++- scripts/generate_next_gen_metrics_test.go | 124 ++++++++++++++++++++++ 2 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 scripts/generate_next_gen_metrics_test.go diff --git a/scripts/generate-next-gen-metrics.sh b/scripts/generate-next-gen-metrics.sh index 770d30a501..d1456b8011 100755 --- a/scripts/generate-next-gen-metrics.sh +++ b/scripts/generate-next-gen-metrics.sh @@ -41,6 +41,16 @@ if [ ! -f "$NEXT_GEN_SHARED_FILE" ]; then exit 1 fi +require_file_contains() { + local file="$1" + local expected="$2" + + if ! grep -Fq -- "$expected" "$file"; then + echo "Error: Generated file '$file' must contain '$expected'" >&2 + exit 1 + fi +} + # This jq script filters the panels in the Grafana dashboard. # It defines a recursive function `filter_panels` that: # 1. For panels of type "row", it recursively filters their sub-panels. @@ -62,11 +72,13 @@ jq ' .panels |= filter_panels ' "$NEXT_GEN_SHARED_FILE" >"$NEXT_GEN_USER_FILE" -"$SED_CMD" "${SED_INPLACE_ARGS[@]}" "s/\${DS_TEST-CLUSTER}-TiCDC-New-Arch/&-KeyspaceName/" "$NEXT_GEN_USER_FILE" +"$SED_CMD" "${SED_INPLACE_ARGS[@]}" "s/\${DS_TEST-CLUSTER}-cluster-TiCDC-New-Arch/&-KeyspaceName/" "$NEXT_GEN_USER_FILE" "$SED_CMD" "${SED_INPLACE_ARGS[@]}" "s/YiGL8hBZ0aac/lGT5hED6vqTn/" "$NEXT_GEN_USER_FILE" +require_file_contains "$NEXT_GEN_USER_FILE" "-KeyspaceName" echo "Userscope dashboard created at '$NEXT_GEN_USER_FILE'" "$SED_CMD" "${SED_INPLACE_ARGS[@]}" 's/\([^$]\)tidb_cluster/\1sharedpool_id/g' "$NEXT_GEN_SHARED_FILE" +require_file_contains "$NEXT_GEN_SHARED_FILE" "sharedpool_id" echo "Sharedscope dashboard created at '$NEXT_GEN_SHARED_FILE'" diff --git a/scripts/generate_next_gen_metrics_test.go b/scripts/generate_next_gen_metrics_test.go new file mode 100644 index 0000000000..9a8f49ea16 --- /dev/null +++ b/scripts/generate_next_gen_metrics_test.go @@ -0,0 +1,124 @@ +// Copyright 2026 PingCAP, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// See the License for the specific language governing permissions and +// limitations under the License. + +package scripts + +import ( + "fmt" + "os" + "os/exec" + "path/filepath" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestGenerateNextGenMetricsRequiresExpectedMarkers(t *testing.T) { + t.Run("fails when user dashboard misses keyspace suffix", func(t *testing.T) { + sedCmd := writeSedWrapper(t, "user") + _, _, output, err := runGenerateNextGenMetrics(t, sedCmd) + require.Error(t, err) + require.Contains(t, string(output), "must contain '-KeyspaceName'") + }) + + t.Run("fails when shared dashboard misses sharedpool label", func(t *testing.T) { + sedCmd := writeSedWrapper(t, "shared") + _, _, output, err := runGenerateNextGenMetrics(t, sedCmd) + require.Error(t, err) + require.Contains(t, string(output), "must contain 'sharedpool_id'") + }) + + t.Run("succeeds with generated markers present", func(t *testing.T) { + sharedFile, userFile, output, err := runGenerateNextGenMetrics(t, "") + require.NoError(t, err, string(output)) + + userContent, err := os.ReadFile(userFile) + require.NoError(t, err) + require.Contains(t, string(userContent), "-KeyspaceName") + + sharedContent, err := os.ReadFile(sharedFile) + require.NoError(t, err) + require.Contains(t, string(sharedContent), "sharedpool_id") + }) +} + +func runGenerateNextGenMetrics(t *testing.T, sedCmd string) (string, string, []byte, error) { + t.Helper() + + tempDir := t.TempDir() + sharedFile := filepath.Join(tempDir, "ticdc_new_arch_next_gen.json") + userFile := filepath.Join(tempDir, "ticdc_new_arch_with_keyspace_name.json") + + cmd := exec.Command("bash", "./scripts/generate-next-gen-metrics.sh", sharedFile, userFile) + cmd.Dir = repoRoot(t) + if sedCmd != "" { + cmd.Env = append(os.Environ(), "SED_CMD="+sedCmd) + } + + output, err := cmd.CombinedOutput() + return sharedFile, userFile, output, err +} + +func repoRoot(t *testing.T) string { + t.Helper() + + wd, err := os.Getwd() + require.NoError(t, err) + + if _, err := os.Stat(filepath.Join(wd, "scripts", "generate-next-gen-metrics.sh")); err == nil { + return wd + } + + if filepath.Base(wd) == "scripts" { + root := filepath.Dir(wd) + _, err = os.Stat(filepath.Join(root, "scripts", "generate-next-gen-metrics.sh")) + require.NoError(t, err) + return root + } + + t.Fatalf("failed to locate repository root from %s", wd) + return "" +} + +func writeSedWrapper(t *testing.T, skipMode string) string { + t.Helper() + + realSed, err := exec.LookPath("sed") + require.NoError(t, err) + + wrapperPath := filepath.Join(t.TempDir(), "sed-wrapper.sh") + wrapperContent := fmt.Sprintf(`#!/usr/bin/env bash +set -euo pipefail + +real_sed=%q +skip_mode=%q + +if [[ "${1:-}" == "--version" ]]; then + exec "$real_sed" "$@" +fi + +for arg in "$@"; do + if [[ "$skip_mode" == "user" && "$arg" == *"-KeyspaceName/"* ]]; then + exit 0 + fi + if [[ "$skip_mode" == "shared" && "$arg" == *"sharedpool_id"* ]]; then + exit 0 + fi +done + +exec "$real_sed" "$@" +`, realSed, skipMode) + err = os.WriteFile(wrapperPath, []byte(wrapperContent), 0o755) + require.NoError(t, err) + return wrapperPath +} From e581214ea51a2d042d7f0dba6162dd58d29107bc Mon Sep 17 00:00:00 2001 From: tenfyzhong Date: Wed, 8 Apr 2026 15:14:07 +0800 Subject: [PATCH 3/4] scripts: remove next gen metrics test file Signed-off-by: tenfyzhong --- scripts/generate_next_gen_metrics_test.go | 124 ---------------------- 1 file changed, 124 deletions(-) delete mode 100644 scripts/generate_next_gen_metrics_test.go diff --git a/scripts/generate_next_gen_metrics_test.go b/scripts/generate_next_gen_metrics_test.go deleted file mode 100644 index 9a8f49ea16..0000000000 --- a/scripts/generate_next_gen_metrics_test.go +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright 2026 PingCAP, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package scripts - -import ( - "fmt" - "os" - "os/exec" - "path/filepath" - "testing" - - "github.com/stretchr/testify/require" -) - -func TestGenerateNextGenMetricsRequiresExpectedMarkers(t *testing.T) { - t.Run("fails when user dashboard misses keyspace suffix", func(t *testing.T) { - sedCmd := writeSedWrapper(t, "user") - _, _, output, err := runGenerateNextGenMetrics(t, sedCmd) - require.Error(t, err) - require.Contains(t, string(output), "must contain '-KeyspaceName'") - }) - - t.Run("fails when shared dashboard misses sharedpool label", func(t *testing.T) { - sedCmd := writeSedWrapper(t, "shared") - _, _, output, err := runGenerateNextGenMetrics(t, sedCmd) - require.Error(t, err) - require.Contains(t, string(output), "must contain 'sharedpool_id'") - }) - - t.Run("succeeds with generated markers present", func(t *testing.T) { - sharedFile, userFile, output, err := runGenerateNextGenMetrics(t, "") - require.NoError(t, err, string(output)) - - userContent, err := os.ReadFile(userFile) - require.NoError(t, err) - require.Contains(t, string(userContent), "-KeyspaceName") - - sharedContent, err := os.ReadFile(sharedFile) - require.NoError(t, err) - require.Contains(t, string(sharedContent), "sharedpool_id") - }) -} - -func runGenerateNextGenMetrics(t *testing.T, sedCmd string) (string, string, []byte, error) { - t.Helper() - - tempDir := t.TempDir() - sharedFile := filepath.Join(tempDir, "ticdc_new_arch_next_gen.json") - userFile := filepath.Join(tempDir, "ticdc_new_arch_with_keyspace_name.json") - - cmd := exec.Command("bash", "./scripts/generate-next-gen-metrics.sh", sharedFile, userFile) - cmd.Dir = repoRoot(t) - if sedCmd != "" { - cmd.Env = append(os.Environ(), "SED_CMD="+sedCmd) - } - - output, err := cmd.CombinedOutput() - return sharedFile, userFile, output, err -} - -func repoRoot(t *testing.T) string { - t.Helper() - - wd, err := os.Getwd() - require.NoError(t, err) - - if _, err := os.Stat(filepath.Join(wd, "scripts", "generate-next-gen-metrics.sh")); err == nil { - return wd - } - - if filepath.Base(wd) == "scripts" { - root := filepath.Dir(wd) - _, err = os.Stat(filepath.Join(root, "scripts", "generate-next-gen-metrics.sh")) - require.NoError(t, err) - return root - } - - t.Fatalf("failed to locate repository root from %s", wd) - return "" -} - -func writeSedWrapper(t *testing.T, skipMode string) string { - t.Helper() - - realSed, err := exec.LookPath("sed") - require.NoError(t, err) - - wrapperPath := filepath.Join(t.TempDir(), "sed-wrapper.sh") - wrapperContent := fmt.Sprintf(`#!/usr/bin/env bash -set -euo pipefail - -real_sed=%q -skip_mode=%q - -if [[ "${1:-}" == "--version" ]]; then - exec "$real_sed" "$@" -fi - -for arg in "$@"; do - if [[ "$skip_mode" == "user" && "$arg" == *"-KeyspaceName/"* ]]; then - exit 0 - fi - if [[ "$skip_mode" == "shared" && "$arg" == *"sharedpool_id"* ]]; then - exit 0 - fi -done - -exec "$real_sed" "$@" -`, realSed, skipMode) - err = os.WriteFile(wrapperPath, []byte(wrapperContent), 0o755) - require.NoError(t, err) - return wrapperPath -} From cf6ef502e8bb7d078dc904237f1d1896213427a8 Mon Sep 17 00:00:00 2001 From: tenfyzhong Date: Wed, 8 Apr 2026 15:18:13 +0800 Subject: [PATCH 4/4] metrics: remove cluster from TiCDC dashboard title Signed-off-by: tenfyzhong --- metrics/grafana/ticdc_new_arch.json | 2 +- metrics/nextgengrafana/ticdc_new_arch_next_gen.json | 2 +- metrics/nextgengrafana/ticdc_new_arch_with_keyspace_name.json | 2 +- scripts/generate-next-gen-metrics.sh | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/metrics/grafana/ticdc_new_arch.json b/metrics/grafana/ticdc_new_arch.json index bb07b42402..7c438dbf07 100644 --- a/metrics/grafana/ticdc_new_arch.json +++ b/metrics/grafana/ticdc_new_arch.json @@ -27296,7 +27296,7 @@ ] }, "timezone": "browser", - "title": "${DS_TEST-CLUSTER}-cluster-TiCDC-New-Arch", + "title": "${DS_TEST-CLUSTER}-TiCDC-New-Arch", "uid": "YiGL8hBZ0aac", "version": 40 } diff --git a/metrics/nextgengrafana/ticdc_new_arch_next_gen.json b/metrics/nextgengrafana/ticdc_new_arch_next_gen.json index 0b448f6668..b89adf1f76 100644 --- a/metrics/nextgengrafana/ticdc_new_arch_next_gen.json +++ b/metrics/nextgengrafana/ticdc_new_arch_next_gen.json @@ -27296,7 +27296,7 @@ ] }, "timezone": "browser", - "title": "${DS_TEST-CLUSTER}-cluster-TiCDC-New-Arch", + "title": "${DS_TEST-CLUSTER}-TiCDC-New-Arch", "uid": "YiGL8hBZ0aac", "version": 40 } diff --git a/metrics/nextgengrafana/ticdc_new_arch_with_keyspace_name.json b/metrics/nextgengrafana/ticdc_new_arch_with_keyspace_name.json index 525a4439b7..e1881dffce 100644 --- a/metrics/nextgengrafana/ticdc_new_arch_with_keyspace_name.json +++ b/metrics/nextgengrafana/ticdc_new_arch_with_keyspace_name.json @@ -11488,7 +11488,7 @@ ] }, "timezone": "browser", - "title": "${DS_TEST-CLUSTER}-cluster-TiCDC-New-Arch", + "title": "${DS_TEST-CLUSTER}-TiCDC-New-Arch-KeyspaceName", "uid": "lGT5hED6vqTn", "version": 40 } diff --git a/scripts/generate-next-gen-metrics.sh b/scripts/generate-next-gen-metrics.sh index d1456b8011..f12eef3007 100755 --- a/scripts/generate-next-gen-metrics.sh +++ b/scripts/generate-next-gen-metrics.sh @@ -72,7 +72,7 @@ jq ' .panels |= filter_panels ' "$NEXT_GEN_SHARED_FILE" >"$NEXT_GEN_USER_FILE" -"$SED_CMD" "${SED_INPLACE_ARGS[@]}" "s/\${DS_TEST-CLUSTER}-cluster-TiCDC-New-Arch/&-KeyspaceName/" "$NEXT_GEN_USER_FILE" +"$SED_CMD" "${SED_INPLACE_ARGS[@]}" "s/\${DS_TEST-CLUSTER}-TiCDC-New-Arch/&-KeyspaceName/" "$NEXT_GEN_USER_FILE" "$SED_CMD" "${SED_INPLACE_ARGS[@]}" "s/YiGL8hBZ0aac/lGT5hED6vqTn/" "$NEXT_GEN_USER_FILE" require_file_contains "$NEXT_GEN_USER_FILE" "-KeyspaceName"