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 <[email protected]>
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
+

Reply via email to