You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ma...@apache.org on 2026/08/25 15:20:05 UTC
(camel-karavan) 40/42: Karavan-app DevMode Redesign
This is an automated email from the ASF dual-hosted git repository.
mgubaidullin pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-karavan.git
commit 3b7cfae5d515638ffda930ee238ae725b45b1a4c
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Tue Aug 25 11:09:38 2026 -0400
Karavan-app DevMode Redesign
---
karavan-devmode/.dockerignore | 5 ++
karavan-devmode/Dockerfile | 53 ++++++------
karavan-devmode/entrypoint.sh | 60 ++++++++++++++
karavan-devmode/pom.xml | 65 +++++++++++++++
karavan-devmode/src/main/java/KaravanDevMode.java | 96 ++++++++++++++++++++++
.../src/main/resources/log4j2.component.properties | 2 +
.../src/main/resources/log4j2.properties | 21 +++++
7 files changed, 278 insertions(+), 24 deletions(-)
diff --git a/karavan-devmode/.dockerignore b/karavan-devmode/.dockerignore
new file mode 100644
index 00000000..8a8b6548
--- /dev/null
+++ b/karavan-devmode/.dockerignore
@@ -0,0 +1,5 @@
+*
+!target/karavan-devmode*
+!target/lib/*
+!entrypoint.sh
+src/*
\ No newline at end of file
diff --git a/karavan-devmode/Dockerfile b/karavan-devmode/Dockerfile
index 1e3e0fc8..b9625ead 100644
--- a/karavan-devmode/Dockerfile
+++ b/karavan-devmode/Dockerfile
@@ -12,47 +12,52 @@
# 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.
-
-FROM maven:3.9.12-eclipse-temurin-21
+FROM registry.access.redhat.com/ubi9/openjdk-21:1.24-2.1782292637
LABEL "org.opencontainers.image.title"="karavan-devmode"
LABEL "org.opencontainers.image.description"="Apache Camel Karavan DevMode"
LABEL "org.opencontainers.image.url"="https://camel.apache.org"
LABEL "org.opencontainers.image.licenses"="Apache 2.0"
-LABEL "org.opencontainers.image.version"="4.18.1"
+LABEL "org.opencontainers.image.version"="4.22.0"
+
+ENV MAVEN_HOME=/opt/maven
+ENV PATH=$MAVEN_HOME/bin:$PATH
-RUN apt-get update \
- && apt-get install -y --no-install-recommends git \
- && rm -rf /var/lib/apt/lists/*
+USER root
+RUN microdnf update -y \
+ && microdnf install -y git tar gzip jq \
+ && microdnf clean all
-ENV JBANG_VERSION=0.137.0
-ENV CAMEL_VERSION=4.18.1
-ENV JBANG_JAVA_OPTIONS="-Dcamel.jbang.version=4.18.1 -Dcamel.jbang.kameletsVersion=4.18.1"
ENV KARAVAN="/karavan"
-ENV JBANG_DIR="$KARAVAN/.jbang"
+ENV KARAVAN_LIB="$KARAVAN/lib"
+ENV KARAVAN_SCRIPTS="$KARAVAN/scripts"
+ENV DOCKER_CONFIG_DIR="$KARAVAN/.docker"
ENV MAVEN_CONFIG="$KARAVAN/.m2"
-ENV JBANG_REPO=$MAVEN_CONFIG
+ENV MAVEN_REPO="$MAVEN_CONFIG/repository"
ENV BUILDER_PATH="$KARAVAN/builder"
ENV CODE_DIR="$KARAVAN/code"
ENV KAMELETS_DIR="$CODE_DIR/kamelets"
-ENV PATH="$PATH:$KARAVAN/.jbang/bin"
-RUN mkdir -p $JBANG_REPO \
+ENV RUN_IN_BUILD_MODE=false
+ENV RUN_IN_COMPILE_MODE=false
+
+RUN mkdir -p $MAVEN_REPO \
&& mkdir -p $CODE_DIR \
+ && mkdir -p $DOCKER_CONFIG_DIR \
&& mkdir -p $BUILDER_PATH
-RUN useradd -rm -d /karavan -s /bin/bash -g root -G sudo -u 1001 karavan
-RUN chown -R karavan $KARAVAN
-
-RUN chgrp -R 0 $KARAVAN && chmod -R g+rwX $KARAVAN
+COPY target/lib/*.jar $KARAVAN_LIB/
+COPY target/karavan-devmode-*.jar $KARAVAN_LIB
+COPY entrypoint.sh $KARAVAN/
+RUN chmod +x $KARAVAN/entrypoint.sh
+RUN groupadd -g 1001 karavan \
+ && useradd -d $KARAVAN -s /bin/bash -g karavan -u 1001 karavan
+RUN chown -R karavan:karavan $KARAVAN
+RUN chown -R karavan:karavan /home/default
USER karavan
-RUN curl -Ls https://sh.jbang.dev | bash -s - app setup \
- && jbang trust add --quiet https://github.com/apache/camel \
- && jbang app install camel@apache/camel \
- && jbang config set cache-evict never
-
EXPOSE 8080
-WORKDIR $CODE_DIR
-CMD ["jbang", "-Dcamel.jbang.version=4.18.1", "-Dcamel.jbang.kameletsVersion=4.18.1", "camel@apache/camel", "run", "--source-dir=/karavan/code", "--console"]
\ No newline at end of file
+WORKDIR $CODE_DIR
+
+ENTRYPOINT ["/karavan/entrypoint.sh"]
\ No newline at end of file
diff --git a/karavan-devmode/entrypoint.sh b/karavan-devmode/entrypoint.sh
new file mode 100755
index 00000000..685e02fb
--- /dev/null
+++ b/karavan-devmode/entrypoint.sh
@@ -0,0 +1,60 @@
+#!/bin/bash
+
+# Entrypoint script for running Karavan in different modes
+
+# Function to print visually separated log headers
+log_step() {
+ echo ""
+ echo "========================================================================"
+ echo "$1"
+ echo "========================================================================"
+}
+export -f log_step
+
+# Function to determine KARAVAN_HOST based on the environment (K8s vs Docker)
+determine_host() {
+ log_step "π Determining Platform Host Environment"
+ local k8s_namespace_file="/var/run/secrets/kubernetes.io/serviceaccount/namespace"
+
+ if [[ -f "$k8s_namespace_file" ]]; then
+ export NAMESPACE=$(cat "$k8s_namespace_file")
+ export KARAVAN_HOST="karavan.$NAMESPACE"
+ echo "β
Kubernetes environment detected. KARAVAN_HOST set to: $KARAVAN_HOST"
+ else
+ export KARAVAN_HOST="karavan:8080"
+ echo "π³ Docker environment detected. KARAVAN_HOST set to: $KARAVAN_HOST"
+ fi
+}
+export -f determine_host
+
+# Function to set git credentials
+git_auth_username_password() {
+ log_step "π Configure Git Credentials"
+ git config --global credential.helper 'cache --timeout=3600'
+ git_credential_fill() {
+ echo url=$GIT_REPOSITORY
+ echo username=$GIT_USERNAME
+ echo password=$GIT_PASSWORD
+ }
+ git_credential_fill | git credential approve
+}
+export -f git_auth_username_password
+
+determine_host
+
+if [[ "$RUN_IN_COMPILE_MODE" == "true" ]]; then
+ log_step "π·Running compiled..."
+ java $JAVA_OPTS -cp "$KARAVAN_LIB/*" KaravanDevMode export --local-kamelet-dir="$KAMELETS_DIR" --dir=.export
+ mvn compile dependency:copy-dependencies -f .export -DoutputDirectory=target/lib
+ export BASE_PACKAGE_SCAN=$(grep -oP '^camel\.main\.basePackageScan=\K.*' .export/src/main/resources/application.properties)
+ java $JAVA_OPTS -cp ".export/target/lib/*:.export/target/classes" "$BASE_PACKAGE_SCAN".CamelApplication
+elif [[ "$RUN_IN_BUILD_MODE" == "true" ]]; then
+ log_step "π¦ Packaging..."
+ secure_ssh_keys
+ log_step "ποΈ Preparing build.sh script"
+ java $JAVA_OPTS -cp "$KARAVAN_LIB/*" KaravanDevMode fetchBuildScriptFromPlatform
+ /karavan/builder/build.sh
+else
+ log_step "π Karavan Developer Mode for $PROJECT_ID"
+ java $JAVA_OPTS -cp "$KARAVAN_LIB/*" KaravanDevMode run --source-dir="$CODE_DIR" --logging-color=true --console $VERBOSE_OPTION
+fi
\ No newline at end of file
diff --git a/karavan-devmode/pom.xml b/karavan-devmode/pom.xml
new file mode 100644
index 00000000..10f3db84
--- /dev/null
+++ b/karavan-devmode/pom.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"
+ xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.apache.camel.karavan</groupId>
+ <artifactId>karavan-devmode</artifactId>
+ <version>4.22.0</version>
+
+ <properties>
+ <compiler-plugin.version>3.14.0</compiler-plugin.version>
+ <maven.compiler.parameters>true</maven.compiler.parameters>
+ <maven.compiler.source>21</maven.compiler.source>
+ <jandex-maven-plugin-version>3.1.1</jandex-maven-plugin-version>
+ <maven.compiler.target>21</maven.compiler.target>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+ <camel.version>4.22.0</camel.version>
+ </properties>
+
+ <dependencyManagement>
+ <dependencies>
+ <!-- Camel BOM -->
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-bom</artifactId>
+ <version>${camel.version}</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-jbang-core</artifactId>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <executions>
+ <execution>
+ <phase>prepare-package</phase>
+ <goals>
+ <goal>copy-dependencies</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>${project.build.directory}/lib</outputDirectory>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/karavan-devmode/src/main/java/KaravanDevMode.java b/karavan-devmode/src/main/java/KaravanDevMode.java
new file mode 100644
index 00000000..b3bbcfaf
--- /dev/null
+++ b/karavan-devmode/src/main/java/KaravanDevMode.java
@@ -0,0 +1,96 @@
+import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URI;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.time.Duration;
+import java.util.Objects;
+
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+public class KaravanDevMode {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(KaravanDevMode.class.getName());
+
+ public static void main(String... args) throws Exception {
+ var projectId = System.getenv("PROJECT_ID");
+ var isBuildMode = Objects.equals(System.getenv("RUN_IN_BUILD_MODE"), "true");
+
+ if (isBuildMode && args.length == 1 && args[0].equals("fetchBuildScriptFromPlatform")) {
+ Path targetDir = Path.of(System.getenv("BUILDER_PATH"));
+ fetchFilesFromPlatform("configuration", "build.sh", targetDir);
+ } else {
+ if (!isBuildMode) {
+ Path targetDir = Path.of(System.getenv("CODE_DIR"));
+ fetchFilesFromPlatform(projectId, null, targetDir);
+ }
+ // Start Camel JBang
+ CamelJBangMain.run(args);
+ }
+ }
+
+ private static void fetchFilesFromPlatform(String projectId, String filename, Path targetDir) {
+ String platformHost = System.getenv("KARAVAN_HOST");
+ String sessionId = System.getenv("BUILDER_SESSION_ID");
+
+ String url = "http://" + platformHost + "/platform/internal/sources/" + projectId + (filename != null ? "/" + filename : "");
+ LOGGER.info("Fetching project files from Platform...");
+
+ try {
+ HttpClient client = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(10)).build();
+ HttpRequest.Builder requestBuilder = HttpRequest.newBuilder().uri(URI.create(url)).GET();
+ requestBuilder.header("Cookie", "sessionId=" + sessionId);
+ HttpResponse<InputStream> response = client.send(requestBuilder.build(), HttpResponse.BodyHandlers.ofInputStream());
+ if (response.statusCode() == 200) {
+ unzipStream(response.body(), targetDir);
+ LOGGER.info("Files successfully downloaded and extracted.");
+ } else {
+ LOGGER.info("Failed to fetch project files. Platform returned HTTP " + response.statusCode());
+ }
+ } catch (Exception e) {
+ LOGGER.error("Error establishing connection to Platform: " + e.getMessage());
+ }
+ }
+
+ private static void unzipStream(InputStream inputStream, Path targetDir) throws Exception {
+ try (ZipInputStream zis = new ZipInputStream(inputStream)) {
+ ZipEntry entry;
+ while ((entry = zis.getNextEntry()) != null) {
+ Path resolvedPath = targetDir.resolve(entry.getName()).normalize();
+
+ // Zip Slip vulnerability prevention
+ if (!resolvedPath.startsWith(targetDir)) {
+ throw new RuntimeException("Invalid ZIP entry path: " + entry.getName());
+ }
+
+ if (entry.isDirectory()) {
+ Files.createDirectories(resolvedPath);
+ } else {
+ Files.createDirectories(resolvedPath.getParent());
+ try (OutputStream os = Files.newOutputStream(resolvedPath)) {
+ zis.transferTo(os);
+ }
+
+ // Mark file as executable if it is a shell script
+ if (entry.getName().endsWith(".sh")) {
+ boolean success = resolvedPath.toFile().setExecutable(true, false); // true = executable, false = for all users (not just owner)
+ if (!success) {
+ LOGGER.warn("Failed to set executable permission on: {}", resolvedPath.toAbsolutePath());
+ }
+ }
+
+ LOGGER.info("Extracted file: {}", resolvedPath.toAbsolutePath());
+ }
+ zis.closeEntry();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/karavan-devmode/src/main/resources/log4j2.component.properties b/karavan-devmode/src/main/resources/log4j2.component.properties
new file mode 100644
index 00000000..7fd3fcaf
--- /dev/null
+++ b/karavan-devmode/src/main/resources/log4j2.component.properties
@@ -0,0 +1,2 @@
+# camel-main handled JVM shutdown so disable log4j hook
+log4j.shutdownHookEnabled = false
\ No newline at end of file
diff --git a/karavan-devmode/src/main/resources/log4j2.properties b/karavan-devmode/src/main/resources/log4j2.properties
new file mode 100644
index 00000000..8338ca9c
--- /dev/null
+++ b/karavan-devmode/src/main/resources/log4j2.properties
@@ -0,0 +1,21 @@
+# console logger
+appender.stdout.type = Console
+appender.stdout.name = out
+appender.stdout.layout.type = PatternLayout
+# logging style that is similar to spring boot
+appender.stdout.layout.pattern = %style{%d{yyyy-MM-dd HH:mm:ss.SSS}}{Dim} %highlight{%5p} %style{%pid}{Magenta} %style{---}{Dim} %style{[%15.15t]}{Dim} %style{%-40.40c}{Cyan} %style{:}{Dim} %m%n
+
+# file logger
+appender.file.type = File
+appender.file.name = file
+appender.file.fileName = ${sys:user.home}${sys:file.separator}.camel${sys:file.separator}${sys:pid}.log
+appender.file.createOnDemand = true
+appender.file.append = false
+appender.file.layout.type = PatternLayout
+# logging style that is similar to spring boot
+appender.file.layout.pattern = %style{%d{yyyy-MM-dd HH:mm:ss.SSS}}{Dim} %highlight{%5p} %style{%pid}{Magenta} %style{---}{Dim} %style{[%15.15t]}{Dim} %style{%-40.40c}{Cyan} %style{:}{Dim} %m%n
+
+# log to console and file
+rootLogger = INFO,out,file
+rootLogger.level = INFO
+