mirror of https://github.com/grafana/grafana
Schemas: Refactor plugin's metadata (#83696)
* Remove kinds verification for kind-registry * Read plugin's json information with json library instead of use thema binding * Remove grafanaplugin unification * Don't use kindsys for extract the slot name * Fix IsGroup * Remove all plugindef generation * Refactor schema interfaces * Pushed this change from a different branch by mistake... * Create small plugin definition structure adding additional information for plugins registration * Add some validation checks * Delete unused code * Fix imports lintpull/84064/head
parent
beea7d1c2b
commit
1181141b40
@ -1,31 +0,0 @@ |
|||||||
package pfs |
|
||||||
|
|
||||||
import ( |
|
||||||
"github.com/grafana/kindsys" |
|
||||||
) |
|
||||||
|
|
||||||
// GrafanaPlugin specifies what plugins may declare in .cue files in a |
|
||||||
// `grafanaplugin` CUE package in the plugin root directory (adjacent to plugin.json). |
|
||||||
GrafanaPlugin: { |
|
||||||
// id and pascalName are injected from plugin.json. Plugin authors can write |
|
||||||
// values for them in .cue files, but the only valid values will be the ones |
|
||||||
// given in plugin.json. |
|
||||||
id: string |
|
||||||
pascalName: string |
|
||||||
|
|
||||||
// A plugin defines its Composable kinds under this key. |
|
||||||
// |
|
||||||
// This struct is open for forwards compatibility - older versions of Grafana (or |
|
||||||
// dependent tooling) should not break if new versions introduce additional schema interfaces. |
|
||||||
composableKinds?: [Iface=string]: kindsys.Composable & { |
|
||||||
name: pascalName + Iface |
|
||||||
schemaInterface: Iface |
|
||||||
lineage: name: pascalName + Iface |
|
||||||
} |
|
||||||
|
|
||||||
// A plugin defines its Custom kinds under this key. |
|
||||||
customKinds?: [Name=string]: kindsys.Custom & { |
|
||||||
name: Name |
|
||||||
} |
|
||||||
... |
|
||||||
} |
|
||||||
@ -0,0 +1,42 @@ |
|||||||
|
package pfs |
||||||
|
|
||||||
|
type Type string |
||||||
|
|
||||||
|
// Defines values for Type.
|
||||||
|
const ( |
||||||
|
TypeApp Type = "app" |
||||||
|
TypeDatasource Type = "datasource" |
||||||
|
TypePanel Type = "panel" |
||||||
|
TypeRenderer Type = "renderer" |
||||||
|
TypeSecretsmanager Type = "secretsmanager" |
||||||
|
) |
||||||
|
|
||||||
|
type PluginDef struct { |
||||||
|
Id string |
||||||
|
Name string |
||||||
|
Backend *bool |
||||||
|
Type Type |
||||||
|
Info Info |
||||||
|
IAM IAM |
||||||
|
} |
||||||
|
|
||||||
|
type Info struct { |
||||||
|
Version *string |
||||||
|
} |
||||||
|
|
||||||
|
type IAM struct { |
||||||
|
Permissions []Permission `json:"permissions,omitempty"` |
||||||
|
} |
||||||
|
|
||||||
|
type Permission struct { |
||||||
|
Action string `json:"action"` |
||||||
|
Scope *string `json:"scope,omitempty"` |
||||||
|
} |
||||||
|
|
||||||
|
func (pd PluginDef) Validate() error { |
||||||
|
if pd.Id == "" || pd.Name == "" || pd.Type == "" { |
||||||
|
return ErrInvalidRootFile |
||||||
|
} |
||||||
|
|
||||||
|
return nil |
||||||
|
} |
||||||
@ -1,130 +0,0 @@ |
|||||||
//go:build ignore
|
|
||||||
// +build ignore
|
|
||||||
|
|
||||||
package main |
|
||||||
|
|
||||||
import ( |
|
||||||
"bytes" |
|
||||||
"context" |
|
||||||
"encoding/json" |
|
||||||
"fmt" |
|
||||||
"os" |
|
||||||
"path/filepath" |
|
||||||
|
|
||||||
"cuelang.org/go/cue/cuecontext" |
|
||||||
"github.com/dave/dst" |
|
||||||
"github.com/grafana/codejen" |
|
||||||
"github.com/grafana/grafana/pkg/codegen" |
|
||||||
"github.com/grafana/grafana/pkg/cuectx" |
|
||||||
"github.com/grafana/thema" |
|
||||||
"github.com/grafana/thema/encoding/gocode" |
|
||||||
"github.com/grafana/thema/encoding/jsonschema" |
|
||||||
) |
|
||||||
|
|
||||||
var dirPlugindef = filepath.Join("pkg", "plugins", "plugindef") |
|
||||||
|
|
||||||
// main generator for plugindef. plugindef isn't a kind, so it has its own
|
|
||||||
// one-off main generator.
|
|
||||||
func main() { |
|
||||||
v := elsedie(cuectx.BuildGrafanaInstance(nil, dirPlugindef, "", nil))("could not load plugindef cue package") |
|
||||||
|
|
||||||
lin := elsedie(thema.BindLineage(v, cuectx.GrafanaThemaRuntime()))("plugindef lineage is invalid") |
|
||||||
|
|
||||||
jl := &codejen.JennyList[thema.Lineage]{} |
|
||||||
jl.AppendOneToOne(&jennytypego{}, &jennybindgo{}) |
|
||||||
jl.AddPostprocessors(codegen.SlashHeaderMapper(filepath.Join(dirPlugindef, "gen.go"))) |
|
||||||
|
|
||||||
cwd, err := os.Getwd() |
|
||||||
if err != nil { |
|
||||||
fmt.Fprintf(os.Stderr, "could not get working directory: %s", err) |
|
||||||
os.Exit(1) |
|
||||||
} |
|
||||||
|
|
||||||
groot := filepath.Clean(filepath.Join(cwd, "../../..")) |
|
||||||
|
|
||||||
jfs := elsedie(jl.GenerateFS(lin))("plugindef jenny pipeline failed") |
|
||||||
if _, set := os.LookupEnv("CODEGEN_VERIFY"); set { |
|
||||||
if err := jfs.Verify(context.Background(), groot); err != nil { |
|
||||||
die(fmt.Errorf("generated code is out of sync with inputs:\n%s\nrun `make gen-cue` to regenerate", err)) |
|
||||||
} |
|
||||||
} else if err := jfs.Write(context.Background(), groot); err != nil { |
|
||||||
die(fmt.Errorf("error while writing generated code to disk:\n%s", err)) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// one-off jenny for plugindef go types
|
|
||||||
type jennytypego struct{} |
|
||||||
|
|
||||||
func (j *jennytypego) JennyName() string { |
|
||||||
return "PluginGoTypes" |
|
||||||
} |
|
||||||
|
|
||||||
func (j *jennytypego) Generate(lin thema.Lineage) (*codejen.File, error) { |
|
||||||
f, err := codegen.GoTypesJenny{}.Generate(codegen.SchemaForGen{ |
|
||||||
Name: "PluginDef", |
|
||||||
Schema: lin.Latest(), |
|
||||||
IsGroup: false, |
|
||||||
}) |
|
||||||
if f != nil { |
|
||||||
f.RelativePath = filepath.Join(dirPlugindef, f.RelativePath) |
|
||||||
} |
|
||||||
return f, err |
|
||||||
} |
|
||||||
|
|
||||||
// one-off jenny for plugindef go bindings
|
|
||||||
type jennybindgo struct{} |
|
||||||
|
|
||||||
func (j *jennybindgo) JennyName() string { |
|
||||||
return "PluginGoBindings" |
|
||||||
} |
|
||||||
|
|
||||||
func (j *jennybindgo) Generate(lin thema.Lineage) (*codejen.File, error) { |
|
||||||
b, err := gocode.GenerateLineageBinding(lin, &gocode.BindingConfig{ |
|
||||||
TitleName: "PluginDef", |
|
||||||
Assignee: dst.NewIdent("*PluginDef"), |
|
||||||
PrivateFactory: true, |
|
||||||
}) |
|
||||||
if err != nil { |
|
||||||
return nil, err |
|
||||||
} |
|
||||||
return codejen.NewFile(filepath.Join(dirPlugindef, "plugindef_bindings_gen.go"), b, j), nil |
|
||||||
} |
|
||||||
|
|
||||||
// one-off jenny for plugindef json schema generator
|
|
||||||
type jennyjschema struct{} |
|
||||||
|
|
||||||
func (j *jennyjschema) JennyName() string { |
|
||||||
return "PluginJSONSchema" |
|
||||||
} |
|
||||||
|
|
||||||
func (j *jennyjschema) Generate(lin thema.Lineage) (*codejen.File, error) { |
|
||||||
f, err := jsonschema.GenerateSchema(lin.Latest()) |
|
||||||
if err != nil { |
|
||||||
return nil, err |
|
||||||
} |
|
||||||
|
|
||||||
b, _ := cuecontext.New().BuildFile(f).MarshalJSON() |
|
||||||
nb := new(bytes.Buffer) |
|
||||||
die(json.Indent(nb, b, "", " ")) |
|
||||||
return codejen.NewFile(filepath.FromSlash("docs/sources/developers/plugins/plugin.schema.json"), nb.Bytes(), j), nil |
|
||||||
} |
|
||||||
|
|
||||||
func elsedie[T any](t T, err error) func(msg string) T { |
|
||||||
if err != nil { |
|
||||||
return func(msg string) T { |
|
||||||
fmt.Fprintf(os.Stderr, "%s: %s\n", msg, err) |
|
||||||
os.Exit(1) |
|
||||||
return t |
|
||||||
} |
|
||||||
} |
|
||||||
return func(msg string) T { |
|
||||||
return t |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
func die(err error) { |
|
||||||
if err != nil { |
|
||||||
fmt.Fprint(os.Stderr, err, "\n") |
|
||||||
os.Exit(1) |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,43 +0,0 @@ |
|||||||
package plugindef |
|
||||||
|
|
||||||
import ( |
|
||||||
"testing" |
|
||||||
|
|
||||||
"github.com/stretchr/testify/require" |
|
||||||
) |
|
||||||
|
|
||||||
func TestDerivePascal(t *testing.T) { |
|
||||||
table := []struct { |
|
||||||
id, name, out string |
|
||||||
}{ |
|
||||||
{ |
|
||||||
name: "-- Grafana --", |
|
||||||
out: "Grafana", |
|
||||||
}, |
|
||||||
{ |
|
||||||
name: "A weird/Thing", |
|
||||||
out: "AWeirdThing", |
|
||||||
}, |
|
||||||
{ |
|
||||||
name: "/", |
|
||||||
out: "Empty", |
|
||||||
}, |
|
||||||
{ |
|
||||||
name: "some really Long thing WHY would38883 anyone do this i don't know but hey It seems like it this is just going on and", |
|
||||||
out: "SomeReallyLongThingWHYWouldAnyoneDoThisIDonTKnowButHeyItSeemsLi", |
|
||||||
}, |
|
||||||
} |
|
||||||
|
|
||||||
for _, row := range table { |
|
||||||
if row.id == "" { |
|
||||||
row.id = "default-empty-panel" |
|
||||||
} |
|
||||||
|
|
||||||
pd := PluginDef{ |
|
||||||
Id: row.id, |
|
||||||
Name: row.name, |
|
||||||
} |
|
||||||
|
|
||||||
require.Equal(t, row.out, DerivePascalName(pd)) |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,428 +0,0 @@ |
|||||||
package plugindef |
|
||||||
|
|
||||||
import ( |
|
||||||
"regexp" |
|
||||||
"strings" |
|
||||||
|
|
||||||
"github.com/grafana/thema" |
|
||||||
) |
|
||||||
|
|
||||||
thema.#Lineage |
|
||||||
name: "plugindef" |
|
||||||
schemas: [{ |
|
||||||
version: [0, 0] |
|
||||||
schema: { |
|
||||||
// Unique name of the plugin. If the plugin is published on |
|
||||||
// grafana.com, then the plugin `id` has to follow the naming |
|
||||||
// conventions. |
|
||||||
id: string & strings.MinRunes(1) |
|
||||||
id: =~"^([0-9a-z]+\\-([0-9a-z]+\\-)?(\(strings.Join([ for t in _types {t}], "|"))))|(alertGroups|alertlist|annolist|barchart|bargauge|candlestick|canvas|dashlist|debug|datagrid|gauge|geomap|gettingstarted|graph|heatmap|histogram|icon|live|logs|news|nodeGraph|piechart|pluginlist|stat|state-timeline|status-history|table|table-old|text|timeseries|trend|traces|welcome|xychart|alertmanager|cloudwatch|dashboard|elasticsearch|grafana|grafana-azure-monitor-datasource|stackdriver|graphite|influxdb|jaeger|loki|mixed|mssql|mysql|opentsdb|postgres|prometheus|stackdriver|tempo|grafana-testdata-datasource|zipkin|phlare|parca)$" |
|
||||||
|
|
||||||
// An alias is useful when migrating from one plugin id to another (rebranding etc) |
|
||||||
// This should be used sparingly, and is currently only supported though a hardcoded checklist |
|
||||||
aliasIDs?: [...string] |
|
||||||
|
|
||||||
// Human-readable name of the plugin that is shown to the user in |
|
||||||
// the UI. |
|
||||||
name: string |
|
||||||
|
|
||||||
// The set of all plugin types. This hidden field exists solely |
|
||||||
// so that the set can be string-interpolated into other fields. |
|
||||||
_types: ["app", "datasource", "panel", "renderer", "secretsmanager"] |
|
||||||
|
|
||||||
// type indicates which type of Grafana plugin this is, of the defined |
|
||||||
// set of Grafana plugin types. |
|
||||||
type: or(_types) |
|
||||||
|
|
||||||
// IncludeType is a string identifier of a plugin include type, which is |
|
||||||
// a superset of plugin types. |
|
||||||
#IncludeType: type | "dashboard" | "page" |
|
||||||
|
|
||||||
// Metadata about the plugin |
|
||||||
info: #Info |
|
||||||
|
|
||||||
// Metadata about a Grafana plugin. Some fields are used on the plugins |
|
||||||
// page in Grafana and others on grafana.com, if the plugin is published. |
|
||||||
#Info: { |
|
||||||
// Information about the plugin author |
|
||||||
author?: { |
|
||||||
// Author's name |
|
||||||
name?: string |
|
||||||
|
|
||||||
// Author's name |
|
||||||
email?: string |
|
||||||
|
|
||||||
// Link to author's website |
|
||||||
url?: string |
|
||||||
} |
|
||||||
|
|
||||||
// Build information |
|
||||||
build?: #BuildInfo |
|
||||||
|
|
||||||
// Description of plugin. Used on the plugins page in Grafana and |
|
||||||
// for search on grafana.com. |
|
||||||
description?: string |
|
||||||
|
|
||||||
// Array of plugin keywords. Used for search on grafana.com. |
|
||||||
keywords: [...string] |
|
||||||
// should be this, but CUE to openapi converter screws this up |
|
||||||
// by inserting a non-concrete default. |
|
||||||
// keywords: [string, ...string] |
|
||||||
|
|
||||||
// An array of link objects to be displayed on this plugin's |
|
||||||
// project page in the form `{name: 'foo', url: |
|
||||||
// 'http://example.com'}` |
|
||||||
links?: [...{ |
|
||||||
name?: string |
|
||||||
url?: string |
|
||||||
}] |
|
||||||
|
|
||||||
// SVG images that are used as plugin icons |
|
||||||
logos?: { |
|
||||||
// Link to the "small" version of the plugin logo, which must be |
|
||||||
// an SVG image. "Large" and "small" logos can be the same image. |
|
||||||
small: string |
|
||||||
|
|
||||||
// Link to the "large" version of the plugin logo, which must be |
|
||||||
// an SVG image. "Large" and "small" logos can be the same image. |
|
||||||
large: string |
|
||||||
} |
|
||||||
|
|
||||||
// An array of screenshot objects in the form `{name: 'bar', path: |
|
||||||
// 'img/screenshot.png'}` |
|
||||||
screenshots?: [...{ |
|
||||||
name?: string |
|
||||||
path?: string |
|
||||||
}] |
|
||||||
|
|
||||||
// Date when this plugin was built |
|
||||||
updated?: =~"^(\\d{4}-\\d{2}-\\d{2}|\\%TODAY\\%)$" |
|
||||||
|
|
||||||
// Project version of this commit, e.g. `6.7.x` |
|
||||||
version?: =~"^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)|(\\%VERSION\\%)$" |
|
||||||
} |
|
||||||
|
|
||||||
#BuildInfo: { |
|
||||||
// Time when the plugin was built, as a Unix timestamp |
|
||||||
time?: int64 |
|
||||||
repo?: string |
|
||||||
|
|
||||||
// Git branch the plugin was built from |
|
||||||
branch?: string |
|
||||||
|
|
||||||
// Git hash of the commit the plugin was built from |
|
||||||
hash?: string |
|
||||||
number?: int64 |
|
||||||
|
|
||||||
// GitHub pull request the plugin was built from |
|
||||||
pr?: int32 |
|
||||||
} |
|
||||||
|
|
||||||
// Dependency information related to Grafana and other plugins |
|
||||||
dependencies: #Dependencies |
|
||||||
|
|
||||||
#Dependencies: { |
|
||||||
// (Deprecated) Required Grafana version for this plugin, e.g. |
|
||||||
// `6.x.x 7.x.x` to denote plugin requires Grafana v6.x.x or |
|
||||||
// v7.x.x. |
|
||||||
grafanaVersion?: =~"^([0-9]+)(\\.[0-9x]+)?(\\.[0-9x])?$" |
|
||||||
|
|
||||||
// Required Grafana version for this plugin. Validated using |
|
||||||
// https://github.com/npm/node-semver. |
|
||||||
grafanaDependency?: =~"^(<=|>=|<|>|=|~|\\^)?([0-9]+)(\\.[0-9x\\*]+)(\\.[0-9x\\*]+)?(\\s(<=|>=|<|=>)?([0-9]+)(\\.[0-9x]+)(\\.[0-9x]+))?(\\-[0-9]+)?$" |
|
||||||
|
|
||||||
// An array of required plugins on which this plugin depends |
|
||||||
plugins?: [...#Dependency] |
|
||||||
} |
|
||||||
|
|
||||||
// Dependency describes another plugin on which a plugin depends. |
|
||||||
// The id refers to the plugin package identifier, as given on |
|
||||||
// the grafana.com plugin marketplace. |
|
||||||
#Dependency: { |
|
||||||
id: =~"^[0-9a-z]+\\-([0-9a-z]+\\-)?(app|panel|datasource)$" |
|
||||||
type: "app" | "datasource" | "panel" |
|
||||||
name: string |
|
||||||
version: string |
|
||||||
... |
|
||||||
} |
|
||||||
|
|
||||||
// Schema definition for the plugin.json file. Used primarily for schema validation. |
|
||||||
$schema?: string |
|
||||||
|
|
||||||
// For data source plugins, if the plugin supports alerting. Requires `backend` to be set to `true`. |
|
||||||
alerting?: bool |
|
||||||
|
|
||||||
// For data source plugins, if the plugin supports annotation |
|
||||||
// queries. |
|
||||||
annotations?: bool |
|
||||||
|
|
||||||
// Set to true for app plugins that should be enabled and pinned to the navigation bar in all orgs. |
|
||||||
autoEnabled?: bool |
|
||||||
|
|
||||||
// If the plugin has a backend component. |
|
||||||
backend?: bool |
|
||||||
|
|
||||||
// [internal only] Indicates whether the plugin is developed and shipped as part |
|
||||||
// of Grafana. Also known as a 'core plugin'. |
|
||||||
builtIn: bool | *false |
|
||||||
|
|
||||||
// Plugin category used on the Add data source page. |
|
||||||
category?: "tsdb" | "logging" | "cloud" | "tracing" | "profiling" | "sql" | "enterprise" | "iot" | "other" |
|
||||||
|
|
||||||
// Grafana Enterprise specific features. |
|
||||||
enterpriseFeatures?: { |
|
||||||
// Enable/Disable health diagnostics errors. Requires Grafana |
|
||||||
// >=7.5.5. |
|
||||||
healthDiagnosticsErrors?: bool | *false |
|
||||||
... |
|
||||||
} |
|
||||||
|
|
||||||
// The first part of the file name of the backend component |
|
||||||
// executable. There can be multiple executables built for |
|
||||||
// different operating system and architecture. Grafana will |
|
||||||
// check for executables named `<executable>_<$GOOS>_<lower case |
|
||||||
// $GOARCH><.exe for Windows>`, e.g. `plugin_linux_amd64`. |
|
||||||
// Combination of $GOOS and $GOARCH can be found here: |
|
||||||
// https://golang.org/doc/install/source#environment. |
|
||||||
executable?: string |
|
||||||
|
|
||||||
// [internal only] Excludes the plugin from listings in Grafana's UI. Only |
|
||||||
// allowed for `builtIn` plugins. |
|
||||||
hideFromList: bool | *false |
|
||||||
|
|
||||||
// Resources to include in plugin. |
|
||||||
includes?: [...#Include] |
|
||||||
|
|
||||||
// A resource to be included in a plugin. |
|
||||||
#Include: { |
|
||||||
// Unique identifier of the included resource |
|
||||||
uid?: string |
|
||||||
type: #IncludeType |
|
||||||
name?: string |
|
||||||
|
|
||||||
// (Legacy) The Angular component to use for a page. |
|
||||||
component?: string |
|
||||||
|
|
||||||
// The minimum role a user must have to see this page in the navigation menu. |
|
||||||
role?: "Admin" | "Editor" | "Viewer" |
|
||||||
|
|
||||||
// RBAC action the user must have to access the route |
|
||||||
action?: string |
|
||||||
|
|
||||||
// Used for app plugins. |
|
||||||
path?: string |
|
||||||
|
|
||||||
// Add the include to the navigation menu. |
|
||||||
addToNav?: bool |
|
||||||
|
|
||||||
// Page or dashboard when user clicks the icon in the side menu. |
|
||||||
defaultNav?: bool |
|
||||||
|
|
||||||
// Icon to use in the side menu. For information on available |
|
||||||
// icon, refer to [Icons |
|
||||||
// Overview](https://developers.grafana.com/ui/latest/index.html?path=/story/docs-overview-icon--icons-overview). |
|
||||||
icon?: string |
|
||||||
... |
|
||||||
} |
|
||||||
|
|
||||||
// For data source plugins, if the plugin supports logs. It may be used to filter logs only features. |
|
||||||
logs?: bool |
|
||||||
|
|
||||||
// For data source plugins, if the plugin supports metric queries. |
|
||||||
// Used to enable the plugin in the panel editor. |
|
||||||
metrics?: bool |
|
||||||
|
|
||||||
// FIXME there appears to be a bug in thema that prevents this from working. Maybe it'd |
|
||||||
// help to refer to it with an alias, but thema can't support using current list syntax. |
|
||||||
// syntax (fixed by grafana/thema#82). Either way, for now, pascalName gets populated in Go. |
|
||||||
let sani = (strings.ToTitle(regexp.ReplaceAllLiteral("[^a-zA-Z]+", name, ""))) |
|
||||||
|
|
||||||
// [internal only] The PascalCase name for the plugin. Used for creating machine-friendly |
|
||||||
// identifiers, typically in code generation. |
|
||||||
// |
|
||||||
// If not provided, defaults to name, but title-cased and sanitized (only |
|
||||||
// alphabetical characters allowed). |
|
||||||
pascalName: string & =~"^([A-Z][a-zA-Z]{1,62})$" | *sani |
|
||||||
|
|
||||||
// Initialize plugin on startup. By default, the plugin |
|
||||||
// initializes on first use. |
|
||||||
preload?: bool |
|
||||||
|
|
||||||
// For data source plugins. There is a query options section in |
|
||||||
// the plugin's query editor and these options can be turned on |
|
||||||
// if needed. |
|
||||||
queryOptions?: { |
|
||||||
// For data source plugins. If the `max data points` option should |
|
||||||
// be shown in the query options section in the query editor. |
|
||||||
maxDataPoints?: bool |
|
||||||
|
|
||||||
// For data source plugins. If the `min interval` option should be |
|
||||||
// shown in the query options section in the query editor. |
|
||||||
minInterval?: bool |
|
||||||
|
|
||||||
// For data source plugins. If the `cache timeout` option should |
|
||||||
// be shown in the query options section in the query editor. |
|
||||||
cacheTimeout?: bool |
|
||||||
} |
|
||||||
|
|
||||||
// Routes is a list of proxy routes, if any. For datasource plugins only. |
|
||||||
routes?: [...#Route] |
|
||||||
|
|
||||||
// For panel plugins. Hides the query editor. |
|
||||||
skipDataQuery?: bool |
|
||||||
|
|
||||||
// Marks a plugin as a pre-release. |
|
||||||
state?: #ReleaseState |
|
||||||
|
|
||||||
// ReleaseState indicates release maturity state of a plugin. |
|
||||||
#ReleaseState: "alpha" | "beta" | "deprecated" | *"stable" |
|
||||||
|
|
||||||
// For data source plugins, if the plugin supports streaming. Used in Explore to start live streaming. |
|
||||||
streaming?: bool |
|
||||||
|
|
||||||
// For data source plugins, if the plugin supports tracing. Used for example to link logs (e.g. Loki logs) with tracing plugins. |
|
||||||
tracing?: bool |
|
||||||
|
|
||||||
// Optional list of RBAC RoleRegistrations. |
|
||||||
// Describes and organizes the default permissions associated with any of the Grafana basic roles, |
|
||||||
// which characterizes what viewers, editors, admins, or grafana admins can do on the plugin. |
|
||||||
// The Admin basic role inherits its default permissions from the Editor basic role which in turn |
|
||||||
// inherits them from the Viewer basic role. |
|
||||||
roles?: [...#RoleRegistration] |
|
||||||
|
|
||||||
// RoleRegistration describes an RBAC role and its assignments to basic roles. |
|
||||||
// It organizes related RBAC permissions on the plugin into a role and defines which basic roles |
|
||||||
// will get them by default. |
|
||||||
// Example: the role 'Schedules Reader' bundles permissions to view all schedules of the plugin |
|
||||||
// which will be granted to Admins by default. |
|
||||||
#RoleRegistration: { |
|
||||||
// RBAC role definition to bundle related RBAC permissions on the plugin. |
|
||||||
role: #Role |
|
||||||
|
|
||||||
// Default assignment of the role to Grafana basic roles (Viewer, Editor, Admin, Grafana Admin) |
|
||||||
// The Admin basic role inherits its default permissions from the Editor basic role which in turn |
|
||||||
// inherits them from the Viewer basic role. |
|
||||||
grants: [...#BasicRole] |
|
||||||
} |
|
||||||
|
|
||||||
// Role describes an RBAC role which allows grouping multiple related permissions on the plugin, |
|
||||||
// each of which has an action and an optional scope. |
|
||||||
// Example: the role 'Schedules Reader' bundles permissions to view all schedules of the plugin. |
|
||||||
#Role: { |
|
||||||
name: string |
|
||||||
name: =~"^([A-Z][0-9A-Za-z ]+)$" |
|
||||||
description: string |
|
||||||
permissions: [...#Permission] |
|
||||||
} |
|
||||||
|
|
||||||
// Permission describes an RBAC permission on the plugin. A permission has an action and an optional |
|
||||||
// scope. |
|
||||||
// Example: action: 'test-app.schedules:read', scope: 'test-app.schedules:*' |
|
||||||
#Permission: { |
|
||||||
action: string |
|
||||||
scope?: string |
|
||||||
} |
|
||||||
|
|
||||||
// BasicRole is a Grafana basic role, which can be 'Viewer', 'Editor', 'Admin' or 'Grafana Admin'. |
|
||||||
// With RBAC, the Admin basic role inherits its default permissions from the Editor basic role which |
|
||||||
// in turn inherits them from the Viewer basic role. |
|
||||||
#BasicRole: "Grafana Admin" | "Admin" | "Editor" | "Viewer" |
|
||||||
|
|
||||||
// Header describes an HTTP header that is forwarded with a proxied request for |
|
||||||
// a plugin route. |
|
||||||
#Header: { |
|
||||||
name: string |
|
||||||
content: string |
|
||||||
} |
|
||||||
|
|
||||||
// URLParam describes query string parameters for |
|
||||||
// a url in a plugin route |
|
||||||
#URLParam: { |
|
||||||
name: string |
|
||||||
content: string |
|
||||||
} |
|
||||||
|
|
||||||
// A proxy route used in datasource plugins for plugin authentication |
|
||||||
// and adding headers to HTTP requests made by the plugin. |
|
||||||
// For more information, refer to [Authentication for data source |
|
||||||
// plugins](https://grafana.com/developers/plugin-tools/create-a-plugin/extend-a-plugin/add-authentication-for-data-source-plugins). |
|
||||||
#Route: { |
|
||||||
// For data source plugins. The route path that is replaced by the |
|
||||||
// route URL field when proxying the call. |
|
||||||
path?: string |
|
||||||
|
|
||||||
// For data source plugins. Route method matches the HTTP verb |
|
||||||
// like GET or POST. Multiple methods can be provided as a |
|
||||||
// comma-separated list. |
|
||||||
method?: string |
|
||||||
|
|
||||||
// For data source plugins. Route URL is where the request is |
|
||||||
// proxied to. |
|
||||||
url?: string |
|
||||||
|
|
||||||
urlParams?: [...#URLParam] |
|
||||||
reqSignedIn?: bool |
|
||||||
reqRole?: string |
|
||||||
|
|
||||||
// RBAC action the user must have to access the route. i.e. plugin-id.projects:read |
|
||||||
reqAction?: string |
|
||||||
|
|
||||||
// For data source plugins. Route headers adds HTTP headers to the |
|
||||||
// proxied request. |
|
||||||
headers?: [...#Header] |
|
||||||
|
|
||||||
// For data source plugins. Route headers set the body content and |
|
||||||
// length to the proxied request. |
|
||||||
body?: { |
|
||||||
... |
|
||||||
} |
|
||||||
|
|
||||||
// For data source plugins. Token authentication section used with |
|
||||||
// an OAuth API. |
|
||||||
tokenAuth?: #TokenAuth |
|
||||||
|
|
||||||
// For data source plugins. Token authentication section used with |
|
||||||
// an JWT OAuth API. |
|
||||||
jwtTokenAuth?: #JWTTokenAuth |
|
||||||
} |
|
||||||
|
|
||||||
// TODO docs |
|
||||||
#TokenAuth: { |
|
||||||
// URL to fetch the authentication token. |
|
||||||
url?: string |
|
||||||
|
|
||||||
// The list of scopes that your application should be granted |
|
||||||
// access to. |
|
||||||
scopes?: [...string] |
|
||||||
|
|
||||||
// Parameters for the token authentication request. |
|
||||||
params: [string]: string |
|
||||||
} |
|
||||||
|
|
||||||
// TODO docs |
|
||||||
// TODO should this really be separate from TokenAuth? |
|
||||||
#JWTTokenAuth: { |
|
||||||
// URL to fetch the JWT token. |
|
||||||
url: string |
|
||||||
|
|
||||||
// The list of scopes that your application should be granted |
|
||||||
// access to. |
|
||||||
scopes: [...string] |
|
||||||
|
|
||||||
// Parameters for the JWT token authentication request. |
|
||||||
params: [string]: string |
|
||||||
} |
|
||||||
|
|
||||||
// Identity and Access Management information. |
|
||||||
// Allows the plugin to define the permissions it requires to have on Grafana. |
|
||||||
iam: #IAM |
|
||||||
|
|
||||||
// IAM allows the plugin to get a service account with tailored permissions and a token |
|
||||||
// (or to use the client_credentials grant if the token provider is the OAuth2 Server) |
|
||||||
#IAM: { |
|
||||||
// Permissions are the permissions that the external service needs its associated service account to have. |
|
||||||
permissions?: [...#Permission] |
|
||||||
} |
|
||||||
} |
|
||||||
}] |
|
||||||
lenses: [] |
|
||||||
@ -1,73 +0,0 @@ |
|||||||
package plugindef |
|
||||||
|
|
||||||
import ( |
|
||||||
"strings" |
|
||||||
"sync" |
|
||||||
|
|
||||||
"cuelang.org/go/cue/build" |
|
||||||
"github.com/grafana/grafana/pkg/cuectx" |
|
||||||
"github.com/grafana/thema" |
|
||||||
) |
|
||||||
|
|
||||||
//go:generate go run gen.go
|
|
||||||
|
|
||||||
func loadInstanceForplugindef() (*build.Instance, error) { |
|
||||||
return cuectx.LoadGrafanaInstance("pkg/plugins/plugindef", "", nil) |
|
||||||
} |
|
||||||
|
|
||||||
var linonce sync.Once |
|
||||||
var pdlin thema.ConvergentLineage[*PluginDef] |
|
||||||
var pdlinerr error |
|
||||||
|
|
||||||
// Lineage returns the [thema.ConvergentLineage] for plugindef, the canonical
|
|
||||||
// specification for Grafana plugin.json files.
|
|
||||||
//
|
|
||||||
// Unless a custom thema.Runtime is specifically needed, prefer calling this with
|
|
||||||
// nil, as a cached lineage will be returned.
|
|
||||||
func Lineage(rt *thema.Runtime, opts ...thema.BindOption) (thema.ConvergentLineage[*PluginDef], error) { |
|
||||||
if len(opts) == 0 && (rt == nil || rt == cuectx.GrafanaThemaRuntime()) { |
|
||||||
linonce.Do(func() { |
|
||||||
pdlin, pdlinerr = doLineage(rt) |
|
||||||
}) |
|
||||||
return pdlin, pdlinerr |
|
||||||
} |
|
||||||
return doLineage(rt, opts...) |
|
||||||
} |
|
||||||
|
|
||||||
// DerivePascalName derives a PascalCase name from a PluginDef.
|
|
||||||
//
|
|
||||||
// This function does not mutate the input PluginDef; as such, it ignores
|
|
||||||
// whether there exists any value for PluginDef.PascalName.
|
|
||||||
//
|
|
||||||
// FIXME this should be removable once CUE logic for it works/unmarshals correctly.
|
|
||||||
func DerivePascalName(pd PluginDef) string { |
|
||||||
sani := func(s string) string { |
|
||||||
ret := strings.Title(strings.Map(func(r rune) rune { |
|
||||||
switch { |
|
||||||
case r >= 'a' && r <= 'z': |
|
||||||
return r |
|
||||||
case r >= 'A' && r <= 'Z': |
|
||||||
return r |
|
||||||
default: |
|
||||||
return -1 |
|
||||||
} |
|
||||||
}, strings.Title(strings.Map(func(r rune) rune { |
|
||||||
switch r { |
|
||||||
case '-', '_': |
|
||||||
return ' ' |
|
||||||
default: |
|
||||||
return r |
|
||||||
} |
|
||||||
}, s)))) |
|
||||||
if len(ret) > 63 { |
|
||||||
return ret[:63] |
|
||||||
} |
|
||||||
return ret |
|
||||||
} |
|
||||||
|
|
||||||
fromname := sani(pd.Name) |
|
||||||
if len(fromname) != 0 { |
|
||||||
return fromname |
|
||||||
} |
|
||||||
return sani(strings.Split(pd.Id, "-")[1]) |
|
||||||
} |
|
||||||
@ -1,84 +0,0 @@ |
|||||||
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
|
|
||||||
//
|
|
||||||
// Generated by:
|
|
||||||
// pkg/plugins/plugindef/gen.go
|
|
||||||
// Using jennies:
|
|
||||||
// PluginGoBindings
|
|
||||||
//
|
|
||||||
// Run 'make gen-cue' from repository root to regenerate.
|
|
||||||
|
|
||||||
package plugindef |
|
||||||
|
|
||||||
import ( |
|
||||||
"cuelang.org/go/cue/build" |
|
||||||
"github.com/grafana/thema" |
|
||||||
) |
|
||||||
|
|
||||||
// doLineage returns a [thema.ConvergentLineage] for the 'plugindef' Thema lineage.
|
|
||||||
//
|
|
||||||
// The lineage is the canonical specification of plugindef. It contains all
|
|
||||||
// schema versions that have ever existed for plugindef, and the lenses that
|
|
||||||
// allow valid instances of one schema in the lineage to be translated to
|
|
||||||
// another schema in the lineage.
|
|
||||||
//
|
|
||||||
// As a [thema.ConvergentLineage], the returned lineage has one primary schema, 0.0,
|
|
||||||
// which is [thema.AssignableTo] [*PluginDef], the lineage's parameterized type.
|
|
||||||
//
|
|
||||||
// This function will return an error if the [Thema invariants] are not met by
|
|
||||||
// the underlying lineage declaration in CUE, or if [*PluginDef] is not
|
|
||||||
// [thema.AssignableTo] the 0.0 schema.
|
|
||||||
//
|
|
||||||
// [Thema's general invariants]: https://github.com/grafana/thema/blob/main/docs/invariants.md
|
|
||||||
func doLineage(rt *thema.Runtime, opts ...thema.BindOption) (thema.ConvergentLineage[*PluginDef], error) { |
|
||||||
lin, err := baseLineage(rt, opts...) |
|
||||||
if err != nil { |
|
||||||
return nil, err |
|
||||||
} |
|
||||||
|
|
||||||
sch := thema.SchemaP(lin, thema.SV(0, 0)) |
|
||||||
typ := new(PluginDef) |
|
||||||
tsch, err := thema.BindType(sch, typ) |
|
||||||
if err != nil { |
|
||||||
// This will error out if the 0.0 schema isn't assignable to
|
|
||||||
// *PluginDef. If Thema also generates that type, this should be unreachable,
|
|
||||||
// barring a critical bug in Thema's Go generator.
|
|
||||||
return nil, err |
|
||||||
} |
|
||||||
return tsch.ConvergentLineage(), nil |
|
||||||
} |
|
||||||
func baseLineage(rt *thema.Runtime, opts ...thema.BindOption) (thema.Lineage, error) { |
|
||||||
// First, we must get the bytes of the .cue file(s) in which the "plugindef" lineage
|
|
||||||
// is declared, and load them into a
|
|
||||||
// "cuelang.org/go/cue/build".Instance.
|
|
||||||
//
|
|
||||||
// For most Thema-based development workflows, these bytes should come from an embed.FS.
|
|
||||||
// This ensures Go is always compiled with the current state of the .cue files.
|
|
||||||
var inst *build.Instance |
|
||||||
var err error |
|
||||||
|
|
||||||
// loadInstanceForplugindef must be manually implemented in another file in this
|
|
||||||
// Go package.
|
|
||||||
inst, err = loadInstanceForplugindef() |
|
||||||
if err != nil { |
|
||||||
// Errors at this point indicate a problem with basic loading of .cue file bytes,
|
|
||||||
// which typically means the code generator was misconfigured and a path input
|
|
||||||
// is incorrect.
|
|
||||||
return nil, err |
|
||||||
} |
|
||||||
|
|
||||||
raw := rt.Context().BuildInstance(inst) |
|
||||||
|
|
||||||
// An error returned from thema.BindLineage indicates one of the following:
|
|
||||||
// - The parsed path does not exist in the loaded CUE file (["github.com/grafana/thema/errors".ErrValueNotExist])
|
|
||||||
// - The value at the parsed path exists, but does not appear to be a Thema
|
|
||||||
// lineage (["github.com/grafana/thema/errors".ErrValueNotALineage])
|
|
||||||
// - The value at the parsed path exists and is a lineage (["github.com/grafana/thema/errors".ErrInvalidLineage]),
|
|
||||||
// but is invalid due to the violation of some general Thema invariant -
|
|
||||||
// for example, declared schemas don't follow backwards compatibility rules,
|
|
||||||
// lenses are incomplete.
|
|
||||||
return thema.BindLineage(raw, rt, opts...) |
|
||||||
} |
|
||||||
|
|
||||||
// type guards
|
|
||||||
var _ thema.ConvergentLineageFactory[*PluginDef] = doLineage |
|
||||||
var _ thema.LineageFactory = baseLineage |
|
||||||
@ -1,484 +0,0 @@ |
|||||||
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
|
|
||||||
//
|
|
||||||
// Generated by:
|
|
||||||
// pkg/plugins/plugindef/gen.go
|
|
||||||
// Using jennies:
|
|
||||||
// GoTypesJenny
|
|
||||||
//
|
|
||||||
// Run 'make gen-cue' from repository root to regenerate.
|
|
||||||
|
|
||||||
package plugindef |
|
||||||
|
|
||||||
// Defines values for BasicRole.
|
|
||||||
const ( |
|
||||||
BasicRoleAdmin BasicRole = "Admin" |
|
||||||
BasicRoleEditor BasicRole = "Editor" |
|
||||||
BasicRoleGrafanaAdmin BasicRole = "Grafana Admin" |
|
||||||
BasicRoleViewer BasicRole = "Viewer" |
|
||||||
) |
|
||||||
|
|
||||||
// Defines values for DependencyType.
|
|
||||||
const ( |
|
||||||
DependencyTypeApp DependencyType = "app" |
|
||||||
DependencyTypeDatasource DependencyType = "datasource" |
|
||||||
DependencyTypePanel DependencyType = "panel" |
|
||||||
) |
|
||||||
|
|
||||||
// Defines values for IncludeRole.
|
|
||||||
const ( |
|
||||||
IncludeRoleAdmin IncludeRole = "Admin" |
|
||||||
IncludeRoleEditor IncludeRole = "Editor" |
|
||||||
IncludeRoleViewer IncludeRole = "Viewer" |
|
||||||
) |
|
||||||
|
|
||||||
// Defines values for IncludeType.
|
|
||||||
const ( |
|
||||||
IncludeTypeApp IncludeType = "app" |
|
||||||
IncludeTypeDashboard IncludeType = "dashboard" |
|
||||||
IncludeTypeDatasource IncludeType = "datasource" |
|
||||||
IncludeTypePage IncludeType = "page" |
|
||||||
IncludeTypePanel IncludeType = "panel" |
|
||||||
IncludeTypeRenderer IncludeType = "renderer" |
|
||||||
IncludeTypeSecretsmanager IncludeType = "secretsmanager" |
|
||||||
) |
|
||||||
|
|
||||||
// Defines values for Category.
|
|
||||||
const ( |
|
||||||
CategoryCloud Category = "cloud" |
|
||||||
CategoryEnterprise Category = "enterprise" |
|
||||||
CategoryIot Category = "iot" |
|
||||||
CategoryLogging Category = "logging" |
|
||||||
CategoryOther Category = "other" |
|
||||||
CategoryProfiling Category = "profiling" |
|
||||||
CategorySql Category = "sql" |
|
||||||
CategoryTracing Category = "tracing" |
|
||||||
CategoryTsdb Category = "tsdb" |
|
||||||
) |
|
||||||
|
|
||||||
// Defines values for Type.
|
|
||||||
const ( |
|
||||||
TypeApp Type = "app" |
|
||||||
TypeDatasource Type = "datasource" |
|
||||||
TypePanel Type = "panel" |
|
||||||
TypeRenderer Type = "renderer" |
|
||||||
TypeSecretsmanager Type = "secretsmanager" |
|
||||||
) |
|
||||||
|
|
||||||
// Defines values for ReleaseState.
|
|
||||||
const ( |
|
||||||
ReleaseStateAlpha ReleaseState = "alpha" |
|
||||||
ReleaseStateBeta ReleaseState = "beta" |
|
||||||
ReleaseStateDeprecated ReleaseState = "deprecated" |
|
||||||
ReleaseStateStable ReleaseState = "stable" |
|
||||||
) |
|
||||||
|
|
||||||
// BasicRole is a Grafana basic role, which can be 'Viewer', 'Editor', 'Admin' or 'Grafana Admin'.
|
|
||||||
// With RBAC, the Admin basic role inherits its default permissions from the Editor basic role which
|
|
||||||
// in turn inherits them from the Viewer basic role.
|
|
||||||
type BasicRole string |
|
||||||
|
|
||||||
// BuildInfo defines model for BuildInfo.
|
|
||||||
type BuildInfo struct { |
|
||||||
// Git branch the plugin was built from
|
|
||||||
Branch *string `json:"branch,omitempty"` |
|
||||||
|
|
||||||
// Git hash of the commit the plugin was built from
|
|
||||||
Hash *string `json:"hash,omitempty"` |
|
||||||
Number *int64 `json:"number,omitempty"` |
|
||||||
|
|
||||||
// GitHub pull request the plugin was built from
|
|
||||||
Pr *int32 `json:"pr,omitempty"` |
|
||||||
Repo *string `json:"repo,omitempty"` |
|
||||||
|
|
||||||
// Time when the plugin was built, as a Unix timestamp
|
|
||||||
Time *int64 `json:"time,omitempty"` |
|
||||||
} |
|
||||||
|
|
||||||
// Dependencies defines model for Dependencies.
|
|
||||||
type Dependencies struct { |
|
||||||
// Required Grafana version for this plugin. Validated using
|
|
||||||
// https://github.com/npm/node-semver.
|
|
||||||
GrafanaDependency *string `json:"grafanaDependency,omitempty"` |
|
||||||
|
|
||||||
// (Deprecated) Required Grafana version for this plugin, e.g.
|
|
||||||
// `6.x.x 7.x.x` to denote plugin requires Grafana v6.x.x or
|
|
||||||
// v7.x.x.
|
|
||||||
GrafanaVersion *string `json:"grafanaVersion,omitempty"` |
|
||||||
|
|
||||||
// An array of required plugins on which this plugin depends
|
|
||||||
Plugins []Dependency `json:"plugins,omitempty"` |
|
||||||
} |
|
||||||
|
|
||||||
// Dependency describes another plugin on which a plugin depends.
|
|
||||||
// The id refers to the plugin package identifier, as given on
|
|
||||||
// the grafana.com plugin marketplace.
|
|
||||||
type Dependency struct { |
|
||||||
Id string `json:"id"` |
|
||||||
Name string `json:"name"` |
|
||||||
Type DependencyType `json:"type"` |
|
||||||
Version string `json:"version"` |
|
||||||
} |
|
||||||
|
|
||||||
// DependencyType defines model for Dependency.Type.
|
|
||||||
type DependencyType string |
|
||||||
|
|
||||||
// Header describes an HTTP header that is forwarded with a proxied request for
|
|
||||||
// a plugin route.
|
|
||||||
type Header struct { |
|
||||||
Content string `json:"content"` |
|
||||||
Name string `json:"name"` |
|
||||||
} |
|
||||||
|
|
||||||
// IAM allows the plugin to get a service account with tailored permissions and a token
|
|
||||||
// (or to use the client_credentials grant if the token provider is the OAuth2 Server)
|
|
||||||
type IAM struct { |
|
||||||
// Permissions are the permissions that the external service needs its associated service account to have.
|
|
||||||
Permissions []Permission `json:"permissions,omitempty"` |
|
||||||
} |
|
||||||
|
|
||||||
// A resource to be included in a plugin.
|
|
||||||
type Include struct { |
|
||||||
// RBAC action the user must have to access the route
|
|
||||||
Action *string `json:"action,omitempty"` |
|
||||||
|
|
||||||
// Add the include to the navigation menu.
|
|
||||||
AddToNav *bool `json:"addToNav,omitempty"` |
|
||||||
|
|
||||||
// (Legacy) The Angular component to use for a page.
|
|
||||||
Component *string `json:"component,omitempty"` |
|
||||||
|
|
||||||
// Page or dashboard when user clicks the icon in the side menu.
|
|
||||||
DefaultNav *bool `json:"defaultNav,omitempty"` |
|
||||||
|
|
||||||
// Icon to use in the side menu. For information on available
|
|
||||||
// icon, refer to [Icons
|
|
||||||
// Overview](https://developers.grafana.com/ui/latest/index.html?path=/story/docs-overview-icon--icons-overview).
|
|
||||||
Icon *string `json:"icon,omitempty"` |
|
||||||
Name *string `json:"name,omitempty"` |
|
||||||
|
|
||||||
// Used for app plugins.
|
|
||||||
Path *string `json:"path,omitempty"` |
|
||||||
|
|
||||||
// The minimum role a user must have to see this page in the navigation menu.
|
|
||||||
Role *IncludeRole `json:"role,omitempty"` |
|
||||||
|
|
||||||
// IncludeType is a string identifier of a plugin include type, which is
|
|
||||||
// a superset of plugin types.
|
|
||||||
Type IncludeType `json:"type"` |
|
||||||
|
|
||||||
// Unique identifier of the included resource
|
|
||||||
Uid *string `json:"uid,omitempty"` |
|
||||||
} |
|
||||||
|
|
||||||
// The minimum role a user must have to see this page in the navigation menu.
|
|
||||||
type IncludeRole string |
|
||||||
|
|
||||||
// IncludeType is a string identifier of a plugin include type, which is
|
|
||||||
// a superset of plugin types.
|
|
||||||
type IncludeType string |
|
||||||
|
|
||||||
// Metadata about a Grafana plugin. Some fields are used on the plugins
|
|
||||||
// page in Grafana and others on grafana.com, if the plugin is published.
|
|
||||||
type Info struct { |
|
||||||
// Information about the plugin author
|
|
||||||
Author *struct { |
|
||||||
// Author's name
|
|
||||||
Email *string `json:"email,omitempty"` |
|
||||||
|
|
||||||
// Author's name
|
|
||||||
Name *string `json:"name,omitempty"` |
|
||||||
|
|
||||||
// Link to author's website
|
|
||||||
Url *string `json:"url,omitempty"` |
|
||||||
} `json:"author,omitempty"` |
|
||||||
Build *BuildInfo `json:"build,omitempty"` |
|
||||||
|
|
||||||
// Description of plugin. Used on the plugins page in Grafana and
|
|
||||||
// for search on grafana.com.
|
|
||||||
Description *string `json:"description,omitempty"` |
|
||||||
|
|
||||||
// Array of plugin keywords. Used for search on grafana.com.
|
|
||||||
Keywords []string `json:"keywords"` |
|
||||||
|
|
||||||
// An array of link objects to be displayed on this plugin's
|
|
||||||
// project page in the form `{name: 'foo', url:
|
|
||||||
// 'http://example.com'}`
|
|
||||||
Links []struct { |
|
||||||
Name *string `json:"name,omitempty"` |
|
||||||
Url *string `json:"url,omitempty"` |
|
||||||
} `json:"links,omitempty"` |
|
||||||
|
|
||||||
// SVG images that are used as plugin icons
|
|
||||||
Logos *struct { |
|
||||||
// Link to the "large" version of the plugin logo, which must be
|
|
||||||
// an SVG image. "Large" and "small" logos can be the same image.
|
|
||||||
Large string `json:"large"` |
|
||||||
|
|
||||||
// Link to the "small" version of the plugin logo, which must be
|
|
||||||
// an SVG image. "Large" and "small" logos can be the same image.
|
|
||||||
Small string `json:"small"` |
|
||||||
} `json:"logos,omitempty"` |
|
||||||
|
|
||||||
// An array of screenshot objects in the form `{name: 'bar', path:
|
|
||||||
// 'img/screenshot.png'}`
|
|
||||||
Screenshots []struct { |
|
||||||
Name *string `json:"name,omitempty"` |
|
||||||
Path *string `json:"path,omitempty"` |
|
||||||
} `json:"screenshots,omitempty"` |
|
||||||
|
|
||||||
// Date when this plugin was built
|
|
||||||
Updated *string `json:"updated,omitempty"` |
|
||||||
|
|
||||||
// Project version of this commit, e.g. `6.7.x`
|
|
||||||
Version *string `json:"version,omitempty"` |
|
||||||
} |
|
||||||
|
|
||||||
// TODO docs
|
|
||||||
// TODO should this really be separate from TokenAuth?
|
|
||||||
type JWTTokenAuth struct { |
|
||||||
// Parameters for the JWT token authentication request.
|
|
||||||
Params map[string]string `json:"params"` |
|
||||||
|
|
||||||
// The list of scopes that your application should be granted
|
|
||||||
// access to.
|
|
||||||
Scopes []string `json:"scopes"` |
|
||||||
|
|
||||||
// URL to fetch the JWT token.
|
|
||||||
Url string `json:"url"` |
|
||||||
} |
|
||||||
|
|
||||||
// Permission describes an RBAC permission on the plugin. A permission has an action and an optional
|
|
||||||
// scope.
|
|
||||||
// Example: action: 'test-app.schedules:read', scope: 'test-app.schedules:*'
|
|
||||||
type Permission struct { |
|
||||||
Action string `json:"action"` |
|
||||||
Scope *string `json:"scope,omitempty"` |
|
||||||
} |
|
||||||
|
|
||||||
// PluginDef defines model for PluginDef.
|
|
||||||
type PluginDef struct { |
|
||||||
// Schema definition for the plugin.json file. Used primarily for schema validation.
|
|
||||||
Schema *string `json:"$schema,omitempty"` |
|
||||||
|
|
||||||
// For data source plugins, if the plugin supports alerting. Requires `backend` to be set to `true`.
|
|
||||||
Alerting *bool `json:"alerting,omitempty"` |
|
||||||
|
|
||||||
// An alias is useful when migrating from one plugin id to another (rebranding etc)
|
|
||||||
// This should be used sparingly, and is currently only supported though a hardcoded checklist
|
|
||||||
AliasIDs []string `json:"aliasIDs,omitempty"` |
|
||||||
|
|
||||||
// For data source plugins, if the plugin supports annotation
|
|
||||||
// queries.
|
|
||||||
Annotations *bool `json:"annotations,omitempty"` |
|
||||||
|
|
||||||
// Set to true for app plugins that should be enabled and pinned to the navigation bar in all orgs.
|
|
||||||
AutoEnabled *bool `json:"autoEnabled,omitempty"` |
|
||||||
|
|
||||||
// If the plugin has a backend component.
|
|
||||||
Backend *bool `json:"backend,omitempty"` |
|
||||||
|
|
||||||
// [internal only] Indicates whether the plugin is developed and shipped as part
|
|
||||||
// of Grafana. Also known as a 'core plugin'.
|
|
||||||
BuiltIn bool `json:"builtIn"` |
|
||||||
|
|
||||||
// Plugin category used on the Add data source page.
|
|
||||||
Category *Category `json:"category,omitempty"` |
|
||||||
Dependencies Dependencies `json:"dependencies"` |
|
||||||
|
|
||||||
// Grafana Enterprise specific features.
|
|
||||||
EnterpriseFeatures *struct { |
|
||||||
// Enable/Disable health diagnostics errors. Requires Grafana
|
|
||||||
// >=7.5.5.
|
|
||||||
HealthDiagnosticsErrors *bool `json:"healthDiagnosticsErrors,omitempty"` |
|
||||||
} `json:"enterpriseFeatures,omitempty"` |
|
||||||
|
|
||||||
// The first part of the file name of the backend component
|
|
||||||
// executable. There can be multiple executables built for
|
|
||||||
// different operating system and architecture. Grafana will
|
|
||||||
// check for executables named `<executable>_<$GOOS>_<lower case
|
|
||||||
// $GOARCH><.exe for Windows>`, e.g. `plugin_linux_amd64`.
|
|
||||||
// Combination of $GOOS and $GOARCH can be found here:
|
|
||||||
// https://golang.org/doc/install/source#environment.
|
|
||||||
Executable *string `json:"executable,omitempty"` |
|
||||||
|
|
||||||
// [internal only] Excludes the plugin from listings in Grafana's UI. Only
|
|
||||||
// allowed for `builtIn` plugins.
|
|
||||||
HideFromList bool `json:"hideFromList"` |
|
||||||
|
|
||||||
// IAM allows the plugin to get a service account with tailored permissions and a token
|
|
||||||
// (or to use the client_credentials grant if the token provider is the OAuth2 Server)
|
|
||||||
Iam IAM `json:"iam"` |
|
||||||
|
|
||||||
// Unique name of the plugin. If the plugin is published on
|
|
||||||
// grafana.com, then the plugin `id` has to follow the naming
|
|
||||||
// conventions.
|
|
||||||
Id string `json:"id"` |
|
||||||
|
|
||||||
// Resources to include in plugin.
|
|
||||||
Includes []Include `json:"includes,omitempty"` |
|
||||||
|
|
||||||
// Metadata about a Grafana plugin. Some fields are used on the plugins
|
|
||||||
// page in Grafana and others on grafana.com, if the plugin is published.
|
|
||||||
Info Info `json:"info"` |
|
||||||
|
|
||||||
// For data source plugins, if the plugin supports logs. It may be used to filter logs only features.
|
|
||||||
Logs *bool `json:"logs,omitempty"` |
|
||||||
|
|
||||||
// For data source plugins, if the plugin supports metric queries.
|
|
||||||
// Used to enable the plugin in the panel editor.
|
|
||||||
Metrics *bool `json:"metrics,omitempty"` |
|
||||||
|
|
||||||
// Human-readable name of the plugin that is shown to the user in
|
|
||||||
// the UI.
|
|
||||||
Name string `json:"name"` |
|
||||||
|
|
||||||
// [internal only] The PascalCase name for the plugin. Used for creating machine-friendly
|
|
||||||
// identifiers, typically in code generation.
|
|
||||||
//
|
|
||||||
// If not provided, defaults to name, but title-cased and sanitized (only
|
|
||||||
// alphabetical characters allowed).
|
|
||||||
PascalName string `json:"pascalName"` |
|
||||||
|
|
||||||
// Initialize plugin on startup. By default, the plugin
|
|
||||||
// initializes on first use.
|
|
||||||
Preload *bool `json:"preload,omitempty"` |
|
||||||
|
|
||||||
// For data source plugins. There is a query options section in
|
|
||||||
// the plugin's query editor and these options can be turned on
|
|
||||||
// if needed.
|
|
||||||
QueryOptions *struct { |
|
||||||
// For data source plugins. If the `cache timeout` option should
|
|
||||||
// be shown in the query options section in the query editor.
|
|
||||||
CacheTimeout *bool `json:"cacheTimeout,omitempty"` |
|
||||||
|
|
||||||
// For data source plugins. If the `max data points` option should
|
|
||||||
// be shown in the query options section in the query editor.
|
|
||||||
MaxDataPoints *bool `json:"maxDataPoints,omitempty"` |
|
||||||
|
|
||||||
// For data source plugins. If the `min interval` option should be
|
|
||||||
// shown in the query options section in the query editor.
|
|
||||||
MinInterval *bool `json:"minInterval,omitempty"` |
|
||||||
} `json:"queryOptions,omitempty"` |
|
||||||
|
|
||||||
// Optional list of RBAC RoleRegistrations.
|
|
||||||
// Describes and organizes the default permissions associated with any of the Grafana basic roles,
|
|
||||||
// which characterizes what viewers, editors, admins, or grafana admins can do on the plugin.
|
|
||||||
// The Admin basic role inherits its default permissions from the Editor basic role which in turn
|
|
||||||
// inherits them from the Viewer basic role.
|
|
||||||
Roles []RoleRegistration `json:"roles,omitempty"` |
|
||||||
|
|
||||||
// Routes is a list of proxy routes, if any. For datasource plugins only.
|
|
||||||
Routes []Route `json:"routes,omitempty"` |
|
||||||
|
|
||||||
// For panel plugins. Hides the query editor.
|
|
||||||
SkipDataQuery *bool `json:"skipDataQuery,omitempty"` |
|
||||||
|
|
||||||
// ReleaseState indicates release maturity state of a plugin.
|
|
||||||
State *ReleaseState `json:"state,omitempty"` |
|
||||||
|
|
||||||
// For data source plugins, if the plugin supports streaming. Used in Explore to start live streaming.
|
|
||||||
Streaming *bool `json:"streaming,omitempty"` |
|
||||||
|
|
||||||
// For data source plugins, if the plugin supports tracing. Used for example to link logs (e.g. Loki logs) with tracing plugins.
|
|
||||||
Tracing *bool `json:"tracing,omitempty"` |
|
||||||
|
|
||||||
// type indicates which type of Grafana plugin this is, of the defined
|
|
||||||
// set of Grafana plugin types.
|
|
||||||
Type Type `json:"type"` |
|
||||||
} |
|
||||||
|
|
||||||
// Plugin category used on the Add data source page.
|
|
||||||
type Category string |
|
||||||
|
|
||||||
// Type type indicates which type of Grafana plugin this is, of the defined
|
|
||||||
// set of Grafana plugin types.
|
|
||||||
type Type string |
|
||||||
|
|
||||||
// ReleaseState indicates release maturity state of a plugin.
|
|
||||||
type ReleaseState string |
|
||||||
|
|
||||||
// Role describes an RBAC role which allows grouping multiple related permissions on the plugin,
|
|
||||||
// each of which has an action and an optional scope.
|
|
||||||
// Example: the role 'Schedules Reader' bundles permissions to view all schedules of the plugin.
|
|
||||||
type Role struct { |
|
||||||
Description string `json:"description"` |
|
||||||
Name string `json:"name"` |
|
||||||
Permissions []Permission `json:"permissions"` |
|
||||||
} |
|
||||||
|
|
||||||
// RoleRegistration describes an RBAC role and its assignments to basic roles.
|
|
||||||
// It organizes related RBAC permissions on the plugin into a role and defines which basic roles
|
|
||||||
// will get them by default.
|
|
||||||
// Example: the role 'Schedules Reader' bundles permissions to view all schedules of the plugin
|
|
||||||
// which will be granted to Admins by default.
|
|
||||||
type RoleRegistration struct { |
|
||||||
// Default assignment of the role to Grafana basic roles (Viewer, Editor, Admin, Grafana Admin)
|
|
||||||
// The Admin basic role inherits its default permissions from the Editor basic role which in turn
|
|
||||||
// inherits them from the Viewer basic role.
|
|
||||||
Grants []BasicRole `json:"grants"` |
|
||||||
|
|
||||||
// Role describes an RBAC role which allows grouping multiple related permissions on the plugin,
|
|
||||||
// each of which has an action and an optional scope.
|
|
||||||
// Example: the role 'Schedules Reader' bundles permissions to view all schedules of the plugin.
|
|
||||||
Role Role `json:"role"` |
|
||||||
} |
|
||||||
|
|
||||||
// A proxy route used in datasource plugins for plugin authentication
|
|
||||||
// and adding headers to HTTP requests made by the plugin.
|
|
||||||
// For more information, refer to [Authentication for data source
|
|
||||||
// plugins](https://grafana.com/developers/plugin-tools/create-a-plugin/extend-a-plugin/add-authentication-for-data-source-plugins).
|
|
||||||
type Route struct { |
|
||||||
// For data source plugins. Route headers set the body content and
|
|
||||||
// length to the proxied request.
|
|
||||||
Body map[string]any `json:"body,omitempty"` |
|
||||||
|
|
||||||
// For data source plugins. Route headers adds HTTP headers to the
|
|
||||||
// proxied request.
|
|
||||||
Headers []Header `json:"headers,omitempty"` |
|
||||||
|
|
||||||
// TODO docs
|
|
||||||
// TODO should this really be separate from TokenAuth?
|
|
||||||
JwtTokenAuth *JWTTokenAuth `json:"jwtTokenAuth,omitempty"` |
|
||||||
|
|
||||||
// For data source plugins. Route method matches the HTTP verb
|
|
||||||
// like GET or POST. Multiple methods can be provided as a
|
|
||||||
// comma-separated list.
|
|
||||||
Method *string `json:"method,omitempty"` |
|
||||||
|
|
||||||
// For data source plugins. The route path that is replaced by the
|
|
||||||
// route URL field when proxying the call.
|
|
||||||
Path *string `json:"path,omitempty"` |
|
||||||
|
|
||||||
// RBAC action the user must have to access the route. i.e. plugin-id.projects:read
|
|
||||||
ReqAction *string `json:"reqAction,omitempty"` |
|
||||||
ReqRole *string `json:"reqRole,omitempty"` |
|
||||||
ReqSignedIn *bool `json:"reqSignedIn,omitempty"` |
|
||||||
|
|
||||||
// TODO docs
|
|
||||||
TokenAuth *TokenAuth `json:"tokenAuth,omitempty"` |
|
||||||
|
|
||||||
// For data source plugins. Route URL is where the request is
|
|
||||||
// proxied to.
|
|
||||||
Url *string `json:"url,omitempty"` |
|
||||||
UrlParams []URLParam `json:"urlParams,omitempty"` |
|
||||||
} |
|
||||||
|
|
||||||
// TODO docs
|
|
||||||
type TokenAuth struct { |
|
||||||
// Parameters for the token authentication request.
|
|
||||||
Params map[string]string `json:"params"` |
|
||||||
|
|
||||||
// The list of scopes that your application should be granted
|
|
||||||
// access to.
|
|
||||||
Scopes []string `json:"scopes,omitempty"` |
|
||||||
|
|
||||||
// URL to fetch the authentication token.
|
|
||||||
Url *string `json:"url,omitempty"` |
|
||||||
} |
|
||||||
|
|
||||||
// URLParam describes query string parameters for
|
|
||||||
// a url in a plugin route
|
|
||||||
type URLParam struct { |
|
||||||
Content string `json:"content"` |
|
||||||
Name string `json:"name"` |
|
||||||
} |
|
||||||
Loading…
Reference in new issue