Plugins: Refactor plugin config into separate env var and request scoped services (#83261)
* seperate services for env + req * merge with main * fix tests * undo changes to golden file * fix linter * remove unused fields * split out new config struct * provide config * undo go mod changes * more renaming * fix tests * undo bra.toml changes * update go.work.sum * undo changes * trigger * apply PR feedback
This commit is contained in:
@@ -1,16 +1,13 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"github.com/grafana/grafana-azure-sdk-go/azsettings"
|
||||
|
||||
"github.com/grafana/grafana/pkg/plugins/log"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
type Cfg struct {
|
||||
log log.Logger
|
||||
|
||||
// PluginManagementCfg is the configuration for the plugin management system.
|
||||
// It includes settings which are used to configure different components of plugin management.
|
||||
type PluginManagementCfg struct {
|
||||
DevMode bool
|
||||
|
||||
PluginsPath string
|
||||
@@ -20,25 +17,6 @@ type Cfg struct {
|
||||
DisablePlugins []string
|
||||
ForwardHostEnvVars []string
|
||||
|
||||
// AWS Plugin Auth
|
||||
AWSAllowedAuthProviders []string
|
||||
AWSAssumeRoleEnabled bool
|
||||
AWSExternalId string
|
||||
AWSSessionDuration string
|
||||
AWSListMetricsPageLimit string
|
||||
AWSForwardSettingsPlugins []string
|
||||
|
||||
// Azure Cloud settings
|
||||
Azure *azsettings.AzureSettings
|
||||
AzureAuthEnabled bool
|
||||
|
||||
// Proxy Settings
|
||||
ProxySettings setting.SecureSocksDSProxySettings
|
||||
|
||||
BuildVersion string // TODO Remove
|
||||
|
||||
LogDatasourceRequests bool
|
||||
|
||||
PluginsCDNURLTemplate string
|
||||
|
||||
Tracing Tracing
|
||||
@@ -52,57 +30,27 @@ type Cfg struct {
|
||||
|
||||
AngularSupportEnabled bool
|
||||
HideAngularDeprecation []string
|
||||
|
||||
ConcurrentQueryCount int
|
||||
|
||||
UserFacingDefaultError string
|
||||
|
||||
DataProxyRowLimit int64
|
||||
|
||||
SQLDatasourceMaxOpenConnsDefault int
|
||||
SQLDatasourceMaxIdleConnsDefault int
|
||||
SQLDatasourceMaxConnLifetimeDefault int
|
||||
}
|
||||
|
||||
func NewCfg(devMode bool, pluginsPath string, pluginSettings setting.PluginSettings, pluginsAllowUnsigned []string,
|
||||
awsAllowedAuthProviders []string, awsAssumeRoleEnabled bool, awsExternalId string, awsSessionDuration string, awsListMetricsPageLimit string, AWSForwardSettingsPlugins []string, azure *azsettings.AzureSettings, secureSocksDSProxy setting.SecureSocksDSProxySettings,
|
||||
grafanaVersion string, logDatasourceRequests bool, pluginsCDNURLTemplate string, appURL string, appSubURL string, tracing Tracing, features featuremgmt.FeatureToggles, angularSupportEnabled bool,
|
||||
grafanaComURL string, disablePlugins []string, hideAngularDeprecation []string, forwardHostEnvVars []string, concurrentQueryCount int, azureAuthEnabled bool,
|
||||
userFacingDefaultError string, dataProxyRowLimit int64,
|
||||
sqlDatasourceMaxOpenConnsDefault int, sqlDatasourceMaxIdleConnsDefault int, sqlDatasourceMaxConnLifetimeDefault int,
|
||||
) *Cfg {
|
||||
return &Cfg{
|
||||
log: log.New("plugin.cfg"),
|
||||
PluginsPath: pluginsPath,
|
||||
BuildVersion: grafanaVersion,
|
||||
DevMode: devMode,
|
||||
PluginSettings: pluginSettings,
|
||||
PluginsAllowUnsigned: pluginsAllowUnsigned,
|
||||
DisablePlugins: disablePlugins,
|
||||
AWSAllowedAuthProviders: awsAllowedAuthProviders,
|
||||
AWSAssumeRoleEnabled: awsAssumeRoleEnabled,
|
||||
AWSExternalId: awsExternalId,
|
||||
AWSSessionDuration: awsSessionDuration,
|
||||
AWSListMetricsPageLimit: awsListMetricsPageLimit,
|
||||
AWSForwardSettingsPlugins: AWSForwardSettingsPlugins,
|
||||
Azure: azure,
|
||||
ProxySettings: secureSocksDSProxy,
|
||||
LogDatasourceRequests: logDatasourceRequests,
|
||||
PluginsCDNURLTemplate: pluginsCDNURLTemplate,
|
||||
Tracing: tracing,
|
||||
GrafanaComURL: grafanaComURL,
|
||||
GrafanaAppURL: appURL,
|
||||
GrafanaAppSubURL: appSubURL,
|
||||
Features: features,
|
||||
AngularSupportEnabled: angularSupportEnabled,
|
||||
HideAngularDeprecation: hideAngularDeprecation,
|
||||
ForwardHostEnvVars: forwardHostEnvVars,
|
||||
ConcurrentQueryCount: concurrentQueryCount,
|
||||
AzureAuthEnabled: azureAuthEnabled,
|
||||
UserFacingDefaultError: userFacingDefaultError,
|
||||
DataProxyRowLimit: dataProxyRowLimit,
|
||||
SQLDatasourceMaxOpenConnsDefault: sqlDatasourceMaxOpenConnsDefault,
|
||||
SQLDatasourceMaxIdleConnsDefault: sqlDatasourceMaxIdleConnsDefault,
|
||||
SQLDatasourceMaxConnLifetimeDefault: sqlDatasourceMaxConnLifetimeDefault,
|
||||
// NewPluginManagementCfg returns a new PluginManagementCfg.
|
||||
func NewPluginManagementCfg(devMode bool, pluginsPath string, pluginSettings setting.PluginSettings, pluginsAllowUnsigned []string,
|
||||
pluginsCDNURLTemplate string, appURL string, appSubURL string, tracing Tracing, features featuremgmt.FeatureToggles,
|
||||
angularSupportEnabled bool, grafanaComURL string, disablePlugins []string, hideAngularDeprecation []string,
|
||||
forwardHostEnvVars []string) *PluginManagementCfg {
|
||||
return &PluginManagementCfg{
|
||||
PluginsPath: pluginsPath,
|
||||
DevMode: devMode,
|
||||
PluginSettings: pluginSettings,
|
||||
PluginsAllowUnsigned: pluginsAllowUnsigned,
|
||||
DisablePlugins: disablePlugins,
|
||||
PluginsCDNURLTemplate: pluginsCDNURLTemplate,
|
||||
Tracing: tracing,
|
||||
GrafanaComURL: grafanaComURL,
|
||||
GrafanaAppURL: appURL,
|
||||
GrafanaAppSubURL: appSubURL,
|
||||
Features: features,
|
||||
AngularSupportEnabled: angularSupportEnabled,
|
||||
HideAngularDeprecation: hideAngularDeprecation,
|
||||
ForwardHostEnvVars: forwardHostEnvVars,
|
||||
}
|
||||
}
|
||||
|
||||
+15
-320
@@ -2,32 +2,14 @@ package envvars
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"slices"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/grafana/grafana-aws-sdk/pkg/awsds"
|
||||
"github.com/grafana/grafana-azure-sdk-go/azsettings"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend/proxy"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/experimental/featuretoggles"
|
||||
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/plugins/auth"
|
||||
"github.com/grafana/grafana/pkg/plugins/config"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
)
|
||||
|
||||
const (
|
||||
customConfigPrefix = "GF_PLUGIN"
|
||||
)
|
||||
|
||||
// allowedHostEnvVarNames is the list of environment variables that can be passed from Grafana's process to the
|
||||
// permittedHostEnvVarNames is the list of environment variables that can be passed from Grafana's process to the
|
||||
// plugin's process
|
||||
var allowedHostEnvVarNames = []string{
|
||||
var permittedHostEnvVarNames = []string{
|
||||
// Env vars used by net/http (Go stdlib) for http/https proxy
|
||||
// https://github.com/golang/net/blob/fbaf41277f28102c36926d1368dafbe2b54b4c1d/http/httpproxy/proxy.go#L91-L93
|
||||
"HTTP_PROXY",
|
||||
@@ -39,286 +21,25 @@ var allowedHostEnvVarNames = []string{
|
||||
}
|
||||
|
||||
type Provider interface {
|
||||
Get(ctx context.Context, p *plugins.Plugin) []string
|
||||
PluginEnvVars(ctx context.Context, p *plugins.Plugin) []string
|
||||
}
|
||||
|
||||
type Service struct {
|
||||
cfg *config.Cfg
|
||||
license plugins.Licensing
|
||||
type Service struct{}
|
||||
|
||||
func DefaultProvider() *Service {
|
||||
return &Service{}
|
||||
}
|
||||
|
||||
func NewProvider(cfg *config.Cfg, license plugins.Licensing) *Service {
|
||||
return &Service{
|
||||
cfg: cfg,
|
||||
license: license,
|
||||
}
|
||||
func (s *Service) PluginEnvVars(_ context.Context, _ *plugins.Plugin) []string {
|
||||
return PermittedHostEnvVars()
|
||||
}
|
||||
|
||||
func (s *Service) Get(ctx context.Context, p *plugins.Plugin) []string {
|
||||
hostEnv := []string{
|
||||
fmt.Sprintf("GF_VERSION=%s", s.cfg.BuildVersion),
|
||||
}
|
||||
|
||||
if s.license != nil {
|
||||
hostEnv = append(
|
||||
hostEnv,
|
||||
fmt.Sprintf("GF_EDITION=%s", s.license.Edition()),
|
||||
fmt.Sprintf("GF_ENTERPRISE_LICENSE_PATH=%s", s.license.Path()),
|
||||
fmt.Sprintf("GF_ENTERPRISE_APP_URL=%s", s.license.AppURL()),
|
||||
)
|
||||
hostEnv = append(hostEnv, s.license.Environment()...)
|
||||
}
|
||||
|
||||
if p.ExternalService != nil {
|
||||
hostEnv = append(
|
||||
hostEnv,
|
||||
fmt.Sprintf("GF_APP_URL=%s", s.cfg.GrafanaAppURL),
|
||||
fmt.Sprintf("GF_PLUGIN_APP_CLIENT_ID=%s", p.ExternalService.ClientID),
|
||||
fmt.Sprintf("GF_PLUGIN_APP_CLIENT_SECRET=%s", p.ExternalService.ClientSecret),
|
||||
)
|
||||
if p.ExternalService.PrivateKey != "" {
|
||||
hostEnv = append(hostEnv, fmt.Sprintf("GF_PLUGIN_APP_PRIVATE_KEY=%s", p.ExternalService.PrivateKey))
|
||||
}
|
||||
}
|
||||
|
||||
hostEnv = append(hostEnv, s.featureToggleEnableVar(ctx)...)
|
||||
hostEnv = append(hostEnv, s.awsEnvVars()...)
|
||||
hostEnv = append(hostEnv, s.secureSocksProxyEnvVars()...)
|
||||
hostEnv = append(hostEnv, azsettings.WriteToEnvStr(s.cfg.Azure)...)
|
||||
hostEnv = append(hostEnv, s.tracingEnvVars(p)...)
|
||||
|
||||
// If SkipHostEnvVars is enabled, get some allowed variables from the current process and pass
|
||||
// them down to the plugin. If the flag is not set, do not add anything else because ALL env vars
|
||||
// from the current process (os.Environ()) will be forwarded to the plugin's process by go-plugin
|
||||
if p.SkipHostEnvVars {
|
||||
hostEnv = append(hostEnv, s.allowedHostEnvVars()...)
|
||||
}
|
||||
|
||||
ev := getPluginSettings(p.ID, s.cfg).asEnvVar(customConfigPrefix, hostEnv...)
|
||||
|
||||
return ev
|
||||
}
|
||||
|
||||
// GetConfigMap returns a map of configuration that should be passed in a plugin request.
|
||||
//
|
||||
//nolint:gocyclo
|
||||
func (s *Service) GetConfigMap(ctx context.Context, pluginID string, _ *auth.ExternalService) map[string]string {
|
||||
m := make(map[string]string)
|
||||
|
||||
if s.cfg.GrafanaAppURL != "" {
|
||||
m[backend.AppURL] = s.cfg.GrafanaAppURL
|
||||
}
|
||||
if s.cfg.ConcurrentQueryCount != 0 {
|
||||
m[backend.ConcurrentQueryCount] = strconv.Itoa(s.cfg.ConcurrentQueryCount)
|
||||
}
|
||||
|
||||
if s.cfg.UserFacingDefaultError != "" {
|
||||
m[backend.UserFacingDefaultError] = s.cfg.UserFacingDefaultError
|
||||
}
|
||||
|
||||
if s.cfg.DataProxyRowLimit != 0 {
|
||||
m[backend.SQLRowLimit] = strconv.FormatInt(s.cfg.DataProxyRowLimit, 10)
|
||||
}
|
||||
|
||||
m[backend.SQLMaxOpenConnsDefault] = strconv.Itoa(s.cfg.SQLDatasourceMaxOpenConnsDefault)
|
||||
m[backend.SQLMaxIdleConnsDefault] = strconv.Itoa(s.cfg.SQLDatasourceMaxIdleConnsDefault)
|
||||
m[backend.SQLMaxConnLifetimeSecondsDefault] = strconv.Itoa(s.cfg.SQLDatasourceMaxConnLifetimeDefault)
|
||||
|
||||
// TODO add support via plugin SDK
|
||||
// if externalService != nil {
|
||||
// m[oauthtokenretriever.AppURL] = s.cfg.GrafanaAppURL
|
||||
// m[oauthtokenretriever.AppClientID] = externalService.ClientID
|
||||
// m[oauthtokenretriever.AppClientSecret] = externalService.ClientSecret
|
||||
// m[oauthtokenretriever.AppPrivateKey] = externalService.PrivateKey
|
||||
// }
|
||||
|
||||
if s.cfg.Features != nil {
|
||||
enabledFeatures := s.cfg.Features.GetEnabled(ctx)
|
||||
if len(enabledFeatures) > 0 {
|
||||
features := make([]string, 0, len(enabledFeatures))
|
||||
for feat := range enabledFeatures {
|
||||
features = append(features, feat)
|
||||
}
|
||||
sort.Strings(features)
|
||||
m[featuretoggles.EnabledFeatures] = strings.Join(features, ",")
|
||||
}
|
||||
}
|
||||
|
||||
if slices.Contains[[]string, string](s.cfg.AWSForwardSettingsPlugins, pluginID) {
|
||||
if !s.cfg.AWSAssumeRoleEnabled {
|
||||
m[awsds.AssumeRoleEnabledEnvVarKeyName] = "false"
|
||||
}
|
||||
if len(s.cfg.AWSAllowedAuthProviders) > 0 {
|
||||
m[awsds.AllowedAuthProvidersEnvVarKeyName] = strings.Join(s.cfg.AWSAllowedAuthProviders, ",")
|
||||
}
|
||||
if s.cfg.AWSExternalId != "" {
|
||||
m[awsds.GrafanaAssumeRoleExternalIdKeyName] = s.cfg.AWSExternalId
|
||||
}
|
||||
if s.cfg.AWSSessionDuration != "" {
|
||||
m[awsds.SessionDurationEnvVarKeyName] = s.cfg.AWSSessionDuration
|
||||
}
|
||||
if s.cfg.AWSListMetricsPageLimit != "" {
|
||||
m[awsds.ListMetricsPageLimitKeyName] = s.cfg.AWSListMetricsPageLimit
|
||||
}
|
||||
}
|
||||
|
||||
if s.cfg.ProxySettings.Enabled {
|
||||
m[proxy.PluginSecureSocksProxyEnabled] = "true"
|
||||
m[proxy.PluginSecureSocksProxyClientCert] = s.cfg.ProxySettings.ClientCert
|
||||
m[proxy.PluginSecureSocksProxyClientKey] = s.cfg.ProxySettings.ClientKey
|
||||
m[proxy.PluginSecureSocksProxyRootCACert] = s.cfg.ProxySettings.RootCA
|
||||
m[proxy.PluginSecureSocksProxyProxyAddress] = s.cfg.ProxySettings.ProxyAddress
|
||||
m[proxy.PluginSecureSocksProxyServerName] = s.cfg.ProxySettings.ServerName
|
||||
m[proxy.PluginSecureSocksProxyAllowInsecure] = strconv.FormatBool(s.cfg.ProxySettings.AllowInsecure)
|
||||
}
|
||||
|
||||
// Settings here will be extracted by grafana-azure-sdk-go from the plugin context
|
||||
if s.cfg.AzureAuthEnabled {
|
||||
m[azsettings.AzureAuthEnabled] = strconv.FormatBool(s.cfg.AzureAuthEnabled)
|
||||
}
|
||||
azureSettings := s.cfg.Azure
|
||||
if azureSettings != nil && slices.Contains[[]string, string](azureSettings.ForwardSettingsPlugins, pluginID) {
|
||||
if azureSettings.Cloud != "" {
|
||||
m[azsettings.AzureCloud] = azureSettings.Cloud
|
||||
}
|
||||
|
||||
if azureSettings.ManagedIdentityEnabled {
|
||||
m[azsettings.ManagedIdentityEnabled] = "true"
|
||||
|
||||
if azureSettings.ManagedIdentityClientId != "" {
|
||||
m[azsettings.ManagedIdentityClientID] = azureSettings.ManagedIdentityClientId
|
||||
}
|
||||
}
|
||||
|
||||
if azureSettings.UserIdentityEnabled {
|
||||
m[azsettings.UserIdentityEnabled] = "true"
|
||||
|
||||
if azureSettings.UserIdentityTokenEndpoint != nil {
|
||||
if azureSettings.UserIdentityTokenEndpoint.TokenUrl != "" {
|
||||
m[azsettings.UserIdentityTokenURL] = azureSettings.UserIdentityTokenEndpoint.TokenUrl
|
||||
}
|
||||
if azureSettings.UserIdentityTokenEndpoint.ClientId != "" {
|
||||
m[azsettings.UserIdentityClientID] = azureSettings.UserIdentityTokenEndpoint.ClientId
|
||||
}
|
||||
if azureSettings.UserIdentityTokenEndpoint.ClientSecret != "" {
|
||||
m[azsettings.UserIdentityClientSecret] = azureSettings.UserIdentityTokenEndpoint.ClientSecret
|
||||
}
|
||||
if azureSettings.UserIdentityTokenEndpoint.UsernameAssertion {
|
||||
m[azsettings.UserIdentityAssertion] = "username"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if azureSettings.WorkloadIdentityEnabled {
|
||||
m[azsettings.WorkloadIdentityEnabled] = "true"
|
||||
|
||||
if azureSettings.WorkloadIdentitySettings != nil {
|
||||
if azureSettings.WorkloadIdentitySettings.ClientId != "" {
|
||||
m[azsettings.WorkloadIdentityClientID] = azureSettings.WorkloadIdentitySettings.ClientId
|
||||
}
|
||||
if azureSettings.WorkloadIdentitySettings.TenantId != "" {
|
||||
m[azsettings.WorkloadIdentityTenantID] = azureSettings.WorkloadIdentitySettings.TenantId
|
||||
}
|
||||
if azureSettings.WorkloadIdentitySettings.TokenFile != "" {
|
||||
m[azsettings.WorkloadIdentityTokenFile] = azureSettings.WorkloadIdentitySettings.TokenFile
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO add support via plugin SDK
|
||||
// ps := getPluginSettings(pluginID, s.cfg)
|
||||
// for k, v := range ps {
|
||||
// m[fmt.Sprintf("%s_%s", customConfigPrefix, strings.ToUpper(k))] = v
|
||||
// }
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
func (s *Service) tracingEnvVars(plugin *plugins.Plugin) []string {
|
||||
pluginTracingEnabled := s.cfg.Features != nil && s.cfg.Features.IsEnabledGlobally(featuremgmt.FlagEnablePluginsTracingByDefault)
|
||||
if v, exists := s.cfg.PluginSettings[plugin.ID]["tracing"]; exists && !pluginTracingEnabled {
|
||||
pluginTracingEnabled = v == "true"
|
||||
}
|
||||
if !s.cfg.Tracing.IsEnabled() || !pluginTracingEnabled {
|
||||
return nil
|
||||
}
|
||||
|
||||
vars := []string{
|
||||
fmt.Sprintf("GF_INSTANCE_OTLP_ADDRESS=%s", s.cfg.Tracing.OpenTelemetry.Address),
|
||||
fmt.Sprintf("GF_INSTANCE_OTLP_PROPAGATION=%s", s.cfg.Tracing.OpenTelemetry.Propagation),
|
||||
|
||||
fmt.Sprintf("GF_INSTANCE_OTLP_SAMPLER_TYPE=%s", s.cfg.Tracing.OpenTelemetry.Sampler),
|
||||
fmt.Sprintf("GF_INSTANCE_OTLP_SAMPLER_PARAM=%.6f", s.cfg.Tracing.OpenTelemetry.SamplerParam),
|
||||
fmt.Sprintf("GF_INSTANCE_OTLP_SAMPLER_REMOTE_URL=%s", s.cfg.Tracing.OpenTelemetry.SamplerRemoteURL),
|
||||
}
|
||||
if plugin.Info.Version != "" {
|
||||
vars = append(vars, fmt.Sprintf("GF_PLUGIN_VERSION=%s", plugin.Info.Version))
|
||||
}
|
||||
return vars
|
||||
}
|
||||
|
||||
func (s *Service) featureToggleEnableVar(ctx context.Context) []string {
|
||||
var variables []string // an array is used for consistency and keep the logic simpler for no features case
|
||||
|
||||
if s.cfg.Features == nil {
|
||||
return variables
|
||||
}
|
||||
|
||||
enabledFeatures := s.cfg.Features.GetEnabled(ctx)
|
||||
if len(enabledFeatures) > 0 {
|
||||
features := make([]string, 0, len(enabledFeatures))
|
||||
for feat := range enabledFeatures {
|
||||
features = append(features, feat)
|
||||
}
|
||||
variables = append(variables, fmt.Sprintf("GF_INSTANCE_FEATURE_TOGGLES_ENABLE=%s", strings.Join(features, ",")))
|
||||
}
|
||||
|
||||
return variables
|
||||
}
|
||||
|
||||
func (s *Service) awsEnvVars() []string {
|
||||
var variables []string
|
||||
if !s.cfg.AWSAssumeRoleEnabled {
|
||||
variables = append(variables, awsds.AssumeRoleEnabledEnvVarKeyName+"=false")
|
||||
}
|
||||
if len(s.cfg.AWSAllowedAuthProviders) > 0 {
|
||||
variables = append(variables, awsds.AllowedAuthProvidersEnvVarKeyName+"="+strings.Join(s.cfg.AWSAllowedAuthProviders, ","))
|
||||
}
|
||||
if s.cfg.AWSExternalId != "" {
|
||||
variables = append(variables, awsds.GrafanaAssumeRoleExternalIdKeyName+"="+s.cfg.AWSExternalId)
|
||||
}
|
||||
if s.cfg.AWSSessionDuration != "" {
|
||||
variables = append(variables, awsds.SessionDurationEnvVarKeyName+"="+s.cfg.AWSSessionDuration)
|
||||
}
|
||||
if s.cfg.AWSListMetricsPageLimit != "" {
|
||||
variables = append(variables, awsds.ListMetricsPageLimitKeyName+"="+s.cfg.AWSListMetricsPageLimit)
|
||||
}
|
||||
|
||||
return variables
|
||||
}
|
||||
|
||||
func (s *Service) secureSocksProxyEnvVars() []string {
|
||||
if s.cfg.ProxySettings.Enabled {
|
||||
return []string{
|
||||
proxy.PluginSecureSocksProxyClientCert + "=" + s.cfg.ProxySettings.ClientCert,
|
||||
proxy.PluginSecureSocksProxyClientKey + "=" + s.cfg.ProxySettings.ClientKey,
|
||||
proxy.PluginSecureSocksProxyRootCACert + "=" + s.cfg.ProxySettings.RootCA,
|
||||
proxy.PluginSecureSocksProxyProxyAddress + "=" + s.cfg.ProxySettings.ProxyAddress,
|
||||
proxy.PluginSecureSocksProxyServerName + "=" + s.cfg.ProxySettings.ServerName,
|
||||
proxy.PluginSecureSocksProxyEnabled + "=" + strconv.FormatBool(s.cfg.ProxySettings.Enabled),
|
||||
proxy.PluginSecureSocksProxyAllowInsecure + "=" + strconv.FormatBool(s.cfg.ProxySettings.AllowInsecure),
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// allowedHostEnvVars returns the variables that can be passed from Grafana's process
|
||||
// PermittedHostEnvVars returns the variables that can be passed from Grafana's process
|
||||
// (current process, also known as: "host") to the plugin process.
|
||||
// A string in format "k=v" is returned for each variable in allowedHostEnvVarNames, if it's set.
|
||||
func (s *Service) allowedHostEnvVars() []string {
|
||||
// A string in format "k=v" is returned for each variable in PermittedHostEnvVarNames, if it's set.
|
||||
func PermittedHostEnvVars() []string {
|
||||
var r []string
|
||||
for _, envVarName := range allowedHostEnvVarNames {
|
||||
for _, envVarName := range PermittedHostEnvVarNames() {
|
||||
if envVarValue, ok := os.LookupEnv(envVarName); ok {
|
||||
r = append(r, envVarName+"="+envVarValue)
|
||||
}
|
||||
@@ -326,32 +47,6 @@ func (s *Service) allowedHostEnvVars() []string {
|
||||
return r
|
||||
}
|
||||
|
||||
type pluginSettings map[string]string
|
||||
|
||||
func getPluginSettings(pluginID string, cfg *config.Cfg) pluginSettings {
|
||||
ps := pluginSettings{}
|
||||
for k, v := range cfg.PluginSettings[pluginID] {
|
||||
if k == "path" || strings.ToLower(k) == "id" {
|
||||
continue
|
||||
}
|
||||
ps[k] = v
|
||||
}
|
||||
|
||||
return ps
|
||||
}
|
||||
|
||||
func (ps pluginSettings) asEnvVar(prefix string, hostEnv ...string) []string {
|
||||
env := make([]string, 0, len(ps))
|
||||
for k, v := range ps {
|
||||
key := fmt.Sprintf("%s_%s", prefix, strings.ToUpper(k))
|
||||
if value := os.Getenv(key); value != "" {
|
||||
v = value
|
||||
}
|
||||
|
||||
env = append(env, fmt.Sprintf("%s=%s", key, v))
|
||||
}
|
||||
|
||||
env = append(env, hostEnv...)
|
||||
|
||||
return env
|
||||
func PermittedHostEnvVarNames() []string {
|
||||
return permittedHostEnvVarNames
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -29,10 +29,10 @@ var (
|
||||
|
||||
type Service struct {
|
||||
pluginRegistry registry.Service
|
||||
cfg *config.Cfg
|
||||
cfg *config.PluginManagementCfg
|
||||
}
|
||||
|
||||
func ProvideService(pluginRegistry registry.Service, cfg *config.Cfg) *Service {
|
||||
func ProvideService(pluginRegistry registry.Service, cfg *config.PluginManagementCfg) *Service {
|
||||
return &Service{
|
||||
pluginRegistry: pluginRegistry,
|
||||
cfg: cfg,
|
||||
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
func TestQueryData(t *testing.T) {
|
||||
t.Run("Empty registry should return not registered error", func(t *testing.T) {
|
||||
registry := fakes.NewFakePluginRegistry()
|
||||
client := ProvideService(registry, &config.Cfg{})
|
||||
client := ProvideService(registry, &config.PluginManagementCfg{})
|
||||
_, err := client.QueryData(context.Background(), &backend.QueryDataRequest{})
|
||||
require.Error(t, err)
|
||||
require.ErrorIs(t, err, plugins.ErrPluginNotRegistered)
|
||||
@@ -63,7 +63,7 @@ func TestQueryData(t *testing.T) {
|
||||
err := registry.Add(context.Background(), p)
|
||||
require.NoError(t, err)
|
||||
|
||||
client := ProvideService(registry, &config.Cfg{})
|
||||
client := ProvideService(registry, &config.PluginManagementCfg{})
|
||||
_, err = client.QueryData(context.Background(), &backend.QueryDataRequest{
|
||||
PluginContext: backend.PluginContext{
|
||||
PluginID: "grafana",
|
||||
@@ -79,7 +79,7 @@ func TestQueryData(t *testing.T) {
|
||||
func TestCheckHealth(t *testing.T) {
|
||||
t.Run("empty plugin registry should return plugin not registered error", func(t *testing.T) {
|
||||
registry := fakes.NewFakePluginRegistry()
|
||||
client := ProvideService(registry, &config.Cfg{})
|
||||
client := ProvideService(registry, &config.PluginManagementCfg{})
|
||||
_, err := client.CheckHealth(context.Background(), &backend.CheckHealthRequest{})
|
||||
require.Error(t, err)
|
||||
require.ErrorIs(t, err, plugins.ErrPluginNotRegistered)
|
||||
@@ -125,7 +125,7 @@ func TestCheckHealth(t *testing.T) {
|
||||
err := registry.Add(context.Background(), p)
|
||||
require.NoError(t, err)
|
||||
|
||||
client := ProvideService(registry, &config.Cfg{})
|
||||
client := ProvideService(registry, &config.PluginManagementCfg{})
|
||||
_, err = client.CheckHealth(context.Background(), &backend.CheckHealthRequest{
|
||||
PluginContext: backend.PluginContext{
|
||||
PluginID: "grafana",
|
||||
@@ -189,7 +189,7 @@ func TestCallResource(t *testing.T) {
|
||||
err := registry.Add(context.Background(), p)
|
||||
require.NoError(t, err)
|
||||
|
||||
client := ProvideService(registry, &config.Cfg{})
|
||||
client := ProvideService(registry, &config.PluginManagementCfg{})
|
||||
|
||||
err = client.CallResource(context.Background(), req, sender)
|
||||
require.NoError(t, err)
|
||||
@@ -252,7 +252,7 @@ func TestCallResource(t *testing.T) {
|
||||
err := registry.Add(context.Background(), p)
|
||||
require.NoError(t, err)
|
||||
|
||||
client := ProvideService(registry, &config.Cfg{})
|
||||
client := ProvideService(registry, &config.PluginManagementCfg{})
|
||||
|
||||
err = client.CallResource(context.Background(), req, sender)
|
||||
require.NoError(t, err)
|
||||
@@ -298,7 +298,7 @@ func TestCallResource(t *testing.T) {
|
||||
err := registry.Add(context.Background(), p)
|
||||
require.NoError(t, err)
|
||||
|
||||
client := ProvideService(registry, &config.Cfg{})
|
||||
client := ProvideService(registry, &config.PluginManagementCfg{})
|
||||
|
||||
err = client.CallResource(context.Background(), req, sender)
|
||||
require.NoError(t, err)
|
||||
@@ -366,7 +366,7 @@ func TestCallResource(t *testing.T) {
|
||||
err := registry.Add(context.Background(), p)
|
||||
require.NoError(t, err)
|
||||
|
||||
client := ProvideService(registry, &config.Cfg{})
|
||||
client := ProvideService(registry, &config.PluginManagementCfg{})
|
||||
|
||||
err = client.CallResource(context.Background(), req, sender)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -255,6 +255,21 @@ func (s *FakePluginStorage) Extract(ctx context.Context, pluginID string, dirNam
|
||||
return &storage.ExtractedPluginArchive{}, nil
|
||||
}
|
||||
|
||||
type FakePluginEnvProvider struct {
|
||||
PluginEnvVarsFunc func(ctx context.Context, plugin *plugins.Plugin) []string
|
||||
}
|
||||
|
||||
func NewFakePluginEnvProvider() *FakePluginEnvProvider {
|
||||
return &FakePluginEnvProvider{}
|
||||
}
|
||||
|
||||
func (p *FakePluginEnvProvider) PluginEnvVars(ctx context.Context, plugin *plugins.Plugin) []string {
|
||||
if p.PluginEnvVarsFunc != nil {
|
||||
return p.PluginEnvVarsFunc(ctx, plugin)
|
||||
}
|
||||
return []string{}
|
||||
}
|
||||
|
||||
type FakeProcessManager struct {
|
||||
StartFunc func(_ context.Context, p *plugins.Plugin) error
|
||||
StopFunc func(_ context.Context, p *plugins.Plugin) error
|
||||
|
||||
@@ -28,7 +28,7 @@ type PluginInstaller struct {
|
||||
serviceRegistry auth.ExternalServiceRegistry
|
||||
}
|
||||
|
||||
func ProvideInstaller(cfg *config.Cfg, pluginRegistry registry.Service, pluginLoader loader.Service,
|
||||
func ProvideInstaller(cfg *config.PluginManagementCfg, pluginRegistry registry.Service, pluginLoader loader.Service,
|
||||
pluginRepo repo.Service, serviceRegistry auth.ExternalServiceRegistry) *PluginInstaller {
|
||||
return New(pluginRegistry, pluginLoader, pluginRepo,
|
||||
storage.FileSystem(log.NewPrettyLogger("installer.fs"), cfg.PluginsPath), storage.SimpleDirNameGeneratorFunc, serviceRegistry)
|
||||
|
||||
@@ -18,10 +18,10 @@ import (
|
||||
// on the plugins CDN, and it will switch to the correct implementation depending on the plugin and the config.
|
||||
type Service struct {
|
||||
cdn *pluginscdn.Service
|
||||
cfg *config.Cfg
|
||||
cfg *config.PluginManagementCfg
|
||||
}
|
||||
|
||||
func ProvideService(cfg *config.Cfg, cdn *pluginscdn.Service) *Service {
|
||||
func ProvideService(cfg *config.PluginManagementCfg, cdn *pluginscdn.Service) *Service {
|
||||
return &Service{cfg: cfg, cdn: cdn}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ func NewPluginInfo(pluginJSON plugins.JSONData, class plugins.Class, fs plugins.
|
||||
}
|
||||
}
|
||||
|
||||
func DefaultService(cfg *config.Cfg) *Service {
|
||||
func DefaultService(cfg *config.PluginManagementCfg) *Service {
|
||||
return &Service{cfg: cfg, cdn: pluginscdn.ProvideService(cfg)}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ func TestService(t *testing.T) {
|
||||
},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
cfg := &config.Cfg{
|
||||
cfg := &config.PluginManagementCfg{
|
||||
PluginsCDNURLTemplate: tc.cdnBaseURL,
|
||||
PluginSettings: map[string]map[string]string{
|
||||
"one": {"cdn": "true"},
|
||||
@@ -142,7 +142,7 @@ func TestService(t *testing.T) {
|
||||
appSubURL: "/grafana/",
|
||||
},
|
||||
} {
|
||||
cfg := &config.Cfg{GrafanaAppSubURL: tc.appSubURL}
|
||||
cfg := &config.PluginManagementCfg{GrafanaAppSubURL: tc.appSubURL}
|
||||
svc := ProvideService(cfg, pluginscdn.ProvideService(cfg))
|
||||
|
||||
dir := "/plugins/test-datasource"
|
||||
|
||||
@@ -37,7 +37,7 @@ func NewLocalFinder(devMode bool, features featuremgmt.FeatureToggles) *Local {
|
||||
}
|
||||
}
|
||||
|
||||
func ProvideLocalFinder(cfg *config.Cfg) *Local {
|
||||
func ProvideLocalFinder(cfg *config.PluginManagementCfg) *Local {
|
||||
return NewLocalFinder(cfg.DevMode, cfg.Features)
|
||||
}
|
||||
|
||||
|
||||
@@ -61,14 +61,14 @@ func TestLoader_Load(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
class plugins.Class
|
||||
cfg *config.Cfg
|
||||
cfg *config.PluginManagementCfg
|
||||
pluginPaths []string
|
||||
want []*plugins.Plugin
|
||||
}{
|
||||
{
|
||||
name: "Load a Core plugin",
|
||||
class: plugins.ClassCore,
|
||||
cfg: &config.Cfg{Features: featuremgmt.WithFeatures()},
|
||||
cfg: &config.PluginManagementCfg{Features: featuremgmt.WithFeatures()},
|
||||
pluginPaths: []string{filepath.Join(corePluginDir, "app/plugins/datasource/cloudwatch")},
|
||||
want: []*plugins.Plugin{
|
||||
{
|
||||
@@ -117,7 +117,7 @@ func TestLoader_Load(t *testing.T) {
|
||||
{
|
||||
name: "Load a Bundled plugin",
|
||||
class: plugins.ClassBundled,
|
||||
cfg: &config.Cfg{Features: featuremgmt.WithFeatures()},
|
||||
cfg: &config.PluginManagementCfg{Features: featuremgmt.WithFeatures()},
|
||||
pluginPaths: []string{"../testdata/valid-v2-signature"},
|
||||
want: []*plugins.Plugin{
|
||||
{
|
||||
@@ -158,7 +158,7 @@ func TestLoader_Load(t *testing.T) {
|
||||
{
|
||||
name: "Load plugin with symbolic links",
|
||||
class: plugins.ClassExternal,
|
||||
cfg: &config.Cfg{Features: featuremgmt.WithFeatures()},
|
||||
cfg: &config.PluginManagementCfg{Features: featuremgmt.WithFeatures()},
|
||||
pluginPaths: []string{"../testdata/symbolic-plugin-dirs"},
|
||||
want: []*plugins.Plugin{
|
||||
{
|
||||
@@ -237,7 +237,7 @@ func TestLoader_Load(t *testing.T) {
|
||||
{
|
||||
name: "Load an unsigned plugin (development)",
|
||||
class: plugins.ClassExternal,
|
||||
cfg: &config.Cfg{
|
||||
cfg: &config.PluginManagementCfg{
|
||||
DevMode: true,
|
||||
Features: featuremgmt.WithFeatures(),
|
||||
},
|
||||
@@ -277,14 +277,14 @@ func TestLoader_Load(t *testing.T) {
|
||||
{
|
||||
name: "Load an unsigned plugin (production)",
|
||||
class: plugins.ClassExternal,
|
||||
cfg: &config.Cfg{Features: featuremgmt.WithFeatures()},
|
||||
cfg: &config.PluginManagementCfg{Features: featuremgmt.WithFeatures()},
|
||||
pluginPaths: []string{"../testdata/unsigned-datasource"},
|
||||
want: []*plugins.Plugin{},
|
||||
},
|
||||
{
|
||||
name: "Load an unsigned plugin using PluginsAllowUnsigned config (production)",
|
||||
class: plugins.ClassExternal,
|
||||
cfg: &config.Cfg{
|
||||
cfg: &config.PluginManagementCfg{
|
||||
PluginsAllowUnsigned: []string{"test-datasource"},
|
||||
Features: featuremgmt.WithFeatures(),
|
||||
},
|
||||
@@ -324,14 +324,14 @@ func TestLoader_Load(t *testing.T) {
|
||||
{
|
||||
name: "Load a plugin with v1 manifest should return signatureInvalid",
|
||||
class: plugins.ClassExternal,
|
||||
cfg: &config.Cfg{Features: featuremgmt.WithFeatures()},
|
||||
cfg: &config.PluginManagementCfg{Features: featuremgmt.WithFeatures()},
|
||||
pluginPaths: []string{"../testdata/lacking-files"},
|
||||
want: []*plugins.Plugin{},
|
||||
},
|
||||
{
|
||||
name: "Load a plugin with v1 manifest using PluginsAllowUnsigned config (production) should return signatureInvali",
|
||||
class: plugins.ClassExternal,
|
||||
cfg: &config.Cfg{
|
||||
cfg: &config.PluginManagementCfg{
|
||||
PluginsAllowUnsigned: []string{"test-datasource"},
|
||||
Features: featuremgmt.WithFeatures(),
|
||||
},
|
||||
@@ -341,7 +341,7 @@ func TestLoader_Load(t *testing.T) {
|
||||
{
|
||||
name: "Load a plugin with manifest which has a file not found in plugin folder",
|
||||
class: plugins.ClassExternal,
|
||||
cfg: &config.Cfg{
|
||||
cfg: &config.PluginManagementCfg{
|
||||
PluginsAllowUnsigned: []string{"test-datasource"},
|
||||
Features: featuremgmt.WithFeatures(),
|
||||
},
|
||||
@@ -351,7 +351,7 @@ func TestLoader_Load(t *testing.T) {
|
||||
{
|
||||
name: "Load a plugin with file which is missing from the manifest",
|
||||
class: plugins.ClassExternal,
|
||||
cfg: &config.Cfg{
|
||||
cfg: &config.PluginManagementCfg{
|
||||
PluginsAllowUnsigned: []string{"test-datasource"},
|
||||
Features: featuremgmt.WithFeatures(),
|
||||
},
|
||||
@@ -361,7 +361,7 @@ func TestLoader_Load(t *testing.T) {
|
||||
{
|
||||
name: "Load an app with includes",
|
||||
class: plugins.ClassExternal,
|
||||
cfg: &config.Cfg{
|
||||
cfg: &config.PluginManagementCfg{
|
||||
PluginsAllowUnsigned: []string{"test-app"},
|
||||
Features: featuremgmt.WithFeatures(),
|
||||
},
|
||||
@@ -413,7 +413,7 @@ func TestLoader_Load(t *testing.T) {
|
||||
{
|
||||
name: "Load a plugin with app sub url set",
|
||||
class: plugins.ClassExternal,
|
||||
cfg: &config.Cfg{
|
||||
cfg: &config.PluginManagementCfg{
|
||||
DevMode: true,
|
||||
GrafanaAppSubURL: "grafana",
|
||||
Features: featuremgmt.WithFeatures(),
|
||||
|
||||
@@ -42,7 +42,7 @@ type Opts struct {
|
||||
}
|
||||
|
||||
// New returns a new Bootstrap stage.
|
||||
func New(cfg *config.Cfg, opts Opts) *Bootstrap {
|
||||
func New(cfg *config.PluginManagementCfg, opts Opts) *Bootstrap {
|
||||
if opts.ConstructFunc == nil {
|
||||
opts.ConstructFunc = DefaultConstructFunc(signature.DefaultCalculator(cfg), assetpath.DefaultService(cfg))
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ func DefaultConstructFunc(signatureCalculator plugins.SignatureCalculator, asset
|
||||
}
|
||||
|
||||
// DefaultDecorateFuncs are the default DecorateFuncs used for the Decorate step of the Bootstrap stage.
|
||||
func DefaultDecorateFuncs(cfg *config.Cfg) []DecorateFunc {
|
||||
func DefaultDecorateFuncs(cfg *config.PluginManagementCfg) []DecorateFunc {
|
||||
return []DecorateFunc{
|
||||
AppDefaultNavURLDecorateFunc,
|
||||
TemplateDecorateFunc,
|
||||
@@ -161,7 +161,7 @@ func configureAppChildPlugin(parent *plugins.Plugin, child *plugins.Plugin) {
|
||||
// SkipHostEnvVarsDecorateFunc returns a DecorateFunc that configures the SkipHostEnvVars field of the plugin.
|
||||
// It will be set to true if the FlagPluginsSkipHostEnvVars feature flag is set, and the plugin is not present in the
|
||||
// ForwardHostEnvVars plugin ids list.
|
||||
func SkipHostEnvVarsDecorateFunc(cfg *config.Cfg) DecorateFunc {
|
||||
func SkipHostEnvVarsDecorateFunc(cfg *config.PluginManagementCfg) DecorateFunc {
|
||||
return func(_ context.Context, p *plugins.Plugin) (*plugins.Plugin, error) {
|
||||
p.SkipHostEnvVars = cfg.Features.IsEnabledGlobally(featuremgmt.FlagPluginsSkipHostEnvVars) &&
|
||||
!slices.Contains(cfg.ForwardHostEnvVars, p.ID)
|
||||
|
||||
@@ -144,7 +144,7 @@ func TestSkipEnvVarsDecorateFunc(t *testing.T) {
|
||||
const pluginID = "plugin-id"
|
||||
|
||||
t.Run("feature flag is not present", func(t *testing.T) {
|
||||
f := SkipHostEnvVarsDecorateFunc(&config.Cfg{Features: featuremgmt.WithFeatures()})
|
||||
f := SkipHostEnvVarsDecorateFunc(&config.PluginManagementCfg{Features: featuremgmt.WithFeatures()})
|
||||
p, err := f(context.Background(), &plugins.Plugin{JSONData: plugins.JSONData{ID: pluginID}})
|
||||
require.NoError(t, err)
|
||||
require.False(t, p.SkipHostEnvVars)
|
||||
@@ -152,7 +152,7 @@ func TestSkipEnvVarsDecorateFunc(t *testing.T) {
|
||||
|
||||
t.Run("feature flag is present", func(t *testing.T) {
|
||||
t.Run("no plugin settings should set SkipHostEnvVars to true", func(t *testing.T) {
|
||||
f := SkipHostEnvVarsDecorateFunc(&config.Cfg{
|
||||
f := SkipHostEnvVarsDecorateFunc(&config.PluginManagementCfg{
|
||||
Features: featuremgmt.WithFeatures(featuremgmt.FlagPluginsSkipHostEnvVars),
|
||||
})
|
||||
p, err := f(context.Background(), &plugins.Plugin{JSONData: plugins.JSONData{ID: pluginID}})
|
||||
@@ -188,7 +188,7 @@ func TestSkipEnvVarsDecorateFunc(t *testing.T) {
|
||||
},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
f := SkipHostEnvVarsDecorateFunc(&config.Cfg{
|
||||
f := SkipHostEnvVarsDecorateFunc(&config.PluginManagementCfg{
|
||||
Features: featuremgmt.WithFeatures(featuremgmt.FlagPluginsSkipHostEnvVars),
|
||||
ForwardHostEnvVars: tc.forwardHostEnvVars,
|
||||
})
|
||||
|
||||
@@ -40,7 +40,7 @@ type Opts struct {
|
||||
}
|
||||
|
||||
// New returns a new Discovery stage.
|
||||
func New(cfg *config.Cfg, opts Opts) *Discovery {
|
||||
func New(cfg *config.PluginManagementCfg, opts Opts) *Discovery {
|
||||
if opts.FindFunc == nil {
|
||||
opts.FindFunc = DefaultFindFunc(cfg)
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
|
||||
// DefaultFindFunc is the default function used for the Find step of the Discovery stage. It will scan the local
|
||||
// filesystem for plugins.
|
||||
func DefaultFindFunc(cfg *config.Cfg) FindFunc {
|
||||
func DefaultFindFunc(cfg *config.PluginManagementCfg) FindFunc {
|
||||
return finder.NewLocalFinder(cfg.DevMode, cfg.Features).Find
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ type Initializer interface {
|
||||
type InitializeFunc func(ctx context.Context, p *plugins.Plugin) (*plugins.Plugin, error)
|
||||
|
||||
type Initialize struct {
|
||||
cfg *config.Cfg
|
||||
cfg *config.PluginManagementCfg
|
||||
initializeSteps []InitializeFunc
|
||||
log log.Logger
|
||||
}
|
||||
@@ -27,7 +27,7 @@ type Opts struct {
|
||||
}
|
||||
|
||||
// New returns a new Initialization stage.
|
||||
func New(cfg *config.Cfg, opts Opts) *Initialize {
|
||||
func New(cfg *config.PluginManagementCfg, opts Opts) *Initialize {
|
||||
if opts.InitializeFuncs == nil {
|
||||
opts.InitializeFuncs = []InitializeFunc{}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ func (b *BackendClientInit) Initialize(ctx context.Context, p *plugins.Plugin) (
|
||||
}
|
||||
|
||||
// this will ensure that the env variables are calculated every time a plugin is started
|
||||
envFunc := func() []string { return b.envVarProvider.Get(ctx, p) }
|
||||
envFunc := func() []string { return b.envVarProvider.PluginEnvVars(ctx, p) }
|
||||
|
||||
if backendClient, err := backendFactory(p.ID, p.Logger(), envFunc); err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -121,12 +121,12 @@ func (f *fakeBackendProvider) BackendFactory(_ context.Context, _ *plugins.Plugi
|
||||
}
|
||||
|
||||
type fakeEnvVarsProvider struct {
|
||||
GetFunc func(ctx context.Context, p *plugins.Plugin) []string
|
||||
PluginEnvVarsFunc func(ctx context.Context, p *plugins.Plugin) []string
|
||||
}
|
||||
|
||||
func (f *fakeEnvVarsProvider) Get(ctx context.Context, p *plugins.Plugin) []string {
|
||||
if f.GetFunc != nil {
|
||||
return f.GetFunc(ctx, p)
|
||||
func (f *fakeEnvVarsProvider) PluginEnvVars(ctx context.Context, p *plugins.Plugin) []string {
|
||||
if f.PluginEnvVarsFunc != nil {
|
||||
return f.PluginEnvVars(ctx, p)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ type Terminator interface {
|
||||
type TerminateFunc func(ctx context.Context, p *plugins.Plugin) error
|
||||
|
||||
type Terminate struct {
|
||||
cfg *config.Cfg
|
||||
cfg *config.PluginManagementCfg
|
||||
terminateSteps []TerminateFunc
|
||||
log log.Logger
|
||||
}
|
||||
@@ -27,7 +27,7 @@ type Opts struct {
|
||||
}
|
||||
|
||||
// New returns a new Termination stage.
|
||||
func New(cfg *config.Cfg, opts Opts) (*Terminate, error) {
|
||||
func New(cfg *config.PluginManagementCfg, opts Opts) (*Terminate, error) {
|
||||
if opts.TerminateFuncs == nil {
|
||||
opts.TerminateFuncs = []TerminateFunc{}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
)
|
||||
|
||||
// DefaultValidateFuncs are the default ValidateFunc used for the Validate step of the Validation stage.
|
||||
func DefaultValidateFuncs(cfg *config.Cfg) []ValidateFunc {
|
||||
func DefaultValidateFuncs(cfg *config.PluginManagementCfg) []ValidateFunc {
|
||||
return []ValidateFunc{
|
||||
SignatureValidationStep(signature.NewValidator(signature.NewUnsignedAuthorizer(cfg))),
|
||||
ModuleJSValidationStep(),
|
||||
@@ -74,16 +74,16 @@ func (v *ModuleJSValidator) Validate(_ context.Context, p *plugins.Plugin) error
|
||||
}
|
||||
|
||||
type AngularDetector struct {
|
||||
cfg *config.Cfg
|
||||
cfg *config.PluginManagementCfg
|
||||
angularInspector angularinspector.Inspector
|
||||
log log.Logger
|
||||
}
|
||||
|
||||
func AngularDetectionStep(cfg *config.Cfg, angularInspector angularinspector.Inspector) ValidateFunc {
|
||||
func AngularDetectionStep(cfg *config.PluginManagementCfg, angularInspector angularinspector.Inspector) ValidateFunc {
|
||||
return newAngularDetector(cfg, angularInspector).Validate
|
||||
}
|
||||
|
||||
func newAngularDetector(cfg *config.Cfg, angularInspector angularinspector.Inspector) *AngularDetector {
|
||||
func newAngularDetector(cfg *config.PluginManagementCfg, angularInspector angularinspector.Inspector) *AngularDetector {
|
||||
return &AngularDetector{
|
||||
cfg: cfg,
|
||||
angularInspector: angularInspector,
|
||||
|
||||
@@ -17,7 +17,7 @@ type Validator interface {
|
||||
type ValidateFunc func(ctx context.Context, p *plugins.Plugin) error
|
||||
|
||||
type Validate struct {
|
||||
cfg *config.Cfg
|
||||
cfg *config.PluginManagementCfg
|
||||
validateSteps []ValidateFunc
|
||||
log log.Logger
|
||||
}
|
||||
@@ -27,7 +27,7 @@ type Opts struct {
|
||||
}
|
||||
|
||||
// New returns a new Validation stage.
|
||||
func New(cfg *config.Cfg, opts Opts) *Validate {
|
||||
func New(cfg *config.PluginManagementCfg, opts Opts) *Validate {
|
||||
if opts.ValidateFuncs == nil {
|
||||
opts.ValidateFuncs = DefaultValidateFuncs(cfg)
|
||||
}
|
||||
|
||||
@@ -5,18 +5,18 @@ import (
|
||||
"github.com/grafana/grafana/pkg/plugins/config"
|
||||
)
|
||||
|
||||
func ProvideOSSAuthorizer(cfg *config.Cfg) *UnsignedPluginAuthorizer {
|
||||
func ProvideOSSAuthorizer(cfg *config.PluginManagementCfg) *UnsignedPluginAuthorizer {
|
||||
return NewUnsignedAuthorizer(cfg)
|
||||
}
|
||||
|
||||
func NewUnsignedAuthorizer(cfg *config.Cfg) *UnsignedPluginAuthorizer {
|
||||
func NewUnsignedAuthorizer(cfg *config.PluginManagementCfg) *UnsignedPluginAuthorizer {
|
||||
return &UnsignedPluginAuthorizer{
|
||||
cfg: cfg,
|
||||
}
|
||||
}
|
||||
|
||||
type UnsignedPluginAuthorizer struct {
|
||||
cfg *config.Cfg
|
||||
cfg *config.PluginManagementCfg
|
||||
}
|
||||
|
||||
func (u *UnsignedPluginAuthorizer) CanLoadPlugin(p *plugins.Plugin) bool {
|
||||
|
||||
@@ -59,17 +59,17 @@ func (m *PluginManifest) isV2() bool {
|
||||
|
||||
type Signature struct {
|
||||
kr plugins.KeyRetriever
|
||||
cfg *config.Cfg
|
||||
cfg *config.PluginManagementCfg
|
||||
log log.Logger
|
||||
}
|
||||
|
||||
var _ plugins.SignatureCalculator = &Signature{}
|
||||
|
||||
func ProvideService(cfg *config.Cfg, kr plugins.KeyRetriever) *Signature {
|
||||
func ProvideService(cfg *config.PluginManagementCfg, kr plugins.KeyRetriever) *Signature {
|
||||
return NewCalculator(cfg, kr)
|
||||
}
|
||||
|
||||
func NewCalculator(cfg *config.Cfg, kr plugins.KeyRetriever) *Signature {
|
||||
func NewCalculator(cfg *config.PluginManagementCfg, kr plugins.KeyRetriever) *Signature {
|
||||
return &Signature{
|
||||
kr: kr,
|
||||
cfg: cfg,
|
||||
@@ -77,7 +77,7 @@ func NewCalculator(cfg *config.Cfg, kr plugins.KeyRetriever) *Signature {
|
||||
}
|
||||
}
|
||||
|
||||
func DefaultCalculator(cfg *config.Cfg) *Signature {
|
||||
func DefaultCalculator(cfg *config.PluginManagementCfg) *Signature {
|
||||
return &Signature{
|
||||
kr: statickey.New(),
|
||||
cfg: cfg,
|
||||
|
||||
@@ -52,7 +52,7 @@ NR7DnB0CCQHO+4FlSPtXFTzNepoc+CytQyDAeOLMLmf2Tqhk2YShk+G/YlVX
|
||||
-----END PGP SIGNATURE-----`
|
||||
|
||||
t.Run("valid manifest", func(t *testing.T) {
|
||||
s := ProvideService(&config.Cfg{}, statickey.New())
|
||||
s := ProvideService(&config.PluginManagementCfg{}, statickey.New())
|
||||
manifest, err := s.readPluginManifest(context.Background(), []byte(txt))
|
||||
|
||||
require.NoError(t, err)
|
||||
@@ -69,7 +69,7 @@ NR7DnB0CCQHO+4FlSPtXFTzNepoc+CytQyDAeOLMLmf2Tqhk2YShk+G/YlVX
|
||||
|
||||
t.Run("invalid manifest", func(t *testing.T) {
|
||||
modified := strings.ReplaceAll(txt, "README.md", "xxxxxxxxxx")
|
||||
s := ProvideService(&config.Cfg{}, statickey.New())
|
||||
s := ProvideService(&config.PluginManagementCfg{}, statickey.New())
|
||||
_, err := s.readPluginManifest(context.Background(), []byte(modified))
|
||||
require.Error(t, err)
|
||||
})
|
||||
@@ -107,7 +107,7 @@ khdr/tZ1PDgRxMqB/u+Vtbpl0xSxgblnrDOYMSI=
|
||||
-----END PGP SIGNATURE-----`
|
||||
|
||||
t.Run("valid manifest", func(t *testing.T) {
|
||||
s := ProvideService(&config.Cfg{}, statickey.New())
|
||||
s := ProvideService(&config.PluginManagementCfg{}, statickey.New())
|
||||
manifest, err := s.readPluginManifest(context.Background(), []byte(txt))
|
||||
|
||||
require.NoError(t, err)
|
||||
@@ -155,7 +155,7 @@ func TestCalculate(t *testing.T) {
|
||||
|
||||
for _, tc := range tcs {
|
||||
basePath := filepath.Join(parentDir, "testdata/non-pvt-with-root-url/plugin")
|
||||
s := ProvideService(&config.Cfg{GrafanaAppURL: tc.appURL}, statickey.New())
|
||||
s := ProvideService(&config.PluginManagementCfg{GrafanaAppURL: tc.appURL}, statickey.New())
|
||||
sig, err := s.Calculate(context.Background(), &fakes.FakePluginSource{
|
||||
PluginClassFunc: func(ctx context.Context) plugins.Class {
|
||||
return plugins.ClassExternal
|
||||
@@ -183,7 +183,7 @@ func TestCalculate(t *testing.T) {
|
||||
basePath := "../testdata/renderer-added-file/plugin"
|
||||
|
||||
runningWindows = true
|
||||
s := ProvideService(&config.Cfg{}, statickey.New())
|
||||
s := ProvideService(&config.PluginManagementCfg{}, statickey.New())
|
||||
sig, err := s.Calculate(context.Background(), &fakes.FakePluginSource{
|
||||
PluginClassFunc: func(ctx context.Context) plugins.Class {
|
||||
return plugins.ClassExternal
|
||||
@@ -247,7 +247,7 @@ func TestCalculate(t *testing.T) {
|
||||
toSlash = tc.platform.toSlashFunc()
|
||||
fromSlash = tc.platform.fromSlashFunc()
|
||||
|
||||
s := ProvideService(&config.Cfg{}, statickey.New())
|
||||
s := ProvideService(&config.PluginManagementCfg{}, statickey.New())
|
||||
pfs, err := tc.fsFactory()
|
||||
require.NoError(t, err)
|
||||
pfs, err = newPathSeparatorOverrideFS(string(tc.platform.separator), pfs)
|
||||
@@ -715,7 +715,7 @@ func Test_validateManifest(t *testing.T) {
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
s := ProvideService(&config.Cfg{}, statickey.New())
|
||||
s := ProvideService(&config.PluginManagementCfg{}, statickey.New())
|
||||
err := s.validateManifest(context.Background(), *tc.manifest, nil)
|
||||
require.Errorf(t, err, tc.expectedErr)
|
||||
})
|
||||
@@ -811,7 +811,7 @@ pHo=
|
||||
}
|
||||
|
||||
func Test_VerifyRevokedKey(t *testing.T) {
|
||||
s := ProvideService(&config.Cfg{}, &revokedKeyProvider{})
|
||||
s := ProvideService(&config.PluginManagementCfg{}, &revokedKeyProvider{})
|
||||
m := createV2Manifest(t)
|
||||
txt := `-----BEGIN PGP SIGNED MESSAGE-----
|
||||
Hash: SHA512
|
||||
|
||||
@@ -16,10 +16,10 @@ var ErrPluginNotCDN = errors.New("plugin is not a cdn plugin")
|
||||
|
||||
// Service provides methods for the plugins CDN.
|
||||
type Service struct {
|
||||
cfg *config.Cfg
|
||||
cfg *config.PluginManagementCfg
|
||||
}
|
||||
|
||||
func ProvideService(cfg *config.Cfg) *Service {
|
||||
func ProvideService(cfg *config.PluginManagementCfg) *Service {
|
||||
return &Service{cfg: cfg}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
)
|
||||
|
||||
func TestService(t *testing.T) {
|
||||
svc := ProvideService(&config.Cfg{
|
||||
svc := ProvideService(&config.PluginManagementCfg{
|
||||
PluginsCDNURLTemplate: "https://cdn.example.com",
|
||||
PluginSettings: map[string]map[string]string{
|
||||
"one": {"cdn": "true"},
|
||||
@@ -40,7 +40,7 @@ func TestService(t *testing.T) {
|
||||
},
|
||||
} {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
u, err := ProvideService(&config.Cfg{PluginsCDNURLTemplate: c.cfgURL}).BaseURL()
|
||||
u, err := ProvideService(&config.PluginManagementCfg{PluginsCDNURLTemplate: c.cfgURL}).BaseURL()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, c.expBaseURL, u)
|
||||
})
|
||||
|
||||
@@ -21,7 +21,7 @@ type Manager struct {
|
||||
log log.PrettyLogger
|
||||
}
|
||||
|
||||
func ProvideService(cfg *config.Cfg) (*Manager, error) {
|
||||
func ProvideService(cfg *config.PluginManagementCfg) (*Manager, error) {
|
||||
baseURL, err := url.JoinPath(cfg.GrafanaComURL, "/api/plugins")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
Reference in New Issue
Block a user