Kindsys: Remove Raw kind category (#60992)

* Remove Raw references

* Remove more raws

* Re-generate files

* Remove raw folder from veneer

* Fix import

* Fix lint

* Bring back raw folder in grafana-schema

* Another lint

* Remove use of "Structured" word in kinds

* Delete unused function and remove some structured words

* Bunch more removals of structured name

Co-authored-by: sam boyer <sdboyer@grafana.com>
This commit is contained in:
Selene
2023-01-05 13:54:42 -05:00
committed by GitHub
co-authored by sam boyer
parent db369fc5b2
commit 8f29450594
34 changed files with 148 additions and 560 deletions
+1 -2
View File
@@ -13,8 +13,7 @@ This document is the guide to extending kindsys. But first, we have to identify
* **Code generators** - written using the `github.com/grafana/codejen` framework, which applies the [single responsibility principle](https://en.wikipedia.org/wiki/Single-responsibility_principle) to code generation, allowing us to compose modular code generators. Each jenny - a modular generator with a single responsibility - is declared as a `pkg/codegen/jenny_*.go` file.
* **Registries** - generated lists of all or a well-defined subset of kinds that can be used in code. `pkg/registries/corekind` is a registry of all core `pkg/kindsys.Interface` implementations; `packages/grafana-schema/src/index.gen.ts` is a registry of all the TypeScript types generated from the current versions of each kind's schema.
* **Kind declarations** - the declarations of individual kinds. By kind category:
* **Core Structured** - each child directory of `kinds/structured`.
* **Raw** - each child directory of `kinds/raw`.
* **Core** - each child directory of `kinds`.
* **Composable** - In Grafana core, `public/app/plugins/*/*/models.cue` files.
* **Custom** - No examples in Grafana core. See [operator-app-sdk](https://github.com/grafana/operator-app-sdk) (TODO that repo is private; make it public, or point to public examples).
+3 -11
View File
@@ -67,22 +67,14 @@ type Interface interface {
Maturity() Maturity // TODO unclear if we want maturity for raw kinds
}
// TODO docs
type Raw interface {
Interface
// TODO docs
Decl() *Decl[RawProperties]
}
type Structured interface {
type Core interface {
Interface
// TODO docs
Lineage() thema.Lineage
// TODO docs
Decl() *Decl[CoreStructuredProperties] // TODO figure out how to reconcile this interface with CustomStructuredProperties
Decl() *Decl[CoreProperties] // TODO figure out how to reconcile this interface with CustomProperties
}
// type Composable interface {
@@ -92,5 +84,5 @@ type Structured interface {
// Lineage() thema.Lineage
//
// // TODO docs
// Properties() CoreStructuredProperties // TODO figure out how to reconcile this interface with CustomStructuredProperties
// Properties() CoreProperties // TODO figure out how to reconcile this interface with CustomProperties
// }
+8 -7
View File
@@ -1,15 +1,16 @@
package kindsys
// CustomStructured specifies the Kind category for plugin-defined arbitrary types.
// Custom kinds have the same purpose as CoreStructured kinds, differing only in
// Custom specifies the kind category for plugin-defined arbitrary types.
// Custom kinds have the same purpose as Core kinds, differing only in
// that they are declared by external plugins rather than in Grafana core. As such,
// this specification is kept closely aligned with the CoreStructured kind.
// this specification is kept closely aligned with the Core kind.
//
// Grafana provides Kubernetes apiserver-shaped APIs for interacting with custom kinds -
// The same API patterns (and clients) used to interact with CustomResources.
#CustomStructured: {
#Structured
// Grafana provides Kubernetes apiserver-shaped HTTP APIs for interacting with custom
// kinds - the same API patterns (and clients) used to interact with k8s CustomResources.
#Custom: S={
_sharedKind
lineage: { name: S.machineName }
lineageIsGroup: false
...
}
+25 -60
View File
@@ -6,25 +6,23 @@ import (
"github.com/grafana/thema"
)
// A Kind specifies a type of Grafana resource.
// A Kind is a specification for a type of object that Grafana knows
// how to work with. Each kind definition contains a schema, and some
// declarative metadata and constraints.
//
// An instance of a Kind is called an entity. An entity is a sequence of bytes -
// for example, a JSON file or HTTP request body - that conforms to the
// constraints defined in a Kind, and enforced by Grafana's entity system.
// An instance of a kind is called a resource. Resources are a sequence of
// bytes - for example, a JSON file or HTTP request body - that conforms
// to the schemas and other constraints defined in a Kind.
//
// Once Grafana has determined a given byte sequence to be an
// instance of a known Kind, kind-specific behaviors can be applied,
// requests can be routed, events can be triggered, etc.
//
// Classes and objects in most programming languages are analogous:
// - #Kind is like a `class` keyword
// - Each declaration of #Kind is like a class declaration
// - Byte sequences are like arguments to the class constructor
// - Entities are like objects - what's returned from the constructor
// Grafana's kinds are similar to Kubernetes CustomResourceDefinitions.
// Grafana provides a standard mechanism for representing its kinds as CRDs.
//
// There are four categories of kinds: Raw, Composable, CoreStructured,
// and CustomStructured.
#Kind: #Raw | #Composable | #CoreStructured | #CustomStructured
// There are three categories of kinds: Core, Custom, and Composable.
#Kind: #Composable | #Core | #Custom
// properties shared between all kind categories.
_sharedKind: {
@@ -66,69 +64,37 @@ _sharedKind: {
// https://github.com/grafana/thema/issues/62
lineageIsGroup: bool
// lineage is the Thema lineage containing all the schemas that have existed for this kind.
lineage: thema.#Lineage
// currentVersion is computed to be the syntactic version number of the latest
// schema in lineage.
currentVersion: thema.#SyntacticVersion & (thema.#LatestVersion & {lin: lineage}).out
maturity: #Maturity
// The kind system itself is not mature enough yet for any single
// kind to advance beyond "experimental"
// TODO allow more maturity stages once system is ready https://github.com/orgs/grafana/projects/133/views/8
maturity: *"merged" | "experimental"
// form indicates whether the kind has a schema ("structured") or not ("raw")
form: "structured" | "raw"
}
// Maturity indicates the how far a given kind declaration is in its initial
// journey. Mature kinds still evolve, but with guarantees about compatibility.
#Maturity: "merged" | "experimental" | "stable" | "mature"
// Structured encompasses all three of the structured kind categories, in which
// a schema specifies validity rules for the byte sequence. These represent all
// the conventional types and functional resources in Grafana, such as
// dashboards and datasources.
//
// Structured kinds may be defined either by Grafana itself (#CoreStructured),
// or by plugins (#CustomStructured). Plugin-defined kinds have a slightly
// reduced set of capabilities, due to the constraints imposed by them being run
// in separate processes, and the risks arising from executing code from
// potentially untrusted third parties.
#Structured: S={
// Core specifies the kind category for core-defined arbitrary types.
// Familiar types and functional resources in Grafana, such as dashboards and
// and datasources, are represented as core kinds.
#Core: S=close({
_sharedKind
form: "structured"
// lineage is the Thema lineage containing all the schemas that have existed for this kind.
// It is required that lineage.name is the same as the [machineName].
lineage: thema.#Lineage & { name: S.machineName }
currentVersion: thema.#SyntacticVersion & (thema.#LatestVersion & {lin: lineage}).out
}
// Raw is a category of Kind that specifies handling for a raw file,
// like an image, or an svg or parquet file. Grafana mostly acts as asset storage for raw
// kinds: the byte sequence is a black box to Grafana, and type is determined
// through metadata such as file extension.
#Raw: {
_sharedKind
form: "raw"
// TODO docs
extensions?: [...string]
lineage: { name: S.machineName }
lineageIsGroup: false
})
// known TODOs
// - sanitize function
// - get summary
}
// TODO
#CoreStructured: {
#Structured
lineageIsGroup: false
}
// Composable is a category of structured kind that provides schema elements for
// composition into CoreStructured and CustomStructured kinds. Grafana plugins
// Composable is a category of kind that provides schema elements for
// composition into Core and Custom kinds. Grafana plugins
// provide composable kinds; for example, a datasource plugin provides one to
// describe the structure of its queries, which is then composed into dashboards
// and alerting rules.
@@ -138,7 +104,6 @@ _sharedKind: {
// that ComposableKind.
#Composable: S={
_sharedKind
form: "structured"
// TODO docs
// TODO unify this with the existing slots decls in pkg/framework/coremodel
+15 -31
View File
@@ -12,49 +12,33 @@ type CommonProperties struct {
Maturity Maturity `json:"maturity"`
}
// RawProperties represents the static properties in a #Raw kind declaration that are
// trivially representable with basic Go types.
//
// When a .cue #Raw declaration is loaded through the standard [LoadCoreKind],
// func, it is fully validated and populated according to all rules specified
// in CUE for #Raw kinds.
type RawProperties struct {
CommonProperties
Extensions []string `json:"extensions"`
}
func (m RawProperties) _private() {}
func (m RawProperties) Common() CommonProperties {
return m.CommonProperties
}
// CoreStructuredProperties represents the static properties in the declaration of a
// #CoreStructured kind that are representable with basic Go types. This
// CoreProperties represents the static properties in the declaration of a
// #Core kind that are representable with basic Go types. This
// excludes Thema schemas.
//
// When a .cue #CoreStructured declaration is loaded through the standard [LoadCoreKind],
// When a .cue #Core declaration is loaded through the standard [LoadCoreKind],
// func, it is fully validated and populated according to all rules specified
// in CUE for #CoreStructured kinds.
type CoreStructuredProperties struct {
// in CUE for #Core kinds.
type CoreProperties struct {
CommonProperties
CurrentVersion thema.SyntacticVersion `json:"currentVersion"`
}
func (m CoreStructuredProperties) _private() {}
func (m CoreStructuredProperties) Common() CommonProperties {
func (m CoreProperties) _private() {}
func (m CoreProperties) Common() CommonProperties {
return m.CommonProperties
}
// CustomStructuredProperties represents the static properties in the declaration of a
// #CustomStructured kind that are representable with basic Go types. This
// CustomProperties represents the static properties in the declaration of a
// #Custom kind that are representable with basic Go types. This
// excludes Thema schemas.
type CustomStructuredProperties struct {
type CustomProperties struct {
CommonProperties
CurrentVersion thema.SyntacticVersion `json:"currentVersion"`
}
func (m CustomStructuredProperties) _private() {}
func (m CustomStructuredProperties) Common() CommonProperties {
func (m CustomProperties) _private() {}
func (m CustomProperties) Common() CommonProperties {
return m.CommonProperties
}
@@ -72,8 +56,8 @@ func (m ComposableProperties) Common() CommonProperties {
}
// SomeKindProperties is an interface type to abstract over the different kind
// property struct types: [RawProperties], [CoreStructuredProperties],
// [CustomStructuredProperties], [ComposableProperties].
// property struct types: [CoreProperties], [CustomProperties],
// [ComposableProperties].
//
// It is the traditional interface counterpart to the generic type constraint
// KindProperties.
@@ -85,5 +69,5 @@ type SomeKindProperties interface {
// KindProperties is a type parameter that comprises the base possible set of
// kind metadata configurations.
type KindProperties interface {
RawProperties | CoreStructuredProperties | CustomStructuredProperties | ComposableProperties
CoreProperties | CustomProperties | ComposableProperties
}
+19 -39
View File
@@ -12,19 +12,10 @@ import (
"github.com/grafana/thema"
)
// DeclParentPath is the path, relative to the repository root, where
// each child directory is expected to contain directories with .cue files,
// declaring one kind.
var DeclParentPath = "kinds"
// CoreStructuredDeclParentPath is the path, relative to the repository root, where
// CoreDeclParentPath is the path, relative to the repository root, where
// each child directory is expected to contain .cue files declaring one
// CoreStructured kind.
var CoreStructuredDeclParentPath = filepath.Join(DeclParentPath, "structured")
// RawDeclParentPath is the path, relative to the repository root, where each child
// directory is expected to contain .cue files declaring one Raw kind.
var RawDeclParentPath = filepath.Join(DeclParentPath, "raw")
// Core kind.
var CoreDeclParentPath = "kinds"
// GoCoreKindParentPath is the path, relative to the repository root, to the directory
// containing one directory per kind, full of generated Go kind output: types and bindings.
@@ -99,12 +90,10 @@ func ToKindMeta[T KindProperties](v cue.Value) (T, error) {
anyprops := any(*props).(SomeKindProperties)
switch anyprops.(type) {
case RawProperties:
kdef = fw.LookupPath(cue.MakePath(cue.Def("Raw")))
case CoreStructuredProperties:
kdef = fw.LookupPath(cue.MakePath(cue.Def("CoreStructured")))
case CustomStructuredProperties:
kdef = fw.LookupPath(cue.MakePath(cue.Def("CustomStructured")))
case CoreProperties:
kdef = fw.LookupPath(cue.MakePath(cue.Def("Core")))
case CustomProperties:
kdef = fw.LookupPath(cue.MakePath(cue.Def("Custom")))
case ComposableProperties:
kdef = fw.LookupPath(cue.MakePath(cue.Def("Composable")))
default:
@@ -136,8 +125,7 @@ type SomeDecl struct {
Properties SomeKindProperties
}
// BindKindLineage binds the lineage for the kind declaration. nil, nil is returned
// for raw kinds.
// BindKindLineage binds the lineage for the kind declaration.
//
// For kinds with a corresponding Go type, it is left to the caller to associate
// that Go type with the lineage returned from this function by a call to [thema.BindType].
@@ -146,30 +134,22 @@ func (decl *SomeDecl) BindKindLineage(rt *thema.Runtime, opts ...thema.BindOptio
rt = cuectx.GrafanaThemaRuntime()
}
switch decl.Properties.(type) {
case RawProperties:
return nil, nil
case CoreStructuredProperties, CustomStructuredProperties, ComposableProperties:
case CoreProperties, CustomProperties, ComposableProperties:
return thema.BindLineage(decl.V.LookupPath(cue.MakePath(cue.Str("lineage"))), rt, opts...)
default:
panic("unreachable")
}
}
// IsRaw indicates whether the represented kind is a raw kind.
func (decl *SomeDecl) IsRaw() bool {
_, is := decl.Properties.(RawProperties)
// IsCore indicates whether the represented kind is a core kind.
func (decl *SomeDecl) IsCore() bool {
_, is := decl.Properties.(CoreProperties)
return is
}
// IsCoreStructured indicates whether the represented kind is a core structured kind.
func (decl *SomeDecl) IsCoreStructured() bool {
_, is := decl.Properties.(CoreStructuredProperties)
return is
}
// IsCustomStructured indicates whether the represented kind is a custom structured kind.
func (decl *SomeDecl) IsCustomStructured() bool {
_, is := decl.Properties.(CustomStructuredProperties)
// IsCustom indicates whether the represented kind is a custom kind.
func (decl *SomeDecl) IsCustom() bool {
_, is := decl.Properties.(CustomProperties)
return is
}
@@ -204,7 +184,7 @@ func (decl *Decl[T]) Some() *SomeDecl {
//
// declpath is the path to the directory containing the core kind declaration,
// relative to the grafana/grafana root. For example, dashboards are in
// "kinds/structured/dashboard".
// "kinds/dashboard".
//
// The .cue file bytes containing the core kind declaration will be retrieved
// from the central embedded FS, [grafana.CueSchemaFS]. If desired (e.g. for
@@ -215,15 +195,15 @@ func (decl *Decl[T]) Some() *SomeDecl {
// This is a low-level function, primarily intended for use in code generation.
// For representations of core kinds that are useful in Go programs at runtime,
// see ["github.com/grafana/grafana/pkg/registry/corekind"].
func LoadCoreKind[T RawProperties | CoreStructuredProperties](declpath string, ctx *cue.Context, overlay fs.FS) (*Decl[T], error) {
func LoadCoreKind(declpath string, ctx *cue.Context, overlay fs.FS) (*Decl[CoreProperties], error) {
vk, err := cuectx.BuildGrafanaInstance(ctx, declpath, "kind", overlay)
if err != nil {
return nil, err
}
decl := &Decl[T]{
decl := &Decl[CoreProperties]{
V: vk,
}
decl.Properties, err = ToKindMeta[T](vk)
decl.Properties, err = ToKindMeta[CoreProperties](vk)
if err != nil {
return nil, err
}
+5 -9
View File
@@ -54,15 +54,13 @@ var plannedCoreKinds = []string{
}
type KindStateReport struct {
Core []kindsys.CoreStructuredProperties `json:"core"`
Raw []kindsys.RawProperties `json:"raw"`
Composable []kindsys.ComposableProperties `json:"composable"`
Core []kindsys.CoreProperties `json:"core"`
Composable []kindsys.ComposableProperties `json:"composable"`
}
func emptyKindStateReport() KindStateReport {
return KindStateReport{
Core: make([]kindsys.CoreStructuredProperties, 0),
Raw: make([]kindsys.RawProperties, 0),
Core: make([]kindsys.CoreProperties, 0),
Composable: make([]kindsys.ComposableProperties, 0),
}
}
@@ -75,10 +73,8 @@ func buildKindStateReport() KindStateReport {
for _, k := range b.All() {
seen[k.Props().Common().Name] = true
switch props := k.Props().(type) {
case kindsys.CoreStructuredProperties:
case kindsys.CoreProperties:
r.Core = append(r.Core, props)
case kindsys.RawProperties:
r.Raw = append(r.Raw, props)
}
}
@@ -86,7 +82,7 @@ func buildKindStateReport() KindStateReport {
if seen[kn] {
continue
}
r.Core = append(r.Core, kindsys.CoreStructuredProperties{
r.Core = append(r.Core, kindsys.CoreProperties{
CommonProperties: kindsys.CommonProperties{
Name: kn,
PluralName: kn + "s",
-13
View File
@@ -133,19 +133,6 @@
]
}
],
"raw": [
{
"name": "SVG",
"pluralName": "SVGs",
"machineName": "svg",
"pluralMachineName": "svgs",
"lineageIsGroup": false,
"maturity": "merged",
"extensions": [
"svg"
]
}
],
"composable": [
{
"name": "AlertGroups-Panel",