mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 11:50:44 +00:00
Merge pull request #78438 from 11janci/jjanik-cs-filtering
Match label and fields selectors in ComponentStatus List API
This commit is contained in:
commit
9243fcdd65
@ -20,9 +20,13 @@ go_library(
|
|||||||
"//pkg/probe/http:go_default_library",
|
"//pkg/probe/http:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/internalversion:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/internalversion:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/fields:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/util/net:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/util/net:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apiserver/pkg/registry/generic:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/registry/rest:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/registry/rest:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apiserver/pkg/storage:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -36,7 +40,10 @@ go_test(
|
|||||||
deps = [
|
deps = [
|
||||||
"//pkg/apis/core:go_default_library",
|
"//pkg/apis/core:go_default_library",
|
||||||
"//pkg/probe:go_default_library",
|
"//pkg/probe:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/internalversion:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/fields:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/util/diff:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/util/diff:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/endpoints/request:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/endpoints/request:go_default_library",
|
||||||
],
|
],
|
||||||
|
@ -21,6 +21,11 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/fields"
|
||||||
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
|
"k8s.io/apiserver/pkg/registry/generic"
|
||||||
|
"k8s.io/apiserver/pkg/storage"
|
||||||
|
|
||||||
metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion"
|
metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
@ -70,13 +75,47 @@ func (rs *REST) List(ctx context.Context, options *metainternalversion.ListOptio
|
|||||||
wait.Wait()
|
wait.Wait()
|
||||||
close(statuses)
|
close(statuses)
|
||||||
|
|
||||||
|
pred := componentStatusPredicate(options)
|
||||||
|
|
||||||
reply := []api.ComponentStatus{}
|
reply := []api.ComponentStatus{}
|
||||||
for status := range statuses {
|
for status := range statuses {
|
||||||
reply = append(reply, status)
|
// ComponentStatus resources currently (v1.14) do not support labeling, however the filtering is executed
|
||||||
|
// nonetheless in case the request contains Label or Field selectors (which will effectively filter out
|
||||||
|
// all of the results and return an empty response).
|
||||||
|
if matched := matchesPredicate(status, &pred); matched {
|
||||||
|
reply = append(reply, status)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return &api.ComponentStatusList{Items: reply}, nil
|
return &api.ComponentStatusList{Items: reply}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func componentStatusPredicate(options *metainternalversion.ListOptions) storage.SelectionPredicate {
|
||||||
|
pred := storage.SelectionPredicate{
|
||||||
|
Label: labels.Everything(),
|
||||||
|
Field: fields.Everything(),
|
||||||
|
GetAttrs: nil,
|
||||||
|
IndexFields: []string{},
|
||||||
|
}
|
||||||
|
if options != nil {
|
||||||
|
if options.LabelSelector != nil {
|
||||||
|
pred.Label = options.LabelSelector
|
||||||
|
}
|
||||||
|
if options.FieldSelector != nil {
|
||||||
|
pred.Field = options.FieldSelector
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pred
|
||||||
|
}
|
||||||
|
|
||||||
|
func matchesPredicate(status api.ComponentStatus, pred *storage.SelectionPredicate) bool {
|
||||||
|
// currently no fields except the generic meta fields are supported for predicate matching
|
||||||
|
fieldsSet := generic.AddObjectMetaFieldsSet(make(fields.Set, 2), &status.ObjectMeta, true)
|
||||||
|
return pred.MatchesObjectAttributes(
|
||||||
|
status.ObjectMeta.Labels,
|
||||||
|
fieldsSet,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
func (rs *REST) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) {
|
func (rs *REST) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) {
|
||||||
servers := rs.GetServersToValidate()
|
servers := rs.GetServersToValidate()
|
||||||
|
|
||||||
|
@ -22,6 +22,10 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion"
|
||||||
|
"k8s.io/apimachinery/pkg/fields"
|
||||||
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"time"
|
"time"
|
||||||
@ -88,6 +92,44 @@ func TestList_NoError(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestList_WithLabelSelectors(t *testing.T) {
|
||||||
|
r := NewTestREST(testResponse{result: probe.Success, data: "ok"})
|
||||||
|
opts := metainternalversion.ListOptions{
|
||||||
|
LabelSelector: labels.SelectorFromSet(map[string]string{
|
||||||
|
"testLabel": "testValue",
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
got, err := r.List(genericapirequest.NewContext(), &opts)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
expect := &api.ComponentStatusList{
|
||||||
|
Items: []api.ComponentStatus{},
|
||||||
|
}
|
||||||
|
if e, a := expect, got; !reflect.DeepEqual(e, a) {
|
||||||
|
t.Errorf("Got unexpected object. Diff: %s", diff.ObjectDiff(e, a))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestList_WithFieldSelectors(t *testing.T) {
|
||||||
|
r := NewTestREST(testResponse{result: probe.Success, data: "ok"})
|
||||||
|
opts := metainternalversion.ListOptions{
|
||||||
|
FieldSelector: fields.SelectorFromSet(map[string]string{
|
||||||
|
"testField": "testValue",
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
got, err := r.List(genericapirequest.NewContext(), &opts)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
expect := &api.ComponentStatusList{
|
||||||
|
Items: []api.ComponentStatus{},
|
||||||
|
}
|
||||||
|
if e, a := expect, got; !reflect.DeepEqual(e, a) {
|
||||||
|
t.Errorf("Got unexpected object. Diff: %s", diff.ObjectDiff(e, a))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestList_FailedCheck(t *testing.T) {
|
func TestList_FailedCheck(t *testing.T) {
|
||||||
r := NewTestREST(testResponse{result: probe.Failure, data: ""})
|
r := NewTestREST(testResponse{result: probe.Failure, data: ""})
|
||||||
got, err := r.List(genericapirequest.NewContext(), nil)
|
got, err := r.List(genericapirequest.NewContext(), nil)
|
||||||
|
Loading…
Reference in New Issue
Block a user