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:27 UTC

[camel-karavan] 02/02: DevMode 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 c56e125bbe8c959ae197a815128c57d8fc4d5802
Author: Marat Gubaidullin <ma...@gmail.com>
AuthorDate: Tue Jul 25 20:40:13 2023 -0400

    DevMode improvements #817
---
 .../apache/camel/karavan/api/DevModeResource.java  | 15 +++++---
 .../camel/karavan/docker/DockerEventListener.java  |  5 ++-
 .../apache/camel/karavan/docker/DockerService.java | 42 +++++++++++++---------
 .../karavan/kubernetes/KubernetesService.java      | 24 +++++++------
 .../camel/karavan/kubernetes/PodEventHandler.java  |  9 ++---
 .../apache/camel/karavan/service/AuthService.java  |  1 -
 .../apache/camel/karavan/service/EventService.java |  4 +--
 .../apache/camel/karavan/shared/Configuration.java | 16 +++++++++
 .../AuthService.java => shared/Constants.java}     | 23 +++---------
 .../org/apache/camel/karavan/shared/EventType.java | 16 +++++++++
 .../src/main/webui/src/api/ProjectService.ts       | 24 ++++++-------
 .../webui/src/containers/ContainerTableRow.tsx     |  2 +-
 .../src/main/webui/src/project/DevModeToolbar.tsx  | 21 ++++++-----
 .../src/main/webui/src/project/ProjectToolbar.tsx  |  1 -
 .../webui/src/project/pipeline/ProjectStatus.tsx   |  3 --
 15 files changed, 117 insertions(+), 89 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 6379b058..d6d647c9 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
@@ -16,6 +16,8 @@
  */
 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.DockerService;
 import org.apache.camel.karavan.infinispan.InfinispanService;
 import org.apache.camel.karavan.infinispan.model.CamelStatus;
@@ -24,6 +26,7 @@ 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.shared.ConfigService;
+import org.apache.camel.karavan.shared.EventType;
 import org.eclipse.microprofile.config.inject.ConfigProperty;
 
 import javax.inject.Inject;
@@ -31,7 +34,6 @@ 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")
 public class DevModeResource {
@@ -51,6 +53,9 @@ public class DevModeResource {
     @Inject
     DockerService dockerService;
 
+    @Inject
+    EventBus eventBus;
+
     @POST
     @Produces(MediaType.APPLICATION_JSON)
     @Consumes(MediaType.APPLICATION_JSON)
@@ -64,12 +69,12 @@ public class DevModeResource {
 
         if (!Objects.equals(status.getState(), ContainerStatus.State.running.name())){
             status.setInTransit(true);
-            infinispanService.saveContainerStatus(status);
+            eventBus.send(EventType.CONTAINER_STATUS, JsonObject.mapFrom(status));
 
             if (ConfigService.inKubernetes()) {
-                kubernetesService.runDevModeContainer(project, "");
+                kubernetesService.runDevModeContainer(project, jBangOptions);
             } else {
-                dockerService.runDevmodeContainer(project, "");
+                dockerService.runDevmodeContainer(project, jBangOptions);
             }
             return Response.ok(containerName).build();
         }
@@ -102,7 +107,7 @@ public class DevModeResource {
     public Response deleteDevMode(@PathParam("projectId") String projectId, @PathParam("deletePVC") boolean deletePVC) {
         infinispanService.setContainerStatusTransit(projectId, environment, projectId);
         if (ConfigService.inKubernetes()) {
-            kubernetesService.deleteRunner(projectId, deletePVC);
+            kubernetesService.deleteDevModePod(projectId, deletePVC);
         } else {
             dockerService.deleteContainer(projectId);
         }
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 86c40428..34a2905f 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
@@ -6,7 +6,6 @@ import com.github.dockerjava.api.model.ContainerPort;
 import com.github.dockerjava.api.model.Event;
 import com.github.dockerjava.api.model.EventType;
 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.eclipse.microprofile.config.inject.ConfigProperty;
@@ -20,8 +19,8 @@ import java.time.Instant;
 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.Constants.LABEL_PROJECT_ID;
+import static org.apache.camel.karavan.shared.Constants.LABEL_TYPE;
 import static org.apache.camel.karavan.shared.EventType.DEVMODE_CONTAINER_READY;
 import static org.apache.camel.karavan.shared.EventType.INFINISPAN_STARTED;
 
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 84178d09..b7a6fa5e 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
@@ -1,3 +1,19 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.apache.camel.karavan.docker;
 
 import com.github.dockerjava.api.DockerClient;
@@ -29,6 +45,7 @@ import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.stream.Collectors;
 
+import static org.apache.camel.karavan.shared.Constants.*;
 import static org.apache.camel.karavan.shared.EventType.*;
 
 @ApplicationScoped
@@ -36,12 +53,10 @@ public class DockerService {
 
     private static final Logger LOGGER = Logger.getLogger(DockerService.class.getName());
 
-    public static final String INFINISPAN_CONTAINER_NAME = "infinispan";
-    public static final String KARAVAN_CONTAINER_NAME = "karavan-headless";
+    protected static final String INFINISPAN_CONTAINER_NAME = "infinispan";
+    protected static final String KARAVAN_CONTAINER_NAME = "karavan-headless";
 
-    public static final String NETWORK_NAME = "karavan";
-    public static final String LABEL_TYPE = "org.apache.camel.karavan.type";
-    public static final String LABEL_PROJECT_ID = "org.apache.camel.karavan.projectId";
+    protected static final String NETWORK_NAME = "karavan";
     private static final DecimalFormat formatCpu = new DecimalFormat("0.00");
     private static final DecimalFormat formatMiB = new DecimalFormat("0.0");
     private static final DecimalFormat formatGiB = new DecimalFormat("0.00");
@@ -59,8 +74,6 @@ public class DockerService {
 
     @ConfigProperty(name = "infinispan.image")
     String infinispanImage;
-    @ConfigProperty(name = "infinispan.hosts")
-    String infinispanHosts;
     @ConfigProperty(name = "infinispan.port")
     String infinispanPort;
     @ConfigProperty(name = "infinispan.username")
@@ -71,9 +84,6 @@ public class DockerService {
     @Inject
     DockerEventListener dockerEventListener;
 
-    @Inject
-    InfinispanService infinispanService;
-
     @Inject
     EventBus eventBus;
 
@@ -81,13 +91,17 @@ public class DockerService {
 
     public void runDevmodeContainer(Project project, String jBangOptions) throws InterruptedException {
         String projectId = project.getProjectId();
-        LOGGER.infof("DevMode starting for %s", projectId);
+        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"))
                 .withInterval(10000000000L).withTimeout(10000000000L).withStartPeriod(10000000000L).withRetries(30);
 
+        List<String> env = jBangOptions !=null && !jBangOptions.trim().isEmpty()
+                ? List.of(ENV_VAR_JBANG_OPTIONS + "=" + jBangOptions)
+                : List.of();
+
         createContainer(projectId, devmodeImage,
-                List.of(), null, false, false, healthCheck,
+                env, null, false, false, healthCheck,
                 Map.of(LABEL_TYPE, ContainerStatus.ContainerType.devmode.name(), LABEL_PROJECT_ID, projectId));
 
         startContainer(projectId);
@@ -298,14 +312,10 @@ 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()).withForce(true).exec();
-            System.out.println("removeContainerCmd " + (System.currentTimeMillis() - time));
         }
     }
 
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 3be6850a..1e83cac7 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
@@ -29,6 +29,7 @@ import io.fabric8.tekton.client.DefaultTektonClient;
 import io.fabric8.tekton.pipeline.v1beta1.*;
 import io.vertx.mutiny.core.eventbus.EventBus;
 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.apache.camel.karavan.infinispan.model.ProjectFile;
 import org.apache.camel.karavan.service.CodeService;
@@ -47,6 +48,7 @@ import java.util.*;
 import java.util.stream.Collectors;
 
 import static org.apache.camel.karavan.service.CodeService.APPLICATION_PROPERTIES_FILENAME;
+import static org.apache.camel.karavan.shared.Constants.*;
 
 @Default
 @Readiness
@@ -54,12 +56,12 @@ import static org.apache.camel.karavan.service.CodeService.APPLICATION_PROPERTIE
 public class KubernetesService implements HealthCheck {
 
     private static final Logger LOGGER = Logger.getLogger(KubernetesService.class.getName());
-    public static final int INFORMERS = 4;
+    protected static final int INFORMERS = 4;
     private static final String CAMEL_PREFIX = "camel";
     private static final String KARAVAN_PREFIX = "karavan";
     private static final String JBANG_CACHE_SUFFIX = "jbang-cache";
     private static final String M2_CACHE_SUFFIX = "m2-cache";
-    public static final String PVC_MAVEN_SETTINGS = "maven-settings";
+    protected static final String PVC_MAVEN_SETTINGS = "maven-settings";
 
     @Inject
     EventBus eventBus;
@@ -400,9 +402,9 @@ public class KubernetesService implements HealthCheck {
         createService(name);
     }
 
-    public void deleteRunner(String name, boolean deletePVC) {
+    public void deleteDevModePod(String name, boolean deletePVC) {
         try {
-            LOGGER.info("Delete runner: " + name + " in the namespace: " + getNamespace());
+            LOGGER.info("Delete devmode pod: " + name + " in the namespace: " + getNamespace());
             kubernetesClient().pods().inNamespace(getNamespace()).withName(name).delete();
             kubernetesClient().services().inNamespace(getNamespace()).withName(name).delete();
             if (deletePVC) {
@@ -426,7 +428,7 @@ public class KubernetesService implements HealthCheck {
         Map<String, String> labels = new HashMap<>();
         labels.putAll(getRuntimeLabels());
         labels.putAll(getKaravanRunnerLabels(name));
-        labels.put("karavan/projectId", projectId);
+        labels.put(LABEL_PROJECT_ID, projectId);
 
         ResourceRequirements resources = getResourceRequirements(containerResources);
 
@@ -448,7 +450,7 @@ public class KubernetesService implements HealthCheck {
                 .withPorts(port)
                 .withResources(resources)
                 .withImagePullPolicy("Always")
-                .withEnv(new EnvVarBuilder().withName("JBANG_OPTIONS").withValue(jbangOptions).build())
+                .withEnv(new EnvVarBuilder().withName(ENV_VAR_JBANG_OPTIONS).withValue(jbangOptions).build())
                 .withVolumeMounts(
                         new VolumeMountBuilder().withName(name).withMountPath("/karavan/.jbang/cache").build(),
                         new VolumeMountBuilder().withName("maven-settings").withSubPath("maven-settings.xml")
@@ -473,14 +475,14 @@ public class KubernetesService implements HealthCheck {
                 .build();
     }
 
-    private void createPVC(String runnerName) {
-        PersistentVolumeClaim old = kubernetesClient().persistentVolumeClaims().inNamespace(getNamespace()).withName(runnerName).get();
+    private void createPVC(String podName) {
+        PersistentVolumeClaim old = kubernetesClient().persistentVolumeClaims().inNamespace(getNamespace()).withName(podName).get();
         if (old == null) {
             PersistentVolumeClaim pvc = new PersistentVolumeClaimBuilder()
                     .withNewMetadata()
-                    .withName(runnerName)
+                    .withName(podName)
                     .withNamespace(getNamespace())
-                    .withLabels(getKaravanRunnerLabels(runnerName))
+                    .withLabels(getKaravanRunnerLabels(podName))
                     .endMetadata()
                     .withNewSpec()
                     .withResources(new ResourceRequirementsBuilder().withRequests(Map.of("storage", new Quantity("2Gi"))).build())
@@ -533,7 +535,7 @@ public class KubernetesService implements HealthCheck {
     }
 
     public static Map<String, String> getKaravanRunnerLabels(String name) {
-        return Map.of("karavan/type", "runner",
+        return Map.of(LABEL_TYPE, ContainerStatus.ContainerType.devmode.name(),
                 "app.kubernetes.io/name", name);
     }
 
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 b46af28c..5d9417ac 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
@@ -14,6 +14,7 @@ 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.Constants.LABEL_PROJECT_ID;
 import static org.apache.camel.karavan.shared.EventType.CONTAINER_STATUS;
 
 public class PodEventHandler implements ResourceEventHandler<Pod> {
@@ -60,7 +61,7 @@ public class PodEventHandler implements ResourceEventHandler<Pod> {
         try {
             LOGGER.info("onDelete " + pod.getMetadata().getName());
             String deployment = pod.getMetadata().getLabels().get("app");
-            String projectId = deployment != null ? deployment : pod.getMetadata().getLabels().get("karavan/projectId");
+            String projectId = deployment != null ? deployment : pod.getMetadata().getLabels().get(LABEL_PROJECT_ID);
             infinispanService.deleteContainerStatus(projectId, kubernetesService.environment, pod.getMetadata().getName());
         } catch (Exception e){
             LOGGER.error(e.getMessage(), e.getCause());
@@ -70,7 +71,7 @@ public class PodEventHandler implements ResourceEventHandler<Pod> {
 
     public ContainerStatus getPodStatus(Pod pod) {
         String deployment = pod.getMetadata().getLabels().get("app");
-        String projectId = deployment != null ? deployment : pod.getMetadata().getLabels().get("karavan/projectId");
+        String projectId = deployment != null ? deployment : pod.getMetadata().getLabels().get(LABEL_PROJECT_ID);
         try {
             boolean ready = pod.getStatus().getConditions().stream().anyMatch(c -> c.getType().equals("Ready"));
             String creationTimestamp = pod.getMetadata().getCreationTimestamp();
@@ -89,8 +90,8 @@ public class PodEventHandler implements ResourceEventHandler<Pod> {
                     projectId,
                     kubernetesService.environment,
                     pod.getMetadata().getName().equals(projectId) ? ContainerStatus.ContainerType.devmode : ContainerStatus.ContainerType.project,
-                    requestMemory + " : " + limitMemory,
-                    requestCpu + " : " + limitCpu,
+                    requestMemory + " / " + limitMemory,
+                    requestCpu + " / " + limitCpu,
                     creationTimestamp);
 
             if (ready) {
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/AuthService.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/AuthService.java
index bcd8f90f..e3b489fe 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/AuthService.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/AuthService.java
@@ -16,7 +16,6 @@
  */
 package org.apache.camel.karavan.service;
 
-import io.vertx.core.Vertx;
 import org.eclipse.microprofile.config.ConfigProvider;
 import org.jboss.logging.Logger;
 
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 f3e011f4..ea858d05 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
@@ -78,7 +78,8 @@ public class EventService {
     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())) {
+        System.out.println(status);
+        if (status != null && !status.getCodeLoaded() && status.getContainerId() != null && status.getState().equals(ContainerStatus.State.running.name())) {
             if (ConfigService.inKubernetes()) {
                 camelService.reloadProjectCode(projectId);
             } else {
@@ -91,7 +92,6 @@ public class EventService {
     public void saveContainerStatus(JsonObject data) {
         if (infinispanService.isReady()) {
             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);
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/shared/Configuration.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/shared/Configuration.java
index 2e39bbb0..6ccabdf9 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/shared/Configuration.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/shared/Configuration.java
@@ -1,3 +1,19 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.apache.camel.karavan.shared;
 
 import java.util.List;
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/AuthService.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/shared/Constants.java
similarity index 52%
copy from karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/AuthService.java
copy to karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/shared/Constants.java
index bcd8f90f..07834b3b 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/AuthService.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/shared/Constants.java
@@ -14,26 +14,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.karavan.service;
+package org.apache.camel.karavan.shared;
 
-import io.vertx.core.Vertx;
-import org.eclipse.microprofile.config.ConfigProvider;
-import org.jboss.logging.Logger;
+public class Constants {
 
-import javax.enterprise.context.ApplicationScoped;
-import java.net.MalformedURLException;
-import java.util.Map;
+    public static final String ENV_VAR_JBANG_OPTIONS = "JBANG_OPTIONS";
 
-@ApplicationScoped
-public class AuthService {
+    public static final String LABEL_TYPE = "org.apache.camel.karavan/type";
+    public static final String LABEL_PROJECT_ID = "org.apache.camel.karavan/projectId";
 
-    private static final Logger LOGGER = Logger.getLogger(AuthService.class.getName());
-
-    public String authType() {
-        return ConfigProvider.getConfig().getValue("karavan.auth", String.class);
-    }
-
-    public Map<String, String> getSsoConfig() throws MalformedURLException {
-        return Map.of("url", ConfigProvider.getConfig().getValue("karavan.frontend.auth-server-url", String.class));
-    }
 }
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 a1085fb9..3a375e41 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
@@ -1,3 +1,19 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.apache.camel.karavan.shared;
 
 public class EventType {
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 28f6cf2b..8b043d61 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
@@ -17,10 +17,10 @@ export class ProjectService {
     public static startDevModeContainer(project: Project, verbose: boolean) {
         useDevModeStore.setState({status: "wip"})
         KaravanApi.startDevModeContainer(project, verbose, res => {
+            useDevModeStore.setState({status: "none"})
             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
             }
@@ -30,19 +30,20 @@ export class ProjectService {
     public static reloadDevModeCode(project: Project) {
         useDevModeStore.setState({status: "wip"})
         KaravanApi.reloadDevModeCode(project.projectId, res => {
+            useDevModeStore.setState({status: "none"})
             if (res.status === 200 || res.status === 201) {
                 // setIsReloadingPod(false);
             } else {
                 // Todo notification
                 // setIsReloadingPod(false);
             }
-            useDevModeStore.setState({status: "none"})
         });
     }
 
     public static stopDevModeContainer(project: Project) {
         useDevModeStore.setState({status: "wip"})
         KaravanApi.manageContainer("dev", project.projectId, 'stop', res => {
+            useDevModeStore.setState({status: "none"})
             if (res.status === 200) {
                 useLogStore.setState({showLog: false, type: 'container', isRunning: false})
             } else {
@@ -54,6 +55,7 @@ export class ProjectService {
     public static pauseDevModeContainer(project: Project) {
         useDevModeStore.setState({status: "wip"})
         KaravanApi.manageContainer("dev", project.projectId, 'pause', res => {
+            useDevModeStore.setState({status: "none"})
             if (res.status === 200) {
                 useLogStore.setState({showLog: false, type: 'container', isRunning: false})
             } else {
@@ -66,12 +68,12 @@ export class ProjectService {
         useDevModeStore.setState({status: "wip"})
         ProjectEventBus.sendLog("set", '');
         KaravanApi.deleteDevModeContainer(project.projectId, false, res => {
+            useDevModeStore.setState({status: "none"})
             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"})
         });
     }
 
@@ -80,22 +82,19 @@ export class ProjectService {
         KaravanApi.getDevModePodStatus(projectId, res => {
             if (res.status === 200) {
                 unstable_batchedUpdates(() => {
-                    const podStatus = res.data;
-                    if (useDevModeStore.getState().podName !== podStatus.containerName){
-                        useDevModeStore.setState({podName: podStatus.containerName})
+                    const containerStatus = res.data;
+                    if (useDevModeStore.getState().podName !== containerStatus.containerName){
+                        useDevModeStore.setState({podName: containerStatus.containerName})
                     }
                     if (useDevModeStore.getState().status !== "wip"){
-                        useDevModeStore.setState({status: "wip"})
                         useLogStore.setState({isRunning: true})
                     }
-                    useProjectStore.setState({containerStatus: res.data});
+                    useProjectStore.setState({containerStatus: containerStatus});
                 })
             } else {
                 unstable_batchedUpdates(() => {
-                    if (useDevModeStore.getState().status !== 'none') {
-                        useDevModeStore.setState({status: "none", podName: undefined})
-                        useProjectStore.setState({containerStatus: new ContainerStatus()});
-                    }
+                    useDevModeStore.setState({status: "none", podName: undefined})
+                    useProjectStore.setState({containerStatus: new ContainerStatus({})});
                 })
             }
         });
@@ -178,7 +177,6 @@ export class ProjectService {
 
     public static createProject(project: Project) {
         KaravanApi.postProject(project, res => {
-            console.log(res.status)
             if (res.status === 200 || res.status === 201) {
                 ProjectService.refreshProjectData();
                 // this.props.toast?.call(this, "Success", "Project created", "success");
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 660c2f0d..13d702d2 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
@@ -57,7 +57,7 @@ export const ContainerTableRow = (props: Props) => {
                 </Td>
                 <Td>
                     {!inTransit && <Label color={color}>{container.state}</Label>}
-                    {inTransit && <Spinner isSVG size="md" aria-label="spinner"/>}
+                    {inTransit && <Spinner isSVG size="lg" aria-label="spinner"/>}
                 </Td>
                 <Td className="project-action-buttons">
                     {container.type !== 'internal' &&
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 510372e5..58dae7ea 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
@@ -1,5 +1,5 @@
 import React, {useState} from 'react';
-import {Button, Flex, FlexItem, Label, Switch, Tooltip, TooltipPosition} from '@patternfly/react-core';
+import {Button, Flex, FlexItem, Label, Spinner, Switch, Tooltip, TooltipPosition} from '@patternfly/react-core';
 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";
@@ -23,13 +23,16 @@ export const DevModeToolbar = (props: Props) => {
     const [verbose, setVerbose] = useState(false);
 
     const commands = containerStatus.commands;
-    const ports = containerStatus.ports;
     const isRunning = containerStatus.state === 'running';
     const inTransit = containerStatus.inTransit;
+    const isLoading= status === 'wip';
     const color = containerStatus.state === 'running' ? "green" : "grey";
     const icon = isRunning ? <UpIcon/> : <DownIcon/>;
     return (<Flex className="toolbar" direction={{default: "row"}} alignItems={{default: "alignItemsCenter"}}>
-        {<FlexItem>
+        <FlexItem>
+            {(inTransit || isLoading) && <Spinner isSVG size="lg" aria-label="spinner"/>}
+        </FlexItem>
+        {containerStatus.containerId && <FlexItem>
             <Label icon={icon} color={color}>
                 <Tooltip content={"Show log"} position={TooltipPosition.bottom}>
                     <Button variant="link"
@@ -51,8 +54,7 @@ export const DevModeToolbar = (props: Props) => {
         </FlexItem>
         {!isRunning && <FlexItem>
             <Tooltip content="Run in developer mode" position={TooltipPosition.bottom}>
-                <Button isLoading={status === 'wip'}
-                        isSmall
+                <Button isSmall
                         isDisabled={(!(commands.length === 0) && !commands.includes('run')) || inTransit}
                         variant={"primary"}
                         icon={<RocketIcon/>}
@@ -63,8 +65,7 @@ export const DevModeToolbar = (props: Props) => {
         </FlexItem>}
         {isRunning && <FlexItem>
             <Tooltip content="Reload" position={TooltipPosition.bottom}>
-                <Button isLoading={status === 'wip'}
-                        isSmall
+                <Button isSmall
                         isDisabled={inTransit}
                         variant={"primary"}
                         className="project-button"
@@ -75,8 +76,7 @@ export const DevModeToolbar = (props: Props) => {
         </FlexItem>}
         {<FlexItem>
             <Tooltip content="Stop container" position={TooltipPosition.bottom}>
-                <Button isLoading={status === 'wip'}
-                        isSmall
+                <Button isSmall
                         isDisabled={!commands.includes('stop') || inTransit}
                         variant={"control"}
                         icon={<StopIcon/>}
@@ -86,8 +86,7 @@ export const DevModeToolbar = (props: Props) => {
         </FlexItem>}
         {<FlexItem>
             <Tooltip content="Delete container" position={TooltipPosition.bottom}>
-                <Button isLoading={status === 'wip'}
-                        isSmall
+                <Button isSmall
                         isDisabled={!commands.includes('delete') || inTransit}
                         variant={"control"}
                         icon={<DeleteIcon/>}
diff --git a/karavan-web/karavan-app/src/main/webui/src/project/ProjectToolbar.tsx b/karavan-web/karavan-app/src/main/webui/src/project/ProjectToolbar.tsx
index 2f639228..daed745b 100644
--- a/karavan-web/karavan-app/src/main/webui/src/project/ProjectToolbar.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/project/ProjectToolbar.tsx
@@ -34,7 +34,6 @@ export const ProjectToolbar = (props: Props) => {
         [state.file, state.editAdvancedProperties, state.setEditAdvancedProperties, state.setAddProperty], shallow )
 
     useEffect(() => {
-        console.log("ProjectToolbar useEffect", isPushing, project.lastCommitTimestamp);
     }, [project, file]);
 
     function isFile(): boolean {
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 f32d070e..add844b9 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
@@ -65,15 +65,12 @@ export class ProjectStatus extends React.Component<Props, State> {
             });
             KaravanApi.getProjectDeploymentStatus(projectId, env, (status?: DeploymentStatus) => {
                 this.setState({deploymentStatus: status});
-                // console.log(status);
             });
             KaravanApi.getProjectPodStatuses(projectId, env, (statuses: ContainerStatus[]) => {
                 this.setState({podStatuses: statuses});
-                // console.log(status);
             });
             KaravanApi.getProjectCamelStatus(projectId, env, (status: CamelStatus) => {
                 this.setState({camelStatus: status});
-                // console.log(status);
             });
         }
     }