mirror of https://github.com/grafana/grafana
Backend Plugins: Plugin configuration using Grafana config (#23451)
Enables adding a section `plugin.<plugin id>` and key/value to Grafana configuration file which will be converted and sent as environment variables to the backend plugin. Also sends some additional environment variables, Grafana version (GF_VERSION), Grafana edition (GF_EDITION) and enterprise license path (GF_ENTERPRISE_LICENSE_PATH). Co-authored-by: Arve Knudsen <arve.knudsen@gmail.com> Fixes #21515,pull/23543/head^2
parent
941cd59894
commit
34266cd369
@ -0,0 +1,39 @@ |
|||||||
|
package backendplugin |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
"strings" |
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/setting" |
||||||
|
) |
||||||
|
|
||||||
|
type pluginSettings map[string]string |
||||||
|
|
||||||
|
func (ps pluginSettings) ToEnv(prefix string, hostEnv []string) []string { |
||||||
|
env := []string{} |
||||||
|
for k, v := range ps { |
||||||
|
env = append(env, fmt.Sprintf("%s_%s=%s", prefix, strings.ToUpper(k), v)) |
||||||
|
} |
||||||
|
|
||||||
|
env = append(env, hostEnv...) |
||||||
|
|
||||||
|
return env |
||||||
|
} |
||||||
|
|
||||||
|
func extractPluginSettings(cfg *setting.Cfg) map[string]pluginSettings { |
||||||
|
psMap := map[string]pluginSettings{} |
||||||
|
for pluginID, settings := range cfg.PluginSettings { |
||||||
|
ps := pluginSettings{} |
||||||
|
for k, v := range settings { |
||||||
|
if k == "path" || strings.ToLower(k) == "id" { |
||||||
|
continue |
||||||
|
} |
||||||
|
|
||||||
|
ps[k] = v |
||||||
|
} |
||||||
|
|
||||||
|
psMap[pluginID] = ps |
||||||
|
} |
||||||
|
|
||||||
|
return psMap |
||||||
|
} |
||||||
@ -0,0 +1,46 @@ |
|||||||
|
package backendplugin |
||||||
|
|
||||||
|
import ( |
||||||
|
"sort" |
||||||
|
"testing" |
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/setting" |
||||||
|
"github.com/stretchr/testify/require" |
||||||
|
) |
||||||
|
|
||||||
|
func TestPluginSettings(t *testing.T) { |
||||||
|
t.Run("Should only extract from sections beginning with 'plugin.' in config", func(t *testing.T) { |
||||||
|
cfg := &setting.Cfg{ |
||||||
|
PluginSettings: setting.PluginSettings{ |
||||||
|
"plugin": map[string]string{ |
||||||
|
"key1": "value1", |
||||||
|
"key2": "value2", |
||||||
|
}, |
||||||
|
}, |
||||||
|
} |
||||||
|
|
||||||
|
ps := extractPluginSettings(cfg) |
||||||
|
require.Len(t, ps, 1) |
||||||
|
require.Len(t, ps["plugin"], 2) |
||||||
|
|
||||||
|
t.Run("Should skip path setting", func(t *testing.T) { |
||||||
|
cfg.PluginSettings["plugin"]["path"] = "value" |
||||||
|
ps := extractPluginSettings(cfg) |
||||||
|
require.Len(t, ps["plugin"], 2) |
||||||
|
}) |
||||||
|
|
||||||
|
t.Run("Should skip id setting", func(t *testing.T) { |
||||||
|
cfg.PluginSettings["plugin"]["id"] = "value" |
||||||
|
ps := extractPluginSettings(cfg) |
||||||
|
require.Len(t, ps["plugin"], 2) |
||||||
|
}) |
||||||
|
|
||||||
|
t.Run("Should return expected environment variables from plugin settings ", func(t *testing.T) { |
||||||
|
ps := extractPluginSettings(cfg) |
||||||
|
env := ps["plugin"].ToEnv("GF_PLUGIN", []string{"GF_VERSION=6.7.0"}) |
||||||
|
sort.Strings(env) |
||||||
|
require.Len(t, env, 3) |
||||||
|
require.EqualValues(t, []string{"GF_PLUGIN_KEY1=value1", "GF_PLUGIN_KEY2=value2", "GF_VERSION=6.7.0"}, env) |
||||||
|
}) |
||||||
|
}) |
||||||
|
} |
||||||
@ -0,0 +1,25 @@ |
|||||||
|
package setting |
||||||
|
|
||||||
|
import ( |
||||||
|
"strings" |
||||||
|
|
||||||
|
"gopkg.in/ini.v1" |
||||||
|
) |
||||||
|
|
||||||
|
// PluginSettings maps plugin id to map of key/value settings.
|
||||||
|
type PluginSettings map[string]map[string]string |
||||||
|
|
||||||
|
func extractPluginSettings(sections []*ini.Section) PluginSettings { |
||||||
|
psMap := PluginSettings{} |
||||||
|
for _, section := range sections { |
||||||
|
sectionName := section.Name() |
||||||
|
if !strings.HasPrefix(sectionName, "plugin.") { |
||||||
|
continue |
||||||
|
} |
||||||
|
|
||||||
|
pluginID := strings.Replace(sectionName, "plugin.", "", 1) |
||||||
|
psMap[pluginID] = section.KeysHash() |
||||||
|
} |
||||||
|
|
||||||
|
return psMap |
||||||
|
} |
||||||
@ -0,0 +1,43 @@ |
|||||||
|
package setting |
||||||
|
|
||||||
|
import ( |
||||||
|
"testing" |
||||||
|
|
||||||
|
"github.com/stretchr/testify/require" |
||||||
|
) |
||||||
|
|
||||||
|
func TestPluginSettings(t *testing.T) { |
||||||
|
cfg := NewCfg() |
||||||
|
sec, err := cfg.Raw.NewSection("plugin") |
||||||
|
require.NoError(t, err) |
||||||
|
_, err = sec.NewKey("key", "value") |
||||||
|
require.NoError(t, err) |
||||||
|
|
||||||
|
sec, err = cfg.Raw.NewSection("plugin.plugin") |
||||||
|
require.NoError(t, err) |
||||||
|
_, err = sec.NewKey("key1", "value1") |
||||||
|
require.NoError(t, err) |
||||||
|
_, err = sec.NewKey("key2", "value2") |
||||||
|
require.NoError(t, err) |
||||||
|
|
||||||
|
sec, err = cfg.Raw.NewSection("plugin.plugin2") |
||||||
|
require.NoError(t, err) |
||||||
|
_, err = sec.NewKey("key3", "value3") |
||||||
|
require.NoError(t, err) |
||||||
|
_, err = sec.NewKey("key4", "value4") |
||||||
|
require.NoError(t, err) |
||||||
|
|
||||||
|
sec, err = cfg.Raw.NewSection("other") |
||||||
|
require.NoError(t, err) |
||||||
|
_, err = sec.NewKey("keySomething", "whatever") |
||||||
|
require.NoError(t, err) |
||||||
|
|
||||||
|
ps := extractPluginSettings(cfg.Raw.Sections()) |
||||||
|
require.Len(t, ps, 2) |
||||||
|
require.Len(t, ps["plugin"], 2) |
||||||
|
require.Equal(t, ps["plugin"]["key1"], "value1") |
||||||
|
require.Equal(t, ps["plugin"]["key2"], "value2") |
||||||
|
require.Len(t, ps["plugin2"], 2) |
||||||
|
require.Equal(t, ps["plugin2"]["key3"], "value3") |
||||||
|
require.Equal(t, ps["plugin2"]["key4"], "value4") |
||||||
|
} |
||||||
Loading…
Reference in new issue