1package manager 2 3import ( 4 "context" 5 "os" 6 "path/filepath" 7 8 "github.com/grafana/grafana/pkg/bus" 9 "github.com/grafana/grafana/pkg/components/simplejson" 10 "github.com/grafana/grafana/pkg/models" 11 "github.com/grafana/grafana/pkg/plugins" 12 "github.com/grafana/grafana/pkg/services/dashboards" 13) 14 15func (m *PluginManager) GetPluginDashboards(orgID int64, pluginID string) ([]*plugins.PluginDashboardInfoDTO, error) { 16 plugin, exists := m.Plugin(context.TODO(), pluginID) 17 if !exists { 18 return nil, plugins.NotFoundError{PluginID: pluginID} 19 } 20 21 result := make([]*plugins.PluginDashboardInfoDTO, 0) 22 23 // load current dashboards 24 query := models.GetDashboardsByPluginIdQuery{OrgId: orgID, PluginId: pluginID} 25 if err := bus.Dispatch(&query); err != nil { 26 return nil, err 27 } 28 29 existingMatches := make(map[int64]bool) 30 for _, include := range plugin.Includes { 31 if include.Type != plugins.TypeDashboard { 32 continue 33 } 34 35 dashboard, err := m.LoadPluginDashboard(plugin.ID, include.Path) 36 if err != nil { 37 return nil, err 38 } 39 40 res := &plugins.PluginDashboardInfoDTO{} 41 res.Path = include.Path 42 res.PluginId = plugin.ID 43 res.Title = dashboard.Title 44 res.Revision = dashboard.Data.Get("revision").MustInt64(1) 45 46 // find existing dashboard 47 for _, existingDash := range query.Result { 48 if existingDash.Slug == dashboard.Slug { 49 res.DashboardId = existingDash.Id 50 res.Imported = true 51 res.ImportedUri = "db/" + existingDash.Slug 52 res.ImportedUrl = existingDash.GetUrl() 53 res.ImportedRevision = existingDash.Data.Get("revision").MustInt64(1) 54 existingMatches[existingDash.Id] = true 55 } 56 } 57 58 result = append(result, res) 59 } 60 61 // find deleted dashboards 62 for _, dash := range query.Result { 63 if _, exists := existingMatches[dash.Id]; !exists { 64 result = append(result, &plugins.PluginDashboardInfoDTO{ 65 Slug: dash.Slug, 66 DashboardId: dash.Id, 67 Removed: true, 68 }) 69 } 70 } 71 72 return result, nil 73} 74 75func (m *PluginManager) LoadPluginDashboard(pluginID, path string) (*models.Dashboard, error) { 76 plugin, exists := m.Plugin(context.TODO(), pluginID) 77 if !exists { 78 return nil, plugins.NotFoundError{PluginID: pluginID} 79 } 80 81 dashboardFilePath := filepath.Join(plugin.PluginDir, path) 82 // nolint:gosec 83 // We can ignore the gosec G304 warning on this one because `plugin.PluginDir` is based 84 // on plugin folder structure on disk and not user input. `path` comes from the 85 // `plugin.json` configuration file for the loaded plugin 86 reader, err := os.Open(dashboardFilePath) 87 if err != nil { 88 return nil, err 89 } 90 91 defer func() { 92 if err := reader.Close(); err != nil { 93 m.log.Warn("Failed to close file", "path", dashboardFilePath, "err", err) 94 } 95 }() 96 97 data, err := simplejson.NewFromReader(reader) 98 if err != nil { 99 return nil, err 100 } 101 102 return models.NewDashboardFromJson(data), nil 103} 104 105func (m *PluginManager) ImportDashboard(ctx context.Context, pluginID, path string, orgID, folderID int64, dashboardModel *simplejson.Json, 106 overwrite bool, inputs []plugins.ImportDashboardInput, user *models.SignedInUser) (plugins.PluginDashboardInfoDTO, 107 *models.Dashboard, error) { 108 var dashboard *models.Dashboard 109 if pluginID != "" { 110 var err error 111 if dashboard, err = m.LoadPluginDashboard(pluginID, path); err != nil { 112 return plugins.PluginDashboardInfoDTO{}, &models.Dashboard{}, err 113 } 114 } else { 115 dashboard = models.NewDashboardFromJson(dashboardModel) 116 } 117 118 evaluator := &DashTemplateEvaluator{ 119 template: dashboard.Data, 120 inputs: inputs, 121 } 122 123 generatedDash, err := evaluator.Eval() 124 if err != nil { 125 return plugins.PluginDashboardInfoDTO{}, &models.Dashboard{}, err 126 } 127 128 saveCmd := models.SaveDashboardCommand{ 129 Dashboard: generatedDash, 130 OrgId: orgID, 131 UserId: user.UserId, 132 Overwrite: overwrite, 133 PluginId: pluginID, 134 FolderId: folderID, 135 } 136 137 dto := &dashboards.SaveDashboardDTO{ 138 OrgId: orgID, 139 Dashboard: saveCmd.GetDashboardModel(), 140 Overwrite: saveCmd.Overwrite, 141 User: user, 142 } 143 144 savedDash, err := dashboards.NewService(m.sqlStore).ImportDashboard(ctx, dto) 145 if err != nil { 146 return plugins.PluginDashboardInfoDTO{}, &models.Dashboard{}, err 147 } 148 149 return plugins.PluginDashboardInfoDTO{ 150 PluginId: pluginID, 151 Title: savedDash.Title, 152 Path: path, 153 Revision: savedDash.Data.Get("revision").MustInt64(1), 154 FolderId: savedDash.FolderId, 155 ImportedUri: "db/" + savedDash.Slug, 156 ImportedUrl: savedDash.GetUrl(), 157 ImportedRevision: dashboard.Data.Get("revision").MustInt64(1), 158 Imported: true, 159 DashboardId: savedDash.Id, 160 Slug: savedDash.Slug, 161 }, savedDash, nil 162} 163