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 94dc40783305 CAMEL-25454: camel-jbang - kubernetes run, k3s manifest
with --output and explicit image options with --cluster-type (#27591)
94dc40783305 is described below
commit 94dc4078330547021ac7f7da20a809acc43b4c13
Author: allthingssecurity <[email protected]>
AuthorDate: Sat Oct 10 01:20:45 2026 +0530
CAMEL-25454: camel-jbang - kubernetes run, k3s manifest with --output and
explicit image options with --cluster-type (#27591)
Follow-up to CAMEL-24662: --cluster-type=k3s with --output reads the
kubernetes.yml manifest built by the kubernetes-maven-plugin. The Minikube
defaults no longer replace an --image-builder or --image-push set by the
user,
the no-push default applies only with the docker builder (jib falls back to
pushing), and the docker-env hint is printed once and only when an image is
built.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---
.../ROOT/pages/camel-4x-upgrade-guide-4_23.adoc | 8 +
.../modules/ROOT/pages/camel-jbang-kubernetes.adoc | 13 +-
.../jbang-commands/camel-jbang-kubernetes-run.adoc | 4 +-
.../camel-jbang-plugin-commands-metadata.json | 2 +-
.../core/commands/kubernetes/KubernetesHelper.java | 20 ++-
.../core/commands/kubernetes/KubernetesRun.java | 50 ++++--
.../commands/kubernetes/KubernetesHelperTest.java | 71 ++++++++
.../kubernetes/KubernetesRunClusterTypeTest.java | 196 +++++++++++++++++++++
.../kubernetes/KubernetesRunCustomTest.java | 35 +++-
9 files changed, 368 insertions(+), 31 deletions(-)
diff --git
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
index 0652619a5217..adfdf36b2044 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
@@ -2122,6 +2122,14 @@ validated before can now report errors, and
`camel_write_file` refuses to write
TUI Source tab an XML route file with such problems is not saved, as a YAML
file; a Java file is saved and its problems are shown.
+`camel kubernetes run --cluster-type=<type>` now uses the given cluster type.
Before, unless `--disable-auto` was set,
+the detected cluster type (OpenShift, Minikube or Kubernetes) replaced it,
together with its image settings. The
+defaults of the cluster type still apply, also to an explicit type (Minikube:
`--image-builder=docker` and, with the
+docker builder, `--image-push=false`; OpenShift: the current namespace as
`--image-group`), but they no longer replace
+an `--image-builder` or `--image-push` that you set, also when Minikube is
detected. With another builder on Minikube,
+such as `--image-builder=jib`, the image is pushed by default.
`--disable-auto` turns off both the
+detection and the defaults, as before.
+
=== camel-jbang (MCP servers)
The Camel authoring tools for AI agents are now defined once, in
`camel-jbang-core`, and exposed under the
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 094c55ed5b79..70206c8308c2 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-jbang-kubernetes.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-jbang-kubernetes.adoc
@@ -29,8 +29,10 @@ camel kubernetes run * --runtime=spring-boot --name=my-app
This exports a Spring Boot project named `my-app`, builds the container image,
pushes it, and deploys it to the cluster
`kubectl` is connected to. The runtime is one of `spring-boot`, `quarkus` (the
default) or `main`.
-Local clusters (Kind, Minikube) and OpenShift are detected, and the image
registry is configured for them.
-Use `--cluster-type` to set the cluster type explicitly, skipping
auto-detection while still applying the cluster-specific defaults.
+Minikube and OpenShift are detected, and the image build and registry are
configured for them.
+Use `--cluster-type` to set the cluster type explicitly (for example
`--cluster-type=kind`, which is not detected),
+skipping auto-detection while still applying the cluster-specific defaults.
+The image options you set yourself, such as `--image-builder` and
`--image-push`, are kept.
For any other cluster, tell the plugin where to push the image:
[source,bash]
@@ -57,7 +59,7 @@ Useful options of `run`:
| Print the logs once the application has started.
| --disable-auto
-| Do not detect the cluster type (Kind, Minikube, OpenShift).
+| Do not detect the cluster type (Minikube, OpenShift), and do not apply the
cluster-specific defaults.
| --verbose
| Show the output of the Maven build and the deployment.
@@ -288,7 +290,10 @@ eval $(minikube -p minikube docker-env)
camel kubernetes run * --runtime=spring-boot
----
-On Minikube the image is built with Docker straight into the Minikube Docker
daemon, so nothing is pushed.
+On Minikube the image is built with Docker straight into the Minikube Docker
daemon, so nothing is pushed
+(unless you set `--image-push`). If you set another `--image-builder`, such as
`jib`, the image is pushed as on any other cluster.
+Minikube is only detected when its Docker environment is active (`eval
$(minikube docker-env)`);
+with `--cluster-type=minikube`, `run` prints a hint when it is not.
== Troubleshooting
diff --git
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-kubernetes-run.adoc
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-kubernetes-run.adoc
index f9abdf15fbef..b70363a1d899 100644
---
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-kubernetes-run.adoc
+++
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-kubernetes-run.adoc
@@ -39,10 +39,10 @@ camel kubernetes run [options]
| `--gav` | The Maven group:artifact:version | | String
| `--image` | The image name to be built. | | String
| `--image-build` | Whether to build container image as part of the run. |
true | boolean
-| `--image-builder` | The image builder used to build the container image
(e.g. docker, jib, s2i). | jib | String
+| `--image-builder` | The image builder used to build the container image
(e.g. docker, jib, s2i). Default is jib, or docker on Minikube unless
--disable-auto is set. | | String
| `--image-group` | The image registry group used to push images to. | |
String
| `--image-platform` | List of target platforms. Each platform is defined
using os and architecture (e.g. linux/amd64). | | String
-| `--image-push` | Whether to push image to given image registry as part of
the run. | true | boolean
+| `--image-push` | Whether to push image to given image registry as part of
the run. Default is true, or false on Minikube with the docker image builder
unless --disable-auto is set. | | Boolean
| `--image-registry` | The image registry to hold the app container image. |
| String
| `--java-version,--java` | Java version | 21 | String
| `--kamelets-version` | Apache Camel Kamelets version | | String
diff --git
a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/generated/resources/META-INF/camel-jbang-plugin-commands-metadata.json
b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/generated/resources/META-INF/camel-jbang-plugin-commands-metadata.json
index 3af001de5e32..eaad31dec933 100644
---
a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/generated/resources/META-INF/camel-jbang-plugin-commands-metadata.json
+++
b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/generated/resources/META-INF/camel-jbang-plugin-commands-metadata.json
@@ -1,5 +1,5 @@
{
"commands": [
- { "name": "kubernetes", "fullName": "kubernetes", "description": "Manage
Camel applications running on Kubernetes", "sourceClass":
"org.apache.camel.dsl.jbang.core.commands.kubernetes.KubernetesCommand",
"plugin": "kubernetes", "options": [ { "names": "--kube-config", "description":
"Path to the kube config file to initialize Kubernetes client", "javaType":
"java.lang.String", "type": "string" }, { "names": "--name", "description":
"The integration name. Use this when the name should [...]
+ { "name": "kubernetes", "fullName": "kubernetes", "description": "Manage
Camel applications running on Kubernetes", "sourceClass":
"org.apache.camel.dsl.jbang.core.commands.kubernetes.KubernetesCommand",
"plugin": "kubernetes", "options": [ { "names": "--kube-config", "description":
"Path to the kube config file to initialize Kubernetes client", "javaType":
"java.lang.String", "type": "string" }, { "names": "--name", "description":
"The integration name. Use this when the name should [...]
]
}
diff --git
a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesHelper.java
b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesHelper.java
index e5a3c3693b07..c5f68c743634 100644
---
a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesHelper.java
+++
b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesHelper.java
@@ -176,10 +176,7 @@ public final class KubernetesHelper {
GenericKubernetesResourceList list =
getKubernetesClient().genericKubernetesResources(nodecrd)
.withLabels(Collections.singletonMap("minikube.k8s.io/name", null)).list();
minikube = list.getItems().size() > 0;
- // thse env properties are set when running eval $(minikube
docker-env) in the console
- // this is important for the docker builder to actually build the
image in the exposed docker from the minikube registry
- minikubeEnv = System.getenv("MINIKUBE_ACTIVE_DOCKERD") != null
- && System.getenv("DOCKER_TLS_VERIFY") != null;
+ minikubeEnv = isMinikubeDockerEnv();
if (minikube && !minikubeEnv) {
System.out.println(
"It seems you have minikube running but forgot to run
\"eval $(minikube docker-env)\", default cluster to kubernetes.");
@@ -190,6 +187,15 @@ public final class KubernetesHelper {
return minikube && minikubeEnv;
}
+ /**
+ * Whether the Minikube Docker environment is active in this console,
which is what {@code eval $(minikube
+ * docker-env)} sets. The docker image builder needs it to build the image
in the Docker daemon of Minikube.
+ */
+ static boolean isMinikubeDockerEnv() {
+ return System.getenv("MINIKUBE_ACTIVE_DOCKERD") != null
+ && System.getenv("DOCKER_TLS_VERIFY") != null;
+ }
+
// when minikube is used with the registry addon exposed
// the build of images uses docker builder directly from the registry
inside minikube
// that doesn't generate the container image digest in the registry
@@ -341,7 +347,8 @@ public final class KubernetesHelper {
public static File getKubernetesManifest(String clusterType, File
workingDir, String extension) {
String manifestFile;
- if (ClusterType.KIND.isEqualTo(clusterType) ||
ClusterType.MINIKUBE.isEqualTo(clusterType)) {
+ if (ClusterType.KIND.isEqualTo(clusterType) ||
ClusterType.MINIKUBE.isEqualTo(clusterType)
+ || ClusterType.K3S.isEqualTo(clusterType)) {
manifestFile = "kubernetes";
} else {
manifestFile =
Optional.ofNullable(clusterType).map(String::toLowerCase).orElse("kubernetes");
@@ -355,7 +362,8 @@ public final class KubernetesHelper {
public static Path getKubernetesManifestPath(String clusterType, Path
workingDir, String extension) {
String manifestFile;
- if (ClusterType.KIND.isEqualTo(clusterType) ||
ClusterType.MINIKUBE.isEqualTo(clusterType)) {
+ if (ClusterType.KIND.isEqualTo(clusterType) ||
ClusterType.MINIKUBE.isEqualTo(clusterType)
+ || ClusterType.K3S.isEqualTo(clusterType)) {
manifestFile = "kubernetes";
} else {
manifestFile =
Optional.ofNullable(clusterType).map(String::toLowerCase).orElse("kubernetes");
diff --git
a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesRun.java
b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesRun.java
index 5b16e24f4516..91ff84200ee2 100644
---
a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesRun.java
+++
b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesRun.java
@@ -156,9 +156,11 @@ public class KubernetesRun extends KubernetesBaseCommand {
description = "The image registry group used to push
images to.")
String imageGroup;
- @CommandLine.Option(names = { "--image-builder" }, defaultValue = "jib",
- description = "The image builder used to build the
container image (e.g. docker, jib, s2i).")
- String imageBuilder = "jib";
+ // no default value, so that detectCluster() can tell an explicit value
from the default
+ @CommandLine.Option(names = { "--image-builder" },
+ description = "The image builder used to build the
container image (e.g. docker, jib, s2i)."
+ + " Default is jib, or docker on
Minikube unless --disable-auto is set.")
+ String imageBuilder;
@CommandLine.Option(names = { "--cluster-type" },
completionCandidates =
ClusterTypeCompletionCandidates.class,
@@ -170,9 +172,11 @@ public class KubernetesRun extends KubernetesBaseCommand {
description = "Whether to build container image as
part of the run.")
boolean imageBuild = true;
- @CommandLine.Option(names = { "--image-push" }, defaultValue = "true",
- description = "Whether to push image to given image
registry as part of the run.")
- boolean imagePush = true;
+ // no default value, so that detectCluster() can tell an explicit value
from the default
+ @CommandLine.Option(names = { "--image-push" },
+ description = "Whether to push image to given image
registry as part of the run."
+ + " Default is true, or false on
Minikube with the docker image builder unless --disable-auto is set.")
+ Boolean imagePush;
@CommandLine.Option(names = { "--image-platform" },
description = "List of target platforms. Each platform
is defined using os and architecture (e.g. linux/amd64).")
@@ -283,6 +287,8 @@ public class KubernetesRun extends KubernetesBaseCommand {
private CamelContext devModeContext;
private Thread devModeShutdownTask;
private int devModeReloadCount;
+ // detectCluster() runs again on every dev mode reload, the Minikube
docker-env hint is printed only once
+ private boolean dockerEnvHintPrinted;
private KubernetesPodLogs reusablePodLogs;
private Printer quietPrinter;
@@ -806,8 +812,9 @@ public class KubernetesRun extends KubernetesBaseCommand {
return 0;
}
- private void detectCluster() {
- if (!disableAuto && clusterType == null) {
+ void detectCluster() {
+ boolean explicitClusterType = clusterType != null;
+ if (!disableAuto && !explicitClusterType) {
if (verbose) {
printer().print("Automatic Kubernetes cluster detection... ");
}
@@ -820,16 +827,37 @@ public class KubernetesRun extends KubernetesBaseCommand {
this.clusterType = ClusterType.KUBERNETES.name();
}
if (!disableAuto) {
- // Apply per-cluster defaults for the resolved cluster type
(explicit or detected)
+ // Apply per-cluster defaults for the resolved cluster type
(explicit or detected),
+ // but keep the image options the user has set
if (ClusterType.MINIKUBE.isEqualTo(clusterType)) {
- this.imageBuilder = "docker";
- this.imagePush = false;
+ if (imageBuilder == null) {
+ this.imageBuilder = "docker";
+ }
+ // the docker builder builds straight into the Minikube Docker
daemon, so there is nothing to push;
+ // other builders (jib) still push, as the image would
otherwise not reach the cluster
+ if (imagePush == null && "docker".equals(imageBuilder)) {
+ this.imagePush = false;
+ }
+ // the detection only returns Minikube when its Docker
environment is active, and tells the user otherwise
+ if (explicitClusterType && !dockerEnvHintPrinted && imageBuild
&& output == null
+ && "docker".equals(imageBuilder)
+ && Boolean.FALSE.equals(imagePush) &&
!KubernetesHelper.isMinikubeDockerEnv()) {
+ printer().println("The Minikube Docker environment is not
active: run \"eval $(minikube docker-env)\""
+ + " so that the image is built in the
Docker daemon of Minikube.");
+ dockerEnvHintPrinted = true;
+ }
} else if (ClusterType.OPENSHIFT.isEqualTo(clusterType)) {
if (ObjectHelper.isEmpty(imageGroup)) {
this.imageGroup = client().getNamespace();
}
}
}
+ if (imageBuilder == null) {
+ this.imageBuilder = "jib";
+ }
+ if (imagePush == null) {
+ this.imagePush = true;
+ }
}
/*
diff --git
a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesHelperTest.java
b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesHelperTest.java
new file mode 100644
index 000000000000..3b3985e4af02
--- /dev/null
+++
b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesHelperTest.java
@@ -0,0 +1,71 @@
+/*
+ * 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;
+
+import java.io.File;
+import java.nio.file.Path;
+import java.util.Locale;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.EnumSource;
+
+class KubernetesHelperTest {
+
+ private final Path workingDir = Path.of("target", "kubernetes");
+
+ // KubernetesExport builds with the kubernetes-maven-plugin for every
cluster type but OpenShift,
+ // and that plugin writes the manifest as kubernetes.yml (kubernetes.json)
+ @ParameterizedTest
+ @EnumSource(value = ClusterType.class, names = "OPENSHIFT", mode =
EnumSource.Mode.EXCLUDE)
+ void manifestOfKubernetesMavenPlugin(ClusterType clusterType) {
+ String name = clusterType.name().toLowerCase(Locale.ROOT);
+
+ Assertions.assertEquals(workingDir.resolve("kubernetes.yml"),
+ KubernetesHelper.getKubernetesManifestPath(name, workingDir));
+ Assertions.assertEquals(workingDir.resolve("kubernetes.json"),
+ KubernetesHelper.getKubernetesManifestPath(clusterType.name(),
workingDir, "json"));
+ Assertions.assertEquals(new File(workingDir.toFile(),
"kubernetes.yml"),
+ KubernetesHelper.getKubernetesManifest(name,
workingDir.toFile()));
+ }
+
+ @Test
+ void manifestOfOpenShiftMavenPlugin() {
+ Assertions.assertEquals(workingDir.resolve("openshift.yml"),
+ KubernetesHelper.getKubernetesManifestPath("openshift",
workingDir));
+ Assertions.assertEquals(workingDir.resolve("openshift.json"),
+ KubernetesHelper.getKubernetesManifestPath("OPENSHIFT",
workingDir, "json"));
+ Assertions.assertEquals(new File(workingDir.toFile(), "openshift.yml"),
+ KubernetesHelper.getKubernetesManifest("openshift",
workingDir.toFile()));
+ }
+
+ @Test
+ void manifestOfKnativeService() {
+ // KubernetesRun reads the service.yml that the knative-service trait
writes
+ Path jkubeDir = Path.of("src", "main", "jkube");
+ Assertions.assertEquals(jkubeDir.resolve("service.yml"),
+ KubernetesHelper.getKubernetesManifestPath("service",
jkubeDir));
+ }
+
+ @Test
+ void manifestWithoutClusterType() {
+ Assertions.assertEquals(workingDir.resolve("kubernetes.yml"),
+ KubernetesHelper.getKubernetesManifestPath(null, workingDir));
+ }
+}
diff --git
a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesRunClusterTypeTest.java
b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesRunClusterTypeTest.java
new file mode 100644
index 000000000000..21a0b5c46ee8
--- /dev/null
+++
b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesRunClusterTypeTest.java
@@ -0,0 +1,196 @@
+/*
+ * 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;
+
+import java.net.HttpURLConnection;
+import java.util.Collections;
+
+import io.fabric8.kubernetes.api.model.Node;
+import io.fabric8.kubernetes.api.model.NodeBuilder;
+import io.fabric8.kubernetes.api.model.NodeListBuilder;
+import io.fabric8.kubernetes.client.KubernetesClient;
+import io.fabric8.kubernetes.client.server.mock.EnableKubernetesMockClient;
+import io.fabric8.kubernetes.client.server.mock.KubernetesMockServer;
+import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
+import org.apache.camel.dsl.jbang.core.common.CommandLineHelper;
+import org.apache.camel.dsl.jbang.core.common.StringPrinter;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junitpioneer.jupiter.ClearEnvironmentVariable;
+import org.junitpioneer.jupiter.SetEnvironmentVariable;
+import picocli.CommandLine;
+
+/**
+ * Checks how the cluster type and the per-cluster image defaults are resolved
by {@link KubernetesRun}, without
+ * exporting or building a project.
+ */
+@EnableKubernetesMockClient
+class KubernetesRunClusterTypeTest {
+
+ private static final String DOCKER_ENV_HINT = "eval $(minikube
docker-env)";
+
+ KubernetesMockServer server;
+ KubernetesClient client;
+
+ private StringPrinter printer;
+
+ @BeforeEach
+ void setup() {
+ CommandLineHelper.useHomeDir("target");
+ printer = new StringPrinter();
+ KubernetesHelper.setKubernetesClient(client);
+ }
+
+ @Test
+ @SetEnvironmentVariable(key = "MINIKUBE_ACTIVE_DOCKERD", value =
"minikube")
+ @SetEnvironmentVariable(key = "DOCKER_TLS_VERIFY", value = "1")
+ void explicitMinikubeAppliesImageDefaults() {
+ KubernetesRun command = detectCluster("--cluster-type=minikube");
+
+
Assertions.assertTrue(ClusterType.MINIKUBE.isEqualTo(command.clusterType),
command.clusterType);
+ Assertions.assertEquals("docker", command.imageBuilder);
+ Assertions.assertFalse(command.imagePush);
+ Assertions.assertFalse(printer.getOutput().contains(DOCKER_ENV_HINT),
printer.getOutput());
+ }
+
+ @Test
+ @ClearEnvironmentVariable(key = "MINIKUBE_ACTIVE_DOCKERD")
+ @ClearEnvironmentVariable(key = "DOCKER_TLS_VERIFY")
+ void explicitMinikubeWithoutDockerEnvPrintsHint() {
+ KubernetesRun command = detectCluster("--cluster-type=minikube");
+
+
Assertions.assertTrue(ClusterType.MINIKUBE.isEqualTo(command.clusterType),
command.clusterType);
+ Assertions.assertEquals("docker", command.imageBuilder);
+ Assertions.assertFalse(command.imagePush);
+ Assertions.assertTrue(printer.getOutput().contains(DOCKER_ENV_HINT),
+ "Expected the minikube docker-env hint, but the output was: "
+ printer.getOutput());
+ }
+
+ @Test
+ @ClearEnvironmentVariable(key = "MINIKUBE_ACTIVE_DOCKERD")
+ @ClearEnvironmentVariable(key = "DOCKER_TLS_VERIFY")
+ void dockerEnvHintIsPrintedOnceAcrossReloads() {
+ KubernetesRun command = detectCluster("--cluster-type=minikube");
+ // dev mode calls detectCluster() again on every reload
+ command.detectCluster();
+ command.detectCluster();
+
+ String output = printer.getOutput();
+ Assertions.assertEquals(output.indexOf(DOCKER_ENV_HINT),
output.lastIndexOf(DOCKER_ENV_HINT), output);
+ Assertions.assertTrue(output.contains(DOCKER_ENV_HINT), output);
+ }
+
+ @Test
+ @SetEnvironmentVariable(key = "MINIKUBE_ACTIVE_DOCKERD", value =
"minikube")
+ @SetEnvironmentVariable(key = "DOCKER_TLS_VERIFY", value = "1")
+ void explicitMinikubeWithBareImagePushFlagPushes() {
+ KubernetesRun command = detectCluster("--cluster-type=minikube",
"--image-push");
+
+ Assertions.assertEquals("docker", command.imageBuilder);
+ Assertions.assertEquals(Boolean.TRUE, command.imagePush);
+ }
+
+ @Test
+ @SetEnvironmentVariable(key = "MINIKUBE_ACTIVE_DOCKERD", value =
"minikube")
+ @SetEnvironmentVariable(key = "DOCKER_TLS_VERIFY", value = "1")
+ void explicitMinikubeKeepsImageOptionsSetByUser() {
+ KubernetesRun command = detectCluster("--cluster-type=minikube",
"--image-builder=jib", "--image-push=true");
+
+
Assertions.assertTrue(ClusterType.MINIKUBE.isEqualTo(command.clusterType),
command.clusterType);
+ Assertions.assertEquals("jib", command.imageBuilder);
+ Assertions.assertTrue(command.imagePush);
+ }
+
+ @Test
+ @SetEnvironmentVariable(key = "MINIKUBE_ACTIVE_DOCKERD", value =
"minikube")
+ @SetEnvironmentVariable(key = "DOCKER_TLS_VERIFY", value = "1")
+ void detectedMinikubeKeepsImageBuilderSetByUser() {
+ setupServerExpectsMinikube();
+ KubernetesRun command = detectCluster("--image-builder=jib");
+
+
Assertions.assertTrue(ClusterType.MINIKUBE.isEqualTo(command.clusterType),
command.clusterType);
+ Assertions.assertEquals("jib", command.imageBuilder);
+ // not set by the user: the minikube no-push default only applies to
the docker builder, a jib image is pushed
+ Assertions.assertTrue(command.imagePush);
+ }
+
+ @Test
+ @ClearEnvironmentVariable(key = "MINIKUBE_ACTIVE_DOCKERD")
+ @ClearEnvironmentVariable(key = "DOCKER_TLS_VERIFY")
+ void explicitMinikubeWithoutImageBuildPrintsNoHint() {
+ KubernetesRun command = detectCluster("--cluster-type=minikube",
"--image-build=false");
+
+ Assertions.assertEquals("docker", command.imageBuilder);
+ Assertions.assertFalse(command.imagePush);
+ Assertions.assertFalse(printer.getOutput().contains(DOCKER_ENV_HINT),
printer.getOutput());
+ }
+
+ @Test
+ @ClearEnvironmentVariable(key = "MINIKUBE_ACTIVE_DOCKERD")
+ @ClearEnvironmentVariable(key = "DOCKER_TLS_VERIFY")
+ void explicitMinikubeWithOutputPrintsNoHint() {
+ KubernetesRun command = detectCluster("--cluster-type=minikube",
"--output=yaml");
+
+ Assertions.assertEquals("docker", command.imageBuilder);
+ Assertions.assertFalse(command.imagePush);
+ Assertions.assertFalse(printer.getOutput().contains(DOCKER_ENV_HINT),
printer.getOutput());
+ }
+
+ @Test
+ @SetEnvironmentVariable(key = "MINIKUBE_ACTIVE_DOCKERD", value =
"minikube")
+ @SetEnvironmentVariable(key = "DOCKER_TLS_VERIFY", value = "1")
+ void disableAutoSkipsMinikubeDefaults() {
+ KubernetesRun command = detectCluster("--cluster-type=minikube",
"--disable-auto");
+
+
Assertions.assertTrue(ClusterType.MINIKUBE.isEqualTo(command.clusterType),
command.clusterType);
+ Assertions.assertEquals("jib", command.imageBuilder);
+ Assertions.assertTrue(command.imagePush);
+ }
+
+ @Test
+ @SetEnvironmentVariable(key = "MINIKUBE_ACTIVE_DOCKERD", value =
"minikube")
+ @SetEnvironmentVariable(key = "DOCKER_TLS_VERIFY", value = "1")
+ void explicitK3sIsNotDetected() {
+ setupServerExpectsMinikube();
+ KubernetesRun command = detectCluster("--cluster-type=k3s");
+
+ Assertions.assertTrue(ClusterType.K3S.isEqualTo(command.clusterType),
command.clusterType);
+ Assertions.assertEquals("jib", command.imageBuilder);
+ Assertions.assertTrue(command.imagePush);
+ }
+
+ private KubernetesRun detectCluster(String... args) {
+ KubernetesRun command = new KubernetesRun(new
CamelJBangMain().withPrinter(printer));
+ CommandLine.populateCommand(command, args);
+ command.detectCluster();
+ return command;
+ }
+
+ private void setupServerExpectsMinikube() {
+ Node node = new NodeBuilder()
+ .withNewMetadata()
+ .withName("minikube")
+ .withLabels(Collections.singletonMap("minikube.k8s.io/name",
"minikube"))
+ .endMetadata()
+ .build();
+
server.expect().get().withPath("/api/v1/nodes?labelSelector=minikube.k8s.io%2Fname")
+ .andReturn(HttpURLConnection.HTTP_OK, new
NodeListBuilder().addToItems(node).build())
+ .once();
+ }
+}
diff --git
a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesRunCustomTest.java
b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesRunCustomTest.java
index 02c187a7c212..f6eda1fb82d5 100644
---
a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesRunCustomTest.java
+++
b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesRunCustomTest.java
@@ -161,15 +161,12 @@ class KubernetesRunCustomTest {
}
@Test
- @SetEnvironmentVariable(key = "MINIKUBE_ACTIVE_DOCKERD", value = "foo")
- @SetEnvironmentVariable(key = "DOCKER_TLS_VERIFY", value = "foo")
public void explicitMinikubeClusterTypeShouldApplyDefaults() throws
Exception {
- // Even without auto-detection (minikube env vars are set but ignored
because clusterType is explicit),
- // passing --cluster-type=minikube should still apply the minikube
defaults:
+ // The cluster is not detected as minikube (no minikube node, no
minikube docker-env),
+ // but passing --cluster-type=minikube should still apply the minikube
defaults:
// imageBuilder=docker and imagePush=false.
KubernetesHelper.setKubernetesClient(client);
- setupServerExpectsMinikube();
- KubernetesRun command = createCommand(List.of("classpath:route.yaml"),
+ KubernetesRun command =
createCommandKeepingImagePush(List.of("classpath:route.yaml"),
"--image-registry=quay.io", "--image-group=camel-test",
"--output=yaml",
"--cluster-type=minikube");
int exit = command.doCall();
@@ -201,6 +198,24 @@ class KubernetesRunCustomTest {
printer.getOutput());
}
+ @Test
+ public void explicitK3sClusterTypeShouldOutputKubernetesManifest() throws
Exception {
+ // K3S is built with the kubernetes-maven-plugin, which writes
kubernetes.yml (not k3s.yml)
+ KubernetesHelper.setKubernetesClient(client);
+ KubernetesRun command = createCommand(List.of("classpath:route.yaml"),
+ "--image-registry=quay.io", "--image-group=camel-test",
"--output=yaml",
+ "--cluster-type=k3s");
+ int exit = command.doCall();
+
+ Assertions.assertEquals(0, exit, printer.getOutput());
+ Assertions.assertEquals(ClusterType.K3S.name().toLowerCase(),
command.clusterType.toLowerCase());
+
+ var manifest =
KubernetesBaseTestSupport.getKubernetesManifestAsStream(printer.getOutput(),
command.output);
+ List<HasMetadata> resources = client.load(manifest).items();
+ // expects Service, Deployment manifests in kubernetes.yml
+ Assertions.assertEquals(2, resources.size());
+ }
+
@Test
@SetEnvironmentVariable(key = "MINIKUBE_ACTIVE_DOCKERD", value = "foo")
@SetEnvironmentVariable(key = "DOCKER_TLS_VERIFY", value = "foo")
@@ -340,6 +355,13 @@ class KubernetesRunCustomTest {
}
private KubernetesRun createCommand(List<String> files, String... args) {
+ KubernetesRun command = createCommandKeepingImagePush(files, args);
+ command.imagePush = false;
+ return command;
+ }
+
+ // keeps --image-push as given (or not set), so that the defaults of the
cluster type apply to it
+ private KubernetesRun createCommandKeepingImagePush(List<String> files,
String... args) {
var argsArr = Optional.ofNullable(args).orElse(new String[0]);
var argsLst = new ArrayList<>(Arrays.asList(argsArr));
var jbangMain = new CamelJBangMain().withPrinter(printer);
@@ -351,7 +373,6 @@ class KubernetesRunCustomTest {
};
CommandLine.populateCommand(command, argsLst.toArray(new String[0]));
command.imageBuild = false;
- command.imagePush = false;
return command;
}