The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/pkg/registry/apis/provisioning/resources/object.go

168 lines
4.7 KiB

package resources
import (
"context"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
dashboard "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1"
folders "github.com/grafana/grafana/apps/folder/pkg/apis/folder/v1beta1"
"github.com/grafana/grafana/pkg/apimachinery/utils"
provisioning "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1"
"github.com/grafana/grafana/pkg/registry/apis/dashboard/legacy"
"github.com/grafana/grafana/pkg/storage/legacysql/dualwrite"
"github.com/grafana/grafana/pkg/storage/unified/resource"
"github.com/grafana/grafana/pkg/storage/unified/resourcepb"
)
// Get repository stats
//
//go:generate mockery --name ResourceLister --structname MockResourceLister --inpackage --filename resource_lister_mock.go --with-expecter
type ResourceLister interface {
List(ctx context.Context, namespace, repository string) (*provisioning.ResourceList, error)
Stats(ctx context.Context, namespace, repository string) (*provisioning.ResourceStats, error)
}
type ResourceListerFromSearch struct {
managed resourcepb.ManagedObjectIndexClient
index resourcepb.ResourceIndexClient
legacyMigrator legacy.LegacyMigrator
storageStatus dualwrite.Service
}
func NewResourceLister(
managed resourcepb.ManagedObjectIndexClient,
index resourcepb.ResourceIndexClient,
legacyMigrator legacy.LegacyMigrator,
storageStatus dualwrite.Service,
) ResourceLister {
return &ResourceListerFromSearch{
index: index,
managed: managed,
legacyMigrator: legacyMigrator,
storageStatus: storageStatus,
}
}
// List implements ResourceLister.
func (o *ResourceListerFromSearch) List(ctx context.Context, namespace, repository string) (*provisioning.ResourceList, error) {
objects, err := o.managed.ListManagedObjects(ctx, &resourcepb.ListManagedObjectsRequest{
Namespace: namespace,
Kind: string(utils.ManagerKindRepo),
Id: repository,
})
if err != nil {
return nil, err
}
if objects.Error != nil {
return nil, resource.GetError(objects.Error)
}
list := &provisioning.ResourceList{}
for _, v := range objects.Items {
list.Items = append(list.Items, provisioning.ResourceListItem{
Path: v.Path,
Group: v.Object.Group,
Resource: v.Object.Resource,
Name: v.Object.Name,
Hash: v.Hash,
Time: v.Time,
Title: v.Title,
Folder: v.Folder,
})
}
return list, nil
}
// Stats implements ResourceLister.
func (o *ResourceListerFromSearch) Stats(ctx context.Context, namespace, repository string) (*provisioning.ResourceStats, error) {
req := &resourcepb.CountManagedObjectsRequest{
Namespace: namespace,
}
if repository != "" {
req.Kind = string(utils.ManagerKindRepo)
req.Id = repository
}
counts, err := o.managed.CountManagedObjects(ctx, req)
if err != nil {
return nil, err
}
if counts.Error != nil {
return nil, resource.GetError(counts.Error)
}
lookup := make(map[string]*provisioning.ManagerStats)
for _, v := range counts.Items {
key := v.Kind + ":" + v.Id
m := lookup[key]
if m == nil {
m = &provisioning.ManagerStats{
Kind: utils.ManagerKind(v.Kind),
Identity: v.Id,
}
lookup[key] = m
}
m.Stats = append(m.Stats, provisioning.ResourceCount{
Group: v.Group,
Resource: v.Resource,
Count: v.Count,
})
}
stats := &provisioning.ResourceStats{
TypeMeta: metav1.TypeMeta{
APIVersion: provisioning.SchemeGroupVersion.String(),
Kind: "ResourceStats",
},
}
for _, v := range lookup {
stats.Managed = append(stats.Managed, *v)
}
// When selecting an explicit repository, do not fetch global stats
if repository != "" {
return stats, nil
}
// Get the stats based on what a migration could support
if dualwrite.IsReadingLegacyDashboardsAndFolders(ctx, o.storageStatus) {
rsp, err := o.legacyMigrator.Migrate(ctx, legacy.MigrateOptions{
Namespace: namespace,
Resources: []schema.GroupResource{{
Group: dashboard.GROUP, Resource: dashboard.DASHBOARD_RESOURCE,
}, {
Group: folders.GROUP, Resource: folders.RESOURCE,
}},
WithHistory: false,
OnlyCount: true,
})
if err != nil {
return nil, err
}
for _, v := range rsp.Summary {
stats.Instance = append(stats.Instance, provisioning.ResourceCount{
Group: v.Group,
Resource: v.Resource,
Count: v.Count,
})
}
return stats, nil
}
// Get full instance stats
info, err := o.index.GetStats(ctx, &resourcepb.ResourceStatsRequest{
Namespace: namespace,
})
if err != nil {
return nil, err
}
for _, v := range info.Stats {
stats.Instance = append(stats.Instance, provisioning.ResourceCount{
Group: v.Group,
Resource: v.Resource,
Count: v.Count,
})
}
return stats, nil
}