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/storage/unified/apistore/util.go

121 lines
4.3 KiB

// SPDX-License-Identifier: AGPL-3.0-only
// Provenance-includes-location: https://github.com/kubernetes-sigs/apiserver-runtime/blob/main/pkg/experimental/storage/filepath/jsonfile_rest.go
// Provenance-includes-license: Apache-2.0
// Provenance-includes-copyright: The Kubernetes Authors.
package apistore
import (
"fmt"
"strconv"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/selection"
"k8s.io/apiserver/pkg/storage"
"github.com/grafana/grafana/pkg/apimachinery/utils"
"github.com/grafana/grafana/pkg/storage/unified/resource"
)
func toListRequest(k *resource.ResourceKey, opts storage.ListOptions) (*resource.ListRequest, storage.SelectionPredicate, error) {
predicate := opts.Predicate
req := &resource.ListRequest{
Limit: opts.Predicate.Limit,
Options: &resource.ListOptions{
Key: k,
},
NextPageToken: predicate.Continue,
}
if opts.ResourceVersion != "" {
rv, err := strconv.ParseInt(opts.ResourceVersion, 10, 64)
if err != nil {
return nil, predicate, apierrors.NewBadRequest(fmt.Sprintf("invalid resource version: %s", opts.ResourceVersion))
}
req.ResourceVersion = rv
}
switch opts.ResourceVersionMatch {
case "":
req.VersionMatchV2 = resource.ResourceVersionMatchV2_Unset
case metav1.ResourceVersionMatchNotOlderThan:
req.VersionMatchV2 = resource.ResourceVersionMatchV2_NotOlderThan
case metav1.ResourceVersionMatchExact:
req.VersionMatchV2 = resource.ResourceVersionMatchV2_Exact
default:
return nil, predicate, apierrors.NewBadRequest(
fmt.Sprintf("unsupported version match: %v", opts.ResourceVersionMatch),
)
}
if opts.Predicate.Label != nil && !opts.Predicate.Label.Empty() {
requirements, selectable := opts.Predicate.Label.Requirements()
if !selectable {
return nil, predicate, nil // not selectable
}
for _, r := range requirements {
v := r.Key()
// Parse the history request from labels
// TODO: for LabelGetFullpath, we just skip this for unistore. We need a better solution for
// getting the full path for folders in unistore, without making a request for each parent folder.
// In modes 0-2 we added this label to indicate that the sql query should return that data as
// an annotation on the folder. However, this annotation cannot be saved to unified storage, otherwise
// we will have to recompute annotations for all descendants of a folder during a folder move.
// While we look for a better solution, unified storage will continue to return all folders & the folder
// service will get the full path by retrieving each parent folder.
if v == utils.LabelKeyGetHistory || v == utils.LabelKeyGetTrash || v == utils.LabelGetFullpath {
if len(requirements) != 1 {
return nil, predicate, apierrors.NewBadRequest("single label supported with: " + v)
}
if opts.Predicate.Field != nil && !opts.Predicate.Field.Empty() {
return nil, predicate, apierrors.NewBadRequest("field selector not supported with: " + v)
}
if r.Operator() != selection.Equals {
return nil, predicate, apierrors.NewBadRequest("only = operator supported with: " + v)
}
vals := r.Values().List()
if len(vals) != 1 {
return nil, predicate, apierrors.NewBadRequest("expecting single value for: " + v)
}
if v == utils.LabelKeyGetTrash {
req.Source = resource.ListRequest_TRASH
if vals[0] != "true" {
return nil, predicate, apierrors.NewBadRequest("expecting true for: " + v)
}
} else if v == utils.LabelKeyGetHistory {
req.Source = resource.ListRequest_HISTORY
req.Options.Key.Name = vals[0]
}
req.Options.Labels = nil
req.Options.Fields = nil
return req, storage.Everything, nil
}
req.Options.Labels = append(req.Options.Labels, &resource.Requirement{
Key: v,
Operator: string(r.Operator()),
Values: r.Values().List(),
})
}
}
if opts.Predicate.Field != nil && !opts.Predicate.Field.Empty() {
requirements := opts.Predicate.Field.Requirements()
for _, r := range requirements {
requirement := &resource.Requirement{Key: r.Field, Operator: string(r.Operator)}
if r.Value != "" {
requirement.Values = append(requirement.Values, r.Value)
}
req.Options.Labels = append(req.Options.Labels, requirement)
}
}
return req, predicate, nil
}