diff --git a/pkg/registry/core/componentstatus/BUILD b/pkg/registry/core/componentstatus/BUILD index 55aa5f9aa6c..145f3265e43 100644 --- a/pkg/registry/core/componentstatus/BUILD +++ b/pkg/registry/core/componentstatus/BUILD @@ -20,9 +20,13 @@ go_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/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/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/storage:go_default_library", ], ) @@ -36,7 +40,10 @@ go_test( deps = [ "//pkg/apis/core: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/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/apiserver/pkg/endpoints/request:go_default_library", ], diff --git a/pkg/registry/core/componentstatus/rest.go b/pkg/registry/core/componentstatus/rest.go index ed8aaec6cb4..6e34e241045 100644 --- a/pkg/registry/core/componentstatus/rest.go +++ b/pkg/registry/core/componentstatus/rest.go @@ -21,6 +21,11 @@ import ( "fmt" "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" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" @@ -70,13 +75,47 @@ func (rs *REST) List(ctx context.Context, options *metainternalversion.ListOptio wait.Wait() close(statuses) + pred := componentStatusPredicate(options) + reply := []api.ComponentStatus{} 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 } +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) { servers := rs.GetServersToValidate() diff --git a/pkg/registry/core/componentstatus/rest_test.go b/pkg/registry/core/componentstatus/rest_test.go index 3b2194f56ec..62366ab4fbe 100644 --- a/pkg/registry/core/componentstatus/rest_test.go +++ b/pkg/registry/core/componentstatus/rest_test.go @@ -22,6 +22,10 @@ import ( "strings" "testing" + metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion" + "k8s.io/apimachinery/pkg/fields" + "k8s.io/apimachinery/pkg/labels" + "net/http" "net/url" "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) { r := NewTestREST(testResponse{result: probe.Failure, data: ""}) got, err := r.List(genericapirequest.NewContext(), nil)