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
+33
View File
@@ -41,6 +41,7 @@ type ResourceServer interface {
resourcepb.ManagedObjectIndexServer
resourcepb.BlobStoreServer
resourcepb.DiagnosticsServer
resourcepb.QuotasServer
}
type ListIterator interface {
@@ -1466,6 +1467,38 @@ func (s *server) PutBlob(ctx context.Context, req *resourcepb.PutBlobRequest) (*
return rsp, nil
}
func (s *server) GetQuotaUsage(ctx context.Context, req *resourcepb.QuotaUsageRequest) (*resourcepb.QuotaUsageResponse, error) {
if s.overridesService == nil {
return &resourcepb.QuotaUsageResponse{Error: &resourcepb.ErrorResult{
Message: "overrides service not configured on resource server",
Code: http.StatusNotImplemented,
}}, nil
}
nsr := NamespacedResource{
Namespace: req.Key.Namespace,
Group: req.Key.Group,
Resource: req.Key.Resource,
}
usage, err := s.backend.GetResourceStats(ctx, nsr, 0)
if err != nil {
return &resourcepb.QuotaUsageResponse{Error: AsErrorResult(err)}, nil
}
limit, err := s.overridesService.GetQuota(ctx, nsr)
if err != nil {
return &resourcepb.QuotaUsageResponse{Error: AsErrorResult(err)}, nil
}
// handle case where no resources exist yet - very unlikely but possible
rsp := &resourcepb.QuotaUsageResponse{Limit: int64(limit.Limit)}
if len(usage) <= 0 {
rsp.Usage = 0
} else {
rsp.Usage = usage[0].Count
}
return rsp, nil
}
func (s *server) getPartialObject(ctx context.Context, key *resourcepb.ResourceKey, rv int64) (utils.GrafanaMetaAccessor, *resourcepb.ErrorResult) {
if r := verifyRequestKey(key); r != nil {
return nil, r