Merge pull request #78438 from 11janci/jjanik-cs-filtering

Match label and fields selectors in ComponentStatus List API
This commit is contained in:
Kubernetes Prow Robot 2019-09-18 06:47:29 -07:00 committed by GitHub
commit 9243fcdd65
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 89 additions and 1 deletions

View File

@ -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",
], ],

View File

@ -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()

View File

@ -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)