plugindef: Move pluginmeta out of coremodels as standalone thema lineage (#56765)

* Get pluginmeta mostly moved over to pkg/plugins/plugindef

* Remove dead func

* Fix up pfs, use sync.Once in plugindef

* Update to latest thema

* Chase Endec->Codec conversion in Thema

* Comments on slash header gen; use ToSlash

* Also generate JSON schema for plugindef

* Generate JSON Schema as well

* Fix slot loading from kindsys cue decls

* Remove unused vars

* skip generating plugin.schema.json for now

Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com>
This commit is contained in:
sam boyer
2022-11-15 14:48:31 +01:00
committed by GitHub
co-authored by Marcus Efraimsson
parent ff1afbb699
commit 78f0340031
29 changed files with 458 additions and 451 deletions
+132
View File
@@ -0,0 +1,132 @@
//go:build ignore
// +build ignore
package main
import (
"bytes"
"context"
"encoding/json"
"fmt"
"go/ast"
"os"
"path/filepath"
"strings"
"cuelang.org/go/cue/cuecontext"
"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"
"golang.org/x/tools/go/ast/astutil"
)
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)
}
grootp := strings.Split(cwd, string(os.PathSeparator))
groot := filepath.Join(string(os.PathSeparator), filepath.Join(grootp[:len(grootp)-3]...))
jfs := elsedie(jl.GenerateFS([]thema.Lineage{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) {
b, err := gocode.GenerateTypesOpenAPI(lin.Latest(), &gocode.TypeConfigOpenAPI{
ApplyFuncs: []astutil.ApplyFunc{
codegen.PrefixReplacer("Plugindef", "PluginDef"),
},
})
if err != nil {
return nil, err
}
return codejen.NewFile(filepath.Join(dirPlugindef, "plugindef_types_gen.go"), b, j), nil
}
// 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: ast.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)
}
}
+399
View File
@@ -0,0 +1,399 @@
package plugindef
import (
"strings"
"github.com/grafana/thema"
)
thema.#Lineage
name: "plugindef"
seqs: [
{
schemas: [
{
// 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|gauge|geomap|gettingstarted|graph|heatmap|heatmap-old|histogram|icon|live|logs|news|nodeGraph|piechart|pluginlist|stat|state-timeline|status-history|table|table-old|text|timeseries|traces|welcome|xychart|alertmanager|cloudwatch|dashboard|elasticsearch|grafana|grafana-azure-monitor-datasource|graphite|influxdb|jaeger|loki|mixed|mssql|mysql|opentsdb|postgres|prometheus|stackdriver|tempo|testdata|zipkin|phlare|parca)$"
// 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"
// Human-readable name of the plugin that is shown to the user in
// the UI.
name: string
// Plugin category used on the Add data source page.
category?: "tsdb" | "logging" | "cloud" | "tracing" | "sql" | "enterprise" | "profiling" | "other"
// For data source plugins, if the plugin supports annotation
// queries.
annotations?: bool
// For data source plugins, if the plugin supports alerting.
alerting?: bool
// If the plugin has a backend component.
backend?: bool
// builtin indicates whether the plugin is developed and shipped as part
// of Grafana. Also known as a "core plugin."
builtIn: bool | *false
// hideFromList excludes the plugin from listings in Grafana's UI. Only
// allowed for builtin plugins.
hideFromList: 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
// Initialize plugin on startup. By default, the plugin
// initializes on first use.
preload?: bool
// Marks a plugin as a pre-release.
state?: #ReleaseState
// ReleaseState indicates release maturity state of a plugin.
#ReleaseState: "alpha" | "beta" | "deprecated" | *"stable"
// 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
role?: "Admin" | "Editor" | "Viewer"
// Used for app plugins.
path?: string
// Add the include to the side 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.
logs?: bool
// For panel plugins. Hides the query editor.
skipDataQuery?: bool
// For data source plugins, if the plugin supports metric queries.
// Used in Explore.
metrics?: bool
// For data source plugins, if the plugin supports streaming.
streaming?: bool
// This is an undocumented feature.
tables?: bool
// For data source plugins, if the plugin supports tracing.
tracing?: bool
// For data source plugins, include hidden queries in the data
// request.
hiddenQueries?: bool
// Set to true for app plugins that should be enabled by default
// in all orgs
autoEnabled?: 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 option
// 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"
// Dependencies needed by the plugin.
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]+))?$"
// 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
...
}
// 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
}
// 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]
// 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/docs/grafana/latest/developers/plugins/authentication/).
#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
// 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
}
// Grafana Enerprise specific features.
enterpriseFeatures?: {
// Enable/Disable health diagnostics errors. Requires Grafana
// >=7.5.5.
healthDiagnosticsErrors?: bool | *false
...
}
},
]
},
]
+38
View File
@@ -0,0 +1,38 @@
package plugindef
import (
"sync"
"cuelang.org/go/cue/build"
"github.com/grafana/grafana/pkg/cuectx"
"github.com/grafana/thema"
)
//go:generate go run gen.go
// PkgName is the name of the CUE package that Grafana will load when looking
// for kind declarations by a Grafana plugin.
const PkgName = "grafanaplugin"
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...)
}
@@ -0,0 +1,85 @@
// THIS FILE IS GENERATED. EDITING IS FUTILE.
//
// 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)
}
// type guards
var _ thema.ConvergentLineageFactory[*PluginDef] = doLineage
var _ thema.LineageFactory = baseLineage
@@ -0,0 +1,568 @@
// THIS FILE IS GENERATED. EDITING IS FUTILE.
//
// Generated by:
// pkg/plugins/plugindef/gen.go
// Using jennies:
// PluginGoTypes
//
// Run 'make gen-cue' from repository root to regenerate.
package plugindef
// Defines values for Category.
const (
CategoryCloud Category = "cloud"
CategoryEnterprise Category = "enterprise"
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 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 ReleaseState.
const (
ReleaseStateAlpha ReleaseState = "alpha"
ReleaseStateBeta ReleaseState = "beta"
ReleaseStateDeprecated ReleaseState = "deprecated"
ReleaseStateStable ReleaseState = "stable"
)
// Defines values for RoleRegistrationGrants.
const (
RoleRegistrationGrantsAdmin RoleRegistrationGrants = "Admin"
RoleRegistrationGrantsEditor RoleRegistrationGrants = "Editor"
RoleRegistrationGrantsGrafanaAdmin RoleRegistrationGrants = "Grafana Admin"
RoleRegistrationGrantsViewer RoleRegistrationGrants = "Viewer"
)
// PluginDef defines model for plugindef.
type PluginDef struct {
// For data source plugins, if the plugin supports alerting.
Alerting *bool `json:"alerting,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 by default
// in all orgs
AutoEnabled *bool `json:"autoEnabled,omitempty"`
// If the plugin has a backend component.
Backend *bool `json:"backend,omitempty"`
// builtin 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 needed by the plugin.
Dependencies struct {
// Required Grafana version for this plugin. Validated using
// https://github.com/npm/node-semver.
GrafanaDependency string `json:"grafanaDependency"`
// (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"`
} `json:"dependencies"`
// Grafana Enerprise 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"`
// For data source plugins, include hidden queries in the data
// request.
HiddenQueries *bool `json:"hiddenQueries,omitempty"`
// hideFromList excludes the plugin from listings in Grafana's UI. Only
// allowed for builtin plugins.
HideFromList bool `json:"hideFromList"`
// 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 the plugin.
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"`
} `json:"info"`
// For data source plugins, if the plugin supports logs.
Logs *bool `json:"logs,omitempty"`
// For data source plugins, if the plugin supports metric queries.
// Used in Explore.
Metrics *bool `json:"metrics,omitempty"`
// Human-readable name of the plugin that is shown to the user in
// the UI.
Name string `json:"name"`
// 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.
Streaming *bool `json:"streaming,omitempty"`
// This is an undocumented feature.
Tables *bool `json:"tables,omitempty"`
// For data source plugins, if the plugin supports tracing.
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 indicates which type of Grafana plugin this is, of the defined
// set of Grafana plugin types.
type Type 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.
type BasicRole string
// BuildInfo defines model for plugindef.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 plugindef.Dependencies.
type Dependencies struct {
// Required Grafana version for this plugin. Validated using
// https://github.com/npm/node-semver.
GrafanaDependency string `json:"grafanaDependency"`
// (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"`
}
// A resource to be included in a plugin.
type Include struct {
// Add the include to the side 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"`
Role *IncludeRole `json:"role,omitempty"`
Type IncludeType `json:"type"`
// Unique identifier of the included resource
Uid *string `json:"uid,omitempty"`
}
// IncludeRole defines model for Include.Role.
type IncludeRole string
// IncludeType defines model for Include.Type.
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]interface{} `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 option
// scope.
// Example: action: 'test-app.schedules:read', scope: 'test-app.schedules:*'
type Permission struct {
Action string `json:"action"`
Scope *string `json:"scope,omitempty"`
}
// 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 []struct {
Action string `json:"action"`
Scope *string `json:"scope,omitempty"`
} `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 []RoleRegistrationGrants `json:"grants"`
// RBAC role definition to bundle related RBAC permissions on the plugin.
Role struct {
Description string `json:"description"`
Name string `json:"name"`
Permissions []struct {
Action string `json:"action"`
Scope *string `json:"scope,omitempty"`
} `json:"permissions"`
} `json:"role"`
}
// RoleRegistrationGrants defines model for RoleRegistration.Grants.
type RoleRegistrationGrants 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/docs/grafana/latest/developers/plugins/authentication/).
type Route struct {
// For data source plugins. Route headers set the body content and
// length to the proxied request.
Body *map[string]interface{} `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"`
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]interface{} `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"`
}