Create app.go file and define app configuration, custom route and basic handler for that route
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
package v1alpha1
|
||||
|
||||
import "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
||||
const (
|
||||
// APIGroup is the API group used by all kinds in this package
|
||||
APIGroup = "dashvalidator.grafana.app"
|
||||
// APIVersion is the API version used by all kinds in this package
|
||||
APIVersion = "v1alpha1"
|
||||
)
|
||||
|
||||
var (
|
||||
// GroupVersion is a schema.GroupVersion consisting of the Group and Version constants for this package
|
||||
GroupVersion = schema.GroupVersion{
|
||||
Group: APIGroup,
|
||||
Version: APIVersion,
|
||||
}
|
||||
)
|
||||
Generated
+99
@@ -0,0 +1,99 @@
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
type DashboardCompatibilityScoreClient struct {
|
||||
client *resource.TypedClient[*DashboardCompatibilityScore, *DashboardCompatibilityScoreList]
|
||||
}
|
||||
|
||||
func NewDashboardCompatibilityScoreClient(client resource.Client) *DashboardCompatibilityScoreClient {
|
||||
return &DashboardCompatibilityScoreClient{
|
||||
client: resource.NewTypedClient[*DashboardCompatibilityScore, *DashboardCompatibilityScoreList](client, DashboardCompatibilityScoreKind()),
|
||||
}
|
||||
}
|
||||
|
||||
func NewDashboardCompatibilityScoreClientFromGenerator(generator resource.ClientGenerator) (*DashboardCompatibilityScoreClient, error) {
|
||||
c, err := generator.ClientFor(DashboardCompatibilityScoreKind())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewDashboardCompatibilityScoreClient(c), nil
|
||||
}
|
||||
|
||||
func (c *DashboardCompatibilityScoreClient) Get(ctx context.Context, identifier resource.Identifier) (*DashboardCompatibilityScore, error) {
|
||||
return c.client.Get(ctx, identifier)
|
||||
}
|
||||
|
||||
func (c *DashboardCompatibilityScoreClient) List(ctx context.Context, namespace string, opts resource.ListOptions) (*DashboardCompatibilityScoreList, error) {
|
||||
return c.client.List(ctx, namespace, opts)
|
||||
}
|
||||
|
||||
func (c *DashboardCompatibilityScoreClient) ListAll(ctx context.Context, namespace string, opts resource.ListOptions) (*DashboardCompatibilityScoreList, 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 *DashboardCompatibilityScoreClient) Create(ctx context.Context, obj *DashboardCompatibilityScore, opts resource.CreateOptions) (*DashboardCompatibilityScore, error) {
|
||||
// Make sure apiVersion and kind are set
|
||||
obj.APIVersion = GroupVersion.Identifier()
|
||||
obj.Kind = DashboardCompatibilityScoreKind().Kind()
|
||||
return c.client.Create(ctx, obj, opts)
|
||||
}
|
||||
|
||||
func (c *DashboardCompatibilityScoreClient) Update(ctx context.Context, obj *DashboardCompatibilityScore, opts resource.UpdateOptions) (*DashboardCompatibilityScore, error) {
|
||||
return c.client.Update(ctx, obj, opts)
|
||||
}
|
||||
|
||||
func (c *DashboardCompatibilityScoreClient) Patch(ctx context.Context, identifier resource.Identifier, req resource.PatchRequest, opts resource.PatchOptions) (*DashboardCompatibilityScore, error) {
|
||||
return c.client.Patch(ctx, identifier, req, opts)
|
||||
}
|
||||
|
||||
func (c *DashboardCompatibilityScoreClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus DashboardCompatibilityScoreStatus, opts resource.UpdateOptions) (*DashboardCompatibilityScore, error) {
|
||||
return c.client.Update(ctx, &DashboardCompatibilityScore{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: DashboardCompatibilityScoreKind().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 *DashboardCompatibilityScoreClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error {
|
||||
return c.client.Delete(ctx, identifier, opts)
|
||||
}
|
||||
Generated
+28
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// Code generated by grafana-app-sdk. DO NOT EDIT.
|
||||
//
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/resource"
|
||||
)
|
||||
|
||||
// DashboardCompatibilityScoreJSONCodec is an implementation of resource.Codec for kubernetes JSON encoding
|
||||
type DashboardCompatibilityScoreJSONCodec struct{}
|
||||
|
||||
// Read reads JSON-encoded bytes from `reader` and unmarshals them into `into`
|
||||
func (*DashboardCompatibilityScoreJSONCodec) 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 (*DashboardCompatibilityScoreJSONCodec) Write(writer io.Writer, from resource.Object) error {
|
||||
return json.NewEncoder(writer).Encode(from)
|
||||
}
|
||||
|
||||
// Interface compliance checks
|
||||
var _ resource.Codec = &DashboardCompatibilityScoreJSONCodec{}
|
||||
Generated
+31
@@ -0,0 +1,31 @@
|
||||
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
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 DashboardCompatibilityScoreMetadata 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"`
|
||||
}
|
||||
|
||||
// NewDashboardCompatibilityScoreMetadata creates a new DashboardCompatibilityScoreMetadata object.
|
||||
func NewDashboardCompatibilityScoreMetadata() *DashboardCompatibilityScoreMetadata {
|
||||
return &DashboardCompatibilityScoreMetadata{
|
||||
Finalizers: []string{},
|
||||
Labels: map[string]string{},
|
||||
}
|
||||
}
|
||||
Generated
+326
@@ -0,0 +1,326 @@
|
||||
//
|
||||
// Code generated by grafana-app-sdk. DO NOT EDIT.
|
||||
//
|
||||
|
||||
package v1alpha1
|
||||
|
||||
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 DashboardCompatibilityScore struct {
|
||||
metav1.TypeMeta `json:",inline" yaml:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata" yaml:"metadata"`
|
||||
|
||||
// Spec is the spec of the DashboardCompatibilityScore
|
||||
Spec DashboardCompatibilityScoreSpec `json:"spec" yaml:"spec"`
|
||||
|
||||
Status DashboardCompatibilityScoreStatus `json:"status" yaml:"status"`
|
||||
}
|
||||
|
||||
func NewDashboardCompatibilityScore() *DashboardCompatibilityScore {
|
||||
return &DashboardCompatibilityScore{
|
||||
Spec: *NewDashboardCompatibilityScoreSpec(),
|
||||
Status: *NewDashboardCompatibilityScoreStatus(),
|
||||
}
|
||||
}
|
||||
|
||||
func (o *DashboardCompatibilityScore) GetSpec() any {
|
||||
return o.Spec
|
||||
}
|
||||
|
||||
func (o *DashboardCompatibilityScore) SetSpec(spec any) error {
|
||||
cast, ok := spec.(DashboardCompatibilityScoreSpec)
|
||||
if !ok {
|
||||
return fmt.Errorf("cannot set spec type %#v, not of type Spec", spec)
|
||||
}
|
||||
o.Spec = cast
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *DashboardCompatibilityScore) GetSubresources() map[string]any {
|
||||
return map[string]any{
|
||||
"status": o.Status,
|
||||
}
|
||||
}
|
||||
|
||||
func (o *DashboardCompatibilityScore) GetSubresource(name string) (any, bool) {
|
||||
switch name {
|
||||
case "status":
|
||||
return o.Status, true
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
|
||||
func (o *DashboardCompatibilityScore) SetSubresource(name string, value any) error {
|
||||
switch name {
|
||||
case "status":
|
||||
cast, ok := value.(DashboardCompatibilityScoreStatus)
|
||||
if !ok {
|
||||
return fmt.Errorf("cannot set status type %#v, not of type DashboardCompatibilityScoreStatus", value)
|
||||
}
|
||||
o.Status = cast
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("subresource '%s' does not exist", name)
|
||||
}
|
||||
}
|
||||
|
||||
func (o *DashboardCompatibilityScore) 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 *DashboardCompatibilityScore) 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 *DashboardCompatibilityScore) 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 *DashboardCompatibilityScore) 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 *DashboardCompatibilityScore) GetCreatedBy() string {
|
||||
if o.ObjectMeta.Annotations == nil {
|
||||
o.ObjectMeta.Annotations = make(map[string]string)
|
||||
}
|
||||
|
||||
return o.ObjectMeta.Annotations["grafana.com/createdBy"]
|
||||
}
|
||||
|
||||
func (o *DashboardCompatibilityScore) SetCreatedBy(createdBy string) {
|
||||
if o.ObjectMeta.Annotations == nil {
|
||||
o.ObjectMeta.Annotations = make(map[string]string)
|
||||
}
|
||||
|
||||
o.ObjectMeta.Annotations["grafana.com/createdBy"] = createdBy
|
||||
}
|
||||
|
||||
func (o *DashboardCompatibilityScore) 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 *DashboardCompatibilityScore) 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 *DashboardCompatibilityScore) GetUpdatedBy() string {
|
||||
if o.ObjectMeta.Annotations == nil {
|
||||
o.ObjectMeta.Annotations = make(map[string]string)
|
||||
}
|
||||
|
||||
return o.ObjectMeta.Annotations["grafana.com/updatedBy"]
|
||||
}
|
||||
|
||||
func (o *DashboardCompatibilityScore) SetUpdatedBy(updatedBy string) {
|
||||
if o.ObjectMeta.Annotations == nil {
|
||||
o.ObjectMeta.Annotations = make(map[string]string)
|
||||
}
|
||||
|
||||
o.ObjectMeta.Annotations["grafana.com/updatedBy"] = updatedBy
|
||||
}
|
||||
|
||||
func (o *DashboardCompatibilityScore) Copy() resource.Object {
|
||||
return resource.CopyObject(o)
|
||||
}
|
||||
|
||||
func (o *DashboardCompatibilityScore) DeepCopyObject() runtime.Object {
|
||||
return o.Copy()
|
||||
}
|
||||
|
||||
func (o *DashboardCompatibilityScore) DeepCopy() *DashboardCompatibilityScore {
|
||||
cpy := &DashboardCompatibilityScore{}
|
||||
o.DeepCopyInto(cpy)
|
||||
return cpy
|
||||
}
|
||||
|
||||
func (o *DashboardCompatibilityScore) DeepCopyInto(dst *DashboardCompatibilityScore) {
|
||||
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 = &DashboardCompatibilityScore{}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type DashboardCompatibilityScoreList struct {
|
||||
metav1.TypeMeta `json:",inline" yaml:",inline"`
|
||||
metav1.ListMeta `json:"metadata" yaml:"metadata"`
|
||||
Items []DashboardCompatibilityScore `json:"items" yaml:"items"`
|
||||
}
|
||||
|
||||
func (o *DashboardCompatibilityScoreList) DeepCopyObject() runtime.Object {
|
||||
return o.Copy()
|
||||
}
|
||||
|
||||
func (o *DashboardCompatibilityScoreList) Copy() resource.ListObject {
|
||||
cpy := &DashboardCompatibilityScoreList{
|
||||
TypeMeta: o.TypeMeta,
|
||||
Items: make([]DashboardCompatibilityScore, len(o.Items)),
|
||||
}
|
||||
o.ListMeta.DeepCopyInto(&cpy.ListMeta)
|
||||
for i := 0; i < len(o.Items); i++ {
|
||||
if item, ok := o.Items[i].Copy().(*DashboardCompatibilityScore); ok {
|
||||
cpy.Items[i] = *item
|
||||
}
|
||||
}
|
||||
return cpy
|
||||
}
|
||||
|
||||
func (o *DashboardCompatibilityScoreList) 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 *DashboardCompatibilityScoreList) SetItems(items []resource.Object) {
|
||||
o.Items = make([]DashboardCompatibilityScore, len(items))
|
||||
for i := 0; i < len(items); i++ {
|
||||
o.Items[i] = *items[i].(*DashboardCompatibilityScore)
|
||||
}
|
||||
}
|
||||
|
||||
func (o *DashboardCompatibilityScoreList) DeepCopy() *DashboardCompatibilityScoreList {
|
||||
cpy := &DashboardCompatibilityScoreList{}
|
||||
o.DeepCopyInto(cpy)
|
||||
return cpy
|
||||
}
|
||||
|
||||
func (o *DashboardCompatibilityScoreList) DeepCopyInto(dst *DashboardCompatibilityScoreList) {
|
||||
resource.CopyObjectInto(dst, o)
|
||||
}
|
||||
|
||||
// Interface compliance compile-time check
|
||||
var _ resource.ListObject = &DashboardCompatibilityScoreList{}
|
||||
|
||||
// Copy methods for all subresource types
|
||||
|
||||
// DeepCopy creates a full deep copy of Spec
|
||||
func (s *DashboardCompatibilityScoreSpec) DeepCopy() *DashboardCompatibilityScoreSpec {
|
||||
cpy := &DashboardCompatibilityScoreSpec{}
|
||||
s.DeepCopyInto(cpy)
|
||||
return cpy
|
||||
}
|
||||
|
||||
// DeepCopyInto deep copies Spec into another Spec object
|
||||
func (s *DashboardCompatibilityScoreSpec) DeepCopyInto(dst *DashboardCompatibilityScoreSpec) {
|
||||
resource.CopyObjectInto(dst, s)
|
||||
}
|
||||
|
||||
// DeepCopy creates a full deep copy of DashboardCompatibilityScoreStatus
|
||||
func (s *DashboardCompatibilityScoreStatus) DeepCopy() *DashboardCompatibilityScoreStatus {
|
||||
cpy := &DashboardCompatibilityScoreStatus{}
|
||||
s.DeepCopyInto(cpy)
|
||||
return cpy
|
||||
}
|
||||
|
||||
// DeepCopyInto deep copies DashboardCompatibilityScoreStatus into another DashboardCompatibilityScoreStatus object
|
||||
func (s *DashboardCompatibilityScoreStatus) DeepCopyInto(dst *DashboardCompatibilityScoreStatus) {
|
||||
resource.CopyObjectInto(dst, s)
|
||||
}
|
||||
Generated
+34
@@ -0,0 +1,34 @@
|
||||
//
|
||||
// Code generated by grafana-app-sdk. DO NOT EDIT.
|
||||
//
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
"github.com/grafana/grafana-app-sdk/resource"
|
||||
)
|
||||
|
||||
// schema is unexported to prevent accidental overwrites
|
||||
var (
|
||||
schemaDashboardCompatibilityScore = resource.NewSimpleSchema("dashvalidator.grafana.app", "v1alpha1", NewDashboardCompatibilityScore(), &DashboardCompatibilityScoreList{}, resource.WithKind("DashboardCompatibilityScore"),
|
||||
resource.WithPlural("dashboardcompatibilityscores"), resource.WithScope(resource.NamespacedScope))
|
||||
kindDashboardCompatibilityScore = resource.Kind{
|
||||
Schema: schemaDashboardCompatibilityScore,
|
||||
Codecs: map[resource.KindEncoding]resource.Codec{
|
||||
resource.KindEncodingJSON: &DashboardCompatibilityScoreJSONCodec{},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
// Kind returns a resource.Kind for this Schema with a JSON codec
|
||||
func DashboardCompatibilityScoreKind() resource.Kind {
|
||||
return kindDashboardCompatibilityScore
|
||||
}
|
||||
|
||||
// Schema returns a resource.SimpleSchema representation of DashboardCompatibilityScore
|
||||
func DashboardCompatibilityScoreSchema() *resource.SimpleSchema {
|
||||
return schemaDashboardCompatibilityScore
|
||||
}
|
||||
|
||||
// Interface compliance checks
|
||||
var _ resource.Schema = kindDashboardCompatibilityScore
|
||||
Generated
+48
@@ -0,0 +1,48 @@
|
||||
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
// DataSourceMapping specifies a datasource to validate dashboard queries against.
|
||||
// Maps logical datasource references in the dashboard to actual datasource instances.
|
||||
// +k8s:openapi-gen=true
|
||||
type DashboardCompatibilityScoreDataSourceMapping struct {
|
||||
// Unique identifier of the datasource instance.
|
||||
// Example: "prometheus-prod-us-west"
|
||||
Uid string `json:"uid"`
|
||||
// Type of datasource plugin.
|
||||
// MVP: Only "prometheus" supported.
|
||||
// Future: "mysql", "postgres", "elasticsearch", etc.
|
||||
Type string `json:"type"`
|
||||
// Optional human-readable name for display in results.
|
||||
// If not provided, UID will be used in error messages.
|
||||
// Example: "Production Prometheus (US-West)"
|
||||
Name *string `json:"name,omitempty"`
|
||||
}
|
||||
|
||||
// NewDashboardCompatibilityScoreDataSourceMapping creates a new DashboardCompatibilityScoreDataSourceMapping object.
|
||||
func NewDashboardCompatibilityScoreDataSourceMapping() *DashboardCompatibilityScoreDataSourceMapping {
|
||||
return &DashboardCompatibilityScoreDataSourceMapping{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type DashboardCompatibilityScoreSpec struct {
|
||||
// Complete dashboard JSON object to validate.
|
||||
// Must be a v1 dashboard schema (contains "panels" array).
|
||||
// v2 dashboards (with "elements" structure) are not yet supported.
|
||||
DashboardJson map[string]interface{} `json:"dashboardJson"`
|
||||
// Array of datasources to validate against.
|
||||
// The validator will check dashboard queries against each datasource
|
||||
// and provide per-datasource compatibility results.
|
||||
//
|
||||
// MVP: Only single datasource supported (array length = 1), Prometheus type only.
|
||||
// Future: Will support multiple datasources for dashboards with mixed queries.
|
||||
DatasourceMappings []DashboardCompatibilityScoreDataSourceMapping `json:"datasourceMappings"`
|
||||
}
|
||||
|
||||
// NewDashboardCompatibilityScoreSpec creates a new DashboardCompatibilityScoreSpec object.
|
||||
func NewDashboardCompatibilityScoreSpec() *DashboardCompatibilityScoreSpec {
|
||||
return &DashboardCompatibilityScoreSpec{
|
||||
DashboardJson: map[string]interface{}{},
|
||||
DatasourceMappings: []DashboardCompatibilityScoreDataSourceMapping{},
|
||||
}
|
||||
}
|
||||
Generated
+151
@@ -0,0 +1,151 @@
|
||||
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
// DataSourceResult contains validation results for a single datasource.
|
||||
// Provides aggregate statistics and per-query breakdown of compatibility.
|
||||
// +k8s:openapi-gen=true
|
||||
type DashboardCompatibilityScoreDataSourceResult struct {
|
||||
// Datasource UID that was validated (matches DataSourceMapping.uid)
|
||||
Uid string `json:"uid"`
|
||||
// Datasource type (matches DataSourceMapping.type)
|
||||
Type string `json:"type"`
|
||||
// Optional display name (matches DataSourceMapping.name if provided)
|
||||
Name *string `json:"name,omitempty"`
|
||||
// Total number of queries in the dashboard targeting this datasource.
|
||||
// Includes all panel targets/queries that reference this datasource.
|
||||
TotalQueries int64 `json:"totalQueries"`
|
||||
// Number of queries successfully validated.
|
||||
// May be less than totalQueries if some queries couldn't be parsed.
|
||||
CheckedQueries int64 `json:"checkedQueries"`
|
||||
// Total number of unique metrics/identifiers referenced across all queries.
|
||||
// For Prometheus: metric names extracted from PromQL expressions.
|
||||
// For SQL datasources: table and column names.
|
||||
TotalMetrics int64 `json:"totalMetrics"`
|
||||
// Number of metrics that exist in the datasource schema.
|
||||
// foundMetrics <= totalMetrics
|
||||
FoundMetrics int64 `json:"foundMetrics"`
|
||||
// Array of metric names that were referenced but don't exist.
|
||||
// Useful for debugging why a dashboard shows "no data".
|
||||
// Example for Prometheus: ["http_requests_total", "api_latency_seconds"]
|
||||
MissingMetrics []string `json:"missingMetrics"`
|
||||
// Per-query breakdown showing which specific queries have issues.
|
||||
// One entry per query target (refId: "A", "B", "C", etc.) in each panel.
|
||||
// Allows pinpointing exactly which panel/query needs fixing.
|
||||
QueryBreakdown []DashboardCompatibilityScoreQueryBreakdown `json:"queryBreakdown"`
|
||||
// Overall compatibility score for this datasource (0-100).
|
||||
// Calculated as: (foundMetrics / totalMetrics) * 100
|
||||
// Used to calculate the global compatibilityScore in status.
|
||||
CompatibilityScore float64 `json:"compatibilityScore"`
|
||||
}
|
||||
|
||||
// NewDashboardCompatibilityScoreDataSourceResult creates a new DashboardCompatibilityScoreDataSourceResult object.
|
||||
func NewDashboardCompatibilityScoreDataSourceResult() *DashboardCompatibilityScoreDataSourceResult {
|
||||
return &DashboardCompatibilityScoreDataSourceResult{
|
||||
MissingMetrics: []string{},
|
||||
QueryBreakdown: []DashboardCompatibilityScoreQueryBreakdown{},
|
||||
}
|
||||
}
|
||||
|
||||
// QueryBreakdown provides compatibility details for a single query within a panel.
|
||||
// Granular per-query results allow users to identify exactly which queries need fixing.
|
||||
//
|
||||
// Note: A panel can have multiple queries (refId: "A", "B", "C", etc.),
|
||||
// so there may be multiple QueryBreakdown entries for the same panelID.
|
||||
// +k8s:openapi-gen=true
|
||||
type DashboardCompatibilityScoreQueryBreakdown struct {
|
||||
// Human-readable panel title for context.
|
||||
// Example: "CPU Usage", "Request Rate"
|
||||
PanelTitle string `json:"panelTitle"`
|
||||
// Numeric panel ID from dashboard JSON.
|
||||
// Used to correlate with dashboard structure.
|
||||
PanelID int64 `json:"panelID"`
|
||||
// Query identifier within the panel.
|
||||
// Values: "A", "B", "C", etc. (from panel.targets[].refId)
|
||||
// Uniquely identifies which query in a multi-query panel this refers to.
|
||||
QueryRefId string `json:"queryRefId"`
|
||||
// Number of unique metrics referenced in this specific query.
|
||||
// For Prometheus: metrics extracted from the PromQL expr.
|
||||
// Example: rate(http_requests_total[5m]) references 1 metric.
|
||||
TotalMetrics int64 `json:"totalMetrics"`
|
||||
// Number of those metrics that exist in the datasource.
|
||||
// foundMetrics <= totalMetrics
|
||||
FoundMetrics int64 `json:"foundMetrics"`
|
||||
// Array of missing metric names specific to this query.
|
||||
// Helps identify exactly which part of a query expression will fail.
|
||||
// Empty array means query is fully compatible.
|
||||
MissingMetrics []string `json:"missingMetrics"`
|
||||
// Compatibility percentage for this individual query (0-100).
|
||||
// Calculated as: (foundMetrics / totalMetrics) * 100
|
||||
// 100 = query will work perfectly, 0 = query will return no data.
|
||||
CompatibilityScore float64 `json:"compatibilityScore"`
|
||||
}
|
||||
|
||||
// NewDashboardCompatibilityScoreQueryBreakdown creates a new DashboardCompatibilityScoreQueryBreakdown object.
|
||||
func NewDashboardCompatibilityScoreQueryBreakdown() *DashboardCompatibilityScoreQueryBreakdown {
|
||||
return &DashboardCompatibilityScoreQueryBreakdown{
|
||||
MissingMetrics: []string{},
|
||||
}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type DashboardCompatibilityScorestatusOperatorState 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 DashboardCompatibilityScoreStatusOperatorStateState `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"`
|
||||
}
|
||||
|
||||
// NewDashboardCompatibilityScorestatusOperatorState creates a new DashboardCompatibilityScorestatusOperatorState object.
|
||||
func NewDashboardCompatibilityScorestatusOperatorState() *DashboardCompatibilityScorestatusOperatorState {
|
||||
return &DashboardCompatibilityScorestatusOperatorState{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type DashboardCompatibilityScoreStatus struct {
|
||||
// Overall compatibility score across all datasources (0-100).
|
||||
// Calculated as: (total found metrics / total referenced metrics) * 100
|
||||
//
|
||||
// Score interpretation:
|
||||
// - 100: Perfect compatibility, all queries will work
|
||||
// - 80-99: Excellent, minor missing metrics
|
||||
// - 50-79: Fair, significant missing metrics
|
||||
// - 0-49: Poor, most queries will fail
|
||||
CompatibilityScore float64 `json:"compatibilityScore"`
|
||||
// Per-datasource validation results.
|
||||
// Array length matches spec.datasourceMappings.
|
||||
// Each element contains detailed metrics and query-level breakdown.
|
||||
DatasourceResults []DashboardCompatibilityScoreDataSourceResult `json:"datasourceResults"`
|
||||
// ISO 8601 timestamp of when validation was last performed.
|
||||
// Example: "2024-01-15T10:30:00Z"
|
||||
LastChecked *string `json:"lastChecked,omitempty"`
|
||||
// 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]DashboardCompatibilityScorestatusOperatorState `json:"operatorStates,omitempty"`
|
||||
// Human-readable summary of validation result.
|
||||
// Examples: "All queries compatible", "3 missing metrics found"
|
||||
Message *string `json:"message,omitempty"`
|
||||
// additionalFields is reserved for future use
|
||||
AdditionalFields map[string]interface{} `json:"additionalFields,omitempty"`
|
||||
}
|
||||
|
||||
// NewDashboardCompatibilityScoreStatus creates a new DashboardCompatibilityScoreStatus object.
|
||||
func NewDashboardCompatibilityScoreStatus() *DashboardCompatibilityScoreStatus {
|
||||
return &DashboardCompatibilityScoreStatus{
|
||||
DatasourceResults: []DashboardCompatibilityScoreDataSourceResult{},
|
||||
}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type DashboardCompatibilityScoreStatusOperatorStateState string
|
||||
|
||||
const (
|
||||
DashboardCompatibilityScoreStatusOperatorStateStateSuccess DashboardCompatibilityScoreStatusOperatorStateState = "success"
|
||||
DashboardCompatibilityScoreStatusOperatorStateStateInProgress DashboardCompatibilityScoreStatusOperatorStateState = "in_progress"
|
||||
DashboardCompatibilityScoreStatusOperatorStateStateFailed DashboardCompatibilityScoreStatusOperatorStateState = "failed"
|
||||
)
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,89 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/app"
|
||||
"github.com/grafana/grafana-app-sdk/logging"
|
||||
"github.com/grafana/grafana-app-sdk/resource"
|
||||
"github.com/grafana/grafana-app-sdk/simple"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
||||
validatorv1alpha1 "github.com/grafana/grafana/apps/dashvalidator/pkg/apis/dashvalidator/v1alpha1"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext"
|
||||
)
|
||||
|
||||
type DashValidatorConfig struct {
|
||||
DatasourceSvc datasources.DataSourceService
|
||||
PluginCtx *plugincontext.Provider
|
||||
}
|
||||
|
||||
func New(cfg app.Config) (app.App, error) {
|
||||
specificConfig, ok := cfg.SpecificConfig.(*DashValidatorConfig)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid config type: expected DashValidatorConfig")
|
||||
}
|
||||
|
||||
log := logging.DefaultLogger.With("app", "dashvalidator")
|
||||
|
||||
// configure our app
|
||||
simpleConfig := simple.AppConfig{
|
||||
Name: "dashvalidator",
|
||||
KubeConfig: cfg.KubeConfig,
|
||||
|
||||
//Define our custom route
|
||||
VersionedCustomRoutes: map[string]simple.AppVersionRouteHandlers{
|
||||
"v1alpha1": {
|
||||
{
|
||||
Namespaced: true,
|
||||
Path: "check",
|
||||
Method: "POST",
|
||||
}: handleCheckRoute(log, specificConfig.DatasourceSvc, specificConfig.PluginCtx),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
a, err := simple.NewApp(simpleConfig)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create app: %w", err)
|
||||
}
|
||||
|
||||
return a, nil
|
||||
}
|
||||
|
||||
// custom route handler to check dashboard compatibility
|
||||
func handleCheckRoute(
|
||||
log logging.Logger,
|
||||
datasourceSvc datasources.DataSourceService,
|
||||
pluginCtx *plugincontext.Provider,
|
||||
) func(context.Context, app.CustomRouteResponseWriter, *app.CustomRouteRequest) error {
|
||||
|
||||
return func(ctx context.Context, w app.CustomRouteResponseWriter, r *app.CustomRouteRequest) error {
|
||||
logger := log.WithContext(ctx)
|
||||
logger.Info("Received compatibility check request")
|
||||
|
||||
// TODO validation logic here
|
||||
|
||||
// for now a simple response
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
return json.NewEncoder(w).Encode(map[string]interface{}{
|
||||
"message": "Handler working!",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func GetKinds() map[schema.GroupVersion][]resource.Kind {
|
||||
gv := schema.GroupVersion{
|
||||
Group: "dashvalidator.grafana.com",
|
||||
Version: "v1alpha1",
|
||||
}
|
||||
|
||||
return map[schema.GroupVersion][]resource.Kind{
|
||||
gv: {validatorv1alpha1.DashboardCompatibilityScoreKind()},
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user