Skip to content

Commit

Permalink
feat: Dashboard variables set default value on import
Browse files Browse the repository at this point in the history
  • Loading branch information
rahulguptajss committed Dec 20, 2024
1 parent 6f5c2ad commit 9a91aa0
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 0 deletions.
76 changes: 76 additions & 0 deletions cmd/tools/grafana/grafana.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ type options struct {
customizeDir string
customAllValue string
customCluster string
varDefaults string
defaultDropdownMap map[string][]string
}

type Folder struct {
Expand Down Expand Up @@ -437,6 +439,30 @@ func initImportVars() {
}
opts.dirGrafanaFolderMap[k] = v
}

// Parse default dropdown values
opts.defaultDropdownMap = make(map[string][]string)
if opts.varDefaults != "" {
if !validateVarDefaults(opts.varDefaults) {
fmt.Println("Error: Invalid format for --var-defaults. Expected format is 'variable1=value1,value2;variable2=value3'")
os.Exit(1)
}
pairs := strings.Split(opts.varDefaults, ";")
for _, pair := range pairs {
parts := strings.SplitN(pair, "=", 2)
if len(parts) == 2 {
values := strings.Split(parts[1], ",")
opts.defaultDropdownMap[parts[0]] = values
}
}
}
}

// validateVarDefaults validates the format of the --var-defaults input string.
// The expected format is 'variable1=value1,value2;variable2=value3'.
func validateVarDefaults(input string) bool {
re := regexp.MustCompile(`^([^=;,]+=[^=;,]+(,[^=;,]+)*)(;[^=;,]+=[^=;,]+(,[^=;,]+)*)*$`)
return re.MatchString(input)
}

func checkAndCreateServerFolder(folder *Folder) error {
Expand Down Expand Up @@ -519,6 +545,11 @@ func importFiles(dir string, folder *Folder) {
data = changeClusterLabel(data, opts.customCluster)
}

// Set default dropdown values if provided
if len(opts.defaultDropdownMap) > 0 {
data = setDefaultDropdownValues(data, opts.defaultDropdownMap)
}

// 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)
Expand Down Expand Up @@ -590,6 +621,24 @@ func importFiles(dir string, folder *Folder) {
}
}

// setDefaultDropdownValues sets the default values for specified dropdown variables in the dashboard JSON data.
// It takes a map of variable names to their default values and updates the JSON data accordingly.
func setDefaultDropdownValues(data []byte, defaultValues map[string][]string) []byte {
for variable, defaultValues := range defaultValues {
variablePath := fmt.Sprintf("templating.list.#(name=%q)", variable)
variableData := gjson.GetBytes(data, variablePath)
if variableData.Exists() {
current := map[string]any{
"selected": true,
"text": defaultValues,
"value": defaultValues,
}
data, _ = sjson.SetBytes(data, variablePath+".current", current)
}
}
return data
}

// This function will rewrite all panel expressions in the dashboard to use the new cluster label.
// Example:
// sum(write_data{datacenter=~"$Datacenter",cluster=~"$Cluster",svm=~"$SVM"})
Expand Down Expand Up @@ -1293,13 +1342,40 @@ func init() {
addCommonFlags(importCmd, exportCmd, customizeCmd)
addImportExportFlags(importCmd, exportCmd)
addImportCustomizeFlags(importCmd, customizeCmd)
addImportFlags(importCmd)

customizeCmd.PersistentFlags().StringVarP(&opts.customizeDir, "output-dir", "o", "", "Write customized dashboards to the local directory. The directory must not exist")

metricsCmd.PersistentFlags().StringVarP(&opts.dir, "directory", "d",
"", "local directory that contains dashboards (searched recursively).")
}

func addImportFlags(cmd *cobra.Command) {
cmd.PersistentFlags().StringVar(&opts.varDefaults, "var-defaults", "", `
Default values for dropdown variables in the format 'variable1=value1,value2;variable2=value3'.
Examples:
1. Set a single variable:
To set the default value for the 'Datacenter' variable to 'DC1':
--var-defaults "Datacenter=DC1"
2. Set multiple values for a single variable:
To set the default values for the 'Datacenter' variable to 'DC1' and 'DC2':
--var-defaults "Datacenter=DC1,DC2"
3. Set multiple variables in one command:
To set the default values for 'Datacenter' to 'DC1' and 'DC2', and 'Cluster' to 'Cluster1':
--var-defaults "Datacenter=DC1,DC2;Cluster=Cluster1"
4. Set multiple values for multiple variables:
To set the default values for 'Datacenter' to 'DC1' and 'DC2', and 'Cluster' to 'Cluster1' and 'Cluster2':
--var-defaults "Datacenter=DC1,DC2;Cluster=Cluster1,Cluster2"
Note: Ensure that variable names and values do not contain the characters '=', ',', or ';' as these are used as delimiters.
`)
}

func addImportCustomizeFlags(commands ...*cobra.Command) {
for _, cmd := range commands {
cmd.PersistentFlags().StringSliceVar(&opts.labels, "labels", nil,
Expand Down
30 changes: 30 additions & 0 deletions cmd/tools/grafana/grafana_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -675,3 +675,33 @@ func TestClusterRewrite(t *testing.T) {
})
}
}

func TestValidateVarDefaults(t *testing.T) {
tests := []struct {
input string
want bool
}{
{input: "Datacenter=DC1,DC2;Cluster=Cluster1", want: true},
{input: "Datacenter=DC1;Cluster=Cluster1,Cluster2", want: true},
{input: "Datacenter=DC1,DC2;Cluster=Cluster1;Region=US,EU", want: true},
{input: "Datacenter=DC1,DC2;Cluster=Cluster1;Region=US,EU;SVM=SAN,NAS", want: true},
{input: "Datacenter=DC1,DC2", want: true},
{input: "Datacenter=nane,rtp;Cluster=Cluster2,A250-15-28-29", want: true},
{input: "Datacenter=nane,rtp;Cluster=Cluster2,A250-15-28#29", want: true},
{input: "Datacenter=DC1,DC2;", want: false}, // trailing semicolon
{input: "=DC1,DC2;Cluster=Cluster1", want: false}, // missing variable name
{input: "Datacenter=;Cluster=Cluster1", want: false}, // missing value
{input: "Datacenter=DC1,DC2;Cluster=", want: false}, // missing value
{input: "Datacenter=DC1,DC2;Cluster", want: false}, // missing equals sign
{input: "Datacenter=DC1,DC2;Cluster=Cluster1;", want: false}, // trailing semicolon
}

for _, tt := range tests {
t.Run(tt.input, func(t *testing.T) {
got := validateVarDefaults(tt.input)
if got != tt.want {
t.Errorf("validateVarDefaults(%q) = %v, want %v", tt.input, got, tt.want)
}
})
}
}

0 comments on commit 9a91aa0

Please sign in to comment.