a3daf0e39d
* 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>
124 lines
3.3 KiB
Go
124 lines
3.3 KiB
Go
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/operator"
|
|
"github.com/grafana/grafana-app-sdk/resource"
|
|
"github.com/grafana/grafana/pkg/storage/unified/resourcepb"
|
|
|
|
unifiedStorage "github.com/grafana/grafana/pkg/storage/unified/resource"
|
|
|
|
"github.com/grafana/grafana-app-sdk/simple"
|
|
quotasv0alpha1 "github.com/grafana/grafana/apps/quotas/pkg/apis/quotas/v0alpha1"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
|
)
|
|
|
|
type QuotasAppConfig struct {
|
|
ResourceClient unifiedStorage.ResourceClient
|
|
}
|
|
|
|
type QuotasHandler struct {
|
|
ResourceClient unifiedStorage.ResourceClient
|
|
}
|
|
|
|
func NewQuotasHandler(cfg *QuotasAppConfig) *QuotasHandler {
|
|
return &QuotasHandler{
|
|
ResourceClient: cfg.ResourceClient,
|
|
}
|
|
}
|
|
|
|
// GetQuota handles requests for the GET /usage resource route
|
|
func (h *QuotasHandler) GetQuota(ctx context.Context, writer app.CustomRouteResponseWriter, request *app.CustomRouteRequest) error {
|
|
if !request.URL.Query().Has("group") {
|
|
// TODO its returning a 500 instead of 400 bad request
|
|
writer.WriteHeader(http.StatusBadRequest)
|
|
return fmt.Errorf("missing required query parameters: group")
|
|
}
|
|
if !request.URL.Query().Has("resource") {
|
|
writer.WriteHeader(http.StatusBadRequest)
|
|
return fmt.Errorf("missing required query parameters: resource")
|
|
}
|
|
group := request.URL.Query().Get("group")
|
|
res := request.URL.Query().Get("resource")
|
|
|
|
quotaReq := &resourcepb.QuotaUsageRequest{
|
|
Key: &resourcepb.ResourceKey{
|
|
Namespace: request.ResourceIdentifier.Namespace,
|
|
Group: group,
|
|
Resource: res,
|
|
},
|
|
}
|
|
quota, err := h.ResourceClient.GetQuotaUsage(ctx, quotaReq)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
writer.Header().Set("Content-Type", "application/json")
|
|
return json.NewEncoder(writer).Encode(quotasv0alpha1.GetUsage{
|
|
TypeMeta: metav1.TypeMeta{
|
|
APIVersion: "quotas.grafana.com/v0alpha1",
|
|
Kind: "Quotas",
|
|
},
|
|
GetUsageBody: quotasv0alpha1.GetUsageBody{
|
|
Namespace: request.ResourceIdentifier.Namespace,
|
|
Group: group,
|
|
Resource: res,
|
|
Usage: quota.Usage,
|
|
Limit: quota.Limit,
|
|
},
|
|
})
|
|
}
|
|
|
|
func New(cfg app.Config) (app.App, error) {
|
|
appConfig, ok := cfg.SpecificConfig.(*QuotasAppConfig)
|
|
if !ok {
|
|
return nil, fmt.Errorf("expected QuotasAppConfig but got %T", cfg.SpecificConfig)
|
|
}
|
|
handler := NewQuotasHandler(appConfig)
|
|
|
|
simpleConfig := simple.AppConfig{
|
|
Name: "quotas",
|
|
KubeConfig: cfg.KubeConfig,
|
|
InformerConfig: simple.AppInformerConfig{
|
|
InformerOptions: operator.InformerOptions{
|
|
ErrorHandler: func(ctx context.Context, err error) {
|
|
logging.FromContext(ctx).Error("Informer processing error", "error", err)
|
|
},
|
|
},
|
|
},
|
|
ManagedKinds: []simple.AppManagedKind{},
|
|
VersionedCustomRoutes: map[string]simple.AppVersionRouteHandlers{
|
|
"v0alpha1": {
|
|
{
|
|
Namespaced: true,
|
|
Path: "usage",
|
|
Method: "GET",
|
|
}: handler.GetQuota,
|
|
},
|
|
},
|
|
}
|
|
|
|
a, err := simple.NewApp(simpleConfig)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
err = a.ValidateManifest(cfg.ManifestData)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return a, nil
|
|
}
|
|
|
|
func GetKinds() map[schema.GroupVersion][]resource.Kind {
|
|
return map[schema.GroupVersion][]resource.Kind{}
|
|
}
|