This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch camel-4.8.x
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/camel-4.8.x by this push:
new 351d06c6a6d Camel 21386 4.8.x (#16098)
351d06c6a6d is described below
commit 351d06c6a6dafbdbcb78ccd01822e57ed425aefa
Author: Thomas Diesler <[email protected]>
AuthorDate: Mon Oct 28 12:09:42 2024 +0100
Camel 21386 4.8.x (#16098)
* [CAMEL-21381] camel k8s cannot run spring-boot on openshift (#16084)
* [CAMEL-21386] camel k8s run --dev does not work on openshift
---
dsl/camel-jbang/README.md | 4 +-
.../dsl/jbang/core/commands/CamelCommand.java | 4 +-
.../dsl/jbang/core/commands/CommandHelper.java | 11 ++
.../core/commands/action/CamelThreadDump.java | 2 +-
.../camel/dsl/jbang/core/common/PluginHelper.java | 2 +-
.../core/commands/kubernetes/KubernetesDelete.java | 7 +-
.../core/commands/kubernetes/KubernetesExport.java | 1 -
.../core/commands/kubernetes/KubernetesHelper.java | 47 ++++---
.../core/commands/kubernetes/KubernetesRun.java | 150 ++++++++++++---------
.../jbang/core/commands/kubernetes/PodLogs.java | 110 ++++++++-------
.../commands/kubernetes/KubernetesClientTest.java | 47 -------
.../core/commands/kubernetes/PodLogsTest.java | 7 +-
12 files changed, 201 insertions(+), 191 deletions(-)
diff --git a/dsl/camel-jbang/README.md b/dsl/camel-jbang/README.md
index 08bb58fa0db..62f17a370e7 100644
--- a/dsl/camel-jbang/README.md
+++ b/dsl/camel-jbang/README.md
@@ -9,10 +9,10 @@ jbang app install camel@apache/camel
If you however like to install camel-jbang from this project build you create
an alias to the local entry point.
```shell
-jbang alias add --name camel -Dcamel.jbang.version=4.8.1-SNAPSHOT
./dsl/camel-jbang/camel-jbang-main/dist/CamelJBang.java
+jbang alias add --name camel -Dcamel.jbang.version=4.8.2-SNAPSHOT
./dsl/camel-jbang/camel-jbang-main/dist/CamelJBang.java
jbang camel version
-Camel JBang version: 4.8.1-SNAPSHOT
+Camel JBang version: 4.8.2-SNAPSHOT
```
Alternatively, you can change the version in
[`CamelJBang.java`](https://github.com/apache/camel/blob/main/dsl/camel-jbang/camel-jbang-main/src/main/jbang/main/CamelJBang.java#L22)
\ No newline at end of file
diff --git
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelCommand.java
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelCommand.java
index 41ae9f33f67..eb4b256f024 100644
---
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelCommand.java
+++
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelCommand.java
@@ -115,7 +115,9 @@ public abstract class CamelCommand implements
Callable<Integer> {
}
protected Printer printer() {
- return getMain().getOut();
+ var out = getMain().getOut();
+ CommandHelper.SetPrinter(out);
+ return out;
}
protected void printConfigurationValues(String header) {
diff --git
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CommandHelper.java
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CommandHelper.java
index 1ce40f1a4f8..864da314bec 100644
---
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CommandHelper.java
+++
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CommandHelper.java
@@ -18,13 +18,24 @@ package org.apache.camel.dsl.jbang.core.commands;
import java.io.File;
+import org.apache.camel.dsl.jbang.core.common.Printer;
import org.apache.camel.util.FileUtil;
public final class CommandHelper {
+ private static ThreadLocal<Printer> printerAssociation = new
ThreadLocal<>();
+
private CommandHelper() {
}
+ public static Printer GetPrinter() {
+ return printerAssociation.get();
+ }
+
+ public static void SetPrinter(Printer out) {
+ printerAssociation.set(out);
+ }
+
public static void cleanExportDir(String dir) {
File target = new File(dir);
File[] files = target.listFiles();
diff --git
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelThreadDump.java
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelThreadDump.java
index d5666ded944..5bd19d7b36e 100644
---
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelThreadDump.java
+++
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelThreadDump.java
@@ -148,7 +148,7 @@ public class CamelThreadDump extends ActionWatchCommand {
if (!rows.isEmpty()) {
int total = jo.getInteger("threadCount");
int peak = jo.getInteger("peakThreadCount");
- printer().printf("PID: %s\tThreads: %d\tPeak: %d\t\tDisplay:
%d/%d\n", pid, total, peak, rows.size(), total);
+ printer().printf("PID: %s\tThreads: %d\tPeak: %d\t\tDisplay:
%d/%d%n", pid, total, peak, rows.size(), total);
if (depth == 1) {
singleTable(rows);
diff --git
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/PluginHelper.java
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/PluginHelper.java
index fbe0af60b29..fe9e504aa15 100644
---
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/PluginHelper.java
+++
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/PluginHelper.java
@@ -157,7 +157,7 @@ public final class PluginHelper {
instance =
Optional.of(Plugin.class.cast(ObjectHelper.newInstance(pluginClass)));
} else {
String gav = String.join(":", group, "camel-jbang-plugin-" +
command, version);
- main.getOut().printf(String.format("ERROR: Failed to read file
%s in dependency %s.\n", path, gav));
+ main.getOut().printf(String.format("ERROR: Failed to read file
%s in dependency %s%n", path, gav));
}
} catch (IOException e) {
throw new RuntimeCamelException(String.format("Failed to read the
file %s.", path), e);
diff --git
a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesDelete.java
b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesDelete.java
index a5c44169177..226f050adb1 100644
---
a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesDelete.java
+++
b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesDelete.java
@@ -44,6 +44,10 @@ public class KubernetesDelete extends KubernetesBaseCommand {
description = "The working directory where to find
exported project sources.")
String workingDir;
+ @CommandLine.Option(names = { "--cluster-type" },
+ description = "The target cluster type. Special
configurations may be applied to different cluster types such as Kind or
Minikube or Openshift.")
+ protected String clusterType;
+
public KubernetesDelete(CamelJBangMain main) {
super(main);
}
@@ -71,7 +75,8 @@ public class KubernetesDelete extends KubernetesBaseCommand {
return 1;
}
- File manifest = KubernetesHelper.resolveKubernetesManifest(new
File(resolvedWorkingDir, "target/kubernetes"));
+ File resolvedManifestDir = new File(resolvedWorkingDir,
"target/kubernetes");
+ File manifest =
KubernetesHelper.resolveKubernetesManifest(clusterType, resolvedManifestDir);
try (FileInputStream fis = new FileInputStream(manifest)) {
List<StatusDetails> status;
if (!ObjectHelper.isEmpty(namespace)) {
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 6fa5cb92c4c..ef7b0b91962 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
@@ -125,7 +125,6 @@ public class KubernetesExport extends Export {
public KubernetesExport(CamelJBangMain main, String[] files) {
super(main);
-
this.files = Arrays.asList(files);
}
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 6f5d6724ab2..976de6a4ae3 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
@@ -31,8 +31,10 @@ import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.json.JsonMapper;
+import io.fabric8.kubernetes.api.model.Pod;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.KubernetesClientBuilder;
+import org.apache.camel.dsl.jbang.core.commands.CommandHelper;
import org.apache.camel.dsl.jbang.core.common.YamlHelper;
import org.apache.camel.util.FileUtil;
import org.apache.camel.util.StringHelper;
@@ -74,6 +76,7 @@ public final class KubernetesHelper {
public static KubernetesClient getKubernetesClient() {
if (kubernetesClient == null) {
kubernetesClient = new KubernetesClientBuilder().build();
+ printClientInfo(kubernetesClient);
}
return kubernetesClient;
@@ -87,7 +90,18 @@ public final class KubernetesHelper {
return clients.get(config);
}
- return clients.put(config, new
KubernetesClientBuilder().withConfig(config).build());
+ var client = new KubernetesClientBuilder().withConfig(config).build();
+ printClientInfo(client);
+ return clients.put(config, client);
+ }
+
+ private static void printClientInfo(KubernetesClient client) {
+ var printer = CommandHelper.GetPrinter();
+ if (printer != null) {
+ var serverUrl = client.getConfiguration().getMasterUrl();
+ var info = client.getKubernetesVersion();
+ printer.println(String.format("Kubernetes v%s.%s %s",
info.getMajor(), info.getMinor(), serverUrl));
+ }
}
/**
@@ -146,29 +160,23 @@ public final class KubernetesHelper {
return json().convertValue(model, Map.class);
}
- public static File resolveKubernetesManifest(String workingDir) throws
FileNotFoundException {
- return resolveKubernetesManifest(new File(workingDir));
+ public static File resolveKubernetesManifest(String clusterType, String
workingDir) throws FileNotFoundException {
+ return resolveKubernetesManifest(clusterType, new File(workingDir));
}
- public static File resolveKubernetesManifest(String workingDir, String
extension) throws FileNotFoundException {
- return resolveKubernetesManifest(new File(workingDir), extension);
+ public static File resolveKubernetesManifest(String clusterType, String
workingDir, String extension)
+ throws FileNotFoundException {
+ return resolveKubernetesManifest(clusterType, new File(workingDir),
extension);
}
- public static File resolveKubernetesManifest(File workingDir) throws
FileNotFoundException {
- return resolveKubernetesManifest(workingDir, "yml");
+ public static File resolveKubernetesManifest(String clusterType, File
workingDir) throws FileNotFoundException {
+ return resolveKubernetesManifest(clusterType, workingDir, "yml");
}
- public static File resolveKubernetesManifest(File workingDir, String
extension) throws FileNotFoundException {
-
- // Try explicit Kubernetes manifest first
- String clusterType = ClusterType.KUBERNETES.name();
- File manifest = getKubernetesManifest(clusterType, workingDir,
extension);
- if (manifest.exists()) {
- return manifest;
- }
+ public static File resolveKubernetesManifest(String clusterType, File
workingDir, String extension)
+ throws FileNotFoundException {
- // Try arbitrary Kubernetes manifest first
- manifest = getKubernetesManifest(clusterType, workingDir);
+ var manifest = getKubernetesManifest(clusterType, workingDir);
if (manifest.exists()) {
return manifest;
}
@@ -178,6 +186,10 @@ public final class KubernetesHelper {
.formatted(extension, workingDir.toPath().toString()));
}
+ public static String getPodPhase(Pod pod) {
+ return Optional.ofNullable(pod).map(p ->
p.getStatus().getPhase()).orElse("Unknown");
+ }
+
public static File getKubernetesManifest(String clusterType, String
workingDir) {
return getKubernetesManifest(clusterType, new File(workingDir));
}
@@ -193,7 +205,6 @@ public final class KubernetesHelper {
} else {
manifestFile =
Optional.ofNullable(clusterType).map(String::toLowerCase).orElse("kubernetes");
}
-
return new File(workingDir, "%s.%s".formatted(manifestFile,
extension));
}
}
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 19319d2b566..a25c8f5cc9d 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
@@ -44,6 +44,8 @@ import org.apache.camel.util.StringHelper;
import org.apache.camel.util.concurrent.ThreadHelper;
import picocli.CommandLine;
+import static
org.apache.camel.dsl.jbang.core.commands.kubernetes.KubernetesHelper.getPodPhase;
+
@CommandLine.Command(name = "run", description = "Run Camel application on
Kubernetes", sortOptions = false)
public class KubernetesRun extends KubernetesBaseCommand {
@@ -239,8 +241,12 @@ public class KubernetesRun extends KubernetesBaseCommand {
description = "Maven/Gradle build properties, ex.
--build-property=prop1=foo")
List<String> buildProperties = new ArrayList<>();
- CamelContext reloadContext;
- int reloadCount;
+ // DevMode/Reload state
+ private CamelContext devModeContext;
+ private Thread devModeShutdownTask;
+ private int devModeReloadCount;
+
+ private PodLogs reusablePodLogs;
public KubernetesRun(CamelJBangMain main) {
super(main);
@@ -273,9 +279,10 @@ public class KubernetesRun extends KubernetesBaseCommand {
File manifest;
switch (output) {
case "yaml" ->
- manifest =
KubernetesHelper.resolveKubernetesManifest(workingDir + "/target/kubernetes");
+ manifest =
KubernetesHelper.resolveKubernetesManifest(clusterType, workingDir +
"/target/kubernetes");
case "json" ->
- manifest =
KubernetesHelper.resolveKubernetesManifest(workingDir + "/target/kubernetes",
"json");
+ manifest =
KubernetesHelper.resolveKubernetesManifest(clusterType, workingDir +
"/target/kubernetes",
+ "json");
default -> {
printer().printf("Unsupported output format '%s'
(supported: yaml, json)%n", output);
return 1;
@@ -305,7 +312,6 @@ public class KubernetesRun extends KubernetesBaseCommand {
if (dev || logs) {
startPodLogging(projectName);
- printer().println("Stopped pod logging!");
}
return 0;
@@ -313,8 +319,8 @@ public class KubernetesRun extends KubernetesBaseCommand {
private String getIndexedWorkingDir(String projectName) {
var workingDir = RUN_PLATFORM_DIR + "/" + projectName;
- if (reloadCount > 0) {
- workingDir += "-%03d".formatted(reloadCount);
+ if (devModeReloadCount > 0) {
+ workingDir += "-%03d".formatted(devModeReloadCount);
}
return workingDir;
}
@@ -395,51 +401,79 @@ public class KubernetesRun extends KubernetesBaseCommand {
FileWatcherResourceReloadStrategy reloadStrategy = new
FileWatcherResourceReloadStrategy(watchDir);
reloadStrategy.setResourceReload((name, resource) -> {
- reloadCount += 1;
- reloadContext.close();
- printer().printf("Reloading project due to file change: %s%n",
FileUtil.stripPath(name));
- String reloadWorkingDir = getIndexedWorkingDir(projectName);
- KubernetesExport export = configureExport(reloadWorkingDir);
- int exit = export.export();
- if (exit != 0) {
- printer().printf("Project reexport failed for: %s%n",
reloadWorkingDir);
- return;
- }
- exit = deployProject(reloadWorkingDir, true);
- if (exit != 0) {
- printer().printf("Project redeploy failed for: %s%n",
reloadWorkingDir);
- return;
- }
- if (dev || wait || logs) {
- waitForRunningPod(projectName);
- }
- if (dev) {
+ synchronized (this) {
+
+ printer().printf("Reloading project due to file change: %s%n",
FileUtil.stripPath(name));
+
+ String currentWorkingDir = getIndexedWorkingDir(projectName);
+ devModeReloadCount += 1;
+
+ String reloadWorkingDir = getIndexedWorkingDir(projectName);
+ devModeContext.close();
+
+ // Re-export updated project
+ //
+ KubernetesExport export = configureExport(reloadWorkingDir);
+ int exit = export.export();
+ if (exit != 0) {
+ printer().printf("Project reexport failed for: %s%n",
reloadWorkingDir);
+ return;
+ }
+
+ reusablePodLogs.retryForReload = true;
+ try {
+
+ // Undeploy/Delete current project
+ //
+ KubernetesDelete deleteCommand = new
KubernetesDelete(getMain());
+ deleteCommand.workingDir = currentWorkingDir;
+ deleteCommand.clusterType = clusterType;
+ deleteCommand.name = projectName;
+ deleteCommand.doCall();
+
+ // Re-deploy updated project
+ //
+ exit = deployProject(reloadWorkingDir, true);
+ if (exit != 0) {
+ printer().printf("Project redeploy failed for: %s%n",
reloadWorkingDir);
+ return;
+ }
+
+ waitForRunningPod(projectName);
+
+ } finally {
+ reusablePodLogs.retryForReload = false;
+ }
+
+ // Recursively setup --dev mode for updated project
+ //
+ Runtime.getRuntime().removeShutdownHook(devModeShutdownTask);
setupDevMode(projectName, reloadWorkingDir);
+
+ printer().printf("Project reloaded: %s%n", reloadWorkingDir);
}
- printer().printf("Project reloaded: %s%n", reloadWorkingDir);
});
if (filter != null) {
reloadStrategy.setFileFilter(filter);
}
- reloadContext = new DefaultCamelContext(false);
- reloadContext.addService(reloadStrategy);
- reloadContext.start();
+ devModeContext = new DefaultCamelContext(false);
+ devModeContext.addService(reloadStrategy);
+ devModeContext.start();
if (cleanup) {
- installShutdownInterceptor(projectName, workingDir);
+ installShutdownHook(projectName, workingDir);
}
}
private void startPodLogging(String projectName) throws Exception {
try {
- var podLogs = new PodLogs(getMain());
- podLogs.withClient(client());
- podLogs.label = "%s=%s".formatted(BaseTrait.KUBERNETES_NAME_LABEL,
projectName);
+ reusablePodLogs = new PodLogs(getMain());
if (!ObjectHelper.isEmpty(namespace)) {
- podLogs.namespace = namespace;
+ reusablePodLogs.namespace = namespace;
}
- podLogs.doCall();
+ reusablePodLogs.name = projectName;
+ reusablePodLogs.doCall();
} catch (Exception e) {
printer().println("Failed to read pod logs - " + e);
throw e;
@@ -455,24 +489,28 @@ public class KubernetesRun extends KubernetesBaseCommand {
}
printer().println("Run: " + kubectlCmd);
}
- client(Pod.class).withLabel(BaseTrait.KUBERNETES_NAME_LABEL,
projectName)
- .waitUntilCondition(it ->
"Running".equals(it.getStatus().getPhase()), 10, TimeUnit.MINUTES);
+ var pod = client(Pod.class).withLabel(BaseTrait.KUBERNETES_NAME_LABEL,
projectName)
+ .waitUntilCondition(it -> "Running".equals(getPodPhase(it)),
10, TimeUnit.MINUTES);
+ if (!quiet) {
+ printer().println(String.format("Pod '%s' in phase %s",
pod.getMetadata().getName(), getPodPhase(pod)));
+ }
}
- private void installShutdownInterceptor(String projectName, String
workingDir) {
+ private void installShutdownHook(String projectName, String workingDir) {
KubernetesDelete deleteCommand = new KubernetesDelete(getMain());
- deleteCommand.name = projectName;
+ deleteCommand.clusterType = clusterType;
deleteCommand.workingDir = workingDir;
+ deleteCommand.name = projectName;
- Thread task = new Thread(() -> {
+ devModeShutdownTask = new Thread(() -> {
try {
deleteCommand.doCall();
} catch (Exception e) {
throw new RuntimeException(e);
}
});
- task.setName(ThreadHelper.resolveThreadName(null,
"CamelShutdownInterceptor"));
- Runtime.getRuntime().addShutdownHook(task);
+ devModeShutdownTask.setName(ThreadHelper.resolveThreadName(null,
"CamelShutdownInterceptor"));
+ Runtime.getRuntime().addShutdownHook(devModeShutdownTask);
}
private Integer buildProject(String workingDir) throws IOException,
InterruptedException {
@@ -493,17 +531,10 @@ public class KubernetesRun extends KubernetesBaseCommand {
args.add("--file");
args.add(workingDir);
- if (runtime == RuntimeType.quarkus) {
-
- if (ClusterType.KUBERNETES.isEqualTo(clusterType)) {
- if (!ObjectHelper.isEmpty(namespace)) {
- args.add("-Dquarkus.kubernetes.namespace=" + namespace);
- }
- }
-
- } else {
-
- if (!ObjectHelper.isEmpty(namespace)) {
+ if (!ObjectHelper.isEmpty(namespace)) {
+ if (runtime == RuntimeType.quarkus &&
ClusterType.KUBERNETES.isEqualTo(clusterType)) {
+ args.add("-Dquarkus.kubernetes.namespace=" + namespace);
+ } else {
args.add("-Djkube.namespace=%s".formatted(namespace));
}
}
@@ -547,6 +578,8 @@ public class KubernetesRun extends KubernetesBaseCommand {
args.add("--file");
args.add(workingDir);
+ boolean isOpenshift = ClusterType.OPENSHIFT.isEqualTo(clusterType);
+
if (runtime == RuntimeType.quarkus) {
if (imagePlatforms != null) {
@@ -556,7 +589,7 @@ public class KubernetesRun extends KubernetesBaseCommand {
args.add("-Dquarkus.container-image.build=" + imageBuild);
args.add("-Dquarkus.container-image.push=" + imagePush);
- if (ClusterType.OPENSHIFT.isEqualTo(clusterType)) {
+ if (isOpenshift) {
args.add("-Dquarkus.openshift.deploy=true");
} else {
args.add("-Dquarkus.kubernetes.deploy=true");
@@ -581,11 +614,8 @@ public class KubernetesRun extends KubernetesBaseCommand {
args.add("-Djkube.namespace=%s".formatted(namespace));
}
- args.add("package");
- if (reload) {
- args.add("k8s:undeploy");
- }
- args.add("k8s:deploy");
+ var prefix = isOpenshift ? "oc" : "k8s";
+ args.add(prefix + ":deploy");
}
if (!quiet) {
diff --git
a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/PodLogs.java
b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/PodLogs.java
index cd6f65d7bf0..42baee9cea7 100644
---
a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/PodLogs.java
+++
b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/PodLogs.java
@@ -19,19 +19,20 @@ package org.apache.camel.dsl.jbang.core.commands.kubernetes;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
-import java.util.concurrent.atomic.AtomicInteger;
+import java.util.Optional;
-import io.fabric8.kubernetes.api.model.Pod;
-import io.fabric8.kubernetes.api.model.PodList;
import io.fabric8.kubernetes.client.dsl.LogWatch;
import io.fabric8.kubernetes.client.dsl.PodResource;
import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
import org.apache.camel.dsl.jbang.core.commands.kubernetes.traits.BaseTrait;
import org.apache.camel.dsl.jbang.core.common.SourceScheme;
import org.apache.camel.util.FileUtil;
+import org.apache.camel.util.ObjectHelper;
import picocli.CommandLine;
import picocli.CommandLine.Command;
+import static
org.apache.camel.dsl.jbang.core.commands.kubernetes.KubernetesHelper.getPodPhase;
+
@Command(name = "logs", description = "Print the logs of a Kubernetes pod",
sortOptions = false)
public class PodLogs extends KubernetesBaseCommand {
@@ -56,10 +57,13 @@ public class PodLogs extends KubernetesBaseCommand {
description = "The number of lines from the end of the
logs to show. Defaults to -1 to show all the lines.")
int tail = -1;
- int maxWaitAttempts = 30; // total timeout of 60 seconds
+ // total timeout of 60s
+ int maxRetryAttempts = 30;
+ boolean retryForReload;
+ private int retryCount;
// used for testing
- int maxLogMessages = -1;
+ long maxMessageCount = -1;
long messageCount = 0;
public PodLogs(CamelJBangMain main) {
@@ -67,6 +71,7 @@ public class PodLogs extends KubernetesBaseCommand {
}
public Integer doCall() throws Exception {
+
if (name == null && label == null && filePath == null) {
printer().println("Name or label selector must be set");
return 1;
@@ -87,76 +92,69 @@ public class PodLogs extends KubernetesBaseCommand {
printer().println("--label selector must be in syntax: key=value");
}
- boolean shouldResume = true;
- AtomicInteger resumeCount = new AtomicInteger();
- while (shouldResume) {
- shouldResume = watchLogs(parts[0], parts[1], container,
resumeCount);
- printer().printf("PodLogs: [resume=%b, count=%d]%n", shouldResume,
resumeCount.get());
- resumeCount.incrementAndGet();
+ var retry = watchLogs();
+ while ((retry || retryForReload) && ++retryCount < maxRetryAttempts) {
sleepWell();
+ printer().printf("Retry %d/%d Pod log for label %s%n", retryCount,
maxRetryAttempts, label);
+ retry = watchLogs();
}
+ printer().println("Stopped pod logging!");
return 0;
}
- public boolean watchLogs(String label, String labelValue, String
container, AtomicInteger resumeCount) {
- PodList pods = pods().withLabel(label, labelValue).list();
+ // Returns true if a retry should be attempted
+ private boolean watchLogs() {
- Pod pod = pods.getItems().stream()
- .filter(p -> p.getStatus().getPhase() != null &&
!"Terminated".equals(p.getStatus().getPhase()))
+ PodResource podRes = pods().withLabel(label)
+ .resources()
.findFirst()
.orElse(null);
-
- if (pod == null) {
- if (resumeCount.get() == 0) {
- printer().printf("Pod for label %s=%s not available - Waiting
...%n".formatted(label, labelValue));
- }
-
- // use 2-sec delay in waiting for pod logs mode
- sleepWell();
- return resumeCount.get() < maxWaitAttempts;
- }
-
- String containerName = null;
- if (pod.getSpec() != null && pod.getSpec().getContainers() != null) {
- if (container != null &&
pod.getSpec().getContainers().stream().anyMatch(c ->
container.equals(c.getName()))) {
- containerName = container;
- } else if (!pod.getSpec().getContainers().isEmpty()) {
- containerName = pod.getSpec().getContainers().get(0).getName();
- }
+ if (podRes == null) {
+ printer().printf("Pod for label %s not available%n", label);
+ return true;
}
- PodResource podRes = pods().withName(pod.getMetadata().getName());
+ var terminated = isPodTerminated(podRes);
+ if (!terminated) {
- LogWatch logs;
- if (tail < 0) {
- if (containerName != null) {
- logs = podRes.inContainer(containerName).watchLog();
- } else {
- logs = podRes.watchLog();
- }
- } else {
- if (containerName != null) {
- logs =
podRes.inContainer(containerName).tailingLines(tail).watchLog();
+ LogWatch logs;
+ if (tail < 0) {
+ if (!ObjectHelper.isEmpty(container)) {
+ logs = podRes.inContainer(container).watchLog();
+ } else {
+ logs = podRes.watchLog();
+ }
} else {
- logs = podRes.tailingLines(tail).watchLog();
+ if (!ObjectHelper.isEmpty(container)) {
+ logs =
podRes.inContainer(container).tailingLines(tail).watchLog();
+ } else {
+ logs = podRes.tailingLines(tail).watchLog();
+ }
}
- }
- try (logs; BufferedReader reader = new BufferedReader(new
InputStreamReader(logs.getOutput()))) {
- String line;
- while ((line = reader.readLine()) != null) {
- printer().println(line);
- if (messageCount++ > maxLogMessages && maxLogMessages > 0) {
- return false;
+ try (logs; BufferedReader reader = new BufferedReader(new
InputStreamReader(logs.getOutput()))) {
+ String line;
+ while ((line = reader.readLine()) != null) {
+ printer().println(line);
+ if (maxMessageCount > 0 && ++messageCount >
maxMessageCount) {
+ return false;
+ }
+ retryCount = 0;
}
- resumeCount.set(0);
+ } catch (IOException e) {
+ printer().println("Failed to read pod logs - " +
e.getMessage());
}
- } catch (IOException e) {
- printer().println("Failed to read pod logs - " + e.getMessage());
+
+ terminated = isPodTerminated(podRes);
}
- return resumeCount.get() < maxWaitAttempts;
+ return !terminated;
+ }
+
+ private boolean isPodTerminated(PodResource podRes) {
+ var phase = Optional.ofNullable(podRes).map(pr ->
getPodPhase(pr.get())).orElse("Unknown");
+ return "Terminated".equals(phase);
}
private void sleepWell() {
diff --git
a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesClientTest.java
b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesClientTest.java
deleted file mode 100644
index d532b3bb99a..00000000000
---
a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesClientTest.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * 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 io.fabric8.kubernetes.client.KubernetesClient;
-import io.fabric8.kubernetes.client.KubernetesClientException;
-import io.fabric8.openshift.client.OpenShiftClient;
-import org.junit.jupiter.api.Test;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-class KubernetesClientTest {
-
- private static final Logger log =
LoggerFactory.getLogger(KubernetesClientTest.class);
-
- @Test
- public void shouldHaveOpenshiftClient() {
- try (KubernetesClient client = KubernetesHelper.getKubernetesClient())
{
- OpenShiftClient openShiftClient =
client.adapt(OpenShiftClient.class);
- try {
- openShiftClient.projects().list().getItems().forEach(project
-> {
- log.debug("Project: {}", project.getMetadata().getName());
- });
- log.info("OpenShiftClient is authenticated and working
properly.");
- } catch (KubernetesClientException e) {
- log.debug("OpenShiftClient is not authenticated: {}",
e.getMessage());
- }
- } catch (Exception e) {
- log.debug("Cannot construct OpenShiftClient: {}", e.getMessage());
- }
- }
-}
diff --git
a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/PodLogsTest.java
b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/PodLogsTest.java
index d031c7d2430..ffb83fe20bc 100644
---
a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/PodLogsTest.java
+++
b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/PodLogsTest.java
@@ -32,8 +32,9 @@ class PodLogsTest extends KubernetesBaseTest {
public void shouldHandlePodNotFound() throws Exception {
PodLogs command = createCommand();
command.name = "mickey-mouse";
- command.maxWaitAttempts = 2; // total timeout of 4 seconds
- command.doCall();
+ command.maxRetryAttempts = 2; // total timeout of 4 seconds
+ int exit = command.doCall();
+ Assertions.assertEquals(0, exit);
Assertions.assertTrue(
printer.getOutput().contains("Pod for label
app.kubernetes.io/name=mickey-mouse not available"));
@@ -54,7 +55,7 @@ class PodLogsTest extends KubernetesBaseTest {
kubernetesClient.pods().resource(pod).create();
var podLog = createCommand();
- podLog.maxLogMessages = 10;
+ podLog.maxMessageCount = 10;
podLog.name = "routes";
int exit = podLog.doCall();
Assertions.assertEquals(0, exit);