This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new 853a0232bde CAMEL-21001: camel-jbang Kubernetes - Add Route trait 
(#15381)
853a0232bde is described below

commit 853a0232bde7298ea4c5fc60975802422f1c0f4b
Author: GaĆ«lle Fournier <[email protected]>
AuthorDate: Mon Sep 2 14:05:43 2024 +0200

    CAMEL-21001: camel-jbang Kubernetes - Add Route trait (#15381)
---
 .../modules/ROOT/pages/camel-jbang-kubernetes.adoc | 100 +++++++++++++-
 .../camel-jbang-plugin-kubernetes/pom.xml          |   7 +
 .../core/commands/kubernetes/KubernetesExport.java |   2 +-
 .../commands/kubernetes/traits/IngressTrait.java   |   5 +
 .../commands/kubernetes/traits/RouteTrait.java     | 148 +++++++++++++++++++++
 .../commands/kubernetes/traits/TraitCatalog.java   |   1 +
 .../commands/kubernetes/traits/TraitContext.java   |   8 ++
 .../commands/kubernetes/KubernetesCommandTest.java |   2 +-
 .../commands/kubernetes/KubernetesExportTest.java  |  52 ++++++++
 .../commands/kubernetes/KubernetesRunTest.java     |   2 +-
 .../src/test/resources/route/tls.key               |  16 +++
 .../src/test/resources/route/tls.pem               |  10 ++
 12 files changed, 349 insertions(+), 4 deletions(-)

diff --git a/docs/user-manual/modules/ROOT/pages/camel-jbang-kubernetes.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-jbang-kubernetes.adoc
index 315806ac7dd..533b41cb8d7 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-jbang-kubernetes.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-jbang-kubernetes.adoc
@@ -962,7 +962,7 @@ The ingress trait provides the following configuration 
options:
 
 |===
 
-he syntax to specify container trait options is as follows:
+The syntax to specify container trait options is as follows:
 
 [source,bash]
 ----
@@ -1011,6 +1011,104 @@ spec:
 <3> Custom ingress backend path
 <4> Custom ingress backend path type
 
+=== Route trait options
+
+The Route trait enhance the Kubenetes manifest with a Route resource to expose 
the application to the outside world. This requires the presence in the 
Kubenetes manifest of a Service Resource.
+
+NOTE: You need to enable the Openshift profile trait with 
`--trait-profile=openshift` option.
+
+The Camel JBang plugin automatically creates an Route Resource if the Service 
Resource is generated for the Camel route's service trait application.
+
+The Route trait provides the following configuration options:
+
+[cols="2m,1m,5a"]
+|===
+|Property | Type | Description
+
+| route.enabled
+| bool
+| Can be used to enable or disable a trait. All traits share this common 
property (default `true`).
+
+| route.annotations
+| map[string]string
+| The annotations added to the route. This can be used to set 
https://docs.openshift.com/container-platform/4.16/networking/routes/route-configuration.html#nw-route-specific-annotations_route-configuration[openshift
 route specific annotations] options.
+
+| route.host
+| string
+| To configure the host exposed by the route.
+
+| ingress.tls-termination
+| string
+| The TLS termination type, like `edge`, `passthrough` or `reencrypt`. Refer 
to the OpenShift route documentation for additional information.
+
+| route.tls-certificate
+| string
+| The TLS certificate contents or file (`file:absolute.path`). Refer to the 
OpenShift route documentation for additional information.
+
+| route.tls-key
+| string
+| The TLS certificate key contents or file (`file:absolute.path`). Refer to 
the OpenShift route documentation for additional information.
+
+| route.tls-ca-certificate
+| string
+| The TLS CA certificate contents or file (`file:absolute.path`). Refer to the 
OpenShift route documentation for additional information.
+
+| route.tls-destination-ca-certificate
+| string
+| The destination CA contents or file (`file:absolute.path`). The destination 
CA certificate provides the contents of the CA certificate of the final 
destination. When using reencrypt termination this file should be provided in 
order to have routers use it for health checks on the secure connection. If 
this field is not specified, the router may provide its own destination CA and 
perform hostname validation using the short service name 
(service.namespace.svc), which allows infrastructure [...]
+
+
+| route.tls-insecure-edge-termination-policy
+| string
+| To configure how to deal with insecure traffic, e.g. `Allow`, `Disable` or 
`Redirect` traffic. Refer to the OpenShift route documentation for additional 
information.
+
+|===
+
+The syntax to specify container trait options is as follows:
+
+[source,bash]
+----
+camel kubernetes export Sample.java --trait route.[key]=[value]
+----
+
+You may specify these options with the export command to customize the Route 
Resource specification.
+
+[source,bash]
+----
+camel kubernetes export Sample.java --trait-profile=openshift --trait 
ingress.host=example.com -t route.tls-termination=edge -t 
route.tls-certificate=file:/tmp/tls.crt -t route.tls-key=file:/tmp/tls.key
+----
+
+
+This results in the following container specification in the Route resource.
+
+[source,yaml]
+----
+apiVersion: route.openshift.io/v1
+kind: Route
+metadata:
+  name: route-service
+spec:
+  host: example.com #<1>
+  port:
+    targetPort: http #<2>
+  tls:
+    certificate: | #<3>
+      ...
+    key: | #<4>
+      ...
+    termination: edge #<5>
+  to: #<6>
+    kind: Service
+    name: route-service
+----
+<1> Custom route host
+<2> Service port name
+<3> Custom route TLS certificate content
+<4> Custom route TLS certificate key content
+<5> Custom route TLS termination
+<6> Service Resource reference
+
+
 === OpenApi specifications
 
 You can mount OpenAPI specifications to the application container with this 
trait.
diff --git a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/pom.xml 
b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/pom.xml
index 5a7f7024b1c..2de19edff12 100644
--- a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/pom.xml
+++ b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/pom.xml
@@ -54,6 +54,13 @@
             <version>${kubernetes-client-version}</version>
         </dependency>
 
+        <!-- Openshift -->
+        <dependency>
+            <groupId>io.fabric8</groupId>
+            <artifactId>openshift-model</artifactId>
+            <version>${kubernetes-client-version}</version>
+        </dependency>
+
         <!-- Knative model -->
         <dependency>
             <groupId>io.fabric8</groupId>
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesExport.java
 
b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesExport.java
index a606d1eaba5..b53c1f3190f 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesExport.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesExport.java
@@ -216,7 +216,7 @@ public class KubernetesExport extends Export {
                 .collect(Collectors.toMap(parts -> parts[0], parts -> 
parts[1])));
 
         if (traitProfile != null) {
-            context.setProfile(TraitProfile.valueOf(traitProfile));
+            
context.setProfile(TraitProfile.valueOf(traitProfile.toUpperCase()));
         }
 
         if (serviceAccount != null) {
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/traits/IngressTrait.java
 
b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/traits/IngressTrait.java
index 0d2eb4e49e5..5c125abc8c4 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/traits/IngressTrait.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/traits/IngressTrait.java
@@ -102,4 +102,9 @@ public class IngressTrait extends BaseTrait {
 
         context.add(ingressBuilder);
     }
+
+    @Override
+    public boolean accept(TraitProfile profile) {
+        return TraitProfile.KUBERNETES == profile;
+    }
 }
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/traits/RouteTrait.java
 
b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/traits/RouteTrait.java
new file mode 100644
index 00000000000..1eecc7b6db6
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/traits/RouteTrait.java
@@ -0,0 +1,148 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.dsl.jbang.core.commands.kubernetes.traits;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Optional;
+
+import io.fabric8.kubernetes.api.model.IntOrString;
+import io.fabric8.kubernetes.api.model.IntOrStringBuilder;
+import io.fabric8.openshift.api.model.RouteBuilder;
+import io.fabric8.openshift.api.model.TLSConfigBuilder;
+import org.apache.camel.util.IOHelper;
+import org.apache.camel.util.StringHelper;
+import org.apache.camel.v1.integrationspec.Traits;
+import org.apache.camel.v1.integrationspec.traits.Container;
+import org.apache.camel.v1.integrationspec.traits.Route;
+
+import static 
org.apache.camel.dsl.jbang.core.commands.kubernetes.traits.ContainerTrait.DEFAULT_CONTAINER_PORT_NAME;
+
+public class RouteTrait extends BaseTrait {
+
+    public static final int RouteTrait = 2200;
+
+    public RouteTrait() {
+        super("route", RouteTrait);
+    }
+
+    @Override
+    public boolean configure(Traits traitConfig, TraitContext context) {
+        if (context.getRoute().isPresent()) {
+            return false;
+        }
+
+        // explicitly disabled
+        if (traitConfig.getRoute() != null && 
!Optional.ofNullable(traitConfig.getRoute().getEnabled()).orElse(true)) {
+            return false;
+        }
+
+        // configured service
+        if (traitConfig.getRoute() != null) {
+            return context.getService() != null;
+        }
+
+        return true;
+    }
+
+    @Override
+    public void apply(Traits traitConfig, TraitContext context) {
+        Route routeTrait = 
Optional.ofNullable(traitConfig.getRoute()).orElseGet(Route::new);
+        Container containerTrait = 
Optional.ofNullable(traitConfig.getContainer()).orElseGet(Container::new);
+
+        RouteBuilder routeBuilder = new RouteBuilder();
+        routeBuilder.withNewMetadata()
+                .withName(context.getName())
+                .endMetadata();
+        if (routeTrait.getAnnotations() != null) {
+            
routeBuilder.editMetadata().withAnnotations(routeTrait.getAnnotations()).endMetadata();
+        }
+
+        IntOrString servicePortName = new IntOrStringBuilder()
+                
.withValue(Optional.ofNullable(containerTrait.getServicePortName()).orElse(DEFAULT_CONTAINER_PORT_NAME))
+                .build();
+        routeBuilder
+                .withNewSpec()
+                .withNewPort()
+                .withTargetPort(servicePortName)
+                .endPort()
+                .withNewTo()
+                .withKind("Service")
+                .withName(context.getName())
+                .endTo()
+                .endSpec();
+
+        if (routeTrait.getHost() != null) {
+            routeBuilder.editSpec().withHost(routeTrait.getHost()).endSpec();
+        }
+
+        TLSConfigBuilder tlsConfigBuilder = new TLSConfigBuilder();
+        if (routeTrait.getTlsTermination() != null) {
+            
tlsConfigBuilder.withTermination(routeTrait.getTlsTermination().getValue());
+        }
+        if (routeTrait.getTlsCertificate() != null) {
+            
tlsConfigBuilder.withCertificate(getContent(routeTrait.getTlsCertificate()));
+        }
+        if (routeTrait.getTlsKey() != null) {
+            tlsConfigBuilder.withKey(getContent(routeTrait.getTlsKey()));
+        }
+        if (routeTrait.getTlsCACertificate() != null) {
+            
tlsConfigBuilder.withCaCertificate(getContent(routeTrait.getTlsCACertificate()));
+        }
+        if (routeTrait.getTlsDestinationCACertificate() != null) {
+            
tlsConfigBuilder.withDestinationCACertificate(getContent(routeTrait.getTlsDestinationCACertificate()));
+        }
+
+        if (routeTrait.getTlsInsecureEdgeTerminationPolicy() != null) {
+            
tlsConfigBuilder.withInsecureEdgeTerminationPolicy(routeTrait.getTlsInsecureEdgeTerminationPolicy().getValue());
+        }
+
+        routeBuilder.editSpec().withTls(tlsConfigBuilder.build()).endSpec();
+        context.add(routeBuilder);
+
+    }
+
+    @Override
+    public boolean accept(TraitProfile profile) {
+        return TraitProfile.OPENSHIFT == profile;
+    }
+
+    private String getContent(String value) {
+        if (value.startsWith("file:")) {
+            String filePath = StringHelper.after(value, ":");
+            final File file = new File(filePath);
+            if (!file.exists()) {
+                throw new RuntimeException(filePath + " does not exist");
+            }
+            if (file.isDirectory()) {
+                throw new RuntimeException(filePath + " is not a file");
+            }
+            try (InputStream is = new FileInputStream(file)) {
+                return IOHelper.loadText(is);
+            } catch (FileNotFoundException e) {
+                throw new RuntimeException(e);
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        } else {
+            return value;
+        }
+    }
+}
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/traits/TraitCatalog.java
 
b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/traits/TraitCatalog.java
index 339d9a9fb0b..97037f066a3 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/traits/TraitCatalog.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/traits/TraitCatalog.java
@@ -40,6 +40,7 @@ public class TraitCatalog {
         register(new KnativeTrait());
         register(new KnativeServiceTrait());
         register(new ServiceTrait());
+        register(new RouteTrait());
         register(new IngressTrait());
         register(new ContainerTrait());
         register(new EnvTrait());
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/traits/TraitContext.java
 
b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/traits/TraitContext.java
index 5585e2188a3..e77ceaf784d 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/traits/TraitContext.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/traits/TraitContext.java
@@ -36,6 +36,7 @@ import io.fabric8.kubernetes.api.model.ServiceBuilder;
 import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder;
 import io.fabric8.kubernetes.api.model.batch.v1.CronJobBuilder;
 import io.fabric8.kubernetes.api.model.networking.v1.IngressBuilder;
+import io.fabric8.openshift.api.model.RouteBuilder;
 import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.catalog.CamelCatalog;
 import org.apache.camel.dsl.jbang.core.commands.kubernetes.CatalogHelper;
@@ -142,6 +143,13 @@ public class TraitContext {
                 .findFirst();
     }
 
+    public Optional<RouteBuilder> getRoute() {
+        return resourceRegistry.stream()
+                .filter(it -> 
it.getClass().isAssignableFrom(RouteBuilder.class))
+                .map(it -> (RouteBuilder) it)
+                .findFirst();
+    }
+
     public Optional<io.fabric8.knative.serving.v1.ServiceBuilder> 
getKnativeService() {
         return resourceRegistry.stream()
                 .filter(it -> 
it.getClass().isAssignableFrom(io.fabric8.knative.serving.v1.ServiceBuilder.class))
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesCommandTest.java
 
b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesCommandTest.java
index a7ef0113f0a..45cef6faa23 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesCommandTest.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesCommandTest.java
@@ -45,7 +45,7 @@ class KubernetesCommandTest extends KubernetesBaseTest {
                 "yaml");
 
         List<HasMetadata> resources = 
kubernetesClient.load(getKubernetesManifestAsStream(printer.getOutput())).items();
-        Assertions.assertEquals(3, resources.size());
+        Assertions.assertEquals(4, resources.size());
 
         Deployment deployment = resources.stream()
                 .filter(it -> Deployment.class.isAssignableFrom(it.getClass()))
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesExportTest.java
 
b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesExportTest.java
index 8bbd061c744..0579cb7a279 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesExportTest.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesExportTest.java
@@ -41,6 +41,7 @@ import io.fabric8.kubernetes.api.model.Service;
 import io.fabric8.kubernetes.api.model.ServicePort;
 import io.fabric8.kubernetes.api.model.apps.Deployment;
 import io.fabric8.kubernetes.api.model.networking.v1.Ingress;
+import io.fabric8.openshift.api.model.Route;
 import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
 import org.apache.camel.dsl.jbang.core.commands.kubernetes.traits.BaseTrait;
@@ -212,6 +213,7 @@ class KubernetesExportTest extends KubernetesBaseTest {
     @MethodSource("runtimeProvider")
     public void shouldAddIngressSpec(RuntimeType rt) throws Exception {
         KubernetesExport command = createCommand(new String[] { 
"classpath:route-service.yaml" },
+                "--trait-profile", "kubernetes",
                 "--trait", "ingress.host=example.com",
                 "--trait", "ingress.path=/something(/|$)(.*)",
                 "--trait", "ingress.pathType=ImplementationSpecific",
@@ -222,6 +224,7 @@ class KubernetesExportTest extends KubernetesBaseTest {
 
         Assertions.assertTrue(hasService(rt));
         Assertions.assertFalse(hasKnativeService(rt));
+        Assertions.assertFalse(hasRoute(rt));
 
         Deployment deployment = getDeployment(rt);
         Container container = 
deployment.getSpec().getTemplate().getSpec().getContainers().get(0);
@@ -248,6 +251,42 @@ class KubernetesExportTest extends KubernetesBaseTest {
         Assertions.assertEquals("true", 
ingress.getMetadata().getAnnotations().get("nginx.ingress.kubernetes.io/use-regex"));
     }
 
+    @ParameterizedTest
+    @MethodSource("runtimeProvider")
+    public void shouldAddRouteSpec(RuntimeType rt) throws Exception {
+        String certificate = IOHelper.loadText(new 
FileInputStream("src/test/resources/route/tls.pem"));
+        String key = IOHelper.loadText(new 
FileInputStream("src/test/resources/route/tls.key"));
+        KubernetesExport command = createCommand(new String[] { 
"classpath:route-service.yaml" },
+                "--trait-profile", "openshift",
+                "--trait", "route.host=example.com",
+                "--trait", "route.tls-termination=edge",
+                "--trait", "route.tls-certificate=" + certificate,
+                "--trait", "route.tls-key=" + key,
+                "--runtime=" + rt.runtime());
+        command.doCall();
+
+        Assertions.assertTrue(hasService(rt));
+        Assertions.assertFalse(hasKnativeService(rt));
+        Assertions.assertFalse(hasIngress(rt));
+
+        Deployment deployment = getDeployment(rt);
+        Container container = 
deployment.getSpec().getTemplate().getSpec().getContainers().get(0);
+        Assertions.assertEquals("route-service", 
deployment.getMetadata().getName());
+        Assertions.assertEquals(1, 
deployment.getSpec().getTemplate().getSpec().getContainers().size());
+        Assertions.assertEquals("route-service:1.0-SNAPSHOT", 
container.getImage());
+        Assertions.assertEquals(1, container.getPorts().size());
+        Assertions.assertEquals("http", container.getPorts().get(0).getName());
+        Assertions.assertEquals(8080, 
container.getPorts().get(0).getContainerPort());
+
+        Route route = getRoute(rt);
+        Assertions.assertEquals("route-service", 
route.getMetadata().getName());
+        Assertions.assertEquals("example.com", route.getSpec().getHost());
+        Assertions.assertEquals("edge", 
route.getSpec().getTls().getTermination());
+        Assertions.assertEquals("route-service", 
route.getSpec().getTo().getName());
+        
Assertions.assertTrue(certificate.startsWith(route.getSpec().getTls().getCertificate()));
+        
Assertions.assertTrue(key.startsWith(route.getSpec().getTls().getKey()));
+    }
+
     @ParameterizedTest
     @MethodSource("runtimeProvider")
     public void shouldAddContainerSpec(RuntimeType rt) throws Exception {
@@ -730,6 +769,19 @@ class KubernetesExportTest extends KubernetesBaseTest {
                 .orElseThrow(() -> new RuntimeCamelException("Cannot find 
ingress for: %s".formatted(rt.runtime())));
     }
 
+    private boolean hasIngress(RuntimeType rt) throws IOException {
+        return getResource(rt, Ingress.class).isPresent();
+    }
+
+    private Route getRoute(RuntimeType rt) throws IOException {
+        return getResource(rt, Route.class)
+                .orElseThrow(() -> new RuntimeCamelException("Cannot find 
route for: %s".formatted(rt.runtime())));
+    }
+
+    private boolean hasRoute(RuntimeType rt) throws IOException {
+        return getResource(rt, Route.class).isPresent();
+    }
+
     private boolean hasService(RuntimeType rt) throws IOException {
         return getResource(rt, Service.class).isPresent();
     }
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesRunTest.java
 
b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesRunTest.java
index 89411e099f8..0afcb941961 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesRunTest.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesRunTest.java
@@ -58,7 +58,7 @@ class KubernetesRunTest extends KubernetesBaseTest {
         Assertions.assertEquals(0, exit);
 
         List<HasMetadata> resources = 
kubernetesClient.load(getKubernetesManifestAsStream(printer.getOutput())).items();
-        Assertions.assertEquals(3, resources.size());
+        Assertions.assertEquals(4, resources.size());
 
         Deployment deployment = resources.stream()
                 .filter(it -> Deployment.class.isAssignableFrom(it.getClass()))
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/resources/route/tls.key
 
b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/resources/route/tls.key
new file mode 100644
index 00000000000..72062169275
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/resources/route/tls.key
@@ -0,0 +1,16 @@
+-----BEGIN PRIVATE KEY-----
+MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKulUTZ8B1qccZ8c
+DXRGSY08gW8KvLlcxxxGC4gZHNT3CBUF8n5R4KE30aZyYZ/rtsQZu05juZJxaJ0q
+mbe75dlQ5d+Xc9BMXeQg/MpTZw5TAN7OIdGYYpFBe+1PLZ6wEfjkYrMqMUcfq2Lq
+hTLdAbvBJnuRcYZLqmBeOQ8FTrKrAgMBAAECgYEAnkHRbEPU3/WISSQrP36iyCb2
+S/SBZwKkzmvCrBxDWhPeDswp9c/2JY76rNWfLzy8iXgUG8WUzvHje61Qh3gmBcKe
+bUaTGl4Vy8Ha1YBADo5RfRrdm0FE4tvgvu/TkqFqpBBZweu54285hk5zlG7n/D7Y
+dnNXUpu5MlNb5x3gW0kCQQDUL//cwcXUxY/evaJP4jSe+ZwEQZo+zXRLiPUulBoV
+aw28CVMuxdgwqAo1X1IKefPeUaf7RQu8gCKaRnpGuEuXAkEAzxZTfMmvmCUDIew4
+5Gk6bK265XQWdhcgiq254lpBGOYmDj9yCE7yA+zmASQwMsXTdQOi1hOCEyrXuSJ5
+c++EDQJAFh3WrnzoEPByuYXMmET8tSFRWMQ5vpgNqh3haHR5b4gUC2hxaiunCBNL
+1RpVY9AoUiDywGcG/SPh93CnKB3niwJBAKP7AtsifZgVXtiizB4aMThTjVYaSZrz
+D0Kg9DuHylpkDChmFu77TGrNUQgAVuYtfhb/bRblVa/F0hJ4eQHT3JUCQBVT68tb
+OgRUk0aP9tC3021VN82X6+klowSQN8oBPX8+TfDWSUilp/+j24Hky+Z29Do7yR/R
+qutnL92CvBlVLV4=
+-----END PRIVATE KEY-----
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/resources/route/tls.pem
 
b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/resources/route/tls.pem
new file mode 100644
index 00000000000..c7974ea37cc
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/resources/route/tls.pem
@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE-----
+MIIBajCCARCgAwIBAgIUbYqrLSOSQHoxD8CwG6Bi2PJi9c8wCgYIKoZIzj0EAwIw
+EzERMA8GA1UEAxMIc3dhcm0tY2EwHhcNMTcwNDI0MjE0MzAwWhcNMzcwNDE5MjE0
+MzAwWjATMREwDwYDVQQDEwhzd2FybS1jYTBZMBMGByqGSM49AgEGCCqGSM49AwEH
+A0IABJk/VyMPYdaqDXJb/VXh5n/1Yuv7iNrxV3Qb3l06XD46seovcDWs3IZNV1lf
+3Skyr0ofcchipoiHkXBODojJydSjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB
+Af8EBTADAQH/MB0GA1UdDgQWBBRUXxuRcnFjDfR/RIAUQab8ZV/n4jAKBggqhkjO
+PQQDAgNIADBFAiAy+JTe6Uc3KyLCMiqGl2GyWGQqQDEcO3/YG36x7om65AIhAJvz
+pxv6zFeVEkAEEkqIYi0omA9+CjanB/6Bz4n1uw8H
+-----END CERTIFICATE-----

Reply via email to