From 987572e0be6c3c9be361279d237adaa3d1a149d1 Mon Sep 17 00:00:00 2001 From: Jose Date: Wed, 11 Jan 2023 15:55:08 +0100 Subject: [PATCH] Add HTTPS port in generated containers by Kubernetes These changes will add an additional container port HTTPS in the generated manifests: ```yaml containers: - image: ... imagePullPolicy: IfNotPresent name: kubernetes-kind ports: - containerPort: 8080 name: http protocol: TCP - containerPort: 8443 name: https protocol: TCP ``` By default, the Ingress and Route resources will use the "http" port. However, as part of these changes, I've added a new property to select between "https" or "http", or any other that user might have added as part of the configuration. Example: ``` quarkus.kubernetes.ingress.target-port=https quarkus.openshift.route.target-port=https ``` Finally, note that the https container won't be added for the Knative resources because of the following Dekorate issue: https://github.com/dekorateio/dekorate/issues/1119. Also, that the nodeport for Kind and Minikube resources will only be added for the http ports due to this Dekorate limitation: https://github.com/dekorateio/dekorate/issues/1120. Both issues should be addressed in Dekorate and then fixed in a later pull requested. Fix https://github.com/quarkusio/quarkus/issues/29999 --- .../asciidoc/deploying-to-kubernetes.adoc | 1 + .../kind/deployment/KindProcessor.java | 14 ++-- .../RemoveNodePortForNotHttpPorts.java | 25 +++++++ .../deployment/AddNodePortDecorator.java | 27 +++----- .../deployment/ApplyIngressRuleDecorator.java | 16 +++++ .../ApplyOpenshiftRouteConfigurator.java | 5 +- .../deployment/DevClusterHelper.java | 19 +++--- .../kubernetes/deployment/IngressConfig.java | 7 ++ .../deployment/KnativeProcessor.java | 12 ++-- .../deployment/KubernetesCommonHelper.java | 30 +++++++-- .../deployment/OpenshiftProcessor.java | 13 ++-- .../ReplacePortNameInDefaultIngressRule.java | 49 ++++++++++++++ .../kubernetes/deployment/RouteConfig.java | 5 +- .../VanillaKubernetesProcessor.java | 26 ++++--- .../http/deployment/VertxHttpProcessor.java | 16 ++++- .../it/kubernetes/BasicKubernetesTest.java | 10 ++- .../it/kubernetes/KindWithDefaultsTest.java | 2 +- .../it/kubernetes/KnativeWithHealthTest.java | 2 +- ...MinikubeWithApplicationPropertiesTest.java | 4 +- .../KubernetesServiceMappingTest.java | 8 +-- ...bernetesWithApplicationPropertiesTest.java | 4 +- .../KubernetesWithCustomResourcesTest.java | 2 +- .../KubernetesWithIngressTargetPortTest.java | 67 +++++++++++++++++++ .../KubernetesWithMultiplePortsTest.java | 6 +- .../KubernetesWithSidecarAndJibTest.java | 2 +- ...MinikubeWithApplicationPropertiesTest.java | 2 +- .../kubernetes/MinikubeWithDefaultsTest.java | 8 ++- ...penshiftWithApplicationPropertiesTest.java | 2 +- .../OpenshiftWithRoutePropertiesTest.java | 2 +- .../it/kubernetes/OpenshiftWithS2iTest.java | 2 +- ...rnetes-with-ingress-target-port.properties | 2 + 31 files changed, 299 insertions(+), 91 deletions(-) create mode 100644 extensions/kubernetes/kind/deployment/src/main/java/io/quarkus/kind/deployment/RemoveNodePortForNotHttpPorts.java create mode 100644 extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/ApplyIngressRuleDecorator.java create mode 100644 extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/ReplacePortNameInDefaultIngressRule.java create mode 100644 integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithIngressTargetPortTest.java create mode 100644 integration-tests/kubernetes/quarkus-standard-way/src/test/resources/kubernetes-with-ingress-target-port.properties diff --git a/docs/src/main/asciidoc/deploying-to-kubernetes.adoc b/docs/src/main/asciidoc/deploying-to-kubernetes.adoc index 54b1535575b8a9..f48f4ea988ac35 100644 --- a/docs/src/main/asciidoc/deploying-to-kubernetes.adoc +++ b/docs/src/main/asciidoc/deploying-to-kubernetes.adoc @@ -770,6 +770,7 @@ To secure the incoming connections, Kubernetes allows enabling https://kubernete [source] ---- quarkus.kubernetes.ingress.expose=true +quarkus.kubernetes.ingress.target-port=https ## Ingress TLS configuration: quarkus.kubernetes.ingress.tls.my-secret.enabled=true ---- diff --git a/extensions/kubernetes/kind/deployment/src/main/java/io/quarkus/kind/deployment/KindProcessor.java b/extensions/kubernetes/kind/deployment/src/main/java/io/quarkus/kind/deployment/KindProcessor.java index 4f8cda93968fef..be9c69ffbc5470 100644 --- a/extensions/kubernetes/kind/deployment/src/main/java/io/quarkus/kind/deployment/KindProcessor.java +++ b/extensions/kubernetes/kind/deployment/src/main/java/io/quarkus/kind/deployment/KindProcessor.java @@ -81,9 +81,8 @@ public void createLabels(KubernetesConfig config, BuildProducer createConfigurators(KubernetesConfig config, List ports) { List result = new ArrayList<>(); - KubernetesCommonHelper.combinePorts(ports, config).entrySet().forEach(e -> { - result.add(new ConfiguratorBuildItem(new AddPortToKubernetesConfig(e.getValue()))); - }); + KubernetesCommonHelper.combinePorts(ports, config).values() + .forEach(value -> result.add(new ConfiguratorBuildItem(new AddPortToKubernetesConfig(value)))); return result; } @@ -106,9 +105,16 @@ public List createDecorators(ApplicationInfoBuildItem applic List roleBindings, Optional customProjectRoot) { - return DevClusterHelper.createDecorators(KIND, applicationInfo, outputTarget, config, packageConfig, + List result = DevClusterHelper.createDecorators(KIND, applicationInfo, outputTarget, config, + packageConfig, metricsConfiguration, annotations, labels, envs, baseImage, image, command, ports, livenessPath, readinessPath, roles, roleBindings, customProjectRoot); + + // TODO: Dekorate sets the same nodeport for all the ports: https://github.com/dekorateio/dekorate/issues/1120 + // so we need to only keep the one for http + String name = ResourceNameUtil.getResourceName(config, applicationInfo); + result.add(new DecoratorBuildItem(KIND, new RemoveNodePortForNotHttpPorts(name))); + return result; } @BuildStep diff --git a/extensions/kubernetes/kind/deployment/src/main/java/io/quarkus/kind/deployment/RemoveNodePortForNotHttpPorts.java b/extensions/kubernetes/kind/deployment/src/main/java/io/quarkus/kind/deployment/RemoveNodePortForNotHttpPorts.java new file mode 100644 index 00000000000000..7df4578fbb13df --- /dev/null +++ b/extensions/kubernetes/kind/deployment/src/main/java/io/quarkus/kind/deployment/RemoveNodePortForNotHttpPorts.java @@ -0,0 +1,25 @@ +package io.quarkus.kind.deployment; + +import io.dekorate.kind.decorator.ApplyPortToKindServiceDecorator; +import io.dekorate.kubernetes.decorator.Decorator; +import io.dekorate.kubernetes.decorator.NamedResourceDecorator; +import io.fabric8.kubernetes.api.model.ObjectMeta; +import io.fabric8.kubernetes.api.model.ServicePortFluent; + +public class RemoveNodePortForNotHttpPorts extends NamedResourceDecorator { + public RemoveNodePortForNotHttpPorts(String name) { + super(name); + } + + @Override + public void andThenVisit(ServicePortFluent servicePort, ObjectMeta objectMeta) { + if (servicePort.hasNodePort() && !servicePort.getName().equals("http")) { + servicePort.withNodePort(null); + } + } + + @Override + public Class[] after() { + return new Class[] { ApplyPortToKindServiceDecorator.class }; + } +} diff --git a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/AddNodePortDecorator.java b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/AddNodePortDecorator.java index 56fd16db6a6a9c..465c02a9dfeaf3 100644 --- a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/AddNodePortDecorator.java +++ b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/AddNodePortDecorator.java @@ -2,7 +2,6 @@ import static io.quarkus.kubernetes.deployment.Constants.*; -import java.util.Optional; import java.util.function.Predicate; import org.jboss.logging.Logger; @@ -18,13 +17,9 @@ public class AddNodePortDecorator extends NamedResourceDecorator matchingPortName; + private final String matchingPortName; - public AddNodePortDecorator(String name, int nodePort) { - this(name, nodePort, Optional.empty()); - } - - public AddNodePortDecorator(String name, int nodePort, Optional matchingPortName) { + public AddNodePortDecorator(String name, int nodePort, String matchingPortName) { super(name); if (nodePort < MIN_NODE_PORT_VALUE || nodePort > MAX_NODE_PORT_VALUE) { log.info("Using a port outside of the " + MIN_NODE_PORT_VALUE + "-" + MAX_NODE_PORT_VALUE @@ -37,18 +32,12 @@ public AddNodePortDecorator(String name, int nodePort, Optional matching @SuppressWarnings("unchecked") @Override public void andThenVisit(ServiceSpecFluent service, ObjectMeta resourceMeta) { - ServiceSpecFluent.PortsNested editPort; - if (matchingPortName.isPresent()) { - editPort = service.editMatchingPort(new Predicate() { - @Override - public boolean test(ServicePortBuilder servicePortBuilder) { - return (servicePortBuilder.hasName()) - && (servicePortBuilder.getName().equals(matchingPortName.get())); - } - }); - } else { - editPort = service.editFirstPort(); - } + ServiceSpecFluent.PortsNested editPort = service.editMatchingPort(new Predicate() { + @Override + public boolean test(ServicePortBuilder servicePortBuilder) { + return servicePortBuilder.hasName() && servicePortBuilder.getName().equals(matchingPortName); + } + }); editPort.withNodePort(nodePort); editPort.endPort(); } diff --git a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/ApplyIngressRuleDecorator.java b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/ApplyIngressRuleDecorator.java new file mode 100644 index 00000000000000..dfe7950147b7f5 --- /dev/null +++ b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/ApplyIngressRuleDecorator.java @@ -0,0 +1,16 @@ +package io.quarkus.kubernetes.deployment; + +import java.util.Optional; + +import io.dekorate.kubernetes.config.IngressRule; +import io.dekorate.kubernetes.config.Port; +import io.dekorate.kubernetes.decorator.AddIngressRuleDecorator; + +/** + * TODO: Workaround for https://github.com/dekorateio/dekorate/issues/1123 where all the ports are being configured as rules. + */ +public class ApplyIngressRuleDecorator extends AddIngressRuleDecorator { + public ApplyIngressRuleDecorator(String name, Optional defaultHostPort, IngressRule rule) { + super(name, defaultHostPort, rule); + } +} diff --git a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/ApplyOpenshiftRouteConfigurator.java b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/ApplyOpenshiftRouteConfigurator.java index 731b02befd50f9..5a1033db69e450 100644 --- a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/ApplyOpenshiftRouteConfigurator.java +++ b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/ApplyOpenshiftRouteConfigurator.java @@ -22,10 +22,7 @@ public void visit(OpenshiftConfigFluent config) { routeBuilder.withHost(routeConfig.host.get()); } - if (routeConfig.targetPort.isPresent()) { - routeBuilder.withTargetPort(routeConfig.targetPort.get()); - } - + routeBuilder.withTargetPort(routeConfig.targetPort); routeBuilder.endRoute(); } } diff --git a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/DevClusterHelper.java b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/DevClusterHelper.java index c16456e7035e73..d530a7d6f77dc5 100644 --- a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/DevClusterHelper.java +++ b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/DevClusterHelper.java @@ -2,7 +2,6 @@ package io.quarkus.kubernetes.deployment; import static io.quarkus.kubernetes.deployment.Constants.DEFAULT_HTTP_PORT; -import static io.quarkus.kubernetes.deployment.Constants.HTTP_PORT; import static io.quarkus.kubernetes.deployment.Constants.KUBERNETES; import static io.quarkus.kubernetes.deployment.Constants.MAX_NODE_PORT_VALUE; import static io.quarkus.kubernetes.deployment.Constants.MAX_PORT_NUMBER; @@ -21,6 +20,7 @@ import io.dekorate.kubernetes.annotation.ServiceType; import io.dekorate.kubernetes.config.EnvBuilder; +import io.dekorate.kubernetes.config.Port; import io.dekorate.kubernetes.decorator.AddEnvVarDecorator; import io.dekorate.kubernetes.decorator.ApplicationContainerDecorator; import io.dekorate.kubernetes.decorator.ApplyImagePullPolicyDecorator; @@ -71,10 +71,11 @@ public static List createDecorators(String clusterKind, Optional project = KubernetesCommonHelper.createProject(applicationInfo, customProjectRoot, outputTarget, packageConfig); + Optional port = KubernetesCommonHelper.getPort(ports, config); result.addAll(KubernetesCommonHelper.createDecorators(project, clusterKind, name, config, metricsConfiguration, annotations, labels, command, - ports, livenessPath, readinessPath, roles, roleBindings)); + port, livenessPath, readinessPath, roles, roleBindings)); image.ifPresent(i -> { result.add(new DecoratorBuildItem(clusterKind, new ApplyContainerImageDecorator(name, i.getImage()))); @@ -102,17 +103,19 @@ public static List createDecorators(String clusterKind, if (!nodeConfigPorts.isEmpty()) { for (Map.Entry entry : nodeConfigPorts) { result.add(new DecoratorBuildItem(KUBERNETES, - new AddNodePortDecorator(name, entry.getValue().nodePort.getAsInt(), Optional.of(entry.getKey())))); + new AddNodePortDecorator(name, entry.getValue().nodePort.getAsInt(), entry.getKey()))); } } else { - result.add(new DecoratorBuildItem(clusterKind, new AddNodePortDecorator(name, config.getNodePort() - .orElseGet(() -> getStablePortNumberInRange(name, MIN_NODE_PORT_VALUE, MAX_NODE_PORT_VALUE))))); + result.add(new DecoratorBuildItem(clusterKind, + new AddNodePortDecorator(name, + config.getNodePort().orElseGet( + () -> getStablePortNumberInRange(name, MIN_NODE_PORT_VALUE, MAX_NODE_PORT_VALUE)), + config.ingress.targetPort))); } //Probe port handling - Integer port = ports.stream().filter(p -> HTTP_PORT.equals(p.getName())).map(KubernetesPortBuildItem::getPort) - .findFirst().orElse(DEFAULT_HTTP_PORT); - result.add(new DecoratorBuildItem(clusterKind, new ApplyHttpGetActionPortDecorator(name, name, port))); + Integer portNumber = port.map(Port::getContainerPort).orElse(DEFAULT_HTTP_PORT); + result.add(new DecoratorBuildItem(clusterKind, new ApplyHttpGetActionPortDecorator(name, name, portNumber))); return result; } diff --git a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/IngressConfig.java b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/IngressConfig.java index 3fe9fea8b6db59..3264c9c2067035 100644 --- a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/IngressConfig.java +++ b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/IngressConfig.java @@ -27,6 +27,13 @@ public class IngressConfig { @ConfigItem Optional ingressClassName; + /** + * The default target named port. If not provided, it will be deducted from the Service resource ports. + * Options are: "http" and "https". + */ + @ConfigItem(defaultValue = "http") + String targetPort; + /** * Custom annotations to add to exposition (route or ingress) resources */ diff --git a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/KnativeProcessor.java b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/KnativeProcessor.java index 5dbdae6a96256b..0b97f1338a1ef7 100644 --- a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/KnativeProcessor.java +++ b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/KnativeProcessor.java @@ -29,6 +29,7 @@ import io.dekorate.knative.decorator.ApplyServiceAccountToRevisionSpecDecorator; import io.dekorate.knative.decorator.ApplyTrafficDecorator; import io.dekorate.kubernetes.config.EnvBuilder; +import io.dekorate.kubernetes.config.Port; import io.dekorate.kubernetes.decorator.AddConfigMapDataDecorator; import io.dekorate.kubernetes.decorator.AddConfigMapResourceProvidingDecorator; import io.dekorate.kubernetes.decorator.AddEnvVarDecorator; @@ -116,9 +117,11 @@ public void createLabels(KnativeConfig config, BuildProducer createConfigurators(KnativeConfig config, List ports) { List result = new ArrayList<>(); - KubernetesCommonHelper.combinePorts(ports, config).values().forEach(value -> { - result.add(new ConfiguratorBuildItem(new AddPortToKnativeConfig(value))); - }); + KubernetesCommonHelper.combinePorts(ports, config).values() + // TODO: At the moment, Knative only supports http ports because this issue in Dekorate: + // https://github.com/dekorateio/dekorate/issues/1119 + .stream().filter(p -> p.getName().equals("http")) + .forEach(value -> result.add(new ConfiguratorBuildItem(new AddPortToKnativeConfig(value)))); return result; } @@ -151,8 +154,9 @@ public List createDecorators(ApplicationInfoBuildItem applic String name = ResourceNameUtil.getResourceName(config, applicationInfo); Optional project = KubernetesCommonHelper.createProject(applicationInfo, customProjectRoot, outputTarget, packageConfig); + Optional port = KubernetesCommonHelper.getPort(ports, config, "http"); result.addAll(KubernetesCommonHelper.createDecorators(project, KNATIVE, name, config, metricsConfiguration, annotations, - labels, command, ports, livenessPath, readinessPath, roles, roleBindings)); + labels, command, port, livenessPath, readinessPath, roles, roleBindings)); image.ifPresent(i -> { result.add(new DecoratorBuildItem(KNATIVE, new ApplyContainerImageDecorator(name, i.getImage()))); diff --git a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/KubernetesCommonHelper.java b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/KubernetesCommonHelper.java index 043ba96b1ea15d..24b09a99aca44e 100644 --- a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/KubernetesCommonHelper.java +++ b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/KubernetesCommonHelper.java @@ -1,6 +1,7 @@ package io.quarkus.kubernetes.deployment; +import static io.dekorate.kubernetes.decorator.AddServiceResourceDecorator.distinct; import static io.quarkus.kubernetes.deployment.Constants.QUARKUS_ANNOTATIONS_BUILD_TIMESTAMP; import static io.quarkus.kubernetes.deployment.Constants.QUARKUS_ANNOTATIONS_COMMIT_ID; import static io.quarkus.kubernetes.deployment.Constants.QUARKUS_ANNOTATIONS_VCS_URL; @@ -112,6 +113,23 @@ public static Optional createProject(ApplicationInfoBuildItem app, } } + /** + * Creates the configurator build items. + */ + public static Optional getPort(List ports, KubernetesConfig config) { + return getPort(ports, config, config.ingress.targetPort); + } + + /** + * Creates the configurator build items. + */ + public static Optional getPort(List ports, PlatformConfiguration config, String targetPort) { + return combinePorts(ports, config).values().stream() + .filter(distinct(p -> p.getName())) + .filter(p -> p.getName().equals(targetPort)) + .findFirst(); + } + /** * Creates the configurator build items. */ @@ -153,7 +171,7 @@ public static List createDecorators(Optional projec List annotations, List labels, Optional command, - List ports, + Optional port, Optional livenessProbePath, Optional readinessProbePath, List roles, @@ -161,7 +179,7 @@ public static List createDecorators(Optional projec List result = new ArrayList<>(); result.addAll(createLabelDecorators(project, target, name, config, labels)); - result.addAll(createAnnotationDecorators(project, target, name, config, metricsConfiguration, annotations, ports)); + result.addAll(createAnnotationDecorators(project, target, name, config, metricsConfiguration, annotations, port)); result.addAll(createPodDecorators(project, target, name, config)); result.addAll(createContainerDecorators(project, target, name, config)); result.addAll(createMountAndVolumeDecorators(project, target, name, config)); @@ -171,7 +189,7 @@ public static List createDecorators(Optional projec result.addAll(createArgsDecorator(project, target, name, config, command)); //Handle Probes - if (!ports.isEmpty()) { + if (!port.isEmpty()) { result.addAll(createProbeDecorators(name, target, config.getLivenessProbe(), config.getReadinessProbe(), livenessProbePath, readinessProbePath)); } @@ -428,7 +446,7 @@ private static List createAnnotationDecorators(Optional metricsConfiguration, List annotations, - List ports) { + Optional port) { List result = new ArrayList<>(); annotations.forEach(a -> { @@ -471,14 +489,14 @@ private static List createAnnotationDecorators(Optional { String path = m.metricsEndpoint(); String prefix = config.getPrometheusConfig().prefix; - if (!ports.isEmpty() && path != null) { + if (port.isPresent() && path != null) { result.add(new DecoratorBuildItem(target, new AddAnnotationDecorator(name, config.getPrometheusConfig().scrape.orElse(prefix + "/scrape"), "true", PROMETHEUS_ANNOTATION_TARGETS))); result.add(new DecoratorBuildItem(target, new AddAnnotationDecorator(name, config.getPrometheusConfig().path.orElse(prefix + "/path"), path, PROMETHEUS_ANNOTATION_TARGETS))); result.add(new DecoratorBuildItem(target, new AddAnnotationDecorator(name, - config.getPrometheusConfig().port.orElse(prefix + "/port"), "" + ports.get(0).getPort(), + config.getPrometheusConfig().port.orElse(prefix + "/port"), "" + port.get().getContainerPort(), PROMETHEUS_ANNOTATION_TARGETS))); result.add(new DecoratorBuildItem(target, new AddAnnotationDecorator(name, config.getPrometheusConfig().scheme.orElse(prefix + "/scheme"), "http", diff --git a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/OpenshiftProcessor.java b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/OpenshiftProcessor.java index 2fc01290b51a90..8ccb1cc0d79bca 100644 --- a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/OpenshiftProcessor.java +++ b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/OpenshiftProcessor.java @@ -3,7 +3,6 @@ import static io.quarkus.kubernetes.deployment.Constants.DEFAULT_HTTP_PORT; import static io.quarkus.kubernetes.deployment.Constants.DEFAULT_S2I_IMAGE_NAME; -import static io.quarkus.kubernetes.deployment.Constants.HTTP_PORT; import static io.quarkus.kubernetes.deployment.Constants.OPENSHIFT; import static io.quarkus.kubernetes.deployment.Constants.OPENSHIFT_APP_RUNTIME; import static io.quarkus.kubernetes.deployment.Constants.QUARKUS; @@ -21,6 +20,7 @@ import io.dekorate.kubernetes.config.EnvBuilder; import io.dekorate.kubernetes.config.ImageConfiguration; import io.dekorate.kubernetes.config.ImageConfigurationBuilder; +import io.dekorate.kubernetes.config.Port; import io.dekorate.kubernetes.decorator.AddAnnotationDecorator; import io.dekorate.kubernetes.decorator.AddEnvVarDecorator; import io.dekorate.kubernetes.decorator.AddLabelDecorator; @@ -191,10 +191,11 @@ public List createDecorators(ApplicationInfoBuildItem applic Optional project = KubernetesCommonHelper.createProject(applicationInfo, customProjectRoot, outputTarget, packageConfig); + Optional port = KubernetesCommonHelper.getPort(ports, config, config.route.targetPort); result.addAll(KubernetesCommonHelper.createDecorators(project, OPENSHIFT, name, config, metricsConfiguration, annotations, labels, command, - ports, livenessPath, readinessPath, roles, roleBindings)); + port, livenessPath, readinessPath, roles, roleBindings)); if (config.flavor == v3) { //Openshift 3.x doesn't recognize 'app.kubernetes.io/name', it uses 'app' instead. @@ -289,13 +290,13 @@ public List createDecorators(ApplicationInfoBuildItem applic // Service handling result.add(new DecoratorBuildItem(OPENSHIFT, new ApplyServiceTypeDecorator(name, config.getServiceType().name()))); if ((config.getServiceType() == ServiceType.NodePort) && config.nodePort.isPresent()) { - result.add(new DecoratorBuildItem(OPENSHIFT, new AddNodePortDecorator(name, config.nodePort.getAsInt()))); + result.add(new DecoratorBuildItem(OPENSHIFT, + new AddNodePortDecorator(name, config.nodePort.getAsInt(), config.route.targetPort))); } // Probe port handling - Integer port = ports.stream().filter(p -> HTTP_PORT.equals(p.getName())).map(KubernetesPortBuildItem::getPort) - .findFirst().orElse(DEFAULT_HTTP_PORT); - result.add(new DecoratorBuildItem(OPENSHIFT, new ApplyHttpGetActionPortDecorator(name, name, port))); + Integer portNumber = port.map(Port::getContainerPort).orElse(DEFAULT_HTTP_PORT); + result.add(new DecoratorBuildItem(OPENSHIFT, new ApplyHttpGetActionPortDecorator(name, name, portNumber))); // Handle non-openshift builds if (deploymentKind == DeploymentResourceKind.DeploymentConfig diff --git a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/ReplacePortNameInDefaultIngressRule.java b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/ReplacePortNameInDefaultIngressRule.java new file mode 100644 index 00000000000000..6d3dd224712773 --- /dev/null +++ b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/ReplacePortNameInDefaultIngressRule.java @@ -0,0 +1,49 @@ +package io.quarkus.kubernetes.deployment; + +import io.dekorate.kubernetes.decorator.AddIngressDecorator; +import io.dekorate.kubernetes.decorator.AddIngressRuleDecorator; +import io.dekorate.kubernetes.decorator.Decorator; +import io.dekorate.kubernetes.decorator.NamedResourceDecorator; +import io.fabric8.kubernetes.api.model.ObjectMeta; +import io.fabric8.kubernetes.api.model.networking.v1.HTTPIngressPathBuilder; +import io.fabric8.kubernetes.api.model.networking.v1.IngressSpecBuilder; + +public class ReplacePortNameInDefaultIngressRule extends NamedResourceDecorator { + + private final String host; + private final String targetPortName; + + public ReplacePortNameInDefaultIngressRule(String name, String host, String targetPortName) { + super(name); + this.host = host; + this.targetPortName = targetPortName; + } + + @Override + public void andThenVisit(IngressSpecBuilder spec, ObjectMeta objectMeta) { + spec.editMatchingRule(r -> host == null || host.equals(r.getHost())) + .editHttp() + .removeMatchingFromPaths(p -> pathForCurrentService(p) && !pathUsingTargetPort(p)) + .endHttp() + .endRule() + .build(); + } + + @Override + public Class[] after() { + return new Class[] { AddIngressDecorator.class, AddIngressRuleDecorator.class }; + } + + @Override + public Class[] before() { + return new Class[] { ApplyIngressRuleDecorator.class }; + } + + private boolean pathForCurrentService(HTTPIngressPathBuilder path) { + return path.hasBackend() && getName().equals(path.getBackend().getService().getName()); + } + + private boolean pathUsingTargetPort(HTTPIngressPathBuilder path) { + return path.getBackend().getService().getPort().getName().equals(targetPortName); + } +} diff --git a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/RouteConfig.java b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/RouteConfig.java index 65680fdb2c1f8d..075cae4cf3d456 100644 --- a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/RouteConfig.java +++ b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/RouteConfig.java @@ -23,9 +23,10 @@ public class RouteConfig { /** * The target named port. If not provided, it will be deducted from the Service resource ports. + * Options are: "http" and "https". */ - @ConfigItem - Optional targetPort; + @ConfigItem(defaultValue = "http") + String targetPort; /** * Custom annotations to add to exposition (route or ingress) resources diff --git a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/VanillaKubernetesProcessor.java b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/VanillaKubernetesProcessor.java index 60e5fc20c28e11..94f6cd7e9eb586 100644 --- a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/VanillaKubernetesProcessor.java +++ b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/VanillaKubernetesProcessor.java @@ -1,11 +1,9 @@ package io.quarkus.kubernetes.deployment; -import static io.dekorate.kubernetes.decorator.AddServiceResourceDecorator.distinct; import static io.quarkus.kubernetes.deployment.Constants.DEFAULT_HTTP_PORT; import static io.quarkus.kubernetes.deployment.Constants.DEPLOYMENT_GROUP; import static io.quarkus.kubernetes.deployment.Constants.DEPLOYMENT_VERSION; -import static io.quarkus.kubernetes.deployment.Constants.HTTP_PORT; import static io.quarkus.kubernetes.deployment.Constants.INGRESS; import static io.quarkus.kubernetes.deployment.Constants.KUBERNETES; import static io.quarkus.kubernetes.spi.KubernetesDeploymentTargetBuildItem.VANILLA_KUBERNETES_PRIORITY; @@ -24,7 +22,6 @@ import io.dekorate.kubernetes.config.Port; import io.dekorate.kubernetes.decorator.AddAnnotationDecorator; import io.dekorate.kubernetes.decorator.AddEnvVarDecorator; -import io.dekorate.kubernetes.decorator.AddIngressRuleDecorator; import io.dekorate.kubernetes.decorator.AddIngressTlsDecorator; import io.dekorate.kubernetes.decorator.ApplicationContainerDecorator; import io.dekorate.kubernetes.decorator.ApplyImagePullPolicyDecorator; @@ -118,7 +115,6 @@ public List createConfigurators(KubernetesConfig config, } return result; - } @BuildStep @@ -141,8 +137,9 @@ public List createDecorators(ApplicationInfoBuildItem applic Optional project = KubernetesCommonHelper.createProject(applicationInfo, customProjectRoot, outputTarget, packageConfig); + Optional port = KubernetesCommonHelper.getPort(ports, config); result.addAll(KubernetesCommonHelper.createDecorators(project, KUBERNETES, name, config, metricsConfiguration, - annotations, labels, command, ports, livenessPath, readinessPath, roles, roleBindings)); + annotations, labels, command, port, livenessPath, readinessPath, roles, roleBindings)); KubernetesConfig.DeploymentResourceKind deploymentKind = config.getDeploymentResourceKind(capabilities); if (deploymentKind != KubernetesConfig.DeploymentResourceKind.Deployment) { @@ -178,12 +175,13 @@ public List createDecorators(ApplicationInfoBuildItem applic new AddAnnotationDecorator(name, annotation.getKey(), annotation.getValue(), INGRESS))); } - Optional defaultHostPort = KubernetesCommonHelper.combinePorts(ports, config).values().stream() - .filter(distinct(p -> p.getName())) - .findFirst(); + // Workaround to overwrite the default target ports that Dekorate internally configures: + result.add(new DecoratorBuildItem(KUBERNETES, new ReplacePortNameInDefaultIngressRule(name, + config.ingress.host.orElse(null), + config.ingress.targetPort))); for (IngressRuleConfig rule : config.ingress.rules.values()) { - result.add(new DecoratorBuildItem(KUBERNETES, new AddIngressRuleDecorator(name, defaultHostPort, + result.add(new DecoratorBuildItem(KUBERNETES, new ApplyIngressRuleDecorator(name, port, new IngressRuleBuilder() .withHost(rule.host) .withPath(rule.path) @@ -230,17 +228,17 @@ public List createDecorators(ApplicationInfoBuildItem applic if (!nodeConfigPorts.isEmpty()) { for (Map.Entry entry : nodeConfigPorts) { result.add(new DecoratorBuildItem(KUBERNETES, - new AddNodePortDecorator(name, entry.getValue().nodePort.getAsInt(), Optional.of(entry.getKey())))); + new AddNodePortDecorator(name, entry.getValue().nodePort.getAsInt(), entry.getKey()))); } } else if (config.nodePort.isPresent()) { - result.add(new DecoratorBuildItem(KUBERNETES, new AddNodePortDecorator(name, config.nodePort.getAsInt()))); + result.add(new DecoratorBuildItem(KUBERNETES, + new AddNodePortDecorator(name, config.nodePort.getAsInt(), config.ingress.targetPort))); } } // Probe port handling - Integer port = ports.stream().filter(p -> HTTP_PORT.equals(p.getName())).map(KubernetesPortBuildItem::getPort) - .findFirst().orElse(DEFAULT_HTTP_PORT); - result.add(new DecoratorBuildItem(KUBERNETES, new ApplyHttpGetActionPortDecorator(name, name, port))); + Integer portNumber = port.map(Port::getContainerPort).orElse(DEFAULT_HTTP_PORT); + result.add(new DecoratorBuildItem(KUBERNETES, new ApplyHttpGetActionPortDecorator(name, name, portNumber))); // Handle remote debug configuration if (config.remoteDebug.enabled) { diff --git a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/VertxHttpProcessor.java b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/VertxHttpProcessor.java index 0380a2925edc24..b095f2b0b4ab21 100644 --- a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/VertxHttpProcessor.java +++ b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/VertxHttpProcessor.java @@ -56,6 +56,7 @@ import io.quarkus.vertx.http.runtime.CurrentRequestProducer; import io.quarkus.vertx.http.runtime.CurrentVertxRequest; import io.quarkus.vertx.http.runtime.HttpBuildTimeConfig; +import io.quarkus.vertx.http.runtime.HttpConfiguration; import io.quarkus.vertx.http.runtime.HttpHostConfigSource; import io.quarkus.vertx.http.runtime.VertxHttpRecorder; import io.quarkus.vertx.http.runtime.attribute.ExchangeAttributeBuilder; @@ -147,9 +148,20 @@ void filterMultipleVertxInstancesWarning(LaunchModeBuildItem launchModeBuildItem } @BuildStep - public KubernetesPortBuildItem kubernetes() { + public void kubernetes(BuildProducer kubernetesPorts) { + HttpConfiguration.InsecureRequests insecureRequests = ConfigProvider.getConfig() + .getOptionalValue("quarkus.http.insecure-requests", HttpConfiguration.InsecureRequests.class) + .orElse(HttpConfiguration.InsecureRequests.ENABLED); + if (insecureRequests != HttpConfiguration.InsecureRequests.DISABLED) { + // ssl is not disabled + int sslPort = ConfigProvider.getConfig() + .getOptionalValue("quarkus.http.ssl-port", Integer.class) + .orElse(8443); + kubernetesPorts.produce(new KubernetesPortBuildItem(sslPort, "https")); + } + int port = ConfigProvider.getConfig().getOptionalValue("quarkus.http.port", Integer.class).orElse(8080); - return new KubernetesPortBuildItem(port, "http"); + kubernetesPorts.produce(new KubernetesPortBuildItem(port, "http")); } @BuildStep diff --git a/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/BasicKubernetesTest.java b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/BasicKubernetesTest.java index cf2c06f8dc6406..2f087e1ebb512f 100644 --- a/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/BasicKubernetesTest.java +++ b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/BasicKubernetesTest.java @@ -78,8 +78,7 @@ public void assertGeneratedResources() throws IOException { assertThat(podSpec.getSecurityContext()).isNull(); assertThat(podSpec.getContainers()).singleElement().satisfies(container -> { assertThat(container.getImagePullPolicy()).isEqualTo("Always"); // expect the default value - assertThat(container.getPorts()).singleElement().satisfies(p -> { - + assertThat(container.getPorts()).hasSize(2).anySatisfy(p -> { assertThat(p.getContainerPort()).isEqualTo(8080); }); }); @@ -96,10 +95,15 @@ public void assertGeneratedResources() throws IOException { assertThat(spec.getSelector()).containsOnly(entry("app.kubernetes.io/name", "basic"), entry("app.kubernetes.io/version", "0.1-SNAPSHOT")); - assertThat(spec.getPorts()).hasSize(1).singleElement().satisfies(p -> { + assertThat(spec.getPorts()).hasSize(2).anySatisfy(p -> { assertThat(p.getPort()).isEqualTo(80); assertThat(p.getTargetPort().getIntVal()).isEqualTo(8080); }); + + assertThat(spec.getPorts()).hasSize(2).anySatisfy(p -> { + assertThat(p.getPort()).isEqualTo(443); + assertThat(p.getTargetPort().getIntVal()).isEqualTo(8443); + }); }); }); } diff --git a/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KindWithDefaultsTest.java b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KindWithDefaultsTest.java index fd3735691ec82b..6f6223fc798028 100644 --- a/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KindWithDefaultsTest.java +++ b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KindWithDefaultsTest.java @@ -71,7 +71,7 @@ public void assertGeneratedResources() throws IOException { assertThat(s.getSpec()).satisfies(spec -> { assertEquals("NodePort", spec.getType()); - assertThat(spec.getPorts()).hasSize(1).singleElement().satisfies(p -> { + assertThat(spec.getPorts()).hasSize(2).anySatisfy(p -> { assertThat(p.getNodePort()).isNotNull(); }); }); diff --git a/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KnativeWithHealthTest.java b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KnativeWithHealthTest.java index 0d3dc92619a7fa..7c864082ded539 100644 --- a/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KnativeWithHealthTest.java +++ b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KnativeWithHealthTest.java @@ -54,7 +54,7 @@ public void assertGeneratedResources() throws IOException { assertThat(spec.getTemplate()).satisfies(template -> { assertThat(template.getSpec()).satisfies(templateSpec -> { assertThat(templateSpec.getContainers()).hasSize(1).singleElement().satisfies(c -> { - assertThat(c.getPorts()).hasSize(1).singleElement().satisfies(p -> { + assertThat(c.getPorts()).hasSize(1).anySatisfy(p -> { assertThat(p.getName()).isEqualTo("http1"); }); assertThat(c.getReadinessProbe()).isNotNull().satisfies(p -> { diff --git a/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesAndMinikubeWithApplicationPropertiesTest.java b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesAndMinikubeWithApplicationPropertiesTest.java index d78895a5ced4a1..5274a01c492ace 100644 --- a/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesAndMinikubeWithApplicationPropertiesTest.java +++ b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesAndMinikubeWithApplicationPropertiesTest.java @@ -72,7 +72,7 @@ private void assertKubernetes(Path kubernetesDir) throws IOException { assertThat(i).isInstanceOfSatisfying(Service.class, s -> { assertThat(s.getSpec()).satisfies(spec -> { assertEquals("ClusterIP", spec.getType()); - assertThat(spec.getPorts()).hasSize(1).singleElement().satisfies(p -> { + assertThat(spec.getPorts()).hasSize(2).anySatisfy(p -> { assertThat(p.getNodePort()).isNull(); assertThat(p.getPort()).isEqualTo(80); assertThat(p.getTargetPort().getIntVal()).isEqualTo(9090); @@ -109,7 +109,7 @@ private void assertMinikube(Path kubernetesDir) throws IOException { assertThat(i).isInstanceOfSatisfying(Service.class, s -> { assertThat(s.getSpec()).satisfies(spec -> { assertEquals("NodePort", spec.getType()); - assertThat(spec.getPorts()).hasSize(1).singleElement().satisfies(p -> { + assertThat(spec.getPorts()).hasSize(2).anySatisfy(p -> { assertThat(p.getNodePort()).isNotNull(); assertThat(p.getPort()).isEqualTo(80); assertThat(p.getTargetPort().getIntVal()).isEqualTo(9090); diff --git a/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesServiceMappingTest.java b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesServiceMappingTest.java index 08810c40da738a..d49f646ed7a039 100644 --- a/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesServiceMappingTest.java +++ b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesServiceMappingTest.java @@ -55,15 +55,15 @@ public void assertGeneratedResources() throws IOException { assertThat(deploymentSpec.getTemplate()).satisfies(t -> { assertThat(t.getSpec()).satisfies(podSpec -> { List ports = podSpec.getContainers().get(0).getPorts(); - assertThat(ports.size()).isEqualTo(2); + assertThat(ports.size()).isEqualTo(3); assertTrue(ports.stream().anyMatch(port -> "http".equals(port.getName()) && port.getContainerPort() == 8080 && "TCP".equals(port.getProtocol())), - () -> "http port not found in the pod containers!"); + "http port not found in the pod containers!"); assertTrue(ports.stream().anyMatch(port -> "debug".equals(port.getName()) && port.getContainerPort() == 5005 && "UDP".equals(port.getProtocol())), - () -> "debug port not found in the pod containers!"); + "debug port not found in the pod containers!"); }); }); }); @@ -74,7 +74,7 @@ public void assertGeneratedResources() throws IOException { assertThat(m.getName()).isEqualTo("kubernetes-service-mapping"); }); assertThat(s.getSpec()).satisfies(serviceSpec -> { - assertThat(serviceSpec.getPorts().size()).isEqualTo(2); + assertThat(serviceSpec.getPorts().size()).isEqualTo(3); assertTrue(serviceSpec.getPorts().stream().anyMatch(port -> "http".equals(port.getName()) && port.getTargetPort().getIntVal() == 8080 && "TCP".equals(port.getProtocol()) diff --git a/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithApplicationPropertiesTest.java b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithApplicationPropertiesTest.java index 78e00fa64cb5ef..809001232da48c 100644 --- a/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithApplicationPropertiesTest.java +++ b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithApplicationPropertiesTest.java @@ -72,7 +72,7 @@ public void assertGeneratedResources() throws IOException { assertThat(container.getImage()) .isEqualTo("quay.io/grp/kubernetes-with-application-properties:0.1-SNAPSHOT"); - assertThat(container.getPorts()).singleElement().satisfies(p -> { + assertThat(container.getPorts()).anySatisfy(p -> { assertThat(p.getContainerPort()).isEqualTo(9090); }); assertThat(container.getImagePullPolicy()).isEqualTo("IfNotPresent"); @@ -93,7 +93,7 @@ public void assertGeneratedResources() throws IOException { assertThat(s.getSpec()).satisfies(spec -> { assertEquals("NodePort", spec.getType()); assertThat(spec.getSelector()).containsOnly(entry("app.kubernetes.io/name", "test-it")); - assertThat(spec.getPorts()).hasSize(1).singleElement().satisfies(p -> { + assertThat(spec.getPorts()).hasSize(2).anySatisfy(p -> { assertThat(p.getPort()).isEqualTo(80); assertThat(p.getTargetPort().getIntVal()).isEqualTo(9090); }); diff --git a/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithCustomResourcesTest.java b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithCustomResourcesTest.java index 3225ed9258f3e5..fb829b72f4a99f 100644 --- a/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithCustomResourcesTest.java +++ b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithCustomResourcesTest.java @@ -89,7 +89,7 @@ public void assertGeneratedResources() throws IOException { assertThat(spec.getSelector()).containsOnly(entry("app.kubernetes.io/name", "custom-resources"), entry("app.kubernetes.io/version", "0.1-SNAPSHOT")); - assertThat(spec.getPorts()).hasSize(1).singleElement().satisfies(p -> { + assertThat(spec.getPorts()).hasSize(2).anySatisfy(p -> { assertThat(p.getPort()).isEqualTo(80); assertThat(p.getTargetPort().getIntVal()).isEqualTo(8080); }); diff --git a/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithIngressTargetPortTest.java b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithIngressTargetPortTest.java new file mode 100644 index 00000000000000..76d0a327c1f899 --- /dev/null +++ b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithIngressTargetPortTest.java @@ -0,0 +1,67 @@ + +package io.quarkus.it.kubernetes; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.List; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.fabric8.kubernetes.api.model.apps.Deployment; +import io.fabric8.kubernetes.api.model.networking.v1.Ingress; +import io.quarkus.builder.Version; +import io.quarkus.maven.dependency.Dependency; +import io.quarkus.test.ProdBuildResults; +import io.quarkus.test.ProdModeTestResults; +import io.quarkus.test.QuarkusProdModeTest; + +public class KubernetesWithIngressTargetPortTest { + + private static final String APP_NAME = "kubernetes-with-ingress-target-port"; + + @RegisterExtension + static final QuarkusProdModeTest config = new QuarkusProdModeTest() + .withApplicationRoot((jar) -> jar.addClasses(GreetingResource.class)) + .setApplicationName(APP_NAME) + .setApplicationVersion("0.1-SNAPSHOT") + .withConfigurationResource(APP_NAME + ".properties") + .setLogFileName("k8s.log") + .setForcedDependencies(List.of(Dependency.of("io.quarkus", "quarkus-kubernetes", Version.getVersion()))); + + @ProdBuildResults + private ProdModeTestResults prodModeTestResults; + + @Test + public void assertGeneratedResources() throws IOException { + final Path kubernetesDir = prodModeTestResults.getBuildDir().resolve("kubernetes"); + assertThat(kubernetesDir) + .isDirectoryContaining(p -> p.getFileName().endsWith("kubernetes.json")) + .isDirectoryContaining(p -> p.getFileName().endsWith("kubernetes.yml")); + List kubernetesList = DeserializationUtil + .deserializeAsList(kubernetesDir.resolve("kubernetes.yml")); + + assertThat(kubernetesList.get(0)).isInstanceOfSatisfying(Deployment.class, d -> { + assertThat(d.getMetadata()).satisfies(m -> { + assertThat(m.getName()).isEqualTo(APP_NAME); + }); + }); + + assertThat(kubernetesList).filteredOn(i -> "Ingress".equals(i.getKind())).singleElement().satisfies(item -> { + assertThat(item).isInstanceOfSatisfying(Ingress.class, ingress -> { + assertThat(ingress.getMetadata()).satisfies(m -> { + assertThat(m.getName()).isEqualTo(APP_NAME); + }); + + assertThat(ingress.getSpec().getRules()).allSatisfy(rule -> { + assertThat(rule.getHttp().getPaths()).allSatisfy(path -> { + assertThat(path.getBackend().getService().getPort().getName()).isEqualTo("https"); + }); + }); + }); + }); + } +} diff --git a/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithMultiplePortsTest.java b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithMultiplePortsTest.java index f22eb638671dc9..50c8889d83b4c2 100644 --- a/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithMultiplePortsTest.java +++ b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithMultiplePortsTest.java @@ -50,9 +50,11 @@ public void assertGeneratedResources() throws IOException { assertThat(deploymentSpec.getTemplate()).satisfies(t -> { assertThat(t.getSpec()).satisfies(podSpec -> { assertThat(podSpec.getContainers()).singleElement().satisfies(container -> { - assertThat(container.getPorts()).hasSize(2); + assertThat(container.getPorts()).hasSize(3); assertThat(container.getPorts()).filteredOn(cp -> cp.getContainerPort() == 8080).singleElement() .satisfies(c -> assertThat(c.getName()).isEqualTo("http")); + assertThat(container.getPorts()).filteredOn(cp -> cp.getContainerPort() == 8443).singleElement() + .satisfies(c -> assertThat(c.getName()).isEqualTo("https")); assertThat(container.getPorts()).filteredOn(cp -> cp.getContainerPort() == 5005).singleElement() .satisfies(c -> assertThat(c.getName()).isEqualTo("remote")); }); @@ -66,7 +68,7 @@ public void assertGeneratedResources() throws IOException { assertThat(i).isInstanceOfSatisfying(Service.class, s -> { assertThat(s.getSpec()).satisfies(spec -> { assertEquals("NodePort", spec.getType()); - assertThat(spec.getPorts()).hasSize(2); + assertThat(spec.getPorts()).hasSize(3); assertThat(spec.getPorts()).filteredOn(sp -> sp.getPort() == 8080).singleElement().satisfies(p -> { assertThat(p.getNodePort()).isEqualTo(30000); }); diff --git a/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithSidecarAndJibTest.java b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithSidecarAndJibTest.java index 896d2602387ad8..9560575704d8f8 100644 --- a/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithSidecarAndJibTest.java +++ b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithSidecarAndJibTest.java @@ -66,7 +66,7 @@ private void assertApplicationContainer(io.fabric8.kubernetes.api.model.PodSpec assertThat(c.getArgs()).isEmpty(); assertThat(c.getWorkingDir()).isNull(); assertThat(c.getVolumeMounts()).isEmpty(); - assertThat(c.getPorts()).singleElement().satisfies(p -> assertThat(p.getContainerPort()).isEqualTo(8080)); + assertThat(c.getPorts()).anySatisfy(p -> assertThat(p.getContainerPort()).isEqualTo(8080)); assertThat(c.getEnv()).allSatisfy(e -> assertThat(e.getName()).isNotEqualToIgnoringCase("foo")); }); } diff --git a/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/MinikubeWithApplicationPropertiesTest.java b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/MinikubeWithApplicationPropertiesTest.java index 64fbf02727315f..9b71dd3e13a868 100644 --- a/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/MinikubeWithApplicationPropertiesTest.java +++ b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/MinikubeWithApplicationPropertiesTest.java @@ -72,7 +72,7 @@ public void assertGeneratedResources() throws IOException { assertThat(s.getSpec()).satisfies(spec -> { assertEquals("NodePort", spec.getType()); - assertThat(spec.getPorts()).hasSize(1).singleElement().satisfies(p -> { + assertThat(spec.getPorts()).hasSize(2).anySatisfy(p -> { assertThat(p.getNodePort()).isEqualTo(31999); assertThat(p.getPort()).isEqualTo(80); assertThat(p.getTargetPort().getIntVal()).isEqualTo(9090); diff --git a/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/MinikubeWithDefaultsTest.java b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/MinikubeWithDefaultsTest.java index d3499db1986fff..8e2050db79c20a 100644 --- a/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/MinikubeWithDefaultsTest.java +++ b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/MinikubeWithDefaultsTest.java @@ -70,9 +70,15 @@ public void assertGeneratedResources() throws IOException { assertThat(s.getSpec()).satisfies(spec -> { assertEquals("NodePort", spec.getType()); - assertThat(spec.getPorts()).hasSize(1).singleElement().satisfies(p -> { + assertThat(spec.getPorts()).hasSize(2); + assertThat(spec.getPorts()).anySatisfy(p -> { + assertThat(p.getName()).isEqualTo("http"); assertThat(p.getNodePort()).isNotNull(); }); + assertThat(spec.getPorts()).anySatisfy(p -> { + assertThat(p.getName()).isEqualTo("https"); + assertThat(p.getNodePort()).isNull(); + }); }); }); }); diff --git a/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/OpenshiftWithApplicationPropertiesTest.java b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/OpenshiftWithApplicationPropertiesTest.java index 6e8c0e89b74963..9baf8dd69659e2 100644 --- a/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/OpenshiftWithApplicationPropertiesTest.java +++ b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/OpenshiftWithApplicationPropertiesTest.java @@ -72,7 +72,7 @@ public void assertGeneratedResources() throws IOException { assertThat(s.getSpec()).satisfies(spec -> { assertThat(spec.getSelector()).containsOnly(entry("app.kubernetes.io/name", "test-it")); - assertThat(spec.getPorts()).hasSize(1).singleElement().satisfies(p -> { + assertThat(spec.getPorts()).hasSize(2).anySatisfy(p -> { assertThat(p.getPort()).isEqualTo(80); assertThat(p.getTargetPort().getIntVal()).isEqualTo(9090); }); diff --git a/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/OpenshiftWithRoutePropertiesTest.java b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/OpenshiftWithRoutePropertiesTest.java index 187ac17189e296..a9b057e595ca7b 100644 --- a/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/OpenshiftWithRoutePropertiesTest.java +++ b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/OpenshiftWithRoutePropertiesTest.java @@ -45,7 +45,7 @@ public void assertGeneratedResources() throws IOException { assertThat(s.getSpec()).satisfies(spec -> { assertThat(spec.getSelector()).contains(entry("app.kubernetes.io/name", "test-it")); - assertThat(spec.getPorts()).hasSize(1).singleElement().satisfies(p -> { + assertThat(spec.getPorts()).hasSize(2).anySatisfy(p -> { assertThat(p.getPort()).isEqualTo(80); assertThat(p.getTargetPort().getIntVal()).isEqualTo(9090); }); diff --git a/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/OpenshiftWithS2iTest.java b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/OpenshiftWithS2iTest.java index 5dbbce800188c1..bc4f485a61bd9e 100644 --- a/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/OpenshiftWithS2iTest.java +++ b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/OpenshiftWithS2iTest.java @@ -102,7 +102,7 @@ public void assertGeneratedResources() throws IOException { assertThat(openshiftList).filteredOn(h -> "Service".equals(h.getKind())).singleElement().satisfies(h -> { assertThat(h).isInstanceOfSatisfying(Service.class, s -> { assertThat(s.getSpec()).satisfies(spec -> { - assertThat(spec.getPorts()).hasSize(1).singleElement().satisfies(p -> { + assertThat(spec.getPorts()).hasSize(2).anySatisfy(p -> { assertThat(p.getPort()).isEqualTo(80); assertThat(p.getTargetPort().getIntVal()).isEqualTo(8080); }); diff --git a/integration-tests/kubernetes/quarkus-standard-way/src/test/resources/kubernetes-with-ingress-target-port.properties b/integration-tests/kubernetes/quarkus-standard-way/src/test/resources/kubernetes-with-ingress-target-port.properties new file mode 100644 index 00000000000000..594f0d5c7bac3a --- /dev/null +++ b/integration-tests/kubernetes/quarkus-standard-way/src/test/resources/kubernetes-with-ingress-target-port.properties @@ -0,0 +1,2 @@ +quarkus.kubernetes.ingress.expose=true +quarkus.kubernetes.ingress.target-port=https \ No newline at end of file