Plugins: Add metrics for fs + cloud provisioning info (#111030)

* add new metrics for plugin fs + cloud provisioning

* fix test

* update label
This commit is contained in:
Will Browne
2025-09-15 14:54:16 +01:00
committed by GitHub
parent 5b07d7031a
commit 2df39fc71a
15 changed files with 152 additions and 31 deletions
@@ -30,6 +30,7 @@ import (
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/pluginsintegration/pipeline"
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginerrs"
"github.com/grafana/grafana/pkg/services/pluginsintegration/provisionedplugins"
"github.com/grafana/grafana/pkg/setting"
)
@@ -1558,7 +1559,7 @@ func newLoader(t *testing.T, cfg *config.PluginManagementCfg, reg registry.Servi
return ProvideService(cfg, pipeline.ProvideDiscoveryStage(cfg, reg),
pipeline.ProvideBootstrapStage(cfg, signature.DefaultCalculator(cfg), assets),
pipeline.ProvideValidationStage(cfg, signature.NewValidator(signature.NewUnsignedAuthorizer(cfg)), angularInspector),
pipeline.ProvideInitializationStage(cfg, reg, backendFactory, proc, &fakes.FakeAuthService{}, fakes.NewFakeRoleRegistry(), fakes.NewFakeActionSetRegistry(), fakes.NewFakePluginEnvProvider(), tracing.InitializeTracerForTest()),
pipeline.ProvideInitializationStage(cfg, reg, backendFactory, proc, &fakes.FakeAuthService{}, fakes.NewFakeRoleRegistry(), fakes.NewFakeActionSetRegistry(), fakes.NewFakePluginEnvProvider(), tracing.InitializeTracerForTest(), provisionedplugins.NewNoop()),
terminate, errTracker)
}
@@ -1589,7 +1590,7 @@ func newLoaderWithOpts(t *testing.T, cfg *config.PluginManagementCfg, opts loade
return ProvideService(cfg, pipeline.ProvideDiscoveryStage(cfg, reg),
pipeline.ProvideBootstrapStage(cfg, signature.DefaultCalculator(cfg), assets),
pipeline.ProvideValidationStage(cfg, signature.NewValidator(signature.NewUnsignedAuthorizer(cfg)), angularInspector),
pipeline.ProvideInitializationStage(cfg, reg, backendFactoryProvider, proc, authServiceRegistry, fakes.NewFakeRoleRegistry(), fakes.NewFakeActionSetRegistry(), fakes.NewFakePluginEnvProvider(), tracing.InitializeTracerForTest()),
pipeline.ProvideInitializationStage(cfg, reg, backendFactoryProvider, proc, authServiceRegistry, fakes.NewFakeRoleRegistry(), fakes.NewFakeActionSetRegistry(), fakes.NewFakePluginEnvProvider(), tracing.InitializeTracerForTest(), provisionedplugins.NewNoop()),
terminate, errTracker)
}
@@ -20,6 +20,7 @@ import (
"github.com/grafana/grafana/pkg/plugins/manager/registry"
"github.com/grafana/grafana/pkg/plugins/manager/signature"
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginaccesscontrol"
"github.com/grafana/grafana/pkg/services/pluginsintegration/provisionedplugins"
)
func ProvideDiscoveryStage(cfg *config.PluginManagementCfg, pr registry.Service) *discovery.Discovery {
@@ -67,10 +68,9 @@ func ProvideValidationStage(cfg *config.PluginManagementCfg, sv signature.Valida
func ProvideInitializationStage(cfg *config.PluginManagementCfg, pr registry.Service, bp plugins.BackendFactoryProvider,
pm process.Manager, externalServiceRegistry auth.ExternalServiceRegistry,
roleRegistry pluginaccesscontrol.RoleRegistry,
actionSetRegistry pluginaccesscontrol.ActionSetRegistry,
pluginEnvProvider envvars.Provider,
tracer tracing.Tracer) *initialization.Initialize {
roleRegistry pluginaccesscontrol.RoleRegistry, actionSetRegistry pluginaccesscontrol.ActionSetRegistry,
pluginEnvProvider envvars.Provider, tracer tracing.Tracer, provisionedPluginsManager provisionedplugins.Manager,
) *initialization.Initialize {
return initialization.New(cfg, initialization.Opts{
InitializeFuncs: []initialization.InitializeFunc{
ExternalServiceRegistrationStep(cfg, externalServiceRegistry, tracer),
@@ -80,6 +80,8 @@ func ProvideInitializationStage(cfg *config.PluginManagementCfg, pr registry.Ser
RegisterActionSetsStep(actionSetRegistry),
ReportBuildMetrics,
ReportTargetMetrics,
ReportFSMetrics,
ReportCloudProvisioningMetrics(provisionedPluginsManager),
initialization.PluginRegistrationStep(pr),
},
})
@@ -9,6 +9,7 @@ import (
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
"github.com/grafana/grafana/pkg/cmd/grafana-cli/logger"
"github.com/grafana/grafana/pkg/infra/metrics"
"github.com/grafana/grafana/pkg/infra/tracing"
"github.com/grafana/grafana/pkg/plugins"
@@ -20,6 +21,7 @@ import (
"github.com/grafana/grafana/pkg/plugins/manager/registry"
"github.com/grafana/grafana/pkg/plugins/manager/signature"
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginaccesscontrol"
"github.com/grafana/grafana/pkg/services/pluginsintegration/provisionedplugins"
)
// ExternalServiceRegistration implements an InitializeFunc for registering external services.
@@ -139,6 +141,48 @@ func ReportTargetMetrics(_ context.Context, p *plugins.Plugin) (*plugins.Plugin,
return p, nil
}
// ReportFSMetrics reports plugin filesystem information for all non-core plugins.
func ReportFSMetrics(_ context.Context, p *plugins.Plugin) (*plugins.Plugin, error) {
if p.IsCorePlugin() {
// No metrics for core plugins
return p, nil
}
metrics.SetPluginFSInformation(p.ID, p.FS.Type())
return p, nil
}
// ReportCloudProvisioningMetrics reports plugin cloud provisioning information for all non-core plugins.
func ReportCloudProvisioningMetrics(ppManaged provisionedplugins.Manager) initialization.InitializeFunc {
cloudProvisioningMethod := plugins.CloudProvisioningMethodNone
pps, err := ppManaged.ProvisionedPlugins(context.Background())
if err != nil {
cloudProvisioningMethod = plugins.CloudProvisioningMethodUnknown
logger.Warn("Failed to get provisioned plugins", "error", err)
}
return func(ctx context.Context, p *plugins.Plugin) (*plugins.Plugin, error) {
if p.IsCorePlugin() {
// No metrics for core plugins
return p, nil
}
for _, pp := range pps {
if pp.ID != p.ID {
continue
}
if pp.URL == "" {
cloudProvisioningMethod = plugins.CloudProvisioningMethodCatalog
} else {
cloudProvisioningMethod = plugins.CloudProvisioningMethodURL
}
metrics.SetPluginProvisioningInformation(p.ID, string(cloudProvisioningMethod))
}
return p, nil
}
}
// SignatureValidation implements a ValidateFunc for validating plugin signatures.
type SignatureValidation struct {
signatureValidator signature.Validator
@@ -5,8 +5,8 @@ import (
"slices"
"github.com/Masterminds/semver"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/pluginsintegration/managedplugins"
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore"
"github.com/grafana/grafana/pkg/services/pluginsintegration/provisionedplugins"
@@ -51,11 +51,14 @@ func (s *Service) isManaged(ctx context.Context, pluginID string) bool {
func (s *Service) isProvisioned(ctx context.Context, pluginID string) bool {
if s.provisionedPlugins == nil {
var err error
s.provisionedPlugins, err = s.provisionedPluginsManager.ProvisionedPlugins(ctx)
pps, err := s.provisionedPluginsManager.ProvisionedPlugins(ctx)
if err != nil {
return false
}
s.provisionedPlugins = make([]string, len(pps))
for _, pp := range pps {
s.provisionedPlugins = append(s.provisionedPlugins, pp.ID)
}
}
return slices.Contains(s.provisionedPlugins, pluginID)
}
@@ -3,17 +3,22 @@ package provisionedplugins
import "context"
type Manager interface {
ProvisionedPlugins(ctx context.Context) ([]string, error)
ProvisionedPlugins(ctx context.Context) ([]Plugin, error)
}
var _ Manager = (*Noop)(nil)
type Plugin struct {
ID string
URL string
}
type Noop struct{}
func NewNoop() *Noop {
return &Noop{}
}
func (s *Noop) ProvisionedPlugins(_ context.Context) ([]string, error) {
return []string{}, nil
func (s *Noop) ProvisionedPlugins(_ context.Context) ([]Plugin, error) {
return []Plugin{}, nil
}
@@ -33,6 +33,7 @@ import (
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginconfig"
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginerrs"
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore"
"github.com/grafana/grafana/pkg/services/pluginsintegration/provisionedplugins"
"github.com/grafana/grafana/pkg/setting"
)
@@ -54,7 +55,7 @@ func CreateIntegrationTestCtx(t *testing.T, cfg *setting.Cfg, coreRegistry *core
disc := pipeline.ProvideDiscoveryStage(pCfg, reg)
boot := pipeline.ProvideBootstrapStage(pCfg, signature.ProvideService(pCfg, statickey.New()), assetpath.ProvideService(pCfg, cdn, pluginassets.ProvideService()))
valid := pipeline.ProvideValidationStage(pCfg, signature.NewValidator(signature.NewUnsignedAuthorizer(pCfg)), angularInspector)
init := pipeline.ProvideInitializationStage(pCfg, reg, provider.ProvideService(coreRegistry), proc, &fakes.FakeAuthService{}, fakes.NewFakeRoleRegistry(), fakes.NewFakeActionSetRegistry(), nil, tracing.InitializeTracerForTest())
init := pipeline.ProvideInitializationStage(pCfg, reg, provider.ProvideService(coreRegistry), proc, &fakes.FakeAuthService{}, fakes.NewFakeRoleRegistry(), fakes.NewFakeActionSetRegistry(), nil, tracing.InitializeTracerForTest(), provisionedplugins.NewNoop())
term, err := pipeline.ProvideTerminationStage(pCfg, reg, proc)
require.NoError(t, err)
@@ -100,7 +101,7 @@ func CreateTestLoader(t *testing.T, cfg *pluginsCfg.PluginManagementCfg, opts Lo
if opts.Initializer == nil {
reg := registry.ProvideService()
coreRegistry := coreplugin.NewRegistry(make(map[string]backendplugin.PluginFactoryFunc))
opts.Initializer = pipeline.ProvideInitializationStage(cfg, reg, provider.ProvideService(coreRegistry), process.ProvideService(), &fakes.FakeAuthService{}, fakes.NewFakeRoleRegistry(), fakes.NewFakeActionSetRegistry(), nil, tracing.InitializeTracerForTest())
opts.Initializer = pipeline.ProvideInitializationStage(cfg, reg, provider.ProvideService(coreRegistry), process.ProvideService(), &fakes.FakeAuthService{}, fakes.NewFakeRoleRegistry(), fakes.NewFakeActionSetRegistry(), nil, tracing.InitializeTracerForTest(), provisionedplugins.NewNoop())
}
if opts.Terminator == nil {