Skip to content

Commit a8271e1

Browse files
committed
switching to an informer based implementation
also fully removing the additional operation/context fields
1 parent 7ded399 commit a8271e1

File tree

14 files changed

+167
-543
lines changed

14 files changed

+167
-543
lines changed

kubernetes-client/src/main/java/io/fabric8/kubernetes/client/KubernetesClientTimeoutException.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ public class KubernetesClientTimeoutException extends KubernetesClientException
3030
private static final String KNOWS_RESOURCES_FORMAT = "Timed out waiting for [%d] milliseconds for multiple resources. %s";
3131

3232
private final List<HasMetadata> resourcesNotReady;
33+
34+
public KubernetesClientTimeoutException(String kind, String name, String namespace, long amount, TimeUnit timeUnit) {
35+
super(String.format(RESOURCE_FORMAT, timeUnit.toMillis(amount), kind, name, namespace));
36+
this.resourcesNotReady = Collections.emptyList();
37+
}
3338

3439
public KubernetesClientTimeoutException(HasMetadata resource, long amount, TimeUnit timeUnit) {
3540
super(String.format(RESOURCE_FORMAT, timeUnit.toMillis(amount), resource.getKind(), resource.getMetadata().getName(), resource.getMetadata().getNamespace()));

kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/Waitable.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
2020

2121
public interface Waitable<T, P> {
2222

23+
@Deprecated
2324
long DEFAULT_INITIAL_BACKOFF_MILLIS = 5L;
25+
@Deprecated
2426
double DEFAULT_BACKOFF_MULTIPLIER = 2d;
2527

2628
T waitUntilReady(long amount, TimeUnit timeUnit) throws InterruptedException;

kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/base/BaseOperation.java

Lines changed: 58 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
package io.fabric8.kubernetes.client.dsl.base;
1717

1818
import io.fabric8.kubernetes.api.model.ObjectReference;
19-
import io.fabric8.kubernetes.client.WatcherException;
2019
import io.fabric8.kubernetes.client.dsl.WritableOperation;
2120
import io.fabric8.kubernetes.client.utils.CreateOrReplaceHelper;
2221
import org.slf4j.Logger;
@@ -38,6 +37,7 @@
3837
import io.fabric8.kubernetes.client.Config;
3938
import io.fabric8.kubernetes.client.ConfigBuilder;
4039
import io.fabric8.kubernetes.client.KubernetesClientException;
40+
import io.fabric8.kubernetes.client.KubernetesClientTimeoutException;
4141
import io.fabric8.kubernetes.client.OperationInfo;
4242
import io.fabric8.kubernetes.client.ResourceNotFoundException;
4343
import io.fabric8.kubernetes.client.Watch;
@@ -59,7 +59,6 @@
5959
import io.fabric8.kubernetes.client.informers.impl.DefaultSharedIndexInformer;
6060
import io.fabric8.kubernetes.client.internal.readiness.Readiness;
6161
import io.fabric8.kubernetes.client.utils.HttpClientUtils;
62-
import io.fabric8.kubernetes.client.utils.KubernetesResourceUtil;
6362
import io.fabric8.kubernetes.client.utils.URLUtils;
6463
import io.fabric8.kubernetes.client.utils.Utils;
6564
import io.fabric8.kubernetes.client.utils.WatcherToggle;
@@ -73,11 +72,11 @@
7372
import java.net.MalformedURLException;
7473
import java.net.URL;
7574
import java.util.Arrays;
76-
import java.util.Collections;
7775
import java.util.Iterator;
7876
import java.util.List;
7977
import java.util.Map;
8078
import java.util.Objects;
79+
import java.util.concurrent.CompletableFuture;
8180
import java.util.concurrent.ExecutionException;
8281
import java.util.concurrent.TimeUnit;
8382
import java.util.concurrent.TimeoutException;
@@ -89,8 +88,6 @@
8988
import okhttp3.HttpUrl;
9089
import okhttp3.Request;
9190

92-
import static java.util.concurrent.TimeUnit.NANOSECONDS;
93-
9491
public class BaseOperation<T extends HasMetadata, L extends KubernetesResourceList<T>, R extends Resource<T>>
9592
extends OperationSupport
9693
implements
@@ -1123,34 +1120,49 @@ public T waitUntilReady(long amount, TimeUnit timeUnit) throws InterruptedExcept
11231120
@Override
11241121
public T waitUntilCondition(Predicate<T> condition, long amount, TimeUnit timeUnit)
11251122
throws InterruptedException {
1123+
1124+
CompletableFuture<T> future = new CompletableFuture<>();
1125+
1126+
try (SharedIndexInformer<T> informer = this.createInformer(0)) {
1127+
informer.addEventHandler(new ResourceEventHandler<T>() {
1128+
1129+
void test(T obj) {
1130+
try {
1131+
if (condition.test(obj)) {
1132+
future.complete(obj);
1133+
informer.stop(); // immediately stop the watch
1134+
}
1135+
} catch (Exception e) {
1136+
future.completeExceptionally(e);
1137+
}
1138+
}
1139+
1140+
@Override
1141+
public void onAdd(T obj) {
1142+
test(obj);
1143+
}
11261144

1127-
long remainingNanosToWait = timeUnit.toNanos(amount);
1128-
while (remainingNanosToWait > 0) {
1129-
1130-
T item = fromServer().get();
1131-
if (condition.test(item)) {
1132-
return item;
1133-
}
1145+
@Override
1146+
public void onUpdate(T oldObj, T newObj) {
1147+
test(newObj);
1148+
}
11341149

1135-
final WaitForConditionWatcher<T> watcher = new WaitForConditionWatcher<>(condition);
1136-
final long startTime = System.nanoTime();
1137-
try (Watch ignored = watch(KubernetesResourceUtil.getResourceVersion(item), watcher)) {
1138-
return watcher.getFuture().get(remainingNanosToWait, NANOSECONDS);
1139-
} catch (ExecutionException e) {
1140-
Throwable cause = e.getCause();
1141-
if (cause instanceof WatcherException && ((WatcherException)cause).isHttpGone()) {
1142-
LOG.debug("Restarting the watch due to http gone");
1143-
remainingNanosToWait -= (System.nanoTime() - startTime);
1144-
continue;
1150+
@Override
1151+
public void onDelete(T obj, boolean deletedFinalStateUnknown) {
1152+
test(null);
11451153
}
1146-
throw KubernetesClientException.launderThrowable(cause);
1147-
} catch (TimeoutException e) {
1148-
break;
1154+
});
1155+
informer.run();
1156+
return future.get(amount, timeUnit);
1157+
} catch (ExecutionException e) {
1158+
throw KubernetesClientException.launderThrowable(e.getCause());
1159+
} catch (TimeoutException e) {
1160+
T item = getItem();
1161+
if (item != null) {
1162+
throw new KubernetesClientTimeoutException(item, amount, timeUnit);
11491163
}
1164+
throw new KubernetesClientTimeoutException(getKind(), getName(), getNamespace(), amount, timeUnit);
11501165
}
1151-
1152-
LOG.debug("ran out of time waiting for watcher, wait condition not met");
1153-
throw new IllegalArgumentException(type.getSimpleName() + " with name:[" + name + "] in namespace:[" + namespace + "] matching condition not found!");
11541166
}
11551167

11561168
public void setType(Class<T> type) {
@@ -1179,30 +1191,38 @@ public Informable<T> withIndexers(Map<String, Function<T, List<String>>> indexer
11791191

11801192
@Override
11811193
public SharedIndexInformer<T> inform(ResourceEventHandler<T> handler, long resync) {
1182-
// convert the name into something listable
1183-
FilterWatchListDeletable<T, L> baseOperation =
1184-
getName() == null ? this : withFields(Collections.singletonMap("metadata.name", getName()));
1194+
DefaultSharedIndexInformer<T, L> informer = createInformer(resync);
1195+
if (handler != null) {
1196+
informer.addEventHandler(handler);
1197+
}
1198+
// synchronous start list/watch must succeed in the calling thread
1199+
informer.run();
1200+
return informer;
1201+
}
11851202

1203+
private DefaultSharedIndexInformer<T, L> createInformer(long resync) {
1204+
T item = getItem();
1205+
String name = (Utils.isNotNullOrEmpty(getName()) || item != null) ? checkName(item) : null;
1206+
11861207
// use the local context / namespace
11871208
DefaultSharedIndexInformer<T, L> informer = new DefaultSharedIndexInformer<>(getType(), new ListerWatcher<T, L>() {
11881209
@Override
11891210
public L list(ListOptions params, String namespace, OperationContext context) {
1190-
return baseOperation.list(params);
1211+
// convert the name into something listable
1212+
if (name != null) {
1213+
params.setFieldSelector("metadata.name="+name);
1214+
}
1215+
return BaseOperation.this.list(params);
11911216
}
11921217

11931218
@Override
11941219
public Watch watch(ListOptions params, String namespace, OperationContext context, Watcher<T> watcher) {
1195-
return baseOperation.watch(params, watcher);
1220+
return BaseOperation.this.watch(params, watcher);
11961221
}
11971222
}, resync, context, Runnable::run); // just run the event notification in the websocket thread
1198-
if (handler != null) {
1199-
informer.addEventHandler(handler);
1200-
}
12011223
if (indexers != null) {
12021224
informer.addIndexers(indexers);
12031225
}
1204-
// synchronous start list/watch must succeed in the calling thread
1205-
informer.run();
12061226
return informer;
12071227
}
12081228
}

kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/base/WaitForConditionWatcher.java

Lines changed: 0 additions & 68 deletions
This file was deleted.

0 commit comments

Comments
 (0)