From 6a9719dfe98e6ac963b1e3135ebc4e16f878b7e3 Mon Sep 17 00:00:00 2001 From: Samir Faci Date: Fri, 28 May 2021 14:38:44 -0700 Subject: [PATCH] Adding support for filtering for datasource --- .drone.yml | 6 ++--- .vscode/launch.json | 10 ++------ api/common.go | 15 ++++++++++++ api/dashboards.go | 46 +----------------------------------- api/datasources.go | 25 +++++++++++++------- api/support.go | 51 ++++++++++++++++++++++++++++++++++++++++ cmd/dashboardClear.go | 2 +- cmd/datasources.go | 14 +++++++++++ cmd/datasourcesClear.go | 3 ++- cmd/datasourcesExport.go | 3 ++- cmd/datasourcesImport.go | 3 ++- cmd/datasourcesList.go | 8 +++---- 12 files changed, 113 insertions(+), 73 deletions(-) create mode 100644 api/support.go diff --git a/.drone.yml b/.drone.yml index 658f0d7b..28205787 100644 --- a/.drone.yml +++ b/.drone.yml @@ -8,7 +8,5 @@ steps: - make linux - cp conf/importer-example.yml conf/importer.yml - make test - - ./bin/grafana-dashboard-manager_linux version - - name: release - when: - event: tag + - ./bin/gdg_linux version + diff --git a/.vscode/launch.json b/.vscode/launch.json index 7fd64134..5c8a830d 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -11,14 +11,8 @@ "mode": "debug", "program": "${workspaceFolder}", "args": [ - "dash", - "export", - // "-f", - // "'General'", - "-d", - "monitored-query-diagnostics" - // "--context", - // "prod" + "users", + "list", //"promote", //"-u", //"user@domain.com" diff --git a/api/common.go b/api/common.go index be40b74a..d8c699c5 100644 --- a/api/common.go +++ b/api/common.go @@ -4,14 +4,29 @@ import ( "fmt" "os" "path/filepath" + "strings" + "github.com/gosimple/slug" "github.com/netsage-project/grafana-dashboard-manager/config" + "github.com/netsage-project/sdk" log "github.com/sirupsen/logrus" "github.com/spf13/viper" ) var DefaultFolderName = "General" +func GetSlug(title string) string { + return strings.ToLower(slug.Make(title)) +} + +//Update the slug in the board returned +func updateSlug(board *sdk.FoundBoard) { + elements := strings.Split(board.URI, "/") + if len(elements) > 1 { + board.Slug = elements[len(elements)-1] + } +} + //buildDashboardPath returns the dashboard path for a given folder func buildDashboardPath(conf *viper.Viper, folderName string) string { if folderName == "" { diff --git a/api/dashboards.go b/api/dashboards.go index 46b669cf..f1737ae8 100644 --- a/api/dashboards.go +++ b/api/dashboards.go @@ -10,59 +10,15 @@ import ( "regexp" "strings" - "github.com/gosimple/slug" "github.com/spf13/viper" "github.com/tidwall/pretty" - "github.com/netsage-project/grafana-dashboard-manager/config" - "github.com/netsage-project/sdk" log "github.com/sirupsen/logrus" "github.com/thoas/go-funk" "github.com/yalp/jsonpath" ) -type DashboardFilter struct { - FolderFilter string // Name of Folder - DashFilter string //name of dashboard -} - -//GetFolders splits the comma delimited folder list and returns a slice -func (s *DashboardFilter) GetFolders() []string { - if s.FolderFilter == "" { - return config.GetDefaultGrafanaConfig().GetMonitoredFolders() - } - s.FolderFilter = quoteRegex.ReplaceAllString(s.FolderFilter, "") - - return strings.Split(s.FolderFilter, ",") -} - -func (s DashboardFilter) ValidateDashboard(dashUid string) bool { - if s.DashFilter == "" { - return true - } - return dashUid == s.DashFilter -} - -func (s DashboardFilter) Validate(folder, dashUid string) bool { - return s.ValidateDashboard(dashUid) && s.ValidateFolder(folder) -} - -func (s DashboardFilter) ValidateFolder(folder string) bool { - if s.FolderFilter == "" { - return true - } - return folder == s.FolderFilter -} - -//Update the slug in the board returned -func updateSlug(board *sdk.FoundBoard) { - elements := strings.Split(board.URI, "/") - if len(elements) > 1 { - board.Slug = elements[len(elements)-1] - } -} - //ListDashboards: List all dashboards optionally filtered by folder name. If folderFilters // is blank, defaults to the configured Monitored folders func ListDashboards(client *sdk.Client, filters *DashboardFilter) []sdk.FoundBoard { @@ -216,7 +172,7 @@ func ExportDashboards(client *sdk.Client, filters DashboardFilter, conf *viper.V title, err := jsonpath.Read(board, "$.title") rawTitle := fmt.Sprintf("%v", title) - slugName := strings.ToLower(slug.Make(rawTitle)) + slugName := GetSlug(rawTitle) if _, err = client.DeleteDashboard(ctx, slugName); err != nil { log.Println(err) continue diff --git a/api/datasources.go b/api/datasources.go index 1c04b238..56e4facd 100644 --- a/api/datasources.go +++ b/api/datasources.go @@ -15,20 +15,26 @@ import ( ) //ListDataSources: list all the currently configured datasources -func ListDataSources(client *sdk.Client, folderFilters []string) []sdk.Datasource { +func ListDataSources(client *sdk.Client, filter DatasourceFilter) []sdk.Datasource { ctx := context.Background() ds, err := client.GetAllDatasources(ctx) if err != nil { panic(err) } + result := make([]sdk.Datasource, 0) + for _, item := range ds { + if filter.ValidateDatasource(GetSlug(item.Name)) { + result = append(result, item) + } + } - return ds + return result } //ImportDataSources: will read in all the configured datasources. //NOTE: credentials cannot be retrieved and need to be set via configuration -func ImportDataSources(client *sdk.Client, conf *viper.Viper) []string { +func ImportDataSources(client *sdk.Client, filter DatasourceFilter, conf *viper.Viper) []string { var ( datasources []sdk.Datasource dsPacked []byte @@ -36,7 +42,7 @@ func ImportDataSources(client *sdk.Client, conf *viper.Viper) []string { err error dataFiles []string ) - datasources = ListDataSources(client, nil) + datasources = ListDataSources(client, filter) for _, ds := range datasources { if dsPacked, err = json.MarshalIndent(ds, "", " "); err != nil { fmt.Fprintf(os.Stderr, "%s for %s\n", err, ds.Name) @@ -53,10 +59,10 @@ func ImportDataSources(client *sdk.Client, conf *viper.Viper) []string { } //Removes all current datasources -func DeleteAllDataSources(client *sdk.Client) []string { +func DeleteAllDataSources(client *sdk.Client, filter DatasourceFilter) []string { ctx := context.Background() var ds []string = make([]string, 0) - items := ListDataSources(client, nil) + items := ListDataSources(client, filter) for _, item := range items { client.DeleteDatasource(ctx, item.ID) ds = append(ds, item.Name) @@ -65,14 +71,14 @@ func DeleteAllDataSources(client *sdk.Client) []string { } //ExportDataSources: exports all datasources to grafana using the credentials configured in config file. -func ExportDataSources(client *sdk.Client, folderFilters []string, query string, conf *viper.Viper) []string { +func ExportDataSources(client *sdk.Client, filter DatasourceFilter, conf *viper.Viper) []string { var datasources []sdk.Datasource var status sdk.StatusMessage var exported []string = make([]string, 0) ctx := context.Background() filesInDir, err := ioutil.ReadDir(getResourcePath(conf, "ds")) - datasources = ListDataSources(client, nil) + datasources = ListDataSources(client, filter) var rawDS []byte if err != nil { @@ -91,6 +97,9 @@ func ExportDataSources(client *sdk.Client, folderFilters []string, query string, fmt.Fprint(os.Stderr, err) continue } + if !filter.ValidateDatasource(GetSlug(newDS.Name)) { + continue + } dsConfig := config.GetDefaultGrafanaConfig() var creds *config.GrafanaDataSource diff --git a/api/support.go b/api/support.go new file mode 100644 index 00000000..404b8370 --- /dev/null +++ b/api/support.go @@ -0,0 +1,51 @@ +package api + +import ( + "strings" + + "github.com/netsage-project/grafana-dashboard-manager/config" +) + +type DashboardFilter struct { + FolderFilter string // Name of Folder + DashFilter string //name of dashboard +} + +//GetFolders splits the comma delimited folder list and returns a slice +func (s *DashboardFilter) GetFolders() []string { + if s.FolderFilter == "" { + return config.GetDefaultGrafanaConfig().GetMonitoredFolders() + } + s.FolderFilter = quoteRegex.ReplaceAllString(s.FolderFilter, "") + + return strings.Split(s.FolderFilter, ",") +} + +func (s DashboardFilter) ValidateDashboard(dashUid string) bool { + if s.DashFilter == "" { + return true + } + return dashUid == s.DashFilter +} + +func (s DashboardFilter) Validate(folder, dashUid string) bool { + return s.ValidateDashboard(dashUid) && s.ValidateFolder(folder) +} + +func (s DashboardFilter) ValidateFolder(folder string) bool { + if s.FolderFilter == "" { + return true + } + return folder == s.FolderFilter +} + +type DatasourceFilter struct { + Name string //name of datasource +} + +func (s DatasourceFilter) ValidateDatasource(name string) bool { + if s.Name == "" { + return true + } + return name == s.Name +} diff --git a/cmd/dashboardClear.go b/cmd/dashboardClear.go index c9e03e71..834b45a0 100644 --- a/cmd/dashboardClear.go +++ b/cmd/dashboardClear.go @@ -22,7 +22,7 @@ var ClearDashboards = &cobra.Command{ log.Info("No dashboards were found. 0 dashboards removed") } else { - log.Infof("%s dashboards were deleted", len(deletedDashboards)) + log.Infof("%d dashboards were deleted", len(deletedDashboards)) tableObj.Render() } diff --git a/cmd/datasources.go b/cmd/datasources.go index 3d22b13d..77c08409 100644 --- a/cmd/datasources.go +++ b/cmd/datasources.go @@ -1,9 +1,21 @@ package cmd import ( + "github.com/netsage-project/grafana-dashboard-manager/api" "github.com/spf13/cobra" ) +func getDatasourcesGlobalFlags(cmd *cobra.Command) api.DatasourceFilter { + dashboardFilter, _ := cmd.Flags().GetString("datasource") + + filters := api.DatasourceFilter{ + Name: dashboardFilter, + } + + return filters + +} + // versionCmd represents the version command var datasources = &cobra.Command{ Use: "datasources", @@ -14,4 +26,6 @@ var datasources = &cobra.Command{ func init() { rootCmd.AddCommand(datasources) + datasources.PersistentFlags().StringP("datasource", "d", "", "filter by datasource slug") + } diff --git a/cmd/datasourcesClear.go b/cmd/datasourcesClear.go index 11d54f58..ec4673db 100644 --- a/cmd/datasourcesClear.go +++ b/cmd/datasourcesClear.go @@ -13,7 +13,8 @@ var ClearDataSources = &cobra.Command{ Long: `clear all datasources from grafana`, Run: func(cmd *cobra.Command, args []string) { log.Info("Delete datasources") - savedFiles := api.DeleteAllDataSources(client) + filters := getDatasourcesGlobalFlags(cmd) + savedFiles := api.DeleteAllDataSources(client, filters) tableObj.AppendHeader(table.Row{"type", "filename"}) for _, file := range savedFiles { tableObj.AppendRow(table.Row{"datasource", file}) diff --git a/cmd/datasourcesExport.go b/cmd/datasourcesExport.go index c557c157..d6582a3a 100644 --- a/cmd/datasourcesExport.go +++ b/cmd/datasourcesExport.go @@ -13,7 +13,8 @@ var exportDataSources = &cobra.Command{ Long: `export all datasources`, Run: func(cmd *cobra.Command, args []string) { log.Info("Exporting datasources") - exportedList := api.ExportDataSources(client, nil, "", configProvider) + filters := getDatasourcesGlobalFlags(cmd) + exportedList := api.ExportDataSources(client, filters, configProvider) tableObj.AppendHeader(table.Row{"type", "filename"}) for _, file := range exportedList { tableObj.AppendRow(table.Row{"datasource", file}) diff --git a/cmd/datasourcesImport.go b/cmd/datasourcesImport.go index b65f7658..e391c0ed 100644 --- a/cmd/datasourcesImport.go +++ b/cmd/datasourcesImport.go @@ -14,7 +14,8 @@ var ImportDataSources = &cobra.Command{ Long: `import all datasources from grafana to local filesystem`, Run: func(cmd *cobra.Command, args []string) { log.Infof("Importing datasources for context: '%s'", config.GetContext()) - savedFiles := api.ImportDataSources(client, configProvider) + filters := getDatasourcesGlobalFlags(cmd) + savedFiles := api.ImportDataSources(client, filters, configProvider) tableObj.AppendHeader(table.Row{"type", "filename"}) for _, file := range savedFiles { tableObj.AppendRow(table.Row{"datasource", file}) diff --git a/cmd/datasourcesList.go b/cmd/datasourcesList.go index 8702aeb0..41990679 100644 --- a/cmd/datasourcesList.go +++ b/cmd/datasourcesList.go @@ -15,16 +15,16 @@ var listDataSources = &cobra.Command{ Short: "List all dashboards", Long: `List all dashboards`, Run: func(cmd *cobra.Command, args []string) { - tableObj.AppendHeader(table.Row{"id", "name", "type", "default", "url"}) - - datasources := api.ListDataSources(client, nil) + tableObj.AppendHeader(table.Row{"id", "name", "slug", "type", "default", "url"}) + filters := getDatasourcesGlobalFlags(cmd) + datasources := api.ListDataSources(client, filters) log.Infof("Listing datasources for context: '%s'", config.GetContext()) if len(datasources) == 0 { log.Info("No datasources found") } else { for _, link := range datasources { url := fmt.Sprintf("%s/datasource/edit/%d", config.GetDefaultGrafanaConfig().URL, link.ID) - tableObj.AppendRow(table.Row{link.ID, link.Name, link.Type, link.IsDefault, url}) + tableObj.AppendRow(table.Row{link.ID, link.Name, api.GetSlug(link.Name), link.Type, link.IsDefault, url}) } tableObj.Render() }