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:
co-authored by
Steve Simpson
parent
297e886e1b
commit
a3daf0e39d
@@ -56,7 +56,8 @@ import (
|
||||
_ "github.com/grafana/e2e"
|
||||
_ "github.com/grafana/gofpdf"
|
||||
_ "github.com/grafana/gomemcache/memcache"
|
||||
_ "github.com/grafana/tempo/pkg/traceql"
|
||||
|
||||
_ "github.com/grafana/grafana/apps/alerting/alertenrichment/pkg/apis/alertenrichment/v1beta1"
|
||||
_ "github.com/grafana/grafana/apps/scope/pkg/apis/scope/v0alpha1"
|
||||
_ "github.com/grafana/tempo/pkg/traceql"
|
||||
)
|
||||
|
||||
@@ -95,3 +95,7 @@ func (d *directResourceClient) BulkProcess(ctx context.Context, opts ...grpc.Cal
|
||||
func (b *directResourceClient) RebuildIndexes(ctx context.Context, req *resourcepb.RebuildIndexesRequest, opts ...grpc.CallOption) (*resourcepb.RebuildIndexesResponse, error) {
|
||||
return nil, fmt.Errorf("not implemented")
|
||||
}
|
||||
|
||||
func (b *directResourceClient) GetQuotaUsage(ctx context.Context, req *resourcepb.QuotaUsageRequest, opts ...grpc.CallOption) (*resourcepb.QuotaUsageResponse, error) {
|
||||
return nil, fmt.Errorf("not implemented")
|
||||
}
|
||||
|
||||
@@ -1103,3 +1103,7 @@ func (m *MockClient) BulkProcess(ctx context.Context, opts ...grpc.CallOption) (
|
||||
func (m *MockClient) UpdateIndex(ctx context.Context, reason string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockClient) GetQuotaUsage(ctx context.Context, req *resourcepb.QuotaUsageRequest, opts ...grpc.CallOption) (*resourcepb.QuotaUsageResponse, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -284,3 +284,6 @@ func (m *MockClient) BulkProcess(ctx context.Context, opts ...grpc.CallOption) (
|
||||
func (m *MockClient) UpdateIndex(ctx context.Context, reason string) error {
|
||||
return nil
|
||||
}
|
||||
func (m *MockClient) GetQuotaUsage(ctx context.Context, in *resourcepb.QuotaUsageRequest, opts ...grpc.CallOption) (*resourcepb.QuotaUsageResponse, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ package appregistry
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana/pkg/registry/apps/quotas"
|
||||
"github.com/open-feature/go-sdk/openfeature"
|
||||
"k8s.io/client-go/rest"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/app"
|
||||
@@ -44,12 +46,17 @@ func ProvideAppInstallers(
|
||||
exampleAppInstaller *example.ExampleAppInstaller,
|
||||
advisorAppInstaller *advisor.AdvisorAppInstaller,
|
||||
alertingHistorianAppInstaller *historian.AlertingHistorianAppInstaller,
|
||||
quotasAppInstaller *quotas.QuotasAppInstaller,
|
||||
) []appsdkapiserver.AppInstaller {
|
||||
featureClient := openfeature.NewDefaultClient()
|
||||
installers := []appsdkapiserver.AppInstaller{
|
||||
playlistAppInstaller,
|
||||
pluginsApplInstaller,
|
||||
exampleAppInstaller,
|
||||
}
|
||||
if featureClient.Boolean(context.Background(), featuremgmt.FlagKubernetesUnifiedStorageQuotas, false, openfeature.TransactionContext(context.Background())) {
|
||||
installers = append(installers, quotasAppInstaller)
|
||||
}
|
||||
//nolint:staticcheck // not yet migrated to OpenFeature
|
||||
if features.IsEnabledGlobally(featuremgmt.FlagKubernetesShortURLs) {
|
||||
installers = append(installers, shorturlAppInstaller)
|
||||
|
||||
@@ -3,6 +3,7 @@ package appregistry
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/registry/apps/quotas"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/registry/apps/advisor"
|
||||
@@ -27,6 +28,7 @@ func TestProvideAppInstallers_Table(t *testing.T) {
|
||||
exampleAppInstaller := &example.ExampleAppInstaller{}
|
||||
advisorAppInstaller := &advisor.AdvisorAppInstaller{}
|
||||
historianAppInstaller := &historian.AlertingHistorianAppInstaller{}
|
||||
quotasAppInstaller := "as.QuotasAppInstaller{}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -43,7 +45,7 @@ func TestProvideAppInstallers_Table(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
features := featuremgmt.WithFeatures(tt.flags...)
|
||||
got := ProvideAppInstallers(features, playlistInstaller, pluginsInstaller, nil, tt.rulesInst, correlationsAppInstaller, notificationsAppInstaller, nil, annotationAppInstaller, exampleAppInstaller, advisorAppInstaller, historianAppInstaller)
|
||||
got := ProvideAppInstallers(features, playlistInstaller, pluginsInstaller, nil, tt.rulesInst, correlationsAppInstaller, notificationsAppInstaller, nil, annotationAppInstaller, exampleAppInstaller, advisorAppInstaller, historianAppInstaller, quotasAppInstaller)
|
||||
if tt.expectRulesApp {
|
||||
require.Contains(t, got, tt.rulesInst)
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
package quotas
|
||||
|
||||
import (
|
||||
"github.com/grafana/grafana/apps/quotas/pkg/apis"
|
||||
"github.com/grafana/grafana/pkg/storage/unified/resource"
|
||||
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"
|
||||
quotasapp "github.com/grafana/grafana/apps/quotas/pkg/app"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
var (
|
||||
_ appsdkapiserver.AppInstaller = (*QuotasAppInstaller)(nil)
|
||||
)
|
||||
|
||||
type QuotasAppInstaller struct {
|
||||
appsdkapiserver.AppInstaller
|
||||
cfg *setting.Cfg
|
||||
}
|
||||
|
||||
func RegisterAppInstaller(
|
||||
cfg *setting.Cfg,
|
||||
features featuremgmt.FeatureToggles,
|
||||
resourceClient resource.ResourceClient,
|
||||
) (*QuotasAppInstaller, error) {
|
||||
installer := &QuotasAppInstaller{
|
||||
cfg: cfg,
|
||||
}
|
||||
specificConfig := "asapp.QuotasAppConfig{
|
||||
ResourceClient: resourceClient,
|
||||
}
|
||||
provider := simple.NewAppProvider(apis.LocalManifest(), specificConfig, quotasapp.New)
|
||||
|
||||
appConfig := app.Config{
|
||||
KubeConfig: restclient.Config{}, // this will be overridden by the installer's InitializeApp method
|
||||
ManifestData: *apis.LocalManifest().ManifestData,
|
||||
SpecificConfig: specificConfig,
|
||||
}
|
||||
i, err := appsdkapiserver.NewDefaultAppInstaller(provider, appConfig, apis.NewGoTypeAssociator())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
installer.AppInstaller = i
|
||||
|
||||
return installer, nil
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package appregistry
|
||||
|
||||
import (
|
||||
"github.com/google/wire"
|
||||
"github.com/grafana/grafana/pkg/registry/apps/quotas"
|
||||
|
||||
"github.com/grafana/grafana/pkg/registry/apps/alerting/historian"
|
||||
"github.com/grafana/grafana/pkg/registry/apps/alerting/notifications"
|
||||
@@ -29,5 +30,6 @@ var WireSet = wire.NewSet(
|
||||
historian.RegisterAppInstaller,
|
||||
logsdrilldown.RegisterAppInstaller,
|
||||
annotation.RegisterAppInstaller,
|
||||
quotas.RegisterAppInstaller,
|
||||
example.RegisterAppInstaller,
|
||||
)
|
||||
|
||||
Generated
+11
-2
@@ -89,6 +89,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/registry/apps/logsdrilldown"
|
||||
"github.com/grafana/grafana/pkg/registry/apps/playlist"
|
||||
"github.com/grafana/grafana/pkg/registry/apps/plugins"
|
||||
"github.com/grafana/grafana/pkg/registry/apps/quotas"
|
||||
"github.com/grafana/grafana/pkg/registry/apps/shorturl"
|
||||
"github.com/grafana/grafana/pkg/registry/backgroundsvcs"
|
||||
"github.com/grafana/grafana/pkg/registry/usagestatssvcs"
|
||||
@@ -824,7 +825,11 @@ func Initialize(ctx context.Context, cfg *setting.Cfg, opts Options, apiOpts api
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
v2 := appregistry.ProvideAppInstallers(featureToggles, playlistAppInstaller, appInstaller, shortURLAppInstaller, alertingRulesAppInstaller, correlationsAppInstaller, alertingNotificationsAppInstaller, logsDrilldownAppInstaller, annotationAppInstaller, exampleAppInstaller, advisorAppInstaller, alertingHistorianAppInstaller)
|
||||
quotasAppInstaller, err := quotas.RegisterAppInstaller(cfg, featureToggles, resourceClient)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
v2 := appregistry.ProvideAppInstallers(featureToggles, playlistAppInstaller, appInstaller, shortURLAppInstaller, alertingRulesAppInstaller, correlationsAppInstaller, alertingNotificationsAppInstaller, logsDrilldownAppInstaller, annotationAppInstaller, exampleAppInstaller, advisorAppInstaller, alertingHistorianAppInstaller, quotasAppInstaller)
|
||||
builderMetrics := builder.ProvideBuilderMetrics(registerer)
|
||||
apiserverService, err := apiserver.ProvideService(cfg, featureToggles, routeRegisterImpl, tracingService, serverLockService, sqlStore, kvStore, middlewareHandler, scopedPluginDatasourceProvider, plugincontextProvider, pluginstoreService, dualwriteService, resourceClient, inlineSecureValueSupport, eventualRestConfigProvider, v, eventualRestConfigProvider, registerer, aggregatorRunner, v2, builderMetrics)
|
||||
if err != nil {
|
||||
@@ -1477,7 +1482,11 @@ func InitializeForTest(ctx context.Context, t sqlutil.ITestDB, testingT interfac
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
v2 := appregistry.ProvideAppInstallers(featureToggles, playlistAppInstaller, appInstaller, shortURLAppInstaller, alertingRulesAppInstaller, correlationsAppInstaller, alertingNotificationsAppInstaller, logsDrilldownAppInstaller, annotationAppInstaller, exampleAppInstaller, advisorAppInstaller, alertingHistorianAppInstaller)
|
||||
quotasAppInstaller, err := quotas.RegisterAppInstaller(cfg, featureToggles, resourceClient)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
v2 := appregistry.ProvideAppInstallers(featureToggles, playlistAppInstaller, appInstaller, shortURLAppInstaller, alertingRulesAppInstaller, correlationsAppInstaller, alertingNotificationsAppInstaller, logsDrilldownAppInstaller, annotationAppInstaller, exampleAppInstaller, advisorAppInstaller, alertingHistorianAppInstaller, quotasAppInstaller)
|
||||
builderMetrics := builder.ProvideBuilderMetrics(registerer)
|
||||
apiserverService, err := apiserver.ProvideService(cfg, featureToggles, routeRegisterImpl, tracingService, serverLockService, sqlStore, kvStore, middlewareHandler, scopedPluginDatasourceProvider, plugincontextProvider, pluginstoreService, dualwriteService, resourceClient, inlineSecureValueSupport, eventualRestConfigProvider, v, eventualRestConfigProvider, registerer, aggregatorRunner, v2, builderMetrics)
|
||||
if err != nil {
|
||||
|
||||
@@ -414,6 +414,13 @@ var (
|
||||
Owner: grafanaDataProSquad,
|
||||
RequiresRestart: true,
|
||||
},
|
||||
{
|
||||
Name: "kubernetesUnifiedStorageQuotas",
|
||||
Description: "Adds support for Kubernetes unified storage quotas",
|
||||
Stage: FeatureStageExperimental,
|
||||
Owner: grafanaSearchAndStorageSquad,
|
||||
RequiresRestart: true,
|
||||
},
|
||||
{
|
||||
Name: "kubernetesLogsDrilldown",
|
||||
Description: "Adds support for Kubernetes logs drilldown",
|
||||
|
||||
Generated
+1
@@ -56,6 +56,7 @@ kubernetesShortURLs,experimental,@grafana/grafana-app-platform-squad,false,true,
|
||||
useKubernetesShortURLsAPI,experimental,@grafana/sharing-squad,false,false,true
|
||||
kubernetesAlertingRules,experimental,@grafana/alerting-squad,false,true,false
|
||||
kubernetesCorrelations,experimental,@grafana/datapro,false,true,false
|
||||
kubernetesUnifiedStorageQuotas,experimental,@grafana/search-and-storage,false,true,false
|
||||
kubernetesLogsDrilldown,experimental,@grafana/observability-logs,false,true,false
|
||||
kubernetesQueryCaching,experimental,@grafana/grafana-operator-experience-squad,false,true,false
|
||||
dashboardDisableSchemaValidationV1,experimental,@grafana/grafana-app-platform-squad,false,false,false
|
||||
|
||||
|
Generated
+4
@@ -183,6 +183,10 @@ const (
|
||||
// Adds support for Kubernetes correlations
|
||||
FlagKubernetesCorrelations = "kubernetesCorrelations"
|
||||
|
||||
// FlagKubernetesUnifiedStorageQuotas
|
||||
// Adds support for Kubernetes unified storage quotas
|
||||
FlagKubernetesUnifiedStorageQuotas = "kubernetesUnifiedStorageQuotas"
|
||||
|
||||
// FlagKubernetesLogsDrilldown
|
||||
// Adds support for Kubernetes logs drilldown
|
||||
FlagKubernetesLogsDrilldown = "kubernetesLogsDrilldown"
|
||||
|
||||
+13
@@ -2039,6 +2039,19 @@
|
||||
"requiresRestart": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"name": "kubernetesUnifiedStorageQuotas",
|
||||
"resourceVersion": "1764965198011",
|
||||
"creationTimestamp": "2025-12-05T20:06:38Z"
|
||||
},
|
||||
"spec": {
|
||||
"description": "Adds support for Kubernetes unified storage quotas",
|
||||
"stage": "experimental",
|
||||
"codeowner": "@grafana/search-and-storage",
|
||||
"requiresRestart": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"name": "localeFormatPreference",
|
||||
|
||||
@@ -166,6 +166,7 @@ type resourceClientMock struct {
|
||||
resourcepb.BulkStoreClient
|
||||
resourcepb.BlobStoreClient
|
||||
resourcepb.DiagnosticsClient
|
||||
resourcepb.QuotasClient
|
||||
}
|
||||
|
||||
// always return GRPC Unauthenticated code
|
||||
|
||||
@@ -587,6 +587,22 @@ message ResourceTableRow {
|
||||
bytes object = 4;
|
||||
}
|
||||
|
||||
message QuotaUsageRequest {
|
||||
// Namespace (tenant)
|
||||
ResourceKey key = 1;
|
||||
}
|
||||
|
||||
message QuotaUsageResponse {
|
||||
// Error details
|
||||
ErrorResult error = 1;
|
||||
|
||||
// Current usage
|
||||
int64 usage = 2;
|
||||
|
||||
// Current limit
|
||||
int64 limit = 3;
|
||||
}
|
||||
|
||||
// This provides the CRUD+List+Watch support needed for a k8s apiserver
|
||||
// The semantics and behaviors of this service are constrained by kubernetes
|
||||
// This does not understand the resource schemas, only deals with json bytes
|
||||
@@ -631,3 +647,8 @@ service Diagnostics {
|
||||
// Check if the service is healthy
|
||||
rpc IsHealthy(HealthCheckRequest) returns (HealthCheckResponse);
|
||||
}
|
||||
|
||||
service Quotas {
|
||||
// Get current quota usage and limits
|
||||
rpc GetQuotaUsage(QuotaUsageRequest) returns (QuotaUsageResponse);
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ type ResourceClient interface {
|
||||
resourcepb.BulkStoreClient
|
||||
resourcepb.BlobStoreClient
|
||||
resourcepb.DiagnosticsClient
|
||||
resourcepb.QuotasClient
|
||||
}
|
||||
|
||||
// Internal implementation
|
||||
@@ -49,6 +50,7 @@ type resourceClient struct {
|
||||
resourcepb.BulkStoreClient
|
||||
resourcepb.BlobStoreClient
|
||||
resourcepb.DiagnosticsClient
|
||||
resourcepb.QuotasClient
|
||||
}
|
||||
|
||||
func NewResourceClient(conn, indexConn grpc.ClientConnInterface, cfg *setting.Cfg, features featuremgmt.FeatureToggles, tracer trace.Tracer) (ResourceClient, error) {
|
||||
@@ -76,6 +78,7 @@ func newResourceClient(storageCc grpc.ClientConnInterface, indexCc grpc.ClientCo
|
||||
BulkStoreClient: resourcepb.NewBulkStoreClient(storageCc),
|
||||
BlobStoreClient: resourcepb.NewBlobStoreClient(storageCc),
|
||||
DiagnosticsClient: resourcepb.NewDiagnosticsClient(storageCc),
|
||||
QuotasClient: resourcepb.NewQuotasClient(storageCc),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,6 +105,7 @@ func NewLocalResourceClient(server ResourceServer) ResourceClient {
|
||||
&resourcepb.BlobStore_ServiceDesc,
|
||||
&resourcepb.BulkStore_ServiceDesc,
|
||||
&resourcepb.Diagnostics_ServiceDesc,
|
||||
&resourcepb.Quotas_ServiceDesc,
|
||||
} {
|
||||
channel.RegisterService(
|
||||
grpchan.InterceptServer(
|
||||
|
||||
@@ -394,6 +394,80 @@ func (_c *MockResourceClient_GetBlob_Call) RunAndReturn(run func(context.Context
|
||||
return _c
|
||||
}
|
||||
|
||||
// GetQuotaUsage provides a mock function with given fields: ctx, in, opts
|
||||
func (_m *MockResourceClient) GetQuotaUsage(ctx context.Context, in *resourcepb.QuotaUsageRequest, opts ...grpc.CallOption) (*resourcepb.QuotaUsageResponse, error) {
|
||||
_va := make([]interface{}, len(opts))
|
||||
for _i := range opts {
|
||||
_va[_i] = opts[_i]
|
||||
}
|
||||
var _ca []interface{}
|
||||
_ca = append(_ca, ctx, in)
|
||||
_ca = append(_ca, _va...)
|
||||
ret := _m.Called(_ca...)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetQuotaUsage")
|
||||
}
|
||||
|
||||
var r0 *resourcepb.QuotaUsageResponse
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *resourcepb.QuotaUsageRequest, ...grpc.CallOption) (*resourcepb.QuotaUsageResponse, error)); ok {
|
||||
return rf(ctx, in, opts...)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *resourcepb.QuotaUsageRequest, ...grpc.CallOption) *resourcepb.QuotaUsageResponse); ok {
|
||||
r0 = rf(ctx, in, opts...)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*resourcepb.QuotaUsageResponse)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *resourcepb.QuotaUsageRequest, ...grpc.CallOption) error); ok {
|
||||
r1 = rf(ctx, in, opts...)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// MockResourceClient_GetQuotaUsage_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetQuotaUsage'
|
||||
type MockResourceClient_GetQuotaUsage_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// GetQuotaUsage is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - in *resourcepb.QuotaUsageRequest
|
||||
// - opts ...grpc.CallOption
|
||||
func (_e *MockResourceClient_Expecter) GetQuotaUsage(ctx interface{}, in interface{}, opts ...interface{}) *MockResourceClient_GetQuotaUsage_Call {
|
||||
return &MockResourceClient_GetQuotaUsage_Call{Call: _e.mock.On("GetQuotaUsage",
|
||||
append([]interface{}{ctx, in}, opts...)...)}
|
||||
}
|
||||
|
||||
func (_c *MockResourceClient_GetQuotaUsage_Call) Run(run func(ctx context.Context, in *resourcepb.QuotaUsageRequest, opts ...grpc.CallOption)) *MockResourceClient_GetQuotaUsage_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
variadicArgs := make([]grpc.CallOption, len(args)-2)
|
||||
for i, a := range args[2:] {
|
||||
if a != nil {
|
||||
variadicArgs[i] = a.(grpc.CallOption)
|
||||
}
|
||||
}
|
||||
run(args[0].(context.Context), args[1].(*resourcepb.QuotaUsageRequest), variadicArgs...)
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockResourceClient_GetQuotaUsage_Call) Return(_a0 *resourcepb.QuotaUsageResponse, _a1 error) *MockResourceClient_GetQuotaUsage_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockResourceClient_GetQuotaUsage_Call) RunAndReturn(run func(context.Context, *resourcepb.QuotaUsageRequest, ...grpc.CallOption) (*resourcepb.QuotaUsageResponse, error)) *MockResourceClient_GetQuotaUsage_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// GetStats provides a mock function with given fields: ctx, in, opts
|
||||
func (_m *MockResourceClient) GetStats(ctx context.Context, in *resourcepb.ResourceStatsRequest, opts ...grpc.CallOption) (*resourcepb.ResourceStatsResponse, error) {
|
||||
_va := make([]interface{}, len(opts))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -5,6 +5,8 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
@@ -22,6 +24,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/storage/unified/resourcepb"
|
||||
"github.com/grafana/grafana/pkg/util/scheduler"
|
||||
)
|
||||
@@ -614,3 +617,70 @@ func TestArtificialDelayAfterSuccessfulOperation(t *testing.T) {
|
||||
check(t, false, &resourcepb.UpdateResponse{Error: AsErrorResult(errors.New("some error"))}, nil)
|
||||
check(t, false, &resourcepb.DeleteResponse{Error: AsErrorResult(errors.New("some error"))}, nil)
|
||||
}
|
||||
|
||||
func TestGetQuotaUsage(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
t.Run("returns error when overrides service is not configured", func(t *testing.T) {
|
||||
s := &server{
|
||||
overridesService: nil,
|
||||
log: log.NewNopLogger(),
|
||||
}
|
||||
|
||||
resp, err := s.GetQuotaUsage(ctx, &resourcepb.QuotaUsageRequest{
|
||||
Key: &resourcepb.ResourceKey{
|
||||
Namespace: "stacks-123",
|
||||
Group: "dashboard.grafana.app",
|
||||
Resource: "dashboards",
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, resp.Error)
|
||||
assert.Equal(t, int32(http.StatusNotImplemented), resp.Error.Code)
|
||||
assert.Equal(t, "overrides service not configured on resource server", resp.Error.Message)
|
||||
})
|
||||
|
||||
t.Run("returns usage and limit successfully", func(t *testing.T) {
|
||||
// Create a temporary overrides config file
|
||||
tmpFile := filepath.Join(t.TempDir(), "overrides.yaml")
|
||||
content := `"123":
|
||||
quotas:
|
||||
dashboard.grafana.app/dashboards:
|
||||
limit: 500
|
||||
`
|
||||
require.NoError(t, os.WriteFile(tmpFile, []byte(content), 0644))
|
||||
|
||||
// Create a real OverridesService with the temp file
|
||||
overridesService, err := NewOverridesService(ctx, log.NewNopLogger(), prometheus.NewRegistry(), tracing.NewNoopTracerService(), ReloadOptions{
|
||||
FilePath: tmpFile,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, overridesService.init(ctx))
|
||||
defer func() {
|
||||
_ = overridesService.stop(ctx)
|
||||
}()
|
||||
|
||||
// Create a mock backend that returns resource stats (reusing mockStorageBackend from search_test.go)
|
||||
mockBackend := &mockStorageBackend{
|
||||
resourceStats: []ResourceStats{{Count: 42}},
|
||||
}
|
||||
|
||||
s := &server{
|
||||
backend: mockBackend,
|
||||
overridesService: overridesService,
|
||||
log: log.NewNopLogger(),
|
||||
}
|
||||
|
||||
resp, err := s.GetQuotaUsage(ctx, &resourcepb.QuotaUsageRequest{
|
||||
Key: &resourcepb.ResourceKey{
|
||||
Namespace: "stacks-123",
|
||||
Group: "dashboard.grafana.app",
|
||||
Resource: "dashboards",
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Nil(t, resp.Error)
|
||||
assert.Equal(t, int64(42), resp.Usage)
|
||||
assert.Equal(t, int64(500), resp.Limit)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -2484,6 +2484,114 @@ func (x *ResourceTableRow) GetObject() []byte {
|
||||
return nil
|
||||
}
|
||||
|
||||
type QuotaUsageRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
// Namespace (tenant)
|
||||
Key *ResourceKey `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *QuotaUsageRequest) Reset() {
|
||||
*x = QuotaUsageRequest{}
|
||||
mi := &file_resource_proto_msgTypes[30]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *QuotaUsageRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*QuotaUsageRequest) ProtoMessage() {}
|
||||
|
||||
func (x *QuotaUsageRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_resource_proto_msgTypes[30]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use QuotaUsageRequest.ProtoReflect.Descriptor instead.
|
||||
func (*QuotaUsageRequest) Descriptor() ([]byte, []int) {
|
||||
return file_resource_proto_rawDescGZIP(), []int{30}
|
||||
}
|
||||
|
||||
func (x *QuotaUsageRequest) GetKey() *ResourceKey {
|
||||
if x != nil {
|
||||
return x.Key
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type QuotaUsageResponse struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
// Error details
|
||||
Error *ErrorResult `protobuf:"bytes,1,opt,name=error,proto3" json:"error,omitempty"`
|
||||
// Current usage
|
||||
Usage int64 `protobuf:"varint,2,opt,name=usage,proto3" json:"usage,omitempty"`
|
||||
// Current limit
|
||||
Limit int64 `protobuf:"varint,3,opt,name=limit,proto3" json:"limit,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *QuotaUsageResponse) Reset() {
|
||||
*x = QuotaUsageResponse{}
|
||||
mi := &file_resource_proto_msgTypes[31]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *QuotaUsageResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*QuotaUsageResponse) ProtoMessage() {}
|
||||
|
||||
func (x *QuotaUsageResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_resource_proto_msgTypes[31]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use QuotaUsageResponse.ProtoReflect.Descriptor instead.
|
||||
func (*QuotaUsageResponse) Descriptor() ([]byte, []int) {
|
||||
return file_resource_proto_rawDescGZIP(), []int{31}
|
||||
}
|
||||
|
||||
func (x *QuotaUsageResponse) GetError() *ErrorResult {
|
||||
if x != nil {
|
||||
return x.Error
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *QuotaUsageResponse) GetUsage() int64 {
|
||||
if x != nil {
|
||||
return x.Usage
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *QuotaUsageResponse) GetLimit() int64 {
|
||||
if x != nil {
|
||||
return x.Limit
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type WatchEvent_Resource struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Version int64 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"`
|
||||
@@ -2494,7 +2602,7 @@ type WatchEvent_Resource struct {
|
||||
|
||||
func (x *WatchEvent_Resource) Reset() {
|
||||
*x = WatchEvent_Resource{}
|
||||
mi := &file_resource_proto_msgTypes[30]
|
||||
mi := &file_resource_proto_msgTypes[32]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -2506,7 +2614,7 @@ func (x *WatchEvent_Resource) String() string {
|
||||
func (*WatchEvent_Resource) ProtoMessage() {}
|
||||
|
||||
func (x *WatchEvent_Resource) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_resource_proto_msgTypes[30]
|
||||
mi := &file_resource_proto_msgTypes[32]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -2553,7 +2661,7 @@ type BulkResponse_Summary struct {
|
||||
|
||||
func (x *BulkResponse_Summary) Reset() {
|
||||
*x = BulkResponse_Summary{}
|
||||
mi := &file_resource_proto_msgTypes[31]
|
||||
mi := &file_resource_proto_msgTypes[33]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -2565,7 +2673,7 @@ func (x *BulkResponse_Summary) String() string {
|
||||
func (*BulkResponse_Summary) ProtoMessage() {}
|
||||
|
||||
func (x *BulkResponse_Summary) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_resource_proto_msgTypes[31]
|
||||
mi := &file_resource_proto_msgTypes[33]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -2649,7 +2757,7 @@ type BulkResponse_Rejected struct {
|
||||
|
||||
func (x *BulkResponse_Rejected) Reset() {
|
||||
*x = BulkResponse_Rejected{}
|
||||
mi := &file_resource_proto_msgTypes[32]
|
||||
mi := &file_resource_proto_msgTypes[34]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -2661,7 +2769,7 @@ func (x *BulkResponse_Rejected) String() string {
|
||||
func (*BulkResponse_Rejected) ProtoMessage() {}
|
||||
|
||||
func (x *BulkResponse_Rejected) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_resource_proto_msgTypes[32]
|
||||
mi := &file_resource_proto_msgTypes[34]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -2718,7 +2826,7 @@ type ListManagedObjectsResponse_Item struct {
|
||||
|
||||
func (x *ListManagedObjectsResponse_Item) Reset() {
|
||||
*x = ListManagedObjectsResponse_Item{}
|
||||
mi := &file_resource_proto_msgTypes[33]
|
||||
mi := &file_resource_proto_msgTypes[35]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -2730,7 +2838,7 @@ func (x *ListManagedObjectsResponse_Item) String() string {
|
||||
func (*ListManagedObjectsResponse_Item) ProtoMessage() {}
|
||||
|
||||
func (x *ListManagedObjectsResponse_Item) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_resource_proto_msgTypes[33]
|
||||
mi := &file_resource_proto_msgTypes[35]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -2801,7 +2909,7 @@ type CountManagedObjectsResponse_ResourceCount struct {
|
||||
|
||||
func (x *CountManagedObjectsResponse_ResourceCount) Reset() {
|
||||
*x = CountManagedObjectsResponse_ResourceCount{}
|
||||
mi := &file_resource_proto_msgTypes[34]
|
||||
mi := &file_resource_proto_msgTypes[36]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -2813,7 +2921,7 @@ func (x *CountManagedObjectsResponse_ResourceCount) String() string {
|
||||
func (*CountManagedObjectsResponse_ResourceCount) ProtoMessage() {}
|
||||
|
||||
func (x *CountManagedObjectsResponse_ResourceCount) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_resource_proto_msgTypes[34]
|
||||
mi := &file_resource_proto_msgTypes[36]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -2886,7 +2994,7 @@ type ResourceTableColumnDefinition_Properties struct {
|
||||
|
||||
func (x *ResourceTableColumnDefinition_Properties) Reset() {
|
||||
*x = ResourceTableColumnDefinition_Properties{}
|
||||
mi := &file_resource_proto_msgTypes[35]
|
||||
mi := &file_resource_proto_msgTypes[37]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -2898,7 +3006,7 @@ func (x *ResourceTableColumnDefinition_Properties) String() string {
|
||||
func (*ResourceTableColumnDefinition_Properties) ProtoMessage() {}
|
||||
|
||||
func (x *ResourceTableColumnDefinition_Properties) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_resource_proto_msgTypes[35]
|
||||
mi := &file_resource_proto_msgTypes[37]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -3320,68 +3428,85 @@ var file_resource_proto_rawDesc = string([]byte{
|
||||
0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
|
||||
0x12, 0x14, 0x0a, 0x05, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52,
|
||||
0x05, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74,
|
||||
0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2a, 0x49,
|
||||
0x0a, 0x14, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f,
|
||||
0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x12, 0x1b, 0x0a, 0x17, 0x44, 0x45, 0x50, 0x52, 0x45, 0x43,
|
||||
0x41, 0x54, 0x45, 0x44, 0x5f, 0x4e, 0x6f, 0x74, 0x4f, 0x6c, 0x64, 0x65, 0x72, 0x54, 0x68, 0x61,
|
||||
0x6e, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10, 0x44, 0x45, 0x50, 0x52, 0x45, 0x43, 0x41, 0x54, 0x45,
|
||||
0x44, 0x5f, 0x45, 0x78, 0x61, 0x63, 0x74, 0x10, 0x01, 0x2a, 0x4d, 0x0a, 0x16, 0x52, 0x65, 0x73,
|
||||
0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x63,
|
||||
0x68, 0x56, 0x32, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00,
|
||||
0x12, 0x09, 0x0a, 0x05, 0x55, 0x6e, 0x73, 0x65, 0x74, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x45,
|
||||
0x78, 0x61, 0x63, 0x74, 0x10, 0x02, 0x12, 0x10, 0x0a, 0x0c, 0x4e, 0x6f, 0x74, 0x4f, 0x6c, 0x64,
|
||||
0x65, 0x72, 0x54, 0x68, 0x61, 0x6e, 0x10, 0x03, 0x32, 0xed, 0x02, 0x0a, 0x0d, 0x52, 0x65, 0x73,
|
||||
0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x35, 0x0a, 0x04, 0x52, 0x65,
|
||||
0x61, 0x64, 0x12, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65,
|
||||
0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x72, 0x65, 0x73, 0x6f,
|
||||
0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x12, 0x3b, 0x0a, 0x06, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x17, 0x2e, 0x72, 0x65,
|
||||
0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e,
|
||||
0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b,
|
||||
0x0a, 0x06, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x17, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75,
|
||||
0x72, 0x63, 0x65, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x1a, 0x18, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x55, 0x70, 0x64,
|
||||
0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x06, 0x44,
|
||||
0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x17, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
|
||||
0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18,
|
||||
0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x35, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74,
|
||||
0x12, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72,
|
||||
0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
|
||||
0x37, 0x0a, 0x05, 0x57, 0x61, 0x74, 0x63, 0x68, 0x12, 0x16, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75,
|
||||
0x72, 0x63, 0x65, 0x2e, 0x57, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||
0x1a, 0x14, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x57, 0x61, 0x74, 0x63,
|
||||
0x68, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x30, 0x01, 0x32, 0x4b, 0x0a, 0x09, 0x42, 0x75, 0x6c, 0x6b,
|
||||
0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x3e, 0x0a, 0x0b, 0x42, 0x75, 0x6c, 0x6b, 0x50, 0x72, 0x6f,
|
||||
0x63, 0x65, 0x73, 0x73, 0x12, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e,
|
||||
0x42, 0x75, 0x6c, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x72, 0x65,
|
||||
0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x42, 0x75, 0x6c, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x28, 0x01, 0x32, 0xd9, 0x01, 0x0a, 0x12, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65,
|
||||
0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x62, 0x0a, 0x13,
|
||||
0x43, 0x6f, 0x75, 0x6e, 0x74, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64, 0x4f, 0x62, 0x6a, 0x65,
|
||||
0x63, 0x74, 0x73, 0x12, 0x24, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x43,
|
||||
0x6f, 0x75, 0x6e, 0x74, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63,
|
||||
0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f,
|
||||
0x75, 0x72, 0x63, 0x65, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65,
|
||||
0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||
0x12, 0x5f, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64, 0x4f,
|
||||
0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x23, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
|
||||
0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64, 0x4f, 0x62, 0x6a,
|
||||
0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x72, 0x65,
|
||||
0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x6e, 0x61, 0x67,
|
||||
0x65, 0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x32, 0x57, 0x0a, 0x0b, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73,
|
||||
0x12, 0x48, 0x0a, 0x09, 0x49, 0x73, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x79, 0x12, 0x1c, 0x2e,
|
||||
0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43,
|
||||
0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x72, 0x65,
|
||||
0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65,
|
||||
0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x3b, 0x5a, 0x39, 0x67, 0x69,
|
||||
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x66, 0x61, 0x6e, 0x61,
|
||||
0x2f, 0x67, 0x72, 0x61, 0x66, 0x61, 0x6e, 0x61, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x73, 0x74, 0x6f,
|
||||
0x72, 0x61, 0x67, 0x65, 0x2f, 0x75, 0x6e, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2f, 0x72, 0x65, 0x73,
|
||||
0x6f, 0x75, 0x72, 0x63, 0x65, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x3c,
|
||||
0x0a, 0x11, 0x51, 0x75, 0x6f, 0x74, 0x61, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75,
|
||||
0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
|
||||
0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f,
|
||||
0x75, 0x72, 0x63, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, 0x6d, 0x0a, 0x12,
|
||||
0x51, 0x75, 0x6f, 0x74, 0x61, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x12, 0x2b, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x45, 0x72, 0x72,
|
||||
0x6f, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12,
|
||||
0x14, 0x0a, 0x05, 0x75, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05,
|
||||
0x75, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x03,
|
||||
0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x2a, 0x49, 0x0a, 0x14, 0x52,
|
||||
0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x61,
|
||||
0x74, 0x63, 0x68, 0x12, 0x1b, 0x0a, 0x17, 0x44, 0x45, 0x50, 0x52, 0x45, 0x43, 0x41, 0x54, 0x45,
|
||||
0x44, 0x5f, 0x4e, 0x6f, 0x74, 0x4f, 0x6c, 0x64, 0x65, 0x72, 0x54, 0x68, 0x61, 0x6e, 0x10, 0x00,
|
||||
0x12, 0x14, 0x0a, 0x10, 0x44, 0x45, 0x50, 0x52, 0x45, 0x43, 0x41, 0x54, 0x45, 0x44, 0x5f, 0x45,
|
||||
0x78, 0x61, 0x63, 0x74, 0x10, 0x01, 0x2a, 0x4d, 0x0a, 0x16, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72,
|
||||
0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x56, 0x32,
|
||||
0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x09, 0x0a,
|
||||
0x05, 0x55, 0x6e, 0x73, 0x65, 0x74, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x78, 0x61, 0x63,
|
||||
0x74, 0x10, 0x02, 0x12, 0x10, 0x0a, 0x0c, 0x4e, 0x6f, 0x74, 0x4f, 0x6c, 0x64, 0x65, 0x72, 0x54,
|
||||
0x68, 0x61, 0x6e, 0x10, 0x03, 0x32, 0xed, 0x02, 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72,
|
||||
0x63, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x35, 0x0a, 0x04, 0x52, 0x65, 0x61, 0x64, 0x12,
|
||||
0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52,
|
||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
|
||||
0x65, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b,
|
||||
0x0a, 0x06, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x17, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75,
|
||||
0x72, 0x63, 0x65, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x1a, 0x18, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x43, 0x72, 0x65,
|
||||
0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x06, 0x55,
|
||||
0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x17, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
|
||||
0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18,
|
||||
0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65,
|
||||
0x74, 0x65, 0x12, 0x17, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x44, 0x65,
|
||||
0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x72, 0x65,
|
||||
0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x35, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x15, 0x2e,
|
||||
0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e,
|
||||
0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x05,
|
||||
0x57, 0x61, 0x74, 0x63, 0x68, 0x12, 0x16, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
|
||||
0x2e, 0x57, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e,
|
||||
0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x57, 0x61, 0x74, 0x63, 0x68, 0x45, 0x76,
|
||||
0x65, 0x6e, 0x74, 0x30, 0x01, 0x32, 0x4b, 0x0a, 0x09, 0x42, 0x75, 0x6c, 0x6b, 0x53, 0x74, 0x6f,
|
||||
0x72, 0x65, 0x12, 0x3e, 0x0a, 0x0b, 0x42, 0x75, 0x6c, 0x6b, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73,
|
||||
0x73, 0x12, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x42, 0x75, 0x6c,
|
||||
0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75,
|
||||
0x72, 0x63, 0x65, 0x2e, 0x42, 0x75, 0x6c, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||
0x28, 0x01, 0x32, 0xd9, 0x01, 0x0a, 0x12, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64, 0x4f, 0x62,
|
||||
0x6a, 0x65, 0x63, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x62, 0x0a, 0x13, 0x43, 0x6f, 0x75,
|
||||
0x6e, 0x74, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73,
|
||||
0x12, 0x24, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x43, 0x6f, 0x75, 0x6e,
|
||||
0x74, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52,
|
||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
|
||||
0x65, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64, 0x4f, 0x62,
|
||||
0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5f, 0x0a,
|
||||
0x12, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64, 0x4f, 0x62, 0x6a, 0x65,
|
||||
0x63, 0x74, 0x73, 0x12, 0x23, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x4c,
|
||||
0x69, 0x73, 0x74, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74,
|
||||
0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75,
|
||||
0x72, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64, 0x4f,
|
||||
0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x57,
|
||||
0x0a, 0x0b, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x12, 0x48, 0x0a,
|
||||
0x09, 0x49, 0x73, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x79, 0x12, 0x1c, 0x2e, 0x72, 0x65, 0x73,
|
||||
0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63,
|
||||
0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75,
|
||||
0x72, 0x63, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52,
|
||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x54, 0x0a, 0x06, 0x51, 0x75, 0x6f, 0x74, 0x61,
|
||||
0x73, 0x12, 0x4a, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x51, 0x75, 0x6f, 0x74, 0x61, 0x55, 0x73, 0x61,
|
||||
0x67, 0x65, 0x12, 0x1b, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x51, 0x75,
|
||||
0x6f, 0x74, 0x61, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
||||
0x1c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x51, 0x75, 0x6f, 0x74, 0x61,
|
||||
0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x3b, 0x5a,
|
||||
0x39, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x66,
|
||||
0x61, 0x6e, 0x61, 0x2f, 0x67, 0x72, 0x61, 0x66, 0x61, 0x6e, 0x61, 0x2f, 0x70, 0x6b, 0x67, 0x2f,
|
||||
0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2f, 0x75, 0x6e, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2f,
|
||||
0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x33,
|
||||
})
|
||||
|
||||
var (
|
||||
@@ -3397,7 +3522,7 @@ func file_resource_proto_rawDescGZIP() []byte {
|
||||
}
|
||||
|
||||
var file_resource_proto_enumTypes = make([]protoimpl.EnumInfo, 7)
|
||||
var file_resource_proto_msgTypes = make([]protoimpl.MessageInfo, 36)
|
||||
var file_resource_proto_msgTypes = make([]protoimpl.MessageInfo, 38)
|
||||
var file_resource_proto_goTypes = []any{
|
||||
(ResourceVersionMatch)(0), // 0: resource.ResourceVersionMatch
|
||||
(ResourceVersionMatchV2)(0), // 1: resource.ResourceVersionMatchV2
|
||||
@@ -3436,12 +3561,14 @@ var file_resource_proto_goTypes = []any{
|
||||
(*ResourceTable)(nil), // 34: resource.ResourceTable
|
||||
(*ResourceTableColumnDefinition)(nil), // 35: resource.ResourceTableColumnDefinition
|
||||
(*ResourceTableRow)(nil), // 36: resource.ResourceTableRow
|
||||
(*WatchEvent_Resource)(nil), // 37: resource.WatchEvent.Resource
|
||||
(*BulkResponse_Summary)(nil), // 38: resource.BulkResponse.Summary
|
||||
(*BulkResponse_Rejected)(nil), // 39: resource.BulkResponse.Rejected
|
||||
(*ListManagedObjectsResponse_Item)(nil), // 40: resource.ListManagedObjectsResponse.Item
|
||||
(*CountManagedObjectsResponse_ResourceCount)(nil), // 41: resource.CountManagedObjectsResponse.ResourceCount
|
||||
(*ResourceTableColumnDefinition_Properties)(nil), // 42: resource.ResourceTableColumnDefinition.Properties
|
||||
(*QuotaUsageRequest)(nil), // 37: resource.QuotaUsageRequest
|
||||
(*QuotaUsageResponse)(nil), // 38: resource.QuotaUsageResponse
|
||||
(*WatchEvent_Resource)(nil), // 39: resource.WatchEvent.Resource
|
||||
(*BulkResponse_Summary)(nil), // 40: resource.BulkResponse.Summary
|
||||
(*BulkResponse_Rejected)(nil), // 41: resource.BulkResponse.Rejected
|
||||
(*ListManagedObjectsResponse_Item)(nil), // 42: resource.ListManagedObjectsResponse.Item
|
||||
(*CountManagedObjectsResponse_ResourceCount)(nil), // 43: resource.CountManagedObjectsResponse.ResourceCount
|
||||
(*ResourceTableColumnDefinition_Properties)(nil), // 44: resource.ResourceTableColumnDefinition.Properties
|
||||
}
|
||||
var file_resource_proto_depIdxs = []int32{
|
||||
10, // 0: resource.ErrorResult.details:type_name -> resource.ErrorDetails
|
||||
@@ -3465,51 +3592,55 @@ var file_resource_proto_depIdxs = []int32{
|
||||
9, // 18: resource.ListResponse.error:type_name -> resource.ErrorResult
|
||||
21, // 19: resource.WatchRequest.options:type_name -> resource.ListOptions
|
||||
3, // 20: resource.WatchEvent.type:type_name -> resource.WatchEvent.Type
|
||||
37, // 21: resource.WatchEvent.resource:type_name -> resource.WatchEvent.Resource
|
||||
37, // 22: resource.WatchEvent.previous:type_name -> resource.WatchEvent.Resource
|
||||
39, // 21: resource.WatchEvent.resource:type_name -> resource.WatchEvent.Resource
|
||||
39, // 22: resource.WatchEvent.previous:type_name -> resource.WatchEvent.Resource
|
||||
7, // 23: resource.BulkRequest.key:type_name -> resource.ResourceKey
|
||||
4, // 24: resource.BulkRequest.action:type_name -> resource.BulkRequest.Action
|
||||
9, // 25: resource.BulkResponse.error:type_name -> resource.ErrorResult
|
||||
38, // 26: resource.BulkResponse.summary:type_name -> resource.BulkResponse.Summary
|
||||
39, // 27: resource.BulkResponse.rejected:type_name -> resource.BulkResponse.Rejected
|
||||
40, // 28: resource.ListManagedObjectsResponse.items:type_name -> resource.ListManagedObjectsResponse.Item
|
||||
40, // 26: resource.BulkResponse.summary:type_name -> resource.BulkResponse.Summary
|
||||
41, // 27: resource.BulkResponse.rejected:type_name -> resource.BulkResponse.Rejected
|
||||
42, // 28: resource.ListManagedObjectsResponse.items:type_name -> resource.ListManagedObjectsResponse.Item
|
||||
9, // 29: resource.ListManagedObjectsResponse.error:type_name -> resource.ErrorResult
|
||||
41, // 30: resource.CountManagedObjectsResponse.items:type_name -> resource.CountManagedObjectsResponse.ResourceCount
|
||||
43, // 30: resource.CountManagedObjectsResponse.items:type_name -> resource.CountManagedObjectsResponse.ResourceCount
|
||||
9, // 31: resource.CountManagedObjectsResponse.error:type_name -> resource.ErrorResult
|
||||
5, // 32: resource.HealthCheckResponse.status:type_name -> resource.HealthCheckResponse.ServingStatus
|
||||
35, // 33: resource.ResourceTable.columns:type_name -> resource.ResourceTableColumnDefinition
|
||||
36, // 34: resource.ResourceTable.rows:type_name -> resource.ResourceTableRow
|
||||
6, // 35: resource.ResourceTableColumnDefinition.type:type_name -> resource.ResourceTableColumnDefinition.ColumnType
|
||||
42, // 36: resource.ResourceTableColumnDefinition.properties:type_name -> resource.ResourceTableColumnDefinition.Properties
|
||||
44, // 36: resource.ResourceTableColumnDefinition.properties:type_name -> resource.ResourceTableColumnDefinition.Properties
|
||||
7, // 37: resource.ResourceTableRow.key:type_name -> resource.ResourceKey
|
||||
7, // 38: resource.BulkResponse.Rejected.key:type_name -> resource.ResourceKey
|
||||
4, // 39: resource.BulkResponse.Rejected.action:type_name -> resource.BulkRequest.Action
|
||||
7, // 40: resource.ListManagedObjectsResponse.Item.object:type_name -> resource.ResourceKey
|
||||
18, // 41: resource.ResourceStore.Read:input_type -> resource.ReadRequest
|
||||
12, // 42: resource.ResourceStore.Create:input_type -> resource.CreateRequest
|
||||
14, // 43: resource.ResourceStore.Update:input_type -> resource.UpdateRequest
|
||||
16, // 44: resource.ResourceStore.Delete:input_type -> resource.DeleteRequest
|
||||
22, // 45: resource.ResourceStore.List:input_type -> resource.ListRequest
|
||||
24, // 46: resource.ResourceStore.Watch:input_type -> resource.WatchRequest
|
||||
26, // 47: resource.BulkStore.BulkProcess:input_type -> resource.BulkRequest
|
||||
30, // 48: resource.ManagedObjectIndex.CountManagedObjects:input_type -> resource.CountManagedObjectsRequest
|
||||
28, // 49: resource.ManagedObjectIndex.ListManagedObjects:input_type -> resource.ListManagedObjectsRequest
|
||||
32, // 50: resource.Diagnostics.IsHealthy:input_type -> resource.HealthCheckRequest
|
||||
19, // 51: resource.ResourceStore.Read:output_type -> resource.ReadResponse
|
||||
13, // 52: resource.ResourceStore.Create:output_type -> resource.CreateResponse
|
||||
15, // 53: resource.ResourceStore.Update:output_type -> resource.UpdateResponse
|
||||
17, // 54: resource.ResourceStore.Delete:output_type -> resource.DeleteResponse
|
||||
23, // 55: resource.ResourceStore.List:output_type -> resource.ListResponse
|
||||
25, // 56: resource.ResourceStore.Watch:output_type -> resource.WatchEvent
|
||||
27, // 57: resource.BulkStore.BulkProcess:output_type -> resource.BulkResponse
|
||||
31, // 58: resource.ManagedObjectIndex.CountManagedObjects:output_type -> resource.CountManagedObjectsResponse
|
||||
29, // 59: resource.ManagedObjectIndex.ListManagedObjects:output_type -> resource.ListManagedObjectsResponse
|
||||
33, // 60: resource.Diagnostics.IsHealthy:output_type -> resource.HealthCheckResponse
|
||||
51, // [51:61] is the sub-list for method output_type
|
||||
41, // [41:51] is the sub-list for method input_type
|
||||
41, // [41:41] is the sub-list for extension type_name
|
||||
41, // [41:41] is the sub-list for extension extendee
|
||||
0, // [0:41] is the sub-list for field type_name
|
||||
7, // 38: resource.QuotaUsageRequest.key:type_name -> resource.ResourceKey
|
||||
9, // 39: resource.QuotaUsageResponse.error:type_name -> resource.ErrorResult
|
||||
7, // 40: resource.BulkResponse.Rejected.key:type_name -> resource.ResourceKey
|
||||
4, // 41: resource.BulkResponse.Rejected.action:type_name -> resource.BulkRequest.Action
|
||||
7, // 42: resource.ListManagedObjectsResponse.Item.object:type_name -> resource.ResourceKey
|
||||
18, // 43: resource.ResourceStore.Read:input_type -> resource.ReadRequest
|
||||
12, // 44: resource.ResourceStore.Create:input_type -> resource.CreateRequest
|
||||
14, // 45: resource.ResourceStore.Update:input_type -> resource.UpdateRequest
|
||||
16, // 46: resource.ResourceStore.Delete:input_type -> resource.DeleteRequest
|
||||
22, // 47: resource.ResourceStore.List:input_type -> resource.ListRequest
|
||||
24, // 48: resource.ResourceStore.Watch:input_type -> resource.WatchRequest
|
||||
26, // 49: resource.BulkStore.BulkProcess:input_type -> resource.BulkRequest
|
||||
30, // 50: resource.ManagedObjectIndex.CountManagedObjects:input_type -> resource.CountManagedObjectsRequest
|
||||
28, // 51: resource.ManagedObjectIndex.ListManagedObjects:input_type -> resource.ListManagedObjectsRequest
|
||||
32, // 52: resource.Diagnostics.IsHealthy:input_type -> resource.HealthCheckRequest
|
||||
37, // 53: resource.Quotas.GetQuotaUsage:input_type -> resource.QuotaUsageRequest
|
||||
19, // 54: resource.ResourceStore.Read:output_type -> resource.ReadResponse
|
||||
13, // 55: resource.ResourceStore.Create:output_type -> resource.CreateResponse
|
||||
15, // 56: resource.ResourceStore.Update:output_type -> resource.UpdateResponse
|
||||
17, // 57: resource.ResourceStore.Delete:output_type -> resource.DeleteResponse
|
||||
23, // 58: resource.ResourceStore.List:output_type -> resource.ListResponse
|
||||
25, // 59: resource.ResourceStore.Watch:output_type -> resource.WatchEvent
|
||||
27, // 60: resource.BulkStore.BulkProcess:output_type -> resource.BulkResponse
|
||||
31, // 61: resource.ManagedObjectIndex.CountManagedObjects:output_type -> resource.CountManagedObjectsResponse
|
||||
29, // 62: resource.ManagedObjectIndex.ListManagedObjects:output_type -> resource.ListManagedObjectsResponse
|
||||
33, // 63: resource.Diagnostics.IsHealthy:output_type -> resource.HealthCheckResponse
|
||||
38, // 64: resource.Quotas.GetQuotaUsage:output_type -> resource.QuotaUsageResponse
|
||||
54, // [54:65] is the sub-list for method output_type
|
||||
43, // [43:54] is the sub-list for method input_type
|
||||
43, // [43:43] is the sub-list for extension type_name
|
||||
43, // [43:43] is the sub-list for extension extendee
|
||||
0, // [0:43] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_resource_proto_init() }
|
||||
@@ -3524,9 +3655,9 @@ func file_resource_proto_init() {
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_resource_proto_rawDesc), len(file_resource_proto_rawDesc)),
|
||||
NumEnums: 7,
|
||||
NumMessages: 36,
|
||||
NumMessages: 38,
|
||||
NumExtensions: 0,
|
||||
NumServices: 4,
|
||||
NumServices: 5,
|
||||
},
|
||||
GoTypes: file_resource_proto_goTypes,
|
||||
DependencyIndexes: file_resource_proto_depIdxs,
|
||||
|
||||
@@ -709,3 +709,94 @@ var Diagnostics_ServiceDesc = grpc.ServiceDesc{
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "resource.proto",
|
||||
}
|
||||
|
||||
const (
|
||||
Quotas_GetQuotaUsage_FullMethodName = "/resource.Quotas/GetQuotaUsage"
|
||||
)
|
||||
|
||||
// QuotasClient is the client API for Quotas service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
type QuotasClient interface {
|
||||
// Get current quota usage and limits
|
||||
GetQuotaUsage(ctx context.Context, in *QuotaUsageRequest, opts ...grpc.CallOption) (*QuotaUsageResponse, error)
|
||||
}
|
||||
|
||||
type quotasClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewQuotasClient(cc grpc.ClientConnInterface) QuotasClient {
|
||||
return "asClient{cc}
|
||||
}
|
||||
|
||||
func (c *quotasClient) GetQuotaUsage(ctx context.Context, in *QuotaUsageRequest, opts ...grpc.CallOption) (*QuotaUsageResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(QuotaUsageResponse)
|
||||
err := c.cc.Invoke(ctx, Quotas_GetQuotaUsage_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// QuotasServer is the server API for Quotas service.
|
||||
// All implementations should embed UnimplementedQuotasServer
|
||||
// for forward compatibility
|
||||
type QuotasServer interface {
|
||||
// Get current quota usage and limits
|
||||
GetQuotaUsage(context.Context, *QuotaUsageRequest) (*QuotaUsageResponse, error)
|
||||
}
|
||||
|
||||
// UnimplementedQuotasServer should be embedded to have forward compatible implementations.
|
||||
type UnimplementedQuotasServer struct {
|
||||
}
|
||||
|
||||
func (UnimplementedQuotasServer) GetQuotaUsage(context.Context, *QuotaUsageRequest) (*QuotaUsageResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetQuotaUsage not implemented")
|
||||
}
|
||||
|
||||
// UnsafeQuotasServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to QuotasServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeQuotasServer interface {
|
||||
mustEmbedUnimplementedQuotasServer()
|
||||
}
|
||||
|
||||
func RegisterQuotasServer(s grpc.ServiceRegistrar, srv QuotasServer) {
|
||||
s.RegisterService(&Quotas_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _Quotas_GetQuotaUsage_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(QuotaUsageRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(QuotasServer).GetQuotaUsage(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Quotas_GetQuotaUsage_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(QuotasServer).GetQuotaUsage(ctx, req.(*QuotaUsageRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// Quotas_ServiceDesc is the grpc.ServiceDesc for Quotas service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var Quotas_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "resource.Quotas",
|
||||
HandlerType: (*QuotasServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "GetQuotaUsage",
|
||||
Handler: _Quotas_GetQuotaUsage_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "resource.proto",
|
||||
}
|
||||
|
||||
@@ -312,6 +312,7 @@ func (s *service) starting(ctx context.Context) error {
|
||||
resourcepb.RegisterManagedObjectIndexServer(srv, server)
|
||||
resourcepb.RegisterBlobStoreServer(srv, server)
|
||||
resourcepb.RegisterDiagnosticsServer(srv, server)
|
||||
resourcepb.RegisterQuotasServer(srv, server)
|
||||
grpc_health_v1.RegisterHealthServer(srv, healthService)
|
||||
|
||||
// register reflection service
|
||||
|
||||
Reference in New Issue
Block a user