Register external datasource plugins on startup

Current code only registers core datasource k8s api groups.

Add external plugins.

Companion grafana-enterprise PR:

https://github.com/grafana/grafana-enterprise/pull/10125
This commit is contained in:
beejeebus
2025-11-07 14:42:41 -05:00
parent 90ddd922ad
commit 0e9fe9dc40
2 changed files with 26 additions and 26 deletions
+24 -24
View File
@@ -3,10 +3,8 @@ package datasource
import (
"context"
"encoding/json"
"errors"
"fmt"
"maps"
"path/filepath"
"github.com/prometheus/client_golang/prometheus"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -23,7 +21,6 @@ import (
datasourceV0 "github.com/grafana/grafana/pkg/apis/datasource/v0alpha1"
queryV0 "github.com/grafana/grafana/pkg/apis/query/v0alpha1"
grafanaregistry "github.com/grafana/grafana/pkg/apiserver/registry/generic"
"github.com/grafana/grafana/pkg/configprovider"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/plugins/manager/sources"
"github.com/grafana/grafana/pkg/promlib/models"
@@ -31,7 +28,6 @@ import (
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/apiserver/builder"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/tsdb/grafana-testdata-datasource/kinds"
)
@@ -53,7 +49,6 @@ type DataSourceAPIBuilder struct {
}
func RegisterAPIService(
cfgProvider configprovider.ConfigProvider,
features featuremgmt.FeatureToggles,
apiRegistrar builder.APIRegistrar,
pluginClient plugins.Client, // access to everything
@@ -61,6 +56,7 @@ func RegisterAPIService(
contextProvider PluginContextWrapper,
accessControl accesscontrol.AccessControl,
reg prometheus.Registerer,
pluginSources sources.Registry,
) (*DataSourceAPIBuilder, error) {
// We want to expose just a limited set of plugins
//nolint:staticcheck // not yet migrated to OpenFeature
@@ -75,13 +71,9 @@ func RegisterAPIService(
var err error
var builder *DataSourceAPIBuilder
cfg, err := cfgProvider.Get(context.Background())
pluginJSONs, err := getDatasourcePlugins(pluginSources)
if err != nil {
return nil, err
}
pluginJSONs, err := getCorePlugins(cfg)
if err != nil {
return nil, err
return nil, fmt.Errorf("error getting list of datasource plugins: %s", err)
}
ids := []string{
@@ -299,21 +291,29 @@ func (b *DataSourceAPIBuilder) GetOpenAPIDefinitions() openapi.GetOpenAPIDefinit
}
}
func getCorePlugins(cfg *setting.Cfg) ([]plugins.JSONData, error) {
coreDataSourcesPath := filepath.Join(cfg.StaticRootPath, "app", "plugins", "datasource")
coreDataSourcesSrc := sources.NewLocalSource(
plugins.ClassCore,
[]string{coreDataSourcesPath},
)
func getDatasourcePlugins(pluginSources sources.Registry) ([]plugins.JSONData, error) {
var pluginJSONs []plugins.JSONData
res, err := coreDataSourcesSrc.Discover(context.Background())
if err != nil {
return nil, errors.New("failed to load core data source plugins")
}
// It's possible that the same plugin will be found in different sources.
// Registering the same plugin twice in the API is Probably A Bad Thing,
// so this map keeps track of uniques, so we can skip duplicates.
var uniquePlugins = map[string]bool{}
pluginJSONs := make([]plugins.JSONData, 0, len(res))
for _, p := range res {
pluginJSONs = append(pluginJSONs, p.Primary.JSONData)
for _, pluginSource := range pluginSources.List(context.Background()) {
res, err := pluginSource.Discover(context.Background())
if err != nil {
return nil, err
}
for _, p := range res {
if p.Primary.JSONData.Type == plugins.TypeDataSource {
if _, found := uniquePlugins[p.Primary.JSONData.ID]; found {
backend.Logger.Info("Found duplicate plugin %s when registering API groups.", p.Primary.JSONData.ID)
continue
}
uniquePlugins[p.Primary.JSONData.ID] = true
pluginJSONs = append(pluginJSONs, p.Primary.JSONData)
}
}
}
return pluginJSONs, nil
}
+2 -2
View File
@@ -847,7 +847,7 @@ func Initialize(ctx context.Context, cfg *setting.Cfg, opts Options, apiOpts api
apiService := api4.ProvideService(cfg, routeRegisterImpl, accessControl, userService, authinfoimplService, ossGroups, identitySynchronizer, orgService, ldapImpl, userAuthTokenService, bundleregistryService)
dashboardsAPIBuilder := dashboard.RegisterAPIService(cfg, featureToggles, apiserverService, dashboardService, dashboardProvisioningService, service15, dashboardServiceImpl, dashboardPermissionsService, accessControl, accessClient, provisioningServiceImpl, dashboardsStore, registerer, sqlStore, tracingService, resourceClient, dualwriteService, sortService, quotaService, libraryPanelService, eventualRestConfigProvider, userService, libraryElementService, publicDashboardServiceImpl)
snapshotsAPIBuilder := dashboardsnapshot.RegisterAPIService(serviceImpl, apiserverService, cfg, featureToggles, sqlStore, registerer)
dataSourceAPIBuilder, err := datasource.RegisterAPIService(configProvider, featureToggles, apiserverService, middlewareHandler, scopedPluginDatasourceProvider, plugincontextProvider, accessControl, registerer)
dataSourceAPIBuilder, err := datasource.RegisterAPIService(featureToggles, apiserverService, middlewareHandler, scopedPluginDatasourceProvider, plugincontextProvider, accessControl, registerer, sourcesService)
if err != nil {
return nil, err
}
@@ -1485,7 +1485,7 @@ func InitializeForTest(ctx context.Context, t sqlutil.ITestDB, testingT interfac
apiService := api4.ProvideService(cfg, routeRegisterImpl, accessControl, userService, authinfoimplService, ossGroups, identitySynchronizer, orgService, ldapImpl, userAuthTokenService, bundleregistryService)
dashboardsAPIBuilder := dashboard.RegisterAPIService(cfg, featureToggles, apiserverService, dashboardService, dashboardProvisioningService, service15, dashboardServiceImpl, dashboardPermissionsService, accessControl, accessClient, provisioningServiceImpl, dashboardsStore, registerer, sqlStore, tracingService, resourceClient, dualwriteService, sortService, quotaService, libraryPanelService, eventualRestConfigProvider, userService, libraryElementService, publicDashboardServiceImpl)
snapshotsAPIBuilder := dashboardsnapshot.RegisterAPIService(serviceImpl, apiserverService, cfg, featureToggles, sqlStore, registerer)
dataSourceAPIBuilder, err := datasource.RegisterAPIService(configProvider, featureToggles, apiserverService, middlewareHandler, scopedPluginDatasourceProvider, plugincontextProvider, accessControl, registerer)
dataSourceAPIBuilder, err := datasource.RegisterAPIService(featureToggles, apiserverService, middlewareHandler, scopedPluginDatasourceProvider, plugincontextProvider, accessControl, registerer, sourcesService)
if err != nil {
return nil, err
}