Unified Storage: Pass ns, group, resource to GetResourceStats instead of just namespace (#114050)

* passes nsr to GetResourceStats instead of just namespace

* removes ns check

* fixes failing tests

* make update-workspace

* pass group and resource from rebuild request when getting resource stats
This commit is contained in:
owensmallwood
2025-11-18 13:05:21 -06:00
committed by GitHub
parent bf3de07147
commit 8dddff3ce4
12 changed files with 57 additions and 26 deletions
+1 -1
View File
@@ -403,7 +403,7 @@ require (
github.com/diegoholiveira/jsonlogic/v3 v3.7.4 // indirect
github.com/distribution/reference v0.6.0 // indirect
github.com/docker/docker v28.4.0+incompatible // indirect
github.com/docker/go-connections v0.6.0 // @grafana/grafana-app-platform-squad
github.com/docker/go-connections v0.6.0 // indirect; @grafana/grafana-app-platform-squad
github.com/docker/go-units v0.5.0 // indirect
github.com/dolthub/flatbuffers/v23 v23.3.3-dh.2 // indirect
github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71 // indirect
+3 -3
View File
@@ -15,7 +15,6 @@ import (
_ "github.com/blugelabs/bluge"
_ "github.com/blugelabs/bluge_segment_api"
_ "github.com/crewjam/saml"
_ "github.com/docker/go-connections/nat"
_ "github.com/go-jose/go-jose/v4"
_ "github.com/gobwas/glob"
_ "github.com/googleapis/gax-go/v2"
@@ -31,7 +30,6 @@ import (
_ "github.com/spf13/cobra" // used by the standalone apiserver cli
_ "github.com/spyzhov/ajson"
_ "github.com/stretchr/testify/require"
_ "github.com/testcontainers/testcontainers-go"
_ "gocloud.dev/secrets/awskms"
_ "gocloud.dev/secrets/azurekeyvault"
_ "gocloud.dev/secrets/gcpkms"
@@ -56,7 +54,9 @@ 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"
_ "github.com/testcontainers/testcontainers-go"
)
@@ -165,7 +165,7 @@ type rowsWrapper struct {
rejected []dashboardRow
}
func (a *dashboardSqlAccess) GetResourceStats(ctx context.Context, namespace string, minCount int) ([]resource.ResourceStats, error) {
func (a *dashboardSqlAccess) GetResourceStats(ctx context.Context, nsr resource.NamespacedResource, minCount int) ([]resource.ResourceStats, error) {
return nil, fmt.Errorf("not implemented")
}
@@ -23,7 +23,7 @@ func ProvideStorageBackend() *StorageBackendImpl {
}
// GetResourceStats implements resource.StorageBackend.
func (c *StorageBackendImpl) GetResourceStats(ctx context.Context, namespace string, minCount int) ([]resource.ResourceStats, error) {
func (c *StorageBackendImpl) GetResourceStats(ctx context.Context, nsr resource.NamespacedResource, minCount int) ([]resource.ResourceStats, error) {
return []resource.ResourceStats{}, errNoopStorage
}
@@ -60,7 +60,7 @@ func ProvideStorageBackend(dbProvider legacysql.LegacyDatabaseProvider) *Resourc
}
}
func (s *ResourcePermSqlBackend) GetResourceStats(ctx context.Context, namespace string, minCount int) ([]resource.ResourceStats, error) {
func (s *ResourcePermSqlBackend) GetResourceStats(ctx context.Context, nsr resource.NamespacedResource, minCount int) ([]resource.ResourceStats, error) {
return []resource.ResourceStats{}, errNotImplemented
}
+23 -6
View File
@@ -245,7 +245,10 @@ func (s *searchSupport) ListManagedObjects(ctx context.Context, req *resourcepb.
}
rsp := &resourcepb.ListManagedObjectsResponse{}
stats, err := s.storage.GetResourceStats(ctx, req.Namespace, 0)
nsr := NamespacedResource{
Namespace: req.Namespace,
}
stats, err := s.storage.GetResourceStats(ctx, nsr, 0)
if err != nil {
rsp.Error = AsErrorResult(err)
return rsp, nil
@@ -286,7 +289,10 @@ func (s *searchSupport) ListManagedObjects(ctx context.Context, req *resourcepb.
func (s *searchSupport) CountManagedObjects(ctx context.Context, req *resourcepb.CountManagedObjectsRequest) (*resourcepb.CountManagedObjectsResponse, error) {
rsp := &resourcepb.CountManagedObjectsResponse{}
stats, err := s.storage.GetResourceStats(ctx, req.Namespace, 0)
nsr := NamespacedResource{
Namespace: req.Namespace,
}
stats, err := s.storage.GetResourceStats(ctx, nsr, 0)
if err != nil {
rsp.Error = AsErrorResult(err)
return rsp, nil
@@ -408,7 +414,10 @@ func (s *searchSupport) GetStats(ctx context.Context, req *resourcepb.ResourceSt
return rsp, nil
}
stats, err := s.storage.GetResourceStats(ctx, req.Namespace, 0)
nsr := NamespacedResource{
Namespace: req.Namespace,
}
stats, err := s.storage.GetResourceStats(ctx, nsr, 0)
if err != nil {
return &resourcepb.ResourceStatsResponse{
Error: AsErrorResult(err),
@@ -457,7 +466,7 @@ func (s *searchSupport) buildIndexes(ctx context.Context) (int, error) {
group := errgroup.Group{}
group.SetLimit(s.initWorkers)
stats, err := s.storage.GetResourceStats(ctx, "", s.initMinSize)
stats, err := s.storage.GetResourceStats(ctx, NamespacedResource{}, s.initMinSize)
if err != nil {
return 0, err
}
@@ -657,7 +666,12 @@ func (s *searchSupport) rebuildIndex(ctx context.Context, req rebuildRequest) {
// Get the correct value of size + RV for building the index. This is important for our Bleve
// backend to decide whether to build index in-memory or as file-based.
stats, err := s.storage.GetResourceStats(ctx, req.Namespace, 0)
nsr := NamespacedResource{
Namespace: req.Namespace,
Group: req.Group,
Resource: req.Resource,
}
stats, err := s.storage.GetResourceStats(ctx, nsr, 0)
if err != nil {
span.RecordError(fmt.Errorf("failed to get resource stats: %w", err))
l.Error("failed to get resource stats", "error", err)
@@ -750,7 +764,10 @@ func (s *searchSupport) getOrCreateIndex(ctx context.Context, key NamespacedReso
// Get correct value of size + RV for building the index. This is important for our Bleve
// backend to decide whether to build index in-memory or as file-based.
stats, err := s.storage.GetResourceStats(ctx, key.Namespace, 0)
nsr := NamespacedResource{
Namespace: key.Namespace,
}
stats, err := s.storage.GetResourceStats(ctx, nsr, 0)
if err != nil {
return nil, fmt.Errorf("failed to get resource stats: %w", err)
}
+1 -1
View File
@@ -88,7 +88,7 @@ type mockStorageBackend struct {
resourceStats []ResourceStats
}
func (m *mockStorageBackend) GetResourceStats(ctx context.Context, namespace string, minCount int) ([]ResourceStats, error) {
func (m *mockStorageBackend) GetResourceStats(ctx context.Context, nsr NamespacedResource, minCount int) ([]ResourceStats, error) {
var result []ResourceStats
for _, stat := range m.resourceStats {
// Apply the minCount filter like the real implementation does
+1 -1
View File
@@ -123,7 +123,7 @@ type StorageBackend interface {
WatchWriteEvents(ctx context.Context) (<-chan *WrittenEvent, error)
// Get resource stats within the storage backend. When namespace is empty, it will apply to all
GetResourceStats(ctx context.Context, namespace string, minCount int) ([]ResourceStats, error)
GetResourceStats(ctx context.Context, nsr NamespacedResource, minCount int) ([]ResourceStats, error)
// GetResourceLastImportTimes returns import times for all namespaced resources in the backend.
GetResourceLastImportTimes(ctx context.Context) iter.Seq2[ResourceLastImportTime, error]
@@ -1223,8 +1223,8 @@ func (k *kvStorageBackend) WatchWriteEvents(ctx context.Context) (<-chan *Writte
}
// GetResourceStats returns resource stats within the storage backend.
func (k *kvStorageBackend) GetResourceStats(ctx context.Context, namespace string, minCount int) ([]ResourceStats, error) {
return k.dataStore.GetResourceStats(ctx, namespace, minCount)
func (k *kvStorageBackend) GetResourceStats(ctx context.Context, nsr NamespacedResource, minCount int) ([]ResourceStats, error) {
return k.dataStore.GetResourceStats(ctx, nsr.Namespace, minCount)
}
func (k *kvStorageBackend) GetResourceLastImportTimes(ctx context.Context) iter.Seq2[ResourceLastImportTime, error] {
@@ -1397,7 +1397,7 @@ func TestKvStorageBackend_GetResourceStats_Success(t *testing.T) {
}
// Get stats for default namespace
stats, err := backend.GetResourceStats(ctx, "default", 0)
stats, err := backend.GetResourceStats(ctx, NamespacedResource{Namespace: "default"}, 0)
require.NoError(t, err)
require.Len(t, stats, 2) // Should have stats for 2 resource types in default namespace
@@ -1413,12 +1413,12 @@ func TestKvStorageBackend_GetResourceStats_Success(t *testing.T) {
require.Equal(t, int64(1), resourceTypes["default/core/services"])
// Get stats for all namespaces (empty string)
allStats, err := backend.GetResourceStats(ctx, "", 0)
allStats, err := backend.GetResourceStats(ctx, NamespacedResource{Namespace: ""}, 0)
require.NoError(t, err)
require.Len(t, allStats, 4) // Should have stats for all 4 resource types across namespaces
// Get stats with minCount filter
filteredStats, err := backend.GetResourceStats(ctx, "", 1)
filteredStats, err := backend.GetResourceStats(ctx, NamespacedResource{Namespace: ""}, 1)
require.NoError(t, err)
require.Len(t, filteredStats, 1) // Only resources in default namespace has count > 1
+4 -2
View File
@@ -262,13 +262,15 @@ func (b *backend) Stop(_ context.Context) error {
}
// GetResourceStats implements Backend.
func (b *backend) GetResourceStats(ctx context.Context, namespace string, minCount int) ([]resource.ResourceStats, error) {
func (b *backend) GetResourceStats(ctx context.Context, nsr resource.NamespacedResource, minCount int) ([]resource.ResourceStats, error) {
ctx, span := b.tracer.Start(ctx, tracePrefix+"GetResourceStats")
defer span.End()
req := &sqlStatsRequest{
SQLTemplate: sqltemplate.New(b.dialect),
Namespace: namespace,
Namespace: nsr.Namespace,
Group: nsr.Group,
Resource: nsr.Resource,
MinCount: minCount, // not used in query... yet?
}
+16 -4
View File
@@ -262,7 +262,10 @@ func runTestIntegrationBackendGetResourceStats(t *testing.T, backend resource.St
require.NoError(t, err)
t.Run("Get stats for ns1", func(t *testing.T) {
stats, err := backend.GetResourceStats(ctx, nsPrefix+"-stats-ns1", 0)
nsr := resource.NamespacedResource{
Namespace: nsPrefix + "-stats-ns1",
}
stats, err := backend.GetResourceStats(ctx, nsr, 0)
require.NoError(t, err)
require.Len(t, stats, 2)
@@ -285,7 +288,10 @@ func runTestIntegrationBackendGetResourceStats(t *testing.T, backend resource.St
})
t.Run("Get stats for ns2", func(t *testing.T) {
stats, err := backend.GetResourceStats(ctx, nsPrefix+"-stats-ns2", 0)
nsr := resource.NamespacedResource{
Namespace: nsPrefix + "-stats-ns2",
}
stats, err := backend.GetResourceStats(ctx, nsr, 0)
require.NoError(t, err)
require.Len(t, stats, 1)
@@ -297,7 +303,10 @@ func runTestIntegrationBackendGetResourceStats(t *testing.T, backend resource.St
})
t.Run("Get stats with minimum count", func(t *testing.T) {
stats, err := backend.GetResourceStats(ctx, nsPrefix+"-stats-ns1", 1)
nsr := resource.NamespacedResource{
Namespace: nsPrefix + "-stats-ns1",
}
stats, err := backend.GetResourceStats(ctx, nsr, 1)
require.NoError(t, err)
require.Len(t, stats, 1)
@@ -308,7 +317,10 @@ func runTestIntegrationBackendGetResourceStats(t *testing.T, backend resource.St
})
t.Run("Get stats for non-existent namespace", func(t *testing.T) {
stats, err := backend.GetResourceStats(ctx, "non-existent", 0)
nsr := resource.NamespacedResource{
Namespace: "non-existent",
}
stats, err := backend.GetResourceStats(ctx, nsr, 0)
require.NoError(t, err)
require.Empty(t, stats)
})