Plugins API: Merge meta and installs (#112962)
This commit is contained in:
+2
-4
@@ -3,8 +3,8 @@ module github.com/grafana/grafana/apps/plugins
|
||||
go 1.25.3
|
||||
|
||||
require (
|
||||
github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37
|
||||
github.com/grafana/grafana-app-sdk v0.48.1
|
||||
github.com/grafana/grafana-app-sdk/logging v0.48.1
|
||||
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250428110029-a8ea72012bde
|
||||
k8s.io/apimachinery v0.34.1
|
||||
k8s.io/apiserver v0.34.1
|
||||
@@ -14,7 +14,6 @@ require (
|
||||
|
||||
require (
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/blang/semver/v4 v4.0.0 // indirect
|
||||
github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 // indirect
|
||||
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
@@ -37,8 +36,8 @@ require (
|
||||
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f // indirect
|
||||
github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37 // indirect
|
||||
github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 // indirect
|
||||
github.com/grafana/grafana-app-sdk/logging v0.48.1 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
@@ -93,7 +92,6 @@ require (
|
||||
k8s.io/api v0.34.1 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.34.1 // indirect
|
||||
k8s.io/client-go v0.34.1 // indirect
|
||||
k8s.io/component-base v0.34.1 // indirect
|
||||
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
|
||||
sigs.k8s.io/randfill v1.0.0 // indirect
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
|
||||
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
|
||||
github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 h1:N7oVaKyGp8bttX0bfZGmcGkjz7DLQXhAn3DNd3T0ous=
|
||||
github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874/go.mod h1:r5xuitiExdLAJ09PR7vBVENGvp4ZuTBeWTGtxuX3K+c=
|
||||
github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
|
||||
@@ -242,8 +240,6 @@ k8s.io/apiserver v0.34.1 h1:U3JBGdgANK3dfFcyknWde1G6X1F4bg7PXuvlqt8lITA=
|
||||
k8s.io/apiserver v0.34.1/go.mod h1:eOOc9nrVqlBI1AFCvVzsob0OxtPZUCPiUJL45JOTBG0=
|
||||
k8s.io/client-go v0.34.1 h1:ZUPJKgXsnKwVwmKKdPfw4tB58+7/Ik3CrjOEhsiZ7mY=
|
||||
k8s.io/client-go v0.34.1/go.mod h1:kA8v0FP+tk6sZA0yKLRG67LWjqufAoSHA2xVGKw9Of8=
|
||||
k8s.io/component-base v0.34.1 h1:v7xFgG+ONhytZNFpIz5/kecwD+sUhVE6HU7qQUiRM4A=
|
||||
k8s.io/component-base v0.34.1/go.mod h1:mknCpLlTSKHzAQJJnnHVKqjxR7gBeHRv0rPXA7gdtQ0=
|
||||
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
||||
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 h1:Y3gxNAuB0OBLImH611+UDZcmKS3g6CthxToOb37KgwE=
|
||||
|
||||
@@ -5,14 +5,13 @@ manifest: {
|
||||
groupOverride: "plugins.grafana.app"
|
||||
versions: {
|
||||
"v0alpha1": {
|
||||
served: false
|
||||
served: true
|
||||
codegen: {
|
||||
ts: {enabled: false}
|
||||
go: {enabled: true}
|
||||
}
|
||||
kinds: [
|
||||
pluginMetaV0Alpha1,
|
||||
pluginInstallV0Alpha1,
|
||||
pluginV0Alpha1,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,17 +4,33 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
pluginMetaV0Alpha1: {
|
||||
kind: "PluginMeta"
|
||||
plural: "pluginsmeta"
|
||||
pluginV0Alpha1: {
|
||||
kind: "Plugin"
|
||||
plural: "plugins"
|
||||
scope: "Namespaced"
|
||||
schema: {
|
||||
spec: {
|
||||
pluginJSON: #JSONData,
|
||||
id: string
|
||||
version: string
|
||||
url?: string
|
||||
class: "core" | "external" | "cdn"
|
||||
}
|
||||
}
|
||||
routes: {
|
||||
"/meta": {
|
||||
"GET": {
|
||||
request: {}
|
||||
response: #JSONData,
|
||||
responseMetadata: {
|
||||
typeMeta: false
|
||||
objectMeta: false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// JSON configuration schema for Grafana plugins
|
||||
// Converted from: https://github.com/grafana/grafana/blob/main/docs/sources/developers/plugins/plugin.schema.json
|
||||
#JSONData: {
|
||||
@@ -217,4 +233,4 @@ pluginMetaV0Alpha1: {
|
||||
title?: string
|
||||
description?: string
|
||||
}]
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package plugins
|
||||
|
||||
pluginInstallV0Alpha1: {
|
||||
kind: "PluginInstall"
|
||||
plural: "plugininstalls"
|
||||
scope: "Namespaced"
|
||||
schema: {
|
||||
spec: {
|
||||
id: string
|
||||
version: string
|
||||
url?: string
|
||||
class: "core" | "external" | "cdn"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
package v0alpha1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
type PluginClient struct {
|
||||
client *resource.TypedClient[*Plugin, *PluginList]
|
||||
}
|
||||
|
||||
func NewPluginClient(client resource.Client) *PluginClient {
|
||||
return &PluginClient{
|
||||
client: resource.NewTypedClient[*Plugin, *PluginList](client, PluginKind()),
|
||||
}
|
||||
}
|
||||
|
||||
func NewPluginClientFromGenerator(generator resource.ClientGenerator) (*PluginClient, error) {
|
||||
c, err := generator.ClientFor(PluginKind())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewPluginClient(c), nil
|
||||
}
|
||||
|
||||
func (c *PluginClient) Get(ctx context.Context, identifier resource.Identifier) (*Plugin, error) {
|
||||
return c.client.Get(ctx, identifier)
|
||||
}
|
||||
|
||||
func (c *PluginClient) List(ctx context.Context, namespace string, opts resource.ListOptions) (*PluginList, error) {
|
||||
return c.client.List(ctx, namespace, opts)
|
||||
}
|
||||
|
||||
func (c *PluginClient) ListAll(ctx context.Context, namespace string, opts resource.ListOptions) (*PluginList, error) {
|
||||
resp, err := c.client.List(ctx, namespace, resource.ListOptions{
|
||||
ResourceVersion: opts.ResourceVersion,
|
||||
Limit: opts.Limit,
|
||||
LabelFilters: opts.LabelFilters,
|
||||
FieldSelectors: opts.FieldSelectors,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for resp.GetContinue() != "" {
|
||||
page, err := c.client.List(ctx, namespace, resource.ListOptions{
|
||||
Continue: resp.GetContinue(),
|
||||
ResourceVersion: opts.ResourceVersion,
|
||||
Limit: opts.Limit,
|
||||
LabelFilters: opts.LabelFilters,
|
||||
FieldSelectors: opts.FieldSelectors,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp.SetContinue(page.GetContinue())
|
||||
resp.SetResourceVersion(page.GetResourceVersion())
|
||||
resp.SetItems(append(resp.GetItems(), page.GetItems()...))
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (c *PluginClient) Create(ctx context.Context, obj *Plugin, opts resource.CreateOptions) (*Plugin, error) {
|
||||
// Make sure apiVersion and kind are set
|
||||
obj.APIVersion = GroupVersion.Identifier()
|
||||
obj.Kind = PluginKind().Kind()
|
||||
return c.client.Create(ctx, obj, opts)
|
||||
}
|
||||
|
||||
func (c *PluginClient) Update(ctx context.Context, obj *Plugin, opts resource.UpdateOptions) (*Plugin, error) {
|
||||
return c.client.Update(ctx, obj, opts)
|
||||
}
|
||||
|
||||
func (c *PluginClient) Patch(ctx context.Context, identifier resource.Identifier, req resource.PatchRequest, opts resource.PatchOptions) (*Plugin, error) {
|
||||
return c.client.Patch(ctx, identifier, req, opts)
|
||||
}
|
||||
|
||||
func (c *PluginClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus PluginStatus, opts resource.UpdateOptions) (*Plugin, error) {
|
||||
return c.client.Update(ctx, &Plugin{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: PluginKind().Kind(),
|
||||
APIVersion: GroupVersion.Identifier(),
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: opts.ResourceVersion,
|
||||
Namespace: identifier.Namespace,
|
||||
Name: identifier.Name,
|
||||
},
|
||||
Status: newStatus,
|
||||
}, resource.UpdateOptions{
|
||||
Subresource: "status",
|
||||
ResourceVersion: opts.ResourceVersion,
|
||||
})
|
||||
}
|
||||
|
||||
func (c *PluginClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error {
|
||||
return c.client.Delete(ctx, identifier, opts)
|
||||
}
|
||||
|
||||
type GetMetaRequest struct {
|
||||
Headers http.Header
|
||||
}
|
||||
|
||||
func (c *PluginClient) GetMeta(ctx context.Context, identifier resource.Identifier, request GetMetaRequest) (*GetMeta, error) {
|
||||
resp, err := c.client.SubresourceRequest(ctx, identifier, resource.CustomRouteRequestOptions{
|
||||
Path: "/meta",
|
||||
Verb: "GET",
|
||||
Headers: request.Headers,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cast := GetMeta{}
|
||||
err = json.Unmarshal(resp, &cast)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to unmarshal response bytes into GetMeta: %w", err)
|
||||
}
|
||||
return &cast, nil
|
||||
}
|
||||
+5
-5
@@ -11,18 +11,18 @@ import (
|
||||
"github.com/grafana/grafana-app-sdk/resource"
|
||||
)
|
||||
|
||||
// PluginMetaJSONCodec is an implementation of resource.Codec for kubernetes JSON encoding
|
||||
type PluginMetaJSONCodec struct{}
|
||||
// PluginJSONCodec is an implementation of resource.Codec for kubernetes JSON encoding
|
||||
type PluginJSONCodec struct{}
|
||||
|
||||
// Read reads JSON-encoded bytes from `reader` and unmarshals them into `into`
|
||||
func (*PluginMetaJSONCodec) Read(reader io.Reader, into resource.Object) error {
|
||||
func (*PluginJSONCodec) Read(reader io.Reader, into resource.Object) error {
|
||||
return json.NewDecoder(reader).Decode(into)
|
||||
}
|
||||
|
||||
// Write writes JSON-encoded bytes into `writer` marshaled from `from`
|
||||
func (*PluginMetaJSONCodec) Write(writer io.Writer, from resource.Object) error {
|
||||
func (*PluginJSONCodec) Write(writer io.Writer, from resource.Object) error {
|
||||
return json.NewEncoder(writer).Encode(from)
|
||||
}
|
||||
|
||||
// Interface compliance checks
|
||||
var _ resource.Codec = &PluginMetaJSONCodec{}
|
||||
var _ resource.Codec = &PluginJSONCodec{}
|
||||
@@ -0,0 +1,463 @@
|
||||
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
|
||||
|
||||
package v0alpha1
|
||||
|
||||
import (
|
||||
time "time"
|
||||
)
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type Info struct {
|
||||
// Required fields
|
||||
// +listType=set
|
||||
Keywords []string `json:"keywords"`
|
||||
Logos V0alpha1InfoLogos `json:"logos"`
|
||||
Updated time.Time `json:"updated"`
|
||||
Version string `json:"version"`
|
||||
// Optional fields
|
||||
Author *V0alpha1InfoAuthor `json:"author,omitempty"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
// +listType=atomic
|
||||
Links []V0alpha1InfoLinks `json:"links,omitempty"`
|
||||
// +listType=atomic
|
||||
Screenshots []V0alpha1InfoScreenshots `json:"screenshots,omitempty"`
|
||||
}
|
||||
|
||||
// NewInfo creates a new Info object.
|
||||
func NewInfo() *Info {
|
||||
return &Info{
|
||||
Keywords: []string{},
|
||||
Logos: *NewV0alpha1InfoLogos(),
|
||||
}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type Dependencies struct {
|
||||
// Required field
|
||||
GrafanaDependency string `json:"grafanaDependency"`
|
||||
// Optional fields
|
||||
GrafanaVersion *string `json:"grafanaVersion,omitempty"`
|
||||
// +listType=set
|
||||
// +listMapKey=id
|
||||
Plugins []V0alpha1DependenciesPlugins `json:"plugins,omitempty"`
|
||||
Extensions *V0alpha1DependenciesExtensions `json:"extensions,omitempty"`
|
||||
}
|
||||
|
||||
// NewDependencies creates a new Dependencies object.
|
||||
func NewDependencies() *Dependencies {
|
||||
return &Dependencies{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type EnterpriseFeatures struct {
|
||||
// Allow additional properties
|
||||
HealthDiagnosticsErrors *bool `json:"healthDiagnosticsErrors,omitempty"`
|
||||
}
|
||||
|
||||
// NewEnterpriseFeatures creates a new EnterpriseFeatures object.
|
||||
func NewEnterpriseFeatures() *EnterpriseFeatures {
|
||||
return &EnterpriseFeatures{
|
||||
HealthDiagnosticsErrors: (func(input bool) *bool { return &input })(false),
|
||||
}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type Include struct {
|
||||
Uid *string `json:"uid,omitempty"`
|
||||
Type *IncludeType `json:"type,omitempty"`
|
||||
Name *string `json:"name,omitempty"`
|
||||
Component *string `json:"component,omitempty"`
|
||||
Role *IncludeRole `json:"role,omitempty"`
|
||||
Action *string `json:"action,omitempty"`
|
||||
Path *string `json:"path,omitempty"`
|
||||
AddToNav *bool `json:"addToNav,omitempty"`
|
||||
DefaultNav *bool `json:"defaultNav,omitempty"`
|
||||
Icon *string `json:"icon,omitempty"`
|
||||
}
|
||||
|
||||
// NewInclude creates a new Include object.
|
||||
func NewInclude() *Include {
|
||||
return &Include{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type QueryOptions struct {
|
||||
MaxDataPoints *bool `json:"maxDataPoints,omitempty"`
|
||||
MinInterval *bool `json:"minInterval,omitempty"`
|
||||
CacheTimeout *bool `json:"cacheTimeout,omitempty"`
|
||||
}
|
||||
|
||||
// NewQueryOptions creates a new QueryOptions object.
|
||||
func NewQueryOptions() *QueryOptions {
|
||||
return &QueryOptions{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type Route struct {
|
||||
Path *string `json:"path,omitempty"`
|
||||
Method *string `json:"method,omitempty"`
|
||||
Url *string `json:"url,omitempty"`
|
||||
ReqSignedIn *bool `json:"reqSignedIn,omitempty"`
|
||||
ReqRole *string `json:"reqRole,omitempty"`
|
||||
ReqAction *string `json:"reqAction,omitempty"`
|
||||
// +listType=atomic
|
||||
Headers []string `json:"headers,omitempty"`
|
||||
Body map[string]interface{} `json:"body,omitempty"`
|
||||
TokenAuth *V0alpha1RouteTokenAuth `json:"tokenAuth,omitempty"`
|
||||
JwtTokenAuth *V0alpha1RouteJwtTokenAuth `json:"jwtTokenAuth,omitempty"`
|
||||
// +listType=atomic
|
||||
UrlParams []V0alpha1RouteUrlParams `json:"urlParams,omitempty"`
|
||||
}
|
||||
|
||||
// NewRoute creates a new Route object.
|
||||
func NewRoute() *Route {
|
||||
return &Route{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type IAM struct {
|
||||
// +listType=atomic
|
||||
Permissions []V0alpha1IAMPermissions `json:"permissions,omitempty"`
|
||||
}
|
||||
|
||||
// NewIAM creates a new IAM object.
|
||||
func NewIAM() *IAM {
|
||||
return &IAM{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type Role struct {
|
||||
Role *V0alpha1RoleRole `json:"role,omitempty"`
|
||||
// +listType=set
|
||||
Grants []string `json:"grants,omitempty"`
|
||||
}
|
||||
|
||||
// NewRole creates a new Role object.
|
||||
func NewRole() *Role {
|
||||
return &Role{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type Extensions struct {
|
||||
// +listType=atomic
|
||||
AddedComponents []V0alpha1ExtensionsAddedComponents `json:"addedComponents,omitempty"`
|
||||
// +listType=atomic
|
||||
AddedLinks []V0alpha1ExtensionsAddedLinks `json:"addedLinks,omitempty"`
|
||||
// +listType=set
|
||||
// +listMapKey=id
|
||||
ExposedComponents []V0alpha1ExtensionsExposedComponents `json:"exposedComponents,omitempty"`
|
||||
// +listType=set
|
||||
// +listMapKey=id
|
||||
ExtensionPoints []V0alpha1ExtensionsExtensionPoints `json:"extensionPoints,omitempty"`
|
||||
}
|
||||
|
||||
// NewExtensions creates a new Extensions object.
|
||||
func NewExtensions() *Extensions {
|
||||
return &Extensions{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type GetMeta struct {
|
||||
// Unique name of the plugin
|
||||
Id string `json:"id"`
|
||||
// Plugin type
|
||||
Type GetMetaType `json:"type"`
|
||||
// Human-readable name of the plugin
|
||||
Name string `json:"name"`
|
||||
// Metadata for the plugin
|
||||
Info Info `json:"info"`
|
||||
// Dependency information
|
||||
Dependencies Dependencies `json:"dependencies"`
|
||||
// Optional fields
|
||||
Alerting *bool `json:"alerting,omitempty"`
|
||||
Annotations *bool `json:"annotations,omitempty"`
|
||||
AutoEnabled *bool `json:"autoEnabled,omitempty"`
|
||||
Backend *bool `json:"backend,omitempty"`
|
||||
BuildMode *string `json:"buildMode,omitempty"`
|
||||
BuiltIn *bool `json:"builtIn,omitempty"`
|
||||
Category *GetMetaCategory `json:"category,omitempty"`
|
||||
EnterpriseFeatures *EnterpriseFeatures `json:"enterpriseFeatures,omitempty"`
|
||||
Executable *string `json:"executable,omitempty"`
|
||||
HideFromList *bool `json:"hideFromList,omitempty"`
|
||||
// +listType=atomic
|
||||
Includes []Include `json:"includes,omitempty"`
|
||||
Logs *bool `json:"logs,omitempty"`
|
||||
Metrics *bool `json:"metrics,omitempty"`
|
||||
MultiValueFilterOperators *bool `json:"multiValueFilterOperators,omitempty"`
|
||||
PascalName *string `json:"pascalName,omitempty"`
|
||||
Preload *bool `json:"preload,omitempty"`
|
||||
QueryOptions *QueryOptions `json:"queryOptions,omitempty"`
|
||||
// +listType=atomic
|
||||
Routes []Route `json:"routes,omitempty"`
|
||||
SkipDataQuery *bool `json:"skipDataQuery,omitempty"`
|
||||
State *GetMetaState `json:"state,omitempty"`
|
||||
Streaming *bool `json:"streaming,omitempty"`
|
||||
Tracing *bool `json:"tracing,omitempty"`
|
||||
Iam *IAM `json:"iam,omitempty"`
|
||||
// +listType=atomic
|
||||
Roles []Role `json:"roles,omitempty"`
|
||||
Extensions *Extensions `json:"extensions,omitempty"`
|
||||
}
|
||||
|
||||
// NewGetMeta creates a new GetMeta object.
|
||||
func NewGetMeta() *GetMeta {
|
||||
return &GetMeta{
|
||||
Info: *NewInfo(),
|
||||
Dependencies: *NewDependencies(),
|
||||
}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type V0alpha1InfoLogos struct {
|
||||
Small string `json:"small"`
|
||||
Large string `json:"large"`
|
||||
}
|
||||
|
||||
// NewV0alpha1InfoLogos creates a new V0alpha1InfoLogos object.
|
||||
func NewV0alpha1InfoLogos() *V0alpha1InfoLogos {
|
||||
return &V0alpha1InfoLogos{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type V0alpha1InfoAuthor struct {
|
||||
Name *string `json:"name,omitempty"`
|
||||
Email *string `json:"email,omitempty"`
|
||||
Url *string `json:"url,omitempty"`
|
||||
}
|
||||
|
||||
// NewV0alpha1InfoAuthor creates a new V0alpha1InfoAuthor object.
|
||||
func NewV0alpha1InfoAuthor() *V0alpha1InfoAuthor {
|
||||
return &V0alpha1InfoAuthor{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type V0alpha1InfoLinks struct {
|
||||
Name *string `json:"name,omitempty"`
|
||||
Url *string `json:"url,omitempty"`
|
||||
}
|
||||
|
||||
// NewV0alpha1InfoLinks creates a new V0alpha1InfoLinks object.
|
||||
func NewV0alpha1InfoLinks() *V0alpha1InfoLinks {
|
||||
return &V0alpha1InfoLinks{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type V0alpha1InfoScreenshots struct {
|
||||
Name *string `json:"name,omitempty"`
|
||||
Path *string `json:"path,omitempty"`
|
||||
}
|
||||
|
||||
// NewV0alpha1InfoScreenshots creates a new V0alpha1InfoScreenshots object.
|
||||
func NewV0alpha1InfoScreenshots() *V0alpha1InfoScreenshots {
|
||||
return &V0alpha1InfoScreenshots{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type V0alpha1DependenciesPlugins struct {
|
||||
Id string `json:"id"`
|
||||
Type V0alpha1DependenciesPluginsType `json:"type"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// NewV0alpha1DependenciesPlugins creates a new V0alpha1DependenciesPlugins object.
|
||||
func NewV0alpha1DependenciesPlugins() *V0alpha1DependenciesPlugins {
|
||||
return &V0alpha1DependenciesPlugins{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type V0alpha1DependenciesExtensions struct {
|
||||
// +listType=set
|
||||
ExposedComponents []string `json:"exposedComponents,omitempty"`
|
||||
}
|
||||
|
||||
// NewV0alpha1DependenciesExtensions creates a new V0alpha1DependenciesExtensions object.
|
||||
func NewV0alpha1DependenciesExtensions() *V0alpha1DependenciesExtensions {
|
||||
return &V0alpha1DependenciesExtensions{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type V0alpha1RouteTokenAuth struct {
|
||||
Url *string `json:"url,omitempty"`
|
||||
// +listType=set
|
||||
Scopes []string `json:"scopes,omitempty"`
|
||||
Params map[string]interface{} `json:"params,omitempty"`
|
||||
}
|
||||
|
||||
// NewV0alpha1RouteTokenAuth creates a new V0alpha1RouteTokenAuth object.
|
||||
func NewV0alpha1RouteTokenAuth() *V0alpha1RouteTokenAuth {
|
||||
return &V0alpha1RouteTokenAuth{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type V0alpha1RouteJwtTokenAuth struct {
|
||||
Url *string `json:"url,omitempty"`
|
||||
// +listType=set
|
||||
Scopes []string `json:"scopes,omitempty"`
|
||||
Params map[string]interface{} `json:"params,omitempty"`
|
||||
}
|
||||
|
||||
// NewV0alpha1RouteJwtTokenAuth creates a new V0alpha1RouteJwtTokenAuth object.
|
||||
func NewV0alpha1RouteJwtTokenAuth() *V0alpha1RouteJwtTokenAuth {
|
||||
return &V0alpha1RouteJwtTokenAuth{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type V0alpha1RouteUrlParams struct {
|
||||
Name *string `json:"name,omitempty"`
|
||||
Content *string `json:"content,omitempty"`
|
||||
}
|
||||
|
||||
// NewV0alpha1RouteUrlParams creates a new V0alpha1RouteUrlParams object.
|
||||
func NewV0alpha1RouteUrlParams() *V0alpha1RouteUrlParams {
|
||||
return &V0alpha1RouteUrlParams{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type V0alpha1IAMPermissions struct {
|
||||
Action *string `json:"action,omitempty"`
|
||||
Scope *string `json:"scope,omitempty"`
|
||||
}
|
||||
|
||||
// NewV0alpha1IAMPermissions creates a new V0alpha1IAMPermissions object.
|
||||
func NewV0alpha1IAMPermissions() *V0alpha1IAMPermissions {
|
||||
return &V0alpha1IAMPermissions{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type V0alpha1RoleRolePermissions struct {
|
||||
Action *string `json:"action,omitempty"`
|
||||
Scope *string `json:"scope,omitempty"`
|
||||
}
|
||||
|
||||
// NewV0alpha1RoleRolePermissions creates a new V0alpha1RoleRolePermissions object.
|
||||
func NewV0alpha1RoleRolePermissions() *V0alpha1RoleRolePermissions {
|
||||
return &V0alpha1RoleRolePermissions{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type V0alpha1RoleRole struct {
|
||||
Name *string `json:"name,omitempty"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
// +listType=atomic
|
||||
Permissions []V0alpha1RoleRolePermissions `json:"permissions,omitempty"`
|
||||
}
|
||||
|
||||
// NewV0alpha1RoleRole creates a new V0alpha1RoleRole object.
|
||||
func NewV0alpha1RoleRole() *V0alpha1RoleRole {
|
||||
return &V0alpha1RoleRole{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type V0alpha1ExtensionsAddedComponents struct {
|
||||
// +listType=set
|
||||
Targets []string `json:"targets"`
|
||||
Title string `json:"title"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
}
|
||||
|
||||
// NewV0alpha1ExtensionsAddedComponents creates a new V0alpha1ExtensionsAddedComponents object.
|
||||
func NewV0alpha1ExtensionsAddedComponents() *V0alpha1ExtensionsAddedComponents {
|
||||
return &V0alpha1ExtensionsAddedComponents{
|
||||
Targets: []string{},
|
||||
}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type V0alpha1ExtensionsAddedLinks struct {
|
||||
// +listType=set
|
||||
Targets []string `json:"targets"`
|
||||
Title string `json:"title"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
}
|
||||
|
||||
// NewV0alpha1ExtensionsAddedLinks creates a new V0alpha1ExtensionsAddedLinks object.
|
||||
func NewV0alpha1ExtensionsAddedLinks() *V0alpha1ExtensionsAddedLinks {
|
||||
return &V0alpha1ExtensionsAddedLinks{
|
||||
Targets: []string{},
|
||||
}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type V0alpha1ExtensionsExposedComponents struct {
|
||||
Id string `json:"id"`
|
||||
Title *string `json:"title,omitempty"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
}
|
||||
|
||||
// NewV0alpha1ExtensionsExposedComponents creates a new V0alpha1ExtensionsExposedComponents object.
|
||||
func NewV0alpha1ExtensionsExposedComponents() *V0alpha1ExtensionsExposedComponents {
|
||||
return &V0alpha1ExtensionsExposedComponents{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type V0alpha1ExtensionsExtensionPoints struct {
|
||||
Id string `json:"id"`
|
||||
Title *string `json:"title,omitempty"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
}
|
||||
|
||||
// NewV0alpha1ExtensionsExtensionPoints creates a new V0alpha1ExtensionsExtensionPoints object.
|
||||
func NewV0alpha1ExtensionsExtensionPoints() *V0alpha1ExtensionsExtensionPoints {
|
||||
return &V0alpha1ExtensionsExtensionPoints{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type IncludeType string
|
||||
|
||||
const (
|
||||
IncludeTypeDashboard IncludeType = "dashboard"
|
||||
IncludeTypePage IncludeType = "page"
|
||||
IncludeTypePanel IncludeType = "panel"
|
||||
IncludeTypeDatasource IncludeType = "datasource"
|
||||
)
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type IncludeRole string
|
||||
|
||||
const (
|
||||
IncludeRoleAdmin IncludeRole = "Admin"
|
||||
IncludeRoleEditor IncludeRole = "Editor"
|
||||
IncludeRoleViewer IncludeRole = "Viewer"
|
||||
)
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type GetMetaType string
|
||||
|
||||
const (
|
||||
GetMetaTypeApp GetMetaType = "app"
|
||||
GetMetaTypeDatasource GetMetaType = "datasource"
|
||||
GetMetaTypePanel GetMetaType = "panel"
|
||||
GetMetaTypeRenderer GetMetaType = "renderer"
|
||||
)
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type GetMetaCategory string
|
||||
|
||||
const (
|
||||
GetMetaCategoryTsdb GetMetaCategory = "tsdb"
|
||||
GetMetaCategoryLogging GetMetaCategory = "logging"
|
||||
GetMetaCategoryCloud GetMetaCategory = "cloud"
|
||||
GetMetaCategoryTracing GetMetaCategory = "tracing"
|
||||
GetMetaCategoryProfiling GetMetaCategory = "profiling"
|
||||
GetMetaCategorySql GetMetaCategory = "sql"
|
||||
GetMetaCategoryEnterprise GetMetaCategory = "enterprise"
|
||||
GetMetaCategoryIot GetMetaCategory = "iot"
|
||||
GetMetaCategoryOther GetMetaCategory = "other"
|
||||
)
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type GetMetaState string
|
||||
|
||||
const (
|
||||
GetMetaStateAlpha GetMetaState = "alpha"
|
||||
GetMetaStateBeta GetMetaState = "beta"
|
||||
)
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type V0alpha1DependenciesPluginsType string
|
||||
|
||||
const (
|
||||
V0alpha1DependenciesPluginsTypeApp V0alpha1DependenciesPluginsType = "app"
|
||||
V0alpha1DependenciesPluginsTypeDatasource V0alpha1DependenciesPluginsType = "datasource"
|
||||
V0alpha1DependenciesPluginsTypePanel V0alpha1DependenciesPluginsType = "panel"
|
||||
)
|
||||
+4
-4
@@ -9,7 +9,7 @@ import (
|
||||
// metadata contains embedded CommonMetadata and can be extended with custom string fields
|
||||
// TODO: use CommonMetadata instead of redefining here; currently needs to be defined here
|
||||
// without external reference as using the CommonMetadata reference breaks thema codegen.
|
||||
type PluginMetaMetadata struct {
|
||||
type PluginMetadata struct {
|
||||
UpdateTimestamp time.Time `json:"updateTimestamp"`
|
||||
CreatedBy string `json:"createdBy"`
|
||||
Uid string `json:"uid"`
|
||||
@@ -22,9 +22,9 @@ type PluginMetaMetadata struct {
|
||||
Labels map[string]string `json:"labels"`
|
||||
}
|
||||
|
||||
// NewPluginMetaMetadata creates a new PluginMetaMetadata object.
|
||||
func NewPluginMetaMetadata() *PluginMetaMetadata {
|
||||
return &PluginMetaMetadata{
|
||||
// NewPluginMetadata creates a new PluginMetadata object.
|
||||
func NewPluginMetadata() *PluginMetadata {
|
||||
return &PluginMetadata{
|
||||
Finalizers: []string{},
|
||||
Labels: map[string]string{},
|
||||
}
|
||||
+51
-51
@@ -15,22 +15,22 @@ import (
|
||||
)
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginMeta struct {
|
||||
type Plugin struct {
|
||||
metav1.TypeMeta `json:",inline" yaml:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata" yaml:"metadata"`
|
||||
|
||||
// Spec is the spec of the PluginMeta
|
||||
Spec PluginMetaSpec `json:"spec" yaml:"spec"`
|
||||
// Spec is the spec of the Plugin
|
||||
Spec PluginSpec `json:"spec" yaml:"spec"`
|
||||
|
||||
Status PluginMetaStatus `json:"status" yaml:"status"`
|
||||
Status PluginStatus `json:"status" yaml:"status"`
|
||||
}
|
||||
|
||||
func (o *PluginMeta) GetSpec() any {
|
||||
func (o *Plugin) GetSpec() any {
|
||||
return o.Spec
|
||||
}
|
||||
|
||||
func (o *PluginMeta) SetSpec(spec any) error {
|
||||
cast, ok := spec.(PluginMetaSpec)
|
||||
func (o *Plugin) SetSpec(spec any) error {
|
||||
cast, ok := spec.(PluginSpec)
|
||||
if !ok {
|
||||
return fmt.Errorf("cannot set spec type %#v, not of type Spec", spec)
|
||||
}
|
||||
@@ -38,13 +38,13 @@ func (o *PluginMeta) SetSpec(spec any) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *PluginMeta) GetSubresources() map[string]any {
|
||||
func (o *Plugin) GetSubresources() map[string]any {
|
||||
return map[string]any{
|
||||
"status": o.Status,
|
||||
}
|
||||
}
|
||||
|
||||
func (o *PluginMeta) GetSubresource(name string) (any, bool) {
|
||||
func (o *Plugin) GetSubresource(name string) (any, bool) {
|
||||
switch name {
|
||||
case "status":
|
||||
return o.Status, true
|
||||
@@ -53,12 +53,12 @@ func (o *PluginMeta) GetSubresource(name string) (any, bool) {
|
||||
}
|
||||
}
|
||||
|
||||
func (o *PluginMeta) SetSubresource(name string, value any) error {
|
||||
func (o *Plugin) SetSubresource(name string, value any) error {
|
||||
switch name {
|
||||
case "status":
|
||||
cast, ok := value.(PluginMetaStatus)
|
||||
cast, ok := value.(PluginStatus)
|
||||
if !ok {
|
||||
return fmt.Errorf("cannot set status type %#v, not of type PluginMetaStatus", value)
|
||||
return fmt.Errorf("cannot set status type %#v, not of type PluginStatus", value)
|
||||
}
|
||||
o.Status = cast
|
||||
return nil
|
||||
@@ -67,7 +67,7 @@ func (o *PluginMeta) SetSubresource(name string, value any) error {
|
||||
}
|
||||
}
|
||||
|
||||
func (o *PluginMeta) GetStaticMetadata() resource.StaticMetadata {
|
||||
func (o *Plugin) GetStaticMetadata() resource.StaticMetadata {
|
||||
gvk := o.GroupVersionKind()
|
||||
return resource.StaticMetadata{
|
||||
Name: o.ObjectMeta.Name,
|
||||
@@ -78,7 +78,7 @@ func (o *PluginMeta) GetStaticMetadata() resource.StaticMetadata {
|
||||
}
|
||||
}
|
||||
|
||||
func (o *PluginMeta) SetStaticMetadata(metadata resource.StaticMetadata) {
|
||||
func (o *Plugin) SetStaticMetadata(metadata resource.StaticMetadata) {
|
||||
o.Name = metadata.Name
|
||||
o.Namespace = metadata.Namespace
|
||||
o.SetGroupVersionKind(schema.GroupVersionKind{
|
||||
@@ -88,7 +88,7 @@ func (o *PluginMeta) SetStaticMetadata(metadata resource.StaticMetadata) {
|
||||
})
|
||||
}
|
||||
|
||||
func (o *PluginMeta) GetCommonMetadata() resource.CommonMetadata {
|
||||
func (o *Plugin) GetCommonMetadata() resource.CommonMetadata {
|
||||
dt := o.DeletionTimestamp
|
||||
var deletionTimestamp *time.Time
|
||||
if dt != nil {
|
||||
@@ -120,7 +120,7 @@ func (o *PluginMeta) GetCommonMetadata() resource.CommonMetadata {
|
||||
}
|
||||
}
|
||||
|
||||
func (o *PluginMeta) SetCommonMetadata(metadata resource.CommonMetadata) {
|
||||
func (o *Plugin) SetCommonMetadata(metadata resource.CommonMetadata) {
|
||||
o.UID = types.UID(metadata.UID)
|
||||
o.ResourceVersion = metadata.ResourceVersion
|
||||
o.Generation = metadata.Generation
|
||||
@@ -165,7 +165,7 @@ func (o *PluginMeta) SetCommonMetadata(metadata resource.CommonMetadata) {
|
||||
}
|
||||
}
|
||||
|
||||
func (o *PluginMeta) GetCreatedBy() string {
|
||||
func (o *Plugin) GetCreatedBy() string {
|
||||
if o.ObjectMeta.Annotations == nil {
|
||||
o.ObjectMeta.Annotations = make(map[string]string)
|
||||
}
|
||||
@@ -173,7 +173,7 @@ func (o *PluginMeta) GetCreatedBy() string {
|
||||
return o.ObjectMeta.Annotations["grafana.com/createdBy"]
|
||||
}
|
||||
|
||||
func (o *PluginMeta) SetCreatedBy(createdBy string) {
|
||||
func (o *Plugin) SetCreatedBy(createdBy string) {
|
||||
if o.ObjectMeta.Annotations == nil {
|
||||
o.ObjectMeta.Annotations = make(map[string]string)
|
||||
}
|
||||
@@ -181,7 +181,7 @@ func (o *PluginMeta) SetCreatedBy(createdBy string) {
|
||||
o.ObjectMeta.Annotations["grafana.com/createdBy"] = createdBy
|
||||
}
|
||||
|
||||
func (o *PluginMeta) GetUpdateTimestamp() time.Time {
|
||||
func (o *Plugin) GetUpdateTimestamp() time.Time {
|
||||
if o.ObjectMeta.Annotations == nil {
|
||||
o.ObjectMeta.Annotations = make(map[string]string)
|
||||
}
|
||||
@@ -190,7 +190,7 @@ func (o *PluginMeta) GetUpdateTimestamp() time.Time {
|
||||
return parsed
|
||||
}
|
||||
|
||||
func (o *PluginMeta) SetUpdateTimestamp(updateTimestamp time.Time) {
|
||||
func (o *Plugin) SetUpdateTimestamp(updateTimestamp time.Time) {
|
||||
if o.ObjectMeta.Annotations == nil {
|
||||
o.ObjectMeta.Annotations = make(map[string]string)
|
||||
}
|
||||
@@ -198,7 +198,7 @@ func (o *PluginMeta) SetUpdateTimestamp(updateTimestamp time.Time) {
|
||||
o.ObjectMeta.Annotations["grafana.com/updateTimestamp"] = updateTimestamp.Format(time.RFC3339)
|
||||
}
|
||||
|
||||
func (o *PluginMeta) GetUpdatedBy() string {
|
||||
func (o *Plugin) GetUpdatedBy() string {
|
||||
if o.ObjectMeta.Annotations == nil {
|
||||
o.ObjectMeta.Annotations = make(map[string]string)
|
||||
}
|
||||
@@ -206,7 +206,7 @@ func (o *PluginMeta) GetUpdatedBy() string {
|
||||
return o.ObjectMeta.Annotations["grafana.com/updatedBy"]
|
||||
}
|
||||
|
||||
func (o *PluginMeta) SetUpdatedBy(updatedBy string) {
|
||||
func (o *Plugin) SetUpdatedBy(updatedBy string) {
|
||||
if o.ObjectMeta.Annotations == nil {
|
||||
o.ObjectMeta.Annotations = make(map[string]string)
|
||||
}
|
||||
@@ -214,21 +214,21 @@ func (o *PluginMeta) SetUpdatedBy(updatedBy string) {
|
||||
o.ObjectMeta.Annotations["grafana.com/updatedBy"] = updatedBy
|
||||
}
|
||||
|
||||
func (o *PluginMeta) Copy() resource.Object {
|
||||
func (o *Plugin) Copy() resource.Object {
|
||||
return resource.CopyObject(o)
|
||||
}
|
||||
|
||||
func (o *PluginMeta) DeepCopyObject() runtime.Object {
|
||||
func (o *Plugin) DeepCopyObject() runtime.Object {
|
||||
return o.Copy()
|
||||
}
|
||||
|
||||
func (o *PluginMeta) DeepCopy() *PluginMeta {
|
||||
cpy := &PluginMeta{}
|
||||
func (o *Plugin) DeepCopy() *Plugin {
|
||||
cpy := &Plugin{}
|
||||
o.DeepCopyInto(cpy)
|
||||
return cpy
|
||||
}
|
||||
|
||||
func (o *PluginMeta) DeepCopyInto(dst *PluginMeta) {
|
||||
func (o *Plugin) DeepCopyInto(dst *Plugin) {
|
||||
dst.TypeMeta.APIVersion = o.TypeMeta.APIVersion
|
||||
dst.TypeMeta.Kind = o.TypeMeta.Kind
|
||||
o.ObjectMeta.DeepCopyInto(&dst.ObjectMeta)
|
||||
@@ -237,34 +237,34 @@ func (o *PluginMeta) DeepCopyInto(dst *PluginMeta) {
|
||||
}
|
||||
|
||||
// Interface compliance compile-time check
|
||||
var _ resource.Object = &PluginMeta{}
|
||||
var _ resource.Object = &Plugin{}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginMetaList struct {
|
||||
type PluginList struct {
|
||||
metav1.TypeMeta `json:",inline" yaml:",inline"`
|
||||
metav1.ListMeta `json:"metadata" yaml:"metadata"`
|
||||
Items []PluginMeta `json:"items" yaml:"items"`
|
||||
Items []Plugin `json:"items" yaml:"items"`
|
||||
}
|
||||
|
||||
func (o *PluginMetaList) DeepCopyObject() runtime.Object {
|
||||
func (o *PluginList) DeepCopyObject() runtime.Object {
|
||||
return o.Copy()
|
||||
}
|
||||
|
||||
func (o *PluginMetaList) Copy() resource.ListObject {
|
||||
cpy := &PluginMetaList{
|
||||
func (o *PluginList) Copy() resource.ListObject {
|
||||
cpy := &PluginList{
|
||||
TypeMeta: o.TypeMeta,
|
||||
Items: make([]PluginMeta, len(o.Items)),
|
||||
Items: make([]Plugin, len(o.Items)),
|
||||
}
|
||||
o.ListMeta.DeepCopyInto(&cpy.ListMeta)
|
||||
for i := 0; i < len(o.Items); i++ {
|
||||
if item, ok := o.Items[i].Copy().(*PluginMeta); ok {
|
||||
if item, ok := o.Items[i].Copy().(*Plugin); ok {
|
||||
cpy.Items[i] = *item
|
||||
}
|
||||
}
|
||||
return cpy
|
||||
}
|
||||
|
||||
func (o *PluginMetaList) GetItems() []resource.Object {
|
||||
func (o *PluginList) GetItems() []resource.Object {
|
||||
items := make([]resource.Object, len(o.Items))
|
||||
for i := 0; i < len(o.Items); i++ {
|
||||
items[i] = &o.Items[i]
|
||||
@@ -272,48 +272,48 @@ func (o *PluginMetaList) GetItems() []resource.Object {
|
||||
return items
|
||||
}
|
||||
|
||||
func (o *PluginMetaList) SetItems(items []resource.Object) {
|
||||
o.Items = make([]PluginMeta, len(items))
|
||||
func (o *PluginList) SetItems(items []resource.Object) {
|
||||
o.Items = make([]Plugin, len(items))
|
||||
for i := 0; i < len(items); i++ {
|
||||
o.Items[i] = *items[i].(*PluginMeta)
|
||||
o.Items[i] = *items[i].(*Plugin)
|
||||
}
|
||||
}
|
||||
|
||||
func (o *PluginMetaList) DeepCopy() *PluginMetaList {
|
||||
cpy := &PluginMetaList{}
|
||||
func (o *PluginList) DeepCopy() *PluginList {
|
||||
cpy := &PluginList{}
|
||||
o.DeepCopyInto(cpy)
|
||||
return cpy
|
||||
}
|
||||
|
||||
func (o *PluginMetaList) DeepCopyInto(dst *PluginMetaList) {
|
||||
func (o *PluginList) DeepCopyInto(dst *PluginList) {
|
||||
resource.CopyObjectInto(dst, o)
|
||||
}
|
||||
|
||||
// Interface compliance compile-time check
|
||||
var _ resource.ListObject = &PluginMetaList{}
|
||||
var _ resource.ListObject = &PluginList{}
|
||||
|
||||
// Copy methods for all subresource types
|
||||
|
||||
// DeepCopy creates a full deep copy of Spec
|
||||
func (s *PluginMetaSpec) DeepCopy() *PluginMetaSpec {
|
||||
cpy := &PluginMetaSpec{}
|
||||
func (s *PluginSpec) DeepCopy() *PluginSpec {
|
||||
cpy := &PluginSpec{}
|
||||
s.DeepCopyInto(cpy)
|
||||
return cpy
|
||||
}
|
||||
|
||||
// DeepCopyInto deep copies Spec into another Spec object
|
||||
func (s *PluginMetaSpec) DeepCopyInto(dst *PluginMetaSpec) {
|
||||
func (s *PluginSpec) DeepCopyInto(dst *PluginSpec) {
|
||||
resource.CopyObjectInto(dst, s)
|
||||
}
|
||||
|
||||
// DeepCopy creates a full deep copy of PluginMetaStatus
|
||||
func (s *PluginMetaStatus) DeepCopy() *PluginMetaStatus {
|
||||
cpy := &PluginMetaStatus{}
|
||||
// DeepCopy creates a full deep copy of PluginStatus
|
||||
func (s *PluginStatus) DeepCopy() *PluginStatus {
|
||||
cpy := &PluginStatus{}
|
||||
s.DeepCopyInto(cpy)
|
||||
return cpy
|
||||
}
|
||||
|
||||
// DeepCopyInto deep copies PluginMetaStatus into another PluginMetaStatus object
|
||||
func (s *PluginMetaStatus) DeepCopyInto(dst *PluginMetaStatus) {
|
||||
// DeepCopyInto deep copies PluginStatus into another PluginStatus object
|
||||
func (s *PluginStatus) DeepCopyInto(dst *PluginStatus) {
|
||||
resource.CopyObjectInto(dst, s)
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
//
|
||||
// Code generated by grafana-app-sdk. DO NOT EDIT.
|
||||
//
|
||||
|
||||
package v0alpha1
|
||||
|
||||
import (
|
||||
"github.com/grafana/grafana-app-sdk/resource"
|
||||
)
|
||||
|
||||
// schema is unexported to prevent accidental overwrites
|
||||
var (
|
||||
schemaPlugin = resource.NewSimpleSchema("plugins.grafana.app", "v0alpha1", &Plugin{}, &PluginList{}, resource.WithKind("Plugin"),
|
||||
resource.WithPlural("plugins"), resource.WithScope(resource.NamespacedScope))
|
||||
kindPlugin = resource.Kind{
|
||||
Schema: schemaPlugin,
|
||||
Codecs: map[resource.KindEncoding]resource.Codec{
|
||||
resource.KindEncodingJSON: &PluginJSONCodec{},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
// Kind returns a resource.Kind for this Schema with a JSON codec
|
||||
func PluginKind() resource.Kind {
|
||||
return kindPlugin
|
||||
}
|
||||
|
||||
// Schema returns a resource.SimpleSchema representation of Plugin
|
||||
func PluginSchema() *resource.SimpleSchema {
|
||||
return schemaPlugin
|
||||
}
|
||||
|
||||
// Interface compliance checks
|
||||
var _ resource.Schema = kindPlugin
|
||||
@@ -0,0 +1,25 @@
|
||||
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
|
||||
|
||||
package v0alpha1
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginSpec struct {
|
||||
Id string `json:"id"`
|
||||
Version string `json:"version"`
|
||||
Url *string `json:"url,omitempty"`
|
||||
Class PluginSpecClass `json:"class"`
|
||||
}
|
||||
|
||||
// NewPluginSpec creates a new PluginSpec object.
|
||||
func NewPluginSpec() *PluginSpec {
|
||||
return &PluginSpec{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginSpecClass string
|
||||
|
||||
const (
|
||||
PluginSpecClassCore PluginSpecClass = "core"
|
||||
PluginSpecClassExternal PluginSpecClass = "external"
|
||||
PluginSpecClassCdn PluginSpecClass = "cdn"
|
||||
)
|
||||
+14
-14
@@ -3,42 +3,42 @@
|
||||
package v0alpha1
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginMetastatusOperatorState struct {
|
||||
type PluginstatusOperatorState struct {
|
||||
// lastEvaluation is the ResourceVersion last evaluated
|
||||
LastEvaluation string `json:"lastEvaluation"`
|
||||
// state describes the state of the lastEvaluation.
|
||||
// It is limited to three possible states for machine evaluation.
|
||||
State PluginMetaStatusOperatorStateState `json:"state"`
|
||||
State PluginStatusOperatorStateState `json:"state"`
|
||||
// descriptiveState is an optional more descriptive state field which has no requirements on format
|
||||
DescriptiveState *string `json:"descriptiveState,omitempty"`
|
||||
// details contains any extra information that is operator-specific
|
||||
Details map[string]interface{} `json:"details,omitempty"`
|
||||
}
|
||||
|
||||
// NewPluginMetastatusOperatorState creates a new PluginMetastatusOperatorState object.
|
||||
func NewPluginMetastatusOperatorState() *PluginMetastatusOperatorState {
|
||||
return &PluginMetastatusOperatorState{}
|
||||
// NewPluginstatusOperatorState creates a new PluginstatusOperatorState object.
|
||||
func NewPluginstatusOperatorState() *PluginstatusOperatorState {
|
||||
return &PluginstatusOperatorState{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginMetaStatus struct {
|
||||
type PluginStatus struct {
|
||||
// operatorStates is a map of operator ID to operator state evaluations.
|
||||
// Any operator which consumes this kind SHOULD add its state evaluation information to this field.
|
||||
OperatorStates map[string]PluginMetastatusOperatorState `json:"operatorStates,omitempty"`
|
||||
OperatorStates map[string]PluginstatusOperatorState `json:"operatorStates,omitempty"`
|
||||
// additionalFields is reserved for future use
|
||||
AdditionalFields map[string]interface{} `json:"additionalFields,omitempty"`
|
||||
}
|
||||
|
||||
// NewPluginMetaStatus creates a new PluginMetaStatus object.
|
||||
func NewPluginMetaStatus() *PluginMetaStatus {
|
||||
return &PluginMetaStatus{}
|
||||
// NewPluginStatus creates a new PluginStatus object.
|
||||
func NewPluginStatus() *PluginStatus {
|
||||
return &PluginStatus{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginMetaStatusOperatorStateState string
|
||||
type PluginStatusOperatorStateState string
|
||||
|
||||
const (
|
||||
PluginMetaStatusOperatorStateStateSuccess PluginMetaStatusOperatorStateState = "success"
|
||||
PluginMetaStatusOperatorStateStateInProgress PluginMetaStatusOperatorStateState = "in_progress"
|
||||
PluginMetaStatusOperatorStateStateFailed PluginMetaStatusOperatorStateState = "failed"
|
||||
PluginStatusOperatorStateStateSuccess PluginStatusOperatorStateState = "success"
|
||||
PluginStatusOperatorStateStateInProgress PluginStatusOperatorStateState = "in_progress"
|
||||
PluginStatusOperatorStateStateFailed PluginStatusOperatorStateState = "failed"
|
||||
)
|
||||
@@ -1,99 +0,0 @@
|
||||
package v0alpha1
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
type PluginInstallClient struct {
|
||||
client *resource.TypedClient[*PluginInstall, *PluginInstallList]
|
||||
}
|
||||
|
||||
func NewPluginInstallClient(client resource.Client) *PluginInstallClient {
|
||||
return &PluginInstallClient{
|
||||
client: resource.NewTypedClient[*PluginInstall, *PluginInstallList](client, PluginInstallKind()),
|
||||
}
|
||||
}
|
||||
|
||||
func NewPluginInstallClientFromGenerator(generator resource.ClientGenerator) (*PluginInstallClient, error) {
|
||||
c, err := generator.ClientFor(PluginInstallKind())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewPluginInstallClient(c), nil
|
||||
}
|
||||
|
||||
func (c *PluginInstallClient) Get(ctx context.Context, identifier resource.Identifier) (*PluginInstall, error) {
|
||||
return c.client.Get(ctx, identifier)
|
||||
}
|
||||
|
||||
func (c *PluginInstallClient) List(ctx context.Context, namespace string, opts resource.ListOptions) (*PluginInstallList, error) {
|
||||
return c.client.List(ctx, namespace, opts)
|
||||
}
|
||||
|
||||
func (c *PluginInstallClient) ListAll(ctx context.Context, namespace string, opts resource.ListOptions) (*PluginInstallList, error) {
|
||||
resp, err := c.client.List(ctx, namespace, resource.ListOptions{
|
||||
ResourceVersion: opts.ResourceVersion,
|
||||
Limit: opts.Limit,
|
||||
LabelFilters: opts.LabelFilters,
|
||||
FieldSelectors: opts.FieldSelectors,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for resp.GetContinue() != "" {
|
||||
page, err := c.client.List(ctx, namespace, resource.ListOptions{
|
||||
Continue: resp.GetContinue(),
|
||||
ResourceVersion: opts.ResourceVersion,
|
||||
Limit: opts.Limit,
|
||||
LabelFilters: opts.LabelFilters,
|
||||
FieldSelectors: opts.FieldSelectors,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp.SetContinue(page.GetContinue())
|
||||
resp.SetResourceVersion(page.GetResourceVersion())
|
||||
resp.SetItems(append(resp.GetItems(), page.GetItems()...))
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (c *PluginInstallClient) Create(ctx context.Context, obj *PluginInstall, opts resource.CreateOptions) (*PluginInstall, error) {
|
||||
// Make sure apiVersion and kind are set
|
||||
obj.APIVersion = GroupVersion.Identifier()
|
||||
obj.Kind = PluginInstallKind().Kind()
|
||||
return c.client.Create(ctx, obj, opts)
|
||||
}
|
||||
|
||||
func (c *PluginInstallClient) Update(ctx context.Context, obj *PluginInstall, opts resource.UpdateOptions) (*PluginInstall, error) {
|
||||
return c.client.Update(ctx, obj, opts)
|
||||
}
|
||||
|
||||
func (c *PluginInstallClient) Patch(ctx context.Context, identifier resource.Identifier, req resource.PatchRequest, opts resource.PatchOptions) (*PluginInstall, error) {
|
||||
return c.client.Patch(ctx, identifier, req, opts)
|
||||
}
|
||||
|
||||
func (c *PluginInstallClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus PluginInstallStatus, opts resource.UpdateOptions) (*PluginInstall, error) {
|
||||
return c.client.Update(ctx, &PluginInstall{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: PluginInstallKind().Kind(),
|
||||
APIVersion: GroupVersion.Identifier(),
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: opts.ResourceVersion,
|
||||
Namespace: identifier.Namespace,
|
||||
Name: identifier.Name,
|
||||
},
|
||||
Status: newStatus,
|
||||
}, resource.UpdateOptions{
|
||||
Subresource: "status",
|
||||
ResourceVersion: opts.ResourceVersion,
|
||||
})
|
||||
}
|
||||
|
||||
func (c *PluginInstallClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error {
|
||||
return c.client.Delete(ctx, identifier, opts)
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
//
|
||||
// Code generated by grafana-app-sdk. DO NOT EDIT.
|
||||
//
|
||||
|
||||
package v0alpha1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/resource"
|
||||
)
|
||||
|
||||
// PluginInstallJSONCodec is an implementation of resource.Codec for kubernetes JSON encoding
|
||||
type PluginInstallJSONCodec struct{}
|
||||
|
||||
// Read reads JSON-encoded bytes from `reader` and unmarshals them into `into`
|
||||
func (*PluginInstallJSONCodec) Read(reader io.Reader, into resource.Object) error {
|
||||
return json.NewDecoder(reader).Decode(into)
|
||||
}
|
||||
|
||||
// Write writes JSON-encoded bytes into `writer` marshaled from `from`
|
||||
func (*PluginInstallJSONCodec) Write(writer io.Writer, from resource.Object) error {
|
||||
return json.NewEncoder(writer).Encode(from)
|
||||
}
|
||||
|
||||
// Interface compliance checks
|
||||
var _ resource.Codec = &PluginInstallJSONCodec{}
|
||||
@@ -1,31 +0,0 @@
|
||||
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
|
||||
|
||||
package v0alpha1
|
||||
|
||||
import (
|
||||
time "time"
|
||||
)
|
||||
|
||||
// metadata contains embedded CommonMetadata and can be extended with custom string fields
|
||||
// TODO: use CommonMetadata instead of redefining here; currently needs to be defined here
|
||||
// without external reference as using the CommonMetadata reference breaks thema codegen.
|
||||
type PluginInstallMetadata struct {
|
||||
UpdateTimestamp time.Time `json:"updateTimestamp"`
|
||||
CreatedBy string `json:"createdBy"`
|
||||
Uid string `json:"uid"`
|
||||
CreationTimestamp time.Time `json:"creationTimestamp"`
|
||||
DeletionTimestamp *time.Time `json:"deletionTimestamp,omitempty"`
|
||||
Finalizers []string `json:"finalizers"`
|
||||
ResourceVersion string `json:"resourceVersion"`
|
||||
Generation int64 `json:"generation"`
|
||||
UpdatedBy string `json:"updatedBy"`
|
||||
Labels map[string]string `json:"labels"`
|
||||
}
|
||||
|
||||
// NewPluginInstallMetadata creates a new PluginInstallMetadata object.
|
||||
func NewPluginInstallMetadata() *PluginInstallMetadata {
|
||||
return &PluginInstallMetadata{
|
||||
Finalizers: []string{},
|
||||
Labels: map[string]string{},
|
||||
}
|
||||
}
|
||||
@@ -1,319 +0,0 @@
|
||||
//
|
||||
// Code generated by grafana-app-sdk. DO NOT EDIT.
|
||||
//
|
||||
|
||||
package v0alpha1
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/grafana/grafana-app-sdk/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"time"
|
||||
)
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginInstall struct {
|
||||
metav1.TypeMeta `json:",inline" yaml:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata" yaml:"metadata"`
|
||||
|
||||
// Spec is the spec of the PluginInstall
|
||||
Spec PluginInstallSpec `json:"spec" yaml:"spec"`
|
||||
|
||||
Status PluginInstallStatus `json:"status" yaml:"status"`
|
||||
}
|
||||
|
||||
func (o *PluginInstall) GetSpec() any {
|
||||
return o.Spec
|
||||
}
|
||||
|
||||
func (o *PluginInstall) SetSpec(spec any) error {
|
||||
cast, ok := spec.(PluginInstallSpec)
|
||||
if !ok {
|
||||
return fmt.Errorf("cannot set spec type %#v, not of type Spec", spec)
|
||||
}
|
||||
o.Spec = cast
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *PluginInstall) GetSubresources() map[string]any {
|
||||
return map[string]any{
|
||||
"status": o.Status,
|
||||
}
|
||||
}
|
||||
|
||||
func (o *PluginInstall) GetSubresource(name string) (any, bool) {
|
||||
switch name {
|
||||
case "status":
|
||||
return o.Status, true
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
|
||||
func (o *PluginInstall) SetSubresource(name string, value any) error {
|
||||
switch name {
|
||||
case "status":
|
||||
cast, ok := value.(PluginInstallStatus)
|
||||
if !ok {
|
||||
return fmt.Errorf("cannot set status type %#v, not of type PluginInstallStatus", value)
|
||||
}
|
||||
o.Status = cast
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("subresource '%s' does not exist", name)
|
||||
}
|
||||
}
|
||||
|
||||
func (o *PluginInstall) GetStaticMetadata() resource.StaticMetadata {
|
||||
gvk := o.GroupVersionKind()
|
||||
return resource.StaticMetadata{
|
||||
Name: o.ObjectMeta.Name,
|
||||
Namespace: o.ObjectMeta.Namespace,
|
||||
Group: gvk.Group,
|
||||
Version: gvk.Version,
|
||||
Kind: gvk.Kind,
|
||||
}
|
||||
}
|
||||
|
||||
func (o *PluginInstall) SetStaticMetadata(metadata resource.StaticMetadata) {
|
||||
o.Name = metadata.Name
|
||||
o.Namespace = metadata.Namespace
|
||||
o.SetGroupVersionKind(schema.GroupVersionKind{
|
||||
Group: metadata.Group,
|
||||
Version: metadata.Version,
|
||||
Kind: metadata.Kind,
|
||||
})
|
||||
}
|
||||
|
||||
func (o *PluginInstall) GetCommonMetadata() resource.CommonMetadata {
|
||||
dt := o.DeletionTimestamp
|
||||
var deletionTimestamp *time.Time
|
||||
if dt != nil {
|
||||
deletionTimestamp = &dt.Time
|
||||
}
|
||||
// Legacy ExtraFields support
|
||||
extraFields := make(map[string]any)
|
||||
if o.Annotations != nil {
|
||||
extraFields["annotations"] = o.Annotations
|
||||
}
|
||||
if o.ManagedFields != nil {
|
||||
extraFields["managedFields"] = o.ManagedFields
|
||||
}
|
||||
if o.OwnerReferences != nil {
|
||||
extraFields["ownerReferences"] = o.OwnerReferences
|
||||
}
|
||||
return resource.CommonMetadata{
|
||||
UID: string(o.UID),
|
||||
ResourceVersion: o.ResourceVersion,
|
||||
Generation: o.Generation,
|
||||
Labels: o.Labels,
|
||||
CreationTimestamp: o.CreationTimestamp.Time,
|
||||
DeletionTimestamp: deletionTimestamp,
|
||||
Finalizers: o.Finalizers,
|
||||
UpdateTimestamp: o.GetUpdateTimestamp(),
|
||||
CreatedBy: o.GetCreatedBy(),
|
||||
UpdatedBy: o.GetUpdatedBy(),
|
||||
ExtraFields: extraFields,
|
||||
}
|
||||
}
|
||||
|
||||
func (o *PluginInstall) SetCommonMetadata(metadata resource.CommonMetadata) {
|
||||
o.UID = types.UID(metadata.UID)
|
||||
o.ResourceVersion = metadata.ResourceVersion
|
||||
o.Generation = metadata.Generation
|
||||
o.Labels = metadata.Labels
|
||||
o.CreationTimestamp = metav1.NewTime(metadata.CreationTimestamp)
|
||||
if metadata.DeletionTimestamp != nil {
|
||||
dt := metav1.NewTime(*metadata.DeletionTimestamp)
|
||||
o.DeletionTimestamp = &dt
|
||||
} else {
|
||||
o.DeletionTimestamp = nil
|
||||
}
|
||||
o.Finalizers = metadata.Finalizers
|
||||
if o.Annotations == nil {
|
||||
o.Annotations = make(map[string]string)
|
||||
}
|
||||
if !metadata.UpdateTimestamp.IsZero() {
|
||||
o.SetUpdateTimestamp(metadata.UpdateTimestamp)
|
||||
}
|
||||
if metadata.CreatedBy != "" {
|
||||
o.SetCreatedBy(metadata.CreatedBy)
|
||||
}
|
||||
if metadata.UpdatedBy != "" {
|
||||
o.SetUpdatedBy(metadata.UpdatedBy)
|
||||
}
|
||||
// Legacy support for setting Annotations, ManagedFields, and OwnerReferences via ExtraFields
|
||||
if metadata.ExtraFields != nil {
|
||||
if annotations, ok := metadata.ExtraFields["annotations"]; ok {
|
||||
if cast, ok := annotations.(map[string]string); ok {
|
||||
o.Annotations = cast
|
||||
}
|
||||
}
|
||||
if managedFields, ok := metadata.ExtraFields["managedFields"]; ok {
|
||||
if cast, ok := managedFields.([]metav1.ManagedFieldsEntry); ok {
|
||||
o.ManagedFields = cast
|
||||
}
|
||||
}
|
||||
if ownerReferences, ok := metadata.ExtraFields["ownerReferences"]; ok {
|
||||
if cast, ok := ownerReferences.([]metav1.OwnerReference); ok {
|
||||
o.OwnerReferences = cast
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (o *PluginInstall) GetCreatedBy() string {
|
||||
if o.ObjectMeta.Annotations == nil {
|
||||
o.ObjectMeta.Annotations = make(map[string]string)
|
||||
}
|
||||
|
||||
return o.ObjectMeta.Annotations["grafana.com/createdBy"]
|
||||
}
|
||||
|
||||
func (o *PluginInstall) SetCreatedBy(createdBy string) {
|
||||
if o.ObjectMeta.Annotations == nil {
|
||||
o.ObjectMeta.Annotations = make(map[string]string)
|
||||
}
|
||||
|
||||
o.ObjectMeta.Annotations["grafana.com/createdBy"] = createdBy
|
||||
}
|
||||
|
||||
func (o *PluginInstall) GetUpdateTimestamp() time.Time {
|
||||
if o.ObjectMeta.Annotations == nil {
|
||||
o.ObjectMeta.Annotations = make(map[string]string)
|
||||
}
|
||||
|
||||
parsed, _ := time.Parse(time.RFC3339, o.ObjectMeta.Annotations["grafana.com/updateTimestamp"])
|
||||
return parsed
|
||||
}
|
||||
|
||||
func (o *PluginInstall) SetUpdateTimestamp(updateTimestamp time.Time) {
|
||||
if o.ObjectMeta.Annotations == nil {
|
||||
o.ObjectMeta.Annotations = make(map[string]string)
|
||||
}
|
||||
|
||||
o.ObjectMeta.Annotations["grafana.com/updateTimestamp"] = updateTimestamp.Format(time.RFC3339)
|
||||
}
|
||||
|
||||
func (o *PluginInstall) GetUpdatedBy() string {
|
||||
if o.ObjectMeta.Annotations == nil {
|
||||
o.ObjectMeta.Annotations = make(map[string]string)
|
||||
}
|
||||
|
||||
return o.ObjectMeta.Annotations["grafana.com/updatedBy"]
|
||||
}
|
||||
|
||||
func (o *PluginInstall) SetUpdatedBy(updatedBy string) {
|
||||
if o.ObjectMeta.Annotations == nil {
|
||||
o.ObjectMeta.Annotations = make(map[string]string)
|
||||
}
|
||||
|
||||
o.ObjectMeta.Annotations["grafana.com/updatedBy"] = updatedBy
|
||||
}
|
||||
|
||||
func (o *PluginInstall) Copy() resource.Object {
|
||||
return resource.CopyObject(o)
|
||||
}
|
||||
|
||||
func (o *PluginInstall) DeepCopyObject() runtime.Object {
|
||||
return o.Copy()
|
||||
}
|
||||
|
||||
func (o *PluginInstall) DeepCopy() *PluginInstall {
|
||||
cpy := &PluginInstall{}
|
||||
o.DeepCopyInto(cpy)
|
||||
return cpy
|
||||
}
|
||||
|
||||
func (o *PluginInstall) DeepCopyInto(dst *PluginInstall) {
|
||||
dst.TypeMeta.APIVersion = o.TypeMeta.APIVersion
|
||||
dst.TypeMeta.Kind = o.TypeMeta.Kind
|
||||
o.ObjectMeta.DeepCopyInto(&dst.ObjectMeta)
|
||||
o.Spec.DeepCopyInto(&dst.Spec)
|
||||
o.Status.DeepCopyInto(&dst.Status)
|
||||
}
|
||||
|
||||
// Interface compliance compile-time check
|
||||
var _ resource.Object = &PluginInstall{}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginInstallList struct {
|
||||
metav1.TypeMeta `json:",inline" yaml:",inline"`
|
||||
metav1.ListMeta `json:"metadata" yaml:"metadata"`
|
||||
Items []PluginInstall `json:"items" yaml:"items"`
|
||||
}
|
||||
|
||||
func (o *PluginInstallList) DeepCopyObject() runtime.Object {
|
||||
return o.Copy()
|
||||
}
|
||||
|
||||
func (o *PluginInstallList) Copy() resource.ListObject {
|
||||
cpy := &PluginInstallList{
|
||||
TypeMeta: o.TypeMeta,
|
||||
Items: make([]PluginInstall, len(o.Items)),
|
||||
}
|
||||
o.ListMeta.DeepCopyInto(&cpy.ListMeta)
|
||||
for i := 0; i < len(o.Items); i++ {
|
||||
if item, ok := o.Items[i].Copy().(*PluginInstall); ok {
|
||||
cpy.Items[i] = *item
|
||||
}
|
||||
}
|
||||
return cpy
|
||||
}
|
||||
|
||||
func (o *PluginInstallList) GetItems() []resource.Object {
|
||||
items := make([]resource.Object, len(o.Items))
|
||||
for i := 0; i < len(o.Items); i++ {
|
||||
items[i] = &o.Items[i]
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
func (o *PluginInstallList) SetItems(items []resource.Object) {
|
||||
o.Items = make([]PluginInstall, len(items))
|
||||
for i := 0; i < len(items); i++ {
|
||||
o.Items[i] = *items[i].(*PluginInstall)
|
||||
}
|
||||
}
|
||||
|
||||
func (o *PluginInstallList) DeepCopy() *PluginInstallList {
|
||||
cpy := &PluginInstallList{}
|
||||
o.DeepCopyInto(cpy)
|
||||
return cpy
|
||||
}
|
||||
|
||||
func (o *PluginInstallList) DeepCopyInto(dst *PluginInstallList) {
|
||||
resource.CopyObjectInto(dst, o)
|
||||
}
|
||||
|
||||
// Interface compliance compile-time check
|
||||
var _ resource.ListObject = &PluginInstallList{}
|
||||
|
||||
// Copy methods for all subresource types
|
||||
|
||||
// DeepCopy creates a full deep copy of Spec
|
||||
func (s *PluginInstallSpec) DeepCopy() *PluginInstallSpec {
|
||||
cpy := &PluginInstallSpec{}
|
||||
s.DeepCopyInto(cpy)
|
||||
return cpy
|
||||
}
|
||||
|
||||
// DeepCopyInto deep copies Spec into another Spec object
|
||||
func (s *PluginInstallSpec) DeepCopyInto(dst *PluginInstallSpec) {
|
||||
resource.CopyObjectInto(dst, s)
|
||||
}
|
||||
|
||||
// DeepCopy creates a full deep copy of PluginInstallStatus
|
||||
func (s *PluginInstallStatus) DeepCopy() *PluginInstallStatus {
|
||||
cpy := &PluginInstallStatus{}
|
||||
s.DeepCopyInto(cpy)
|
||||
return cpy
|
||||
}
|
||||
|
||||
// DeepCopyInto deep copies PluginInstallStatus into another PluginInstallStatus object
|
||||
func (s *PluginInstallStatus) DeepCopyInto(dst *PluginInstallStatus) {
|
||||
resource.CopyObjectInto(dst, s)
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
//
|
||||
// Code generated by grafana-app-sdk. DO NOT EDIT.
|
||||
//
|
||||
|
||||
package v0alpha1
|
||||
|
||||
import (
|
||||
"github.com/grafana/grafana-app-sdk/resource"
|
||||
)
|
||||
|
||||
// schema is unexported to prevent accidental overwrites
|
||||
var (
|
||||
schemaPluginInstall = resource.NewSimpleSchema("plugins.grafana.app", "v0alpha1", &PluginInstall{}, &PluginInstallList{}, resource.WithKind("PluginInstall"),
|
||||
resource.WithPlural("plugininstalls"), resource.WithScope(resource.NamespacedScope))
|
||||
kindPluginInstall = resource.Kind{
|
||||
Schema: schemaPluginInstall,
|
||||
Codecs: map[resource.KindEncoding]resource.Codec{
|
||||
resource.KindEncodingJSON: &PluginInstallJSONCodec{},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
// Kind returns a resource.Kind for this Schema with a JSON codec
|
||||
func PluginInstallKind() resource.Kind {
|
||||
return kindPluginInstall
|
||||
}
|
||||
|
||||
// Schema returns a resource.SimpleSchema representation of PluginInstall
|
||||
func PluginInstallSchema() *resource.SimpleSchema {
|
||||
return schemaPluginInstall
|
||||
}
|
||||
|
||||
// Interface compliance checks
|
||||
var _ resource.Schema = kindPluginInstall
|
||||
@@ -1,25 +0,0 @@
|
||||
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
|
||||
|
||||
package v0alpha1
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginInstallSpec struct {
|
||||
Id string `json:"id"`
|
||||
Version string `json:"version"`
|
||||
Url *string `json:"url,omitempty"`
|
||||
Class PluginInstallSpecClass `json:"class"`
|
||||
}
|
||||
|
||||
// NewPluginInstallSpec creates a new PluginInstallSpec object.
|
||||
func NewPluginInstallSpec() *PluginInstallSpec {
|
||||
return &PluginInstallSpec{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginInstallSpecClass string
|
||||
|
||||
const (
|
||||
PluginInstallSpecClassCore PluginInstallSpecClass = "core"
|
||||
PluginInstallSpecClassExternal PluginInstallSpecClass = "external"
|
||||
PluginInstallSpecClassCdn PluginInstallSpecClass = "cdn"
|
||||
)
|
||||
@@ -1,44 +0,0 @@
|
||||
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
|
||||
|
||||
package v0alpha1
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginInstallstatusOperatorState struct {
|
||||
// lastEvaluation is the ResourceVersion last evaluated
|
||||
LastEvaluation string `json:"lastEvaluation"`
|
||||
// state describes the state of the lastEvaluation.
|
||||
// It is limited to three possible states for machine evaluation.
|
||||
State PluginInstallStatusOperatorStateState `json:"state"`
|
||||
// descriptiveState is an optional more descriptive state field which has no requirements on format
|
||||
DescriptiveState *string `json:"descriptiveState,omitempty"`
|
||||
// details contains any extra information that is operator-specific
|
||||
Details map[string]interface{} `json:"details,omitempty"`
|
||||
}
|
||||
|
||||
// NewPluginInstallstatusOperatorState creates a new PluginInstallstatusOperatorState object.
|
||||
func NewPluginInstallstatusOperatorState() *PluginInstallstatusOperatorState {
|
||||
return &PluginInstallstatusOperatorState{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginInstallStatus struct {
|
||||
// operatorStates is a map of operator ID to operator state evaluations.
|
||||
// Any operator which consumes this kind SHOULD add its state evaluation information to this field.
|
||||
OperatorStates map[string]PluginInstallstatusOperatorState `json:"operatorStates,omitempty"`
|
||||
// additionalFields is reserved for future use
|
||||
AdditionalFields map[string]interface{} `json:"additionalFields,omitempty"`
|
||||
}
|
||||
|
||||
// NewPluginInstallStatus creates a new PluginInstallStatus object.
|
||||
func NewPluginInstallStatus() *PluginInstallStatus {
|
||||
return &PluginInstallStatus{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginInstallStatusOperatorStateState string
|
||||
|
||||
const (
|
||||
PluginInstallStatusOperatorStateStateSuccess PluginInstallStatusOperatorStateState = "success"
|
||||
PluginInstallStatusOperatorStateStateInProgress PluginInstallStatusOperatorStateState = "in_progress"
|
||||
PluginInstallStatusOperatorStateStateFailed PluginInstallStatusOperatorStateState = "failed"
|
||||
)
|
||||
@@ -1,99 +0,0 @@
|
||||
package v0alpha1
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
type PluginMetaClient struct {
|
||||
client *resource.TypedClient[*PluginMeta, *PluginMetaList]
|
||||
}
|
||||
|
||||
func NewPluginMetaClient(client resource.Client) *PluginMetaClient {
|
||||
return &PluginMetaClient{
|
||||
client: resource.NewTypedClient[*PluginMeta, *PluginMetaList](client, PluginMetaKind()),
|
||||
}
|
||||
}
|
||||
|
||||
func NewPluginMetaClientFromGenerator(generator resource.ClientGenerator) (*PluginMetaClient, error) {
|
||||
c, err := generator.ClientFor(PluginMetaKind())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewPluginMetaClient(c), nil
|
||||
}
|
||||
|
||||
func (c *PluginMetaClient) Get(ctx context.Context, identifier resource.Identifier) (*PluginMeta, error) {
|
||||
return c.client.Get(ctx, identifier)
|
||||
}
|
||||
|
||||
func (c *PluginMetaClient) List(ctx context.Context, namespace string, opts resource.ListOptions) (*PluginMetaList, error) {
|
||||
return c.client.List(ctx, namespace, opts)
|
||||
}
|
||||
|
||||
func (c *PluginMetaClient) ListAll(ctx context.Context, namespace string, opts resource.ListOptions) (*PluginMetaList, error) {
|
||||
resp, err := c.client.List(ctx, namespace, resource.ListOptions{
|
||||
ResourceVersion: opts.ResourceVersion,
|
||||
Limit: opts.Limit,
|
||||
LabelFilters: opts.LabelFilters,
|
||||
FieldSelectors: opts.FieldSelectors,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for resp.GetContinue() != "" {
|
||||
page, err := c.client.List(ctx, namespace, resource.ListOptions{
|
||||
Continue: resp.GetContinue(),
|
||||
ResourceVersion: opts.ResourceVersion,
|
||||
Limit: opts.Limit,
|
||||
LabelFilters: opts.LabelFilters,
|
||||
FieldSelectors: opts.FieldSelectors,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp.SetContinue(page.GetContinue())
|
||||
resp.SetResourceVersion(page.GetResourceVersion())
|
||||
resp.SetItems(append(resp.GetItems(), page.GetItems()...))
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (c *PluginMetaClient) Create(ctx context.Context, obj *PluginMeta, opts resource.CreateOptions) (*PluginMeta, error) {
|
||||
// Make sure apiVersion and kind are set
|
||||
obj.APIVersion = GroupVersion.Identifier()
|
||||
obj.Kind = PluginMetaKind().Kind()
|
||||
return c.client.Create(ctx, obj, opts)
|
||||
}
|
||||
|
||||
func (c *PluginMetaClient) Update(ctx context.Context, obj *PluginMeta, opts resource.UpdateOptions) (*PluginMeta, error) {
|
||||
return c.client.Update(ctx, obj, opts)
|
||||
}
|
||||
|
||||
func (c *PluginMetaClient) Patch(ctx context.Context, identifier resource.Identifier, req resource.PatchRequest, opts resource.PatchOptions) (*PluginMeta, error) {
|
||||
return c.client.Patch(ctx, identifier, req, opts)
|
||||
}
|
||||
|
||||
func (c *PluginMetaClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus PluginMetaStatus, opts resource.UpdateOptions) (*PluginMeta, error) {
|
||||
return c.client.Update(ctx, &PluginMeta{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: PluginMetaKind().Kind(),
|
||||
APIVersion: GroupVersion.Identifier(),
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: opts.ResourceVersion,
|
||||
Namespace: identifier.Namespace,
|
||||
Name: identifier.Name,
|
||||
},
|
||||
Status: newStatus,
|
||||
}, resource.UpdateOptions{
|
||||
Subresource: "status",
|
||||
ResourceVersion: opts.ResourceVersion,
|
||||
})
|
||||
}
|
||||
|
||||
func (c *PluginMetaClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error {
|
||||
return c.client.Delete(ctx, identifier, opts)
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
//
|
||||
// Code generated by grafana-app-sdk. DO NOT EDIT.
|
||||
//
|
||||
|
||||
package v0alpha1
|
||||
|
||||
import (
|
||||
"github.com/grafana/grafana-app-sdk/resource"
|
||||
)
|
||||
|
||||
// schema is unexported to prevent accidental overwrites
|
||||
var (
|
||||
schemaPluginMeta = resource.NewSimpleSchema("plugins.grafana.app", "v0alpha1", &PluginMeta{}, &PluginMetaList{}, resource.WithKind("PluginMeta"),
|
||||
resource.WithPlural("pluginmetas"), resource.WithScope(resource.NamespacedScope))
|
||||
kindPluginMeta = resource.Kind{
|
||||
Schema: schemaPluginMeta,
|
||||
Codecs: map[resource.KindEncoding]resource.Codec{
|
||||
resource.KindEncodingJSON: &PluginMetaJSONCodec{},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
// Kind returns a resource.Kind for this Schema with a JSON codec
|
||||
func PluginMetaKind() resource.Kind {
|
||||
return kindPluginMeta
|
||||
}
|
||||
|
||||
// Schema returns a resource.SimpleSchema representation of PluginMeta
|
||||
func PluginMetaSchema() *resource.SimpleSchema {
|
||||
return schemaPluginMeta
|
||||
}
|
||||
|
||||
// Interface compliance checks
|
||||
var _ resource.Schema = kindPluginMeta
|
||||
@@ -1,477 +0,0 @@
|
||||
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
|
||||
|
||||
package v0alpha1
|
||||
|
||||
import (
|
||||
time "time"
|
||||
)
|
||||
|
||||
// JSON configuration schema for Grafana plugins
|
||||
// Converted from: https://github.com/grafana/grafana/blob/main/docs/sources/developers/plugins/plugin.schema.json
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginMetaJSONData struct {
|
||||
// Unique name of the plugin
|
||||
Id string `json:"id"`
|
||||
// Plugin type
|
||||
Type PluginMetaJSONDataType `json:"type"`
|
||||
// Human-readable name of the plugin
|
||||
Name string `json:"name"`
|
||||
// Metadata for the plugin
|
||||
Info PluginMetaInfo `json:"info"`
|
||||
// Dependency information
|
||||
Dependencies PluginMetaDependencies `json:"dependencies"`
|
||||
// Optional fields
|
||||
Alerting *bool `json:"alerting,omitempty"`
|
||||
Annotations *bool `json:"annotations,omitempty"`
|
||||
AutoEnabled *bool `json:"autoEnabled,omitempty"`
|
||||
Backend *bool `json:"backend,omitempty"`
|
||||
BuildMode *string `json:"buildMode,omitempty"`
|
||||
BuiltIn *bool `json:"builtIn,omitempty"`
|
||||
Category *PluginMetaJSONDataCategory `json:"category,omitempty"`
|
||||
EnterpriseFeatures *PluginMetaEnterpriseFeatures `json:"enterpriseFeatures,omitempty"`
|
||||
Executable *string `json:"executable,omitempty"`
|
||||
HideFromList *bool `json:"hideFromList,omitempty"`
|
||||
// +listType=atomic
|
||||
Includes []PluginMetaInclude `json:"includes,omitempty"`
|
||||
Logs *bool `json:"logs,omitempty"`
|
||||
Metrics *bool `json:"metrics,omitempty"`
|
||||
MultiValueFilterOperators *bool `json:"multiValueFilterOperators,omitempty"`
|
||||
PascalName *string `json:"pascalName,omitempty"`
|
||||
Preload *bool `json:"preload,omitempty"`
|
||||
QueryOptions *PluginMetaQueryOptions `json:"queryOptions,omitempty"`
|
||||
// +listType=atomic
|
||||
Routes []PluginMetaRoute `json:"routes,omitempty"`
|
||||
SkipDataQuery *bool `json:"skipDataQuery,omitempty"`
|
||||
State *PluginMetaJSONDataState `json:"state,omitempty"`
|
||||
Streaming *bool `json:"streaming,omitempty"`
|
||||
Tracing *bool `json:"tracing,omitempty"`
|
||||
Iam *PluginMetaIAM `json:"iam,omitempty"`
|
||||
// +listType=atomic
|
||||
Roles []PluginMetaRole `json:"roles,omitempty"`
|
||||
Extensions *PluginMetaExtensions `json:"extensions,omitempty"`
|
||||
}
|
||||
|
||||
// NewPluginMetaJSONData creates a new PluginMetaJSONData object.
|
||||
func NewPluginMetaJSONData() *PluginMetaJSONData {
|
||||
return &PluginMetaJSONData{
|
||||
Info: *NewPluginMetaInfo(),
|
||||
Dependencies: *NewPluginMetaDependencies(),
|
||||
}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginMetaInfo struct {
|
||||
// Required fields
|
||||
// +listType=set
|
||||
Keywords []string `json:"keywords"`
|
||||
Logos PluginMetaV0alpha1InfoLogos `json:"logos"`
|
||||
Updated time.Time `json:"updated"`
|
||||
Version string `json:"version"`
|
||||
// Optional fields
|
||||
Author *PluginMetaV0alpha1InfoAuthor `json:"author,omitempty"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
// +listType=atomic
|
||||
Links []PluginMetaV0alpha1InfoLinks `json:"links,omitempty"`
|
||||
// +listType=atomic
|
||||
Screenshots []PluginMetaV0alpha1InfoScreenshots `json:"screenshots,omitempty"`
|
||||
}
|
||||
|
||||
// NewPluginMetaInfo creates a new PluginMetaInfo object.
|
||||
func NewPluginMetaInfo() *PluginMetaInfo {
|
||||
return &PluginMetaInfo{
|
||||
Keywords: []string{},
|
||||
Logos: *NewPluginMetaV0alpha1InfoLogos(),
|
||||
}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginMetaDependencies struct {
|
||||
// Required field
|
||||
GrafanaDependency string `json:"grafanaDependency"`
|
||||
// Optional fields
|
||||
GrafanaVersion *string `json:"grafanaVersion,omitempty"`
|
||||
// +listType=set
|
||||
// +listMapKey=id
|
||||
Plugins []PluginMetaV0alpha1DependenciesPlugins `json:"plugins,omitempty"`
|
||||
Extensions *PluginMetaV0alpha1DependenciesExtensions `json:"extensions,omitempty"`
|
||||
}
|
||||
|
||||
// NewPluginMetaDependencies creates a new PluginMetaDependencies object.
|
||||
func NewPluginMetaDependencies() *PluginMetaDependencies {
|
||||
return &PluginMetaDependencies{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginMetaEnterpriseFeatures struct {
|
||||
// Allow additional properties
|
||||
HealthDiagnosticsErrors *bool `json:"healthDiagnosticsErrors,omitempty"`
|
||||
}
|
||||
|
||||
// NewPluginMetaEnterpriseFeatures creates a new PluginMetaEnterpriseFeatures object.
|
||||
func NewPluginMetaEnterpriseFeatures() *PluginMetaEnterpriseFeatures {
|
||||
return &PluginMetaEnterpriseFeatures{
|
||||
HealthDiagnosticsErrors: (func(input bool) *bool { return &input })(false),
|
||||
}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginMetaInclude struct {
|
||||
Uid *string `json:"uid,omitempty"`
|
||||
Type *PluginMetaIncludeType `json:"type,omitempty"`
|
||||
Name *string `json:"name,omitempty"`
|
||||
Component *string `json:"component,omitempty"`
|
||||
Role *PluginMetaIncludeRole `json:"role,omitempty"`
|
||||
Action *string `json:"action,omitempty"`
|
||||
Path *string `json:"path,omitempty"`
|
||||
AddToNav *bool `json:"addToNav,omitempty"`
|
||||
DefaultNav *bool `json:"defaultNav,omitempty"`
|
||||
Icon *string `json:"icon,omitempty"`
|
||||
}
|
||||
|
||||
// NewPluginMetaInclude creates a new PluginMetaInclude object.
|
||||
func NewPluginMetaInclude() *PluginMetaInclude {
|
||||
return &PluginMetaInclude{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginMetaQueryOptions struct {
|
||||
MaxDataPoints *bool `json:"maxDataPoints,omitempty"`
|
||||
MinInterval *bool `json:"minInterval,omitempty"`
|
||||
CacheTimeout *bool `json:"cacheTimeout,omitempty"`
|
||||
}
|
||||
|
||||
// NewPluginMetaQueryOptions creates a new PluginMetaQueryOptions object.
|
||||
func NewPluginMetaQueryOptions() *PluginMetaQueryOptions {
|
||||
return &PluginMetaQueryOptions{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginMetaRoute struct {
|
||||
Path *string `json:"path,omitempty"`
|
||||
Method *string `json:"method,omitempty"`
|
||||
Url *string `json:"url,omitempty"`
|
||||
ReqSignedIn *bool `json:"reqSignedIn,omitempty"`
|
||||
ReqRole *string `json:"reqRole,omitempty"`
|
||||
ReqAction *string `json:"reqAction,omitempty"`
|
||||
// +listType=atomic
|
||||
Headers []string `json:"headers,omitempty"`
|
||||
Body map[string]interface{} `json:"body,omitempty"`
|
||||
TokenAuth *PluginMetaV0alpha1RouteTokenAuth `json:"tokenAuth,omitempty"`
|
||||
JwtTokenAuth *PluginMetaV0alpha1RouteJwtTokenAuth `json:"jwtTokenAuth,omitempty"`
|
||||
// +listType=atomic
|
||||
UrlParams []PluginMetaV0alpha1RouteUrlParams `json:"urlParams,omitempty"`
|
||||
}
|
||||
|
||||
// NewPluginMetaRoute creates a new PluginMetaRoute object.
|
||||
func NewPluginMetaRoute() *PluginMetaRoute {
|
||||
return &PluginMetaRoute{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginMetaIAM struct {
|
||||
// +listType=atomic
|
||||
Permissions []PluginMetaV0alpha1IAMPermissions `json:"permissions,omitempty"`
|
||||
}
|
||||
|
||||
// NewPluginMetaIAM creates a new PluginMetaIAM object.
|
||||
func NewPluginMetaIAM() *PluginMetaIAM {
|
||||
return &PluginMetaIAM{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginMetaRole struct {
|
||||
Role *PluginMetaV0alpha1RoleRole `json:"role,omitempty"`
|
||||
// +listType=set
|
||||
Grants []string `json:"grants,omitempty"`
|
||||
}
|
||||
|
||||
// NewPluginMetaRole creates a new PluginMetaRole object.
|
||||
func NewPluginMetaRole() *PluginMetaRole {
|
||||
return &PluginMetaRole{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginMetaExtensions struct {
|
||||
// +listType=atomic
|
||||
AddedComponents []PluginMetaV0alpha1ExtensionsAddedComponents `json:"addedComponents,omitempty"`
|
||||
// +listType=atomic
|
||||
AddedLinks []PluginMetaV0alpha1ExtensionsAddedLinks `json:"addedLinks,omitempty"`
|
||||
// +listType=set
|
||||
// +listMapKey=id
|
||||
ExposedComponents []PluginMetaV0alpha1ExtensionsExposedComponents `json:"exposedComponents,omitempty"`
|
||||
// +listType=set
|
||||
// +listMapKey=id
|
||||
ExtensionPoints []PluginMetaV0alpha1ExtensionsExtensionPoints `json:"extensionPoints,omitempty"`
|
||||
}
|
||||
|
||||
// NewPluginMetaExtensions creates a new PluginMetaExtensions object.
|
||||
func NewPluginMetaExtensions() *PluginMetaExtensions {
|
||||
return &PluginMetaExtensions{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginMetaSpec struct {
|
||||
PluginJSON PluginMetaJSONData `json:"pluginJSON"`
|
||||
}
|
||||
|
||||
// NewPluginMetaSpec creates a new PluginMetaSpec object.
|
||||
func NewPluginMetaSpec() *PluginMetaSpec {
|
||||
return &PluginMetaSpec{
|
||||
PluginJSON: *NewPluginMetaJSONData(),
|
||||
}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginMetaV0alpha1InfoLogos struct {
|
||||
Small string `json:"small"`
|
||||
Large string `json:"large"`
|
||||
}
|
||||
|
||||
// NewPluginMetaV0alpha1InfoLogos creates a new PluginMetaV0alpha1InfoLogos object.
|
||||
func NewPluginMetaV0alpha1InfoLogos() *PluginMetaV0alpha1InfoLogos {
|
||||
return &PluginMetaV0alpha1InfoLogos{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginMetaV0alpha1InfoAuthor struct {
|
||||
Name *string `json:"name,omitempty"`
|
||||
Email *string `json:"email,omitempty"`
|
||||
Url *string `json:"url,omitempty"`
|
||||
}
|
||||
|
||||
// NewPluginMetaV0alpha1InfoAuthor creates a new PluginMetaV0alpha1InfoAuthor object.
|
||||
func NewPluginMetaV0alpha1InfoAuthor() *PluginMetaV0alpha1InfoAuthor {
|
||||
return &PluginMetaV0alpha1InfoAuthor{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginMetaV0alpha1InfoLinks struct {
|
||||
Name *string `json:"name,omitempty"`
|
||||
Url *string `json:"url,omitempty"`
|
||||
}
|
||||
|
||||
// NewPluginMetaV0alpha1InfoLinks creates a new PluginMetaV0alpha1InfoLinks object.
|
||||
func NewPluginMetaV0alpha1InfoLinks() *PluginMetaV0alpha1InfoLinks {
|
||||
return &PluginMetaV0alpha1InfoLinks{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginMetaV0alpha1InfoScreenshots struct {
|
||||
Name *string `json:"name,omitempty"`
|
||||
Path *string `json:"path,omitempty"`
|
||||
}
|
||||
|
||||
// NewPluginMetaV0alpha1InfoScreenshots creates a new PluginMetaV0alpha1InfoScreenshots object.
|
||||
func NewPluginMetaV0alpha1InfoScreenshots() *PluginMetaV0alpha1InfoScreenshots {
|
||||
return &PluginMetaV0alpha1InfoScreenshots{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginMetaV0alpha1DependenciesPlugins struct {
|
||||
Id string `json:"id"`
|
||||
Type PluginMetaV0alpha1DependenciesPluginsType `json:"type"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// NewPluginMetaV0alpha1DependenciesPlugins creates a new PluginMetaV0alpha1DependenciesPlugins object.
|
||||
func NewPluginMetaV0alpha1DependenciesPlugins() *PluginMetaV0alpha1DependenciesPlugins {
|
||||
return &PluginMetaV0alpha1DependenciesPlugins{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginMetaV0alpha1DependenciesExtensions struct {
|
||||
// +listType=set
|
||||
ExposedComponents []string `json:"exposedComponents,omitempty"`
|
||||
}
|
||||
|
||||
// NewPluginMetaV0alpha1DependenciesExtensions creates a new PluginMetaV0alpha1DependenciesExtensions object.
|
||||
func NewPluginMetaV0alpha1DependenciesExtensions() *PluginMetaV0alpha1DependenciesExtensions {
|
||||
return &PluginMetaV0alpha1DependenciesExtensions{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginMetaV0alpha1RouteTokenAuth struct {
|
||||
Url *string `json:"url,omitempty"`
|
||||
// +listType=set
|
||||
Scopes []string `json:"scopes,omitempty"`
|
||||
Params map[string]interface{} `json:"params,omitempty"`
|
||||
}
|
||||
|
||||
// NewPluginMetaV0alpha1RouteTokenAuth creates a new PluginMetaV0alpha1RouteTokenAuth object.
|
||||
func NewPluginMetaV0alpha1RouteTokenAuth() *PluginMetaV0alpha1RouteTokenAuth {
|
||||
return &PluginMetaV0alpha1RouteTokenAuth{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginMetaV0alpha1RouteJwtTokenAuth struct {
|
||||
Url *string `json:"url,omitempty"`
|
||||
// +listType=set
|
||||
Scopes []string `json:"scopes,omitempty"`
|
||||
Params map[string]interface{} `json:"params,omitempty"`
|
||||
}
|
||||
|
||||
// NewPluginMetaV0alpha1RouteJwtTokenAuth creates a new PluginMetaV0alpha1RouteJwtTokenAuth object.
|
||||
func NewPluginMetaV0alpha1RouteJwtTokenAuth() *PluginMetaV0alpha1RouteJwtTokenAuth {
|
||||
return &PluginMetaV0alpha1RouteJwtTokenAuth{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginMetaV0alpha1RouteUrlParams struct {
|
||||
Name *string `json:"name,omitempty"`
|
||||
Content *string `json:"content,omitempty"`
|
||||
}
|
||||
|
||||
// NewPluginMetaV0alpha1RouteUrlParams creates a new PluginMetaV0alpha1RouteUrlParams object.
|
||||
func NewPluginMetaV0alpha1RouteUrlParams() *PluginMetaV0alpha1RouteUrlParams {
|
||||
return &PluginMetaV0alpha1RouteUrlParams{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginMetaV0alpha1IAMPermissions struct {
|
||||
Action *string `json:"action,omitempty"`
|
||||
Scope *string `json:"scope,omitempty"`
|
||||
}
|
||||
|
||||
// NewPluginMetaV0alpha1IAMPermissions creates a new PluginMetaV0alpha1IAMPermissions object.
|
||||
func NewPluginMetaV0alpha1IAMPermissions() *PluginMetaV0alpha1IAMPermissions {
|
||||
return &PluginMetaV0alpha1IAMPermissions{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginMetaV0alpha1RoleRolePermissions struct {
|
||||
Action *string `json:"action,omitempty"`
|
||||
Scope *string `json:"scope,omitempty"`
|
||||
}
|
||||
|
||||
// NewPluginMetaV0alpha1RoleRolePermissions creates a new PluginMetaV0alpha1RoleRolePermissions object.
|
||||
func NewPluginMetaV0alpha1RoleRolePermissions() *PluginMetaV0alpha1RoleRolePermissions {
|
||||
return &PluginMetaV0alpha1RoleRolePermissions{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginMetaV0alpha1RoleRole struct {
|
||||
Name *string `json:"name,omitempty"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
// +listType=atomic
|
||||
Permissions []PluginMetaV0alpha1RoleRolePermissions `json:"permissions,omitempty"`
|
||||
}
|
||||
|
||||
// NewPluginMetaV0alpha1RoleRole creates a new PluginMetaV0alpha1RoleRole object.
|
||||
func NewPluginMetaV0alpha1RoleRole() *PluginMetaV0alpha1RoleRole {
|
||||
return &PluginMetaV0alpha1RoleRole{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginMetaV0alpha1ExtensionsAddedComponents struct {
|
||||
// +listType=set
|
||||
Targets []string `json:"targets"`
|
||||
Title string `json:"title"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
}
|
||||
|
||||
// NewPluginMetaV0alpha1ExtensionsAddedComponents creates a new PluginMetaV0alpha1ExtensionsAddedComponents object.
|
||||
func NewPluginMetaV0alpha1ExtensionsAddedComponents() *PluginMetaV0alpha1ExtensionsAddedComponents {
|
||||
return &PluginMetaV0alpha1ExtensionsAddedComponents{
|
||||
Targets: []string{},
|
||||
}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginMetaV0alpha1ExtensionsAddedLinks struct {
|
||||
// +listType=set
|
||||
Targets []string `json:"targets"`
|
||||
Title string `json:"title"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
}
|
||||
|
||||
// NewPluginMetaV0alpha1ExtensionsAddedLinks creates a new PluginMetaV0alpha1ExtensionsAddedLinks object.
|
||||
func NewPluginMetaV0alpha1ExtensionsAddedLinks() *PluginMetaV0alpha1ExtensionsAddedLinks {
|
||||
return &PluginMetaV0alpha1ExtensionsAddedLinks{
|
||||
Targets: []string{},
|
||||
}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginMetaV0alpha1ExtensionsExposedComponents struct {
|
||||
Id string `json:"id"`
|
||||
Title *string `json:"title,omitempty"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
}
|
||||
|
||||
// NewPluginMetaV0alpha1ExtensionsExposedComponents creates a new PluginMetaV0alpha1ExtensionsExposedComponents object.
|
||||
func NewPluginMetaV0alpha1ExtensionsExposedComponents() *PluginMetaV0alpha1ExtensionsExposedComponents {
|
||||
return &PluginMetaV0alpha1ExtensionsExposedComponents{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginMetaV0alpha1ExtensionsExtensionPoints struct {
|
||||
Id string `json:"id"`
|
||||
Title *string `json:"title,omitempty"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
}
|
||||
|
||||
// NewPluginMetaV0alpha1ExtensionsExtensionPoints creates a new PluginMetaV0alpha1ExtensionsExtensionPoints object.
|
||||
func NewPluginMetaV0alpha1ExtensionsExtensionPoints() *PluginMetaV0alpha1ExtensionsExtensionPoints {
|
||||
return &PluginMetaV0alpha1ExtensionsExtensionPoints{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginMetaJSONDataType string
|
||||
|
||||
const (
|
||||
PluginMetaJSONDataTypeApp PluginMetaJSONDataType = "app"
|
||||
PluginMetaJSONDataTypeDatasource PluginMetaJSONDataType = "datasource"
|
||||
PluginMetaJSONDataTypePanel PluginMetaJSONDataType = "panel"
|
||||
PluginMetaJSONDataTypeRenderer PluginMetaJSONDataType = "renderer"
|
||||
)
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginMetaJSONDataCategory string
|
||||
|
||||
const (
|
||||
PluginMetaJSONDataCategoryTsdb PluginMetaJSONDataCategory = "tsdb"
|
||||
PluginMetaJSONDataCategoryLogging PluginMetaJSONDataCategory = "logging"
|
||||
PluginMetaJSONDataCategoryCloud PluginMetaJSONDataCategory = "cloud"
|
||||
PluginMetaJSONDataCategoryTracing PluginMetaJSONDataCategory = "tracing"
|
||||
PluginMetaJSONDataCategoryProfiling PluginMetaJSONDataCategory = "profiling"
|
||||
PluginMetaJSONDataCategorySql PluginMetaJSONDataCategory = "sql"
|
||||
PluginMetaJSONDataCategoryEnterprise PluginMetaJSONDataCategory = "enterprise"
|
||||
PluginMetaJSONDataCategoryIot PluginMetaJSONDataCategory = "iot"
|
||||
PluginMetaJSONDataCategoryOther PluginMetaJSONDataCategory = "other"
|
||||
)
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginMetaJSONDataState string
|
||||
|
||||
const (
|
||||
PluginMetaJSONDataStateAlpha PluginMetaJSONDataState = "alpha"
|
||||
PluginMetaJSONDataStateBeta PluginMetaJSONDataState = "beta"
|
||||
)
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginMetaIncludeType string
|
||||
|
||||
const (
|
||||
PluginMetaIncludeTypeDashboard PluginMetaIncludeType = "dashboard"
|
||||
PluginMetaIncludeTypePage PluginMetaIncludeType = "page"
|
||||
PluginMetaIncludeTypePanel PluginMetaIncludeType = "panel"
|
||||
PluginMetaIncludeTypeDatasource PluginMetaIncludeType = "datasource"
|
||||
)
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginMetaIncludeRole string
|
||||
|
||||
const (
|
||||
PluginMetaIncludeRoleAdmin PluginMetaIncludeRole = "Admin"
|
||||
PluginMetaIncludeRoleEditor PluginMetaIncludeRole = "Editor"
|
||||
PluginMetaIncludeRoleViewer PluginMetaIncludeRole = "Viewer"
|
||||
)
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PluginMetaV0alpha1DependenciesPluginsType string
|
||||
|
||||
const (
|
||||
PluginMetaV0alpha1DependenciesPluginsTypeApp PluginMetaV0alpha1DependenciesPluginsType = "app"
|
||||
PluginMetaV0alpha1DependenciesPluginsTypeDatasource PluginMetaV0alpha1DependenciesPluginsType = "datasource"
|
||||
PluginMetaV0alpha1DependenciesPluginsTypePanel PluginMetaV0alpha1DependenciesPluginsType = "panel"
|
||||
)
|
||||
File diff suppressed because one or more lines are too long
@@ -2,8 +2,11 @@ package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/app"
|
||||
"github.com/grafana/grafana-app-sdk/k8s"
|
||||
"github.com/grafana/grafana-app-sdk/logging"
|
||||
"github.com/grafana/grafana-app-sdk/operator"
|
||||
"github.com/grafana/grafana-app-sdk/resource"
|
||||
"github.com/grafana/grafana-app-sdk/simple"
|
||||
@@ -11,16 +14,15 @@ import (
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
pluginsapi "github.com/grafana/grafana/apps/plugins/pkg/apis"
|
||||
pluginsv0alpha1 "github.com/grafana/grafana/apps/plugins/pkg/apis/plugins/v0alpha1"
|
||||
)
|
||||
|
||||
func New(cfg app.Config) (app.App, error) {
|
||||
managedKinds := []simple.AppManagedKind{}
|
||||
for _, kinds := range GetKinds() {
|
||||
for _, k := range kinds {
|
||||
managedKinds = append(managedKinds, simple.AppManagedKind{
|
||||
Kind: k,
|
||||
})
|
||||
}
|
||||
cfg.KubeConfig.APIPath = "apis"
|
||||
clientGenerator := k8s.NewClientRegistry(cfg.KubeConfig, k8s.DefaultClientConfig())
|
||||
client, err := pluginsv0alpha1.NewPluginClientFromGenerator(clientGenerator)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
simpleConfig := simple.AppConfig{
|
||||
@@ -33,7 +35,32 @@ func New(cfg app.Config) (app.App, error) {
|
||||
},
|
||||
},
|
||||
},
|
||||
ManagedKinds: managedKinds,
|
||||
ManagedKinds: []simple.AppManagedKind{
|
||||
{
|
||||
Kind: pluginsv0alpha1.PluginKind(),
|
||||
CustomRoutes: simple.AppCustomRouteHandlers{
|
||||
simple.AppCustomRoute{
|
||||
Method: http.MethodGet,
|
||||
Path: "meta",
|
||||
}: func(ctx context.Context, w app.CustomRouteResponseWriter, req *app.CustomRouteRequest) error {
|
||||
plugin, err := client.Get(ctx, resource.Identifier{
|
||||
Namespace: req.ResourceIdentifier.Namespace,
|
||||
Name: req.ResourceIdentifier.Name,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logging.DefaultLogger.Debug("fetched plugin", "plugin", plugin)
|
||||
// TODO: Implement this in future PR
|
||||
w.WriteHeader(http.StatusNotImplemented)
|
||||
if _, err := w.Write([]byte("Not implemented")); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
a, err := simple.NewApp(simpleConfig)
|
||||
|
||||
@@ -41,12 +41,12 @@ type PluginInstall struct {
|
||||
Source Source
|
||||
}
|
||||
|
||||
func (p *PluginInstall) ToPluginInstallV0Alpha1(namespace string) *pluginsv0alpha1.PluginInstall {
|
||||
func (p *PluginInstall) ToPluginInstallV0Alpha1(namespace string) *pluginsv0alpha1.Plugin {
|
||||
var url *string = nil
|
||||
if p.URL != "" {
|
||||
url = &p.URL
|
||||
}
|
||||
return &pluginsv0alpha1.PluginInstall{
|
||||
return &pluginsv0alpha1.Plugin{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: namespace,
|
||||
Name: p.ID,
|
||||
@@ -54,16 +54,16 @@ func (p *PluginInstall) ToPluginInstallV0Alpha1(namespace string) *pluginsv0alph
|
||||
PluginInstallSourceAnnotation: p.Source,
|
||||
},
|
||||
},
|
||||
Spec: pluginsv0alpha1.PluginInstallSpec{
|
||||
Spec: pluginsv0alpha1.PluginSpec{
|
||||
Id: p.ID,
|
||||
Version: p.Version,
|
||||
Url: url,
|
||||
Class: pluginsv0alpha1.PluginInstallSpecClass(p.Class),
|
||||
Class: pluginsv0alpha1.PluginSpecClass(p.Class),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PluginInstall) ShouldUpdate(existing *pluginsv0alpha1.PluginInstall) bool {
|
||||
func (p *PluginInstall) ShouldUpdate(existing *pluginsv0alpha1.Plugin) bool {
|
||||
update := p.ToPluginInstallV0Alpha1(existing.Namespace)
|
||||
if source, ok := existing.Annotations[PluginInstallSourceAnnotation]; ok && source != p.Source {
|
||||
return true
|
||||
@@ -92,7 +92,7 @@ func equalStringPointers(a, b *string) bool {
|
||||
|
||||
type InstallRegistrar struct {
|
||||
clientGenerator resource.ClientGenerator
|
||||
client *pluginsv0alpha1.PluginInstallClient
|
||||
client *pluginsv0alpha1.PluginClient
|
||||
clientOnce sync.Once
|
||||
}
|
||||
|
||||
@@ -103,9 +103,9 @@ func NewInstallRegistrar(clientGenerator resource.ClientGenerator) *InstallRegis
|
||||
}
|
||||
}
|
||||
|
||||
func (r *InstallRegistrar) GetClient() (*pluginsv0alpha1.PluginInstallClient, error) {
|
||||
func (r *InstallRegistrar) GetClient() (*pluginsv0alpha1.PluginClient, error) {
|
||||
r.clientOnce.Do(func() {
|
||||
client, err := pluginsv0alpha1.NewPluginInstallClientFromGenerator(r.clientGenerator)
|
||||
client, err := pluginsv0alpha1.NewPluginClientFromGenerator(r.clientGenerator)
|
||||
if err != nil {
|
||||
r.client = nil
|
||||
return
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/internalversion"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apiserver/pkg/registry/rest"
|
||||
|
||||
claims "github.com/grafana/authlib/types"
|
||||
pluginsv0alpha1 "github.com/grafana/grafana/apps/plugins/pkg/apis/plugins/v0alpha1"
|
||||
)
|
||||
|
||||
var (
|
||||
_ rest.Scoper = (*PluginMetaStorage)(nil)
|
||||
_ rest.SingularNameProvider = (*PluginMetaStorage)(nil)
|
||||
_ rest.Getter = (*PluginMetaStorage)(nil)
|
||||
_ rest.Lister = (*PluginMetaStorage)(nil)
|
||||
_ rest.Storage = (*PluginMetaStorage)(nil)
|
||||
_ rest.TableConvertor = (*PluginMetaStorage)(nil)
|
||||
)
|
||||
|
||||
type PluginMetaStorage struct {
|
||||
gr schema.GroupResource
|
||||
namespacer claims.NamespaceFormatter
|
||||
tableConverter rest.TableConvertor
|
||||
}
|
||||
|
||||
func NewPluginMetaStorage(
|
||||
namespacer claims.NamespaceFormatter,
|
||||
) *PluginMetaStorage {
|
||||
gr := schema.GroupResource{
|
||||
Group: pluginsv0alpha1.PluginMetaKind().Group(),
|
||||
Resource: strings.ToLower(pluginsv0alpha1.PluginMetaKind().Plural()),
|
||||
}
|
||||
return &PluginMetaStorage{
|
||||
gr: gr,
|
||||
namespacer: namespacer,
|
||||
tableConverter: rest.NewDefaultTableConvertor(gr),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *PluginMetaStorage) New() runtime.Object {
|
||||
return pluginsv0alpha1.PluginMetaKind().ZeroValue()
|
||||
}
|
||||
|
||||
func (s *PluginMetaStorage) Destroy() {}
|
||||
|
||||
func (s *PluginMetaStorage) NamespaceScoped() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *PluginMetaStorage) GetSingularName() string {
|
||||
return strings.ToLower(pluginsv0alpha1.PluginMetaKind().Kind())
|
||||
}
|
||||
|
||||
func (s *PluginMetaStorage) NewList() runtime.Object {
|
||||
return pluginsv0alpha1.PluginMetaKind().ZeroListValue()
|
||||
}
|
||||
|
||||
func (s *PluginMetaStorage) ConvertToTable(ctx context.Context, object runtime.Object, tableOptions runtime.Object) (*metav1.Table, error) {
|
||||
return s.tableConverter.ConvertToTable(ctx, object, tableOptions)
|
||||
}
|
||||
|
||||
func (s *PluginMetaStorage) List(ctx context.Context, options *internalversion.ListOptions) (runtime.Object, error) {
|
||||
return s.NewList(), nil
|
||||
}
|
||||
|
||||
func (s *PluginMetaStorage) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) {
|
||||
return nil, apierrors.NewNotFound(s.gr, name)
|
||||
}
|
||||
@@ -1,20 +1,15 @@
|
||||
package plugins
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||
"k8s.io/apiserver/pkg/registry/generic"
|
||||
"k8s.io/apiserver/pkg/registry/rest"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/app"
|
||||
appsdkapiserver "github.com/grafana/grafana-app-sdk/k8s/apiserver"
|
||||
"github.com/grafana/grafana-app-sdk/simple"
|
||||
pluginsappapis "github.com/grafana/grafana/apps/plugins/pkg/apis"
|
||||
pluginsv0alpha1 "github.com/grafana/grafana/apps/plugins/pkg/apis/plugins/v0alpha1"
|
||||
pluginsapp "github.com/grafana/grafana/apps/plugins/pkg/app"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver/appinstaller"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
@@ -26,16 +21,13 @@ var (
|
||||
|
||||
type PluginsAppInstaller struct {
|
||||
appsdkapiserver.AppInstaller
|
||||
cfg *setting.Cfg
|
||||
}
|
||||
|
||||
func RegisterAppInstaller(
|
||||
cfg *setting.Cfg,
|
||||
features featuremgmt.FeatureToggles,
|
||||
) (*PluginsAppInstaller, error) {
|
||||
installer := &PluginsAppInstaller{
|
||||
cfg: cfg,
|
||||
}
|
||||
installer := &PluginsAppInstaller{}
|
||||
specificConfig := any(nil)
|
||||
provider := simple.NewAppProvider(pluginsappapis.LocalManifest(), specificConfig, pluginsapp.New)
|
||||
appConfig := app.Config{
|
||||
@@ -51,21 +43,6 @@ func RegisterAppInstaller(
|
||||
return installer, nil
|
||||
}
|
||||
|
||||
func (p *PluginsAppInstaller) InstallAPIs(
|
||||
server appsdkapiserver.GenericAPIServer,
|
||||
restOptsGetter generic.RESTOptionsGetter,
|
||||
) error {
|
||||
pluginMetaGVR := pluginsv0alpha1.PluginMetaKind().GroupVersionResource()
|
||||
replacedStorage := map[schema.GroupVersionResource]rest.Storage{
|
||||
pluginMetaGVR: pluginsapp.NewPluginMetaStorage(request.GetNamespaceMapper(p.cfg)),
|
||||
}
|
||||
wrappedServer := &customStorageWrapper{
|
||||
wrapped: server,
|
||||
replace: replacedStorage,
|
||||
}
|
||||
return p.AppInstaller.InstallAPIs(wrappedServer, restOptsGetter)
|
||||
}
|
||||
|
||||
// GetAuthorizer returns the authorizer for the plugins app.
|
||||
func (p *PluginsAppInstaller) GetAuthorizer() authorizer.Authorizer {
|
||||
return pluginsapp.GetAuthorizer()
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/logging"
|
||||
"github.com/grafana/grafana-app-sdk/resource"
|
||||
|
||||
"github.com/grafana/grafana/apps/plugins/pkg/app/install"
|
||||
@@ -90,6 +91,11 @@ func (s *syncer) Sync(ctx context.Context, source install.Source, installedPlugi
|
||||
return nil
|
||||
}
|
||||
|
||||
if !s.featureToggles.IsEnabled(ctx, featuremgmt.FlagPluginStoreServiceLoading) {
|
||||
logging.DefaultLogger.Warn("pluginInstallAPISync is enabled, but pluginStoreServiceLoading is disabled. skipping plugin sync.")
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(installedPlugins) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -20,234 +20,68 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/org/orgtest"
|
||||
)
|
||||
|
||||
// Test helpers to avoid import cycles
|
||||
type fakeServerLock struct {
|
||||
lockFunc func(ctx context.Context, actionName string, maxInterval time.Duration, fn func(ctx context.Context)) error
|
||||
}
|
||||
|
||||
func (f *fakeServerLock) LockExecuteAndRelease(ctx context.Context, actionName string, maxInterval time.Duration, fn func(ctx context.Context)) error {
|
||||
if f.lockFunc != nil {
|
||||
return f.lockFunc(ctx, actionName, maxInterval, fn)
|
||||
}
|
||||
fn(ctx)
|
||||
return nil
|
||||
}
|
||||
|
||||
type fakePluginInstallClient struct {
|
||||
listAllFunc func(ctx context.Context, namespace string, opts resource.ListOptions) (*pluginsv0alpha1.PluginInstallList, error)
|
||||
getFunc func(ctx context.Context, identifier resource.Identifier) (*pluginsv0alpha1.PluginInstall, error)
|
||||
createFunc func(ctx context.Context, obj *pluginsv0alpha1.PluginInstall, opts resource.CreateOptions) (*pluginsv0alpha1.PluginInstall, error)
|
||||
updateFunc func(ctx context.Context, obj *pluginsv0alpha1.PluginInstall, opts resource.UpdateOptions) (*pluginsv0alpha1.PluginInstall, error)
|
||||
deleteFunc func(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error
|
||||
}
|
||||
|
||||
func (f *fakePluginInstallClient) Get(ctx context.Context, identifier resource.Identifier) (*pluginsv0alpha1.PluginInstall, error) {
|
||||
if f.getFunc != nil {
|
||||
return f.getFunc(ctx, identifier)
|
||||
}
|
||||
// Return a proper k8s NotFound error
|
||||
return nil, errorsK8s.NewNotFound(schema.GroupResource{
|
||||
Group: pluginsv0alpha1.APIGroup,
|
||||
Resource: "plugininstalls",
|
||||
}, identifier.Name)
|
||||
}
|
||||
|
||||
func (f *fakePluginInstallClient) ListAll(ctx context.Context, namespace string, opts resource.ListOptions) (*pluginsv0alpha1.PluginInstallList, error) {
|
||||
if f.listAllFunc != nil {
|
||||
return f.listAllFunc(ctx, namespace, opts)
|
||||
}
|
||||
return &pluginsv0alpha1.PluginInstallList{}, nil
|
||||
}
|
||||
|
||||
func (f *fakePluginInstallClient) List(ctx context.Context, namespace string, opts resource.ListOptions) (*pluginsv0alpha1.PluginInstallList, error) {
|
||||
return f.ListAll(ctx, namespace, opts)
|
||||
}
|
||||
|
||||
func (f *fakePluginInstallClient) Create(ctx context.Context, obj *pluginsv0alpha1.PluginInstall, opts resource.CreateOptions) (*pluginsv0alpha1.PluginInstall, error) {
|
||||
if f.createFunc != nil {
|
||||
return f.createFunc(ctx, obj, opts)
|
||||
}
|
||||
return obj, nil
|
||||
}
|
||||
|
||||
func (f *fakePluginInstallClient) Update(ctx context.Context, obj *pluginsv0alpha1.PluginInstall, opts resource.UpdateOptions) (*pluginsv0alpha1.PluginInstall, error) {
|
||||
if f.updateFunc != nil {
|
||||
return f.updateFunc(ctx, obj, opts)
|
||||
}
|
||||
return obj, nil
|
||||
}
|
||||
|
||||
func (f *fakePluginInstallClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus pluginsv0alpha1.PluginInstallStatus, opts resource.UpdateOptions) (*pluginsv0alpha1.PluginInstall, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (f *fakePluginInstallClient) Patch(ctx context.Context, identifier resource.Identifier, req resource.PatchRequest, opts resource.PatchOptions) (*pluginsv0alpha1.PluginInstall, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (f *fakePluginInstallClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error {
|
||||
if f.deleteFunc != nil {
|
||||
return f.deleteFunc(ctx, identifier, opts)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type fakeClientGenerator struct {
|
||||
client *fakePluginInstallClient
|
||||
}
|
||||
|
||||
func (f *fakeClientGenerator) ClientFor(kind resource.Kind) (resource.Client, error) {
|
||||
return &fakeResourceClient{client: f.client}, nil
|
||||
}
|
||||
|
||||
type fakeResourceClient struct {
|
||||
client *fakePluginInstallClient
|
||||
}
|
||||
|
||||
func (f *fakeResourceClient) Get(ctx context.Context, identifier resource.Identifier) (resource.Object, error) {
|
||||
return f.client.Get(ctx, identifier)
|
||||
}
|
||||
|
||||
func (f *fakeResourceClient) GetInto(ctx context.Context, identifier resource.Identifier, into resource.Object) error {
|
||||
obj, err := f.client.Get(ctx, identifier)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Copy the object data into the provided 'into' object
|
||||
if target, ok := into.(*pluginsv0alpha1.PluginInstall); ok {
|
||||
*target = *obj
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakeResourceClient) List(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
||||
return f.client.ListAll(ctx, namespace, options)
|
||||
}
|
||||
|
||||
func (f *fakeResourceClient) ListInto(ctx context.Context, namespace string, options resource.ListOptions, into resource.ListObject) error {
|
||||
list, err := f.client.ListAll(ctx, namespace, options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Copy the list data into the provided 'into' object
|
||||
if target, ok := into.(*pluginsv0alpha1.PluginInstallList); ok {
|
||||
*target = *list
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakeResourceClient) Create(ctx context.Context, identifier resource.Identifier, obj resource.Object, options resource.CreateOptions) (resource.Object, error) {
|
||||
plugin := obj.(*pluginsv0alpha1.PluginInstall)
|
||||
return f.client.Create(ctx, plugin, options)
|
||||
}
|
||||
|
||||
func (f *fakeResourceClient) CreateInto(ctx context.Context, identifier resource.Identifier, obj resource.Object, options resource.CreateOptions, into resource.Object) error {
|
||||
created, err := f.Create(ctx, identifier, obj, options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Copy the created object data into the provided 'into' object
|
||||
if plugin, ok := created.(*pluginsv0alpha1.PluginInstall); ok {
|
||||
if target, ok := into.(*pluginsv0alpha1.PluginInstall); ok {
|
||||
*target = *plugin
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakeResourceClient) Update(ctx context.Context, identifier resource.Identifier, obj resource.Object, options resource.UpdateOptions) (resource.Object, error) {
|
||||
plugin := obj.(*pluginsv0alpha1.PluginInstall)
|
||||
return f.client.Update(ctx, plugin, options)
|
||||
}
|
||||
|
||||
func (f *fakeResourceClient) UpdateInto(ctx context.Context, identifier resource.Identifier, obj resource.Object, options resource.UpdateOptions, into resource.Object) error {
|
||||
updated, err := f.Update(ctx, identifier, obj, options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Copy the updated object data into the provided 'into' object
|
||||
if plugin, ok := updated.(*pluginsv0alpha1.PluginInstall); ok {
|
||||
if target, ok := into.(*pluginsv0alpha1.PluginInstall); ok {
|
||||
*target = *plugin
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakeResourceClient) Patch(ctx context.Context, identifier resource.Identifier, patch resource.PatchRequest, options resource.PatchOptions) (resource.Object, error) {
|
||||
return f.client.Patch(ctx, identifier, patch, options)
|
||||
}
|
||||
|
||||
func (f *fakeResourceClient) PatchInto(ctx context.Context, identifier resource.Identifier, patch resource.PatchRequest, options resource.PatchOptions, into resource.Object) error {
|
||||
patched, err := f.Patch(ctx, identifier, patch, options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Copy the patched object data into the provided 'into' object
|
||||
if plugin, ok := patched.(*pluginsv0alpha1.PluginInstall); ok {
|
||||
if target, ok := into.(*pluginsv0alpha1.PluginInstall); ok {
|
||||
*target = *plugin
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakeResourceClient) Delete(ctx context.Context, identifier resource.Identifier, options resource.DeleteOptions) error {
|
||||
return f.client.Delete(ctx, identifier, options)
|
||||
}
|
||||
|
||||
func (f *fakeResourceClient) SubresourceRequest(ctx context.Context, identifier resource.Identifier, req resource.CustomRouteRequestOptions) ([]byte, error) {
|
||||
return []byte{}, nil
|
||||
}
|
||||
|
||||
func (f *fakeResourceClient) Watch(ctx context.Context, namespace string, options resource.WatchOptions) (resource.WatchResponse, error) {
|
||||
return &fakeWatchResponse{}, nil
|
||||
}
|
||||
|
||||
type fakeWatchResponse struct{}
|
||||
|
||||
func (f *fakeWatchResponse) Stop() {}
|
||||
|
||||
func (f *fakeWatchResponse) WatchEvents() <-chan resource.WatchEvent {
|
||||
ch := make(chan resource.WatchEvent)
|
||||
close(ch)
|
||||
return ch
|
||||
}
|
||||
|
||||
func TestSyncer_Sync(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
featureToggleEnabled bool
|
||||
orgs []*org.OrgDTO
|
||||
orgServiceError error
|
||||
serverLockError error
|
||||
expectedError error
|
||||
expectSyncCalls int
|
||||
name string
|
||||
pluginInstallAPISyncEnabled bool
|
||||
pluginStoreServiceEnabled bool
|
||||
installedPlugins []*plugins.Plugin
|
||||
orgs []*org.OrgDTO
|
||||
orgServiceError error
|
||||
serverLockError error
|
||||
expectedError error
|
||||
expectSyncCalls int
|
||||
}{
|
||||
{
|
||||
name: "feature toggle disabled",
|
||||
featureToggleEnabled: false,
|
||||
orgs: []*org.OrgDTO{{ID: 1, Name: "Org 1"}},
|
||||
expectedError: nil,
|
||||
expectSyncCalls: 0,
|
||||
name: "plugin install API sync feature toggle disabled",
|
||||
pluginInstallAPISyncEnabled: false,
|
||||
pluginStoreServiceEnabled: true,
|
||||
installedPlugins: []*plugins.Plugin{{JSONData: plugins.JSONData{ID: "test-plugin", Info: plugins.Info{Version: "1.0.0"}}, Class: plugins.ClassCore}},
|
||||
orgs: []*org.OrgDTO{{ID: 1, Name: "Org 1"}},
|
||||
expectedError: nil,
|
||||
expectSyncCalls: 0,
|
||||
},
|
||||
{
|
||||
name: "feature toggle enabled, no orgs",
|
||||
featureToggleEnabled: true,
|
||||
orgs: []*org.OrgDTO{},
|
||||
expectedError: nil,
|
||||
expectSyncCalls: 0,
|
||||
name: "plugin store service feature toggle disabled",
|
||||
pluginInstallAPISyncEnabled: true,
|
||||
pluginStoreServiceEnabled: false,
|
||||
installedPlugins: []*plugins.Plugin{{JSONData: plugins.JSONData{ID: "test-plugin", Info: plugins.Info{Version: "1.0.0"}}, Class: plugins.ClassCore}},
|
||||
orgs: []*org.OrgDTO{{ID: 1, Name: "Org 1"}},
|
||||
expectedError: nil,
|
||||
expectSyncCalls: 0,
|
||||
},
|
||||
{
|
||||
name: "feature toggle enabled, single org",
|
||||
featureToggleEnabled: true,
|
||||
orgs: []*org.OrgDTO{{ID: 1, Name: "Org 1"}},
|
||||
expectedError: nil,
|
||||
expectSyncCalls: 1,
|
||||
name: "both feature toggles enabled, no orgs",
|
||||
pluginInstallAPISyncEnabled: true,
|
||||
pluginStoreServiceEnabled: true,
|
||||
installedPlugins: []*plugins.Plugin{{JSONData: plugins.JSONData{ID: "test-plugin", Info: plugins.Info{Version: "1.0.0"}}, Class: plugins.ClassCore}},
|
||||
orgs: []*org.OrgDTO{},
|
||||
expectedError: nil,
|
||||
expectSyncCalls: 0,
|
||||
},
|
||||
{
|
||||
name: "feature toggle enabled, multiple orgs",
|
||||
featureToggleEnabled: true,
|
||||
name: "both feature toggles enabled, empty installed plugins",
|
||||
pluginInstallAPISyncEnabled: true,
|
||||
pluginStoreServiceEnabled: true,
|
||||
installedPlugins: []*plugins.Plugin{},
|
||||
orgs: []*org.OrgDTO{{ID: 1, Name: "Org 1"}},
|
||||
expectedError: nil,
|
||||
expectSyncCalls: 0,
|
||||
},
|
||||
{
|
||||
name: "both feature toggles enabled, single org",
|
||||
pluginInstallAPISyncEnabled: true,
|
||||
pluginStoreServiceEnabled: true,
|
||||
installedPlugins: []*plugins.Plugin{{JSONData: plugins.JSONData{ID: "test-plugin", Info: plugins.Info{Version: "1.0.0"}}, Class: plugins.ClassCore}},
|
||||
orgs: []*org.OrgDTO{{ID: 1, Name: "Org 1"}},
|
||||
expectedError: nil,
|
||||
expectSyncCalls: 1,
|
||||
},
|
||||
{
|
||||
name: "both feature toggles enabled, multiple orgs",
|
||||
pluginInstallAPISyncEnabled: true,
|
||||
pluginStoreServiceEnabled: true,
|
||||
installedPlugins: []*plugins.Plugin{{JSONData: plugins.JSONData{ID: "test-plugin", Info: plugins.Info{Version: "1.0.0"}}, Class: plugins.ClassCore}},
|
||||
orgs: []*org.OrgDTO{
|
||||
{ID: 1, Name: "Org 1"},
|
||||
{ID: 2, Name: "Org 2"},
|
||||
@@ -257,20 +91,24 @@ func TestSyncer_Sync(t *testing.T) {
|
||||
expectSyncCalls: 3,
|
||||
},
|
||||
{
|
||||
name: "org service error",
|
||||
featureToggleEnabled: true,
|
||||
orgs: nil,
|
||||
orgServiceError: errors.New("org service error"),
|
||||
expectedError: errors.New("org service error"),
|
||||
expectSyncCalls: 0,
|
||||
name: "org service error",
|
||||
pluginInstallAPISyncEnabled: true,
|
||||
pluginStoreServiceEnabled: true,
|
||||
installedPlugins: []*plugins.Plugin{{JSONData: plugins.JSONData{ID: "test-plugin", Info: plugins.Info{Version: "1.0.0"}}, Class: plugins.ClassCore}},
|
||||
orgs: nil,
|
||||
orgServiceError: errors.New("org service error"),
|
||||
expectedError: errors.New("org service error"),
|
||||
expectSyncCalls: 0,
|
||||
},
|
||||
{
|
||||
name: "server lock error",
|
||||
featureToggleEnabled: true,
|
||||
orgs: []*org.OrgDTO{{ID: 1, Name: "Org 1"}},
|
||||
serverLockError: errors.New("lock error"),
|
||||
expectedError: errors.New("lock error"),
|
||||
expectSyncCalls: 0,
|
||||
name: "server lock error",
|
||||
pluginInstallAPISyncEnabled: true,
|
||||
pluginStoreServiceEnabled: true,
|
||||
installedPlugins: []*plugins.Plugin{{JSONData: plugins.JSONData{ID: "test-plugin", Info: plugins.Info{Version: "1.0.0"}}, Class: plugins.ClassCore}},
|
||||
orgs: []*org.OrgDTO{{ID: 1, Name: "Org 1"}},
|
||||
serverLockError: errors.New("lock error"),
|
||||
expectedError: errors.New("lock error"),
|
||||
expectSyncCalls: 0,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -280,7 +118,8 @@ func TestSyncer_Sync(t *testing.T) {
|
||||
|
||||
// Setup feature toggles
|
||||
ft := featuremgmt.NewMockFeatureToggles(t)
|
||||
ft.EXPECT().IsEnabled(ctx, featuremgmt.FlagPluginInstallAPISync).Return(tt.featureToggleEnabled).Maybe()
|
||||
ft.EXPECT().IsEnabled(ctx, featuremgmt.FlagPluginInstallAPISync).Return(tt.pluginInstallAPISyncEnabled).Maybe()
|
||||
ft.EXPECT().IsEnabled(ctx, featuremgmt.FlagPluginStoreServiceLoading).Return(tt.pluginStoreServiceEnabled).Maybe()
|
||||
|
||||
// Setup org service
|
||||
orgService := orgtest.NewOrgServiceFake()
|
||||
@@ -298,12 +137,12 @@ func TestSyncer_Sync(t *testing.T) {
|
||||
// Setup fake client and registrar
|
||||
syncCalls := 0
|
||||
fakeClient := &fakePluginInstallClient{
|
||||
createFunc: func(ctx context.Context, obj *pluginsv0alpha1.PluginInstall, opts resource.CreateOptions) (*pluginsv0alpha1.PluginInstall, error) {
|
||||
createFunc: func(ctx context.Context, obj *pluginsv0alpha1.Plugin, opts resource.CreateOptions) (*pluginsv0alpha1.Plugin, error) {
|
||||
syncCalls++
|
||||
return obj, nil
|
||||
},
|
||||
listAllFunc: func(ctx context.Context, namespace string, opts resource.ListOptions) (*pluginsv0alpha1.PluginInstallList, error) {
|
||||
return &pluginsv0alpha1.PluginInstallList{}, nil
|
||||
listAllFunc: func(ctx context.Context, namespace string, opts resource.ListOptions) (*pluginsv0alpha1.PluginList, error) {
|
||||
return &pluginsv0alpha1.PluginList{}, nil
|
||||
},
|
||||
}
|
||||
clientGen := &fakeClientGenerator{client: fakeClient}
|
||||
@@ -320,10 +159,7 @@ func TestSyncer_Sync(t *testing.T) {
|
||||
)
|
||||
|
||||
// Execute
|
||||
installedPlugins := []*plugins.Plugin{
|
||||
{JSONData: plugins.JSONData{ID: "test-plugin", Info: plugins.Info{Version: "1.0.0"}}},
|
||||
}
|
||||
err := s.Sync(ctx, install.SourcePluginStore, installedPlugins)
|
||||
err := s.Sync(ctx, install.SourcePluginStore, tt.installedPlugins)
|
||||
|
||||
// Verify
|
||||
if tt.expectedError != nil {
|
||||
@@ -342,7 +178,7 @@ func TestSyncer_syncNamespace(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
installedPlugins []*plugins.Plugin
|
||||
apiPlugins []pluginsv0alpha1.PluginInstall
|
||||
apiPlugins []pluginsv0alpha1.Plugin
|
||||
clientListError error
|
||||
expectedError error
|
||||
expectedRegCalls int
|
||||
@@ -353,7 +189,7 @@ func TestSyncer_syncNamespace(t *testing.T) {
|
||||
{
|
||||
name: "no installed plugins, no API plugins",
|
||||
installedPlugins: []*plugins.Plugin{},
|
||||
apiPlugins: []pluginsv0alpha1.PluginInstall{},
|
||||
apiPlugins: []pluginsv0alpha1.Plugin{},
|
||||
expectedError: nil,
|
||||
expectedRegCalls: 0,
|
||||
expectedUnregCalls: 0,
|
||||
@@ -364,7 +200,7 @@ func TestSyncer_syncNamespace(t *testing.T) {
|
||||
{JSONData: plugins.JSONData{ID: "plugin-1", Info: plugins.Info{Version: "1.0.0"}}, Class: plugins.ClassCore},
|
||||
{JSONData: plugins.JSONData{ID: "plugin-2", Info: plugins.Info{Version: "2.0.0"}}, Class: plugins.ClassExternal},
|
||||
},
|
||||
apiPlugins: []pluginsv0alpha1.PluginInstall{},
|
||||
apiPlugins: []pluginsv0alpha1.Plugin{},
|
||||
expectedError: nil,
|
||||
expectedRegCalls: 2,
|
||||
expectedUnregCalls: 0,
|
||||
@@ -373,7 +209,7 @@ func TestSyncer_syncNamespace(t *testing.T) {
|
||||
{
|
||||
name: "API plugins only",
|
||||
installedPlugins: []*plugins.Plugin{},
|
||||
apiPlugins: []pluginsv0alpha1.PluginInstall{
|
||||
apiPlugins: []pluginsv0alpha1.Plugin{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "plugin-1",
|
||||
@@ -381,7 +217,7 @@ func TestSyncer_syncNamespace(t *testing.T) {
|
||||
install.PluginInstallSourceAnnotation: install.SourcePluginStore,
|
||||
},
|
||||
},
|
||||
Spec: pluginsv0alpha1.PluginInstallSpec{Id: "plugin-1"},
|
||||
Spec: pluginsv0alpha1.PluginSpec{Id: "plugin-1"},
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
@@ -390,7 +226,7 @@ func TestSyncer_syncNamespace(t *testing.T) {
|
||||
install.PluginInstallSourceAnnotation: install.SourcePluginStore,
|
||||
},
|
||||
},
|
||||
Spec: pluginsv0alpha1.PluginInstallSpec{Id: "plugin-2"},
|
||||
Spec: pluginsv0alpha1.PluginSpec{Id: "plugin-2"},
|
||||
},
|
||||
},
|
||||
expectedError: nil,
|
||||
@@ -405,7 +241,7 @@ func TestSyncer_syncNamespace(t *testing.T) {
|
||||
{JSONData: plugins.JSONData{ID: "plugin-2", Info: plugins.Info{Version: "2.0.0"}}, Class: plugins.ClassExternal},
|
||||
{JSONData: plugins.JSONData{ID: "plugin-3", Info: plugins.Info{Version: "3.0.0"}}, Class: plugins.ClassExternal},
|
||||
},
|
||||
apiPlugins: []pluginsv0alpha1.PluginInstall{
|
||||
apiPlugins: []pluginsv0alpha1.Plugin{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "plugin-2",
|
||||
@@ -413,7 +249,7 @@ func TestSyncer_syncNamespace(t *testing.T) {
|
||||
install.PluginInstallSourceAnnotation: install.SourcePluginStore,
|
||||
},
|
||||
},
|
||||
Spec: pluginsv0alpha1.PluginInstallSpec{Id: "plugin-2", Version: "2.0.0"},
|
||||
Spec: pluginsv0alpha1.PluginSpec{Id: "plugin-2", Version: "2.0.0"},
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
@@ -422,7 +258,7 @@ func TestSyncer_syncNamespace(t *testing.T) {
|
||||
install.PluginInstallSourceAnnotation: install.SourcePluginStore,
|
||||
},
|
||||
},
|
||||
Spec: pluginsv0alpha1.PluginInstallSpec{Id: "plugin-4"},
|
||||
Spec: pluginsv0alpha1.PluginSpec{Id: "plugin-4"},
|
||||
},
|
||||
},
|
||||
expectedError: nil,
|
||||
@@ -434,7 +270,7 @@ func TestSyncer_syncNamespace(t *testing.T) {
|
||||
{
|
||||
name: "list error",
|
||||
installedPlugins: []*plugins.Plugin{},
|
||||
apiPlugins: []pluginsv0alpha1.PluginInstall{},
|
||||
apiPlugins: []pluginsv0alpha1.Plugin{},
|
||||
clientListError: errors.New("list error"),
|
||||
expectedError: errors.New("list error"),
|
||||
},
|
||||
@@ -450,15 +286,15 @@ func TestSyncer_syncNamespace(t *testing.T) {
|
||||
|
||||
// Setup fake client
|
||||
fakeClient := &fakePluginInstallClient{
|
||||
listAllFunc: func(ctx context.Context, namespace string, opts resource.ListOptions) (*pluginsv0alpha1.PluginInstallList, error) {
|
||||
listAllFunc: func(ctx context.Context, namespace string, opts resource.ListOptions) (*pluginsv0alpha1.PluginList, error) {
|
||||
if tt.clientListError != nil {
|
||||
return nil, tt.clientListError
|
||||
}
|
||||
return &pluginsv0alpha1.PluginInstallList{
|
||||
return &pluginsv0alpha1.PluginList{
|
||||
Items: tt.apiPlugins,
|
||||
}, nil
|
||||
},
|
||||
createFunc: func(ctx context.Context, obj *pluginsv0alpha1.PluginInstall, opts resource.CreateOptions) (*pluginsv0alpha1.PluginInstall, error) {
|
||||
createFunc: func(ctx context.Context, obj *pluginsv0alpha1.Plugin, opts resource.CreateOptions) (*pluginsv0alpha1.Plugin, error) {
|
||||
registeredIDs = append(registeredIDs, obj.Spec.Id)
|
||||
return obj, nil
|
||||
},
|
||||
@@ -466,7 +302,7 @@ func TestSyncer_syncNamespace(t *testing.T) {
|
||||
unregisteredIDs = append(unregisteredIDs, identifier.Name)
|
||||
return nil
|
||||
},
|
||||
getFunc: func(ctx context.Context, identifier resource.Identifier) (*pluginsv0alpha1.PluginInstall, error) {
|
||||
getFunc: func(ctx context.Context, identifier resource.Identifier) (*pluginsv0alpha1.Plugin, error) {
|
||||
// Check if plugin exists in apiPlugins
|
||||
for i := range tt.apiPlugins {
|
||||
if tt.apiPlugins[i].Name == identifier.Name {
|
||||
@@ -521,7 +357,7 @@ func TestSyncer_syncNamespace(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSyncer_getClient(t *testing.T) {
|
||||
func TestInstallRegistrar_GetClient(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
}{
|
||||
@@ -559,92 +395,196 @@ func TestSyncer_getClient(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSyncer_syncAllNamespaces(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
orgs []*org.OrgDTO
|
||||
orgServiceError error
|
||||
expectedError error
|
||||
expectedCalls int
|
||||
}{
|
||||
{
|
||||
name: "no orgs",
|
||||
orgs: []*org.OrgDTO{},
|
||||
expectedError: nil,
|
||||
expectedCalls: 0,
|
||||
},
|
||||
{
|
||||
name: "single org",
|
||||
orgs: []*org.OrgDTO{
|
||||
{ID: 1, Name: "Org 1"},
|
||||
},
|
||||
expectedError: nil,
|
||||
expectedCalls: 1,
|
||||
},
|
||||
{
|
||||
name: "multiple orgs",
|
||||
orgs: []*org.OrgDTO{
|
||||
{ID: 1, Name: "Org 1"},
|
||||
{ID: 2, Name: "Org 2"},
|
||||
{ID: 3, Name: "Org 3"},
|
||||
},
|
||||
expectedError: nil,
|
||||
expectedCalls: 3,
|
||||
},
|
||||
{
|
||||
name: "org service error",
|
||||
orgs: nil,
|
||||
orgServiceError: errors.New("org service error"),
|
||||
expectedError: errors.New("org service error"),
|
||||
expectedCalls: 0,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
orgService := orgtest.NewOrgServiceFake()
|
||||
orgService.ExpectedOrgs = tt.orgs
|
||||
orgService.ExpectedError = tt.orgServiceError
|
||||
|
||||
// Track namespace sync calls
|
||||
syncCalls := 0
|
||||
fakeClient := &fakePluginInstallClient{
|
||||
createFunc: func(ctx context.Context, obj *pluginsv0alpha1.PluginInstall, opts resource.CreateOptions) (*pluginsv0alpha1.PluginInstall, error) {
|
||||
syncCalls++
|
||||
return obj, nil
|
||||
},
|
||||
listAllFunc: func(ctx context.Context, namespace string, opts resource.ListOptions) (*pluginsv0alpha1.PluginInstallList, error) {
|
||||
return &pluginsv0alpha1.PluginInstallList{}, nil
|
||||
},
|
||||
}
|
||||
|
||||
clientGen := &fakeClientGenerator{client: fakeClient}
|
||||
|
||||
s := newSyncer(
|
||||
featuremgmt.NewMockFeatureToggles(t),
|
||||
clientGen,
|
||||
install.NewInstallRegistrar(clientGen),
|
||||
orgService,
|
||||
func(orgID int64) string { return "org-1" },
|
||||
&fakeServerLock{},
|
||||
)
|
||||
|
||||
installedPlugins := []*plugins.Plugin{
|
||||
{JSONData: plugins.JSONData{ID: "test-plugin", Info: plugins.Info{Version: "1.0.0"}}, Class: plugins.ClassCore},
|
||||
}
|
||||
|
||||
err := s.syncAllNamespaces(ctx, install.SourcePluginStore, installedPlugins)
|
||||
|
||||
if tt.expectedError != nil {
|
||||
require.Error(t, err)
|
||||
require.Equal(t, tt.expectedError.Error(), err.Error())
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
require.Equal(t, tt.expectedCalls, syncCalls)
|
||||
})
|
||||
// Test helpers to avoid import cycles
|
||||
type fakeServerLock struct {
|
||||
lockFunc func(ctx context.Context, actionName string, maxInterval time.Duration, fn func(ctx context.Context)) error
|
||||
}
|
||||
|
||||
func (f *fakeServerLock) LockExecuteAndRelease(ctx context.Context, actionName string, maxInterval time.Duration, fn func(ctx context.Context)) error {
|
||||
if f.lockFunc != nil {
|
||||
return f.lockFunc(ctx, actionName, maxInterval, fn)
|
||||
}
|
||||
fn(ctx)
|
||||
return nil
|
||||
}
|
||||
|
||||
type fakePluginInstallClient struct {
|
||||
listAllFunc func(ctx context.Context, namespace string, opts resource.ListOptions) (*pluginsv0alpha1.PluginList, error)
|
||||
getFunc func(ctx context.Context, identifier resource.Identifier) (*pluginsv0alpha1.Plugin, error)
|
||||
createFunc func(ctx context.Context, obj *pluginsv0alpha1.Plugin, opts resource.CreateOptions) (*pluginsv0alpha1.Plugin, error)
|
||||
updateFunc func(ctx context.Context, obj *pluginsv0alpha1.Plugin, opts resource.UpdateOptions) (*pluginsv0alpha1.Plugin, error)
|
||||
deleteFunc func(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error
|
||||
}
|
||||
|
||||
func (f *fakePluginInstallClient) Get(ctx context.Context, identifier resource.Identifier) (*pluginsv0alpha1.Plugin, error) {
|
||||
if f.getFunc != nil {
|
||||
return f.getFunc(ctx, identifier)
|
||||
}
|
||||
// Return a proper k8s NotFound error
|
||||
return nil, errorsK8s.NewNotFound(schema.GroupResource{
|
||||
Group: pluginsv0alpha1.APIGroup,
|
||||
Resource: "plugininstalls",
|
||||
}, identifier.Name)
|
||||
}
|
||||
|
||||
func (f *fakePluginInstallClient) ListAll(ctx context.Context, namespace string, opts resource.ListOptions) (*pluginsv0alpha1.PluginList, error) {
|
||||
if f.listAllFunc != nil {
|
||||
return f.listAllFunc(ctx, namespace, opts)
|
||||
}
|
||||
return &pluginsv0alpha1.PluginList{}, nil
|
||||
}
|
||||
|
||||
func (f *fakePluginInstallClient) List(ctx context.Context, namespace string, opts resource.ListOptions) (*pluginsv0alpha1.PluginList, error) {
|
||||
return f.ListAll(ctx, namespace, opts)
|
||||
}
|
||||
|
||||
func (f *fakePluginInstallClient) Create(ctx context.Context, obj *pluginsv0alpha1.Plugin, opts resource.CreateOptions) (*pluginsv0alpha1.Plugin, error) {
|
||||
if f.createFunc != nil {
|
||||
return f.createFunc(ctx, obj, opts)
|
||||
}
|
||||
return obj, nil
|
||||
}
|
||||
|
||||
func (f *fakePluginInstallClient) Update(ctx context.Context, obj *pluginsv0alpha1.Plugin, opts resource.UpdateOptions) (*pluginsv0alpha1.Plugin, error) {
|
||||
if f.updateFunc != nil {
|
||||
return f.updateFunc(ctx, obj, opts)
|
||||
}
|
||||
return obj, nil
|
||||
}
|
||||
|
||||
func (f *fakePluginInstallClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus pluginsv0alpha1.PluginStatus, opts resource.UpdateOptions) (*pluginsv0alpha1.Plugin, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (f *fakePluginInstallClient) Patch(ctx context.Context, identifier resource.Identifier, req resource.PatchRequest, opts resource.PatchOptions) (*pluginsv0alpha1.Plugin, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (f *fakePluginInstallClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error {
|
||||
if f.deleteFunc != nil {
|
||||
return f.deleteFunc(ctx, identifier, opts)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type fakeClientGenerator struct {
|
||||
client *fakePluginInstallClient
|
||||
}
|
||||
|
||||
func (f *fakeClientGenerator) ClientFor(kind resource.Kind) (resource.Client, error) {
|
||||
return &fakeResourceClient{client: f.client}, nil
|
||||
}
|
||||
|
||||
type fakeResourceClient struct {
|
||||
client *fakePluginInstallClient
|
||||
}
|
||||
|
||||
func (f *fakeResourceClient) Get(ctx context.Context, identifier resource.Identifier) (resource.Object, error) {
|
||||
return f.client.Get(ctx, identifier)
|
||||
}
|
||||
|
||||
func (f *fakeResourceClient) GetInto(ctx context.Context, identifier resource.Identifier, into resource.Object) error {
|
||||
obj, err := f.client.Get(ctx, identifier)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Copy the object data into the provided 'into' object
|
||||
if target, ok := into.(*pluginsv0alpha1.Plugin); ok {
|
||||
*target = *obj
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakeResourceClient) List(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
||||
return f.client.ListAll(ctx, namespace, options)
|
||||
}
|
||||
|
||||
func (f *fakeResourceClient) ListInto(ctx context.Context, namespace string, options resource.ListOptions, into resource.ListObject) error {
|
||||
list, err := f.client.ListAll(ctx, namespace, options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Copy the list data into the provided 'into' object
|
||||
if target, ok := into.(*pluginsv0alpha1.PluginList); ok {
|
||||
*target = *list
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakeResourceClient) Create(ctx context.Context, identifier resource.Identifier, obj resource.Object, options resource.CreateOptions) (resource.Object, error) {
|
||||
plugin := obj.(*pluginsv0alpha1.Plugin)
|
||||
return f.client.Create(ctx, plugin, options)
|
||||
}
|
||||
|
||||
func (f *fakeResourceClient) CreateInto(ctx context.Context, identifier resource.Identifier, obj resource.Object, options resource.CreateOptions, into resource.Object) error {
|
||||
created, err := f.Create(ctx, identifier, obj, options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Copy the created object data into the provided 'into' object
|
||||
if plugin, ok := created.(*pluginsv0alpha1.Plugin); ok {
|
||||
if target, ok := into.(*pluginsv0alpha1.Plugin); ok {
|
||||
*target = *plugin
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakeResourceClient) Update(ctx context.Context, identifier resource.Identifier, obj resource.Object, options resource.UpdateOptions) (resource.Object, error) {
|
||||
plugin := obj.(*pluginsv0alpha1.Plugin)
|
||||
return f.client.Update(ctx, plugin, options)
|
||||
}
|
||||
|
||||
func (f *fakeResourceClient) UpdateInto(ctx context.Context, identifier resource.Identifier, obj resource.Object, options resource.UpdateOptions, into resource.Object) error {
|
||||
updated, err := f.Update(ctx, identifier, obj, options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Copy the updated object data into the provided 'into' object
|
||||
if plugin, ok := updated.(*pluginsv0alpha1.Plugin); ok {
|
||||
if target, ok := into.(*pluginsv0alpha1.Plugin); ok {
|
||||
*target = *plugin
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakeResourceClient) Patch(ctx context.Context, identifier resource.Identifier, patch resource.PatchRequest, options resource.PatchOptions) (resource.Object, error) {
|
||||
return f.client.Patch(ctx, identifier, patch, options)
|
||||
}
|
||||
|
||||
func (f *fakeResourceClient) PatchInto(ctx context.Context, identifier resource.Identifier, patch resource.PatchRequest, options resource.PatchOptions, into resource.Object) error {
|
||||
patched, err := f.Patch(ctx, identifier, patch, options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Copy the patched object data into the provided 'into' object
|
||||
if plugin, ok := patched.(*pluginsv0alpha1.Plugin); ok {
|
||||
if target, ok := into.(*pluginsv0alpha1.Plugin); ok {
|
||||
*target = *plugin
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakeResourceClient) Delete(ctx context.Context, identifier resource.Identifier, options resource.DeleteOptions) error {
|
||||
return f.client.Delete(ctx, identifier, options)
|
||||
}
|
||||
|
||||
func (f *fakeResourceClient) SubresourceRequest(ctx context.Context, identifier resource.Identifier, req resource.CustomRouteRequestOptions) ([]byte, error) {
|
||||
return []byte{}, nil
|
||||
}
|
||||
|
||||
func (f *fakeResourceClient) Watch(ctx context.Context, namespace string, options resource.WatchOptions) (resource.WatchResponse, error) {
|
||||
return &fakeWatchResponse{}, nil
|
||||
}
|
||||
|
||||
type fakeWatchResponse struct{}
|
||||
|
||||
func (f *fakeWatchResponse) Stop() {}
|
||||
|
||||
func (f *fakeWatchResponse) WatchEvents() <-chan resource.WatchEvent {
|
||||
ch := make(chan resource.WatchEvent)
|
||||
close(ch)
|
||||
return ch
|
||||
}
|
||||
|
||||
@@ -20,19 +20,30 @@ func TestIntegrationPluginsIntegrationDiscovery(t *testing.T) {
|
||||
"freshness": "Current",
|
||||
"resources": [
|
||||
{
|
||||
"resource": "plugininstalls",
|
||||
"resource": "plugins",
|
||||
"responseKind": {
|
||||
"group": "",
|
||||
"kind": "PluginInstall",
|
||||
"kind": "Plugin",
|
||||
"version": ""
|
||||
},
|
||||
"scope": "Namespaced",
|
||||
"singularResource": "plugininstalls",
|
||||
"singularResource": "plugins",
|
||||
"subresources": [
|
||||
{
|
||||
"responseKind": {
|
||||
"group": "",
|
||||
"kind": "PluginInstall",
|
||||
"kind": "ResourceCallOptions",
|
||||
"version": ""
|
||||
},
|
||||
"subresource": "meta",
|
||||
"verbs": [
|
||||
"get"
|
||||
]
|
||||
},
|
||||
{
|
||||
"responseKind": {
|
||||
"group": "",
|
||||
"kind": "Plugin",
|
||||
"version": ""
|
||||
},
|
||||
"subresource": "status",
|
||||
@@ -53,35 +64,6 @@ func TestIntegrationPluginsIntegrationDiscovery(t *testing.T) {
|
||||
"update",
|
||||
"watch"
|
||||
]
|
||||
},
|
||||
{
|
||||
"resource": "pluginmetas",
|
||||
"responseKind": {
|
||||
"group": "",
|
||||
"kind": "PluginMeta",
|
||||
"version": ""
|
||||
},
|
||||
"scope": "Namespaced",
|
||||
"singularResource": "pluginmeta",
|
||||
"subresources": [
|
||||
{
|
||||
"responseKind": {
|
||||
"group": "",
|
||||
"kind": "PluginMeta",
|
||||
"version": ""
|
||||
},
|
||||
"subresource": "status",
|
||||
"verbs": [
|
||||
"get",
|
||||
"patch",
|
||||
"update"
|
||||
]
|
||||
}
|
||||
],
|
||||
"verbs": [
|
||||
"get",
|
||||
"list"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -16,88 +16,54 @@ import (
|
||||
"github.com/grafana/grafana/pkg/util/testutil"
|
||||
)
|
||||
|
||||
var gvrPluginInstalls = schema.GroupVersionResource{
|
||||
var gvrPlugins = schema.GroupVersionResource{
|
||||
Group: "plugins.grafana.app",
|
||||
Version: "v0alpha1",
|
||||
Resource: "plugininstalls",
|
||||
Resource: "plugins",
|
||||
}
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
testsuite.Run(m)
|
||||
}
|
||||
|
||||
func TestIntegrationPluginInstalls(t *testing.T) {
|
||||
func TestIntegrationPlugins(t *testing.T) {
|
||||
testutil.SkipIntegrationTestInShortMode(t)
|
||||
|
||||
t.Run("create plugin install", func(t *testing.T) {
|
||||
t.Run("create plugin", func(t *testing.T) {
|
||||
helper := setupHelper(t)
|
||||
ctx := context.Background()
|
||||
client := helper.GetResourceClient(apis.ResourceClientArgs{
|
||||
User: helper.Org1.Admin,
|
||||
GVR: gvrPluginInstalls,
|
||||
GVR: gvrPlugins,
|
||||
})
|
||||
pluginName := "test-plugin-create"
|
||||
pluginInstall := helper.LoadYAMLOrJSON(fmt.Sprintf(`{
|
||||
plugin := helper.LoadYAMLOrJSON(fmt.Sprintf(`{
|
||||
"apiVersion": "plugins.grafana.app/v0alpha1",
|
||||
"kind": "PluginInstall",
|
||||
"kind": "Plugin",
|
||||
"metadata": {"name": "%s"},
|
||||
"spec": {"version": "1.0.0"}
|
||||
}`, pluginName))
|
||||
created, err := client.Resource.Create(ctx, pluginInstall, metav1.CreateOptions{})
|
||||
created, err := client.Resource.Create(ctx, plugin, metav1.CreateOptions{})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, created)
|
||||
require.Equal(t, pluginName, created.GetName())
|
||||
})
|
||||
|
||||
t.Run("create plugin install with status is ignored", func(t *testing.T) {
|
||||
t.Skip("status is not ignored on create. this might require a change in the SDK. skipping for now")
|
||||
helper := setupHelper(t)
|
||||
ctx := context.Background()
|
||||
client := helper.GetResourceClient(apis.ResourceClientArgs{
|
||||
User: helper.Org1.Admin,
|
||||
GVR: gvrPluginInstalls,
|
||||
})
|
||||
pluginName := "test-plugin-create-with-status"
|
||||
pluginInstall := helper.LoadYAMLOrJSON(fmt.Sprintf(`{
|
||||
"apiVersion": "plugins.grafana.app/v0alpha1",
|
||||
"kind": "PluginInstall",
|
||||
"metadata": {"name": "%s"},
|
||||
"spec": {"version": "1.0.0"},
|
||||
"status": {
|
||||
"operatorStates": {
|
||||
"test-operator": {
|
||||
"lastEvaluation": "1",
|
||||
"state": "success"
|
||||
}
|
||||
}
|
||||
}
|
||||
}`, pluginName))
|
||||
created, err := client.Resource.Create(ctx, pluginInstall, metav1.CreateOptions{})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, created)
|
||||
require.Equal(t, pluginName, created.GetName())
|
||||
// Status should be empty as it's ignored on create
|
||||
status, found, err := unstructured.NestedMap(created.Object, "status")
|
||||
require.NoError(t, err)
|
||||
require.True(t, found) // status field should exist
|
||||
require.Empty(t, status) // but it should be empty
|
||||
})
|
||||
|
||||
t.Run("get plugin install", func(t *testing.T) {
|
||||
helper := setupHelper(t)
|
||||
ctx := context.Background()
|
||||
client := helper.GetResourceClient(apis.ResourceClientArgs{
|
||||
User: helper.Org1.Admin,
|
||||
GVR: gvrPluginInstalls,
|
||||
GVR: gvrPlugins,
|
||||
})
|
||||
pluginName := "test-plugin-get"
|
||||
pluginInstall := helper.LoadYAMLOrJSON(fmt.Sprintf(`{
|
||||
plugin := helper.LoadYAMLOrJSON(fmt.Sprintf(`{
|
||||
"apiVersion": "plugins.grafana.app/v0alpha1",
|
||||
"kind": "PluginInstall",
|
||||
"kind": "Plugin",
|
||||
"metadata": {"name": "%s"},
|
||||
"spec": {"version": "1.0.0"}
|
||||
}`, pluginName))
|
||||
created, err := client.Resource.Create(ctx, pluginInstall, metav1.CreateOptions{})
|
||||
created, err := client.Resource.Create(ctx, plugin, metav1.CreateOptions{})
|
||||
require.NoError(t, err)
|
||||
fetched, err := client.Resource.Get(ctx, pluginName, metav1.GetOptions{})
|
||||
require.NoError(t, err)
|
||||
@@ -111,16 +77,16 @@ func TestIntegrationPluginInstalls(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
client := helper.GetResourceClient(apis.ResourceClientArgs{
|
||||
User: helper.Org1.Admin,
|
||||
GVR: gvrPluginInstalls,
|
||||
GVR: gvrPlugins,
|
||||
})
|
||||
pluginName := "test-plugin-update"
|
||||
pluginInstall := helper.LoadYAMLOrJSON(fmt.Sprintf(`{
|
||||
plugin := helper.LoadYAMLOrJSON(fmt.Sprintf(`{
|
||||
"apiVersion": "plugins.grafana.app/v0alpha1",
|
||||
"kind": "PluginInstall",
|
||||
"kind": "Plugin",
|
||||
"metadata": {"name": "%s"},
|
||||
"spec": {"version": "1.0.0"}
|
||||
}`, pluginName))
|
||||
created, err := client.Resource.Create(ctx, pluginInstall, metav1.CreateOptions{})
|
||||
created, err := client.Resource.Create(ctx, plugin, metav1.CreateOptions{})
|
||||
require.NoError(t, err)
|
||||
updatedSpec := created.DeepCopy()
|
||||
updatedSpec.Object["spec"] = map[string]interface{}{
|
||||
@@ -132,116 +98,21 @@ func TestIntegrationPluginInstalls(t *testing.T) {
|
||||
require.Equal(t, "2.0.0", updated.Object["spec"].(map[string]interface{})["version"])
|
||||
})
|
||||
|
||||
t.Run("update plugin install with status is ignored", func(t *testing.T) {
|
||||
helper := setupHelper(t)
|
||||
ctx := context.Background()
|
||||
client := helper.GetResourceClient(apis.ResourceClientArgs{
|
||||
User: helper.Org1.Admin,
|
||||
GVR: gvrPluginInstalls,
|
||||
})
|
||||
pluginName := "test-plugin-update-with-status"
|
||||
pluginInstall := helper.LoadYAMLOrJSON(fmt.Sprintf(`{
|
||||
"apiVersion": "plugins.grafana.app/v0alpha1",
|
||||
"kind": "PluginInstall",
|
||||
"metadata": {"name": "%s"},
|
||||
"spec": {"version": "1.0.0"}
|
||||
}`, pluginName))
|
||||
created, err := client.Resource.Create(ctx, pluginInstall, metav1.CreateOptions{})
|
||||
require.NoError(t, err)
|
||||
|
||||
// Try to update the status via a normal update
|
||||
withStatus := created.DeepCopy()
|
||||
withStatus.Object["status"] = map[string]interface{}{
|
||||
"operatorStates": map[string]interface{}{
|
||||
"test-operator": map[string]interface{}{
|
||||
"lastEvaluation": "1",
|
||||
"state": "success",
|
||||
},
|
||||
},
|
||||
}
|
||||
updated, err := client.Resource.Update(ctx, withStatus, metav1.UpdateOptions{})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, updated)
|
||||
|
||||
// The status should not have been updated
|
||||
status, found, err := unstructured.NestedMap(updated.Object, "status")
|
||||
require.NoError(t, err)
|
||||
require.True(t, found)
|
||||
require.Empty(t, status)
|
||||
|
||||
// also check with get
|
||||
fetched, err := client.Resource.Get(ctx, pluginName, metav1.GetOptions{})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, fetched)
|
||||
status, found, err = unstructured.NestedMap(fetched.Object, "status")
|
||||
require.NoError(t, err)
|
||||
require.True(t, found)
|
||||
require.Empty(t, status)
|
||||
})
|
||||
|
||||
t.Run("update plugin install status", func(t *testing.T) {
|
||||
helper := setupHelper(t)
|
||||
ctx := context.Background()
|
||||
client := helper.GetResourceClient(apis.ResourceClientArgs{
|
||||
User: helper.Org1.Admin,
|
||||
GVR: gvrPluginInstalls,
|
||||
})
|
||||
pluginName := "test-plugin-status"
|
||||
pluginInstall := helper.LoadYAMLOrJSON(fmt.Sprintf(`{
|
||||
"apiVersion": "plugins.grafana.app/v0alpha1",
|
||||
"kind": "PluginInstall",
|
||||
"metadata": {"name": "%s"},
|
||||
"spec": {"version": "1.0.0"}
|
||||
}`, pluginName))
|
||||
created, err := client.Resource.Create(ctx, pluginInstall, metav1.CreateOptions{})
|
||||
require.NoError(t, err)
|
||||
|
||||
// Update the status
|
||||
status := created.DeepCopy()
|
||||
statusPayload := map[string]interface{}{
|
||||
"operatorStates": map[string]interface{}{
|
||||
"test-operator": map[string]interface{}{
|
||||
"lastEvaluation": "1",
|
||||
"state": "success",
|
||||
},
|
||||
},
|
||||
}
|
||||
status.Object["status"] = statusPayload
|
||||
updated, err := client.Resource.UpdateStatus(ctx, status, metav1.UpdateOptions{})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, updated)
|
||||
|
||||
// Check the status on the returned object
|
||||
actualStatus, found, err := unstructured.NestedMap(updated.Object, "status")
|
||||
require.NoError(t, err)
|
||||
require.True(t, found)
|
||||
require.Equal(t, statusPayload, actualStatus)
|
||||
|
||||
// Get the status to ensure it persisted
|
||||
fetched, err := client.Resource.Get(ctx, pluginName, metav1.GetOptions{})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, fetched)
|
||||
actualStatus, found, err = unstructured.NestedMap(fetched.Object, "status")
|
||||
require.NoError(t, err)
|
||||
require.True(t, found)
|
||||
require.Equal(t, statusPayload, actualStatus)
|
||||
})
|
||||
|
||||
t.Run("list plugin installs", func(t *testing.T) {
|
||||
helper := setupHelper(t)
|
||||
ctx := context.Background()
|
||||
client := helper.GetResourceClient(apis.ResourceClientArgs{
|
||||
User: helper.Org1.Admin,
|
||||
GVR: gvrPluginInstalls,
|
||||
GVR: gvrPlugins,
|
||||
})
|
||||
pluginName := "test-plugin-list"
|
||||
pluginInstall := helper.LoadYAMLOrJSON(fmt.Sprintf(`{
|
||||
plugin := helper.LoadYAMLOrJSON(fmt.Sprintf(`{
|
||||
"apiVersion": "plugins.grafana.app/v0alpha1",
|
||||
"kind": "PluginInstall",
|
||||
"kind": "Plugin",
|
||||
"metadata": {"name": "%s"},
|
||||
"spec": {"version": "1.0.0"}
|
||||
}`, pluginName))
|
||||
created, err := client.Resource.Create(ctx, pluginInstall, metav1.CreateOptions{})
|
||||
created, err := client.Resource.Create(ctx, plugin, metav1.CreateOptions{})
|
||||
require.NoError(t, err)
|
||||
list, err := client.Resource.List(ctx, metav1.ListOptions{})
|
||||
require.NoError(t, err)
|
||||
@@ -254,16 +125,16 @@ func TestIntegrationPluginInstalls(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
client := helper.GetResourceClient(apis.ResourceClientArgs{
|
||||
User: helper.Org1.Admin,
|
||||
GVR: gvrPluginInstalls,
|
||||
GVR: gvrPlugins,
|
||||
})
|
||||
pluginName := "test-plugin-delete"
|
||||
pluginInstall := helper.LoadYAMLOrJSON(fmt.Sprintf(`{
|
||||
plugin := helper.LoadYAMLOrJSON(fmt.Sprintf(`{
|
||||
"apiVersion": "plugins.grafana.app/v0alpha1",
|
||||
"kind": "PluginInstall",
|
||||
"kind": "Plugin",
|
||||
"metadata": {"name": "%s"},
|
||||
"spec": {"version": "1.0.0"}
|
||||
}`, pluginName))
|
||||
_, err := client.Resource.Create(ctx, pluginInstall, metav1.CreateOptions{})
|
||||
_, err := client.Resource.Create(ctx, plugin, metav1.CreateOptions{})
|
||||
require.NoError(t, err)
|
||||
err = client.Resource.Delete(ctx, pluginName, metav1.DeleteOptions{})
|
||||
require.NoError(t, err)
|
||||
@@ -281,15 +152,15 @@ func TestIntegrationPluginInstalls(t *testing.T) {
|
||||
t.Run(fmt.Sprintf("with basic role: %s", user.Identity.GetOrgRole()), func(t *testing.T) {
|
||||
client := helper.GetResourceClient(apis.ResourceClientArgs{
|
||||
User: user,
|
||||
GVR: gvrPluginInstalls,
|
||||
GVR: gvrPlugins,
|
||||
})
|
||||
pluginInstall := helper.LoadYAMLOrJSON(`{
|
||||
plugin := helper.LoadYAMLOrJSON(`{
|
||||
"apiVersion": "plugins.grafana.app/v0alpha1",
|
||||
"kind": "PluginInstall",
|
||||
"kind": "Plugin",
|
||||
"metadata": {"name": "test-plugin"},
|
||||
"spec": {"version": "1.0.0"}
|
||||
}`)
|
||||
_, err := client.Resource.Create(context.Background(), pluginInstall, metav1.CreateOptions{})
|
||||
_, err := client.Resource.Create(context.Background(), plugin, metav1.CreateOptions{})
|
||||
statusError := helper.AsStatusError(err)
|
||||
require.Equal(t, metav1.StatusReasonForbidden, statusError.Status().Reason)
|
||||
err = client.Resource.Delete(context.Background(), "test-plugin", metav1.DeleteOptions{})
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
package plugins
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
||||
"github.com/grafana/grafana/pkg/tests/apis"
|
||||
"github.com/grafana/grafana/pkg/util/testutil"
|
||||
)
|
||||
|
||||
var gvrPluginMeta = schema.GroupVersionResource{
|
||||
Group: "plugins.grafana.app",
|
||||
Version: "v0alpha1",
|
||||
Resource: "pluginmetas",
|
||||
}
|
||||
|
||||
func TestIntegrationPluginMeta(t *testing.T) {
|
||||
testutil.SkipIntegrationTestInShortMode(t)
|
||||
|
||||
t.Run("list plugin metas", func(t *testing.T) {
|
||||
helper := setupHelper(t)
|
||||
ctx := context.Background()
|
||||
client := helper.GetResourceClient(apis.ResourceClientArgs{
|
||||
User: helper.Org1.Admin,
|
||||
GVR: gvrPluginMeta,
|
||||
})
|
||||
list, err := client.Resource.List(ctx, metav1.ListOptions{})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, list)
|
||||
require.Empty(t, list.Items)
|
||||
})
|
||||
|
||||
t.Run("get plugin meta", func(t *testing.T) {
|
||||
helper := setupHelper(t)
|
||||
ctx := context.Background()
|
||||
client := helper.GetResourceClient(apis.ResourceClientArgs{
|
||||
User: helper.Org1.Admin,
|
||||
GVR: gvrPluginMeta,
|
||||
})
|
||||
_, err := client.Resource.Get(ctx, "example", metav1.GetOptions{})
|
||||
require.Error(t, err)
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user