From ac65b924ddd268dff6b5a67cdc5188314b78d7db Mon Sep 17 00:00:00 2001 From: Rohan Kumar Date: Thu, 17 Sep 2020 20:16:14 +0530 Subject: [PATCH] Fix #2460: Querying for an event based on InvolvedObject fields Added an `withInvolvedObject(ObjectReference objectReference)` method in Filterable interface which would transform object references into fieldsSelector values --- CHANGELOG.md | 1 + .../kubernetes/client/dsl/Filterable.java | 10 ++++- .../client/dsl/base/BaseOperation.java | 37 +++++++++++++++++++ .../client/utils/PodOperationUtilTest.java | 4 ++ .../kubernetes/client/mock/EventTest.java | 34 +++++++++++++++++ 5 files changed, 84 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 198c7224a45..75b3da2a205 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ * Fix #2111: Support automatic refreshing for expired OIDC tokens * Fix #2314: Fetch logs should wait for the job's associated pod to be ready * Fix #2043: Support for Tekton Triggers +* Fix #2460: Querying for an event based on InvolvedObject fields ### 4.11.1 (2020-09-02) diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/Filterable.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/Filterable.java index 0f36a80f670..7f260dc3459 100644 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/Filterable.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/Filterable.java @@ -16,8 +16,7 @@ package io.fabric8.kubernetes.client.dsl; import io.fabric8.kubernetes.api.model.LabelSelector; -import io.fabric8.kubernetes.client.Watch; -import io.fabric8.kubernetes.client.Watcher; +import io.fabric8.kubernetes.api.model.ObjectReference; import java.util.Map; @@ -48,5 +47,12 @@ public interface Filterable { T withoutField(String key, String value); T withLabelSelector(LabelSelector selector); + + /** + * Filter with the object that this event is about. + * @param objectReference {@link ObjectReference} for providing information of referred object + * @return filtered resource + */ + T withInvolvedObject(ObjectReference objectReference); } diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/base/BaseOperation.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/base/BaseOperation.java index 301a9fdcdbd..6cd2b7c9e91 100755 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/base/BaseOperation.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/base/BaseOperation.java @@ -15,6 +15,7 @@ */ package io.fabric8.kubernetes.client.dsl.base; +import io.fabric8.kubernetes.api.model.ObjectReference; import io.fabric8.kubernetes.client.utils.KubernetesResourceUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -87,6 +88,13 @@ public class BaseOperation { private static final Logger LOG = LoggerFactory.getLogger(BaseOperation.class); + private static final String INVOLVED_OBJECT_NAME = "involvedObject.name"; + private static final String INVOLVED_OBJECT_NAMESPACE = "involvedObject.namespace"; + private static final String INVOLVED_OBJECT_KIND = "involvedObject.kind"; + private static final String INVOLVED_OBJECT_UID = "involvedObject.uid"; + private static final String INVOLVED_OBJECT_RESOURCE_VERSION = "involvedObject.resourceVersion"; + private static final String INVOLVED_OBJECT_API_VERSION = "involvedObject.apiVersion"; + private static final String INVOLVED_OBJECT_FIELD_PATH = "involvedObject.fieldPath"; private final Boolean cascading; private final T item; @@ -514,6 +522,35 @@ public FilterWatchListDeletable> withField(Stri return this; } + @Override + public FilterWatchListDeletable> withInvolvedObject(ObjectReference objectReference) { + if (objectReference != null) { + if (objectReference.getName() != null) { + fields.put(INVOLVED_OBJECT_NAME, objectReference.getName()); + } + if (objectReference.getNamespace() != null) { + fields.put(INVOLVED_OBJECT_NAMESPACE, objectReference.getNamespace()); + } + if (objectReference.getKind() != null) { + fields.put(INVOLVED_OBJECT_KIND, objectReference.getKind()); + } + if (objectReference.getUid() != null) { + fields.put(INVOLVED_OBJECT_UID, objectReference.getUid()); + } + if (objectReference.getResourceVersion() != null) { + fields.put(INVOLVED_OBJECT_RESOURCE_VERSION, objectReference.getResourceVersion()); + } + if (objectReference.getApiVersion() != null) { + fields.put(INVOLVED_OBJECT_API_VERSION, objectReference.getApiVersion()); + } + if (objectReference.getFieldPath() != null) { + fields.put(INVOLVED_OBJECT_FIELD_PATH, objectReference.getFieldPath()); + } + } + return this; + } + + /** * @deprecated as the underlying implementation does not align with the arguments fully. * Method is created to have a similar API as `withoutLabels`, but should eventually be replaced diff --git a/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/utils/PodOperationUtilTest.java b/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/utils/PodOperationUtilTest.java index baf6235c057..457d0550962 100644 --- a/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/utils/PodOperationUtilTest.java +++ b/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/utils/PodOperationUtilTest.java @@ -18,6 +18,7 @@ import io.fabric8.kubernetes.api.model.DoneablePod; import io.fabric8.kubernetes.api.model.LabelSelector; import io.fabric8.kubernetes.api.model.ListOptions; +import io.fabric8.kubernetes.api.model.ObjectReference; import io.fabric8.kubernetes.api.model.Pod; import io.fabric8.kubernetes.api.model.PodBuilder; import io.fabric8.kubernetes.api.model.PodList; @@ -180,6 +181,9 @@ private FilterWatchListDeletable> get @Override public FilterWatchListDeletable> withLabelSelector(LabelSelector selector) { return null; } + @Override + public FilterWatchListDeletable> withInvolvedObject(ObjectReference objectReference) { return null; } + @Override public PodList list() { return getMockPodList(controllerUid); } diff --git a/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/EventTest.java b/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/EventTest.java index bea2e9564d7..988f6e1e541 100644 --- a/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/EventTest.java +++ b/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/EventTest.java @@ -17,20 +17,27 @@ import io.fabric8.kubernetes.api.model.Event; import io.fabric8.kubernetes.api.model.EventBuilder; +import io.fabric8.kubernetes.api.model.EventList; +import io.fabric8.kubernetes.api.model.EventListBuilder; +import io.fabric8.kubernetes.api.model.ObjectReferenceBuilder; import io.fabric8.kubernetes.api.model.WatchEvent; import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.client.KubernetesClientException; import io.fabric8.kubernetes.client.Watch; import io.fabric8.kubernetes.client.Watcher; import io.fabric8.kubernetes.client.server.mock.KubernetesServer; +import io.fabric8.kubernetes.client.utils.Utils; import org.junit.Rule; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.migrationsupport.rules.EnableRuleMigrationSupport; +import java.net.HttpURLConnection; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; @EnableRuleMigrationSupport @@ -74,4 +81,31 @@ public void onClose(KubernetesClientException cause) { assertTrue(eventReceivedLatch.await(1, TimeUnit.SECONDS)); watch.close(); } + + @Test + void testInvolvedObjectFieldQuery() { + // Given + server.expect().get().withPath("/api/v1/namespaces/ns1/events?fieldSelector=" + + Utils.toUrlEncoded("involvedObject.name=foo," + + "involvedObject.uid=6d71451a-f8df-11ea-a8ac-0e13a02d8ebd," + + "involvedObject.namespace=ns1," + + "involvedObject.kind=Deployment")) + .andReturn(HttpURLConnection.HTTP_OK, new EventListBuilder().withItems(new EventBuilder() + .withNewMetadata().withName("foo-event").endMetadata() + .build()) + .build()).once(); + KubernetesClient client = server.getClient(); + + // When + EventList eventList = client.v1().events().inNamespace("ns1").withInvolvedObject(new ObjectReferenceBuilder() + .withName("foo") + .withNamespace("ns1") + .withKind("Deployment") + .withUid("6d71451a-f8df-11ea-a8ac-0e13a02d8ebd") + .build()).list(); + + // Then + assertNotNull(eventList); + assertEquals(1, eventList.getItems().size()); + } }