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/07/26 00:40:26 UTC
[camel-karavan] 01/02: Container management improvements #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 5eafe2958b74831443eb3e552574953657e43a8f
Author: Marat Gubaidullin <ma...@gmail.com>
AuthorDate: Tue Jul 25 17:27:28 2023 -0400
Container management improvements #817
---
.../apache/camel/karavan/api/DevModeResource.java | 18 ++--
.../camel/karavan/api/InfrastructureResource.java | 62 +++++++++--
.../camel/karavan/docker/DockerEventListener.java | 111 +++++++++++---------
.../apache/camel/karavan/docker/DockerService.java | 113 ++++++++++++++++-----
.../karavan/kubernetes/KubernetesService.java | 2 +-
.../camel/karavan/kubernetes/PodEventHandler.java | 28 +++--
.../apache/camel/karavan/service/CamelService.java | 6 +-
.../apache/camel/karavan/service/EventService.java | 41 ++++----
.../camel/karavan/service/ScheduledService.java | 32 +++++-
.../org/apache/camel/karavan/shared/EventType.java | 2 +-
.../src/main/resources/application.properties | 2 +-
.../src/main/webui/src/api/KaravanApi.tsx | 23 +++--
.../src/main/webui/src/api/ProjectModels.ts | 3 +
.../src/main/webui/src/api/ProjectService.ts | 49 ++++++---
.../src/main/webui/src/api/ProjectStore.ts | 6 +-
.../webui/src/containers/ContainerTableRow.tsx | 71 +++++++++----
.../main/webui/src/containers/ContainersPage.tsx | 35 ++++---
.../src/main/webui/src/project/DevModeToolbar.tsx | 92 ++++++++---------
.../src/main/webui/src/project/ProjectPage.tsx | 2 +-
.../webui/src/project/dashboard/InfoContainer.tsx | 4 +-
.../webui/src/project/pipeline/ProjectStatus.tsx | 2 +-
.../main/webui/src/services/ServicesTableRow.tsx | 4 +-
.../camel/karavan/headless/CamelService.java | 4 +-
.../camel/karavan/headless/HeadlessService.java | 3 +-
.../karavan/infinispan/InfinispanService.java | 24 ++++-
.../karavan/infinispan/model/ContainerStatus.java | 104 +++++++++++++------
.../karavan/infinispan/model/KaravanSchema.java | 4 +-
27 files changed, 572 insertions(+), 275 deletions(-)
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 13edee0e..6379b058 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
@@ -30,6 +30,7 @@ import javax.inject.Inject;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
+import java.util.Objects;
import java.util.Optional;
@Path("/api/devmode")
@@ -58,7 +59,13 @@ public class DevModeResource {
String containerName = project.getProjectId();
ContainerStatus status = infinispanService.getDevModeContainerStatus(project.getProjectId(), environment);
if (status == null) {
- infinispanService.saveContainerStatus(ContainerStatus.createDevMode(project.getProjectId(), environment));
+ status = ContainerStatus.createDevMode(project.getProjectId(), environment);
+ }
+
+ if (!Objects.equals(status.getState(), ContainerStatus.State.running.name())){
+ status.setInTransit(true);
+ infinispanService.saveContainerStatus(status);
+
if (ConfigService.inKubernetes()) {
kubernetesService.runDevModeContainer(project, "");
} else {
@@ -93,15 +100,10 @@ public class DevModeResource {
@Consumes(MediaType.APPLICATION_JSON)
@Path("/{projectId}/{deletePVC}")
public Response deleteDevMode(@PathParam("projectId") String projectId, @PathParam("deletePVC") boolean deletePVC) {
- ContainerStatus status = infinispanService.getDevModeContainerStatus(projectId, environment);
- if (status != null) {
- status.setLifeCycle(ContainerStatus.Lifecycle.deleting);
- infinispanService.saveContainerStatus(status);
- }
+ infinispanService.setContainerStatusTransit(projectId, environment, projectId);
if (ConfigService.inKubernetes()) {
kubernetesService.deleteRunner(projectId, deletePVC);
} else {
- dockerService.stopContainer(projectId);
dockerService.deleteContainer(projectId);
}
return Response.accepted().build();
@@ -109,7 +111,7 @@ public class DevModeResource {
@GET
@Produces(MediaType.APPLICATION_JSON)
- @Path("/pod/{projectId}")
+ @Path("/container/{projectId}")
public Response getPodStatus(@PathParam("projectId") String projectId) throws RuntimeException {
if (infinispanService.isReady()) {
ContainerStatus cs = infinispanService.getDevModeContainerStatus(projectId, environment);
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 443c9e69..8291c7eb 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
@@ -17,8 +17,10 @@
package org.apache.camel.karavan.api;
import io.smallrye.mutiny.Multi;
+import io.vertx.core.json.JsonObject;
import io.vertx.mutiny.core.eventbus.EventBus;
import io.vertx.mutiny.core.eventbus.Message;
+import org.apache.camel.karavan.docker.DockerService;
import org.apache.camel.karavan.infinispan.InfinispanService;
import org.apache.camel.karavan.infinispan.model.ContainerStatus;
import org.apache.camel.karavan.infinispan.model.DeploymentStatus;
@@ -50,6 +52,9 @@ public class InfrastructureResource {
@Inject
KubernetesService kubernetesService;
+ @Inject
+ DockerService dockerService;
+
@ConfigProperty(name = "karavan.environment")
String environment;
@@ -101,9 +106,13 @@ public class InfrastructureResource {
@Produces(MediaType.APPLICATION_JSON)
@Path("/deployment")
public List<DeploymentStatus> getAllDeploymentStatuses() throws Exception {
- return infinispanService.getDeploymentStatuses().stream()
- .sorted(Comparator.comparing(DeploymentStatus::getProjectId))
- .collect(Collectors.toList());
+ if (infinispanService.isReady()) {
+ return infinispanService.getDeploymentStatuses().stream()
+ .sorted(Comparator.comparing(DeploymentStatus::getProjectId))
+ .collect(Collectors.toList());
+ } else {
+ return List.of();
+ }
}
@GET
@@ -154,9 +163,29 @@ public class InfrastructureResource {
}
}
+ @POST
+ @Produces(MediaType.APPLICATION_JSON)
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Path("/container/{env}/{name}")
+ public Response startContainer(@PathParam("env") String env, @PathParam("name") String name, JsonObject command) throws Exception {
+ if (infinispanService.isReady()) {
+ infinispanService.setContainerStatusTransit(name, env, name);
+ if (command.containsKey("command")) {
+ if (command.getString("command").equalsIgnoreCase("start")) {
+ dockerService.startContainer(name);
+ return Response.ok().build();
+ } else if (command.getString("command").equalsIgnoreCase("stop")) {
+ dockerService.stopContainer(name);
+ return Response.ok().build();
+ }
+ }
+ }
+ return Response.notModified().build();
+ }
+
@GET
@Produces(MediaType.APPLICATION_JSON)
- @Path("/pod/{env}")
+ @Path("/container/{env}")
public List<ContainerStatus> getContainerStatusesByEnv(@PathParam("env") String env) throws Exception {
return infinispanService.getContainerStatuses(env).stream()
.sorted(Comparator.comparing(ContainerStatus::getProjectId))
@@ -165,10 +194,10 @@ public class InfrastructureResource {
@GET
@Produces(MediaType.APPLICATION_JSON)
- @Path("/pod/{projectId}/{env}")
+ @Path("/container/{projectId}/{env}")
public List<ContainerStatus> getContainerStatusesByProjectAndEnv(@PathParam("projectId") String projectId, @PathParam("env") String env) throws Exception {
return infinispanService.getContainerStatuses(projectId, env).stream()
- .filter(podStatus -> Objects.equals(podStatus.getType(), ContainerStatus.CType.project))
+ .filter(podStatus -> Objects.equals(podStatus.getType(), ContainerStatus.ContainerType.project))
.sorted(Comparator.comparing(ContainerStatus::getContainerName))
.collect(Collectors.toList());
}
@@ -176,10 +205,23 @@ public class InfrastructureResource {
@DELETE
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
- @Path("/pod/{env}/{name}")
- public Response deleteContainer(@PathParam("env") String env, @PathParam("name") String name) throws Exception {
- kubernetesService.deletePod(name, kubernetesService.getNamespace());
- return Response.accepted().build();
+ @Path("/container/{env}/{name}")
+ public Response deleteContainer(@PathParam("env") String env, @PathParam("name") String name) {
+ if (infinispanService.isReady()) {
+ infinispanService.setContainerStatusTransit(name, env, name);
+ try {
+ if (ConfigService.inKubernetes()) {
+ kubernetesService.deletePod(name, kubernetesService.getNamespace());
+ } else {
+ dockerService.deleteContainer(name);
+ }
+ return Response.accepted().build();
+ } catch (Exception e) {
+ LOGGER.error(e.getMessage());
+ return Response.notModified().build();
+ }
+ }
+ return Response.notModified().build();
}
@GET
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 b055716d..86c40428 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
@@ -17,12 +17,10 @@ import javax.inject.Inject;
import java.io.Closeable;
import java.io.IOException;
import java.time.Instant;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
+import java.util.*;
import java.util.stream.Collectors;
+import static org.apache.camel.karavan.docker.DockerService.LABEL_PROJECT_ID;
import static org.apache.camel.karavan.docker.DockerService.LABEL_TYPE;
import static org.apache.camel.karavan.shared.EventType.DEVMODE_CONTAINER_READY;
import static org.apache.camel.karavan.shared.EventType.INFINISPAN_STARTED;
@@ -63,24 +61,22 @@ public class DockerEventListener implements ResultCallback<Event> {
public void onContainerEvent(Event event, Container container) {
if (infinispanService.isReady()) {
- if (Arrays.asList("destroy", "stop", "die", "kill", "pause", "destroy", "rename").contains(event.getStatus())) {
- onDeleteContainer(container);
- } else if (Arrays.asList("create", "start", "unpause").contains(event.getStatus())) {
- onCreateContainer(container, event);
- } else {
+// if (Arrays.asList("create", "start", "unpause", "stop", "pause").contains(event.getStatus())) {
+// onExistingContainer(container);
+// } else {
String status = event.getStatus();
if (status.startsWith("health_status:")) {
if (container.getNames()[0].equals("/infinispan")) {
onInfinispanHealthEvent(container, event);
} else if (inDevMode(container)) {
- onDevModeHealthEvent(container,event);
+ onDevModeHealthEvent(container, event);
}
}
- }
+// }
}
}
- private void onDeleteContainer(Container container){
+ public void onDeletedContainer(Container container) {
String name = container.getNames()[0].replace("/", "");
infinispanService.deleteContainerStatus(name, environment, name);
if (inDevMode(container)) {
@@ -88,24 +84,27 @@ public class DockerEventListener implements ResultCallback<Event> {
}
}
- protected void onCreateContainer(Container container, Event event){
- String name = container.getNames()[0].replace("/", "");
- List<Integer> ports = Arrays.stream(container.getPorts()).map(ContainerPort::getPrivatePort).filter(Objects::nonNull).collect(Collectors.toList());
- ContainerStatus.Lifecycle lc = event.getStatus().equals("create") ? ContainerStatus.Lifecycle.init : ContainerStatus.Lifecycle.ready;
- ContainerStatus.CType type = getCtype(container.getLabels());
- String created = Instant.ofEpochSecond(container.getCreated()).toString();
- ContainerStatus ci = infinispanService.getContainerStatus(name, environment, name);
- if (ci == null) {
- ci = ContainerStatus.createWithId(name, environment, container.getId(), container.getImage(), ports, type, lc, created);
- } else {
- ci.setContainerId(container.getId());
- ci.setPorts(ports);
- ci.setType(type);
- ci.setLifeCycle(lc);
- ci.setCreated(created);
- ci.setImage(container.getImage());
+ protected void onExistingContainer(Container container) {
+ if (infinispanService.isReady()) {
+ String name = container.getNames()[0].replace("/", "");
+ List<Integer> ports = Arrays.stream(container.getPorts()).map(ContainerPort::getPrivatePort).filter(Objects::nonNull).collect(Collectors.toList());
+ List<ContainerStatus.Command> commands = getContainerCommand(container.getState());
+ ContainerStatus.ContainerType type = getContainerType(container.getLabels());
+ String created = Instant.ofEpochSecond(container.getCreated()).toString();
+ ContainerStatus ci = infinispanService.getContainerStatus(name, environment, name);
+ if (ci == null) {
+ ci = ContainerStatus.createWithId(name, environment, container.getId(), container.getImage(), ports, type, commands, container.getState(), created);
+ } else {
+ ci.setContainerId(container.getId());
+ ci.setPorts(ports);
+ ci.setType(type);
+ ci.setCommands(commands);
+ ci.setCreated(created);
+ ci.setState(container.getState());
+ ci.setImage(container.getImage());
+ }
+ infinispanService.saveContainerStatus(ci);
}
- infinispanService.saveContainerStatus(ci);
}
public void onInfinispanHealthEvent(Container container, Event event) {
@@ -116,36 +115,50 @@ public class DockerEventListener implements ResultCallback<Event> {
}
public void onDevModeHealthEvent(Container container, Event event) {
- String name = container.getNames()[0].replace("/", "");
String status = event.getStatus();
String health = status.replace("health_status: ", "");
LOGGER.infof("Container %s health status: %s", container.getNames()[0], health);
- // update ContainerStatus: set ready and
- ContainerStatus cs = infinispanService.getDevModeContainerStatus(name, environment);
- if (cs != null) {
- cs.setLifeCycle(ContainerStatus.Lifecycle.ready);
- cs.setContainerId(container.getId());
- infinispanService.saveContainerStatus(cs);
- eventBus.publish(DEVMODE_CONTAINER_READY, JsonObject.mapFrom(cs));
- }
+ eventBus.publish(DEVMODE_CONTAINER_READY, container.getLabels().get(LABEL_PROJECT_ID));
}
private boolean inDevMode(Container container) {
- return Objects.equals(getCtype(container.getLabels()), ContainerStatus.CType.devmode);
+ return Objects.equals(getContainerType(container.getLabels()), ContainerStatus.ContainerType.devmode);
}
- private ContainerStatus.CType getCtype(Map<String, String> labels) {
+ private ContainerStatus.ContainerType getContainerType(Map<String, String> labels) {
String type = labels.get(LABEL_TYPE);
- if (Objects.equals(type, ContainerStatus.CType.devmode.name())) {
- return ContainerStatus.CType.devmode;
- } else if (Objects.equals(type, ContainerStatus.CType.devservice.name())) {
- return ContainerStatus.CType.devservice;
- } else if (Objects.equals(type, ContainerStatus.CType.project.name())) {
- return ContainerStatus.CType.project;
- } else if (Objects.equals(type, ContainerStatus.CType.internal.name())) {
- return ContainerStatus.CType.internal;
+ if (Objects.equals(type, ContainerStatus.ContainerType.devmode.name())) {
+ return ContainerStatus.ContainerType.devmode;
+ } else if (Objects.equals(type, ContainerStatus.ContainerType.devservice.name())) {
+ return ContainerStatus.ContainerType.devservice;
+ } else if (Objects.equals(type, ContainerStatus.ContainerType.project.name())) {
+ return ContainerStatus.ContainerType.project;
+ } else if (Objects.equals(type, ContainerStatus.ContainerType.internal.name())) {
+ return ContainerStatus.ContainerType.internal;
+ }
+ return ContainerStatus.ContainerType.unknown;
+ }
+
+ private List<ContainerStatus.Command> getContainerCommand(String state) {
+ List<ContainerStatus.Command> result = new ArrayList<>();
+ if (Objects.equals(state, ContainerStatus.State.created.name())) {
+ result.add(ContainerStatus.Command.run);
+ result.add(ContainerStatus.Command.delete);
+ } else if (Objects.equals(state, ContainerStatus.State.exited.name())) {
+ result.add(ContainerStatus.Command.run);
+ result.add(ContainerStatus.Command.delete);
+ } else if (Objects.equals(state, ContainerStatus.State.running.name())) {
+ result.add(ContainerStatus.Command.pause);
+ result.add(ContainerStatus.Command.stop);
+ result.add(ContainerStatus.Command.delete);
+ } else if (Objects.equals(state, ContainerStatus.State.paused.name())) {
+ result.add(ContainerStatus.Command.run);
+ result.add(ContainerStatus.Command.stop);
+ result.add(ContainerStatus.Command.delete);
+ } else if (Objects.equals(state, ContainerStatus.State.dead.name())) {
+ result.add(ContainerStatus.Command.delete);
}
- return ContainerStatus.CType.unknown;
+ return result;
}
@Override
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 27d5a6b3..84178d09 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
@@ -14,7 +14,7 @@ import com.github.dockerjava.httpclient5.ApacheDockerHttpClient;
import com.github.dockerjava.transport.DockerHttpClient;
import io.smallrye.mutiny.tuples.Tuple2;
import io.vertx.core.eventbus.EventBus;
-import io.vertx.core.json.JsonObject;
+import org.apache.camel.karavan.infinispan.InfinispanService;
import org.apache.camel.karavan.infinispan.model.ContainerStatus;
import org.apache.camel.karavan.infinispan.model.Project;
import org.eclipse.microprofile.config.inject.ConfigProperty;
@@ -24,6 +24,7 @@ import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import java.io.IOException;
import java.text.DecimalFormat;
+import java.time.Instant;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
@@ -47,6 +48,9 @@ public class DockerService {
private static final Map<String, Tuple2<Long, Long>> previousStats = new ConcurrentHashMap<>();
private static final List<String> infinispanHealthCheckCMD = List.of("CMD", "curl", "-f", "http://localhost:11222/rest/v2/cache-managers/default/health/status");
+ @ConfigProperty(name = "karavan.environment")
+ String environment;
+
@ConfigProperty(name = "karavan.devmode.image")
String devmodeImage;
@@ -67,17 +71,25 @@ public class DockerService {
@Inject
DockerEventListener dockerEventListener;
+ @Inject
+ InfinispanService infinispanService;
+
@Inject
EventBus eventBus;
+ private DockerClient dockerClient;
+
public void runDevmodeContainer(Project project, String jBangOptions) throws InterruptedException {
String projectId = project.getProjectId();
LOGGER.infof("DevMode starting for %s", projectId);
+
HealthCheck healthCheck = new HealthCheck().withTest(List.of("CMD", "curl", "-f", "http://localhost:8080/q/dev/health"))
.withInterval(10000000000L).withTimeout(10000000000L).withStartPeriod(10000000000L).withRetries(30);
+
createContainer(projectId, devmodeImage,
List.of(), null, false, false, healthCheck,
- Map.of(LABEL_TYPE, ContainerStatus.CType.devmode.name(), LABEL_PROJECT_ID, projectId));
+ Map.of(LABEL_TYPE, ContainerStatus.ContainerType.devmode.name(), LABEL_PROJECT_ID, projectId));
+
startContainer(projectId);
LOGGER.infof("DevMode started for %s", projectId);
}
@@ -91,8 +103,9 @@ public class DockerService {
createContainer(INFINISPAN_CONTAINER_NAME, infinispanImage,
List.of("USER=" + infinispanUsername, "PASS=" + infinispanPassword),
- infinispanPort, false, true, healthCheck, Map.of()
- );
+ infinispanPort, false, true, healthCheck,
+ Map.of(LABEL_TYPE, ContainerStatus.ContainerType.internal.name()));
+
startContainer(INFINISPAN_CONTAINER_NAME);
LOGGER.info("Infinispan is started");
} catch (Exception e) {
@@ -110,7 +123,9 @@ public class DockerService {
"INFINISPAN_USERNAME=" + infinispanUsername,
"INFINISPAN_PASSWORD=" + infinispanPassword
),
- null, false, false, new HealthCheck(), Map.of());
+ null, false, false, new HealthCheck(),
+ Map.of(LABEL_TYPE, ContainerStatus.ContainerType.internal.name()));
+
startContainer(KARAVAN_CONTAINER_NAME);
LOGGER.info("Karavan headless is started");
} catch (Exception e) {
@@ -127,26 +142,33 @@ public class DockerService {
}
}
- public void collectContainersStats() {
- getDockerClient().listContainersCmd().exec().forEach(container -> {
- Statistics stats = getContainerStats(container.getId());
-
- String name = container.getNames()[0].replace("/", "");
- String memoryUsage = formatMemory(stats.getMemoryStats().getUsage());
- String memoryLimit = formatMemory(stats.getMemoryStats().getLimit());
- JsonObject data = JsonObject.of(
- "projectId", name,
- "memory", memoryUsage + " / " + memoryLimit,
- "cpu", formatCpu(name, stats)
- );
- eventBus.publish(CONTAINER_STATISTICS, data);
+ public List<ContainerStatus> collectContainersStatuses() {
+ List<ContainerStatus> result = new ArrayList<>();
+ getDockerClient().listContainersCmd().withShowAll(true).exec().forEach(container -> {
+ ContainerStatus containerStatus = getContainerStatus(container);
+ updateStatistics(containerStatus, container);
+ result.add(containerStatus);
});
+ return result;
}
- public void collectContainersStatuses() {
- getDockerClient().listContainersCmd().exec().forEach(container -> {
- dockerEventListener.onCreateContainer(container, new Event(container.getStatus(), container.getId(), container.getImage(), container.getCreated()));
- });
+ private ContainerStatus getContainerStatus(Container container) {
+ String name = container.getNames()[0].replace("/", "");
+ List<Integer> ports = Arrays.stream(container.getPorts()).map(ContainerPort::getPrivatePort).filter(Objects::nonNull).collect(Collectors.toList());
+ List<ContainerStatus.Command> commands = getContainerCommand(container.getState());
+ ContainerStatus.ContainerType type = getContainerType(container.getLabels());
+ String created = Instant.ofEpochSecond(container.getCreated()).toString();
+ return ContainerStatus.createWithId(name, environment, container.getId(), container.getImage(), ports, type, commands, container.getState(), created);
+ }
+
+ private void updateStatistics(ContainerStatus containerStatus, Container container) {
+ Statistics stats = getContainerStats(container.getId());
+ if (stats != null && stats.getMemoryStats() != null) {
+ String memoryUsage = formatMemory(stats.getMemoryStats().getUsage());
+ String memoryLimit = formatMemory(stats.getMemoryStats().getLimit());
+ containerStatus.setMemoryInfo(memoryUsage + " / " + memoryLimit);
+ containerStatus.setCpuInfo(formatCpu(containerStatus.getContainerName(), stats));
+ }
}
public void startListeners() {
@@ -276,10 +298,14 @@ public class DockerService {
}
public void deleteContainer(String name) {
+ long time = System.currentTimeMillis();
List<Container> containers = getDockerClient().listContainersCmd().withShowAll(true).withNameFilter(List.of(name)).exec();
+ System.out.println("Get containers " + (System.currentTimeMillis() - time));
+ time = System.currentTimeMillis();
if (containers.size() == 1) {
Container container = containers.get(0);
- getDockerClient().removeContainerCmd(container.getId()).exec();
+ getDockerClient().removeContainerCmd(container.getId()).withForce(true).exec();
+ System.out.println("removeContainerCmd " + (System.currentTimeMillis() - time));
}
}
@@ -335,7 +361,10 @@ public class DockerService {
}
private DockerClient getDockerClient() {
- return DockerClientImpl.getInstance(getDockerClientConfig(), getDockerHttpClient());
+ if (dockerClient == null) {
+ dockerClient = DockerClientImpl.getInstance(getDockerClientConfig(), getDockerHttpClient());
+ }
+ return dockerClient;
}
private String formatMemory(Long memory) {
@@ -350,6 +379,42 @@ public class DockerService {
}
}
+ private ContainerStatus.ContainerType getContainerType(Map<String, String> labels) {
+ String type = labels.get(LABEL_TYPE);
+ if (Objects.equals(type, ContainerStatus.ContainerType.devmode.name())) {
+ return ContainerStatus.ContainerType.devmode;
+ } else if (Objects.equals(type, ContainerStatus.ContainerType.devservice.name())) {
+ return ContainerStatus.ContainerType.devservice;
+ } else if (Objects.equals(type, ContainerStatus.ContainerType.project.name())) {
+ return ContainerStatus.ContainerType.project;
+ } else if (Objects.equals(type, ContainerStatus.ContainerType.internal.name())) {
+ return ContainerStatus.ContainerType.internal;
+ }
+ return ContainerStatus.ContainerType.unknown;
+ }
+
+ private List<ContainerStatus.Command> getContainerCommand(String state) {
+ List<ContainerStatus.Command> result = new ArrayList<>();
+ if (Objects.equals(state, ContainerStatus.State.created.name())) {
+ result.add(ContainerStatus.Command.run);
+ result.add(ContainerStatus.Command.delete);
+ } else if (Objects.equals(state, ContainerStatus.State.exited.name())) {
+ result.add(ContainerStatus.Command.run);
+ result.add(ContainerStatus.Command.delete);
+ } else if (Objects.equals(state, ContainerStatus.State.running.name())) {
+ result.add(ContainerStatus.Command.pause);
+ result.add(ContainerStatus.Command.stop);
+ result.add(ContainerStatus.Command.delete);
+ } else if (Objects.equals(state, ContainerStatus.State.paused.name())) {
+ result.add(ContainerStatus.Command.run);
+ result.add(ContainerStatus.Command.stop);
+ result.add(ContainerStatus.Command.delete);
+ } else if (Objects.equals(state, ContainerStatus.State.dead.name())) {
+ result.add(ContainerStatus.Command.delete);
+ }
+ return result;
+ }
+
private String formatCpu(String containerName, Statistics stats) {
try {
double cpuUsage = 0;
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/kubernetes/KubernetesService.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/kubernetes/KubernetesService.java
index 92971460..3be6850a 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/kubernetes/KubernetesService.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/kubernetes/KubernetesService.java
@@ -115,7 +115,7 @@ public class KubernetesService implements HealthCheck {
SharedIndexInformer<Pod> podRunInformer = kubernetesClient().pods().inNamespace(getNamespace())
.withLabels(getRuntimeLabels()).inform();
- podRunInformer.addEventHandlerWithResyncPeriod(new PodEventHandler(infinispanService, this), 30 * 1000L);
+ podRunInformer.addEventHandlerWithResyncPeriod(new PodEventHandler(infinispanService, this, eventBus), 30 * 1000L);
informers.add(podRunInformer);
LOGGER.info("Started Kubernetes Informers");
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/kubernetes/PodEventHandler.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/kubernetes/PodEventHandler.java
index e60f354b..b46af28c 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/kubernetes/PodEventHandler.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/kubernetes/PodEventHandler.java
@@ -5,21 +5,28 @@ import io.fabric8.kubernetes.api.model.Pod;
import io.fabric8.kubernetes.api.model.Quantity;
import io.fabric8.kubernetes.api.model.ResourceRequirements;
import io.fabric8.kubernetes.client.informers.ResourceEventHandler;
+import io.vertx.core.json.JsonObject;
+import io.vertx.mutiny.core.eventbus.EventBus;
import org.apache.camel.karavan.infinispan.InfinispanService;
import org.apache.camel.karavan.infinispan.model.ContainerStatus;
import org.jboss.logging.Logger;
+import java.util.List;
+
import static org.apache.camel.karavan.service.CodeService.DEFAULT_CONTAINER_RESOURCES;
+import static org.apache.camel.karavan.shared.EventType.CONTAINER_STATUS;
public class PodEventHandler implements ResourceEventHandler<Pod> {
private static final Logger LOGGER = Logger.getLogger(PodEventHandler.class.getName());
private final InfinispanService infinispanService;
private final KubernetesService kubernetesService;
+ private final EventBus eventBus;
- public PodEventHandler(InfinispanService infinispanService, KubernetesService kubernetesService) {
+ public PodEventHandler(InfinispanService infinispanService, KubernetesService kubernetesService, EventBus eventBus) {
this.infinispanService = infinispanService;
this.kubernetesService = kubernetesService;
+ this.eventBus = eventBus;
}
@Override
@@ -28,7 +35,7 @@ public class PodEventHandler implements ResourceEventHandler<Pod> {
LOGGER.info("onAdd " + pod.getMetadata().getName());
ContainerStatus ps = getPodStatus(pod);
if (ps != null) {
- infinispanService.saveContainerStatus(ps);
+ eventBus.send(CONTAINER_STATUS, JsonObject.mapFrom(ps));
}
} catch (Exception e){
LOGGER.error(e.getMessage(), e.getCause());
@@ -41,7 +48,7 @@ public class PodEventHandler implements ResourceEventHandler<Pod> {
LOGGER.info("onUpdate " + newPod.getMetadata().getName());
ContainerStatus ps = getPodStatus(newPod);
if (ps != null) {
- infinispanService.saveContainerStatus(ps);
+ eventBus.send(CONTAINER_STATUS, JsonObject.mapFrom(ps));
}
} catch (Exception e){
LOGGER.error(e.getMessage(), e.getCause());
@@ -76,17 +83,22 @@ public class PodEventHandler implements ResourceEventHandler<Pod> {
String requestCpu = resourceRequirements.getRequests().getOrDefault("cpu", new Quantity()).toString();
String limitMemory = resourceRequirements.getLimits().getOrDefault("memory", new Quantity()).toString();
String limitCpu = resourceRequirements.getLimits().getOrDefault("cpu", new Quantity()).toString();
- return new ContainerStatus(
+ ContainerStatus status = new ContainerStatus(
pod.getMetadata().getName(),
- ContainerStatus.Lifecycle.ready,
+ List.of(ContainerStatus.Command.delete),
projectId,
kubernetesService.environment,
- pod.getMetadata().getName().equals(projectId) ? ContainerStatus.CType.devmode : ContainerStatus.CType.project,
+ pod.getMetadata().getName().equals(projectId) ? ContainerStatus.ContainerType.devmode : ContainerStatus.ContainerType.project,
requestMemory + " : " + limitMemory,
requestCpu + " : " + limitCpu,
- creationTimestamp
+ creationTimestamp);
- );
+ if (ready) {
+ status.setState(ContainerStatus.State.running.name());
+ } else {
+ status.setState(ContainerStatus.State.created.name());
+ }
+ return status;
} catch (Exception ex) {
LOGGER.error(ex.getMessage(), ex.getCause());
return null;
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 ba3afb33..884ff168 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
@@ -37,6 +37,8 @@ import java.util.Arrays;
import java.util.Objects;
import java.util.concurrent.ExecutionException;
+import static org.apache.camel.karavan.shared.EventType.CONTAINER_STATUS;
+
@ApplicationScoped
public class CamelService {
@@ -71,12 +73,12 @@ public class CamelService {
public void reloadProjectCode(String projectId) {
LOGGER.info("Reload project code " + projectId);
try {
- ContainerStatus containerStatus = infinispanService.getDevModeContainerStatus(projectId, environment);
infinispanService.getProjectFiles(projectId).forEach(projectFile ->
putRequest(projectId, projectFile.getName(), projectFile.getCode(), 1000));
reloadRequest(projectId);
+ ContainerStatus containerStatus = infinispanService.getDevModeContainerStatus(projectId, environment);
containerStatus.setCodeLoaded(true);
- infinispanService.saveContainerStatus(containerStatus);
+ eventBus.send(CONTAINER_STATUS, JsonObject.mapFrom(containerStatus));
} catch (Exception ex) {
LOGGER.error(ex.getMessage());
}
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 4d6f0b7a..f3e011f4 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
@@ -9,11 +9,13 @@ import org.apache.camel.karavan.infinispan.model.ContainerStatus;
import org.apache.camel.karavan.kubernetes.KubernetesService;
import org.apache.camel.karavan.shared.ConfigService;
import org.apache.camel.karavan.shared.EventType;
+import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.jboss.logging.Logger;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import java.io.IOException;
+import java.util.Objects;
import static org.apache.camel.karavan.shared.EventType.*;
@@ -22,6 +24,9 @@ public class EventService {
private static final Logger LOGGER = Logger.getLogger(EventService.class.getName());
+ @ConfigProperty(name = "karavan.environment")
+ String environment;
+
@Inject
InfinispanService infinispanService;
@@ -37,9 +42,6 @@ public class EventService {
@Inject
ProjectService projectService;
- @Inject
- ConfigService configService;
-
@Inject
EventBus bus;
@@ -73,29 +75,30 @@ public class EventService {
}
@ConsumeEvent(value = DEVMODE_CONTAINER_READY, blocking = true, ordered = true)
- void receiveCommand(JsonObject message) {
- LOGGER.info("received Status " + message);
- ContainerStatus status = message.mapTo(ContainerStatus.class);
- if (!status.getCodeLoaded() && status.getContainerId() != null && status.getLifeCycle().equals(ContainerStatus.Lifecycle.ready)) {
+ void receiveCommand(String projectId) {
+ LOGGER.info("DEVMODE_CONTAINER_READY " + projectId);
+ ContainerStatus status = infinispanService.getContainerStatus(projectId, environment, projectId);
+ if (!status.getCodeLoaded() && status.getContainerId() != null && status.getState().equals(ContainerStatus.State.running.name())) {
if (ConfigService.inKubernetes()) {
- camelService.reloadProjectCode(status.getProjectId());
+ camelService.reloadProjectCode(projectId);
} else {
- infinispanService.sendCodeReloadCommand(status.getProjectId());
+ infinispanService.sendCodeReloadCommand(projectId);
}
}
}
- @ConsumeEvent(value = CONTAINER_STATISTICS, blocking = true, ordered = true)
- public void saveStats(JsonObject data) {
- String projectId = data.getString("projectId");
- String memory = data.getString("memory");
- String cpu = data.getString("cpu");
+ @ConsumeEvent(value = CONTAINER_STATUS, blocking = true, ordered = true)
+ public void saveContainerStatus(JsonObject data) {
if (infinispanService.isReady()) {
- ContainerStatus containerStatus = infinispanService.getDevModeContainerStatus(projectId, configService.getConfiguration().getEnvironment());
- if (containerStatus != null) {
- containerStatus.setCpuInfo(cpu);
- containerStatus.setMemoryInfo(memory);
- infinispanService.saveContainerStatus(containerStatus);
+ ContainerStatus newStatus = data.mapTo(ContainerStatus.class);
+ System.out.println(newStatus);
+ ContainerStatus oldStatus = infinispanService.getContainerStatus(newStatus.getProjectId(), newStatus.getEnv(), newStatus.getContainerName());
+ if (oldStatus == null || Objects.equals(oldStatus.getInTransit(), Boolean.FALSE)) {
+ infinispanService.saveContainerStatus(newStatus);
+ } else if (Objects.equals(oldStatus.getInTransit(), Boolean.TRUE)){
+ if (!Objects.equals(oldStatus.getState(), newStatus.getState())) {
+ infinispanService.saveContainerStatus(newStatus);
+ }
}
}
}
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/ScheduledService.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/ScheduledService.java
index 7886a86d..16fcbeb6 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/ScheduledService.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/ScheduledService.java
@@ -17,19 +17,29 @@
package org.apache.camel.karavan.service;
import io.quarkus.scheduler.Scheduled;
+import io.vertx.core.eventbus.EventBus;
+import io.vertx.core.json.JsonObject;
import org.apache.camel.karavan.docker.DockerService;
import org.apache.camel.karavan.infinispan.InfinispanService;
+import org.apache.camel.karavan.infinispan.model.ContainerStatus;
import org.apache.camel.karavan.shared.ConfigService;
+import org.apache.camel.karavan.shared.EventType;
+import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.jboss.logging.Logger;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
+import java.util.List;
+import java.util.stream.Collectors;
@ApplicationScoped
public class ScheduledService {
private static final Logger LOGGER = Logger.getLogger(ScheduledService.class.getName());
+ @ConfigProperty(name = "karavan.environment")
+ String environment;
+
@Inject
DockerService dockerService;
@@ -42,9 +52,25 @@ public class ScheduledService {
@Inject
InfinispanService infinispanService;
- @Scheduled(every = "{karavan.container.statistics.interval}", concurrentExecution = Scheduled.ConcurrentExecution.SKIP)
- void collectContainersStats() {
- dockerService.collectContainersStats();
+ @Inject
+ EventBus eventBus;
+
+ @Scheduled(every = "{karavan.container.status.interval}", concurrentExecution = Scheduled.ConcurrentExecution.SKIP)
+ void collectContainersStatuses() {
+ if (infinispanService.isReady()) {
+ List<ContainerStatus> statusesInDocker = dockerService.collectContainersStatuses();
+ List<String> namesInDocker = statusesInDocker.stream().map(ContainerStatus::getContainerName).collect(Collectors.toList());
+ List<ContainerStatus> statusesInInfinispan = infinispanService.getContainerStatuses(environment);
+ // clean deleted
+ statusesInInfinispan.stream().filter(cs -> !namesInDocker.contains(cs.getContainerName())).forEach(containerStatus -> {
+ infinispanService.deleteContainerStatus(containerStatus);
+ infinispanService.deleteCamelStatuses(containerStatus.getProjectId(), containerStatus.getEnv());
+ });
+ // send statuses to save
+ statusesInDocker.forEach(containerStatus -> {
+ eventBus.send(EventType.CONTAINER_STATUS, JsonObject.mapFrom(containerStatus));
+ });
+ }
}
@Scheduled(every = "{karavan.container.infinispan.interval}", concurrentExecution = Scheduled.ConcurrentExecution.SKIP)
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 ac89a948..a1085fb9 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
@@ -10,7 +10,7 @@ public class EventType {
public static final String INFINISPAN_STARTED = "INFINISPAN_STARTED";
- public static final String CONTAINER_STATISTICS = "CONTAINER_STATISTICS";
+ public static final String CONTAINER_STATUS = "CONTAINER_STATUS";
public static final String DEVMODE_CONTAINER_READY = "DEVMODE_STATUS";
}
diff --git a/karavan-web/karavan-app/src/main/resources/application.properties b/karavan-web/karavan-app/src/main/resources/application.properties
index 37a78899..93f3db4b 100644
--- a/karavan-web/karavan-app/src/main/resources/application.properties
+++ b/karavan-web/karavan-app/src/main/resources/application.properties
@@ -4,7 +4,7 @@ karavan.environments=dev
karavan.default-runtime=quarkus
karavan.runtimes=quarkus,spring-boot
karavan.camel.status.interval=off
-karavan.container.statistics.interval=3s
+karavan.container.status.interval=3s
karavan.container.infinispan.interval=5s
karavan.devmode.image=ghcr.io/apache/camel-karavan-runner:3.21.1-snapshot
karavan.headless.image=entropy1/karavan-headless:3.21.1-SNAPSHOT
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 7a964268..fc0ed2e8 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
@@ -304,7 +304,7 @@ export class KaravanApi {
}
static async getDevModePodStatus(projectId: string, after: (res: AxiosResponse<ContainerStatus>) => void) {
- instance.get('/api/devmode/pod/' + projectId)
+ instance.get('/api/devmode/container/' + projectId)
.then(res => {
after(res);
}).catch(err => {
@@ -312,7 +312,7 @@ export class KaravanApi {
});
}
- static async reloadDevMode(projectId: string, after: (res: AxiosResponse<any>) => void) {
+ static async reloadDevModeCode(projectId: string, after: (res: AxiosResponse<any>) => void) {
instance.get('/api/devmode/reload/' + projectId)
.then(res => {
after(res);
@@ -330,7 +330,7 @@ export class KaravanApi {
});
}
- static async runProject(project: Project, verbose: boolean, after: (res: AxiosResponse<string>) => void) {
+ static async startDevModeContainer(project: Project, verbose: boolean, after: (res: AxiosResponse<string>) => void) {
instance.post('/api/devmode' + (verbose ? '/--verbose' : ''), project)
.then(res => {
after(res);
@@ -339,7 +339,7 @@ export class KaravanApi {
});
}
- static async deleteRunner(name: string, deletePVC: boolean, after: (res: AxiosResponse<any>) => void) {
+ static async deleteDevModeContainer(name: string, deletePVC: boolean, after: (res: AxiosResponse<any>) => void) {
instance.delete('/api/devmode/' + name + "/" + deletePVC)
.then(res => {
after(res);
@@ -453,7 +453,7 @@ export class KaravanApi {
}
static async getProjectPodStatuses(project: string, env: string, after: (statuses: ContainerStatus[]) => void) {
- instance.get('/api/infrastructure/pod/' + project + "/" + env)
+ instance.get('/api/infrastructure/container/' + project + "/" + env)
.then(res => {
if (res.status === 200) {
after(res.data);
@@ -463,8 +463,17 @@ export class KaravanApi {
});
}
- static async deletePod(environment: string, name: string, after: (res: AxiosResponse<any>) => void) {
- instance.delete('/api/infrastructure/pod/' + environment + '/' + name)
+ static async manageContainer(environment: string, name: string, command: 'run' | 'pause' | 'stop', after: (res: AxiosResponse<any>) => void) {
+ instance.post('/api/infrastructure/container/' + environment + '/' + name, {command: command})
+ .then(res => {
+ after(res);
+ }).catch(err => {
+ after(err);
+ });
+ }
+
+ static async deleteContainer(environment: string, name: string, after: (res: AxiosResponse<any>) => void) {
+ instance.delete('/api/infrastructure/container/' + environment + '/' + name)
.then(res => {
after(res);
}).catch(err => {
diff --git a/karavan-web/karavan-app/src/main/webui/src/api/ProjectModels.ts b/karavan-web/karavan-app/src/main/webui/src/api/ProjectModels.ts
index fe0fb19e..3a4ced02 100644
--- a/karavan-web/karavan-app/src/main/webui/src/api/ProjectModels.ts
+++ b/karavan-web/karavan-app/src/main/webui/src/api/ProjectModels.ts
@@ -71,6 +71,7 @@ export class ContainerStatus {
containerName: string = '';
containerId: string = '';
lifeCycle: string = '';
+ state: string = '';
deployment: string = '';
projectId: string = '';
env: string = '';
@@ -80,6 +81,8 @@ export class ContainerStatus {
created: string = '';
image: string = '';
ports: [] = [];
+ commands: string [] = [];
+ inTransit: boolean = false;
public constructor(init?: Partial<ContainerStatus>) {
Object.assign(this, init);
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 4fbd9da7..28f6cf2b 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
@@ -14,43 +14,68 @@ import {ProjectEventBus} from "./ProjectEventBus";
export class ProjectService {
- public static startRunner(project: Project, verbose: boolean) {
- useDevModeStore.setState({status: "starting"})
- KaravanApi.runProject(project, verbose, res => {
+ public static startDevModeContainer(project: Project, verbose: boolean) {
+ useDevModeStore.setState({status: "wip"})
+ KaravanApi.startDevModeContainer(project, verbose, res => {
if (res.status === 200 || res.status === 201) {
ProjectEventBus.sendLog("set", '');
useLogStore.setState({showLog: true, type: 'container', podName: res.data})
+ useDevModeStore.setState({status: "none"})
} else {
// Todo notification
}
});
}
- public static reloadRunner(project: Project) {
- useDevModeStore.setState({status: "reloading"})
- KaravanApi.reloadDevMode(project.projectId, res => {
+ public static reloadDevModeCode(project: Project) {
+ useDevModeStore.setState({status: "wip"})
+ KaravanApi.reloadDevModeCode(project.projectId, res => {
if (res.status === 200 || res.status === 201) {
// setIsReloadingPod(false);
} else {
// Todo notification
// setIsReloadingPod(false);
}
+ useDevModeStore.setState({status: "none"})
});
}
- public static deleteRunner(project: Project) {
- useDevModeStore.setState({status: "deleting"})
+ public static stopDevModeContainer(project: Project) {
+ useDevModeStore.setState({status: "wip"})
+ KaravanApi.manageContainer("dev", project.projectId, 'stop', res => {
+ if (res.status === 200) {
+ useLogStore.setState({showLog: false, type: 'container', isRunning: false})
+ } else {
+ ProjectEventBus.sendAlert(new ToastMessage("Error stopping DevMode container", res.statusText, 'warning'))
+ }
+ });
+ }
+
+ public static pauseDevModeContainer(project: Project) {
+ useDevModeStore.setState({status: "wip"})
+ KaravanApi.manageContainer("dev", project.projectId, 'pause', res => {
+ if (res.status === 200) {
+ useLogStore.setState({showLog: false, type: 'container', isRunning: false})
+ } else {
+ ProjectEventBus.sendAlert(new ToastMessage("Error stopping DevMode container", res.statusText, 'warning'))
+ }
+ });
+ }
+
+ public static deleteDevModeContainer(project: Project) {
+ useDevModeStore.setState({status: "wip"})
ProjectEventBus.sendLog("set", '');
- KaravanApi.deleteRunner(project.projectId, false, res => {
+ KaravanApi.deleteDevModeContainer(project.projectId, false, res => {
if (res.status === 202) {
useLogStore.setState({showLog: false, type: 'container', isRunning: false})
} else {
ProjectEventBus.sendAlert(new ToastMessage("Error delete runner", res.statusText, 'warning'))
}
+ useDevModeStore.setState({status: "none"})
});
}
- public static getDevModePodStatus(project: Project) {
+ public static getDevModeStatus(project: Project) {
const projectId = project.projectId;
KaravanApi.getDevModePodStatus(projectId, res => {
if (res.status === 200) {
@@ -59,8 +84,8 @@ export class ProjectService {
if (useDevModeStore.getState().podName !== podStatus.containerName){
useDevModeStore.setState({podName: podStatus.containerName})
}
- if (useDevModeStore.getState().status !== "running"){
- useDevModeStore.setState({status: "running"})
+ if (useDevModeStore.getState().status !== "wip"){
+ useDevModeStore.setState({status: "wip"})
useLogStore.setState({isRunning: true})
}
useProjectStore.setState({containerStatus: res.data});
diff --git a/karavan-web/karavan-app/src/main/webui/src/api/ProjectStore.ts b/karavan-web/karavan-app/src/main/webui/src/api/ProjectStore.ts
index 418d1848..80c99593 100644
--- a/karavan-web/karavan-app/src/main/webui/src/api/ProjectStore.ts
+++ b/karavan-web/karavan-app/src/main/webui/src/api/ProjectStore.ts
@@ -137,14 +137,14 @@ export const useFileStore = create<FileState>((set) => ({
interface DevModeState {
podName?: string,
- status: "none" | "starting" | "deleting"| "reloading" | "running",
- setStatus: (status: "none" | "starting" | "deleting"| "reloading" | "running") => void,
+ status: "none" | "wip",
+ setStatus: (status: "none" | "wip") => void,
}
export const useDevModeStore = create<DevModeState>((set) => ({
podName: undefined,
status: "none",
- setStatus: (status: "none" | "starting" | "deleting"| "reloading" | "running") => {
+ setStatus: (status: "none" | "wip") => {
set((state: DevModeState) => ({
status: status,
}));
diff --git a/karavan-web/karavan-app/src/main/webui/src/containers/ContainerTableRow.tsx b/karavan-web/karavan-app/src/main/webui/src/containers/ContainerTableRow.tsx
index 29241c44..660c2f0d 100644
--- a/karavan-web/karavan-app/src/main/webui/src/containers/ContainerTableRow.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/containers/ContainerTableRow.tsx
@@ -2,13 +2,16 @@ import React, {useState} from 'react';
import {
Button,
Tooltip,
- Flex, FlexItem, Label, Badge
+ Flex, FlexItem, Label, Badge, Spinner
} from '@patternfly/react-core';
import '../designer/karavan.css';
import {ExpandableRowContent, Tbody, Td, Tr} from "@patternfly/react-table";
import StopIcon from "@patternfly/react-icons/dist/js/icons/stop-icon";
import PlayIcon from "@patternfly/react-icons/dist/esm/icons/play-icon";
import {ContainerStatus} from "../api/ProjectModels";
+import PauseIcon from "@patternfly/react-icons/dist/esm/icons/pause-icon";
+import DeleteIcon from "@patternfly/react-icons/dist/js/icons/times-icon";
+import {KaravanApi} from "../api/KaravanApi";
interface Props {
index: number
@@ -18,14 +21,13 @@ interface Props {
export const ContainerTableRow = (props: Props) => {
const [isExpanded, setIsExpanded] = useState<boolean>(false);
- const [running, setRunning] = useState<boolean>(false);
const container = props.container;
- const env = container.env;
+ const commands = container.commands;
const ports = container.ports;
- const icon = running ? <StopIcon/> : <PlayIcon/>;
- const tooltip = running ? "Stop container" : "Start container";
- const color = container.lifeCycle === 'ready' ? "green" : "grey";
+ const isRunning = container.state === 'running';
+ const inTransit = container.inTransit;
+ const color = container.state === 'running' ? "green" : "grey";
return (
<Tbody isExpanded={isExpanded}>
<Tr key={container.containerName}>
@@ -48,23 +50,52 @@ export const ContainerTableRow = (props: Props) => {
</Td>
<Td>{container.image}</Td>
<Td>
- <Label color={color}>{container.cpuInfo}</Label>
+ {isRunning && container.cpuInfo && <Label color={color}>{container.cpuInfo}</Label>}
</Td>
<Td>
- <Label color={color}>{container.memoryInfo}</Label>
+ {isRunning && container.memoryInfo && <Label color={color}>{container.memoryInfo}</Label>}
+ </Td>
+ <Td>
+ {!inTransit && <Label color={color}>{container.state}</Label>}
+ {inTransit && <Spinner isSVG size="md" aria-label="spinner"/>}
</Td>
- {/*<Td>{container.environment}</Td>*/}
<Td className="project-action-buttons">
- <Flex direction={{default: "row"}} justifyContent={{default: "justifyContentFlexEnd"}}
- spaceItems={{default: 'spaceItemsNone'}}>
- <FlexItem>
- <Tooltip content={tooltip} position={"bottom"}>
- <Button variant={"plain"} icon={icon} onClick={e => {
- // setProject(project, "delete");
- }}></Button>
- </Tooltip>
- </FlexItem>
- </Flex>
+ {container.type !== 'internal' &&
+ <Flex direction={{default: "row"}} justifyContent={{default: "justifyContentFlexEnd"}}
+ spaceItems={{default: 'spaceItemsNone'}}>
+ <FlexItem>
+ <Tooltip content={"Start container"} position={"bottom"}>
+ <Button variant={"plain"} icon={<PlayIcon/>} isDisabled={!commands.includes('run') || inTransit}
+ onClick={e => {
+ KaravanApi.manageContainer(container.env, container.containerName, 'run', res => {});
+ }}></Button>
+ </Tooltip>
+ </FlexItem>
+ <FlexItem>
+ <Tooltip content={"Pause container"} position={"bottom"}>
+ <Button variant={"plain"} icon={<PauseIcon/>} isDisabled={!commands.includes('pause') || inTransit}
+ onClick={e => {
+ KaravanApi.manageContainer(container.env, container.containerName, 'pause', res => {});
+ }}></Button>
+ </Tooltip>
+ </FlexItem>
+ <FlexItem>
+ <Tooltip content={"Stop container"} position={"bottom"}>
+ <Button variant={"plain"} icon={<StopIcon/>} isDisabled={!commands.includes('stop') || inTransit}
+ onClick={e => {
+ KaravanApi.manageContainer(container.env, container.containerName, 'stop', res => {});
+ }}></Button>
+ </Tooltip>
+ </FlexItem>
+ <FlexItem>
+ <Tooltip content={"Delete container"} position={"bottom"}>
+ <Button variant={"plain"} icon={<DeleteIcon/>} isDisabled={!commands.includes('delete') || inTransit}
+ onClick={e => {
+ KaravanApi.deleteContainer(container.env, container.containerName, res => {});
+ }}></Button>
+ </Tooltip>
+ </FlexItem>
+ </Flex>}
</Td>
</Tr>
{<Tr isExpanded={isExpanded}>
@@ -84,7 +115,7 @@ export const ContainerTableRow = (props: Props) => {
<Td colSpan={2}>
<ExpandableRowContent>
<Flex direction={{default: "row"}} cellPadding={"0px"}>
- {ports.map(port => <FlexItem>{port}</FlexItem>)}
+ {ports.map((port, index) => <FlexItem key={index}>{port}</FlexItem>)}
</Flex>
</ExpandableRowContent>
</Td>
diff --git a/karavan-web/karavan-app/src/main/webui/src/containers/ContainersPage.tsx b/karavan-web/karavan-app/src/main/webui/src/containers/ContainersPage.tsx
index 34d44ff7..9d1f6607 100644
--- a/karavan-web/karavan-app/src/main/webui/src/containers/ContainersPage.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/containers/ContainersPage.tsx
@@ -40,7 +40,7 @@ export const ContainersPage = () => {
useEffect(() => {
const interval = setInterval(() => {
onGetProjects()
- }, 2000);
+ }, 700);
return () => {
clearInterval(interval)
};
@@ -111,21 +111,23 @@ export const ContainersPage = () => {
function getEmptyState() {
return (
- <Tr>
- <Td colSpan={8}>
- <Bullseye>
- {loading && <Spinner className="progress-stepper" isSVG diameter="80px" aria-label="Loading..."/>}
- {!loading &&
- <EmptyState variant={EmptyStateVariant.small}>
- <EmptyStateIcon icon={SearchIcon}/>
- <Title headingLevel="h2" size="lg">
- No results found
- </Title>
- </EmptyState>
- }
- </Bullseye>
- </Td>
- </Tr>
+ <Tbody>
+ <Tr>
+ <Td colSpan={8}>
+ <Bullseye>
+ {loading && <Spinner className="progress-stepper" isSVG diameter="80px" aria-label="Loading..."/>}
+ {!loading &&
+ <EmptyState variant={EmptyStateVariant.small}>
+ <EmptyStateIcon icon={SearchIcon}/>
+ <Title headingLevel="h2" size="lg">
+ No results found
+ </Title>
+ </EmptyState>
+ }
+ </Bullseye>
+ </Td>
+ </Tr>
+ </Tbody>
)
}
@@ -145,6 +147,7 @@ export const ContainersPage = () => {
<Th key='image'>Image</Th>
<Th key='cpuInfo'>CPU</Th>
<Th key='memoryInfo'>Memory</Th>
+ <Th key='state'>State</Th>
<Th key='action'></Th>
</Tr>
</Thead>
diff --git a/karavan-web/karavan-app/src/main/webui/src/project/DevModeToolbar.tsx b/karavan-web/karavan-app/src/main/webui/src/project/DevModeToolbar.tsx
index 4f202b92..510372e5 100644
--- a/karavan-web/karavan-app/src/main/webui/src/project/DevModeToolbar.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/project/DevModeToolbar.tsx
@@ -3,12 +3,13 @@ import {Button, Flex, FlexItem, Label, Switch, Tooltip, TooltipPosition} from '@
import '../designer/karavan.css';
import RocketIcon from "@patternfly/react-icons/dist/esm/icons/rocket-icon";
import ReloadIcon from "@patternfly/react-icons/dist/esm/icons/bolt-icon";
-import DeleteIcon from "@patternfly/react-icons/dist/esm/icons/times-circle-icon";
+import DeleteIcon from "@patternfly/react-icons/dist/esm/icons/trash-icon";
import {useDevModeStore, useLogStore, useProjectStore} from "../api/ProjectStore";
import {ProjectService} from "../api/ProjectService";
import {shallow} from "zustand/shallow";
import UpIcon from "@patternfly/react-icons/dist/esm/icons/check-circle-icon";
import DownIcon from "@patternfly/react-icons/dist/esm/icons/error-circle-o-icon";
+import StopIcon from "@patternfly/react-icons/dist/js/icons/stop-icon";
interface Props {
@@ -18,29 +19,18 @@ interface Props {
export const DevModeToolbar = (props: Props) => {
const [status] = useDevModeStore((state) => [state.status], shallow)
- const [project,containerStatus ] = useProjectStore((state) => [state.project, state.containerStatus], shallow)
+ const [project, containerStatus ] = useProjectStore((state) => [state.project, state.containerStatus], shallow)
const [verbose, setVerbose] = useState(false);
-
- function getColor() {
- return getRunning() ? "green" : "grey";
- }
-
- function getRunning(): boolean {
- return containerStatus.lifeCycle === 'ready';
- }
-
- function getIcon() {
- return (getRunning() ? <UpIcon/> : <DownIcon/>)
- }
-
- const isRunning = status === "running";
- const isStartingPod = status === "starting";
- const isReloadingPod = status === "reloading";
- const isDeletingPod = status === "deleting";
+ const commands = containerStatus.commands;
+ const ports = containerStatus.ports;
+ const isRunning = containerStatus.state === 'running';
+ const inTransit = containerStatus.inTransit;
+ const color = containerStatus.state === 'running' ? "green" : "grey";
+ const icon = isRunning ? <UpIcon/> : <DownIcon/>;
return (<Flex className="toolbar" direction={{default: "row"}} alignItems={{default: "alignItemsCenter"}}>
- {isRunning && <FlexItem>
- <Label icon={getIcon()} color={getColor()}>
+ {<FlexItem>
+ <Label icon={icon} color={color}>
<Tooltip content={"Show log"} position={TooltipPosition.bottom}>
<Button variant="link"
onClick={e =>
@@ -50,19 +40,7 @@ export const DevModeToolbar = (props: Props) => {
</Tooltip>
</Label>
</FlexItem>}
- {(isRunning || isDeletingPod) && !isReloadingPod && props.reloadOnly !== true && <FlexItem>
- <Tooltip content="Stop devmode" position={TooltipPosition.bottom}>
- <Button isLoading={isDeletingPod ? true : undefined}
- isSmall
- variant={"secondary"}
- className="project-button"
- icon={!isRunning ? <DeleteIcon/> : <div></div>}
- onClick={() => ProjectService.deleteRunner(project)}>
- {isDeletingPod ? "..." : "Stop"}
- </Button>
- </Tooltip>
- </FlexItem>}
- {!isRunning && !isReloadingPod && !isDeletingPod && props.reloadOnly !== true && <FlexItem>
+ <FlexItem>
<Tooltip content="Verbose" position={TooltipPosition.bottom}>
<Switch aria-label="verbose"
id="verbose"
@@ -70,28 +48,50 @@ export const DevModeToolbar = (props: Props) => {
onChange={checked => setVerbose(checked)}
/>
</Tooltip>
- </FlexItem>}
- {!isRunning && !isReloadingPod && props.reloadOnly !== true && <FlexItem>
+ </FlexItem>
+ {!isRunning && <FlexItem>
<Tooltip content="Run in developer mode" position={TooltipPosition.bottom}>
- <Button isLoading={isStartingPod ? true : undefined}
+ <Button isLoading={status === 'wip'}
isSmall
+ isDisabled={(!(commands.length === 0) && !commands.includes('run')) || inTransit}
variant={"primary"}
- className="project-button"
- icon={!isStartingPod ? <RocketIcon/> : <div></div>}
- onClick={() => ProjectService.startRunner(project, verbose)}>
- {isStartingPod ? "..." : "Run"}
+ icon={<RocketIcon/>}
+ onClick={() => ProjectService.startDevModeContainer(project, verbose)}>
+ {"Run"}
</Button>
</Tooltip>
</FlexItem>}
- {(isRunning || isReloadingPod) && <FlexItem>
+ {isRunning && <FlexItem>
<Tooltip content="Reload" position={TooltipPosition.bottom}>
- <Button isLoading={isReloadingPod ? true : undefined}
+ <Button isLoading={status === 'wip'}
isSmall
+ isDisabled={inTransit}
variant={"primary"}
className="project-button"
- icon={!isReloadingPod ? <ReloadIcon/> : <div></div>}
- onClick={() => ProjectService.reloadRunner(project)}>
- {isReloadingPod ? "..." : "Reload"}
+ icon={<ReloadIcon/>}
+ onClick={() => ProjectService.reloadDevModeCode(project)}>Reload
+ </Button>
+ </Tooltip>
+ </FlexItem>}
+ {<FlexItem>
+ <Tooltip content="Stop container" position={TooltipPosition.bottom}>
+ <Button isLoading={status === 'wip'}
+ isSmall
+ isDisabled={!commands.includes('stop') || inTransit}
+ variant={"control"}
+ icon={<StopIcon/>}
+ onClick={() => ProjectService.stopDevModeContainer(project)}>
+ </Button>
+ </Tooltip>
+ </FlexItem>}
+ {<FlexItem>
+ <Tooltip content="Delete container" position={TooltipPosition.bottom}>
+ <Button isLoading={status === 'wip'}
+ isSmall
+ isDisabled={!commands.includes('delete') || inTransit}
+ variant={"control"}
+ icon={<DeleteIcon/>}
+ onClick={() => ProjectService.deleteDevModeContainer(project)}>
</Button>
</Tooltip>
</FlexItem>}
diff --git a/karavan-web/karavan-app/src/main/webui/src/project/ProjectPage.tsx b/karavan-web/karavan-app/src/main/webui/src/project/ProjectPage.tsx
index 90b08ed3..cab863b6 100644
--- a/karavan-web/karavan-app/src/main/webui/src/project/ProjectPage.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/project/ProjectPage.tsx
@@ -26,7 +26,7 @@ export const ProjectPage = () => {
useEffect(() => {
// TODO: make status request only when started or just opened
const interval = setInterval(() => {
- ProjectService.getDevModePodStatus(project);
+ ProjectService.getDevModeStatus(project);
}, 1000);
return () => {
clearInterval(interval)
diff --git a/karavan-web/karavan-app/src/main/webui/src/project/dashboard/InfoContainer.tsx b/karavan-web/karavan-app/src/main/webui/src/project/dashboard/InfoContainer.tsx
index 03bc5f9e..29c7247d 100644
--- a/karavan-web/karavan-app/src/main/webui/src/project/dashboard/InfoContainer.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/project/dashboard/InfoContainer.tsx
@@ -35,7 +35,7 @@ export const InfoContainer = (props: Props) => {
}
function getRunning(): boolean {
- return props.containerStatus.lifeCycle === 'ready';
+ return props.containerStatus.state === 'running';
}
const containerStatus = props.containerStatus;
@@ -50,7 +50,7 @@ export const InfoContainer = (props: Props) => {
<DescriptionListGroup>
<DescriptionListTerm>Status</DescriptionListTerm>
<DescriptionListDescription>
- {getPodInfoLabel(containerStatus.lifeCycle)}
+ {getPodInfoLabel(containerStatus.state)}
</DescriptionListDescription>
</DescriptionListGroup>
<DescriptionListGroup>
diff --git a/karavan-web/karavan-app/src/main/webui/src/project/pipeline/ProjectStatus.tsx b/karavan-web/karavan-app/src/main/webui/src/project/pipeline/ProjectStatus.tsx
index 491a2b80..f32d070e 100644
--- a/karavan-web/karavan-app/src/main/webui/src/project/pipeline/ProjectStatus.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/project/pipeline/ProjectStatus.tsx
@@ -87,7 +87,7 @@ export class ProjectStatus extends React.Component<Props, State> {
});
break;
case "pod":
- KaravanApi.deletePod(environment, name, (res: any) => {
+ KaravanApi.deleteContainer(environment, name, (res: any) => {
// if (Array.isArray(res) && Array.from(res).length > 0)
// this.onRefresh();
});
diff --git a/karavan-web/karavan-app/src/main/webui/src/services/ServicesTableRow.tsx b/karavan-web/karavan-app/src/main/webui/src/services/ServicesTableRow.tsx
index 621f58a5..f6affafe 100644
--- a/karavan-web/karavan-app/src/main/webui/src/services/ServicesTableRow.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/services/ServicesTableRow.tsx
@@ -47,7 +47,7 @@ export const ServicesTableRow = (props: Props) => {
<Td>{service.image}</Td>
<Td>
<Flex direction={{default: "row"}}>
- {service.ports.map(port => <FlexItem>{port}</FlexItem>)}
+ {service.ports.map(port => <FlexItem key={port}>{port}</FlexItem>)}
</Flex>
</Td>
{/*<Td>{service.environment}</Td>*/}
@@ -70,7 +70,7 @@ export const ServicesTableRow = (props: Props) => {
<Td colSpan={2}>
<ExpandableRowContent>
<Flex direction={{default: "column"}} cellPadding={"0px"}>
- {keys.map(key => <FlexItem>{key + ": " + env[key]}</FlexItem>)}
+ {keys.map(key => <FlexItem key={key}>{key + ": " + env[key]}</FlexItem>)}
</Flex>
</ExpandableRowContent>
</Td>
diff --git a/karavan-web/karavan-headless/src/main/java/org/apache/camel/karavan/headless/CamelService.java b/karavan-web/karavan-headless/src/main/java/org/apache/camel/karavan/headless/CamelService.java
index 41aa5838..089ade28 100644
--- a/karavan-web/karavan-headless/src/main/java/org/apache/camel/karavan/headless/CamelService.java
+++ b/karavan-web/karavan-headless/src/main/java/org/apache/camel/karavan/headless/CamelService.java
@@ -66,10 +66,10 @@ public class CamelService {
public void reloadProjectCode(String projectId) {
LOGGER.info("Reload project code " + projectId);
try {
- ContainerStatus containerStatus = infinispanService.getDevModeContainerStatus(projectId, environment);
infinispanService.getProjectFiles(projectId).forEach(projectFile ->
putRequest(projectId, projectFile.getName(), projectFile.getCode(), 1000));
reloadRequest(projectId);
+ ContainerStatus containerStatus = infinispanService.getDevModeContainerStatus(projectId, environment);
containerStatus.setCodeLoaded(true);
infinispanService.saveContainerStatus(containerStatus);
} catch (Exception ex) {
@@ -106,7 +106,7 @@ public class CamelService {
public void collectCamelStatuses() {
if (infinispanService.isReady()) {
infinispanService.getContainerStatuses(environment).stream()
- .filter(status -> status.getType().equals(ContainerStatus.CType.devmode) || status.getType().equals(ContainerStatus.CType.project))
+ .filter(status -> status.getType().equals(ContainerStatus.ContainerType.devmode) || status.getType().equals(ContainerStatus.ContainerType.project))
.forEach(status -> {
CamelStatusRequest csr = new CamelStatusRequest(status.getProjectId(), status.getContainerName());
eventBus.publish(CMD_COLLECT_CAMEL_STATUS, JsonObject.mapFrom(csr));
diff --git a/karavan-web/karavan-headless/src/main/java/org/apache/camel/karavan/headless/HeadlessService.java b/karavan-web/karavan-headless/src/main/java/org/apache/camel/karavan/headless/HeadlessService.java
index e6f8624f..ba2b805b 100644
--- a/karavan-web/karavan-headless/src/main/java/org/apache/camel/karavan/headless/HeadlessService.java
+++ b/karavan-web/karavan-headless/src/main/java/org/apache/camel/karavan/headless/HeadlessService.java
@@ -39,12 +39,11 @@ public class HeadlessService {
void onStart(@Observes StartupEvent ev) {
LOGGER.info("Starting Headless Karavan");
infinispanService.start(true);
- infinispanService.clearAllStatuses();
}
@Scheduled(every = "{karavan.camel.status.interval}", concurrentExecution = Scheduled.ConcurrentExecution.SKIP)
void collectCamelStatuses() {
- LOGGER.info("Collect info statuses");
+ LOGGER.info("Collect Camel statuses");
// collect Camel statuses
camelService.collectCamelStatuses();
}
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 efd1ee2c..ac905f64 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
@@ -67,6 +67,7 @@ public class InfinispanService {
private RemoteCache<GroupedKey, PipelineStatus> pipelineStatuses;
private RemoteCache<GroupedKey, DeploymentStatus> deploymentStatuses;
private RemoteCache<GroupedKey, ContainerStatus> containerStatuses;
+ private RemoteCache<GroupedKey, Boolean> transits;
private RemoteCache<GroupedKey, ServiceStatus> serviceStatuses;
private RemoteCache<GroupedKey, CamelStatus> camelStatuses;
private RemoteCache<String, String> commits;
@@ -107,6 +108,7 @@ public class InfinispanService {
serviceStatuses = getOrCreateCache(ServiceStatus.CACHE, false);
camelStatuses = getOrCreateCache(CamelStatus.CACHE, false);
commits = getOrCreateCache("commits", false);
+ transits = getOrCreateCache("transits", false);
deploymentStatuses = getOrCreateCache(DeploymentStatus.CACHE, false);
codeReloadCommands = getOrCreateCache("code_reload_commands", true);
@@ -250,6 +252,18 @@ public class InfinispanService {
return new ArrayList<>(serviceStatuses.values());
}
+ public List<Boolean> getTransits() {
+ return new ArrayList<>(transits.values());
+ }
+
+ public Boolean getTransit(String projectId, String env, String containerName) {
+ return transits.get(GroupedKey.create(projectId, env, containerName));
+ }
+
+ public void setTransit(String projectId, String env, String containerName) {
+ transits.put(GroupedKey.create(projectId,env,containerName), true);
+ }
+
public List<ContainerStatus> getContainerStatuses() {
return new ArrayList<>(containerStatuses.values());
}
@@ -262,6 +276,12 @@ public class InfinispanService {
.execute().list();
}
+ public void setContainerStatusTransit(String projectId, String env, String containerName) {
+ ContainerStatus cs = getContainerStatus(projectId, env, containerName);
+ cs.setInTransit(true);
+ saveContainerStatus(cs);
+ }
+
public ContainerStatus getContainerStatus(String projectId, String env, String containerName) {
return containerStatuses.get(GroupedKey.create(projectId, env, containerName));
}
@@ -353,14 +373,14 @@ public class InfinispanService {
public List<ContainerStatus> getLoadedDevModeStatuses() {
QueryFactory queryFactory = Search.getQueryFactory(containerStatuses);
return queryFactory.<ContainerStatus>create("FROM karavan.ContainerStatus WHERE type = :type AND codeLoaded = true")
- .setParameter("type", ContainerStatus.CType.devmode)
+ .setParameter("type", ContainerStatus.ContainerType.devmode)
.execute().list();
}
public List<ContainerStatus> getDevModeStatuses() {
QueryFactory queryFactory = Search.getQueryFactory(containerStatuses);
return queryFactory.<ContainerStatus>create("FROM karavan.ContainerStatus WHERE type = :type")
- .setParameter("type", ContainerStatus.CType.devmode)
+ .setParameter("type", ContainerStatus.ContainerType.devmode)
.execute().list();
}
diff --git a/karavan-web/karavan-infinispan/src/main/java/org/apache/camel/karavan/infinispan/model/ContainerStatus.java b/karavan-web/karavan-infinispan/src/main/java/org/apache/camel/karavan/infinispan/model/ContainerStatus.java
index de1fea4e..ef7ca779 100644
--- a/karavan-web/karavan-infinispan/src/main/java/org/apache/camel/karavan/infinispan/model/ContainerStatus.java
+++ b/karavan-web/karavan-infinispan/src/main/java/org/apache/camel/karavan/infinispan/model/ContainerStatus.java
@@ -9,7 +9,16 @@ import java.util.List;
public class ContainerStatus {
- public enum CType {
+ public enum State {
+ created,
+ running,
+ restarting,
+ paused,
+ exited,
+ dead
+ }
+
+ public enum ContainerType {
@ProtoEnumValue(number = 0, name = "internal") internal,
@ProtoEnumValue(number = 1, name = "devmode") devmode,
@ProtoEnumValue(number = 2, name = "devservice") devservice,
@@ -17,10 +26,11 @@ public class ContainerStatus {
@ProtoEnumValue(number = 5, name = "unknown") unknown,
}
- public enum Lifecycle {
- @ProtoEnumValue(number = 0, name = "init") init,
- @ProtoEnumValue(number = 1, name = "ready") ready,
- @ProtoEnumValue(number = 2, name = "deleting") deleting,
+ public enum Command {
+ @ProtoEnumValue(number = 0, name = "run") run,
+ @ProtoEnumValue(number = 1, name = "pause") pause,
+ @ProtoEnumValue(number = 2, name = "stop") stop,
+ @ProtoEnumValue(number = 3, name = "delete") delete,
}
public static final String CACHE = "container_statuses";
@@ -37,7 +47,7 @@ public class ContainerStatus {
@ProtoField(number = 6)
String env;
@ProtoField(number = 7)
- CType type;
+ ContainerType type;
@ProtoField(number = 8)
String memoryInfo;
@ProtoField(number = 9)
@@ -45,14 +55,16 @@ public class ContainerStatus {
@ProtoField(number = 10)
String created;
@ProtoField(number = 11)
- Lifecycle lifeCycle;
+ List<Command> commands;
@ProtoField(number = 12)
- Boolean codeLoaded;
+ String state;
@ProtoField(number = 13)
- Boolean logging;
+ Boolean codeLoaded;
+ @ProtoField(number = 14)
+ Boolean inTransit = false;
@ProtoFactory
- public ContainerStatus(String projectId, String containerName, String containerId, String image, List<Integer> ports, String env, CType type, String memoryInfo, String cpuInfo, String created, Lifecycle lifeCycle, Boolean codeLoaded, Boolean logging) {
+ public ContainerStatus(String projectId, String containerName, String containerId, String image, List<Integer> ports, String env, ContainerType type, String memoryInfo, String cpuInfo, String created, List<Command> commands, String state, Boolean codeLoaded, Boolean inTransit) {
this.projectId = projectId;
this.containerName = containerName;
this.containerId = containerId;
@@ -63,14 +75,15 @@ public class ContainerStatus {
this.memoryInfo = memoryInfo;
this.cpuInfo = cpuInfo;
this.created = created;
- this.lifeCycle = lifeCycle;
+ this.commands = commands;
+ this.state = state;
this.codeLoaded = codeLoaded;
- this.logging = logging;
+ this.inTransit = inTransit;
}
- public ContainerStatus(String containerName, Lifecycle lifeCycle, String projectId, String env, CType type, String memoryInfo, String cpuInfo, String created) {
+ public ContainerStatus(String containerName, List<Command> commands, String projectId, String env, ContainerType type, String memoryInfo, String cpuInfo, String created) {
this.containerName = containerName;
- this.lifeCycle = lifeCycle;
+ this.commands = commands;
this.projectId = projectId;
this.env = env;
this.type = type;
@@ -79,9 +92,9 @@ public class ContainerStatus {
this.created = created;
}
- public ContainerStatus(String containerName, Lifecycle lifeCycle, String projectId, String env, CType type, String created) {
+ public ContainerStatus(String containerName, List<Command> commands, String projectId, String env, ContainerType type, String created) {
this.containerName = containerName;
- this.lifeCycle = lifeCycle;
+ this.commands = commands;
this.projectId = projectId;
this.env = env;
this.created = created;
@@ -89,17 +102,18 @@ public class ContainerStatus {
}
public static ContainerStatus createDevMode(String projectId, String env) {
- return new ContainerStatus(projectId, projectId, null, null, null, env, CType.devmode, null, null, null, Lifecycle.init, false, false);
+ return new ContainerStatus(projectId, projectId, null, null, null, env, ContainerType.devmode, null, null, null, List.of(Command.run), null, false, false);
}
- public static ContainerStatus createWithId(String name, String env, String containerId, String image, List<Integer> ports, CType type, Lifecycle lifeCycle, String created) {
+ public static ContainerStatus createWithId(String name, String env, String containerId, String image, List<Integer> ports, ContainerType type, List<Command> commands, String status, String created) {
return new ContainerStatus(name, name, containerId, image, ports, env, type,
- null, null, created, lifeCycle, false, false);
+ null, null, created, commands, status, false, false);
}
public ContainerStatus() {
}
+
public String getProjectId() {
return projectId;
}
@@ -148,11 +162,11 @@ public class ContainerStatus {
this.env = env;
}
- public CType getType() {
+ public ContainerType getType() {
return type;
}
- public void setType(CType type) {
+ public void setType(ContainerType type) {
this.type = type;
}
@@ -180,12 +194,20 @@ public class ContainerStatus {
this.created = created;
}
- public Lifecycle getLifeCycle() {
- return lifeCycle;
+ public List<Command> getCommands() {
+ return commands;
}
- public void setLifeCycle(Lifecycle lifeCycle) {
- this.lifeCycle = lifeCycle;
+ public void setCommands(List<Command> commands) {
+ this.commands = commands;
+ }
+
+ public String getState() {
+ return state;
+ }
+
+ public void setState(String state) {
+ this.state = state;
}
public Boolean getCodeLoaded() {
@@ -196,11 +218,31 @@ public class ContainerStatus {
this.codeLoaded = codeLoaded;
}
- public Boolean getLogging() {
- return logging;
- }
-
- public void setLogging(Boolean logging) {
- this.logging = logging;
+ public Boolean getInTransit() {
+ return inTransit;
+ }
+
+ public void setInTransit(Boolean inTransit) {
+ this.inTransit = inTransit;
+ }
+
+ @Override
+ public String toString() {
+ return "ContainerStatus{" +
+ "projectId='" + projectId + '\'' +
+ ", containerName='" + containerName + '\'' +
+ ", containerId='" + containerId + '\'' +
+ ", image='" + image + '\'' +
+ ", ports=" + ports +
+ ", env='" + env + '\'' +
+ ", type=" + type +
+ ", memoryInfo='" + memoryInfo + '\'' +
+ ", cpuInfo='" + cpuInfo + '\'' +
+ ", created='" + created + '\'' +
+ ", commands=" + commands +
+ ", state='" + state + '\'' +
+ ", codeLoaded=" + codeLoaded +
+ ", logging=" + inTransit +
+ '}';
}
}
diff --git a/karavan-web/karavan-infinispan/src/main/java/org/apache/camel/karavan/infinispan/model/KaravanSchema.java b/karavan-web/karavan-infinispan/src/main/java/org/apache/camel/karavan/infinispan/model/KaravanSchema.java
index c20115b3..29731935 100644
--- a/karavan-web/karavan-infinispan/src/main/java/org/apache/camel/karavan/infinispan/model/KaravanSchema.java
+++ b/karavan-web/karavan-infinispan/src/main/java/org/apache/camel/karavan/infinispan/model/KaravanSchema.java
@@ -14,8 +14,8 @@ import org.infinispan.protostream.annotations.AutoProtoSchemaBuilder;
CamelStatus.Name.class,
DeploymentStatus.class,
ContainerStatus.class,
- ContainerStatus.CType.class,
- ContainerStatus.Lifecycle.class,
+ ContainerStatus.ContainerType.class,
+ ContainerStatus.Command.class,
ServiceStatus.class
},
schemaFileName = "karavan.proto",