Alerting: Support field selectors in time interval API (#90022)
* fix kind of TimeInterval * register custom fields for selectors * support field selectors in legacy storage * support selectors in storage ===== Misc * refactor conversions to build in one place * hide implementation of provenance status behind accessors to use the key in selectors * fix provenance error
This commit is contained in:
@@ -54,19 +54,18 @@ func convertToK8sResource(orgID int64, receiver definitions.GettableApiReceiver,
|
||||
}
|
||||
|
||||
uid := getUID(receiver) // TODO replace to stable UID when we switch to normal storage
|
||||
return &model.Receiver{
|
||||
r := &model.Receiver{
|
||||
TypeMeta: resourceInfo.TypeMeta(),
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
UID: types.UID(uid), // This is needed to make PATCH work
|
||||
Name: uid, // TODO replace to stable UID when we switch to normal storage
|
||||
Namespace: namespacer(orgID),
|
||||
Annotations: map[string]string{ // TODO find a better place for provenance?
|
||||
"grafana.com/provenance": string(provenance),
|
||||
},
|
||||
UID: types.UID(uid), // This is needed to make PATCH work
|
||||
Name: uid, // TODO replace to stable UID when we switch to normal storage
|
||||
Namespace: namespacer(orgID),
|
||||
ResourceVersion: "", // TODO: Implement optimistic concurrency.
|
||||
},
|
||||
Spec: spec,
|
||||
}, nil
|
||||
}
|
||||
r.SetProvenanceStatus(string(provenance))
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func convertToDomainModel(receiver *model.Receiver) (definitions.GettableApiReceiver, error) {
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"hash/fnv"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
|
||||
model "github.com/grafana/grafana/pkg/apis/alerting_notifications/v0alpha1"
|
||||
@@ -19,7 +20,7 @@ func getIntervalUID(t definitions.MuteTimeInterval) string {
|
||||
return fmt.Sprintf("%016x", sum.Sum64())
|
||||
}
|
||||
|
||||
func convertToK8sResources(orgID int64, intervals []definitions.MuteTimeInterval, namespacer request.NamespaceMapper) (*model.TimeIntervalList, error) {
|
||||
func convertToK8sResources(orgID int64, intervals []definitions.MuteTimeInterval, namespacer request.NamespaceMapper, selector fields.Selector) (*model.TimeIntervalList, error) {
|
||||
data, err := json.Marshal(intervals)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -30,23 +31,15 @@ func convertToK8sResources(orgID int64, intervals []definitions.MuteTimeInterval
|
||||
return nil, err
|
||||
}
|
||||
result := &model.TimeIntervalList{}
|
||||
|
||||
for idx := range specs {
|
||||
interval := intervals[idx]
|
||||
spec := specs[idx]
|
||||
uid := getIntervalUID(interval) // TODO replace to stable UID when we switch to normal storage
|
||||
result.Items = append(result.Items, model.TimeInterval{
|
||||
TypeMeta: resourceInfo.TypeMeta(),
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
UID: types.UID(uid), // TODO This is needed to make PATCH work
|
||||
Name: uid, // TODO replace to stable UID when we switch to normal storage
|
||||
Namespace: namespacer(orgID),
|
||||
Annotations: map[string]string{ // TODO find a better place for provenance?
|
||||
"grafana.com/provenance": string(interval.Provenance),
|
||||
},
|
||||
ResourceVersion: interval.Version,
|
||||
},
|
||||
Spec: spec,
|
||||
})
|
||||
item := buildTimeInterval(orgID, interval, spec, namespacer)
|
||||
if selector != nil && !selector.Empty() && !selector.Matches(model.SelectableTimeIntervalsFields(&item)) {
|
||||
continue
|
||||
}
|
||||
result.Items = append(result.Items, item)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
@@ -61,21 +54,24 @@ func convertToK8sResource(orgID int64, interval definitions.MuteTimeInterval, na
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := buildTimeInterval(orgID, interval, spec, namespacer)
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
func buildTimeInterval(orgID int64, interval definitions.MuteTimeInterval, spec model.TimeIntervalSpec, namespacer request.NamespaceMapper) model.TimeInterval {
|
||||
uid := getIntervalUID(interval) // TODO replace to stable UID when we switch to normal storage
|
||||
return &model.TimeInterval{
|
||||
i := model.TimeInterval{
|
||||
TypeMeta: resourceInfo.TypeMeta(),
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
UID: types.UID(uid), // TODO This is needed to make PATCH work
|
||||
Name: uid, // TODO replace to stable UID when we switch to normal storage
|
||||
Namespace: namespacer(orgID),
|
||||
Annotations: map[string]string{ // TODO find a better place for provenance?
|
||||
"grafana.com/provenance": string(interval.Provenance),
|
||||
},
|
||||
UID: types.UID(uid), // TODO This is needed to make PATCH work
|
||||
Name: uid, // TODO replace to stable UID when we switch to normal storage
|
||||
Namespace: namespacer(orgID),
|
||||
ResourceVersion: interval.Version,
|
||||
},
|
||||
Spec: spec,
|
||||
}, nil
|
||||
}
|
||||
i.SetProvenanceStatus(string(interval.Provenance))
|
||||
return i
|
||||
}
|
||||
|
||||
func convertToDomainModel(interval *model.TimeInterval) (definitions.MuteTimeInterval, error) {
|
||||
|
||||
@@ -59,7 +59,7 @@ func (s *legacyStorage) ConvertToTable(ctx context.Context, object runtime.Objec
|
||||
return s.tableConverter.ConvertToTable(ctx, object, tableOptions)
|
||||
}
|
||||
|
||||
func (s *legacyStorage) List(ctx context.Context, _ *internalversion.ListOptions) (runtime.Object, error) {
|
||||
func (s *legacyStorage) List(ctx context.Context, opts *internalversion.ListOptions) (runtime.Object, error) {
|
||||
orgId, err := request.OrgIDForList(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -70,7 +70,7 @@ func (s *legacyStorage) List(ctx context.Context, _ *internalversion.ListOptions
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return convertToK8sResources(orgId, res, s.namespacer)
|
||||
return convertToK8sResources(orgId, res, s.namespacer, opts.FieldSelector)
|
||||
}
|
||||
|
||||
func (s *legacyStorage) Get(ctx context.Context, uid string, _ *metav1.GetOptions) (runtime.Object, error) {
|
||||
|
||||
@@ -4,10 +4,13 @@ import (
|
||||
"fmt"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apiserver/pkg/registry/generic"
|
||||
genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
|
||||
"k8s.io/apiserver/pkg/registry/rest"
|
||||
apistore "k8s.io/apiserver/pkg/storage"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
|
||||
@@ -63,7 +66,7 @@ func NewStorage(
|
||||
NewListFunc: resourceInfo.NewListFunc,
|
||||
KeyRootFunc: grafanaregistry.KeyRootFunc(resourceInfo.GroupResource()),
|
||||
KeyFunc: grafanaregistry.NamespaceKeyFunc(resourceInfo.GroupResource()),
|
||||
PredicateFunc: grafanaregistry.Matcher,
|
||||
PredicateFunc: Matcher,
|
||||
DefaultQualifiedResource: resourceInfo.GroupResource(),
|
||||
SingularQualifiedResource: resourceInfo.SingularGroupResource(),
|
||||
TableConvertor: legacyStore.tableConverter,
|
||||
@@ -71,7 +74,7 @@ func NewStorage(
|
||||
UpdateStrategy: strategy,
|
||||
DeleteStrategy: strategy,
|
||||
}
|
||||
options := &generic.StoreOptions{RESTOptions: optsGetter, AttrFunc: grafanaregistry.GetAttrs}
|
||||
options := &generic.StoreOptions{RESTOptions: optsGetter, AttrFunc: GetAttrs}
|
||||
if err := s.CompleteWithOptions(options); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -79,3 +82,19 @@ func NewStorage(
|
||||
}
|
||||
return legacyStore, nil
|
||||
}
|
||||
|
||||
func GetAttrs(obj runtime.Object) (labels.Set, fields.Set, error) {
|
||||
if s, ok := obj.(*model.TimeInterval); ok {
|
||||
return s.Labels, model.SelectableTimeIntervalsFields(s), nil
|
||||
}
|
||||
return nil, nil, fmt.Errorf("object of type %T is not supported", obj)
|
||||
}
|
||||
|
||||
// Matcher returns a generic.SelectionPredicate that matches on label and field selectors.
|
||||
func Matcher(label labels.Selector, field fields.Selector) apistore.SelectionPredicate {
|
||||
return apistore.SelectionPredicate{
|
||||
Label: label,
|
||||
Field: field,
|
||||
GetAttrs: GetAttrs,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user