Skip to content

Commit

Permalink
fix fabric8io#3845 fabric8io#3407: refining resourceList to use commo…
Browse files Browse the repository at this point in the history
…n logic

also various cleanups and adding some migration docs
  • Loading branch information
shawkins committed Feb 17, 2022
1 parent 0e6b058 commit 5568828
Show file tree
Hide file tree
Showing 27 changed files with 215 additions and 792 deletions.
24 changes: 24 additions & 0 deletions doc/MIGRATION-v6.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
## Contents:
- [API/Impl split](#api-impl-split)
- [Deprecation Removals](#deprecation-removals)
- [Resource Changes](#resource-changes)
- [IntOrString changes](#intorstring-changes)
- [Deprecations](#deprecations)

## API/Impl split

Expand All @@ -25,6 +27,25 @@ When you rely solely on a compile dependency to the respective -api dependencies
- Removed deprecatedHttpClientUtils.createHttpClient(final Config config, final Consumer<OkHttpClient.Builder> additionalConfig), please use the OkHttpClientFactory instead
- Removed deprecated methods on SharedInformerFactory dealing with the OperationContext

### Extension Development

Extension development may now be done using only the kubernetes-client-api dependency. Please see the [extensions](../extensions).

## Resource Changes

KubernetesClient.resource no longer returns NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicable, use NamespaceableResource instead.

This may require you to implement previously deprecated methods on your own. For example, instead of:

client.resource(deployment).inNamespace(session.getNamespace()).deletingExisting().createOrReplace();

Use:

var resource = client.resource(deployment).inNamespace(session.getNamespace());
resource.delete();
resource.waitUntilCondition(Objects::isNull, 30, TimeUnit.SECONDS);
resource.create();

## IntOrString changes

We've removed setter methods `setIntVal`, `setKind`, `setStrVal` from the class. You'd need to rely on constructors or builders for creating `IntOrString` object. Here are some examples:
Expand Down Expand Up @@ -53,3 +74,6 @@ We've removed setter methods `setIntVal`, `setKind`, `setStrVal` from the class.
IntOrString i2 = new IntOrString("3000");
String strValue = i2.getStrVal();
```
## Deprecations

- ApiVersionUtil classes in each extension have been deprecated, you should use io.fabric8.kubernetes.client.utils.ApiVersionUtil instead.
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@

import io.fabric8.kubernetes.api.builder.Visitor;
import io.fabric8.kubernetes.client.ClientContext;
import io.fabric8.kubernetes.client.dsl.base.BaseOperation;
import io.fabric8.kubernetes.client.dsl.base.HasMetadataOperation;
import io.fabric8.kubernetes.client.dsl.base.OperationContext;
import io.fabric8.kubernetes.client.dsl.internal.HasMetadataOperationsImpl;
Expand All @@ -42,7 +41,7 @@ public VolumeSnapshotClassOperationsImpl(OperationContext context) {
}

@Override
public BaseOperation<VolumeSnapshotClass, VolumeSnapshotClassList, VolumeSnapshotClassResource> newInstance(OperationContext context) {
public VolumeSnapshotClassOperationsImpl newInstance(OperationContext context) {
return new VolumeSnapshotClassOperationsImpl(context);
}

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

import io.fabric8.kubernetes.api.builder.Visitor;
import io.fabric8.kubernetes.client.ClientContext;
import io.fabric8.kubernetes.client.dsl.base.BaseOperation;
import io.fabric8.kubernetes.client.dsl.base.HasMetadataOperation;
import io.fabric8.kubernetes.client.dsl.base.OperationContext;
import io.fabric8.kubernetes.client.dsl.internal.HasMetadataOperationsImpl;
Expand All @@ -38,7 +37,7 @@ public VolumeSnapshotContentOperationsImpl(OperationContext context) {
}

@Override
public BaseOperation<VolumeSnapshotContent, VolumeSnapshotContentList, VolumeSnapshotContentResource> newInstance(OperationContext context) {
public VolumeSnapshotContentOperationsImpl newInstance(OperationContext context) {
return new VolumeSnapshotContentOperationsImpl(context);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
package io.fabric8.volumesnapshot.client.internal;

import io.fabric8.kubernetes.client.ClientContext;
import io.fabric8.kubernetes.client.dsl.base.BaseOperation;
import io.fabric8.kubernetes.client.dsl.base.HasMetadataOperation;
import io.fabric8.kubernetes.client.dsl.base.OperationContext;
import io.fabric8.kubernetes.client.dsl.internal.HasMetadataOperationsImpl;
Expand All @@ -35,7 +34,7 @@ public VolumeSnapshotOperationsImpl(OperationContext ctx) {
}

@Override
public BaseOperation<VolumeSnapshot, VolumeSnapshotList, VolumeSnapshotResource> newInstance(OperationContext context) {
public VolumeSnapshotOperationsImpl newInstance(OperationContext context) {
return new VolumeSnapshotOperationsImpl(context);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public final class Adapters {

private static final Set<ClassLoader> CLASS_LOADERS = new HashSet<>();
private static final Map<Class, ExtensionAdapter> EXTENSION_ADAPTER_MAP = new HashMap<>();
private static volatile ExtensionAdapter.HandlerFactory HANDLER_FACTORY;
private static volatile ExtensionAdapter.HandlerFactory handlerFactory;

static {
//Register adapters
Expand All @@ -47,8 +47,8 @@ private Adapters() {

public static <C> void register(ExtensionAdapter<C> adapter) {
EXTENSION_ADAPTER_MAP.put(adapter.getExtensionType(), adapter);
if (HANDLER_FACTORY != null) {
adapter.registerHandlers(HANDLER_FACTORY);
if (handlerFactory != null) {
adapter.registerHandlers(handlerFactory);
}
}

Expand All @@ -61,7 +61,6 @@ public static <C> ExtensionAdapter<C> get(Class<C> type) {
if (EXTENSION_ADAPTER_MAP.containsKey(type)) {
return EXTENSION_ADAPTER_MAP.get(type);
} else {
// TODO: should handlers be registered as a side effect
try {
for (ExtensionAdapter adapter : ServiceLoader.load(ExtensionAdapter.class, ExtensionAdapter.class.getClassLoader())) {
if (adapter.getExtensionType().equals(type)) {
Expand Down Expand Up @@ -113,8 +112,8 @@ private static void discoverServices(ClassLoader classLoader) {
}
}

public static void initializeHandlers(ExtensionAdapter.HandlerFactory handlerFactory) {
HANDLER_FACTORY = handlerFactory;
public static void initializeHandlers(ExtensionAdapter.HandlerFactory factory) {
handlerFactory = factory;
EXTENSION_ADAPTER_MAP.values().forEach(ea -> ea.registerHandlers(handlerFactory));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -162,23 +162,6 @@ default <T extends HasMetadata> MixedOperation<T, KubernetesResourceList<T>, Res
return resources(resourceType, null);
}

/**
* Typed API for managing resources. Any properly annotated POJO can be utilized as a resource.
*
* <p>
* Note: your resource 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 resource
* @param <T> T type represents resource type. If it's a namespaced resource, it must implement
* {@link io.fabric8.kubernetes.api.model.Namespaced}
* @param <L> L type represents resource list type
* @return returns a MixedOperation object with which you can do basic resource operations. If the class is a known type the dsl operation logic will be used.
*/
@Override
<T extends HasMetadata, L extends KubernetesResourceList<T>> MixedOperation<T, L, Resource<T>> resources(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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,21 @@

package io.fabric8.kubernetes.client.dsl;

import java.util.List;

import io.fabric8.kubernetes.api.builder.Visitable;
import io.fabric8.kubernetes.client.FromServerGettable;

import java.util.List;

public interface ListVisitFromServerGetDeleteRecreateWaitApplicable<T> extends Visitable<ListVisitFromServerGetDeleteRecreateWaitApplicable<T>>,
FromServerGettable<List<T>>,
Waitable<List<T>, T>,
ListVisitFromServerWritable<T>,
DryRunable<ListVisitFromServerWritable<T>> {


/**
* Get each item as as a {@link Resource}
* @return the resources
*/
List<Resource<T>> getResources();
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,15 @@ public abstract class ClientAdapter<C extends Client> implements Client {

protected Client client;

public ClientAdapter() {
protected ClientAdapter() {
this(new KubernetesClientBuilder().build());
}

public ClientAdapter(Config configuration) {
protected ClientAdapter(Config configuration) {
this(new KubernetesClientBuilder().withConfig(configuration).build());
}

public ClientAdapter(Client client) {
protected ClientAdapter(Client client) {
this.client = client;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,21 @@ public static void setResourceVersion(HasMetadata entity, String resourceVersion
}
}

/**
* Set namespace of a kubernetes resource if possible
*
* @param entity entity provided
* @param namespace the new namesapce
*/
public static void setNamespace(HasMetadata entity, String namespace) {
if (entity != null) {
ObjectMeta metadata = entity.getMetadata();
if (metadata != null) {
metadata.setNamespace(namespace);
}
}
}

/**
* Returns the kind of the entity
*
Expand Down Expand Up @@ -386,7 +401,7 @@ public static Duration getAge(HasMetadata kubernetesResource) {
public static <T extends HasMetadata> Class<? extends KubernetesResourceList> inferListType(Class<T> type) {
return (Class<? extends KubernetesResourceList>) loadRelated(type, "List", CustomResourceList.class);
}

public static <T extends HasMetadata, V extends VisitableBuilder<T, V>> Class<V> inferBuilderType(Class<T> type) {
return (Class<V>) loadRelated(type, "Builder", null);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,19 @@

package io.fabric8.kubernetes.client;

import io.fabric8.kubernetes.client.dsl.MixedOperation;
import io.fabric8.kubernetes.client.dsl.Resource;
import io.fabric8.kubernetes.client.dsl.base.OperationSupport;
import io.fabric8.kubernetes.client.http.HttpClient;
import io.fabric8.kubernetes.api.model.APIGroup;
import io.fabric8.kubernetes.api.model.APIGroupList;
import io.fabric8.kubernetes.api.model.APIResourceList;
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.api.model.RootPaths;
import io.fabric8.kubernetes.client.dsl.MixedOperation;
import io.fabric8.kubernetes.client.dsl.Resource;
import io.fabric8.kubernetes.client.dsl.base.OperationSupport;
import io.fabric8.kubernetes.client.dsl.base.ResourceDefinitionContext;
import io.fabric8.kubernetes.client.dsl.internal.HasMetadataOperationsImpl;
import io.fabric8.kubernetes.client.http.HttpClient;
import io.fabric8.kubernetes.client.utils.HttpClientUtils;
import io.fabric8.kubernetes.client.utils.Utils;

Expand Down Expand Up @@ -167,8 +170,23 @@ protected SimpleClientContext newState(Config updated) {
@Override
public <T extends HasMetadata, L extends KubernetesResourceList<T>, R extends Resource<T>> MixedOperation<T, L, R> resources(
Class<T> resourceType, Class<L> listClass, Class<R> resourceClass) {
// TODO: make this more robust - list and resource class could be null
return Handlers.getOperation(resourceType, listClass, this);
if (GenericKubernetesResource.class.equals(resourceType)) {
throw new KubernetesClientException("resources cannot be called with a generic type");
}
try {
// TODO: check the Resource class type
return Handlers.getOperation(resourceType, listClass, this);
} catch (Exception e) {
//may be the wrong list type, try more general - may still fail if the resource is not properly annotated
if (resourceClass == null || Resource.class.equals(resourceClass)) {
return (MixedOperation<T, L, R>) newHasMetadataOperation(ResourceDefinitionContext.fromResourceType(resourceType), resourceType, listClass);
}
throw KubernetesClientException.launderThrowable(e);
}
}

public <T extends HasMetadata, L extends KubernetesResourceList<T>> HasMetadataOperationsImpl<T, L> newHasMetadataOperation(ResourceDefinitionContext rdContext, Class<T> resourceType, Class<L> listClass) {
return new HasMetadataOperationsImpl<>(this, rdContext, resourceType, listClass);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ public <T extends HasMetadata> NamespaceableResource<T> resource(T item) {
// lookup the operation given the item
ResourceHandler<T, ?> resourceHandler = Handlers.get(item, this);
HasMetadataOperation<T, ?, ?> op = resourceHandler.operation(this, null);
return new NamespaceableResourceAdapter<T>(item, op);
return new NamespaceableResourceAdapter<>(item, op);
}

/**
Expand Down Expand Up @@ -464,28 +464,14 @@ public MixedOperation<GenericKubernetesResource, GenericKubernetesResourceList,
return genericKubernetesResources(context);
}

@Override
public <T extends HasMetadata, L extends KubernetesResourceList<T>> HasMetadataOperation<T, L, Resource<T>> resources(
Class<T> resourceType, Class<L> listClass) {
try {
if (GenericKubernetesResource.class.equals(resourceType)) {
throw new KubernetesClientException("resources cannot be called with a generic type");
}
return Handlers.getOperation(resourceType, listClass, this);
} catch (Exception e) {
//may be the wrong list type, try more general
return customResources(ResourceDefinitionContext.fromResourceType(resourceType), resourceType, listClass);
}
}

/**
* {@inheritDoc}
*/
@Override
public <T extends HasMetadata, L extends KubernetesResourceList<T>> HasMetadataOperationsImpl<T, L> customResources(ResourceDefinitionContext rdContext, Class<T> resourceType, Class<L> listClass) {
return new HasMetadataOperationsImpl<>(this, rdContext, resourceType, listClass);
return newHasMetadataOperation(rdContext, resourceType, listClass);
}

@Override
public DiscoveryAPIGroupDSL discovery() {
return adapt(DiscoveryAPIGroupClient.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import io.fabric8.kubernetes.api.model.DeletionPropagation;
import io.fabric8.kubernetes.api.model.HasMetadata;
import io.fabric8.kubernetes.api.model.ListOptions;
import io.fabric8.kubernetes.api.model.ObjectMeta;
import io.fabric8.kubernetes.client.dsl.Deletable;
import io.fabric8.kubernetes.client.dsl.EditReplacePatchDeletable;
import io.fabric8.kubernetes.client.dsl.Gettable;
Expand Down Expand Up @@ -70,26 +69,25 @@ public class NamespaceableResourceAdapter<T extends HasMetadata> implements Name
public NamespaceableResourceAdapter(T item, HasMetadataOperation<T, ?, ?> op) {
this.operation = op;
this.item = item;
this.resource = getResource(item, op);
}

public static <T extends HasMetadata> Resource<T> getResource(T item, HasMetadataOperation<T, ?, ?> op) {
String namespace = KubernetesResourceUtil.getNamespace(item);
if (namespace != null) {
this.resource = op.inNamespace(namespace).withItem(item);
} else {
this.resource = op.withItem(item);
return op.inNamespace(namespace).withItem(item);
}
return op.withItem(item);
}

@Override
public Resource<T> inNamespace(String name) {
return operation.inNamespace(name).withItem(setItemNamespace(item, name));
}

// TODO: move to KubernetesResourceUtil
static <T extends HasMetadata> T setItemNamespace(T item, String name) {
item = Serialization.clone(item);
if (item.getMetadata() == null) {
item.setMetadata(new ObjectMeta());
}
item.getMetadata().setNamespace(name);
KubernetesResourceUtil.setNamespace(item, name);
return item;
}

Expand Down

0 comments on commit 5568828

Please sign in to comment.