This is an automated email from the ASF dual-hosted git repository.

marat pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-karavan.git


The following commit(s) were added to refs/heads/main by this push:
     new d72e4dd2 Fix #1357
d72e4dd2 is described below

commit d72e4dd2ba75fe4b88fbd5141f6a403604531daf
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Mon Aug 12 07:07:20 2024 -0400

    Fix #1357
---
 .../camel/karavan/api/ContainerResource.java       | 10 ++--
 .../karavan/docker/DockerComposeConverter.java     | 25 ++++++++++
 .../camel/karavan/docker/DockerForKaravan.java     | 15 ++----
 .../apache/camel/karavan/docker/DockerService.java | 35 ++++++++++---
 .../camel/karavan/model/DockerComposeService.java  | 17 ++-----
 .../camel/karavan/model/DockerComposeVolume.java   | 58 ++++++++++++++++++++++
 .../camel/karavan/service/ConfigService.java       | 13 ++---
 .../camel/karavan/service/ProjectService.java      | 26 ++++++----
 8 files changed, 145 insertions(+), 54 deletions(-)

diff --git 
a/karavan-app/src/main/java/org/apache/camel/karavan/api/ContainerResource.java 
b/karavan-app/src/main/java/org/apache/camel/karavan/api/ContainerResource.java
index d20c0e6e..adf945a4 100644
--- 
a/karavan-app/src/main/java/org/apache/camel/karavan/api/ContainerResource.java
+++ 
b/karavan-app/src/main/java/org/apache/camel/karavan/api/ContainerResource.java
@@ -140,11 +140,11 @@ public class ContainerResource {
         }
     }
 
-    private boolean needPull(JsonObject command) {
-        if (command != null && command.containsKey("pullImage")) {
-            return command.getBoolean("pullImage");
-        }
-        return false;
+    private DockerService.PULL_IMAGE needPull(JsonObject command) {
+        try {
+            return 
DockerService.PULL_IMAGE.valueOf(command.getString("pullImage"));
+        } catch (Exception ignored) {}
+        return DockerService.PULL_IMAGE.never;
     }
 
     private void setContainerStatusTransit(String projectId, String name, 
String type) {
diff --git 
a/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerComposeConverter.java
 
b/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerComposeConverter.java
index 27323646..61534da3 100644
--- 
a/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerComposeConverter.java
+++ 
b/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerComposeConverter.java
@@ -21,6 +21,7 @@ import io.vertx.core.json.JsonArray;
 import io.vertx.core.json.JsonObject;
 import org.apache.camel.karavan.model.DockerCompose;
 import org.apache.camel.karavan.model.DockerComposeService;
+import org.apache.camel.karavan.model.DockerComposeVolume;
 import org.yaml.snakeyaml.DumperOptions;
 import org.yaml.snakeyaml.Yaml;
 import org.yaml.snakeyaml.introspector.Property;
@@ -29,9 +30,13 @@ import org.yaml.snakeyaml.representer.Representer;
 
 import java.util.Map;
 
+import static com.github.dockerjava.api.model.MountType.BIND;
+import static com.github.dockerjava.api.model.MountType.VOLUME;
+
 public class DockerComposeConverter {
 
     private static final String ENVIRONMENT = "environment";
+    private static final String VOLUMES = "volumes";
 
     public static DockerCompose fromCode(String code) {
         Yaml yaml = new Yaml();
@@ -75,6 +80,26 @@ public class DockerComposeConverter {
             });
             service.put(ENVIRONMENT, env);
         }
+        if (service.containsKey(VOLUMES) && service.getValue(VOLUMES) 
instanceof JsonArray) {
+            JsonArray volumes = new JsonArray();
+            JsonArray yamlVolumes = service.getJsonArray(VOLUMES);
+            yamlVolumes.forEach(o -> {
+                if (o instanceof JsonObject) {
+                    volumes.add(o);
+                } else if (o instanceof String) {
+                    var parts = ((String) o).split(":");
+                    if (parts.length == 2) {
+                        var part0 = parts[0];
+                        var type = part0.startsWith("/") || 
part0.startsWith("~") || part0.startsWith("./") ? VOLUME : BIND;
+                        volumes.add(JsonObject.mapFrom(new 
DockerComposeVolume(type.name().toLowerCase(), parts[0], parts[1])));
+                    } else if (parts.length == 1) {
+                        volumes.add(JsonObject.mapFrom(new 
DockerComposeVolume(VOLUME.name().toLowerCase(), null, parts[0])));
+                    }
+                }
+            });
+            service.put(VOLUMES, volumes);
+        }
+
         DockerComposeService ds = service.mapTo(DockerComposeService.class);
         if (ds.getContainer_name() == null) {
             ds.setContainer_name(name);
diff --git 
a/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForKaravan.java
 
b/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForKaravan.java
index feb08009..8b59d527 100644
--- 
a/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForKaravan.java
+++ 
b/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForKaravan.java
@@ -22,6 +22,7 @@ import com.github.dockerjava.api.model.RestartPolicy;
 import jakarta.enterprise.context.ApplicationScoped;
 import jakarta.inject.Inject;
 import org.apache.camel.karavan.model.DockerComposeService;
+import org.apache.camel.karavan.model.DockerComposeVolume;
 import org.apache.camel.karavan.model.PodContainerStatus;
 import org.apache.camel.karavan.model.Project;
 import org.eclipse.microprofile.config.inject.ConfigProperty;
@@ -30,7 +31,6 @@ import org.jboss.logging.Logger;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
-import java.util.Objects;
 
 import static org.apache.camel.karavan.KaravanConstants.*;
 import static 
org.apache.camel.karavan.service.CodeService.BUILD_SCRIPT_FILENAME;
@@ -68,11 +68,6 @@ public class DockerForKaravan {
 
         var imageName = projectDevmodeImage != null ? projectDevmodeImage : 
devmodeImage;
 
-        if (dockerService.getImages().stream().noneMatch(i -> 
Objects.equals(i.getTag(), imageName))) {
-            LOGGER.info("Pulling DevMode image from DockerHub: " + imageName);
-            dockerService.pullImageFromDockerHub(imageName, true);
-        }
-
         return dockerService.createContainer(projectId,
                 (imageName),
                 env, compose.getPortsMap(), healthCheck,
@@ -80,14 +75,14 @@ public class DockerForKaravan {
                         LABEL_PROJECT_ID, projectId,
                         LABEL_CAMEL_RUNTIME, CamelRuntime.CAMEL_MAIN.getValue()
                 ),
-                compose.getVolumesMap(), null, RestartPolicy.noRestart(), 
false,
+                compose.getVolumes(), null, RestartPolicy.noRestart(), 
DockerService.PULL_IMAGE.ifNotExists,
                 compose.getCpus(), compose.getCpu_percent(), 
compose.getMem_limit(), compose.getMem_reservation());
     }
 
     public void runBuildProject(Project project, String script, 
DockerComposeService compose, Map<String, String> sshFiles, String tag) throws 
Exception {
         String containerName = project.getProjectId() + BUILDER_SUFFIX;
         dockerService.deleteContainer(containerName);
-        Container c = createBuildContainer(containerName, project, 
compose.getEnvironmentList(), compose.getVolumesMap(), tag);
+        Container c = createBuildContainer(containerName, project, 
compose.getEnvironmentList(), compose.getVolumes(), tag);
         dockerService.copyExecFile(c.getId(), "/karavan/builder", 
BUILD_SCRIPT_FILENAME, script);
         sshFiles.forEach((name, text) -> {
             dockerService.copyExecFile(c.getId(), "/karavan/.ssh", name, text);
@@ -95,7 +90,7 @@ public class DockerForKaravan {
         dockerService.runContainer(c);
     }
 
-    protected Container createBuildContainer(String containerName, Project 
project, List<String> env, Map<String, String> volumes, String tag) throws 
InterruptedException {
+    protected Container createBuildContainer(String containerName, Project 
project, List<String> env, List<DockerComposeVolume> volumes, String tag) 
throws InterruptedException {
         LOGGER.infof("Starting Build Container ", containerName);
 
         return dockerService.createContainer(containerName, devmodeImage,
@@ -105,7 +100,7 @@ public class DockerForKaravan {
                         LABEL_PROJECT_ID, project.getProjectId(),
                         LABEL_TAG, tag
                 ),
-                volumes, null,RestartPolicy.noRestart(), false, 
+                volumes, null,RestartPolicy.noRestart(), 
DockerService.PULL_IMAGE.ifNotExists,
                 null, null, null, null,
                 "/karavan/builder/build.sh");
     }
diff --git 
a/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerService.java 
b/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerService.java
index e5710187..ed89fd79 100644
--- 
a/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerService.java
+++ 
b/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerService.java
@@ -34,6 +34,7 @@ import jakarta.enterprise.event.Observes;
 import jakarta.inject.Inject;
 import org.apache.camel.karavan.model.ContainerImage;
 import org.apache.camel.karavan.model.DockerComposeService;
+import org.apache.camel.karavan.model.DockerComposeVolume;
 import org.apache.camel.karavan.model.PodContainerStatus;
 import org.apache.camel.karavan.service.CodeService;
 import org.apache.camel.karavan.service.ConfigService;
@@ -54,10 +55,15 @@ import java.util.*;
 import java.util.stream.Collectors;
 
 import static org.apache.camel.karavan.KaravanConstants.LABEL_PROJECT_ID;
+import static org.apache.camel.karavan.KaravanConstants.LABEL_TYPE;
 
 @ApplicationScoped
 public class DockerService {
 
+    public enum PULL_IMAGE {
+        always, ifNotExists, never
+    }
+
     private static final Logger LOGGER = 
Logger.getLogger(DockerService.class.getName());
 
     @ConfigProperty(name = "karavan.docker.network")
@@ -120,7 +126,7 @@ public class DockerService {
 
     public Container getContainer(String id) {
         try (ListContainersCmd cmd = 
getDockerClient().listContainersCmd().withShowAll(true).withIdFilter(List.of(id)))
 {
-            List<Container> containers =  cmd.exec();
+            List<Container> containers = cmd.exec();
             return containers.isEmpty() ? null : containers.get(0);
         }
     }
@@ -136,7 +142,7 @@ public class DockerService {
         }
     }
 
-    public Container createContainerFromCompose(DockerComposeService compose, 
Map<String, String> labels, Boolean pullAlways, String... command) throws 
InterruptedException {
+    public Container createContainerFromCompose(DockerComposeService compose, 
Map<String, String> labels, PULL_IMAGE pullImage, String... command) throws 
InterruptedException {
         List<Container> containers = 
findContainer(compose.getContainer_name());
         if (containers.isEmpty()) {
             HealthCheck healthCheck = 
DockerUtils.getHealthCheck(compose.getHealthcheck());
@@ -153,7 +159,7 @@ public class DockerService {
             }
 
             return createContainer(compose.getContainer_name(), 
compose.getImage(),
-                    env, compose.getPortsMap(), healthCheck, labels, 
compose.getVolumesMap(), networkName, restartPolicy, pullAlways,
+                    env, compose.getPortsMap(), healthCheck, labels, 
compose.getVolumes(), networkName, restartPolicy, pullImage,
                     compose.getCpus(), compose.getCpu_percent(), 
compose.getMem_limit(), compose.getMem_reservation(), command);
 
         } else {
@@ -170,20 +176,33 @@ public class DockerService {
 
     public Container createContainer(String name, String image, List<String> 
env, Map<Integer, Integer> ports,
                                      HealthCheck healthCheck, Map<String, 
String> labels,
-                                     Map<String, String> volumes, String 
network, RestartPolicy restartPolicy,
-                                     boolean pullAlways, String cpus, String 
cpu_percent, String mem_limit, String mem_reservation,
+                                     List<DockerComposeVolume> volumes, String 
network, RestartPolicy restartPolicy,
+                                     PULL_IMAGE pullImage, String cpus, String 
cpu_percent, String mem_limit, String mem_reservation,
                                      String... command) throws 
InterruptedException {
         List<Container> containers = findContainer(name);
         if (containers.isEmpty()) {
-            pullImage(image, pullAlways);
+            if (Objects.equals(labels.get(LABEL_TYPE), 
PodContainerStatus.ContainerType.devmode.name())
+                    || Objects.equals(labels.get(LABEL_TYPE), 
PodContainerStatus.ContainerType.build.name())
+                    || Objects.equals(labels.get(LABEL_TYPE), 
PodContainerStatus.ContainerType.devservice.name())) {
+                LOGGER.info("Pulling DevMode image from DockerHub: " + image);
+                pullImageFromDockerHub(image, Objects.equals(pullImage, 
PULL_IMAGE.always));
+            }
+            if (Objects.equals(labels.get(LABEL_TYPE), 
PodContainerStatus.ContainerType.project.name())) {
+                LOGGER.info("Pulling Project image from Registry: " + image);
+                pullImage(image, Objects.equals(pullImage, PULL_IMAGE.always));
+            }
 
             try (CreateContainerCmd createContainerCmd = 
getDockerClient().createContainerCmd(image).withName(name).withLabels(labels).withEnv(env).withHostName(name).withHealthcheck(healthCheck))
 {
                 Ports portBindings = DockerUtils.getPortBindings(ports);
 
                 List<Mount> mounts = new ArrayList<>();
                 if (volumes != null && !volumes.isEmpty()) {
-                    volumes.forEach((hostPath, containerPath) -> {
-                        mounts.add(new 
Mount().withType(MountType.BIND).withSource(hostPath).withTarget(containerPath));
+                    volumes.forEach(volume -> {
+                        var mount = new 
Mount().withType(MountType.valueOf(volume.getType())).withTarget(volume.getTarget());
+                        if (volume.getSource() != null) {
+                            mount = mount.withSource(volume.getSource());
+                        }
+                        mounts.add(mount);
                     });
                 }
                 if (command.length > 0) {
diff --git 
a/karavan-app/src/main/java/org/apache/camel/karavan/model/DockerComposeService.java
 
b/karavan-app/src/main/java/org/apache/camel/karavan/model/DockerComposeService.java
index 75e3db3a..1e295399 100644
--- 
a/karavan-app/src/main/java/org/apache/camel/karavan/model/DockerComposeService.java
+++ 
b/karavan-app/src/main/java/org/apache/camel/karavan/model/DockerComposeService.java
@@ -33,7 +33,7 @@ public class DockerComposeService {
     private String mem_limit;
     private String mem_reservation;
     private List<String> ports;
-    private List<String> volumes;
+    private List<DockerComposeVolume> volumes;
     private List<String> expose;
     private List<String> depends_on;
     private List<String> networks;
@@ -86,17 +86,6 @@ public class DockerComposeService {
         return p;
     }
 
-    public Map<String, String> getVolumesMap() {
-        Map<String, String> p = new HashMap<>();
-        if (volumes != null && !volumes.isEmpty()) {
-            volumes.forEach(s -> {
-                String[] values = s.split(":");
-                p.put(values[0], values[1]);
-            });
-        }
-        return p;
-    }
-
     public List<String> getExpose() {
         return expose;
     }
@@ -181,11 +170,11 @@ public class DockerComposeService {
         this.mem_reservation = mem_reservation;
     }
 
-    public List<String> getVolumes() {
+    public List<DockerComposeVolume> getVolumes() {
         return volumes;
     }
 
-    public void setVolumes(List<String> volumes) {
+    public void setVolumes(List<DockerComposeVolume> volumes) {
         this.volumes = volumes;
     }
 
diff --git 
a/karavan-app/src/main/java/org/apache/camel/karavan/model/DockerComposeVolume.java
 
b/karavan-app/src/main/java/org/apache/camel/karavan/model/DockerComposeVolume.java
new file mode 100644
index 00000000..4f9920e3
--- /dev/null
+++ 
b/karavan-app/src/main/java/org/apache/camel/karavan/model/DockerComposeVolume.java
@@ -0,0 +1,58 @@
+/*
+ * 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.karavan.model;
+
+public class DockerComposeVolume {
+
+    private String type;
+    private String source;
+    private String target;
+
+    public DockerComposeVolume() {
+    }
+
+    public DockerComposeVolume(String type, String source, String target) {
+        this.type = type;
+        this.source = source;
+        this.target = target;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public String getSource() {
+        return source;
+    }
+
+    public void setSource(String source) {
+        this.source = source;
+    }
+
+    public String getTarget() {
+        return target;
+    }
+
+    public void setTarget(String target) {
+        this.target = target;
+    }
+}
diff --git 
a/karavan-app/src/main/java/org/apache/camel/karavan/service/ConfigService.java 
b/karavan-app/src/main/java/org/apache/camel/karavan/service/ConfigService.java
index a4cb1e4d..87212c68 100644
--- 
a/karavan-app/src/main/java/org/apache/camel/karavan/service/ConfigService.java
+++ 
b/karavan-app/src/main/java/org/apache/camel/karavan/service/ConfigService.java
@@ -137,18 +137,19 @@ public class ConfigService {
         var parts = filename.split("\\.");
         var prefix = parts[0];
         if (environment.equals(DEV_ENVIRONMENT) && 
!getEnvs().contains(prefix)) { // no prefix AND dev env
-            storeFile(f);
-        } else if (Objects.equals(prefix, environment)){ // with prefix == env
-            storeFile(f);
+            storeFile(f.getName(), f.getCode());
+        } else if (Objects.equals(prefix, environment)) { // with prefix == env
+            filename = f.getName().substring(environment.length() + 1);
+            storeFile(filename, f.getCode());
         }
     }
 
-    private void storeFile(ProjectFile f) throws Exception {
+    private void storeFile(String filename , String code) throws Exception {
         if (inKubernetes()) {
-            createConfigMapFromFile(f.getName(), f.getCode());
+            createConfigMapFromFile(filename, code);
         } else {
             if (sharedFolder.isPresent()) {
-                Files.writeString(Paths.get(sharedFolder.get(), f.getName()), 
f.getCode());
+                Files.writeString(Paths.get(sharedFolder.get(), filename), 
code);
             } else {
                 throw new Exception("Shared folder not configured");
             }
diff --git 
a/karavan-app/src/main/java/org/apache/camel/karavan/service/ProjectService.java
 
b/karavan-app/src/main/java/org/apache/camel/karavan/service/ProjectService.java
index 2890eabd..e2954b68 100644
--- 
a/karavan-app/src/main/java/org/apache/camel/karavan/service/ProjectService.java
+++ 
b/karavan-app/src/main/java/org/apache/camel/karavan/service/ProjectService.java
@@ -69,17 +69,21 @@ public class ProjectService {
     EventBus eventBus;
 
     public Project commitAndPushProject(String projectId, String message) 
throws Exception {
-        LOGGER.info("Commit project: " + projectId);
-        Project p = karavanCache.getProject(projectId);
-        List<ProjectFile> files = karavanCache.getProjectFiles(projectId);
-        RevCommit commit = gitService.commitAndPushProject(p, files, message);
-        karavanCache.syncFilesCommited(projectId);
-        String commitId = commit.getId().getName();
-        Long lastUpdate = commit.getCommitTime() * 1000L;
-        p.setLastCommit(commitId);
-        p.setLastCommitTimestamp(lastUpdate);
-        karavanCache.saveProject(p);
-        return p;
+        if (Objects.equals(environment, DEV_ENVIRONMENT)) {
+            LOGGER.info("Commit project: " + projectId);
+            Project p = karavanCache.getProject(projectId);
+            List<ProjectFile> files = karavanCache.getProjectFiles(projectId);
+            RevCommit commit = gitService.commitAndPushProject(p, files, 
message);
+            karavanCache.syncFilesCommited(projectId);
+            String commitId = commit.getId().getName();
+            Long lastUpdate = commit.getCommitTime() * 1000L;
+            p.setLastCommit(commitId);
+            p.setLastCommitTimestamp(lastUpdate);
+            karavanCache.saveProject(p);
+            return p;
+        } else {
+            throw new RuntimeException("Unsupported environment: " + 
environment);
+        }
     }
 
     public String runProjectWithJBangOptions(Project project, String 
jBangOptions) throws Exception {

Reply via email to