Skip to content

Commit

Permalink
fix #3569: removing all api references to customResource
Browse files Browse the repository at this point in the history
further minimizing SharedInformerFactoryImpl concerns and removing the
use of the executor
  • Loading branch information
shawkins committed May 15, 2022
1 parent 51cc99a commit 40cc132
Show file tree
Hide file tree
Showing 24 changed files with 407 additions and 737 deletions.
2 changes: 1 addition & 1 deletion doc/CHEATSHEET.md
Original file line number Diff line number Diff line change
Expand Up @@ -2032,7 +2032,7 @@ podInformer.addEventHandler(new ResourceEventHandler<Pod>() {
```
- Create `SharedIndexInformer` for some Custom Resource(in our case, `Dummy` resource provided in our [examples](https://github.com/fabric8io/kubernetes-client/tree/master/kubernetes-examples/src/main/java/io/fabric8/kubernetes/examples/crds). By default it watches in all namespaces.
```java
SharedIndexInformer<Dummy> dummyInformer = sharedInformerFactory.sharedIndexInformerForCustomResource(Dummy.class, 60 * 1000L);
SharedIndexInformer<Dummy> dummyInformer = sharedInformerFactory.sharedIndexInformerFor(Dummy.class, 60 * 1000L);
dummyInformer.addEventHandler(new ResourceEventHandler<Dummy>() {
@Override
public void onAdd(Dummy dummy) {
Expand Down
17 changes: 16 additions & 1 deletion doc/FAQ.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,19 @@ Further more you will also have choices in the HttpClient that is utilized.

By default kubenetes-client has a runtime dependency on OkHttp (kubernetes-httpclient-okhttp). If you need to directly manipulate OkHttp, you add a compile dependency to kubernetes-httpclient-okhttp.

If you wish to use another HttpClient implementation typically you will exclude kubernetes-httpclient-okhttp and include the other runtime dependency instead.
If you wish to use another HttpClient implementation typically you will exclude kubernetes-httpclient-okhttp and include the other runtime dependency instead.

### What threading concerns are there?

There has been a lot of changes under the covers with thread utilization in the fabric8 client over the 5.x and 6.x releases. So the exact details of what threads are created / used where will depend on the particular release version.

At the core the thread utilization will depend upon the http client implementation. Per client OkHttp maintains a pool of threads for task execution. It will dedicate 2 threads out of that pool per WebSocket connection. If you have a lot of WebSocket usage (Informer or Watches) with OkHttp, you can expect to see a large number of threads in use - which can potentially exhaust the OkHttp defaults.

With the JDK http client it will only maintain a selector thread and a small worker pool which will be based upon your available processors per client. It does not matter how many Informers or Watches you run, the same worker pool is shared.

If it recommended with either client that your Watchers and ResourceEventHandlers do not execute long running tasks. When using the OkHttp client this inhibits Watch event processing that can timeout the ping for that particular watch. When using the JDK http client the long running task will inhibit the use of that thread for ALL http processing. Note that calling other KubernetesClient operations, especially those with waits, can be long-running. We are working towards providing non-blocking for may of these operations, but until that is available consider using a separate task queue for such work.

On top of the http client threads the fabric8 client maintains a task thread pool for scheduled tasks and for potentially long-running tasks that are called from WebSocket operations, such as handling input and output streams from Exec calls. Currently this thread pool cannot be configured, but in the future it may be configurable per client instance.

Finally the fabric8 client will use 2 threads per PortForward - this may be improved upon in the future.

Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@
import io.fabric8.kubernetes.client.dsl.ServiceResource;
import io.fabric8.kubernetes.client.dsl.StorageAPIGroupDSL;
import io.fabric8.kubernetes.client.dsl.V1APIGroupDSL;
import io.fabric8.kubernetes.client.dsl.base.CustomResourceDefinitionContext;
import io.fabric8.kubernetes.client.dsl.base.ResourceDefinitionContext;
import io.fabric8.kubernetes.client.extended.leaderelection.LeaderElectorBuilder;
import io.fabric8.kubernetes.client.extended.run.RunOperations;
Expand Down Expand Up @@ -124,25 +123,6 @@ public interface KubernetesClient extends Client {
*/
CertificatesAPIGroupDSL certificates();

/**
* Typed API for managing CustomResources. You would need to provide POJOs for
* CustomResource into this and with it you would be able to instantiate a client
* specific to CustomResource.
*
* <p>
* Note: your CustomResource POJO (T in this context) must implement
* {@link io.fabric8.kubernetes.api.model.Namespaced} if it is a namespace-scoped resource.
* </p>
*
* @param resourceType Class for CustomResource
* @param <T> T type represents CustomResource type. If it's a namespaced resource, it must implement
* {@link io.fabric8.kubernetes.api.model.Namespaced}
* @return returns a MixedOperation object with which you can do basic CustomResource operations
* @deprecated use {@link #resources(Class)} instead
*/
@Deprecated
<T extends CustomResource> MixedOperation<T, KubernetesResourceList<T>, Resource<T>> customResources(Class<T> resourceType);

/**
* Typed API for managing resources. Any properly annotated POJO can be utilized as a resource.
*
Expand All @@ -161,65 +141,15 @@ default <T extends HasMetadata> MixedOperation<T, KubernetesResourceList<T>, Res
return resources(resourceType, null);
}

/**
* Typed API for managing CustomResources. You would need to provide POJOs for
* CustomResource into this and with it you would be able to instantiate a client
* specific to CustomResource.
*
* <p>
* Note: your CustomResource POJO (T in this context) must implement
* {@link io.fabric8.kubernetes.api.model.Namespaced} if it is a namespace-scoped resource.
* </p>
*
* @param resourceType Class for CustomResource
* @param listClass Class for list object for CustomResource
* @param <T> T type represents CustomResource type. If it's a namespace-scoped resource, it must implement
* {@link io.fabric8.kubernetes.api.model.Namespaced}
* @param <L> L type represents CustomResourceList type
* @return returns a MixedOperation object with which you can do basic CustomResource operations
* @deprecated use {@link #resources(Class, Class)} instead
*/
@Deprecated
<T extends CustomResource, L extends KubernetesResourceList<T>> MixedOperation<T, L, Resource<T>> customResources(
Class<T> resourceType, Class<L> listClass);

/**
* Typed API for managing CustomResources. You would need to provide POJOs for
* CustomResource into this and with it you would be able to instantiate a client
* specific to CustomResource.
*
* <p>
* Note: your CustomResource POJO (T in this context) must implement
* <a href=
* "https://github.com/fabric8io/kubernetes-client/blob/master/kubernetes-model-generator/kubernetes-model-core/src/main/java/io/fabric8/kubernetes/api/model/Namespaced.java">
* io.fabric8.kubernetes.api.model.Namespaced
* </a> if it is a Namespaced scoped resource.
* </p>
*
* @deprecated Since 5.x versions of client {@link CustomResourceDefinitionContext} is now configured via annotations
* inside POJOs, no need to provide it explicitly here.
* @param context ResourceDefinitionContext describes the core fields used to search for CustomResources
* @param resourceType Class for CustomResource
* @param listClass Class for list object for CustomResource
* @param <T> T type represents CustomResource type. If it's Namespaced resource, it must implement
* io.fabric8.kubernetes.api.model.Namespaced
* @param <L> L type represents CustomResourceList type
* @return returns a MixedOperation object with which you can do basic CustomResource operations
*/
@Deprecated
<T extends HasMetadata, L extends KubernetesResourceList<T>> MixedOperation<T, L, Resource<T>> customResources(
ResourceDefinitionContext context, Class<T> resourceType, Class<L> listClass);

/**
* Semi-Typed API for managing {@link GenericKubernetesResource}s which can represent any resource.
*
* @param context ResourceDefinitionContext describes the core fields
* @param context ResourceDefinitionContext describes the core metadata
* @return returns a MixedOperation object with which you can do basic operations
* @see #genericKubernetesResources(String, String) if you don't want to supply a complete {@link ResourceDefinitionContext}
*/
default MixedOperation<GenericKubernetesResource, GenericKubernetesResourceList, Resource<GenericKubernetesResource>> genericKubernetesResources(
ResourceDefinitionContext context) {
return customResources(context, GenericKubernetesResource.class, GenericKubernetesResourceList.class);
}
MixedOperation<GenericKubernetesResource, GenericKubernetesResourceList, Resource<GenericKubernetesResource>> genericKubernetesResources(
ResourceDefinitionContext context);

/**
* Semi-typed API for managing resources.
Expand Down Expand Up @@ -539,6 +469,8 @@ NamespaceListVisitFromServerGetDeleteRecreateWaitApplicable<HasMetadata> resourc
* Get an instance of Kubernetes Client informer factory. It allows you to construct and
* cache informers for API types. With it you can subscribe to all the events related to
* your Kubernetes type. It's like watch but a bit organized.
* <p>
* Each call to this method returns a new factory.
*
* @return SharedInformerFactory object
*/
Expand All @@ -548,10 +480,14 @@ NamespaceListVisitFromServerGetDeleteRecreateWaitApplicable<HasMetadata> resourc
* Get an instance of Kubernetes Client informer factory. It allows you to construct and
* cache informers for API types. With it you can subscribe to all the events related to
* your Kubernetes type. It's like watch but a bit organized.
* <p>
* Each call to this method returns a new factory.
*
* @param executorService thread pool for informer factory
* @return SharedInformerFactory object
* @deprecated the {@link ExecutorService} is no longer used, use {@link #informers()} instead
*/
@Deprecated
SharedInformerFactory informers(ExecutorService executorService);

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,148 +16,80 @@

package io.fabric8.kubernetes.client.informers;

import io.fabric8.kubernetes.api.model.GenericKubernetesResource;
import io.fabric8.kubernetes.api.model.HasMetadata;
import io.fabric8.kubernetes.api.model.KubernetesResourceList;
import io.fabric8.kubernetes.client.CustomResource;
import io.fabric8.kubernetes.client.dsl.Informable;
import io.fabric8.kubernetes.client.dsl.base.CustomResourceDefinitionContext;
import io.fabric8.kubernetes.client.dsl.base.ResourceDefinitionContext;

import java.util.concurrent.Future;

public interface SharedInformerFactory {

/**
* Configure Namespace for {@link SharedInformerFactory}
*
* @param namespace namespace to configure
* @return {@link SharedInformerFactory} with namespace configured
* @deprecated use {@link Informable} instead
*/
@Deprecated
SharedInformerFactory inNamespace(String namespace);

/**
* Configure Name for {@link SharedInformerFactory}
*
* @param name name to be configured
* @return {@link SharedInformerFactory} with name configured
* @deprecated use {@link Informable} instead
*/
@Deprecated
SharedInformerFactory withName(String name);

/**
* Constructs and returns a shared index informer with resync period specified. And the
* informer cache will be overwritten.
*
* <b>Note:</b>It watches for events in <b>ALL NAMESPACES</b>.
*
* @param apiTypeClass apiType class
* @param resyncPeriodInMillis resync period in milliseconds
* @param <T> the type parameter (should extend {@link io.fabric8.kubernetes.api.model.HasMetadata} and implement {@link io.fabric8.kubernetes.api.model.Namespaced}) if Namespace scoped resource
* @return the shared index informer
*/
<T extends HasMetadata> SharedIndexInformer<T> sharedIndexInformerFor(Class<T> apiTypeClass,
long resyncPeriodInMillis);

/**
* Constructs and returns a shared index informer with resync period specified for custom resources.
*
* <b>Note:</b>It watches for events in <b>ALL NAMESPACES</b>.
*
* @param customResourceContext basic information about the Custom Resource Definition corresponding to that custom resource
* @param apiTypeClass apiType class
* @param apiListTypeClass api list type class
* @param resyncPeriodInMillis resync period in milliseconds
* @param <T> the type parameter (should extend {@link io.fabric8.kubernetes.api.model.HasMetadata} and implement {@link io.fabric8.kubernetes.api.model.Namespaced})
* @param <L> the type's list parameter (should extend {@link io.fabric8.kubernetes.api.model.KubernetesResourceList}
* @return the shared index informer
* @deprecated Since 5.x versions of client {@link CustomResourceDefinitionContext} are configured via annotations in CustomResource implementations, please use any of the alternative sharedIndexInformerForCustomResource methods
*/
@Deprecated
<T extends CustomResource<?, ?>, L extends KubernetesResourceList<T>> SharedIndexInformer<T> sharedIndexInformerForCustomResource(
CustomResourceDefinitionContext customResourceContext, Class<T> apiTypeClass, Class<L> apiListTypeClass,
long resyncPeriodInMillis);

/**
* Constructs and returns a shared index informer with resync period specified for a Custom Resource. You
* can use it for scenarios where you don't have a POJO for your custom type by specifying group, version and plural in
* {@link CustomResourceDefinitionContext}
*
* <b>Note:</b>It watches for events in <b>ALL NAMESPACES</b>.
*
* @param genericResourceContext object containing details about resource like apiGroup, version and plural, etc.
* @param resyncPeriodInMillis resync period in milliseconds.
* @return {@link SharedIndexInformer} for GenericKubernetesResource
* @deprecated use {@link #sharedIndexInformerFor(Class, long)}
*/
@Deprecated
SharedIndexInformer<GenericKubernetesResource> sharedIndexInformerForCustomResource(
ResourceDefinitionContext genericResourceContext, long resyncPeriodInMillis);

/**
* Constructs and returns a shared index informer with resync period specified for custom resources.
* POJO
*
* @param apiTypeClass apiType class
* @param resyncPeriodInMillis resync period in milliseconds
* @param <T> the type parameter (should extend {@link io.fabric8.kubernetes.api.model.HasMetadata} and implement {@link io.fabric8.kubernetes.api.model.Namespaced})
* @return the shared index informer
* @deprecated use {@link #sharedIndexInformerFor(Class, long)} instead
*/
@Deprecated
<T extends CustomResource<?, ?>> SharedIndexInformer<T> sharedIndexInformerForCustomResource(
Class<T> apiTypeClass, long resyncPeriodInMillis);

/**
* Constructs and returns a shared index informer with resync period specified for custom resources.
*
* <b>Note:</b>It watches for events in <b>ALL NAMESPACES</b>.
*
* @param apiTypeClass apiType class
* @param apiListTypeClass api list type class
* @param resyncPeriodInMillis resync period in milliseconds
* @param <T> the type parameter (should extend {@link io.fabric8.kubernetes.api.model.HasMetadata} and implement {@link io.fabric8.kubernetes.api.model.Namespaced})
* @param <L> the type's list parameter (should extend {@link io.fabric8.kubernetes.api.model.KubernetesResourceList}
* @return the shared index informer
* @deprecated use {@link #sharedIndexInformerFor(Class, long)}
*/
@Deprecated
<T extends CustomResource<?, ?>, L extends KubernetesResourceList<T>> SharedIndexInformer<T> sharedIndexInformerForCustomResource(
Class<T> apiTypeClass, Class<L> apiListTypeClass, long resyncPeriodInMillis);

/**
* Gets existing shared index informer, return null if the requesting informer
* is never constructed. If there are multiple SharedIndexInformer objects corresponding
* to a Kubernetes resource, then it returns the first one
*
* @param apiTypeClass API type class
* @param <T> type of API type
* @return SharedIndexInformer object
*/
<T> SharedIndexInformer<T> getExistingSharedIndexInformer(Class<T> apiTypeClass);

/**
* Starts all registered informers in an asynchronous fashion.
*
* @return {@link Future} for status of all started informer tasks.
*/
Future<Void> startAllRegisteredInformers();

/**
* Stop all registered informers and shut down thread pool.
*/
void stopAllRegisteredInformers();

/**
* Stop all registered informers
*
* @param shutDownThreadPool Whether to shut down thread pool or not.
*/
void stopAllRegisteredInformers(boolean shutDownThreadPool);

void addSharedInformerEventListener(SharedInformerEventListener event);
/**
* Configure Namespace for {@link SharedInformerFactory}
*
* @param namespace namespace to configure
* @return {@link SharedInformerFactory} with namespace configured
* @deprecated use {@link Informable} instead
*/
@Deprecated
SharedInformerFactory inNamespace(String namespace);

/**
* Configure Name for {@link SharedInformerFactory}
*
* @param name name to be configured
* @return {@link SharedInformerFactory} with name configured
* @deprecated use {@link Informable} instead
*/
@Deprecated
SharedInformerFactory withName(String name);

/**
* Constructs and returns a shared index informer with resync period specified. And the
* informer cache will be overwritten.
*
* <b>Note:</b>It watches for events in <b>ALL NAMESPACES</b>.
*
* @param apiTypeClass apiType class
* @param resyncPeriodInMillis resync period in milliseconds
* @param <T> the type parameter (should extend {@link io.fabric8.kubernetes.api.model.HasMetadata} and implement
* {@link io.fabric8.kubernetes.api.model.Namespaced}) if Namespace scoped resource
* @return the shared index informer
*/
<T extends HasMetadata> SharedIndexInformer<T> sharedIndexInformerFor(Class<T> apiTypeClass,
long resyncPeriodInMillis);

/**
* Gets existing shared index informer, return null if the requesting informer
* is never constructed. If there are multiple SharedIndexInformer objects corresponding
* to a Kubernetes resource, then it returns the first one
*
* @param apiTypeClass API type class
* @param <T> type of API type
* @return SharedIndexInformer object
*/
<T> SharedIndexInformer<T> getExistingSharedIndexInformer(Class<T> apiTypeClass);

/**
* Starts all registered informers in an asynchronous fashion.
*
* @return {@link Future} for status of all started informer tasks.
*/
Future<Void> startAllRegisteredInformers();

/**
* Stop all registered informers and shut down thread pool.
*/
void stopAllRegisteredInformers();

/**
* Stop all registered informers
*
* @param shutDownThreadPool Whether to shut down thread pool or not.
* @deprecated use {@link #stopAllRegisteredInformers()} instead
*/
@Deprecated
void stopAllRegisteredInformers(boolean shutDownThreadPool);

void addSharedInformerEventListener(SharedInformerEventListener event);

}

0 comments on commit 40cc132

Please sign in to comment.