| 
									
										
										
										
											2016-02-25 21:55:31 +08:00
										 |  |  | package api | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2020-04-21 22:16:41 +08:00
										 |  |  | 	"encoding/json" | 
					
						
							| 
									
										
										
										
											2020-03-13 19:31:44 +08:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2020-03-18 19:08:20 +08:00
										 |  |  | 	"net/http" | 
					
						
							| 
									
										
										
										
											2021-04-21 21:17:23 +08:00
										 |  |  | 	"os" | 
					
						
							|  |  |  | 	"path/filepath" | 
					
						
							| 
									
										
										
										
											2016-03-15 22:52:29 +08:00
										 |  |  | 	"sort" | 
					
						
							| 
									
										
										
										
											2021-04-21 21:17:23 +08:00
										 |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2016-03-15 22:52:29 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-21 21:17:23 +08:00
										 |  |  | 	"gopkg.in/macaron.v1" | 
					
						
							| 
									
										
										
										
											2020-11-05 22:37:11 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-21 21:17:23 +08:00
										 |  |  | 	"github.com/grafana/grafana-plugin-sdk-go/backend" | 
					
						
							| 
									
										
										
										
											2016-02-25 21:55:31 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/api/dtos" | 
					
						
							| 
									
										
										
										
											2021-01-15 21:43:20 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/api/response" | 
					
						
							| 
									
										
										
										
											2016-02-25 21:55:31 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/bus" | 
					
						
							| 
									
										
										
										
											2020-02-20 02:17:05 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/models" | 
					
						
							| 
									
										
										
										
											2016-02-25 21:55:31 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/plugins" | 
					
						
							| 
									
										
										
										
											2020-03-03 18:45:16 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/plugins/backendplugin" | 
					
						
							| 
									
										
										
										
											2021-05-13 02:05:16 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/plugins/manager/installer" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/setting" | 
					
						
							| 
									
										
										
										
											2016-02-25 21:55:31 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-15 21:43:20 +08:00
										 |  |  | func (hs *HTTPServer) GetPluginList(c *models.ReqContext) response.Response { | 
					
						
							| 
									
										
										
										
											2016-03-09 01:17:47 +08:00
										 |  |  | 	typeFilter := c.Query("type") | 
					
						
							|  |  |  | 	enabledFilter := c.Query("enabled") | 
					
						
							|  |  |  | 	embeddedFilter := c.Query("embedded") | 
					
						
							| 
									
										
										
										
											2016-04-09 04:42:33 +08:00
										 |  |  | 	coreFilter := c.Query("core") | 
					
						
							| 
									
										
										
										
											2016-03-09 01:17:47 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-16 22:40:46 +08:00
										 |  |  | 	// For users with viewer role we only return core plugins
 | 
					
						
							|  |  |  | 	if !c.HasRole(models.ROLE_ADMIN) { | 
					
						
							|  |  |  | 		coreFilter = "1" | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-08 14:02:49 +08:00
										 |  |  | 	pluginSettingsMap, err := hs.PluginManager.GetPluginSettings(c.OrgId) | 
					
						
							| 
									
										
										
										
											2016-02-25 21:55:31 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2021-01-15 21:43:20 +08:00
										 |  |  | 		return response.Error(500, "Failed to get list of plugins", err) | 
					
						
							| 
									
										
										
										
											2016-02-25 21:55:31 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-15 22:52:29 +08:00
										 |  |  | 	result := make(dtos.PluginList, 0) | 
					
						
							| 
									
										
										
										
											2021-03-17 23:06:10 +08:00
										 |  |  | 	for _, pluginDef := range hs.PluginManager.Plugins() { | 
					
						
							| 
									
										
										
										
											2016-03-09 01:17:47 +08:00
										 |  |  | 		// filter out app sub plugins
 | 
					
						
							|  |  |  | 		if embeddedFilter == "0" && pluginDef.IncludedInAppId != "" { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-09 04:42:33 +08:00
										 |  |  | 		// filter out core plugins
 | 
					
						
							| 
									
										
										
										
											2020-03-16 22:40:46 +08:00
										 |  |  | 		if (coreFilter == "0" && pluginDef.IsCorePlugin) || (coreFilter == "1" && !pluginDef.IsCorePlugin) { | 
					
						
							| 
									
										
										
										
											2016-04-09 04:42:33 +08:00
										 |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-09 01:17:47 +08:00
										 |  |  | 		// filter on type
 | 
					
						
							|  |  |  | 		if typeFilter != "" && typeFilter != pluginDef.Type { | 
					
						
							| 
									
										
										
										
											2016-03-08 18:29:36 +08:00
										 |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-12 19:46:42 +08:00
										 |  |  | 		if pluginDef.State == plugins.PluginStateAlpha && !hs.Cfg.PluginsEnableAlpha { | 
					
						
							| 
									
										
										
										
											2018-11-15 18:10:47 +08:00
										 |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-15 22:52:29 +08:00
										 |  |  | 		listItem := dtos.PluginListItem{ | 
					
						
							| 
									
										
										
										
											2016-04-12 00:47:04 +08:00
										 |  |  | 			Id:            pluginDef.Id, | 
					
						
							|  |  |  | 			Name:          pluginDef.Name, | 
					
						
							|  |  |  | 			Type:          pluginDef.Type, | 
					
						
							| 
									
										
										
										
											2019-05-09 17:45:39 +08:00
										 |  |  | 			Category:      pluginDef.Category, | 
					
						
							| 
									
										
										
										
											2016-04-12 00:47:04 +08:00
										 |  |  | 			Info:          &pluginDef.Info, | 
					
						
							|  |  |  | 			LatestVersion: pluginDef.GrafanaNetVersion, | 
					
						
							|  |  |  | 			HasUpdate:     pluginDef.GrafanaNetHasUpdate, | 
					
						
							| 
									
										
										
										
											2016-05-04 01:00:42 +08:00
										 |  |  | 			DefaultNavUrl: pluginDef.DefaultNavUrl, | 
					
						
							| 
									
										
										
										
											2017-04-07 18:00:03 +08:00
										 |  |  | 			State:         pluginDef.State, | 
					
						
							| 
									
										
										
										
											2020-04-09 15:00:16 +08:00
										 |  |  | 			Signature:     pluginDef.Signature, | 
					
						
							| 
									
										
										
										
											2020-12-11 19:57:57 +08:00
										 |  |  | 			SignatureType: pluginDef.SignatureType, | 
					
						
							|  |  |  | 			SignatureOrg:  pluginDef.SignatureOrg, | 
					
						
							| 
									
										
										
										
											2016-02-25 21:55:31 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if pluginSetting, exists := pluginSettingsMap[pluginDef.Id]; exists { | 
					
						
							|  |  |  | 			listItem.Enabled = pluginSetting.Enabled | 
					
						
							|  |  |  | 			listItem.Pinned = pluginSetting.Pinned | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-04 01:00:42 +08:00
										 |  |  | 		if listItem.DefaultNavUrl == "" || !listItem.Enabled { | 
					
						
							| 
									
										
										
										
											2021-03-10 19:41:29 +08:00
										 |  |  | 			listItem.DefaultNavUrl = hs.Cfg.AppSubURL + "/plugins/" + listItem.Id + "/" | 
					
						
							| 
									
										
										
										
											2016-05-04 01:00:42 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-23 22:45:43 +08:00
										 |  |  | 		// filter out disabled plugins
 | 
					
						
							| 
									
										
										
										
											2016-03-09 01:17:47 +08:00
										 |  |  | 		if enabledFilter == "1" && !listItem.Enabled { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-14 19:00:56 +08:00
										 |  |  | 		// filter out built in data sources
 | 
					
						
							| 
									
										
										
										
											2021-03-17 23:06:10 +08:00
										 |  |  | 		if ds := hs.PluginManager.GetDataSource(pluginDef.Id); ds != nil { | 
					
						
							| 
									
										
										
										
											2016-03-14 19:00:56 +08:00
										 |  |  | 			if ds.BuiltIn { | 
					
						
							|  |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-25 21:55:31 +08:00
										 |  |  | 		result = append(result, listItem) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-15 22:52:29 +08:00
										 |  |  | 	sort.Sort(result) | 
					
						
							| 
									
										
										
										
											2021-01-15 21:43:20 +08:00
										 |  |  | 	return response.JSON(200, result) | 
					
						
							| 
									
										
										
										
											2016-02-25 21:55:31 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-17 23:06:10 +08:00
										 |  |  | func (hs *HTTPServer) GetPluginSettingByID(c *models.ReqContext) response.Response { | 
					
						
							| 
									
										
										
										
											2018-03-22 19:37:35 +08:00
										 |  |  | 	pluginID := c.Params(":pluginId") | 
					
						
							| 
									
										
										
										
											2016-02-25 21:55:31 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-17 23:06:10 +08:00
										 |  |  | 	def := hs.PluginManager.GetPlugin(pluginID) | 
					
						
							|  |  |  | 	if def == nil { | 
					
						
							| 
									
										
										
										
											2021-01-15 21:43:20 +08:00
										 |  |  | 		return response.Error(404, "Plugin not found, no installed plugin with that id", nil) | 
					
						
							| 
									
										
										
										
											2018-03-22 19:37:35 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-03-09 01:17:47 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-22 19:37:35 +08:00
										 |  |  | 	dto := &dtos.PluginSetting{ | 
					
						
							|  |  |  | 		Type:          def.Type, | 
					
						
							|  |  |  | 		Id:            def.Id, | 
					
						
							|  |  |  | 		Name:          def.Name, | 
					
						
							|  |  |  | 		Info:          &def.Info, | 
					
						
							|  |  |  | 		Dependencies:  &def.Dependencies, | 
					
						
							|  |  |  | 		Includes:      def.Includes, | 
					
						
							|  |  |  | 		BaseUrl:       def.BaseUrl, | 
					
						
							|  |  |  | 		Module:        def.Module, | 
					
						
							|  |  |  | 		DefaultNavUrl: def.DefaultNavUrl, | 
					
						
							|  |  |  | 		LatestVersion: def.GrafanaNetVersion, | 
					
						
							|  |  |  | 		HasUpdate:     def.GrafanaNetHasUpdate, | 
					
						
							|  |  |  | 		State:         def.State, | 
					
						
							| 
									
										
										
										
											2020-04-09 15:00:16 +08:00
										 |  |  | 		Signature:     def.Signature, | 
					
						
							| 
									
										
										
										
											2020-12-11 19:57:57 +08:00
										 |  |  | 		SignatureType: def.SignatureType, | 
					
						
							|  |  |  | 		SignatureOrg:  def.SignatureOrg, | 
					
						
							| 
									
										
										
										
											2018-03-22 19:37:35 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-02-25 22:56:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-18 20:53:01 +08:00
										 |  |  | 	if app := hs.PluginManager.GetApp(def.Id); app != nil { | 
					
						
							| 
									
										
										
										
											2021-02-25 17:00:21 +08:00
										 |  |  | 		dto.Enabled = app.AutoEnabled | 
					
						
							|  |  |  | 		dto.Pinned = app.AutoEnabled | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-20 02:17:05 +08:00
										 |  |  | 	query := models.GetPluginSettingByIdQuery{PluginId: pluginID, OrgId: c.OrgId} | 
					
						
							| 
									
										
										
										
											2018-03-22 19:37:35 +08:00
										 |  |  | 	if err := bus.Dispatch(&query); err != nil { | 
					
						
							| 
									
										
										
										
											2020-11-19 20:34:28 +08:00
										 |  |  | 		if !errors.Is(err, models.ErrPluginSettingNotFound) { | 
					
						
							| 
									
										
										
										
											2021-01-15 21:43:20 +08:00
										 |  |  | 			return response.Error(500, "Failed to get login settings", nil) | 
					
						
							| 
									
										
										
										
											2016-02-25 21:55:31 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-03-22 19:37:35 +08:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		dto.Enabled = query.Result.Enabled | 
					
						
							|  |  |  | 		dto.Pinned = query.Result.Pinned | 
					
						
							|  |  |  | 		dto.JsonData = query.Result.JsonData | 
					
						
							| 
									
										
										
										
											2016-02-25 21:55:31 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-03-22 19:37:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-15 21:43:20 +08:00
										 |  |  | 	return response.JSON(200, dto) | 
					
						
							| 
									
										
										
										
											2016-02-25 21:55:31 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-18 20:53:01 +08:00
										 |  |  | func (hs *HTTPServer) UpdatePluginSetting(c *models.ReqContext, cmd models.UpdatePluginSettingCmd) response.Response { | 
					
						
							| 
									
										
										
										
											2018-03-22 19:37:35 +08:00
										 |  |  | 	pluginID := c.Params(":pluginId") | 
					
						
							| 
									
										
										
										
											2016-02-25 21:55:31 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-18 20:53:01 +08:00
										 |  |  | 	if app := hs.PluginManager.GetApp(pluginID); app == nil { | 
					
						
							|  |  |  | 		return response.Error(404, "Plugin not installed", nil) | 
					
						
							| 
									
										
										
										
											2016-02-25 21:55:31 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-18 20:53:01 +08:00
										 |  |  | 	cmd.OrgId = c.OrgId | 
					
						
							|  |  |  | 	cmd.PluginId = pluginID | 
					
						
							| 
									
										
										
										
											2016-02-25 21:55:31 +08:00
										 |  |  | 	if err := bus.Dispatch(&cmd); err != nil { | 
					
						
							| 
									
										
										
										
											2021-01-15 21:43:20 +08:00
										 |  |  | 		return response.Error(500, "Failed to update plugin setting", err) | 
					
						
							| 
									
										
										
										
											2016-02-25 21:55:31 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-15 21:43:20 +08:00
										 |  |  | 	return response.Success("Plugin settings updated") | 
					
						
							| 
									
										
										
										
											2016-02-25 21:55:31 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-03-11 16:57:20 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-08 14:02:49 +08:00
										 |  |  | func (hs *HTTPServer) GetPluginDashboards(c *models.ReqContext) response.Response { | 
					
						
							| 
									
										
										
										
											2018-03-22 19:37:35 +08:00
										 |  |  | 	pluginID := c.Params(":pluginId") | 
					
						
							| 
									
										
										
										
											2016-03-11 16:57:20 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-08 14:02:49 +08:00
										 |  |  | 	list, err := hs.PluginManager.GetPluginDashboards(c.OrgId, pluginID) | 
					
						
							| 
									
										
										
										
											2018-03-22 19:37:35 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-11-19 20:34:28 +08:00
										 |  |  | 		var notFound plugins.PluginNotFoundError | 
					
						
							|  |  |  | 		if errors.As(err, ¬Found) { | 
					
						
							| 
									
										
										
										
											2021-01-15 21:43:20 +08:00
										 |  |  | 			return response.Error(404, notFound.Error(), nil) | 
					
						
							| 
									
										
										
										
											2016-03-11 16:57:20 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-15 21:43:20 +08:00
										 |  |  | 		return response.Error(500, "Failed to get plugin dashboards", err) | 
					
						
							| 
									
										
										
										
											2016-03-11 16:57:20 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-03-22 19:37:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-15 21:43:20 +08:00
										 |  |  | 	return response.JSON(200, list) | 
					
						
							| 
									
										
										
										
											2016-03-11 16:57:20 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-08 14:02:49 +08:00
										 |  |  | func (hs *HTTPServer) GetPluginMarkdown(c *models.ReqContext) response.Response { | 
					
						
							| 
									
										
										
										
											2018-03-22 19:37:35 +08:00
										 |  |  | 	pluginID := c.Params(":pluginId") | 
					
						
							| 
									
										
										
										
											2017-08-31 20:05:52 +08:00
										 |  |  | 	name := c.Params(":name") | 
					
						
							| 
									
										
										
										
											2016-03-14 02:21:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-08 14:02:49 +08:00
										 |  |  | 	content, err := hs.PluginManager.GetPluginMarkdown(pluginID, name) | 
					
						
							| 
									
										
										
										
											2018-03-22 19:37:35 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-11-19 20:34:28 +08:00
										 |  |  | 		var notFound plugins.PluginNotFoundError | 
					
						
							|  |  |  | 		if errors.As(err, ¬Found) { | 
					
						
							| 
									
										
										
										
											2021-01-15 21:43:20 +08:00
										 |  |  | 			return response.Error(404, notFound.Error(), nil) | 
					
						
							| 
									
										
										
										
											2016-03-14 02:21:44 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-15 21:43:20 +08:00
										 |  |  | 		return response.Error(500, "Could not get markdown file", err) | 
					
						
							| 
									
										
										
										
											2016-03-14 02:21:44 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-03-22 19:37:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-19 17:53:14 +08:00
										 |  |  | 	// fallback try readme
 | 
					
						
							|  |  |  | 	if len(content) == 0 { | 
					
						
							| 
									
										
										
										
											2021-03-08 14:02:49 +08:00
										 |  |  | 		content, err = hs.PluginManager.GetPluginMarkdown(pluginID, "readme") | 
					
						
							| 
									
										
										
										
											2018-12-19 17:53:14 +08:00
										 |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2021-01-15 21:43:20 +08:00
										 |  |  | 			return response.Error(501, "Could not get markdown file", err) | 
					
						
							| 
									
										
										
										
											2018-12-19 17:53:14 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-15 21:43:20 +08:00
										 |  |  | 	resp := response.Respond(200, content) | 
					
						
							| 
									
										
										
										
											2021-03-18 01:12:28 +08:00
										 |  |  | 	resp.SetHeader("Content-Type", "text/plain; charset=utf-8") | 
					
						
							| 
									
										
										
										
											2018-03-22 19:37:35 +08:00
										 |  |  | 	return resp | 
					
						
							| 
									
										
										
										
											2016-03-14 02:21:44 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-08 14:02:49 +08:00
										 |  |  | func (hs *HTTPServer) ImportDashboard(c *models.ReqContext, apiCmd dtos.ImportDashboardCommand) response.Response { | 
					
						
							| 
									
										
										
										
											2021-05-04 15:03:42 +08:00
										 |  |  | 	var err error | 
					
						
							| 
									
										
										
										
											2020-01-15 19:10:02 +08:00
										 |  |  | 	if apiCmd.PluginId == "" && apiCmd.Dashboard == nil { | 
					
						
							| 
									
										
										
										
											2021-01-15 21:43:20 +08:00
										 |  |  | 		return response.Error(422, "Dashboard must be set", nil) | 
					
						
							| 
									
										
										
										
											2020-01-15 19:10:02 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-04 15:03:42 +08:00
										 |  |  | 	trimDefaults := c.QueryBoolWithDefault("trimdefaults", true) | 
					
						
							|  |  |  | 	if trimDefaults && !hs.LoadSchemaService.IsDisabled() { | 
					
						
							|  |  |  | 		apiCmd.Dashboard, err = hs.LoadSchemaService.DashboardApplyDefaults(apiCmd.Dashboard) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return response.Error(500, "Error while applying default value to the dashboard json", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-24 15:31:34 +08:00
										 |  |  | 	dashInfo, dash, err := hs.PluginManager.ImportDashboard(apiCmd.PluginId, apiCmd.Path, c.OrgId, apiCmd.FolderId, | 
					
						
							| 
									
										
										
										
											2021-03-08 14:02:49 +08:00
										 |  |  | 		apiCmd.Dashboard, apiCmd.Overwrite, apiCmd.Inputs, c.SignedInUser, hs.DataService) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2021-03-17 23:06:10 +08:00
										 |  |  | 		return hs.dashboardSaveErrorToApiResponse(err) | 
					
						
							| 
									
										
										
										
											2016-03-11 16:57:20 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-24 15:31:34 +08:00
										 |  |  | 	err = hs.LibraryPanelService.ConnectLibraryPanelsForDashboard(c, dash) | 
					
						
							| 
									
										
										
										
											2021-05-20 15:40:23 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return response.Error(500, "Error while connecting library panels", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-08 14:02:49 +08:00
										 |  |  | 	return response.JSON(200, dashInfo) | 
					
						
							| 
									
										
										
										
											2016-03-11 16:57:20 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2020-01-31 18:15:50 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-18 19:08:20 +08:00
										 |  |  | // CollectPluginMetrics collect metrics from a plugin.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // /api/plugins/:pluginId/metrics
 | 
					
						
							| 
									
										
										
										
											2021-01-15 21:43:20 +08:00
										 |  |  | func (hs *HTTPServer) CollectPluginMetrics(c *models.ReqContext) response.Response { | 
					
						
							| 
									
										
										
										
											2020-03-18 19:08:20 +08:00
										 |  |  | 	pluginID := c.Params("pluginId") | 
					
						
							| 
									
										
										
										
											2021-03-17 23:06:10 +08:00
										 |  |  | 	plugin := hs.PluginManager.GetPlugin(pluginID) | 
					
						
							|  |  |  | 	if plugin == nil { | 
					
						
							| 
									
										
										
										
											2021-01-15 21:43:20 +08:00
										 |  |  | 		return response.Error(404, "Plugin not found", nil) | 
					
						
							| 
									
										
										
										
											2020-03-18 19:08:20 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	resp, err := hs.BackendPluginManager.CollectMetrics(c.Req.Context(), plugin.Id) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-06-11 22:14:05 +08:00
										 |  |  | 		return translatePluginRequestErrorToAPIError(err) | 
					
						
							| 
									
										
										
										
											2020-03-18 19:08:20 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	headers := make(http.Header) | 
					
						
							|  |  |  | 	headers.Set("Content-Type", "text/plain") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-15 21:43:20 +08:00
										 |  |  | 	return response.CreateNormalResponse(headers, resp.PrometheusMetrics, http.StatusOK) | 
					
						
							| 
									
										
										
										
											2020-03-18 19:08:20 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-21 21:17:23 +08:00
										 |  |  | // GetPluginAssets returns public plugin assets (images, JS, etc.)
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // /public/plugins/:pluginId/*
 | 
					
						
							|  |  |  | func (hs *HTTPServer) GetPluginAssets(c *models.ReqContext) { | 
					
						
							|  |  |  | 	pluginID := c.Params("pluginId") | 
					
						
							|  |  |  | 	plugin := hs.PluginManager.GetPlugin(pluginID) | 
					
						
							|  |  |  | 	if plugin == nil { | 
					
						
							|  |  |  | 		c.Handle(hs.Cfg, 404, "Plugin not found", nil) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	requestedFile := filepath.Clean(c.Params("*")) | 
					
						
							|  |  |  | 	pluginFilePath := filepath.Join(plugin.PluginDir, requestedFile) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// It's safe to ignore gosec warning G304 since we already clean the requested file path and subsequently
 | 
					
						
							|  |  |  | 	// use this with a prefix of the plugin's directory, which is set during plugin loading
 | 
					
						
							|  |  |  | 	// nolint:gosec
 | 
					
						
							|  |  |  | 	f, err := os.Open(pluginFilePath) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		if os.IsNotExist(err) { | 
					
						
							|  |  |  | 			c.Handle(hs.Cfg, 404, "Could not find plugin file", err) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		c.Handle(hs.Cfg, 500, "Could not open plugin file", err) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer func() { | 
					
						
							|  |  |  | 		if err := f.Close(); err != nil { | 
					
						
							|  |  |  | 			hs.log.Error("Failed to close file", "err", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	fi, err := f.Stat() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Handle(hs.Cfg, 500, "Plugin file exists but could not open", err) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if shouldExclude(fi) { | 
					
						
							|  |  |  | 		c.Handle(hs.Cfg, 404, "Plugin file not found", nil) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	headers := func(c *macaron.Context) { | 
					
						
							|  |  |  | 		c.Resp.Header().Set("Cache-Control", "public, max-age=3600") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if hs.Cfg.Env == setting.Dev { | 
					
						
							|  |  |  | 		headers = func(c *macaron.Context) { | 
					
						
							|  |  |  | 			c.Resp.Header().Set("Cache-Control", "max-age=0, must-revalidate, no-cache") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	headers(c.Context) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	http.ServeContent(c.Resp, c.Req.Request, pluginFilePath, fi.ModTime(), f) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-06 21:37:36 +08:00
										 |  |  | // CheckHealth returns the health of a plugin.
 | 
					
						
							| 
									
										
										
										
											2020-01-31 18:15:50 +08:00
										 |  |  | // /api/plugins/:pluginId/health
 | 
					
						
							| 
									
										
										
										
											2021-01-15 21:43:20 +08:00
										 |  |  | func (hs *HTTPServer) CheckHealth(c *models.ReqContext) response.Response { | 
					
						
							| 
									
										
										
										
											2020-01-31 18:15:50 +08:00
										 |  |  | 	pluginID := c.Params("pluginId") | 
					
						
							| 
									
										
										
										
											2020-03-13 19:31:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-19 02:39:56 +08:00
										 |  |  | 	pCtx, found, err := hs.PluginContextProvider.Get(pluginID, "", c.SignedInUser, false) | 
					
						
							| 
									
										
										
										
											2020-03-13 19:31:44 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2021-01-15 21:43:20 +08:00
										 |  |  | 		return response.Error(500, "Failed to get plugin settings", err) | 
					
						
							| 
									
										
										
										
											2020-03-13 19:31:44 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-03-24 01:24:08 +08:00
										 |  |  | 	if !found { | 
					
						
							|  |  |  | 		return response.Error(404, "Plugin not found", nil) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-03-13 19:31:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-24 02:08:21 +08:00
										 |  |  | 	resp, err := hs.BackendPluginManager.CheckHealth(c.Req.Context(), pCtx) | 
					
						
							| 
									
										
										
										
											2020-01-31 18:15:50 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-06-11 22:14:05 +08:00
										 |  |  | 		return translatePluginRequestErrorToAPIError(err) | 
					
						
							| 
									
										
										
										
											2020-01-31 18:15:50 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	payload := map[string]interface{}{ | 
					
						
							| 
									
										
										
										
											2020-04-21 22:16:41 +08:00
										 |  |  | 		"status":  resp.Status.String(), | 
					
						
							|  |  |  | 		"message": resp.Message, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Unmarshal JSONDetails if it's not empty.
 | 
					
						
							|  |  |  | 	if len(resp.JSONDetails) > 0 { | 
					
						
							|  |  |  | 		var jsonDetails map[string]interface{} | 
					
						
							|  |  |  | 		err = json.Unmarshal(resp.JSONDetails, &jsonDetails) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2021-01-15 21:43:20 +08:00
										 |  |  | 			return response.Error(500, "Failed to unmarshal detailed response from backend plugin", err) | 
					
						
							| 
									
										
										
										
											2020-04-21 22:16:41 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		payload["details"] = jsonDetails | 
					
						
							| 
									
										
										
										
											2020-01-31 18:15:50 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-11 22:14:05 +08:00
										 |  |  | 	if resp.Status != backend.HealthStatusOk { | 
					
						
							| 
									
										
										
										
											2021-01-15 21:43:20 +08:00
										 |  |  | 		return response.JSON(503, payload) | 
					
						
							| 
									
										
										
										
											2020-01-31 18:15:50 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-15 21:43:20 +08:00
										 |  |  | 	return response.JSON(200, payload) | 
					
						
							| 
									
										
										
										
											2020-01-31 18:15:50 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-13 19:31:44 +08:00
										 |  |  | // CallResource passes a resource call from a plugin to the backend plugin.
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-01-31 18:15:50 +08:00
										 |  |  | // /api/plugins/:pluginId/resources/*
 | 
					
						
							| 
									
										
										
										
											2020-03-03 18:45:16 +08:00
										 |  |  | func (hs *HTTPServer) CallResource(c *models.ReqContext) { | 
					
						
							| 
									
										
										
										
											2020-01-31 18:15:50 +08:00
										 |  |  | 	pluginID := c.Params("pluginId") | 
					
						
							| 
									
										
										
										
											2020-02-20 02:17:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-19 02:39:56 +08:00
										 |  |  | 	pCtx, found, err := hs.PluginContextProvider.Get(pluginID, "", c.SignedInUser, false) | 
					
						
							| 
									
										
										
										
											2020-02-20 02:17:05 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-03-13 19:31:44 +08:00
										 |  |  | 		c.JsonApiErr(500, "Failed to get plugin settings", err) | 
					
						
							|  |  |  | 		return | 
					
						
							| 
									
										
										
										
											2020-01-31 18:15:50 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-03-24 01:24:08 +08:00
										 |  |  | 	if !found { | 
					
						
							|  |  |  | 		c.JsonApiErr(404, "Plugin not found", nil) | 
					
						
							|  |  |  | 		return | 
					
						
							| 
									
										
										
										
											2020-02-20 02:17:05 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-03-24 01:24:08 +08:00
										 |  |  | 	hs.BackendPluginManager.CallResource(pCtx, c, c.Params("*")) | 
					
						
							| 
									
										
										
										
											2020-02-20 02:17:05 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2020-06-11 22:14:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-24 01:24:08 +08:00
										 |  |  | func (hs *HTTPServer) GetPluginErrorsList(_ *models.ReqContext) response.Response { | 
					
						
							| 
									
										
										
										
											2021-02-10 20:31:47 +08:00
										 |  |  | 	return response.JSON(200, hs.PluginManager.ScanningErrors()) | 
					
						
							| 
									
										
										
										
											2020-10-23 22:45:43 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-13 02:05:16 +08:00
										 |  |  | func (hs *HTTPServer) InstallPlugin(c *models.ReqContext, dto dtos.InstallPluginCommand) response.Response { | 
					
						
							|  |  |  | 	pluginID := c.Params("pluginId") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err := hs.PluginManager.Install(c.Req.Context(), pluginID, dto.Version) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		var dupeErr plugins.DuplicatePluginError | 
					
						
							|  |  |  | 		if errors.As(err, &dupeErr) { | 
					
						
							|  |  |  | 			return response.Error(http.StatusConflict, "Plugin already installed", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		var versionUnsupportedErr installer.ErrVersionUnsupported | 
					
						
							|  |  |  | 		if errors.As(err, &versionUnsupportedErr) { | 
					
						
							|  |  |  | 			return response.Error(http.StatusConflict, "Plugin version not supported", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		var versionNotFoundErr installer.ErrVersionNotFound | 
					
						
							|  |  |  | 		if errors.As(err, &versionNotFoundErr) { | 
					
						
							|  |  |  | 			return response.Error(http.StatusNotFound, "Plugin version not found", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if errors.Is(err, installer.ErrPluginNotFound) { | 
					
						
							|  |  |  | 			return response.Error(http.StatusNotFound, "Plugin not found", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if errors.Is(err, plugins.ErrInstallCorePlugin) { | 
					
						
							|  |  |  | 			return response.Error(http.StatusForbidden, "Cannot install or change a Core plugin", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return response.Error(http.StatusInternalServerError, "Failed to install plugin", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return response.JSON(http.StatusOK, []byte{}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (hs *HTTPServer) UninstallPlugin(c *models.ReqContext) response.Response { | 
					
						
							|  |  |  | 	pluginID := c.Params("pluginId") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err := hs.PluginManager.Uninstall(c.Req.Context(), pluginID) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		if errors.Is(err, plugins.ErrPluginNotInstalled) { | 
					
						
							|  |  |  | 			return response.Error(http.StatusNotFound, "Plugin not installed", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if errors.Is(err, plugins.ErrUninstallCorePlugin) { | 
					
						
							|  |  |  | 			return response.Error(http.StatusForbidden, "Cannot uninstall a Core plugin", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if errors.Is(err, plugins.ErrUninstallOutsideOfPluginDir) { | 
					
						
							|  |  |  | 			return response.Error(http.StatusForbidden, "Cannot uninstall a plugin outside of the plugins directory", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return response.Error(http.StatusInternalServerError, "Failed to uninstall plugin", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return response.JSON(http.StatusOK, []byte{}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-15 21:43:20 +08:00
										 |  |  | func translatePluginRequestErrorToAPIError(err error) response.Response { | 
					
						
							| 
									
										
										
										
											2020-06-11 22:14:05 +08:00
										 |  |  | 	if errors.Is(err, backendplugin.ErrPluginNotRegistered) { | 
					
						
							| 
									
										
										
										
											2021-01-15 21:43:20 +08:00
										 |  |  | 		return response.Error(404, "Plugin not found", err) | 
					
						
							| 
									
										
										
										
											2020-06-11 22:14:05 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if errors.Is(err, backendplugin.ErrMethodNotImplemented) { | 
					
						
							| 
									
										
										
										
											2021-01-15 21:43:20 +08:00
										 |  |  | 		return response.Error(404, "Not found", err) | 
					
						
							| 
									
										
										
										
											2020-06-11 22:14:05 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if errors.Is(err, backendplugin.ErrHealthCheckFailed) { | 
					
						
							| 
									
										
										
										
											2021-01-15 21:43:20 +08:00
										 |  |  | 		return response.Error(500, "Plugin health check failed", err) | 
					
						
							| 
									
										
										
										
											2020-06-11 22:14:05 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if errors.Is(err, backendplugin.ErrPluginUnavailable) { | 
					
						
							| 
									
										
										
										
											2021-01-15 21:43:20 +08:00
										 |  |  | 		return response.Error(503, "Plugin unavailable", err) | 
					
						
							| 
									
										
										
										
											2020-06-11 22:14:05 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-15 21:43:20 +08:00
										 |  |  | 	return response.Error(500, "Plugin request failed", err) | 
					
						
							| 
									
										
										
										
											2020-06-11 22:14:05 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2021-04-21 21:17:23 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | func shouldExclude(fi os.FileInfo) bool { | 
					
						
							|  |  |  | 	normalizedFilename := strings.ToLower(fi.Name()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	isUnixExecutable := fi.Mode()&0111 == 0111 | 
					
						
							|  |  |  | 	isWindowsExecutable := strings.HasSuffix(normalizedFilename, ".exe") | 
					
						
							|  |  |  | 	isScript := strings.HasSuffix(normalizedFilename, ".sh") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return isUnixExecutable || isWindowsExecutable || isScript | 
					
						
							|  |  |  | } |