Unified storage: Add quotas app to apiserver (#114425)

* initial generation

* went through doc to add new resource

* added dummy kind so grafana will run

* added dummy handler and custom route

* fix app name

* gets custom route working - still a dummy route

* adds groupOverride to manifest

* adds quotas to grpc client and server

* WIP - trying to get api recognized - not working

* Gets route working

* fixes group and resource vars

* expects group and resource as separate params

* set content-type header on response

* removes Quotas kind and regens

* Update grafana-app-sdk to v0.48.5

* Update codegen

* updates manifest

* formatting

* updates grafana-app-sdk version to 0.48.5

* regen ResourceClient mocks

* adds tests

* remove commented code

* uncomment go mod tidy

* fix tests and make update workspace

* adds quotas app to codeowners

* formatting

* make gen-apps

* deletes temp file

* fix generated folder code

* make gofmt

* make gen-go

* make update-workspace

* add COPY apps/quotas to Dockerfile

* fix test mock

* fixes undefined NewFolderStatus()

* make gen-apps, and add func for NewFolderStatus

* make gen-apps again

* make update-workspace

* regen folder_object_gen.go

* gofmt

* fix linting

* apps/folder make update-workspace

* make gen-apps

* make gen-apps

* fixes enterprise_imports.go

* go get testcontainers

* adds feature toggle

* make update-workspace

* fix go mod

* fix another client mock

---------

Co-authored-by: Steve Simpson <steve@grafana.com>
This commit is contained in:
owensmallwood
2025-12-09 09:40:34 -06:00
committed by GitHub
co-authored by Steve Simpson
parent 297e886e1b
commit a3daf0e39d
47 changed files with 1758 additions and 149 deletions
@@ -0,0 +1,33 @@
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
package v0alpha1
import (
"github.com/grafana/grafana-app-sdk/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
)
type GetUsageRequestParamsObject struct {
metav1.TypeMeta `json:",inline"`
GetUsageRequestParams `json:",inline"`
}
func NewGetUsageRequestParamsObject() *GetUsageRequestParamsObject {
return &GetUsageRequestParamsObject{}
}
func (o *GetUsageRequestParamsObject) DeepCopyObject() runtime.Object {
dst := NewGetUsageRequestParamsObject()
o.DeepCopyInto(dst)
return dst
}
func (o *GetUsageRequestParamsObject) DeepCopyInto(dst *GetUsageRequestParamsObject) {
dst.TypeMeta.APIVersion = o.TypeMeta.APIVersion
dst.TypeMeta.Kind = o.TypeMeta.Kind
dstGetUsageRequestParams := GetUsageRequestParams{}
_ = resource.CopyObjectInto(&dstGetUsageRequestParams, &o.GetUsageRequestParams)
}
var _ runtime.Object = NewGetUsageRequestParamsObject()
@@ -0,0 +1,13 @@
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
package v0alpha1
type GetUsageRequestParams struct {
Group string `json:"group"`
Resource string `json:"resource"`
}
// NewGetUsageRequestParams creates a new GetUsageRequestParams object.
func NewGetUsageRequestParams() *GetUsageRequestParams {
return &GetUsageRequestParams{}
}
@@ -0,0 +1,17 @@
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
package v0alpha1
// +k8s:openapi-gen=true
type GetUsageBody struct {
Namespace string `json:"namespace"`
Resource string `json:"resource"`
Group string `json:"group"`
Usage int64 `json:"usage"`
Limit int64 `json:"limit"`
}
// NewGetUsageBody creates a new GetUsageBody object.
func NewGetUsageBody() *GetUsageBody {
return &GetUsageBody{}
}
@@ -0,0 +1,37 @@
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
package v0alpha1
import (
"github.com/grafana/grafana-app-sdk/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
)
// +k8s:openapi-gen=true
type GetUsage struct {
metav1.TypeMeta `json:",inline"`
GetUsageBody `json:",inline"`
}
func NewGetUsage() *GetUsage {
return &GetUsage{}
}
func (t *GetUsageBody) DeepCopyInto(dst *GetUsageBody) {
_ = resource.CopyObjectInto(dst, t)
}
func (o *GetUsage) DeepCopyObject() runtime.Object {
dst := NewGetUsage()
o.DeepCopyInto(dst)
return dst
}
func (o *GetUsage) DeepCopyInto(dst *GetUsage) {
dst.TypeMeta.APIVersion = o.TypeMeta.APIVersion
dst.TypeMeta.Kind = o.TypeMeta.Kind
o.GetUsageBody.DeepCopyInto(&dst.GetUsageBody)
}
var _ runtime.Object = NewGetUsage()
+213
View File
@@ -0,0 +1,213 @@
//
// This file is generated by grafana-app-sdk
// DO NOT EDIT
//
package apis
import (
"fmt"
"strings"
"github.com/grafana/grafana-app-sdk/app"
"github.com/grafana/grafana-app-sdk/resource"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/kube-openapi/pkg/spec3"
"k8s.io/kube-openapi/pkg/validation/spec"
v0alpha1 "github.com/grafana/grafana/apps/quotas/pkg/apis/quotas/v0alpha1"
)
var appManifestData = app.ManifestData{
AppName: "quotas",
Group: "quotas.grafana.app",
PreferredVersion: "v0alpha1",
Versions: []app.ManifestVersion{
{
Name: "v0alpha1",
Served: true,
Kinds: []app.ManifestVersionKind{},
Routes: app.ManifestVersionRoutes{
Namespaced: map[string]spec3.PathProps{
"/usage": {
Get: &spec3.Operation{
OperationProps: spec3.OperationProps{
OperationId: "getUsage",
Parameters: []*spec3.Parameter{
{
ParameterProps: spec3.ParameterProps{
Name: "group",
In: "query",
Required: true,
Schema: &spec.Schema{
SchemaProps: spec.SchemaProps{
Type: []string{"string"},
},
},
},
},
{
ParameterProps: spec3.ParameterProps{
Name: "resource",
In: "query",
Required: true,
Schema: &spec.Schema{
SchemaProps: spec.SchemaProps{
Type: []string{"string"},
},
},
},
},
},
Responses: &spec3.Responses{
ResponsesProps: spec3.ResponsesProps{
Default: &spec3.Response{
ResponseProps: spec3.ResponseProps{
Description: "Default OK response",
Content: map[string]*spec3.MediaType{
"application/json": {
MediaTypeProps: spec3.MediaTypeProps{
Schema: &spec.Schema{
SchemaProps: spec.SchemaProps{
Type: []string{"object"},
Properties: map[string]spec.Schema{
"apiVersion": {
SchemaProps: spec.SchemaProps{
Type: []string{"string"},
Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
},
},
"group": {
SchemaProps: spec.SchemaProps{
Type: []string{"string"},
},
},
"kind": {
SchemaProps: spec.SchemaProps{
Type: []string{"string"},
Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
},
},
"limit": {
SchemaProps: spec.SchemaProps{
Type: []string{"integer"},
},
},
"namespace": {
SchemaProps: spec.SchemaProps{
Type: []string{"string"},
},
},
"resource": {
SchemaProps: spec.SchemaProps{
Type: []string{"string"},
},
},
"usage": {
SchemaProps: spec.SchemaProps{
Type: []string{"integer"},
},
},
},
Required: []string{
"namespace",
"resource",
"group",
"usage",
"limit",
"apiVersion",
"kind",
},
}},
}},
},
},
},
}},
},
},
},
},
Cluster: map[string]spec3.PathProps{},
Schemas: map[string]spec.Schema{},
},
},
},
}
func LocalManifest() app.Manifest {
return app.NewEmbeddedManifest(appManifestData)
}
func RemoteManifest() app.Manifest {
return app.NewAPIServerManifest("quotas")
}
var kindVersionToGoType = map[string]resource.Kind{}
// ManifestGoTypeAssociator returns the associated resource.Kind instance for a given Kind and Version, if one exists.
// If there is no association for the provided Kind and Version, exists will return false.
func ManifestGoTypeAssociator(kind, version string) (goType resource.Kind, exists bool) {
goType, exists = kindVersionToGoType[fmt.Sprintf("%s/%s", kind, version)]
return goType, exists
}
var customRouteToGoResponseType = map[string]any{
"v0alpha1||<namespace>/usage|GET": v0alpha1.GetUsage{},
}
// ManifestCustomRouteResponsesAssociator returns the associated response go type for a given kind, version, custom route path, and method, if one exists.
// kind may be empty for custom routes which are not kind subroutes. Leading slashes are removed from subroute paths.
// If there is no association for the provided kind, version, custom route path, and method, exists will return false.
// Resource routes (those without a kind) should prefix their route with "<namespace>/" if the route is namespaced (otherwise the route is assumed to be cluster-scope)
func ManifestCustomRouteResponsesAssociator(kind, version, path, verb string) (goType any, exists bool) {
if len(path) > 0 && path[0] == '/' {
path = path[1:]
}
goType, exists = customRouteToGoResponseType[fmt.Sprintf("%s|%s|%s|%s", version, kind, path, strings.ToUpper(verb))]
return goType, exists
}
var customRouteToGoParamsType = map[string]runtime.Object{}
func ManifestCustomRouteQueryAssociator(kind, version, path, verb string) (goType runtime.Object, exists bool) {
if len(path) > 0 && path[0] == '/' {
path = path[1:]
}
goType, exists = customRouteToGoParamsType[fmt.Sprintf("%s|%s|%s|%s", version, kind, path, strings.ToUpper(verb))]
return goType, exists
}
var customRouteToGoRequestBodyType = map[string]any{}
func ManifestCustomRouteRequestBodyAssociator(kind, version, path, verb string) (goType any, exists bool) {
if len(path) > 0 && path[0] == '/' {
path = path[1:]
}
goType, exists = customRouteToGoRequestBodyType[fmt.Sprintf("%s|%s|%s|%s", version, kind, path, strings.ToUpper(verb))]
return goType, exists
}
type GoTypeAssociator struct{}
func NewGoTypeAssociator() *GoTypeAssociator {
return &GoTypeAssociator{}
}
func (g *GoTypeAssociator) KindToGoType(kind, version string) (goType resource.Kind, exists bool) {
return ManifestGoTypeAssociator(kind, version)
}
func (g *GoTypeAssociator) CustomRouteReturnGoType(kind, version, path, verb string) (goType any, exists bool) {
return ManifestCustomRouteResponsesAssociator(kind, version, path, verb)
}
func (g *GoTypeAssociator) CustomRouteQueryGoType(kind, version, path, verb string) (goType runtime.Object, exists bool) {
return ManifestCustomRouteQueryAssociator(kind, version, path, verb)
}
func (g *GoTypeAssociator) CustomRouteRequestBodyGoType(kind, version, path, verb string) (goType any, exists bool) {
return ManifestCustomRouteRequestBodyAssociator(kind, version, path, verb)
}