mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
[search] grouping - support indexing dashboard tags, filtering by tag, listing tags (#95670)
[search] grouping
This commit is contained in:
parent
f539a70d6d
commit
f8a5813573
@ -151,13 +151,7 @@ func (i *Index) Init(ctx context.Context) error {
|
|||||||
|
|
||||||
logger.Info("indexing batch", "kind", rt.Key.Resource, "count", len(list.Items))
|
logger.Info("indexing batch", "kind", rt.Key.Resource, "count", len(list.Items))
|
||||||
//add changes to batches for shards with changes in the List
|
//add changes to batches for shards with changes in the List
|
||||||
tenants, err := i.AddToBatches(ctx, list)
|
err = i.writeBatch(ctx, list)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Index the batches for tenants with changes if the batch is large enough
|
|
||||||
err = i.IndexBatches(ctx, i.opts.BatchSize, tenants)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -187,6 +181,20 @@ func (i *Index) Init(ctx context.Context) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *Index) writeBatch(ctx context.Context, list *ListResponse) error {
|
||||||
|
tenants, err := i.AddToBatches(ctx, list)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Index the batches for tenants with changes if the batch is large enough
|
||||||
|
err = i.IndexBatches(ctx, i.opts.BatchSize, tenants)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (i *Index) Index(ctx context.Context, data *Data) error {
|
func (i *Index) Index(ctx context.Context, data *Data) error {
|
||||||
ctx, span := i.tracer.Start(ctx, tracingPrexfixIndex+"Index")
|
ctx, span := i.tracer.Start(ctx, tracingPrexfixIndex+"Index")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
@ -235,15 +243,15 @@ func (i *Index) Delete(ctx context.Context, uid string, key *ResourceKey) error
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Index) Search(ctx context.Context, tenant string, query string, limit int, offset int) ([]IndexedResource, error) {
|
func (i *Index) Search(ctx context.Context, request *SearchRequest) (*IndexResults, error) {
|
||||||
ctx, span := i.tracer.Start(ctx, tracingPrexfixIndex+"Search")
|
ctx, span := i.tracer.Start(ctx, tracingPrexfixIndex+"Search")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
logger := i.log.FromContext(ctx)
|
logger := i.log.FromContext(ctx)
|
||||||
|
|
||||||
if tenant == "" {
|
if request.Tenant == "" {
|
||||||
tenant = "default"
|
request.Tenant = "default"
|
||||||
}
|
}
|
||||||
shard, err := i.getShard(tenant)
|
shard, err := i.getShard(request.Tenant)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -251,23 +259,30 @@ func (i *Index) Search(ctx context.Context, tenant string, query string, limit i
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
logger.Info("got index for tenant", "tenant", tenant, "docCount", docCount)
|
logger.Info("got index for tenant", "tenant", request.Tenant, "docCount", docCount)
|
||||||
|
|
||||||
fields, _ := shard.index.Fields()
|
fields, _ := shard.index.Fields()
|
||||||
logger.Debug("indexed fields", "fields", fields)
|
logger.Debug("indexed fields", "fields", fields)
|
||||||
|
|
||||||
// use 10 as a default limit for now
|
// use 10 as a default limit for now
|
||||||
if limit <= 0 {
|
if request.Limit <= 0 {
|
||||||
limit = 10
|
request.Limit = 10
|
||||||
}
|
}
|
||||||
|
|
||||||
req := bleve.NewSearchRequest(bleve.NewQueryStringQuery(query))
|
query := bleve.NewQueryStringQuery(request.Query)
|
||||||
req.From = offset
|
req := bleve.NewSearchRequest(query)
|
||||||
req.Size = limit
|
|
||||||
|
for _, group := range request.GroupBy {
|
||||||
|
facet := bleve.NewFacetRequest("Spec."+group.Name, int(group.Limit))
|
||||||
|
req.AddFacet(group.Name+"_facet", facet)
|
||||||
|
}
|
||||||
|
|
||||||
|
req.From = int(request.Offset)
|
||||||
|
req.Size = int(request.Size)
|
||||||
|
|
||||||
req.Fields = []string{"*"} // return all indexed fields in search results
|
req.Fields = []string{"*"} // return all indexed fields in search results
|
||||||
|
|
||||||
logger.Info("searching index", "query", query, "tenant", tenant)
|
logger.Info("searching index", "query", request.Query, "tenant", request.Tenant)
|
||||||
res, err := shard.index.Search(req)
|
res, err := shard.index.Search(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -282,7 +297,15 @@ func (i *Index) Search(ctx context.Context, tenant string, query string, limit i
|
|||||||
results[resKey] = ir
|
results[resKey] = ir
|
||||||
}
|
}
|
||||||
|
|
||||||
return results, nil
|
groups := []*Group{}
|
||||||
|
for _, group := range request.GroupBy {
|
||||||
|
groupByFacet := res.Facets[group.Name+"_facet"]
|
||||||
|
for _, term := range groupByFacet.Terms.Terms() {
|
||||||
|
groups = append(groups, &Group{Name: term.Term, Count: int64(term.Count)})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &IndexResults{Values: results, Groups: groups}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Index) Count() (uint64, error) {
|
func (i *Index) Count() (uint64, error) {
|
||||||
|
@ -25,6 +25,11 @@ type IndexedResource struct {
|
|||||||
Spec any
|
Spec any
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type IndexResults struct {
|
||||||
|
Values []IndexedResource
|
||||||
|
Groups []*Group
|
||||||
|
}
|
||||||
|
|
||||||
func (ir IndexedResource) FromSearchHit(hit *search.DocumentMatch) IndexedResource {
|
func (ir IndexedResource) FromSearchHit(hit *search.DocumentMatch) IndexedResource {
|
||||||
ir.Uid = hit.Fields["Uid"].(string)
|
ir.Uid = hit.Fields["Uid"].(string)
|
||||||
ir.Kind = hit.Fields["Kind"].(string)
|
ir.Kind = hit.Fields["Kind"].(string)
|
||||||
@ -178,6 +183,10 @@ func getSpecObjectMappings() map[string][]SpecFieldMapping {
|
|||||||
Field: "description",
|
Field: "description",
|
||||||
Type: "string",
|
Type: "string",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Field: "tags",
|
||||||
|
Type: "string[]",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,7 +207,7 @@ func createSpecObjectMapping(kind string) *mapping.DocumentMapping {
|
|||||||
|
|
||||||
// Create a field mapping based on field type
|
// Create a field mapping based on field type
|
||||||
switch fieldType {
|
switch fieldType {
|
||||||
case "string":
|
case "string", "string[]":
|
||||||
specMapping.AddFieldMappingsAt(fieldName, bleve.NewTextFieldMapping())
|
specMapping.AddFieldMappingsAt(fieldName, bleve.NewTextFieldMapping())
|
||||||
case "int", "int64", "float64":
|
case "int", "int64", "float64":
|
||||||
specMapping.AddFieldMappingsAt(fieldName, bleve.NewNumericFieldMapping())
|
specMapping.AddFieldMappingsAt(fieldName, bleve.NewNumericFieldMapping())
|
||||||
|
@ -28,17 +28,18 @@ func (is *IndexServer) Search(ctx context.Context, req *SearchRequest) (*SearchR
|
|||||||
ctx, span := is.tracer.Start(ctx, tracingPrefixIndexServer+"Search")
|
ctx, span := is.tracer.Start(ctx, tracingPrefixIndexServer+"Search")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
|
|
||||||
results, err := is.index.Search(ctx, req.Tenant, req.Query, int(req.Limit), int(req.Offset))
|
results, err := is.index.Search(ctx, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
res := &SearchResponse{}
|
res := &SearchResponse{}
|
||||||
for _, r := range results {
|
for _, r := range results.Values {
|
||||||
resJsonBytes, err := json.Marshal(r)
|
resJsonBytes, err := json.Marshal(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
res.Items = append(res.Items, &ResourceWrapper{Value: resJsonBytes})
|
res.Items = append(res.Items, &ResourceWrapper{Value: resJsonBytes})
|
||||||
|
res.Groups = results.Groups
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
@ -21,22 +21,35 @@ const testTenant = "default"
|
|||||||
var testContext = context.Background()
|
var testContext = context.Background()
|
||||||
|
|
||||||
func TestIndexDashboard(t *testing.T) {
|
func TestIndexDashboard(t *testing.T) {
|
||||||
data, err := os.ReadFile("./testdata/dashboard-resource.json")
|
data := readTestData(t, "dashboard-resource.json")
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
list := &ListResponse{Items: []*ResourceWrapper{{Value: data}}}
|
list := &ListResponse{Items: []*ResourceWrapper{{Value: data}}}
|
||||||
index := newTestIndex(t)
|
index := newTestIndex(t, 1)
|
||||||
_, err = index.AddToBatches(testContext, list)
|
|
||||||
|
err := index.writeBatch(testContext, list)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = index.IndexBatches(testContext, 1, []string{testTenant})
|
|
||||||
require.NoError(t, err)
|
|
||||||
assertCountEquals(t, index, 1)
|
assertCountEquals(t, index, 1)
|
||||||
assertSearchCountEquals(t, index, 1)
|
assertSearchCountEquals(t, index, "*", 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIndexDashboardWithTags(t *testing.T) {
|
||||||
|
data := readTestData(t, "dashboard-tagged-resource.json")
|
||||||
|
data2 := readTestData(t, "dashboard-tagged-resource2.json")
|
||||||
|
list := &ListResponse{Items: []*ResourceWrapper{{Value: data}, {Value: data2}}}
|
||||||
|
index := newTestIndex(t, 2)
|
||||||
|
|
||||||
|
err := index.writeBatch(testContext, list)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
assertCountEquals(t, index, 2)
|
||||||
|
assertSearchCountEquals(t, index, "tag1", 2)
|
||||||
|
assertSearchCountEquals(t, index, "tag4", 1)
|
||||||
|
assertSearchGroupCountEquals(t, index, "*", "tags", 4)
|
||||||
|
assertSearchGroupCountEquals(t, index, "tag4", "tags", 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIndexBatch(t *testing.T) {
|
func TestIndexBatch(t *testing.T) {
|
||||||
index := newTestIndex(t)
|
index := newTestIndex(t, 1000)
|
||||||
|
|
||||||
startAll := time.Now()
|
startAll := time.Now()
|
||||||
ns := namespaces()
|
ns := namespaces()
|
||||||
@ -105,7 +118,7 @@ func namespaces() []string {
|
|||||||
return ns
|
return ns
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestIndex(t *testing.T) *Index {
|
func newTestIndex(t *testing.T, batchSize int) *Index {
|
||||||
tracingCfg := tracing.NewEmptyTracingConfig()
|
tracingCfg := tracing.NewEmptyTracingConfig()
|
||||||
trace, err := tracing.ProvideService(tracingCfg)
|
trace, err := tracing.ProvideService(tracingCfg)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -117,7 +130,7 @@ func newTestIndex(t *testing.T) *Index {
|
|||||||
opts: Opts{
|
opts: Opts{
|
||||||
ListLimit: 5000,
|
ListLimit: 5000,
|
||||||
Workers: 10,
|
Workers: 10,
|
||||||
BatchSize: 1000,
|
BatchSize: batchSize,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -128,8 +141,25 @@ func assertCountEquals(t *testing.T, index *Index, expected uint64) {
|
|||||||
assert.Equal(t, expected, total)
|
assert.Equal(t, expected, total)
|
||||||
}
|
}
|
||||||
|
|
||||||
func assertSearchCountEquals(t *testing.T, index *Index, expected int) {
|
func assertSearchCountEquals(t *testing.T, index *Index, search string, expected int64) {
|
||||||
results, err := index.Search(testContext, testTenant, "*", expected+1, 0)
|
req := &SearchRequest{Query: search, Tenant: testTenant, Limit: expected + 1, Offset: 0, Size: expected + 1}
|
||||||
|
results, err := index.Search(testContext, req)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, expected, len(results))
|
assert.Equal(t, expected, int64(len(results.Values)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertSearchGroupCountEquals(t *testing.T, index *Index, search string, group string, expected int64) {
|
||||||
|
groupBy := []*GroupBy{{Name: group, Limit: 100}}
|
||||||
|
req := &SearchRequest{Query: search, Tenant: testTenant, Limit: expected + 1, Offset: 0, Size: expected + 1, GroupBy: groupBy}
|
||||||
|
results, err := index.Search(testContext, req)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, expected, int64(len(results.Groups)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func readTestData(t *testing.T, name string) []byte {
|
||||||
|
// We can ignore the gosec G304 because this is only for tests
|
||||||
|
// nolint:gosec
|
||||||
|
data, err := os.ReadFile("./testdata/" + name)
|
||||||
|
require.NoError(t, err)
|
||||||
|
return data
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -334,10 +334,25 @@ message SearchRequest {
|
|||||||
// pagination support
|
// pagination support
|
||||||
int64 limit = 5;
|
int64 limit = 5;
|
||||||
int64 offset = 6;
|
int64 offset = 6;
|
||||||
|
// batch size (optional)
|
||||||
|
int64 size = 7;
|
||||||
|
// grouping (optional)
|
||||||
|
repeated GroupBy groupBy = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GroupBy {
|
||||||
|
string name = 1;
|
||||||
|
int64 limit = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Group {
|
||||||
|
string name = 1;
|
||||||
|
int64 count = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message SearchResponse {
|
message SearchResponse {
|
||||||
repeated ResourceWrapper items = 1;
|
repeated ResourceWrapper items = 1;
|
||||||
|
repeated Group groups = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message HistoryRequest {
|
message HistoryRequest {
|
||||||
|
284
pkg/storage/unified/resource/testdata/dashboard-tagged-resource.json
vendored
Normal file
284
pkg/storage/unified/resource/testdata/dashboard-tagged-resource.json
vendored
Normal file
@ -0,0 +1,284 @@
|
|||||||
|
{
|
||||||
|
"kind": "Dashboard",
|
||||||
|
"apiVersion": "dashboard.grafana.app/v0alpha1",
|
||||||
|
"metadata": {
|
||||||
|
"name": "adg5xd8",
|
||||||
|
"namespace": "default",
|
||||||
|
"uid": "86ab200a-e8b0-47ce-bbc1-8c2e078b0956",
|
||||||
|
"creationTimestamp": "2024-10-30T20:24:07Z",
|
||||||
|
"annotations": {
|
||||||
|
"grafana.app/createdBy": "user:be2g71ke8yoe8b",
|
||||||
|
"grafana.app/originHash": "Grafana v9.2.0 (NA)",
|
||||||
|
"grafana.app/originName": "UI",
|
||||||
|
"grafana.app/originPath": "/dashboard/new"
|
||||||
|
},
|
||||||
|
"managedFields": [
|
||||||
|
{
|
||||||
|
"manager": "Mozilla",
|
||||||
|
"operation": "Update",
|
||||||
|
"apiVersion": "dashboard.grafana.app/v0alpha1",
|
||||||
|
"time": "2024-10-30T20:24:07Z",
|
||||||
|
"fieldsType": "FieldsV1",
|
||||||
|
"fieldsV1": {
|
||||||
|
"f:metadata": {
|
||||||
|
"f:annotations": {
|
||||||
|
".": {},
|
||||||
|
"f:grafana.app/originHash": {},
|
||||||
|
"f:grafana.app/originName": {},
|
||||||
|
"f:grafana.app/originPath": {}
|
||||||
|
},
|
||||||
|
"f:generateName": {}
|
||||||
|
},
|
||||||
|
"f:spec": {
|
||||||
|
"f:annotations": {
|
||||||
|
".": {},
|
||||||
|
"f:list": {}
|
||||||
|
},
|
||||||
|
"f:description": {},
|
||||||
|
"f:editable": {},
|
||||||
|
"f:fiscalYearStartMonth": {},
|
||||||
|
"f:graphTooltip": {},
|
||||||
|
"f:id": {},
|
||||||
|
"f:links": {},
|
||||||
|
"f:panels": {},
|
||||||
|
"f:preload": {},
|
||||||
|
"f:schemaVersion": {},
|
||||||
|
"f:tags": {},
|
||||||
|
"f:templating": {
|
||||||
|
".": {},
|
||||||
|
"f:list": {}
|
||||||
|
},
|
||||||
|
"f:timepicker": {},
|
||||||
|
"f:timezone": {},
|
||||||
|
"f:title": {},
|
||||||
|
"f:uid": {},
|
||||||
|
"f:version": {},
|
||||||
|
"f:weekStart": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"spec": {
|
||||||
|
"annotations": {
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"builtIn": 1,
|
||||||
|
"datasource": {
|
||||||
|
"type": "grafana",
|
||||||
|
"uid": "-- Grafana --"
|
||||||
|
},
|
||||||
|
"enable": true,
|
||||||
|
"hide": true,
|
||||||
|
"iconColor": "rgba(0, 211, 255, 1)",
|
||||||
|
"name": "Annotations \u0026 Alerts",
|
||||||
|
"type": "dashboard"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"description": "A dashboard with tags",
|
||||||
|
"editable": true,
|
||||||
|
"fiscalYearStartMonth": 0,
|
||||||
|
"graphTooltip": 0,
|
||||||
|
"id": null,
|
||||||
|
"links": [],
|
||||||
|
"panels": [
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "datasource",
|
||||||
|
"uid": "grafana"
|
||||||
|
},
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "palette-classic"
|
||||||
|
},
|
||||||
|
"custom": {
|
||||||
|
"axisBorderShow": false,
|
||||||
|
"axisCenteredZero": false,
|
||||||
|
"axisColorMode": "text",
|
||||||
|
"axisLabel": "",
|
||||||
|
"axisPlacement": "auto",
|
||||||
|
"barAlignment": 0,
|
||||||
|
"barWidthFactor": 0.6,
|
||||||
|
"drawStyle": "line",
|
||||||
|
"fillOpacity": 0,
|
||||||
|
"gradientMode": "none",
|
||||||
|
"hideFrom": {
|
||||||
|
"legend": false,
|
||||||
|
"tooltip": false,
|
||||||
|
"viz": false
|
||||||
|
},
|
||||||
|
"insertNulls": false,
|
||||||
|
"lineInterpolation": "linear",
|
||||||
|
"lineWidth": 1,
|
||||||
|
"pointSize": 5,
|
||||||
|
"scaleDistribution": {
|
||||||
|
"type": "linear"
|
||||||
|
},
|
||||||
|
"showPoints": "auto",
|
||||||
|
"spanNulls": false,
|
||||||
|
"stacking": {
|
||||||
|
"group": "A",
|
||||||
|
"mode": "none"
|
||||||
|
},
|
||||||
|
"thresholdsStyle": {
|
||||||
|
"mode": "off"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mappings": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "red",
|
||||||
|
"value": 80
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 8,
|
||||||
|
"w": 12,
|
||||||
|
"x": 0,
|
||||||
|
"y": 0
|
||||||
|
},
|
||||||
|
"id": 2,
|
||||||
|
"options": {
|
||||||
|
"legend": {
|
||||||
|
"calcs": [],
|
||||||
|
"displayMode": "list",
|
||||||
|
"placement": "bottom",
|
||||||
|
"showLegend": true
|
||||||
|
},
|
||||||
|
"tooltip": {
|
||||||
|
"mode": "single",
|
||||||
|
"sort": "none"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pluginVersion": "9.2.0",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Panel 2",
|
||||||
|
"type": "timeseries"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "datasource",
|
||||||
|
"uid": "grafana"
|
||||||
|
},
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "palette-classic"
|
||||||
|
},
|
||||||
|
"custom": {
|
||||||
|
"axisBorderShow": false,
|
||||||
|
"axisCenteredZero": false,
|
||||||
|
"axisColorMode": "text",
|
||||||
|
"axisLabel": "",
|
||||||
|
"axisPlacement": "auto",
|
||||||
|
"barAlignment": 0,
|
||||||
|
"barWidthFactor": 0.6,
|
||||||
|
"drawStyle": "line",
|
||||||
|
"fillOpacity": 0,
|
||||||
|
"gradientMode": "none",
|
||||||
|
"hideFrom": {
|
||||||
|
"legend": false,
|
||||||
|
"tooltip": false,
|
||||||
|
"viz": false
|
||||||
|
},
|
||||||
|
"insertNulls": false,
|
||||||
|
"lineInterpolation": "linear",
|
||||||
|
"lineWidth": 1,
|
||||||
|
"pointSize": 5,
|
||||||
|
"scaleDistribution": {
|
||||||
|
"type": "linear"
|
||||||
|
},
|
||||||
|
"showPoints": "auto",
|
||||||
|
"spanNulls": false,
|
||||||
|
"stacking": {
|
||||||
|
"group": "A",
|
||||||
|
"mode": "none"
|
||||||
|
},
|
||||||
|
"thresholdsStyle": {
|
||||||
|
"mode": "off"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mappings": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "red",
|
||||||
|
"value": 80
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 8,
|
||||||
|
"w": 12,
|
||||||
|
"x": 0,
|
||||||
|
"y": 8
|
||||||
|
},
|
||||||
|
"id": 1,
|
||||||
|
"options": {
|
||||||
|
"legend": {
|
||||||
|
"calcs": [],
|
||||||
|
"displayMode": "list",
|
||||||
|
"placement": "bottom",
|
||||||
|
"showLegend": true
|
||||||
|
},
|
||||||
|
"tooltip": {
|
||||||
|
"mode": "single",
|
||||||
|
"sort": "none"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pluginVersion": "9.2.0",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "datasource",
|
||||||
|
"uid": "grafana"
|
||||||
|
},
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Another Panel",
|
||||||
|
"type": "timeseries"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"preload": false,
|
||||||
|
"schemaVersion": 40,
|
||||||
|
"tags": [
|
||||||
|
"tag1",
|
||||||
|
"tag2",
|
||||||
|
"tag3"
|
||||||
|
],
|
||||||
|
"templating": {
|
||||||
|
"list": []
|
||||||
|
},
|
||||||
|
"timepicker": {},
|
||||||
|
"timezone": "browser",
|
||||||
|
"title": "Dashboard with Tags",
|
||||||
|
"uid": "",
|
||||||
|
"version": 0,
|
||||||
|
"weekStart": ""
|
||||||
|
}
|
||||||
|
}
|
284
pkg/storage/unified/resource/testdata/dashboard-tagged-resource2.json
vendored
Normal file
284
pkg/storage/unified/resource/testdata/dashboard-tagged-resource2.json
vendored
Normal file
@ -0,0 +1,284 @@
|
|||||||
|
{
|
||||||
|
"kind": "Dashboard",
|
||||||
|
"apiVersion": "dashboard.grafana.app/v0alpha1",
|
||||||
|
"metadata": {
|
||||||
|
"name": "foo",
|
||||||
|
"namespace": "default",
|
||||||
|
"uid": "86ab200a-e8b0-47ce-bbc1-8c2e078b0956-2",
|
||||||
|
"creationTimestamp": "2024-10-30T20:24:07Z",
|
||||||
|
"annotations": {
|
||||||
|
"grafana.app/createdBy": "user:be2g71ke8yoe8b",
|
||||||
|
"grafana.app/originHash": "Grafana v9.2.0 (NA)",
|
||||||
|
"grafana.app/originName": "UI",
|
||||||
|
"grafana.app/originPath": "/dashboard/new"
|
||||||
|
},
|
||||||
|
"managedFields": [
|
||||||
|
{
|
||||||
|
"manager": "Mozilla",
|
||||||
|
"operation": "Update",
|
||||||
|
"apiVersion": "dashboard.grafana.app/v0alpha1",
|
||||||
|
"time": "2024-10-30T20:24:07Z",
|
||||||
|
"fieldsType": "FieldsV1",
|
||||||
|
"fieldsV1": {
|
||||||
|
"f:metadata": {
|
||||||
|
"f:annotations": {
|
||||||
|
".": {},
|
||||||
|
"f:grafana.app/originHash": {},
|
||||||
|
"f:grafana.app/originName": {},
|
||||||
|
"f:grafana.app/originPath": {}
|
||||||
|
},
|
||||||
|
"f:generateName": {}
|
||||||
|
},
|
||||||
|
"f:spec": {
|
||||||
|
"f:annotations": {
|
||||||
|
".": {},
|
||||||
|
"f:list": {}
|
||||||
|
},
|
||||||
|
"f:description": {},
|
||||||
|
"f:editable": {},
|
||||||
|
"f:fiscalYearStartMonth": {},
|
||||||
|
"f:graphTooltip": {},
|
||||||
|
"f:id": {},
|
||||||
|
"f:links": {},
|
||||||
|
"f:panels": {},
|
||||||
|
"f:preload": {},
|
||||||
|
"f:schemaVersion": {},
|
||||||
|
"f:tags": {},
|
||||||
|
"f:templating": {
|
||||||
|
".": {},
|
||||||
|
"f:list": {}
|
||||||
|
},
|
||||||
|
"f:timepicker": {},
|
||||||
|
"f:timezone": {},
|
||||||
|
"f:title": {},
|
||||||
|
"f:uid": {},
|
||||||
|
"f:version": {},
|
||||||
|
"f:weekStart": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"spec": {
|
||||||
|
"annotations": {
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"builtIn": 1,
|
||||||
|
"datasource": {
|
||||||
|
"type": "grafana",
|
||||||
|
"uid": "-- Grafana --"
|
||||||
|
},
|
||||||
|
"enable": true,
|
||||||
|
"hide": true,
|
||||||
|
"iconColor": "rgba(0, 211, 255, 1)",
|
||||||
|
"name": "Annotations \u0026 Alerts",
|
||||||
|
"type": "dashboard"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"description": "Another dashboard with tags",
|
||||||
|
"editable": true,
|
||||||
|
"fiscalYearStartMonth": 0,
|
||||||
|
"graphTooltip": 0,
|
||||||
|
"id": null,
|
||||||
|
"links": [],
|
||||||
|
"panels": [
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "datasource",
|
||||||
|
"uid": "grafana"
|
||||||
|
},
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "palette-classic"
|
||||||
|
},
|
||||||
|
"custom": {
|
||||||
|
"axisBorderShow": false,
|
||||||
|
"axisCenteredZero": false,
|
||||||
|
"axisColorMode": "text",
|
||||||
|
"axisLabel": "",
|
||||||
|
"axisPlacement": "auto",
|
||||||
|
"barAlignment": 0,
|
||||||
|
"barWidthFactor": 0.6,
|
||||||
|
"drawStyle": "line",
|
||||||
|
"fillOpacity": 0,
|
||||||
|
"gradientMode": "none",
|
||||||
|
"hideFrom": {
|
||||||
|
"legend": false,
|
||||||
|
"tooltip": false,
|
||||||
|
"viz": false
|
||||||
|
},
|
||||||
|
"insertNulls": false,
|
||||||
|
"lineInterpolation": "linear",
|
||||||
|
"lineWidth": 1,
|
||||||
|
"pointSize": 5,
|
||||||
|
"scaleDistribution": {
|
||||||
|
"type": "linear"
|
||||||
|
},
|
||||||
|
"showPoints": "auto",
|
||||||
|
"spanNulls": false,
|
||||||
|
"stacking": {
|
||||||
|
"group": "A",
|
||||||
|
"mode": "none"
|
||||||
|
},
|
||||||
|
"thresholdsStyle": {
|
||||||
|
"mode": "off"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mappings": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "red",
|
||||||
|
"value": 80
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 8,
|
||||||
|
"w": 12,
|
||||||
|
"x": 0,
|
||||||
|
"y": 0
|
||||||
|
},
|
||||||
|
"id": 2,
|
||||||
|
"options": {
|
||||||
|
"legend": {
|
||||||
|
"calcs": [],
|
||||||
|
"displayMode": "list",
|
||||||
|
"placement": "bottom",
|
||||||
|
"showLegend": true
|
||||||
|
},
|
||||||
|
"tooltip": {
|
||||||
|
"mode": "single",
|
||||||
|
"sort": "none"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pluginVersion": "9.2.0",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Panel 2",
|
||||||
|
"type": "timeseries"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "datasource",
|
||||||
|
"uid": "grafana"
|
||||||
|
},
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "palette-classic"
|
||||||
|
},
|
||||||
|
"custom": {
|
||||||
|
"axisBorderShow": false,
|
||||||
|
"axisCenteredZero": false,
|
||||||
|
"axisColorMode": "text",
|
||||||
|
"axisLabel": "",
|
||||||
|
"axisPlacement": "auto",
|
||||||
|
"barAlignment": 0,
|
||||||
|
"barWidthFactor": 0.6,
|
||||||
|
"drawStyle": "line",
|
||||||
|
"fillOpacity": 0,
|
||||||
|
"gradientMode": "none",
|
||||||
|
"hideFrom": {
|
||||||
|
"legend": false,
|
||||||
|
"tooltip": false,
|
||||||
|
"viz": false
|
||||||
|
},
|
||||||
|
"insertNulls": false,
|
||||||
|
"lineInterpolation": "linear",
|
||||||
|
"lineWidth": 1,
|
||||||
|
"pointSize": 5,
|
||||||
|
"scaleDistribution": {
|
||||||
|
"type": "linear"
|
||||||
|
},
|
||||||
|
"showPoints": "auto",
|
||||||
|
"spanNulls": false,
|
||||||
|
"stacking": {
|
||||||
|
"group": "A",
|
||||||
|
"mode": "none"
|
||||||
|
},
|
||||||
|
"thresholdsStyle": {
|
||||||
|
"mode": "off"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mappings": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "red",
|
||||||
|
"value": 80
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 8,
|
||||||
|
"w": 12,
|
||||||
|
"x": 0,
|
||||||
|
"y": 8
|
||||||
|
},
|
||||||
|
"id": 1,
|
||||||
|
"options": {
|
||||||
|
"legend": {
|
||||||
|
"calcs": [],
|
||||||
|
"displayMode": "list",
|
||||||
|
"placement": "bottom",
|
||||||
|
"showLegend": true
|
||||||
|
},
|
||||||
|
"tooltip": {
|
||||||
|
"mode": "single",
|
||||||
|
"sort": "none"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pluginVersion": "9.2.0",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "datasource",
|
||||||
|
"uid": "grafana"
|
||||||
|
},
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Another Panel",
|
||||||
|
"type": "timeseries"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"preload": false,
|
||||||
|
"schemaVersion": 40,
|
||||||
|
"tags": [
|
||||||
|
"tag1",
|
||||||
|
"tag2",
|
||||||
|
"tag4"
|
||||||
|
],
|
||||||
|
"templating": {
|
||||||
|
"list": []
|
||||||
|
},
|
||||||
|
"timepicker": {},
|
||||||
|
"timezone": "browser",
|
||||||
|
"title": "Dashboard with Tags",
|
||||||
|
"uid": "",
|
||||||
|
"version": 0,
|
||||||
|
"weekStart": ""
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user