Files

133 lines
4.7 KiB
Go

// 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/resourcepb"
)
func toListRequest(k *resourcepb.ResourceKey, opts storage.ListOptions) (*resourcepb.ListRequest, storage.SelectionPredicate, error) {
predicate := opts.Predicate
req := &resourcepb.ListRequest{
Limit: opts.Predicate.Limit,
Options: &resourcepb.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 = resourcepb.ResourceVersionMatchV2_Unset
case metav1.ResourceVersionMatchNotOlderThan:
req.VersionMatchV2 = resourcepb.ResourceVersionMatchV2_NotOlderThan
case metav1.ResourceVersionMatchExact:
req.VersionMatchV2 = resourcepb.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 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)
}
switch v {
case utils.LabelKeyGetTrash:
req.Source = resourcepb.ListRequest_TRASH
if vals[0] != "true" {
return nil, predicate, apierrors.NewBadRequest("expecting true for: " + v)
}
case utils.LabelKeyGetHistory:
req.Source = resourcepb.ListRequest_HISTORY
if opts.Predicate.Field == nil || opts.Predicate.Field.Empty() {
return nil, predicate, apierrors.NewBadRequest("metadata.name field selector required for history requests")
}
fieldRequirements := opts.Predicate.Field.Requirements()
if len(fieldRequirements) != 1 {
return nil, predicate, apierrors.NewBadRequest("only one field selector supported for history requests")
}
fieldReq := fieldRequirements[0]
if fieldReq.Field != "metadata.name" {
return nil, predicate, apierrors.NewBadRequest("metadata.name field selector required for history requests")
}
req.Options.Key.Name = fieldReq.Value
}
req.Options.Labels = nil
req.Options.Fields = nil
return req, storage.Everything, nil
}
req.Options.Labels = append(req.Options.Labels, &resourcepb.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 := &resourcepb.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
}