From 3f19a5c390a93e72939e8389a03524cd9347543a Mon Sep 17 00:00:00 2001 From: Samir Faci Date: Sat, 29 May 2021 17:49:15 -0700 Subject: [PATCH] Refactoring --- .vscode/launch.json | 2 +- api/common.go | 12 ++++ api/contract.go | 50 +++++++++++++++ api/dashboards.go | 67 ++++++++------------ api/datasources.go | 34 +++++----- api/filters.go | 131 +++++++++++++++++++++++++++++++++++++++ api/login.go | 31 +++++---- api/support.go | 51 --------------- api/user.go | 14 ++--- cmd/dashboard.go | 9 ++- cmd/dashboardClear.go | 3 +- cmd/dashboardExport.go | 5 +- cmd/dashboardImport.go | 3 +- cmd/dashboardList.go | 3 +- cmd/datasources.go | 8 +-- cmd/datasourcesClear.go | 3 +- cmd/datasourcesExport.go | 3 +- cmd/datasourcesImport.go | 3 +- cmd/datasourcesList.go | 2 +- cmd/root.go | 19 ++---- cmd/userPromote.go | 3 +- cmd/usersList.go | 3 +- go.mod | 2 + go.sum | 6 ++ 24 files changed, 289 insertions(+), 178 deletions(-) create mode 100644 api/contract.go create mode 100644 api/filters.go delete mode 100644 api/support.go diff --git a/.vscode/launch.json b/.vscode/launch.json index 5c8a830d..63749d9f 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -11,7 +11,7 @@ "mode": "debug", "program": "${workspaceFolder}", "args": [ - "users", + "dash", "list", //"promote", //"-u", diff --git a/api/common.go b/api/common.go index d8c699c5..5fda1e71 100644 --- a/api/common.go +++ b/api/common.go @@ -1,6 +1,7 @@ package api import ( + "context" "fmt" "os" "path/filepath" @@ -74,3 +75,14 @@ func findAllFiles(folder string) []string { return fileList } + +//getFolderNameIDMap helper function to build a mapping for name to folderID +func getFolderNameIDMap(client *sdk.Client, ctx context.Context) map[string]int { + + folders, _ := client.GetAllFolders(ctx) + var folderMap map[string]int = make(map[string]int) + for _, folder := range folders { + folderMap[folder.Title] = folder.ID + } + return folderMap +} diff --git a/api/contract.go b/api/contract.go new file mode 100644 index 00000000..f6ca313f --- /dev/null +++ b/api/contract.go @@ -0,0 +1,50 @@ +package api + +import ( + "github.com/netsage-project/grafana-dashboard-manager/config" + "github.com/netsage-project/sdk" + "github.com/spf13/viper" +) + +type ApiService interface { + //Dashboard + ListDashboards(filter Filter) []sdk.FoundBoard + ImportDashboards(filter Filter) []string + ExportDashboards(filter Filter) + DeleteAllDashboards(filter Filter) []string + //DataSources + ListDataSources(filter Filter) []sdk.Datasource + ImportDataSources(filter Filter) []string + ExportDataSources(filter Filter) []string + DeleteAllDataSources(filter Filter) []string + //Login + Login() *sdk.Client + AdminLogin() *sdk.Client + //User + ListUsers() []sdk.User + PromoteUser(userLogin string) (*sdk.StatusMessage, error) +} + +type DashNGoImpl struct { + client *sdk.Client + adminClient *sdk.Client + grafanaConf *config.GrafanaConfig + configRef *viper.Viper + debug bool +} + +func (s *DashNGoImpl) init() { + s.grafanaConf = config.GetDefaultGrafanaConfig() + s.configRef = config.Config() + s.client = s.Login() + s.adminClient = s.AdminLogin() + s.debug = s.configRef.GetBool("global.debug") + +} + +func NewApiService() ApiService { + d := &DashNGoImpl{} + d.init() + return d + +} diff --git a/api/dashboards.go b/api/dashboards.go index f1737ae8..8fd78b48 100644 --- a/api/dashboards.go +++ b/api/dashboards.go @@ -7,10 +7,8 @@ import ( "io/ioutil" "os" "path/filepath" - "regexp" "strings" - "github.com/spf13/viper" "github.com/tidwall/pretty" "github.com/netsage-project/sdk" @@ -21,10 +19,10 @@ import ( //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 { +func (s *DashNGoImpl) ListDashboards(filters Filter) []sdk.FoundBoard { ctx := context.Background() var boardsList []sdk.FoundBoard = make([]sdk.FoundBoard, 0) - boardLinks, err := client.SearchDashboards(ctx, "", false) + boardLinks, err := s.client.SearchDashboards(ctx, "", false) if err != nil { panic(err) } @@ -47,8 +45,8 @@ func ListDashboards(client *sdk.Client, filters *DashboardFilter) []sdk.FoundBoa continue } updateSlug(&link) - if filters.DashFilter != "" { - if link.Slug == filters.DashFilter { + if filters.GetFilter("DashFilter") != "" { + if link.Slug == filters.GetFilter("DashFilter") { validUid = true } else { validUid = false @@ -70,7 +68,7 @@ func ListDashboards(client *sdk.Client, filters *DashboardFilter) []sdk.FoundBoa } //ImportDashboards saves all dashboards matching query to configured location -func ImportDashboards(client *sdk.Client, filter DashboardFilter, conf *viper.Viper) []string { +func (s *DashNGoImpl) ImportDashboards(filter Filter) []string { var ( boardLinks []sdk.FoundBoard rawBoard []byte @@ -79,14 +77,14 @@ func ImportDashboards(client *sdk.Client, filter DashboardFilter, conf *viper.Vi ) ctx := context.Background() - boardLinks = ListDashboards(client, &filter) + boardLinks = s.ListDashboards(filter) var boards []string = make([]string, 0) for _, link := range boardLinks { - if rawBoard, meta, err = client.GetRawDashboardByUID(ctx, link.UID); err != nil { + if rawBoard, meta, err = s.client.GetRawDashboardByUID(ctx, link.UID); err != nil { fmt.Fprintf(os.Stderr, "%s for %s\n", err, link.URI) continue } - fileName := fmt.Sprintf("%s/%s.json", buildDashboardPath(conf, link.FolderTitle), meta.Slug) + fileName := fmt.Sprintf("%s/%s.json", buildDashboardPath(s.configRef, link.FolderTitle), meta.Slug) if err = ioutil.WriteFile(fileName, pretty.Pretty(rawBoard), os.FileMode(int(0666))); err != nil { fmt.Fprintf(os.Stderr, "%s for %s\n", err, meta.Slug) } else { @@ -97,24 +95,14 @@ func ImportDashboards(client *sdk.Client, filter DashboardFilter, conf *viper.Vi return boards } -//getFolderNameIDMap helper function to build a mapping for name to folderID -func getFolderNameIDMap(client *sdk.Client, ctx context.Context) map[string]int { - - folders, _ := client.GetAllFolders(ctx) - var folderMap map[string]int = make(map[string]int, 0) - for _, folder := range folders { - folderMap[folder.Title] = folder.ID - } - return folderMap -} - //ExportDashboards finds all the dashboards in the configured location and exports them to grafana. // if the folde doesn't exist, it'll be created. -func ExportDashboards(client *sdk.Client, filters DashboardFilter, conf *viper.Viper) { - filesInDir := findAllFiles(getResourcePath(conf, "dashboard")) +// if the folde doesn't exist, it'll be created. +func (s *DashNGoImpl) ExportDashboards(filters Filter) { + filesInDir := findAllFiles(getResourcePath(s.configRef, "dashboard")) ctx := context.Background() var rawBoard []byte - folderMap := getFolderNameIDMap(client, ctx) + folderMap := getFolderNameIDMap(s.client, ctx) var err error var folderName string = "" var folderId int @@ -142,6 +130,7 @@ func ExportDashboards(client *sdk.Client, filters DashboardFilter, conf *viper.V folderId = sdk.DefaultFolderId folderName = DefaultFolderName } + validateMap := map[string]string{FolderFilter: folderName, DashFilter: baseFile} if folderName == DefaultFolderName { folderId = sdk.DefaultFolderId @@ -149,12 +138,9 @@ func ExportDashboards(client *sdk.Client, filters DashboardFilter, conf *viper.V if val, ok := folderMap[folderName]; ok { folderId = val } else { - createFolder := filters.ValidateFolder(folderName) - validUid := filters.ValidateDashboard(baseFile) - - if createFolder && validUid { + if filters.Validate(validateMap) { folder := sdk.Folder{Title: folderName} - folder, err = client.CreateFolder(ctx, folder) + folder, err = s.client.CreateFolder(ctx, folder) if err != nil { panic(err) } @@ -165,15 +151,18 @@ func ExportDashboards(client *sdk.Client, filters DashboardFilter, conf *viper.V } //If folder OR slug is filtered, then skip if it doesn't match - if !filters.Validate(folderName, baseFile) { + if !filters.Validate(validateMap) { continue } title, err := jsonpath.Read(board, "$.title") + if err != nil { + log.Warn("Could not get dashboard title") + } rawTitle := fmt.Sprintf("%v", title) slugName := GetSlug(rawTitle) - if _, err = client.DeleteDashboard(ctx, slugName); err != nil { + if _, err = s.client.DeleteDashboard(ctx, slugName); err != nil { log.Println(err) continue } @@ -186,7 +175,7 @@ func ExportDashboards(client *sdk.Client, filters DashboardFilter, conf *viper.V Dashboard: rawBoard, } - _, err = client.SetRawDashboardWithParam(ctx, request) + _, err = s.client.SetRawDashboardWithParam(ctx, request) if err != nil { log.Printf("error on Exporting dashboard %s", rawTitle) continue @@ -197,14 +186,14 @@ func ExportDashboards(client *sdk.Client, filters DashboardFilter, conf *viper.V //DeleteAllDashboards clears all current dashboards being monitored. Any folder not white listed // will not be affected -func DeleteAllDashboards(client *sdk.Client, filter DashboardFilter) []string { +func (s *DashNGoImpl) DeleteAllDashboards(filter Filter) []string { ctx := context.Background() var dashboards []string = make([]string, 0) - items := ListDashboards(client, &filter) + items := s.ListDashboards(filter) for _, item := range items { - if filter.Validate(item.FolderTitle, item.Slug) { - _, err := client.DeleteDashboardByUID(ctx, item.UID) + if filter.Validate(map[string]string{FolderFilter: item.FolderTitle, DashFilter: item.Slug}) { + _, err := s.client.DeleteDashboardByUID(ctx, item.UID) if err == nil { dashboards = append(dashboards, item.Title) } @@ -213,9 +202,3 @@ func DeleteAllDashboards(client *sdk.Client, filter DashboardFilter) []string { return dashboards } - -var quoteRegex *regexp.Regexp - -func init() { - quoteRegex, _ = regexp.Compile("['\"]+") -} diff --git a/api/datasources.go b/api/datasources.go index 56e4facd..7ed7f050 100644 --- a/api/datasources.go +++ b/api/datasources.go @@ -11,20 +11,19 @@ import ( "github.com/gosimple/slug" "github.com/netsage-project/grafana-dashboard-manager/config" "github.com/netsage-project/sdk" - "github.com/spf13/viper" ) //ListDataSources: list all the currently configured datasources -func ListDataSources(client *sdk.Client, filter DatasourceFilter) []sdk.Datasource { +func (s *DashNGoImpl) ListDataSources(filter Filter) []sdk.Datasource { ctx := context.Background() - ds, err := client.GetAllDatasources(ctx) + ds, err := s.client.GetAllDatasources(ctx) if err != nil { panic(err) } result := make([]sdk.Datasource, 0) for _, item := range ds { - if filter.ValidateDatasource(GetSlug(item.Name)) { + if filter.Validate(map[string]string{Name: GetSlug(item.Name)}) { result = append(result, item) } } @@ -34,7 +33,7 @@ func ListDataSources(client *sdk.Client, filter DatasourceFilter) []sdk.Datasour //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, filter DatasourceFilter, conf *viper.Viper) []string { +func (s *DashNGoImpl) ImportDataSources(filter Filter) []string { var ( datasources []sdk.Datasource dsPacked []byte @@ -42,13 +41,13 @@ func ImportDataSources(client *sdk.Client, filter DatasourceFilter, conf *viper. err error dataFiles []string ) - datasources = ListDataSources(client, filter) + datasources = s.ListDataSources(filter) for _, ds := range datasources { if dsPacked, err = json.MarshalIndent(ds, "", " "); err != nil { fmt.Fprintf(os.Stderr, "%s for %s\n", err, ds.Name) continue } - dsPath := buildDataSourcePath(conf, slug.Make(ds.Name)) + dsPath := buildDataSourcePath(s.configRef, slug.Make(ds.Name)) if err = ioutil.WriteFile(dsPath, dsPacked, os.FileMode(int(0666))); err != nil { fmt.Fprintf(os.Stderr, "%s for %s\n", err, meta.Slug) } else { @@ -59,33 +58,33 @@ func ImportDataSources(client *sdk.Client, filter DatasourceFilter, conf *viper. } //Removes all current datasources -func DeleteAllDataSources(client *sdk.Client, filter DatasourceFilter) []string { +func (s *DashNGoImpl) DeleteAllDataSources(filter Filter) []string { ctx := context.Background() var ds []string = make([]string, 0) - items := ListDataSources(client, filter) + items := s.ListDataSources(filter) for _, item := range items { - client.DeleteDatasource(ctx, item.ID) + s.client.DeleteDatasource(ctx, item.ID) ds = append(ds, item.Name) } return ds } //ExportDataSources: exports all datasources to grafana using the credentials configured in config file. -func ExportDataSources(client *sdk.Client, filter DatasourceFilter, conf *viper.Viper) []string { +func (s *DashNGoImpl) ExportDataSources(filter Filter) []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, filter) + filesInDir, err := ioutil.ReadDir(getResourcePath(s.configRef, "ds")) + datasources = s.ListDataSources(filter) var rawDS []byte if err != nil { fmt.Fprint(os.Stderr, err) } for _, file := range filesInDir { - fileLocation := fmt.Sprintf("%s/%s", getResourcePath(conf, "ds"), file.Name()) + fileLocation := fmt.Sprintf("%s/%s", getResourcePath(s.configRef, "ds"), file.Name()) if strings.HasSuffix(file.Name(), ".json") { if rawDS, err = ioutil.ReadFile(fileLocation); err != nil { fmt.Fprint(os.Stderr, err) @@ -97,7 +96,8 @@ func ExportDataSources(client *sdk.Client, filter DatasourceFilter, conf *viper. fmt.Fprint(os.Stderr, err) continue } - if !filter.ValidateDatasource(GetSlug(newDS.Name)) { + + if !filter.Validate(map[string]string{Name: GetSlug(newDS.Name)}) { continue } dsConfig := config.GetDefaultGrafanaConfig() @@ -122,13 +122,13 @@ func ExportDataSources(client *sdk.Client, filter DatasourceFilter, conf *viper. for _, existingDS := range datasources { if existingDS.Name == newDS.Name { - if status, err = client.DeleteDatasource(ctx, existingDS.ID); err != nil { + if status, err = s.client.DeleteDatasource(ctx, existingDS.ID); err != nil { fmt.Fprintf(os.Stderr, "error on deleting datasource %s with %s", newDS.Name, err) } break } } - if status, err = client.CreateDatasource(ctx, newDS); err != nil { + if status, err = s.client.CreateDatasource(ctx, newDS); err != nil { fmt.Fprintf(os.Stderr, "error on importing datasource %s with %s (%s)", newDS.Name, err, *status.Message) } else { exported = append(exported, fileLocation) diff --git a/api/filters.go b/api/filters.go new file mode 100644 index 00000000..9bdda105 --- /dev/null +++ b/api/filters.go @@ -0,0 +1,131 @@ +package api + +import ( + "regexp" + "strings" + + "github.com/netsage-project/grafana-dashboard-manager/config" + "github.com/thoas/go-funk" +) + +//Currently supported filters +const ( + DashFilter = "DashFilter" + FolderFilter = "FolderFilter" + Name = "Name" +) + +type Filter interface { + GetTypes() []string //Return list of active Filter Types + GetFilter(key string) string //Get the Filter value + AddFilter(key, value string) //Add a filter query + Validate(items map[string]string) bool //Validate if Entry is valid + GetFolders() []string //List of supported folders if Any +} + +type BaseFilter struct { + Filters map[string]string +} + +//GetTypes returns all the current keys for the configured Filter +func (s BaseFilter) GetTypes() []string { + keys := funk.Keys(s.Filters) + return keys.([]string) +} + +//GetFilter returns the value of the filter +func (s BaseFilter) GetFilter(key string) string { + if val, ok := s.Filters[key]; ok { + return val + } + return "" +} + +//AddFilter adds a filter and the corresponding value +func (s BaseFilter) AddFilter(key, value string) { + s.Filters[key] = value +} + +func (s *BaseFilter) Init() { + s.Filters = make(map[string]string) +} + +type DashboardFilter struct { + quoteRegex *regexp.Regexp + BaseFilter +} + +//NewDashboardFilter creates a new dashboard filter +func NewDashboardFilter() *DashboardFilter { + s := DashboardFilter{} + s.init() + return &s + +} + +func (s *DashboardFilter) init() { + s.BaseFilter.Init() + s.quoteRegex, _ = regexp.Compile("['\"]+") +} + +//GetFolders splits the comma delimited folder list and returns a slice +func (s *DashboardFilter) GetFolders() []string { + if s.GetFilter(FolderFilter) == "" { + return config.GetDefaultGrafanaConfig().GetMonitoredFolders() + } + folderFilter := s.GetFilter(FolderFilter) + folderFilter = s.quoteRegex.ReplaceAllString(folderFilter, "") + s.AddFilter(FolderFilter, folderFilter) + + return strings.Split(folderFilter, ",") +} + +func (s DashboardFilter) validateDashboard(dashUid string) bool { + if s.GetFilter(DashFilter) == "" { + return true + } + return dashUid == s.GetFilter(DashFilter) +} + +func (s DashboardFilter) Validate(items map[string]string) bool { + var folderCheck, dashboardCheck bool + //Check folder + if folderFilter, ok := items[FolderFilter]; ok { + folderCheck = s.validateFolder(folderFilter) + } else { + folderCheck = true + } + + //check Dash + if dashFilter, ok := items[DashFilter]; ok { + dashboardCheck = s.validateDashboard(dashFilter) + } else { + dashboardCheck = true + } + return folderCheck && dashboardCheck +} + +func (s DashboardFilter) validateFolder(folder string) bool { + if s.GetFilter(FolderFilter) == "" { + return true + } + return folder == s.GetFilter(FolderFilter) +} + +type DatasourceFilter struct { + BaseFilter +} + +//GetFolders return empty list since Folders NA for datasources +func (s DatasourceFilter) GetFolders() []string { + return []string{} +} + +//Validate returns true if mapped values are valid +func (s DatasourceFilter) Validate(items map[string]string) bool { + if s.GetFilter(Name) == "" { + return true + } + return items[Name] == s.GetFilter(Name) + +} diff --git a/api/login.go b/api/login.go index 2d0c6ab0..1ebba1bb 100644 --- a/api/login.go +++ b/api/login.go @@ -3,40 +3,39 @@ package api import ( "fmt" - "github.com/netsage-project/grafana-dashboard-manager/config" "github.com/netsage-project/sdk" ) //Login: Logs into grafana returning a client instance using Token or Basic Auth -func Login(grafanaConf *config.GrafanaConfig) *sdk.Client { - if grafanaConf.APIToken != "" { - return tokenLogin(grafanaConf.URL, grafanaConf.APIToken) - } else if grafanaConf.UserName != "" && grafanaConf.Password != "" { - return authLogin(grafanaConf.URL, grafanaConf.UserName, grafanaConf.Password) +func (s *DashNGoImpl) Login() *sdk.Client { + if s.grafanaConf.APIToken != "" { + return s.tokenLogin() + } else if s.grafanaConf.UserName != "" && s.grafanaConf.Password != "" { + return s.authLogin() } panic("Invalid auth configuration. Either Token or password based credentials required") } -func AdminLogin(grafanaConf *config.GrafanaConfig) *sdk.Client { - if grafanaConf.UserName != "" && grafanaConf.Password != "" { - grafanaConf.AdminEnabled = true - return authLogin(grafanaConf.URL, grafanaConf.UserName, grafanaConf.Password) +func (s *DashNGoImpl) AdminLogin() *sdk.Client { + if s.grafanaConf.UserName != "" && s.grafanaConf.Password != "" { + s.grafanaConf.AdminEnabled = true + return s.authLogin() } else { - grafanaConf.AdminEnabled = false + s.grafanaConf.AdminEnabled = false return nil } } //tokenLogin: given a URL and token return the client -func tokenLogin(url, token string) *sdk.Client { - return sdk.NewClient(url, token, sdk.DefaultHTTPClient) +func (s *DashNGoImpl) tokenLogin() *sdk.Client { + return sdk.NewClient(s.grafanaConf.URL, s.grafanaConf.APIToken, sdk.DefaultHTTPClient) } //AuthLogin: Login using a username/password -func authLogin(url, username, password string) *sdk.Client { - basicAuth := fmt.Sprintf("%s:%s", username, password) - return sdk.NewClient(url, basicAuth, sdk.DefaultHTTPClient) +func (s *DashNGoImpl) authLogin() *sdk.Client { + basicAuth := fmt.Sprintf("%s:%s", s.grafanaConf.UserName, s.grafanaConf.Password) + return sdk.NewClient(s.grafanaConf.URL, basicAuth, sdk.DefaultHTTPClient) } diff --git a/api/support.go b/api/support.go deleted file mode 100644 index 404b8370..00000000 --- a/api/support.go +++ /dev/null @@ -1,51 +0,0 @@ -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/api/user.go b/api/user.go index 6ef630f3..1897f512 100644 --- a/api/user.go +++ b/api/user.go @@ -19,10 +19,10 @@ func validateUserAPI(client *sdk.Client) { } //ListUsers list all grafana users -func ListUsers(client *sdk.Client) []sdk.User { +func (s *DashNGoImpl) ListUsers() []sdk.User { ctx := context.Background() - validateUserAPI(client) - users, err := client.GetAllUsers(ctx) + validateUserAPI(s.adminClient) + users, err := s.adminClient.GetAllUsers(ctx) if err != nil { logrus.Fatal(err) } @@ -30,12 +30,12 @@ func ListUsers(client *sdk.Client) []sdk.User { } //PromoteUser promote the user to have Admin Access -func PromoteUser(client *sdk.Client, userLogin string) (*sdk.StatusMessage, error) { +func (s *DashNGoImpl) PromoteUser(userLogin string) (*sdk.StatusMessage, error) { - validateUserAPI(client) + validateUserAPI(s.adminClient) ctx := context.Background() //Get all users - users := ListUsers(client) + users := s.ListUsers() var user *sdk.User for _, item := range users { if item.Login == userLogin { @@ -52,7 +52,7 @@ func PromoteUser(client *sdk.Client, userLogin string) (*sdk.StatusMessage, erro role := sdk.UserPermissions{ IsGrafanaAdmin: true, } - msg, err := client.UpdateUserPermissions(ctx, role, user.ID) + msg, err := s.adminClient.UpdateUserPermissions(ctx, role, user.ID) if err != nil { errorMsg := fmt.Sprintf("failed to promote user: '%s'", userLogin) logrus.Error(errorMsg) diff --git a/cmd/dashboard.go b/cmd/dashboard.go index 6f18b954..61223085 100644 --- a/cmd/dashboard.go +++ b/cmd/dashboard.go @@ -5,14 +5,13 @@ import ( "github.com/spf13/cobra" ) -func getDashboardGlobalFlags(cmd *cobra.Command) api.DashboardFilter { +func getDashboardGlobalFlags(cmd *cobra.Command) api.Filter { folderFilter, _ := cmd.Flags().GetString("folder") dashboardFilter, _ := cmd.Flags().GetString("dashboard") - filters := api.DashboardFilter{ - FolderFilter: folderFilter, - DashFilter: dashboardFilter, - } + filters := api.NewDashboardFilter() + filters.AddFilter(api.FolderFilter, folderFilter) + filters.AddFilter(api.DashFilter, dashboardFilter) return filters diff --git a/cmd/dashboardClear.go b/cmd/dashboardClear.go index 834b45a0..e5249160 100644 --- a/cmd/dashboardClear.go +++ b/cmd/dashboardClear.go @@ -2,7 +2,6 @@ package cmd import ( "github.com/jedib0t/go-pretty/table" - "github.com/netsage-project/grafana-dashboard-manager/api" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -13,7 +12,7 @@ var ClearDashboards = &cobra.Command{ Long: `clear all monitored dashboards from grafana`, Run: func(cmd *cobra.Command, args []string) { filter := getDashboardGlobalFlags(cmd) - deletedDashboards := api.DeleteAllDashboards(client, filter) + deletedDashboards := client.DeleteAllDashboards(filter) tableObj.AppendHeader(table.Row{"type", "filename"}) for _, file := range deletedDashboards { tableObj.AppendRow(table.Row{"dashboard", file}) diff --git a/cmd/dashboardExport.go b/cmd/dashboardExport.go index db840edb..7c691357 100644 --- a/cmd/dashboardExport.go +++ b/cmd/dashboardExport.go @@ -2,7 +2,6 @@ package cmd import ( "github.com/jedib0t/go-pretty/table" - "github.com/netsage-project/grafana-dashboard-manager/api" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -14,10 +13,10 @@ var exportDashboard = &cobra.Command{ Run: func(cmd *cobra.Command, args []string) { filter := getDashboardGlobalFlags(cmd) - api.ExportDashboards(client, filter, configProvider) + client.ExportDashboards(filter) tableObj.AppendHeader(table.Row{"Title", "id", "folder", "UID"}) - boards := api.ListDashboards(client, &filter) + boards := client.ListDashboards(filter) for _, link := range boards { tableObj.AppendRow(table.Row{link.Title, link.ID, link.FolderTitle, link.UID}) diff --git a/cmd/dashboardImport.go b/cmd/dashboardImport.go index 19e1f16b..95fff252 100644 --- a/cmd/dashboardImport.go +++ b/cmd/dashboardImport.go @@ -2,7 +2,6 @@ package cmd import ( "github.com/jedib0t/go-pretty/table" - "github.com/netsage-project/grafana-dashboard-manager/api" "github.com/netsage-project/grafana-dashboard-manager/config" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -14,7 +13,7 @@ var importDashboard = &cobra.Command{ Long: `Import all dashboards from grafana to local file system`, Run: func(cmd *cobra.Command, args []string) { filter := getDashboardGlobalFlags(cmd) - savedFiles := api.ImportDashboards(client, filter, configProvider) + savedFiles := client.ImportDashboards(filter) log.Infof("Importing dashboards for context: '%s'", config.GetContext()) tableObj.AppendHeader(table.Row{"type", "filename"}) for _, file := range savedFiles { diff --git a/cmd/dashboardList.go b/cmd/dashboardList.go index 5488c680..e8b96801 100644 --- a/cmd/dashboardList.go +++ b/cmd/dashboardList.go @@ -4,7 +4,6 @@ import ( "fmt" "github.com/jedib0t/go-pretty/table" - "github.com/netsage-project/grafana-dashboard-manager/api" "github.com/netsage-project/grafana-dashboard-manager/config" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -18,7 +17,7 @@ var listDashboards = &cobra.Command{ tableObj.AppendHeader(table.Row{"id", "Title", "Slug", "Folder", "UID", "URL"}) filters := getDashboardGlobalFlags(cmd) - boards := api.ListDashboards(client, &filters) + boards := client.ListDashboards(filters) log.Infof("Listing dashboards for context: '%s'", config.GetContext()) for _, link := range boards { diff --git a/cmd/datasources.go b/cmd/datasources.go index 77c08409..60e3aba9 100644 --- a/cmd/datasources.go +++ b/cmd/datasources.go @@ -5,12 +5,12 @@ import ( "github.com/spf13/cobra" ) -func getDatasourcesGlobalFlags(cmd *cobra.Command) api.DatasourceFilter { +func getDatasourcesGlobalFlags(cmd *cobra.Command) api.Filter { dashboardFilter, _ := cmd.Flags().GetString("datasource") - filters := api.DatasourceFilter{ - Name: dashboardFilter, - } + filters := api.DatasourceFilter{} + filters.Init() + filters.AddFilter("Name", dashboardFilter) return filters diff --git a/cmd/datasourcesClear.go b/cmd/datasourcesClear.go index ec4673db..1a4d8cd7 100644 --- a/cmd/datasourcesClear.go +++ b/cmd/datasourcesClear.go @@ -2,7 +2,6 @@ package cmd import ( "github.com/jedib0t/go-pretty/table" - "github.com/netsage-project/grafana-dashboard-manager/api" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -14,7 +13,7 @@ var ClearDataSources = &cobra.Command{ Run: func(cmd *cobra.Command, args []string) { log.Info("Delete datasources") filters := getDatasourcesGlobalFlags(cmd) - savedFiles := api.DeleteAllDataSources(client, filters) + savedFiles := client.DeleteAllDataSources(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 d6582a3a..ceedf9d9 100644 --- a/cmd/datasourcesExport.go +++ b/cmd/datasourcesExport.go @@ -2,7 +2,6 @@ package cmd import ( "github.com/jedib0t/go-pretty/table" - "github.com/netsage-project/grafana-dashboard-manager/api" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -14,7 +13,7 @@ var exportDataSources = &cobra.Command{ Run: func(cmd *cobra.Command, args []string) { log.Info("Exporting datasources") filters := getDatasourcesGlobalFlags(cmd) - exportedList := api.ExportDataSources(client, filters, configProvider) + exportedList := client.ExportDataSources(filters) 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 e391c0ed..f64c9d4b 100644 --- a/cmd/datasourcesImport.go +++ b/cmd/datasourcesImport.go @@ -2,7 +2,6 @@ package cmd import ( "github.com/jedib0t/go-pretty/table" - "github.com/netsage-project/grafana-dashboard-manager/api" "github.com/netsage-project/grafana-dashboard-manager/config" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -15,7 +14,7 @@ var ImportDataSources = &cobra.Command{ Run: func(cmd *cobra.Command, args []string) { log.Infof("Importing datasources for context: '%s'", config.GetContext()) filters := getDatasourcesGlobalFlags(cmd) - savedFiles := api.ImportDataSources(client, filters, configProvider) + savedFiles := client.ImportDataSources(filters) 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 41990679..31412776 100644 --- a/cmd/datasourcesList.go +++ b/cmd/datasourcesList.go @@ -17,7 +17,7 @@ var listDataSources = &cobra.Command{ Run: func(cmd *cobra.Command, args []string) { tableObj.AppendHeader(table.Row{"id", "name", "slug", "type", "default", "url"}) filters := getDatasourcesGlobalFlags(cmd) - datasources := api.ListDataSources(client, filters) + datasources := client.ListDataSources(filters) log.Infof("Listing datasources for context: '%s'", config.GetContext()) if len(datasources) == 0 { log.Info("No datasources found") diff --git a/cmd/root.go b/cmd/root.go index 41cb9076..36cc3d24 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -9,17 +9,12 @@ import ( "github.com/netsage-project/grafana-dashboard-manager/api" "github.com/netsage-project/grafana-dashboard-manager/config" - "github.com/netsage-project/sdk" "github.com/spf13/cobra" - "github.com/spf13/viper" ) var ( - configProvider *viper.Viper - client *sdk.Client - adminClient *sdk.Client - tableObj table.Writer - debug bool + tableObj table.Writer + client api.ApiService ) // rootCmd represents the base command when called without any subcommands @@ -51,7 +46,7 @@ func init() { } func initConfig() { - configProvider = config.Config() + configProvider := config.Config() setupGrafanaClient() log.Debug("Creating output locations") dir := configProvider.GetString("env.output.datasources") @@ -63,15 +58,9 @@ func initConfig() { tableObj.SetOutputMirror(os.Stdout) tableObj.SetStyle(table.StyleLight) - // Cobra also supports local flags, which will only run - // when this action is called directly. - debug = configProvider.GetBool("global.debug") - } func setupGrafanaClient() { - grafana := config.GetDefaultGrafanaConfig() - client = api.Login(grafana) - adminClient = api.AdminLogin(grafana) + client = api.NewApiService() } diff --git a/cmd/userPromote.go b/cmd/userPromote.go index 70d2f23b..5459f405 100644 --- a/cmd/userPromote.go +++ b/cmd/userPromote.go @@ -1,7 +1,6 @@ package cmd import ( - "github.com/netsage-project/grafana-dashboard-manager/api" "github.com/netsage-project/grafana-dashboard-manager/config" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -17,7 +16,7 @@ var promoteUser = &cobra.Command{ log.Infof("Listing dashboards for context: '%s'", config.GetContext()) userLogin, _ := cmd.Flags().GetString("user") - msg, err := api.PromoteUser(adminClient, userLogin) + msg, err := client.PromoteUser(userLogin) if err != nil { log.Error(err.Error()) } else { diff --git a/cmd/usersList.go b/cmd/usersList.go index 71d77d13..8143531b 100644 --- a/cmd/usersList.go +++ b/cmd/usersList.go @@ -4,7 +4,6 @@ import ( "strings" "github.com/jedib0t/go-pretty/table" - "github.com/netsage-project/grafana-dashboard-manager/api" "github.com/netsage-project/grafana-dashboard-manager/config" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -18,7 +17,7 @@ var listUserCmd = &cobra.Command{ log.Infof("Listing dashboards for context: '%s'", config.GetContext()) tableObj.AppendHeader(table.Row{"id", "login", "name", "email", "admin", "grafanaAdmin", "disabled", "authLabels"}) - users := api.ListUsers(adminClient) + users := client.ListUsers() if len(users) == 0 { log.Info("No users found") } else { diff --git a/go.mod b/go.mod index be0a84a8..d9703cba 100644 --- a/go.mod +++ b/go.mod @@ -8,10 +8,12 @@ require ( github.com/go-openapi/strfmt v0.20.1 // indirect github.com/gosimple/slug v1.9.0 github.com/jedib0t/go-pretty v4.3.0+incompatible + github.com/jinzhu/copier v0.3.0 // indirect github.com/mattn/go-runewidth v0.0.12 // indirect github.com/mitchellh/mapstructure v1.4.1 // indirect github.com/netsage-project/sdk v0.1.3-0.20210512193805-a3b05178eae0 github.com/rivo/uniseg v0.2.0 // indirect + github.com/rjeczalik/interfaces v0.1.1 // indirect github.com/sirupsen/logrus v1.6.0 github.com/spf13/cobra v1.0.0 github.com/spf13/viper v1.7.1 diff --git a/go.sum b/go.sum index f77bb1ce..bb37cab9 100644 --- a/go.sum +++ b/go.sum @@ -157,6 +157,8 @@ github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NH github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jedib0t/go-pretty v4.3.0+incompatible h1:CGs8AVhEKg/n9YbUenWmNStRW2PHJzaeDodcfvRAbIo= github.com/jedib0t/go-pretty v4.3.0+incompatible/go.mod h1:XemHduiw8R651AF9Pt4FwCTKeG3oo7hrHJAoznj9nag= +github.com/jinzhu/copier v0.3.0 h1:P5zN9OYSxmtzZmwgcVmt5Iu8egfP53BGMPAFgEksKPI= +github.com/jinzhu/copier v0.3.0/go.mod h1:24xnZezI2Yqac9J61UC6/dG/k76ttpq0DdJI3QmUvro= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= @@ -242,6 +244,8 @@ github.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be/go.mod h1:MIDF github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rjeczalik/interfaces v0.1.1 h1:xhFQNGtz3T3CQgtJJwWn+i3Ekl1WeObh7wtTtCbyKT0= +github.com/rjeczalik/interfaces v0.1.1/go.mod h1:TNwD+kCGmXYrXksRDD5ikspp08m/Aosbr67zVLMjnOY= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -398,6 +402,7 @@ golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190501045030-23463209683d/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= @@ -406,6 +411,7 @@ golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc h1:NCy3Ohtk6Iny5V/reW2Ktypo4zIpWBdRJ1uFMjBxdg8= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=