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

View File

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

View File

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