From 62dcd98130b382a7c2ed1e5528e640cbf74b27ee Mon Sep 17 00:00:00 2001 From: Rohan Kumar Date: Thu, 3 Dec 2020 17:40:43 +0530 Subject: [PATCH] Fix #231: IngressEnricher ignores IngressRules defined in XML config --- CHANGELOG.md | 1 + .../config/resource/IngressRuleConfig.java | 32 ++ .../resource/IngressRulePathConfig.java | 33 ++ .../IngressRulePathResourceConfig.java | 31 ++ .../kit/config/resource/IngressTlsConfig.java | 32 ++ .../kit/config/resource/ResourceConfig.java | 6 +- .../api/util/KubernetesResourceUtil.java | 7 + .../api/util/KubernetesResourceUtilTest.java | 7 + .../enricher/generic/IngressEnricher.java | 187 +++++++--- .../generic/openshift/RouteEnricher.java | 7 +- .../enricher/generic/IngressEnricherTest.java | 327 +++++++++++++++++- .../generic/openshift/RouteEnricherTest.java | 6 - quickstarts/maven/spring-boot/pom.xml | 23 ++ 13 files changed, 642 insertions(+), 57 deletions(-) create mode 100644 jkube-kit/config/resource/src/main/java/org/eclipse/jkube/kit/config/resource/IngressRuleConfig.java create mode 100644 jkube-kit/config/resource/src/main/java/org/eclipse/jkube/kit/config/resource/IngressRulePathConfig.java create mode 100644 jkube-kit/config/resource/src/main/java/org/eclipse/jkube/kit/config/resource/IngressRulePathResourceConfig.java create mode 100644 jkube-kit/config/resource/src/main/java/org/eclipse/jkube/kit/config/resource/IngressTlsConfig.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 6acb28d406..c3e667ff5b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ Usage: * Fix #387: Update Fabric8 Kubernetes Client to v4.13.0 to support `networking.k8s.io/v1` `Ingress` * Fix #473: Debug goals work with QuarkusGenerator generated container images * Fix #484: cacheFrom configuration parameter is missing +* Fix #231: IngressEnricher ignores IngressRules defined in XML config ### 1.0.2 (2020-10-30) * Fix #429: Added quickstart for Micronaut framework diff --git a/jkube-kit/config/resource/src/main/java/org/eclipse/jkube/kit/config/resource/IngressRuleConfig.java b/jkube-kit/config/resource/src/main/java/org/eclipse/jkube/kit/config/resource/IngressRuleConfig.java new file mode 100644 index 0000000000..2bd1b19bcd --- /dev/null +++ b/jkube-kit/config/resource/src/main/java/org/eclipse/jkube/kit/config/resource/IngressRuleConfig.java @@ -0,0 +1,32 @@ +/** + * 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.resource; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Builder(toBuilder = true) +@AllArgsConstructor +@NoArgsConstructor +@Getter +@EqualsAndHashCode +public class IngressRuleConfig { + private String host; + private List paths; +} diff --git a/jkube-kit/config/resource/src/main/java/org/eclipse/jkube/kit/config/resource/IngressRulePathConfig.java b/jkube-kit/config/resource/src/main/java/org/eclipse/jkube/kit/config/resource/IngressRulePathConfig.java new file mode 100644 index 0000000000..0d0b2f5424 --- /dev/null +++ b/jkube-kit/config/resource/src/main/java/org/eclipse/jkube/kit/config/resource/IngressRulePathConfig.java @@ -0,0 +1,33 @@ +/** + * 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.resource; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Builder(toBuilder = true) +@AllArgsConstructor +@NoArgsConstructor +@Getter +@EqualsAndHashCode +public class IngressRulePathConfig { + private String pathType; + private String path; + private String serviceName; + private int servicePort; + private IngressRulePathResourceConfig resource; +} diff --git a/jkube-kit/config/resource/src/main/java/org/eclipse/jkube/kit/config/resource/IngressRulePathResourceConfig.java b/jkube-kit/config/resource/src/main/java/org/eclipse/jkube/kit/config/resource/IngressRulePathResourceConfig.java new file mode 100644 index 0000000000..a44af1ca6a --- /dev/null +++ b/jkube-kit/config/resource/src/main/java/org/eclipse/jkube/kit/config/resource/IngressRulePathResourceConfig.java @@ -0,0 +1,31 @@ +/** + * 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.resource; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Builder(toBuilder = true) +@AllArgsConstructor +@NoArgsConstructor +@Getter +@EqualsAndHashCode +public class IngressRulePathResourceConfig { + private String apiGroup; + private String kind; + private String name; +} diff --git a/jkube-kit/config/resource/src/main/java/org/eclipse/jkube/kit/config/resource/IngressTlsConfig.java b/jkube-kit/config/resource/src/main/java/org/eclipse/jkube/kit/config/resource/IngressTlsConfig.java new file mode 100644 index 0000000000..2a7b307b7b --- /dev/null +++ b/jkube-kit/config/resource/src/main/java/org/eclipse/jkube/kit/config/resource/IngressTlsConfig.java @@ -0,0 +1,32 @@ +/** + * 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.resource; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Builder(toBuilder = true) +@AllArgsConstructor +@NoArgsConstructor +@Getter +@EqualsAndHashCode +public class IngressTlsConfig { + private List hosts; + private String secretName; +} diff --git a/jkube-kit/config/resource/src/main/java/org/eclipse/jkube/kit/config/resource/ResourceConfig.java b/jkube-kit/config/resource/src/main/java/org/eclipse/jkube/kit/config/resource/ResourceConfig.java index c381d47ff8..175dcc9e25 100644 --- a/jkube-kit/config/resource/src/main/java/org/eclipse/jkube/kit/config/resource/ResourceConfig.java +++ b/jkube-kit/config/resource/src/main/java/org/eclipse/jkube/kit/config/resource/ResourceConfig.java @@ -13,7 +13,6 @@ */ package org.eclipse.jkube.kit.config.resource; -import io.fabric8.kubernetes.api.model.extensions.IngressRule; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.EqualsAndHashCode; @@ -79,7 +78,10 @@ public class ResourceConfig { @Singular private List serviceAccounts; @Singular - private List ingressRules; + private List ingressRules; + + @Singular + private List ingressTlsConfigs; private OpenshiftBuildConfig openshiftBuildConfig; private String routeDomain; diff --git a/jkube-kit/enricher/api/src/main/java/org/eclipse/jkube/kit/enricher/api/util/KubernetesResourceUtil.java b/jkube-kit/enricher/api/src/main/java/org/eclipse/jkube/kit/enricher/api/util/KubernetesResourceUtil.java index b0a4c886e2..c5d57703c4 100644 --- a/jkube-kit/enricher/api/src/main/java/org/eclipse/jkube/kit/enricher/api/util/KubernetesResourceUtil.java +++ b/jkube-kit/enricher/api/src/main/java/org/eclipse/jkube/kit/enricher/api/util/KubernetesResourceUtil.java @@ -79,6 +79,7 @@ import org.eclipse.jkube.kit.common.util.ResourceUtil; import org.eclipse.jkube.kit.config.image.ImageName; import org.eclipse.jkube.kit.config.resource.GroupArtifactVersion; +import org.eclipse.jkube.kit.config.resource.JKubeAnnotations; import org.eclipse.jkube.kit.config.resource.PlatformMode; import org.eclipse.jkube.kit.config.resource.ResourceVersioning; import org.apache.commons.lang3.StringUtils; @@ -104,6 +105,7 @@ private KubernetesResourceUtil() { } public static final String OPENSHIFT_V1_VERSION = "apps.openshift.io/v1"; public static final String CRONJOB_VERSION = "batch/v1beta1"; public static final String RBAC_VERSION = "rbac.authorization.k8s.io/v1"; + public static final String EXPOSE_LABEL = "expose"; public static final ResourceVersioning DEFAULT_RESOURCE_VERSIONING = new ResourceVersioning() .withCoreVersion(API_VERSION) @@ -1030,4 +1032,9 @@ private static boolean isLocalCustomisation(PodSpec podSpec) { } return true; } + + public static boolean isExposedService(ObjectMeta objectMeta) { + return containsLabelInMetadata(objectMeta, EXPOSE_LABEL, "true") || + containsLabelInMetadata(objectMeta, JKubeAnnotations.SERVICE_EXPOSE_URL.value(), "true"); + } } diff --git a/jkube-kit/enricher/api/src/test/java/org/eclipse/jkube/kit/enricher/api/util/KubernetesResourceUtilTest.java b/jkube-kit/enricher/api/src/test/java/org/eclipse/jkube/kit/enricher/api/util/KubernetesResourceUtilTest.java index c2f52065d8..5a310f49bf 100644 --- a/jkube-kit/enricher/api/src/test/java/org/eclipse/jkube/kit/enricher/api/util/KubernetesResourceUtilTest.java +++ b/jkube-kit/enricher/api/src/test/java/org/eclipse/jkube/kit/enricher/api/util/KubernetesResourceUtilTest.java @@ -16,6 +16,7 @@ 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.ObjectMetaBuilder; import io.fabric8.kubernetes.api.model.PodSpec; import io.fabric8.kubernetes.api.model.PodSpecBuilder; import io.fabric8.kubernetes.api.model.Quantity; @@ -266,6 +267,12 @@ public void testGetResourceShouldLoadNetworkV1Ingress() throws IOException { assertEquals("my-ingress", result.getMetadata().getName()); } + @Test + public void testIsExposedService() { + assertTrue(KubernetesResourceUtil.isExposedService(new ObjectMetaBuilder().addToLabels("expose", "true").build())); + assertTrue(KubernetesResourceUtil.isExposedService(new ObjectMetaBuilder().addToLabels("jkube.io/exposeUrl", "true").build())); + } + private PodSpec getDefaultGeneratedPodSpec() { return new PodSpecBuilder() .addNewContainer() 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 2096275b55..bcf0244b1a 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 @@ -14,32 +14,46 @@ package org.eclipse.jkube.enricher.generic; import io.fabric8.kubernetes.api.builder.TypedVisitor; +import io.fabric8.kubernetes.api.model.IntOrString; import io.fabric8.kubernetes.api.model.KubernetesListBuilder; import io.fabric8.kubernetes.api.model.ObjectMeta; +import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; import io.fabric8.kubernetes.api.model.ServiceBuilder; import io.fabric8.kubernetes.api.model.ServicePort; import io.fabric8.kubernetes.api.model.ServiceSpec; +import io.fabric8.kubernetes.api.model.extensions.HTTPIngressPath; import io.fabric8.kubernetes.api.model.extensions.HTTPIngressPathBuilder; +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 org.apache.commons.lang3.StringUtils; 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.config.resource.IngressRuleConfig; +import org.eclipse.jkube.kit.config.resource.IngressRulePathConfig; +import org.eclipse.jkube.kit.config.resource.IngressRulePathResourceConfig; +import org.eclipse.jkube.kit.config.resource.IngressTlsConfig; import org.eclipse.jkube.kit.config.resource.JKubeAnnotations; import org.eclipse.jkube.kit.config.resource.PlatformMode; import org.eclipse.jkube.kit.config.resource.ResourceConfig; import org.eclipse.jkube.kit.enricher.api.BaseEnricher; import org.eclipse.jkube.kit.enricher.api.JKubeEnricherContext; +import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.concurrent.atomic.AtomicBoolean; -import static org.eclipse.jkube.kit.enricher.api.util.KubernetesResourceUtil.containsLabelInMetadata; -import static org.eclipse.jkube.kit.enricher.api.util.KubernetesResourceUtil.removeLabel; +import static org.eclipse.jkube.kit.enricher.api.util.KubernetesResourceUtil.isExposedService; /** * Enricher which generates an Ingress for each exposed Service @@ -63,7 +77,7 @@ public void create(PlatformMode platformMode, final KubernetesListBuilder listBu listBuilder.accept(new TypedVisitor() { @Override public void visit(ServiceBuilder serviceBuilder) { - Ingress ingress = addIngress(listBuilder, serviceBuilder, getRouteDomain(resourceConfig), log); + Ingress ingress = addIngress(listBuilder, serviceBuilder, getRouteDomain(resourceConfig), getIngressRuleXMLConfig(resourceConfig), getIngressTlsXMLConfig(resourceConfig), log); if (ingress != null) { listBuilder.addToItems(ingress); } @@ -72,7 +86,7 @@ public void visit(ServiceBuilder serviceBuilder) { } } - protected static Ingress addIngress(KubernetesListBuilder listBuilder, ServiceBuilder serviceBuilder, String routeDomainPostfix, KitLogger log) { + protected static Ingress addIngress(KubernetesListBuilder listBuilder, ServiceBuilder serviceBuilder, String routeDomainPostfix, List ingressRuleConfigs, List ingressTlsConfigs, KitLogger log) { ObjectMeta serviceMetadata = serviceBuilder.buildMetadata(); if (serviceMetadata == null) { log.info("No Metadata for service! "); @@ -83,45 +97,127 @@ protected static Ingress addIngress(KubernetesListBuilder listBuilder, ServiceBu if (!hasIngress(listBuilder, serviceName)) { Integer servicePort = getServicePort(serviceBuilder); if (servicePort != null) { + return new IngressBuilder() + .withMetadata(getIngressMetadata(serviceMetadata)) + .withSpec(getIngressSpec(routeDomainPostfix, serviceName, servicePort, ingressRuleConfigs, ingressTlsConfigs)) + .build(); - IngressBuilder ingressBuilder = new IngressBuilder(). - withMetadata(serviceMetadata). - withNewSpec(). - endSpec(); - - // removing `expose : true` label from metadata. - removeLabel(ingressBuilder.buildMetadata(), EXPOSE_LABEL, "true"); - removeLabel(ingressBuilder.buildMetadata(), JKubeAnnotations.SERVICE_EXPOSE_URL.value(), "true"); - ingressBuilder.withNewMetadataLike(ingressBuilder.buildMetadata()); - - if (StringUtils.isNotBlank(routeDomainPostfix)) { - routeDomainPostfix = serviceName + "." + FileUtil.stripPrefix(routeDomainPostfix, "."); - ingressBuilder = ingressBuilder.withSpec(new IngressSpecBuilder().addNewRule(). - withHost(routeDomainPostfix). - withNewHttp(). - withPaths(new HTTPIngressPathBuilder() - .withNewBackend() - .withServiceName(serviceName) - .withServicePort(KubernetesHelper.createIntOrString(getServicePort(serviceBuilder))) - .endBackend() - .build()) - .endHttp(). - endRule().build()); - } else { - ingressBuilder.withSpec(new IngressSpecBuilder().withBackend(new IngressBackendBuilder(). - withNewServiceName(serviceName) - .withNewServicePort(getServicePort(serviceBuilder)) - .build()).build()); - } - - return ingressBuilder.build(); } } } return null; } - private static Integer getServicePort(ServiceBuilder serviceBuilder) { + private static ObjectMeta getIngressMetadata(ObjectMeta serviceMetadata) { + ObjectMetaBuilder ingressMetadataBuilder = new ObjectMetaBuilder(serviceMetadata); + + // removing `expose : true` label from metadata. + ingressMetadataBuilder.removeFromLabels(Collections.singletonMap(EXPOSE_LABEL, "true")); + ingressMetadataBuilder.removeFromLabels(Collections.singletonMap(JKubeAnnotations.SERVICE_EXPOSE_URL.value(), "true")); + + return ingressMetadataBuilder.build(); + } + + private static IngressSpec getIngressSpec(String routeDomainPostfix, String serviceName, Integer servicePort, List ingressRuleConfig, List ingressTlsConfigs) { + if (ingressRuleConfig == null || ingressRuleConfig.isEmpty()) { + return getOpinionatedIngressSpec(routeDomainPostfix, serviceName, servicePort); + } + return getXmlConfiguredIngressSpec(ingressRuleConfig, ingressTlsConfigs); + } + + private static IngressSpec getXmlConfiguredIngressSpec(List ingressRuleConfigs, List ingressTlsConfigs) { + IngressSpecBuilder ingressSpecBuilder = new IngressSpecBuilder(); + for (IngressRuleConfig ingressRuleConfig: ingressRuleConfigs) { + IngressRule ingressRule = getIngressRuleFromXmlConfig(ingressRuleConfig); + ingressSpecBuilder.addToRules(ingressRule); + } + + for (IngressTlsConfig ingressTlsConfig : ingressTlsConfigs) { + IngressTLS ingressTLS = getIngressTlsFromXMLConfig(ingressTlsConfig); + ingressSpecBuilder.addToTls(ingressTLS); + } + return ingressSpecBuilder.build(); + } + + private static IngressTLS getIngressTlsFromXMLConfig(IngressTlsConfig ingressTlsConfig) { + IngressTLSBuilder ingressTLSBuilder = new IngressTLSBuilder(); + if (ingressTlsConfig.getHosts() != null && !ingressTlsConfig.getHosts().isEmpty()) { + ingressTLSBuilder.withHosts(ingressTlsConfig.getHosts()); + } + if (ingressTlsConfig.getSecretName() != null) { + ingressTLSBuilder.withSecretName(ingressTlsConfig.getSecretName()); + } + return ingressTLSBuilder.build(); + } + + private static IngressSpec getOpinionatedIngressSpec(String routeDomainPostfix, String serviceName, Integer servicePort) { + IngressSpecBuilder ingressSpecBuilder = new IngressSpecBuilder(); + if (StringUtils.isNotBlank(routeDomainPostfix)) { + routeDomainPostfix = serviceName + "." + FileUtil.stripPrefix(routeDomainPostfix, "."); + ingressSpecBuilder.addNewRule() + .withHost(routeDomainPostfix) + .withNewHttp() + .withPaths(new HTTPIngressPathBuilder() + .withNewBackend() + .withServiceName(serviceName) + .withServicePort(KubernetesHelper.createIntOrString(servicePort)) + .endBackend() + .build()) + .endHttp() + .endRule().build(); + } else { + ingressSpecBuilder.withBackend(new IngressBackendBuilder(). + withNewServiceName(serviceName) + .withNewServicePort(servicePort) + .build()); + } + return ingressSpecBuilder.build(); + } + + private static IngressRule getIngressRuleFromXmlConfig(IngressRuleConfig ingressRuleConfig) { + IngressRuleBuilder ingressRuleBuilder = new IngressRuleBuilder(); + if (ingressRuleConfig.getHost() != null) { + ingressRuleBuilder.withHost(ingressRuleConfig.getHost()); + } + if (ingressRuleConfig.getPaths() != null && !ingressRuleConfig.getPaths().isEmpty()) { + HTTPIngressRuleValueBuilder httpIngressPathBuilder = new HTTPIngressRuleValueBuilder(); + for (IngressRulePathConfig ingressRulePathConfig : ingressRuleConfig.getPaths()) { + httpIngressPathBuilder.addToPaths(getHTTPIngressPath(ingressRulePathConfig)); + } + ingressRuleBuilder.withHttp(httpIngressPathBuilder.build()); + } + return ingressRuleBuilder.build(); + } + + private static HTTPIngressPath getHTTPIngressPath(IngressRulePathConfig ingressRulePathConfig) { + HTTPIngressPathBuilder httpIngressPathBuilder = new HTTPIngressPathBuilder(); + if (ingressRulePathConfig.getPath() != null) { + httpIngressPathBuilder.withPath(ingressRulePathConfig.getPath()); + } + if (ingressRulePathConfig.getPathType() != null) { + httpIngressPathBuilder.withPathType(ingressRulePathConfig.getPathType()); + } + return httpIngressPathBuilder.withBackend(getIngressBackend(ingressRulePathConfig)) + .build(); + } + + private static IngressBackend getIngressBackend(IngressRulePathConfig ingressRulePathConfig) { + IngressBackendBuilder ingressBackendBuilder = new IngressBackendBuilder(); + if (ingressRulePathConfig.getServiceName() != null) { + ingressBackendBuilder.withServiceName(ingressRulePathConfig.getServiceName()); + } + if (ingressRulePathConfig.getServicePort() > 0) { + ingressBackendBuilder.withServicePort(new IntOrString(ingressRulePathConfig.getServicePort())); + } + if (ingressRulePathConfig.getResource() != null) { + IngressRulePathResourceConfig resource = ingressRulePathConfig.getResource(); + ingressBackendBuilder.withNewResource(resource.getApiGroup(), resource.getKind(), resource.getName()); + } + + return ingressBackendBuilder.build(); + } + + static Integer getServicePort(ServiceBuilder serviceBuilder) { ServiceSpec spec = serviceBuilder.buildSpec(); if (spec != null) { List ports = spec.getPorts(); @@ -165,7 +261,7 @@ public void visit(IngressBuilder builder) { * * @return true if we should create an Ingress for this service. */ - private static boolean shouldCreateExternalURLForService(ServiceBuilder service, KitLogger log) { + static boolean shouldCreateExternalURLForService(ServiceBuilder service, KitLogger log) { String serviceName = service.buildMetadata().getName(); ServiceSpec spec = service.buildSpec(); if (spec != null && !isKuberentesSystemService(serviceName)) { @@ -188,7 +284,7 @@ private static boolean isKuberentesSystemService(String serviceName) { return "kubernetes".equals(serviceName) || "kubernetes-ro".equals(serviceName); } - private String getRouteDomain(ResourceConfig resourceConfig) { + protected String getRouteDomain(ResourceConfig resourceConfig) { if (resourceConfig != null && resourceConfig.getRouteDomain() != null) { return resourceConfig.getRouteDomain(); } @@ -199,8 +295,17 @@ private String getRouteDomain(ResourceConfig resourceConfig) { return null; } - private static boolean isExposedService(ObjectMeta objectMeta) { - return containsLabelInMetadata(objectMeta, EXPOSE_LABEL, "true") || - containsLabelInMetadata(objectMeta, JKubeAnnotations.SERVICE_EXPOSE_URL.value(), "true"); + static List getIngressRuleXMLConfig(ResourceConfig resourceConfig) { + if (resourceConfig != null) { + return resourceConfig.getIngressRules(); + } + return Collections.emptyList(); + } + + static List getIngressTlsXMLConfig(ResourceConfig resourceConfig) { + if (resourceConfig != null) { + return resourceConfig.getIngressTlsConfigs(); + } + return Collections.emptyList(); } } diff --git a/jkube-kit/enricher/generic/src/main/java/org/eclipse/jkube/enricher/generic/openshift/RouteEnricher.java b/jkube-kit/enricher/generic/src/main/java/org/eclipse/jkube/enricher/generic/openshift/RouteEnricher.java index 47c484f679..a484e3178f 100644 --- a/jkube-kit/enricher/generic/src/main/java/org/eclipse/jkube/enricher/generic/openshift/RouteEnricher.java +++ b/jkube-kit/enricher/generic/src/main/java/org/eclipse/jkube/enricher/generic/openshift/RouteEnricher.java @@ -41,7 +41,7 @@ import lombok.Getter; import org.apache.commons.lang3.StringUtils; -import static org.eclipse.jkube.kit.enricher.api.util.KubernetesResourceUtil.containsLabelInMetadata; +import static org.eclipse.jkube.kit.enricher.api.util.KubernetesResourceUtil.isExposedService; import static org.eclipse.jkube.kit.enricher.api.util.KubernetesResourceUtil.mergeMetadata; import static org.eclipse.jkube.kit.enricher.api.util.KubernetesResourceUtil.mergeSimpleFields; import static org.eclipse.jkube.kit.enricher.api.util.KubernetesResourceUtil.removeItemFromKubernetesBuilder; @@ -281,9 +281,4 @@ static Route createOpinionatedRouteFromService(ServiceBuilder serviceBuilder, St } return null; } - - static boolean isExposedService(ObjectMeta objectMeta) { - return containsLabelInMetadata(objectMeta, EXPOSE_LABEL, "true") || - containsLabelInMetadata(objectMeta, JKubeAnnotations.SERVICE_EXPOSE_URL.value(), "true"); - } } \ No newline at end of file diff --git a/jkube-kit/enricher/generic/src/test/java/org/eclipse/jkube/enricher/generic/IngressEnricherTest.java b/jkube-kit/enricher/generic/src/test/java/org/eclipse/jkube/enricher/generic/IngressEnricherTest.java index d110bb8b81..fb935359b6 100644 --- a/jkube-kit/enricher/generic/src/test/java/org/eclipse/jkube/enricher/generic/IngressEnricherTest.java +++ b/jkube-kit/enricher/generic/src/test/java/org/eclipse/jkube/enricher/generic/IngressEnricherTest.java @@ -13,21 +13,36 @@ */ package org.eclipse.jkube.enricher.generic; +import io.fabric8.kubernetes.api.model.HasMetadata; import io.fabric8.kubernetes.api.model.IntOrString; import io.fabric8.kubernetes.api.model.KubernetesListBuilder; import io.fabric8.kubernetes.api.model.Service; import io.fabric8.kubernetes.api.model.ServiceBuilder; +import io.fabric8.kubernetes.api.model.ServicePortBuilder; import io.fabric8.kubernetes.api.model.extensions.Ingress; +import io.fabric8.kubernetes.api.model.extensions.IngressBuilder; +import io.fabric8.kubernetes.api.model.extensions.IngressTLSBuilder; import mockit.Expectations; import mockit.Mocked; import org.eclipse.jkube.kit.common.KitLogger; +import org.eclipse.jkube.kit.config.resource.IngressRuleConfig; +import org.eclipse.jkube.kit.config.resource.IngressRulePathConfig; +import org.eclipse.jkube.kit.config.resource.IngressRulePathResourceConfig; +import org.eclipse.jkube.kit.config.resource.IngressTlsConfig; import org.eclipse.jkube.kit.config.resource.PlatformMode; +import org.eclipse.jkube.kit.config.resource.ResourceConfig; import org.eclipse.jkube.kit.enricher.api.JKubeEnricherContext; import org.junit.Test; +import java.util.Collections; +import java.util.List; + import static org.eclipse.jkube.kit.enricher.api.BaseEnricher.CREATE_EXTERNAL_URLS; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; public class IngressEnricherTest { @Mocked @@ -37,7 +52,21 @@ public class IngressEnricherTest { private KitLogger logger; @Test - public void testCreate() { + public void testCreateShouldNotCreateAnyIngress() { + // Given + Service providedService = getTestService().build(); + KubernetesListBuilder kubernetesListBuilder = new KubernetesListBuilder().addToItems(providedService); + IngressEnricher ingressEnricher = new IngressEnricher(context); + + // When + ingressEnricher.create(PlatformMode.kubernetes, kubernetesListBuilder); + + // Then + assertEquals(1, kubernetesListBuilder.buildItems().size()); + } + + @Test + public void testCreateWithExternalUrlsSetTrue() { // Given new Expectations() {{ // Enable creation of Ingress for Service of type LoadBalancer @@ -62,6 +91,100 @@ public void testCreate() { assertEquals(providedService.getSpec().getPorts().get(0).getTargetPort(), ingress.getSpec().getBackend().getServicePort()); } + @Test + public void testCreateIngressFromXMLConfigWithConfiguredServiceName() { + // Given + ResourceConfig resourceConfig = ResourceConfig.builder() + .ingressRule(IngressRuleConfig.builder() + .host("foo.bar.com") + .paths(Collections.singletonList(IngressRulePathConfig.builder() + .pathType("ImplementationSpecific") + .path("/icons") + .serviceName("hello-k8s") + .servicePort(80) + .build())) + .build()) + .ingressRule(IngressRuleConfig.builder() + .host("*.foo.com") + .paths(Collections.singletonList(IngressRulePathConfig.builder() + .path("/icons-storage") + .pathType("Exact") + .resource(IngressRulePathResourceConfig.builder() + .apiGroup("k8s.example.com") + .kind("StorageBucket") + .name("icon-assets") + .build()) + .build())) + .build()) + .ingressTlsConfig(IngressTlsConfig.builder() + .hosts(Collections.singletonList("https-example.foo.com")) + .secretName("testsecret-tls") + .build()) + .build(); + new Expectations() {{ + // Enable creation of Ingress for Service of type LoadBalancer + context.getProperty(CREATE_EXTERNAL_URLS); + result = "true"; + + context.getConfiguration().getResource(); + result = resourceConfig; + }}; + + Service providedService = getTestService().build(); + KubernetesListBuilder kubernetesListBuilder = new KubernetesListBuilder().addToItems(providedService); + IngressEnricher ingressEnricher = new IngressEnricher(context); + + // When + ingressEnricher.create(PlatformMode.kubernetes, kubernetesListBuilder); + + // Then + assertEquals(2, kubernetesListBuilder.buildItems().size()); + HasMetadata lastItem = kubernetesListBuilder.buildLastItem(); + assertTrue(lastItem instanceof Ingress); + Ingress ingress = (Ingress) lastItem; + assertNotNull(ingress); + assertEquals(providedService.getMetadata().getName(), ingress.getMetadata().getName()); + assertNotNull(ingress.getSpec()); + assertEquals(resourceConfig.getIngressTlsConfigs().get(0).getHosts(), ingress.getSpec().getTls().get(0).getHosts()); + assertEquals(resourceConfig.getIngressTlsConfigs().get(0).getSecretName(), ingress.getSpec().getTls().get(0).getSecretName()); + assertEquals(resourceConfig.getIngressRules().get(0).getHost(), ingress.getSpec().getRules().get(0).getHost()); + assertEquals(resourceConfig.getIngressRules().get(0).getPaths().get(0).getServiceName(), ingress.getSpec().getRules().get(0).getHttp().getPaths().get(0).getBackend().getServiceName()); + assertEquals(resourceConfig.getIngressRules().get(0).getPaths().get(0).getServicePort(), ingress.getSpec().getRules().get(0).getHttp().getPaths().get(0).getBackend().getServicePort().getIntVal().intValue()); + assertEquals(resourceConfig.getIngressRules().get(0).getPaths().get(0).getPath(), ingress.getSpec().getRules().get(0).getHttp().getPaths().get(0).getPath()); + assertEquals(resourceConfig.getIngressRules().get(0).getPaths().get(0).getPathType(), ingress.getSpec().getRules().get(0).getHttp().getPaths().get(0).getPathType()); + assertEquals(resourceConfig.getIngressRules().get(1).getHost(), ingress.getSpec().getRules().get(1).getHost()); + assertEquals(resourceConfig.getIngressRules().get(1).getPaths().get(0).getResource().getApiGroup(), ingress.getSpec().getRules().get(1).getHttp().getPaths().get(0).getBackend().getResource().getApiGroup()); + assertEquals(resourceConfig.getIngressRules().get(1).getPaths().get(0).getResource().getKind(), ingress.getSpec().getRules().get(1).getHttp().getPaths().get(0).getBackend().getResource().getKind()); + assertEquals(resourceConfig.getIngressRules().get(1).getPaths().get(0).getResource().getName(), ingress.getSpec().getRules().get(1).getHttp().getPaths().get(0).getBackend().getResource().getName()); + assertEquals(resourceConfig.getIngressRules().get(1).getPaths().get(0).getPathType(), ingress.getSpec().getRules().get(1).getHttp().getPaths().get(0).getPathType()); + assertEquals(resourceConfig.getIngressRules().get(1).getPaths().get(0).getPath(), ingress.getSpec().getRules().get(1).getHttp().getPaths().get(0).getPath()); + } + + @Test + public void testCreateIngressFromResourceFragment() { + // Given + new Expectations() {{ + // Enable creation of Ingress for Service of type LoadBalancer + context.getProperty(CREATE_EXTERNAL_URLS); + result = "true"; + }}; + + Service providedService = getTestService().build(); + Ingress providedIngress = getTestIngressFragment().build(); + KubernetesListBuilder kubernetesListBuilder = new KubernetesListBuilder().addToItems(providedService, providedIngress); + IngressEnricher ingressEnricher = new IngressEnricher(context); + + // When + ingressEnricher.create(PlatformMode.kubernetes, kubernetesListBuilder); + + // Then + HasMetadata hasMetadata = kubernetesListBuilder.buildLastItem(); + assertEquals(2, kubernetesListBuilder.buildItems().size()); + assertTrue(hasMetadata instanceof Ingress); + Ingress ingress = (Ingress) hasMetadata; + assertEquals(providedIngress, ingress); + } + @Test public void testAddIngress() { // Given @@ -69,7 +192,7 @@ public void testAddIngress() { KubernetesListBuilder kubernetesListBuilder = new KubernetesListBuilder().addToItems(testSvcBuilder); // When - Ingress ingress = IngressEnricher.addIngress(kubernetesListBuilder, testSvcBuilder, "org.eclipse.jkube", logger); + Ingress ingress = IngressEnricher.addIngress(kubernetesListBuilder, testSvcBuilder, "org.eclipse.jkube", Collections.emptyList(), Collections.emptyList(), logger); // Then assertNotNull(ingress); @@ -78,6 +201,206 @@ public void testAddIngress() { assertEquals(testSvcBuilder.buildMetadata().getName() + "." + "org.eclipse.jkube", ingress.getSpec().getRules().get(0).getHost()); } + @Test + public void testAddIngressWithNullServiceMetadata() { + // Given + ServiceBuilder serviceBuilder = new ServiceBuilder().withMetadata(null); + KubernetesListBuilder kubernetesListBuilder = new KubernetesListBuilder().addToItems(serviceBuilder); + + // When + Ingress ingress = IngressEnricher.addIngress(kubernetesListBuilder, serviceBuilder, "org.eclipse.jkube", Collections.emptyList(), Collections.emptyList(), logger); + + // Then + assertNull(ingress); + } + + @Test + public void testGetServicePortWithHttpPort() { + // Given + ServiceBuilder serviceBuilder = getTestService(); + + // When + Integer port = IngressEnricher.getServicePort(serviceBuilder); + + // Then + assertNotNull(port); + assertEquals(8080, port.intValue()); + } + + @Test + public void testGetServiceWithNoHttpPort() { + // Given + ServiceBuilder serviceBuilder = getTestService() + .editSpec() + .withPorts(new ServicePortBuilder() + .withName("p1") + .withProtocol("TCP") + .withPort(9001) + .build()) + .endSpec(); + + // When + Integer port = IngressEnricher.getServicePort(serviceBuilder); + + // Then + assertNotNull(port); + assertEquals(9001, port.intValue()); + } + + @Test + public void testGetServiceWithNoPort() { + // Given + ServiceBuilder serviceBuilder = getTestService() + .editSpec() + .withPorts(Collections.emptyList()) + .endSpec(); + + // When + Integer port = IngressEnricher.getServicePort(serviceBuilder); + + // Then + assertNotNull(port); + assertEquals(0, port.intValue()); + } + + @Test + public void testShouldCreateExternalURLForService() { + assertTrue(IngressEnricher.shouldCreateExternalURLForService(getTestService(), logger)); + assertFalse(IngressEnricher.shouldCreateExternalURLForService(getTestService().editSpec() + .withType("ClusterIP") + .endSpec(), logger)); + assertFalse(IngressEnricher.shouldCreateExternalURLForService(getTestService().editSpec() + .addNewPort() + .withName("p2") + .withProtocol("TCP") + .withPort(9090) + .endPort() + .endSpec(), logger)); + } + + @Test + public void testGetRouteDomainNoConfig() { + // Given + IngressEnricher ingressEnricher = new IngressEnricher(context); + + // When + String result = ingressEnricher.getRouteDomain(ResourceConfig.builder().build()); + + assertNull(result); + } + + @Test + public void testGetRouteDomainFromResourceConfig() { + // Given + IngressEnricher ingressEnricher = new IngressEnricher(context); + ResourceConfig resourceConfig = ResourceConfig.builder() + .routeDomain("org.eclipse.jkube") + .build(); + + // When + String result = ingressEnricher.getRouteDomain(resourceConfig); + + // Then + assertEquals("org.eclipse.jkube", result); + } + + @Test + public void testGetRouteDomainFromProperty() { + // Given + new Expectations() {{ + context.getProperty("jkube.domain"); + result = "org.eclipse.jkube"; + }}; + IngressEnricher ingressEnricher = new IngressEnricher(context); + + // When + String result = ingressEnricher.getRouteDomain(ResourceConfig.builder().build()); + + // Then + assertEquals("org.eclipse.jkube", result); + } + + @Test + public void testGetIngressRuleXMLConfigWithNonNullResourceConfig() { + // Given + ResourceConfig resourceConfig = ResourceConfig.builder() + .ingressRule(IngressRuleConfig.builder() + .host("host1") + .build()) + .build(); + + // When + List ingressRuleXMLConfig = IngressEnricher.getIngressRuleXMLConfig(resourceConfig); + + // Then + assertNotNull(ingressRuleXMLConfig); + assertEquals(1, ingressRuleXMLConfig.size()); + } + + @Test + public void testGetIngressRuleXMLConfigWithNullResourceConfig() { + // Given + When + List ingressRuleConfigs = IngressEnricher.getIngressRuleXMLConfig(null); + + // Then + assertNotNull(ingressRuleConfigs); + assertTrue(ingressRuleConfigs.isEmpty()); + } + + @Test + public void testGetIngressTlsXMLConfigWithNonNullResourceConfig() { + // Given + ResourceConfig resourceConfig = ResourceConfig.builder() + .ingressTlsConfig(IngressTlsConfig.builder() + .secretName("secret1") + .build()) + .build(); + + // When + List ingressTlsConfig = IngressEnricher.getIngressTlsXMLConfig(resourceConfig); + + // Then + assertNotNull(ingressTlsConfig); + assertEquals(1, ingressTlsConfig.size()); + } + + @Test + public void testGetIngressTlsXMLConfigWithNullResourceConfig() { + // Given + When + List ingressTlsConfigs = IngressEnricher.getIngressTlsXMLConfig(null); + + // Then + assertNotNull(ingressTlsConfigs); + assertTrue(ingressTlsConfigs.isEmpty()); + } + + private IngressBuilder getTestIngressFragment() { + return new IngressBuilder() + .withNewMetadata() + .withName("test-svc") + .addToAnnotations("ingress.kubernetes.io/rewrite-target", "/") + .endMetadata() + .withNewSpec() + .withTls(new IngressTLSBuilder() + .addNewHost("my.host.com") + .withSecretName("letsencrypt-pod") + .build()) + .addNewRule() + .withHost("my.host.com") + .withNewHttp() + .addNewPath() + .withPath("/") + .withPathType("Prefix") + .withNewBackend() + .withServiceName("test-svc") + .withServicePort(new IntOrString(8080)) + .endBackend() + .endPath() + .endHttp() + .endRule() + .endSpec(); + } + private ServiceBuilder getTestService() { return new ServiceBuilder() .withNewMetadata() diff --git a/jkube-kit/enricher/generic/src/test/java/org/eclipse/jkube/enricher/generic/openshift/RouteEnricherTest.java b/jkube-kit/enricher/generic/src/test/java/org/eclipse/jkube/enricher/generic/openshift/RouteEnricherTest.java index c8d04a9aa2..0a06826163 100644 --- a/jkube-kit/enricher/generic/src/test/java/org/eclipse/jkube/enricher/generic/openshift/RouteEnricherTest.java +++ b/jkube-kit/enricher/generic/src/test/java/org/eclipse/jkube/enricher/generic/openshift/RouteEnricherTest.java @@ -222,12 +222,6 @@ public void testCreateOpinionatedRouteFromServiceWithNullService() { assertNull(route); } - @Test - public void testIsExposedService() { - assertTrue(RouteEnricher.isExposedService(new ObjectMetaBuilder().addToLabels("expose", "true").build())); - assertTrue(RouteEnricher.isExposedService(new ObjectMetaBuilder().addToLabels("jkube.io/exposeUrl", "true").build())); - } - @Test public void testMergeRouteWithEmptyFragment() { // Given diff --git a/quickstarts/maven/spring-boot/pom.xml b/quickstarts/maven/spring-boot/pom.xml index 0f22678ec0..d23818d4e0 100644 --- a/quickstarts/maven/spring-boot/pom.xml +++ b/quickstarts/maven/spring-boot/pom.xml @@ -212,6 +212,29 @@ + + + + + https-example.foo.com + + testsecret-tls + + + + + hello.example.systems + + + ImplementationSpecific + / + ${project.artifactId} + 8080 + + + + +