From 5568828c8bb816cfc888a38b3a8efd134e863aa7 Mon Sep 17 00:00:00 2001 From: Steve Hawkins Date: Thu, 17 Feb 2022 08:57:31 -0500 Subject: [PATCH] fix #3845 #3407: refining resourceList to use common logic also various cleanups and adding some migration docs --- doc/MIGRATION-v6.md | 24 ++ .../VolumeSnapshotClassOperationsImpl.java | 3 +- .../VolumeSnapshotContentOperationsImpl.java | 3 +- .../VolumeSnapshotOperationsImpl.java | 3 +- .../fabric8/kubernetes/client/Adapters.java | 11 +- .../kubernetes/client/KubernetesClient.java | 17 -- ...ServerGetDeleteRecreateWaitApplicable.java | 11 +- .../client/dsl/VisitFromServerWritable.java | 25 -- .../client/extension/ClientAdapter.java | 6 +- .../client/utils/KubernetesResourceUtil.java | 17 +- .../fabric8/kubernetes/client/BaseClient.java | 30 +- .../client/BaseKubernetesClient.java | 20 +- .../client/NamespaceableResourceAdapter.java | 16 +- .../client/ResourcedHasMetadataOperation.java | 10 +- .../client/dsl/base/BaseOperation.java | 10 +- .../client/dsl/base/HasMetadataOperation.java | 2 +- ...nericKubernetesResourceOperationsImpl.java | 3 +- .../KubernetesListOperationsImpl.java | 11 +- ...rGetWatchDeleteRecreateWaitApplicable.java | 26 -- ...WatchDeleteRecreateWaitApplicableImpl.java | 259 ------------------ ...hDeleteRecreateWaitApplicableListImpl.java | 106 +++++-- ...rGetWatchDeleteRecreateWaitApplicable.java | 55 ---- .../informers/SharedInformerFactoryImpl.java | 68 +---- .../client/utils/DeleteAndCreateHelper.java | 86 ------ .../utils/DeleteAndCreateHelperTest.java | 177 ------------ .../client/mock/ResourceListTest.java | 6 +- .../client/server/mock/OpenShiftLoadTest.java | 2 +- 27 files changed, 215 insertions(+), 792 deletions(-) delete mode 100644 kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/dsl/VisitFromServerWritable.java delete mode 100644 kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicable.java delete mode 100644 kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableImpl.java delete mode 100644 kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/VisitFromServerGetWatchDeleteRecreateWaitApplicable.java delete mode 100644 kubernetes-client/src/main/java/io/fabric8/kubernetes/client/utils/DeleteAndCreateHelper.java delete mode 100644 kubernetes-client/src/test/java/io/fabric8/kubernetes/client/utils/DeleteAndCreateHelperTest.java diff --git a/doc/MIGRATION-v6.md b/doc/MIGRATION-v6.md index 0bd4b0d4cac..cff973db123 100644 --- a/doc/MIGRATION-v6.md +++ b/doc/MIGRATION-v6.md @@ -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 @@ -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 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: @@ -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. diff --git a/extensions/volumesnapshot/client/src/main/java/io/fabric8/volumesnapshot/client/internal/VolumeSnapshotClassOperationsImpl.java b/extensions/volumesnapshot/client/src/main/java/io/fabric8/volumesnapshot/client/internal/VolumeSnapshotClassOperationsImpl.java index 6ef8a314cca..e931866bc29 100644 --- a/extensions/volumesnapshot/client/src/main/java/io/fabric8/volumesnapshot/client/internal/VolumeSnapshotClassOperationsImpl.java +++ b/extensions/volumesnapshot/client/src/main/java/io/fabric8/volumesnapshot/client/internal/VolumeSnapshotClassOperationsImpl.java @@ -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; @@ -42,7 +41,7 @@ public VolumeSnapshotClassOperationsImpl(OperationContext context) { } @Override - public BaseOperation newInstance(OperationContext context) { + public VolumeSnapshotClassOperationsImpl newInstance(OperationContext context) { return new VolumeSnapshotClassOperationsImpl(context); } diff --git a/extensions/volumesnapshot/client/src/main/java/io/fabric8/volumesnapshot/client/internal/VolumeSnapshotContentOperationsImpl.java b/extensions/volumesnapshot/client/src/main/java/io/fabric8/volumesnapshot/client/internal/VolumeSnapshotContentOperationsImpl.java index b878647435d..6bd2856634a 100644 --- a/extensions/volumesnapshot/client/src/main/java/io/fabric8/volumesnapshot/client/internal/VolumeSnapshotContentOperationsImpl.java +++ b/extensions/volumesnapshot/client/src/main/java/io/fabric8/volumesnapshot/client/internal/VolumeSnapshotContentOperationsImpl.java @@ -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; @@ -38,7 +37,7 @@ public VolumeSnapshotContentOperationsImpl(OperationContext context) { } @Override - public BaseOperation newInstance(OperationContext context) { + public VolumeSnapshotContentOperationsImpl newInstance(OperationContext context) { return new VolumeSnapshotContentOperationsImpl(context); } diff --git a/extensions/volumesnapshot/client/src/main/java/io/fabric8/volumesnapshot/client/internal/VolumeSnapshotOperationsImpl.java b/extensions/volumesnapshot/client/src/main/java/io/fabric8/volumesnapshot/client/internal/VolumeSnapshotOperationsImpl.java index 22f1a355bd2..af361042994 100644 --- a/extensions/volumesnapshot/client/src/main/java/io/fabric8/volumesnapshot/client/internal/VolumeSnapshotOperationsImpl.java +++ b/extensions/volumesnapshot/client/src/main/java/io/fabric8/volumesnapshot/client/internal/VolumeSnapshotOperationsImpl.java @@ -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; @@ -35,7 +34,7 @@ public VolumeSnapshotOperationsImpl(OperationContext ctx) { } @Override - public BaseOperation newInstance(OperationContext context) { + public VolumeSnapshotOperationsImpl newInstance(OperationContext context) { return new VolumeSnapshotOperationsImpl(context); } diff --git a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/Adapters.java b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/Adapters.java index 65f39115245..f64e8f1eaeb 100644 --- a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/Adapters.java +++ b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/Adapters.java @@ -34,7 +34,7 @@ public final class Adapters { private static final Set CLASS_LOADERS = new HashSet<>(); private static final Map EXTENSION_ADAPTER_MAP = new HashMap<>(); - private static volatile ExtensionAdapter.HandlerFactory HANDLER_FACTORY; + private static volatile ExtensionAdapter.HandlerFactory handlerFactory; static { //Register adapters @@ -47,8 +47,8 @@ private Adapters() { public static void register(ExtensionAdapter adapter) { EXTENSION_ADAPTER_MAP.put(adapter.getExtensionType(), adapter); - if (HANDLER_FACTORY != null) { - adapter.registerHandlers(HANDLER_FACTORY); + if (handlerFactory != null) { + adapter.registerHandlers(handlerFactory); } } @@ -61,7 +61,6 @@ public static ExtensionAdapter get(Class 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)) { @@ -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)); } } diff --git a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/KubernetesClient.java b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/KubernetesClient.java index 4b8204bd2af..6d45e774069 100644 --- a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/KubernetesClient.java +++ b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/KubernetesClient.java @@ -162,23 +162,6 @@ default MixedOperation, Res return resources(resourceType, null); } - /** - * Typed API for managing resources. Any properly annotated POJO can be utilized as a resource. - * - *

- * Note: your resource POJO (T in this context) must implement - * {@link io.fabric8.kubernetes.api.model.Namespaced} if it is a namespace-scoped resource. - *

- * - * @param resourceType Class for resource - * @param T type represents resource type. If it's a namespaced resource, it must implement - * {@link io.fabric8.kubernetes.api.model.Namespaced} - * @param 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 - > MixedOperation> resources(Class resourceType, Class 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 diff --git a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/dsl/ListVisitFromServerGetDeleteRecreateWaitApplicable.java b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/dsl/ListVisitFromServerGetDeleteRecreateWaitApplicable.java index 71b5d23993e..c710c44f161 100644 --- a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/dsl/ListVisitFromServerGetDeleteRecreateWaitApplicable.java +++ b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/dsl/ListVisitFromServerGetDeleteRecreateWaitApplicable.java @@ -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 extends Visitable>, FromServerGettable>, Waitable, T>, ListVisitFromServerWritable, DryRunable> { + + + /** + * Get each item as as a {@link Resource} + * @return the resources + */ + List> getResources(); } diff --git a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/dsl/VisitFromServerWritable.java b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/dsl/VisitFromServerWritable.java deleted file mode 100644 index 7fea6d80efa..00000000000 --- a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/dsl/VisitFromServerWritable.java +++ /dev/null @@ -1,25 +0,0 @@ -/** - * 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; - -import io.fabric8.kubernetes.client.GracePeriodConfigurable; -import io.fabric8.kubernetes.client.PropagationPolicyConfigurable; - -public interface VisitFromServerWritable extends CascadingDeletable, - GracePeriodConfigurable>, - RecreateApplicable, - PropagationPolicyConfigurable> { -} diff --git a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/extension/ClientAdapter.java b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/extension/ClientAdapter.java index baa18547d86..1f19f358b7a 100644 --- a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/extension/ClientAdapter.java +++ b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/extension/ClientAdapter.java @@ -39,15 +39,15 @@ public abstract class ClientAdapter 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; } diff --git a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/utils/KubernetesResourceUtil.java b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/utils/KubernetesResourceUtil.java index 490f1ecbd3c..f5fc13f9314 100644 --- a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/utils/KubernetesResourceUtil.java +++ b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/utils/KubernetesResourceUtil.java @@ -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 * @@ -386,7 +401,7 @@ public static Duration getAge(HasMetadata kubernetesResource) { public static Class inferListType(Class type) { return (Class) loadRelated(type, "List", CustomResourceList.class); } - + public static > Class inferBuilderType(Class type) { return (Class) loadRelated(type, "Builder", null); } diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/BaseClient.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/BaseClient.java index df033ab21ea..15283a4e76d 100644 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/BaseClient.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/BaseClient.java @@ -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; @@ -167,8 +170,23 @@ protected SimpleClientContext newState(Config updated) { @Override public , R extends Resource> MixedOperation resources( Class resourceType, Class listClass, Class 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) newHasMetadataOperation(ResourceDefinitionContext.fromResourceType(resourceType), resourceType, listClass); + } + throw KubernetesClientException.launderThrowable(e); + } + } + + public > HasMetadataOperationsImpl newHasMetadataOperation(ResourceDefinitionContext rdContext, Class resourceType, Class listClass) { + return new HasMetadataOperationsImpl<>(this, rdContext, resourceType, listClass); } } diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/BaseKubernetesClient.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/BaseKubernetesClient.java index c042e970cc8..51e9a6e7796 100644 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/BaseKubernetesClient.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/BaseKubernetesClient.java @@ -256,7 +256,7 @@ public NamespaceableResource resource(T item) { // lookup the operation given the item ResourceHandler resourceHandler = Handlers.get(item, this); HasMetadataOperation op = resourceHandler.operation(this, null); - return new NamespaceableResourceAdapter(item, op); + return new NamespaceableResourceAdapter<>(item, op); } /** @@ -464,28 +464,14 @@ public MixedOperation> HasMetadataOperation> resources( - Class resourceType, Class 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 > HasMetadataOperationsImpl customResources(ResourceDefinitionContext rdContext, Class resourceType, Class listClass) { - return new HasMetadataOperationsImpl<>(this, rdContext, resourceType, listClass); + return newHasMetadataOperation(rdContext, resourceType, listClass); } - + @Override public DiscoveryAPIGroupDSL discovery() { return adapt(DiscoveryAPIGroupClient.class); diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/NamespaceableResourceAdapter.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/NamespaceableResourceAdapter.java index 73334d942c6..f43b23fd226 100644 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/NamespaceableResourceAdapter.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/NamespaceableResourceAdapter.java @@ -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; @@ -70,12 +69,15 @@ public class NamespaceableResourceAdapter implements Name public NamespaceableResourceAdapter(T item, HasMetadataOperation op) { this.operation = op; this.item = item; + this.resource = getResource(item, op); + } + + public static Resource getResource(T item, HasMetadataOperation 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 @@ -83,13 +85,9 @@ public Resource inNamespace(String name) { return operation.inNamespace(name).withItem(setItemNamespace(item, name)); } - // TODO: move to KubernetesResourceUtil static 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; } diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/ResourcedHasMetadataOperation.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/ResourcedHasMetadataOperation.java index 08e65ff2a42..81fba120820 100644 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/ResourcedHasMetadataOperation.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/ResourcedHasMetadataOperation.java @@ -47,12 +47,12 @@ public HasMetadataOperationsImpl newInstance(OperationContext context) { return new ResourcedHasMetadataOperation<>(context, this.rdc, type, listType, adapter); } - public static , R extends Resource> void register( + public static > void register( Class type, BiFunction, Client, R> target) { - Handlers.register(type, (c) -> { - return new ResourcedHasMetadataOperation<>(HasMetadataOperationsImpl.defaultContext(c), ResourceDefinitionContext.fromResourceType(type), type, - KubernetesResourceUtil.inferListType(type), target); - }); + Handlers.register(type, + c -> new ResourcedHasMetadataOperation<>(HasMetadataOperationsImpl.defaultContext(c), + ResourceDefinitionContext.fromResourceType(type), type, + KubernetesResourceUtil.inferListType(type), target)); } } 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 48ed1073162..0df841ed512 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 @@ -38,7 +38,6 @@ import io.fabric8.kubernetes.client.dsl.FilterNested; import io.fabric8.kubernetes.client.dsl.FilterWatchListDeletable; import io.fabric8.kubernetes.client.dsl.MixedOperation; -import io.fabric8.kubernetes.client.dsl.NonNamespaceOperation; import io.fabric8.kubernetes.client.dsl.Resource; import io.fabric8.kubernetes.client.dsl.internal.DefaultOperationInfo; import io.fabric8.kubernetes.client.dsl.internal.WatchConnectionManager; @@ -241,17 +240,16 @@ public ExtensibleResource lockResourceVersion(String resourceVersion) { } @Override - public NonNamespaceOperation inNamespace(String namespace) { + public BaseOperation inNamespace(String namespace) { return newInstance(context.withNamespace(namespace)); } @Override - public NonNamespaceOperation inAnyNamespace() { + public BaseOperation inAnyNamespace() { Config updated = new ConfigBuilder(config).withNamespace(null).build(); return newInstance(context.withConfig(updated).withNamespace(null)); } - @Override public ExtensibleResource cascading(boolean cascading) { return newInstance(context.withCascading(cascading).withPropagationPolicy(null)); @@ -259,7 +257,7 @@ public ExtensibleResource cascading(boolean cascading) { @Override public R load(InputStream is) { - return newResource(context.withItem(unmarshal(is, type))); + return withItem(unmarshal(is, type)); } @Override @@ -519,6 +517,8 @@ public T patchStatus(T item) { @Override public R withItem(T item) { + // set both the item and the name - not all operations are looking at the item for the name + // things like configMaps().load(...).watch(...) for example return newResource(context.withItem(item).withName(KubernetesResourceUtil.getName(item))); } diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/base/HasMetadataOperation.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/base/HasMetadataOperation.java index 988ae8b92e8..f7c2e187182 100644 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/base/HasMetadataOperation.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/base/HasMetadataOperation.java @@ -267,7 +267,7 @@ public T patch(PatchContext patchContext, String patch) { } @Override - public BaseOperation newInstance(OperationContext context) { + public HasMetadataOperation newInstance(OperationContext context) { return new HasMetadataOperation<>(context, type, listType); } diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/GenericKubernetesResourceOperationsImpl.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/GenericKubernetesResourceOperationsImpl.java index 1411f9576ec..5569d64f076 100644 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/GenericKubernetesResourceOperationsImpl.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/GenericKubernetesResourceOperationsImpl.java @@ -18,7 +18,6 @@ import io.fabric8.kubernetes.api.model.GenericKubernetesResource; import io.fabric8.kubernetes.api.model.GenericKubernetesResourceList; import io.fabric8.kubernetes.client.dsl.Resource; -import io.fabric8.kubernetes.client.dsl.base.BaseOperation; import io.fabric8.kubernetes.client.dsl.base.HasMetadataOperation; import io.fabric8.kubernetes.client.dsl.base.OperationContext; @@ -38,7 +37,7 @@ protected void validateOperation(Class type) { } @Override - public BaseOperation> newInstance(OperationContext context) { + public HasMetadataOperation> newInstance(OperationContext context) { return new GenericKubernetesResourceOperationsImpl(context, resourceNamespaced); } diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/KubernetesListOperationsImpl.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/KubernetesListOperationsImpl.java index 47d603ca172..a2326959bdc 100644 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/KubernetesListOperationsImpl.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/KubernetesListOperationsImpl.java @@ -18,9 +18,9 @@ import io.fabric8.kubernetes.api.model.HasMetadata; import io.fabric8.kubernetes.api.model.KubernetesList; import io.fabric8.kubernetes.api.model.KubernetesListBuilder; -import io.fabric8.kubernetes.client.BaseClient; import io.fabric8.kubernetes.client.ClientContext; import io.fabric8.kubernetes.client.KubernetesClientException; +import io.fabric8.kubernetes.client.NamespaceableResourceAdapter; import io.fabric8.kubernetes.client.ResourceHandler; import io.fabric8.kubernetes.client.dsl.Createable; import io.fabric8.kubernetes.client.dsl.Gettable; @@ -124,9 +124,14 @@ public KubernetesList get() { return new KubernetesListBuilder(list).withItems(list.getItems().stream().map(meta -> getResource(meta).get()).collect(Collectors.toList())).build(); } + /** + * Similar to Loadable.load - does not use the namespace from the resource + * + * see also {@link NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableListImpl#getResource(OperationContext, HasMetadata)} + */ private Resource getResource(HasMetadata resource) { - ResourceHandler handler = NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableImpl.handlerOf(resource, context); - return handler.operation(this.context, null).newInstance(context.withItem(resource)); + ResourceHandler handler = NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableListImpl.handlerOf(resource, context); + return handler.operation(context, null).newInstance(context.withItem(null)).withItem(resource); } @Override diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicable.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicable.java deleted file mode 100644 index 0d879d20ae3..00000000000 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicable.java +++ /dev/null @@ -1,26 +0,0 @@ -/** - * 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.dsl.Namespaceable; - -public interface NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicable extends - VisitFromServerGetWatchDeleteRecreateWaitApplicable, - Namespaceable> -{ - -} diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableImpl.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableImpl.java deleted file mode 100644 index 86630f97839..00000000000 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableImpl.java +++ /dev/null @@ -1,259 +0,0 @@ -/** - * 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.api.builder.TypedVisitor; -import io.fabric8.kubernetes.api.builder.VisitableBuilder; -import io.fabric8.kubernetes.api.builder.Visitor; -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.ObjectMetaBuilder; -import io.fabric8.kubernetes.client.BaseClient; -import io.fabric8.kubernetes.client.ClientContext; -import io.fabric8.kubernetes.client.Handlers; -import io.fabric8.kubernetes.client.KubernetesClientException; -import io.fabric8.kubernetes.client.ResourceHandler; -import io.fabric8.kubernetes.client.Watch; -import io.fabric8.kubernetes.client.Watcher; -import io.fabric8.kubernetes.client.dsl.Applicable; -import io.fabric8.kubernetes.client.dsl.CascadingDeletable; -import io.fabric8.kubernetes.client.dsl.Deletable; -import io.fabric8.kubernetes.client.dsl.Gettable; -import io.fabric8.kubernetes.client.dsl.Readiable; -import io.fabric8.kubernetes.client.dsl.Resource; -import io.fabric8.kubernetes.client.dsl.VisitFromServerWritable; -import io.fabric8.kubernetes.client.dsl.Waitable; -import io.fabric8.kubernetes.client.dsl.base.HasMetadataOperation; -import io.fabric8.kubernetes.client.dsl.base.OperationContext; -import io.fabric8.kubernetes.client.readiness.Readiness; -import io.fabric8.kubernetes.client.utils.KubernetesResourceUtil; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.TimeUnit; -import java.util.function.Consumer; -import java.util.function.Predicate; -import java.util.function.UnaryOperator; - -import static io.fabric8.kubernetes.client.utils.DeleteAndCreateHelper.deleteAndCreateItem; - -/** - * Resource like operation with specific namespace rules. - *
If the item has a namespace, it is the default (unlike other operations) - *
If the user call inNamespace, that will be used - *
else the default namespace from the config will be used - */ -public class NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableImpl implements - NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicable, - Waitable, - Readiable { - - private final NamespaceVisitOperationContext namespaceVisitOperationContext; - private final OperationContext context; - - static class ChangeNamespace extends TypedVisitor { - - private final String explicitNamespace; - - ChangeNamespace(String explicitNamespace) { - this.explicitNamespace = explicitNamespace; - } - - @Override - public void visit(ObjectMetaBuilder builder) { - builder.withNamespace(explicitNamespace); - } - } - - public NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableImpl(OperationContext context, NamespaceVisitOperationContext namespaceVisitOperationContext) { - this.context = context; - this.namespaceVisitOperationContext = namespaceVisitOperationContext; - } - - public NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableImpl(ClientContext clientContext, HasMetadata item) { - this(HasMetadataOperationsImpl.defaultContext(clientContext).withItem(item), new NamespaceVisitOperationContext()); - handlerOf(item, this.context); // validate the handler - } - - @Override - public HasMetadata apply() { - return createOrReplace(); - } - - @Override - public HasMetadata createOrReplace() { - if (namespaceVisitOperationContext.isDeletingExisting()) { - return deleteAndCreateItem(get(), getResource()); - } - return getResource().createOrReplace(get()); - } - - @Override - public Waitable createOrReplaceAnd() { - HasMetadata item = createOrReplace(); - return newInstance(context.withItem(item), namespaceVisitOperationContext); - } - - @Override - public Boolean delete() { - return getResource().delete(); - } - - @Override - public HasMetadata get() { - if (!context.isReloadingFromServer()) { - return (HasMetadata) context.getItem(); - } - return getResource().get(); - } - - @Override - public VisitFromServerGetWatchDeleteRecreateWaitApplicable inNamespace(String explicitNamespace) { - HasMetadata item = acceptVisitors(get(), Collections.emptyList(), explicitNamespace, this.context); - return newInstance(context.withItem(item).withNamespace(explicitNamespace), namespaceVisitOperationContext.withExplicitNamespace(explicitNamespace)); - } - - @Override - public Gettable fromServer() { - return getResource().fromServer(); - } - - @Override - public Applicable deletingExisting() { - return newInstance(context, namespaceVisitOperationContext.withDeletingExisting(true)); - } - - @Override - public VisitFromServerGetWatchDeleteRecreateWaitApplicable accept(Visitor... visitors) { - HasMetadata item = acceptVisitors(get(), Arrays.asList(visitors), namespaceVisitOperationContext.getExplicitNamespace(), this.context); - return newInstance(context.withItem(item), namespaceVisitOperationContext); - } - - @Override - public CascadingDeletable withGracePeriod(long gracePeriodSeconds) { - return newInstance(context.withGracePeriodSeconds(gracePeriodSeconds), namespaceVisitOperationContext); - } - - @Override - public CascadingDeletable withPropagationPolicy(DeletionPropagation propagationPolicy) { - return newInstance(context.withPropagationPolicy(propagationPolicy), namespaceVisitOperationContext); - } - - @Override - public Deletable cascading(boolean cascading) { - return getResource().cascading(cascading); - } - - @Override - public Waitable withWaitRetryBackoff(long initialBackoff, TimeUnit backoffUnit, double backoffMultiplier) { - return this; - } - - @Override - public Watch watch(Watcher watcher) { - return getResource().watch(watcher); - } - - @Override - public Watch watch(String resourceVersion, Watcher watcher) { - return getResource().watch(resourceVersion, watcher); - } - - @Override - public Watch watch(ListOptions options, Watcher watcher) { - return getResource().watch(options, watcher); - } - - Resource getResource() { - HasMetadata meta = (HasMetadata) context.getItem(); - ResourceHandler handler = handlerOf(meta, context); - HasMetadataOperation> operation = handler.operation(context, null); - return operation.newInstance(context).inNamespace(KubernetesResourceUtil.getNamespace(meta)).withName(KubernetesResourceUtil.getName(meta)); - } - - protected Readiness getReadiness() { - return Readiness.getInstance(); - } - - @Override - public final boolean isReady() { - HasMetadata meta = fromServer().get(); - if (meta == null) { - return false; - } - return getReadiness().isReady(meta); - } - - @Override - public HasMetadata waitUntilReady(long amount, TimeUnit timeUnit) { - return getResource().waitUntilReady(amount, timeUnit); - } - - @Override - public VisitFromServerWritable dryRun(boolean isDryRun) { - return newInstance(context.withDryRun(isDryRun), namespaceVisitOperationContext); - } - - public NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableImpl newInstance(OperationContext context, NamespaceVisitOperationContext namespaceVisitOperationContext) { - return new NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableImpl(context, namespaceVisitOperationContext); - } - - @Override - public HasMetadata waitUntilCondition(Predicate condition, long amount, TimeUnit timeUnit) { - return getResource().waitUntilCondition(condition, amount, timeUnit); - } - - @Override - public HasMetadata edit(Class visitorType, Visitor visitor) { - return getResource().edit(visitorType, visitor); - } - - @Override - public HasMetadata edit(UnaryOperator function) { - return getResource().edit(function); - } - - @Override - public HasMetadata edit(Visitor... visitors) { - return getResource().edit(visitors); - } - - @Override - public HasMetadata accept(Consumer function) { - return getResource().accept(function); - } - - static HasMetadata acceptVisitors(HasMetadata item, List visitors, String explicitNamespace, OperationContext context) { - ResourceHandler h = handlerOf(item, context); - VisitableBuilder builder = h.edit(item); - - //Let's apply any visitor that might have been specified. - for (Visitor v : visitors) { - builder.accept(v); - } - if (explicitNamespace != null) { - builder.accept(new ChangeNamespace(explicitNamespace)); - } - return builder.build(); - } - - static > ResourceHandler handlerOf(T item, OperationContext context) { - return Handlers.get(item, new BaseClient(context)); - } - -} diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableListImpl.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableListImpl.java index b931dd2b58a..a7dc3e617eb 100644 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableListImpl.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableListImpl.java @@ -16,20 +16,34 @@ package io.fabric8.kubernetes.client.dsl.internal; import com.fasterxml.jackson.databind.ObjectMapper; - +import io.fabric8.kubernetes.api.builder.TypedVisitor; +import io.fabric8.kubernetes.api.builder.VisitableBuilder; import io.fabric8.kubernetes.api.builder.Visitor; import io.fabric8.kubernetes.api.model.DeletionPropagation; import io.fabric8.kubernetes.api.model.HasMetadata; import io.fabric8.kubernetes.api.model.KubernetesList; import io.fabric8.kubernetes.api.model.KubernetesResourceList; +import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; +import io.fabric8.kubernetes.client.BaseClient; import io.fabric8.kubernetes.client.ClientContext; -import io.fabric8.kubernetes.client.Config; +import io.fabric8.kubernetes.client.Handlers; +import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.client.KubernetesClientException; import io.fabric8.kubernetes.client.KubernetesClientTimeoutException; -import io.fabric8.kubernetes.client.dsl.*; -import io.fabric8.kubernetes.client.dsl.base.HasMetadataOperation; +import io.fabric8.kubernetes.client.NamespaceableResourceAdapter; +import io.fabric8.kubernetes.client.ResourceHandler; +import io.fabric8.kubernetes.client.dsl.Applicable; +import io.fabric8.kubernetes.client.dsl.CascadingDeletable; +import io.fabric8.kubernetes.client.dsl.Deletable; +import io.fabric8.kubernetes.client.dsl.Gettable; +import io.fabric8.kubernetes.client.dsl.ListVisitFromServerGetDeleteRecreateWaitApplicable; +import io.fabric8.kubernetes.client.dsl.ListVisitFromServerWritable; +import io.fabric8.kubernetes.client.dsl.NamespaceListVisitFromServerGetDeleteRecreateWaitApplicable; +import io.fabric8.kubernetes.client.dsl.ParameterNamespaceListVisitFromServerGetDeleteRecreateWaitApplicable; +import io.fabric8.kubernetes.client.dsl.Readiable; +import io.fabric8.kubernetes.client.dsl.Resource; +import io.fabric8.kubernetes.client.dsl.Waitable; import io.fabric8.kubernetes.client.dsl.base.OperationContext; -import io.fabric8.kubernetes.client.http.HttpClient; import io.fabric8.kubernetes.client.readiness.Readiness; import io.fabric8.kubernetes.client.utils.Serialization; import io.fabric8.kubernetes.client.utils.Utils; @@ -38,6 +52,7 @@ import java.io.InputStream; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -53,6 +68,20 @@ public class NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableListImpl implements ParameterNamespaceListVisitFromServerGetDeleteRecreateWaitApplicable, Waitable, HasMetadata>, Readiable { + + static class ChangeNamespace extends TypedVisitor { + + private final String explicitNamespace; + + ChangeNamespace(String explicitNamespace) { + this.explicitNamespace = explicitNamespace; + } + + @Override + public void visit(ObjectMetaBuilder builder) { + builder.withNamespace(explicitNamespace); + } + } private static final Logger LOGGER = LoggerFactory.getLogger(NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableListImpl.class); protected static final String EXPRESSION = "expression"; @@ -84,23 +113,33 @@ List getItems() { } return asHasMetadata(item).stream() - .map(meta -> NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableImpl.acceptVisitors(meta, + .map(meta -> acceptVisitors(meta, Collections.emptyList(), namespaceVisitOperationContext.getExplicitNamespace(), this.context)) .collect(Collectors.toList()); } - List getOperations() { + @Override + public List> getResources() { return getItems().stream() - .map(meta -> new NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableImpl(context.withItem(meta), - namespaceVisitOperationContext)) + .map(this::getResource) .collect(Collectors.toList()); } + + /** + * similar to {@link KubernetesClient#resource(HasMetadata)}, but we want to inherit the context + * The namespacing is the same - use the item namespace if available + */ + Resource getResource(HasMetadata meta) { + ResourceHandler handler = handlerOf(meta, context); + return NamespaceableResourceAdapter.getResource(meta, + handler.operation(context, null).newInstance(context.withItem(null))); + } @Override public List waitUntilCondition(Predicate condition, long amount, TimeUnit timeUnit) { - List operations = getOperations(); + List> operations = getResources(); if (operations.isEmpty()) { return Collections.emptyList(); } @@ -108,9 +147,9 @@ public List waitUntilCondition(Predicate condition, // we have to create a thread for each item that mostly waits final ExecutorService executor = Executors.newFixedThreadPool(operations.size(), Utils.daemonThreadFactory(this)); try { - List items = operations.stream().map(o -> o.get()).collect(Collectors.toList()); + List items = operations.stream().map(Resource::get).collect(Collectors.toList()); final List> futures = new ArrayList<>(items.size()); - for (final NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableImpl impl : operations) { + for (final Resource impl : operations) { futures.add(CompletableFuture.supplyAsync(() -> impl.waitUntilCondition(condition, amount, timeUnit))); } @@ -149,7 +188,7 @@ private static void logAsNotReady(Throwable t, HasMetadata meta) { @Override public boolean isReady() { - return getOperations().stream().map(impl -> impl.get()).allMatch(meta -> getReadiness().isReady(meta)); + return getResources().stream().map(impl -> impl.get()).allMatch(meta -> getReadiness().isReady(meta)); } @Override @@ -170,9 +209,18 @@ public List apply() { @Override public List createOrReplace() { - return getOperations().stream() - .map(impl -> impl.createOrReplace()) - .filter(Objects::nonNull) + List> operations = getResources(); + + if (!namespaceVisitOperationContext.isDeletingExisting()) { + return operations.stream() + .map(Resource::createOrReplace) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + } + operations.stream().forEach(Resource::delete); + waitUntilCondition(Objects::isNull, 30, TimeUnit.SECONDS); + return operations.stream() + .map(Resource::create) .collect(Collectors.toList()); } @@ -183,7 +231,7 @@ public Waitable, HasMetadata> createOrReplaceAnd() { @Override public Boolean delete() { - for (NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableImpl impl : getOperations()) { + for (Resource impl : getResources()) { if (Boolean.FALSE.equals(impl.delete())) { return false; } @@ -193,7 +241,7 @@ public Boolean delete() { @Override public List get() { - return getOperations().stream().map(impl -> impl.get()).collect(Collectors.toList()); + return getResources().stream().map(Resource::get).collect(Collectors.toList()); } @Override @@ -213,7 +261,9 @@ public Applicable> deletingExisting() { @Override public ListVisitFromServerGetDeleteRecreateWaitApplicable accept(Visitor... visitors) { - return newInstance(context.withItem(getOperations().stream().map(oper -> oper.accept(visitors).get()).collect(Collectors.toList())), namespaceVisitOperationContext); + return newInstance(context.withItem(getItems().stream() + .map(i -> acceptVisitors(i, Arrays.asList(visitors), namespaceVisitOperationContext.getExplicitNamespace(), context)) + .collect(Collectors.toList())), namespaceVisitOperationContext); } @Override public CascadingDeletable> withGracePeriod(long gracePeriodSeconds) @@ -265,5 +315,23 @@ protected List asHasMetadata(Object item) { public NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableListImpl newInstance(OperationContext context, NamespaceVisitOperationContext namespaceVisitOperationContext) { return new NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableListImpl(context, namespaceVisitOperationContext); } + + static HasMetadata acceptVisitors(HasMetadata item, List visitors, String explicitNamespace, OperationContext context) { + ResourceHandler h = handlerOf(item, context); + VisitableBuilder builder = h.edit(item); + + //Let's apply any visitor that might have been specified. + for (Visitor v : visitors) { + builder.accept(v); + } + if (explicitNamespace != null) { + builder.accept(new ChangeNamespace(explicitNamespace)); + } + return builder.build(); + } + + static > ResourceHandler handlerOf(T item, OperationContext context) { + return Handlers.get(item, new BaseClient(context)); + } } diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/VisitFromServerGetWatchDeleteRecreateWaitApplicable.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/VisitFromServerGetWatchDeleteRecreateWaitApplicable.java deleted file mode 100644 index 2b6d53ab093..00000000000 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/VisitFromServerGetWatchDeleteRecreateWaitApplicable.java +++ /dev/null @@ -1,55 +0,0 @@ -/** - * 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.api.builder.TypedVisitor; -import io.fabric8.kubernetes.api.builder.Visitable; -import io.fabric8.kubernetes.api.builder.Visitor; -import io.fabric8.kubernetes.client.FromServerGettable; -import io.fabric8.kubernetes.client.Watcher; -import io.fabric8.kubernetes.client.dsl.DryRunable; -import io.fabric8.kubernetes.client.dsl.Editable; -import io.fabric8.kubernetes.client.dsl.Readiable; -import io.fabric8.kubernetes.client.dsl.VisitFromServerWritable; -import io.fabric8.kubernetes.client.dsl.Waitable; -import io.fabric8.kubernetes.client.dsl.Watchable; - -public interface VisitFromServerGetWatchDeleteRecreateWaitApplicable extends Visitable>, - FromServerGettable, - Watchable>, - Waitable, - VisitFromServerWritable, - DryRunable>, - Readiable, - Editable { - - /** - * @deprecated use {@link Editable#edit(Visitor...)} instead - */ - @Override - @Deprecated - VisitFromServerGetWatchDeleteRecreateWaitApplicable accept(Visitor... arg0); - - /** - * @deprecated use {@link Editable#edit(Class, Visitor)} instead - */ - @Override - @Deprecated - default VisitFromServerGetWatchDeleteRecreateWaitApplicable accept(Class type, Visitor visitor) { - return accept(new TypedVisitor() {@Override public Class getType() {return type;} @Override public void visit(V element) {visitor.visit(element);}}); - } -} diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/informers/SharedInformerFactoryImpl.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/informers/SharedInformerFactoryImpl.java index 3010482f97a..39049b14e05 100644 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/informers/SharedInformerFactoryImpl.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/informers/SharedInformerFactoryImpl.java @@ -121,24 +121,7 @@ public SharedInformerFactory withName(String name) { */ @Override public synchronized SharedIndexInformer sharedIndexInformerFor(Class apiTypeClass, long resyncPeriodInMillis) { - return sharedIndexInformerFor(apiTypeClass, null, null, resyncPeriodInMillis, ResourceDefinitionContext.fromResourceType(apiTypeClass)); - } - - /** - * Constructs and returns a shared index informer with resync period specified. - * - * Note:It watches for events in ALL NAMESPACES. - * - * @param apiTypeClass apiType class - * @param operationContext {@link OperationContext} Operation Context - * @param resyncPeriodInMillis resync period in milliseconds - * @param 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 - * @deprecated use {@link Informable} instead - */ - @Deprecated - public synchronized SharedIndexInformer sharedIndexInformerFor(Class apiTypeClass, OperationContext operationContext, long resyncPeriodInMillis) { - return sharedIndexInformerFor(apiTypeClass, null, operationContext, resyncPeriodInMillis, ResourceDefinitionContext.fromResourceType(apiTypeClass)); + return sharedIndexInformerFor(apiTypeClass, null, resyncPeriodInMillis, ResourceDefinitionContext.fromResourceType(apiTypeClass)); } /** @@ -159,7 +142,7 @@ public synchronized SharedIndexInformer sharedIndexIn @Deprecated public synchronized , L extends KubernetesResourceList> SharedIndexInformer sharedIndexInformerForCustomResource( CustomResourceDefinitionContext customResourceContext, Class apiTypeClass, Class apiListTypeClass, long resyncPeriodInMillis) { - return sharedIndexInformerFor(apiTypeClass, apiListTypeClass, null, resyncPeriodInMillis, customResourceContext); + return sharedIndexInformerFor(apiTypeClass, apiListTypeClass, resyncPeriodInMillis, customResourceContext); } /** @@ -177,22 +160,7 @@ public synchronized SharedIndexInformer sharedIndexIn @Override @Deprecated public synchronized SharedIndexInformer sharedIndexInformerForCustomResource(ResourceDefinitionContext genericResourceContext, long resyncPeriodInMillis) { - return sharedIndexInformerFor(GenericKubernetesResource.class, GenericKubernetesResourceList.class, null, resyncPeriodInMillis, genericResourceContext); - } - - /** - * Constructs and returns a shared index informer with resync period specified for custom resources. - * - * @param apiTypeClass apiType class - * @param resyncPeriodInMillis resync period in milliseconds - * @param the type parameter (should extend {@link CustomResource} and implement {@link io.fabric8.kubernetes.api.model.Namespaced}) - * @return the shared index informer - * @deprecated use {@link Informable} instead - */ - @Deprecated - public synchronized > SharedIndexInformer sharedIndexInformerForCustomResource( - Class apiTypeClass, OperationContext operationContext, long resyncPeriodInMillis) { - return sharedIndexInformerFor(apiTypeClass, null, operationContext, resyncPeriodInMillis, ResourceDefinitionContext.fromResourceType(apiTypeClass)); + return sharedIndexInformerFor(GenericKubernetesResource.class, GenericKubernetesResourceList.class, resyncPeriodInMillis, genericResourceContext); } /** @@ -223,12 +191,12 @@ public synchronized > SharedIndexInformer share * @param the type parameter (should extend {@link io.fabric8.kubernetes.api.model.HasMetadata} and implement {@link io.fabric8.kubernetes.api.model.Namespaced}) * @param the type's list parameter (should extend {@link io.fabric8.kubernetes.api.model.KubernetesResourceList} * @return the shared index informer - * @deprecated use {@link #sharedIndexInformerFor(Class, Class, OperationContext, long, ResourceDefinitionContext)} + * @deprecated use {@link #sharedIndexInformerFor(Class, long)} */ @Override @Deprecated public synchronized , L extends KubernetesResourceList> SharedIndexInformer sharedIndexInformerForCustomResource(Class apiTypeClass, Class apiListTypeClass, long resyncPeriodInMillis) { - return sharedIndexInformerFor(apiTypeClass, apiListTypeClass, null, resyncPeriodInMillis, ResourceDefinitionContext.fromResourceType(apiTypeClass)); + return sharedIndexInformerFor(apiTypeClass, apiListTypeClass, resyncPeriodInMillis, ResourceDefinitionContext.fromResourceType(apiTypeClass)); } /** @@ -238,15 +206,14 @@ public synchronized , L extends KubernetesResource * * @param apiTypeClass apiType class * @param apiListTypeClass api list type class - * @param operationContext operation context * @param resyncPeriodInMillis resync period in milliseconds * @param the type parameter (should extend {@link io.fabric8.kubernetes.api.model.HasMetadata} and implement {@link io.fabric8.kubernetes.api.model.Namespaced}) * @param the type's list parameter (should extend {@link io.fabric8.kubernetes.api.model.KubernetesResourceList} * @return the shared index informer */ - private synchronized > SharedIndexInformer sharedIndexInformerFor(Class apiTypeClass, Class apiListTypeClass, OperationContext operationContext, long resyncPeriodInMillis, ResourceDefinitionContext rdc) { + private synchronized > SharedIndexInformer sharedIndexInformerFor(Class apiTypeClass, Class apiListTypeClass, long resyncPeriodInMillis, ResourceDefinitionContext rdc) { - HasMetadataOperationsImpl resources = getResourceOperation(apiTypeClass, apiListTypeClass, operationContext, rdc); + HasMetadataOperationsImpl resources = getResourceOperation(apiTypeClass, apiListTypeClass, rdc); // we want the resources to no longer reference a resourceVersion SharedIndexInformer informer = new DefaultSharedIndexInformer<>(apiTypeClass, resources.withResourceVersion(null), resyncPeriodInMillis, informerExecutor); @@ -255,18 +222,7 @@ private synchronized } private > HasMetadataOperationsImpl getResourceOperation( - Class apiTypeClass, Class apiListTypeClass, OperationContext operationContext, ResourceDefinitionContext rdc) { - - if (operationContext != null) { - // the operationcontext takes precedence over the resource context - rdc = new ResourceDefinitionContext.Builder() - .withGroup(Utils.coalesce(operationContext.getApiGroupName(), rdc.getGroup())) - .withVersion(Utils.coalesce(operationContext.getApiGroupVersion(), rdc.getVersion())) - .withPlural(Utils.coalesce(operationContext.getPlural(), rdc.getPlural())) - .withNamespaced(rdc.isNamespaceScoped()) - .withKind(rdc.getKind()) - .build(); - } + Class apiTypeClass, Class apiListTypeClass, ResourceDefinitionContext rdc) { HasMetadataOperationsImpl resources = client.customResources(rdc, apiTypeClass, apiListTypeClass); @@ -279,14 +235,6 @@ private > HasMetadata resources = (HasMetadataOperationsImpl) resources.withName(name); } - if (operationContext != null) { - OperationContext context = resources.getOperationContext().withOperationContext(operationContext); - // If OperationContext contains namespace, ignore global watch - if (operationContext.getNamespace() != null) { - context = context.withIsNamespaceConfiguredFromGlobalConfig(false); - } - resources = resources.newInstance(context); - } return resources; } diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/utils/DeleteAndCreateHelper.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/utils/DeleteAndCreateHelper.java deleted file mode 100644 index 2f992000001..00000000000 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/utils/DeleteAndCreateHelper.java +++ /dev/null @@ -1,86 +0,0 @@ -/** - * 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.utils; - -import io.fabric8.kubernetes.api.model.HasMetadata; -import io.fabric8.kubernetes.client.KubernetesClientException; -import io.fabric8.kubernetes.client.dsl.Resource; - -import java.net.HttpURLConnection; -import java.util.Objects; -import java.util.concurrent.TimeUnit; -import java.util.function.Function; -import java.util.function.UnaryOperator; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class DeleteAndCreateHelper { - private static final Logger LOG = LoggerFactory.getLogger(DeleteAndCreateHelper.class); - private static final int MAX_WAIT_SECONDS = 30; - - private final UnaryOperator createTask; - private final Function awaitDeleteTask; - private final Function deleteTask; - - public DeleteAndCreateHelper(UnaryOperator createTask, Function deleteTask, Function awaitDeleteTask) { - this.createTask = createTask; - this.awaitDeleteTask = awaitDeleteTask; - this.deleteTask = deleteTask; - } - - public T deleteAndCreate(T item) { - Boolean deleted = deleteTask.apply(item); - if (!deleted) { - LOG.debug("did not delete because item did not exist, continuing to create {}", item.getMetadata().getName()); - } - - try { - return createTask.apply(item); - } catch (KubernetesClientException e) { - // depending on the grace period, the object might not actually be deleted by the time we try to create - // if that's the case, give it some time. - if (e.getCode() == HttpURLConnection.HTTP_CONFLICT) { - if (!deleted) { - LOG.error("there was no item to delete, but received HTTP_CONFLICT response upon creation of item {}", item.getMetadata().getName(), e); - throw e; - } - - if (Boolean.FALSE.equals(awaitDeleteTask.apply(item))) { - throw new KubernetesClientException("Timed out waiting for item to be deleted before recreating: " + item.getMetadata().getName(), e); - } - - return createTask.apply(item); - } - - throw e; - } - } - - public static HasMetadata deleteAndCreateItem(HasMetadata meta, Resource resource) { - DeleteAndCreateHelper deleteAndCreateHelper = new DeleteAndCreateHelper<>( - m -> resource.create(m), - m -> resource.delete(), - waitUntilDeletedOrInterrupted(resource) - ); - - return deleteAndCreateHelper.deleteAndCreate(meta); - } - - private static Function waitUntilDeletedOrInterrupted(Resource resource) { - return m -> resource.waitUntilCondition(Objects::isNull, MAX_WAIT_SECONDS , TimeUnit.SECONDS) == null; - } -} diff --git a/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/utils/DeleteAndCreateHelperTest.java b/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/utils/DeleteAndCreateHelperTest.java deleted file mode 100644 index 9a2c8cf9b0d..00000000000 --- a/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/utils/DeleteAndCreateHelperTest.java +++ /dev/null @@ -1,177 +0,0 @@ -/** - * 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.utils; - -import io.fabric8.kubernetes.api.model.Pod; -import io.fabric8.kubernetes.api.model.PodBuilder; -import io.fabric8.kubernetes.api.model.StatusBuilder; -import io.fabric8.kubernetes.client.KubernetesClientException; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; - -import java.net.HttpURLConnection; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.Function; -import java.util.function.UnaryOperator; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; - -class DeleteAndCreateHelperTest { - @Test - void testDeleteAndCreate() { - // Given - AtomicBoolean wasPodDeleted = new AtomicBoolean(false); - Function deletePodTask = p -> { - wasPodDeleted.set(true); - return true; - }; - UnaryOperator createPodTask = Mockito.mock(UnaryOperator.class, Mockito.RETURNS_DEEP_STUBS); - when(createPodTask.apply(any())) - .thenReturn(getPod()); - DeleteAndCreateHelper podDeleteAndCreateHelper = new DeleteAndCreateHelper<>( - createPodTask, - deletePodTask, - p -> true - ); - - // When - Pod podCreated = podDeleteAndCreateHelper.deleteAndCreate(getPod()); - - // Then - assertNotNull(podCreated); - assertTrue(wasPodDeleted.get()); - } - - @Test - void testDeleteAndCreateWhenDeletionFailed() { - // Given - AtomicBoolean wasPodDeleted = new AtomicBoolean(false); - Function deletePodTask = p -> { - wasPodDeleted.set(true); - return false; - }; - UnaryOperator createPodTask = Mockito.mock(UnaryOperator.class, Mockito.RETURNS_DEEP_STUBS); - when(createPodTask.apply(any())).thenAnswer(invocation -> invocation.getArgument(0)); - - DeleteAndCreateHelper podDeleteAndCreateHelper = new DeleteAndCreateHelper<>( - createPodTask, - deletePodTask, - p -> { - throw new RuntimeException("should not be called because creation will succeed first"); - } - ); - - // When - Pod podToDeleteAndCreate = getPod(); - Pod result = podDeleteAndCreateHelper.deleteAndCreate(podToDeleteAndCreate); - - // Then - assertEquals(podToDeleteAndCreate, result); - verify(createPodTask).apply(podToDeleteAndCreate); - } - - @Test - void testThrowExceptionOnConflictAfterNoDelete() { - // Given - AtomicBoolean wasPodDeleted = new AtomicBoolean(false); - Function deletePodTask = p -> { - wasPodDeleted.set(true); - return false; - }; - - UnaryOperator createPodTask = Mockito.mock(UnaryOperator.class, Mockito.RETURNS_DEEP_STUBS); - when(createPodTask.apply(any())).thenThrow(new KubernetesClientException("The POST operation could not be completed at " + - "this time, please try again", - HttpURLConnection.HTTP_CONFLICT, new StatusBuilder().withCode(HttpURLConnection.HTTP_CONFLICT).build())); - DeleteAndCreateHelper podDeleteAndCreateHelper = new DeleteAndCreateHelper<>( - createPodTask, - deletePodTask, - p -> { - throw new RuntimeException("should not be called because creation will succeed first"); - } - ); - - // When - Pod podToDeleteAndCreate = getPod(); - assertThrows(KubernetesClientException.class,() -> podDeleteAndCreateHelper.deleteAndCreate(podToDeleteAndCreate)); - } - - @Test - void testDeleteAndCreateWhenDeletionSucceedsButNotFinishedInTime() { - // Given - UnaryOperator createPodTask = Mockito.mock(UnaryOperator.class, Mockito.RETURNS_DEEP_STUBS); - when(createPodTask.apply(any())).thenThrow(new KubernetesClientException("The POST operation could not be completed at " + - "this time, please try again", - HttpURLConnection.HTTP_CONFLICT, new StatusBuilder().withCode(HttpURLConnection.HTTP_CONFLICT).build())); - DeleteAndCreateHelper podDeleteAndCreateHelper = new DeleteAndCreateHelper<>( - createPodTask, - p -> true, // deletion succeeds - p -> false // but doesn't finish in time - ); - - // When - Pod podToDeleteAndCreate = getPod(); - assertThrows(KubernetesClientException.class,() -> podDeleteAndCreateHelper.deleteAndCreate(podToDeleteAndCreate)); - } - - @Test - void testDeleteAndCreateAfterWaitingForItemToBeDeleted() { - // Given - AtomicBoolean wasPodDeleted = new AtomicBoolean(false); - Function deletePodTask = p -> { - wasPodDeleted.set(true); - return true; - }; - - AtomicBoolean awaitedDeletion = new AtomicBoolean(false); - Function awaitDeletionTask = p -> { - awaitedDeletion.set(true); - return true; - }; - - UnaryOperator createPodTask = Mockito.mock(UnaryOperator.class, Mockito.RETURNS_DEEP_STUBS); - when(createPodTask.apply(any())) - .thenThrow(new KubernetesClientException("The POST operation could not be completed at " + - "this time, please try again", - HttpURLConnection.HTTP_CONFLICT, new StatusBuilder().withCode(HttpURLConnection.HTTP_CONFLICT).build())) - .thenReturn(getPod()); - - DeleteAndCreateHelper podDeleteAndCreateHelper = new DeleteAndCreateHelper<>( - createPodTask, - deletePodTask, - awaitDeletionTask - ); - - // When - Pod podCreated = podDeleteAndCreateHelper.deleteAndCreate(getPod()); - - // Then - assertNotNull(podCreated); - assertTrue(wasPodDeleted.get()); - assertTrue(awaitedDeletion.get()); - } - - private Pod getPod() { - return new PodBuilder() - .withNewMetadata().withName("p1").endMetadata() - .build(); - } -} diff --git a/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/ResourceListTest.java b/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/ResourceListTest.java index d08a8041c6a..81931e7d0d2 100644 --- a/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/ResourceListTest.java +++ b/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/ResourceListTest.java @@ -154,12 +154,16 @@ void testCreateOrReplaceWithoutDeleteExisting() throws Exception { void testCreateOrReplaceWithDeleteExisting() throws Exception { server.expect().delete().withPath("/api/v1/namespaces/ns1/services/my-service").andReturn(HTTP_OK , service).once(); server.expect().delete().withPath("/api/v1/namespaces/ns1/configmaps/my-configmap").andReturn(HTTP_OK, configMap).once(); + server.expect().get().withPath("/api/v1/namespaces/ns1/services?fieldSelector=metadata.name%3Dmy-service").andReturn(HTTP_OK, + new KubernetesListBuilder().withNewMetadata().endMetadata().build()).once(); + server.expect().get().withPath("/api/v1/namespaces/ns1/configmaps?fieldSelector=metadata.name%3Dmy-configmap").andReturn(HTTP_OK, + new KubernetesListBuilder().withNewMetadata().endMetadata().build()).once(); server.expect().post().withPath("/api/v1/namespaces/ns1/services").andReturn(HTTP_OK, updatedService).once(); server.expect().post().withPath("/api/v1/namespaces/ns1/configmaps").andReturn(HTTP_OK, updatedConfigMap).once(); client.resourceList(resourcesToUpdate).inNamespace("ns1").deletingExisting().createOrReplace(); - assertEquals(4, server.getRequestCount()); + assertEquals(6, server.getRequestCount()); RecordedRequest request = server.getLastRequest(); assertEquals("/api/v1/namespaces/ns1/configmaps", request.getPath()); assertEquals("POST", request.getMethod()); diff --git a/kubernetes-tests/src/test/java/io/fabric8/openshift/client/server/mock/OpenShiftLoadTest.java b/kubernetes-tests/src/test/java/io/fabric8/openshift/client/server/mock/OpenShiftLoadTest.java index 52b0a45f707..ed2a0687e97 100644 --- a/kubernetes-tests/src/test/java/io/fabric8/openshift/client/server/mock/OpenShiftLoadTest.java +++ b/kubernetes-tests/src/test/java/io/fabric8/openshift/client/server/mock/OpenShiftLoadTest.java @@ -40,7 +40,7 @@ void testResourceGetFromLoadWhenSingleDocumentsWithStartingDelimiter() { assertNotNull(result); assertEquals(5, result.size()); HasMetadata deploymentResource = result.get(1); - assertEquals("v1", deploymentResource.getApiVersion()); + assertEquals("image.openshift.io/v1", deploymentResource.getApiVersion()); assertEquals("ImageStream", deploymentResource.getKind()); assertEquals("eap-app", deploymentResource.getMetadata().getName()); }