From 368f0b2475af8114bef817c78297d516776d5c5a Mon Sep 17 00:00:00 2001 From: Rahul Gupta Date: Tue, 16 May 2023 18:00:11 +0530 Subject: [PATCH] feat: Harvest should add grafana import rewrite svm filtering for multi-tenant support --- cmd/tools/grafana/grafana.go | 30 ++++++++++++++++++++++++++++++ cmd/tools/grafana/grafana_test.go | 27 +++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/cmd/tools/grafana/grafana.go b/cmd/tools/grafana/grafana.go index f6fee7150..f35385681 100644 --- a/cmd/tools/grafana/grafana.go +++ b/cmd/tools/grafana/grafana.go @@ -58,6 +58,7 @@ type options struct { labels []string dirGrafanaFolderMap map[string]*Folder addMultiSelect bool + svmRegex string } type Folder struct { @@ -182,6 +183,28 @@ func exportFiles(dir string, folder *Folder) error { return nil } +func addSvmRegex(content []byte, fileName string, val string) []byte { + var err error + newContent := content + var svmExpression []string + if fileName == "snapmirror.json" { + svmExpression = []string{"templating.list.#(name=\"DestinationSVM\")", "templating.list.#(name=\"SourceSVM\")"} + } else { + svmExpression = []string{"templating.list.#(name=\"SVM\")"} + } + for _, s := range svmExpression { + svm := gjson.GetBytes(content, s) + if svm.Exists() { + newContent, err = sjson.SetBytes(newContent, s+".regex", []byte(val)) + if err != nil { + fmt.Printf("error while setting svm regex") + continue + } + } + } + return newContent +} + func addLabel(content []byte, label string, labelMap map[string]string) []byte { // extract the list of variables templateList := gjson.GetBytes(content, "templating.list") @@ -469,6 +492,11 @@ func importFiles(dir string, folder *Folder) { } } + // add svm regex + if opts.svmRegex != "" { + data = addSvmRegex(data, file.Name(), opts.svmRegex) + } + // labelMap is used to ensure we don't modify the query of one of the new labels we're adding labelMap := make(map[string]string) caser := cases.Title(language.Und) @@ -1015,6 +1043,7 @@ func addFlags(commands ...*cobra.Command) { cmd.PersistentFlags().StringVar(&opts.config, "config", "./harvest.yml", "harvest config file path") cmd.PersistentFlags().StringVarP(&opts.addr, "addr", "a", "http://127.0.0.1:3000", "Address of Grafana server (IP, FQDN or hostname)") cmd.PersistentFlags().StringVarP(&opts.token, "token", "t", "", "API token issued by Grafana server for authentication") + cmd.PersistentFlags().StringVar(&opts.svmRegex, "svm-variable-regex", "", "SVM variable regex to filter SVM query results") cmd.PersistentFlags().StringVarP(&opts.prefix, "prefix", "p", "", "Use global metric prefix in queries") cmd.PersistentFlags().StringVarP(&opts.datasource, "datasource", "s", grafanaDataSource, "Grafana datasource for the dashboards") cmd.PersistentFlags().BoolVarP(&opts.variable, "variable", "v", false, "Use datasource as variable, overrides: --datasource") @@ -1023,6 +1052,7 @@ func addFlags(commands ...*cobra.Command) { cmd.PersistentFlags().BoolVarP(&opts.useInsecureTLS, "insecure", "k", false, "Allow insecure server connections when using SSL") cmd.PersistentFlags().StringVarP(&opts.serverfolder.name, "serverfolder", "f", "", "Grafana folder name for dashboards") cmd.PersistentFlags().StringVarP(&opts.dir, "directory", "d", "", "When importing, import dashboards from this local directory.\nWhen exporting, local directory to write dashboards to") + _ = cmd.PersistentFlags().MarkHidden("svm-variable-regex") _ = cmd.MarkPersistentFlagRequired("serverfolder") _ = cmd.MarkPersistentFlagRequired("directory") } diff --git a/cmd/tools/grafana/grafana_test.go b/cmd/tools/grafana/grafana_test.go index 4d88a7b51..9096d5310 100644 --- a/cmd/tools/grafana/grafana_test.go +++ b/cmd/tools/grafana/grafana_test.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "github.com/tidwall/gjson" + "path/filepath" "regexp" "strings" "testing" @@ -102,6 +103,32 @@ func TestAddPrefixToMetricNames(t *testing.T) { }) } +func TestAddSvmRegex(t *testing.T) { + + regex := ".*ABC.*" + visitDashboards( + []string{"../../../grafana/dashboards/cmode/svm.json", "../../../grafana/dashboards/cmode/snapmirror.json"}, + func(path string, data []byte) { + file := filepath.Base(path) + out := addSvmRegex(data, file, regex) + if file == "svm.json" { + r := gjson.GetBytes(out, "templating.list.#(name=\"SVM\").regex") + if r.String() != regex { + t.Errorf("path: %s \nExpected: [%s]\n Got: [%s]", path, regex, r.String()) + } + } else if file == "snapmirror.json" { + r := gjson.GetBytes(out, "templating.list.#(name=\"DestinationSVM\").regex") + if r.String() != regex { + t.Errorf("path: %s \nExpected: [%s]\n Got: [%s]", path, regex, r.String()) + } + r = gjson.GetBytes(out, "templating.list.#(name=\"SourceSVM\").regex") + if r.String() != regex { + t.Errorf("path: %s \nExpected: [%s]\n Got: [%s]", path, regex, r.String()) + } + } + }) +} + func getExp(expr string, expressions *[]string) { regex := regexp.MustCompile(`([a-zA-Z0-9_+-]+)\s?{.+?}`) match := regex.FindAllStringSubmatch(expr, -1)