diff --git a/do-backup.go b/do-backup.go index 629349a..f6ae4ea 100644 --- a/do-backup.go +++ b/do-backup.go @@ -32,14 +32,14 @@ func doBackup(opts ...option) { cmd = initCommand(opts...) ) if cmd.applyHierarchically { - backupDashboardsHierchically() + backupDashboardsHierchically(cmd) return } if cmd.applyForBoards { backupDashboards(cmd) } if cmd.applyForDs { - backupDatasources(cmd) + backupDatasources(cmd, nil) } if cmd.applyForUsers { backupUsers(cmd) @@ -48,7 +48,45 @@ func doBackup(opts ...option) { } func backupDashboardsHierchically(cmd *command) { - // TODO db+ds + var ( + boardLinks []sdk.FoundBoard + rawBoard []byte + meta sdk.BoardProperties + board sdk.Board + datasources = make(map[string]bool) + err error + ) + if boardLinks, err = cmd.grafana.SearchDashboards(cmd.boardTitle, cmd.starred, cmd.tags...); err != nil { + fmt.Fprintf(os.Stderr, fmt.Sprintf("%s\n", err)) + os.Exit(1) + } + if cmd.verbose { + fmt.Printf("Found %d dashboards that matched the conditions.\n", len(boardLinks)) + } + for _, link := range boardLinks { + select { + case <-cancel: + exitBySignal() + default: + if rawBoard, meta, err = cmd.grafana.GetRawDashboard(link.URI); err != nil { + fmt.Fprintf(os.Stderr, fmt.Sprintf("%s for %s\n", err, link.URI)) + continue + } + if err = json.Unmarshal(rawBoard, board); err != nil { + fmt.Fprintf(os.Stderr, fmt.Sprintf("error %s parsing %s\n", err, meta.Slug)) + } else { + extractDatasources(datasources, board) + } + var fname = fmt.Sprintf("%s.db.json", meta.Slug) + if err = ioutil.WriteFile(fname, rawBoard, os.FileMode(int(0666))); err != nil { + fmt.Fprintf(os.Stderr, fmt.Sprintf("%s for %s\n", err, meta.Slug)) + continue + } + if cmd.verbose { + fmt.Printf("%s writen into %s.\n", meta.Slug, fname) + } + } + } } func backupDashboards(cmd *command) { @@ -114,7 +152,7 @@ func backupUsers(cmd *command) { } } -func backupDatasources(cmd *command, users ...map[string]bool) { +func backupDatasources(cmd *command, datasources map[string]bool) { var ( allDatasources []sdk.Datasource rawDs []byte @@ -132,6 +170,11 @@ func backupDatasources(cmd *command, users ...map[string]bool) { case <-cancel: exitBySignal() default: + if datasources != nil { + if _, ok := datasources[ds.Name]; !ok { + continue + } + } if rawDs, err = json.Marshal(ds); err != nil { fmt.Fprintf(os.Stderr, "datasource marshal error %s\n", err) continue @@ -148,6 +191,12 @@ func backupDatasources(cmd *command, users ...map[string]bool) { } } -func backupHierarchically(cmd *command) { - +func extractDatasources(datasources map[string]bool, board sdk.Board) { + for _, row := range board.Rows { + for _, panel := range row.Panels { + if panel.Datasource != nil { + datasources[*panel.Datasource] = true + } + } + } } diff --git a/do-object-list.go b/do-object-list.go index dd70e40..6328129 100644 --- a/do-object-list.go +++ b/do-object-list.go @@ -28,7 +28,6 @@ import ( func doObjectList(opts ...option) { var ( cmd = initCommand(opts...) - err error ) if cmd.applyForBoards { listDashboards(cmd) @@ -53,7 +52,7 @@ func listDashboards(cmd *command) { for _, meta := range foundBoards { select { case <-cancel: - exit() + exitBySignal() default: fmt.Printf("<%d> \"%s\" %v ", meta.ID, meta.Title, meta.Tags) if meta.IsStarred { @@ -79,7 +78,7 @@ func listDatasources(cmd *command) { for _, ds := range datasources { select { case <-cancel: - exit() + exitBySignal() default: fmt.Printf("<%d> \"%s\" (%s) %s\n", ds.ID, ds.Name, ds.Type, ds.URL) } @@ -101,7 +100,7 @@ func listUsers(cmd *command) { for _, user := range allUsers { select { case <-cancel: - exit() + exitBySignal() default: fmt.Printf("%s \"%s\" <%s>", user.Login, user.Name, user.Email) if user.IsGrafanaAdmin { @@ -110,7 +109,7 @@ func listUsers(cmd *command) { fmt.Println() } if cmd.verbose { - fmt.Printf("Found %d users.\n", len(users)) + fmt.Printf("Found %d users.\n", len(allUsers)) } } } diff --git a/main.go b/main.go index 0654046..10ab797 100644 --- a/main.go +++ b/main.go @@ -134,7 +134,7 @@ func applyFor(c *command) error { for _, objectKind := range strings.Split(strings.ToLower(*flagApplyFor), ",") { switch objectKind { case "auto": - c.applyForHierarchy = true + c.applyHierarchically = true c.applyForBoards = true c.applyForDs = true case "all":