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 2023/09/05 20:25:28 UTC
[camel-karavan] 02/05: Refactor Docker services for #817
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
commit f7526d0dd74177bbfcad2d5953ba7cf3ce9d0f6d
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Tue Sep 5 15:10:30 2023 -0400
Refactor Docker services for #817
---
karavan-web/karavan-app/pom.xml | 13 ---
.../apache/camel/karavan/api/DevModeResource.java | 44 ++++------
.../camel/karavan/api/InfrastructureResource.java | 13 ++-
.../apache/camel/karavan/api/ProjectResource.java | 12 +--
.../camel/karavan/docker/DockerEventListener.java | 6 +-
.../camel/karavan/docker/DockerForGitea.java | 5 +-
.../camel/karavan/docker/DockerForInfinispan.java | 5 +-
.../camel/karavan/docker/DockerForKaravan.java | 11 ++-
.../apache/camel/karavan/docker/DockerService.java | 76 ++++++++---------
.../camel/karavan/docker/DockerServiceUtils.java | 61 +-------------
.../karavan/docker/model/DockerComposeService.java | 16 +++-
.../apache/camel/karavan/service/CamelService.java | 35 +++++++-
.../apache/camel/karavan/service/CodeService.java | 97 +++++++++++++++++++++-
.../apache/camel/karavan/service/DelayRoute.java | 20 -----
.../apache/camel/karavan/service/EventService.java | 59 +++++++------
.../camel/karavan/service/KaravanService.java | 2 +-
.../camel/karavan/service/ProjectService.java | 67 ++++++++++++++-
.../org/apache/camel/karavan/shared/EventType.java | 3 +-
.../main/resources/snippets/project-compose.yaml | 8 ++
.../src/main/webui/src/api/KaravanApi.tsx | 4 +-
.../src/main/webui/src/api/ProjectService.ts | 17 ++--
.../src/main/webui/src/main/MainDataPoller.tsx | 2 -
.../src/main/webui/src/project/ProjectPanel.tsx | 6 +-
.../src/main/webui/src/project/files/FilesTab.tsx | 4 +-
.../karavan/infinispan/InfinispanService.java | 7 ++
25 files changed, 348 insertions(+), 245 deletions(-)
diff --git a/karavan-web/karavan-app/pom.xml b/karavan-web/karavan-app/pom.xml
index 96c8e5ff..387faad1 100644
--- a/karavan-web/karavan-app/pom.xml
+++ b/karavan-web/karavan-app/pom.xml
@@ -128,19 +128,6 @@
<artifactId>camel-openapi-rest-dsl-generator</artifactId>
<version>${camel.version}</version>
</dependency>
- <dependency>
- <groupId>org.apache.camel.quarkus</groupId>
- <artifactId>camel-quarkus-core</artifactId>
- </dependency>
- <dependency>
- <groupId>org.apache.camel.quarkus</groupId>
- <artifactId>camel-quarkus-vertx</artifactId>
- </dependency>
- <dependency>
- <groupId>org.apache.camel</groupId>
- <artifactId>camel-endpointdsl</artifactId>
- <version>${camel.version}</version>
- </dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-container-image-docker</artifactId>
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/DevModeResource.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/DevModeResource.java
index 5b10fa9b..3e2c879b 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/DevModeResource.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/DevModeResource.java
@@ -18,7 +18,10 @@ package org.apache.camel.karavan.api;
import io.vertx.core.json.JsonObject;
import io.vertx.mutiny.core.eventbus.EventBus;
-import org.apache.camel.karavan.docker.DockerForKaravan;
+import jakarta.inject.Inject;
+import jakarta.ws.rs.*;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
import org.apache.camel.karavan.docker.DockerService;
import org.apache.camel.karavan.infinispan.InfinispanService;
import org.apache.camel.karavan.infinispan.model.CamelStatus;
@@ -26,16 +29,10 @@ import org.apache.camel.karavan.infinispan.model.ContainerStatus;
import org.apache.camel.karavan.infinispan.model.Project;
import org.apache.camel.karavan.kubernetes.KubernetesService;
import org.apache.camel.karavan.service.CamelService;
+import org.apache.camel.karavan.service.ProjectService;
import org.apache.camel.karavan.shared.ConfigService;
-import org.apache.camel.karavan.shared.EventType;
import org.eclipse.microprofile.config.inject.ConfigProperty;
-import jakarta.inject.Inject;
-import jakarta.ws.rs.*;
-import jakarta.ws.rs.core.MediaType;
-import jakarta.ws.rs.core.Response;
-import java.util.Objects;
-
import static org.apache.camel.karavan.shared.EventType.CONTAINER_STATUS;
@Path("/api/devmode")
@@ -57,7 +54,7 @@ public class DevModeResource {
DockerService dockerService;
@Inject
- DockerForKaravan dockerForKaravan;
+ ProjectService projectService;
@Inject
EventBus eventBus;
@@ -66,32 +63,23 @@ public class DevModeResource {
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@Path("/{jBangOptions}")
- public Response runProjectWithJBangOptions(Project project, @PathParam("jBangOptions") String jBangOptions) throws InterruptedException {
- String containerName = project.getProjectId();
- ContainerStatus status = infinispanService.getDevModeContainerStatus(project.getProjectId(), environment);
- if (status == null) {
- status = ContainerStatus.createDevMode(project.getProjectId(), environment);
- }
-
- if (!Objects.equals(status.getState(), ContainerStatus.State.running.name())){
- status.setInTransit(true);
- eventBus.send(EventType.CONTAINER_STATUS, JsonObject.mapFrom(status));
-
- if (ConfigService.inKubernetes()) {
- kubernetesService.runDevModeContainer(project, jBangOptions);
+ public Response runProjectWithJBangOptions(Project project, @PathParam("jBangOptions") String jBangOptions) {
+ try {
+ String containerName = projectService.runProjectWithJBangOptions(project, jBangOptions);
+ if (containerName != null) {
+ return Response.ok(containerName).build();
} else {
- dockerForKaravan.createDevmodeContainer(project.getProjectId(), jBangOptions);
- dockerService.runContainer(project.getProjectId());
+ return Response.notModified().build();
}
- return Response.ok(containerName).build();
+ } catch (Exception e) {
+ return Response.serverError().entity(e).build();
}
- return Response.notModified().build();
}
@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
- public Response runProject(Project project) throws InterruptedException {
+ public Response runProject(Project project) throws Exception {
return runProjectWithJBangOptions(project, "");
}
@@ -121,7 +109,7 @@ public class DevModeResource {
return Response.accepted().build();
}
- private void setContainerStatusTransit(String name, String type){
+ private void setContainerStatusTransit(String name, String type) {
ContainerStatus status = infinispanService.getContainerStatus(name, environment, name);
if (status == null) {
status = ContainerStatus.createByType(name, environment, ContainerStatus.ContainerType.valueOf(type));
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/InfrastructureResource.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/InfrastructureResource.java
index 5c5f9fae..8f94786a 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/InfrastructureResource.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/InfrastructureResource.java
@@ -29,6 +29,7 @@ import org.apache.camel.karavan.infinispan.model.DeploymentStatus;
import org.apache.camel.karavan.infinispan.model.Project;
import org.apache.camel.karavan.infinispan.model.ServiceStatus;
import org.apache.camel.karavan.kubernetes.KubernetesService;
+import org.apache.camel.karavan.service.CodeService;
import org.apache.camel.karavan.service.ProjectService;
import org.apache.camel.karavan.shared.ConfigService;
import org.eclipse.microprofile.config.inject.ConfigProperty;
@@ -66,6 +67,9 @@ public class InfrastructureResource {
@Inject
ProjectService projectService;
+ @Inject
+ CodeService codeService;
+
@ConfigProperty(name = "karavan.environment")
String environment;
@@ -186,7 +190,7 @@ public class InfrastructureResource {
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@Path("/container/{env}/{type}/{name}")
- public Response startContainer(@PathParam("env") String env, @PathParam("type") String type, @PathParam("name") String name, JsonObject command) throws Exception {
+ public Response manageContainer(@PathParam("env") String env, @PathParam("type") String type, @PathParam("name") String name, JsonObject command) throws Exception {
if (infinispanService.isReady()) {
// set container statuses
setContainerStatusTransit(name, type);
@@ -195,14 +199,15 @@ public class InfrastructureResource {
if (command.getString("command").equalsIgnoreCase("run")) {
if (Objects.equals(type, ContainerStatus.ContainerType.devservice.name())) {
String code = projectService.getDevServiceCode();
- DockerComposeService dockerComposeService = dockerService.convertToDockerComposeService(code, name);
+ DockerComposeService dockerComposeService = codeService.convertToDockerComposeService(code, name);
if (dockerComposeService != null) {
dockerForKaravan.createDevserviceContainer(dockerComposeService);
dockerService.runContainer(dockerComposeService.getContainer_name());
}
} else if (Objects.equals(type, ContainerStatus.ContainerType.devmode.name())) {
- dockerForKaravan.createDevmodeContainer(name, "");
- dockerService.runContainer(name);
+// TODO: merge with DevMode service
+// dockerForKaravan.createDevmodeContainer(name, "");
+// dockerService.runContainer(name);
}
return Response.ok().build();
} else if (command.getString("command").equalsIgnoreCase("stop")) {
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/ProjectResource.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/ProjectResource.java
index cc73eae9..b62ad193 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/ProjectResource.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/ProjectResource.java
@@ -25,6 +25,8 @@ import org.apache.camel.karavan.service.GitService;
import jakarta.inject.Inject;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
+import org.apache.camel.karavan.service.ProjectService;
+
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.Comparator;
@@ -43,7 +45,7 @@ public class ProjectResource {
GitService gitService;
@Inject
- CodeService codeService;
+ ProjectService projectService;
@GET
@Produces(MediaType.APPLICATION_JSON)
@@ -69,13 +71,7 @@ public class ProjectResource {
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public Project save(Project project) throws Exception {
- boolean isNew = infinispanService.getProject(project.getProjectId()) == null;
- infinispanService.saveProject(project);
- if (isNew){
- ProjectFile appProp = codeService.getApplicationProperties(project);
- infinispanService.saveProjectFile(appProp);
- }
- return project;
+ return projectService.save(project);
}
@DELETE
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerEventListener.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerEventListener.java
index e9a7b746..8ed7b546 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerEventListener.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerEventListener.java
@@ -50,10 +50,12 @@ public class DockerEventListener implements ResultCallback<Event> {
try {
if (Objects.equals(event.getType(), EventType.CONTAINER)) {
Container container = dockerService.getContainer(event.getId());
- onContainerEvent(event, container);
+ if (container != null) {
+ onContainerEvent(event, container);
+ }
}
} catch (Exception exception) {
- LOGGER.error(exception.getMessage());
+ exception.printStackTrace();
}
}
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForGitea.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForGitea.java
index 38397495..da52c520 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForGitea.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForGitea.java
@@ -26,6 +26,7 @@ import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import org.apache.camel.karavan.infinispan.model.ContainerStatus;
import org.apache.camel.karavan.infinispan.model.GitConfig;
+import org.apache.camel.karavan.service.CodeService;
import org.apache.camel.karavan.service.GitService;
import org.apache.camel.karavan.service.GiteaService;
import org.jboss.logging.Logger;
@@ -56,12 +57,12 @@ public class DockerForGitea {
GitService gitService;
@Inject
- EventBus eventBus;
+ CodeService codeService;
public void startGitea() {
try {
LOGGER.info("Gitea container is starting...");
- var compose = dockerService.getInternalDockerComposeService(GITEA_CONTAINER_NAME);
+ var compose = codeService.getInternalDockerComposeService(GITEA_CONTAINER_NAME);
Container c = dockerService.createContainerFromCompose(compose, ContainerStatus.ContainerType.internal);
dockerService.runContainer(GITEA_CONTAINER_NAME);
LOGGER.info("Gitea container is started");
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForInfinispan.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForInfinispan.java
index b7c8c197..54774463 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForInfinispan.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForInfinispan.java
@@ -20,6 +20,7 @@ import io.vertx.core.eventbus.EventBus;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import org.apache.camel.karavan.infinispan.model.ContainerStatus;
+import org.apache.camel.karavan.service.CodeService;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.jboss.logging.Logger;
@@ -42,12 +43,12 @@ public class DockerForInfinispan {
DockerService dockerService;
@Inject
- EventBus eventBus;
+ CodeService codeService;
public void startInfinispan() {
try {
LOGGER.info("Infinispan is starting...");
- var compose = dockerService.getInternalDockerComposeService(INFINISPAN_CONTAINER_NAME);
+ var compose = codeService.getInternalDockerComposeService(INFINISPAN_CONTAINER_NAME);
compose.addEnvironment("USER", infinispanUsername);
compose.addEnvironment("PASS", infinispanPassword);
dockerService.createContainerFromCompose(compose, ContainerStatus.ContainerType.internal);
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForKaravan.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForKaravan.java
index c6d2b728..9ae18fa4 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForKaravan.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForKaravan.java
@@ -50,7 +50,12 @@ public class DockerForKaravan {
@Inject
DockerService dockerService;
- public void createDevmodeContainer(String projectId, String jBangOptions) throws InterruptedException {
+ public void runProjectInDevMode(String projectId, String jBangOptions, Map<Integer, Integer> ports, Map<String, String> files) throws Exception {
+ createDevmodeContainer(projectId, jBangOptions, ports);
+ dockerService.runContainer(projectId);
+ dockerService.copyFiles(projectId, "/code", files);
+ }
+ protected void createDevmodeContainer(String projectId, String jBangOptions, Map<Integer, Integer> ports) throws InterruptedException {
LOGGER.infof("DevMode starting for %s with JBANG_OPTIONS=%s", projectId, jBangOptions);
HealthCheck healthCheck = new HealthCheck().withTest(List.of("CMD", "curl", "-f", "http://localhost:8080/q/dev/health"))
@@ -61,7 +66,7 @@ public class DockerForKaravan {
: List.of();
dockerService.createContainer(projectId, devmodeImage,
- env, null, false, List.of(), healthCheck,
+ env, ports, healthCheck,
Map.of(LABEL_TYPE, ContainerStatus.ContainerType.devmode.name(), LABEL_PROJECT_ID, projectId),
Map.of());
@@ -83,7 +88,7 @@ public class DockerForKaravan {
"INFINISPAN_USERNAME=" + infinispanUsername,
"INFINISPAN_PASSWORD=" + infinispanPassword
),
- null, false, List.of(), new HealthCheck(),
+ null, new HealthCheck(),
Map.of(LABEL_TYPE, ContainerStatus.ContainerType.internal.name()),
Map.of());
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerService.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerService.java
index e8b22d2c..5a2932c4 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerService.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerService.java
@@ -34,8 +34,10 @@ import jakarta.inject.Inject;
import org.apache.camel.karavan.docker.model.DockerComposeService;
import org.apache.camel.karavan.infinispan.model.ContainerStatus;
import org.apache.commons.compress.archivers.ArchiveEntry;
+import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
+import org.apache.commons.compress.utils.IOUtils;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.jboss.logging.Logger;
@@ -121,7 +123,7 @@ public class DockerService extends DockerServiceUtils {
public Container getContainer(String id) {
List<Container> containers = getDockerClient().listContainersCmd().withShowAll(true).withIdFilter(List.of(id)).exec();
- return containers.get(0);
+ return containers.isEmpty() ? null : containers.get(0);
}
public Container getContainerByName(String name) {
@@ -149,14 +151,11 @@ public class DockerService extends DockerServiceUtils {
HealthCheck healthCheck = getHealthCheck(compose.getHealthcheck());
List<String> env = compose.getEnvironment() != null ? compose.getEnvironmentList() : List.of();
- String ports = String.join(",", compose.getPorts());
LOGGER.infof("Compose Service started for %s", compose.getContainer_name());
return createContainer(compose.getContainer_name(), compose.getImage(),
- env, ports, false, compose.getExpose(), healthCheck,
- Map.of(LABEL_TYPE, type.name()),
- Map.of());
+ env, compose.getPortsMap(), healthCheck, Map.of(LABEL_TYPE, type.name()), Map.of());
} else {
LOGGER.info("Compose Service already exists: " + containers.get(0).getId());
@@ -164,17 +163,8 @@ public class DockerService extends DockerServiceUtils {
}
}
- public Container createContainerFromCompose(String yaml, String name, ContainerStatus.ContainerType type) throws Exception {
- var compose = convertToDockerComposeService(yaml, name);
- if (compose != null) {
- return createContainerFromCompose(compose, type);
- } else {
- throw new Exception("Service not found in compose YAML!");
- }
- }
-
- public Container createContainer(String name, String image, List<String> env, String ports, boolean inRange,
- List<String> exposed, HealthCheck healthCheck, Map<String, String> labels,
+ public Container createContainer(String name, String image, List<String> env, Map<Integer, Integer> ports,
+ HealthCheck healthCheck, Map<String, String> labels,
Map<String, String> volumes) throws InterruptedException {
List<Container> containers = getDockerClient().listContainersCmd().withShowAll(true).withNameFilter(List.of(name)).exec();
if (containers.size() == 0) {
@@ -183,14 +173,7 @@ public class DockerService extends DockerServiceUtils {
CreateContainerCmd createContainerCmd = getDockerClient().createContainerCmd(image)
.withName(name).withLabels(labels).withEnv(env).withHostName(name).withHealthcheck(healthCheck);
- Ports portBindings;
- List<ExposedPort> exposedPorts = new ArrayList<>();
- if (exposed != null) {
- exposedPorts.addAll(exposed.stream().map(i -> ExposedPort.tcp(Integer.parseInt(i))).toList());
- portBindings = getPortBindings(ports,exposedPorts, inRange);
- } else {
- portBindings = getPortBindings(ports,exposedPorts, inRange);
- }
+ Ports portBindings = getPortBindings(ports);
List<Mount> mounts = new ArrayList<>();
if (volumes != null && !volumes.isEmpty()) {
@@ -198,8 +181,7 @@ public class DockerService extends DockerServiceUtils {
mounts.add(new Mount().withType(MountType.BIND).withSource(hostPath).withTarget(containerPath));
});
}
-
- createContainerCmd.withExposedPorts(exposedPorts);
+// createContainerCmd.withExposedPorts(exposedPorts);
createContainerCmd.withHostConfig(new HostConfig()
.withPortBindings(portBindings)
.withMounts(mounts)
@@ -260,25 +242,23 @@ public class DockerService extends DockerServiceUtils {
}
public void execStart(String id, ResultCallback.Adapter<Frame> callBack) throws InterruptedException {
- getDockerClient().execStartCmd(id).exec(callBack).awaitCompletion();
+ dockerClient.execStartCmd(id).exec(callBack).awaitCompletion();
+ }
+
+ public void copyFiles(String containerId, String containerPath, Map<String, String> files) throws IOException {
+ String temp = vertx.fileSystem().createTempDirectoryBlocking(containerId);
+ files.forEach((fileName, code) -> addFile(temp, fileName, code));
+ dockerClient.copyArchiveToContainerCmd(containerId).withRemotePath(containerPath)
+ .withDirChildrenOnly(true).withHostResource(temp).exec();
}
- public void copyFile(String id, String containerPath, String filename, String text) throws IOException {
-// try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
-// TarArchiveOutputStream tarArchive = new TarArchiveOutputStream(byteArrayOutputStream)) {
-// tarArchive.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX);
-// tarArchive.setBigNumberMode(TarArchiveOutputStream.BIGNUMBER_POSIX);
-//
-// String temp = vertx.fileSystem().createTempDirectoryBlocking("x");
-// String path = temp + File.separator + filename;
-// vertx.fileSystem().writeFileBlocking(path, Buffer.buffer(text));
-//
-// ArchiveEntry archive = tarArchive.createArchiveEntry(Paths.get(path), "app.ini");
-// tarArchive.putArchiveEntry(archive);;
-// tarArchive.finish();
- getDockerClient().copyArchiveToContainerCmd(id).withRemotePath("/data")
- .withHostResource("/Users/marat/projects/camel-karavan/karavan-web/karavan-app/src/main/resources/gitea").exec();
-// }
+ private void addFile(String temp, String fileName, String code) {
+ try {
+ String path = temp + File.separator + fileName;
+ vertx.fileSystem().writeFileBlocking(path, Buffer.buffer(code));
+ } catch (Exception e) {
+ LOGGER.error(e.getMessage());
+ }
}
public void logContainer(String containerName, LogCallback callback) {
@@ -359,4 +339,14 @@ public class DockerService extends DockerServiceUtils {
}
return dockerClient;
}
+
+ public int getMaxPortMapped(int port) {
+ return getDockerClient().listContainersCmd().withShowAll(true).exec().stream()
+ .map(c -> List.of(c.ports))
+ .flatMap(java.util.List::stream)
+ .filter(p -> Objects.equals(p.getPrivatePort(), port))
+ .map(ContainerPort::getPublicPort).filter(Objects::nonNull)
+ .mapToInt(Integer::intValue)
+ .max().orElse(port);
+ }
}
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerServiceUtils.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerServiceUtils.java
index 703f33ae..0b8b698f 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerServiceUtils.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerServiceUtils.java
@@ -42,8 +42,6 @@ import static org.apache.camel.karavan.shared.Constants.LABEL_TYPE;
public class DockerServiceUtils {
- protected static final String ENVIRONMENT = "environment";
-
protected static final DecimalFormat formatCpu = new DecimalFormat("0.00");
protected static final DecimalFormat formatMiB = new DecimalFormat("0.0");
protected static final DecimalFormat formatGiB = new DecimalFormat("0.00");
@@ -71,46 +69,6 @@ public class DockerServiceUtils {
}
}
- public DockerComposeService getInternalDockerComposeService (String name) {
- String composeText = getResourceFile("/services/internal.yaml");
- return convertToDockerComposeService(composeText, name);
- }
-
- public DockerComposeService convertToDockerComposeService(String code, String name) {
- Yaml yaml = new Yaml();
- Map<String, Object> obj = yaml.load(code);
- JsonObject json = JsonObject.mapFrom(obj);
- JsonObject services = json.getJsonObject("services");
- if (services.containsKey(name)) {
- JsonObject service = services.getJsonObject(name);
- return convertToDockerComposeService(name, service);
- } else {
- Optional<JsonObject> j = services.fieldNames().stream()
- .map(services::getJsonObject)
- .filter(s -> s.getString("container_name").equalsIgnoreCase(name)).findFirst();
- if (j.isPresent()) {
- return convertToDockerComposeService(name, j.get());
- }
- }
- return null;
- }
-
- public DockerComposeService convertToDockerComposeService(String name, JsonObject service) {
- if (service.containsKey(ENVIRONMENT) && service.getValue(ENVIRONMENT) instanceof JsonArray) {
- JsonObject env = new JsonObject();
- service.getJsonArray(ENVIRONMENT).forEach(o -> {
- String[] kv = o.toString().split("=");
- env.put(kv[0], kv[1]);
- });
- service.put(ENVIRONMENT, env);
- }
- DockerComposeService ds = service.mapTo(DockerComposeService.class);
- if (ds.getContainer_name() == null) {
- ds.setContainer_name(name);
- }
- return ds;
- }
-
protected HealthCheck getHealthCheck(HealthCheckConfig config) {
if (config != null) {
HealthCheck healthCheck = new HealthCheck().withTest(config.getTest());
@@ -151,29 +109,16 @@ public class DockerServiceUtils {
return Duration.parse(s).toMillis() * 1000000L;
}
- protected Ports getPortBindings(String ports, List<ExposedPort> exposedPorts, boolean inRange) {
+ protected Ports getPortBindings(Map<Integer, Integer> ports) {
Ports portBindings = new Ports();
- getPortsFromString(ports).forEach((hostPort, containerPort) -> {
- Ports.Binding binding = (exposedPorts.stream().anyMatch(e -> e.getPort() == containerPort))
- ? (inRange ? Ports.Binding.bindPortRange(hostPort, hostPort + 1000) : Ports.Binding.bindPort(hostPort))
- : Ports.Binding.bindPort(hostPort);
+ ports.forEach((hostPort, containerPort) -> {
+ Ports.Binding binding = Ports.Binding.bindPort(hostPort);
portBindings.bind(ExposedPort.tcp(containerPort), binding);
});
return portBindings;
}
- protected Map<Integer, Integer> getPortsFromString(String ports) {
- Map<Integer, Integer> p = new HashMap<>();
- if (ports != null && !ports.isEmpty()) {
- Arrays.stream(ports.split(",")).forEach(s -> {
- String[] values = s.split(":");
- p.put(Integer.parseInt(values[0]), Integer.parseInt(values[1]));
- });
- }
- return p;
- }
-
protected String formatMemory(Long memory) {
try {
if (memory < (1073741824)) {
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/model/DockerComposeService.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/model/DockerComposeService.java
index a348c706..629153e4 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/model/DockerComposeService.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/model/DockerComposeService.java
@@ -1,9 +1,6 @@
package org.apache.camel.karavan.docker.model;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
import java.util.stream.Collectors;
public class DockerComposeService {
@@ -52,6 +49,17 @@ public class DockerComposeService {
this.ports = ports;
}
+ public Map<Integer, Integer> getPortsMap() {
+ Map<Integer, Integer> p = new HashMap<>();
+ if (ports != null && !ports.isEmpty()) {
+ ports.forEach(s -> {
+ String[] values = s.split(":");
+ p.put(Integer.parseInt(values[0]), Integer.parseInt(values[1]));
+ });
+ }
+ return p;
+ }
+
public List<String> getExpose() {
return expose;
}
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/CamelService.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/CamelService.java
index e76fcb30..73557d4d 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/CamelService.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/CamelService.java
@@ -27,6 +27,7 @@ import org.apache.camel.karavan.infinispan.InfinispanService;
import org.apache.camel.karavan.infinispan.model.CamelStatus;
import org.apache.camel.karavan.infinispan.model.ContainerStatus;
import org.apache.camel.karavan.kubernetes.KubernetesService;
+import org.apache.camel.karavan.shared.ConfigService;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.eclipse.microprofile.faulttolerance.CircuitBreaker;
import org.jboss.logging.Logger;
@@ -40,8 +41,7 @@ import java.util.concurrent.ExecutionException;
import static org.apache.camel.karavan.shared.Constants.LABEL_PROJECT_ID;
import static org.apache.camel.karavan.shared.Constants.RELOAD_TRY_COUNT;
-import static org.apache.camel.karavan.shared.EventType.CONTAINER_STATUS;
-import static org.apache.camel.karavan.shared.EventType.DEVMODE_CONTAINER_READY;
+import static org.apache.camel.karavan.shared.EventType.*;
@ApplicationScoped
public class CamelService {
@@ -74,6 +74,37 @@ public class CamelService {
return webClient;
}
+
+ public void loadCodeToDevMode(String projectId) {
+ LOGGER.info("DevMode reload code " + projectId);
+ ContainerStatus status = infinispanService.getContainerStatus(projectId, environment, projectId);
+ CamelStatus cs = infinispanService.getCamelStatus(projectId, environment, CamelStatus.Name.context.name());
+ if (status != null
+ && !Objects.equals(status.getCodeLoaded(), Boolean.TRUE)
+ && status.getContainerId() != null
+ && status.getState().equals(ContainerStatus.State.running.name())
+ && camelIsStarted(cs)) {
+ LOGGER.info("CAMEL STARTED -> SEND RELOAD");
+ if (ConfigService.inKubernetes()) {
+ reloadProjectCode(projectId);
+ } else {
+ infinispanService.sendCodeReloadCommand(projectId);
+ }
+ } else {
+
+ }
+ }
+
+ private boolean camelIsStarted(CamelStatus camelStatus) {
+ try {
+ String status = camelStatus.getStatus();
+ JsonObject obj = new JsonObject(status);
+ return Objects.equals("Started", obj.getJsonObject("context").getString("state"));
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
public void reloadProjectCode(String projectId) {
LOGGER.info("Reload project code " + projectId);
try {
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/CodeService.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/CodeService.java
index f961d968..4e243bc2 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/CodeService.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/CodeService.java
@@ -23,12 +23,16 @@ import io.apicurio.datamodels.openapi.models.OasDocument;
import io.quarkus.qute.Engine;
import io.quarkus.qute.Template;
import io.quarkus.qute.TemplateInstance;
+import io.vertx.core.json.JsonArray;
+import io.vertx.core.json.JsonObject;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import org.apache.camel.CamelContext;
import org.apache.camel.generator.openapi.RestDslGenerator;
import org.apache.camel.impl.DefaultCamelContext;
import org.apache.camel.karavan.api.KameletResources;
+import org.apache.camel.karavan.docker.DockerService;
+import org.apache.camel.karavan.docker.model.DockerComposeService;
import org.apache.camel.karavan.infinispan.InfinispanService;
import org.apache.camel.karavan.infinispan.model.GitRepo;
import org.apache.camel.karavan.infinispan.model.GitRepoFile;
@@ -55,10 +59,18 @@ public class CodeService {
private static final Logger LOGGER = Logger.getLogger(CodeService.class.getName());
public static final String APPLICATION_PROPERTIES_FILENAME = "application.properties";
public static final String DEV_SERVICES_FILENAME = "devservices.yaml";
+ public static final String PROJECT_COMPOSE_FILENAME = "project-compose.yaml";
+ private static final String SNIPPETS_PATH = "/snippets/";
+ private static final int INTERNAL_PORT = 8080;
+
+ protected static final String ENVIRONMENT = "environment";
@Inject
KubernetesService kubernetesService;
+ @Inject
+ DockerService dockerService;
+
@Inject
InfinispanService infinispanService;
@@ -106,20 +118,22 @@ public class CodeService {
return null;
}
- public Map<String, String> getApplicationPropertiesTemplates() {
+ public Map<String, String> getTemplates() {
Map<String, String> result = new HashMap<>();
List<String> files = new ArrayList<>(interfaces);
- files.addAll(targets.stream().map(target -> target + "-" + APPLICATION_PROPERTIES_FILENAME).collect(Collectors.toList()));
+ files.addAll(targets.stream().map(target -> target + "-" + APPLICATION_PROPERTIES_FILENAME).toList());
runtimes.forEach(runtime -> {
files.forEach(file -> {
String templateName = runtime + "-" + file;
- String templatePath = "/snippets/" + templateName;
+ String templatePath = SNIPPETS_PATH + templateName;
String templateText = getResourceFile(templatePath);
result.put(templateName, templateText);
});
});
+
+ result.put(PROJECT_COMPOSE_FILENAME, getResourceFile(SNIPPETS_PATH + PROJECT_COMPOSE_FILENAME));
return result;
}
@@ -254,4 +268,81 @@ public class CodeService {
public String getProjectRuntime(String file) {
return getProperty(file, "camel.jbang.runtime");
}
+
+ public ProjectFile createInitialProjectCompose(Project project) {
+ int port = getNextAvailablePort();
+ String templateText = getTemplateText(PROJECT_COMPOSE_FILENAME);
+ Template result = engine.parse(templateText);
+ TemplateInstance instance = result
+ .data("projectId", project.getProjectId())
+ .data("projectPort", port)
+ .data("projectImage", project.getProjectId());
+ String code = instance.render();
+ return new ProjectFile(PROJECT_COMPOSE_FILENAME, code, project.getProjectId(), Instant.now().toEpochMilli());
+ }
+
+ private int getNextAvailablePort() {
+ int dockerPort = dockerService.getMaxPortMapped(INTERNAL_PORT);
+ int projectPort = getMaxPortMappedInProjects();
+ return Math.max(projectPort, dockerPort) + 1;
+ }
+
+
+ private int getMaxPortMappedInProjects() {
+ List<ProjectFile> files = infinispanService.getProjectFilesByName(PROJECT_COMPOSE_FILENAME).stream()
+ .filter(f -> !Objects.equals(f.getProjectId(), Project.Type.templates.name())).toList();
+ if (!files.isEmpty()) {
+ return files.stream().map(f -> convertToDockerComposeService(f.getCode(), f.getProjectId()))
+ .map(dcs -> {
+ Optional<Integer> port = dcs.getPortsMap().entrySet().stream()
+ .filter(e -> Objects.equals(e.getValue(), INTERNAL_PORT)).map(Map.Entry::getKey).findFirst();
+ return port.orElse(INTERNAL_PORT);
+ })
+ .mapToInt(Integer::intValue)
+ .max().orElse(INTERNAL_PORT);
+ } else {
+ return INTERNAL_PORT;
+ }
+ }
+
+
+ public DockerComposeService getInternalDockerComposeService (String name) {
+ String composeText = getResourceFile("/services/internal.yaml");
+ return convertToDockerComposeService(composeText, name);
+ }
+
+ public DockerComposeService convertToDockerComposeService(String code, String name) {
+ Yaml yaml = new Yaml();
+ Map<String, Object> obj = yaml.load(code);
+ JsonObject json = JsonObject.mapFrom(obj);
+ JsonObject services = json.getJsonObject("services");
+ if (services.containsKey(name)) {
+ JsonObject service = services.getJsonObject(name);
+ return convertToDockerComposeService(name, service);
+ } else {
+ Optional<JsonObject> j = services.fieldNames().stream()
+ .map(services::getJsonObject)
+ .filter(s -> s.getString("container_name").equalsIgnoreCase(name)).findFirst();
+ if (j.isPresent()) {
+ return convertToDockerComposeService(name, j.get());
+ }
+ }
+ return null;
+ }
+
+ public DockerComposeService convertToDockerComposeService(String name, JsonObject service) {
+ if (service.containsKey(ENVIRONMENT) && service.getValue(ENVIRONMENT) instanceof JsonArray) {
+ JsonObject env = new JsonObject();
+ service.getJsonArray(ENVIRONMENT).forEach(o -> {
+ String[] kv = o.toString().split("=");
+ env.put(kv[0], kv[1]);
+ });
+ service.put(ENVIRONMENT, env);
+ }
+ DockerComposeService ds = service.mapTo(DockerComposeService.class);
+ if (ds.getContainer_name() == null) {
+ ds.setContainer_name(name);
+ }
+ return ds;
+ }
}
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/DelayRoute.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/DelayRoute.java
deleted file mode 100644
index 8e594246..00000000
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/DelayRoute.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package org.apache.camel.karavan.service;
-
-import org.apache.camel.builder.endpoint.EndpointRouteBuilder;
-import org.apache.camel.karavan.infinispan.InfinispanService;
-
-import static org.apache.camel.karavan.shared.EventType.*;
-
-public class DelayRoute extends EndpointRouteBuilder {
-
- @Override
- public void configure() throws Exception {
- from(vertx(DEVMODE_DELAY_MESSAGE))
- .delay(500)
- .to(vertx(DEVMODE_CONTAINER_READY));
-
-// from(vertx(InfinispanService.INFINISPAN_START_DELAY))
-// .delay(1000)
-// .toD(vertx(InfinispanService.INFINISPAN_START));
- }
-}
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/EventService.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/EventService.java
index 326946dd..e873d25f 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/EventService.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/EventService.java
@@ -8,16 +8,13 @@ import jakarta.inject.Inject;
import org.apache.camel.karavan.infinispan.InfinispanService;
import org.apache.camel.karavan.infinispan.model.CamelStatus;
import org.apache.camel.karavan.infinispan.model.ContainerStatus;
-import org.apache.camel.karavan.shared.ConfigService;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.jboss.logging.Logger;
-import java.util.Map;
import java.util.Objects;
-import static org.apache.camel.karavan.shared.Constants.LABEL_PROJECT_ID;
-import static org.apache.camel.karavan.shared.Constants.RELOAD_TRY_COUNT;
-import static org.apache.camel.karavan.shared.EventType.*;
+import static org.apache.camel.karavan.shared.EventType.CONTAINER_STATUS;
+import static org.apache.camel.karavan.shared.EventType.DEVMODE_CONTAINER_READY;
@ApplicationScoped
public class EventService {
@@ -38,31 +35,31 @@ public class EventService {
@ConsumeEvent(value = DEVMODE_CONTAINER_READY, blocking = true, ordered = true)
void receiveCommand(JsonObject json) {
- String projectId = json.getString(LABEL_PROJECT_ID);
- Integer reloadCount = json.getInteger(RELOAD_TRY_COUNT);
- LOGGER.info("DEVMODE_CONTAINER_READY " + projectId + " : " + reloadCount);
- ContainerStatus status = infinispanService.getContainerStatus(projectId, environment, projectId);
- CamelStatus cs = infinispanService.getCamelStatus(projectId, environment, CamelStatus.Name.context.name());
- if (status != null
- && !Objects.equals(status.getCodeLoaded(), Boolean.TRUE)
- && status.getContainerId() != null
- && status.getState().equals(ContainerStatus.State.running.name())
- && camelIsStarted(cs)) {
- LOGGER.info("CAMEL STARTED -> SEND RELOAD");
- if (ConfigService.inKubernetes()) {
- camelService.reloadProjectCode(projectId);
- } else {
- infinispanService.sendCodeReloadCommand(projectId);
- }
- } else if (reloadCount < 30) {
- LOGGER.info("CAMEL NOT STARTED -> SEND DEVMODE_CONTAINER_READY");
- // retry again
- Map<String, Object> message = Map.of(
- LABEL_PROJECT_ID, projectId,
- RELOAD_TRY_COUNT, ++reloadCount
- );
- eventBus.publish(DEVMODE_DELAY_MESSAGE, JsonObject.mapFrom(message));
- }
+// String projectId = json.getString(LABEL_PROJECT_ID);
+// Integer reloadCount = json.getInteger(RELOAD_TRY_COUNT);
+// LOGGER.info("DEVMODE_CONTAINER_READY " + projectId + " : " + reloadCount);
+// ContainerStatus status = infinispanService.getContainerStatus(projectId, environment, projectId);
+// CamelStatus cs = infinispanService.getCamelStatus(projectId, environment, CamelStatus.Name.context.name());
+// if (status != null
+// && !Objects.equals(status.getCodeLoaded(), Boolean.TRUE)
+// && status.getContainerId() != null
+// && status.getState().equals(ContainerStatus.State.running.name())
+// && camelIsStarted(cs)) {
+// LOGGER.info("CAMEL STARTED -> SEND RELOAD");
+// if (ConfigService.inKubernetes()) {
+// camelService.reloadProjectCode(projectId);
+// } else {
+// infinispanService.sendCodeReloadCommand(projectId);
+// }
+// } else if (reloadCount < 30) {
+// LOGGER.info("CAMEL NOT STARTED -> SEND DEVMODE_CONTAINER_READY");
+// // retry again
+// Map<String, Object> message = Map.of(
+// LABEL_PROJECT_ID, projectId,
+// RELOAD_TRY_COUNT, ++reloadCount
+// );
+// eventBus.publish(DEVMODE_DELAY_MESSAGE, JsonObject.mapFrom(message));
+// }
}
private boolean camelIsStarted(CamelStatus camelStatus) {
@@ -75,6 +72,8 @@ public class EventService {
}
}
+
+
@ConsumeEvent(value = CONTAINER_STATUS, blocking = true, ordered = true)
public void saveContainerStatus(JsonObject data) {
if (infinispanService.isReady()) {
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/KaravanService.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/KaravanService.java
index 7e91bed2..6a5304a9 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/KaravanService.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/KaravanService.java
@@ -93,7 +93,7 @@ public class KaravanService {
dockerService.startListeners();
dockerForInfinispan.startInfinispan();
- dockerForKaravan.startKaravanHeadlessContainer();
+// dockerForKaravan.startKaravanHeadlessContainer();
if (giteaInstall) {
dockerForGitea.startGitea();
giteaService.install();
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/ProjectService.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/ProjectService.java
index 7dbdd75a..1ec31c08 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/ProjectService.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/ProjectService.java
@@ -17,17 +17,25 @@
package org.apache.camel.karavan.service;
import io.smallrye.mutiny.tuples.Tuple2;
+import io.vertx.core.json.JsonObject;
+import io.vertx.mutiny.core.eventbus.EventBus;
+import jakarta.ws.rs.PathParam;
+import jakarta.ws.rs.core.Response;
+import org.apache.camel.karavan.docker.DockerForKaravan;
+import org.apache.camel.karavan.docker.model.DockerComposeService;
import org.apache.camel.karavan.infinispan.InfinispanService;
+import org.apache.camel.karavan.infinispan.model.ContainerStatus;
import org.apache.camel.karavan.infinispan.model.GitRepo;
import org.apache.camel.karavan.infinispan.model.Project;
import org.apache.camel.karavan.infinispan.model.ProjectFile;
import org.apache.camel.karavan.kubernetes.KubernetesService;
+import org.apache.camel.karavan.shared.ConfigService;
+import org.apache.camel.karavan.shared.EventType;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.eclipse.microprofile.faulttolerance.Retry;
import org.eclipse.microprofile.health.HealthCheck;
import org.eclipse.microprofile.health.HealthCheckResponse;
-import org.eclipse.microprofile.health.HealthCheckResponseBuilder;
import org.eclipse.microprofile.health.Readiness;
import org.jboss.logging.Logger;
@@ -36,11 +44,14 @@ import jakarta.enterprise.inject.Default;
import jakarta.inject.Inject;
import java.time.Instant;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.stream.Collectors;
import static org.apache.camel.karavan.service.CodeService.DEV_SERVICES_FILENAME;
+import static org.apache.camel.karavan.service.CodeService.PROJECT_COMPOSE_FILENAME;
@Default
@Readiness
@@ -49,6 +60,9 @@ public class ProjectService implements HealthCheck{
private static final Logger LOGGER = Logger.getLogger(ProjectService.class.getName());
+ @ConfigProperty(name = "karavan.environment")
+ String environment;
+
@ConfigProperty(name = "karavan.git-pull-interval")
String gitPullInterval;
@@ -58,12 +72,18 @@ public class ProjectService implements HealthCheck{
@Inject
KubernetesService kubernetesService;
+ @Inject
+ DockerForKaravan dockerForKaravan;
+
@Inject
GitService gitService;
@Inject
CodeService codeService;
+ @Inject
+ EventBus eventBus;
+
private AtomicBoolean ready = new AtomicBoolean(false);
private AtomicBoolean readyToPull = new AtomicBoolean(false);
@@ -77,6 +97,47 @@ public class ProjectService implements HealthCheck{
}
}
+ public String runProjectWithJBangOptions(Project project, @PathParam("jBangOptions") String jBangOptions) throws Exception {
+ String containerName = project.getProjectId();
+ ContainerStatus status = infinispanService.getDevModeContainerStatus(project.getProjectId(), environment);
+ if (status == null) {
+ status = ContainerStatus.createDevMode(project.getProjectId(), environment);
+ }
+
+ if (!Objects.equals(status.getState(), ContainerStatus.State.running.name())) {
+ status.setInTransit(true);
+ eventBus.send(EventType.CONTAINER_STATUS, JsonObject.mapFrom(status));
+
+ if (ConfigService.inKubernetes()) {
+ kubernetesService.runDevModeContainer(project, jBangOptions);
+ } else {
+ Map<String, String> files = infinispanService.getProjectFiles(project.getProjectId()).stream()
+ .filter(f -> !Objects.equals(f.getName(), PROJECT_COMPOSE_FILENAME))
+ .collect(Collectors.toMap(ProjectFile::getName, ProjectFile::getCode));
+ ProjectFile compose = infinispanService.getProjectFile(project.getProjectId(), PROJECT_COMPOSE_FILENAME);
+ DockerComposeService dcs = codeService.convertToDockerComposeService(compose.getCode(), project.getProjectId());
+ dockerForKaravan.runProjectInDevMode(project.getProjectId(), jBangOptions, dcs.getPortsMap(), files);
+ }
+ return containerName;
+ } else {
+ return null;
+ }
+ }
+
+ public Project save(Project project) throws Exception {
+ boolean isNew = infinispanService.getProject(project.getProjectId()) == null;
+ infinispanService.saveProject(project);
+ if (isNew){
+ ProjectFile appProp = codeService.getApplicationProperties(project);
+ infinispanService.saveProjectFile(appProp);
+ if (!ConfigService.inKubernetes()) {
+ ProjectFile projectCompose = codeService.createInitialProjectCompose(project);
+ infinispanService.saveProjectFile(projectCompose);
+ }
+ }
+ return project;
+ }
+
public void pullCommits() {
if (readyToPull.get()) {
LOGGER.info("Pull commits...");
@@ -224,7 +285,7 @@ public class ProjectService implements HealthCheck{
templates = new Project(Project.Type.templates.name(), "Templates", "Templates", "", "", Instant.now().toEpochMilli(), Project.Type.templates);
infinispanService.saveProject(templates);
- codeService.getApplicationPropertiesTemplates().forEach((name, value) -> {
+ codeService.getTemplates().forEach((name, value) -> {
ProjectFile file = new ProjectFile(name, value, Project.Type.templates.name(), Instant.now().toEpochMilli());
infinispanService.saveProjectFile(file);
});
@@ -262,7 +323,7 @@ public class ProjectService implements HealthCheck{
pipelines = new Project(Project.Type.pipelines.name(), "Pipelines", "CI/CD Pipelines", "", "", Instant.now().toEpochMilli(), Project.Type.pipelines);
infinispanService.saveProject(pipelines);
- codeService.getApplicationPropertiesTemplates().forEach((name, value) -> {
+ codeService.getTemplates().forEach((name, value) -> {
ProjectFile file = new ProjectFile(name, value, Project.Type.pipelines.name(), Instant.now().toEpochMilli());
infinispanService.saveProjectFile(file);
});
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/shared/EventType.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/shared/EventType.java
index 0f6ba504..480185ab 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/shared/EventType.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/shared/EventType.java
@@ -19,7 +19,6 @@ package org.apache.camel.karavan.shared;
public class EventType {
public static final String CONTAINER_STATUS = "CONTAINER_STATUS";
- public static final String DEVMODE_CONTAINER_READY = "DEVMODE_STATUS";
- public static final String DEVMODE_DELAY_MESSAGE = "DEVMODE_DELAY_MESSAGE";
+ public static final String DEVMODE_CONTAINER_READY = "DEVMODE_CONTAINER_READY";
}
diff --git a/karavan-web/karavan-app/src/main/resources/snippets/project-compose.yaml b/karavan-web/karavan-app/src/main/resources/snippets/project-compose.yaml
new file mode 100644
index 00000000..36c668af
--- /dev/null
+++ b/karavan-web/karavan-app/src/main/resources/snippets/project-compose.yaml
@@ -0,0 +1,8 @@
+services:
+ {projectId}:
+ image: {projectImage}
+ restart: always
+ ports:
+ - "{projectPort}:8080"
+ networks:
+ - karavan
diff --git a/karavan-web/karavan-app/src/main/webui/src/api/KaravanApi.tsx b/karavan-web/karavan-app/src/main/webui/src/api/KaravanApi.tsx
index 9237fba3..a8ab3c75 100644
--- a/karavan-web/karavan-app/src/main/webui/src/api/KaravanApi.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/api/KaravanApi.tsx
@@ -257,8 +257,8 @@ export class KaravanApi {
});
}
- static async getFiles(project: string, after: (files: ProjectFile[]) => void) {
- instance.get('/api/file/' + project)
+ static async getFiles(projectId: string, after: (files: ProjectFile[]) => void) {
+ instance.get('/api/file/' + projectId)
.then(res => {
if (res.status === 200) {
after(res.data);
diff --git a/karavan-web/karavan-app/src/main/webui/src/api/ProjectService.ts b/karavan-web/karavan-app/src/main/webui/src/api/ProjectService.ts
index 9ebc6eda..7bef52d9 100644
--- a/karavan-web/karavan-app/src/main/webui/src/api/ProjectService.ts
+++ b/karavan-web/karavan-app/src/main/webui/src/api/ProjectService.ts
@@ -111,7 +111,7 @@ export class ProjectService {
if (res.status === 200 || res.status === 201) {
useProjectStore.setState({isPushing: false})
ProjectService.refreshProject(project.projectId);
- ProjectService.refreshProjectData();
+ ProjectService.refreshProjectData(project.projectId);
} else {
// Todo notification
}
@@ -169,7 +169,7 @@ export class ProjectService {
KaravanApi.deleteProject(project, res => {
if (res.status === 204) {
// this.props.toast?.call(this, 'Success', 'Project deleted', 'success');
- ProjectService.refreshProjectData();
+ ProjectService.refreshProjectData(project.projectId);
} else {
// this.props.toast?.call(this, 'Error', res.statusText, 'danger');
}
@@ -179,7 +179,7 @@ export class ProjectService {
public static createProject(project: Project) {
KaravanApi.postProject(project, res => {
if (res.status === 200 || res.status === 201) {
- ProjectService.refreshProjectData();
+ ProjectService.refreshProjectData(project.projectId);
// this.props.toast?.call(this, 'Success', 'Project created', 'success');
} else {
// this.props.toast?.call(this, 'Error', res.status + ', ' + res.statusText, 'danger');
@@ -191,7 +191,7 @@ export class ProjectService {
KaravanApi.postProjectFile(file, res => {
if (res.status === 200) {
// console.log(res) //TODO show notification
- ProjectService.refreshProjectData();
+ ProjectService.refreshProjectData(file.projectId);
} else {
// console.log(res) //TODO show notification
}
@@ -201,15 +201,14 @@ export class ProjectService {
public static deleteFile(file: ProjectFile) {
KaravanApi.deleteProjectFile(file, res => {
if (res.status === 204) {
- ProjectService.refreshProjectData();
+ ProjectService.refreshProjectData(file.projectId);
} else {
}
});
}
- public static refreshProjectData() {
- const project = useProjectStore.getState().project;
- KaravanApi.getProject(project.projectId, (project: Project) => {
+ public static refreshProjectData(projectId: string) {
+ KaravanApi.getProject(projectId, (project: Project) => {
// ProjectEventBus.selectProject(project);
KaravanApi.getTemplatesFiles((files: ProjectFile[]) => {
files.filter(f => f.name.endsWith('java'))
@@ -220,7 +219,7 @@ export class ProjectService {
})
});
});
- KaravanApi.getFiles(project.projectId, (files: ProjectFile[]) => {
+ KaravanApi.getFiles(projectId, (files: ProjectFile[]) => {
useFilesStore.setState({files: files});
});
diff --git a/karavan-web/karavan-app/src/main/webui/src/main/MainDataPoller.tsx b/karavan-web/karavan-app/src/main/webui/src/main/MainDataPoller.tsx
index 6ff24777..8d7de7ab 100644
--- a/karavan-web/karavan-app/src/main/webui/src/main/MainDataPoller.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/main/MainDataPoller.tsx
@@ -33,12 +33,10 @@ export function MainDataPoller () {
}, [project, readiness]);
function getData() {
- console.log(readiness);
KaravanApi.getReadiness((r: any) => {
setReadiness(r);
})
if (readiness) {
- console.log("getData");
setLoading(true);
KaravanApi.getConfiguration((config: AppConfig) => {
if (project.projectId === undefined) {
diff --git a/karavan-web/karavan-app/src/main/webui/src/project/ProjectPanel.tsx b/karavan-web/karavan-app/src/main/webui/src/project/ProjectPanel.tsx
index 2240c8a8..94fb1d28 100644
--- a/karavan-web/karavan-app/src/main/webui/src/project/ProjectPanel.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/project/ProjectPanel.tsx
@@ -19,10 +19,12 @@ export function ProjectPanel () {
useEffect(() => {
onRefresh();
- });
+ }, [project]);
function onRefresh () {
- ProjectService.refreshProjectData();
+ if (project.projectId) {
+ ProjectService.refreshProjectData(project.projectId);
+ }
}
function isBuildIn(): boolean {
diff --git a/karavan-web/karavan-app/src/main/webui/src/project/files/FilesTab.tsx b/karavan-web/karavan-app/src/main/webui/src/project/files/FilesTab.tsx
index 6c444bf5..2e2d0bd8 100644
--- a/karavan-web/karavan-app/src/main/webui/src/project/files/FilesTab.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/project/files/FilesTab.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import React, {useEffect} from 'react';
import {
Badge,
Button,
@@ -115,7 +115,7 @@ export function FilesTab () {
<Td modifier={"fitContent"}>
{canDeleteFiles() &&
<Button style={{padding: '0'}} variant={"plain"}
- isDisabled={file.name === 'application.properties'}
+ isDisabled={['application.properties', 'project-compose.yaml'].includes(file.name)}
onClick={e =>
useFileStore.setState({file: file, operation: "delete"})
}>
diff --git a/karavan-web/karavan-infinispan/src/main/java/org/apache/camel/karavan/infinispan/InfinispanService.java b/karavan-web/karavan-infinispan/src/main/java/org/apache/camel/karavan/infinispan/InfinispanService.java
index 3ea2c584..eae0311f 100644
--- a/karavan-web/karavan-infinispan/src/main/java/org/apache/camel/karavan/infinispan/InfinispanService.java
+++ b/karavan-web/karavan-infinispan/src/main/java/org/apache/camel/karavan/infinispan/InfinispanService.java
@@ -196,6 +196,13 @@ public class InfinispanService implements HealthCheck {
return list.size() > 0 ? list.get(0) : null;
}
+ public List<ProjectFile> getProjectFilesByName(String filename) {
+ QueryFactory queryFactory = Search.getQueryFactory(files);
+ return queryFactory.<ProjectFile>create("FROM karavan.ProjectFile WHERE name = :name")
+ .setParameter("name", filename)
+ .execute().list();
+ }
+
public void saveProjectFile(ProjectFile file) {
files.put(GroupedKey.create(file.getProjectId(), DEFAULT_ENVIRONMENT, file.getName()), file);
}