The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/pkg/kindsys/slot.go

121 lines
3.5 KiB

package kindsys
import (
"fmt"
"cuelang.org/go/cue"
)
// Slot represents one of Grafana's named slot definitions.
// TODO link to framework docs
type Slot struct {
name string
raw cue.Value
plugins map[string]bool
}
// Name returns the name of the Slot.
//
// The name is also used as the path at which a Slot lineage is defined in a
// plugin models.cue file.
func (s Slot) Name() string {
return s.name
}
// MetaSchema returns the meta-schema that is the contract between core or
// custom kinds that compose the meta-schema, and the plugin-declared composable
// kinds that implement the meta-schema.
func (s Slot) MetaSchema() cue.Value {
return s.raw
}
// ForPluginType indicates whether for this Slot, plugins of the given type may
// provide a slot implementation (first return value), and for those types that
// may, whether they must produce one (second return value).
//
// Expected values here are those in the set of
// ["github.com/grafana/grafana/pkg/plugins/plugindef".Type], though passing
// a string not in that set will harmlessly return {false, false}. That type is
// not used here to avoid import cycles.
//
// Note that, at least for now, plugins are not required to provide any slot
// implementations, and do so by simply not containing any .cue files in the
// "grafanaplugin" package. Consequently, the "must" return value is best
// understood as, "IF a plugin provides a *.cue files, it MUST contain an
// implementation of this slot."
func (s Slot) ForPluginType(plugintype string) (may, must bool) {
must, may = s.plugins[plugintype]
return
}
// IsGroup indicates whether the slot specifies a group lineage - one in which
// each top-level key represents a distinct schema for objects that are expected
// to exist in the wild, but objects corresponding to the root of the schema are not
// expected to exist.
func (s Slot) IsGroup() bool {
// TODO rely on first-class Thema properties for this, one they exist - https://github.com/grafana/thema/issues/62
switch s.name {
case "Panel", "DSOptions":
return true
case "Query":
return false
default:
panic("unreachable - unknown slot name " + s.name)
}
}
func FindSlot(name string) (*Slot, error) {
sl, has := AllSlots(nil)[name]
if !has {
return nil, fmt.Errorf("unsupported slot: %s", name)
}
return sl, nil
}
// AllSlots returns a map of all [Slot]s defined in the Grafana kindsys
// framework.
//
// TODO cache this for core context
func AllSlots(ctx *cue.Context) map[string]*Slot {
fw := CUEFramework(ctx)
slots := make(map[string]*Slot)
// Ignore err, can only happen if we change structure of fw files, and all we'd
// do is panic and that's what the next line will do anyway. Same for similar ignored
// errors later in this func
iter, _ := fw.LookupPath(cue.ParsePath("pluginTypeMetaSchema")).Fields(cue.Optional(true))
type nameopt struct {
name string
req bool
}
plugslots := make(map[string][]nameopt)
for iter.Next() {
plugin := iter.Selector().String()
iiter, _ := iter.Value().Fields(cue.Optional(true))
for iiter.Next() {
slotname := iiter.Selector().String()
plugslots[slotname] = append(plugslots[slotname], nameopt{
name: plugin,
req: !iiter.IsOptional(),
})
}
}
iter, _ = fw.LookupPath(cue.ParsePath("slots")).Fields(cue.Optional(true))
for iter.Next() {
n := iter.Selector().String()
sl := Slot{
name: n,
raw: iter.Value(),
plugins: make(map[string]bool),
}
for _, no := range plugslots[n] {
sl.plugins[no.name] = no.req
}
slots[n] = &sl
}
return slots
}