From 6a3f8dc459476e70cec175a65bbd6683a9a8bbf8 Mon Sep 17 00:00:00 2001 From: Marc Nuri Date: Fri, 29 Nov 2024 09:39:50 +0100 Subject: [PATCH] DONT MERGE Signed-off-by: Marc Nuri --- .jenkins/pipelines/java-8.Jenkinsfile | 2 +- gradle-plugin/kubernetes/pom.xml | 2 +- gradle-plugin/openshift/pom.xml | 2 +- .../service/docker/RegistryServicePullIT.java | 2 +- .../service/docker/RegistryServicePushIT.java | 2 +- jkube-kit/common/pom.xml | 11 +- .../kit/common/util/KubernetesHelper.java | 2 +- .../kit/common/util/OpenshiftHelper.java | 14 +- .../validator/IgnorePortValidationRule.java | 19 +-- .../IgnoreResourceMemoryLimitRule.java | 30 ---- .../util/validator/ResourceValidator.java | 106 +++--------- .../common/util/validator/ValidationRule.java | 8 +- .../util/validator/ResourceValidatorTest.java | 55 +++---- .../util/validator/valid-deployment.yml | 110 +++++++++++++ jkube-kit/config/resource/pom.xml | 2 +- jkube-kit/config/service/pom.xml | 2 +- .../kit/config/service/DebugServiceTest.java | 7 +- .../kit/config/service/PodLogServiceTest.java | 150 +++++++++++------ .../PortForwardServicePortOrderTest.java | 2 +- .../openshift/OpenShiftBuildServiceTest.java | 2 +- .../OpenshiftBuildServiceIntegrationTest.java | 2 +- .../openshift/WebServerEventCollector.java | 4 +- .../enricher/generic/DependencyEnricher.java | 20 ++- .../enricher/generic/IngressEnricher.java | 9 +- .../ExtensionsV1beta1IngressConverter.java | 153 ------------------ ...ExtensionsV1Beta1IngressConverterTest.java | 121 -------------- jkube-kit/helm/pom.xml | 2 +- .../jkube/kit/resource/helm/HelmService.java | 9 +- .../resource/helm/oci/OCIRegistryClient.java | 21 ++- .../kit/resource/helm/HelmServiceTestIT.java | 2 +- .../resource/helm/HelmServiceUploadIT.java | 6 +- .../helm/TestMockResponseProvider.java | 6 +- .../helm/oci/OCIRegistryClientTest.java | 6 +- .../helm/oci/OCIRegistryInterceptorTest.java | 2 +- jkube-kit/jkube-kit-spring-boot/pom.xml | 2 +- jkube-kit/parent/pom.xml | 54 ++----- jkube-kit/remote-dev/pom.xml | 2 +- .../jkube/kit/resource/service/WriteUtil.java | 12 +- kubernetes-maven-plugin/plugin/pom.xml | 2 +- openshift-maven-plugin/plugin/pom.xml | 2 +- pom.xml | 12 +- 41 files changed, 375 insertions(+), 604 deletions(-) delete mode 100644 jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/validator/IgnoreResourceMemoryLimitRule.java create mode 100644 jkube-kit/common/src/test/resources/util/validator/valid-deployment.yml delete mode 100644 jkube-kit/enricher/generic/src/main/java/org/eclipse/jkube/enricher/generic/ingress/ExtensionsV1beta1IngressConverter.java delete mode 100644 jkube-kit/enricher/generic/src/test/java/org/eclipse/jkube/enricher/generic/ingress/ExtensionsV1Beta1IngressConverterTest.java diff --git a/.jenkins/pipelines/java-8.Jenkinsfile b/.jenkins/pipelines/java-8.Jenkinsfile index bb6ade18d8..93bf037513 100644 --- a/.jenkins/pipelines/java-8.Jenkinsfile +++ b/.jenkins/pipelines/java-8.Jenkinsfile @@ -5,7 +5,7 @@ pipeline { tools { maven 'apache-maven-latest' // https://wiki.eclipse.org/Jenkins#JDK - jdk 'temurin-jdk8-latest' + jdk 'temurin-jdk11-latest' } options { disableConcurrentBuilds(abortPrevious: true) diff --git a/gradle-plugin/kubernetes/pom.xml b/gradle-plugin/kubernetes/pom.xml index 4c2a621ff1..dba4580794 100644 --- a/gradle-plugin/kubernetes/pom.xml +++ b/gradle-plugin/kubernetes/pom.xml @@ -182,7 +182,7 @@ io.fabric8 - openshift-server-mock + kubernetes-server-mock org.junit.jupiter diff --git a/gradle-plugin/openshift/pom.xml b/gradle-plugin/openshift/pom.xml index e852cf3bc0..9bce62b382 100644 --- a/gradle-plugin/openshift/pom.xml +++ b/gradle-plugin/openshift/pom.xml @@ -79,7 +79,7 @@ io.fabric8 - openshift-server-mock + kubernetes-server-mock org.junit.jupiter diff --git a/jkube-kit/build/service/docker/src/test/java/org/eclipse/jkube/kit/build/service/docker/RegistryServicePullIT.java b/jkube-kit/build/service/docker/src/test/java/org/eclipse/jkube/kit/build/service/docker/RegistryServicePullIT.java index 629d3ef62c..8ad77e3aff 100644 --- a/jkube-kit/build/service/docker/src/test/java/org/eclipse/jkube/kit/build/service/docker/RegistryServicePullIT.java +++ b/jkube-kit/build/service/docker/src/test/java/org/eclipse/jkube/kit/build/service/docker/RegistryServicePullIT.java @@ -224,7 +224,7 @@ void pullImageWithPolicy_whenPullFailure_thenThrowException() throws IOException // When assertThatExceptionOfType(DockerAccessException.class) .isThrownBy(() -> registryService.pullImageWithPolicy("example.org/foo/bar:latest", imagePullManager, registryConfig, buildConfiguration)) - .withMessage("Unable to pull 'example.org/foo/bar:latest' from registry 'example.org' : {\"message\":\"ERROR\"} (Server Error: 500)"); + .withMessage("Unable to pull 'example.org/foo/bar:latest' from registry 'example.org' : {\"message\":\"ERROR\"} (Internal Server Error: 500)"); } private RegistryConfig createNewRegistryConfig(String registry) { diff --git a/jkube-kit/build/service/docker/src/test/java/org/eclipse/jkube/kit/build/service/docker/RegistryServicePushIT.java b/jkube-kit/build/service/docker/src/test/java/org/eclipse/jkube/kit/build/service/docker/RegistryServicePushIT.java index 288c68d380..76d692fc07 100644 --- a/jkube-kit/build/service/docker/src/test/java/org/eclipse/jkube/kit/build/service/docker/RegistryServicePushIT.java +++ b/jkube-kit/build/service/docker/src/test/java/org/eclipse/jkube/kit/build/service/docker/RegistryServicePushIT.java @@ -222,7 +222,7 @@ void pushImage_whenPushFailed_thenThrowException() throws IOException { // When assertThatExceptionOfType(DockerAccessException.class) .isThrownBy(() -> registryService.pushImage(imageConfiguration, 0, registryConfig, false)) - .withMessage("Unable to push 'example.org/foo/bar:latest' to registry 'example.org' : {\"message\":\"ERROR\"} (Server Error: 500)"); + .withMessage("Unable to push 'example.org/foo/bar:latest' to registry 'example.org' : {\"message\":\"ERROR\"} (Internal Server Error: 500)"); } @Test diff --git a/jkube-kit/common/pom.xml b/jkube-kit/common/pom.xml index 9def9d7b7e..ca3a3e086b 100644 --- a/jkube-kit/common/pom.xml +++ b/jkube-kit/common/pom.xml @@ -40,6 +40,11 @@ openshift-client + + io.fabric8 + kubernetes-model-validator + + org.apache.commons commons-lang3 @@ -133,7 +138,7 @@ io.fabric8 - openshift-server-mock + kubernetes-server-mock org.mockito @@ -143,10 +148,6 @@ org.assertj assertj-core - - com.networknt - json-schema-validator - com.marcnuri.helm-java helm-java diff --git a/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/KubernetesHelper.java b/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/KubernetesHelper.java index 4cfdfe210c..a2b6a77360 100644 --- a/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/KubernetesHelper.java +++ b/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/KubernetesHelper.java @@ -840,7 +840,7 @@ public static Path exportKubernetesClientConfigToFile(io.fabric8.kubernetes.clie kubeConfigBuilder.addToContexts(kubernetesClientConfig.getCurrentContext()); kubeConfigBuilder.withCurrentContext(kubernetesClientConfig.getCurrentContext().getName()); kubeConfigBuilder.addToUsers(createKubeConfigUserFromClient(kubernetesClientConfig)); - KubeConfigUtils.persistKubeConfigIntoFile(kubeConfigBuilder.build(), targetKubeConfig.toString()); + KubeConfigUtils.persistKubeConfigIntoFile(kubeConfigBuilder.build(), targetKubeConfig.toFile()); return targetKubeConfig; } catch (IOException ioException) { throw new JKubeException("Failure in exporting KubernetesClient config : " + ioException.getMessage()); diff --git a/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/OpenshiftHelper.java b/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/OpenshiftHelper.java index 850e326fb7..2e4e220f6d 100644 --- a/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/OpenshiftHelper.java +++ b/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/OpenshiftHelper.java @@ -17,6 +17,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import io.fabric8.kubernetes.api.model.HasMetadata; @@ -53,7 +54,7 @@ public static boolean isOpenShift(KubernetesClient client) { public static KubernetesList processTemplatesLocally(Template entity, boolean failOnMissingParameterValue) { - List objects = null; + List objects = null; if (entity != null) { objects = entity.getObjects(); if (objects == null || objects.isEmpty()) { @@ -86,7 +87,8 @@ public static KubernetesList processTemplatesLocally(Template entity, boolean fa return Serialization.unmarshal(json, KubernetesList.class); } else { KubernetesList answer = new KubernetesList(); - answer.setItems(objects); + Objects.requireNonNull(objects).stream().filter(o -> o instanceof HasMetadata) + .forEach(o -> answer.getItems().add((HasMetadata) o)); return answer; } } @@ -109,9 +111,9 @@ public static boolean isFinished(String status) { } public static Template combineTemplates(Template firstTemplate, Template template) { - List objects = template.getObjects(); + List objects = template.getObjects(); if (objects != null) { - for (HasMetadata object : objects) { + for (Object object : objects) { addTemplateObject(firstTemplate, object); } } @@ -156,8 +158,8 @@ private static void combineParameters(List parameters, List objects = template.getObjects(); + private static void addTemplateObject(Template template, Object object) { + List objects = template.getObjects(); objects.add(object); template.setObjects(objects); } diff --git a/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/validator/IgnorePortValidationRule.java b/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/validator/IgnorePortValidationRule.java index 7219a33f0d..601d6876e5 100644 --- a/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/validator/IgnorePortValidationRule.java +++ b/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/validator/IgnorePortValidationRule.java @@ -13,7 +13,7 @@ */ package org.eclipse.jkube.kit.common.util.validator; -import com.networknt.schema.ValidationMessage; +import io.fabric8.kubernetes.schema.validator.ValidationMessage; /** * Model to represent ignore validation rules as tuple of json tree path and constraint ruleType @@ -21,19 +21,10 @@ */ public class IgnorePortValidationRule implements ValidationRule { - private final String ruleType; - - public IgnorePortValidationRule(String aRuleType) { - this.ruleType = aRuleType; - } - - public String getType() { - return ruleType; - } - @Override - public boolean ignore(ValidationMessage msg) { - return msg.getType().equalsIgnoreCase(TYPE) && - msg.getMessage().contains(": integer found, object expected"); + public boolean ignore(ValidationMessage validationMessage) { + return validationMessage.getLevel() == ValidationMessage.Level.ERROR && + (validationMessage.getSchema() != null && validationMessage.getSchema().endsWith("/io.k8s.apimachinery.pkg.util.intstr.IntOrString")) && + validationMessage.getMessage().matches(".+/(targetPort|port)'] Instance type \\(integer\\) does not match any allowed primitive type \\(allowed: \\[\\\"string\\\"\\]\\)$"); } } diff --git a/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/validator/IgnoreResourceMemoryLimitRule.java b/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/validator/IgnoreResourceMemoryLimitRule.java deleted file mode 100644 index 7d87cfd5d8..0000000000 --- a/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/validator/IgnoreResourceMemoryLimitRule.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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.common.util.validator; - -import com.networknt.schema.ValidationMessage; - -public class IgnoreResourceMemoryLimitRule implements ValidationRule { - private final String ruleType; - - public IgnoreResourceMemoryLimitRule(String aRuleType) { this.ruleType = aRuleType; } - - public String getType() { return ruleType; } - - @Override - public boolean ignore(ValidationMessage aValidationMsg) { - return aValidationMsg.getType().equalsIgnoreCase(TYPE) - && aValidationMsg.getMessage().contains("string found, object expected"); - } -} diff --git a/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/validator/ResourceValidator.java b/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/validator/ResourceValidator.java index e7a89a1804..3a8c49c5f0 100644 --- a/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/validator/ResourceValidator.java +++ b/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/validator/ResourceValidator.java @@ -14,12 +14,11 @@ package org.eclipse.jkube.kit.common.util.validator; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; -import java.net.URL; +import java.nio.file.Files; import java.util.ArrayList; -import java.util.Collections; +import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -29,20 +28,15 @@ import javax.validation.Path; import javax.validation.metadata.ConstraintDescriptor; +import io.fabric8.kubernetes.schema.validator.ValidationMessage; +import io.fabric8.kubernetes.schema.validator.ValidationReport; +import io.fabric8.kubernetes.schema.validator.Validator; import org.eclipse.jkube.kit.common.KitLogger; import org.eclipse.jkube.kit.common.util.ResourceClassifier; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; -import com.google.gson.JsonIOException; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import com.networknt.schema.JsonMetaSchema; -import com.networknt.schema.JsonSchema; -import com.networknt.schema.JsonSchemaFactory; -import com.networknt.schema.NonValidationKeyword; -import com.networknt.schema.ValidationMessage; /** * Validates Kubernetes/OpenShift resource descriptors using JSON schema validation method. @@ -51,10 +45,8 @@ public class ResourceValidator { - public static final String SCHEMA_JSON = "schema/validation-schema.json"; private KitLogger log; private final File[] resources; - private ResourceClassifier target = ResourceClassifier.KUBERNETES; private final List ignoreValidationRules = new ArrayList<>(); /** @@ -66,6 +58,7 @@ public ResourceValidator(File inputFile) { } else { resources = new File[]{inputFile}; } + setupIgnoreRules(); } /** @@ -75,9 +68,7 @@ public ResourceValidator(File inputFile) { */ public ResourceValidator(File inputFile, ResourceClassifier target, KitLogger log) { this(inputFile); - this.target = target; this.log = log; - setupIgnoreRules(this.target); } /* @@ -86,9 +77,8 @@ public ResourceValidator(File inputFile, ResourceClassifier target, KitLogger lo * e.g. In DeploymentConfig(https://docs.openshift.com/container-platform/3.6/rest_api/openshift_v1.html#v1-deploymentconfig) model 'status' field is marked as * required. */ - private void setupIgnoreRules(ResourceClassifier target) { - ignoreValidationRules.add(new IgnorePortValidationRule(ValidationRule.TYPE)); - ignoreValidationRules.add(new IgnoreResourceMemoryLimitRule(ValidationRule.TYPE)); + private void setupIgnoreRules() { + ignoreValidationRules.add(new IgnorePortValidationRule()); } @@ -102,29 +92,27 @@ private void setupIgnoreRules(ResourceClassifier target) { * @throws IOException IOException */ public int validate() throws IOException { + final Validator validator = Validator.newInstance(); for(File resource: resources) { if (resource.isFile() && resource.exists()) { log.info("validating %s resource", resource.toString()); JsonNode inputSpecNode = geFileContent(resource); - String kind = inputSpecNode.get("kind").toString(); - for (URL schemaFile : Collections.list(ResourceValidator.class.getClassLoader().getResources(SCHEMA_JSON))) { - JsonSchema schema = getJsonSchema(schemaFile, kind); - Set errors = schema.validate(inputSpecNode); - processErrors(errors, resource); + final ValidationReport report = validator.validate(inputSpecNode); + if (report.hasErrors()) { + processErrors(report.getMessages(), resource); } } } - return resources.length; } - private void processErrors(Set errors, File resource) { - Set constraintViolations = new HashSet<>(); + private void processErrors(Collection errors, File resource) { + final Set constraintViolations = new HashSet<>(); for (ValidationMessage errorMsg: errors) { - if(!ignoreError(errorMsg)) + if (!ignoreError(errorMsg)) { constraintViolations.add(new ConstraintViolationImpl(errorMsg)); + } } - if(!constraintViolations.isEmpty()) { throw new ConstraintViolationException(getErrorMessage(resource, constraintViolations), constraintViolations); } @@ -153,61 +141,13 @@ private String getErrorMessage(File resource, Set viola return validationError.toString(); } - private JsonSchema getJsonSchema(URL schemaUrl, String kind) throws IOException { - final JsonMetaSchema v7 = JsonMetaSchema.getV7(); - final String defaultUri = v7.getIri(); - JsonObject jsonSchema = fixUrlIfUnversioned(getSchemaJson(schemaUrl), defaultUri); - checkIfKindPropertyExists(kind); - getResourceProperties(kind, jsonSchema); - final JsonMetaSchema metaSchema = JsonMetaSchema.builder(v7.getIri(), v7) - .keywords(createNonValidationKeywordList()) - .build(); - return new JsonSchemaFactory.Builder() - .defaultMetaSchemaIri(defaultUri).metaSchema(metaSchema).build() - .getSchema(jsonSchema.toString()); - } - - private void getResourceProperties(String kind, JsonObject jsonSchema) { - String kindKey = kind.replaceAll("\"", "").toLowerCase(); - if (jsonSchema.get("resources") != null && jsonSchema.get("resources").getAsJsonObject().get(kindKey) != null) { - jsonSchema.add("properties" , jsonSchema.get("resources").getAsJsonObject() - .getAsJsonObject(kindKey) - .getAsJsonObject("properties")); - } - } - - private void checkIfKindPropertyExists(String kind) { - if(kind == null) { - throw new JsonIOException("Invalid kind of resource or 'kind' is missing from resource definition"); - } - } - private JsonNode geFileContent(File file) throws IOException { - try (InputStream resourceStream = new FileInputStream(file)) { + try (InputStream resourceStream = Files.newInputStream(file.toPath())) { ObjectMapper jsonMapper = new ObjectMapper(new YAMLFactory()); return jsonMapper.readTree(resourceStream); } } - public JsonObject getSchemaJson(URL schemaUrl) throws IOException { - ObjectMapper objectMapper = new ObjectMapper(); - String rootNode = objectMapper.readValue(schemaUrl, JsonNode.class).toString(); - JsonObject jsonObject = new JsonParser().parse(rootNode).getAsJsonObject(); - jsonObject.remove("id"); - return jsonObject; - } - - static List createNonValidationKeywordList() { - List nonValidationKeywords = new ArrayList<>(); - nonValidationKeywords.add(new NonValidationKeyword("javaType")); - nonValidationKeywords.add(new NonValidationKeyword("javaInterfaces")); - nonValidationKeywords.add(new NonValidationKeyword("resources")); - nonValidationKeywords.add(new NonValidationKeyword("javaOmitEmpty")); - nonValidationKeywords.add(new NonValidationKeyword("existingJavaType")); - nonValidationKeywords.add(new NonValidationKeyword("$module")); - return nonValidationKeywords; - } - private static class ConstraintViolationImpl implements ConstraintViolation { private final ValidationMessage errorMsg; @@ -273,18 +213,8 @@ public U unwrap(Class aClass) { @Override public String toString() { - return "[message=" + getMessage().replaceFirst("[$]", "") +", violation type="+errorMsg.getType()+"]"; - } - } - - private static JsonObject fixUrlIfUnversioned(JsonObject jsonSchema, String versionedUri) { - final String uri = jsonSchema.get("$schema").getAsString(); - if (uri.matches("^https?://json-schema.org/draft-05/schema[^/]*$")) { - final JsonObject ret = jsonSchema.deepCopy(); - ret.addProperty("$schema", versionedUri); - return ret; + return "[message=" + getMessage().replaceFirst("[$]", "") +", violation type="+errorMsg.getLevel().name()+"]"; } - return jsonSchema; } } diff --git a/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/validator/ValidationRule.java b/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/validator/ValidationRule.java index b54f253f0f..446e8a82b2 100644 --- a/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/validator/ValidationRule.java +++ b/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/validator/ValidationRule.java @@ -13,13 +13,9 @@ */ package org.eclipse.jkube.kit.common.util.validator; -import com.networknt.schema.ValidationMessage; -/** - * Created by hshinde on 9/23/17. - */ -public interface ValidationRule { - String TYPE = "type"; +import io.fabric8.kubernetes.schema.validator.ValidationMessage; +public interface ValidationRule { boolean ignore(ValidationMessage msg); } diff --git a/jkube-kit/common/src/test/java/org/eclipse/jkube/kit/common/util/validator/ResourceValidatorTest.java b/jkube-kit/common/src/test/java/org/eclipse/jkube/kit/common/util/validator/ResourceValidatorTest.java index bd84cfe6e7..afaff03b10 100644 --- a/jkube-kit/common/src/test/java/org/eclipse/jkube/kit/common/util/validator/ResourceValidatorTest.java +++ b/jkube-kit/common/src/test/java/org/eclipse/jkube/kit/common/util/validator/ResourceValidatorTest.java @@ -14,9 +14,7 @@ package org.eclipse.jkube.kit.common.util.validator; -import com.networknt.schema.AbstractKeyword; -import com.networknt.schema.NonValidationKeyword; -import org.assertj.core.api.Condition; +import org.assertj.core.api.InstanceOfAssertFactories; import org.eclipse.jkube.kit.common.KitLogger; import org.eclipse.jkube.kit.common.util.ResourceClassifier; import org.junit.jupiter.api.BeforeEach; @@ -25,7 +23,6 @@ import javax.validation.ConstraintViolation; import javax.validation.ConstraintViolationException; import java.nio.file.Paths; -import java.util.List; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -39,7 +36,7 @@ public void setUp() { } @Test - void validateWithValidResource() throws Exception { + void validateWithValidService() throws Exception { // Given final ResourceValidator validator = new ResourceValidator( Paths.get(ResourceValidatorTest.class.getResource("/util/validator/valid-service.yml").toURI()).toFile(), @@ -52,6 +49,20 @@ void validateWithValidResource() throws Exception { assertThat(result).isEqualTo(1); } + @Test + void validateWithValidDeployment() throws Exception { + // Given + final ResourceValidator validator = new ResourceValidator( + Paths.get(ResourceValidatorTest.class.getResource("/util/validator/valid-deployment.yml").toURI()).toFile(), + ResourceClassifier.KUBERNETES, + logger + ); + // When + final int result = validator.validate(); + // Then + assertThat(result).isEqualTo(1); + } + @Test void validateWithInvalidResource() throws Exception { // Given @@ -66,35 +77,9 @@ void validateWithInvalidResource() throws Exception { assertThat(result).isNotNull() .hasMessageStartingWith("Invalid Resource :") .hasMessageContaining("invalid-deployment.yml") - .has(new HasErrMessage("$.spec.replicas: string found, integer expected")); - } - - @Test - void createNonValidationKeywordList_whenInvoked_shouldReturnNonValidationKeywordList() { - // Given + When - List nonValidationKeywordList = ResourceValidator.createNonValidationKeywordList(); - - // Then - assertThat(nonValidationKeywordList) - .extracting(AbstractKeyword::getValue) - .containsExactlyInAnyOrder("javaType", "javaInterfaces", "resources", "javaOmitEmpty", "existingJavaType", "$module"); - } - - private static final class HasErrMessage extends Condition { - - private final String message; - - private HasErrMessage(String message) { - this.message = message; - } - - @Override - public boolean matches(Throwable value) { - if (value instanceof ConstraintViolationException) { - final ConstraintViolationException ex = (ConstraintViolationException)value; - return ex.getConstraintViolations().stream().map(ConstraintViolation::getMessage).anyMatch(m -> m.equals(message)); - } - return false; - } + .extracting(ConstraintViolationException::getConstraintViolations) + .asInstanceOf(InstanceOfAssertFactories.set(ConstraintViolation.class)) + .extracting("message") + .contains("[Path '/spec/replicas'] Instance type (string) does not match any allowed primitive type (allowed: [\"integer\"])"); } } diff --git a/jkube-kit/common/src/test/resources/util/validator/valid-deployment.yml b/jkube-kit/common/src/test/resources/util/validator/valid-deployment.yml new file mode 100644 index 0000000000..f999346fd4 --- /dev/null +++ b/jkube-kit/common/src/test/resources/util/validator/valid-deployment.yml @@ -0,0 +1,110 @@ +# +# 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 +# + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + annotations: + jkube.eclipse.org/git-url: git@github.com:manusa/jkube.git + jkube.eclipse.org/git-commit: 082bc465b1e51433bfc14065b440ad8cf4a0b7c2 + jkube.eclipse.org/git-branch: master + jkube.eclipse.org/scm-url: https://github.com/spring-projects/spring-boot/spring-boot-starter-parent/external-resources + jkube.eclipse.org/scm-tag: HEAD + labels: + app: external-resources + provider: jkube + version: 1.33.7 + group: org.eclipse.jkube.quickstarts.maven + name: external-resources +spec: + replicas: 13373 + revisionHistoryLimit: 2 + selector: + matchLabels: + app: external-resources + provider: jkube + group: org.eclipse.jkube.quickstarts.maven + template: + metadata: + annotations: + jkube.eclipse.org/scm-url: https://github.com/spring-projects/spring-boot/spring-boot-starter-parent/external-resources + jkube.eclipse.org/git-url: git@github.com:manusa/jkube.git + jkube.eclipse.org/scm-tag: HEAD + jkube.eclipse.org/git-commit: 082bc465b1e51433bfc14065b440ad8cf4a0b7c2 + jkube.eclipse.org/git-branch: master + labels: + app: external-resources + provider: jkube + version: 1.33.7 + group: org.eclipse.jkube.quickstarts.maven + spec: + containers: + - env: + - name: KUBERNETES_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: HOSTNAME + valueFrom: + fieldRef: + fieldPath: metadata.name + image: maven/external-resources:latest + imagePullPolicy: IfNotPresent + livenessProbe: + failureThreshold: 3 + httpGet: + path: /actuator/health + port: 8080 + scheme: HTTP + initialDelaySeconds: 180 + successThreshold: 1 + name: spring-boot + ports: + - containerPort: 8080 + name: http + protocol: TCP + - containerPort: 9779 + name: prometheus + protocol: TCP + - containerPort: 8778 + name: jolokia + protocol: TCP + readinessProbe: + failureThreshold: 3 + httpGet: + path: /actuator/health + port: 8080 + scheme: HTTP + initialDelaySeconds: 10 + successThreshold: 1 + resources: + limits: + cpu: 500m + memory: 512Mi + requests: + cpu: 200m + memory: 256Mi + securityContext: + privileged: false + volumeMounts: + - mountPath: /deployments/config + name: config + volumes: + - configMap: + items: + - key: application.properties + path: application.properties + name: external-resources + name: config diff --git a/jkube-kit/config/resource/pom.xml b/jkube-kit/config/resource/pom.xml index 6c002ffeea..e47518be32 100644 --- a/jkube-kit/config/resource/pom.xml +++ b/jkube-kit/config/resource/pom.xml @@ -55,7 +55,7 @@ io.fabric8 - openshift-server-mock + kubernetes-server-mock org.mockito diff --git a/jkube-kit/config/service/pom.xml b/jkube-kit/config/service/pom.xml index cc7ebbcef5..6f3d73c673 100644 --- a/jkube-kit/config/service/pom.xml +++ b/jkube-kit/config/service/pom.xml @@ -76,7 +76,7 @@ io.fabric8 - openshift-server-mock + kubernetes-server-mock org.mockito diff --git a/jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/DebugServiceTest.java b/jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/DebugServiceTest.java index 1a7771f26b..91a56b6eca 100644 --- a/jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/DebugServiceTest.java +++ b/jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/DebugServiceTest.java @@ -39,12 +39,13 @@ import io.fabric8.kubernetes.client.dsl.NonDeletingOperation; import io.fabric8.kubernetes.client.server.mock.EnableKubernetesMockClient; import io.fabric8.kubernetes.client.server.mock.KubernetesMockServer; +import io.fabric8.mockwebserver.http.RecordedRequest; import io.fabric8.openshift.api.model.DeploymentConfig; import io.fabric8.openshift.api.model.DeploymentConfigBuilder; import io.fabric8.openshift.api.model.DeploymentConfigSpecBuilder; import io.fabric8.openshift.client.OpenShiftClient; import io.fabric8.zjsonpatch.JsonPatch; -import okhttp3.mockwebserver.RecordedRequest; +import io.vertx.core.Vertx; import org.assertj.core.api.InstanceOfAssertFactories; import org.assertj.core.groups.Tuple; import org.eclipse.jkube.kit.common.JKubeConfiguration; @@ -388,7 +389,7 @@ private Deployment withDeploymentRollout(Deployment deployment) { JsonPatch.apply(Serialization.unmarshal(r.getBody().inputStream(), JsonNode.class), Serialization.convertValue(deployment, JsonNode.class)), Deployment.class); - kubernetesClient.resource(new PodBuilder() + Vertx.currentContext().executeBlocking(() -> kubernetesClient.resource(new PodBuilder() .withMetadata(new ObjectMetaBuilder(d.getSpec().getTemplate().getMetadata()) .withName("pod-in-debug-mode") .build()) @@ -396,7 +397,7 @@ private Deployment withDeploymentRollout(Deployment deployment) { .withStatus(new PodStatusBuilder() .withPhase("Running") .build()) - .build()).create(); + .build()).create()); return d; }) .always(); diff --git a/jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/PodLogServiceTest.java b/jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/PodLogServiceTest.java index 1ec12dbe35..5cabe55f41 100644 --- a/jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/PodLogServiceTest.java +++ b/jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/PodLogServiceTest.java @@ -14,7 +14,6 @@ package org.eclipse.jkube.kit.config.service; import io.fabric8.kubernetes.api.model.HasMetadata; -import io.fabric8.kubernetes.api.model.LabelSelector; import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; import io.fabric8.kubernetes.api.model.Pod; import io.fabric8.kubernetes.api.model.PodBuilder; @@ -26,29 +25,29 @@ import io.fabric8.kubernetes.client.server.mock.EnableKubernetesMockClient; import io.fabric8.kubernetes.client.server.mock.KubernetesMockServer; import org.eclipse.jkube.kit.common.KitLogger; +import org.eclipse.jkube.kit.common.util.AsyncUtil; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; import java.util.Collection; import java.util.Collections; +import java.util.concurrent.TimeUnit; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.timeout; -import static org.mockito.Mockito.verify; +import static org.assertj.core.api.Assertions.assertThat; @EnableKubernetesMockClient(crud = true) class PodLogServiceTest { KubernetesMockServer kubernetesMockServer; KubernetesClient kubernetesClient; - private KitLogger log; - private KitLogger oldPodLog; - private KitLogger newPodLog; + private ByteArrayOutputStream out; + private ByteArrayOutputStream oldPodOut; + private ByteArrayOutputStream newPodOut; private PodLogService.PodLogServiceContext podLogServiceContext; private Collection entities; @@ -56,13 +55,13 @@ class PodLogServiceTest { @BeforeEach void setUp() { - log = spy(new KitLogger.SilentLogger()); - oldPodLog = spy(new KitLogger.SilentLogger()); - newPodLog = spy(new KitLogger.SilentLogger()); + out = new ByteArrayOutputStream(); + oldPodOut = new ByteArrayOutputStream(); + newPodOut = new ByteArrayOutputStream(); podLogServiceContext = PodLogService.PodLogServiceContext.builder() - .log(log) - .oldPodLog(oldPodLog) - .newPodLog(newPodLog) + .log(new KitLogger.PrintStreamLogger(new PrintStream(out))) + .oldPodLog(new KitLogger.PrintStreamLogger(new PrintStream(oldPodOut))) + .newPodLog(new KitLogger.PrintStreamLogger(new PrintStream(newPodOut))) .build(); // Create a Deployment to use as the source of the Selector final Deployment deployment = kubernetesClient.resource(new DeploymentBuilder() @@ -90,8 +89,9 @@ void setUp() { void shouldLogSelector() { new PodLogService(podLogServiceContext) .tailAppPodsLogs(kubernetesClient, null, entities, false, null, true, null, false); - verify(log, timeout(1000)) - .info(eq("Watching pods with selector %s waiting for a running pod..."), any(LabelSelector.class)); + assertThat(AsyncUtil.await(out::toString).apply(o -> o.contains("[INFO] Watching pods with selector LabelSelector("))) + .succeedsWithin(1, TimeUnit.SECONDS).asString() + .contains(") waiting for a running pod...\n"); } @Test @@ -99,8 +99,9 @@ void shouldLogSelector() { void shouldLogName() { new PodLogService(podLogServiceContext.toBuilder().podName("the-pod").build()) .tailAppPodsLogs(kubernetesClient, null, entities, false, null, true, null, false); - verify(log, timeout(1000)) - .info(eq("Watching pod with selector %s, and name %s waiting for a running pod..."), any(LabelSelector.class), eq("the-pod")); + assertThat(AsyncUtil.await(out::toString).apply(o -> o.contains("[INFO] Watching pod with selector LabelSelector("))) + .succeedsWithin(1, TimeUnit.SECONDS).asString() + .contains("), and name the-pod waiting for a running pod...\n"); } @Test @@ -108,10 +109,12 @@ void shouldLogName() { void noPodShouldWarnUser() { new PodLogService(podLogServiceContext) .tailAppPodsLogs(kubernetesClient, null, entities, false, null, true, null, false); - verify(log, timeout(1000)) - .warn("No pod is running yet. Are you sure you deployed your app using Eclipse JKube apply/deploy mechanism?"); - verify(log, timeout(1000)) - .warn("Or did you undeploy it? If so try running the Eclipse JKube apply/deploy tasks again."); + assertThat(AsyncUtil.await(out::toString).apply(o -> o.contains("No pod is running yet"))) + .succeedsWithin(1, TimeUnit.SECONDS).asString() + .containsSubsequence( + "[WARN] No pod is running yet. Are you sure you deployed your app using Eclipse JKube apply/deploy mechanism?\n", + "[WARN] Or did you undeploy it? If so try running the Eclipse JKube apply/deploy tasks again.\n" + ); } @DisplayName("With Pod running and mismatched container, should error") @@ -130,8 +133,11 @@ void podRunningNoContainer(boolean follow) { new PodLogService(podLogServiceContext.toBuilder().logContainerName("non-existent").build()) .tailAppPodsLogs(kubernetesClient, null, entities, false, null, follow, null, false); // Then - verify(log, timeout(1000)) - .error("log container name %s does not exist in pod!! Did you set the correct value for property 'jkube.log.container'", "non-existent"); + assertThat(AsyncUtil.await(out::toString).apply(o -> o.contains("[ERROR] log container name "))) + .succeedsWithin(1, TimeUnit.SECONDS).asString() + .containsSubsequence( + "[ERROR] log container name non-existent does not exist in pod!! Did you set the correct value for property 'jkube.log.container'\n" + ); } @Test @@ -143,8 +149,9 @@ void podRunningShouldLogControlMessages() { new PodLogService(podLogServiceContext) .tailAppPodsLogs(kubernetesClient, null, entities, false, null, true, null, false); // Then - verify(newPodLog, timeout(1000)).info("Tailing log of pod: the-pod"); - verify(newPodLog, timeout(1000)).info("Press Ctrl-C to stop tailing the log"); + assertThat(AsyncUtil.await(newPodOut::toString).apply(o -> o.contains("[INFO] Tailing log of pod: the-pod\n"))) + .succeedsWithin(1, TimeUnit.SECONDS).asString() + .contains("[INFO] Press Ctrl-C to stop tailing the log\n"); } @Test @@ -156,7 +163,8 @@ void podRunningShouldLogStatusUpdates() { new PodLogService(podLogServiceContext) .tailAppPodsLogs(kubernetesClient, null, entities, false, null, true, null, false); // Then - verify(newPodLog, timeout(1000)).info("%s status: %s%s", "the-pod", "Running ", ""); + assertThat(AsyncUtil.await(newPodOut::toString).apply(o -> o.contains("[INFO] the-pod status: Running \n"))) + .succeedsWithin(1, TimeUnit.SECONDS); } @Test @@ -166,11 +174,13 @@ void podRunningAndDeletionShouldLogStatusUpdates() { kubernetesClient.resource(runningPod).createOr(NonDeletingOperation::update); new PodLogService(podLogServiceContext) .tailAppPodsLogs(kubernetesClient, null, entities, false, null, true, null, false); - verify(newPodLog, timeout(1000)).info("%s status: %s%s", "the-pod", "Running ", ""); + assertThat(AsyncUtil.await(newPodOut::toString).apply(o -> o.contains("[INFO] the-pod status: Running \n"))) + .succeedsWithin(1, TimeUnit.SECONDS); // When kubernetesClient.resource(runningPod).delete(); // Then - verify(oldPodLog, timeout(1000)).info("%s status: %s%s", "the-pod", "Running ", ": Pod Deleted"); + assertThat(AsyncUtil.await(oldPodOut::toString).apply(o -> o.contains("[INFO] the-pod status: Running : Pod Deleted"))) + .succeedsWithin(1, TimeUnit.SECONDS); } @@ -181,11 +191,13 @@ void podRunningAndDeletionShouldClosePreviousWatch() { kubernetesClient.resource(runningPod).createOr(NonDeletingOperation::update); new PodLogService(podLogServiceContext) .tailAppPodsLogs(kubernetesClient, null, entities, false, null, true, null, false); - verify(newPodLog, timeout(1000)).info("%s status: %s%s", "the-pod", "Running ", ""); + assertThat(AsyncUtil.await(newPodOut::toString).apply(o -> o.contains("[INFO] the-pod status: Running \n"))) + .succeedsWithin(1, TimeUnit.SECONDS); // When kubernetesClient.resource(runningPod).delete(); // Then - verify(log, timeout(1000)).info("Closing log watcher for %s (Deleted)", "the-pod"); + assertThat(AsyncUtil.await(out::toString).apply(o -> o.contains("[INFO] Closing log watcher for the-pod (Deleted)"))) + .succeedsWithin(1, TimeUnit.SECONDS); } @Test @@ -195,14 +207,16 @@ void podRunningAndAdditionShouldLogStatusUpdates() { kubernetesClient.resource(runningPod).createOr(NonDeletingOperation::update); new PodLogService(podLogServiceContext) .tailAppPodsLogs(kubernetesClient, null, entities, false, null, true, null, false); - verify(newPodLog, timeout(1000)).info("Tailing log of pod: the-pod"); + assertThat(AsyncUtil.await(newPodOut::toString).apply(o -> o.contains("[INFO] Tailing log of pod: the-pod\n"))) + .succeedsWithin(1, TimeUnit.SECONDS); // When kubernetesClient.resource(new PodBuilder(runningPod).editMetadata() .withName("new-pod") .endMetadata().build()) .createOr(NonDeletingOperation::update); // Then - verify(newPodLog, timeout(1000)).info("%s status: %s%s", "new-pod", "Running ", ""); + assertThat(AsyncUtil.await(newPodOut::toString).apply(o -> o.contains("[INFO] new-pod status: Running \n"))) + .succeedsWithin(1, TimeUnit.SECONDS); } @Test @@ -212,14 +226,19 @@ void podPendingAndThenRunningShouldLogStatusUpdates() { kubernetesClient.resource(new PodBuilder(runningPod).editStatus().withPhase("Pending").endStatus().build()).createOr(NonDeletingOperation::update); new PodLogService(podLogServiceContext) .tailAppPodsLogs(kubernetesClient, null, entities, false, null, true, null, false); - verify(newPodLog, timeout(1000)).info("%s status: %s%s", "the-pod", "Pending ", ""); + assertThat(AsyncUtil.await(newPodOut::toString).apply(o -> o.contains("[INFO] the-pod status: Pending \n"))) + .succeedsWithin(1, TimeUnit.SECONDS); // When kubernetesClient.pods().withName("the-pod") .edit(p -> new PodBuilder(p).editStatus().withPhase("Running").endStatus().build()); // Then - verify(newPodLog, timeout(1000)).info("%s status: %s%s", "the-pod", "Running ", ""); - // Finally (prevents Client from being closed before completing the log execution) - verify(newPodLog, timeout(1000)).info("Tailing log of pod: the-pod"); + assertThat(AsyncUtil.await(newPodOut::toString).apply(o -> o.contains("[INFO] Tailing log of pod: the-pod\n"))) + .succeedsWithin(1, TimeUnit.SECONDS).asString() + .containsSubsequence( + "[INFO] the-pod status: Running \n", + // Finally (prevents Client from being closed before completing the log execution) + "[INFO] Tailing log of pod: the-pod\n" + ); } @Test @@ -236,9 +255,13 @@ void podRunningShouldLogContainerLogs() { new PodLogService(podLogServiceContext) .tailAppPodsLogs(kubernetesClient, null, entities, false, null, true, null, false); // Then - verify(log, timeout(1000)).info("[[s]]%s", "The"); - verify(log, timeout(1000)).info("[[s]]%s", "Application"); - verify(log, timeout(1000)).info("[[s]]%s", "Logs"); + assertThat(AsyncUtil.await(out::toString).apply(o -> o.contains("[INFO] [[s]]Logs"))) + .succeedsWithin(1, TimeUnit.SECONDS).asString() + .containsSubsequence( + "[INFO] [[s]]The\n", + "[INFO] [[s]]Application\n", + "[INFO] [[s]]Logs\n" + ); } @Test @@ -255,9 +278,13 @@ void podRunningWithNoFollowShouldLogContainerLogs() { new PodLogService(podLogServiceContext) .tailAppPodsLogs(kubernetesClient, null, entities, false, null, false, null, false); // Then - verify(log, timeout(1000)).info("[[s]]%s", "The"); - verify(log, timeout(1000)).info("[[s]]%s", "Application"); - verify(log, timeout(1000)).info("[[s]]%s", "Logs"); + assertThat(AsyncUtil.await(out::toString).apply(o -> o.contains("[INFO] [[s]]Logs"))) + .succeedsWithin(1, TimeUnit.SECONDS).asString() + .containsSubsequence( + "[INFO] [[s]]The\n", + "[INFO] [[s]]Application\n", + "[INFO] [[s]]Logs\n" + ); } @Test @@ -274,9 +301,13 @@ void podRunningWithNoFollowInCurrentThreadShouldLogContainerLogs() { new PodLogService(podLogServiceContext) .tailAppPodsLogs(kubernetesClient, null, entities, false, null, false, null, true); // Then - verify(log).info("[[s]]%s", "The"); - verify(log).info("[[s]]%s", "Application"); - verify(log).info("[[s]]%s", "Logs"); + assertThat(AsyncUtil.await(out::toString).apply(o -> o.contains("[INFO] [[s]]Logs"))) + .succeedsWithin(1, TimeUnit.SECONDS).asString() + .containsSubsequence( + "[INFO] [[s]]The\n", + "[INFO] [[s]]Application\n", + "[INFO] [[s]]Logs\n" + ); } @Test @@ -296,32 +327,45 @@ void podRunningAndDeletedShouldClosePreviousWatcher() { .always(); new PodLogService(podLogServiceContext) .tailAppPodsLogs(kubernetesClient, null, entities, false, null, true, null, false); - verify(newPodLog, timeout(1000)).info("Tailing log of pod: the-pod"); + assertThat(AsyncUtil.await(newPodOut::toString).apply(o -> o.contains("Tailing log of pod: the-pod"))) + .succeedsWithin(1000, TimeUnit.SECONDS); kubernetesClient.resource(runningPod).delete(); // When kubernetesClient.resource(new PodBuilder(runningPod).editMetadata().withName("new-pod").endMetadata().build()) .createOr(NonDeletingOperation::update); // Then - verify(log, timeout(1000)).info("Closing log watcher for %s (Deleted)", "the-pod"); + assertThat(AsyncUtil.await(out::toString).apply(o -> o.contains("[INFO] Closing log watcher for the-pod (Deleted)"))) + .succeedsWithin(1, TimeUnit.SECONDS); // Finally (prevents Client from being closed before completing the log execution) - verify(newPodLog, timeout(1000)).info("Tailing log of pod: new-pod"); + assertThat(AsyncUtil.await(newPodOut::toString).apply(o -> o.contains("Tailing log of pod: new-pod"))) + .succeedsWithin(1000, TimeUnit.SECONDS); } @Test @DisplayName("With Pod running and addition, should close previous watch") - void podRunningAndAdditionShouldClosePreviousWatch() { + void podRunningAndAdditionShouldClosePreviousWatch() throws Exception { // Given + // n.b. The precision of the creationTimestamp is to seconds. + // This leads to a problem in case two pods were created rapidly, since the PodLogEventHandler + // will not be able to distinguish between the two pods and the result of mostRecentPod() will be non-deterministic. kubernetesClient.resource(runningPod).createOr(NonDeletingOperation::update); new PodLogService(podLogServiceContext) .tailAppPodsLogs(kubernetesClient, null, entities, false, null, true, null, false); - verify(newPodLog, timeout(1000)).info("Tailing log of pod: the-pod"); + assertThat(AsyncUtil.await(newPodOut::toString).apply(o -> o.contains("[INFO] Tailing log of pod: the-pod"))) + .succeedsWithin(10, TimeUnit.SECONDS); + // TODO: adding one second delay + Thread.sleep(1001); // When kubernetesClient.resource(new PodBuilder(runningPod).editMetadata() .withName("new-pod") .endMetadata().build()) .createOr(NonDeletingOperation::update); // Then - verify(log, timeout(1000)).info("Closing log watcher for %s as now watching %s", "the-pod", "new-pod"); + assertThat(AsyncUtil.await(newPodOut::toString).apply(o -> o.contains("Tailing log of pod: new-pod"))) + .withFailMessage(() -> "Expected Tailing log of pod: new-pod but got " + newPodOut.toString()) + .succeedsWithin(5, TimeUnit.SECONDS); + assertThat(AsyncUtil.await(out::toString).apply(o -> o.contains("[INFO] Closing log watcher for the-pod as now watching new-pod"))) + .succeedsWithin(1, TimeUnit.SECONDS); } } diff --git a/jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/PortForwardServicePortOrderTest.java b/jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/PortForwardServicePortOrderTest.java index 21d03f4821..cca04d2b40 100644 --- a/jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/PortForwardServicePortOrderTest.java +++ b/jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/PortForwardServicePortOrderTest.java @@ -17,7 +17,7 @@ import io.fabric8.kubernetes.client.NamespacedKubernetesClient; import io.fabric8.kubernetes.client.server.mock.EnableKubernetesMockClient; import io.fabric8.kubernetes.client.server.mock.KubernetesMockServer; -import okhttp3.mockwebserver.RecordedRequest; +import io.fabric8.mockwebserver.http.RecordedRequest; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; diff --git a/jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/openshift/OpenShiftBuildServiceTest.java b/jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/openshift/OpenShiftBuildServiceTest.java index 7bb88a84b5..82cc4154fd 100644 --- a/jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/openshift/OpenShiftBuildServiceTest.java +++ b/jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/openshift/OpenShiftBuildServiceTest.java @@ -110,7 +110,7 @@ void push_withValidImage_shouldLogWarning() throws JKubeServiceException { @Test void initClient_withNoOpenShift_shouldThrowException() { // Given - when(jKubeServiceHub.getClient().adapt(OpenShiftClient.class).isSupported()).thenReturn(false); + when(jKubeServiceHub.getClient().hasApiGroup("openshift.io", false)).thenReturn(false); OpenshiftBuildService openshiftBuildService = new OpenshiftBuildService(jKubeServiceHub); // When + Then assertThatIllegalStateException() diff --git a/jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/openshift/OpenshiftBuildServiceIntegrationTest.java b/jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/openshift/OpenshiftBuildServiceIntegrationTest.java index eb5023b9bc..bea416f838 100644 --- a/jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/openshift/OpenshiftBuildServiceIntegrationTest.java +++ b/jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/openshift/OpenshiftBuildServiceIntegrationTest.java @@ -23,6 +23,7 @@ import io.fabric8.kubernetes.client.server.mock.EnableKubernetesMockClient; import io.fabric8.kubernetes.client.server.mock.KubernetesMockServer; +import io.fabric8.mockwebserver.http.RecordedRequest; import io.fabric8.openshift.api.model.ImageStreamTagBuilder; import io.fabric8.openshift.client.OpenShiftClient; import org.apache.commons.io.FileUtils; @@ -63,7 +64,6 @@ import io.fabric8.openshift.api.model.ImageStreamBuilder; import io.fabric8.openshift.api.model.ImageStreamStatusBuilder; import io.fabric8.openshift.api.model.NamedTagEventListBuilder; -import okhttp3.mockwebserver.RecordedRequest; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/openshift/WebServerEventCollector.java b/jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/openshift/WebServerEventCollector.java index 51b4e4eba9..3e33cca8a9 100644 --- a/jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/openshift/WebServerEventCollector.java +++ b/jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/openshift/WebServerEventCollector.java @@ -13,9 +13,9 @@ */ package org.eclipse.jkube.kit.config.service.openshift; +import io.fabric8.mockwebserver.http.Headers; +import io.fabric8.mockwebserver.http.RecordedRequest; import io.fabric8.mockwebserver.utils.ResponseProvider; -import okhttp3.Headers; -import okhttp3.mockwebserver.RecordedRequest; import java.util.ArrayList; import java.util.Arrays; diff --git a/jkube-kit/enricher/generic/src/main/java/org/eclipse/jkube/enricher/generic/DependencyEnricher.java b/jkube-kit/enricher/generic/src/main/java/org/eclipse/jkube/enricher/generic/DependencyEnricher.java index b25d33d02f..b6d49640ae 100644 --- a/jkube-kit/enricher/generic/src/main/java/org/eclipse/jkube/enricher/generic/DependencyEnricher.java +++ b/jkube-kit/enricher/generic/src/main/java/org/eclipse/jkube/enricher/generic/DependencyEnricher.java @@ -141,10 +141,14 @@ private void enrichKubernetes(final KubernetesListBuilder builder) { for (HasMetadata resource : templates) { if (resource instanceof Template) { Template template = (Template) resource; - List objects = template.getObjects(); + List objects = template.getObjects(); if (objects != null) { removeTemplateObjects(kubernetesItems, objects); - kubernetesItems.addAll(objects); + for (Object object : objects) { + if (object instanceof HasMetadata) { + kubernetesItems.add((HasMetadata) object); + } + } } } } @@ -162,12 +166,16 @@ private void enrichOpenShift(final KubernetesListBuilder builder) { filterAndAddItemsToBuilder(builder, openshiftItems); } - private void removeTemplateObjects(List list, List objects) { - for (HasMetadata object : objects) { + private void removeTemplateObjects(List list, List objects) { + for (Object object : objects) { + if (!(object instanceof HasMetadata)) { + continue; + } + HasMetadata hm = (HasMetadata) object; List copy = new ArrayList<>(list); for (HasMetadata resource : copy) { - if (Objects.equals(resource.getKind(), object.getKind()) && - Objects.equals(KubernetesHelper.getName(object), KubernetesHelper.getName(resource))) { + if (Objects.equals(resource.getKind(), hm.getKind()) && + Objects.equals(KubernetesHelper.getName(hm), KubernetesHelper.getName(resource))) { list.remove(resource); } } diff --git a/jkube-kit/enricher/generic/src/main/java/org/eclipse/jkube/enricher/generic/IngressEnricher.java b/jkube-kit/enricher/generic/src/main/java/org/eclipse/jkube/enricher/generic/IngressEnricher.java index 340b9bcd9b..053955e876 100644 --- a/jkube-kit/enricher/generic/src/main/java/org/eclipse/jkube/enricher/generic/IngressEnricher.java +++ b/jkube-kit/enricher/generic/src/main/java/org/eclipse/jkube/enricher/generic/IngressEnricher.java @@ -21,7 +21,6 @@ import lombok.AllArgsConstructor; import lombok.Getter; import org.apache.commons.lang3.StringUtils; -import org.eclipse.jkube.enricher.generic.ingress.ExtensionsV1beta1IngressConverter; import org.eclipse.jkube.enricher.generic.ingress.NetworkingV1IngressGenerator; import org.eclipse.jkube.kit.common.Configs; import org.eclipse.jkube.kit.config.resource.IngressConfig; @@ -95,10 +94,10 @@ private HasMetadata generateIngressWithConfiguredApiVersion(ServiceBuilder servi serviceBuilder, getRouteDomain(), getConfig(Config.HOST), getIngressRuleXMLConfig(resourceConfig), getIngressTlsXMLConfig(resourceConfig)); HasMetadata generatedIngress = ingress; - String targetIngressApiVersion = getConfig(Config.TARGET_API_VERSION); - if (targetIngressApiVersion.equalsIgnoreCase("extensions/v1beta1")) { - generatedIngress = ExtensionsV1beta1IngressConverter.convert(ingress); - } +// String targetIngressApiVersion = getConfig(Config.TARGET_API_VERSION); +// if (targetIngressApiVersion.equalsIgnoreCase("extensions/v1beta1")) { +// generatedIngress = ExtensionsV1beta1IngressConverter.convert(ingress); +// } return generatedIngress; } diff --git a/jkube-kit/enricher/generic/src/main/java/org/eclipse/jkube/enricher/generic/ingress/ExtensionsV1beta1IngressConverter.java b/jkube-kit/enricher/generic/src/main/java/org/eclipse/jkube/enricher/generic/ingress/ExtensionsV1beta1IngressConverter.java deleted file mode 100644 index 748b401a46..0000000000 --- a/jkube-kit/enricher/generic/src/main/java/org/eclipse/jkube/enricher/generic/ingress/ExtensionsV1beta1IngressConverter.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * 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.enricher.generic.ingress; - -import io.fabric8.kubernetes.api.model.IntOrString; -import io.fabric8.kubernetes.api.model.TypedLocalObjectReferenceBuilder; -import io.fabric8.kubernetes.api.model.extensions.HTTPIngressPath; -import io.fabric8.kubernetes.api.model.extensions.HTTPIngressPathBuilder; -import io.fabric8.kubernetes.api.model.extensions.HTTPIngressRuleValue; -import io.fabric8.kubernetes.api.model.extensions.HTTPIngressRuleValueBuilder; -import io.fabric8.kubernetes.api.model.extensions.Ingress; -import io.fabric8.kubernetes.api.model.extensions.IngressBackend; -import io.fabric8.kubernetes.api.model.extensions.IngressBackendBuilder; -import io.fabric8.kubernetes.api.model.extensions.IngressBuilder; -import io.fabric8.kubernetes.api.model.extensions.IngressRule; -import io.fabric8.kubernetes.api.model.extensions.IngressRuleBuilder; -import io.fabric8.kubernetes.api.model.extensions.IngressSpec; -import io.fabric8.kubernetes.api.model.extensions.IngressSpecBuilder; -import io.fabric8.kubernetes.api.model.extensions.IngressTLS; -import io.fabric8.kubernetes.api.model.extensions.IngressTLSBuilder; - -import java.util.ArrayList; -import java.util.List; - -public class ExtensionsV1beta1IngressConverter { - private ExtensionsV1beta1IngressConverter() { } - - public static Ingress convert(io.fabric8.kubernetes.api.model.networking.v1.Ingress networkV1Ingress) { - if (networkV1Ingress == null) { - return null; - } - IngressBuilder extensionsIngressBuilder = new IngressBuilder(); - if (networkV1Ingress.getMetadata() != null) { - extensionsIngressBuilder.withMetadata(networkV1Ingress.getMetadata()); - } - if (networkV1Ingress.getSpec() != null) { - extensionsIngressBuilder.withSpec(convertIngressSpec(networkV1Ingress.getSpec())); - } - - return extensionsIngressBuilder.build(); - } - - private static IngressSpec convertIngressSpec(io.fabric8.kubernetes.api.model.networking.v1.IngressSpec networkV1IngressSpec) { - IngressSpecBuilder extensionIngressSpecBuilder = new IngressSpecBuilder(); - if (networkV1IngressSpec.getIngressClassName() != null) { - extensionIngressSpecBuilder.withIngressClassName(networkV1IngressSpec.getIngressClassName()); - } - if (networkV1IngressSpec.getDefaultBackend() != null) { - extensionIngressSpecBuilder.withBackend(convertIngressBackend(networkV1IngressSpec.getDefaultBackend())); - } - if (networkV1IngressSpec.getTls() != null) { - extensionIngressSpecBuilder.withTls(convertIngressTls(networkV1IngressSpec.getTls())); - } - if (networkV1IngressSpec.getRules() != null) { - extensionIngressSpecBuilder.withRules(convertIngressRules(networkV1IngressSpec.getRules())); - } - return extensionIngressSpecBuilder.build(); - } - - private static IngressBackend convertIngressBackend(io.fabric8.kubernetes.api.model.networking.v1.IngressBackend networkV1IngressBackend) { - IngressBackendBuilder extensionIngressBackendBuilder = new IngressBackendBuilder(); - if (networkV1IngressBackend.getService() != null) { - extensionIngressBackendBuilder.withServiceName(networkV1IngressBackend.getService().getName()); - if (networkV1IngressBackend.getService().getPort() != null) { - extensionIngressBackendBuilder.withServicePort(new IntOrString(networkV1IngressBackend.getService().getPort().getNumber())); - } - } - if (networkV1IngressBackend.getResource() != null) { - extensionIngressBackendBuilder.withResource(new TypedLocalObjectReferenceBuilder() - .withName(networkV1IngressBackend.getResource().getName()) - .withApiGroup(networkV1IngressBackend.getResource().getApiGroup()) - .withKind(networkV1IngressBackend.getResource().getKind()) - .build()); - } - return extensionIngressBackendBuilder.build(); - } - - private static List convertIngressTls(List networkV1IngressTls) { - List ingressTLS = new ArrayList<>(); - networkV1IngressTls.forEach(t -> ingressTLS.add(convertIngressTls(t))); - - return ingressTLS; - } - - private static IngressTLS convertIngressTls(io.fabric8.kubernetes.api.model.networking.v1.IngressTLS networkV1IngressTls) { - IngressTLSBuilder ingressTLSBuilder = new IngressTLSBuilder(); - if (networkV1IngressTls.getHosts() != null) { - ingressTLSBuilder.withHosts(networkV1IngressTls.getHosts()); - } - if (networkV1IngressTls.getSecretName() != null) { - ingressTLSBuilder.withSecretName(networkV1IngressTls.getSecretName()); - } - return ingressTLSBuilder.build(); - } - - private static List convertIngressRules(List networkingV1IngressRules) { - List ingressRules = new ArrayList<>(); - networkingV1IngressRules.forEach(ir -> ingressRules.add(convertIngressRule(ir))); - - return ingressRules; - } - - private static IngressRule convertIngressRule(io.fabric8.kubernetes.api.model.networking.v1.IngressRule networkingV1IngressRule) { - IngressRuleBuilder ingressRuleBuilder = new IngressRuleBuilder(); - if (networkingV1IngressRule.getHost() != null) { - ingressRuleBuilder.withHost(networkingV1IngressRule.getHost()); - } - if (networkingV1IngressRule.getHttp() != null) { - ingressRuleBuilder.withHttp(convertHTTPIngressRuleValue(networkingV1IngressRule.getHttp())); - } - return ingressRuleBuilder.build(); - } - - private static HTTPIngressRuleValue convertHTTPIngressRuleValue(io.fabric8.kubernetes.api.model.networking.v1.HTTPIngressRuleValue networkV1HTTPIngressRuleValue) { - HTTPIngressRuleValueBuilder httpIngressRuleValueBuilder = new HTTPIngressRuleValueBuilder(); - if (networkV1HTTPIngressRuleValue.getPaths() != null) { - httpIngressRuleValueBuilder.withPaths(convertHTTPIngressPaths(networkV1HTTPIngressRuleValue.getPaths())); - } - return httpIngressRuleValueBuilder.build(); - } - - private static List convertHTTPIngressPaths(List networkV1HttpIngressPaths) { - List httpIngressPaths = new ArrayList<>(); - networkV1HttpIngressPaths.forEach(h -> httpIngressPaths.add(convertHTTPIngressPath(h))); - - return httpIngressPaths; - } - - private static HTTPIngressPath convertHTTPIngressPath(io.fabric8.kubernetes.api.model.networking.v1.HTTPIngressPath networkV1HttpIngressPath) { - HTTPIngressPathBuilder httpIngressPathBuilder = new HTTPIngressPathBuilder(); - if (networkV1HttpIngressPath.getPath() != null) { - httpIngressPathBuilder.withPath(networkV1HttpIngressPath.getPath()); - } - if (networkV1HttpIngressPath.getPathType() != null) { - httpIngressPathBuilder.withPathType(networkV1HttpIngressPath.getPathType()); - } - if (networkV1HttpIngressPath.getBackend() != null) { - httpIngressPathBuilder.withBackend(convertIngressBackend(networkV1HttpIngressPath.getBackend())); - } - return httpIngressPathBuilder.build(); - } -} diff --git a/jkube-kit/enricher/generic/src/test/java/org/eclipse/jkube/enricher/generic/ingress/ExtensionsV1Beta1IngressConverterTest.java b/jkube-kit/enricher/generic/src/test/java/org/eclipse/jkube/enricher/generic/ingress/ExtensionsV1Beta1IngressConverterTest.java deleted file mode 100644 index 77d6031310..0000000000 --- a/jkube-kit/enricher/generic/src/test/java/org/eclipse/jkube/enricher/generic/ingress/ExtensionsV1Beta1IngressConverterTest.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * 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.enricher.generic.ingress; - -import io.fabric8.kubernetes.api.model.extensions.Ingress; -import io.fabric8.kubernetes.api.model.networking.v1.IngressBuilder; -import org.junit.jupiter.api.Test; - -import static org.assertj.core.api.AssertionsForClassTypes.assertThat; - -class ExtensionsV1Beta1IngressConverterTest { - @Test - void convert_withNullInput() { - assertThat(ExtensionsV1beta1IngressConverter.convert(null)).isNull(); - } - - @Test - void convert_withNullSpec() { - // Given - final io.fabric8.kubernetes.api.model.networking.v1.Ingress from = new IngressBuilder() - .withNewMetadata().withName("ingress").endMetadata().build(); - // When - final Ingress result = ExtensionsV1beta1IngressConverter.convert(from); - // Then - assertThat(result) - .hasFieldOrPropertyWithValue("spec", null) - .hasFieldOrPropertyWithValue("metadata.name", "ingress"); - } - - @Test - void convert() { - // Given - io.fabric8.kubernetes.api.model.networking.v1.Ingress networkV1Ingress = new IngressBuilder() - .withNewMetadata().withName("test-ing").endMetadata() - .withNewSpec() - .withIngressClassName("external-lb") - .addNewTl() - .withHosts("test-svc.org.eclipse.jkube") - .withSecretName("test-jkube-ingress") - .endTl() - .addNewRule() - .withHost("test-svc.org.eclipse.jkube") - .withNewHttp() - .addNewPath() - .withPath("/testpath") - .withPathType("Prefix") - .withNewBackend() - .withNewService() - .withName("test") - .withNewPort() - .withNumber(80) - .endPort() - .endService() - .withNewResource("k8s.example.com", "StorageBucket", "icon-assets") - .endBackend() - .endPath() - .endHttp() - .endRule() - .endSpec() - .build(); - - // When - Ingress ingress = ExtensionsV1beta1IngressConverter.convert(networkV1Ingress); - - // Then - assertThat(ingress) - .hasFieldOrPropertyWithValue("metadata.name", "test-ing") - .hasFieldOrPropertyWithValue("spec.ingressClassName", "external-lb") - .satisfies(ir -> assertThat(ir.getSpec().getTls()) - .asList().singleElement() - .hasFieldOrPropertyWithValue("secretName", "test-jkube-ingress") - .extracting("hosts").asList().singleElement() - .isEqualTo("test-svc.org.eclipse.jkube")) - .extracting("spec.rules").asList().singleElement() - .hasFieldOrPropertyWithValue("host", "test-svc.org.eclipse.jkube") - .extracting("http.paths").asList().first() - .hasFieldOrPropertyWithValue("path", "/testpath") - .hasFieldOrPropertyWithValue("pathType", "Prefix") - .hasFieldOrPropertyWithValue("backend.serviceName", "test") - .hasFieldOrPropertyWithValue("backend.servicePort.intVal", 80) - .hasFieldOrPropertyWithValue("backend.resource.apiGroup", "k8s.example.com") - .hasFieldOrPropertyWithValue("backend.resource.kind", "StorageBucket") - .hasFieldOrPropertyWithValue("backend.resource.name", "icon-assets"); - } - - @Test - void convert_withDefaultBackend() { - // Given - io.fabric8.kubernetes.api.model.networking.v1.Ingress networkV1Ingress = new IngressBuilder() - .withNewMetadata().withName("test-jkube").endMetadata() - .withNewSpec() - .withNewDefaultBackend() - .withNewService() - .withName("test-jkube-ingress") - .withNewPort().withNumber(8080).endPort() - .endService() - .endDefaultBackend() - .endSpec() - .build(); - - // When - Ingress ingress = ExtensionsV1beta1IngressConverter.convert(networkV1Ingress); - - // Then - assertThat(ingress) - .isNotNull() - .hasFieldOrPropertyWithValue("spec.backend.serviceName", "test-jkube-ingress") - .hasFieldOrPropertyWithValue("spec.backend.servicePort.intVal", 8080); - } -} diff --git a/jkube-kit/helm/pom.xml b/jkube-kit/helm/pom.xml index d1e608ee9f..39d612cfd4 100644 --- a/jkube-kit/helm/pom.xml +++ b/jkube-kit/helm/pom.xml @@ -85,7 +85,7 @@ io.fabric8 - openshift-server-mock + kubernetes-server-mock diff --git a/jkube-kit/helm/src/main/java/org/eclipse/jkube/kit/resource/helm/HelmService.java b/jkube-kit/helm/src/main/java/org/eclipse/jkube/kit/resource/helm/HelmService.java index 7775317906..0dc9e76184 100644 --- a/jkube-kit/helm/src/main/java/org/eclipse/jkube/kit/resource/helm/HelmService.java +++ b/jkube-kit/helm/src/main/java/org/eclipse/jkube/kit/resource/helm/HelmService.java @@ -381,9 +381,12 @@ private static void processSourceFiles(File sourceDir, File templatesDir) throws } private static void splitAndSaveTemplate(Template template, File templatesDir) throws IOException { - for (HasMetadata object : Optional.ofNullable(template.getObjects()).orElse(Collections.emptyList())) { - String name = KubernetesResourceFragments.getNameWithSuffix(KubernetesHelper.getName(object), - KubernetesHelper.getKind(object)) + YAML_EXTENSION; + for (Object object : Optional.ofNullable(template.getObjects()).orElse(Collections.emptyList())) { + if (!(object instanceof HasMetadata)) { + continue; + } + String name = KubernetesResourceFragments.getNameWithSuffix(KubernetesHelper.getName((HasMetadata) object), + KubernetesHelper.getKind((HasMetadata) object)) + YAML_EXTENSION; File outFile = new File(templatesDir, name); ResourceUtil.save(outFile, object); } diff --git a/jkube-kit/helm/src/main/java/org/eclipse/jkube/kit/resource/helm/oci/OCIRegistryClient.java b/jkube-kit/helm/src/main/java/org/eclipse/jkube/kit/resource/helm/oci/OCIRegistryClient.java index c355988d5a..fc71d8b6dd 100644 --- a/jkube-kit/helm/src/main/java/org/eclipse/jkube/kit/resource/helm/oci/OCIRegistryClient.java +++ b/jkube-kit/helm/src/main/java/org/eclipse/jkube/kit/resource/helm/oci/OCIRegistryClient.java @@ -29,6 +29,9 @@ import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.time.Duration; +import java.util.List; +import java.util.Locale; +import java.util.Map; import java.util.Optional; import static java.net.HttpURLConnection.HTTP_ACCEPTED; @@ -37,12 +40,12 @@ import static org.eclipse.jkube.kit.common.util.AsyncUtil.get; public class OCIRegistryClient { - private static final String DOCKER_CONTENT_DIGEST = "Docker-Content-Digest"; + private static final String DOCKER_CONTENT_DIGEST = "docker-content-digest"; private static final String USER_AGENT = "EclipseJKube"; private static final String OCI_IMAGE_MANIFEST_MEDIA_TYPE = "application/vnd.oci.image.manifest.v1+json"; private static final String HELM_CONFIG_MEDIA_TYPE = "application/vnd.cncf.helm.config.v1+json"; private static final String HELM_CHART_CONTENT_MEDIA_TYPE = "application/vnd.cncf.helm.chart.content.v1.tar+gzip"; - private static final String LOCATION_HEADER = "Location"; + private static final String LOCATION_HEADER = "location"; private static final long OCI_UPLOAD_HTTP_REQUEST_TIMEOUT = 30; private final OCIRegistryEndpoint ociRegistryEndpoint; private final HttpClient httpClient; @@ -130,8 +133,7 @@ private HttpRequest.Builder newRequest() { } private String parseLocationHeaderFromResponse(HttpResponse response) { - String locationHeader = response.header(LOCATION_HEADER); - + String locationHeader = header(response, LOCATION_HEADER); // Only path is returned via GitHub Container Registry if (locationHeader != null && locationHeader.startsWith("/")) { locationHeader = ociRegistryEndpoint.getBaseUrl() + locationHeader; @@ -147,13 +149,22 @@ private static void handleFailure(HttpResponse response) throws BadUploa } private static String extractDockerContentDigestFromResponseHeaders(HttpResponse response) throws BadUploadException { - String dockerContentDigest = response.header(DOCKER_CONTENT_DIGEST); + String dockerContentDigest = header(response, DOCKER_CONTENT_DIGEST); if (StringUtils.isNotBlank(dockerContentDigest)) { return dockerContentDigest; } throw new BadUploadException("No " + DOCKER_CONTENT_DIGEST + " header found in upload response"); } + private static String header(HttpResponse response, String name) { + for (Map.Entry> header : response.headers().entrySet()) { + if (header.getKey().toLowerCase(Locale.ROOT).equals(name) && header.getValue() != null && !header.getValue().isEmpty()) { + return header.getValue().get(0); + } + } + return null; + } + private static String createChartManifestPayload(OCIManifestLayer chartConfig, OCIManifestLayer chartTarball) { return Serialization.asJson(OCIManifest.builder() .schemaVersion(2) diff --git a/jkube-kit/helm/src/test/java/org/eclipse/jkube/kit/resource/helm/HelmServiceTestIT.java b/jkube-kit/helm/src/test/java/org/eclipse/jkube/kit/resource/helm/HelmServiceTestIT.java index 05caae4b32..c8fcea654f 100644 --- a/jkube-kit/helm/src/test/java/org/eclipse/jkube/kit/resource/helm/HelmServiceTestIT.java +++ b/jkube-kit/helm/src/test/java/org/eclipse/jkube/kit/resource/helm/HelmServiceTestIT.java @@ -21,9 +21,9 @@ import io.fabric8.kubernetes.client.server.mock.KubernetesMixedDispatcher; import io.fabric8.kubernetes.client.server.mock.KubernetesMockServer; import io.fabric8.mockwebserver.Context; +import io.fabric8.mockwebserver.MockWebServer; import io.fabric8.mockwebserver.ServerRequest; import io.fabric8.mockwebserver.ServerResponse; -import okhttp3.mockwebserver.MockWebServer; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.eclipse.jkube.kit.common.JKubeConfiguration; diff --git a/jkube-kit/helm/src/test/java/org/eclipse/jkube/kit/resource/helm/HelmServiceUploadIT.java b/jkube-kit/helm/src/test/java/org/eclipse/jkube/kit/resource/helm/HelmServiceUploadIT.java index a4305ea3bc..dcc2937653 100644 --- a/jkube-kit/helm/src/test/java/org/eclipse/jkube/kit/resource/helm/HelmServiceUploadIT.java +++ b/jkube-kit/helm/src/test/java/org/eclipse/jkube/kit/resource/helm/HelmServiceUploadIT.java @@ -28,13 +28,13 @@ import io.fabric8.mockwebserver.Context; import io.fabric8.mockwebserver.DefaultMockServer; import io.fabric8.mockwebserver.MockServer; +import io.fabric8.mockwebserver.MockWebServer; import io.fabric8.mockwebserver.ServerRequest; import io.fabric8.mockwebserver.ServerResponse; import io.fabric8.mockwebserver.dsl.HttpMethod; +import io.fabric8.mockwebserver.http.MockResponse; +import io.fabric8.mockwebserver.http.RecordedRequest; import io.fabric8.mockwebserver.internal.SimpleRequest; -import okhttp3.mockwebserver.MockResponse; -import okhttp3.mockwebserver.MockWebServer; -import okhttp3.mockwebserver.RecordedRequest; import org.eclipse.jkube.kit.common.JKubeConfiguration; import org.eclipse.jkube.kit.common.JavaProject; import org.eclipse.jkube.kit.common.KitLogger; diff --git a/jkube-kit/helm/src/test/java/org/eclipse/jkube/kit/resource/helm/TestMockResponseProvider.java b/jkube-kit/helm/src/test/java/org/eclipse/jkube/kit/resource/helm/TestMockResponseProvider.java index e60a68f055..681f6e8c60 100644 --- a/jkube-kit/helm/src/test/java/org/eclipse/jkube/kit/resource/helm/TestMockResponseProvider.java +++ b/jkube-kit/helm/src/test/java/org/eclipse/jkube/kit/resource/helm/TestMockResponseProvider.java @@ -13,9 +13,9 @@ */ package org.eclipse.jkube.kit.resource.helm; +import io.fabric8.mockwebserver.http.Headers; +import io.fabric8.mockwebserver.http.RecordedRequest; import io.fabric8.mockwebserver.utils.ResponseProvider; -import okhttp3.Headers; -import okhttp3.mockwebserver.RecordedRequest; import java.util.Map; @@ -37,7 +37,7 @@ public int getStatusCode(RecordedRequest recordedRequest) { @Override public Headers getHeaders() { - return Headers.of(headers); + return Headers.builder().addAll(headers.entrySet()).build(); } @Override diff --git a/jkube-kit/helm/src/test/java/org/eclipse/jkube/kit/resource/helm/oci/OCIRegistryClientTest.java b/jkube-kit/helm/src/test/java/org/eclipse/jkube/kit/resource/helm/oci/OCIRegistryClientTest.java index 656315a5a3..98a2d9f61b 100644 --- a/jkube-kit/helm/src/test/java/org/eclipse/jkube/kit/resource/helm/oci/OCIRegistryClientTest.java +++ b/jkube-kit/helm/src/test/java/org/eclipse/jkube/kit/resource/helm/oci/OCIRegistryClientTest.java @@ -137,7 +137,7 @@ void withUploadLocationMissing_throwsException() { // When + Then assertThatIllegalStateException() .isThrownBy(() -> oci.uploadBlobIfNotUploadedYet(chart, chartTarballStream)) - .withMessage("No Location header found in upload initiation response"); + .withMessage("No location header found in upload initiation response"); } @Test @@ -186,7 +186,7 @@ void withDockerDigestMissing_throwsException() { // When + Then assertThatThrownBy(() -> oci.uploadBlobIfNotUploadedYet(chart, chartTarballStream)) .isInstanceOf(BadUploadException.class) - .hasMessage("No Docker-Content-Digest header found in upload response"); + .hasMessage("No docker-content-digest header found in upload response"); } @Test @@ -247,7 +247,7 @@ void withDockerDigestMissing_throwsException() { // When + Then assertThatExceptionOfType(BadUploadException.class) .isThrownBy(() -> oci.uploadOCIManifest(chart, chartConfigBlob, chartTarballBlob)) - .withMessage("No Docker-Content-Digest header found in upload response"); + .withMessage("No docker-content-digest header found in upload response"); } } } diff --git a/jkube-kit/helm/src/test/java/org/eclipse/jkube/kit/resource/helm/oci/OCIRegistryInterceptorTest.java b/jkube-kit/helm/src/test/java/org/eclipse/jkube/kit/resource/helm/oci/OCIRegistryInterceptorTest.java index fa2f47ac8a..98efdb72b7 100644 --- a/jkube-kit/helm/src/test/java/org/eclipse/jkube/kit/resource/helm/oci/OCIRegistryInterceptorTest.java +++ b/jkube-kit/helm/src/test/java/org/eclipse/jkube/kit/resource/helm/oci/OCIRegistryInterceptorTest.java @@ -19,6 +19,7 @@ import java.util.concurrent.CompletableFuture; import io.fabric8.kubernetes.client.http.HttpClient; +import io.fabric8.mockwebserver.http.RecordedRequest; import org.eclipse.jkube.kit.resource.helm.HelmRepository; import io.fabric8.kubernetes.client.http.HttpRequest; @@ -26,7 +27,6 @@ import io.fabric8.kubernetes.client.http.TestHttpResponse; import io.fabric8.kubernetes.client.utils.HttpClientUtils; import io.fabric8.mockwebserver.DefaultMockServer; -import okhttp3.mockwebserver.RecordedRequest; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/jkube-kit/jkube-kit-spring-boot/pom.xml b/jkube-kit/jkube-kit-spring-boot/pom.xml index 5a3247b00e..69e2fc11fc 100644 --- a/jkube-kit/jkube-kit-spring-boot/pom.xml +++ b/jkube-kit/jkube-kit-spring-boot/pom.xml @@ -76,7 +76,7 @@ io.fabric8 - openshift-server-mock + kubernetes-server-mock diff --git a/jkube-kit/parent/pom.xml b/jkube-kit/parent/pom.xml index a0002842d5..b8584894b4 100644 --- a/jkube-kit/parent/pom.xml +++ b/jkube-kit/parent/pom.xml @@ -52,7 +52,6 @@ 3.8.1 3.4.0 3.15.1 - 1.5.4 ${version.kubernetes-client} 2.8.0 0.0.7 @@ -361,6 +360,19 @@ + + io.fabric8 + kubernetes-model-validator + ${version.openshift-client} + + + + org.yaml + snakeyaml + + + + io.fabric8 ianaservicehelper @@ -755,27 +767,9 @@ io.fabric8 - openshift-server-mock + kubernetes-server-mock ${version.kubernetes-client} test - - - com.squareup.okhttp3 - okhttp - - - org.bouncycastle - bcprov-jdk15on - - - org.bouncycastle - bcprov-jdk18on - - - org.junit.jupiter - junit-jupiter-api - - @@ -821,26 +815,6 @@ - - com.networknt - json-schema-validator - ${version.networknt.validator} - - - org.apache.commons - commons-lang3 - - - com.fasterxml.jackson.core - jackson-databind - - - org.slf4j - slf4j-api - - - - diff --git a/jkube-kit/remote-dev/pom.xml b/jkube-kit/remote-dev/pom.xml index fa3ee61cf6..34d73467ec 100644 --- a/jkube-kit/remote-dev/pom.xml +++ b/jkube-kit/remote-dev/pom.xml @@ -63,7 +63,7 @@ io.fabric8 - openshift-server-mock + kubernetes-server-mock test diff --git a/jkube-kit/resource/service/src/main/java/org/eclipse/jkube/kit/resource/service/WriteUtil.java b/jkube-kit/resource/service/src/main/java/org/eclipse/jkube/kit/resource/service/WriteUtil.java index 13824f1459..0d83eb3213 100644 --- a/jkube-kit/resource/service/src/main/java/org/eclipse/jkube/kit/resource/service/WriteUtil.java +++ b/jkube-kit/resource/service/src/main/java/org/eclipse/jkube/kit/resource/service/WriteUtil.java @@ -27,8 +27,11 @@ import java.io.File; import java.io.IOException; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.stream.Collectors; import static org.eclipse.jkube.kit.resource.service.TemplateUtil.getSingletonTemplate; @@ -52,7 +55,14 @@ static File writeResourcesIndividualAndComposite( // no need to worry about this for dropping Route. final Template template = getSingletonTemplate(resources); if (template != null) { - template.getObjects().sort(COMPARATOR); + final List items = new ArrayList<>(); + for (Object object : template.getObjects()) { + if (object instanceof HasMetadata) { + items.add((HasMetadata) object); + } + } + items.sort(COMPARATOR); + template.setObjects(items.stream().map(Object.class::cast).collect(Collectors.toList())); entity = template; } diff --git a/kubernetes-maven-plugin/plugin/pom.xml b/kubernetes-maven-plugin/plugin/pom.xml index 78c910c5e4..326a3b0965 100644 --- a/kubernetes-maven-plugin/plugin/pom.xml +++ b/kubernetes-maven-plugin/plugin/pom.xml @@ -169,7 +169,7 @@ io.fabric8 - openshift-server-mock + kubernetes-server-mock org.junit.jupiter diff --git a/openshift-maven-plugin/plugin/pom.xml b/openshift-maven-plugin/plugin/pom.xml index 56f6e6e0c0..522a5949a6 100644 --- a/openshift-maven-plugin/plugin/pom.xml +++ b/openshift-maven-plugin/plugin/pom.xml @@ -54,7 +54,7 @@ io.fabric8 - openshift-server-mock + kubernetes-server-mock org.junit.jupiter diff --git a/pom.xml b/pom.xml index cf84c7c2c7..af68aad489 100644 --- a/pom.xml +++ b/pom.xml @@ -53,6 +53,16 @@ + + + oss.sonatype.org + https://oss.sonatype.org/content/repositories/snapshots + + true + always + + + maven-central https://repo1.maven.org/maven2/ @@ -105,7 +115,7 @@ 0.8.12 2.5.1 5.11.3 - 6.13.4 + 7.0-SNAPSHOT 4.6 1.18.36 1.18.20.0