Skip to content

Commit

Permalink
Merge pull request #2125 from rohanKanojia/pr/issue2124
Browse files Browse the repository at this point in the history
  • Loading branch information
fusesource-ci authored Apr 23, 2020
2 parents 1150135 + 51f0d4f commit 9eca211
Show file tree
Hide file tree
Showing 4 changed files with 278 additions and 17 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#### Bugs
* Fix #2144: CRD's schema Default fields do not handle boolean and are prefixed with Raw keyword
* KubernetesAttributeExtractor: handle possible /status subpath due to using status subresource on crd
* Fix #2124: Raw Watch on CustomResource does not work if name specified

#### Improvements
#### Dependency Upgrade
Expand All @@ -28,7 +29,7 @@
* Fix #2019: Added CustomResourceCrudTest
* Fix #2054: JobExample doesn't work
* Fix #2082: Added filter node metrics via labels
* Generated *List classes for Knative implement proper KubernetesResourceList interface
* Generated List classes for Knative implement proper KubernetesResourceList interface
* Modify the dependency management of the generator of kubernetes-model to golang module

#### Dependency Upgrade
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@

import com.fasterxml.jackson.databind.ObjectMapper;
import io.fabric8.kubernetes.api.model.DeleteOptions;
import io.fabric8.kubernetes.api.model.Status;
import io.fabric8.kubernetes.client.Config;
import io.fabric8.kubernetes.client.KubernetesClientException;
import io.fabric8.kubernetes.client.Watch;
Expand All @@ -37,6 +36,7 @@

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
Expand Down Expand Up @@ -593,21 +593,16 @@ public void watch(Watcher<String> watcher) throws IOException {
* @throws IOException in case of network error
*/
public Watch watch(String namespace, String name, Map<String, String> labels, String resourceVersion, Watcher<String> watcher) throws IOException {
URL url = new URL(fetchUrl(name, namespace, labels));
HttpUrl.Builder httpUrlBuilder = HttpUrl.get(url).newBuilder();
if (resourceVersion != null) {
httpUrlBuilder.addQueryParameter("resourceVersion", resourceVersion);
}
HttpUrl watchUrl = fetchWatchUrl(namespace, name, labels, resourceVersion);

httpUrlBuilder.addQueryParameter("watch", "true");
String origin = url.getProtocol() + "://" + url.getHost();
if (url.getPort() != -1) {
origin += ":" + url.getPort();
String origin = watchUrl.url().getProtocol() + "://" + watchUrl.url().getHost();
if (watchUrl.url().getPort() != -1) {
origin += ":" + watchUrl.url().getPort();
}

Request request = new Request.Builder()
.get()
.url(httpUrlBuilder.build())
.url(watchUrl)
.addHeader("Origin", origin)
.build();

Expand Down Expand Up @@ -696,13 +691,24 @@ private Map<String, Object> convertJsonOrYamlStringToMap(String objectAsString)
return retVal;
}

private String fetchUrl(String name, String namespace, Map<String, String> labels) {
String url = fetchUrl(namespace, labels);
protected HttpUrl fetchWatchUrl(String namespace, String name, Map<String, String> labels, String resourceVersion) throws MalformedURLException {
String resourceUrl = fetchUrl(namespace, labels);
if (resourceUrl.endsWith("/")) {
resourceUrl = resourceUrl.substring(0, resourceUrl.length() - 1);
}
URL url = new URL(resourceUrl);
HttpUrl.Builder httpUrlBuilder = HttpUrl.get(url).newBuilder();

if (name != null) {
return url + name;
} else {
return url.substring(0, url.length() - 1);
httpUrlBuilder.addQueryParameter("fieldSelector", "metadata.name=" + name);
}

if (resourceVersion != null) {
httpUrlBuilder.addQueryParameter("resourceVersion", resourceVersion);
}

httpUrlBuilder.addQueryParameter("watch", "true");
return httpUrlBuilder.build();
}

private String fetchUrl(String namespace, Map<String, String> labels) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
/**
* Copyright (C) 2015 Red Hat, Inc.
*
* 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 io.fabric8.kubernetes.client.dsl.internal;

import io.fabric8.kubernetes.client.Config;
import io.fabric8.kubernetes.client.ConfigBuilder;
import io.fabric8.kubernetes.client.dsl.base.CustomResourceDefinitionContext;
import io.fabric8.kubernetes.client.utils.Utils;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

import java.net.MalformedURLException;
import java.util.HashMap;
import java.util.Map;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class RawCustomResourceOperationsImplTest {
private OkHttpClient mockClient;
private Config config;
private CustomResourceDefinitionContext customResourceDefinitionContext;

@BeforeEach
public void setUp() {
this.mockClient = Mockito.mock(OkHttpClient.class, Mockito.RETURNS_DEEP_STUBS);
this.config = new ConfigBuilder().withMasterUrl("https://localhost:8443/").build();
this.customResourceDefinitionContext = new CustomResourceDefinitionContext.Builder()
.withGroup("test.fabric8.io")
.withName("hellos.test.fabric8.io")
.withPlural("hellos")
.withScope("Namespaced")
.withVersion("v1alpha1")
.build();
}

@Test
public void testFetchWatchUrlWithNamespace() throws MalformedURLException {
// Given
RawCustomResourceOperationsImpl rawCustomResourceOperations = new RawCustomResourceOperationsImpl(mockClient, config, customResourceDefinitionContext);

// When
HttpUrl url = rawCustomResourceOperations.fetchWatchUrl("test", null, null, null);

// Then
assertEquals("https://localhost:8443/apis/test.fabric8.io/v1alpha1/namespaces/test/hellos?watch=true", url.url().toString());
}

@Test
public void testFetchWatchUrlWithNamespaceAndName() throws MalformedURLException {
// Given
RawCustomResourceOperationsImpl rawCustomResourceOperations = new RawCustomResourceOperationsImpl(mockClient, config, customResourceDefinitionContext);

// When
HttpUrl url = rawCustomResourceOperations.fetchWatchUrl("test", "example-resource", null, null);

// Then
assertEquals("https://localhost:8443/apis/test.fabric8.io/v1alpha1/namespaces/test/hellos?fieldSelector=metadata.name%3Dexample-resource&watch=true", url.url().toString());
}

@Test
public void testFetchWatchUrlWithNamespaceAndNameAndResourceVersion() throws MalformedURLException {
// Given
RawCustomResourceOperationsImpl rawCustomResourceOperations = new RawCustomResourceOperationsImpl(mockClient, config, customResourceDefinitionContext);

// When
HttpUrl url = rawCustomResourceOperations.fetchWatchUrl("test", "example-resource", null, "100069");

// Then
assertEquals("https://localhost:8443/apis/test.fabric8.io/v1alpha1/namespaces/test/hellos?fieldSelector=metadata.name%3Dexample-resource&resourceVersion=100069&watch=true", url.url().toString());
}

@Test
public void testFetchWatchUrlWithoutAnything() throws MalformedURLException {
// Given
RawCustomResourceOperationsImpl rawCustomResourceOperations = new RawCustomResourceOperationsImpl(mockClient, config, customResourceDefinitionContext);

// When
HttpUrl url = rawCustomResourceOperations.fetchWatchUrl(null, null, null, null);

// Then
assertEquals("https://localhost:8443/apis/test.fabric8.io/v1alpha1/hellos?watch=true", url.url().toString());
}

@Test
public void testFetchWatchUrlWithLabels() throws MalformedURLException {
// Given
RawCustomResourceOperationsImpl rawCustomResourceOperations = new RawCustomResourceOperationsImpl(mockClient, config, customResourceDefinitionContext);

// When
Map<String, String> labels = new HashMap<>();
labels.put("foo", "bar");
labels.put("foo1", "bar1");

HttpUrl url = rawCustomResourceOperations.fetchWatchUrl(null, null, labels, null);

// Then
assertEquals("https://localhost:8443/apis/test.fabric8.io/v1alpha1/hellos?labelSelector=" + Utils.toUrlEncoded("foo=bar") + "," + Utils.toUrlEncoded("foo1=bar1") + "&watch=true", url.url().toString());
}

@Test
public void testFetchWatchUrlWithLabelsWithNamespace() throws MalformedURLException {
// Given
RawCustomResourceOperationsImpl rawCustomResourceOperations = new RawCustomResourceOperationsImpl(mockClient, config, customResourceDefinitionContext);

// When
Map<String, String> labels = new HashMap<>();
labels.put("foo", "bar");
labels.put("foo1", "bar1");

HttpUrl url = rawCustomResourceOperations.fetchWatchUrl("test", null, labels, null);

// Then
assertEquals("https://localhost:8443/apis/test.fabric8.io/v1alpha1/namespaces/test/hellos?labelSelector=" + Utils.toUrlEncoded("foo=bar") + "," + Utils.toUrlEncoded("foo1=bar1") + "&watch=true", url.url().toString());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,22 @@

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;

import io.fabric8.kubernetes.api.model.DeleteOptions;
import io.fabric8.kubernetes.api.model.KubernetesResource;
import io.fabric8.kubernetes.api.model.apiextensions.CustomResourceConversionBuilder;
import io.fabric8.kubernetes.client.Watch;
import io.fabric8.kubernetes.client.Watcher;
import io.fabric8.kubernetes.api.model.WatchEvent;
import okhttp3.mockwebserver.RecordedRequest;
import org.junit.Rule;
import org.junit.jupiter.api.Assertions;
Expand Down Expand Up @@ -246,4 +254,119 @@ public void testStatusUpdate() throws IOException {
Map<String, Object> result = client.customResource(customResourceDefinitionContext).updateStatus("ns1", "example-hello", objectAsJsonString);
assertEquals("Success", result.get("status"));
}

@Test
public void testWatchAllResource() throws IOException, InterruptedException {
// Given
server.expect().withPath("/apis/test.fabric8.io/v1alpha1/namespaces/ns1/hellos?watch=true")
.andUpgradeToWebSocket()
.open()
.waitFor(1000)
.andEmit(new WatchEvent(null, "ADDED"))
.done().always();

KubernetesClient client = server.getClient();

AtomicBoolean anyEventReceived = new AtomicBoolean(false);
// When
Watch watch = client.customResource(customResourceDefinitionContext)
.watch("ns1", null, null, null,
new Watcher<String>() {
@Override
public void eventReceived(Action action, String resource) { anyEventReceived.set(true); }
@Override
public void onClose(KubernetesClientException cause) { }
});

Thread.sleep(5 * 1000L);

// Then
assertTrue(anyEventReceived.get());
}

@Test
public void testWatchSingleResource() throws IOException, InterruptedException {
// Given
server.expect().withPath("/apis/test.fabric8.io/v1alpha1/namespaces/ns1/hellos"+ "?fieldSelector=" + Utils.toUrlEncoded("metadata.name=example-hello")+"&watch=true")
.andUpgradeToWebSocket()
.open()
.waitFor(1000)
.andEmit( new WatchEvent(null, "ADDED"))
.done().always();

KubernetesClient client = server.getClient();

AtomicBoolean anyEventReceieved = new AtomicBoolean(false);
// When
Watch watch = client.customResource(customResourceDefinitionContext)
.watch("ns1", "example-hello", null, null,
new Watcher<String>() {
@Override
public void eventReceived(Action action, String resource) { anyEventReceieved.set(true); }
@Override
public void onClose(KubernetesClientException cause) { }
});

Thread.sleep(5 * 1000L);
// Then
assertTrue(anyEventReceieved.get());
}

@Test
public void testWatchWithLabels() throws IOException, InterruptedException {
// Given
server.expect().withPath("/apis/test.fabric8.io/v1alpha1/namespaces/ns1/hellos?labelSelector="+ Utils.toUrlEncoded("foo=bar")+ "&watch=true")
.andUpgradeToWebSocket()
.open()
.waitFor(1000)
.andEmit(new WatchEvent(null, "ADDED"))
.done().always();

KubernetesClient client = server.getClient();

AtomicBoolean anyEventReceived = new AtomicBoolean(false);
// When
Watch watch = client.customResource(customResourceDefinitionContext)
.watch("ns1", null, Collections.singletonMap("foo", "bar"), null,
new Watcher<String>() {
@Override
public void eventReceived(Action action, String resource) { anyEventReceived.set(true); }
@Override
public void onClose(KubernetesClientException cause) { }
});

Thread.sleep(5 * 1000L);
// Then
assertTrue(anyEventReceived.get());
}

@Test
public void testWatchSomeResourceVersion() throws IOException, InterruptedException {
// Given
String watchResourceVersion = "1001";
server.expect().withPath("/apis/test.fabric8.io/v1alpha1/namespaces/ns1/hellos?resourceVersion=" + watchResourceVersion + "&watch=true")
.andUpgradeToWebSocket()
.open()
.waitFor(1000)
.andEmit(new WatchEvent(null, "ADDED"))
.done().always();

KubernetesClient client = server.getClient();

AtomicBoolean anyEventReceived = new AtomicBoolean(false);

// When
Watch watch = client.customResource(customResourceDefinitionContext)
.watch("ns1", null, null, watchResourceVersion,
new Watcher<String>() {
@Override
public void eventReceived(Action action, String resource) { anyEventReceived.set(true); }
@Override
public void onClose(KubernetesClientException cause) { }
});

Thread.sleep(5 * 1000L);
// Then
assertTrue(anyEventReceived.get());
}
}

0 comments on commit 9eca211

Please sign in to comment.