plugins: Introduce generated, static core plugin registry (#54118)
* Refactor towards template/codegen framework * Add templates for plugin gen * Add Go codegen for plugins; overhaul framework, too * Add new codegen output; assorted framework fixes * Regenerate after merge * Remove accidental commit file, update templates * Export the pfs.Tree loader from plugin types * Print details from cuetsy errors * Generate loaders for all plugins and list in registry * Use pfs_gen.go over lineage_gen.go * Un-un-ignore main file * Introduce simple List static registry for plugins * Last tweaks to codegen * remove unused tvars * Ensure loop-local instances for both vars * Generate pfs parsing in-place in registry * Stop generating pfs_gen.go * Move Tree into pfs, rename subdir * Change package name to match dir * Ignore gocyclo on HTTPServer.getNavTree
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
// Copyright 2022 Grafana Labs
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// This file is autogenerated. DO NOT EDIT.
|
||||
//
|
||||
// Run `make gen-cue` from repository root to regenerate.
|
||||
|
||||
package corelist
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
|
||||
"github.com/grafana/grafana"
|
||||
"github.com/grafana/grafana/pkg/plugins/pfs"
|
||||
"github.com/grafana/thema"
|
||||
)
|
||||
|
||||
func makeTreeOrPanic(path string, pkgname string, lib thema.Library) *pfs.Tree {
|
||||
sub, err := fs.Sub(grafana.CueSchemaFS, path)
|
||||
if err != nil {
|
||||
panic("could not create fs sub to " + path)
|
||||
}
|
||||
tree, err := pfs.ParsePluginFS(sub, lib)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("error parsing plugin metadata for %s: %s", pkgname, err))
|
||||
}
|
||||
return tree
|
||||
}
|
||||
|
||||
func coreTreeList(lib thema.Library) pfs.TreeList {
|
||||
return pfs.TreeList{
|
||||
makeTreeOrPanic("public/app/plugins/datasource/alertmanager", "alertmanager", lib),
|
||||
makeTreeOrPanic("public/app/plugins/datasource/cloud-monitoring", "stackdriver", lib),
|
||||
makeTreeOrPanic("public/app/plugins/datasource/cloudwatch", "cloudwatch", lib),
|
||||
makeTreeOrPanic("public/app/plugins/datasource/dashboard", "dashboard", lib),
|
||||
makeTreeOrPanic("public/app/plugins/datasource/elasticsearch", "elasticsearch", lib),
|
||||
makeTreeOrPanic("public/app/plugins/datasource/grafana", "grafana", lib),
|
||||
makeTreeOrPanic("public/app/plugins/datasource/grafana-azure-monitor-datasource", "grafana_azure_monitor_datasource", lib),
|
||||
makeTreeOrPanic("public/app/plugins/datasource/graphite", "graphite", lib),
|
||||
makeTreeOrPanic("public/app/plugins/datasource/jaeger", "jaeger", lib),
|
||||
makeTreeOrPanic("public/app/plugins/datasource/loki", "loki", lib),
|
||||
makeTreeOrPanic("public/app/plugins/datasource/mssql", "mssql", lib),
|
||||
makeTreeOrPanic("public/app/plugins/datasource/mysql", "mysql", lib),
|
||||
makeTreeOrPanic("public/app/plugins/datasource/postgres", "postgres", lib),
|
||||
makeTreeOrPanic("public/app/plugins/datasource/prometheus", "prometheus", lib),
|
||||
makeTreeOrPanic("public/app/plugins/datasource/tempo", "tempo", lib),
|
||||
makeTreeOrPanic("public/app/plugins/datasource/testdata", "testdata", lib),
|
||||
makeTreeOrPanic("public/app/plugins/datasource/zipkin", "zipkin", lib),
|
||||
makeTreeOrPanic("public/app/plugins/panel/alertGroups", "alertGroups", lib),
|
||||
makeTreeOrPanic("public/app/plugins/panel/alertlist", "alertlist", lib),
|
||||
makeTreeOrPanic("public/app/plugins/panel/annolist", "annolist", lib),
|
||||
makeTreeOrPanic("public/app/plugins/panel/barchart", "barchart", lib),
|
||||
makeTreeOrPanic("public/app/plugins/panel/bargauge", "bargauge", lib),
|
||||
makeTreeOrPanic("public/app/plugins/panel/dashlist", "dashlist", lib),
|
||||
makeTreeOrPanic("public/app/plugins/panel/debug", "debug", lib),
|
||||
makeTreeOrPanic("public/app/plugins/panel/gauge", "gauge", lib),
|
||||
makeTreeOrPanic("public/app/plugins/panel/geomap", "geomap", lib),
|
||||
makeTreeOrPanic("public/app/plugins/panel/gettingstarted", "gettingstarted", lib),
|
||||
makeTreeOrPanic("public/app/plugins/panel/graph", "graph", lib),
|
||||
makeTreeOrPanic("public/app/plugins/panel/histogram", "histogram", lib),
|
||||
makeTreeOrPanic("public/app/plugins/panel/icon", "icon", lib),
|
||||
makeTreeOrPanic("public/app/plugins/panel/live", "live", lib),
|
||||
makeTreeOrPanic("public/app/plugins/panel/logs", "logs", lib),
|
||||
makeTreeOrPanic("public/app/plugins/panel/news", "news", lib),
|
||||
makeTreeOrPanic("public/app/plugins/panel/nodeGraph", "nodeGraph", lib),
|
||||
makeTreeOrPanic("public/app/plugins/panel/piechart", "piechart", lib),
|
||||
makeTreeOrPanic("public/app/plugins/panel/stat", "stat", lib),
|
||||
makeTreeOrPanic("public/app/plugins/panel/table-old", "table_old", lib),
|
||||
makeTreeOrPanic("public/app/plugins/panel/text", "text", lib),
|
||||
makeTreeOrPanic("public/app/plugins/panel/traces", "traces", lib),
|
||||
makeTreeOrPanic("public/app/plugins/panel/welcome", "welcome", lib),
|
||||
makeTreeOrPanic("public/app/plugins/panel/xychart", "xychart", lib),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package corelist
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/grafana/grafana/pkg/cuectx"
|
||||
"github.com/grafana/grafana/pkg/plugins/pfs"
|
||||
"github.com/grafana/thema"
|
||||
)
|
||||
|
||||
var coreTrees pfs.TreeList
|
||||
var coreOnce sync.Once
|
||||
|
||||
// New returns a pfs.TreeList containing the plugin trees for all core plugins
|
||||
// in the current version of Grafana.
|
||||
//
|
||||
// Go code within the grafana codebase should only ever call this with nil.
|
||||
func New(lib *thema.Library) pfs.TreeList {
|
||||
var tl pfs.TreeList
|
||||
if lib == nil {
|
||||
coreOnce.Do(func() {
|
||||
coreTrees = coreTreeList(cuectx.ProvideThemaLibrary())
|
||||
})
|
||||
tl = make(pfs.TreeList, len(coreTrees))
|
||||
copy(tl, coreTrees)
|
||||
} else {
|
||||
return coreTreeList(*lib)
|
||||
}
|
||||
return tl
|
||||
}
|
||||
@@ -17,6 +17,9 @@ var ErrInvalidRootFile = errors.New("plugin.json is invalid")
|
||||
// - A required slot for its type is not implemented (e.g. panel plugin does not implemented Panel)
|
||||
var ErrImplementedSlots = errors.New("slot implementation not allowed for this plugin type")
|
||||
|
||||
// ErrInvalidCUE indicates that a plugin's model.cue file contained invalid CUE.
|
||||
var ErrInvalidCUE = errors.New("CUE syntax error")
|
||||
|
||||
// ErrInvalidLineage indicates that the plugin contains an invalid lineage
|
||||
// declaration, according to Thema's validation rules in
|
||||
// ["github.com/grafana/thema".BindLineage].
|
||||
|
||||
+29
-5
@@ -133,7 +133,28 @@ func (t *Tree) RootPlugin() PluginInfo {
|
||||
// SubPlugins returned a map of the PluginInfos for subplugins
|
||||
// within the tree, if any, keyed by subpath.
|
||||
func (t *Tree) SubPlugins() map[string]PluginInfo {
|
||||
panic("TODO")
|
||||
// TODO implement these once ParsePluginFS descends
|
||||
return nil
|
||||
}
|
||||
|
||||
// TreeList is a slice of validated plugin fs Trees with helper methods
|
||||
// for filtering to particular subsets of its members.
|
||||
type TreeList []*Tree
|
||||
|
||||
// LineagesForSlot returns the set of plugin-defined lineages that implement a
|
||||
// particular named Grafana slot (See ["github.com/grafana/grafana/pkg/framework/coremodel".Slot]).
|
||||
func (tl TreeList) LineagesForSlot(slotname string) map[string]thema.Lineage {
|
||||
m := make(map[string]thema.Lineage)
|
||||
for _, tree := range tl {
|
||||
rootp := tree.RootPlugin()
|
||||
rid := rootp.Meta().Id
|
||||
|
||||
if lin, has := rootp.SlotImplementations()[slotname]; has {
|
||||
m[rid] = lin
|
||||
}
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
// PluginInfo represents everything knowable about a single plugin from static
|
||||
@@ -166,8 +187,8 @@ func (pi PluginInfo) Meta() pluginmeta.Model {
|
||||
// ParsePluginFS takes an fs.FS and checks that it represents exactly one valid
|
||||
// plugin fs tree, with the fs.FS root as the root of the tree.
|
||||
//
|
||||
// It does not descend into subdirectories to search for additional
|
||||
// plugin.json files.
|
||||
// It does not descend into subdirectories to search for additional plugin.json
|
||||
// files.
|
||||
// TODO no descent is ok for core plugins, but won't cut it in general
|
||||
func ParsePluginFS(f fs.FS, lib thema.Library) (*Tree, error) {
|
||||
if f == nil {
|
||||
@@ -234,6 +255,9 @@ func ParsePluginFS(f fs.FS, lib thema.Library) (*Tree, error) {
|
||||
}
|
||||
|
||||
val := ctx.BuildInstance(bi)
|
||||
if val.Err() != nil {
|
||||
return nil, ewrap(fmt.Errorf("models.cue is invalid CUE: %w", val.Err()), ErrInvalidCUE)
|
||||
}
|
||||
for _, s := range allslots {
|
||||
iv := val.LookupPath(cue.ParsePath(s.slot.Name()))
|
||||
lin, err := bindSlotLineage(iv, s.slot, r.meta, lib)
|
||||
@@ -249,7 +273,7 @@ func ParsePluginFS(f fs.FS, lib thema.Library) (*Tree, error) {
|
||||
return tree, nil
|
||||
}
|
||||
|
||||
func bindSlotLineage(v cue.Value, s *coremodel.Slot, meta pluginmeta.Model, lib thema.Library) (thema.Lineage, error) {
|
||||
func bindSlotLineage(v cue.Value, s *coremodel.Slot, meta pluginmeta.Model, lib thema.Library, opts ...thema.BindOption) (thema.Lineage, error) {
|
||||
accept, required := s.ForPluginType(string(meta.Type))
|
||||
exists := v.Exists()
|
||||
|
||||
@@ -269,7 +293,7 @@ func bindSlotLineage(v cue.Value, s *coremodel.Slot, meta pluginmeta.Model, lib
|
||||
|
||||
// TODO make this opt real in thema, then uncomment to enforce joinSchema
|
||||
// lin, err := thema.BindLineage(iv, lib, thema.SatisfiesJoinSchema(s.MetaSchema()))
|
||||
lin, err := thema.BindLineage(v, lib)
|
||||
lin, err := thema.BindLineage(v, lib, opts...)
|
||||
if err != nil {
|
||||
return nil, ewrap(fmt.Errorf("%s: invalid thema lineage for slot %s: %w", meta.Id, s.Name(), err), ErrInvalidLineage)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user