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 2022/10/28 00:16:55 UTC

[camel-karavan] 05/08: Fix #501

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 7a6bb5bc96cda3b0567c2c8a45ff7e5bb4e88db2
Author: Marat Gubaidullin <ma...@gmail.com>
AuthorDate: Thu Oct 27 10:10:49 2022 -0400

    Fix #501
---
 .../camel/karavan/api/KubernetesResource.java      | 16 +++-
 .../camel/karavan/model/DeploymentStatus.java      |  1 +
 .../org/apache/camel/karavan/model/PodStatus.java  | 42 +++++++----
 .../camel/karavan/service/InfinispanService.java   | 40 +++++++++-
 .../camel/karavan/service/KaravanService.java      |  9 ++-
 .../camel/karavan/service/KubernetesService.java   | 85 +++++++++-------------
 ...entWatcher.java => DeploymentEventHandler.java} | 63 +++++++++-------
 ...unWatcher.java => PipelineRunEventHandler.java} | 65 ++++++++++++-----
 .../camel/karavan/watcher/PodEventHandler.java     | 84 +++++++++++++++++++++
 .../apache/camel/karavan/watcher/PodWatcher.java   | 40 ----------
 10 files changed, 287 insertions(+), 158 deletions(-)

diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/api/KubernetesResource.java b/karavan-app/src/main/java/org/apache/camel/karavan/api/KubernetesResource.java
index a817434..c79fc51 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/api/KubernetesResource.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/api/KubernetesResource.java
@@ -20,6 +20,7 @@ import io.smallrye.mutiny.Multi;
 import io.vertx.mutiny.core.eventbus.EventBus;
 import io.vertx.mutiny.core.eventbus.Message;
 import org.apache.camel.karavan.model.DeploymentStatus;
+import org.apache.camel.karavan.model.PodStatus;
 import org.apache.camel.karavan.model.Project;
 import org.apache.camel.karavan.service.InfinispanService;
 import org.apache.camel.karavan.service.KubernetesService;
@@ -99,9 +100,9 @@ public class KubernetesResource {
 
     @GET
     @Produces(MediaType.APPLICATION_JSON)
-    @Path("/deployment/")
-    public List<DeploymentStatus> getAll() throws Exception {
-        return infinispanService.getDeploymentStatuses().stream()
+    @Path("/deployment/{env}")
+    public List<DeploymentStatus> getDeploymentStatusesByEnv(@PathParam("env") String env) throws Exception {
+        return infinispanService.getDeploymentStatuses(env).stream()
                 .sorted(Comparator.comparing(DeploymentStatus::getName))
                 .collect(Collectors.toList());
     }
@@ -127,6 +128,15 @@ public class KubernetesResource {
         return Response.ok().build();
     }
 
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("/pod/{env}")
+    public List<PodStatus> getPodStatusesByEnv(@PathParam("env") String env) throws Exception {
+        return infinispanService.getPodStatuses(env).stream()
+                .sorted(Comparator.comparing(PodStatus::getName))
+                .collect(Collectors.toList());
+    }
+
     @DELETE
     @Produces(MediaType.APPLICATION_JSON)
     @Consumes(MediaType.APPLICATION_JSON)
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/model/DeploymentStatus.java b/karavan-app/src/main/java/org/apache/camel/karavan/model/DeploymentStatus.java
index c366be1..f0baa9e 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/model/DeploymentStatus.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/model/DeploymentStatus.java
@@ -1,5 +1,6 @@
 package org.apache.camel.karavan.model;
 
+import org.infinispan.protostream.annotations.ProtoDoc;
 import org.infinispan.protostream.annotations.ProtoFactory;
 import org.infinispan.protostream.annotations.ProtoField;
 
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/model/PodStatus.java b/karavan-app/src/main/java/org/apache/camel/karavan/model/PodStatus.java
index 8c70909..e24f9ea 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/model/PodStatus.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/model/PodStatus.java
@@ -8,29 +8,33 @@ public class PodStatus {
     @ProtoField(number = 1)
     String name;
     @ProtoField(number = 2)
-    Boolean started;
+    String phase;
     @ProtoField(number = 3)
-    Boolean ready;
+    Boolean initialized;
     @ProtoField(number = 4)
-    String reason;
+    Boolean ready;
     @ProtoField(number = 5)
-    String deployment;
+    String reason;
     @ProtoField(number = 6)
+    String deployment;
+    @ProtoField(number = 7)
     String env;
 
-    public PodStatus(String env) {
-        this.name = "";
-        this.started = false;
+    public PodStatus(String name, String deployment, String env) {
+        this.name = name;
+        this.phase = "";
+        this.initialized = false;
         this.ready = false;
         this.reason = "";
-        this.deployment = "";
-        this.env = "";
+        this.deployment = deployment;
+        this.env = env;
     }
 
     @ProtoFactory
-    public PodStatus(String name, Boolean started, Boolean ready, String reason, String deployment, String env) {
+    public PodStatus(String name, String phase, Boolean initialized, Boolean ready, String reason, String deployment, String env) {
         this.name = name;
-        this.started = started;
+        this.phase = phase;
+        this.initialized = initialized;
         this.ready = ready;
         this.reason = reason;
         this.deployment = deployment;
@@ -45,12 +49,20 @@ public class PodStatus {
         this.name = name;
     }
 
-    public Boolean getStarted() {
-        return started;
+    public String getPhase() {
+        return phase;
+    }
+
+    public void setPhase(String phase) {
+        this.phase = phase;
+    }
+
+    public Boolean getInitialized() {
+        return initialized;
     }
 
-    public void setStarted(Boolean started) {
-        this.started = started;
+    public void setInitialized(Boolean initialized) {
+        this.initialized = initialized;
     }
 
     public Boolean getReady() {
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/service/InfinispanService.java b/karavan-app/src/main/java/org/apache/camel/karavan/service/InfinispanService.java
index 9a0fd03..3fddb8f 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/service/InfinispanService.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/service/InfinispanService.java
@@ -97,6 +97,8 @@ public class InfinispanService {
             podStatuses = cacheManager.administration().withFlags(CacheContainerAdmin.AdminFlag.VOLATILE).getOrCreateCache(PodStatus.CACHE, builder.build());
             camelStatuses = cacheManager.administration().withFlags(CacheContainerAdmin.AdminFlag.VOLATILE).getOrCreateCache(CamelStatus.CACHE, builder.build());
             kamelets = cacheManager.administration().withFlags(CacheContainerAdmin.AdminFlag.VOLATILE).getOrCreateCache(Kamelet.CACHE, builder.build());
+
+            cleanStatuses();
         } else {
             LOGGER.info("InfinispanService is starting in remote mode");
             environments = cacheManager.administration().getOrCreateCache(Environment.CACHE, new XMLStringConfiguration(String.format(CACHE_CONFIG, Environment.CACHE)));
@@ -110,6 +112,13 @@ public class InfinispanService {
         }
     }
 
+    private void cleanStatuses() {
+        deploymentStatuses.clear();
+        podStatuses.clear();
+        pipelineStatuses.clear();
+    }
+
+
     public List<Project> getProjects() {
         return projects.values().stream().collect(Collectors.toList());
     }
@@ -167,6 +176,10 @@ public class InfinispanService {
         pipelineStatuses.put(GroupedKey.create(status.getProjectId(), status.getEnv()), status);
     }
 
+    public void deletePipelineStatus(PipelineStatus status) {
+        pipelineStatuses.remove(GroupedKey.create(status.getProjectId(), status.getEnv()));
+    }
+
     public DeploymentStatus getDeploymentStatus(String name, String env) {
         return deploymentStatuses.get(GroupedKey.create(name, env));
     }
@@ -185,12 +198,12 @@ public class InfinispanService {
 
     public List<DeploymentStatus> getDeploymentStatuses(String env) {
         if (cacheManager == null) {
-            QueryFactory queryFactory = org.infinispan.query.Search.getQueryFactory((Cache<?, ?>) files);
+            QueryFactory queryFactory = org.infinispan.query.Search.getQueryFactory((Cache<?, ?>) deploymentStatuses);
             return queryFactory.<DeploymentStatus>create("FROM org.apache.camel.karavan.model.DeploymentStatus WHERE env = :env")
                     .setParameter("env", env)
                     .execute().list();
         } else {
-            QueryFactory queryFactory = Search.getQueryFactory((RemoteCache<?, ?>) files);
+            QueryFactory queryFactory = Search.getQueryFactory((RemoteCache<?, ?>) deploymentStatuses);
             return queryFactory.<DeploymentStatus>create("FROM karavan.DeploymentStatus WHERE env = :env")
                     .setParameter("env", env)
                     .execute().list();
@@ -199,13 +212,13 @@ public class InfinispanService {
 
     public List<PodStatus> getPodStatuses(String projectId, String env) {
         if (cacheManager == null) {
-            QueryFactory queryFactory = org.infinispan.query.Search.getQueryFactory((Cache<?, ?>) files);
+            QueryFactory queryFactory = org.infinispan.query.Search.getQueryFactory((Cache<?, ?>) podStatuses);
             return queryFactory.<PodStatus>create("FROM org.apache.camel.karavan.model.PodStatus WHERE deployment = :deployment AND env = :env")
                     .setParameter("deployment", projectId)
                     .setParameter("env", env)
                     .execute().list();
         } else {
-            QueryFactory queryFactory = Search.getQueryFactory((RemoteCache<?, ?>) files);
+            QueryFactory queryFactory = Search.getQueryFactory((RemoteCache<?, ?>) podStatuses);
             return queryFactory.<PodStatus>create("FROM karavan.PodStatus WHERE deployment = :deployment AND env = :env")
                     .setParameter("deployment", projectId)
                     .setParameter("env", env)
@@ -213,9 +226,28 @@ public class InfinispanService {
         }
     }
 
+    public List<PodStatus> getPodStatuses(String env) {
+        if (cacheManager == null) {
+            QueryFactory queryFactory = org.infinispan.query.Search.getQueryFactory((Cache<?, ?>) podStatuses);
+            return queryFactory.<PodStatus>create("FROM org.apache.camel.karavan.model.PodStatus WHERE env = :env")
+                    .setParameter("env", env)
+                    .execute().list();
+        } else {
+            QueryFactory queryFactory = Search.getQueryFactory((RemoteCache<?, ?>) podStatuses);
+            return queryFactory.<PodStatus>create("FROM karavan.PodStatus WHERE env = :env")
+                    .setParameter("env", env)
+                    .execute().list();
+        }
+    }
+
     public void savePodStatus(PodStatus status) {
         podStatuses.put(GroupedKey.create(status.getDeployment(), status.getName()), status);
     }
+
+    public void deletePodStatus(PodStatus status) {
+        podStatuses.remove(GroupedKey.create(status.getDeployment(), status.getName()));
+    }
+
     public CamelStatus getCamelStatus(String projectId) {
         return camelStatuses.get(GroupedKey.create(projectId, projectId));
     }
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/service/KaravanService.java b/karavan-app/src/main/java/org/apache/camel/karavan/service/KaravanService.java
index 717e7c5..f5d2451 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/service/KaravanService.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/service/KaravanService.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.karavan.service;
 
+import io.quarkus.runtime.ShutdownEvent;
 import io.quarkus.runtime.StartupEvent;
 import io.vertx.core.eventbus.EventBus;
 import org.apache.camel.karavan.model.Environment;
@@ -47,12 +48,18 @@ public class KaravanService {
     String pipeline;
 
     void onStart(@Observes StartupEvent ev) {
+        LOGGER.info("Start Karavan");
         infinispanService.start();
         setEnvironment();
         initialImport();
         startInformers();
     }
 
+    void onStop(@Observes ShutdownEvent ev) {
+        LOGGER.info("Stop Karavan");
+        bus.publish(KubernetesService.STOP_INFORMERS, "");
+    }
+
     void setEnvironment() {
         String cluster = kubernetesService.getCluster();
         String namespace = kubernetesService.getNamespace();
@@ -68,6 +75,6 @@ public class KaravanService {
     }
 
     void startInformers() {
-        bus.publish(KubernetesService.START_WATCHERS, "");
+        bus.publish(KubernetesService.START_INFORMERS, "");
     }
 }
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/service/KubernetesService.java b/karavan-app/src/main/java/org/apache/camel/karavan/service/KubernetesService.java
index 735b47e..b896013 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/service/KubernetesService.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/service/KubernetesService.java
@@ -24,7 +24,11 @@ import io.fabric8.kubernetes.api.model.apps.Deployment;
 import io.fabric8.kubernetes.client.DefaultKubernetesClient;
 import io.fabric8.kubernetes.client.KubernetesClient;
 import io.fabric8.kubernetes.client.Watch;
+import io.fabric8.kubernetes.client.dsl.Informable;
 import io.fabric8.kubernetes.client.dsl.LogWatch;
+import io.fabric8.kubernetes.client.informers.SharedIndexInformer;
+import io.fabric8.kubernetes.client.informers.SharedInformerEventListener;
+import io.fabric8.kubernetes.client.informers.SharedInformerFactory;
 import io.fabric8.openshift.api.model.ImageStream;
 import io.fabric8.openshift.client.OpenShiftClient;
 import io.fabric8.tekton.client.DefaultTektonClient;
@@ -41,9 +45,9 @@ import io.quarkus.vertx.ConsumeEvent;
 import io.vertx.mutiny.core.eventbus.EventBus;
 import org.apache.camel.karavan.model.PipelineRunLog;
 import org.apache.camel.karavan.model.Project;
-import org.apache.camel.karavan.watcher.DeploymentWatcher;
-import org.apache.camel.karavan.watcher.PipelineRunWatcher;
-import org.apache.camel.karavan.watcher.PodWatcher;
+import org.apache.camel.karavan.watcher.DeploymentEventHandler;
+import org.apache.camel.karavan.watcher.PipelineRunEventHandler;
+import org.apache.camel.karavan.watcher.PodEventHandler;
 import org.eclipse.microprofile.config.inject.ConfigProperty;
 import org.jboss.logging.Logger;
 
@@ -65,7 +69,8 @@ import java.util.stream.Collectors;
 public class KubernetesService {
 
     private static final Logger LOGGER = Logger.getLogger(KubernetesService.class.getName());
-    public static final String START_WATCHERS = "start-watchers";
+    public static final String START_INFORMERS = "start-informers";
+    public static final String STOP_INFORMERS = "stop-informers";
 
     @Inject
     EventBus eventBus;
@@ -92,35 +97,36 @@ public class KubernetesService {
     public
     String environment;
 
-    private List<Watch> watches = new ArrayList<>();
+    List<SharedIndexInformer> informers = new ArrayList<>(3);
 
-    @ConsumeEvent(value = START_WATCHERS, blocking = true)
-    void start(String data) {
-        LOGGER.info("Start KubernetesService");
-        String labelName = getRuntimeLabel();
+    @ConsumeEvent(value = START_INFORMERS, blocking = true)
+    void startInformers(String data) {
+        LOGGER.info("Start Kubernetes Informers");
         try {
-            watches.add(kubernetesClient().apps().deployments().inNamespace(getNamespace()).withLabel(labelName, "camel")
-                    .watch(new DeploymentWatcher(infinispanService, this)));
-        } catch (Exception e) {
-            LOGGER.error(e.getMessage());
-        }
-        try {
-            watches.add(kubernetesClient().pods().inNamespace(getNamespace()).withLabel(labelName, "camel")
-                    .watch(new PodWatcher(infinispanService, this)));
-        } catch (Exception e){
-            LOGGER.error(e.getMessage());
-        }
-        try {
-            watches.add(tektonClient().v1beta1().pipelineRuns().inNamespace(getNamespace())
-                    .watch(new PipelineRunWatcher(infinispanService, this)));
+            stopInformers(null);
+            String runtimeLabel = getRuntimeLabel();
+
+            SharedIndexInformer<Deployment> deploymentInformer = kubernetesClient().apps().deployments().inNamespace(getNamespace()).withLabel(runtimeLabel, "camel").inform();
+            deploymentInformer.addEventHandlerWithResyncPeriod(new DeploymentEventHandler(infinispanService, this),30 * 1000L);
+            informers.add(deploymentInformer);
+
+            SharedIndexInformer<PipelineRun> pipelineRunInformer = tektonClient().v1beta1().pipelineRuns().inNamespace(getNamespace()).withLabel(runtimeLabel, "camel").inform();
+            pipelineRunInformer.addEventHandlerWithResyncPeriod(new PipelineRunEventHandler(infinispanService, this),30 * 1000L);
+            informers.add(pipelineRunInformer);
+
+            SharedIndexInformer<Pod> podRunInformer = kubernetesClient().pods().inNamespace(getNamespace()).withLabel(runtimeLabel, "camel").inform();
+            podRunInformer.addEventHandlerWithResyncPeriod(new PodEventHandler(infinispanService, this),30 * 1000L);
+            informers.add(podRunInformer);
+
         } catch (Exception e) {
-            LOGGER.error(e.getMessage());
+            LOGGER.error("Error starting informers: " + e.getMessage());
         }
     }
 
-    void onStop(@Observes ShutdownEvent ev) {
-        LOGGER.info("Stop KubernetesService");
-        watches.forEach(watch -> watch.close());
+    @ConsumeEvent(value = STOP_INFORMERS, blocking = true)
+    void stopInformers(String data) {
+        LOGGER.info("Stop Kubernetes Informers");
+        informers.forEach(informer -> informer.close());
     }
 
     public String createPipelineRun(Project project, String pipelineName, String namespace) throws Exception {
@@ -128,7 +134,8 @@ public class KubernetesService {
 
         Map<String, String> labels = Map.of(
                 "karavan-project-id", project.getProjectId(),
-                "tekton.dev/pipeline", pipelineName
+                "tekton.dev/pipeline", pipelineName,
+                getRuntimeLabel(), "camel"
         );
 
         ObjectMeta meta = new ObjectMetaBuilder()
@@ -231,28 +238,6 @@ public class KubernetesService {
         }
     }
 
-
-//    public List<PodStatus> getDeploymentPodsStatuses(String name, String namespace) {
-//        try {
-//            String labelName = getRuntimeLabel();
-//            List<Pod> pods = kubernetesClient().pods().inNamespace(namespace)
-//                    .withLabel("app.kubernetes.io/name", name)
-//                    .withLabel(labelName, "camel")
-//                    .list().getItems();
-//
-//            return pods.stream().map(pod -> new PodStatus(
-//                    pod.getMetadata().getName(),
-//                    pod.getStatus().getContainerStatuses().get(0).getStarted(),
-//                    pod.getStatus().getContainerStatuses().get(0).getReady(),
-//                    getPodReason(pod),
-//                    pod.getMetadata().getLabels().get("app.kubernetes.io/name")
-//            )).collect(Collectors.toList());
-//        } catch (Exception ex) {
-//            LOGGER.error(ex.getMessage());
-//            return List.of();
-//        }
-//    }
-
     public Deployment getDeployment(String name, String namespace) {
         try {
             return kubernetesClient().apps().deployments().inNamespace(namespace).withName(name).get();
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/watcher/DeploymentWatcher.java b/karavan-app/src/main/java/org/apache/camel/karavan/watcher/DeploymentEventHandler.java
similarity index 53%
rename from karavan-app/src/main/java/org/apache/camel/karavan/watcher/DeploymentWatcher.java
rename to karavan-app/src/main/java/org/apache/camel/karavan/watcher/DeploymentEventHandler.java
index 3177e1e..b4f4323 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/watcher/DeploymentWatcher.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/watcher/DeploymentEventHandler.java
@@ -1,42 +1,56 @@
 package org.apache.camel.karavan.watcher;
 
-import io.fabric8.kubernetes.client.Watcher;
 import io.fabric8.kubernetes.api.model.apps.Deployment;
-import io.fabric8.kubernetes.client.WatcherException;
+import io.fabric8.kubernetes.client.informers.ResourceEventHandler;
 import org.apache.camel.karavan.model.DeploymentStatus;
-import org.apache.camel.karavan.model.PodStatus;
-import org.apache.camel.karavan.model.Project;
 import org.apache.camel.karavan.service.InfinispanService;
 import org.apache.camel.karavan.service.KubernetesService;
 import org.jboss.logging.Logger;
 
-import java.util.List;
+public class DeploymentEventHandler implements ResourceEventHandler<Deployment> {
 
-public class DeploymentWatcher implements Watcher<Deployment> {
-
-    private static final Logger LOGGER = Logger.getLogger(DeploymentWatcher.class.getName());
+    private static final Logger LOGGER = Logger.getLogger(DeploymentEventHandler.class.getName());
     private InfinispanService infinispanService;
     private KubernetesService kubernetesService;
 
-    public DeploymentWatcher(InfinispanService infinispanService, KubernetesService kubernetesService) {
+    public DeploymentEventHandler(InfinispanService infinispanService, KubernetesService kubernetesService) {
         this.infinispanService = infinispanService;
         this.kubernetesService = kubernetesService;
     }
 
     @Override
-    public void eventReceived(Watcher.Action action, Deployment deployment) {
-        LOGGER.info(action.name() + " " + deployment.getMetadata().getName());
-        DeploymentStatus ds = getDeploymentStatus(deployment);
-        switch (action.name()) {
-            case "ADDED":
-                infinispanService.saveDeploymentStatus(ds);
-                break;
-            case "MODIFIED":
-                infinispanService.saveDeploymentStatus(ds);
-                break;
-            case "DELETED":
-                infinispanService.deleteDeploymentStatus(ds);
-                break;
+    public void onAdd(Deployment deployment) {
+        try {
+            LOGGER.info("onAdd " + deployment.getMetadata().getName());
+            DeploymentStatus ds = getDeploymentStatus(deployment);
+            infinispanService.saveDeploymentStatus(ds);
+        } catch (Exception e){
+            LOGGER.error(e.getMessage());
+        }
+    }
+
+    @Override
+    public void onUpdate(Deployment oldDeployment, Deployment newDeployment) {
+        try {
+            LOGGER.info("onUpdate " + newDeployment.getMetadata().getName());
+            DeploymentStatus ds = getDeploymentStatus(newDeployment);
+            infinispanService.saveDeploymentStatus(ds);
+        } catch (Exception e){
+            LOGGER.error(e.getMessage());
+        }
+    }
+
+    @Override
+    public void onDelete(Deployment deployment, boolean deletedFinalStateUnknown) {
+        try {
+            LOGGER.info("onDelete " + deployment.getMetadata().getName());
+            DeploymentStatus ds = new DeploymentStatus(
+                    deployment.getMetadata().getName(),
+                    deployment.getMetadata().getNamespace(),
+                    kubernetesService.environment);
+            infinispanService.deleteDeploymentStatus(ds);
+        } catch (Exception e){
+            LOGGER.error(e.getMessage());
         }
     }
 
@@ -64,9 +78,4 @@ public class DeploymentWatcher implements Watcher<Deployment> {
                     kubernetesService.environment);
         }
     }
-
-    @Override
-    public void onClose(WatcherException cause) {
-
-    }
 }
\ No newline at end of file
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/watcher/PipelineRunWatcher.java b/karavan-app/src/main/java/org/apache/camel/karavan/watcher/PipelineRunEventHandler.java
similarity index 56%
rename from karavan-app/src/main/java/org/apache/camel/karavan/watcher/PipelineRunWatcher.java
rename to karavan-app/src/main/java/org/apache/camel/karavan/watcher/PipelineRunEventHandler.java
index 1e1ba3a..b5d59e9 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/watcher/PipelineRunWatcher.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/watcher/PipelineRunEventHandler.java
@@ -1,7 +1,6 @@
 package org.apache.camel.karavan.watcher;
 
-import io.fabric8.kubernetes.client.Watcher;
-import io.fabric8.kubernetes.client.WatcherException;
+import io.fabric8.kubernetes.client.informers.ResourceEventHandler;
 import io.fabric8.tekton.pipeline.v1beta1.PipelineRun;
 import org.apache.camel.karavan.model.PipelineStatus;
 import org.apache.camel.karavan.model.Project;
@@ -10,31 +9,65 @@ import org.apache.camel.karavan.service.KubernetesService;
 import org.jboss.logging.Logger;
 
 import java.time.Instant;
-import java.util.List;
 
-public class PipelineRunWatcher implements Watcher<PipelineRun> {
+public class PipelineRunEventHandler implements ResourceEventHandler<PipelineRun> {
 
-    private static final Logger LOGGER = Logger.getLogger(PipelineRunWatcher.class.getName());
+    private static final Logger LOGGER = Logger.getLogger(PipelineRunEventHandler.class.getName());
     private InfinispanService infinispanService;
     private KubernetesService kubernetesService;
 
-    public PipelineRunWatcher(InfinispanService infinispanService, KubernetesService kubernetesService) {
+    public PipelineRunEventHandler(InfinispanService infinispanService, KubernetesService kubernetesService) {
         this.infinispanService = infinispanService;
         this.kubernetesService = kubernetesService;
     }
 
     @Override
-    public void eventReceived(Action action, PipelineRun pipelineRun) {
-        LOGGER.info(action.name() + " " + pipelineRun.getMetadata().getName());
+    public void onAdd(PipelineRun pipelineRun) {
+        try {
+            LOGGER.info("onAdd " + pipelineRun.getMetadata().getName());
+            PipelineStatus ps = getPipelineStatus(pipelineRun);
+            if (ps != null) infinispanService.savePipelineStatus(ps);
+        } catch (Exception e){
+            LOGGER.error(e.getMessage());
+        }
+    }
+
+    @Override
+    public void onUpdate(PipelineRun oldPipelineRun, PipelineRun newPipelineRun) {
+        try {
+            LOGGER.info("onUpdate " + newPipelineRun.getMetadata().getName());
+            PipelineStatus ps = getPipelineStatus(newPipelineRun);
+            if (ps != null) infinispanService.savePipelineStatus(ps);
+        } catch (Exception e){
+            LOGGER.error(e.getMessage());
+        }
+    }
+
+    @Override
+    public void onDelete(PipelineRun pipelineRun, boolean deletedFinalStateUnknown) {
+        try {
+            LOGGER.info("onDelete " + pipelineRun.getMetadata().getName());
+            String projectId = pipelineRun.getMetadata().getLabels().get("karavan-project-id");
+            if (projectId != null) {
+                Project project = infinispanService.getProject(projectId);
+                if (project != null) {
+                    PipelineStatus ps = new PipelineStatus(project.getProjectId(), kubernetesService.environment);
+                    infinispanService.deletePipelineStatus(ps);
+                }
+            }
+        } catch (Exception e){
+            LOGGER.error(e.getMessage());
+        }
+    }
+
+    public PipelineStatus getPipelineStatus( PipelineRun pipelineRun) {
         String projectId = pipelineRun.getMetadata().getLabels().get("karavan-project-id");
         if (projectId != null) {
             Project project = infinispanService.getProject(projectId);
-            if (project != null && List.of("MODIFIED", "ADDED").contains(action.name())) {
-                PipelineStatus pipelineStatus = infinispanService.getPipelineStatus(projectId);
-                if (pipelineStatus == null) pipelineStatus = new PipelineStatus(project.getProjectId(), kubernetesService.environment);
+            if (project != null) {
+                PipelineStatus pipelineStatus = new PipelineStatus(project.getProjectId(), kubernetesService.environment);
 
                 if (pipelineRun.getStatus() != null) {
-                    LOGGER.info(action.name()+ " " + pipelineRun.getMetadata().getName() + " " + pipelineRun.getStatus().getConditions().get(0).getReason());
                     Instant runStartTime = Instant.parse(pipelineRun.getStatus().getStartTime());
                     Instant savedStartTime = pipelineStatus.getStartTime() != null
                             ? Instant.parse(pipelineStatus.getStartTime())
@@ -52,9 +85,10 @@ public class PipelineRunWatcher implements Watcher<PipelineRun> {
                     pipelineStatus.setStartTime(null);
                     pipelineStatus.setCompletionTime(null);
                 }
-                infinispanService.savePipelineStatus(pipelineStatus);
+                return pipelineStatus;
             }
         }
+        return null;
     }
 
     private Long getPipelineRunDuration(PipelineRun pipelineRun) {
@@ -69,9 +103,4 @@ public class PipelineRunWatcher implements Watcher<PipelineRun> {
             return 0L;
         }
     }
-
-    @Override
-    public void onClose(WatcherException cause) {
-
-    }
 }
\ No newline at end of file
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/watcher/PodEventHandler.java b/karavan-app/src/main/java/org/apache/camel/karavan/watcher/PodEventHandler.java
new file mode 100644
index 0000000..8d3af7c
--- /dev/null
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/watcher/PodEventHandler.java
@@ -0,0 +1,84 @@
+package org.apache.camel.karavan.watcher;
+
+import io.fabric8.kubernetes.api.model.Pod;
+import io.fabric8.kubernetes.api.model.PodCondition;
+import io.fabric8.kubernetes.client.informers.ResourceEventHandler;
+import org.apache.camel.karavan.model.PodStatus;
+import org.apache.camel.karavan.service.InfinispanService;
+import org.apache.camel.karavan.service.KubernetesService;
+import org.jboss.logging.Logger;
+
+import java.util.Optional;
+
+public class PodEventHandler implements ResourceEventHandler<Pod> {
+
+    private static final Logger LOGGER = Logger.getLogger(PodEventHandler.class.getName());
+    private InfinispanService infinispanService;
+    private KubernetesService kubernetesService;
+
+    public PodEventHandler(InfinispanService infinispanService, KubernetesService kubernetesService) {
+        this.infinispanService = infinispanService;
+        this.kubernetesService = kubernetesService;
+    }
+
+    @Override
+    public void onAdd(Pod pod) {
+        try {
+            LOGGER.info("onAdd " + pod.getMetadata().getName());
+            PodStatus ps = getPodStatus(pod);
+            infinispanService.savePodStatus(ps);
+        } catch (Exception e){
+            LOGGER.error(e.getMessage());
+        }
+    }
+
+    @Override
+    public void onUpdate(Pod oldPod, Pod newPod) {
+        try {
+            LOGGER.info("onUpdate " + newPod.getMetadata().getName());
+            PodStatus ps = getPodStatus(newPod);
+            infinispanService.savePodStatus(ps);
+        } catch (Exception e){
+            LOGGER.error(e.getMessage());
+        }
+    }
+
+    @Override
+    public void onDelete(Pod pod, boolean deletedFinalStateUnknown) {
+        try {
+            LOGGER.info("onDelete " + pod.getMetadata().getName());
+            String deployment = pod.getMetadata().getLabels().get("app.kubernetes.io/name");
+            PodStatus ps = new PodStatus(
+                    pod.getMetadata().getName(),
+                    deployment,
+                    kubernetesService.environment);
+            infinispanService.deletePodStatus(ps);
+        } catch (Exception e){
+            LOGGER.error(e.getMessage());
+        }
+    }
+
+
+    public PodStatus getPodStatus(Pod pod) {
+        String deployment = pod.getMetadata().getLabels().get("app.kubernetes.io/name");
+        try {
+            Optional<PodCondition> initialized = pod.getStatus().getConditions().stream().filter(c -> c.getType().equals("Initialized")).findFirst();
+            Optional<PodCondition> ready = pod.getStatus().getConditions().stream().filter(c -> c.getType().equals("Initialized")).findFirst();
+            return new PodStatus(
+                    pod.getMetadata().getName(),
+                    pod.getStatus().getPhase(),
+                    initialized.isEmpty() ? false : initialized.get().getStatus().equals("True"),
+                    ready.isEmpty() ? false : ready.get().getStatus().equals("True"),
+                    pod.getStatus().getReason(),
+                    deployment,
+                    kubernetesService.environment
+            );
+        } catch (Exception ex) {
+            LOGGER.error(ex.getMessage());
+            return new PodStatus(
+                    pod.getMetadata().getName(),
+                    deployment,
+                    kubernetesService.environment);
+        }
+    }
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/watcher/PodWatcher.java b/karavan-app/src/main/java/org/apache/camel/karavan/watcher/PodWatcher.java
deleted file mode 100644
index 99e0982..0000000
--- a/karavan-app/src/main/java/org/apache/camel/karavan/watcher/PodWatcher.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package org.apache.camel.karavan.watcher;
-
-import io.fabric8.kubernetes.api.model.Pod;
-import io.fabric8.kubernetes.api.model.apps.Deployment;
-import io.fabric8.kubernetes.client.Watcher;
-import io.fabric8.kubernetes.client.WatcherException;
-import org.apache.camel.karavan.model.DeploymentStatus;
-import org.apache.camel.karavan.model.Project;
-import org.apache.camel.karavan.service.InfinispanService;
-import org.apache.camel.karavan.service.KubernetesService;
-import org.jboss.logging.Logger;
-
-public class PodWatcher implements Watcher<Pod> {
-
-    private static final Logger LOGGER = Logger.getLogger(PodWatcher.class.getName());
-    private InfinispanService infinispanService;
-    private KubernetesService kubernetesService;
-
-    public PodWatcher(InfinispanService infinispanService, KubernetesService kubernetesService) {
-        this.infinispanService = infinispanService;
-        this.kubernetesService = kubernetesService;
-    }
-
-    @Override
-    public void eventReceived(Action action, Pod pod) {
-        LOGGER.info(action.name() + " " + pod.getMetadata().getName());
-        String name = pod.getMetadata().getLabels().get("app.kubernetes.io/name");
-//        Project project = infinispanService.getProject(name);
-//        Deployment deployment = kubernetesService.getDeployment(name, pod.getMetadata().getNamespace());
-//        if (project != null && deployment != null) {
-//            DeploymentStatus s = kubernetesService.getDeploymentStatus(project.getProjectId(), deployment);
-//            infinispanService.saveDeploymentStatus(s);
-//        }
-    }
-
-    @Override
-    public void onClose(WatcherException cause) {
-
-    }
-}
\ No newline at end of file