diff --git a/pkg/apis/core/v1/conversion.go b/pkg/apis/core/v1/conversion.go index a6ba99cc895..d89ea26354b 100644 --- a/pkg/apis/core/v1/conversion.go +++ b/pkg/apis/core/v1/conversion.go @@ -435,6 +435,7 @@ func AddFieldLabelConversionsForEvent(scheme *runtime.Scheme) error { "involvedObject.resourceVersion", "involvedObject.fieldPath", "reason", + "reportingComponent", "source", "type", "metadata.namespace", diff --git a/pkg/apis/events/v1/conversion.go b/pkg/apis/events/v1/conversion.go index 379ceeb9630..a45baf2f61f 100644 --- a/pkg/apis/events/v1/conversion.go +++ b/pkg/apis/events/v1/conversion.go @@ -17,8 +17,11 @@ limitations under the License. package v1 import ( + "fmt" + v1 "k8s.io/api/events/v1" conversion "k8s.io/apimachinery/pkg/conversion" + "k8s.io/apimachinery/pkg/runtime" k8s_api "k8s.io/kubernetes/pkg/apis/core" k8s_api_v1 "k8s.io/kubernetes/pkg/apis/core/v1" ) @@ -56,3 +59,29 @@ func Convert_core_Event_To_v1_Event(in *k8s_api.Event, out *v1.Event, s conversi out.DeprecatedCount = in.Count return nil } + +func AddFieldLabelConversionsForEvent(scheme *runtime.Scheme) error { + mapping := map[string]string{ + "reason": "reason", + "regarding.kind": "involvedObject.kind", // map events.k8s.io field to fieldset returned by ToSelectableFields + "regarding.namespace": "involvedObject.namespace", // map events.k8s.io field to fieldset returned by ToSelectableFields + "regarding.name": "involvedObject.name", // map events.k8s.io field to fieldset returned by ToSelectableFields + "regarding.uid": "involvedObject.uid", // map events.k8s.io field to fieldset returned by ToSelectableFields + "regarding.apiVersion": "involvedObject.apiVersion", // map events.k8s.io field to fieldset returned by ToSelectableFields + "regarding.resourceVersion": "involvedObject.resourceVersion", // map events.k8s.io field to fieldset returned by ToSelectableFields + "regarding.fieldPath": "involvedObject.fieldPath", // map events.k8s.io field to fieldset returned by ToSelectableFields + "reportingController": "reportingComponent", // map events.k8s.io field to fieldset returned by ToSelectableFields + "type": "type", + "metadata.namespace": "metadata.namespace", + "metadata.name": "metadata.name", + } + return scheme.AddFieldLabelConversionFunc(SchemeGroupVersion.WithKind("Event"), + func(label, value string) (string, string, error) { + mappedLabel, ok := mapping[label] + if !ok { + return "", "", fmt.Errorf("field label not supported: %s", label) + } + return mappedLabel, value, nil + }, + ) +} diff --git a/pkg/apis/events/v1/register.go b/pkg/apis/events/v1/register.go index 35785dc094f..958d433d6fa 100644 --- a/pkg/apis/events/v1/register.go +++ b/pkg/apis/events/v1/register.go @@ -41,5 +41,5 @@ func init() { // We only register manually written functions here. The registration of the // generated functions takes place in the generated files. The separation // makes the code compile even when the generated files are missing. - localSchemeBuilder.Register(RegisterDefaults) + localSchemeBuilder.Register(RegisterDefaults, AddFieldLabelConversionsForEvent) } diff --git a/pkg/apis/events/v1beta1/conversion.go b/pkg/apis/events/v1beta1/conversion.go index 3a2be8e3168..8c28cd7e581 100644 --- a/pkg/apis/events/v1beta1/conversion.go +++ b/pkg/apis/events/v1beta1/conversion.go @@ -17,8 +17,11 @@ limitations under the License. package v1beta1 import ( + "fmt" + v1beta1 "k8s.io/api/events/v1beta1" conversion "k8s.io/apimachinery/pkg/conversion" + "k8s.io/apimachinery/pkg/runtime" k8s_api "k8s.io/kubernetes/pkg/apis/core" k8s_api_v1 "k8s.io/kubernetes/pkg/apis/core/v1" ) @@ -56,3 +59,29 @@ func Convert_core_Event_To_v1beta1_Event(in *k8s_api.Event, out *v1beta1.Event, out.DeprecatedCount = in.Count return nil } + +func AddFieldLabelConversionsForEvent(scheme *runtime.Scheme) error { + mapping := map[string]string{ + "reason": "reason", + "regarding.kind": "involvedObject.kind", // map events.k8s.io field to fieldset returned by ToSelectableFields + "regarding.namespace": "involvedObject.namespace", // map events.k8s.io field to fieldset returned by ToSelectableFields + "regarding.name": "involvedObject.name", // map events.k8s.io field to fieldset returned by ToSelectableFields + "regarding.uid": "involvedObject.uid", // map events.k8s.io field to fieldset returned by ToSelectableFields + "regarding.apiVersion": "involvedObject.apiVersion", // map events.k8s.io field to fieldset returned by ToSelectableFields + "regarding.resourceVersion": "involvedObject.resourceVersion", // map events.k8s.io field to fieldset returned by ToSelectableFields + "regarding.fieldPath": "involvedObject.fieldPath", // map events.k8s.io field to fieldset returned by ToSelectableFields + "reportingController": "reportingComponent", // map events.k8s.io field to fieldset returned by ToSelectableFields + "type": "type", + "metadata.namespace": "metadata.namespace", + "metadata.name": "metadata.name", + } + return scheme.AddFieldLabelConversionFunc(SchemeGroupVersion.WithKind("Event"), + func(label, value string) (string, string, error) { + mappedLabel, ok := mapping[label] + if !ok { + return "", "", fmt.Errorf("field label not supported: %s", label) + } + return mappedLabel, value, nil + }, + ) +} diff --git a/pkg/apis/events/v1beta1/register.go b/pkg/apis/events/v1beta1/register.go index 7ff9379602f..d4d5d44f64c 100644 --- a/pkg/apis/events/v1beta1/register.go +++ b/pkg/apis/events/v1beta1/register.go @@ -41,5 +41,5 @@ func init() { // We only register manually written functions here. The registration of the // generated functions takes place in the generated files. The separation // makes the code compile even when the generated files are missing. - localSchemeBuilder.Register(RegisterDefaults) + localSchemeBuilder.Register(RegisterDefaults, AddFieldLabelConversionsForEvent) } diff --git a/pkg/printers/internalversion/printers.go b/pkg/printers/internalversion/printers.go index fecdd20782c..9aea4aee9f6 100644 --- a/pkg/printers/internalversion/printers.go +++ b/pkg/printers/internalversion/printers.go @@ -1757,7 +1757,7 @@ func printEvent(obj *api.Event, options printers.GenerateOptions) ([]metav1.Tabl obj.Reason, target, obj.InvolvedObject.FieldPath, - formatEventSource(obj.Source), + formatEventSource(obj.Source, obj.ReportingController, obj.ReportingInstance), strings.TrimSpace(obj.Message), firstTimestamp, int64(count), @@ -2247,13 +2247,29 @@ func layoutContainerCells(containers []api.Container) (names string, images stri return namesBuffer.String(), imagesBuffer.String() } -// formatEventSource formats EventSource as a comma separated string excluding Host when empty -func formatEventSource(es api.EventSource) string { - EventSourceString := []string{es.Component} - if len(es.Host) > 0 { - EventSourceString = append(EventSourceString, es.Host) +// formatEventSource formats EventSource as a comma separated string excluding Host when empty. +// It uses reportingController when Source.Component is empty and reportingInstance when Source.Host is empty +func formatEventSource(es api.EventSource, reportingController, reportingInstance string) string { + return formatEventSourceComponentInstance( + firstNonEmpty(es.Component, reportingController), + firstNonEmpty(es.Host, reportingInstance), + ) +} + +func firstNonEmpty(ss ...string) string { + for _, s := range ss { + if len(s) > 0 { + return s + } } - return strings.Join(EventSourceString, ", ") + return "" +} + +func formatEventSourceComponentInstance(component, instance string) string { + if len(instance) == 0 { + return component + } + return component + ", " + instance } func printControllerRevision(obj *apps.ControllerRevision, options printers.GenerateOptions) ([]metav1.TableRow, error) { diff --git a/pkg/printers/internalversion/printers_test.go b/pkg/printers/internalversion/printers_test.go index 31ab7852608..1ecde89ad60 100644 --- a/pkg/printers/internalversion/printers_test.go +++ b/pkg/printers/internalversion/printers_test.go @@ -255,6 +255,28 @@ func TestPrintEvent(t *testing.T) { // Columns: Last Seen, Type, Reason, Object, Subobject, Message, First Seen, Count, Name expected: []metav1.TableRow{{Cells: []interface{}{"3d", "Warning", "Event Reason", "deployment/Deployment Name", "spec.containers{foo}", "kubelet, Node1", "Message Data", "3d", int64(1), "event7"}}}, }, + // Basic event, with empty Source; generate options=Wide + { + event: api.Event{ + ReportingController: "kubelet", + ReportingInstance: "test", + InvolvedObject: api.ObjectReference{ + Kind: "Deployment", + Name: "Deployment Name", + FieldPath: "spec.containers{foo}", + }, + Reason: "Event Reason", + Message: "Message Data", + FirstTimestamp: metav1.Time{Time: time.Now().UTC().AddDate(0, 0, -3)}, + LastTimestamp: metav1.Time{Time: time.Now().UTC().AddDate(0, 0, -2)}, + Count: 6, + Type: api.EventTypeWarning, + ObjectMeta: metav1.ObjectMeta{Name: "event2"}, + }, + options: printers.GenerateOptions{Wide: true}, + // Columns: Last Seen, Type, Reason, Object, Subobject, Source, Message, First Seen, Count, Name + expected: []metav1.TableRow{{Cells: []interface{}{"2d", "Warning", "Event Reason", "deployment/Deployment Name", "spec.containers{foo}", "kubelet, test", "Message Data", "3d", int64(6), "event2"}}}, + }, } for i, test := range tests { diff --git a/pkg/registry/BUILD b/pkg/registry/BUILD index bced397da5b..2ae4eb3cc14 100644 --- a/pkg/registry/BUILD +++ b/pkg/registry/BUILD @@ -68,7 +68,6 @@ filegroup( "//pkg/registry/core/serviceaccount:all-srcs", "//pkg/registry/discovery/endpointslice:all-srcs", "//pkg/registry/discovery/rest:all-srcs", - "//pkg/registry/events/event:all-srcs", "//pkg/registry/events/rest:all-srcs", "//pkg/registry/extensions/rest:all-srcs", "//pkg/registry/flowcontrol/flowschema:all-srcs", diff --git a/pkg/registry/core/event/strategy.go b/pkg/registry/core/event/strategy.go index 9c1c93c7c62..bc57da36809 100644 --- a/pkg/registry/core/event/strategy.go +++ b/pkg/registry/core/event/strategy.go @@ -104,6 +104,10 @@ func Matcher(label labels.Selector, field fields.Selector) storage.SelectionPred // ToSelectableFields returns a field set that represents the object. func ToSelectableFields(event *api.Event) fields.Set { objectMetaFieldsSet := generic.ObjectMetaFieldsSet(&event.ObjectMeta, true) + source := event.Source.Component + if source == "" { + source = event.ReportingController + } specificFieldsSet := fields.Set{ "involvedObject.kind": event.InvolvedObject.Kind, "involvedObject.namespace": event.InvolvedObject.Namespace, @@ -113,7 +117,8 @@ func ToSelectableFields(event *api.Event) fields.Set { "involvedObject.resourceVersion": event.InvolvedObject.ResourceVersion, "involvedObject.fieldPath": event.InvolvedObject.FieldPath, "reason": event.Reason, - "source": event.Source.Component, + "reportingComponent": event.ReportingController, // use the core/v1 field name + "source": source, "type": event.Type, } return generic.MergeFieldsSets(objectMetaFieldsSet, specificFieldsSet) diff --git a/pkg/registry/core/event/strategy_test.go b/pkg/registry/core/event/strategy_test.go index 639257c713f..1f7010e0dc4 100644 --- a/pkg/registry/core/event/strategy_test.go +++ b/pkg/registry/core/event/strategy_test.go @@ -50,7 +50,7 @@ func TestGetAttrs(t *testing.T) { Type: api.EventTypeNormal, } field := ToSelectableFields(eventA) - expect := fields.Set{ + expectA := fields.Set{ "metadata.name": "f0118", "metadata.namespace": "default", "involvedObject.kind": "Pod", @@ -61,10 +61,49 @@ func TestGetAttrs(t *testing.T) { "involvedObject.resourceVersion": "0", "involvedObject.fieldPath": "", "reason": "ForTesting", + "reportingComponent": "", "source": "test", "type": api.EventTypeNormal, } - if e, a := expect, field; !reflect.DeepEqual(e, a) { + if e, a := expectA, field; !reflect.DeepEqual(e, a) { + t.Errorf("diff: %s", diff.ObjectDiff(e, a)) + } + + eventB := &api.Event{ + ObjectMeta: metav1.ObjectMeta{ + Name: "f0118", + Namespace: "default", + }, + InvolvedObject: api.ObjectReference{ + Kind: "Pod", + Name: "foo", + Namespace: "baz", + UID: "long uid string", + APIVersion: "v1", + ResourceVersion: "0", + FieldPath: "", + }, + Reason: "ForTesting", + ReportingController: "test", + Type: api.EventTypeNormal, + } + field = ToSelectableFields(eventB) + expectB := fields.Set{ + "metadata.name": "f0118", + "metadata.namespace": "default", + "involvedObject.kind": "Pod", + "involvedObject.name": "foo", + "involvedObject.namespace": "baz", + "involvedObject.uid": "long uid string", + "involvedObject.apiVersion": "v1", + "involvedObject.resourceVersion": "0", + "involvedObject.fieldPath": "", + "reason": "ForTesting", + "reportingComponent": "test", + "source": "test", + "type": api.EventTypeNormal, + } + if e, a := expectB, field; !reflect.DeepEqual(e, a) { t.Errorf("diff: %s", diff.ObjectDiff(e, a)) } } diff --git a/pkg/registry/events/event/BUILD b/pkg/registry/events/event/BUILD deleted file mode 100644 index 161f5261423..00000000000 --- a/pkg/registry/events/event/BUILD +++ /dev/null @@ -1,39 +0,0 @@ -load("@io_bazel_rules_go//go:def.bzl", "go_library") - -go_library( - name = "go_default_library", - srcs = [ - "doc.go", - "strategy.go", - ], - importpath = "k8s.io/kubernetes/pkg/registry/events/event", - visibility = ["//visibility:public"], - deps = [ - "//pkg/api/legacyscheme:go_default_library", - "//pkg/apis/core:go_default_library", - "//pkg/apis/core/validation: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/schema:go_default_library", - "//staging/src/k8s.io/apimachinery/pkg/util/validation/field:go_default_library", - "//staging/src/k8s.io/apiserver/pkg/endpoints/request:go_default_library", - "//staging/src/k8s.io/apiserver/pkg/registry/generic:go_default_library", - "//staging/src/k8s.io/apiserver/pkg/storage:go_default_library", - "//staging/src/k8s.io/apiserver/pkg/storage/names:go_default_library", - ], -) - -filegroup( - name = "package-srcs", - srcs = glob(["**"]), - tags = ["automanaged"], - visibility = ["//visibility:private"], -) - -filegroup( - name = "all-srcs", - srcs = [":package-srcs"], - tags = ["automanaged"], - visibility = ["//visibility:public"], -) diff --git a/pkg/registry/events/event/doc.go b/pkg/registry/events/event/doc.go deleted file mode 100644 index 90cedb7aa99..00000000000 --- a/pkg/registry/events/event/doc.go +++ /dev/null @@ -1,17 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package event // import "k8s.io/kubernetes/pkg/registry/events/event" diff --git a/pkg/registry/events/event/strategy.go b/pkg/registry/events/event/strategy.go deleted file mode 100644 index 03d771c1e00..00000000000 --- a/pkg/registry/events/event/strategy.go +++ /dev/null @@ -1,117 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package event - -import ( - "context" - "fmt" - - "k8s.io/apimachinery/pkg/fields" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/util/validation/field" - genericapirequest "k8s.io/apiserver/pkg/endpoints/request" - "k8s.io/apiserver/pkg/registry/generic" - apistorage "k8s.io/apiserver/pkg/storage" - "k8s.io/apiserver/pkg/storage/names" - "k8s.io/kubernetes/pkg/api/legacyscheme" - coreapi "k8s.io/kubernetes/pkg/apis/core" - corevalidation "k8s.io/kubernetes/pkg/apis/core/validation" -) - -// eventStrategy implements verification logic for Pod Presets. -type eventStrategy struct { - runtime.ObjectTyper - names.NameGenerator -} - -// Strategy is the default logic that applies when creating and updating Pod Preset objects. -var Strategy = eventStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} - -// NamespaceScoped returns true because all Events need to be within a namespace. -func (eventStrategy) NamespaceScoped() bool { - return true -} - -// PrepareForCreate clears the status of a Pod Preset before creation. -func (eventStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) { -} - -// PrepareForUpdate clears fields that are not allowed to be set by end users on update. -func (eventStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) { -} - -// Validate validates a new Event. -func (eventStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList { - groupVersion := requestGroupVersion(ctx) - event := obj.(*coreapi.Event) - return corevalidation.ValidateEventCreate(event, groupVersion) -} - -// Canonicalize normalizes the object after validation. -// AllowCreateOnUpdate is false for Event; this means POST is needed to create one. -func (eventStrategy) AllowCreateOnUpdate() bool { - return false -} - -func (eventStrategy) Canonicalize(obj runtime.Object) {} - -// ValidateUpdate is the default update validation for an end user. -func (eventStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { - groupVersion := requestGroupVersion(ctx) - event := obj.(*coreapi.Event) - oldEvent := old.(*coreapi.Event) - return corevalidation.ValidateEventUpdate(event, oldEvent, groupVersion) -} - -// AllowUnconditionalUpdate is the default update policy for Event objects. -func (eventStrategy) AllowUnconditionalUpdate() bool { - return true -} - -// SelectableFields returns a field set that represents the object. -func SelectableFields(pip *coreapi.Event) fields.Set { - return generic.ObjectMetaFieldsSet(&pip.ObjectMeta, true) -} - -// GetAttrs returns labels and fields of a given object for filtering purposes. -func GetAttrs(obj runtime.Object) (labels.Set, fields.Set, error) { - pip, ok := obj.(*coreapi.Event) - if !ok { - return nil, nil, fmt.Errorf("given object is not a Event") - } - return labels.Set(pip.ObjectMeta.Labels), SelectableFields(pip), nil -} - -// Matcher is the filter used by the generic etcd backend to watch events -// from etcd to clients of the apiserver only interested in specific labels/fields. -func Matcher(label labels.Selector, field fields.Selector) apistorage.SelectionPredicate { - return apistorage.SelectionPredicate{ - Label: label, - Field: field, - GetAttrs: GetAttrs, - } -} - -// requestGroupVersion returns the group/version associated with the given context, or a zero-value group/version. -func requestGroupVersion(ctx context.Context) schema.GroupVersion { - if requestInfo, found := genericapirequest.RequestInfoFrom(ctx); found { - return schema.GroupVersion{Group: requestInfo.APIGroup, Version: requestInfo.APIVersion} - } - return schema.GroupVersion{} -} diff --git a/staging/src/k8s.io/client-go/tools/record/events_cache.go b/staging/src/k8s.io/client-go/tools/record/events_cache.go index 1b499efd39f..9374612f262 100644 --- a/staging/src/k8s.io/client-go/tools/record/events_cache.go +++ b/staging/src/k8s.io/client-go/tools/record/events_cache.go @@ -153,7 +153,8 @@ func (f *EventSourceObjectSpamFilter) Filter(event *v1.Event) bool { // localKey - key that makes this event in the local group type EventAggregatorKeyFunc func(event *v1.Event) (aggregateKey string, localKey string) -// EventAggregatorByReasonFunc aggregates events by exact match on event.Source, event.InvolvedObject, event.Type and event.Reason +// EventAggregatorByReasonFunc aggregates events by exact match on event.Source, event.InvolvedObject, event.Type, +// event.Reason, event.ReportingController and event.ReportingInstance func EventAggregatorByReasonFunc(event *v1.Event) (string, string) { return strings.Join([]string{ event.Source.Component, @@ -165,6 +166,8 @@ func EventAggregatorByReasonFunc(event *v1.Event) (string, string) { event.InvolvedObject.APIVersion, event.Type, event.Reason, + event.ReportingController, + event.ReportingInstance, }, ""), event.Message } diff --git a/test/e2e/instrumentation/BUILD b/test/e2e/instrumentation/BUILD index 96d8316f889..3af2587ca40 100644 --- a/test/e2e/instrumentation/BUILD +++ b/test/e2e/instrumentation/BUILD @@ -19,6 +19,7 @@ go_library( "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/types:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/diff:go_default_library", + "//staging/src/k8s.io/client-go/kubernetes/typed/core/v1:go_default_library", "//staging/src/k8s.io/client-go/kubernetes/typed/events/v1:go_default_library", "//test/e2e/framework:go_default_library", "//test/e2e/instrumentation/common:go_default_library", diff --git a/test/e2e/instrumentation/events.go b/test/e2e/instrumentation/events.go index 34d8769be52..3caecf79914 100644 --- a/test/e2e/instrumentation/events.go +++ b/test/e2e/instrumentation/events.go @@ -22,11 +22,12 @@ import ( "fmt" "time" - "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" eventsv1 "k8s.io/api/events/v1" apiequality "k8s.io/apimachinery/pkg/api/equality" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/diff" + corev1 "k8s.io/client-go/kubernetes/typed/core/v1" typedeventsv1 "k8s.io/client-go/kubernetes/typed/events/v1" "k8s.io/kubernetes/test/e2e/framework" "k8s.io/kubernetes/test/e2e/instrumentation/common" @@ -73,10 +74,12 @@ func eventExistsInList(client typedeventsv1.EventInterface, namespace, name stri var _ = common.SIGDescribe("Events API", func() { f := framework.NewDefaultFramework("events") + var coreClient corev1.EventInterface var client typedeventsv1.EventInterface var clientAllNamespaces typedeventsv1.EventInterface ginkgo.BeforeEach(func() { + coreClient = f.ClientSet.CoreV1().Events(f.Namespace.Name) client = f.ClientSet.EventsV1().Events(f.Namespace.Name) clientAllNamespaces = f.ClientSet.EventsV1().Events(metav1.NamespaceAll) }) @@ -103,6 +106,20 @@ var _ = common.SIGDescribe("Events API", func() { foundCreatedEvent = eventExistsInList(client, f.Namespace.Name, eventName) framework.ExpectEqual(foundCreatedEvent, true, "failed to find test event in list with namespace scope") + ginkgo.By("listing events with field selection filtering on source") + filteredCoreV1List, err := coreClient.List(context.TODO(), metav1.ListOptions{FieldSelector: "source=test-controller"}) + framework.ExpectNoError(err, "failed to get filtered list") + if len(filteredCoreV1List.Items) != 1 || filteredCoreV1List.Items[0].Name != eventName { + framework.Failf("expected single event, got %#v", filteredCoreV1List.Items) + } + + ginkgo.By("listing events with field selection filtering on reportingController") + filteredEventsV1List, err := client.List(context.TODO(), metav1.ListOptions{FieldSelector: "reportingController=test-controller"}) + framework.ExpectNoError(err, "failed to get filtered list") + if len(filteredEventsV1List.Items) != 1 || filteredEventsV1List.Items[0].Name != eventName { + framework.Failf("expected single event, got %#v", filteredEventsV1List.Items) + } + ginkgo.By("getting the test event") testEvent, err := client.Get(context.TODO(), eventName, metav1.GetOptions{}) framework.ExpectNoError(err, "failed to get test event")