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/08/10 20:35:10 UTC

[camel-karavan] 03/03: Implements in Kubernetes #839

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 1d2d77cd1a8331fb617a84e9cbd435bca7529441
Author: Marat Gubaidullin <ma...@gmail.com>
AuthorDate: Thu Aug 10 16:33:33 2023 -0400

    Implements in Kubernetes #839
---
 .../camel/karavan/kubernetes/PodEventHandler.java  | 22 +++++++++++++---
 .../apache/camel/karavan/service/CamelService.java | 14 +++++++++-
 .../apache/camel/karavan/service/EventService.java |  2 +-
 .../apache/camel/karavan/service/GitService.java   | 18 ++++++-------
 .../camel/karavan/service/ScheduledService.java    |  2 +-
 .../camel-main-docker-application.properties       |  3 +++
 .../camel-main-kubernetes-application.properties   | 14 ++++++++--
 .../camel-main-openshift-application.properties    | 13 ++++++++--
 .../src/main/webui/src/api/ProjectModels.ts        |  1 -
 .../src/main/webui/src/api/ProjectStore.ts         |  6 +++++
 .../src/main/webui/src/dashboard/DashboardPage.tsx |  2 +-
 .../webui/src/designer/route/DslConnections.tsx    |  4 +--
 .../webui/src/designer/route/DslProperties.tsx     | 13 +++++++---
 .../main/webui/src/designer/route/DslSelector.tsx  |  3 ++-
 .../src/main/webui/src/designer/utils/CamelUi.tsx  |  1 -
 .../src/main/webui/src/project/DevModeToolbar.tsx  | 30 ++++++++++++----------
 .../src/main/webui/src/project/ProjectPage.tsx     | 12 ++-------
 .../src/main/webui/src/project/ProjectToolbar.tsx  | 16 +++++-------
 .../src/main/webui/src/project/file/FileEditor.tsx | 16 ++++--------
 .../webui/src/project/pipeline/ProjectStatus.tsx   |  4 +--
 .../src/main/webui/src/project/trace/TraceTab.tsx  |  1 -
 ....sh => camel-main-builder-script-kubernetes.sh} | 11 ++++----
 ...t.sh => camel-main-builder-script-openshift.sh} | 11 ++++----
 .../resources/quarkus-builder-script-kubernetes.sh |  2 +-
 .../resources/quarkus-builder-script-openshift.sh  |  2 +-
 .../spring-boot-builder-script-kubernetes.sh       |  2 +-
 .../spring-boot-builder-script-openshift.sh        |  2 +-
 27 files changed, 135 insertions(+), 92 deletions(-)

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 5d9417ac..3a684ef9 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
@@ -12,10 +12,14 @@ import org.apache.camel.karavan.infinispan.model.ContainerStatus;
 import org.jboss.logging.Logger;
 
 import java.util.List;
+import java.util.Map;
+import java.util.Objects;
 
 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.Constants.RELOAD_TRY_COUNT;
 import static org.apache.camel.karavan.shared.EventType.CONTAINER_STATUS;
+import static org.apache.camel.karavan.shared.EventType.DEVMODE_CONTAINER_READY;
 
 public class PodEventHandler implements ResourceEventHandler<Pod> {
 
@@ -47,9 +51,18 @@ public class PodEventHandler implements ResourceEventHandler<Pod> {
     public void onUpdate(Pod oldPod, Pod newPod) {
         try {
             LOGGER.info("onUpdate " + newPod.getMetadata().getName());
-            ContainerStatus ps = getPodStatus(newPod);
-            if (ps != null) {
-                eventBus.send(CONTAINER_STATUS, JsonObject.mapFrom(ps));
+            if (!newPod.isMarkedForDeletion() && newPod.getMetadata().getDeletionTimestamp() == null) {
+                ContainerStatus ps = getPodStatus(newPod);
+                if (ps != null) {
+                    eventBus.send(CONTAINER_STATUS, JsonObject.mapFrom(ps));
+                    if (Objects.equals(ps.getState(), ContainerStatus.State.running.name())) {
+                        Map<String, Object> message = Map.of(
+                                LABEL_PROJECT_ID, ps.getProjectId(),
+                                RELOAD_TRY_COUNT, 1
+                        );
+                        eventBus.publish(DEVMODE_CONTAINER_READY, JsonObject.mapFrom(message));
+                    }
+                }
             }
         } catch (Exception e){
             LOGGER.error(e.getMessage(), e.getCause());
@@ -63,6 +76,7 @@ public class PodEventHandler implements ResourceEventHandler<Pod> {
             String deployment = pod.getMetadata().getLabels().get("app");
             String projectId = deployment != null ? deployment : pod.getMetadata().getLabels().get(LABEL_PROJECT_ID);
             infinispanService.deleteContainerStatus(projectId, kubernetesService.environment, pod.getMetadata().getName());
+            infinispanService.deleteCamelStatuses(projectId, kubernetesService.environment);
         } catch (Exception e){
             LOGGER.error(e.getMessage(), e.getCause());
         }
@@ -93,7 +107,7 @@ public class PodEventHandler implements ResourceEventHandler<Pod> {
                     requestMemory + " / " + limitMemory,
                     requestCpu + " / " + limitCpu,
                     creationTimestamp);
-
+            status.setContainerId(pod.getMetadata().getName());
             if (ready) {
                 status.setState(ContainerStatus.State.running.name());
             } else {
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 d3f06f5d..e76fcb30 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
@@ -34,10 +34,14 @@ import org.jboss.logging.Logger;
 import jakarta.enterprise.context.ApplicationScoped;
 import jakarta.inject.Inject;
 import java.util.Arrays;
+import java.util.Map;
 import java.util.Objects;
 import java.util.concurrent.ExecutionException;
 
+import static org.apache.camel.karavan.shared.Constants.LABEL_PROJECT_ID;
+import static org.apache.camel.karavan.shared.Constants.RELOAD_TRY_COUNT;
 import static org.apache.camel.karavan.shared.EventType.CONTAINER_STATUS;
+import static org.apache.camel.karavan.shared.EventType.DEVMODE_CONTAINER_READY;
 
 @ApplicationScoped
 public class CamelService {
@@ -123,11 +127,19 @@ public class CamelService {
     @ConsumeEvent(value = CMD_COLLECT_CAMEL_STATUS, blocking = true, ordered = true)
     public void collectCamelStatuses(JsonObject data) {
         CamelStatusRequest dms = data.mapTo(CamelStatusRequest.class);
+        String projectId = dms.getProjectId();
+        if (infinispanService.getCamelStatus(projectId, environment, CamelStatus.Name.context.name()) == null) {
+            Map<String, Object> message = Map.of(
+                    LABEL_PROJECT_ID, projectId,
+                    RELOAD_TRY_COUNT, 1
+            );
+            eventBus.publish(DEVMODE_CONTAINER_READY, JsonObject.mapFrom(message));
+        }
         Arrays.stream(CamelStatus.Name.values()).forEach(statusName -> {
             String containerName = dms.getContainerName();
             String status = getCamelStatus(containerName, statusName);
             if (status != null) {
-                CamelStatus cs = new CamelStatus(dms.getProjectId(), containerName, statusName, status, environment);
+                CamelStatus cs = new CamelStatus(projectId, containerName, statusName, status, environment);
                 infinispanService.saveCamelStatus(cs);
             }
         });
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 26fabfb2..03da9dce 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
@@ -86,7 +86,7 @@ public class EventService {
         ContainerStatus status = infinispanService.getContainerStatus(projectId, environment, projectId);
         CamelStatus cs = infinispanService.getCamelStatus(projectId, environment, CamelStatus.Name.context.name());
         if (status != null
-                && !status.getCodeLoaded()
+                && !Objects.equals(status.getCodeLoaded(), Boolean.TRUE)
                 && status.getContainerId() != null
                 && status.getState().equals(ContainerStatus.State.running.name())
                 && camelIsStarted(cs)) {
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/GitService.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/GitService.java
index d7d85a13..2ce35d23 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/GitService.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/GitService.java
@@ -132,21 +132,21 @@ public class GitService {
 
     public GitConfig getGitConfig() {
         String propertiesPrefix = "karavan.";
-        String branch = ConfigProvider.getConfig().getValue(propertiesPrefix + "git.branch", String.class);
+        String branch = ConfigProvider.getConfig().getValue(propertiesPrefix + "git-branch", String.class);
         if (ConfigService.inKubernetes()) {
             LOGGER.info("inKubernetes " + kubernetesService.getNamespace());
             Secret secret = kubernetesService.getKaravanSecret();
-            String uri = new String(Base64.getDecoder().decode(secret.getData().get("git.repository").getBytes(StandardCharsets.UTF_8)));
-            String username = new String(Base64.getDecoder().decode(secret.getData().get("git.username").getBytes(StandardCharsets.UTF_8)));
-            String password = new String(Base64.getDecoder().decode(secret.getData().get("git.password").getBytes(StandardCharsets.UTF_8)));
-            if (secret.getData().containsKey("git.branch")) {
-                branch = new String(Base64.getDecoder().decode(secret.getData().get("git.branch").getBytes(StandardCharsets.UTF_8)));
+            String uri = new String(Base64.getDecoder().decode(secret.getData().get("git-repository").getBytes(StandardCharsets.UTF_8)));
+            String username = new String(Base64.getDecoder().decode(secret.getData().get("git-username").getBytes(StandardCharsets.UTF_8)));
+            String password = new String(Base64.getDecoder().decode(secret.getData().get("git-password").getBytes(StandardCharsets.UTF_8)));
+            if (secret.getData().containsKey("git-branch")) {
+                branch = new String(Base64.getDecoder().decode(secret.getData().get("git-branch").getBytes(StandardCharsets.UTF_8)));
             }
             return new GitConfig(uri, username, password, branch);
         } else {
-            String uri = ConfigProvider.getConfig().getValue(propertiesPrefix + "git.repository", String.class);
-            String username = ConfigProvider.getConfig().getValue(propertiesPrefix + "git.username", String.class);
-            String password = ConfigProvider.getConfig().getValue(propertiesPrefix + "git.password", String.class);
+            String uri = ConfigProvider.getConfig().getValue(propertiesPrefix + "git-repository", String.class);
+            String username = ConfigProvider.getConfig().getValue(propertiesPrefix + "git-username", String.class);
+            String password = ConfigProvider.getConfig().getValue(propertiesPrefix + "git-password", String.class);
             return new GitConfig(uri, username, password, branch);
         }
     }
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 296f9fbe..10108b2d 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
@@ -92,7 +92,7 @@ public class ScheduledService {
         }
     }
 
-    @Scheduled(every = "{karavan.git.pull.interval}", concurrentExecution = Scheduled.ConcurrentExecution.SKIP)
+    @Scheduled(every = "{karavan.git-pull-interval}", concurrentExecution = Scheduled.ConcurrentExecution.SKIP)
     void pullCommitsFromGit() {
         projectService.pullCommits();
     }
diff --git a/karavan-web/karavan-app/src/main/resources/snippets/camel-main-docker-application.properties b/karavan-web/karavan-app/src/main/resources/snippets/camel-main-docker-application.properties
index c446e92d..acceb597 100644
--- a/karavan-web/karavan-app/src/main/resources/snippets/camel-main-docker-application.properties
+++ b/karavan-web/karavan-app/src/main/resources/snippets/camel-main-docker-application.properties
@@ -7,3 +7,6 @@ camel.jbang.version=4.0.0-RC2
 camel.jbang.dependencies=camel-console,camel-platform-http-main
 camel.health.enabled=true
 camel.health.exposure-level=full
+camel.server.enabled=true
+camel.server.healthCheckEnabled=true
+camel.server.devConsoleEnabled=true
diff --git a/karavan-web/karavan-app/src/main/resources/snippets/camel-main-kubernetes-application.properties b/karavan-web/karavan-app/src/main/resources/snippets/camel-main-kubernetes-application.properties
index 26fff7c6..6f6a9a91 100644
--- a/karavan-web/karavan-app/src/main/resources/snippets/camel-main-kubernetes-application.properties
+++ b/karavan-web/karavan-app/src/main/resources/snippets/camel-main-kubernetes-application.properties
@@ -7,8 +7,18 @@ camel.jbang.version=4.0.0-RC2
 camel.jbang.dependencies=camel-console,camel-platform-http-main
 camel.health.enabled=true
 camel.health.exposure-level=full
+camel.server.enabled=true
+camel.server.healthCheckEnabled=true
+camel.server.devConsoleEnabled=true
+label.runtime=app.kubernetes.io/runtime
+jib.from.image=gcr.io/distroless/java17@sha256:3a4ea21bd7b412b8b6ae61313b39337d8f03bb6844013810e8e4625d8c765edb
 jkube.version=1.13.1
-jkube.build.strategy=jib
+jkube.skip.build=true
+jkube.namespace=default
 jkube.imagePullPolicy=IfNotPresent
+jkube.enricher.jkube-controller.type=Deployment
 jkube.enricher.jkube-controller.replicaCount=1
-jkube.enricher.jkube-service.port=80
\ No newline at end of file
+jkube.enricher.jkube-service.port=80
+jkube.enricher.jkube-project-label.group=karavan
+jkube.enricher.jkube-project-label.provider=karavan
+jkube.recreate=true
\ No newline at end of file
diff --git a/karavan-web/karavan-app/src/main/resources/snippets/camel-main-openshift-application.properties b/karavan-web/karavan-app/src/main/resources/snippets/camel-main-openshift-application.properties
index 6997a260..6f6a9a91 100644
--- a/karavan-web/karavan-app/src/main/resources/snippets/camel-main-openshift-application.properties
+++ b/karavan-web/karavan-app/src/main/resources/snippets/camel-main-openshift-application.properties
@@ -7,9 +7,18 @@ camel.jbang.version=4.0.0-RC2
 camel.jbang.dependencies=camel-console,camel-platform-http-main
 camel.health.enabled=true
 camel.health.exposure-level=full
+camel.server.enabled=true
+camel.server.healthCheckEnabled=true
+camel.server.devConsoleEnabled=true
+label.runtime=app.kubernetes.io/runtime
+jib.from.image=gcr.io/distroless/java17@sha256:3a4ea21bd7b412b8b6ae61313b39337d8f03bb6844013810e8e4625d8c765edb
 jkube.version=1.13.1
-jkube.build.strategy=jib
+jkube.skip.build=true
+jkube.namespace=default
 jkube.imagePullPolicy=IfNotPresent
 jkube.enricher.jkube-controller.type=Deployment
 jkube.enricher.jkube-controller.replicaCount=1
-jkube.enricher.jkube-service.port=80
\ No newline at end of file
+jkube.enricher.jkube-service.port=80
+jkube.enricher.jkube-project-label.group=karavan
+jkube.enricher.jkube-project-label.provider=karavan
+jkube.recreate=true
\ No newline at end of file
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 82a89413..0c8893b5 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
@@ -70,7 +70,6 @@ export class ServiceStatus {
 export class ContainerStatus {
     containerName: string = '';
     containerId: string = '';
-    lifeCycle: string = '';
     state: string = '';
     deployment: string = '';
     projectId: string = '';
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 deebf7ee..eba4c0c4 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
@@ -118,6 +118,8 @@ interface FileState {
     setEditAdvancedProperties: (editAdvancedProperties: boolean) => void;
     addProperty: string;
     setAddProperty: (addProperty: string) => void;
+    mode: "design" | "code",
+    setMode: (mode: "design" | "code") => void;
 }
 
 export const useFileStore = create<FileState>((set) => ({
@@ -125,6 +127,10 @@ export const useFileStore = create<FileState>((set) => ({
     operation: "none",
     editAdvancedProperties: false,
     addProperty: '',
+    mode: "design",
+    setMode: (mode: "design" | "code") => {
+        set(() => ({mode: mode}));
+    },
     setFile: (operation:  "create" | "select" | "delete"| "none" | "copy" | "upload", file?: ProjectFile) => {
         set((state: FileState) => ({
             file: file,
diff --git a/karavan-web/karavan-app/src/main/webui/src/dashboard/DashboardPage.tsx b/karavan-web/karavan-app/src/main/webui/src/dashboard/DashboardPage.tsx
index b338b3bc..30dad19e 100644
--- a/karavan-web/karavan-app/src/main/webui/src/dashboard/DashboardPage.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/dashboard/DashboardPage.tsx
@@ -325,7 +325,7 @@ export const DashboardPage = () => {
                                 <Badge className="badge">{container.type}</Badge>
                             </Td>
                             <Td style={{verticalAlign: "middle"}}>
-                                <Label color={container.lifeCycle === 'ready' ? "green" : 'grey'}>
+                                <Label color={container.state === 'running' ? "green" : 'grey'}>
                                     {container.containerName}
                                 </Label>
                             </Td>
diff --git a/karavan-web/karavan-app/src/main/webui/src/designer/route/DslConnections.tsx b/karavan-web/karavan-app/src/main/webui/src/designer/route/DslConnections.tsx
index 5280bc12..938042d4 100644
--- a/karavan-web/karavan-app/src/main/webui/src/designer/route/DslConnections.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/designer/route/DslConnections.tsx
@@ -126,7 +126,7 @@ export class DslConnections extends React.Component<Props, State> {
             const imageX = incomingX - r + 5;
             const imageY = fromY - r + 5;
             return (
-                <div style={{display: "block", position: "absolute", top: imageY, left: imageX}}>
+                <div key={pos.step.uuid + "-icon"} style={{display: "block", position: "absolute", top: imageY, left: imageX}}>
                     {CamelUi.getConnectionIcon(pos.step)}
                 </div>
             )
@@ -212,7 +212,7 @@ export class DslConnections extends React.Component<Props, State> {
             const imageX = outgoingX - r + 5;
             const imageY = outgoingY - r + 5;
             return (
-                <div style={{display: "block", position: "absolute", top: imageY, left: imageX}}>
+                <div key={pos.step.uuid + "-icon"} style={{display: "block", position: "absolute", top: imageY, left: imageX}}>
                     {CamelUi.getConnectionIcon(pos.step)}
                 </div>
             )
diff --git a/karavan-web/karavan-app/src/main/webui/src/designer/route/DslProperties.tsx b/karavan-web/karavan-app/src/main/webui/src/designer/route/DslProperties.tsx
index 435480de..f10a0eec 100644
--- a/karavan-web/karavan-app/src/main/webui/src/designer/route/DslProperties.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/designer/route/DslProperties.tsx
@@ -33,7 +33,7 @@ import {Integration, CamelElement} from "karavan-core/lib/model/IntegrationDefin
 import {CamelDefinitionApiExt} from "karavan-core/lib/api/CamelDefinitionApiExt";
 import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
 import {CamelUi, RouteToCreate} from "../utils/CamelUi";
-import {CamelMetadataApi, PropertyMeta} from "karavan-core/lib/model/CamelMetadata";
+import {CamelMetadataApi, DataFormats, PropertyMeta} from "karavan-core/lib/model/CamelMetadata";
 import {IntegrationHeader} from "../utils/KaravanComponents";
 import CloneIcon from "@patternfly/react-icons/dist/esm/icons/clone-icon";
 
@@ -170,7 +170,7 @@ export class DslProperties extends React.Component<Props, State> {
 
     getPropertyFields = (properties: PropertyMeta[]) => {
         return (<>
-            {this.state.step && !['MarshalDefinition', 'UnmarshalDefinition'].includes(this.state.step.dslName) && properties.map((property: PropertyMeta) =>
+            {properties.map((property: PropertyMeta) =>
                 <DslPropertyField key={property.name}
                                   integration={this.props.integration}
                                   property={property}
@@ -186,7 +186,11 @@ export class DslProperties extends React.Component<Props, State> {
     }
 
     render() {
-        const properties = this.getProperties();
+        const dataFormats = DataFormats.map(value => value[0]);
+        const dataFormatElement = this.state.step !== undefined && ['MarshalDefinition', 'UnmarshalDefinition'].includes(this.state.step.dslName);
+        const properties = !dataFormatElement
+                    ? this.getProperties()
+                    : this.getProperties().filter(p => !dataFormats.includes(p.name));
         const propertiesMain = properties.filter(p => !p.label.includes("advanced"));
         const propertiesAdvanced = properties.filter(p => p.label.includes("advanced"));
         return (
@@ -196,7 +200,8 @@ export class DslProperties extends React.Component<Props, State> {
                     {this.state.step === undefined && <IntegrationHeader integration={this.props.integration}/>}
                     {this.state.step && this.getComponentHeader()}
                     {this.getPropertyFields(propertiesMain)}
-                    {propertiesAdvanced.length > 0 &&
+                    {this.state.step && !['MarshalDefinition', 'UnmarshalDefinition'].includes(this.state.step.dslName)
+                        && propertiesAdvanced.length > 0 &&
                         <ExpandableSection
                             toggleText={'Advanced properties'}
                             onToggle={isExpanded => this.setState({isShowAdvanced: !this.state.isShowAdvanced})}
diff --git a/karavan-web/karavan-app/src/main/webui/src/designer/route/DslSelector.tsx b/karavan-web/karavan-app/src/main/webui/src/designer/route/DslSelector.tsx
index 3baca8d8..eb66e7ec 100644
--- a/karavan-web/karavan-app/src/main/webui/src/designer/route/DslSelector.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/designer/route/DslSelector.tsx
@@ -99,7 +99,7 @@ export class DslSelector extends React.Component<Props, State> {
                 </CardBody>
                 <CardFooter className="footer-labels">
                     <div style={{display: "flex", flexDirection: "row", justifyContent: "start"}}>
-                        {labels.map(label => <Badge isRead className="labels">{label}</Badge>)}
+                        {labels.map(label => <Badge key={label} isRead className="labels">{label}</Badge>)}
                     </div>
 
                 </CardFooter>
@@ -179,6 +179,7 @@ export class DslSelector extends React.Component<Props, State> {
                 <PageSection variant={this.props.dark ? "darker" : "light"}>
                     {isEip && <ToggleGroup aria-label="Labels" isCompact>
                         {eipLabels.map(eipLabel => <ToggleGroupItem
+                            key={eipLabel}
                             text={eipLabel}
                             buttonId={eipLabel}
                             isSelected={this.state.selectedLabels.includes(eipLabel)}
diff --git a/karavan-web/karavan-app/src/main/webui/src/designer/utils/CamelUi.tsx b/karavan-web/karavan-app/src/main/webui/src/designer/utils/CamelUi.tsx
index a94ed0ac..8d4157c4 100644
--- a/karavan-web/karavan-app/src/main/webui/src/designer/utils/CamelUi.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/designer/utils/CamelUi.tsx
@@ -88,7 +88,6 @@ import {
     WorkflowIcon
 } from "./KaravanIcons";
 import React from "react";
-import {Icon} from "@patternfly/react-core";
 
 const StepElements: string[] = [
     "AggregateDefinition",
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 9401aeb0..e8462d90 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
@@ -4,22 +4,22 @@ 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/trash-icon";
-import {useDevModeStore, useLogStore, useProjectStore, useStatusesStore} from "../api/ProjectStore";
+import {useAppConfigStore, useDevModeStore, useLogStore, useProjectStore, useStatusesStore} 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 {
     reloadOnly?: boolean
 }
 
 export const DevModeToolbar = (props: Props) => {
 
+    const [config] = useAppConfigStore((state) => [state.config], shallow)
     const [status] = useDevModeStore((state) => [state.status], shallow)
-    const [project ] = useProjectStore((state) => [state.project], shallow)
+    const [project] = useProjectStore((state) => [state.project], shallow)
     const [containers] = useStatusesStore((state) => [state.containers], shallow);
     const [verbose, setVerbose] = useState(false);
 
@@ -27,7 +27,7 @@ export const DevModeToolbar = (props: Props) => {
     const commands = containerStatus?.commands || ['run'];
     const isRunning = containerStatus?.state === 'running';
     const inTransit = containerStatus?.inTransit;
-    const isLoading= status === 'wip';
+    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"}}>
@@ -76,16 +76,18 @@ export const DevModeToolbar = (props: Props) => {
                 </Button>
             </Tooltip>
         </FlexItem>}
-        <FlexItem>
-            <Tooltip content="Stop container" position={TooltipPosition.bottom}>
-                <Button isSmall
-                        isDisabled={!commands.includes('stop') || inTransit}
-                        variant={"control"}
-                        icon={<StopIcon/>}
-                        onClick={() => ProjectService.stopDevModeContainer(project)}>
-                </Button>
-            </Tooltip>
-        </FlexItem>
+        {config.infrastructure !== 'kubernetes' &&
+            <FlexItem>
+                <Tooltip content="Stop container" position={TooltipPosition.bottom}>
+                    <Button 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 isSmall
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 976123ef..a71af8cd 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
@@ -1,4 +1,4 @@
-import React, {useEffect, useState} from 'react';
+import React, {useState} from 'react';
 import {
     PageSection,
 } from '@patternfly/react-core';
@@ -64,14 +64,6 @@ export const ProjectPage = () => {
         }
     }
 
-
-    function tools () {
-        return <ProjectToolbar
-                               mode={mode}
-                               setMode={mode => setMode(mode)}
-        />
-    }
-
     function isBuildIn(): boolean {
         return ['kamelets', 'templates'].includes(project.projectId);
     }
@@ -87,7 +79,7 @@ export const ProjectPage = () => {
     return (
         <PageSection key={key} className="kamelet-section project-page" padding={{default: 'noPadding'}}>
             <PageSection className="tools-section" padding={{default: 'noPadding'}}>
-                <MainToolbar title={<ProjectTitle/>} tools={tools()}/>
+                <MainToolbar title={<ProjectTitle/>} tools={<ProjectToolbar/>}/>
             </PageSection>
             {showFilePanel && <FileEditor/>}
             {!showFilePanel && <ProjectPanel/>}
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 daed745b..748a1594 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
@@ -22,16 +22,13 @@ import {shallow} from "zustand/shallow";
 import {ProjectModelApi} from "karavan-core/lib/api/ProjectModelApi";
 import {ProjectModel, ProjectProperty} from "karavan-core/lib/model/ProjectModel";
 
-interface Props {
-    mode: "design" | "code",
-    setMode: (mode: "design" | "code") => void,
-}
 
-export const ProjectToolbar = (props: Props) => {
+export const ProjectToolbar = () => {
 
     const [project, isPushing] = useProjectStore((state) => [state.project, state.isPushing], shallow )
-    const [file, editAdvancedProperties, setEditAdvancedProperties, setAddProperty] = useFileStore((state) =>
-        [state.file, state.editAdvancedProperties, state.setEditAdvancedProperties, state.setAddProperty], shallow )
+    const [file, editAdvancedProperties, setEditAdvancedProperties, setAddProperty, mode, setMode]
+        = useFileStore((state) =>
+        [state.file, state.editAdvancedProperties, state.setEditAdvancedProperties, state.setAddProperty, state.mode, state.setMode], shallow )
 
     useEffect(() => {
     }, [project, file]);
@@ -72,7 +69,6 @@ export const ProjectToolbar = (props: Props) => {
     }
 
     function getFileToolbar() {
-        const { mode} = props;
         return <Toolbar id="toolbar-group-types">
             <ToolbarContent>
                 <Flex className="toolbar" direction={{default: "row"}} alignItems={{default: "alignItemsCenter"}}>
@@ -80,9 +76,9 @@ export const ProjectToolbar = (props: Props) => {
                     {isYaml() && <FlexItem>
                         <ToggleGroup>
                             <ToggleGroupItem text="Design" buttonId="design" isSelected={mode === "design"}
-                                             onChange={s => props.setMode("design")}/>
+                                             onChange={s => setMode("design")}/>
                             <ToggleGroupItem text="Code" buttonId="code" isSelected={mode === "code"}
-                                             onChange={s => props.setMode("code")}/>
+                                             onChange={s => setMode("code")}/>
                         </ToggleGroup>
                     </FlexItem>}
 
diff --git a/karavan-web/karavan-app/src/main/webui/src/project/file/FileEditor.tsx b/karavan-web/karavan-app/src/main/webui/src/project/file/FileEditor.tsx
index fce383d6..0f2fe9e2 100644
--- a/karavan-web/karavan-app/src/main/webui/src/project/file/FileEditor.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/project/file/FileEditor.tsx
@@ -14,28 +14,22 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import React, {useState} from 'react';
-import {
-    CodeBlockCode,
-    CodeBlock, Skeleton
-} from '@patternfly/react-core';
+import React from 'react';
 import '../../designer/karavan.css';
 import Editor from "@monaco-editor/react";
 import {CamelDefinitionYaml} from "karavan-core/lib/api/CamelDefinitionYaml";
 import {ProjectFile, ProjectFileTypes} from "../../api/ProjectModels";
-import {useAppConfigStore, useFilesStore, useFileStore, useProjectStore} from "../../api/ProjectStore";
+import {useFilesStore, useFileStore, useProjectStore} from "../../api/ProjectStore";
 import {KaravanDesigner} from "../../designer/KaravanDesigner";
 import {ProjectService} from "../../api/ProjectService";
 import {PropertiesTable} from "./PropertiesTable";
+import {shallow} from "zustand/shallow";
 
 export const FileEditor = () => {
 
-    const [editAdvancedProperties] = useState<boolean>(false);
-    const {file, operation} = useFileStore();
-    const [mode, setMode] = useState<"design" | "code">("design");
-    const [key, setKey] = useState<string>('');
+    const [file, operation, mode] = useFileStore((state) =>
+        [state.file, state.operation, state.mode, state.setMode], shallow )
     const {project} = useProjectStore();
-    const {config} = useAppConfigStore();
 
     function save (name: string, code: string) {
         if (file) {
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 ba26da23..b59ac766 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
@@ -198,9 +198,9 @@ export class ProjectStatus extends React.Component<Props, State> {
                     {podStatuses.length === 0 && <Label icon={<DownIcon/>} color={"grey"}>No pods</Label>}
                     <LabelGroup numLabels={2} isVertical>
                         {podStatuses.map(pod => {
-                                const ready = pod.lifeCycle === 'ready';
+                                const ready = pod.state === 'running';
                                 return (
-                                    <Tooltip key={pod.containerName} content={pod.lifeCycle}>
+                                    <Tooltip key={pod.containerName} content={pod.state}>
                                         <Label icon={ready ? <UpIcon/> : <DownIcon/>} color={ready ? "green" : "red"}>
                                             <Button variant="link"
                                                     onClick={e => {
diff --git a/karavan-web/karavan-app/src/main/webui/src/project/trace/TraceTab.tsx b/karavan-web/karavan-app/src/main/webui/src/project/trace/TraceTab.tsx
index 7363832a..f10bf0ab 100644
--- a/karavan-web/karavan-app/src/main/webui/src/project/trace/TraceTab.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/project/trace/TraceTab.tsx
@@ -57,7 +57,6 @@ export const TraceTab = () => {
         if (refreshTrace) {
             KaravanApi.getDevModeStatus(projectId, "trace", res => {
                 if (res.status === 200) {
-                    console.log(JSON.parse(res.data.status))
                     setTrace(JSON.parse(res.data.status));
                 } else {
                     setTrace({});
diff --git a/karavan-web/karavan-cli/src/main/resources/spring-boot-builder-script-openshift.sh b/karavan-web/karavan-cli/src/main/resources/camel-main-builder-script-kubernetes.sh
similarity index 63%
copy from karavan-web/karavan-cli/src/main/resources/spring-boot-builder-script-openshift.sh
copy to karavan-web/karavan-cli/src/main/resources/camel-main-builder-script-kubernetes.sh
index 8b81f918..fb3a074f 100644
--- a/karavan-web/karavan-cli/src/main/resources/spring-boot-builder-script-openshift.sh
+++ b/karavan-web/karavan-cli/src/main/resources/camel-main-builder-script-kubernetes.sh
@@ -14,16 +14,17 @@ fi
 
 cd ${CHECKOUT_DIR}/$(inputs.params.project)
 
-entrypoint -Dcamel.jbang.version=$CAMEL_VERSION camel@apache/camel export --local-kamelet-dir=${KAMELETS_DIR}
+jbang -Dcamel.jbang.version=$CAMEL_VERSION camel@apache/camel export --local-kamelet-dir=${KAMELETS_DIR}
 
 export LAST_COMMIT=$(git rev-parse --short HEAD)
 export DATE=$(date '+%Y%m%d%H%M%S')
 export TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
 export NAMESPACE=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace)
 
-mvn package package oc:build oc:push oc:resource oc:apply \
-  -Popenshift \
+mvn package jib:build k8s:resource k8s:apply \
   -Djkube.namespace=${NAMESPACE} \
-  -Djkube.docker.push.registry=${IMAGE_REGISTRY} \
-  -Djkube.generator.name=${IMAGE_REGISTRY}/${NAMESPACE}/$(inputs.params.project):${DATE} \
+  -Djib.allowInsecureRegistries=true \
+  -Djib.to.image=${IMAGE_REGISTRY}/${IMAGE_GROUP}/$(inputs.params.project):${DATE} \
+  -Djib.to.auth.username=${IMAGE_REGISTRY_USERNAME} \
+  -Djib.to.auth.password=${IMAGE_REGISTRY_PASSWORD}  \
   --settings=$MAVEN_SETTINGS
\ No newline at end of file
diff --git a/karavan-web/karavan-cli/src/main/resources/spring-boot-builder-script-openshift.sh b/karavan-web/karavan-cli/src/main/resources/camel-main-builder-script-openshift.sh
similarity index 63%
copy from karavan-web/karavan-cli/src/main/resources/spring-boot-builder-script-openshift.sh
copy to karavan-web/karavan-cli/src/main/resources/camel-main-builder-script-openshift.sh
index 8b81f918..ebad0494 100644
--- a/karavan-web/karavan-cli/src/main/resources/spring-boot-builder-script-openshift.sh
+++ b/karavan-web/karavan-cli/src/main/resources/camel-main-builder-script-openshift.sh
@@ -14,16 +14,17 @@ fi
 
 cd ${CHECKOUT_DIR}/$(inputs.params.project)
 
-entrypoint -Dcamel.jbang.version=$CAMEL_VERSION camel@apache/camel export --local-kamelet-dir=${KAMELETS_DIR}
+jbang -Dcamel.jbang.version=$CAMEL_VERSION camel@apache/camel export --local-kamelet-dir=${KAMELETS_DIR}
 
 export LAST_COMMIT=$(git rev-parse --short HEAD)
 export DATE=$(date '+%Y%m%d%H%M%S')
 export TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
 export NAMESPACE=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace)
 
-mvn package package oc:build oc:push oc:resource oc:apply \
-  -Popenshift \
+mvn package jib:build oc:resource oc:apply \
   -Djkube.namespace=${NAMESPACE} \
-  -Djkube.docker.push.registry=${IMAGE_REGISTRY} \
-  -Djkube.generator.name=${IMAGE_REGISTRY}/${NAMESPACE}/$(inputs.params.project):${DATE} \
+  -Djib.allowInsecureRegistries=true \
+  -Djib.to.image=${IMAGE_REGISTRY}/${IMAGE_GROUP}/$(inputs.params.project):${DATE} \
+  -Djib.to.auth.username=${IMAGE_REGISTRY_USERNAME} \
+  -Djib.to.auth.password=${IMAGE_REGISTRY_PASSWORD}  \
   --settings=$MAVEN_SETTINGS
\ No newline at end of file
diff --git a/karavan-web/karavan-cli/src/main/resources/quarkus-builder-script-kubernetes.sh b/karavan-web/karavan-cli/src/main/resources/quarkus-builder-script-kubernetes.sh
index bcbd3630..b62a8981 100644
--- a/karavan-web/karavan-cli/src/main/resources/quarkus-builder-script-kubernetes.sh
+++ b/karavan-web/karavan-cli/src/main/resources/quarkus-builder-script-kubernetes.sh
@@ -14,7 +14,7 @@ fi
 
 cd ${CHECKOUT_DIR}/$(inputs.params.project)
 
-entrypoint -Dcamel.jbang.version=$CAMEL_VERSION camel@apache/camel export --local-kamelet-dir=${KAMELETS_DIR}
+jbang -Dcamel.jbang.version=$CAMEL_VERSION camel@apache/camel export --local-kamelet-dir=${KAMELETS_DIR}
 
 export LAST_COMMIT=$(git rev-parse --short HEAD)
 export DATE=$(date '+%Y%m%d%H%M%S')
diff --git a/karavan-web/karavan-cli/src/main/resources/quarkus-builder-script-openshift.sh b/karavan-web/karavan-cli/src/main/resources/quarkus-builder-script-openshift.sh
index 8cfc517c..17669aae 100644
--- a/karavan-web/karavan-cli/src/main/resources/quarkus-builder-script-openshift.sh
+++ b/karavan-web/karavan-cli/src/main/resources/quarkus-builder-script-openshift.sh
@@ -14,7 +14,7 @@ fi
 
 cd ${CHECKOUT_DIR}/$(inputs.params.project)
 
-entrypoint -Dcamel.jbang.version=$CAMEL_VERSION camel@apache/camel export --local-kamelet-dir=${KAMELETS_DIR}
+jbang -Dcamel.jbang.version=$CAMEL_VERSION camel@apache/camel export --local-kamelet-dir=${KAMELETS_DIR}
 
 export LAST_COMMIT=$(git rev-parse --short HEAD)
 export DATE=$(date '+%Y%m%d%H%M%S')
diff --git a/karavan-web/karavan-cli/src/main/resources/spring-boot-builder-script-kubernetes.sh b/karavan-web/karavan-cli/src/main/resources/spring-boot-builder-script-kubernetes.sh
index 2e175498..51f4ccc4 100644
--- a/karavan-web/karavan-cli/src/main/resources/spring-boot-builder-script-kubernetes.sh
+++ b/karavan-web/karavan-cli/src/main/resources/spring-boot-builder-script-kubernetes.sh
@@ -14,7 +14,7 @@ fi
 
 cd ${CHECKOUT_DIR}/$(inputs.params.project)
 
-entrypoint -Dcamel.jbang.version=$CAMEL_VERSION camel@apache/camel export --local-kamelet-dir=${KAMELETS_DIR}
+jbang -Dcamel.jbang.version=$CAMEL_VERSION camel@apache/camel export --local-kamelet-dir=${KAMELETS_DIR}
 
 export LAST_COMMIT=$(git rev-parse --short HEAD)
 export DATE=$(date '+%Y%m%d%H%M%S')
diff --git a/karavan-web/karavan-cli/src/main/resources/spring-boot-builder-script-openshift.sh b/karavan-web/karavan-cli/src/main/resources/spring-boot-builder-script-openshift.sh
index 8b81f918..236abc22 100644
--- a/karavan-web/karavan-cli/src/main/resources/spring-boot-builder-script-openshift.sh
+++ b/karavan-web/karavan-cli/src/main/resources/spring-boot-builder-script-openshift.sh
@@ -14,7 +14,7 @@ fi
 
 cd ${CHECKOUT_DIR}/$(inputs.params.project)
 
-entrypoint -Dcamel.jbang.version=$CAMEL_VERSION camel@apache/camel export --local-kamelet-dir=${KAMELETS_DIR}
+jbang -Dcamel.jbang.version=$CAMEL_VERSION camel@apache/camel export --local-kamelet-dir=${KAMELETS_DIR}
 
 export LAST_COMMIT=$(git rev-parse --short HEAD)
 export DATE=$(date '+%Y%m%d%H%M%S')