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 ad0147f49200c0be7843ce7ee3995d416ca04714 Author: Marat Gubaidullin <[email protected]> AuthorDate: Fri Sep 25 15:22:32 2026 -0400 PLATFORM_HOST --- karavan-devmode/entrypoint.sh | 10 +- karavan-devmode/pom.xml | 5 + karavan-devmode/src/main/java/KaravanDevMode.java | 93 +++--------- ...KaravanDevMode.java => KaravanFileFetcher.java} | 45 ++---- .../src/main/java/KaravanLabelAugmenter.java | 157 +++++++++++++++++++++ 5 files changed, 198 insertions(+), 112 deletions(-) diff --git a/karavan-devmode/entrypoint.sh b/karavan-devmode/entrypoint.sh index 685e02fb..75f7acfc 100755 --- a/karavan-devmode/entrypoint.sh +++ b/karavan-devmode/entrypoint.sh @@ -11,18 +11,18 @@ log_step() { } export -f log_step -# Function to determine KARAVAN_HOST based on the environment (K8s vs Docker) +# Function to determine PLATFORM_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" + export PLATFORM_HOST="karavan.$NAMESPACE" + echo "✅ Kubernetes environment detected. PLATFORM_HOST set to: $PLATFORM_HOST" else - export KARAVAN_HOST="karavan:8080" - echo "🐳 Docker environment detected. KARAVAN_HOST set to: $KARAVAN_HOST" + export PLATFORM_HOST="karavan:8080" + echo "🐳 Docker environment detected. PLATFORM_HOST set to: $PLATFORM_HOST" fi } export -f determine_host diff --git a/karavan-devmode/pom.xml b/karavan-devmode/pom.xml index a38d73b3..4e87feaa 100644 --- a/karavan-devmode/pom.xml +++ b/karavan-devmode/pom.xml @@ -37,6 +37,11 @@ <groupId>org.apache.camel</groupId> <artifactId>camel-jbang-core</artifactId> </dependency> + <dependency> + <groupId>org.apache.maven</groupId> + <artifactId>maven-model</artifactId> + <version>3.9.16</version> + </dependency> </dependencies> <build> diff --git a/karavan-devmode/src/main/java/KaravanDevMode.java b/karavan-devmode/src/main/java/KaravanDevMode.java index b3bbcfaf..c5e94a90 100644 --- a/karavan-devmode/src/main/java/KaravanDevMode.java +++ b/karavan-devmode/src/main/java/KaravanDevMode.java @@ -1,95 +1,40 @@ import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import picocli.CommandLine; -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); - } + CamelJBangMain.run(new KaravanCamelJBangMain(), args); } - private static void fetchFilesFromPlatform(String projectId, String filename, Path targetDir) { - String platformHost = System.getenv("KARAVAN_HOST"); - String sessionId = System.getenv("BUILDER_SESSION_ID"); + static class KaravanCamelJBangMain extends CamelJBangMain { - String url = "http://" + platformHost + "/platform/internal/sources/" + projectId + (filename != null ? "/" + filename : ""); - LOGGER.info("Fetching project files from Platform..."); + private final String projectId = System.getenv("PROJECT_ID"); + private final boolean isBuildMode = Objects.equals(System.getenv("RUN_IN_BUILD_MODE"), "true"); - 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."); + @Override + public void execute(String... args) { + if (args.length == 1 && args[0].equals("fetchBuildScriptFromPlatform")) { + Path targetDir = Path.of(System.getenv("BUILDER_PATH")); + KaravanFileFetcher.fetchFilesFromPlatform("configuration", "build.sh", targetDir); } else { - LOGGER.info("Failed to fetch project files. Platform returned HTTP " + response.statusCode()); + if (!isBuildMode) { + Path targetDir = Path.of(System.getenv("CODE_DIR")); + KaravanFileFetcher.fetchFilesFromPlatform(projectId, null, targetDir); + } + super.execute(args); } - } 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(); + @Override + public void postExecute(CommandLine commandLine, String[] args, int exitCode) { + if (exitCode == 0 && args.length > 0 && Objects.equals(args[0], "export")) { + KaravanLabelAugmenter.addKaravanLabels(args, projectId); } } } diff --git a/karavan-devmode/src/main/java/KaravanDevMode.java b/karavan-devmode/src/main/java/KaravanFileFetcher.java similarity index 59% copy from karavan-devmode/src/main/java/KaravanDevMode.java copy to karavan-devmode/src/main/java/KaravanFileFetcher.java index b3bbcfaf..0fede725 100644 --- a/karavan-devmode/src/main/java/KaravanDevMode.java +++ b/karavan-devmode/src/main/java/KaravanFileFetcher.java @@ -1,7 +1,3 @@ -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; @@ -11,38 +7,18 @@ 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); - } - } +public class KaravanFileFetcher { - private static void fetchFilesFromPlatform(String projectId, String filename, Path targetDir) { - String platformHost = System.getenv("KARAVAN_HOST"); + public static void fetchFilesFromPlatform(String projectId, String filename, Path targetDir) { + String platformHost = System.getenv("PLATFORM_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..."); + System.out.println("Fetching project " + projectId + " files from Platform..."); try { HttpClient client = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(10)).build(); @@ -51,12 +27,15 @@ public class KaravanDevMode { 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."); + System.out.println("Files successfully downloaded and extracted."); } else { - LOGGER.info("Failed to fetch project files. Platform returned HTTP " + response.statusCode()); + System.out.println("Failed to fetch project files. Platform returned HTTP " + response.statusCode()); } } catch (Exception e) { - LOGGER.error("Error establishing connection to Platform: " + e.getMessage()); + e.printStackTrace(); + var causeMessage = e.getCause() != null ? e.getCause().getMessage() : e.getMessage(); + var message = "Error: " + causeMessage; + System.out.println(message); } } @@ -83,11 +62,11 @@ public class KaravanDevMode { 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()); + System.out.printf("Failed to set executable permission on: %s", resolvedPath.toAbsolutePath()); } } - LOGGER.info("Extracted file: {}", resolvedPath.toAbsolutePath()); + System.out.printf("Extracted file: %s", resolvedPath.toAbsolutePath()); } zis.closeEntry(); } diff --git a/karavan-devmode/src/main/java/KaravanLabelAugmenter.java b/karavan-devmode/src/main/java/KaravanLabelAugmenter.java new file mode 100644 index 00000000..8ae9adfc --- /dev/null +++ b/karavan-devmode/src/main/java/KaravanLabelAugmenter.java @@ -0,0 +1,157 @@ +import org.apache.maven.model.Model; +import org.apache.maven.model.io.xpp3.MavenXpp3Reader; +import org.apache.maven.model.io.xpp3.MavenXpp3Writer; +import org.codehaus.plexus.util.xml.Xpp3Dom; + +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 KaravanLabelAugmenter { + + /** + * Adds the two Karavan labels to the JKube plugin of the exported pom.xml, so that every resource JKube + * generates carries them. The pom is written by `camel export` on each build and cannot be prepared in + * advance, which is why it is patched here rather than shipped. + */ + public static void addKaravanLabels(String[] args, String projectId) { + Path pom = exportDir(args).resolve("pom.xml"); + if (!Files.exists(pom)) { + System.out.printf("No pom.xml at %s - Karavan labels not added", pom.toAbsolutePath()); + return; + } + try { + Model model; + try (var reader = Files.newBufferedReader(pom)) { + model = new MavenXpp3Reader().read(reader); + } + var plugin = model.getBuild() == null ? null : model.getBuild().getPlugins().stream() + .filter(p -> Objects.equals(p.getGroupId(), "org.eclipse.jkube")) + .findFirst().orElse(null); + if (plugin == null) { + return; + } + if (plugin.getConfiguration() == null) { + plugin.setConfiguration(new Xpp3Dom("configuration")); + } + var all = child(child(child((Xpp3Dom) plugin.getConfiguration(), "resources"), "labels"), "all"); + var id = model.getArtifactId() != null ? model.getArtifactId() : projectId; + addProperty(all, "org.apache.camel.karavan/type", "packaged"); + addProperty(all, "org.apache.camel.karavan/projectId", id); + + try (var writer = Files.newBufferedWriter(pom)) { + new MavenXpp3Writer().write(writer, model); + } + System.out.printf("Added Karavan labels to %s (projectId %s)%n", pom.toAbsolutePath(), id); + } catch (Exception e) { + System.out.println("Could not add Karavan labels to " + pom.toAbsolutePath() + ": " + e.getMessage()); + } + } + + /** {@code --dir=} of the export command, which is where the pom is written. Defaults to the cwd. */ + private static Path exportDir(String... args) { + for (var arg : args) { + if (arg.startsWith("--dir=")) { + return Path.of(arg.substring("--dir=".length())); + } + } + return Path.of("."); + } + + private static Xpp3Dom child(Xpp3Dom parent, String name) { + var existing = parent.getChild(name); + if (existing != null) { + return existing; + } + var created = new Xpp3Dom(name); + parent.addChild(created); + return created; + } + + private static void addProperty(Xpp3Dom all, String name, String value) { + for (var property : all.getChildren("property")) { + var child = property.getChild("name"); + if (child != null && Objects.equals(child.getValue(), name)) { + return; + } + } + var property = new Xpp3Dom("property"); + var nameNode = new Xpp3Dom("name"); + nameNode.setValue(name); + var valueNode = new Xpp3Dom("value"); + valueNode.setValue(value); + property.addChild(nameNode); + property.addChild(valueNode); + all.addChild(property); + } + + private static void fetchFilesFromPlatform(String projectId, String filename, Path targetDir) { + String platformHost = System.getenv("PLATFORM_HOST"); + String sessionId = System.getenv("BUILDER_SESSION_ID"); + + String url = "http://" + platformHost + "/platform/internal/sources/" + projectId + (filename != null ? "/" + filename : ""); + System.out.println("Fetching project " + projectId + " 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); + System.out.println("Files successfully downloaded and extracted."); + } else { + System.out.println("Failed to fetch project files. Platform returned HTTP " + response.statusCode()); + } + } catch (Exception e) { + e.printStackTrace(); + var causeMessage = e.getCause() != null ? e.getCause().getMessage() : e.getMessage(); + var message = "Error: " + causeMessage; + System.out.println(message); + } + } + + 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) { + System.out.printf("Failed to set executable permission on: %s", resolvedPath.toAbsolutePath()); + } + } + + System.out.printf("Extracted file: %s", resolvedPath.toAbsolutePath()); + } + zis.closeEntry(); + } + } + } +} \ No newline at end of file
