diff --git a/CHANGELOG.md b/CHANGELOG.md index dd9dbb28267..2c80f3b10c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ### 4.10-SNAPSHOT #### Bugs +* Fix #2373: Unable to create a Template on OCP3 #### Improvements diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/utils/BackwardsCompatibilityInterceptor.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/utils/BackwardsCompatibilityInterceptor.java index 38ed204ac37..a800c0579bc 100644 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/utils/BackwardsCompatibilityInterceptor.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/utils/BackwardsCompatibilityInterceptor.java @@ -132,7 +132,7 @@ public int hashCode() { public Response intercept(Chain chain) throws IOException { Request request = chain.request(); Response response = chain.proceed(request); - if (isDeprecatedOpenshiftOapiRequest(request)) { + if (isOpenshiftApiRequest(request)) { return handleOpenshiftOapiRequests(request, response, chain); } else if (!response.isSuccessful() && responseCodeToTransformations.keySet().contains(response.code())) { String url = request.url().toString(); @@ -172,12 +172,11 @@ private static ResourceKey getKey(Matcher m) { private static Response handleOpenshiftOapiRequests(Request request, Response response, Chain chain) throws IOException{ if (!response.isSuccessful()) { String requestUrl = request.url().toString(); - // handle case when /oapi is not available String[] parts = requestUrl.split("/"); String resourcePath = parts[parts.length - 1]; ResourceKey target = openshiftOAPITransformations.get(resourcePath); if (target != null) { - requestUrl = requestUrl.replace("/oapi", "/apis/" + target.getGroup()); + requestUrl = requestUrl.replace("/apis/" + target.getGroup() + "/" + target.getVersion(), "/oapi/v1"); return handleNewRequestAndProceed(request, requestUrl, target, chain); } } @@ -206,9 +205,9 @@ private static Response handleNewRequestAndProceed(Request request, String newUr return chain.proceed(newRequest.build()); } - private static boolean isDeprecatedOpenshiftOapiRequest(Request request) { - if (request != null && request.url() != null) { - return request.url().toString().contains("oapi"); + private static boolean isOpenshiftApiRequest(Request request) { + if (request != null) { + return request.url().toString().contains(".openshift.io"); } return false; } diff --git a/kubernetes-tests/src/test/java/io/fabric8/openshift/client/server/mock/BuildConfigTest.java b/kubernetes-tests/src/test/java/io/fabric8/openshift/client/server/mock/BuildConfigTest.java index 15d92e58e2f..dc21ac0ca84 100644 --- a/kubernetes-tests/src/test/java/io/fabric8/openshift/client/server/mock/BuildConfigTest.java +++ b/kubernetes-tests/src/test/java/io/fabric8/openshift/client/server/mock/BuildConfigTest.java @@ -36,6 +36,7 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.net.HttpURLConnection; import java.net.SocketTimeoutException; import java.util.concurrent.TimeUnit; @@ -200,4 +201,48 @@ public void testDelete() { assertTrue(deleted); } + @Test + void testCreateOrReplaceOpenShift3() { + // Given + BuildConfig buildConfig = getBuildConfig(); + server.expect().post().withPath("/oapi/v1/namespaces/ns1/buildconfigs") + .andReturn(HttpURLConnection.HTTP_OK, buildConfig) + .once(); + OpenShiftClient client = server.getOpenshiftClient(); + + // When + buildConfig = client.buildConfigs().inNamespace("ns1").createOrReplace(buildConfig); + + // Then + assertNotNull(buildConfig); + assertEquals("ruby-sample-build", buildConfig.getMetadata().getName()); + } + + private BuildConfig getBuildConfig() { + return new BuildConfigBuilder() + .withNewMetadata().withName("ruby-sample-build").endMetadata() + .withNewSpec() + .withRunPolicy("Serial") + .addNewTrigger().withType("GitHub").withNewGithub().withSecret("secret101").endGithub().endTrigger() + .addNewTrigger().withType("Generic").withNewGeneric().withSecret("secret101").endGeneric().endTrigger() + .addNewTrigger().withType("ImageChange").endTrigger() + .withNewSource() + .withNewGit().withUri("https://github.com/openshift/ruby-hello-world").endGit() + .endSource() + .withNewStrategy() + .withNewSourceStrategy() + .withNewFrom() + .withKind("ImageStreamTag") + .withName("ruby-20-centos7:latest") + .endFrom() + .endSourceStrategy() + .endStrategy() + .withNewOutput() + .withNewTo().withKind("ImageStreamTag").withName("origin-ruby-sample:latest").endTo() + .endOutput() + .withNewPostCommit().withScript("bundle exec rake test").endPostCommit() + .endSpec() + .build(); + } + } diff --git a/kubernetes-tests/src/test/java/io/fabric8/openshift/client/server/mock/DeploymentConfigTest.java b/kubernetes-tests/src/test/java/io/fabric8/openshift/client/server/mock/DeploymentConfigTest.java index e3321493e88..200119b393a 100644 --- a/kubernetes-tests/src/test/java/io/fabric8/openshift/client/server/mock/DeploymentConfigTest.java +++ b/kubernetes-tests/src/test/java/io/fabric8/openshift/client/server/mock/DeploymentConfigTest.java @@ -38,6 +38,7 @@ import io.fabric8.openshift.api.model.DeploymentConfigListBuilder; import io.fabric8.openshift.client.OpenShiftClient; +import java.net.HttpURLConnection; import java.util.concurrent.atomic.AtomicBoolean; @EnableRuleMigrationSupport @@ -221,35 +222,7 @@ public void testDeployingLatestHandlesMissingLatestVersion() { @Test public void testDeploymentConfigVisitor() { AtomicBoolean visitedContainer = new AtomicBoolean(); - - DeploymentConfig dc1 = new DeploymentConfigBuilder() - .withNewMetadata() - .withName("dc1") - .endMetadata() - .withNewSpec() - .withReplicas(1) - .addToSelector("name", "dc1") - .addNewTrigger() - .withType("ImageChange") - .withNewImageChangeParams() - .withAutomatic(true) - .withContainerNames("container") - .withNewFrom() - .withKind("ImageStreamTag") - .withName("image:1.0") - .endFrom() - .endImageChangeParams() - .endTrigger() - .withNewTemplate() - .withNewSpec() - .addNewContainer() - .withName("container") - .withImage("image") - .endContainer() - .endSpec() - .endTemplate() - .endSpec() - .build(); + DeploymentConfig dc1 = getDeploymentConfig().build(); DeploymentConfig dc2 = new DeploymentConfigBuilder(dc1) .accept(new TypedVisitor>() { @@ -270,4 +243,51 @@ public void visit(ContainerFluent container) { }).build(); assertTrue(visitedContainer.get()); } + + @Test + public void testCreateOrReplaceOnOpenShift3() { + // Given + DeploymentConfig deploymentConfig = getDeploymentConfig().build(); + server.expect().post().withPath("/oapi/v1/namespaces/ns1/deploymentconfigs") + .andReturn(HttpURLConnection.HTTP_OK, deploymentConfig) + .once(); + OpenShiftClient client = server.getOpenshiftClient(); + + // When + deploymentConfig = client.deploymentConfigs().inNamespace("ns1").createOrReplace(deploymentConfig); + + // Then + assertNotNull(deploymentConfig); + assertEquals("dc1", deploymentConfig.getMetadata().getName()); + } + + private DeploymentConfigBuilder getDeploymentConfig() { + return new DeploymentConfigBuilder() + .withNewMetadata() + .withName("dc1") + .endMetadata() + .withNewSpec() + .withReplicas(1) + .addToSelector("name", "dc1") + .addNewTrigger() + .withType("ImageChange") + .withNewImageChangeParams() + .withAutomatic(true) + .withContainerNames("container") + .withNewFrom() + .withKind("ImageStreamTag") + .withName("image:1.0") + .endFrom() + .endImageChangeParams() + .endTrigger() + .withNewTemplate() + .withNewSpec() + .addNewContainer() + .withName("container") + .withImage("image") + .endContainer() + .endSpec() + .endTemplate() + .endSpec(); + } } diff --git a/kubernetes-tests/src/test/java/io/fabric8/openshift/client/server/mock/TemplateTest.java b/kubernetes-tests/src/test/java/io/fabric8/openshift/client/server/mock/TemplateTest.java index ba3c562cab1..8a4bf5b4580 100644 --- a/kubernetes-tests/src/test/java/io/fabric8/openshift/client/server/mock/TemplateTest.java +++ b/kubernetes-tests/src/test/java/io/fabric8/openshift/client/server/mock/TemplateTest.java @@ -16,6 +16,7 @@ package io.fabric8.openshift.client.server.mock; import java.io.IOException; +import java.net.HttpURLConnection; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -24,6 +25,8 @@ 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.api.model.Pod; +import io.fabric8.kubernetes.api.model.PodBuilder; import io.fabric8.kubernetes.api.model.Service; import io.fabric8.kubernetes.api.model.ServicePort; import io.fabric8.kubernetes.api.model.ServiceSpec; @@ -181,7 +184,7 @@ public void testProcess() { } @Test - public void shouldLoadTemplateWithNumberParameters() throws Exception { + public void shouldLoadTemplateWithNumberParameters() { OpenShiftClient client = new DefaultOpenShiftClient(new OpenShiftConfigBuilder().build()); Map map = new HashMap<>(); map.put("PORT", "8080"); @@ -205,7 +208,7 @@ protected static void assertListIsServiceWithPort8080(List items) { List ports = serviceSpec.getPorts(); assertEquals(1, ports.size()); ServicePort port = ports.get(0); - assertEquals(new Integer(8080), port.getPort()); + assertEquals(Integer.valueOf(8080), port.getPort()); } @Test @@ -259,4 +262,68 @@ public void testEmptyParameterMapValueShouldNotThrowNullPointerException() { assertNotNull(list); } + @Test + void testCreateOrReplaceOpenShift3() { + // Given + Template template = getTemplateBuilder().build(); + server.expect().post().withPath("/oapi/v1/namespaces/ns1/templates") + .andReturn(HttpURLConnection.HTTP_OK, template) + .once(); + + OpenShiftClient client = server.getOpenshiftClient(); + + // When + template = client.templates().inNamespace("ns1").createOrReplace(template); + + // Then + assertNotNull(template); + } + + @Test + void testCreateOrReplaceOpenShif4() { + // Given + Template template = getTemplateBuilder().build(); + server.expect().post().withPath("/apis/template.openshift.io/v1/namespaces/ns1/templates") + .andReturn(HttpURLConnection.HTTP_OK, template) + .once(); + OpenShiftClient client = server.getOpenshiftClient(); + + // When + template = client.templates().inNamespace("ns1").createOrReplace(template); + + // Then + assertNotNull(template); + } + + private TemplateBuilder getTemplateBuilder() { + Pod pod = new PodBuilder() + .withNewMetadata().withName("redis-master").endMetadata() + .withNewSpec() + .addNewContainer() + .addNewEnv().withName("REDIS_PASSWORD").withValue("${REDIS_PASSWORD}").endEnv() + .withImage("dockerfile/redis") + .addNewPort() + .withContainerPort(6379) + .withProtocol("TCP") + .endPort() + .endContainer() + .endSpec() + .build(); + return new TemplateBuilder() + .withNewMetadata() + .withName("redis-template") + .addToAnnotations("description", "Description") + .addToAnnotations("iconClass", "icon-redis") + .addToAnnotations("tags", "database,nosql") + .endMetadata() + .addToObjects(pod) + .addNewParameter() + .withDescription("Password used for Redis authentication") + .withFrom("[A-Z0-9]{8}") + .withGenerate("expression") + .withName("REDIS_PASSWORD") + .endParameter() + .addToLabels("redis", "master"); + } + }