From b59e35ca1ee0dd69bce4fa9aa065624685f26182 Mon Sep 17 00:00:00 2001 From: manusa Date: Mon, 3 May 2021 14:35:41 +0200 Subject: [PATCH] fix: Custom Resource fragments can be replaced and recreated with FKC 5.3.x Signed-off-by: Marc Nuri --- CHANGELOG.md | 1 + .../kit/config/service/ApplyService.java | 97 +++++------ .../kubernetes/KubernetesClientUtil.java | 155 +++++------------- .../kubernetes/KubernetesUndeployService.java | 9 +- .../kit/config/service/ApplyServiceTest.java | 29 ++-- .../kubernetes/KubernetesClientUtilTest.java | 44 +++++ .../KubernetesUndeployServiceTest.java | 2 +- 7 files changed, 154 insertions(+), 183 deletions(-) create mode 100644 jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/kubernetes/KubernetesClientUtilTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index b2ea213e6d..412d3eb0d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,7 @@ Usage: * Fix #630: DeploymentConfigEnricher and DefaultControllerEnricher refactored and aligned * Fix #639: Quotas for OpenShift BuildConfig not working * Fix #688: Multiple Custom Resources with same (different apiGroup) name can be added +* Fix #689: Recreate and update of CustomResource fragments works ### 1.2.0 (2021-03-31) * Fix #529: `.maven-dockerignore`, `.maven-dockerexclude`, `.maven-dockerinclude` are no longer supported diff --git a/jkube-kit/config/service/src/main/java/org/eclipse/jkube/kit/config/service/ApplyService.java b/jkube-kit/config/service/src/main/java/org/eclipse/jkube/kit/config/service/ApplyService.java index cb7a4e501f..0470c35336 100644 --- a/jkube-kit/config/service/src/main/java/org/eclipse/jkube/kit/config/service/ApplyService.java +++ b/jkube-kit/config/service/src/main/java/org/eclipse/jkube/kit/config/service/ApplyService.java @@ -13,6 +13,29 @@ */ package org.eclipse.jkube.kit.config.service; +import java.io.File; +import java.io.IOException; +import java.net.HttpURLConnection; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +import org.eclipse.jkube.kit.common.GenericCustomResource; +import org.eclipse.jkube.kit.common.KitLogger; +import org.eclipse.jkube.kit.common.util.FileUtil; +import org.eclipse.jkube.kit.common.util.KubernetesHelper; +import org.eclipse.jkube.kit.common.util.OpenshiftHelper; +import org.eclipse.jkube.kit.common.util.ResourceUtil; +import org.eclipse.jkube.kit.common.util.UserConfigurationCompare; +import org.eclipse.jkube.kit.config.resource.JKubeAnnotations; +import org.eclipse.jkube.kit.config.service.kubernetes.KubernetesClientUtil; + import com.fasterxml.jackson.core.JsonProcessingException; import io.fabric8.kubernetes.api.model.ConfigMap; import io.fabric8.kubernetes.api.model.HasMetadata; @@ -55,33 +78,12 @@ import io.fabric8.openshift.api.model.TagReference; import io.fabric8.openshift.api.model.Template; import io.fabric8.openshift.client.OpenShiftClient; -import org.eclipse.jkube.kit.common.GenericCustomResource; -import org.eclipse.jkube.kit.common.KitLogger; -import org.eclipse.jkube.kit.common.util.FileUtil; -import org.eclipse.jkube.kit.common.util.KubernetesHelper; -import org.eclipse.jkube.kit.common.util.OpenshiftHelper; -import org.eclipse.jkube.kit.common.util.ResourceUtil; -import org.eclipse.jkube.kit.common.util.UserConfigurationCompare; -import org.eclipse.jkube.kit.config.resource.JKubeAnnotations; -import org.eclipse.jkube.kit.config.service.kubernetes.KubernetesClientUtil; import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.StringUtils; -import java.io.File; -import java.io.IOException; -import java.net.HttpURLConnection; -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.stream.Collectors; - +import static org.apache.commons.lang3.StringUtils.isBlank; +import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.eclipse.jkube.kit.common.util.KubernetesHelper.getCrdContext; -import static org.eclipse.jkube.kit.common.util.KubernetesHelper.getFullyQualifiedApiGroupWithKind; import static org.eclipse.jkube.kit.common.util.KubernetesHelper.getKind; import static org.eclipse.jkube.kit.common.util.KubernetesHelper.getName; import static org.eclipse.jkube.kit.common.util.KubernetesHelper.getOrCreateLabels; @@ -395,7 +397,7 @@ protected void doCreateServiceAccount(ServiceAccount serviceAccount, String name (serviceAccount)); try { Object answer; - if (StringUtils.isNotBlank(namespace)) { + if (isNotBlank(namespace)) { answer = kubernetesClient.serviceAccounts().inNamespace(namespace).create(serviceAccount); } else { answer = kubernetesClient.serviceAccounts().inNamespace(getNamespace()).create(serviceAccount); @@ -484,28 +486,27 @@ private void doCreateCustomResourceDefinition(CustomResourceDefinition entity, S } } - public void applyCustomResource(CustomResourceDefinitionContext context, GenericCustomResource genericCustomResource, String sourceName) + private void applyCustomResource(CustomResourceDefinitionContext context, GenericCustomResource genericCustomResource, String sourceName) throws IOException { - String customResourceStr = Serialization.jsonMapper().writeValueAsString(genericCustomResource); String name = genericCustomResource.getMetadata().getName(); String apiGroupWithKind = KubernetesHelper.getFullyQualifiedApiGroupWithKind(context); Objects.requireNonNull(name, "No name for " + genericCustomResource + " " + sourceName); if (isRecreateMode()) { - KubernetesClientUtil.doDeleteCustomResource(kubernetesClient, context, namespace, name); - KubernetesClientUtil.doCreateCustomResource(kubernetesClient, context, namespace, customResourceStr); - log.info("Created Custom Resource: %s %s/%s", apiGroupWithKind, namespace, name); - } else { - Map crFromServer = KubernetesClientUtil.doGetCustomResource(kubernetesClient, context, namespace, name); - if (crFromServer == null) { - KubernetesClientUtil.doCreateCustomResource(kubernetesClient, context, namespace, customResourceStr); - log.info("Created Custom Resource: %s %s/%s", apiGroupWithKind, namespace, name); - } else { - KubernetesClientUtil.doEditCustomResource(kubernetesClient, context, namespace, name, customResourceStr); - log.info("Updated Custom Resource: %s %s/%s", KubernetesHelper.getFullyQualifiedApiGroupWithKind(context), namespace, name); - } + log.info("Attempting to delete Custom Resource: %s %s/%s", apiGroupWithKind, namespace, name); + KubernetesClientUtil.doDeleteAndWait(kubernetesClient, context, namespace, name, 10L); + + } + final GenericCustomResource existentCR = KubernetesClientUtil.doGetCustomResource(kubernetesClient, context, namespace, name); + if (existentCR != null && isBlank(existentCR.getMetadata().getDeletionTimestamp())) { + log.info("Replacing Custom Resource: %s %s/%s", + KubernetesHelper.getFullyQualifiedApiGroupWithKind(context), namespace, name); + genericCustomResource.getMetadata().setResourceVersion(existentCR.getMetadata().getResourceVersion()); } + kubernetesClient.customResource(context).inNamespace(namespace).withName(name) + .createOrReplace(Serialization.jsonMapper().writeValueAsString(genericCustomResource)); + log.info("Created Custom Resource: %s %s/%s", apiGroupWithKind, namespace, name); } protected boolean isBound(PersistentVolumeClaim claim) { @@ -518,7 +519,7 @@ protected void doCreatePersistentVolumeClaim(PersistentVolumeClaim entity, Strin log.info("Creating a PersistentVolumeClaim from " + sourceName + " namespace " + namespace + " name " + getName(entity)); try { Object answer; - if (StringUtils.isNotBlank(namespace)) { + if (isNotBlank(namespace)) { answer = kubernetesClient.persistentVolumeClaims().inNamespace(namespace).create(entity); } else { answer = kubernetesClient.persistentVolumeClaims().inNamespace(getNamespace()).create(entity); @@ -565,7 +566,7 @@ protected void doCreateSecret(Secret secret, String namespace, String sourceName log.info("Creating a Secret from " + sourceName + " namespace " + namespace + " name " + getName(secret)); try { Object answer; - if (StringUtils.isNotBlank(namespace)) { + if (isNotBlank(namespace)) { answer = kubernetesClient.secrets().inNamespace(namespace).create(secret); } else { answer = kubernetesClient.secrets().inNamespace(getNamespace()).create(secret); @@ -582,7 +583,7 @@ protected void logGeneratedEntity(String message, String namespace, HasMetadata namespaceDir.mkdirs(); String kind = getKind(entity); String name = getName(entity); - if (StringUtils.isNotBlank(kind)) { + if (isNotBlank(kind)) { name = kind.toLowerCase() + "-" + name; } if (StringUtils.isBlank(name)) { @@ -938,7 +939,7 @@ protected void doCreateResource(T resource, String na log.info("Creating a " + kind + " from " + sourceName + " namespace " + namespace + " name " + getName(resource)); try { Object answer; - if (StringUtils.isNotBlank(namespace)) { + if (isNotBlank(namespace)) { answer = resources.inNamespace(namespace).create(resource); } else { answer = resources.inNamespace(getNamespace()).create(resource); @@ -964,7 +965,7 @@ protected void doCreateService(Service service, String namespace, String sourceN log.info("Creating a Service from " + sourceName + " namespace " + namespace + " name " + getName(service)); try { Object answer; - if (StringUtils.isNotBlank(namespace)) { + if (isNotBlank(namespace)) { answer = kubernetesClient.services().inNamespace(namespace).create(service); } else { answer = kubernetesClient.services().inNamespace(getNamespace()).create(service); @@ -1023,7 +1024,7 @@ public void applyNamespace(String namespaceName, Map labels) { ObjectMeta metadata = getOrCreateMetadata(entity); metadata.setName(namespaceName); String kubernetesClientNamespace = kubernetesClient.getNamespace(); - if (StringUtils.isNotBlank(kubernetesClientNamespace)) { + if (isNotBlank(kubernetesClientNamespace)) { Map entityLabels = getOrCreateLabels(entity); if (labels != null) { entityLabels.putAll(labels); @@ -1039,7 +1040,7 @@ public void applyNamespace(String namespaceName, Map labels) { ObjectMeta metadata = getOrCreateMetadata(entity); metadata.setName(namespaceName); String kubernetesClientNamespace = kubernetesClient.getNamespace(); - if (StringUtils.isNotBlank(kubernetesClientNamespace)) { + if (isNotBlank(kubernetesClientNamespace)) { Map entityLabels = getOrCreateLabels(entity); if (labels != null) { entityLabels.putAll(labels); @@ -1177,7 +1178,7 @@ protected void doCreateReplicationController(ReplicationController replicationCo log.info("Creating a ReplicationController from " + sourceName + " namespace " + namespace + " name " + getName(replicationController)); try { Object answer; - if (StringUtils.isNotBlank(namespace)) { + if (isNotBlank(namespace)) { answer = kubernetesClient.replicationControllers().inNamespace(namespace).create(replicationController); } else { answer = kubernetesClient.replicationControllers().inNamespace(getNamespace()).create(replicationController); @@ -1222,7 +1223,7 @@ protected void doCreatePod(Pod pod, String namespace, String sourceName) { log.info("Creating a Pod from " + sourceName + " namespace " + namespace + " name " + getName(pod)); try { Object answer; - if (StringUtils.isNotBlank(namespace)) { + if (isNotBlank(namespace)) { answer = kubernetesClient.pods().inNamespace(namespace).create(pod); } else { answer = kubernetesClient.pods().inNamespace(getNamespace()).create(pod); @@ -1256,7 +1257,7 @@ protected void applyJob(Job job, String sourceName) { } public void doCreateJob(Job job, String namespace, String sourceName) { - if (StringUtils.isNotBlank(namespace)) { + if (isNotBlank(namespace)) { kubernetesClient.batch().jobs().inNamespace(namespace).create(job); } else { kubernetesClient.batch().jobs().inNamespace(getNamespace()).create(job); diff --git a/jkube-kit/config/service/src/main/java/org/eclipse/jkube/kit/config/service/kubernetes/KubernetesClientUtil.java b/jkube-kit/config/service/src/main/java/org/eclipse/jkube/kit/config/service/kubernetes/KubernetesClientUtil.java index cf280b5826..8cadfb2289 100644 --- a/jkube-kit/config/service/src/main/java/org/eclipse/jkube/kit/config/service/kubernetes/KubernetesClientUtil.java +++ b/jkube-kit/config/service/src/main/java/org/eclipse/jkube/kit/config/service/kubernetes/KubernetesClientUtil.java @@ -13,44 +13,37 @@ */ package org.eclipse.jkube.kit.config.service.kubernetes; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.function.Supplier; + +import org.eclipse.jkube.kit.common.GenericCustomResource; +import org.eclipse.jkube.kit.common.KitLogger; +import org.eclipse.jkube.kit.common.util.KubernetesHelper; +import org.eclipse.jkube.kit.common.util.OpenshiftHelper; +import org.eclipse.jkube.kit.config.image.ImageName; + import io.fabric8.kubernetes.api.model.DeletionPropagation; import io.fabric8.kubernetes.api.model.HasMetadata; -import io.fabric8.kubernetes.api.model.LabelSelector; -import io.fabric8.kubernetes.api.model.LabelSelectorRequirement; import io.fabric8.kubernetes.api.model.Pod; import io.fabric8.kubernetes.api.model.PodCondition; -import io.fabric8.kubernetes.api.model.PodList; import io.fabric8.kubernetes.api.model.PodStatus; import io.fabric8.kubernetes.api.model.ReplicationController; import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.kubernetes.api.model.apps.ReplicaSet; import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.client.Watcher; -import io.fabric8.kubernetes.client.dsl.FilterWatchListDeletable; -import io.fabric8.kubernetes.client.dsl.LogWatch; -import io.fabric8.kubernetes.client.dsl.NonNamespaceOperation; -import io.fabric8.kubernetes.client.dsl.PodResource; import io.fabric8.kubernetes.client.dsl.Scaleable; import io.fabric8.kubernetes.client.dsl.base.CustomResourceDefinitionContext; +import io.fabric8.kubernetes.client.dsl.internal.RawCustomResourceOperationsImpl; +import io.fabric8.kubernetes.client.utils.Serialization; import io.fabric8.openshift.api.model.DeploymentConfig; import io.fabric8.openshift.client.OpenShiftClient; -import org.eclipse.jkube.kit.common.KitLogger; -import org.eclipse.jkube.kit.common.util.KubernetesHelper; -import org.eclipse.jkube.kit.common.util.OpenshiftHelper; -import org.eclipse.jkube.kit.config.image.ImageName; import org.apache.commons.lang3.StringUtils; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CountDownLatch; - /** * Utility class for executing common tasks using the Kubernetes client * @@ -118,71 +111,6 @@ private static String getS2IBuildName(ImageName imageName, String s2iBuildNameSu return imageName.getSimpleName() + s2iBuildNameSuffix; } - - public static FilterWatchListDeletable withSelector(NonNamespaceOperation> pods, LabelSelector selector, KitLogger log) { - FilterWatchListDeletable answer = pods; - Map matchLabels = selector.getMatchLabels(); - if (matchLabels != null && !matchLabels.isEmpty()) { - answer = answer.withLabels(matchLabels); - } - List matchExpressions = selector.getMatchExpressions(); - if (matchExpressions != null) { - for (LabelSelectorRequirement expression : matchExpressions) { - String key = expression.getKey(); - List values = expression.getValues(); - if (StringUtils.isBlank(key)) { - log.warn("Ignoring empty key in selector expression %s", expression); - continue; - } - if (values == null || values.isEmpty()) { - log.warn("Ignoring empty values in selector expression %s", expression); - continue; - } - String[] valuesArray = values.toArray(new String[values.size()]); - String operator = expression.getOperator(); - switch (operator) { - case "In": - answer = answer.withLabelIn(key, valuesArray); - break; - case "NotIn": - answer = answer.withLabelNotIn(key, valuesArray); - break; - default: - log.warn("Ignoring unknown operator %s in selector expression %s", operator, expression); - } - } - } - return answer; - } - - public static void printLogsAsync(LogWatch logWatcher, final String failureMessage, final CountDownLatch terminateLatch, final KitLogger log) { - final InputStream in = logWatcher.getOutput(); - Thread thread = new Thread() { - @Override - public void run() { - try (BufferedReader reader = new BufferedReader(new InputStreamReader(in))) { - while (true) { - String line = reader.readLine(); - if (line == null) { - return; - } - if (terminateLatch.getCount() <= 0L) { - return; - } - log.info("[[s]]%s", line); - } - } catch (IOException e) { - // Check again the latch which could be already count down to zero in between - // so that an IO exception occurs on read - if (terminateLatch.getCount() > 0L) { - log.error("%s : %s", failureMessage, e); - } - } - } - }; - thread.start(); - } - public static String getPodStatusDescription(Pod pod) { return KubernetesHelper.getPodPhase(pod) + " " + getPodCondition(pod); } @@ -227,42 +155,33 @@ protected static String getPodCondition(Pod pod) { return ""; } - public static Map doCreateCustomResource(KubernetesClient kubernetesClient, CustomResourceDefinitionContext crdContext, String namespace, String customResourceStr) throws IOException { - if ("Namespaced".equals(crdContext.getScope())) { - return kubernetesClient.customResource(crdContext).create(namespace, customResourceStr); - } else { - return kubernetesClient.customResource(crdContext).create(customResourceStr); - } - } - - public static Map doEditCustomResource(KubernetesClient kubernetesClient, CustomResourceDefinitionContext crdContext, String namespace, String name, String customResourceStr) throws IOException { - if ("Namespaced".equals(crdContext.getScope())) { - return kubernetesClient.customResource(crdContext).edit(namespace, name, customResourceStr); - } else { - return kubernetesClient.customResource(crdContext).edit(name, customResourceStr); - } - } - - public static Boolean doDeleteCustomResource( - KubernetesClient kubernetesClient, CustomResourceDefinitionContext crdContext, String namespace, String name) - throws IOException{ - - if ("Namespaced".equals(crdContext.getScope())) { - return kubernetesClient.customResource(crdContext).inNamespace(namespace).withName(name).delete(); - } else { - return kubernetesClient.customResource(crdContext).delete(name); + public static GenericCustomResource doGetCustomResource(KubernetesClient kubernetesClient, CustomResourceDefinitionContext crdContext, String namespace, String name) { + try { + return Serialization.jsonMapper().convertValue( + kubernetesClient.customResource(crdContext).inNamespace(namespace).withName(name).get(), + GenericCustomResource.class + ); + } catch (Exception exception) { // Not found exception + return null; } } - public static Map doGetCustomResource(KubernetesClient kubernetesClient, CustomResourceDefinitionContext crdContext, String namespace, String name) { + public static void doDeleteAndWait(KubernetesClient kubernetesClient, CustomResourceDefinitionContext context, + String namespace, String name, long seconds) { + final RawCustomResourceOperationsImpl crClient = kubernetesClient.customResource(context) + .inNamespace(namespace) + .withName(name); try { - if ("Namespaced".equals(crdContext.getScope())) { - return kubernetesClient.customResource(crdContext).get(namespace, name); - } else { - return kubernetesClient.customResource(crdContext).get(name); + crClient.delete(); + /* Not implemented in Fabric8 Kubernetes Client ----> TODO: replace when sth like this is available + crClient.waitUntilCondition(Objects::isNull, seconds, TimeUnit.SECONDS); + */ + final Supplier getter = () -> doGetCustomResource(kubernetesClient, context, namespace, name); + while (seconds-- > 0 && !Objects.isNull(getter.get())) { + Thread.sleep(1000L); } - } catch (Exception exception) { // Not found exception - return null; + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); } } diff --git a/jkube-kit/config/service/src/main/java/org/eclipse/jkube/kit/config/service/kubernetes/KubernetesUndeployService.java b/jkube-kit/config/service/src/main/java/org/eclipse/jkube/kit/config/service/kubernetes/KubernetesUndeployService.java index d8f28a6f31..4b690330f3 100644 --- a/jkube-kit/config/service/src/main/java/org/eclipse/jkube/kit/config/service/kubernetes/KubernetesUndeployService.java +++ b/jkube-kit/config/service/src/main/java/org/eclipse/jkube/kit/config/service/kubernetes/KubernetesUndeployService.java @@ -18,14 +18,12 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.function.Consumer; import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; -import io.fabric8.kubernetes.api.model.apiextensions.v1beta1.CustomResourceDefinitionList; import org.eclipse.jkube.kit.common.GenericCustomResource; import org.eclipse.jkube.kit.common.KitLogger; import org.eclipse.jkube.kit.common.util.KubernetesHelper; @@ -35,6 +33,7 @@ import io.fabric8.kubernetes.api.model.DeletionPropagation; import io.fabric8.kubernetes.api.model.HasMetadata; +import io.fabric8.kubernetes.api.model.apiextensions.v1beta1.CustomResourceDefinitionList; import io.fabric8.kubernetes.client.dsl.base.CustomResourceDefinitionContext; import static org.eclipse.jkube.kit.common.util.KubernetesHelper.getCrdContext; @@ -106,7 +105,7 @@ private void deleteCustomResourceIfCustomResourceDefinitionContextPresent(Generi } private void deleteCustomResourceIfPresent(GenericCustomResource customResource, String namespace, CustomResourceDefinitionContext crdContext) { - Map cr = KubernetesClientUtil.doGetCustomResource(jKubeServiceHub.getClient(), crdContext, namespace, customResource.getMetadata().getName()); + final GenericCustomResource cr = KubernetesClientUtil.doGetCustomResource(jKubeServiceHub.getClient(), crdContext, namespace, customResource.getMetadata().getName()); if (cr != null) { deleteCustomResource(customResource, namespace, crdContext); } @@ -117,8 +116,8 @@ private void deleteCustomResource(GenericCustomResource customResource, String n String apiVersionAndKind = KubernetesHelper.getFullyQualifiedApiGroupWithKind(crdContext); try { logger.info("Deleting Custom Resource %s %s", apiVersionAndKind, name); - KubernetesClientUtil.doDeleteCustomResource(jKubeServiceHub.getClient(), crdContext, namespace, name); - } catch (IOException exception) { + jKubeServiceHub.getClient().customResource(crdContext).inNamespace(namespace).withName(name).delete(); + } catch (Exception exception) { logger.error("Unable to undeploy %s %s/%s", apiVersionAndKind, namespace, name); } } diff --git a/jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/ApplyServiceTest.java b/jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/ApplyServiceTest.java index 5d5ea42baf..4515d900cd 100644 --- a/jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/ApplyServiceTest.java +++ b/jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/ApplyServiceTest.java @@ -52,6 +52,7 @@ import org.junit.Rule; import org.junit.Test; +import static java.net.HttpURLConnection.HTTP_CONFLICT; import static java.net.HttpURLConnection.HTTP_CREATED; import static java.net.HttpURLConnection.HTTP_NOT_FOUND; import static java.net.HttpURLConnection.HTTP_OK; @@ -255,27 +256,33 @@ public void testProcessCustomEntitiesReplaceCustomResources() throws Exception { mockServer.expect().get() .withPath("/apis/networking.istio.io/v1alpha3/namespaces/default/virtualservices/reviews-route") .andReply(collector.record("get-cr-virtualservice").andReturn(HTTP_OK, "{\"metadata\":{\"resourceVersion\":\"1001\"}}")) - .times(2); - mockServer.expect().patch() - .withPath("/apis/networking.istio.io/v1alpha3/namespaces/default/virtualservices/reviews-route") - .andReply(collector.record("put-cr-virtualservice").andReturn(HTTP_OK, "{}")) + .once(); + mockServer.expect().post() + .withPath("/apis/networking.istio.io/v1alpha3/namespaces/default/virtualservices") + .andReply(collector.record("post-cr-virtualservice").andReturn(HTTP_OK, "{}")) .once(); mockServer.expect().get() .withPath("/apis/networking.istio.io/v1alpha3/namespaces/default/gateways/mygateway-https") .andReply(collector.record("get-cr-gateway").andReturn(HTTP_OK, "{\"metadata\":{\"resourceVersion\":\"1002\"}}")) - .times(2); - mockServer.expect().patch() - .withPath("/apis/networking.istio.io/v1alpha3/namespaces/default/gateways/mygateway-https") - .andReply(collector.record("put-cr-gateway").andReturn(HTTP_OK, "{}")) .once(); + mockServer.expect().post() + .withPath("/apis/networking.istio.io/v1alpha3/namespaces/default/gateways") + .andReply(collector.record("post-cr-gateway").andReturn(HTTP_CONFLICT, "{}")) + .once(); + mockServer.expect().put() + .withPath("/apis/networking.istio.io/v1alpha3/namespaces/default/gateways/mygateway-https") + .andReply(collector.record("put-cr-gateway").andReturn(HTTP_OK, "{\"metadata\":{\"resourceVersion\":\"1002\"}}")) + .once(); // When applyService.applyGenericCustomResource(gateway, gatewayFragment.getName()); applyService.applyGenericCustomResource(virtualService, virtualServiceFragment.getName()); // Then - collector.assertEventsRecordedInOrder("get-crds", "get-cr-gateway", "get-cr-gateway", "put-cr-gateway", "get-crds", "get-cr-virtualservice", "get-cr-virtualservice", "put-cr-virtualservice"); - assertEquals(9, mockServer.getMockServer().getRequestCount()); + collector.assertEventsRecordedInOrder( + "get-crds", "get-cr-gateway", "post-cr-gateway", "put-cr-gateway", + "get-crds", "get-cr-virtualservice", "post-cr-virtualservice"); + assertEquals(8, mockServer.getMockServer().getRequestCount()); } @Test @@ -315,7 +322,7 @@ public void testProcessCustomEntitiesRecreateModeTrue() throws Exception { // Then collector.assertEventsRecordedInOrder("get-crds", "delete-cr-gateway", "post-cr-gateway", "get-crds", "delete-cr-virtualservice", "post-cr-virtualservice"); - assertEquals(7, mockServer.getMockServer().getRequestCount()); + assertEquals(11, mockServer.getMockServer().getRequestCount()); applyService.setRecreateMode(false); } diff --git a/jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/kubernetes/KubernetesClientUtilTest.java b/jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/kubernetes/KubernetesClientUtilTest.java new file mode 100644 index 0000000000..67b74780aa --- /dev/null +++ b/jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/kubernetes/KubernetesClientUtilTest.java @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2019 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at: + * + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.jkube.kit.config.service.kubernetes; + +import io.fabric8.kubernetes.client.KubernetesClient; +import io.fabric8.kubernetes.client.dsl.base.CustomResourceDefinitionContext; +import mockit.Mocked; +import mockit.Verifications; +import org.junit.Test; + +import static org.eclipse.jkube.kit.config.service.kubernetes.KubernetesClientUtil.doDeleteAndWait; + +public class KubernetesClientUtilTest { + + @Mocked + private KubernetesClient kubernetesClient; + + @Test + public void doDeleteAndWait_withExistingResource_shouldDeleteAndReachWaitLimit() { + // Given + final CustomResourceDefinitionContext context = new CustomResourceDefinitionContext(); + // When + doDeleteAndWait(kubernetesClient, context, "namespace", "name", 2L); + // Then + // @formatter:off + new Verifications(){{ + kubernetesClient.customResource(context).inNamespace("namespace").withName("name").delete(); times = 1; + kubernetesClient.customResource(context).inNamespace("namespace").withName("name").get(); times = 2; + }}; + // @formatter:on + } + +} \ No newline at end of file diff --git a/jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/kubernetes/KubernetesUndeployServiceTest.java b/jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/kubernetes/KubernetesUndeployServiceTest.java index ceb82ee220..41bf176b51 100644 --- a/jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/kubernetes/KubernetesUndeployServiceTest.java +++ b/jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/kubernetes/KubernetesUndeployServiceTest.java @@ -138,7 +138,7 @@ public void undeployWithManifestAndCustomResourcesShouldDeleteAllEntities( // Then // @formatter:off new Verifications() {{ - jKubeServiceHub.getClient().customResource((CustomResourceDefinitionContext)any).delete("my-cr"); + jKubeServiceHub.getClient().customResource((CustomResourceDefinitionContext)any).inNamespace(null).withName("my-cr").delete(); times = 1; }}; // @formatter:on