From 58c3175797d1765506a68ff6525e3cfd61335c04 Mon Sep 17 00:00:00 2001 From: Ash-exp Date: Wed, 14 May 2025 12:52:40 +0530 Subject: [PATCH 1/5] fix: Missing argocd application update event if there are no histories --- kubewatch/pkg/resource/application/handler.go | 52 ++++++++----------- 1 file changed, 23 insertions(+), 29 deletions(-) diff --git a/kubewatch/pkg/resource/application/handler.go b/kubewatch/pkg/resource/application/handler.go index 614262585..ece2c85d6 100644 --- a/kubewatch/pkg/resource/application/handler.go +++ b/kubewatch/pkg/resource/application/handler.go @@ -53,52 +53,46 @@ func (impl *InformerImpl) GetSharedInformer(clusterLabels *informerBean.ClusterL _, err := acdInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{ AddFunc: func(obj interface{}) { - impl.logger.Debug("app added") - - if app, ok := obj.(*applicationBean.Application); ok { - impl.logger.Debugf("new app detected: %s, status: %s", app.Name, app.Status.Health.Status) - } + impl.logger.Debugw("ARGO_CD_APPLICATION: new application object found") }, UpdateFunc: func(old interface{}, new interface{}) { - impl.logger.Debug("app update detected") + impl.logger.Debugw("ARGO_CD_APPLICATION: application object update detected") statusTime := time.Now() if oldApp, ok := old.(*applicationBean.Application); ok { if newApp, ok := new.(*applicationBean.Application); ok { - if newApp.Status.History != nil && len(newApp.Status.History) > 0 { - if oldApp.Status.History == nil || len(oldApp.Status.History) == 0 { - impl.logger.Debug("new deployment detected") + if len(oldApp.Status.History) < len(newApp.Status.History) { + impl.logger.Debugw("ARGO_CD_APPLICATION: new deployment detected", "appName", newApp.Name, "status", newApp.Status.Health.Status) + impl.sendAppUpdate(clusterLabels.ClusterId, newApp, statusTime) + } else { + impl.logger.Debugw("ARGO_CD_APPLICATION: old deployment detected for update", "appName", oldApp.Name, "status", oldApp.Status.Health.Status) + oldRevision := oldApp.Status.Sync.Revision + newRevision := newApp.Status.Sync.Revision + oldStatus := string(oldApp.Status.Health.Status) + newStatus := string(newApp.Status.Health.Status) + newSyncStatus := string(newApp.Status.Sync.Status) + oldSyncStatus := string(oldApp.Status.Sync.Status) + if (oldRevision != newRevision) || (oldStatus != newStatus) || (newSyncStatus != oldSyncStatus) { impl.sendAppUpdate(clusterLabels.ClusterId, newApp, statusTime) + impl.logger.Debugw("ARGO_CD_APPLICATION: send update event for application object", "appName", oldApp.Name, "oldRevision", oldRevision, "newRevision", + newRevision, "oldStatus", oldStatus, "newStatus", newStatus, + "newSyncStatus", newSyncStatus, "oldSyncStatus", oldSyncStatus) } else { - impl.logger.Debugf("old deployment detected for update: %s, status:%s", oldApp.Name, oldApp.Status.Health.Status) - oldRevision := oldApp.Status.Sync.Revision - newRevision := newApp.Status.Sync.Revision - oldStatus := string(oldApp.Status.Health.Status) - newStatus := string(newApp.Status.Health.Status) - newSyncStatus := string(newApp.Status.Sync.Status) - oldSyncStatus := string(oldApp.Status.Sync.Status) - if (oldRevision != newRevision) || (oldStatus != newStatus) || (newSyncStatus != oldSyncStatus) { - impl.sendAppUpdate(clusterLabels.ClusterId, newApp, statusTime) - impl.logger.Debug("send update app:" + oldApp.Name + ", oldRevision: " + oldRevision + ", newRevision:" + - newRevision + ", oldStatus: " + oldStatus + ", newStatus: " + newStatus + - ", newSyncStatus: " + newSyncStatus + ", oldSyncStatus: " + oldSyncStatus) - } else { - impl.logger.Debug("skip updating app:" + oldApp.Name + ", oldRevision: " + oldRevision + ", newRevision:" + - newRevision + ", oldStatus: " + oldStatus + ", newStatus: " + newStatus + - ", newSyncStatus: " + newSyncStatus + ", oldSyncStatus: " + oldSyncStatus) - } + impl.logger.Debugw("ARGO_CD_APPLICATION: skip updating event for application object", "appName", oldApp.Name, "oldRevision", oldRevision, "newRevision", + newRevision, "oldStatus", oldStatus, "newStatus", newStatus, + "newSyncStatus", newSyncStatus, "oldSyncStatus", oldSyncStatus) } } } else { - log.Println("app update detected, but skip updating, there is no new app") + impl.logger.Errorw("ARGO_CD_APPLICATION: application object update detected, but could not cast to application object", "oldObj", old, "newObj", new) } } else { - log.Println("app update detected, but skip updating, there is no old app") + impl.logger.Errorw("ARGO_CD_APPLICATION: application object update detected, but could not cast to application object", "oldObj", old) } }, DeleteFunc: func(obj interface{}) { if app, ok := obj.(*applicationBean.Application); ok { statusTime := time.Now() - impl.logger.Debugf("app delete detected: %s, status:%s", app.Name, app.Status.Health.Status) + impl.logger.Debugw("ARGO_CD_APPLICATION: application object delete detected", "appName", app.Name, "status", app.Status.Health.Status) impl.sendAppDelete(clusterLabels.ClusterId, app, statusTime) } }, From b688faf4143c38be68319485897f098960e4c789 Mon Sep 17 00:00:00 2001 From: Ash-exp Date: Wed, 14 May 2025 14:14:37 +0530 Subject: [PATCH 2/5] fix: compare LastSyncedResourcesCount to send update event --- kubewatch/pkg/resource/application/bean.go | 7 +++++++ kubewatch/pkg/resource/application/handler.go | 13 ++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/kubewatch/pkg/resource/application/bean.go b/kubewatch/pkg/resource/application/bean.go index 0870aa69d..68b8ea9d6 100644 --- a/kubewatch/pkg/resource/application/bean.go +++ b/kubewatch/pkg/resource/application/bean.go @@ -26,3 +26,10 @@ type applicationDetail struct { StatusTime time.Time `json:"statusTime"` ClusterId int `json:"clusterId"` } + +func getApplicationLastSyncedResourcesCount(appObj *v1alpha1.Application) int { + if appObj.Status.OperationState == nil || appObj.Status.OperationState.SyncResult == nil { + return 0 + } + return len(appObj.Status.OperationState.SyncResult.Resources) +} diff --git a/kubewatch/pkg/resource/application/handler.go b/kubewatch/pkg/resource/application/handler.go index ece2c85d6..2c162b6fb 100644 --- a/kubewatch/pkg/resource/application/handler.go +++ b/kubewatch/pkg/resource/application/handler.go @@ -71,15 +71,22 @@ func (impl *InformerImpl) GetSharedInformer(clusterLabels *informerBean.ClusterL newStatus := string(newApp.Status.Health.Status) newSyncStatus := string(newApp.Status.Sync.Status) oldSyncStatus := string(oldApp.Status.Sync.Status) - if (oldRevision != newRevision) || (oldStatus != newStatus) || (newSyncStatus != oldSyncStatus) { + oldAppLastSyncedResourcesCount := getApplicationLastSyncedResourcesCount(oldApp) + newAppLastSyncedResourcesCount := getApplicationLastSyncedResourcesCount(newApp) + if (oldRevision != newRevision) || + (oldStatus != newStatus) || + (newSyncStatus != oldSyncStatus) || + (oldAppLastSyncedResourcesCount != newAppLastSyncedResourcesCount) { impl.sendAppUpdate(clusterLabels.ClusterId, newApp, statusTime) impl.logger.Debugw("ARGO_CD_APPLICATION: send update event for application object", "appName", oldApp.Name, "oldRevision", oldRevision, "newRevision", newRevision, "oldStatus", oldStatus, "newStatus", newStatus, - "newSyncStatus", newSyncStatus, "oldSyncStatus", oldSyncStatus) + "newSyncStatus", newSyncStatus, "oldSyncStatus", oldSyncStatus, + "oldAppLastSyncedResourcesCount", oldAppLastSyncedResourcesCount, "newAppLastSyncedResourcesCount", newAppLastSyncedResourcesCount) } else { impl.logger.Debugw("ARGO_CD_APPLICATION: skip updating event for application object", "appName", oldApp.Name, "oldRevision", oldRevision, "newRevision", newRevision, "oldStatus", oldStatus, "newStatus", newStatus, - "newSyncStatus", newSyncStatus, "oldSyncStatus", oldSyncStatus) + "newSyncStatus", newSyncStatus, "oldSyncStatus", oldSyncStatus, + "oldAppLastSyncedResourcesCount", oldAppLastSyncedResourcesCount, "newAppLastSyncedResourcesCount", newAppLastSyncedResourcesCount) } } } else { From 3127716a0ad553d3636f837c002cf84f0edd55c7 Mon Sep 17 00:00:00 2001 From: Ash-exp Date: Wed, 14 May 2025 14:39:39 +0530 Subject: [PATCH 3/5] fix: isNewDeploymentFound logic for application update event --- kubewatch/pkg/resource/application/bean.go | 11 +++++++++++ kubewatch/pkg/resource/application/handler.go | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/kubewatch/pkg/resource/application/bean.go b/kubewatch/pkg/resource/application/bean.go index 68b8ea9d6..45ddc4d41 100644 --- a/kubewatch/pkg/resource/application/bean.go +++ b/kubewatch/pkg/resource/application/bean.go @@ -27,6 +27,17 @@ type applicationDetail struct { ClusterId int `json:"clusterId"` } +// isNewDeploymentFound checks if a new deployment is found by comparing the history of old and new application objects. +func isNewDeploymentFound(oldAppObj, newAppObj *v1alpha1.Application) bool { + if len(oldAppObj.Status.History) < len(newAppObj.Status.History) { + return true + } else if len(oldAppObj.Status.History) != 0 && len(oldAppObj.Status.History) == len(newAppObj.Status.History) { + return oldAppObj.Status.History.LastRevisionHistory().ID < newAppObj.Status.History.LastRevisionHistory().ID + } + return false +} + +// getApplicationLastSyncedResourcesCount returns the count of resources that were last synced in the application. func getApplicationLastSyncedResourcesCount(appObj *v1alpha1.Application) int { if appObj.Status.OperationState == nil || appObj.Status.OperationState.SyncResult == nil { return 0 diff --git a/kubewatch/pkg/resource/application/handler.go b/kubewatch/pkg/resource/application/handler.go index 2c162b6fb..abecfbe5b 100644 --- a/kubewatch/pkg/resource/application/handler.go +++ b/kubewatch/pkg/resource/application/handler.go @@ -60,7 +60,7 @@ func (impl *InformerImpl) GetSharedInformer(clusterLabels *informerBean.ClusterL statusTime := time.Now() if oldApp, ok := old.(*applicationBean.Application); ok { if newApp, ok := new.(*applicationBean.Application); ok { - if len(oldApp.Status.History) < len(newApp.Status.History) { + if isNewDeploymentFound(oldApp, newApp) { impl.logger.Debugw("ARGO_CD_APPLICATION: new deployment detected", "appName", newApp.Name, "status", newApp.Status.Health.Status) impl.sendAppUpdate(clusterLabels.ClusterId, newApp, statusTime) } else { From 995719f88851d5d04dd70d4a9e80b1c516587ed3 Mon Sep 17 00:00:00 2001 From: Ash-exp Date: Wed, 14 May 2025 17:54:26 +0530 Subject: [PATCH 4/5] fix: added IsApplicationObjectUpdated logic for application update event --- kubewatch/pkg/resource/application/bean.go | 18 ---- kubewatch/pkg/resource/application/handler.go | 27 ++---- kubewatch/pkg/resource/application/util.go | 85 +++++++++++++++++++ 3 files changed, 90 insertions(+), 40 deletions(-) create mode 100644 kubewatch/pkg/resource/application/util.go diff --git a/kubewatch/pkg/resource/application/bean.go b/kubewatch/pkg/resource/application/bean.go index 45ddc4d41..0870aa69d 100644 --- a/kubewatch/pkg/resource/application/bean.go +++ b/kubewatch/pkg/resource/application/bean.go @@ -26,21 +26,3 @@ type applicationDetail struct { StatusTime time.Time `json:"statusTime"` ClusterId int `json:"clusterId"` } - -// isNewDeploymentFound checks if a new deployment is found by comparing the history of old and new application objects. -func isNewDeploymentFound(oldAppObj, newAppObj *v1alpha1.Application) bool { - if len(oldAppObj.Status.History) < len(newAppObj.Status.History) { - return true - } else if len(oldAppObj.Status.History) != 0 && len(oldAppObj.Status.History) == len(newAppObj.Status.History) { - return oldAppObj.Status.History.LastRevisionHistory().ID < newAppObj.Status.History.LastRevisionHistory().ID - } - return false -} - -// getApplicationLastSyncedResourcesCount returns the count of resources that were last synced in the application. -func getApplicationLastSyncedResourcesCount(appObj *v1alpha1.Application) int { - if appObj.Status.OperationState == nil || appObj.Status.OperationState.SyncResult == nil { - return 0 - } - return len(appObj.Status.OperationState.SyncResult.Resources) -} diff --git a/kubewatch/pkg/resource/application/handler.go b/kubewatch/pkg/resource/application/handler.go index abecfbe5b..44805a67e 100644 --- a/kubewatch/pkg/resource/application/handler.go +++ b/kubewatch/pkg/resource/application/handler.go @@ -60,33 +60,16 @@ func (impl *InformerImpl) GetSharedInformer(clusterLabels *informerBean.ClusterL statusTime := time.Now() if oldApp, ok := old.(*applicationBean.Application); ok { if newApp, ok := new.(*applicationBean.Application); ok { - if isNewDeploymentFound(oldApp, newApp) { + // Check if the application has a new deployment history + if isNewDeploymentHistoryFound(oldApp, newApp) { impl.logger.Debugw("ARGO_CD_APPLICATION: new deployment detected", "appName", newApp.Name, "status", newApp.Status.Health.Status) impl.sendAppUpdate(clusterLabels.ClusterId, newApp, statusTime) } else { - impl.logger.Debugw("ARGO_CD_APPLICATION: old deployment detected for update", "appName", oldApp.Name, "status", oldApp.Status.Health.Status) - oldRevision := oldApp.Status.Sync.Revision - newRevision := newApp.Status.Sync.Revision - oldStatus := string(oldApp.Status.Health.Status) - newStatus := string(newApp.Status.Health.Status) - newSyncStatus := string(newApp.Status.Sync.Status) - oldSyncStatus := string(oldApp.Status.Sync.Status) - oldAppLastSyncedResourcesCount := getApplicationLastSyncedResourcesCount(oldApp) - newAppLastSyncedResourcesCount := getApplicationLastSyncedResourcesCount(newApp) - if (oldRevision != newRevision) || - (oldStatus != newStatus) || - (newSyncStatus != oldSyncStatus) || - (oldAppLastSyncedResourcesCount != newAppLastSyncedResourcesCount) { + if IsApplicationObjectUpdated(impl.logger, oldApp, newApp) { impl.sendAppUpdate(clusterLabels.ClusterId, newApp, statusTime) - impl.logger.Debugw("ARGO_CD_APPLICATION: send update event for application object", "appName", oldApp.Name, "oldRevision", oldRevision, "newRevision", - newRevision, "oldStatus", oldStatus, "newStatus", newStatus, - "newSyncStatus", newSyncStatus, "oldSyncStatus", oldSyncStatus, - "oldAppLastSyncedResourcesCount", oldAppLastSyncedResourcesCount, "newAppLastSyncedResourcesCount", newAppLastSyncedResourcesCount) + impl.logger.Debugw("ARGO_CD_APPLICATION: send update event for application object", "appName", oldApp.Name) } else { - impl.logger.Debugw("ARGO_CD_APPLICATION: skip updating event for application object", "appName", oldApp.Name, "oldRevision", oldRevision, "newRevision", - newRevision, "oldStatus", oldStatus, "newStatus", newStatus, - "newSyncStatus", newSyncStatus, "oldSyncStatus", oldSyncStatus, - "oldAppLastSyncedResourcesCount", oldAppLastSyncedResourcesCount, "newAppLastSyncedResourcesCount", newAppLastSyncedResourcesCount) + impl.logger.Debugw("ARGO_CD_APPLICATION: skip updating event for application object", "appName", oldApp.Name) } } } else { diff --git a/kubewatch/pkg/resource/application/util.go b/kubewatch/pkg/resource/application/util.go new file mode 100644 index 000000000..d65af83ef --- /dev/null +++ b/kubewatch/pkg/resource/application/util.go @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed 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 application + +import ( + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + synccommon "github.com/argoproj/gitops-engine/pkg/sync/common" + "go.uber.org/zap" +) + +// isNewDeploymentHistoryFound checks +// if a new deployment is found by +// comparing the history of old and new application objects. +func isNewDeploymentHistoryFound(oldAppObj, newAppObj *v1alpha1.Application) bool { + if len(oldAppObj.Status.History) < len(newAppObj.Status.History) { + return true + } else if len(oldAppObj.Status.History) != 0 && len(oldAppObj.Status.History) == len(newAppObj.Status.History) { + return oldAppObj.Status.History.LastRevisionHistory().ID < newAppObj.Status.History.LastRevisionHistory().ID + } + return false +} + +// getApplicationLastSyncedResourcesCount returns the count of resources that were last synced in the application. +func getApplicationLastSyncedResourcesCount(appObj *v1alpha1.Application) int { + if appObj.Status.OperationState == nil || appObj.Status.OperationState.SyncResult == nil { + return 0 + } + return len(appObj.Status.OperationState.SyncResult.Resources) +} + +func getApplicationOperationRevision(appObj *v1alpha1.Application) string { + if appObj.Status.OperationState == nil || appObj.Status.OperationState.Operation.Sync == nil { + return "" + } + return appObj.Status.OperationState.Operation.Sync.Revision +} + +func getApplicationOperationPhase(appObj *v1alpha1.Application) synccommon.OperationPhase { + if appObj.Status.OperationState == nil { + return "" + } + return appObj.Status.OperationState.Phase +} + +func IsApplicationObjectUpdated(logger *zap.SugaredLogger, oldAppObj, newAppObj *v1alpha1.Application) bool { + // Check if the application sync revision has changed + oldRevision := oldAppObj.Status.Sync.Revision + newRevision := newAppObj.Status.Sync.Revision + // Check if the operation revision has changed + oldOperationRevision := getApplicationOperationRevision(oldAppObj) + newOperationRevision := getApplicationOperationRevision(newAppObj) + // Check if the health status has changed + oldStatus := string(oldAppObj.Status.Health.Status) + newStatus := string(newAppObj.Status.Health.Status) + // Check if the operation phase has changed + oldOperationPhase := getApplicationOperationPhase(oldAppObj) + newOperationPhase := getApplicationOperationPhase(newAppObj) + // Check if the last synced resources count has changed + oldAppLastSyncedResourcesCount := getApplicationLastSyncedResourcesCount(oldAppObj) + newAppLastSyncedResourcesCount := getApplicationLastSyncedResourcesCount(newAppObj) + + logger.Debugw("oldRevision", oldRevision, "newRevision", newRevision, + "oldOperationRevision", oldOperationRevision, "newOperationRevision", newOperationRevision, + "oldStatus", oldStatus, "newStatus", newStatus, + "oldOperationPhase", oldOperationPhase, "newOperationPhase", newOperationPhase, + "oldAppLastSyncedResourcesCount", oldAppLastSyncedResourcesCount, "newAppLastSyncedResourcesCount", newAppLastSyncedResourcesCount) + + return (oldRevision != newRevision) || (newOperationRevision != oldOperationRevision) || + (oldStatus != newStatus) || (oldOperationPhase != newOperationPhase) || + (oldAppLastSyncedResourcesCount != newAppLastSyncedResourcesCount) +} From ec831a71e9e967d9afc705aed0c7ee43c92efa4d Mon Sep 17 00:00:00 2001 From: Ash-exp Date: Thu, 15 May 2025 03:02:15 +0530 Subject: [PATCH 5/5] fix: invalid logger msg --- kubewatch/pkg/resource/application/util.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kubewatch/pkg/resource/application/util.go b/kubewatch/pkg/resource/application/util.go index d65af83ef..4522196ac 100644 --- a/kubewatch/pkg/resource/application/util.go +++ b/kubewatch/pkg/resource/application/util.go @@ -73,7 +73,7 @@ func IsApplicationObjectUpdated(logger *zap.SugaredLogger, oldAppObj, newAppObj oldAppLastSyncedResourcesCount := getApplicationLastSyncedResourcesCount(oldAppObj) newAppLastSyncedResourcesCount := getApplicationLastSyncedResourcesCount(newAppObj) - logger.Debugw("oldRevision", oldRevision, "newRevision", newRevision, + logger.Debugw("ARGO_CD_APPLICATION: update event captured with", "oldRevision", oldRevision, "newRevision", newRevision, "oldOperationRevision", oldOperationRevision, "newOperationRevision", newOperationRevision, "oldStatus", oldStatus, "newStatus", newStatus, "oldOperationPhase", oldOperationPhase, "newOperationPhase", newOperationPhase,