Plugins: Add typed models for frontend settings data sources and panels (#42062)

* add model for data source

* add model for panels

* add omitempty

* make consistent with main

* dont emit bools

* resolve conflicts

* remove file

* remove file

* update field name

* always pass jsonData

* minify the changes

* remove dupe line
This commit is contained in:
Will Browne
2021-12-14 10:16:13 +00:00
committed by GitHub
parent 6c4555265a
commit 155487bfb0
2 changed files with 101 additions and 63 deletions

View File

@ -6,7 +6,6 @@ import (
"strconv" "strconv"
"github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol"
@ -15,12 +14,7 @@ import (
"github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/util"
) )
type PreloadPlugin struct { func (hs *HTTPServer) getFSDataSources(c *models.ReqContext, enabledPlugins EnabledPlugins) (map[string]plugins.DataSourceDTO, error) {
Path string `json:"path"`
Version string `json:"version"`
}
func (hs *HTTPServer) getFSDataSources(c *models.ReqContext, enabledPlugins EnabledPlugins) (map[string]interface{}, error) {
orgDataSources := make([]*models.DataSource, 0) orgDataSources := make([]*models.DataSource, 0)
if c.OrgId != 0 { if c.OrgId != 0 {
@ -47,7 +41,7 @@ func (hs *HTTPServer) getFSDataSources(c *models.ReqContext, enabledPlugins Enab
} }
} }
dataSources := make(map[string]interface{}) dataSources := make(map[string]plugins.DataSourceDTO)
for _, ds := range orgDataSources { for _, ds := range orgDataSources {
url := ds.Url url := ds.Url
@ -56,81 +50,81 @@ func (hs *HTTPServer) getFSDataSources(c *models.ReqContext, enabledPlugins Enab
url = "/api/datasources/proxy/" + strconv.FormatInt(ds.Id, 10) url = "/api/datasources/proxy/" + strconv.FormatInt(ds.Id, 10)
} }
dsMap := map[string]interface{}{ dsDTO := plugins.DataSourceDTO{
"id": ds.Id, ID: ds.Id,
"uid": ds.Uid, UID: ds.Uid,
"type": ds.Type, Type: ds.Type,
"name": ds.Name, Name: ds.Name,
"url": url, URL: url,
"isDefault": ds.IsDefault, IsDefault: ds.IsDefault,
"access": ds.Access, Access: string(ds.Access),
} }
meta, exists := enabledPlugins.Get(plugins.DataSource, ds.Type) plugin, exists := enabledPlugins.Get(plugins.DataSource, ds.Type)
if !exists { if !exists {
c.Logger.Error("Could not find plugin definition for data source", "datasource_type", ds.Type) c.Logger.Error("Could not find plugin definition for data source", "datasource_type", ds.Type)
continue continue
} }
dsMap["preload"] = meta.Preload dsDTO.Preload = plugin.Preload
dsMap["module"] = meta.Module dsDTO.Module = plugin.Module
dsMap["meta"] = &plugins.PluginMetaDTO{ dsDTO.PluginMeta = &plugins.PluginMetaDTO{
JSONData: meta.JSONData, JSONData: plugin.JSONData,
Signature: meta.Signature, Signature: plugin.Signature,
Module: meta.Module, Module: plugin.Module,
BaseURL: meta.BaseURL, BaseURL: plugin.BaseURL,
} }
jsonData := ds.JsonData if ds.JsonData == nil {
if jsonData == nil { dsDTO.JSONData = make(map[string]interface{})
jsonData = simplejson.New() } else {
dsDTO.JSONData = ds.JsonData.MustMap()
} }
dsMap["jsonData"] = jsonData
if ds.Access == models.DS_ACCESS_DIRECT { if ds.Access == models.DS_ACCESS_DIRECT {
if ds.BasicAuth { if ds.BasicAuth {
dsMap["basicAuth"] = util.GetBasicAuthHeader( dsDTO.BasicAuth = util.GetBasicAuthHeader(
ds.BasicAuthUser, ds.BasicAuthUser,
hs.DataSourcesService.DecryptedBasicAuthPassword(ds), hs.DataSourcesService.DecryptedBasicAuthPassword(ds),
) )
} }
if ds.WithCredentials { if ds.WithCredentials {
dsMap["withCredentials"] = ds.WithCredentials dsDTO.WithCredentials = ds.WithCredentials
} }
if ds.Type == models.DS_INFLUXDB_08 { if ds.Type == models.DS_INFLUXDB_08 {
dsMap["username"] = ds.User dsDTO.Username = ds.User
dsMap["password"] = hs.DataSourcesService.DecryptedPassword(ds) dsDTO.Password = hs.DataSourcesService.DecryptedPassword(ds)
dsMap["url"] = url + "/db/" + ds.Database dsDTO.URL = url + "/db/" + ds.Database
} }
if ds.Type == models.DS_INFLUXDB { if ds.Type == models.DS_INFLUXDB {
dsMap["username"] = ds.User dsDTO.Username = ds.User
dsMap["password"] = hs.DataSourcesService.DecryptedPassword(ds) dsDTO.Password = hs.DataSourcesService.DecryptedPassword(ds)
dsMap["url"] = url dsDTO.URL = url
} }
} }
if (ds.Type == models.DS_INFLUXDB) || (ds.Type == models.DS_ES) { if (ds.Type == models.DS_INFLUXDB) || (ds.Type == models.DS_ES) {
dsMap["database"] = ds.Database dsDTO.Database = ds.Database
} }
if ds.Type == models.DS_PROMETHEUS { if ds.Type == models.DS_PROMETHEUS {
// add unproxied server URL for link to Prometheus web UI // add unproxied server URL for link to Prometheus web UI
jsonData.Set("directUrl", ds.Url) ds.JsonData.Set("directUrl", ds.Url)
} }
dataSources[ds.Name] = dsMap dataSources[ds.Name] = dsDTO
} }
// add data sources that are built in (meaning they are not added via data sources page, nor have any entry in // add data sources that are built in (meaning they are not added via data sources page, nor have any entry in
// the datasource table) // the datasource table)
for _, ds := range hs.pluginStore.Plugins(c.Req.Context(), plugins.DataSource) { for _, ds := range hs.pluginStore.Plugins(c.Req.Context(), plugins.DataSource) {
if ds.BuiltIn { if ds.BuiltIn {
info := map[string]interface{}{ dto := plugins.DataSourceDTO{
"type": ds.Type, Type: string(ds.Type),
"name": ds.Name, Name: ds.Name,
"meta": &plugins.PluginMetaDTO{ JSONData: make(map[string]interface{}),
PluginMeta: &plugins.PluginMetaDTO{
JSONData: ds.JSONData, JSONData: ds.JSONData,
Signature: ds.Signature, Signature: ds.Signature,
Module: ds.Module, Module: ds.Module,
@ -138,10 +132,10 @@ func (hs *HTTPServer) getFSDataSources(c *models.ReqContext, enabledPlugins Enab
}, },
} }
if ds.Name == grafanads.DatasourceName { if ds.Name == grafanads.DatasourceName {
info["id"] = grafanads.DatasourceID dto.ID = grafanads.DatasourceID
info["uid"] = grafanads.DatasourceUID dto.UID = grafanads.DatasourceUID
} }
dataSources[ds.Name] = info dataSources[ds.Name] = dto
} }
} }
@ -155,10 +149,10 @@ func (hs *HTTPServer) getFrontendSettingsMap(c *models.ReqContext) (map[string]i
return nil, err return nil, err
} }
pluginsToPreload := make([]*PreloadPlugin, 0) pluginsToPreload := make([]*plugins.PreloadPlugin, 0)
for _, app := range enabledPlugins[plugins.App] { for _, app := range enabledPlugins[plugins.App] {
if app.Preload { if app.Preload {
pluginsToPreload = append(pluginsToPreload, &PreloadPlugin{ pluginsToPreload = append(pluginsToPreload, &plugins.PreloadPlugin{
Path: app.Module, Path: app.Module,
Version: app.Info.Version, Version: app.Info.Version,
}) })
@ -172,29 +166,28 @@ func (hs *HTTPServer) getFrontendSettingsMap(c *models.ReqContext) (map[string]i
defaultDS := "-- Grafana --" defaultDS := "-- Grafana --"
for n, ds := range dataSources { for n, ds := range dataSources {
dsM := ds.(map[string]interface{}) if ds.IsDefault {
if isDefault, _ := dsM["isDefault"].(bool); isDefault {
defaultDS = n defaultDS = n
} }
} }
panels := map[string]interface{}{} panels := make(map[string]plugins.PanelDTO)
for _, panel := range enabledPlugins[plugins.Panel] { for _, panel := range enabledPlugins[plugins.Panel] {
if panel.State == plugins.AlphaRelease && !hs.Cfg.PluginsEnableAlpha { if panel.State == plugins.AlphaRelease && !hs.Cfg.PluginsEnableAlpha {
continue continue
} }
panels[panel.ID] = map[string]interface{}{ panels[panel.ID] = plugins.PanelDTO{
"id": panel.ID, ID: panel.ID,
"module": panel.Module, Name: panel.Name,
"baseUrl": panel.BaseURL, Info: panel.Info,
"name": panel.Name, Module: panel.Module,
"info": panel.Info, BaseURL: panel.BaseURL,
"hideFromList": panel.HideFromList, SkipDataQuery: panel.SkipDataQuery,
"sort": getPanelSort(panel.ID), HideFromList: panel.HideFromList,
"skipDataQuery": panel.SkipDataQuery, ReleaseState: string(panel.State),
"state": panel.State, Signature: string(panel.Signature),
"signature": panel.Signature, Sort: getPanelSort(panel.ID),
} }
} }

View File

@ -199,6 +199,46 @@ type PluginMetaDTO struct {
BaseURL string `json:"baseUrl"` BaseURL string `json:"baseUrl"`
} }
type DataSourceDTO struct {
ID int64 `json:"id,omitempty"`
UID string `json:"uid,omitempty"`
Type string `json:"type"`
Name string `json:"name"`
PluginMeta *PluginMetaDTO `json:"meta"`
URL string `json:"url,omitempty"`
IsDefault bool `json:"isDefault"`
Access string `json:"access,omitempty"`
Preload bool `json:"preload"`
Module string `json:"module,omitempty"`
JSONData map[string]interface{} `json:"jsonData"`
BasicAuth string `json:"basicAuth,omitempty"`
WithCredentials bool `json:"withCredentials,omitempty"`
// InfluxDB
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
// InfluxDB + Elasticsearch
Database string `json:"database,omitempty"`
// Prometheus
DirectURL string `json:"directUrl,omitempty"`
}
type PanelDTO struct {
ID string `json:"id"`
Name string `json:"name"`
Info Info `json:"info"`
HideFromList bool `json:"hideFromList"`
Sort int `json:"sort"`
SkipDataQuery bool `json:"skipDataQuery"`
ReleaseState string `json:"state"`
BaseURL string `json:"baseUrl"`
Signature string `json:"signature"`
Module string `json:"module"`
}
const ( const (
signatureMissing ErrorCode = "signatureMissing" signatureMissing ErrorCode = "signatureMissing"
signatureModified ErrorCode = "signatureModified" signatureModified ErrorCode = "signatureModified"
@ -211,3 +251,8 @@ type Error struct {
ErrorCode `json:"errorCode"` ErrorCode `json:"errorCode"`
PluginID string `json:"pluginId,omitempty"` PluginID string `json:"pluginId,omitempty"`
} }
type PreloadPlugin struct {
Path string `json:"path"`
Version string `json:"version"`
}